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