xref: /haiku/src/bin/pkgman/command_install.cpp (revision 5ac9b506412b11afb993bb52d161efe7666958a5)
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