xref: /haiku/src/kits/package/manager/RepositoryBuilder.cpp (revision 4b7e219688450694efc9d1890f83f816758c16d3)
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 <package/manager/RepositoryBuilder.h>
11 
12 #include <errno.h>
13 #include <dirent.h>
14 
15 #include <Entry.h>
16 #include <package/RepositoryCache.h>
17 #include <Path.h>
18 
19 #include <AutoDeleter.h>
20 
21 #include "PackageManagerUtils.h"
22 
23 
24 namespace BPackageKit {
25 
26 namespace BManager {
27 
28 namespace BPrivate {
29 
30 
31 namespace {
32 
33 
34 class PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
35 public:
36 	PackageInfoErrorListener(const char* context)
37 	{
38 	}
39 
40 	virtual void OnError(const BString& message, int line, int column)
41 	{
42 		fErrors << BString().SetToFormat("%s: parse error in line %d:%d: %s\n",
43 			fContext, line, column, message.String());
44 	}
45 
46 	const BString& Errors() const
47 	{
48 		return fErrors;
49 	}
50 
51 private:
52 	const char*	fContext;
53 	BString		fErrors;
54 };
55 
56 
57 } // unnamed namespace
58 
59 
60 BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository)
61 	:
62 	fRepository(repository),
63 	fErrorName(repository.Name()),
64 	fPackagePaths(NULL)
65 {
66 }
67 
68 
69 BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository,
70 	const BString& name, const BString& errorName)
71 	:
72 	fRepository(repository),
73 	fErrorName(errorName.IsEmpty() ? name : errorName),
74 	fPackagePaths(NULL)
75 {
76 	status_t error = fRepository.SetTo(name);
77 	if (error != B_OK)
78 		DIE(error, "failed to init %s repository", fErrorName.String());
79 }
80 
81 
82 BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository,
83 	const BRepositoryConfig& config)
84 	:
85 	fRepository(repository),
86 	fErrorName(fRepository.Name()),
87 	fPackagePaths(NULL)
88 {
89 	status_t error = fRepository.SetTo(config);
90 	if (error != B_OK)
91 		DIE(error, "failed to init %s repository", fErrorName.String());
92 }
93 
94 
95 BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository,
96 	const BRepositoryCache& cache, const BString& errorName)
97 	:
98 	fRepository(repository),
99 	fErrorName(errorName.IsEmpty() ? cache.Info().Name() : errorName),
100 	fPackagePaths(NULL)
101 {
102 	status_t error = fRepository.SetTo(cache);
103 	if (error != B_OK)
104 		DIE(error, "failed to init %s repository", fErrorName.String());
105 	fErrorName = fRepository.Name();
106 }
107 
108 
109 BRepositoryBuilder&
110 BRepositoryBuilder::SetPackagePathMap(BPackagePathMap* packagePaths)
111 {
112 	fPackagePaths = packagePaths;
113 	return *this;
114 }
115 
116 
117 BRepositoryBuilder&
118 BRepositoryBuilder::AddPackage(const BPackageInfo& info,
119 	const char* packageErrorName, BSolverPackage** _package)
120 {
121 	status_t error = fRepository.AddPackage(info, _package);
122 	if (error != B_OK) {
123 		DIE(error, "failed to add %s to %s repository",
124 			packageErrorName != NULL
125 				? packageErrorName
126 				: (BString("package ") << info.Name()).String(),
127 			fErrorName.String());
128 	}
129 	return *this;
130 }
131 
132 
133 BRepositoryBuilder&
134 BRepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package)
135 {
136 	// read a package info from the (HPKG or package info) file
137 	BPackageInfo packageInfo;
138 
139 	size_t pathLength = strlen(path);
140 	status_t error;
141 	PackageInfoErrorListener errorListener(path);
142 	if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) {
143 		// a package file
144 		error = packageInfo.ReadFromPackageFile(path);
145 	} else {
146 		// a package info file (supposedly)
147 		error = packageInfo.ReadFromConfigFile(BEntry(path, true),
148 			&errorListener);
149 	}
150 
151 	if (error != B_OK) {
152 		DIE_DETAILS(errorListener.Errors(), error,
153 			"failed to read package info from \"%s\"", path);
154 	}
155 
156 	// add the package
157 	BSolverPackage* package;
158 	AddPackage(packageInfo, path, &package);
159 
160 	// enter the package path in the path map, if given
161 	if (fPackagePaths != NULL)
162 		(*fPackagePaths)[package] = path;
163 
164 	if (_package != NULL)
165 		*_package = package;
166 
167 	return *this;
168 }
169 
170 
171 BRepositoryBuilder&
172 BRepositoryBuilder::AddPackages(BPackageInstallationLocation location,
173 	const char* locationErrorName)
174 {
175 	status_t error = fRepository.AddPackages(location);
176 	if (error != B_OK) {
177 		DIE(error, "failed to add %s packages to %s repository",
178 			locationErrorName, fErrorName.String());
179 	}
180 	return *this;
181 }
182 
183 
184 BRepositoryBuilder&
185 BRepositoryBuilder::AddPackagesDirectory(const char* path)
186 {
187 	// open directory
188 	DIR* dir = opendir(path);
189 	if (dir == NULL)
190 		DIE(errno, "failed to open package directory \"%s\"", path);
191 	CObjectDeleter<DIR, int> dirCloser(dir, &closedir);
192 
193 	// iterate through directory entries
194 	while (dirent* entry = readdir(dir)) {
195 		// skip "." and ".."
196 		const char* name = entry->d_name;
197 		if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
198 			continue;
199 
200 		// stat() the entry and skip any non-file
201 		BPath entryPath;
202 		status_t error = entryPath.SetTo(path, name);
203 		if (error != B_OK)
204 			DIE(errno, "failed to construct path");
205 
206 		struct stat st;
207 		if (stat(entryPath.Path(), &st) != 0)
208 			DIE(errno, "failed to stat() %s", entryPath.Path());
209 
210 		if (!S_ISREG(st.st_mode))
211 			continue;
212 
213 		AddPackage(entryPath.Path());
214 	}
215 
216 	return *this;
217 }
218 
219 
220 BRepositoryBuilder&
221 BRepositoryBuilder::AddToSolver(BSolver* solver, bool isInstalled)
222 {
223 	fRepository.SetInstalled(isInstalled);
224 
225 	status_t error = solver->AddRepository(&fRepository);
226 	if (error != B_OK) {
227 		DIE(error, "failed to add %s repository to solver",
228 			fErrorName.String());
229 	}
230 	return *this;
231 }
232 
233 
234 }	// namespace BPrivate
235 
236 }	// namespace BManager
237 
238 }	// namespace BPackageKit
239