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