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