1 /* 2 * Copyright 2013, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold <ingo_weinhold@gmx.de> 7 */ 8 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <map> 15 16 #include <package/RepositoryCache.h> 17 #include <package/manager/RepositoryBuilder.h> 18 #include <package/solver/Solver.h> 19 #include <package/solver/SolverPackageSpecifier.h> 20 #include <package/solver/SolverPackageSpecifierList.h> 21 #include <package/solver/SolverProblem.h> 22 #include <package/solver/SolverProblemSolution.h> 23 #include <package/solver/SolverRepository.h> 24 #include <package/solver/SolverResult.h> 25 26 27 using namespace BPackageKit; 28 using namespace BPackageKit::BManager::BPrivate; 29 30 31 static const char* sProgramName = "get_package_dependencies"; 32 33 34 #define DIE(result, msg...) \ 35 do { \ 36 fprintf(stderr, "*** " msg); \ 37 fprintf(stderr, " : %s\n", strerror(result)); \ 38 exit(5); \ 39 } while(0) 40 41 42 void 43 print_usage_and_exit(bool error) 44 { 45 fprintf(error ? stderr : stdout, 46 "Usage: %s <repository> ... -- <package> ...\n" 47 "Resolves the dependencies of the given packages using the given\n" 48 "repositories and prints the URLs of the packages that are also\n" 49 "needed to satisfy all requirements. Fails, if there are conflicts\n" 50 "or some requirements cannot be satisfied.\n", 51 sProgramName); 52 exit(error ? 1 : 0); 53 } 54 55 56 int 57 main(int argc, const char* const* argv) 58 { 59 if (argc < 2) 60 print_usage_and_exit(true); 61 62 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) 63 print_usage_and_exit(false); 64 65 // get lists of repositories and packages 66 int argIndex = 1; 67 const char* const* repositories = argv + argIndex; 68 while (argIndex < argc && strcmp(argv[argIndex], "--") != 0) 69 argIndex++; 70 int repositoryCount = argv + argIndex - repositories; 71 72 if (repositoryCount == 0 || argIndex == argc) 73 print_usage_and_exit(true); 74 75 const char* const* packages = argv + argIndex + 1; 76 int packageCount = argv + argc - packages; 77 78 // create the solver 79 BSolver* solver; 80 status_t error = BSolver::Create(solver); 81 if (error != B_OK) 82 DIE(error, "failed to create solver"); 83 84 // add the "installed" repository with the given packages 85 BSolverRepository installedRepository; 86 { 87 BRepositoryBuilder installedRepositoryBuilder(installedRepository, 88 "installed"); 89 for (int i = 0; i < packageCount; i++) 90 installedRepositoryBuilder.AddPackage(packages[i]); 91 installedRepositoryBuilder.AddToSolver(solver, true); 92 } 93 94 // add external repositories 95 std::map<BSolverRepository*, BRepositoryInfo> repositoryInfos; 96 for (int i = 0; i < repositoryCount; i++) { 97 BSolverRepository* repository = new BSolverRepository; 98 BRepositoryCache cache; 99 error = cache.SetTo(repositories[i]); 100 if (error != B_OK) 101 DIE(error, "failed to read repository file '%s'", repositories[i]); 102 BRepositoryBuilder(*repository, cache) 103 .AddToSolver(solver, false); 104 repositoryInfos[repository] = cache.Info(); 105 } 106 107 // solve 108 error = solver->VerifyInstallation(); 109 if (error != B_OK) 110 DIE(error, "failed to compute packages to install"); 111 112 // print problems (and fail), if any 113 if (solver->HasProblems()) { 114 fprintf(stderr, "Encountered problems:\n"); 115 116 int32 problemCount = solver->CountProblems(); 117 for (int32 i = 0; i < problemCount; i++) { 118 // print problem and possible solutions 119 BSolverProblem* problem = solver->ProblemAt(i); 120 fprintf(stderr, "problem %" B_PRId32 ": %s\n", i + 1, 121 problem->ToString().String()); 122 123 int32 solutionCount = problem->CountSolutions(); 124 for (int32 k = 0; k < solutionCount; k++) { 125 const BSolverProblemSolution* solution = problem->SolutionAt(k); 126 fprintf(stderr, " solution %" B_PRId32 ":\n", k + 1); 127 int32 elementCount = solution->CountElements(); 128 for (int32 l = 0; l < elementCount; l++) { 129 const BSolverProblemSolutionElement* element 130 = solution->ElementAt(l); 131 fprintf(stderr, " - %s\n", element->ToString().String()); 132 } 133 } 134 } 135 136 exit(1); 137 } 138 139 // print URL of packages that additionally need to be installed 140 BSolverResult result; 141 error = solver->GetResult(result); 142 if (error != B_OK) 143 DIE(error, "failed to compute packages to install"); 144 145 bool duplicatePackage = false; 146 for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i); 147 i++) { 148 BSolverPackage* package = element->Package(); 149 150 switch (element->Type()) { 151 case BSolverResultElement::B_TYPE_INSTALL: 152 if (package->Repository() != &installedRepository) { 153 const BRepositoryInfo& info 154 = repositoryInfos[package->Repository()]; 155 BString url = info.OriginalBaseURL(); 156 url << "/packages/" << package->Info().CanonicalFileName(); 157 printf("%s\n", url.String()); 158 } 159 break; 160 161 case BSolverResultElement::B_TYPE_UNINSTALL: 162 fprintf(stderr, "Error: would need to uninstall package %s\n", 163 package->VersionedName().String()); 164 duplicatePackage = true; 165 break; 166 } 167 } 168 169 return duplicatePackage ? 1 : 0; 170 } 171