]> cygwin.com Git - cygwin-apps/setup.git/blob - package_meta.cc
copyright
[cygwin-apps/setup.git] / package_meta.cc
1 /*
2 * Copyright (c) 2001, Robert Collins.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Robert Collins <rbtcollins@hotmail.com>
13 *
14 */
15
16 #if 0
17 static const char *cvsid = "\n%%% $Id$\n";
18 #endif
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <strings.h>
24
25 #include "io_stream.h"
26 #include "compress.h"
27
28 #include "filemanip.h"
29 #include "hash.h"
30 #include "log.h"
31 /* io_stream needs a bit of tweaking to get rid of this. TODO */
32 #include "mount.h"
33 /* this goes at the same time */
34 #include "win32.h"
35
36
37 #include "category.h"
38 #include "script.h"
39
40 #include "package_version.h"
41 #include "cygpackage.h"
42 #include "package_meta.h"
43 #include "package_db.h"
44
45 static const char *standard_dirs[] = {
46 "bin",
47 "etc",
48 "lib",
49 "tmp",
50 "usr",
51 "usr/bin",
52 "usr/lib",
53 "usr/src",
54 "usr/local",
55 "usr/local/bin",
56 "usr/local/etc",
57 "usr/local/lib",
58 "usr/tmp",
59 "var/run",
60 "var/tmp",
61 0
62 };
63
64 void
65 hash::add_subdirs (String const &tpath)
66 {
67 char *nonp, *pp;
68 char *path = tpath.cstr();
69 for (nonp = path; *nonp == '\\' || *nonp == '/'; nonp++);
70 for (pp = path + strlen (path) - 1; pp > nonp; pp--)
71 if (*pp == '/' || *pp == '\\')
72 {
73 int i, s = 0;
74 char c = *pp;
75 *pp = 0;
76 for (i = 0; standard_dirs[i]; i++)
77 if (strcmp (standard_dirs[i] + 1, path) == 0)
78 {
79 s = 1;
80 break;
81 }
82 if (s == 0)
83 add (path);
84 *pp = c;
85 }
86 }
87
88 /*****************/
89
90 CategoryPackage::~CategoryPackage()
91 {
92 CategoryPackage **temp = &key.packages;
93 while (*temp != this)
94 temp = &((*temp)->next);
95 *temp = next;
96 }
97
98 /*****************/
99
100 const
101 packagemeta::_actions
102 packagemeta::Default_action (0);
103 const
104 packagemeta::_actions
105 packagemeta::Install_action (1);
106 const
107 packagemeta::_actions
108 packagemeta::Reinstall_action (2);
109 const
110 packagemeta::_actions
111 packagemeta::Uninstall_action (3);
112
113 char const *
114 packagemeta::_actions::caption ()
115 {
116 switch (_value)
117 {
118 case 0:
119 return "Default";
120 case 1:
121 return "Install";
122 case 2:
123 return "Reinstall";
124 case 3:
125 return "Uninstall";
126 }
127 // Pacify GCC: (all case options are checked above)
128 return 0;
129 }
130
131 packagemeta::_actions & packagemeta::_actions::operator++ ()
132 {
133 ++_value;
134 if (_value > 3)
135 _value = 0;
136 return *this;
137 }
138
139 packagemeta::~packagemeta()
140 {
141 while (Categories.number ())
142 {
143 CategoryPackage *catpkg = Categories.removebyindex (1);
144 delete catpkg;
145 }
146 while (versions.number ())
147 {
148 packageversion *pv = versions.removebyindex(1);
149 delete pv;
150 }
151 }
152
153 void
154 packagemeta::add_version (packageversion & thepkg)
155 {
156 versions.registerbyobject (thepkg);
157 }
158
159 /* assumption: package thepkg is already in the metadata list. */
160 void
161 packagemeta::set_installed (packageversion & thepkg)
162 {
163 packageversion *temp = versions.getbykey (thepkg.key);
164 if (temp == &thepkg)
165 installed = &thepkg;
166 }
167
168 /* uninstall a package if it's installed */
169 void
170 packagemeta::uninstall ()
171 {
172 if (installed)
173 {
174 /* this will need to be pushed down to the version, or even the source level
175 * to allow differences between formats to be seamlessly managed
176 * but for now: here is ok
177 */
178 hash dirs;
179 String line = installed->getfirstfile ();
180
181 try_run_script ("/etc/preremove/", name);
182 while (line.size())
183 {
184 dirs.add_subdirs (line);
185
186 String d = cygpath (String ("/") + line);
187 DWORD dw = GetFileAttributes (d.cstr_oneuse());
188 if (dw != INVALID_FILE_ATTRIBUTES
189 && !(dw & FILE_ATTRIBUTE_DIRECTORY))
190 {
191 log (LOG_BABBLE, String("unlink ")+ d);
192 SetFileAttributes (d.cstr_oneuse(), dw & ~FILE_ATTRIBUTE_READONLY);
193 DeleteFile (d.cstr_oneuse());
194 }
195 /* Check for Windows shortcut of same name. */
196 d += ".lnk";
197 dw = GetFileAttributes (d.cstr_oneuse());
198 if (dw != INVALID_FILE_ATTRIBUTES
199 && !(dw & FILE_ATTRIBUTE_DIRECTORY))
200 {
201 log (LOG_BABBLE, String("unlink ") + d);
202 SetFileAttributes (d.cstr_oneuse(),
203 dw & ~FILE_ATTRIBUTE_READONLY);
204 DeleteFile (d.cstr_oneuse());
205 }
206 line = installed->getnextfile ();
207 }
208 installed->uninstall ();
209
210 dirs.reverse_sort ();
211 char *subdir = 0;
212 while ((subdir = dirs.enumerate (subdir)) != 0)
213 {
214 String d = cygpath (String ("/") + subdir);
215 if (RemoveDirectory (d.cstr_oneuse()))
216 log (LOG_BABBLE, String("rmdir ") + d);
217 }
218 try_run_script ("/etc/postremove/", name);
219 }
220 installed = 0;
221 }
222
223
224 void
225 packagemeta::add_category (Category & cat)
226 {
227 /* add a new record for the package list */
228 CategoryPackage & catpack = Categories.registerbykey (cat);
229 catpack.pkg = this;
230 }
231
232 String const
233 packagemeta::SDesc () const
234 {
235 for (size_t n = 1; n <= versions.number (); ++n)
236 if (versions[n]->SDesc ().size())
237 return versions[n]->SDesc ();
238 return String();
239 };
240
241 /* Return an appropriate caption given the current action. */
242 String
243 packagemeta::action_caption ()
244 {
245 if (!desired && installed)
246 return "Uninstall";
247 else if (!desired)
248 return "Skip";
249 else if (desired == installed && desired->binpicked)
250 {
251 packagedb db;
252 return db.task == PackageDB_Install ? "Reinstall" : "Retrieve";
253 }
254 else if (desired == installed && desired->srcpicked)
255 /* FIXME: Redo source should come up if the tarball is already present locally */
256 return "Source";
257 else if (desired == installed) /* and neither src nor bin */
258 return "Keep";
259 else
260 return desired->Canonical_version ();
261 }
262
263 /* Set the next action given a current action. */
264 void
265 packagemeta::set_action (packageversion * default_version)
266 {
267 /* actions are the following:
268
269 for install modes (from net/local)
270 for each version:
271 install this version
272 install the source for this version
273 and a boolean flag - force install to allow reinstallation, or bypassing requirements
274 globally:
275 install the source for the current version.
276
277 to uninstall a package, the desired version is set to NULL;
278
279 for mirroring modes (download only)
280 for each version
281 download this version
282 download source for this version
283
284 these are represented by the following:
285 the desired pointer in the packagemetadata indicated which version we are operating on.
286 if we are operating on the installed version, reinstall is a valid option.
287 for the selected version, forceinstall means Do an install no matter what, and
288 srcpicked means download the source.
289
290 The default action for any installed package is to install the 'curr version'
291 if it is not already installed.
292
293 The default action for any non-installed package is to do nothing.
294
295 To achieve a no-op, set desired==installed, and if (installed) set forceinstall=0 and
296 srcpicked = 0;
297
298 Iteration through versions should follow the following rules:
299 selected radio button (prev/curr/test) (show as reinstall if that is the
300 current version) ->source only (only if the package is installed) ->oldest version....s
301 kip version of radio button...
302 newest version->uninstall->no-op->selected radio button.
303
304 If any state cannot be set (ie because (say) no prev entry exists for a package
305 simply progress to the next option.
306
307 */
308
309 /* We were set to uninstall the package */
310 if (!desired && installed)
311 {
312 /* No-op - keep whatever we've got */
313 desired = installed;
314 if (desired)
315 {
316 desired->binpicked = 0;
317 desired->srcpicked = 0;
318 }
319 return;
320 }
321 else if (desired == installed
322 && (!installed || !(installed->binpicked || installed->srcpicked)))
323 /* Install the default trust version - this is a 'reinstall' for installed
324 * packages */
325 {
326 desired = NULL;
327 /* No-op */
328 desired = default_version;
329 if (desired)
330 {
331 desired->binpicked = 1;
332 return;
333 }
334 }
335 /* are we currently on the radio button selection and installed */
336 if (desired == default_version && installed &&
337 (!desired || desired->binpicked)
338 && (desired &&
339 (desired->src.Cached () || desired->src.sites.number ())))
340 {
341 /* source only this file */
342 desired = installed;
343 desired->binpicked = 0;
344 desired->srcpicked = 1;
345 return;
346 }
347 /* are we currently on source only or on the radio button but not installed */
348 else if ((desired == installed && installed
349 && installed->srcpicked) || desired == default_version)
350 {
351 /* move onto the loop through versions */
352 desired = versions[1];
353 if (desired == default_version)
354 desired = versions.number () > 1 ? versions[2] : NULL;
355 if (desired)
356 {
357 desired->binpicked = 1;
358 desired->srcpicked = 0;
359 }
360 return;
361 }
362 else
363 {
364 /* preserve the src tick box */
365 int source = desired->srcpicked;
366 /* bump the version selected, skipping the radio button trust along the way */
367 size_t n;
368 for (n = 1; n <= versions.number () && desired != versions[n]; n++);
369 /* n points at pkg->desired */
370 n++;
371 if (n <= versions.number ())
372 {
373 if (default_version == versions[n])
374 n++;
375 if (n <= versions.number ())
376 {
377 desired = versions[n];
378 desired->srcpicked = source;
379 return;
380 }
381 }
382 /* went past the end - uninstall the package */
383 desired = NULL;
384 }
385 }
386
387 int
388 packagemeta::set_requirements (trusts deftrust = TRUST_CURR, size_t depth = 0)
389 {
390 Dependency *dp;
391 packagemeta *required;
392 int changed = 0;
393 if (!desired || (desired != installed && !desired->binpicked))
394 /* uninstall || source only */
395 return 0;
396
397 dp = desired->required;
398 packagedb db;
399 /* cheap test for too much recursion */
400 if (depth > 5)
401 return 0;
402 while (dp)
403 {
404 if ((required = db.packages.getbykey (dp->package)) == NULL)
405 {
406 dp = dp->next;
407 changed++;
408 continue;
409 }
410 if (!required->desired)
411 {
412 /* it's set to uninstall */
413 required->set_action (required->trustp (deftrust));
414 }
415 else if (required->desired != required->installed
416 && !required->desired->binpicked)
417 {
418 /* it's set to change to a different version source only */
419 required->desired->binpicked = 1;
420 }
421 /* does this requirement have requirements? */
422 changed += required->set_requirements (deftrust, depth + 1);
423 dp = dp->next;
424 }
425 return changed;
426 }
427
428
429 // Set a particular type of action.
430 void
431 packagemeta::set_action (_actions action, packageversion * default_version)
432 {
433 packagedb db;
434 if (action == Default_action)
435 {
436 // XXX fix the list use to allow const ref usage.
437 Category tempCategory("Misc");
438 if (installed
439 || Categories.getbykey (db.categories.registerbykey ("Base"))
440 || Categories.getbykey (tempCategory))
441 {
442 desired = default_version;
443 if (desired)
444 {
445 desired->binpicked = desired == installed ? 0 : 1;
446 desired->srcpicked = 0;
447 }
448 }
449 else
450 desired = 0;
451 return;
452 }
453 else if (action == Install_action)
454 {
455 desired = default_version;
456 if (desired)
457 {
458 if (desired != installed)
459 desired->binpicked = 1;
460 else
461 desired->binpicked = 0;
462 desired->srcpicked = 0;
463 }
464 return;
465 }
466 else if (action == Reinstall_action)
467 {
468 desired = installed;
469 if (desired)
470 {
471 desired->binpicked = 1;
472 desired->srcpicked = 0;
473 }
474 }
475 else if (action == Uninstall_action)
476 {
477 desired = 0;
478 }
479 }
This page took 0.053385 seconds and 5 git commands to generate.