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 = m_useRegex ? ".*" : "*";
528
529 if ( m_parser->otherArgs().size() == 1 ) {
530 arg = *(m_parser->otherArgs().begin());
531 }
532
533 map<string, string> l;
534 m_pkgDB->getMatchingPackages( arg, l, m_useRegex );
535 map<string, string>::iterator it = l.begin();
536
537 if ( l.empty() && m_parser->otherArgs().size() > 0 ) {
538 cerr << m_appName << ": No matching packages found" << endl;
539 m_returnValue = PG_GENERAL_ERROR;
540 return;
541 }
542
543 if (m_parser->depSort()) {
544 // sort by dependency, without injecting missing ones
545 // calcDependencies chokes on the full list, so go through the
546 // ports one by one
547
548 initRepo();
549 map<string, string>::iterator mit;
550 string name;
551 while (!l.empty()) {
552 mit = l.begin();
553 name = mit->first;
554 l.erase(mit);
555
556 InstallTransaction trans( name, m_repo, m_pkgDB, m_config );
557 InstallTransaction::InstallResult result __attribute__((unused)) = trans.calcDependencies();
558 const list<string>& depRef = trans.dependencies();
559 list<string>::const_iterator it = depRef.begin();
560
561
562 for (; it != depRef.end(); ++it) {
563 if (l.find(*it) != l.end()) {
564 cout << *it << endl;
565 l.erase(*it);
566 }
567 }
568 cout << name << endl;
569 }
570
571 } else {
572 for ( ; it != l.end(); ++it ) {
573 if ( m_parser->verbose() > 1 ) {
574 // warning: will slow down the process...
575 initRepo();
576 }
577 cout << it->first.c_str();
578 if ( m_parser->verbose() > 0 ) {
579 cout << " " << it->second.c_str();
580 }
581 if ( m_parser->verbose() > 1 ) {
582 const Package* p = m_repo->getPackage( it->first );
583 if ( p ) {
584 cout << " " << p->description();
585 }
586 }
587
588 cout << endl;
589 }
590 }
591 }
592
593 /*!
594 install package
595 \param update whether this is an update operation
596 \param group whether it's a group install (stop on error)
597
598 */
599 void PrtGet::install( bool update, bool group, bool dependencies )
600 {
601 assertMinArgCount(1);
602
603 // this can be done without initRepo()
604 const list<char*>& args = m_parser->otherArgs();
605 list<char*>::const_iterator it = args.begin();
606
607 if ( args.size() == 1 ) {
608 for ( ; it != args.end(); ++it ) {
609 string s = *it;
610 if ( !update && m_pkgDB->isInstalled( s ) ) {
611 cout << "package " << s << " is installed" << endl;
612 m_returnValue = PG_GENERAL_ERROR;
613 return;
614 } else if ( update && !m_pkgDB->isInstalled( s ) ) {
615 // can't upgrade
616 cout << "package " << s << " is not installed" << endl;
617 m_returnValue = PG_GENERAL_ERROR;
618 return;
619 }
620 }
621 }
622
623 initRepo();
624
625 if (dependencies) {
626 // calc dependencies
627 InstallTransaction depTransaction( m_parser->otherArgs(),
628 m_repo, m_pkgDB, m_config );
629 InstallTransaction::InstallResult result =
630 depTransaction.calcDependencies();
631
632 // TODO: code duplication with printDepends!
633 if ( result == InstallTransaction::CYCLIC_DEPEND ) {
634 cerr << "prt-get: cyclic dependencies found" << endl;
635 m_returnValue = PG_GENERAL_ERROR;
636 return;
637 } else if ( result == InstallTransaction::PACKAGE_NOT_FOUND ) {
638 warnPackageNotFound(depTransaction);
639 m_returnValue = PG_GENERAL_ERROR;
640 return;
641 }
642 const list<string>& depRef = depTransaction.dependencies();
643 list<string>::const_iterator it = depRef.begin();
644
645 list<string> deps;
646 for (; it != depRef.end(); ++it) {
647 if (!m_pkgDB->isInstalled(*it)) {
648 deps.push_back(*it);
649 }
650 }
651
652 InstallTransaction transaction( deps, m_repo, m_pkgDB, m_config );
653 executeTransaction( transaction, update, group );
654 } else {
655 InstallTransaction transaction( m_parser->otherArgs(),
656 m_repo, m_pkgDB, m_config );
657 executeTransaction( transaction, update, group );
658 }
659 }
660
661 void PrtGet::executeTransaction( InstallTransaction& transaction,
662 bool update, bool group )
663 {
664 m_currentTransaction = &transaction;
665
666 string command[] = { "install", "installed" };
667 if ( update ) {
668 command[0] = "update";
669 command[1] = "updated";
670 }
671
672 if ( m_parser->isTest() ) {
673 cout << "*** " << m_appName << ": test mode" << endl;
674 }
675
676 InstallTransaction::InstallResult result =
677 transaction.install( m_parser, update, group );
678 bool failed = false;
679 // TODO: use switch
680 if ( result == InstallTransaction::PACKAGE_NOT_FOUND ) {
681 cout << m_appName << ": package(s) not found" << endl;
682 } else if ( result == InstallTransaction::PKGMK_EXEC_ERROR ) {
683 cout << m_appName << " couldn't excecute pkgmk "
684 << "(or alternative command). "
685 << "Make sure it's installed properly" << endl;
686 } else if ( result == InstallTransaction::PKGMK_FAILURE ) {
687 cout << m_appName << ": error while " << command[0] << endl;
688 } else if ( result == InstallTransaction::NO_PACKAGE_GIVEN ) {
689 cout << m_appName << ": no package specified for "
690 << command[0] << endl;
691 } else if ( result == InstallTransaction::PKGADD_EXEC_ERROR ) {
692 cout << m_appName << " couldn't excecute pkgadd. "
693 << "Make sure it's installed properly" << endl;
694 } else if ( result == InstallTransaction::PKGDEST_ERROR ) {
695 cout << m_appName << ": error changing to PKGDEST directory "
696 << transaction.getPkgmkPackageDir() << endl;
697 failed = true;
698 } else if ( result == InstallTransaction::PKGADD_FAILURE ) {
699 cout << m_appName << ": error while pkgadding " << endl;
700 } else if ( result == InstallTransaction::LOG_DIR_FAILURE ) {
701 cout << m_appName << ": can't create log file directory " << endl;
702 } else if ( result == InstallTransaction::LOG_FILE_FAILURE ) {
703 cout << m_appName << ": can't create log file" << endl;
704 failed = true;
705 } else if ( result == InstallTransaction::NO_LOG_FILE ) {
706 cout << m_appName << ": no log file specified, but logging enabled"
707 << endl;
708 failed = true;
709 } else if ( result == InstallTransaction::CANT_LOCK_LOG_FILE ) {
710 cout << m_appName << ": can't create lock file for the log file. "
711 << "\nMaybe there's another instance of prt-get using the same "
712 << "file."
713 << "\nIf this is a stale not, please remove "
714 // TODO: file name of lock file
715 << endl;
716 failed = true;
717 } else if ( result != InstallTransaction::SUCCESS ) {
718 cout << m_appName << ": Unknown error " << result << endl;
719 failed = true;
720 }
721
722 if ( !failed ) {
723 evaluateResult( transaction, update );
724 if ( m_parser->isTest() ) {
725 cout << "\n*** " << m_appName << ": test mode end" << endl;
726 }
727 } else {
728 m_returnValue = PG_INSTALL_ERROR;
729 }
730
731 m_currentTransaction = 0;
732 }
733
734 /*!
735 print dependency listing
736 \param simpleListing Whether it should be in a simple format
737 */
738 void PrtGet::printDepends( bool simpleListing )
739 {
740 assertMinArgCount(1);
741
742 initRepo();
743
744 InstallTransaction transaction( m_parser->otherArgs(),
745 m_repo, m_pkgDB, m_config );
746 InstallTransaction::InstallResult result = transaction.calcDependencies();
747 if ( result == InstallTransaction::CYCLIC_DEPEND ) {
748 cerr << "prt-get: cyclic dependencies found" << endl;
749 m_returnValue = PG_GENERAL_ERROR;
750 return;
751 } else if ( result == InstallTransaction::PACKAGE_NOT_FOUND ) {
752 warnPackageNotFound(transaction);
753 m_returnValue = PG_GENERAL_ERROR;
754 return;
755 }
756
757 const list<string>& deps = transaction.dependencies();
758 if ( simpleListing ) {
759 if ( deps.size() > 0 ) {
760 list<string>::const_iterator it = deps.begin();
761 for ( ; it != deps.end(); ++it ) {
762 cout << *it << " ";
763 }
764 cout << endl;
765 }
766 } else {
767 if ( deps.size() > 0 ) {
768 cout << "-- dependencies ([i] = installed)" << endl;
769 list<string>::const_iterator it = deps.begin();
770
771 bool isAlias;
772 string provider;
773 for ( ; it != deps.end(); ++it ) {
774 isAlias = false;
775 if ( m_pkgDB->isInstalled( *it, true, &isAlias, &provider ) ) {
776 cout << "[i] ";
777 } else {
778 cout << "[ ] ";
779 }
780 if (m_parser->printPath() > 0) {
781 cout << m_repo->getPackage(*it)->path() << "/";
782 }
783 cout << *it;
784
785 if (isAlias) {
786 cout << " (provided by " << provider << ")";
787 }
788 cout << endl;
789 }
790 } else {
791 cout << "No dependencies found" << endl;
792 }
793
794 const list< pair<string, string> >& missing = transaction.missing();
795 if ( missing.size() ) {
796 list< pair<string, string> >::const_iterator mit = missing.begin();
797 cout << endl << "-- missing packages" << endl;
798 for ( ; mit != missing.end(); ++mit ) {
799 cout << mit->first;
800 if ( !mit->second.empty() ) {
801 cout << " from " << mit->second;
802 }
803 cout << endl;
804 }
805 }
806 }
807 }
808
809 /*! read the config file */
810 void PrtGet::readConfig()
811 {
812 string fName = CONF_FILE;
813 if ( m_parser->isAlternateConfigGiven() ) {
814 fName = m_parser->alternateConfigFile();
815 }
816
817 if ( m_config ) {
818 return; // don't initialize twice
819 }
820 m_config = new Configuration( fName, m_parser );
821
822 if (!m_parser->noStdConfig()) {
823 if ( !m_config->parse() ) {
824 cerr << "Can't read config file " << fName
825 << ". Exiting" << endl;
826 m_returnValue = PG_GENERAL_ERROR;
827 return;
828 }
829 }
830
831 const list< pair<char*, ArgParser::ConfigArgType> >& configData =
832 m_parser->configData();
833 list< pair<char*, ArgParser::ConfigArgType> >::const_iterator it =
834 configData.begin();
835 for (; it != configData.end(); ++it) {
836 m_config->addConfig(it->first,
837 it->second == ArgParser::CONFIG_SET,
838 it->second == ArgParser::CONFIG_PREPEND);
839 }
840 }
841
842 /*!
843 print a simple list of port which are installed in a different version
844 than they are in the repository
845 */
846 void PrtGet::printQuickDiff()
847 {
848 initRepo();
849
850 const map<string, string>& installed = m_pkgDB->installedPackages();
851 map<string, string>::const_iterator it = installed.begin();
852 const Package* p = 0;
853 COMP_RESULT result;
854 for ( ; it != installed.end(); ++it ) {
855 if ( !m_locker.isLocked( it->first ) ) {
856 p = m_repo->getPackage( it->first );
857 if ( p ) {
858 result = compareVersions(p->versionReleaseString(),
859 it->second);
860 if (result == GREATER) {
861 cout << it->first.c_str() << " ";
862 }
863 // we don't care about undefined diffs here
864 }
865 }
866 }
867 cout << endl;
868 }
869
870
871 void PrtGet::printFormattedDiffLine(const string& name,
872 const string& versionInstalled,
873 const string& versionPortsTree,
874 bool isLocked)
875 {
876 cout.setf( ios::left, ios::adjustfield );
877 cout.width( 20 );
878 cout.fill( ' ' );
879 cout << name;
880
881 cout.width( 20 );
882 cout.fill( ' ' );
883 cout << versionInstalled;
884
885 string locked = "";
886 if ( isLocked ) {
887 locked = "locked";
888 }
889 cout.width( 20 );
890 cout.fill( ' ' );
891 cout << versionPortsTree << locked << endl;
892 }
893 /*!
894 print an overview of port which are installed in a different version
895 than they are in the repository
896 */
897 void PrtGet::printDiff()
898 {
899 initRepo();
900 map< string, string > l;
901 if ( m_parser->otherArgs().size() > 0 ) {
902 expandWildcardsPkgDB( m_parser->otherArgs(), l );
903 }
904 if ( l.size() < m_parser->otherArgs().size() ) {
905 cerr << "prt-get: no matching installed packages found" << endl;
906 m_returnValue = PG_GENERAL_ERROR;
907 return;
908 }
909
910 #if 0
911 // const list<char*>& l = m_parser->otherArgs();
912 // list<char*>::const_iterator checkIt = l.begin();
913
914 // check whether ports to be checked are installed
915 list< string >::iterator checkIt = l.begin();
916 for ( ; checkIt != l.end(); ++checkIt ) {
917 if ( ! m_pkgDB->isInstalled( *checkIt ) ) {
918 cerr << "Port not installed: " << *checkIt << endl;
919 m_returnValue = PG_GENERAL_ERROR;
920 return;
921 }
922 }
923 #endif
924
925 const map<string, string>& installed = m_pkgDB->installedPackages();
926 map<string, string>::const_iterator it = installed.begin();
927 const Package* p = 0;
928 size_t count = 0;
929 COMP_RESULT result;
930 for ( ; it != installed.end(); ++it ) {
931
932 p = m_repo->getPackage( it->first );
933 if ( p ) {
934 if ( l.size() && l.find( it->first ) == l.end() ) {
935 continue;
936 }
937
938 result = compareVersions( p->versionReleaseString(),
939 it->second );
940 if (result == GREATER ) {
941 if ( !m_locker.isLocked( it->first ) ||
942 m_parser->otherArgs().size() > 0 ||
943 m_parser->all() ) {
944
945
946 ++count;
947 if ( count == 1 ) {
948 cout << "Differences between installed packages "
949 << "and ports tree:\n" << endl;
950 printFormattedDiffLine("Port",
951 "Installed",
952 "Available in the ports tree",
953 false);
954 cout << endl;
955 }
956
957 printFormattedDiffLine(it->first,
958 it->second,
959 p->versionReleaseString(),
960 m_locker.isLocked( it->first ));
961 }
962 } else if (result == UNDEFINED) {
963 m_undefinedVersionComp.push_back(make_pair(p, it->second));
964 }
965 }
966 }
967
968 if (m_undefinedVersionComp.size()) {
969 cout << "\n\n" << "Undecidable version differences (use --strict-diff)"
970 << endl << endl;
971 printFormattedDiffLine("Port",
972 "Installed",
973 "Available in the ports tree",
974 false);
975 cout << endl;
976
977 list< pair< const Package*, string > >::iterator it =
978 m_undefinedVersionComp.begin();
979 const Package* p;
980 for (; it != m_undefinedVersionComp.end(); ++it) {
981 p = it->first;
982 printFormattedDiffLine(p->name(),
983 it->second,
984 p->versionReleaseString(),
985 false);
986 }
987 }
988
989
990 if ( count == 0 ) {
991 cout << "No differences found" << endl;
992 }
993 }
994
995 /*! print path to a port */
996 void PrtGet::printPath()
997 {
998 assertExactArgCount(1);
999
1000 initRepo();
1001 string arg = *(m_parser->otherArgs().begin());
1002 const Package* p = m_repo->getPackage( arg );
1003 if ( p ) {
1004 cout << p->path() << "/" << p->name() << endl;
1005 } else {
1006 cerr << "Package '" << arg << "' not found" << endl;
1007 m_returnValue = PG_GENERAL_ERROR;
1008 return;
1009 }
1010 }
1011
1012
1013 /*! helper method to print the result of an InstallTransaction */
1014 void PrtGet::evaluateResult( InstallTransaction& transaction,
1015 bool update,
1016 bool interrupted )
1017 {
1018 int errors = 0;
1019
1020 // TODO: this is a duplicate, it's in install() as well
1021 string command[] = { "install", "installed" };
1022 if ( update ) {
1023 command[0] = "update";
1024 command[1] = "updated";
1025 }
1026
1027 const list<string>& ignored = transaction.ignoredPackages();
1028 if ( ignored.size() ) {
1029 cout << endl << "-- Packages ignored" << endl;
1030 list<string>::const_iterator iit = ignored.begin();
1031
1032 for ( ; iit != ignored.end(); ++iit ) {
1033 cout << *iit << endl;
1034 }
1035 }
1036
1037 const list< pair<string, string> >& missing = transaction.missing();
1038 if ( missing.size() ) {
1039 ++errors;
1040 cout << endl << "-- Packages not found" << endl;
1041 list< pair<string, string> >::const_iterator mit = missing.begin();
1042
1043 for ( ; mit != missing.end(); ++mit ) {
1044 cout << mit->first;
1045 if ( mit->second != "" ) {
1046 cout << " from " << mit->second;
1047 }
1048 cout << endl;
1049 }
1050 }
1051
1052 const list< pair<string, InstallTransaction::InstallInfo> >& error =
1053 transaction.installError();
1054 if ( error.size() ) {
1055 ++errors;
1056 cout << endl << "-- Packages where "
1057 << command[0] << " failed" << endl;
1058 list< pair<string, InstallTransaction::InstallInfo> >::const_iterator
1059 eit = error.begin();
1060
1061 for ( ; eit != error.end(); ++eit ) {
1062 cout << eit->first;
1063 reportPrePost(eit->second);
1064 cout << endl;
1065 }
1066 }
1067
1068 const list<string>& already = transaction.alreadyInstalledPackages();
1069 if ( already.size() ) {
1070 cout << endl << "-- Packages installed before this run (ignored)"
1071 << endl;
1072 list<string>::const_iterator ait = already.begin();
1073
1074 bool isAlias;
1075 string provider;
1076 for ( ; ait != already.end(); ++ait ) {
1077 isAlias = false;
1078 cout << *ait;
1079 m_pkgDB->isInstalled(*ait, true, &isAlias, &provider);
1080
1081 if (isAlias) {
1082 cout << " (provided by " << provider << ")";
1083 }
1084 cout << endl;
1085 }
1086 }
1087
1088
1089 const list< pair<string, InstallTransaction::InstallInfo> >& inst =
1090 transaction.installedPackages();
1091 if ( inst.size() ) {
1092 cout << endl << "-- Packages " << command[1] << endl;
1093 list< pair<string, InstallTransaction::InstallInfo> >::const_iterator
1094 iit = inst.begin();
1095
1096 bool atLeastOnePackageHasReadme = false;
1097
1098 for ( ; iit != inst.end(); ++iit ) {
1099 if (m_parser->printPath()) {
1100 // TODO: avoid lookup by tuning
1101 // InstallTransaction::installedPackages()
1102 const Package* p = m_repo->getPackage(iit->first);
1103 if (p) {
1104 cout << p->path() << "/";
1105 }
1106 }
1107 cout << iit->first;
1108 if ( iit->second.hasReadme ) {
1109 if ( m_config->readmeMode() ==
1110 Configuration::COMPACT_README ) {
1111 cout << " (README)";
1112 }
1113 atLeastOnePackageHasReadme = true;
1114 }
1115 reportPrePost(iit->second);
1116 cout << endl;
1117 }
1118
1119
1120 // readme's
1121 if ( atLeastOnePackageHasReadme ) {
1122 if ( m_config->readmeMode() == Configuration::VERBOSE_README ) {
1123 cout << endl << "-- " << command[1]
1124 << " packages with README files:" << endl;
1125 iit = inst.begin();
1126 for ( ; iit != inst.end(); ++iit ) {
1127 if ( iit->second.hasReadme ) {
1128 cout << iit->first;
1129 cout << endl;
1130 }
1131 }
1132 }
1133 }
1134 }
1135 if ( m_undefinedVersionComp.size() ) {
1136 cout << endl
1137 << "-- Packages with undecidable version "
1138 << "difference (use --strict-diff)"
1139 << endl;
1140 list< pair<const Package*, string> >::const_iterator uit =
1141 m_undefinedVersionComp.begin();
1142 const Package * p;
1143 for ( ; uit != m_undefinedVersionComp.end(); ++uit ) {
1144 p = uit->first;
1145 cout << p->name() << " ("
1146 << uit->second
1147 << " vs "
1148 << p->versionReleaseString() << ")" << endl;
1149 }
1150 }
1151
1152 cout << endl;
1153
1154 if ( errors == 0 && !interrupted ) {
1155 cout << "prt-get: " << command[1] << " successfully" << endl;
1156 } else {
1157 m_returnValue = PG_PARTIAL_INSTALL_ERROR;
1158 }
1159 }
1160
1161 void PrtGet::reportPrePost(const InstallTransaction::InstallInfo& info) {
1162 if (info.preState != InstallTransaction::NONEXISTENT) {
1163 string preString = "failed";
1164 if (info.preState == InstallTransaction::EXEC_SUCCESS) {
1165 preString = "ok";
1166 }
1167 cout << " [pre: " << preString << "]";
1168 }
1169 if ( info.postState != InstallTransaction::NONEXISTENT) {
1170 string postString = "failed";
1171 if (info.postState == InstallTransaction::EXEC_SUCCESS){
1172 postString = "ok";
1173 }
1174 cout << " [post: " << postString << "]";
1175 }
1176
1177 }
1178
1179 /*! create a cache */
1180 void PrtGet::createCache()
1181 {
1182 if ( m_parser->wasCalledAsPrtCached() ) {
1183 cerr << m_appName << ": Can't create cache from cache. "
1184 << "Use prt-get instead" << endl;
1185 m_returnValue = PG_GENERAL_ERROR;
1186 return;
1187 }
1188
1189 initRepo();
1190 if (m_config->cacheFile() != "") {
1191 m_cacheFile = m_config->cacheFile();
1192 }
1193
1194 Repository::WriteResult result = m_repo->writeCache( m_cacheFile );
1195 if ( result == Repository::DIR_ERR ) {
1196 cerr << "Can't create cache directory " << m_cacheFile << endl;
1197 m_returnValue = PG_GENERAL_ERROR;
1198 return;
1199 }
1200 if ( result == Repository::FILE_ERR ) {
1201 cerr << "Can't open cache file " << m_cacheFile << " for writing"
1202 << endl;
1203 m_returnValue = PG_GENERAL_ERROR;
1204 return;
1205 }
1206
1207 }
1208
1209 /*!
1210 \return true if v1 is greater than v2
1211 */
1212 COMP_RESULT PrtGet::compareVersions( const string& v1, const string& v2 )
1213 {
1214 if (v1 == v2) {
1215 return EQUAL;
1216 }
1217
1218
1219 if (m_parser->preferHigher() ||
1220 (m_config->preferHigher() && !m_parser->strictDiff())) {
1221
1222 COMP_RESULT result = VersionComparator::compareVersions(v1, v2);
1223 return result;
1224 }
1225
1226 if (v1 != v2)
1227 return GREATER;
1228 return LESS;
1229 }
1230
1231 int PrtGet::returnValue() const
1232 {
1233 return m_returnValue;
1234 }
1235
1236
1237 /*! print a list of packages available in the repository */
1238 void PrtGet::printf()
1239 {
1240 map<string, string> sortedOutput;
1241
1242 assertExactArgCount(1);
1243
1244 initRepo();
1245 string filter = m_parser->useRegex() ? "." : "*";
1246 if ( m_parser->hasFilter() ) {
1247 filter = m_parser->filter();
1248 }
1249 list<Package*> packages;
1250 m_repo->getMatchingPackages( filter, packages );
1251 list<Package*>::const_iterator it = packages.begin();
1252
1253 const string formatString = *(m_parser->otherArgs().begin());
1254 string sortString =
1255 StringHelper::stripWhiteSpace( m_parser->sortArgs() );
1256 sortString += "%n"; // make it unique
1257
1258 for ( ; it != packages.end(); ++it ) {
1259 string output = formatString;
1260 string sortkey = sortString;
1261
1262 const Package* p = *it;
1263
1264 StringHelper::replaceAll( output, "%n", p->name() );
1265 StringHelper::replaceAll( output, "%u", p->url() );
1266 StringHelper::replaceAll( output, "%p", p->path() );
1267 StringHelper::replaceAll( output, "%v", p->version() );
1268 StringHelper::replaceAll( output, "%r", p->release() );
1269 StringHelper::replaceAll( output, "%d", p->description() );
1270 StringHelper::replaceAll( output, "%e", p->dependencies() );
1271 StringHelper::replaceAll( output, "%P", p->packager() );
1272 StringHelper::replaceAll( output, "%M", p->maintainer() );
1273
1274 StringHelper::replaceAll( output, "\\t", "\t" );
1275 StringHelper::replaceAll( output, "\\n", "\n" );
1276
1277 StringHelper::replaceAll( sortkey, "%n", p->name() );
1278 StringHelper::replaceAll( sortkey, "%u", p->url() );
1279 StringHelper::replaceAll( sortkey, "%p", p->path() );
1280 StringHelper::replaceAll( sortkey, "%v", p->version() );
1281 StringHelper::replaceAll( sortkey, "%r", p->release() );
1282 StringHelper::replaceAll( sortkey, "%d", p->description() );
1283 StringHelper::replaceAll( sortkey, "%e", p->dependencies() );
1284 StringHelper::replaceAll( sortkey, "%P", p->packager() );
1285 StringHelper::replaceAll( sortkey, "%M", p->maintainer() );
1286
1287 string isInst = "no";
1288 if ( m_pkgDB->isInstalled( p->name() ) ) {
1289 string ip = p->name() + "-" +
1290 m_pkgDB->getPackageVersion( p->name() );
1291 if ( ip == p->name() + "-" + p->versionReleaseString() ) {
1292 isInst = "yes";
1293 } else {
1294 isInst = "diff";
1295 }
1296 }
1297 StringHelper::replaceAll( output, "%i", isInst );
1298 StringHelper::replaceAll( sortkey, "%i", isInst );
1299
1300 string isLocked = m_locker.isLocked( p->name() ) ? "yes" : "no";
1301 StringHelper::replaceAll( output, "%l", isLocked );
1302 StringHelper::replaceAll( sortkey, "%l", isLocked );
1303
1304 string hasReadme = p->hasReadme() ? "yes" : "no";
1305 StringHelper::replaceAll( output, "%R", hasReadme );
1306 StringHelper::replaceAll( sortkey, "%R", hasReadme );
1307
1308 string hasPreInstall = p->hasPreInstall() ? "yes" : "no";
1309 StringHelper::replaceAll( output, "%E", hasPreInstall );
1310 StringHelper::replaceAll( sortkey, "%E", hasPreInstall );
1311
1312 string hasPostInstall = p->hasPostInstall() ? "yes" : "no";
1313 StringHelper::replaceAll( output, "%O", hasPostInstall );
1314 StringHelper::replaceAll( sortkey, "%O", hasPostInstall );
1315
1316 sortedOutput[sortkey] = output;
1317 }
1318
1319 map<string, string>::iterator sortIt = sortedOutput.begin();
1320 for ( ; sortIt != sortedOutput.end(); ++sortIt ) {
1321 if ( StringHelper::stripWhiteSpace(sortIt->second).length() > 0) {
1322 cout << sortIt->second;
1323 }
1324 }
1325 }
1326
1327 void PrtGet::readme()
1328 {
1329 assertExactArgCount(1);
1330
1331 initRepo();
1332 string arg = *(m_parser->otherArgs().begin());
1333 const Package* p = m_repo->getPackage( arg );
1334 if ( p ) {
1335 string file = p->path() + "/" + p->name() + "/README";
1336 printFile(file);
1337 } else {
1338 cerr << "Package '" << arg << "' not found" << endl;
1339 m_returnValue = PG_GENERAL_ERROR;
1340 return;
1341 }
1342 }
1343
1344 bool PrtGet::printFile(const string& file)
1345 {
1346 if (!File::fileExists(file)) {
1347 return false;
1348 }
1349
1350 char* pager = getenv("PAGER");
1351 if (pager) {
1352 Process proc(pager, file);
1353 proc.executeShell();
1354 } else {
1355 FILE* fp = fopen( file.c_str(), "r" );
1356 char buf[255];
1357 if ( fp ) {
1358 while ( fgets( buf, 255, fp ) ) {
1359 cout << buf;
1360 }
1361 fclose( fp );
1362 }
1363 }
1364
1365 return true;
1366 }
1367
1368 void PrtGet::printDependent()
1369 {
1370 assertExactArgCount(1);
1371
1372 initRepo();
1373 string arg = *(m_parser->otherArgs().begin());
1374
1375 if (m_parser->printTree()) {
1376 cout << arg << endl;
1377 printDependent(arg, 2);
1378 } else {
1379 printDependent(arg, 0);
1380 }
1381 }
1382
1383 void PrtGet::printDependent(const string& dep, int level)
1384 {
1385 map<string, Package*>::const_iterator it = m_repo->packages().begin();
1386 static map<string, bool> shownMap;
1387
1388 set<const Package*> dependent;
1389 for ( ; it != m_repo->packages().end(); ++it ) {
1390
1391 // TODO: is the following line needed?
1392 const Package* p = it->second;
1393 if ( p && p->dependencies().find( dep ) != string::npos ) {
1394 list<string> tokens;
1395 StringHelper::split( p->dependencies(), ',', tokens );
1396 list<string>::iterator it = find( tokens.begin(),
1397 tokens.end(),
1398 dep );
1399 if ( it != tokens.end() ) {
1400 dependent.insert( p );
1401 }
1402 }
1403 }
1404
1405 // - there are two modes, tree and non-tree recursive mode; in
1406 // tree mode, packages are shown multiple times, in non tree
1407 // recursive mode they're only printed the first time; this is not
1408 // necessarily optimal for rebuilding:
1409 //
1410 // a -> b -> d
1411 // \ ^
1412 // > c /
1413 //
1414 // trying to rebuild 'd' before 'c' might possibly fail
1415 string indent = "";
1416 if (m_parser->printTree()) {
1417 for (int i = 0; i < level; ++i) {
1418 indent += " ";
1419 }
1420 }
1421 set<const Package*>::iterator it2 = dependent.begin();
1422 for ( ; it2 != dependent.end(); ++it2 ) {
1423 const Package* p = *it2;
1424
1425 if (m_parser->recursive() && !m_parser->printTree()) {
1426 if (shownMap[p->name()]) {
1427 continue;
1428 }
1429 shownMap[p->name()] = true;
1430 }
1431
1432 if ( m_parser->all() || m_pkgDB->isInstalled( p->name() ) ) {
1433
1434 cout << indent << p->name();
1435 if ( m_parser->verbose() > 0 ) {
1436 cout << " " << p->versionReleaseString();
1437 }
1438 if ( m_parser->verbose() > 1 ) {
1439 cout << ": " << p->description();
1440 }
1441
1442 cout << endl;
1443
1444 if (m_parser->recursive()) {
1445 printDependent( p->name(), level+2 );
1446 }
1447 }
1448 }
1449 }
1450
1451 void PrtGet::listOrphans()
1452 {
1453 initRepo();
1454 map<string, string> installed = m_pkgDB->installedPackages();
1455 map<string, bool> required;
1456 map<string, string>::iterator it = installed.begin();
1457
1458 for (; it != installed.end(); ++it) {
1459 list<string> tokens;
1460 const Package* p = m_repo->getPackage(it->first);
1461 if (p) {
1462 StringHelper::split( p->dependencies(), ',', tokens );
1463 list<string>::iterator lit = tokens.begin();
1464 for (; lit != tokens.end(); ++lit) {
1465 required[*lit] = true;
1466 }
1467 }
1468 }
1469
1470 // - we could store the package pointer in another map to avoid
1471 // another getPackage lockup, but it seems better to optimized for
1472 // memory since it's only used when called with -vv
1473
1474 it = installed.begin();
1475 for (; it != installed.end(); ++it) {
1476 if (!required[it->first]) {
1477 cout << it->first;
1478 if ( m_parser->verbose() > 0 ) {
1479 cout << " " << it->second;
1480 }
1481 if ( m_parser->verbose() > 1 ) {
1482 const Package* p = m_repo->getPackage(it->first);
1483 if (p) {
1484 cout << ": " << p->description();
1485 }
1486 }
1487 cout << endl;
1488 }
1489 }
1490 }
1491
1492
1493 void PrtGet::warnPackageNotFound(InstallTransaction& transaction)
1494 {
1495 cerr << "The package '";
1496 cerr << transaction.missing().begin()->first;
1497 cerr << "' could not be found: " << endl;
1498 }
1499
1500 void PrtGet::sysup()
1501 {
1502 // TODO: refactor getDifferentPackages from diff/quickdiff
1503 initRepo();
1504
1505 list<string>* target;
1506 list<string> packagesToUpdate;
1507 list<string> sortedList;
1508
1509 const map<string, string>& installed = m_pkgDB->installedPackages();
1510 map<string, string>::const_iterator it = installed.begin();
1511 const Package* p = 0;
1512 COMP_RESULT result;
1513 for ( ; it != installed.end(); ++it ) {
1514 if ( !m_locker.isLocked( it->first ) ) {
1515 p = m_repo->getPackage( it->first );
1516 if ( p ) {
1517 result = compareVersions( p->versionReleaseString(),
1518 it->second );
1519 if (result == GREATER ) {
1520 packagesToUpdate.push_back( it->first );
1521 } else if (result == UNDEFINED ) {
1522 m_undefinedVersionComp.push_back(make_pair(p, it->second));
1523 }
1524 }
1525 }
1526 }
1527
1528 if ( packagesToUpdate.empty() ) {
1529 cout << "System is up to date" << endl;
1530 return;
1531 }
1532
1533 if ( m_parser->nodeps() ) {
1534 target = &packagesToUpdate;
1535 } else {
1536 // sort by dependency
1537
1538 // TODO: refactor code from printDepends
1539 InstallTransaction depTrans( packagesToUpdate,
1540 m_repo, m_pkgDB, m_config );
1541 InstallTransaction::InstallResult result = depTrans.calcDependencies();
1542 if ( result == InstallTransaction::CYCLIC_DEPEND ) {
1543 cerr << "cyclic dependencies" << endl;
1544 m_returnValue = PG_GENERAL_ERROR;
1545 return;
1546 } else if ( result == InstallTransaction::PACKAGE_NOT_FOUND ) {
1547 warnPackageNotFound(depTrans);
1548 m_returnValue = PG_GENERAL_ERROR;
1549 return;
1550 }
1551
1552 const list<string>& deps = depTrans.dependencies();
1553 if ( deps.size() > 0 ) {
1554 list<string>::const_iterator it = deps.begin();
1555 for ( ; it != deps.end(); ++it ) {
1556 if ( find( packagesToUpdate.begin(),
1557 packagesToUpdate.end(), *it ) !=
1558 packagesToUpdate.end() ) {;
1559 sortedList.push_back( *it );
1560 }
1561 }
1562 }
1563
1564 target = &sortedList;
1565 }
1566
1567 InstallTransaction transaction( *target,
1568 m_repo, m_pkgDB, m_config );
1569 executeTransaction( transaction, true, false );
1570 }
1571
1572
1573 void PrtGet::expandWildcardsPkgDB( const list<char*>& in,
1574 map<string, string>& target )
1575 {
1576 list<char*>::const_iterator it = in.begin();
1577 for ( ; it != in.end(); ++it ) {
1578 map<string, string> l;
1579 m_pkgDB->getMatchingPackages( *it, l, m_useRegex );
1580 map<string, string>::iterator iit = l.begin();
1581 for ( ; iit != l.end(); ++iit ) {
1582 target[iit->first] = iit->second;
1583 }
1584 }
1585 }
1586
1587 void PrtGet::expandWildcardsRepo( const list<char*>& in, list<string>& target )
1588 {
1589 list<char*>::const_iterator it = in.begin();
1590
1591 for ( ; it != in.end(); ++it ) {
1592 list<Package*> l;
1593 m_repo->getMatchingPackages( *it, l );
1594 list<Package*>::iterator iit = l.begin();
1595 for ( ; iit != l.end(); ++iit ) {
1596 target.push_back( (*iit)->name() );
1597 }
1598 }
1599 }
1600
1601
1602 void PrtGet::current()
1603 {
1604 assertExactArgCount(1);
1605
1606 const map<string, string>& installed = m_pkgDB->installedPackages();
1607 map<string, string>::const_iterator it = installed.begin();
1608 string search = *(m_parser->otherArgs().begin());
1609
1610 for ( ; it != installed.end(); ++it ) {
1611 if ( it->first == search ) {
1612 cout << it->second.c_str() << endl;
1613 return;
1614 }
1615 }
1616
1617 cout << "Package " << search << " not installed" << endl;
1618 m_returnValue = 1;
1619 }
1620
1621 SignalHandler::HandlerResult PrtGet::handleSignal( int signal )
1622 {
1623 // TODO: second argument could also be true:
1624 // TODO: kill installtransaction
1625
1626 cout << "prt-get: interrupted" << endl;
1627 if ( m_currentTransaction ) {
1628 evaluateResult( *m_currentTransaction, false, true );
1629 }
1630
1631 return EXIT;
1632 }
1633
1634 /*!
1635 find files matching a pattern in repository
1636
1637 \sa Repository::getMatchingPackages()
1638 */
1639 void PrtGet::fsearch()
1640 {
1641 assertMinArgCount(1);
1642
1643 string arg = "*";
1644 if ( m_parser->otherArgs().size() == 1 ) {
1645 arg = *(m_parser->otherArgs().begin());
1646 }
1647
1648 initRepo();
1649 const map<string, Package*>& packages = m_repo->packages();
1650 map<string, Package*>::const_iterator it = packages.begin();
1651 bool first = true;
1652 for ( ; it != packages.end(); ++it ) {
1653 list<string> matches;
1654 string fp =
1655 it->second->path() + "/" +
1656 it->second->name() + "/" + ".footprint";
1657 if ( File::grep( fp, arg, matches,
1658 m_parser->fullPath(),
1659 m_useRegex)) {
1660 if ( matches.size() > 0 ) {
1661 if ( first ) {
1662 first = false;
1663 } else {
1664 cout << endl;
1665 }
1666 cout << "Found in "
1667 << it->second->path() << "/"
1668 << it->first << ":" << endl;
1669 list<string>::iterator it = matches.begin();
1670 for ( ; it != matches.end(); ++it ) {
1671 cout << " " << *it << endl;
1672 }
1673 }
1674 }
1675 }
1676
1677 if ( first ) {
1678 m_returnValue = PG_GENERAL_ERROR;
1679 }
1680 }
1681
1682 void PrtGet::setLock( bool lock )
1683 {
1684 assertMinArgCount(1);
1685
1686 if ( lock ) {
1687 initRepo();
1688 }
1689
1690 const list<char*>& args = m_parser->otherArgs();
1691 list<char*>::const_iterator it = args.begin();
1692 for ( ; it != args.end(); ++it ) {
1693 if ( lock ) {
1694 if (m_pkgDB->isInstalled( *it )) {
1695 if (!m_locker.lock( *it )) {
1696 cerr << "Already locked: " << *it << endl;
1697 m_returnValue = PG_GENERAL_ERROR;
1698 }
1699 } else {
1700 cerr << "Package '" << *it << "' not found" << endl;
1701 m_returnValue = PG_GENERAL_ERROR;
1702 return;
1703 }
1704
1705 } else {
1706 if ( !m_locker.unlock( *it ) ) {
1707 cerr << "Not locked previously: " << *it << endl;
1708 m_returnValue = PG_GENERAL_ERROR;
1709 return;
1710 }
1711 }
1712 }
1713
1714 if (!m_locker.store()) {
1715 cerr << "Failed to write lock data" << endl;
1716 m_returnValue = PG_GENERAL_ERROR;
1717 }
1718 }
1719
1720 void PrtGet::listLocked()
1721 {
1722 // shares some code with listInstalled
1723 if ( m_locker.openFailed() ) {
1724 cerr << "Failed to open lock data file" << endl;
1725 m_returnValue = PG_GENERAL_ERROR;
1726 }
1727
1728 const map<string, string>& l = m_pkgDB->installedPackages();
1729
1730 if ( l.empty() ) {
1731 return;
1732 }
1733
1734 if ( m_parser->verbose() > 1 ) {
1735 // warning: will slow down the process...
1736 initRepo();
1737 }
1738
1739
1740 const vector<string>& lockedPackages = m_locker.lockedPackages();
1741 vector<string>::const_iterator it = lockedPackages.begin();
1742 for ( ; it != lockedPackages.end(); ++it ) {
1743 cout << *it;
1744 if ( m_parser->verbose() > 0 ) {
1745 cout << " " << m_pkgDB->getPackageVersion(*it);
1746 }
1747 if ( m_parser->verbose() > 1 ) {
1748 const Package* p = m_repo->getPackage( *it );
1749 if ( p ) {
1750 cout << ": " << p->description();
1751 }
1752 }
1753
1754 cout << endl;
1755
1756 }
1757 }
1758
1759
1760 void PrtGet::edit()
1761 {
1762 assertMinArgCount(1);
1763 assertMaxArgCount(2);
1764
1765 char* editor = getenv("EDITOR");
1766 if (editor) {
1767 initRepo();
1768
1769 list<char*>::const_iterator it = m_parser->otherArgs().begin();
1770 string arg = *it;
1771 const Package* p = m_repo->getPackage( arg );
1772 if ( p ) {
1773 string fileName = "Pkgfile";
1774 if (++it != m_parser->otherArgs().end()) {
1775 fileName = *it;
1776 }
1777 string file = p->path() + "/" + p->name() + "/" + fileName;
1778 Process proc(editor, file);
1779 m_returnValue = proc.executeShell();
1780 if (m_returnValue) {
1781 cerr << "error while execution the editor" << endl;
1782 }
1783 } else {
1784 cerr << "Package '" << arg << "' not found" << endl;
1785 m_returnValue = PG_GENERAL_ERROR;
1786 return;
1787 }
1788
1789 } else {
1790 cerr << "Environment variable EDITOR not set" << endl;;
1791 m_returnValue = PG_GENERAL_ERROR;
1792 return;
1793 }
1794
1795 }
1796
1797 void PrtGet::ls()
1798 {
1799 assertExactArgCount(1);
1800
1801 initRepo();
1802
1803 list<char*>::const_iterator it = m_parser->otherArgs().begin();
1804 string arg = *it;
1805 const Package* p = m_repo->getPackage( arg );
1806 if ( p ) {
1807 string dirname = p->path() + "/" + p->name();
1808 DIR* dir = opendir(dirname.c_str());
1809 struct dirent* entry;
1810 vector<string> files;
1811 while ((entry = readdir(dir))) {
1812 string dName = entry->d_name;
1813 if (dName != "." && dName != "..") {
1814 files.push_back(dName);
1815 }
1816 }
1817 closedir(dir);
1818
1819 sort(files.begin(), files.end());
1820 vector<string>::iterator fit = files.begin();
1821 for (; fit != files.end(); ++fit) {
1822 if (m_parser->printPath()) {
1823 cout << p->path() + "/" +p->name() + "/";
1824 }
1825 cout << *fit << endl;
1826 }
1827 } else {
1828 cerr << "Package '" << arg << "' not found" << endl;
1829 m_returnValue = PG_GENERAL_ERROR;
1830 return;
1831 }
1832 }
1833
1834 void PrtGet::cat()
1835 {
1836 assertMinArgCount(1);
1837 assertMaxArgCount(2);
1838
1839 initRepo();
1840
1841 list<char*>::const_iterator it = m_parser->otherArgs().begin();
1842 string arg = *it;
1843 const Package* p = m_repo->getPackage( arg );
1844 if ( p ) {
1845 string fileName = "Pkgfile";
1846 if (++it != m_parser->otherArgs().end()) {
1847 fileName = *it;
1848 }
1849 string file = p->path() + "/" + p->name() + "/" + fileName;
1850 if (!printFile(file)) {
1851 cerr << "File '" << *it << "' not found" << endl;
1852 m_returnValue = PG_GENERAL_ERROR;
1853 return;
1854 }
1855 } else {
1856 cerr << "Package '" << arg << "' not found" << endl;
1857 m_returnValue = PG_GENERAL_ERROR;
1858 return;
1859 }
1860 }
1861
1862 void PrtGet::remove()
1863 {
1864 assertMinArgCount(1);
1865
1866 list<string> removed;
1867 list<string> failed;
1868 list<string> notInstalled;
1869
1870 if ( m_parser->isTest() ) {
1871 cout << "*** " << m_appName << ": test mode" << endl;
1872 }
1873
1874 string command = InstallTransaction::PKGRM_DEFAULT_COMMAND;
1875 if (m_config->removeCommand() != "") {
1876 command = m_config->removeCommand();
1877 }
1878
1879 const list<char*>& args = m_parser->otherArgs();
1880 list<char*>::const_iterator it = args.begin();
1881 for ( ; it != args.end(); ++it ) {
1882 if (m_pkgDB->isInstalled(*it)) {
1883 // TODO: prettify
1884 string args = "";
1885 if (m_parser->installRoot() != "") {
1886 args = "-r " + m_parser->installRoot() + " ";
1887 }
1888 args += (m_parser->pkgrmArgs() + " " + *it);
1889
1890 Process proc(command, args);
1891 if (m_parser->isTest() || proc.executeShell() == 0) {
1892 removed.push_back(*it);
1893 if (m_locker.isLocked(*it)) {
1894 m_locker.unlock(*it);
1895 m_locker.store();
1896 }
1897 } else {
1898 failed.push_back(*it);
1899 }
1900 } else {
1901 notInstalled.push_back(*it);
1902 }
1903 }
1904
1905 if ( removed.size() ) {
1906 cout << endl << "-- Packages removed"
1907 << endl;
1908 list<string>::const_iterator it = removed.begin();
1909
1910 for ( ; it != removed.end(); ++it ) {
1911 cout << *it << endl;
1912 }
1913 }
1914
1915 if ( failed.size() ) {
1916 cout << endl << "-- Packages where removal failed"
1917 << endl;
1918 list<string>::const_iterator it = failed.begin();
1919
1920 for ( ; it != failed.end(); ++it ) {
1921 cout << *it << endl;
1922 }
1923 }
1924
1925 if ( notInstalled.size() ) {
1926 cout << endl << "-- Packages which were not installed"
1927 << endl;
1928 list<string>::const_iterator it = notInstalled.begin();
1929
1930 for ( ; it != notInstalled.end(); ++it ) {
1931 cout << *it << endl;
1932 }
1933 }
1934
1935 if ( m_parser->isTest() ) {
1936 cout << "*** " << m_appName << ": test mode end" << endl;
1937 }
1938
1939
1940
1941 }
1942
1943 void PrtGet::assertMaxArgCount(size_t count)
1944 {
1945 if ( m_parser->otherArgs().size() > count ) {
1946 argCountFailure(count, "at most");
1947 }
1948 }
1949
1950 void PrtGet::assertExactArgCount(size_t count)
1951 {
1952 if ( m_parser->otherArgs().size() != count ) {
1953 argCountFailure(count, "exactly");
1954 }
1955 }
1956
1957 void PrtGet::assertMinArgCount(size_t count)
1958 {
1959 if ( m_parser->otherArgs().size() < count ) {
1960 argCountFailure(count, "at least");
1961 }
1962 }
1963
1964 void PrtGet::argCountFailure(size_t count, const string& specifier)
1965 {
1966 cerr << m_appName << " "
1967 << m_parser->commandName() << " takes " << specifier << " "
1968 << count << (count > 1 ? " arguments" : " argument") << endl;
1969 exit(PG_ARG_ERROR);
1970 }
1971
1972
1973 void PrtGet::printDependTree()
1974 {
1975 assertExactArgCount(1);
1976
1977 initRepo();
1978
1979 list<char*>::const_iterator it = m_parser->otherArgs().begin();
1980 string arg = *it;
1981 const Package* p = m_repo->getPackage( arg );
1982 if (!p) {
1983 cerr << "Package '" << arg << "' not found" << endl;
1984 m_returnValue = PG_GENERAL_ERROR;
1985 return;
1986 }
1987
1988 if (p->dependencies().length() > 0) {
1989
1990 cout << "-- dependencies ([i] = installed";
1991 if (!m_parser->all()) {
1992 cout << ", '-->' = seen before";
1993 }
1994 cout << ")" << endl;
1995 if ( m_pkgDB->isInstalled( *it ) ) {
1996 cout << "[i] ";
1997 } else {
1998 cout << "[ ] ";
1999 }
2000 cout << p->name() << endl;
2001 printDepsLevel(2, p);
2002 }
2003
2004 }
2005
2006 void PrtGet::printDepsLevel(int indent, const Package* package)
2007 {
2008 static map<string, bool> shownMap;
2009
2010 list<string> deps;
2011 StringHelper::split(package->dependencies(), ',', deps);
2012 list<string>::iterator it = deps.begin();
2013 bool isAlias = false;
2014 string aliasName = "";
2015
2016 for (; it != deps.end(); ++it) {
2017 if ( m_pkgDB->isInstalled( *it, true, &isAlias, &aliasName ) ) {
2018 cout << "[i] ";
2019 } else {
2020 cout << "[ ] ";
2021 }
2022 for (int i = 0; i < indent; ++i) {
2023 cout << " ";
2024 }
2025 cout << *it;
2026 if (isAlias) {
2027 cout << " (provided by " << aliasName << ")";
2028 }
2029 const Package* p = m_repo->getPackage( *it );
2030 if (p) {
2031 if (p->dependencies().length() > 0) {
2032 map<string, bool>::iterator shownIt = shownMap.find(*it);
2033 if (shownIt != shownMap.end()) {
2034 cout << " -->" << endl;;
2035 } else {
2036 cout << endl;
2037 printDepsLevel(indent+2, p);
2038 if (!m_parser->all()) {
2039 shownMap[*it] = true;
2040 }
2041 }
2042 } else {
2043 cout << endl;
2044 }
2045 } else {
2046 cout << " (not found in ports tree)" << endl;
2047 }
2048 }
2049 }
2050
2051 void PrtGet::dumpConfig()
2052 {
2053
2054 cout.setf( ios::left, ios::adjustfield );
2055 cout.width( 20 );
2056 cout.fill( ' ' );
2057 cout << "Alias file: " << PkgDB::ALIAS_STORE << endl;
2058
2059 if (!m_parser->noStdConfig()) {
2060 string fName = CONF_FILE;
2061 if ( m_parser->isAlternateConfigGiven() ) {
2062 fName = m_parser->alternateConfigFile();
2063 }
2064 cout.setf( ios::left, ios::adjustfield );
2065 cout.width( 20 );
2066 cout.fill( ' ' );
2067 cout << "Configuration file: " << fName << endl;
2068 }
2069
2070 if (m_config->cacheFile() != "") {
2071 cout.setf( ios::left, ios::adjustfield );
2072 cout.width( 20 );
2073 cout.fill( ' ' );
2074 cout << "Cache file: " << m_config->cacheFile() << endl;
2075 }
2076 if (m_config->makeCommand() != "") {
2077 cout.setf( ios::left, ios::adjustfield );
2078 cout.width( 20 );
2079 cout.fill( ' ' );
2080 cout << "Make command file: " << m_config->makeCommand() << endl;
2081 }
2082 if (m_config->addCommand() != "") {
2083 cout.setf( ios::left, ios::adjustfield );
2084 cout.width( 20 );
2085 cout.fill( ' ' );
2086 cout << "Add command: " << m_config->addCommand() << endl;
2087 }
2088 if (m_config->removeCommand() != "") {
2089 cout.setf( ios::left, ios::adjustfield );
2090 cout.width( 20 );
2091 cout.fill( ' ' );
2092 cout << "Remove command: " << m_config->removeCommand() << endl;
2093 }
2094 if (m_config->runscriptCommand() != "") {
2095 cout.setf( ios::left, ios::adjustfield );
2096 cout.width( 20 );
2097 cout.fill( ' ' );
2098 cout << "Runscript command: " << m_config->runscriptCommand() << endl;
2099 }
2100
2101 cout.setf( ios::left, ios::adjustfield );
2102 cout.width( 20 );
2103 cout.fill( ' ' );
2104 cout << "Run scripts: " <<(m_config->runScripts() ? "yes" : "no" )
2105 << endl;
2106
2107 cout.setf( ios::left, ios::adjustfield );
2108 cout.width( 20 );
2109 cout.fill( ' ' );
2110 cout << "Keep higher version:" <<(m_config->preferHigher() ? "yes" : "no" )
2111 << endl;
2112
2113 cout.setf( ios::left, ios::adjustfield );
2114 cout.width( 20 );
2115 cout.fill( ' ' );
2116 cout << "Readme mode: ";
2117 switch (m_config->readmeMode()) {
2118 case Configuration::VERBOSE_README:
2119 cout << "verbose";
2120 break;
2121 case Configuration::COMPACT_README:
2122 cout << "compact";
2123 break;
2124 case Configuration::NO_README:
2125 cout << "off";
2126 break;
2127 }
2128 cout << endl;
2129
2130 cout << endl;
2131
2132 if (m_config->logFilePattern() != "") {
2133 cout.setf( ios::left, ios::adjustfield );
2134 cout.width( 20 );
2135 cout.fill( ' ' );
2136 cout << "Log file: " << m_config->logFilePattern() << endl;
2137 }
2138 cout.setf( ios::left, ios::adjustfield );
2139 cout.width( 20 );
2140 cout.fill( ' ' );
2141 cout << " Write log: " << (m_config->writeLog() ? "yes" : "no" ) << endl;
2142 cout.setf( ios::left, ios::adjustfield );
2143 cout.width( 20 );
2144 cout.fill( ' ' );
2145 cout << " Append log: " <<(m_config->appendLog() ? "yes" : "no" ) << endl;
2146
2147 cout << endl;
2148 cout.setf( ios::left, ios::adjustfield );
2149 cout.width( 20 );
2150 cout.fill( ' ' );
2151 cout << "Pkgmk settings: " << m_config->logFilePattern() << endl;
2152 cout.setf( ios::left, ios::adjustfield );
2153 cout.width( 20 );
2154 cout.fill( ' ' );
2155 cout << " Package dir: " << InstallTransaction::getPkgmkPackageDir()
2156 << endl;
2157
2158 cout.setf( ios::left, ios::adjustfield );
2159 cout.width( 20 );
2160 cout.fill( ' ' );
2161 cout << " Compression mode: "
2162 << InstallTransaction::getPkgmkCompressionMode() << endl;
2163
2164
2165 cout << endl;
2166 list< pair<string, string> >::const_iterator it =
2167 m_config->rootList().begin();
2168 cout << "Port "
2169 << (m_config->rootList().size() == 1 ? "directory" : "directories")
2170 << ": " << endl;
2171 for (; it != m_config->rootList().end(); ++it) {
2172 cout << " " << it->first;
2173 if (it->second != "") {
2174 cout << " (" << it->second << ")";
2175 }
2176 cout << endl;
2177 }
2178 }
|