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 * Rene Gollent <rene@gollent.com> 8 */ 9 10 11 #include "PackageManager.h" 12 13 #include <package/DownloadFileRequest.h> 14 #include <package/RefreshRepositoryRequest.h> 15 #include <package/solver/SolverPackage.h> 16 #include <package/solver/SolverProblem.h> 17 #include <package/solver/SolverProblemSolution.h> 18 19 #include "pkgman.h" 20 21 22 using namespace BPackageKit::BPrivate; 23 24 25 PackageManager::PackageManager(BPackageInstallationLocation location, 26 bool interactive) 27 : 28 BPackageManager(location, &fClientInstallationInterface, this), 29 BPackageManager::UserInteractionHandler(), 30 fDecisionProvider(interactive), 31 fClientInstallationInterface(), 32 fPreviousDownloadPercentage(0), 33 fInteractive(interactive) 34 { 35 } 36 37 38 PackageManager::~PackageManager() 39 { 40 } 41 42 43 void 44 PackageManager::SetInteractive(bool interactive) 45 { 46 fInteractive = interactive; 47 fDecisionProvider.SetInteractive(interactive); 48 } 49 50 51 void 52 PackageManager::JobFailed(BJob* job) 53 { 54 BString error = job->ErrorString(); 55 if (error.Length() > 0) { 56 error.ReplaceAll("\n", "\n*** "); 57 fprintf(stderr, "%s", error.String()); 58 } 59 } 60 61 62 void 63 PackageManager::JobAborted(BJob* job) 64 { 65 DIE(job->Result(), "aborted"); 66 } 67 68 69 void 70 PackageManager::HandleProblems() 71 { 72 printf("Encountered problems:\n"); 73 74 int32 problemCount = fSolver->CountProblems(); 75 for (int32 i = 0; i < problemCount; i++) { 76 // print problem and possible solutions 77 BSolverProblem* problem = fSolver->ProblemAt(i); 78 printf("problem %" B_PRId32 ": %s\n", i + 1, 79 problem->ToString().String()); 80 81 int32 solutionCount = problem->CountSolutions(); 82 for (int32 k = 0; k < solutionCount; k++) { 83 const BSolverProblemSolution* solution = problem->SolutionAt(k); 84 printf(" solution %" B_PRId32 ":\n", k + 1); 85 int32 elementCount = solution->CountElements(); 86 for (int32 l = 0; l < elementCount; l++) { 87 const BSolverProblemSolutionElement* element 88 = solution->ElementAt(l); 89 printf(" - %s\n", element->ToString().String()); 90 } 91 } 92 93 if (!fInteractive) 94 continue; 95 96 // let the user choose a solution 97 printf("Please select a solution, skip the problem for now or quit.\n"); 98 for (;;) { 99 if (solutionCount > 1) 100 printf("select [1...%" B_PRId32 "/s/q]: ", solutionCount); 101 else 102 printf("select [1/s/q]: "); 103 104 char buffer[32]; 105 if (fgets(buffer, sizeof(buffer), stdin) == NULL 106 || strcmp(buffer, "q\n") == 0) { 107 exit(1); 108 } 109 110 if (strcmp(buffer, "s\n") == 0) 111 break; 112 113 char* end; 114 long selected = strtol(buffer, &end, 0); 115 if (end == buffer || *end != '\n' || selected < 1 116 || selected > solutionCount) { 117 printf("*** invalid input\n"); 118 continue; 119 } 120 121 status_t error = fSolver->SelectProblemSolution(problem, 122 problem->SolutionAt(selected - 1)); 123 if (error != B_OK) 124 DIE(error, "failed to set solution"); 125 break; 126 } 127 } 128 129 if (problemCount > 0 && !fInteractive) 130 exit(1); 131 } 132 133 134 void 135 PackageManager::ConfirmChanges(bool fromMostSpecific) 136 { 137 printf("The following changes will be made:\n"); 138 139 int32 count = fInstalledRepositories.CountItems(); 140 if (fromMostSpecific) { 141 for (int32 i = count - 1; i >= 0; i--) 142 _PrintResult(*fInstalledRepositories.ItemAt(i)); 143 } else { 144 for (int32 i = 0; i < count; i++) 145 _PrintResult(*fInstalledRepositories.ItemAt(i)); 146 } 147 148 if (!fDecisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "y", "n", 149 "y")) { 150 exit(1); 151 } 152 } 153 154 155 void 156 PackageManager::Warn(status_t error, const char* format, ...) 157 { 158 va_list args; 159 va_start(args, format); 160 vfprintf(stderr, format, args); 161 va_end(args); 162 163 if (error == B_OK) 164 printf("\n"); 165 else 166 printf(": %s\n", strerror(error)); 167 } 168 169 170 void 171 PackageManager::ProgressPackageDownloadStarted(const char* packageName) 172 { 173 printf("Downloading %s...\n", packageName); 174 fPreviousDownloadPercentage = 0; 175 } 176 177 178 void 179 PackageManager::ProgressPackageDownloadActive(const char* packageName, 180 float completionPercentage) 181 { 182 int32 currentPercentage = int32(completionPercentage * 100); 183 int32 difference = currentPercentage - fPreviousDownloadPercentage; 184 185 while (difference >= 2) { 186 printf("#"); 187 difference -= 2; 188 } 189 fflush(stdout); 190 191 fPreviousDownloadPercentage = currentPercentage - difference; 192 } 193 194 195 void 196 PackageManager::ProgressPackageDownloadComplete(const char* packageName) 197 { 198 printf("\nFinished downloading %s.\n", packageName); 199 } 200 201 202 void 203 PackageManager::ProgressPackageChecksumStarted(const char* title) 204 { 205 printf("%s...\n", title); 206 } 207 208 209 void 210 PackageManager::ProgressPackageChecksumComplete(const char* title) 211 { 212 printf("%s complete.\n", title); 213 } 214 215 216 void 217 PackageManager::ProgressStartApplyingChanges(InstalledRepository& repository) 218 { 219 printf("[%s] Applying changes ...\n", repository.Name().String()); 220 } 221 222 223 void 224 PackageManager::ProgressTransactionCommitted(InstalledRepository& repository, 225 const char* transactionDirectoryName) 226 { 227 printf("[%s] Changes applied. Old activation state backed up in \"%s\"\n", 228 repository.Name().String(), transactionDirectoryName); 229 printf("[%s] Cleaning up ...\n", repository.Name().String()); 230 } 231 232 233 void 234 PackageManager::ProgressApplyingChangesDone(InstalledRepository& repository) 235 { 236 printf("[%s] Done.\n", repository.Name().String()); 237 } 238 239 240 void 241 PackageManager::_PrintResult(InstalledRepository& installationRepository) 242 { 243 if (!installationRepository.HasChanges()) 244 return; 245 246 printf(" in %s:\n", installationRepository.Name().String()); 247 248 PackageList& packagesToActivate 249 = installationRepository.PackagesToActivate(); 250 PackageList& packagesToDeactivate 251 = installationRepository.PackagesToDeactivate(); 252 253 for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i); 254 i++) { 255 printf(" install package %s from repository %s\n", 256 package->Info().FileName().String(), 257 package->Repository()->Name().String()); 258 } 259 260 for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i); 261 i++) { 262 printf(" uninstall package %s\n", package->VersionedName().String()); 263 } 264 // TODO: Print file/download sizes. Unfortunately our package infos don't 265 // contain the file size. Which is probably correct. The file size (and possibly 266 // other information) should, however, be provided by the repository cache in 267 // some way. Extend BPackageInfo? Create a BPackageFileInfo? 268 } 269