xref: /haiku/src/bin/package/command_add.cpp (revision 73ad2473e7874b3702cf5b0fdf4c81b747812ed9)
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 
118 	PackageWriterListener listener(verbose, quiet);
119 	BPackageWriter packageWriter(&listener);
120 	status_t result = packageWriter.Init(packageFileName, &writerParameters);
121 	if (result != B_OK)
122 		return 1;
123 
124 	// If a package info file has been specified explicitly, open it.
125 	int packageInfoFD = -1;
126 	if (packageInfoFileName != NULL) {
127 		packageInfoFD = open(packageInfoFileName, O_RDONLY);
128 		if (packageInfoFD < 0) {
129 			fprintf(stderr, "Error: Failed to open package info file \"%s\": "
130 				"%s\n", packageInfoFileName, strerror(errno));
131 		}
132 	}
133 
134 	// change directory, if requested
135 	if (changeToDirectory != NULL) {
136 		if (chdir(changeToDirectory) != 0) {
137 			listener.PrintError(
138 				"Error: Failed to change the current working directory to "
139 				"\"%s\": %s\n", changeToDirectory, strerror(errno));
140 		}
141 	}
142 
143 	// add the entries
144 	for (int i = 0; i < entriesToAddCount; i++) {
145 		const char* entry = entriesToAdd[i];
146 
147 		if (strcmp(entry, ".") == 0) {
148 			// add all entries in the current directory; skip .PackageInfo,
149 			// if a different file was specified
150 			if (add_current_directory_entries(packageWriter,
151 					listener, packageInfoFileName != NULL) != B_OK)
152 				return 1;
153 		} else {
154 			// skip .PackageInfo, if a different file was specified
155 			if (packageInfoFileName != NULL
156 				&& strcmp(entry, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
157 				continue;
158 			}
159 
160 			if (packageWriter.AddEntry(entry) != B_OK)
161 				return 1;
162 		}
163 	}
164 
165 	// add the .PackageInfo, if explicitly specified
166 	if (packageInfoFileName != NULL) {
167 		result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME,
168 			packageInfoFD);
169 		if (result != B_OK)
170 			return 1;
171 	}
172 
173 	// write the package
174 	result = packageWriter.Finish();
175 	if (result != B_OK)
176 		return 1;
177 
178 	if (verbose)
179 		printf("\nsuccessfully created package '%s'\n", packageFileName);
180 
181 	return 0;
182 }
183