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 <getopt.h> 11 #include <package/manager/Exceptions.h> 12 #include <ObjectList.h> 13 #include <package/solver/SolverPackage.h> 14 #include <package/solver/SolverPackageSpecifier.h> 15 #include <package/solver/SolverPackageSpecifierList.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 19 #include "Command.h" 20 #include "pkgman.h" 21 #include "PackageManager.h" 22 23 24 // TODO: internationalization! 25 26 27 using namespace BPackageKit; 28 using namespace BPackageKit::BPrivate; 29 using namespace BPackageKit::BManager::BPrivate; 30 31 32 static const char* const kShortUsage = 33 " %command% <package> ...\n" 34 " Installs one or more packages.\n"; 35 36 static const char* const kLongUsage = 37 "Usage: %program% %command% <package> ...\n" 38 "Installs the specified packages. A <package> argument can be a search\n" 39 "string by which the package is looked up in a remote repository or a\n" 40 "path to a local package file. In the latter case the file is copied.\n" 41 "\n" 42 "Options:\n" 43 " --debug <level>\n" 44 " Print debug output. <level> should be between 0 (no debug output,\n" 45 " the default) and 10 (most debug output).\n" 46 " -H, --home\n" 47 " Install the packages in the user's home directory. Default is to\n" 48 " install in the system directory.\n" 49 " -y\n" 50 " Non-interactive mode. Automatically confirm changes, but fail when\n" 51 " encountering problems.\n" 52 "\n"; 53 54 55 DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage, 56 kCommandCategoryPackages) 57 58 59 int 60 InstallCommand::Execute(int argc, const char* const* argv) 61 { 62 BPackageInstallationLocation location 63 = B_PACKAGE_INSTALLATION_LOCATION_SYSTEM; 64 bool interactive = true; 65 66 while (true) { 67 static struct option sLongOptions[] = { 68 { "debug", required_argument, 0, OPTION_DEBUG }, 69 { "help", no_argument, 0, 'h' }, 70 { "home", no_argument, 0, 'H' }, 71 { 0, 0, 0, 0 } 72 }; 73 74 opterr = 0; // don't print errors 75 int c = getopt_long(argc, (char**)argv, "hHy", sLongOptions, NULL); 76 if (c == -1) 77 break; 78 79 if (fCommonOptions.HandleOption(c)) 80 continue; 81 82 switch (c) { 83 case 'h': 84 PrintUsageAndExit(false); 85 break; 86 87 case 'H': 88 location = B_PACKAGE_INSTALLATION_LOCATION_HOME; 89 break; 90 91 case 'y': 92 interactive = false; 93 break; 94 95 default: 96 PrintUsageAndExit(true); 97 break; 98 } 99 } 100 101 // The remaining arguments are the packages to be installed. 102 if (argc < optind + 1) 103 PrintUsageAndExit(true); 104 105 int packageCount = argc - optind; 106 const char* const* packages = argv + optind; 107 108 // perform the installation 109 PackageManager packageManager(location, interactive); 110 packageManager.SetDebugLevel(fCommonOptions.DebugLevel()); 111 try { 112 packageManager.Install(packages, packageCount); 113 } catch (BNothingToDoException&) { 114 // Output already installed packages 115 BSolverPackageSpecifierList packagesToInstall; 116 if (!packagesToInstall.AppendSpecifiers(packages, packageCount)) 117 throw std::bad_alloc(); 118 // Find the installed packages that match the specification 119 const BSolverPackageSpecifier* unmatchedSpecifier; 120 BObjectList<BSolverPackage> installedPackages; 121 packageManager.Solver()->FindPackages(packagesToInstall, 122 BSolver::B_FIND_INSTALLED_ONLY, 123 installedPackages, &unmatchedSpecifier); 124 125 for (int32 i = 0; BSolverPackage* package = installedPackages.ItemAt(i); 126 i++) { 127 BString repository; 128 if (dynamic_cast<PackageManager::MiscLocalRepository*>( 129 package->Repository()) != NULL) 130 repository = "local file"; 131 else 132 repository.SetToFormat( 133 "repository %s", package->Repository()->Name().String()); 134 fprintf(stderr, "%s from %s is already installed.\n", 135 package->VersionedName().String(), 136 repository.String()); 137 } 138 throw; 139 } 140 141 return 0; 142 } 143