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 COMMAND_CATEGORY_PACKAGES)
57
58
59 int
Execute(int argc,const char * const * argv)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