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