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