1 /* 2 * Copyright 2013-2015, 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 <package/manager/PackageManager.h> 12 13 #include <Directory.h> 14 #include <package/CommitTransactionResult.h> 15 #include <package/DownloadFileRequest.h> 16 #include <package/PackageRoster.h> 17 #include <package/RefreshRepositoryRequest.h> 18 #include <package/RepositoryCache.h> 19 #include <package/solver/SolverPackage.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/SolverResult.h> 25 26 #include <CopyEngine.h> 27 #include <package/ActivationTransaction.h> 28 #include <package/DaemonClient.h> 29 #include <package/FetchFileJob.h> 30 #include <package/manager/RepositoryBuilder.h> 31 #include <package/ValidateChecksumJob.h> 32 33 #include "PackageManagerUtils.h" 34 35 36 using BPackageKit::BPrivate::FetchFileJob; 37 using BPackageKit::BPrivate::ValidateChecksumJob; 38 39 40 namespace BPackageKit { 41 42 namespace BManager { 43 44 namespace BPrivate { 45 46 47 // #pragma mark - BPackageManager 48 49 50 BPackageManager::BPackageManager(BPackageInstallationLocation location, 51 InstallationInterface* installationInterface, 52 UserInteractionHandler* userInteractionHandler) 53 : 54 fDebugLevel(0), 55 fLocation(location), 56 fSolver(NULL), 57 fSystemRepository(new (std::nothrow) InstalledRepository("system", 58 B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, -1)), 59 fHomeRepository(new (std::nothrow) InstalledRepository("home", 60 B_PACKAGE_INSTALLATION_LOCATION_HOME, -3)), 61 fInstalledRepositories(10), 62 fOtherRepositories(10, true), 63 fLocalRepository(new (std::nothrow) MiscLocalRepository), 64 fTransactions(5, true), 65 fInstallationInterface(installationInterface), 66 fUserInteractionHandler(userInteractionHandler) 67 { 68 } 69 70 71 BPackageManager::~BPackageManager() 72 { 73 delete fSolver; 74 delete fSystemRepository; 75 delete fHomeRepository; 76 delete fLocalRepository; 77 } 78 79 80 void 81 BPackageManager::Init(uint32 flags) 82 { 83 if (fSolver != NULL) 84 return; 85 86 // create the solver 87 status_t error = BSolver::Create(fSolver); 88 if (error != B_OK) 89 DIE(error, "failed to create solver"); 90 91 if (fSystemRepository == NULL || fHomeRepository == NULL 92 || fLocalRepository == NULL) { 93 throw std::bad_alloc(); 94 } 95 96 fSolver->SetDebugLevel(fDebugLevel); 97 98 BRepositoryBuilder(*fLocalRepository).AddToSolver(fSolver, false); 99 100 // add installation location repositories 101 if ((flags & B_ADD_INSTALLED_REPOSITORIES) != 0) { 102 // We add only the repository of our actual installation location as the 103 // "installed" repository. The repositories for the more general 104 // installation locations are added as regular repositories, but with 105 // better priorities than the actual (remote) repositories. This 106 // prevents the solver from showing conflicts when a package in a more 107 // specific installation location overrides a package in a more general 108 // one. Instead any requirement that is already installed in a more 109 // general installation location will turn up as to be installed as 110 // well. But we can easily filter those out. 111 _AddInstalledRepository(fSystemRepository); 112 113 if (!fSystemRepository->IsInstalled()) 114 _AddInstalledRepository(fHomeRepository); 115 } 116 117 // add other repositories 118 if ((flags & B_ADD_REMOTE_REPOSITORIES) != 0) { 119 BPackageRoster roster; 120 BStringList repositoryNames; 121 error = roster.GetRepositoryNames(repositoryNames); 122 if (error != B_OK) { 123 fUserInteractionHandler->Warn(error, 124 "failed to get repository names"); 125 } 126 127 int32 repositoryNameCount = repositoryNames.CountStrings(); 128 for (int32 i = 0; i < repositoryNameCount; i++) { 129 _AddRemoteRepository(roster, repositoryNames.StringAt(i), 130 (flags & B_REFRESH_REPOSITORIES) != 0); 131 } 132 } 133 } 134 135 136 void 137 BPackageManager::SetDebugLevel(int32 level) 138 { 139 fDebugLevel = level; 140 141 if (fSolver != NULL) 142 fSolver->SetDebugLevel(fDebugLevel); 143 } 144 145 146 void 147 BPackageManager::Install(const char* const* packages, int packageCount) 148 { 149 BSolverPackageSpecifierList packagesToInstall; 150 _AddPackageSpecifiers(packages, packageCount, packagesToInstall); 151 Install(packagesToInstall); 152 } 153 154 155 void 156 BPackageManager::Install(const BSolverPackageSpecifierList& packages) 157 { 158 Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES 159 | B_REFRESH_REPOSITORIES); 160 161 // solve 162 const BSolverPackageSpecifier* unmatchedSpecifier; 163 status_t error = fSolver->Install(packages, &unmatchedSpecifier); 164 if (error != B_OK) { 165 if (unmatchedSpecifier != NULL) { 166 DIE(error, "failed to find a match for \"%s\"", 167 unmatchedSpecifier->SelectString().String()); 168 } else 169 DIE(error, "failed to compute packages to install"); 170 } 171 172 _HandleProblems(); 173 174 // install/uninstall packages 175 _AnalyzeResult(); 176 _ConfirmChanges(); 177 _ApplyPackageChanges(); 178 } 179 180 181 void 182 BPackageManager::Uninstall(const char* const* packages, int packageCount) 183 { 184 BSolverPackageSpecifierList packagesToUninstall; 185 if (!packagesToUninstall.AppendSpecifiers(packages, packageCount)) 186 throw std::bad_alloc(); 187 Uninstall(packagesToUninstall); 188 } 189 190 191 void 192 BPackageManager::Uninstall(const BSolverPackageSpecifierList& packages) 193 { 194 Init(B_ADD_INSTALLED_REPOSITORIES); 195 196 // find the packages that match the specification 197 const BSolverPackageSpecifier* unmatchedSpecifier; 198 PackageList foundPackages; 199 status_t error = fSolver->FindPackages(packages, 200 BSolver::B_FIND_INSTALLED_ONLY, foundPackages, &unmatchedSpecifier); 201 if (error != B_OK) { 202 if (unmatchedSpecifier != NULL) { 203 DIE(error, "failed to find a match for \"%s\"", 204 unmatchedSpecifier->SelectString().String()); 205 } else 206 DIE(error, "failed to compute packages to uninstall"); 207 } 208 209 // determine the inverse base package closure for the found packages 210 // TODO: Optimize! 211 InstalledRepository& installationRepository = InstallationRepository(); 212 bool foundAnotherPackage; 213 do { 214 foundAnotherPackage = false; 215 int32 count = installationRepository.CountPackages(); 216 for (int32 i = 0; i < count; i++) { 217 BSolverPackage* package = installationRepository.PackageAt(i); 218 if (foundPackages.HasItem(package)) 219 continue; 220 221 if (_FindBasePackage(foundPackages, package->Info()) >= 0) { 222 foundPackages.AddItem(package); 223 foundAnotherPackage = true; 224 } 225 } 226 } while (foundAnotherPackage); 227 228 // remove the packages from the repository 229 for (int32 i = 0; BSolverPackage* package = foundPackages.ItemAt(i); i++) 230 installationRepository.DisablePackage(package); 231 232 for (;;) { 233 error = fSolver->VerifyInstallation(BSolver::B_VERIFY_ALLOW_UNINSTALL); 234 if (error != B_OK) 235 DIE(error, "failed to compute packages to uninstall"); 236 237 _HandleProblems(); 238 239 // (virtually) apply the result to this repository 240 _AnalyzeResult(); 241 242 for (int32 i = foundPackages.CountItems() - 1; i >= 0; i--) { 243 if (!installationRepository.PackagesToDeactivate() 244 .AddItem(foundPackages.ItemAt(i))) { 245 throw std::bad_alloc(); 246 } 247 } 248 249 installationRepository.ApplyChanges(); 250 251 // verify the next specific respository 252 if (!_NextSpecificInstallationLocation()) 253 break; 254 255 foundPackages.MakeEmpty(); 256 257 // NOTE: In theory, after verifying a more specific location, it would 258 // be more correct to compute the inverse base package closure for the 259 // packages we need to uninstall and (if anything changed) verify again. 260 // In practice, however, base packages are always required with an exact 261 // version (ATM). If that base package still exist in a more general 262 // location (the only reason why the package requiring the base package 263 // wouldn't be marked to be uninstalled as well) there shouldn't have 264 // been any reason to remove it from the more specific location in the 265 // first place. 266 } 267 268 _ConfirmChanges(true); 269 _ApplyPackageChanges(true); 270 } 271 272 273 void 274 BPackageManager::Update(const char* const* packages, int packageCount) 275 { 276 BSolverPackageSpecifierList packagesToUpdate; 277 _AddPackageSpecifiers(packages, packageCount, packagesToUpdate); 278 Update(packagesToUpdate); 279 } 280 281 282 void 283 BPackageManager::Update(const BSolverPackageSpecifierList& packages) 284 { 285 Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES 286 | B_REFRESH_REPOSITORIES); 287 288 // solve 289 const BSolverPackageSpecifier* unmatchedSpecifier; 290 status_t error = fSolver->Update(packages, true, 291 &unmatchedSpecifier); 292 if (error != B_OK) { 293 if (unmatchedSpecifier != NULL) { 294 DIE(error, "failed to find a match for \"%s\"", 295 unmatchedSpecifier->SelectString().String()); 296 } else 297 DIE(error, "failed to compute packages to update"); 298 } 299 300 _HandleProblems(); 301 302 // install/uninstall packages 303 _AnalyzeResult(); 304 _ConfirmChanges(); 305 _ApplyPackageChanges(); 306 } 307 308 309 void 310 BPackageManager::FullSync() 311 { 312 Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES 313 | B_REFRESH_REPOSITORIES); 314 315 // solve 316 status_t error = fSolver->FullSync(); 317 if (error != B_OK) 318 DIE(error, "failed to compute packages to synchronize"); 319 320 _HandleProblems(); 321 322 // install/uninstall packages 323 _AnalyzeResult(); 324 _ConfirmChanges(); 325 _ApplyPackageChanges(); 326 } 327 328 329 void 330 BPackageManager::VerifyInstallation() 331 { 332 Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES 333 | B_REFRESH_REPOSITORIES); 334 335 for (;;) { 336 status_t error = fSolver->VerifyInstallation(); 337 if (error != B_OK) 338 DIE(error, "failed to compute package dependencies"); 339 340 _HandleProblems(); 341 342 // (virtually) apply the result to this repository 343 _AnalyzeResult(); 344 InstallationRepository().ApplyChanges(); 345 346 // verify the next specific respository 347 if (!_NextSpecificInstallationLocation()) 348 break; 349 } 350 351 _ConfirmChanges(); 352 _ApplyPackageChanges(); 353 } 354 355 356 BPackageManager::InstalledRepository& 357 BPackageManager::InstallationRepository() 358 { 359 if (fInstalledRepositories.IsEmpty()) 360 DIE("no installation repository"); 361 362 return *fInstalledRepositories.LastItem(); 363 } 364 365 366 void 367 BPackageManager::JobStarted(BSupportKit::BJob* job) 368 { 369 if (dynamic_cast<FetchFileJob*>(job) != NULL) { 370 FetchFileJob* fetchJob = (FetchFileJob*)job; 371 fUserInteractionHandler->ProgressPackageDownloadStarted( 372 fetchJob->DownloadFileName()); 373 } else if (dynamic_cast<ValidateChecksumJob*>(job) != NULL) { 374 fUserInteractionHandler->ProgressPackageChecksumStarted( 375 job->Title().String()); 376 } 377 } 378 379 380 void 381 BPackageManager::JobProgress(BSupportKit::BJob* job) 382 { 383 if (dynamic_cast<FetchFileJob*>(job) != NULL) { 384 FetchFileJob* fetchJob = (FetchFileJob*)job; 385 fUserInteractionHandler->ProgressPackageDownloadActive( 386 fetchJob->DownloadFileName(), fetchJob->DownloadProgress(), 387 fetchJob->DownloadBytes(), fetchJob->DownloadTotalBytes()); 388 } 389 } 390 391 392 void 393 BPackageManager::JobSucceeded(BSupportKit::BJob* job) 394 { 395 if (dynamic_cast<FetchFileJob*>(job) != NULL) { 396 FetchFileJob* fetchJob = (FetchFileJob*)job; 397 fUserInteractionHandler->ProgressPackageDownloadComplete( 398 fetchJob->DownloadFileName()); 399 } else if (dynamic_cast<ValidateChecksumJob*>(job) != NULL) { 400 fUserInteractionHandler->ProgressPackageChecksumComplete( 401 job->Title().String()); 402 } 403 } 404 405 406 void 407 BPackageManager::_HandleProblems() 408 { 409 while (fSolver->HasProblems()) { 410 fUserInteractionHandler->HandleProblems(); 411 412 status_t error = fSolver->SolveAgain(); 413 if (error != B_OK) 414 DIE(error, "failed to recompute packages to un/-install"); 415 } 416 } 417 418 419 void 420 BPackageManager::_AnalyzeResult() 421 { 422 BSolverResult result; 423 status_t error = fSolver->GetResult(result); 424 if (error != B_OK) 425 DIE(error, "failed to compute packages to un/-install"); 426 427 InstalledRepository& installationRepository = InstallationRepository(); 428 PackageList& packagesToActivate 429 = installationRepository.PackagesToActivate(); 430 PackageList& packagesToDeactivate 431 = installationRepository.PackagesToDeactivate(); 432 433 PackageList potentialBasePackages; 434 435 for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i); 436 i++) { 437 BSolverPackage* package = element->Package(); 438 439 switch (element->Type()) { 440 case BSolverResultElement::B_TYPE_INSTALL: 441 { 442 PackageList& packageList 443 = dynamic_cast<InstalledRepository*>(package->Repository()) 444 != NULL 445 ? potentialBasePackages 446 : packagesToActivate; 447 if (!packageList.AddItem(package)) 448 throw std::bad_alloc(); 449 break; 450 } 451 452 case BSolverResultElement::B_TYPE_UNINSTALL: 453 if (!packagesToDeactivate.AddItem(package)) 454 throw std::bad_alloc(); 455 break; 456 } 457 } 458 459 // Make sure base packages are installed in the same location. 460 for (int32 i = 0; i < packagesToActivate.CountItems(); i++) { 461 BSolverPackage* package = packagesToActivate.ItemAt(i); 462 int32 index = _FindBasePackage(potentialBasePackages, package->Info()); 463 if (index < 0) 464 continue; 465 466 BSolverPackage* basePackage = potentialBasePackages.RemoveItemAt(index); 467 if (!packagesToActivate.AddItem(basePackage)) 468 throw std::bad_alloc(); 469 } 470 471 fInstallationInterface->ResultComputed(installationRepository); 472 } 473 474 475 void 476 BPackageManager::_ConfirmChanges(bool fromMostSpecific) 477 { 478 // check, if there are any changes at all 479 int32 count = fInstalledRepositories.CountItems(); 480 bool hasChanges = false; 481 for (int32 i = 0; i < count; i++) { 482 if (fInstalledRepositories.ItemAt(i)->HasChanges()) { 483 hasChanges = true; 484 break; 485 } 486 } 487 488 if (!hasChanges) 489 throw BNothingToDoException(); 490 491 fUserInteractionHandler->ConfirmChanges(fromMostSpecific); 492 } 493 494 495 void 496 BPackageManager::_ApplyPackageChanges(bool fromMostSpecific) 497 { 498 int32 count = fInstalledRepositories.CountItems(); 499 if (fromMostSpecific) { 500 for (int32 i = count - 1; i >= 0; i--) 501 _PreparePackageChanges(*fInstalledRepositories.ItemAt(i)); 502 } else { 503 for (int32 i = 0; i < count; i++) 504 _PreparePackageChanges(*fInstalledRepositories.ItemAt(i)); 505 } 506 507 for (int32 i = 0; Transaction* transaction = fTransactions.ItemAt(i); i++) 508 _CommitPackageChanges(*transaction); 509 510 // TODO: Clean up the transaction directories on error! 511 } 512 513 514 void 515 BPackageManager::_PreparePackageChanges( 516 InstalledRepository& installationRepository) 517 { 518 if (!installationRepository.HasChanges()) 519 return; 520 521 PackageList& packagesToActivate 522 = installationRepository.PackagesToActivate(); 523 PackageList& packagesToDeactivate 524 = installationRepository.PackagesToDeactivate(); 525 526 // create the transaction 527 Transaction* transaction = new Transaction(installationRepository); 528 if (!fTransactions.AddItem(transaction)) { 529 delete transaction; 530 throw std::bad_alloc(); 531 } 532 533 status_t error = fInstallationInterface->PrepareTransaction(*transaction); 534 if (error != B_OK) 535 DIE(error, "failed to create transaction"); 536 537 // download the new packages and prepare the transaction 538 for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i); 539 i++) { 540 // get package URL and target entry 541 542 BString fileName(package->Info().FileName()); 543 if (fileName.IsEmpty()) 544 throw std::bad_alloc(); 545 546 BEntry entry; 547 error = entry.SetTo(&transaction->TransactionDirectory(), fileName); 548 if (error != B_OK) 549 DIE(error, "failed to create package entry"); 550 551 RemoteRepository* remoteRepository 552 = dynamic_cast<RemoteRepository*>(package->Repository()); 553 if (remoteRepository != NULL) { 554 // download the package 555 BString url = remoteRepository->Config().PackagesURL(); 556 url << '/' << fileName; 557 558 status_t error = DownloadPackage(url, entry, 559 package->Info().Checksum()); 560 if (error != B_OK) 561 DIE(error, "failed to download package"); 562 } else if (package->Repository() != &installationRepository) { 563 // clone the existing package 564 LocalRepository* localRepository 565 = dynamic_cast<LocalRepository*>(package->Repository()); 566 if (localRepository == NULL) { 567 DIE("internal error: repository %s is not a local repository", 568 package->Repository()->Name().String()); 569 } 570 _ClonePackageFile(localRepository, package, entry); 571 } 572 573 // add package to transaction 574 if (!transaction->ActivationTransaction().AddPackageToActivate( 575 fileName)) { 576 throw std::bad_alloc(); 577 } 578 } 579 580 for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i); 581 i++) { 582 // add package to transaction 583 if (!transaction->ActivationTransaction().AddPackageToDeactivate( 584 package->Info().FileName())) { 585 throw std::bad_alloc(); 586 } 587 } 588 } 589 590 591 void 592 BPackageManager::_CommitPackageChanges(Transaction& transaction) 593 { 594 InstalledRepository& installationRepository = transaction.Repository(); 595 596 fUserInteractionHandler->ProgressStartApplyingChanges( 597 installationRepository); 598 599 // commit the transaction 600 BCommitTransactionResult transactionResult; 601 status_t error = fInstallationInterface->CommitTransaction(transaction, 602 transactionResult); 603 if (error != B_OK) 604 DIE(error, "failed to commit transaction"); 605 if (transactionResult.Error() != B_TRANSACTION_OK) 606 DIE(transactionResult); 607 608 fUserInteractionHandler->ProgressTransactionCommitted( 609 installationRepository, transactionResult); 610 611 BEntry transactionDirectoryEntry; 612 if ((error = transaction.TransactionDirectory() 613 .GetEntry(&transactionDirectoryEntry)) != B_OK 614 || (error = transactionDirectoryEntry.Remove()) != B_OK) { 615 fUserInteractionHandler->Warn(error, 616 "failed to remove transaction directory"); 617 } 618 619 fUserInteractionHandler->ProgressApplyingChangesDone( 620 installationRepository); 621 } 622 623 624 void 625 BPackageManager::_ClonePackageFile(LocalRepository* repository, 626 BSolverPackage* package, const BEntry& entry) 627 { 628 // get source and destination path 629 BPath sourcePath; 630 repository->GetPackagePath(package, sourcePath); 631 632 BPath destinationPath; 633 status_t error = entry.GetPath(&destinationPath); 634 if (error != B_OK) { 635 DIE(error, "failed to entry path of package file to install \"%s\"", 636 package->Info().FileName().String()); 637 } 638 639 // Copy the package. Ideally we would just hard-link it, but BFS doesn't 640 // support that. 641 error = BCopyEngine().CopyEntry(sourcePath.Path(), destinationPath.Path()); 642 if (error != B_OK) 643 DIE(error, "failed to copy package file \"%s\"", sourcePath.Path()); 644 } 645 646 647 int32 648 BPackageManager::_FindBasePackage(const PackageList& packages, 649 const BPackageInfo& info) 650 { 651 if (info.BasePackage().IsEmpty()) 652 return -1; 653 654 // find the requirement matching the base package 655 BPackageResolvableExpression* basePackage = NULL; 656 int32 count = info.RequiresList().CountItems(); 657 for (int32 i = 0; i < count; i++) { 658 BPackageResolvableExpression* requires = info.RequiresList().ItemAt(i); 659 if (requires->Name() == info.BasePackage()) { 660 basePackage = requires; 661 break; 662 } 663 } 664 665 if (basePackage == NULL) { 666 fUserInteractionHandler->Warn(B_OK, "package %s-%s doesn't have a " 667 "matching requires for its base package \"%s\"", 668 info.Name().String(), info.Version().ToString().String(), 669 info.BasePackage().String()); 670 return -1; 671 } 672 673 // find the first package matching the base package requires 674 count = packages.CountItems(); 675 for (int32 i = 0; i < count; i++) { 676 BSolverPackage* package = packages.ItemAt(i); 677 if (package->Name() == basePackage->Name() 678 && package->Info().Matches(*basePackage)) { 679 return i; 680 } 681 } 682 683 return -1; 684 } 685 686 687 void 688 BPackageManager::_AddInstalledRepository(InstalledRepository* repository) 689 { 690 fInstallationInterface->InitInstalledRepository(*repository); 691 692 BRepositoryBuilder(*repository) 693 .AddToSolver(fSolver, repository->Location() == fLocation); 694 repository->SetPriority(repository->InitialPriority()); 695 696 if (!fInstalledRepositories.AddItem(repository)) 697 throw std::bad_alloc(); 698 } 699 700 701 void 702 BPackageManager::_AddRemoteRepository(BPackageRoster& roster, const char* name, 703 bool refresh) 704 { 705 BRepositoryConfig config; 706 status_t error = roster.GetRepositoryConfig(name, &config); 707 if (error != B_OK) { 708 fUserInteractionHandler->Warn(error, 709 "failed to get config for repository \"%s\". Skipping.", name); 710 return; 711 } 712 713 BRepositoryCache cache; 714 error = _GetRepositoryCache(roster, config, refresh, cache); 715 if (error != B_OK) { 716 fUserInteractionHandler->Warn(error, 717 "failed to get cache for repository \"%s\". Skipping.", name); 718 return; 719 } 720 721 RemoteRepository* repository = new RemoteRepository(config); 722 if (!fOtherRepositories.AddItem(repository)) { 723 delete repository; 724 throw std::bad_alloc(); 725 } 726 727 BRepositoryBuilder(*repository, cache, config.Name()) 728 .AddToSolver(fSolver, false); 729 } 730 731 732 status_t 733 BPackageManager::_GetRepositoryCache(BPackageRoster& roster, 734 const BRepositoryConfig& config, bool refresh, BRepositoryCache& _cache) 735 { 736 if (!refresh && roster.GetRepositoryCache(config.Name(), &_cache) == B_OK) 737 return B_OK; 738 739 status_t error = RefreshRepository(config); 740 if (error != B_OK) { 741 fUserInteractionHandler->Warn(error, 742 "refreshing repository \"%s\" failed", config.Name().String()); 743 } 744 745 return roster.GetRepositoryCache(config.Name(), &_cache); 746 } 747 748 749 void 750 BPackageManager::_AddPackageSpecifiers(const char* const* searchStrings, 751 int searchStringCount, BSolverPackageSpecifierList& specifierList) 752 { 753 for (int i = 0; i < searchStringCount; i++) { 754 const char* searchString = searchStrings[i]; 755 if (_IsLocalPackage(searchString)) { 756 BSolverPackage* package = _AddLocalPackage(searchString); 757 if (!specifierList.AppendSpecifier(package)) 758 throw std::bad_alloc(); 759 } else { 760 if (!specifierList.AppendSpecifier(searchString)) 761 throw std::bad_alloc(); 762 } 763 } 764 } 765 766 767 bool 768 BPackageManager::_IsLocalPackage(const char* fileName) 769 { 770 // Simple heuristic: fileName contains ".hpkg" and there's actually a file 771 // it refers to. 772 struct stat st; 773 return strstr(fileName, ".hpkg") != NULL && stat(fileName, &st) == 0 774 && S_ISREG(st.st_mode); 775 } 776 777 778 BSolverPackage* 779 BPackageManager::_AddLocalPackage(const char* fileName) 780 { 781 if (fLocalRepository == NULL) 782 throw std::bad_alloc(); 783 return fLocalRepository->AddLocalPackage(fileName); 784 } 785 786 787 bool 788 BPackageManager::_NextSpecificInstallationLocation() 789 { 790 if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) { 791 fLocation = B_PACKAGE_INSTALLATION_LOCATION_HOME; 792 fSystemRepository->SetInstalled(false); 793 _AddInstalledRepository(fHomeRepository); 794 return true; 795 } 796 797 return false; 798 } 799 800 801 status_t 802 BPackageManager::DownloadPackage(const BString& fileURL, 803 const BEntry& targetEntry, const BString& checksum) 804 { 805 BDecisionProvider provider; 806 BContext context(provider, *this); 807 return DownloadFileRequest(context, fileURL, targetEntry, checksum) 808 .Process(); 809 } 810 811 812 status_t 813 BPackageManager::RefreshRepository(const BRepositoryConfig& repoConfig) 814 { 815 BDecisionProvider provider; 816 BContext context(provider, *this); 817 return BRefreshRepositoryRequest(context, repoConfig).Process(); 818 } 819 820 821 // #pragma mark - RemoteRepository 822 823 824 BPackageManager::RemoteRepository::RemoteRepository( 825 const BRepositoryConfig& config) 826 : 827 BSolverRepository(), 828 fConfig(config) 829 { 830 } 831 832 833 const BRepositoryConfig& 834 BPackageManager::RemoteRepository::Config() const 835 { 836 return fConfig; 837 } 838 839 840 // #pragma mark - LocalRepository 841 842 843 BPackageManager::LocalRepository::LocalRepository() 844 : 845 BSolverRepository() 846 { 847 } 848 849 850 BPackageManager::LocalRepository::LocalRepository(const BString& name) 851 : 852 BSolverRepository(name) 853 { 854 } 855 856 857 // #pragma mark - MiscLocalRepository 858 859 860 BPackageManager::MiscLocalRepository::MiscLocalRepository() 861 : 862 LocalRepository("local"), 863 fPackagePaths() 864 { 865 SetPriority(-127); 866 } 867 868 869 BSolverPackage* 870 BPackageManager::MiscLocalRepository::AddLocalPackage(const char* fileName) 871 { 872 BSolverPackage* package; 873 BRepositoryBuilder(*this).AddPackage(fileName, &package); 874 875 fPackagePaths[package] = fileName; 876 877 return package; 878 } 879 880 881 void 882 BPackageManager::MiscLocalRepository::GetPackagePath(BSolverPackage* package, 883 BPath& _path) 884 { 885 PackagePathMap::const_iterator it = fPackagePaths.find(package); 886 if (it == fPackagePaths.end()) { 887 DIE("package %s not in local repository", 888 package->VersionedName().String()); 889 } 890 891 status_t error = _path.SetTo(it->second.c_str()); 892 if (error != B_OK) 893 DIE(error, "failed to init package path %s", it->second.c_str()); 894 } 895 896 897 // #pragma mark - InstalledRepository 898 899 900 BPackageManager::InstalledRepository::InstalledRepository(const char* name, 901 BPackageInstallationLocation location, int32 priority) 902 : 903 LocalRepository(), 904 fDisabledPackages(10, true), 905 fPackagesToActivate(), 906 fPackagesToDeactivate(), 907 fInitialName(name), 908 fLocation(location), 909 fInitialPriority(priority) 910 { 911 } 912 913 914 void 915 BPackageManager::InstalledRepository::GetPackagePath(BSolverPackage* package, 916 BPath& _path) 917 { 918 directory_which packagesWhich; 919 switch (fLocation) { 920 case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM: 921 packagesWhich = B_SYSTEM_PACKAGES_DIRECTORY; 922 break; 923 case B_PACKAGE_INSTALLATION_LOCATION_HOME: 924 packagesWhich = B_USER_PACKAGES_DIRECTORY; 925 break; 926 default: 927 DIE("don't know packages directory path for installation location " 928 "\"%s\"", Name().String()); 929 } 930 931 BString fileName(package->Info().FileName()); 932 status_t error = find_directory(packagesWhich, &_path); 933 if (error != B_OK || (error = _path.Append(fileName)) != B_OK) { 934 DIE(error, "failed to get path of package file \"%s\" in installation " 935 "location \"%s\"", fileName.String(), Name().String()); 936 } 937 } 938 939 940 void 941 BPackageManager::InstalledRepository::DisablePackage(BSolverPackage* package) 942 { 943 if (fDisabledPackages.HasItem(package)) 944 DIE("package %s already disabled", package->VersionedName().String()); 945 946 if (package->Repository() != this) { 947 DIE("package %s not in repository %s", 948 package->VersionedName().String(), Name().String()); 949 } 950 951 // move to disabled list 952 if (!fDisabledPackages.AddItem(package)) 953 throw std::bad_alloc(); 954 955 RemovePackage(package); 956 } 957 958 959 bool 960 BPackageManager::InstalledRepository::EnablePackage(BSolverPackage* package) 961 { 962 return fDisabledPackages.RemoveItem(package); 963 } 964 965 966 bool 967 BPackageManager::InstalledRepository::HasChanges() const 968 { 969 return !fPackagesToActivate.IsEmpty() || !fPackagesToDeactivate.IsEmpty(); 970 } 971 972 973 void 974 BPackageManager::InstalledRepository::ApplyChanges() 975 { 976 // disable packages to deactivate 977 for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i); 978 i++) { 979 if (!fDisabledPackages.HasItem(package)) 980 DisablePackage(package); 981 } 982 983 // add packages to activate 984 for (int32 i = 0; BSolverPackage* package = fPackagesToActivate.ItemAt(i); 985 i++) { 986 status_t error = AddPackage(package->Info()); 987 if (error != B_OK) { 988 DIE(error, "failed to add package %s to %s repository", 989 package->Name().String(), Name().String()); 990 } 991 } 992 } 993 994 995 // #pragma mark - Transaction 996 997 998 BPackageManager::Transaction::Transaction(InstalledRepository& repository) 999 : 1000 fRepository(repository), 1001 fTransaction(), 1002 fTransactionDirectory() 1003 { 1004 } 1005 1006 1007 BPackageManager::Transaction::~Transaction() 1008 { 1009 } 1010 1011 1012 // #pragma mark - InstallationInterface 1013 1014 1015 BPackageManager::InstallationInterface::~InstallationInterface() 1016 { 1017 } 1018 1019 1020 void 1021 BPackageManager::InstallationInterface::ResultComputed( 1022 InstalledRepository& repository) 1023 { 1024 } 1025 1026 1027 // #pragma mark - ClientInstallationInterface 1028 1029 1030 BPackageManager::ClientInstallationInterface::ClientInstallationInterface() 1031 : 1032 fDaemonClient() 1033 { 1034 } 1035 1036 1037 BPackageManager::ClientInstallationInterface::~ClientInstallationInterface() 1038 { 1039 } 1040 1041 1042 void 1043 BPackageManager::ClientInstallationInterface::InitInstalledRepository( 1044 InstalledRepository& repository) 1045 { 1046 const char* name = repository.InitialName(); 1047 BRepositoryBuilder(repository, name) 1048 .AddPackages(repository.Location(), name); 1049 } 1050 1051 1052 status_t 1053 BPackageManager::ClientInstallationInterface::PrepareTransaction( 1054 Transaction& transaction) 1055 { 1056 return fDaemonClient.CreateTransaction(transaction.Repository().Location(), 1057 transaction.ActivationTransaction(), 1058 transaction.TransactionDirectory()); 1059 } 1060 1061 1062 status_t 1063 BPackageManager::ClientInstallationInterface::CommitTransaction( 1064 Transaction& transaction, BCommitTransactionResult& _result) 1065 { 1066 return fDaemonClient.CommitTransaction(transaction.ActivationTransaction(), 1067 _result); 1068 } 1069 1070 1071 // #pragma mark - UserInteractionHandler 1072 1073 1074 BPackageManager::UserInteractionHandler::~UserInteractionHandler() 1075 { 1076 } 1077 1078 1079 void 1080 BPackageManager::UserInteractionHandler::HandleProblems() 1081 { 1082 throw BAbortedByUserException(); 1083 } 1084 1085 1086 void 1087 BPackageManager::UserInteractionHandler::ConfirmChanges(bool fromMostSpecific) 1088 { 1089 throw BAbortedByUserException(); 1090 } 1091 1092 1093 void 1094 BPackageManager::UserInteractionHandler::Warn(status_t error, 1095 const char* format, ...) 1096 { 1097 } 1098 1099 1100 void 1101 BPackageManager::UserInteractionHandler::ProgressPackageDownloadStarted( 1102 const char* packageName) 1103 { 1104 } 1105 1106 1107 void 1108 BPackageManager::UserInteractionHandler::ProgressPackageDownloadActive( 1109 const char* packageName, float completionPercentage, off_t bytes, 1110 off_t totalBytes) 1111 { 1112 } 1113 1114 1115 void 1116 BPackageManager::UserInteractionHandler::ProgressPackageDownloadComplete( 1117 const char* packageName) 1118 { 1119 } 1120 1121 1122 void 1123 BPackageManager::UserInteractionHandler::ProgressPackageChecksumStarted( 1124 const char* title) 1125 { 1126 } 1127 1128 1129 void 1130 BPackageManager::UserInteractionHandler::ProgressPackageChecksumComplete( 1131 const char* title) 1132 { 1133 } 1134 1135 1136 void 1137 BPackageManager::UserInteractionHandler::ProgressStartApplyingChanges( 1138 InstalledRepository& repository) 1139 { 1140 } 1141 1142 1143 void 1144 BPackageManager::UserInteractionHandler::ProgressTransactionCommitted( 1145 InstalledRepository& repository, const BCommitTransactionResult& result) 1146 { 1147 } 1148 1149 1150 void 1151 BPackageManager::UserInteractionHandler::ProgressApplyingChangesDone( 1152 InstalledRepository& repository) 1153 { 1154 } 1155 1156 1157 } // namespace BPrivate 1158 1159 } // namespace BManager 1160 1161 } // namespace BPackageKit 1162