xref: /haiku/src/bin/package/command_create.cpp (revision 548149fe48f59cf27f6071e9629b8bbe2ad32c1f)
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 
43 	while (true) {
44 		static struct option sLongOptions[] = {
45 			{ "help", no_argument, 0, 'h' },
46 			{ "quiet", no_argument, 0, 'q' },
47 			{ "verbose", no_argument, 0, 'v' },
48 			{ 0, 0, 0, 0 }
49 		};
50 
51 		opterr = 0; // don't print errors
52 		int c = getopt_long(argc, (char**)argv, "+b0123456789C:hi:I:qv",
53 			sLongOptions, NULL);
54 		if (c == -1)
55 			break;
56 
57 		switch (c) {
58 			case '0':
59 			case '1':
60 			case '2':
61 			case '3':
62 			case '4':
63 			case '5':
64 			case '6':
65 			case '7':
66 			case '8':
67 			case '9':
68 				compressionLevel = c - '0';
69 				break;
70 
71 			case 'b':
72 				isBuildPackage = true;
73 				break;
74 
75 			case 'C':
76 				changeToDirectory = optarg;
77 				break;
78 
79 			case 'h':
80 				print_usage_and_exit(false);
81 				break;
82 
83 			case 'i':
84 				packageInfoFileName = optarg;
85 				break;
86 
87 			case 'I':
88 				installPath = optarg;
89 				break;
90 
91 			case 'q':
92 				quiet = true;
93 				break;
94 
95 			case 'v':
96 				verbose = true;
97 				break;
98 
99 			default:
100 				print_usage_and_exit(true);
101 				break;
102 		}
103 	}
104 
105 	// The remaining arguments is the package file, i.e. one more argument.
106 	if (optind + 1 != argc)
107 		print_usage_and_exit(true);
108 
109 	const char* packageFileName = argv[optind++];
110 
111 	// -I is only allowed when -b is given
112 	if (installPath != NULL && !isBuildPackage) {
113 		fprintf(stderr, "Error: \"-I\" is only allowed when \"-b\" is "
114 			"given.\n");
115 		return 1;
116 	}
117 
118 	// create package
119 	BPackageWriterParameters writerParameters;
120 	writerParameters.SetCompressionLevel(compressionLevel);
121 	if (compressionLevel == 0) {
122 		writerParameters.SetCompression(
123 			BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE);
124 	}
125 
126 	PackageWriterListener listener(verbose, quiet);
127 	BPackageWriter packageWriter(&listener);
128 	status_t result = packageWriter.Init(packageFileName, &writerParameters);
129 	if (result != B_OK)
130 		return 1;
131 
132 	// If a package info file has been specified explicitly, open it.
133 	int packageInfoFD = -1;
134 	if (packageInfoFileName != NULL) {
135 		packageInfoFD = open(packageInfoFileName, O_RDONLY);
136 		if (packageInfoFD < 0) {
137 			fprintf(stderr, "Error: Failed to open package info file \"%s\": "
138 				"%s\n", packageInfoFileName, strerror(errno));
139 			return 1;
140 		}
141 	}
142 
143 	// change directory, if requested
144 	if (changeToDirectory != NULL) {
145 		if (chdir(changeToDirectory) != 0) {
146 			listener.PrintError(
147 				"Error: Failed to change the current working directory to "
148 				"\"%s\": %s\n", changeToDirectory, strerror(errno));
149 			return 1;
150 		}
151 	}
152 
153 	if (isBuildPackage)
154 		packageWriter.SetCheckLicenses(false);
155 
156 	// set install path, if specified
157 	if (installPath != NULL) {
158 		result = packageWriter.SetInstallPath(installPath);
159 		if (result != B_OK) {
160 			fprintf(stderr, "Error: Failed to set the package install path: "
161 				"%s\n", strerror(result));
162 			return 1;
163 		}
164 	}
165 
166 	// add all files of the current directory, save for the .PackageInfo
167 	if (!isBuildPackage) {
168 		if (add_current_directory_entries(packageWriter, listener, true)
169 				!= B_OK) {
170 			return 1;
171 		}
172 	}
173 
174 	// add the .PackageInfo
175 	result = packageWriter.AddEntry(
176 		BPackageKit::BHPKG::B_HPKG_PACKAGE_INFO_FILE_NAME, packageInfoFD);
177 	if (result != B_OK)
178 		return 1;
179 
180 	// write the package
181 	result = packageWriter.Finish();
182 	if (result != B_OK)
183 		return 1;
184 
185 	if (verbose)
186 		printf("\nsuccessfully created package '%s'\n", packageFileName);
187 
188 	return 0;
189 }
190