2 * Copyright 2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Ingo Weinhold <ingo_weinhold@gmx.de>
16 #include <package/manager/RepositoryBuilder.h>
17 #include <package/solver/SolverPackageSpecifier.h>
18 #include <package/solver/SolverPackageSpecifierList.h>
19 #include <package/solver/SolverProblem.h>
20 #include <package/solver/SolverResult.h>
22 #include <AutoDeleter.h>
28 // TODO: internationalization!
31 using namespace BPackageKit
;
32 using BManager::BPrivate::BPackagePathMap
;
33 using BManager::BPrivate::BRepositoryBuilder
;
36 static const char* const kShortUsage
=
37 " %command% <package> ... <repository> [ <priority> ] ...\n"
38 " Resolves all packages the given packages depend on.\n";
40 static const char* const kLongUsage
=
41 "Usage: %program% %command% <package> ... <repository> [ <priority> ] ...\n"
42 "Resolves and lists all packages the given packages depend on. Fails, if\n"
43 "not all dependencies could be resolved.\n"
47 " Print debug output. <level> should be between 0 (no debug output,\n"
48 " the default) and 10 (most debug output).\n"
52 " The HPKG or package info file of the package for which the\n"
53 " dependencies shall be resolved. Multiple files can be specified.\n"
55 " Path to a directory containing packages from which the package's\n"
56 " dependencies shall be resolved. Multiple directories can be\n"
59 " Can follow a <repository> to specify the priority of that\n"
60 " repository. The default priority is 0.\n"
64 DEFINE_COMMAND(ResolveDependenciesCommand
, "resolve-dependencies", kShortUsage
,
65 kLongUsage
, kCommandCategoryOther
)
69 check_problems(BSolver
* solver
, const char* errorContext
)
71 if (solver
->HasProblems()) {
73 "Encountered problems %s:\n", errorContext
);
75 int32 problemCount
= solver
->CountProblems();
76 for (int32 i
= 0; i
< problemCount
; i
++) {
77 printf(" %" B_PRId32
": %s\n", i
+ 1,
78 solver
->ProblemAt(i
)->ToString().String());
86 verify_result(const BSolverResult
& result
,
87 const BPackagePathMap
& specifiedPackagePaths
)
91 status_t error
= BSolver::Create(solver
);
93 DIE(error
, "failed to create solver");
95 // Add an installation repository and add all of the result packages save
96 // the specified packages.
97 BSolverRepository installation
;
98 BRepositoryBuilder
installationBuilder(installation
, "installation");
100 for (int32 i
= 0; const BSolverResultElement
* element
= result
.ElementAt(i
);
102 BSolverPackage
* package
= element
->Package();
103 if (specifiedPackagePaths
.find(package
) == specifiedPackagePaths
.end())
104 installationBuilder
.AddPackage(package
->Info());
106 installationBuilder
.AddToSolver(solver
, true);
109 error
= solver
->VerifyInstallation();
111 DIE(error
, "failed to verify computed package dependencies");
113 check_problems(solver
, "verifying computed package dependencies");
118 ResolveDependenciesCommand::Execute(int argc
, const char* const* argv
)
121 static struct option sLongOptions
[] = {
122 { "debug", required_argument
, 0, OPTION_DEBUG
},
123 { "help", no_argument
, 0, 'h' },
127 opterr
= 0; // don't print errors
128 int c
= getopt_long(argc
, (char**)argv
, "h", sLongOptions
, NULL
);
132 if (fCommonOptions
.HandleOption(c
))
137 PrintUsageAndExit(false);
141 PrintUsageAndExit(true);
146 // The remaining arguments are the package (info) files and the repository
147 // directories (at least one), optionally with priorities.
148 if (argc
< optind
+ 2)
149 PrintUsageAndExit(true);
151 // Determine where the package list ends and the repository list starts.
152 const char* const* specifiedPackages
= argv
+ optind
;
153 for (; optind
< argc
; optind
++) {
154 const char* path
= argv
[optind
];
156 if (stat(path
, &st
) != 0)
157 DIE(errno
, "failed to stat() \"%s\"", path
);
159 if (S_ISDIR(st
.st_mode
))
163 const char* const* repositoryDirectories
= argv
+ optind
;
164 int repositoryDirectoryCount
= argc
- optind
;
165 int specifiedPackageCount
= repositoryDirectories
- specifiedPackages
;
169 status_t error
= BSolver::Create(solver
);
171 DIE(error
, "failed to create solver");
173 solver
->SetDebugLevel(fCommonOptions
.DebugLevel());
176 BPackagePathMap packagePaths
;
177 BObjectList
<BSolverRepository
> repositories(10, true);
178 int32 repositoryIndex
= 0;
179 for (int i
= 0; i
< repositoryDirectoryCount
; i
++, repositoryIndex
++) {
180 const char* directoryPath
= repositoryDirectories
[i
];
182 BSolverRepository
* repository
= new(std::nothrow
) BSolverRepository
;
183 if (repository
== NULL
|| !repositories
.AddItem(repository
))
184 DIE(B_NO_MEMORY
, "failed to create repository");
187 if (i
+ 1 < repositoryDirectoryCount
) {
189 long priority
= strtol(repositoryDirectories
[i
+ 1], &end
, 0);
191 repository
->SetPriority((uint8
)priority
);
196 BRepositoryBuilder(*repository
,
197 BString("repository") << repositoryIndex
)
198 .SetPackagePathMap(&packagePaths
)
199 .AddPackagesDirectory(directoryPath
)
200 .AddToSolver(solver
);
203 // add a repository with only the specified packages
204 BPackagePathMap specifiedPackagePaths
;
205 BSolverRepository dummyRepository
;
207 BRepositoryBuilder
builder(dummyRepository
, "dummy",
208 "specified packages");
209 builder
.SetPackagePathMap(&specifiedPackagePaths
);
211 for (int i
= 0; i
< specifiedPackageCount
; i
++)
212 builder
.AddPackage(specifiedPackages
[i
]);
214 builder
.AddToSolver(solver
);
218 BSolverPackageSpecifierList packagesToInstall
;
219 for (BPackagePathMap::const_iterator it
= specifiedPackagePaths
.begin();
220 it
!= specifiedPackagePaths
.end(); ++it
) {
221 if (!packagesToInstall
.AppendSpecifier(it
->first
))
222 DIE(B_NO_MEMORY
, "failed to add specified package");
225 error
= solver
->Install(packagesToInstall
);
227 DIE(error
, "failed to resolve package dependencies");
229 check_problems(solver
, "resolving package dependencies");
231 BSolverResult result
;
232 error
= solver
->GetResult(result
);
234 DIE(error
, "failed to resolve package dependencies");
236 // Verify that the resolved packages don't depend on the specified package.
237 verify_result(result
, specifiedPackagePaths
);
240 for (int32 i
= 0; const BSolverResultElement
* element
= result
.ElementAt(i
);
242 // skip the specified package
243 BSolverPackage
* package
= element
->Package();
244 if (specifiedPackagePaths
.find(package
) != specifiedPackagePaths
.end())
247 // resolve and print the path
248 BPackagePathMap::const_iterator it
= packagePaths
.find(package
);
249 if (it
== packagePaths
.end()) {
250 DIE(B_ERROR
, "ugh, no package %p (%s-%s) not in package path map",
251 package
, package
->Info().Name().String(),
252 package
->Info().Version().ToString().String());
255 printf("%s\n", it
->second
.String());