1/*
2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <dirent.h>
8#include <errno.h>
9#include <getopt.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <Entry.h>
15#include <Path.h>
16
17#include <package/hpkg/HPKGDefs.h>
18#include <package/hpkg/RepositoryWriter.h>
19#include <package/PackageInfo.h>
20#include <package/RepositoryInfo.h>
21
22#include "package.h"
23#include "StandardErrorOutput.h"
24
25
26using BPackageKit::BHPKG::BRepositoryWriterListener;
27using BPackageKit::BHPKG::BRepositoryWriter;
28using namespace BPackageKit;
29
30
31class RepositoryWriterListener	: public BRepositoryWriterListener {
32public:
33	RepositoryWriterListener(bool verbose, bool quiet)
34		: fVerbose(verbose), fQuiet(quiet)
35	{
36	}
37
38	virtual void PrintErrorVarArgs(const char* format, va_list args)
39	{
40		vfprintf(stderr, format, args);
41	}
42
43	virtual void OnPackageAdded(const BPackageInfo& packageInfo)
44	{
45		if (fQuiet)
46			return;
47
48		printf("%s (%s)\n", packageInfo.Name().String(),
49			packageInfo.Version().ToString().String());
50		if (fVerbose) {
51			printf("\tsummary:  %s\n", packageInfo.Summary().String());
52			printf("\tvendor:   %s\n", packageInfo.Vendor().String());
53			printf("\tpackager: %s\n", packageInfo.Packager().String());
54			printf("\tchecksum: %s\n", packageInfo.Checksum().String());
55			if (uint32 flags = packageInfo.Flags()) {
56				printf("\tflags:\n");
57				if ((flags & B_PACKAGE_FLAG_APPROVE_LICENSE) != 0)
58					printf("\t\tapprove_license\n");
59				if ((flags & B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0)
60					printf("\t\tsystem_package\n");
61			}
62		} else
63			printf("\tchecksum: %s\n", packageInfo.Checksum().String());
64	}
65
66	virtual void OnRepositoryInfoSectionDone(uint32 uncompressedSize)
67	{
68		if (fQuiet || !fVerbose)
69			return;
70
71		printf("----- Repository Info Section --------------------\n");
72		printf("repository info size:    %10lu (uncompressed)\n",
73			uncompressedSize);
74	}
75
76	virtual void OnPackageAttributesSectionDone(uint32 stringCount,
77		uint32 uncompressedSize)
78	{
79		if (fQuiet || !fVerbose)
80			return;
81
82		printf("----- Package Attribute Section -------------------\n");
83		printf("string count:            %10lu\n", stringCount);
84		printf("package attributes size: %10lu (uncompressed)\n",
85			uncompressedSize);
86	}
87
88	virtual void OnRepositoryDone(uint32 headerSize, uint32 repositoryInfoSize,
89		uint32 licenseCount, uint32 packageCount, uint32 packageAttributesSize,
90		uint64 totalSize)
91	{
92		if (fQuiet)
93			return;
94
95		printf("----- Package Repository Info -----\n");
96		if (fVerbose)
97			printf("embedded license count   %10lu\n", licenseCount);
98		printf("package count            %10lu\n", packageCount);
99		printf("-----------------------------------\n");
100		printf("header size:             %10lu\n", headerSize);
101		printf("repository header size:  %10lu\n", repositoryInfoSize);
102		printf("package attributes size: %10lu\n", packageAttributesSize);
103		printf("total size:              %10llu\n", totalSize);
104		printf("-----------------------------------\n");
105	}
106
107private:
108	bool fVerbose;
109	bool fQuiet;
110};
111
112
113int
114command_create(int argc, const char* const* argv)
115{
116	const char* changeToDirectory = NULL;
117	bool quiet = false;
118	bool verbose = false;
119
120	while (true) {
121		static struct option sLongOptions[] = {
122			{ "help", no_argument, 0, 'h' },
123			{ "quiet", no_argument, 0, 'q' },
124			{ "verbose", no_argument, 0, 'v' },
125			{ 0, 0, 0, 0 }
126		};
127
128		opterr = 0; // don't print errors
129		int c = getopt_long(argc, (char**)argv, "+C:hqv", sLongOptions, NULL);
130		if (c == -1)
131			break;
132
133		switch (c) {
134			case 'C':
135				changeToDirectory = optarg;
136				break;
137
138			case 'h':
139				print_usage_and_exit(false);
140				break;
141
142			case 'q':
143				quiet = true;
144				break;
145
146			case 'v':
147				verbose = true;
148				break;
149
150			default:
151				print_usage_and_exit(true);
152				break;
153		}
154	}
155
156	// The remaining arguments are the repository info file plus one or more
157	// package files, i.e. at least two more arguments.
158	if (optind + 2 >= argc)
159		print_usage_and_exit(true);
160
161	const char* repositoryInfoFileName = argv[optind++];
162	const char* const* packageFileNames = argv + optind;
163
164	RepositoryWriterListener listener(verbose, quiet);
165
166	BEntry repositoryInfoEntry(repositoryInfoFileName);
167	if (!repositoryInfoEntry.Exists()) {
168		listener.PrintError(
169			"Error: given repository-info file '%s' doesn't exist!\n",
170			repositoryInfoFileName);
171		return 1;
172	}
173
174	// determine path for 'repo' file from given info file
175	BEntry repositoryParentEntry;
176	repositoryInfoEntry.GetParent(&repositoryParentEntry);
177	BPath repositoryPath;
178	if (repositoryParentEntry.GetPath(&repositoryPath) != B_OK) {
179		listener.PrintError(
180			"Error: can't determine path of given repository-info file!\n");
181		return 1;
182	}
183	repositoryPath.Append("repo");
184
185	// create repository
186	BRepositoryInfo repositoryInfo(repositoryInfoEntry);
187	status_t result = repositoryInfo.InitCheck();
188	if (result != B_OK) {
189		listener.PrintError(
190			"Error: can't parse given repository-info file : %s\n",
191			strerror(result));
192		return 1;
193	}
194	BRepositoryWriter repositoryWriter(&listener, &repositoryInfo);
195	if ((result = repositoryWriter.Init(repositoryPath.Path())) != B_OK) {
196		listener.PrintError("Error: can't initialize repository-writer : %s\n",
197			strerror(result));
198		return 1;
199	}
200
201	// change directory, if requested
202	if (changeToDirectory != NULL) {
203		if (chdir(changeToDirectory) != 0) {
204			listener.PrintError(
205				"Error: Failed to change the current working directory to "
206				"\"%s\": %s\n", changeToDirectory, strerror(errno));
207			return 1;
208		}
209	}
210
211	// add all given package files
212	for (int i = 0; i < argc - optind; ++i) {
213		if (verbose)
214			printf("reading package '%s' ...\n", packageFileNames[i]);
215		BEntry entry(packageFileNames[i]);
216		result = repositoryWriter.AddPackage(entry);
217		if (result != B_OK)
218			return 1;
219	}
220
221	// write the repository
222	result = repositoryWriter.Finish();
223	if (result != B_OK)
224		return 1;
225
226	if (verbose) {
227		printf("\nsuccessfully created repository '%s'\n",
228			repositoryPath.Path());
229	}
230
231	return 0;
232}
233