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