1/*
2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <ctype.h>
8#include <errno.h>
9#include <getopt.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <package/hpkg/PackageInfoAttributeValue.h>
15#include <package/hpkg/RepositoryContentHandler.h>
16#include <package/hpkg/RepositoryReader.h>
17#include <package/PackageInfo.h>
18#include <package/RepositoryInfo.h>
19
20#include "package.h"
21#include "StandardErrorOutput.h"
22
23
24using namespace BPackageKit::BHPKG;
25using namespace BPackageKit;
26
27struct RepositoryContentListHandler : BRepositoryContentHandler {
28	RepositoryContentListHandler(bool verbose)
29		:
30		fLevel(0),
31		fVerbose(verbose)
32	{
33	}
34
35	virtual status_t HandleEntry(BPackageEntry* entry)
36	{
37		return B_OK;
38	}
39
40	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
41		BPackageEntryAttribute* attribute)
42	{
43		return B_OK;
44	}
45
46	virtual status_t HandleEntryDone(BPackageEntry* entry)
47	{
48		return B_OK;
49	}
50
51	virtual status_t HandlePackageAttribute(
52		const BPackageInfoAttributeValue& value)
53	{
54		switch (value.attributeID) {
55			case B_PACKAGE_INFO_NAME:
56				if (fVerbose) {
57					printf("package-attributes:\n");
58					printf("\tname: %s\n", value.string);
59				} else
60					printf("package: %s", value.string);
61				break;
62
63			case B_PACKAGE_INFO_SUMMARY:
64				if (fVerbose)
65					printf("\tsummary: %s\n", value.string);
66				break;
67
68			case B_PACKAGE_INFO_DESCRIPTION:
69				if (fVerbose)
70					printf("\tdescription: %s\n", value.string);
71				break;
72
73			case B_PACKAGE_INFO_VENDOR:
74				if (fVerbose)
75					printf("\tvendor: %s\n", value.string);
76				break;
77
78			case B_PACKAGE_INFO_PACKAGER:
79				if (fVerbose)
80					printf("\tpackager: %s\n", value.string);
81				break;
82
83			case B_PACKAGE_INFO_FLAGS:
84				if (value.unsignedInt == 0 || !fVerbose)
85					break;
86				printf("\tflags:\n");
87				if ((value.unsignedInt & B_PACKAGE_FLAG_APPROVE_LICENSE) != 0)
88					printf("\t\tapprove_license\n");
89				if ((value.unsignedInt & B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0)
90					printf("\t\tsystem_package\n");
91				break;
92
93			case B_PACKAGE_INFO_ARCHITECTURE:
94				if (fVerbose) {
95					printf("\tarchitecture: %s\n",
96						BPackageInfo::kArchitectureNames[value.unsignedInt]);
97				}
98				break;
99
100			case B_PACKAGE_INFO_VERSION:
101				if (!fVerbose)
102					printf("(");
103				_PrintPackageVersion(value.version);
104				if (!fVerbose)
105					printf(")\n");
106				break;
107
108			case B_PACKAGE_INFO_COPYRIGHTS:
109				if (fVerbose)
110					printf("\tcopyright: %s\n", value.string);
111				break;
112
113			case B_PACKAGE_INFO_LICENSES:
114				if (fVerbose)
115					printf("\tlicense: %s\n", value.string);
116				break;
117
118			case B_PACKAGE_INFO_URLS:
119				if (fVerbose)
120					printf("\tURL: %s\n", value.string);
121				break;
122
123			case B_PACKAGE_INFO_SOURCE_URLS:
124				if (fVerbose)
125					printf("\tsource URL: %s\n", value.string);
126				break;
127
128			case B_PACKAGE_INFO_PROVIDES:
129				if (!fVerbose)
130					break;
131				printf("\tprovides: %s", value.resolvable.name);
132				if (value.resolvable.haveVersion) {
133					printf(" = ");
134					_PrintPackageVersion(value.resolvable.version);
135				}
136				printf("\n");
137				break;
138
139			case B_PACKAGE_INFO_REQUIRES:
140				if (!fVerbose)
141					break;
142				printf("\trequires: %s", value.resolvableExpression.name);
143				if (value.resolvableExpression.haveOpAndVersion) {
144					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
145							value.resolvableExpression.op]);
146					_PrintPackageVersion(value.resolvableExpression.version);
147				}
148				printf("\n");
149				break;
150
151			case B_PACKAGE_INFO_SUPPLEMENTS:
152				if (!fVerbose)
153					break;
154				printf("\tsupplements: %s", value.resolvableExpression.name);
155				if (value.resolvableExpression.haveOpAndVersion) {
156					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
157							value.resolvableExpression.op]);
158					_PrintPackageVersion(value.resolvableExpression.version);
159				}
160				printf("\n");
161				break;
162
163			case B_PACKAGE_INFO_CONFLICTS:
164				if (!fVerbose)
165					break;
166				printf("\tconflicts: %s", value.resolvableExpression.name);
167				if (value.resolvableExpression.haveOpAndVersion) {
168					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
169							value.resolvableExpression.op]);
170					_PrintPackageVersion(value.resolvableExpression.version);
171				}
172				printf("\n");
173				break;
174
175			case B_PACKAGE_INFO_FRESHENS:
176				if (!fVerbose)
177					break;
178				printf("\tfreshens: %s", value.resolvableExpression.name);
179				if (value.resolvableExpression.haveOpAndVersion) {
180					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
181							value.resolvableExpression.op]);
182					_PrintPackageVersion(value.resolvableExpression.version);
183				}
184				printf("\n");
185				break;
186
187			case B_PACKAGE_INFO_REPLACES:
188				if (!fVerbose)
189					break;
190				printf("\treplaces: %s\n", value.string);
191				break;
192
193			case B_PACKAGE_INFO_CHECKSUM:
194				printf("\tchecksum: %s\n", value.string);
195				break;
196
197			default:
198				printf(
199					"*** Invalid package attribute section: unexpected "
200					"package attribute id %d encountered\n", value.attributeID);
201				return B_BAD_DATA;
202		}
203
204		return B_OK;
205	}
206
207	virtual status_t HandleRepositoryInfo(const BRepositoryInfo& repositoryInfo)
208	{
209		printf("repository-info:\n");
210		printf("\tname: %s\n", repositoryInfo.Name().String());
211		printf("\tsummary: %s\n", repositoryInfo.Summary().String());
212		printf("\turl: %s\n", repositoryInfo.OriginalBaseURL().String());
213		printf("\tvendor: %s\n", repositoryInfo.Vendor().String());
214		printf("\tpriority: %u\n", repositoryInfo.Priority());
215		printf("\tarchitecture: %s\n",
216			BPackageInfo::kArchitectureNames[repositoryInfo.Architecture()]);
217		const BStringList licenseNames = repositoryInfo.LicenseNames();
218		if (!licenseNames.IsEmpty()) {
219			printf("\tlicenses:\n");
220			for (int i = 0; i < licenseNames.CountStrings(); ++i)
221				printf("\t\t%s\n", licenseNames.StringAt(i).String());
222		}
223
224		return B_OK;
225	}
226
227	virtual void HandleErrorOccurred()
228	{
229	}
230
231private:
232	static void _PrintPackageVersion(const BPackageVersionData& version)
233	{
234		printf("%s", version.major);
235		if (version.minor != NULL && version.minor[0] != '\0')
236			printf(".%s", version.minor);
237		if (version.micro != NULL && version.micro[0] != '\0')
238			printf(".%s", version.micro);
239		if (version.preRelease != NULL && version.preRelease[0] != '\0')
240			printf("-%s", version.preRelease);
241		if (version.release > 0)
242			printf("-%d", version.release);
243	}
244
245private:
246	int		fLevel;
247	bool	fVerbose;
248};
249
250
251int
252command_list(int argc, const char* const* argv)
253{
254	bool verbose = false;
255
256	while (true) {
257		static struct option sLongOptions[] = {
258			{ "help", no_argument, 0, 'h' },
259			{ "verbose", no_argument, 0, 'v' },
260			{ 0, 0, 0, 0 }
261		};
262
263		opterr = 0; // don't print errors
264		int c = getopt_long(argc, (char**)argv, "+hv", sLongOptions, NULL);
265		if (c == -1)
266			break;
267
268		switch (c) {
269			case 'h':
270				print_usage_and_exit(false);
271				break;
272
273			case 'v':
274				verbose = true;
275				break;
276
277			default:
278				print_usage_and_exit(true);
279				break;
280		}
281	}
282
283	// One argument should remain -- the repository file name.
284	if (optind + 1 != argc)
285		print_usage_and_exit(true);
286
287	const char* repositoryFileName = argv[optind++];
288
289	// open repository
290	StandardErrorOutput errorOutput;
291	BRepositoryReader repositoryReader(&errorOutput);
292	status_t error = repositoryReader.Init(repositoryFileName);
293	if (error != B_OK)
294		return 1;
295
296	// list
297	RepositoryContentListHandler handler(verbose);
298	error = repositoryReader.ParseContent(&handler);
299	if (error != B_OK)
300		return 1;
301
302	return 0;
303}
304