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