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