]> cygwin.com Git - cygwin-apps/setup.git/blame - package_meta.cc
2002-06-15 Robert Collins <rbtcollins@hotmail.com>
[cygwin-apps/setup.git] / package_meta.cc
CommitLineData
7939f6d1
RC
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
7e8fc33c 17static const char *cvsid = "\n%%% $Id$\n";
7939f6d1
RC
18#endif
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <strings.h>
7939f6d1
RC
24
25#include "io_stream.h"
26#include "compress.h"
27
28#include "filemanip.h"
fa0c0d10
RC
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"
7939f6d1 35
bb849dbd
RC
36
37#include "category.h"
8e9aa511 38#include "script.h"
bb849dbd 39
fa0c0d10 40#include "package_version.h"
7939f6d1
RC
41#include "cygpackage.h"
42#include "package_meta.h"
cbfc4215 43#include "package_db.h"
7939f6d1 44
fa0c0d10 45static const char *standard_dirs[] = {
204315f9
RC
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",
fa0c0d10
RC
61 0
62};
63
64void
3c054baf 65hash::add_subdirs (String const &tpath)
fa0c0d10
RC
66{
67 char *nonp, *pp;
3c054baf 68 char *path = tpath.cstr();
fa0c0d10
RC
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
7c6ef2c3
RC
88/*****************/
89
90CategoryPackage::~CategoryPackage()
91{
92 CategoryPackage **temp = &key.packages;
93 while (*temp != this)
94 temp = &((*temp)->next);
95 *temp = next;
96}
97
98/*****************/
99
7e8fc33c
RC
100const
101 packagemeta::_actions
102packagemeta::Default_action (0);
103const
104 packagemeta::_actions
105packagemeta::Install_action (1);
106const
107 packagemeta::_actions
108packagemeta::Reinstall_action (2);
109const
110 packagemeta::_actions
111packagemeta::Uninstall_action (3);
112
113char const *
114packagemeta::_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
131packagemeta::_actions & packagemeta::_actions::operator++ ()
132{
133 ++_value;
134 if (_value > 3)
135 _value = 0;
136 return *this;
137}
138
7c6ef2c3
RC
139packagemeta::~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
7939f6d1 153void
fa0c0d10 154packagemeta::add_version (packageversion & thepkg)
7939f6d1 155{
bb849dbd 156 versions.registerbyobject (thepkg);
7939f6d1
RC
157}
158
159/* assumption: package thepkg is already in the metadata list. */
160void
fa0c0d10 161packagemeta::set_installed (packageversion & thepkg)
7939f6d1 162{
bb849dbd
RC
163 packageversion *temp = versions.getbykey (thepkg.key);
164 if (temp == &thepkg)
165 installed = &thepkg;
7939f6d1 166}
fa0c0d10
RC
167
168/* uninstall a package if it's installed */
169void
170packagemeta::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;
3c054baf 179 String line = installed->getfirstfile ();
8e9aa511
RC
180
181 try_run_script ("/etc/preremove/", name);
3c054baf 182 while (line.size())
fa0c0d10
RC
183 {
184 dirs.add_subdirs (line);
185
1ac649ed 186 String d = cygpath (String ("/") + line);
3c054baf 187 DWORD dw = GetFileAttributes (d.cstr_oneuse());
7e8fc33c
RC
188 if (dw != INVALID_FILE_ATTRIBUTES
189 && !(dw & FILE_ATTRIBUTE_DIRECTORY))
fa0c0d10 190 {
3c054baf
RC
191 log (LOG_BABBLE, String("unlink ")+ d);
192 SetFileAttributes (d.cstr_oneuse(), dw & ~FILE_ATTRIBUTE_READONLY);
193 DeleteFile (d.cstr_oneuse());
edef4f57
CV
194 }
195 /* Check for Windows shortcut of same name. */
3c054baf
RC
196 d += ".lnk";
197 dw = GetFileAttributes (d.cstr_oneuse());
7e8fc33c
RC
198 if (dw != INVALID_FILE_ATTRIBUTES
199 && !(dw & FILE_ATTRIBUTE_DIRECTORY))
edef4f57 200 {
3c054baf 201 log (LOG_BABBLE, String("unlink ") + d);
1ac649ed
RC
202 SetFileAttributes (d.cstr_oneuse(),
203 dw & ~FILE_ATTRIBUTE_READONLY);
3c054baf 204 DeleteFile (d.cstr_oneuse());
fa0c0d10
RC
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 {
1ac649ed 214 String d = cygpath (String ("/") + subdir);
3c054baf 215 if (RemoveDirectory (d.cstr_oneuse()))
1ac649ed 216 log (LOG_BABBLE, String("rmdir ") + d);
fa0c0d10 217 }
8e9aa511 218 try_run_script ("/etc/postremove/", name);
fa0c0d10
RC
219 }
220 installed = 0;
221}
bb849dbd
RC
222
223
224void
225packagemeta::add_category (Category & cat)
226{
227 /* add a new record for the package list */
4fe323f9
RC
228 CategoryPackage & catpack = Categories.registerbykey (cat);
229 catpack.pkg = this;
bb849dbd
RC
230}
231
3c054baf 232String const
df62e023 233packagemeta::SDesc () const
bb849dbd 234{
7e8fc33c 235 for (size_t n = 1; n <= versions.number (); ++n)
3c054baf 236 if (versions[n]->SDesc ().size())
bcf20115 237 return versions[n]->SDesc ();
076654e7 238 return String();
bb849dbd 239};
cbfc4215
RC
240
241/* Return an appropriate caption given the current action. */
3c054baf 242String
cbfc4215
RC
243packagemeta::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. */
264void
265packagemeta::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 }
a828d772
RC
321 else if (desired == installed &&
322 (!installed ||
323 // neither bin nor source are being installed
324 (!(installed->binpicked || installed->srcpicked) &&
325 // bin or source are available
326 ((installed->bin.sites.number() || desired->bin.Cached()) ||
327 (installed->src.sites.number() || desired->src.Cached()))))
328 )
cbfc4215
RC
329 /* Install the default trust version - this is a 'reinstall' for installed
330 * packages */
331 {
332 desired = NULL;
333 /* No-op */
334 desired = default_version;
335 if (desired)
336 {
a828d772
RC
337 if (desired->bin.sites.number() || desired->bin.Cached())
338 desired->binpicked = 1;
339 else
340 desired->srcpicked = 1;
cbfc4215
RC
341 return;
342 }
343 }
344 /* are we currently on the radio button selection and installed */
345 if (desired == default_version && installed &&
346 (!desired || desired->binpicked)
347 && (desired &&
348 (desired->src.Cached () || desired->src.sites.number ())))
349 {
350 /* source only this file */
351 desired = installed;
352 desired->binpicked = 0;
353 desired->srcpicked = 1;
354 return;
355 }
356 /* are we currently on source only or on the radio button but not installed */
357 else if ((desired == installed && installed
358 && installed->srcpicked) || desired == default_version)
359 {
360 /* move onto the loop through versions */
361 desired = versions[1];
362 if (desired == default_version)
363 desired = versions.number () > 1 ? versions[2] : NULL;
364 if (desired)
365 {
366 desired->binpicked = 1;
367 desired->srcpicked = 0;
368 }
369 return;
370 }
371 else
372 {
373 /* preserve the src tick box */
374 int source = desired->srcpicked;
375 /* bump the version selected, skipping the radio button trust along the way */
376 size_t n;
7e8fc33c 377 for (n = 1; n <= versions.number () && desired != versions[n]; n++);
cbfc4215
RC
378 /* n points at pkg->desired */
379 n++;
380 if (n <= versions.number ())
381 {
382 if (default_version == versions[n])
383 n++;
384 if (n <= versions.number ())
385 {
386 desired = versions[n];
a828d772
RC
387 if (desired->src.sites.number() || desired->src.Cached())
388 desired->srcpicked = source;
389 else
390 desired->srcpicked = 0;
cbfc4215
RC
391 return;
392 }
393 }
394 /* went past the end - uninstall the package */
395 desired = NULL;
396 }
397}
97647369
RC
398
399int
400packagemeta::set_requirements (trusts deftrust = TRUST_CURR, size_t depth = 0)
401{
402 Dependency *dp;
403 packagemeta *required;
404 int changed = 0;
7e8fc33c 405 if (!desired || (desired != installed && !desired->binpicked))
97647369
RC
406 /* uninstall || source only */
407 return 0;
408
409 dp = desired->required;
410 packagedb db;
411 /* cheap test for too much recursion */
412 if (depth > 5)
413 return 0;
414 while (dp)
415 {
416 if ((required = db.packages.getbykey (dp->package)) == NULL)
7e8fc33c
RC
417 {
418 dp = dp->next;
419 changed++;
420 continue;
421 }
97647369 422 if (!required->desired)
7e8fc33c
RC
423 {
424 /* it's set to uninstall */
425 required->set_action (required->trustp (deftrust));
426 }
97647369 427 else if (required->desired != required->installed
7e8fc33c
RC
428 && !required->desired->binpicked)
429 {
430 /* it's set to change to a different version source only */
431 required->desired->binpicked = 1;
432 }
97647369
RC
433 /* does this requirement have requirements? */
434 changed += required->set_requirements (deftrust, depth + 1);
435 dp = dp->next;
436 }
437 return changed;
438}
7e8fc33c
RC
439
440
441// Set a particular type of action.
442void
443packagemeta::set_action (_actions action, packageversion * default_version)
444{
445 packagedb db;
446 if (action == Default_action)
447 {
448 // XXX fix the list use to allow const ref usage.
449 Category tempCategory("Misc");
450 if (installed
451 || Categories.getbykey (db.categories.registerbykey ("Base"))
452 || Categories.getbykey (tempCategory))
453 {
454 desired = default_version;
455 if (desired)
456 {
457 desired->binpicked = desired == installed ? 0 : 1;
458 desired->srcpicked = 0;
459 }
460 }
461 else
462 desired = 0;
463 return;
464 }
465 else if (action == Install_action)
466 {
467 desired = default_version;
468 if (desired)
469 {
470 if (desired != installed)
ceff7035
RC
471 if (desired->bin.sites.number())
472 {
473 desired->binpicked = 1;
474 desired->srcpicked = 0;
475 }
476 else
477 {
478 desired->binpicked = 0;
479 desired->srcpicked = 1;
480 }
7e8fc33c 481 else
ceff7035
RC
482 {
483 desired->binpicked = 0;
484 desired->srcpicked = 0;
485 }
7e8fc33c
RC
486 }
487 return;
488 }
489 else if (action == Reinstall_action)
490 {
491 desired = installed;
492 if (desired)
493 {
494 desired->binpicked = 1;
495 desired->srcpicked = 0;
496 }
497 }
498 else if (action == Uninstall_action)
499 {
500 desired = 0;
501 }
502}
This page took 0.080229 seconds and 5 git commands to generate.