xref: /haiku/src/bin/package_repo/command_create.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
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 
25 using BPackageKit::BHPKG::BRepositoryWriterListener;
26 using BPackageKit::BHPKG::BRepositoryWriter;
27 using namespace BPackageKit;
28 
29 
30 class RepositoryWriterListener	: public BRepositoryWriterListener {
31 public:
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 
108 private:
109 	bool fVerbose;
110 	bool fQuiet;
111 };
112 
113 
114 int
115 command_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