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 BPackageKit::BHPKG::BPackageWriterListener;
29using BPackageKit::BHPKG::BPackageWriter;
30
31
32int
33command_create(int argc, const char* const* argv)
34{
35	const char* changeToDirectory = NULL;
36	const char* packageInfoFileName = NULL;
37	const char* installPath = NULL;
38	bool isBuildPackage = false;
39	bool quiet = false;
40	bool verbose = false;
41
42	while (true) {
43		static struct option sLongOptions[] = {
44			{ "help", no_argument, 0, 'h' },
45			{ "quiet", no_argument, 0, 'q' },
46			{ "verbose", no_argument, 0, 'v' },
47			{ 0, 0, 0, 0 }
48		};
49
50		opterr = 0; // don't print errors
51		int c = getopt_long(argc, (char**)argv, "+bC:hi:I:qv", sLongOptions,
52			NULL);
53		if (c == -1)
54			break;
55
56		switch (c) {
57			case 'b':
58				isBuildPackage = true;
59				break;
60
61			case 'C':
62				changeToDirectory = optarg;
63				break;
64
65			case 'h':
66				print_usage_and_exit(false);
67				break;
68
69			case 'i':
70				packageInfoFileName = optarg;
71				break;
72
73			case 'I':
74				installPath = optarg;
75				break;
76
77			case 'q':
78				quiet = true;
79				break;
80
81			case 'v':
82				verbose = true;
83				break;
84
85			default:
86				print_usage_and_exit(true);
87				break;
88		}
89	}
90
91	// The remaining arguments is the package file, i.e. one more argument.
92	if (optind + 1 != argc)
93		print_usage_and_exit(true);
94
95	const char* packageFileName = argv[optind++];
96
97	// -I is only allowed when -b is given
98	if (installPath != NULL && !isBuildPackage) {
99		fprintf(stderr, "Error: \"-I\" is only allowed when \"-b\" is "
100			"given.\n");
101		return 1;
102	}
103
104	// create package
105	PackageWriterListener listener(verbose, quiet);
106	BPackageWriter packageWriter(&listener);
107	status_t result = packageWriter.Init(packageFileName);
108	if (result != B_OK)
109		return 1;
110
111	// If a package info file has been specified explicitly, open it.
112	int packageInfoFD = -1;
113	if (packageInfoFileName != NULL) {
114		packageInfoFD = open(packageInfoFileName, O_RDONLY);
115		if (packageInfoFD < 0) {
116			fprintf(stderr, "Error: Failed to open package info file \"%s\": "
117				"%s\n", packageInfoFileName, strerror(errno));
118			return 1;
119		}
120	}
121
122	// change directory, if requested
123	if (changeToDirectory != NULL) {
124		if (chdir(changeToDirectory) != 0) {
125			listener.PrintError(
126				"Error: Failed to change the current working directory to "
127				"\"%s\": %s\n", changeToDirectory, strerror(errno));
128			return 1;
129		}
130	}
131
132	if (isBuildPackage)
133		packageWriter.SetCheckLicenses(false);
134
135	// set install path, if specified
136	if (installPath != NULL) {
137		result = packageWriter.SetInstallPath(installPath);
138		if (result != B_OK) {
139			fprintf(stderr, "Error: Failed to set the package install path: "
140				"%s\n", strerror(result));
141			return 1;
142		}
143	}
144
145	// add all files of the current directory, save for the .PackageInfo
146	if (!isBuildPackage) {
147		if (add_current_directory_entries(packageWriter, listener, true)
148				!= B_OK) {
149			return 1;
150		}
151	}
152
153	// add the .PackageInfo
154	result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME,
155		packageInfoFD);
156	if (result != B_OK)
157		return 1;
158
159	// write the package
160	result = packageWriter.Finish();
161	if (result != B_OK)
162		return 1;
163
164	if (verbose)
165		printf("\nsuccessfully created package '%s'\n", packageFileName);
166
167	return 0;
168}
169