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