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