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