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
28using namespace BPackageKit::BHPKG;
29
30
31int
32command_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