xref: /haiku/src/bin/package/command_create.cpp (revision 5ac9b506412b11afb993bb52d161efe7666958a5)
1 /*
2  * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <getopt.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 
16 #include <Entry.h>
17 
18 #include <package/PackageInfo.h>
19 #include <package/hpkg/HPKGDefs.h>
20 #include <package/hpkg/PackageWriter.h>
21 
22 #include "package.h"
23 #include "PackageWriterListener.h"
24 #include "PackageWritingUtils.h"
25 
26 
27 using BPackageKit::BHPKG::BPackageWriter;
28 using BPackageKit::BHPKG::BPackageWriterListener;
29 using BPackageKit::BHPKG::BPackageWriterParameters;
30 
31 
32 int
33 command_create(int argc, const char* const* argv)
34 {
35 	const char* changeToDirectory = NULL;
36 	const char* packageInfoFileName = NULL;
37 	const char* installPath = NULL;
38 	bool isBuildPackage = false;
39 	bool quiet = false;
40 	bool verbose = false;
41 	int32 compressionLevel = BPackageKit::BHPKG::B_HPKG_COMPRESSION_LEVEL_BEST;
42 	int32 compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_ZLIB;
43 
44 	while (true) {
45 		static struct option sLongOptions[] = {
46 			{ "help", no_argument, 0, 'h' },
47 			{ "quiet", no_argument, 0, 'q' },
48 			{ "verbose", no_argument, 0, 'v' },
49 			{ 0, 0, 0, 0 }
50 		};
51 
52 		opterr = 0; // don't print errors
53 		int c = getopt_long(argc, (char**)argv, "+b0123456789C:hi:I:qvz",
54 			sLongOptions, NULL);
55 		if (c == -1)
56 			break;
57 
58 		switch (c) {
59 			case '0':
60 			case '1':
61 			case '2':
62 			case '3':
63 			case '4':
64 			case '5':
65 			case '6':
66 			case '7':
67 			case '8':
68 			case '9':
69 				compressionLevel = c - '0';
70 				break;
71 
72 			case 'b':
73 				isBuildPackage = true;
74 				break;
75 
76 			case 'C':
77 				changeToDirectory = optarg;
78 				break;
79 
80 			case 'h':
81 				print_usage_and_exit(false);
82 				break;
83 
84 			case 'i':
85 				packageInfoFileName = optarg;
86 				break;
87 
88 			case 'I':
89 				installPath = optarg;
90 				break;
91 
92 			case 'q':
93 				quiet = true;
94 				break;
95 
96 			case 'v':
97 				verbose = true;
98 				break;
99 
100 			case 'z':
101 				compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_ZSTD;
102 				break;
103 
104 			default:
105 				print_usage_and_exit(true);
106 				break;
107 		}
108 	}
109 
110 	// The remaining arguments is the package file, i.e. one more argument.
111 	if (optind + 1 != argc)
112 		print_usage_and_exit(true);
113 
114 	const char* packageFileName = argv[optind++];
115 
116 	// -I is only allowed when -b is given
117 	if (installPath != NULL && !isBuildPackage) {
118 		fprintf(stderr, "Error: \"-I\" is only allowed when \"-b\" is "
119 			"given.\n");
120 		return 1;
121 	}
122 
123 	// create package
124 	BPackageWriterParameters writerParameters;
125 	writerParameters.SetCompressionLevel(compressionLevel);
126 	if (compressionLevel == 0) {
127 		writerParameters.SetCompression(
128 			BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE);
129 	}
130 
131 	if (compressionLevel == 0)
132 		compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE;
133 	writerParameters.SetCompression(compression);
134 
135 	PackageWriterListener listener(verbose, quiet);
136 	BPackageWriter packageWriter(&listener);
137 	status_t result = packageWriter.Init(packageFileName, &writerParameters);
138 	if (result != B_OK)
139 		return 1;
140 
141 	// If a package info file has been specified explicitly, open it.
142 	int packageInfoFD = -1;
143 	if (packageInfoFileName != NULL) {
144 		packageInfoFD = open(packageInfoFileName, O_RDONLY);
145 		if (packageInfoFD < 0) {
146 			fprintf(stderr, "Error: Failed to open package info file \"%s\": "
147 				"%s\n", packageInfoFileName, strerror(errno));
148 			return 1;
149 		}
150 	}
151 
152 	// change directory, if requested
153 	if (changeToDirectory != NULL) {
154 		if (chdir(changeToDirectory) != 0) {
155 			listener.PrintError(
156 				"Error: Failed to change the current working directory to "
157 				"\"%s\": %s\n", changeToDirectory, strerror(errno));
158 			return 1;
159 		}
160 	}
161 
162 	if (isBuildPackage)
163 		packageWriter.SetCheckLicenses(false);
164 
165 	// set install path, if specified
166 	if (installPath != NULL) {
167 		result = packageWriter.SetInstallPath(installPath);
168 		if (result != B_OK) {
169 			fprintf(stderr, "Error: Failed to set the package install path: "
170 				"%s\n", strerror(result));
171 			return 1;
172 		}
173 	}
174 
175 	// add all files of the current directory, save for the .PackageInfo
176 	if (!isBuildPackage) {
177 		if (add_current_directory_entries(packageWriter, listener, true)
178 				!= B_OK) {
179 			return 1;
180 		}
181 	}
182 
183 	// add the .PackageInfo
184 	result = packageWriter.AddEntry(
185 		BPackageKit::BHPKG::B_HPKG_PACKAGE_INFO_FILE_NAME, packageInfoFD);
186 	if (result != B_OK)
187 		return 1;
188 
189 	// write the package
190 	result = packageWriter.Finish();
191 	if (result != B_OK)
192 		return 1;
193 
194 	if (verbose)
195 		printf("\nsuccessfully created package '%s'\n", packageFileName);
196 
197 	return 0;
198 }
199