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