xref: /haiku/src/bin/package/command_add.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
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 namespace BPackageKit::BHPKG;
28 
29 
30 int
31 command_add(int argc, const char* const* argv)
32 {
33 	const char* changeToDirectory = NULL;
34 	const char* packageInfoFileName = NULL;
35 	bool quiet = false;
36 	bool verbose = false;
37 	bool force = false;
38 	int32 compressionLevel = BPackageKit::BHPKG::B_HPKG_COMPRESSION_LEVEL_BEST;
39 
40 	while (true) {
41 		static struct option sLongOptions[] = {
42 			{ "help", no_argument, 0, 'h' },
43 			{ "quiet", no_argument, 0, 'q' },
44 			{ "verbose", no_argument, 0, 'v' },
45 			{ 0, 0, 0, 0 }
46 		};
47 
48 		opterr = 0; // don't print errors
49 		int c = getopt_long(argc, (char**)argv, "+0123456789C:fhi:qv",
50 			sLongOptions, NULL);
51 		if (c == -1)
52 			break;
53 
54 		switch (c) {
55 			case '0':
56 			case '1':
57 			case '2':
58 			case '3':
59 			case '4':
60 			case '5':
61 			case '6':
62 			case '7':
63 			case '8':
64 			case '9':
65 				compressionLevel = c - '0';
66 				break;
67 
68 			case 'C':
69 				changeToDirectory = optarg;
70 				break;
71 
72 			case 'h':
73 				print_usage_and_exit(false);
74 				break;
75 
76 			case 'f':
77 				force = true;
78 				break;
79 
80 			case 'i':
81 				packageInfoFileName = optarg;
82 				break;
83 
84 			case 'q':
85 				quiet = true;
86 				break;
87 
88 			case 'v':
89 				verbose = true;
90 				break;
91 
92 			default:
93 				print_usage_and_exit(true);
94 				break;
95 		}
96 	}
97 
98 	// The remaining arguments are the package file and the entries to add.
99 	if (optind >= argc)
100 		print_usage_and_exit(true);
101 
102 	const char* packageFileName = argv[optind++];
103 
104 	// entries must be specified, if a .PackageInfo hasn't been specified via
105 	// an option
106 	if (optind >= argc && packageInfoFileName == NULL)
107 		print_usage_and_exit(true);
108 
109 	const char* const* entriesToAdd = argv + optind;
110 	int entriesToAddCount = argc - optind;
111 
112 	// create package
113 	BPackageWriterParameters writerParameters;
114 	writerParameters.SetFlags(
115 		B_HPKG_WRITER_UPDATE_PACKAGE | (force ? B_HPKG_WRITER_FORCE_ADD : 0));
116 	writerParameters.SetCompressionLevel(compressionLevel);
117 	if (compressionLevel == 0) {
118 		writerParameters.SetCompression(
119 			BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE);
120 	}
121 
122 	PackageWriterListener listener(verbose, quiet);
123 	BPackageWriter packageWriter(&listener);
124 	status_t result = packageWriter.Init(packageFileName, &writerParameters);
125 	if (result != B_OK)
126 		return 1;
127 
128 	// If a package info file has been specified explicitly, open it.
129 	int packageInfoFD = -1;
130 	if (packageInfoFileName != NULL) {
131 		packageInfoFD = open(packageInfoFileName, O_RDONLY);
132 		if (packageInfoFD < 0) {
133 			fprintf(stderr, "Error: Failed to open package info file \"%s\": "
134 				"%s\n", packageInfoFileName, strerror(errno));
135 		}
136 	}
137 
138 	// change directory, if requested
139 	if (changeToDirectory != NULL) {
140 		if (chdir(changeToDirectory) != 0) {
141 			listener.PrintError(
142 				"Error: Failed to change the current working directory to "
143 				"\"%s\": %s\n", changeToDirectory, strerror(errno));
144 		}
145 	}
146 
147 	// add the entries
148 	for (int i = 0; i < entriesToAddCount; i++) {
149 		const char* entry = entriesToAdd[i];
150 
151 		if (strcmp(entry, ".") == 0) {
152 			// add all entries in the current directory; skip .PackageInfo,
153 			// if a different file was specified
154 			if (add_current_directory_entries(packageWriter,
155 					listener, packageInfoFileName != NULL) != B_OK)
156 				return 1;
157 		} else {
158 			// skip .PackageInfo, if a different file was specified
159 			if (packageInfoFileName != NULL
160 				&& strcmp(entry, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
161 				continue;
162 			}
163 
164 			if (packageWriter.AddEntry(entry) != B_OK)
165 				return 1;
166 		}
167 	}
168 
169 	// add the .PackageInfo, if explicitly specified
170 	if (packageInfoFileName != NULL) {
171 		result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME,
172 			packageInfoFD);
173 		if (result != B_OK)
174 			return 1;
175 	}
176 
177 	// write the package
178 	result = packageWriter.Finish();
179 	if (result != B_OK)
180 		return 1;
181 
182 	if (verbose)
183 		printf("\nsuccessfully created package '%s'\n", packageFileName);
184 
185 	return 0;
186 }
187