1 ////////////////////////////////////////////////////////////////////////
2 // FILE: package.cpp
3 // AUTHOR: Johannes Winkelmann, jw@tks6.net
4 // COPYRIGHT: (c) 2002 by Johannes Winkelmann
5 // ---------------------------------------------------------------------
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 ////////////////////////////////////////////////////////////////////////
11
12
13 #include <iostream>
14 #include <cstdio>
15 #include <sys/stat.h>
16 #include <sys/utsname.h>
17 using namespace std;
18
19 #include "package.h"
20 #include "stringhelper.h"
21 using namespace StringHelper;
22
23
24
25 /*!
26 Create a package, which is not yet fully initialized, This is interesting
27 in combination with the lazy initialization
28 */
29 Package::Package( const string& name,
30 const string& path )
31 : m_loaded( false )
32 {
33 m_data = new PackageData( name, path );
34 }
35
36 /*!
37 Create a fully initialized package. Most interesting when created from a
38 cache file
39 */
40 Package::Package( const string& name,
41 const string& path,
42 const string& version,
43 const string& release,
44 const string& description,
45 const string& dependencies,
46 const string& url,
47 const string& packager,
48 const string& maintainer,
49 const string& hasReadme,
50 const string& hasPreInstall,
51 const string& hasPostInstall)
52 : m_loaded( true )
53 {
54 m_data = new PackageData( name, path, version, release,
55 description, dependencies, url,
56 packager, maintainer, hasReadme,
57 hasPreInstall, hasPostInstall );
58
59 }
60
61 Package::~Package()
62 {
63 delete m_data;
64 }
65
66 /*! \return the name of this package */
67 const string& Package::name() const
68 {
69 return m_data->name;
70 }
71
72 /*! \return the path to this package */
73 const string& Package::path() const
74 {
75 return m_data->path;
76 }
77
78 /*! \return the version of this package */
79 const string& Package::version() const
80 {
81 load();
82 return m_data->version;
83 }
84
85 /*! \return the release number of this package */
86 const string& Package::release() const
87 {
88 load();
89 return m_data->release;
90 }
91
92 /*! \return the description field of this package */
93 const string& Package::description() const
94 {
95 load();
96 return m_data->description;
97 }
98
99 /*! \return the dependency line of this package */
100 const string& Package::dependencies() const
101 {
102 load();
103 return m_data->depends;
104 }
105
106 /*! \return the url of this package */
107 const string& Package::url() const
108 {
109 load();
110 return m_data->url;
111 }
112
113 /*! \return the packager of this package */
114 const string& Package::packager() const
115 {
116 load();
117 return m_data->packager;
118 }
119 /*! \return the maintainer of this package */
120 const string& Package::maintainer() const
121 {
122 load();
123 return m_data->maintainer;
124 }
125
126 /*! \return whether or not this package has a readme file */
127 const bool Package::hasReadme() const
128 {
129 load();
130 return m_data->hasReadme;
131 }
132
133 /*! \return a typically formatted version-release string */
134 string Package::versionReleaseString() const
135 {
136 load();
137 return m_data->versionReleaseString;
138 }
139
140 const bool Package::hasPreInstall() const
141 {
142 return m_data->hasPreInstall;
143 }
144
145 const bool Package::hasPostInstall() const
146 {
147 return m_data->hasPostInstall;
148 }
149
150 /*!
151 load from Pkgfile
152 */
153 void Package::load() const
154 {
155 if ( m_loaded ) {
156 return;
157 }
158 m_loaded = true;
159
160 string fileName = m_data->path + "/" + m_data->name + "/Pkgfile";
161
162 // c IO is about four times faster then fstream :-(
163 FILE* fp = fopen( fileName.c_str(), "r" );
164 if ( fp == NULL ) {
165 return;
166 }
167
168
169 const int length = BUFSIZ;
170 char input[length];
171 string line;
172
173 time_t timeNow;
174 time(&timeNow);
175
176 struct utsname unameBuf;
177 if (uname(&unameBuf) != 0) {
178 unameBuf.release[0] = '\0';
179 }
180
181
182
183 while ( fgets( input, length, fp ) ) {
184
185 line = stripWhiteSpace( input );
186
187 if ( line.substr( 0, 8 ) == "version=" ) {
188 m_data->version = getValueBefore( getValue( line, '=' ), '#' );
189 m_data->version = stripWhiteSpace( m_data->version );
190
191 expandShellCommands(m_data->version, timeNow, unameBuf);
192 } else if ( line.substr( 0, 8 ) == "release=" ) {
193 m_data->release = getValueBefore( getValue( line, '=' ), '#' );
194 m_data->release = stripWhiteSpace( m_data->release );
195 } else if ( line[0] == '#' ) {
196 while ( !line.empty() &&
197 ( line[0] == '#' || line[0] == ' ' || line[0] == '\t' ) ) {
198 line = line.substr( 1 );
199 }
200 string::size_type pos = line.find( ':' );
201 if ( pos != string::npos ) {
202 if ( startsWithNoCase( line, "desc" ) ) {
203 m_data->description =
204 stripWhiteSpace( getValue( line, ':' ) );
205
206 } else if ( startsWithNoCase( line, "pack" ) ) {
207 m_data->packager =
208 stripWhiteSpace( getValue( line, ':' ) );
209 } else if ( startsWithNoCase( line, "maint" ) ) {
210 m_data->maintainer =
211 stripWhiteSpace( getValue( line, ':' ) );
212 } else if ( startsWithNoCase( line, "url" ) ) {
213 m_data->url = stripWhiteSpace( getValue( line, ':' ) );
214 } else if ( startsWithNoCase( line, "dep" ) ) {
215 string depends = stripWhiteSpace( getValue( line, ':' ) );
216
217 StringHelper::replaceAll( depends, " ", "," );
218 StringHelper::replaceAll( depends, ",,", "," );
219
220 // TODO: decide which one to use
221 #if 0
222 // remove commented out packages
223 list<string> deps = StringHelper::split( depends, ',' );
224 list<string>::iterator it = deps.begin();
225 for ( ; it != deps.end(); ++it ) {
226 if ( (*it)[0] == '#' ) {
227 cerr << "Commented dep: " << *it << endl;
228 } else {
229 if ( it != deps.begin() ) {
230 m_data->depends += ",";
231 }
232 m_data->depends += *it;
233 }
234 }
235 #else
236 m_data->depends = depends;
237 #endif
238
239 }
240 }
241 }
242 }
243 fclose( fp );
244
245 m_data->generateVersionReleaseString();
246
247 string file = m_data->path + "/" + m_data->name + "/README";
248 struct stat buf;
249 if ( stat( file.c_str(), &buf ) != -1) {
250 m_data->hasReadme = true;
251 }
252 file = m_data->path + "/" + m_data->name + "/pre-install";
253 if ( stat( file.c_str(), &buf ) != -1) {
254 m_data->hasPreInstall = true;
255 }
256 file = m_data->path + "/" + m_data->name + "/post-install";
257 if ( stat( file.c_str(), &buf ) != -1) {
258 m_data->hasPostInstall = true;
259 }
260
261 }
262
263 void Package::setDependencies( const std::string& dependencies )
264 {
265 m_data->depends = dependencies;
266 }
267
268
269
270 PackageData::PackageData( const string& name_,
271 const string& path_,
272 const string& version_,
273 const string& release_,
274 const string& description_,
275 const string& dependencies_,
276 const string& url_,
277 const string& packager_,
278 const string& maintainer_,
279 const string& hasReadme_,
280 const string& hasPreInstall_,
281 const string& hasPostInstall_ )
282 : name( name_ ),
283 path( path_ ),
284 version( version_ ),
285 release( release_ ),
286 description( description_ ),
287 depends( dependencies_ ),
288 url( url_ ),
289 packager( packager_ ),
290 maintainer( maintainer_ )
291
292 {
293 generateVersionReleaseString();
294
295 hasReadme = ( stripWhiteSpace( hasReadme_ ) == "yes" );
296 hasPreInstall = ( stripWhiteSpace( hasPreInstall_ ) == "yes" );
297 hasPostInstall = ( stripWhiteSpace( hasPostInstall_ ) == "yes" );
298 }
299
300 void PackageData::generateVersionReleaseString()
301 {
302 versionReleaseString = version + "-" + release;
303 }
304
305
306 void Package::expandShellCommands(std::string& input,
307 const time_t& timeNow,
308 const struct utsname unameBuf)
309 {
310 // TODO: consider dropping either of the tagsets, depending on feedback
311
312 static const int TAG_COUNT = 2;
313 string startTag[TAG_COUNT] = { "`", "$(" };
314 string endTag[TAG_COUNT] = { "`", ")" };
315
316 for (int i = 0; i < TAG_COUNT; ++i) {
317 string::size_type pos, dpos = 0;
318
319 int len;
320 pos = 0;
321 while ((pos = input.find(startTag[i], pos)) != string::npos) {
322 len = input.length();
323
324 if (unameBuf.release) {
325 input = replaceAll(input,
326 startTag[i] + "uname -r" + endTag[i],
327 unameBuf.release);
328 }
329
330 dpos = input.find(startTag[i] + "date");
331 if (dpos != string::npos) {
332 // NOTE: currently only works for one date pattern
333 string::size_type startpos, endpos;
334 endpos = input.find(endTag[i], dpos+1);
335 startpos = input.find('+', dpos+1);
336
337 string format = input.substr(startpos+1, endpos-startpos-1);
338
339 // support date '+...' and date "+..."
340 int len = format.length();
341 if (format[len-1] == '\'' || format[len-1] == '"') {
342 format = format.substr(0, len-1);
343 }
344 char timeBuf[32];
345 strftime(timeBuf, 32, format.c_str(), localtime(&timeNow));
346
347 input = input.substr(0, dpos) + timeBuf +
348 input.substr(endpos+1);
349 }
350
351 ++pos;
352 }
353 }
354 }
|