1 ////////////////////////////////////////////////////////////////////////
2 // FILE: prtget.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 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #include <iostream>
17 #include <algorithm>
18 #include <set>
19 #include <iomanip>
20 #include <cstdio>
21 #include <cassert>
22 using namespace std;
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <dirent.h>
27 #include <unistd.h>
28
29 #include "prtget.h"
30 #include "repository.h"
31 #include "argparser.h"
32 #include "installtransaction.h"
33 #include "configuration.h"
34
35 #include "stringhelper.h"
36 #include "versioncomparator.h"
37 #include "file.h"
38 #include "process.h"
39 #include "datafileparser.h"
40 using namespace StringHelper;
41
42
43 using VersionComparator::COMP_RESULT;
44 using VersionComparator::GREATER;
45 using VersionComparator::LESS;
46 using VersionComparator::EQUAL;
47 using VersionComparator::UNDEFINED;
48
49 const string PrtGet::CONF_FILE = SYSCONFDIR"/prt-get.conf";
50 const string PrtGet::DEFAULT_CACHE_FILE = LOCALSTATEDIR"/lib/pkg/prt-get.cache";
51
52 /*!
53 Create a PrtGet object
54 \param parser the argument parser to be used
55 */
56 PrtGet::PrtGet( const ArgParser* parser )
57 : m_repo( 0 ),
58 m_config( 0 ),
59 m_parser( parser ),
60 m_cacheFile( DEFAULT_CACHE_FILE ),
61 m_returnValue( PG_OK ),
62 m_currentTransaction( 0 )
63 {
64 if ( m_parser->wasCalledAsPrtCached() ) {
65 m_appName = "prt-cache";
66 } else {
67 m_appName = "prt-get";
68 }
69
70
71 m_pkgDB = new PkgDB(m_parser->installRoot());
72 readConfig();
73
74 m_useRegex = m_config->useRegex() || m_parser->useRegex();
75 }
76
77 /*! destruct PrtGet object */
78 PrtGet::~PrtGet()
79 {
80 if ( m_config ) {
81 delete m_config;
82 }
83 if ( m_repo ) {
84 delete m_repo;
85 }
86
87 delete m_pkgDB;
88 }
89
90
91 /*! print version and exit */
92 void PrtGet::printVersion()
93 {
94 cout << m_appName << " " << VERSION
95 << " by Johannes Winkelmann, jw@tks6.net" << endl;
96 }
97
98 /*! print version, usage and exit */
99 void PrtGet::printUsage()
100 {
101 printVersion();
102 cout << "Usage: " << m_appName << " <command> [options]" << endl;
103
104 cout << "where commands are:" << endl;
105
106 cout << "\nINFORMATION" << endl;
107 cout << " help show this help" << endl;
108 cout << " version show the current version" << endl;
109 cout << " list [<filter>] show a list of available ports"
110 << endl;
111 cout << " printf <format> print formatted list of available"
112 << " ports"
113 << endl;
114 cout << " listinst [<filter>] show a list of installed ports"
115 << endl;
116 cout << " listorphans list of ports with no "
117 << "packages depending on them" << endl;
118 cout << " info <port> show info about a port" << endl;
119 cout << " path <port> show path of a port" << endl;
120 cout << " readme <port> show a port's readme file "
121 << "(if it exists)" << endl;
122 cout << " dup Find duplicate ports" << endl;
123 cout << " isinst <port1 port2...> print whether ports are installed"
124 << endl;
125 cout << " current <port> print installed version of port"
126 << endl;
127
128 cout << "\nDIFFERENCES / CHECK FOR UPDATES" << endl;
129 cout << " diff <port1 port2...> list outdated packages (or check "
130 << "args for change)" << endl;
131 cout << " quickdiff same as diff but simple format"
132 << endl;
133 cout << " where opt can be:" << endl;
134 cout << " --all display locked ports too"
135 << endl;
136 cout << " --prefer-higher prefer higher installed "
137 << "versions over lower ports"
138 << endl;
139 cout << " --strict-diff override prefer higher "
140 << "configuration setting"
141 << endl;
142
143 cout << "\nDEPENDENCIES" << endl;
144 cout << " depends <port1 port2...> show dependencies for these ports"
145 << endl;
146 cout << " quickdep <port1 port2...> same as 'depends' but simple format"
147 << endl;
148 cout << " deptree <port> show dependencies tree for <port>"
149 << endl;
150 cout << " dependent [opt] <port> show installed packages which "
151 << "depend on 'port'"
152 << endl;
153 cout << " where opt can be:" << endl;
154 cout << " --all list all dependent packages, not "
155 << "only installed" << endl;
156 cout << " --recursive print recursive listing" << endl;
157 cout << " --tree print recursive tree listing"
158 << endl;
159
160 cout << "\nSEARCHING" << endl;
161 cout << " search <expr> show port names containing 'expr'" << endl;
162 cout << " dsearch <expr> show ports containing 'expr' in the "
163 << "name or description" << endl;
164 cout << " fsearch <pattern> show file names in footprints matching "
165 << "'pattern'" << endl;
166
167 cout << "\nINSTALL, UPDATE and REMOVAL" << endl;
168 cout << " install [opt] <port1 port2...> install ports" << endl;
169 cout << " update [opt] <port1 port2...> update ports" << endl;
170 cout << " grpinst [opt] <port1 port2...> install ports, stop on error"
171 << endl;
172 cout << " depinst [opt] <port1 port2...> install ports and their dependencies"
173 << endl;
174 cout << " remove [opt] <port1 port2...> remove ports"
175 << endl;
176 cout << " where opt can be:" << endl;
177 cout << " -f, -fi force installation" << endl;
178 cout << " -fr force rebuild" << endl;
179 cout << " -uf update footprint" << endl;
180 cout << " -if ignore footprint" << endl;
181 cout << " -um update md5sum" << endl;
182 cout << " -im ignore md5sum" << endl;
183 cout << " --margs=<string> pass 'string' to pkgmk"
184 << endl;
185 cout << " --aargs=<string> pass 'string' to pkgadd"
186 << endl;
187 cout << " --rargs=<string> pass 'string' to pkgrm"
188 << endl;
189 cout << " --test test mode" << endl;
190 cout << " --log write log file"<< endl;
191 cout << " --ignore=<package1,package2,...>" << endl
192 << " Don't install/update those packages"<< endl;
193 cout << " --pre-install execute pre-install script"
194 << endl;
195 cout << " --post-install execute post-install script"
196 << endl;
197 cout << " --install-scripts execute "
198 << "pre-install and post-install script"
199 << endl;
200
201 cout << "\nSYSTEM UPDATE " << endl;
202 cout << " sysup [opt] update all outdated ports"
203 << endl;
204 cout << " where opt can be:" << endl;
205 cout << " --nodeps don't sort by dependencies"
206 << endl;
207 cout << " --test test mode" << endl;
208 cout << " --log write log file"<< endl;
209 cout << " --prefer-higher prefer higher installed "
210 << "versions over lower ones in ports tree"
211 << endl;
212 cout << " --strict-diff override prefer higher "
213 << "configuration setting"
214 << endl;
215
216 cout << " lock <port1 port2...> lock current version "
217 << "of packages"
218 << endl;
219 cout << " unlock <port1 port2...> unlock packages"
220 << endl;
221 cout << " listlocked list locked packages"
222 << endl;
223
224 cout << "\nFILE OPERATIONS " << endl;
225
226 cout << " ls <port> print a listing of the port's"
227 << " directory" << endl;
228 cout << " cat <port> <file> print out 'port/file'"
229 << endl;
230 cout << " edit <port> <file> edit 'port/file'" << endl;
231
232 cout << "\nGENERAL OPTIONS" << endl;
233 cout << " -v Show version in listing"
234 << endl;
235 cout << " -vv Show version and decription " << "in listing\n" << endl;
236 cout << " --path Print path to port if appropriate (search, list, depends)\n" << endl;
237 cout << " --cache Use a cache file" << endl;
238 cout << " --config=<file> Use alternative "
239 << "configuration file" << endl;
240 cout << " --install-root=.. Use alternative "
241 << "install root directory" << endl;
242
243
244
245
246 cout << " --no-std-config Don't parse "
247 << "default configuration file" << endl;
248 cout << " --config-prepend=.. Prepend '..' to"
249 << " configuration" << endl;
250 cout << " --config-append=.. Append '..' "
251 << "to configuration" << endl;
252 cout << " --config-set=.. Set configuration "
253 << "data '..',\n"
254 << " overriding config file"
255 << endl;
256
257 }
258
259
260 /*! print list of duplicate packages in the repository */
261 void PrtGet::listShadowed()
262 {
263 if ( m_parser->useCache() ) {
264 cout << m_appName << ": command 'dup' can't work on a cache" << endl;
265 m_returnValue = PG_GENERAL_ERROR;
266 return;
267 }
268
269 initRepo( true );
270
271 string format = "%p1 %v1 > %p2 %v2\n";
272 if (m_parser->otherArgs().size() > 0)
273 format = *(m_parser->otherArgs().begin());
274 else if (m_parser->verbose() > 0)
275 format = "* %n\n %p1 %v1 preceeds over \n %p2 %v2\n";
276
277 string output;
278 Package* p1;
279 Package* p2;
280 map<string, pair<Package*, Package*> >::const_iterator it =
281 m_repo->shadowedPackages().begin();
282 for ( ; it != m_repo->shadowedPackages().end(); ++it ) {
283 output = format;
284 p1 = it->second.second;
285 p2 = it->second.first;
286
287 StringHelper::replaceAll(output, "%n", p1->name());
288 StringHelper::replaceAll(output, "%p1", p1->path() + "/" + p1->name());
289 StringHelper::replaceAll(output, "%p2", p2->path() + "/" + p2->name());
290 StringHelper::replaceAll(output, "%v1", p1->versionReleaseString());
291 StringHelper::replaceAll(output, "%v2", p2->versionReleaseString());
292
293 StringHelper::replaceAll(output, "\\n", "\n");
294 cout << output;
295 }
296 }
297
298 /*!
299 find ports matching a pattern in repository
300
301 \sa Repository::getMatchingPackages()
302 */
303 void PrtGet::listPackages()
304 {
305 string arg = "*";
306 assertMaxArgCount(1);
307
308 if ( m_parser->otherArgs().size() == 1 ) {
309 arg = *(m_parser->otherArgs().begin());
310 }
311
312 initRepo();
313 list<Package*> packages;
314 m_repo->getMatchingPackages( arg, packages );
315 if ( packages.size() ) {
316 list<Package*>::iterator it = packages.begin();
317 for ( ; it != packages.end(); ++it ) {
318 if ( m_parser->printPath() ) {
319 cout << (*it)->path() << "/";
320 }
321 cout << (*it)->name();
322 if ( m_parser->verbose() > 0 ) {
323 cout << " " << (*it)->version() << "-" << (*it)->release();
324 }
325 if ( m_parser->verbose() > 1 && !(*it)->description().empty() ) {
326 cout << ": " << (*it)->description();
327 }
328
329 cout << endl;
330 }
331 } else {
332 cout << "No matching packages found" << endl;
333 }
334 }
335
336 /*!
337 search repository for a certain pattern (which is read by the argument
338 parser.
339
340 \sa Repository::searchMatchingPackages()
341 */
342 void PrtGet::searchPackages( bool searchDesc )
343 {
344 assertExactArgCount(1);
345
346 initRepo();
347 string arg = *(m_parser->otherArgs().begin());
348 list<Package*> packages;
349 m_repo->searchMatchingPackages( arg, packages, searchDesc );
350 if ( packages.size() ) {
351 list<Package*>::iterator it = packages.begin();
352 for ( ; it != packages.end(); ++it ) {
353 if ( m_parser->printPath()) {
354 cout << (*it)->path() << "/";
355 }
356 cout << (*it)->name();
357
358 if ( m_parser->verbose() > 0 ) {
359 cout << " " << (*it)->version() << "-" << (*it)->release();
360 }
361 if ( m_parser->verbose() > 1 && !(*it)->description().empty() ) {
362 cout << ": " << (*it)->description();
363 }
364
365
366 cout << endl;
367 }
368 } else {
369 m_returnValue = PG_GENERAL_ERROR;
370 cout << "No matching packages found" << endl;
371 }
372 }
373
374 /*! print info for a package */
375 void PrtGet::printInfo()
376 {
377 assertExactArgCount(1);
378
379 initRepo();
380 string arg = *(m_parser->otherArgs().begin());
381 const Package* p = m_repo->getPackage( arg );
382 if ( p ) {
383 cout << "Name: " << p->name() << "\n"
384 << "Path: " << p->path() << "\n"
385 << "Version: " << p->version() << "\n"
386 << "Release: " << p->release() << endl;
387
388 if ( !p->description().empty() ) {
389 cout << "Description: " << p->description() << endl;
390 }
391 if ( !p->url().empty() ) {
392 cout << "URL: " << p->url() << endl;
393 }
394 if ( !p->packager().empty() ) {
395 cout << "Packager: " << p->packager() << endl;
396 }
397 if ( !p->maintainer().empty() ) {
398 cout << "Maintainer: " << p->maintainer() << endl;
399 }
400
401 if ( !p->dependencies().empty() ) {
402 cout << "Dependencies: " << p->dependencies() << endl;
403 }
404
405 // TODO: don't hardcode file names
406 string filesString = "";
407 if ( p->hasReadme() ) {
408 filesString += "README ";
409 }
410 if ( p->hasPreInstall() ) {
411 filesString += "pre-install ";
412 }
413 if ( p->hasPostInstall() ) {
414 filesString += "post-install ";
415 }
416
417 if ( filesString.length() > 0 ) {
418 filesString = StringHelper::stripWhiteSpace( filesString );
419 StringHelper::replaceAll( filesString, " ", "," );
420 cout << "Files: " << filesString << endl;
421 }
422
423 if ( m_parser->verbose() > 0 && p->hasReadme()) {
424 cout << "\n-- README ------" << endl;
425 readme();
426 }
427
428 } else {
429 cerr << "Package '" << arg << "' not found" << endl;
430 m_returnValue = PG_GENERAL_ERROR;
431 return;
432 }
433 }
434
435
436 /*!
437 initialize repository
438 \sa Repository::initFromCache()
439 \sa Repository::initFromFS()
440 */
441 void PrtGet::initRepo( bool listDuplicate )
442 {
443 if ( !m_repo ) {
444 m_repo = new Repository(m_useRegex);
445
446 if ( m_parser->useCache() ) {
447 if (m_config->cacheFile() != "") {
448 m_cacheFile = m_config->cacheFile();
449 }
450
451 Repository::CacheReadResult result =
452 m_repo->initFromCache( m_cacheFile );
453 if ( result == Repository::ACCESS_ERR ) {
454 cerr << "Can't open cache file: " << m_cacheFile << endl;
455 m_returnValue = PG_GENERAL_ERROR;
456 return;
457 } else if ( result == Repository::FORMAT_ERR ) {
458 cerr << "warning: your cache file "
459 << m_cacheFile << " was made with an "
460 << "older version "
461 << "of prt-get."
462 << "\nPlease regenerate it using"
463 << "\n prt-get cache" << endl;
464 m_returnValue = PG_GENERAL_ERROR;
465 return;
466 }
467
468 struct stat cacheStat;
469 struct stat confStat;
470 stat( m_cacheFile.c_str(), &cacheStat );
471 stat( CONF_FILE.c_str(), &confStat );
472 if ( confStat.st_ctime > cacheStat.st_ctime ) {
473 cerr << "Error: "
474 << "Configuration changed after generating cache"
475 << endl;
476 cerr << "regenerate cache using 'prt-get cache'" << endl;
477 m_returnValue = PG_GENERAL_ERROR;
478 return;
479 }
480
481 if ( !m_parser->wasCalledAsPrtCached() ) {
482 cout << m_appName << ": using cache" << endl;
483 }
484
485 } else {
486 m_repo->initFromFS( m_config->rootList(), listDuplicate );
487 }
488 }
489 }
490
491 /*! print whether a package is installed or not */
492 void PrtGet::isInstalled()
493 {
494 assertMinArgCount(1);
495
496 const list<char*>& l = m_parser->otherArgs();
497 list<char*>::const_iterator it = l.begin();
498 for ( ; it != l.end(); ++it ) {
499 bool isAlias = false;
500 string aliasName;
501
502 if ( m_pkgDB->isInstalled( *it, true, &isAlias, &aliasName ) ) {
503 if (isAlias) {
504 cout << *it << " is provided by package "
505 << aliasName
506 << endl;
507 } else {
508 cout << "package " << *it << " is installed" << endl;
509 }
510 } else {
511 cout << "package " << *it << " is not installed" << endl;
512 m_returnValue = PG_GENERAL_ERROR;
513 }
514 }
515 }
516
517
518 /*! list installed packages */
519 void PrtGet::listInstalled()
520 {
521 assertMaxArgCount(1);
522
523 string arg = "*";
524 if ( m_parser->otherArgs().size() == 1 ) {
525 arg = *(m_parser->otherArgs().begin());
526 }
527
528 map<string, string> l;
529 m_pkgDB->getMatchingPackages( arg, l, m_useRegex );
530 map<string, string>::iterator it = l.begin();
531
532 if ( l.empty() && m_parser->otherArgs().size() > 0 ) {
533 cerr << m_appName << ": No matching packages found" << endl;
534 m_returnValue = PG_GENERAL_ERROR;
535 return;
536 }
537
538 if ( m_parser->verbose() > 1 ) {
539 // warning: will slow down the process...
540 initRepo();
541 }
542
543 for ( ; it != l.end(); ++it ) {
544 cout << it->first.c_str();
545 if ( m_parser->verbose() > 0 ) {
546 cout << " " << it->second.c_str();
547 }
548 if ( m_parser->verbose() > 1 ) {
549 const Package* p = m_repo->getPackage( it->first );
550 if ( p ) {
551 cout << " " << p->description();
552 }
553 }
554
555 cout << endl;
556 }
557 }
558
559 /*!
560 install package
561 \param update whether this is an update operation
562 \param group whether it's a group install (stop on error)
563
564 */
565 void PrtGet::install( bool update, bool group, bool dependencies )
566 {
567 assertMinArgCount(1);
568
569 // this can be done without initRepo()
570 const list<char*>& args = m_parser->otherArgs();
571 list<char*>::const_iterator it = args.begin();
572
573 if ( args.size() == 1 ) {
574 for ( ; it != args.end(); ++it ) {
575 string s = *it;
576 if ( !update && m_pkgDB->isInstalled( s ) ) {
577 cout << "package " << s << " is installed" << endl;
578 m_returnValue = PG_GENERAL_ERROR;
579 return;
580 } else if ( update && !m_pkgDB->isInstalled( s ) ) {
581 // can't upgrade
582 cout << "package " << s << " is not installed" << endl;
583 m_returnValue = PG_GENERAL_ERROR;
584 return;
585 }
586 }
587 }
588
589 initRepo();
590
591 if (dependencies) {
592 // calc dependencies
593 InstallTransaction depTransaction( m_parser->otherArgs(),
594 m_repo, m_pkgDB, m_config );
595 InstallTransaction::InstallResult result =
596 depTransaction.calcDependencies();
597
598 // TODO: code duplication with printDepends!
599 if ( result == InstallTransaction::CYCLIC_DEPEND ) {
600 cerr << "prt-get: cyclic dependencies found" << endl;
601 m_returnValue = PG_GENERAL_ERROR;
602 return;
603 } else if ( result == InstallTransaction::PACKAGE_NOT_FOUND ) {
604 warnPackageNotFound(depTransaction);
605 m_returnValue = PG_GENERAL_ERROR;
606 return;
607 }
608 const list<string>& depRef = depTransaction.dependencies();
609 list<string>::const_iterator it = depRef.begin();
610
611 list<string> deps;
612 for (; it != depRef.end(); ++it) {
613 if (!m_pkgDB->isInstalled(*it)) {
614 deps.push_back(*it);
615 }
616 }
617
618 InstallTransaction transaction( deps, m_repo, m_pkgDB, m_config );
619 executeTransaction( transaction, update, group );
620 } else {
621 InstallTransaction transaction( m_parser->otherArgs(),
622 m_repo, m_pkgDB, m_config );
623 executeTransaction( transaction, update, group );
624 }
625 }
626
627 void PrtGet::executeTransaction( InstallTransaction& transaction,
628 bool update, bool group )
629 {
630 m_currentTransaction = &transaction;
631
632 string command[] = { "install", "installed" };
633 if ( update ) {
634 command[0] = "update";
635 command[1] = "updated";
636 }
637
638 if ( m_parser->isTest() ) {
639 cout << "*** " << m_appName << ": test mode" << endl;
640 }
641
642 InstallTransaction::InstallResult result =
643 transaction.install( m_parser, update, group );
644 bool failed = false;
645 // TODO: use switch
646 if ( result == InstallTransaction::PACKAGE_NOT_FOUND ) {
647 cout << m_appName << ": package(s) not found" << endl;
648 } else if ( result == InstallTransaction::PKGMK_EXEC_ERROR ) {
649 cout << m_appName << " couldn't excecute pkgmk "
650 << "(or alternative command). "
651 << "Make sure it's installed properly" << endl;
652 } else if ( result == InstallTransaction::PKGMK_FAILURE ) {
653 cout << m_appName << ": error while " << command[0] << endl;
654 } else if ( result == InstallTransaction::NO_PACKAGE_GIVEN ) {
655 cout << m_appName << ": no package specified for "
656 << command[0] << endl;
657 } else if ( result == InstallTransaction::PKGADD_EXEC_ERROR ) {
658 cout << m_appName << " couldn't excecute pkgadd. "
659 << "Make sure it's installed properly" << endl;
660 } else if ( result == InstallTransaction::PKGDEST_ERROR ) {
661 cout << m_appName << ": error changing to directory PKGDEST " << endl;
662 failed = true;
663 } else if ( result == InstallTransaction::PKGADD_FAILURE ) {
664 cout << m_appName << ": error while pkgadding " << endl;
665 } else if ( result == InstallTransaction::LOG_DIR_FAILURE ) {
666 cout << m_appName << ": can't create log file directory " << endl;
667 } else if ( result == InstallTransaction::LOG_FILE_FAILURE ) {
668 cout << m_appName << ": can't create log file" << endl;
669 failed = true;
670 } else if ( result == InstallTransaction::NO_LOG_FILE ) {
671 cout << m_appName << ": no log file specified, but logging enabled"
672 << endl;
673 failed = true;
674 } else if ( result == InstallTransaction::CANT_LOCK_LOG_FILE ) {
675 cout << m_appName << ": can't create lock file for the log file. "
676 << "\nMaybe there's another instance of prt-get using the same "
677 << "file."
678 << "\nIf this is a stale not, please remove "
679 // TODO: file name of lock file
680 << endl;
681 failed = true;
682 } else if ( result != InstallTransaction::SUCCESS ) {
683 cout << m_appName << ": Unknown error " << result << endl;
684 failed = true;
685 }
686
687 if ( !failed ) {
688 evaluateResult( transaction, update );
689 if ( m_parser->isTest() ) {
690 cout << "\n*** " << m_appName << ": test mode end" << endl;
691 }
692 } else {
693 m_returnValue = PG_INSTALL_ERROR;
694 }
695
696 m_currentTransaction = 0;
697 }
698
699 /*!
700 print dependency listing
701 \param simpleListing Whether it should be in a simple format
702 */
703 void PrtGet::printDepends( bool simpleListing )
704 {
705 assertMinArgCount(1);
706
707 initRepo();
708
709 InstallTransaction transaction( m_parser->otherArgs(),
710 m_repo, m_pkgDB, m_config );
711 InstallTransaction::InstallResult result = transaction.calcDependencies();
712 if ( result == InstallTransaction::CYCLIC_DEPEND ) {
713 cerr << "prt-get: cyclic dependencies found" << endl;
714 m_returnValue = PG_GENERAL_ERROR;
715 return;
716 } else if ( result == InstallTransaction::PACKAGE_NOT_FOUND ) {
717 warnPackageNotFound(transaction);
718 m_returnValue = PG_GENERAL_ERROR;
719 return;
720 }
721
722 const list<string>& deps = transaction.dependencies();
723 if ( simpleListing ) {
724 if ( deps.size() > 0 ) {
725 list<string>::const_iterator it = deps.begin();
726 for ( ; it != deps.end(); ++it ) {
727 cout << *it << " ";
728 }
729 cout << endl;
730 }
731 } else {
732 if ( deps.size() > 0 ) {
733 cout << "-- dependencies ([i] = installed)" << endl;
734 list<string>::const_iterator it = deps.begin();
735
736 bool isAlias;
737 string provider;
738 for ( ; it != deps.end(); ++it ) {
739 isAlias = false;
740 if ( m_pkgDB->isInstalled( *it, true, &isAlias, &provider ) ) {
741 cout << "[i] ";
742 } else {
743 cout << "[ ] ";
744 }
745 if (m_parser->printPath() > 0) {
746 cout << m_repo->getPackage(*it)->path() << "/";
747 }
748 cout << *it;
749
750 if (isAlias) {
751 cout << " (provided by " << provider << ")";
752 }
753 cout << endl;
754 }
755 } else {
756 cout << "No dependencies found" << endl;
757 }
758
759 const list< pair<string, string> >& missing = transaction.missing();
760 if ( missing.size() ) {
761 list< pair<string, string> >::const_iterator mit = missing.begin();
762 cout << endl << "-- missing packages" << endl;
763 for ( ; mit != missing.end(); ++mit ) {
764 cout << mit->first;
765 if ( !mit->second.empty() ) {
766 cout << " from " << mit->second;
767 }
768 cout << endl;
769 }
770 }
771 }
772 }
773
774 /*! read the config file */
775 void PrtGet::readConfig()
776 {
777 string fName = CONF_FILE;
778 if ( m_parser->isAlternateConfigGiven() ) {
779 fName = m_parser->alternateConfigFile();
780 }
781
782 if ( m_config ) {
783 return; // don't initialize twice
784 }
785 m_config = new Configuration( fName, m_parser );
786
787 if (!m_parser->noStdConfig()) {
788 if ( !m_config->parse() ) {
789 cerr << "Can't read config file " << fName
790 << ". Exiting" << endl;
791 m_returnValue = PG_GENERAL_ERROR;
792 return;
793 }
794 }
795
796 const list< pair<char*, ArgParser::ConfigArgType> >& configData =
797 m_parser->configData();
798 list< pair<char*, ArgParser::ConfigArgType> >::const_iterator it =
799 configData.begin();
800 for (; it != configData.end(); ++it) {
801 m_config->addConfig(it->first,
802 it->second == ArgParser::CONFIG_SET,
803 it->second == ArgParser::CONFIG_PREPEND);
804 }
805 }
806
807 /*!
808 print a simple list of port which are installed in a different version
809 than they are in the repository
810 */
811 void PrtGet::printQuickDiff()
812 {
813 initRepo();
814
815 const map<string, string>& installed = m_pkgDB->installedPackages();
816 map<string, string>::const_iterator it = installed.begin();
817 const Package* p = 0;
818 COMP_RESULT result;
819 for ( ; it != installed.end(); ++it ) {
820 if ( !m_locker.isLocked( it->first ) ) {
821 p = m_repo->getPackage( it->first );
822 if ( p ) {
823 result = compareVersions(p->versionReleaseString(),
824 it->second);
825 if (result == GREATER) {
826 cout << it->first.c_str() << " ";
827 }
828 // we don't care about undefined diffs here
829 }
830 }
831 }
832 cout << endl;
833 }
834
835
836 void PrtGet::printFormattedDiffLine(const string& name,
837 const string& version1,
838 const string& version2,
839 bool isLocked)
840 {
841 cout.setf( ios::left, ios::adjustfield );
842 cout.width( 20 );
843 cout.fill( ' ' );
844 cout << name;
845
846 cout.width( 20 );
847 cout.fill( ' ' );
848 cout << version1;
849
850 string locked = "";
851 if ( isLocked ) {
852 locked = "locked";
853 }
854 cout.width( 20 );
855 cout.fill( ' ' );
856 cout << version2 << locked << endl;
857 }
858 /*!
859 print an overview of port which are installed in a different version
860 than they are in the repository
861 */
862 void PrtGet::printDiff()
863 {
864 initRepo();
865 map< string, string > l;
866 if ( m_parser->otherArgs().size() > 0 ) {
867 expandWildcardsPkgDB( m_parser->otherArgs(), l );
868 }
869 if ( l.size() < m_parser->otherArgs().size() ) {
870 cerr << "prt-get: no matching installed packages found" << endl;
871 m_returnValue = PG_GENERAL_ERROR;
872 return;
873 }
874
875 #if 0
876 // const list<char*>& l = m_parser->otherArgs();
877 // list<char*>::const_iterator checkIt = l.begin();
878
879 // check whether ports to be checked are installed
880 list< string >::iterator checkIt = l.begin();
881 for ( ; checkIt != l.end(); ++checkIt ) {
882 if ( ! m_pkgDB->isInstalled( *checkIt ) ) {
883 cerr << "Port not installed: " << *checkIt << endl;
884 m_returnValue = PG_GENERAL_ERROR;
885 return;
886 }
887 }
888 #endif
889
890 const map<string, string>& installed = m_pkgDB->installedPackages();
891 map<string, string>::const_iterator it = installed.begin();
892 const Package* p = 0;
893 int count = 0;
894 COMP_RESULT result;
895 for ( ; it != installed.end(); ++it ) {
896
897 p = m_repo->getPackage( it->first );
898 if ( p ) {
899 if ( l.size() && l.find( it->first ) == l.end() ) {
900 continue;
901 }
902
903 result = compareVersions( p->versionReleaseString(),
904 it->second );
905 if (result == GREATER ) {
906 if ( !m_locker.isLocked( it->first ) ||
907 m_parser->otherArgs().size() > 0 ||
908 m_parser->all() ) {
909
910
911 ++count;
912 if ( count == 1 ) {
913 cout << "Differences between installed packages "
914 << "and ports tree:\n" << endl;
915 printFormattedDiffLine("Port",
916 "Installed",
917 "Available in the ports tree",
918 false);
919 cout << endl;
920 }
921
922 printFormattedDiffLine(it->first,
923 it->second,
924 p->versionReleaseString(),
925 m_locker.isLocked( it->first ));
926 }
927 } else if (result == UNDEFINED) {
928 m_undefinedVersionComp.push_back(make_pair(p, it->second));
929 }
930 }
931 }
932
933 if (m_undefinedVersionComp.size()) {
934 cout << "\n\n" << "Undecidable version differences (use --strict-diff)"
935 << endl << endl;
936 printFormattedDiffLine("Port",
937 "Installed",
938 "Available in the ports tree",
939 false);
940 cout << endl;
941
942 list< pair< const Package*, string > >::iterator it =
943 m_undefinedVersionComp.begin();
944 const Package* p;
945 for (; it != m_undefinedVersionComp.end(); ++it) {
946 p = it->first;
947 printFormattedDiffLine(p->name(),
948 p->versionReleaseString(),
949 it->second,
950 false);
951 }
952 }
953
954
955 if ( count == 0 ) {
956 cout << "No differences found" << endl;
957 }
958 }
959
960 /*! print path to a port */
961 void PrtGet::printPath()
962 {
963 assertExactArgCount(1);
964
965 initRepo();
966 string arg = *(m_parser->otherArgs().begin());
967 const Package* p = m_repo->getPackage( arg );
968 if ( p ) {
969 cout << p->path() << "/" << p->name() << endl;
970 } else {
971 cerr << "Package '" << arg << "' not found" << endl;
972 m_returnValue = PG_GENERAL_ERROR;
973 return;
974 }
975 }
976
977
978 /*! helper method to print the result of an InstallTransaction */
979 void PrtGet::evaluateResult( InstallTransaction& transaction,
980 bool update,
981 bool interrupted )
982 {
983 int errors = 0;
984
985 // TODO: this is a duplicate, it's in install() as well
986 string command[] = { "install", "installed" };
987 if ( update ) {
988 command[0] = "update";
989 command[1] = "updated";
990 }
991
992 const list<string>& ignored = transaction.ignoredPackages();
993 if ( ignored.size() ) {
994 cout << endl << "-- Packages ignored" << endl;
995 list<string>::const_iterator iit = ignored.begin();
996
997 for ( ; iit != ignored.end(); ++iit ) {
998 cout << *iit << endl;
999 }
1000 }
1001
1002 const list< pair<string, string> >& missing = transaction.missing();
1003 if ( missing.size() ) {
1004 ++errors;
1005 cout << endl << "-- Packages not found" << endl;
1006 list< pair<string, string> >::const_iterator mit = missing.begin();
1007
1008 for ( ; mit != missing.end(); ++mit ) {
1009 cout << mit->first;
1010 if ( mit->second != "" ) {
1011 cout << " from " << mit->second;
1012 }
1013 cout << endl;
1014 }
1015 }
1016
1017 const list< pair<string, InstallTransaction::InstallInfo> >& error =
1018 transaction.installError();
1019 if ( error.size() ) {
1020 ++errors;
1021 cout << endl << "-- Packages where "
1022 << command[0] << " failed" << endl;
1023 list< pair<string, InstallTransaction::InstallInfo> >::const_iterator
1024 eit = error.begin();
1025
1026 for ( ; eit != error.end(); ++eit ) {
1027 cout << eit->first;
1028 reportPrePost(eit->second);
1029 cout << endl;
1030 }
1031 }
1032
1033 const list<string>& already = transaction.alreadyInstalledPackages();
1034 if ( already.size() ) {
1035 cout << endl << "-- Packages installed before this run (ignored)"
1036 << endl;
1037 list<string>::const_iterator ait = already.begin();
1038
1039 bool isAlias;
1040 string provider;
1041 for ( ; ait != already.end(); ++ait ) {
1042 isAlias = false;
1043 cout << *ait;
1044 m_pkgDB->isInstalled(*ait, true, &isAlias, &provider);
1045
1046 if (isAlias) {
1047 cout << " (provided by " << provider << ")";
1048 }
1049 cout << endl;
1050 }
1051 }
1052
1053
1054 const list< pair<string, InstallTransaction::InstallInfo> >& inst =
1055 transaction.installedPackages();
1056 if ( inst.size() ) {
1057 cout << endl << "-- Packages " << command[1] << endl;
1058 list< pair<string, InstallTransaction::InstallInfo> >::const_iterator
1059 iit = inst.begin();
1060
1061 bool atLeastOnePackageHasReadme = false;
1062
1063 for ( ; iit != inst.end(); ++iit ) {
1064 cout << iit->first;
1065 if ( iit->second.hasReadme ) {
1066 if ( m_config->readmeMode() ==
1067 Configuration::COMPACT_README ) {
1068 cout << " (README)";
1069 }
1070 atLeastOnePackageHasReadme = true;
1071 }
1072 reportPrePost(iit->second);
1073 cout << endl;
1074 }
1075
1076
1077 // readme's
1078 if ( atLeastOnePackageHasReadme ) {
1079 if ( m_config->readmeMode() == Configuration::VERBOSE_README ) {
1080 cout << endl << "-- " << command[1]
1081 << " packages with README files:" << endl;
1082 iit = inst.begin();
1083 for ( ; iit != inst.end(); ++iit ) {
1084 if ( iit->second.hasReadme ) {
1085 cout << iit->first;
1086 cout << endl;
1087 }
1088 }
1089 }
1090 }
1091 }
1092 if ( m_undefinedVersionComp.size() ) {
1093 cout << endl
1094 << "-- Packages with undecidable version "
1095 << "difference (use --strict-diff)"
1096 << endl;
1097 list< pair<const Package*, string> >::const_iterator uit =
1098 m_undefinedVersionComp.begin();
1099 const Package * p;
1100 for ( ; uit != m_undefinedVersionComp.end(); ++uit ) {
1101 p = uit->first;
1102 cout << p->name() << " ("
1103 << p->versionReleaseString()
1104 << " vs "
1105 << uit->second << ")" << endl;
1106 }
1107 }
1108
1109 cout << endl;
1110
1111 if ( errors == 0 && !interrupted ) {
1112 cout << "prt-get: " << command[1] << " successfully" << endl;
1113 } else {
1114 m_returnValue = PG_PARTIAL_INSTALL_ERROR;
1115 }
1116 }
1117
1118 void PrtGet::reportPrePost(const InstallTransaction::InstallInfo& info) {
1119 if (info.preState != InstallTransaction::NONEXISTENT) {
1120 string preString = "failed";
1121 if (info.preState == InstallTransaction::EXEC_SUCCESS) {
1122 preString = "ok";
1123 }
1124 cout << " [pre: " << preString << "]";
1125 }
1126 if ( info.postState != InstallTransaction::NONEXISTENT) {
1127 string postString = "failed";
1128 if (info.postState == InstallTransaction::EXEC_SUCCESS){
1129 postString = "ok";
1130 }
1131 cout << " [post: " << postString << "]";
1132 }
1133
1134 }
1135
1136 /*! create a cache */
1137 void PrtGet::createCache()
1138 {
1139 if ( m_parser->wasCalledAsPrtCached() ) {
1140 cerr << m_appName << ": Can't create cache from cache. "
1141 << "Use prt-get instead" << endl;
1142 m_returnValue = PG_GENERAL_ERROR;
1143 return;
1144 }
1145
1146 initRepo();
1147 if (m_config->cacheFile() != "") {
1148 m_cacheFile = m_config->cacheFile();
1149 }
1150
1151 Repository::WriteResult result = m_repo->writeCache( m_cacheFile );
1152 if ( result == Repository::DIR_ERR ) {
1153 cerr << "Can't create cache directory " << m_cacheFile << endl;
1154 m_returnValue = PG_GENERAL_ERROR;
1155 return;
1156 }
1157 if ( result == Repository::FILE_ERR ) {
1158 cerr << "Can't open cache file " << m_cacheFile << " for writing"
1159 << endl;
1160 m_returnValue = PG_GENERAL_ERROR;
1161 return;
1162 }
1163
1164 }
1165
1166 /*!
1167 \return true if v1 is greater than v2
1168 */
1169 COMP_RESULT PrtGet::compareVersions( const string& v1, const string& v2 )
1170 {
1171 if (v1 == v2) {
1172 return EQUAL;
1173 }
1174
1175
1176 if (m_parser->preferHigher() ||
1177 (m_config->preferHigher() && !m_parser->strictDiff())) {
1178
1179 COMP_RESULT result = VersionComparator::compareVersions(v1, v2);
1180 return result;
1181 }
1182
1183 if (v1 != v2)
1184 return GREATER;
1185 return LESS;
1186 }
1187
1188 int PrtGet::returnValue() const
1189 {
1190 return m_returnValue;
1191 }
1192
1193
1194 /*! print a list of packages available in the repository */
1195 void PrtGet::printf()
1196 {
1197 map<string, string> sortedOutput;
1198
1199 assertExactArgCount(1);
1200
1201 initRepo();
1202 string filter = "*";
1203 if ( m_parser->hasFilter() ) {
1204 filter = m_parser->filter();
1205 }
1206 list<Package*> packages;
1207 m_repo->getMatchingPackages( filter, packages );
1208 list<Package*>::const_iterator it = packages.begin();
1209
1210 const string formatString = *(m_parser->otherArgs().begin());
1211 string sortString =
1212 StringHelper::stripWhiteSpace( m_parser->sortArgs() );
1213 sortString += "%n"; // make it unique
1214
1215 for ( ; it != packages.end(); ++it ) {
1216 string output = formatString;
1217 string sortkey = sortString;
1218
1219 const Package* p = *it;
1220
1221 StringHelper::replaceAll( output, "%n", p->name() );
1222 StringHelper::replaceAll( output, "%u", p->url() );
1223 StringHelper::replaceAll( output, "%p", p->path() );
1224 StringHelper::replaceAll( output, "%v", p->version() );
1225 StringHelper::replaceAll( output, "%r", p->release() );
1226 StringHelper::replaceAll( output, "%d", p->description() );
1227 StringHelper::replaceAll( output, "%e", p->dependencies() );
1228 StringHelper::replaceAll( output, "%P", p->packager() );
1229 StringHelper::replaceAll( output, "%M", p->maintainer() );
1230
1231 StringHelper::replaceAll( output, "\\t", "\t" );
1232 StringHelper::replaceAll( output, "\\n", "\n" );
1233
1234 StringHelper::replaceAll( sortkey, "%n", p->name() );
1235 StringHelper::replaceAll( sortkey, "%u", p->url() );
1236 StringHelper::replaceAll( sortkey, "%p", p->path() );
1237 StringHelper::replaceAll( sortkey, "%v", p->version() );
1238 StringHelper::replaceAll( sortkey, "%r", p->release() );
1239 StringHelper::replaceAll( sortkey, "%d", p->description() );
1240 StringHelper::replaceAll( sortkey, "%e", p->dependencies() );
1241 StringHelper::replaceAll( sortkey, "%P", p->packager() );
1242 StringHelper::replaceAll( sortkey, "%M", p->maintainer() );
1243
1244 string isInst = "no";
1245 if ( m_pkgDB->isInstalled( p->name() ) ) {
1246 string ip = p->name() + "-" +
1247 m_pkgDB->getPackageVersion( p->name() );
1248 if ( ip == p->name() + "-" + p->versionReleaseString() ) {
1249 isInst = "yes";
1250 } else {
1251 isInst = "diff";
1252 }
1253 }
1254 StringHelper::replaceAll( output, "%i", isInst );
1255 StringHelper::replaceAll( sortkey, "%i", isInst );
1256
1257 string isLocked = m_locker.isLocked( p->name() ) ? "yes" : "no";
1258 StringHelper::replaceAll( output, "%l", isLocked );
1259 StringHelper::replaceAll( sortkey, "%l", isLocked );
1260
1261 string hasReadme = p->hasReadme() ? "yes" : "no";
1262 StringHelper::replaceAll( output, "%R", hasReadme );
1263 StringHelper::replaceAll( sortkey, "%R", hasReadme );
1264
1265 string hasPreInstall = p->hasPreInstall() ? "yes" : "no";
1266 StringHelper::replaceAll( output, "%E", hasPreInstall );
1267 StringHelper::replaceAll( sortkey, "%E", hasPreInstall );
1268
1269 string hasPostInstall = p->hasPostInstall() ? "yes" : "no";
1270 StringHelper::replaceAll( output, "%O", hasPostInstall );
1271 StringHelper::replaceAll( sortkey, "%O", hasPostInstall );
1272
1273 sortedOutput[sortkey] = output;
1274 }
1275
1276 map<string, string>::iterator sortIt = sortedOutput.begin();
1277 for ( ; sortIt != sortedOutput.end(); ++sortIt ) {
1278 if ( StringHelper::stripWhiteSpace(sortIt->second).length() > 0) {
1279 cout << sortIt->second;
1280 }
1281 }
1282 }
1283
1284 void PrtGet::readme()
1285 {
1286 assertExactArgCount(1);
1287
1288 initRepo();
1289 string arg = *(m_parser->otherArgs().begin());
1290 const Package* p = m_repo->getPackage( arg );
1291 if ( p ) {
1292 string file = p->path() + "/" + p->name() + "/README";
1293 printFile(file);
1294 } else {
1295 cerr << "Package '" << arg << "' not found" << endl;
1296 m_returnValue = PG_GENERAL_ERROR;
1297 return;
1298 }
1299 }
1300
1301 bool PrtGet::printFile(const string& file)
1302 {
1303 if (!File::fileExists(file)) {
1304 return false;
1305 }
1306
1307 char* pager = getenv("PAGER");
1308 if (pager) {
1309 Process proc(pager, file);
1310 proc.executeShell();
1311 } else {
1312 FILE* fp = fopen( file.c_str(), "r" );
1313 char buf[255];
1314 if ( fp ) {
1315 while ( fgets( buf, 255, fp ) ) {
1316 cout << buf;
1317 }
1318 fclose( fp );
1319 }
1320 }
1321
1322 return true;
1323 }
1324
1325 void PrtGet::printDependent()
1326 {
1327 assertExactArgCount(1);
1328
1329 initRepo();
1330 string arg = *(m_parser->otherArgs().begin());
1331
1332 if (m_parser->printTree()) {
1333 cout << arg << endl;
1334 printDependent(arg, 2);
1335 } else {
1336 printDependent(arg, 0);
1337 }
1338 }
1339
1340 void PrtGet::printDependent(const string& dep, int level)
1341 {
1342 map<string, Package*>::const_iterator it = m_repo->packages().begin();
1343 static map<string, bool> shownMap;
1344
1345 set<const Package*> dependent;
1346 for ( ; it != m_repo->packages().end(); ++it ) {
1347
1348 // TODO: is the following line needed?
1349 const Package* p = it->second;
1350 if ( p && p->dependencies().find( dep ) != string::npos ) {
1351 list<string> tokens;
1352 StringHelper::split( p->dependencies(), ',', tokens );
1353 list<string>::iterator it = find( tokens.begin(),
1354 tokens.end(),
1355 dep );
1356 if ( it != tokens.end() ) {
1357 dependent.insert( p );
1358 }
1359 }
1360 }
1361
1362 // - there are two modes, tree and non-tree recursive mode; in
1363 // tree mode, packages are shown multiple times, in non tree
1364 // recursive mode they're only printed the first time; this is not
1365 // necessarily optimal for rebuilding:
1366 //
1367 // a -> b -> d
1368 // \ ^
1369 // > c /
1370 //
1371 // trying to rebuild 'd' before 'c' might possibly fail
1372 string indent = "";
1373 if (m_parser->printTree()) {
1374 for (int i = 0; i < level; ++i) {
1375 indent += " ";
1376 }
1377 }
1378 set<const Package*>::iterator it2 = dependent.begin();
1379 for ( ; it2 != dependent.end(); ++it2 ) {
1380 const Package* p = *it2;
1381
1382 if (m_parser->recursive() && !m_parser->printTree()) {
1383 if (shownMap[p->name()]) {
1384 continue;
1385 }
1386 shownMap[p->name()] = true;
1387 }
1388
1389 if ( m_parser->all() || m_pkgDB->isInstalled( p->name() ) ) {
1390
1391 cout << indent << p->name();
1392 if ( m_parser->verbose() > 0 ) {
1393 cout << " " << p->versionReleaseString();
1394 }
1395 if ( m_parser->verbose() > 1 ) {
1396 cout << ": " << p->description();
1397 }
1398
1399 cout << endl;
1400
1401 if (m_parser->recursive()) {
1402 printDependent( p->name(), level+2 );
1403 }
1404 }
1405 }
1406 }
1407
1408 void PrtGet::listOrphans()
1409 {
1410 initRepo();
1411 map<string, string> installed = m_pkgDB->installedPackages();
1412 map<string, bool> required;
1413 map<string, string>::iterator it = installed.begin();
1414
1415 for (; it != installed.end(); ++it) {
1416 list<string> tokens;
1417 const Package* p = m_repo->getPackage(it->first);
1418 if (p) {
1419 StringHelper::split( p->dependencies(), ',', tokens );
1420 list<string>::iterator lit = tokens.begin();
1421 for (; lit != tokens.end(); ++lit) {
1422 required[*lit] = true;
1423 }
1424 }
1425 }
1426
1427 // - we could store the package pointer in another map to avoid
1428 // another getPackage lockup, but it seems better to optimized for
1429 // memory since it's only used when called with -vv
1430
1431 it = installed.begin();
1432 for (; it != installed.end(); ++it) {
1433 if (!required[it->first]) {
1434 cout << it->first;
1435 if ( m_parser->verbose() > 0 ) {
1436 cout << " " << it->second;
1437 }
1438 if ( m_parser->verbose() > 1 ) {
1439 const Package* p = m_repo->getPackage(it->first);
1440 if (p) {
1441 cout << ": " << p->description();
1442 }
1443 }
1444 cout << endl;
1445 }
1446 }
1447 }
1448
1449
1450 void PrtGet::warnPackageNotFound(InstallTransaction& transaction)
1451 {
1452 cerr << "The package '";
1453 cerr << transaction.missing().begin()->first;
1454 cerr << "' could not be found: " << endl;
1455 }
1456
1457 void PrtGet::sysup()
1458 {
1459 // TODO: refactor getDifferentPackages from diff/quickdiff
1460 initRepo();
1461
1462 list<string>* target;
1463 list<string> packagesToUpdate;
1464 list<string> sortedList;
1465
1466 const map<string, string>& installed = m_pkgDB->installedPackages();
1467 map<string, string>::const_iterator it = installed.begin();
1468 const Package* p = 0;
1469 COMP_RESULT result;
1470 for ( ; it != installed.end(); ++it ) {
1471 if ( !m_locker.isLocked( it->first ) ) {
1472 p = m_repo->getPackage( it->first );
1473 if ( p ) {
1474 result = compareVersions( p->versionReleaseString(),
1475 it->second );
1476 if (result == GREATER ) {
1477 packagesToUpdate.push_back( it->first );
1478 } else if (result == UNDEFINED ) {
1479 m_undefinedVersionComp.push_back(make_pair(p, it->second));
1480 }
1481 }
1482 }
1483 }
1484
1485 if ( packagesToUpdate.empty() ) {
1486 cout << "System is up to date" << endl;
1487 return;
1488 }
1489
1490 if ( m_parser->nodeps() ) {
1491 target = &packagesToUpdate;
1492 } else {
1493 // sort by dependency
1494
1495 // TODO: refactor code from printDepends
1496 InstallTransaction depTrans( packagesToUpdate,
1497 m_repo, m_pkgDB, m_config );
1498 InstallTransaction::InstallResult result = depTrans.calcDependencies();
1499 if ( result == InstallTransaction::CYCLIC_DEPEND ) {
1500 cerr << "cyclic dependencies" << endl;
1501 m_returnValue = PG_GENERAL_ERROR;
1502 return;
1503 } else if ( result == InstallTransaction::PACKAGE_NOT_FOUND ) {
1504 warnPackageNotFound(depTrans);
1505 m_returnValue = PG_GENERAL_ERROR;
1506 return;
1507 }
1508
1509 const list<string>& deps = depTrans.dependencies();
1510 if ( deps.size() > 0 ) {
1511 list<string>::const_iterator it = deps.begin();
1512 for ( ; it != deps.end(); ++it ) {
1513 if ( find( packagesToUpdate.begin(),
1514 packagesToUpdate.end(), *it ) !=
1515 packagesToUpdate.end() ) {;
1516 sortedList.push_back( *it );
1517 }
1518 }
1519 }
1520
1521 target = &sortedList;
1522 }
1523
1524 InstallTransaction transaction( *target,
1525 m_repo, m_pkgDB, m_config );
1526 executeTransaction( transaction, true, false );
1527 }
1528
1529
1530 void PrtGet::expandWildcardsPkgDB( const list<char*>& in,
1531 map<string, string>& target )
1532 {
1533 list<char*>::const_iterator it = in.begin();
1534 for ( ; it != in.end(); ++it ) {
1535 map<string, string> l;
1536 m_pkgDB->getMatchingPackages( *it, l, m_useRegex );
1537 map<string, string>::iterator iit = l.begin();
1538 for ( ; iit != l.end(); ++iit ) {
1539 target[iit->first] = iit->second;
1540 }
1541 }
1542 }
1543
1544 void PrtGet::expandWildcardsRepo( const list<char*>& in, list<string>& target )
1545 {
1546 list<char*>::const_iterator it = in.begin();
1547
1548 for ( ; it != in.end(); ++it ) {
1549 list<Package*> l;
1550 m_repo->getMatchingPackages( *it, l );
1551 list<Package*>::iterator iit = l.begin();
1552 for ( ; iit != l.end(); ++iit ) {
1553 target.push_back( (*iit)->name() );
1554 }
1555 }
1556 }
1557
1558
1559 void PrtGet::current()
1560 {
1561 assertExactArgCount(1);
1562
1563 const map<string, string>& installed = m_pkgDB->installedPackages();
1564 map<string, string>::const_iterator it = installed.begin();
1565 string search = *(m_parser->otherArgs().begin());
1566
1567 for ( ; it != installed.end(); ++it ) {
1568 if ( it->first == search ) {
1569 cout << it->second.c_str() << endl;
1570 return;
1571 }
1572 }
1573
1574 cout << "Package " << search << " not installed" << endl;
1575 m_returnValue = 1;
1576 }
1577
1578 SignalHandler::HandlerResult PrtGet::handleSignal( int signal )
1579 {
1580 // TODO: second argument could also be true:
1581 // TODO: kill installtransaction
1582
1583 cout << "prt-get: interrupted" << endl;
1584 if ( m_currentTransaction ) {
1585 evaluateResult( *m_currentTransaction, false, true );
1586 }
1587 }
1588
1589 /*!
1590 find files matching a pattern in repository
1591
1592 \sa Repository::getMatchingPackages()
1593 */
1594 void PrtGet::fsearch()
1595 {
1596 assertMinArgCount(1);
1597
1598 string arg = "*";
1599 if ( m_parser->otherArgs().size() == 1 ) {
1600 arg = *(m_parser->otherArgs().begin());
1601 }
1602
1603 initRepo();
1604 const map<string, Package*>& packages = m_repo->packages();
1605 map<string, Package*>::const_iterator it = packages.begin();
1606 bool first = true;
1607 for ( ; it != packages.end(); ++it ) {
1608 list<string> matches;
1609 string fp =
1610 it->second->path() + "/" +
1611 it->second->name() + "/" + ".footprint";
1612 if ( File::grep( fp, arg, matches,
1613 m_parser->fullPath(),
1614 m_useRegex)) {
1615 if ( matches.size() > 0 ) {
1616 if ( first ) {
1617 first = false;
1618 } else {
1619 cout << endl;
1620 }
1621 cout << "Found in "
1622 << it->second->path() << "/"
1623 << it->first << ":" << endl;
1624 list<string>::iterator it = matches.begin();
1625 for ( ; it != matches.end(); ++it ) {
1626 cout << " " << *it << endl;
1627 }
1628 }
1629 }
1630 }
1631
1632 if ( first ) {
1633 m_returnValue = PG_GENERAL_ERROR;
1634 }
1635 }
1636
1637 void PrtGet::setLock( bool lock )
1638 {
1639 assertMinArgCount(1);
1640
1641 if ( lock ) {
1642 initRepo();
1643 }
1644
1645 const list<char*>& args = m_parser->otherArgs();
1646 list<char*>::const_iterator it = args.begin();
1647 for ( ; it != args.end(); ++it ) {
1648 if ( lock ) {
1649 if (m_pkgDB->isInstalled( *it )) {
1650 if (!m_locker.lock( *it )) {
1651 cerr << "Already locked: " << *it << endl;
1652 m_returnValue = PG_GENERAL_ERROR;
1653 }
1654 } else {
1655 cerr << "Package '" << *it << "' not found" << endl;
1656 m_returnValue = PG_GENERAL_ERROR;
1657 return;
1658 }
1659
1660 } else {
1661 if ( !m_locker.unlock( *it ) ) {
1662 cerr << "Not locked previously: " << *it << endl;
1663 m_returnValue = PG_GENERAL_ERROR;
1664 return;
1665 }
1666 }
1667 }
1668
1669 if (!m_locker.store()) {
1670 cerr << "Failed to write lock data" << endl;
1671 m_returnValue = PG_GENERAL_ERROR;
1672 }
1673 }
1674
1675 void PrtGet::listLocked()
1676 {
1677 // shares some code with listInstalled
1678 if ( m_locker.openFailed() ) {
1679 cerr << "Failed to open lock data file" << endl;
1680 m_returnValue = PG_GENERAL_ERROR;
1681 }
1682
1683 const map<string, string>& l = m_pkgDB->installedPackages();
1684
1685 if ( l.empty() ) {
1686 return;
1687 }
1688
1689 if ( m_parser->verbose() > 1 ) {
1690 // warning: will slow down the process...
1691 initRepo();
1692 }
1693
1694
1695 const vector<string>& lockedPackages = m_locker.lockedPackages();
1696 vector<string>::const_iterator it = lockedPackages.begin();
1697 for ( ; it != lockedPackages.end(); ++it ) {
1698 cout << *it;
1699 if ( m_parser->verbose() > 0 ) {
1700 cout << " " << m_pkgDB->getPackageVersion(*it);
1701 }
1702 if ( m_parser->verbose() > 1 ) {
1703 const Package* p = m_repo->getPackage( *it );
1704 if ( p ) {
1705 cout << ": " << p->description();
1706 }
1707 }
1708
1709 cout << endl;
1710
1711 }
1712 }
1713
1714
1715 void PrtGet::edit()
1716 {
1717 assertMinArgCount(1);
1718 assertMaxArgCount(2);
1719
1720 char* editor = getenv("EDITOR");
1721 if (editor) {
1722 initRepo();
1723
1724 list<char*>::const_iterator it = m_parser->otherArgs().begin();
1725 string arg = *it;
1726 const Package* p = m_repo->getPackage( arg );
1727 if ( p ) {
1728 string fileName = "Pkgfile";
1729 if (++it != m_parser->otherArgs().end()) {
1730 fileName = *it;
1731 }
1732 string file = p->path() + "/" + p->name() + "/" + fileName;
1733 Process proc(editor, file);
1734 m_returnValue = proc.executeShell();
1735 if (m_returnValue) {
1736 cerr << "error while execution the editor" << endl;
1737 }
1738 } else {
1739 cerr << "Package '" << arg << "' not found" << endl;
1740 m_returnValue = PG_GENERAL_ERROR;
1741 return;
1742 }
1743
1744 } else {
1745 cerr << "Environment variable EDITOR not set" << endl;;
1746 m_returnValue = PG_GENERAL_ERROR;
1747 return;
1748 }
1749
1750 }
1751
1752 void PrtGet::ls()
1753 {
1754 assertExactArgCount(1);
1755
1756 initRepo();
1757
1758 list<char*>::const_iterator it = m_parser->otherArgs().begin();
1759 string arg = *it;
1760 const Package* p = m_repo->getPackage( arg );
1761 if ( p ) {
1762 string dirname = p->path() + "/" + p->name();
1763 DIR* dir = opendir(dirname.c_str());
1764 struct dirent* entry;
1765 vector<string> files;
1766 while (entry = readdir(dir)) {
1767 string dName = entry->d_name;
1768 if (dName != "." && dName != "..") {
1769 files.push_back(dName);
1770 }
1771 }
1772 closedir(dir);
1773
1774 sort(files.begin(), files.end());
1775 vector<string>::iterator fit = files.begin();
1776 for (; fit != files.end(); ++fit) {
1777 if (m_parser->printPath()) {
1778 cout << p->path() + "/" +p->name() + "/";
1779 }
1780 cout << *fit << endl;
1781 }
1782 } else {
1783 cerr << "Package '" << arg << "' not found" << endl;
1784 m_returnValue = PG_GENERAL_ERROR;
1785 return;
1786 }
1787 }
1788
1789 void PrtGet::cat()
1790 {
1791 assertMinArgCount(1);
1792 assertMaxArgCount(2);
1793
1794 initRepo();
1795
1796 list<char*>::const_iterator it = m_parser->otherArgs().begin();
1797 string arg = *it;
1798 const Package* p = m_repo->getPackage( arg );
1799 if ( p ) {
1800 string fileName = "Pkgfile";
1801 if (++it != m_parser->otherArgs().end()) {
1802 fileName = *it;
1803 }
1804 string file = p->path() + "/" + p->name() + "/" + fileName;
1805 if (!printFile(file)) {
1806 cerr << "File '" << *it << "' not found" << endl;
1807 m_returnValue = PG_GENERAL_ERROR;
1808 return;
1809 }
1810 } else {
1811 cerr << "Package '" << arg << "' not found" << endl;
1812 m_returnValue = PG_GENERAL_ERROR;
1813 return;
1814 }
1815 }
1816
1817 void PrtGet::remove()
1818 {
1819 assertMinArgCount(1);
1820
1821 list<string> removed;
1822 list<string> failed;
1823 list<string> notInstalled;
1824
1825 if ( m_parser->isTest() ) {
1826 cout << "*** " << m_appName << ": test mode" << endl;
1827 }
1828
1829 string command = InstallTransaction::PKGRM_DEFAULT_COMMAND;
1830 if (m_config->removeCommand() != "") {
1831 command = m_config->removeCommand();
1832 }
1833
1834 const list<char*>& args = m_parser->otherArgs();
1835 list<char*>::const_iterator it = args.begin();
1836 for ( ; it != args.end(); ++it ) {
1837 if (m_pkgDB->isInstalled(*it)) {
1838 // TODO: prettify
1839 string args = "";
1840 if (m_parser->installRoot() != "") {
1841 args = "-r " + m_parser->installRoot() + " ";
1842 }
1843 args += (m_parser->pkgrmArgs() + " " + *it);
1844
1845 Process proc(command, args);
1846 if (m_parser->isTest() || proc.executeShell() == 0) {
1847 removed.push_back(*it);
1848 if (m_locker.isLocked(*it)) {
1849 m_locker.unlock(*it);
1850 m_locker.store();
1851 }
1852 } else {
1853 failed.push_back(*it);
1854 }
1855 } else {
1856 notInstalled.push_back(*it);
1857 }
1858 }
1859
1860 if ( removed.size() ) {
1861 cout << endl << "-- Packages removed"
1862 << endl;
1863 list<string>::const_iterator it = removed.begin();
1864
1865 for ( ; it != removed.end(); ++it ) {
1866 cout << *it << endl;
1867 }
1868 }
1869
1870 if ( failed.size() ) {
1871 cout << endl << "-- Packages where removal failed"
1872 << endl;
1873 list<string>::const_iterator it = failed.begin();
1874
1875 for ( ; it != failed.end(); ++it ) {
1876 cout << *it << endl;
1877 }
1878 }
1879
1880 if ( notInstalled.size() ) {
1881 cout << endl << "-- Packages which were not installed"
1882 << endl;
1883 list<string>::const_iterator it = notInstalled.begin();
1884
1885 for ( ; it != notInstalled.end(); ++it ) {
1886 cout << *it << endl;
1887 }
1888 }
1889
1890 if ( m_parser->isTest() ) {
1891 cout << "*** " << m_appName << ": test mode end" << endl;
1892 }
1893
1894
1895
1896 }
1897
1898 void PrtGet::assertMaxArgCount(int count)
1899 {
1900 if ( m_parser->otherArgs().size() > count ) {
1901 argCountFailure(count, "at most");
1902 }
1903 }
1904
1905 void PrtGet::assertExactArgCount(int count)
1906 {
1907 if ( m_parser->otherArgs().size() != count ) {
1908 argCountFailure(count, "exactly");
1909 }
1910 }
1911
1912 void PrtGet::assertMinArgCount(int count)
1913 {
1914 if ( m_parser->otherArgs().size() < count ) {
1915 argCountFailure(count, "at least");
1916 }
1917 }
1918
1919 void PrtGet::argCountFailure(int count, const string& specifier)
1920 {
1921 cerr << m_appName << " "
1922 << m_parser->commandName() << " takes " << specifier << " "
1923 << count << (count > 1 ? " arguments" : " argument") << endl;
1924 exit(PG_ARG_ERROR);
1925 }
1926
1927
1928 void PrtGet::printDependTree()
1929 {
1930 assertExactArgCount(1);
1931
1932 initRepo();
1933
1934 list<char*>::const_iterator it = m_parser->otherArgs().begin();
1935 string arg = *it;
1936 const Package* p = m_repo->getPackage( arg );
1937 if (!p) {
1938 cerr << "Package '" << arg << "' not found" << endl;
1939 m_returnValue = PG_GENERAL_ERROR;
1940 return;
1941 }
1942
1943 if (p->dependencies().length() > 0) {
1944
1945 cout << "-- dependencies ([i] = installed";
1946 if (!m_parser->all()) {
1947 cout << ", '-->' = seen before";
1948 }
1949 cout << ")" << endl;
1950 if ( m_pkgDB->isInstalled( *it ) ) {
1951 cout << "[i] ";
1952 } else {
1953 cout << "[ ] ";
1954 }
1955 cout << p->name() << endl;
1956 printDepsLevel(2, p);
1957 }
1958
1959 }
1960
1961 void PrtGet::printDepsLevel(int indent, const Package* package)
1962 {
1963 static map<string, bool> shownMap;
1964
1965 list<string> deps;
1966 StringHelper::split(package->dependencies(), ',', deps);
1967 list<string>::iterator it = deps.begin();
1968 bool isAlias = false;
1969 string aliasName = "";
1970
1971 for (; it != deps.end(); ++it) {
1972 if ( m_pkgDB->isInstalled( *it, true, &isAlias, &aliasName ) ) {
1973 cout << "[i] ";
1974 } else {
1975 cout << "[ ] ";
1976 }
1977 for (int i = 0; i < indent; ++i) {
1978 cout << " ";
1979 }
1980 cout << *it;
1981 if (isAlias) {
1982 cout << " (provided by " << aliasName << ")";
1983 }
1984 const Package* p = m_repo->getPackage( *it );
1985 if (p) {
1986 if (p->dependencies().length() > 0) {
1987 map<string, bool>::iterator shownIt = shownMap.find(*it);
1988 if (shownIt != shownMap.end()) {
1989 cout << " -->" << endl;;
1990 } else {
1991 cout << endl;
1992 printDepsLevel(indent+2, p);
1993 if (!m_parser->all()) {
1994 shownMap[*it] = true;
1995 }
1996 }
1997 } else {
1998 cout << endl;
1999 }
2000 } else {
2001 cout << " (not found in ports tree)" << endl;
2002 }
2003 }
2004 }
2005
2006 void PrtGet::dumpConfig()
2007 {
2008
2009 cout.setf( ios::left, ios::adjustfield );
2010 cout.width( 20 );
2011 cout.fill( ' ' );
2012 cout << "Alias file: " << PkgDB::ALIAS_STORE << endl;
2013
2014 cout.setf( ios::left, ios::adjustfield );
2015 cout.width( 20 );
2016 cout.fill( ' ' );
2017 cout << "Ext. dep. file: "
2018 << Repository::EXTERNAL_DEPENDENCY_FILE << endl;
2019
2020
2021 if (!m_parser->noStdConfig()) {
2022 string fName = CONF_FILE;
2023 if ( m_parser->isAlternateConfigGiven() ) {
2024 fName = m_parser->alternateConfigFile();
2025 }
2026 cout.setf( ios::left, ios::adjustfield );
2027 cout.width( 20 );
2028 cout.fill( ' ' );
2029 cout << "Configuration file: " << fName << endl;
2030 }
2031
2032 if (m_config->cacheFile() != "") {
2033 cout.setf( ios::left, ios::adjustfield );
2034 cout.width( 20 );
2035 cout.fill( ' ' );
2036 cout << "Cache file: " << m_config->cacheFile() << endl;
2037 }
2038 if (m_config->makeCommand() != "") {
2039 cout.setf( ios::left, ios::adjustfield );
2040 cout.width( 20 );
2041 cout.fill( ' ' );
2042 cout << "Make command file: " << m_config->makeCommand() << endl;
2043 }
2044 if (m_config->addCommand() != "") {
2045 cout.setf( ios::left, ios::adjustfield );
2046 cout.width( 20 );
2047 cout.fill( ' ' );
2048 cout << "Add command: " << m_config->addCommand() << endl;
2049 }
2050 if (m_config->removeCommand() != "") {
2051 cout.setf( ios::left, ios::adjustfield );
2052 cout.width( 20 );
2053 cout.fill( ' ' );
2054 cout << "Remove command: " << m_config->removeCommand() << endl;
2055 }
2056 if (m_config->runscriptCommand() != "") {
2057 cout.setf( ios::left, ios::adjustfield );
2058 cout.width( 20 );
2059 cout.fill( ' ' );
2060 cout << "Runscript command: " << m_config->runscriptCommand() << endl;
2061 }
2062
2063 cout.setf( ios::left, ios::adjustfield );
2064 cout.width( 20 );
2065 cout.fill( ' ' );
2066 cout << "Run scripts: " <<(m_config->runScripts() ? "yes" : "no" )
2067 << endl;
2068
2069 cout.setf( ios::left, ios::adjustfield );
2070 cout.width( 20 );
2071 cout.fill( ' ' );
2072 cout << "Keep higher version:" <<(m_config->preferHigher() ? "yes" : "no" )
2073 << endl;
2074
2075 cout.setf( ios::left, ios::adjustfield );
2076 cout.width( 20 );
2077 cout.fill( ' ' );
2078 cout << "Readme mode: ";
2079 switch (m_config->readmeMode()) {
2080 case Configuration::VERBOSE_README:
2081 cout << "verbose";
2082 break;
2083 case Configuration::COMPACT_README:
2084 cout << "compact";
2085 break;
2086 case Configuration::NO_README:
2087 cout << "off";
2088 break;
2089 }
2090 cout << endl;
2091
2092 cout << endl;
2093
2094 if (m_config->logFilePattern() != "") {
2095 cout.setf( ios::left, ios::adjustfield );
2096 cout.width( 20 );
2097 cout.fill( ' ' );
2098 cout << "Log file: " << m_config->logFilePattern() << endl;
2099 }
2100 cout.setf( ios::left, ios::adjustfield );
2101 cout.width( 20 );
2102 cout.fill( ' ' );
2103 cout << " Write log: " << (m_config->writeLog() ? "yes" : "no" ) << endl;
2104 cout.setf( ios::left, ios::adjustfield );
2105 cout.width( 20 );
2106 cout.fill( ' ' );
2107 cout << " Append log: " <<(m_config->appendLog() ? "yes" : "no" ) << endl;
2108
2109
2110
2111 cout << endl;
2112 list< pair<string, string> >::const_iterator it =
2113 m_config->rootList().begin();
2114 cout << "Port "
2115 << (m_config->rootList().size() == 1 ? "directory" : "directories")
2116 << ": " << endl;
2117 for (; it != m_config->rootList().end(); ++it) {
2118 cout << " " << it->first;
2119 if (it->second != "") {
2120 cout << " (" << it->second << ")";
2121 }
2122 cout << endl;
2123 }
2124 }
|