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