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