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