10d68f6afSOliver Tappe/*
20d68f6afSOliver Tappe * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
30d68f6afSOliver Tappe * Distributed under the terms of the MIT License.
40d68f6afSOliver Tappe */
50d68f6afSOliver Tappe
60d68f6afSOliver Tappe
70d68f6afSOliver Tappe#include <dirent.h>
80d68f6afSOliver Tappe#include <errno.h>
90d68f6afSOliver Tappe#include <getopt.h>
100d68f6afSOliver Tappe#include <stdio.h>
110d68f6afSOliver Tappe#include <stdlib.h>
120d68f6afSOliver Tappe#include <string.h>
130d68f6afSOliver Tappe
140d68f6afSOliver Tappe#include <Entry.h>
150d68f6afSOliver Tappe#include <Path.h>
160d68f6afSOliver Tappe
170d68f6afSOliver Tappe#include <package/hpkg/HPKGDefs.h>
180d68f6afSOliver Tappe#include <package/hpkg/RepositoryWriter.h>
190d68f6afSOliver Tappe#include <package/PackageInfo.h>
200d68f6afSOliver Tappe#include <package/RepositoryInfo.h>
210d68f6afSOliver Tappe
220816749eSIngo Weinhold#include "package_repo.h"
230d68f6afSOliver Tappe
240d68f6afSOliver Tappe
250d68f6afSOliver Tappeusing BPackageKit::BHPKG::BRepositoryWriterListener;
260d68f6afSOliver Tappeusing BPackageKit::BHPKG::BRepositoryWriter;
270d68f6afSOliver Tappeusing namespace BPackageKit;
280d68f6afSOliver Tappe
290d68f6afSOliver Tappe
300d68f6afSOliver Tappeclass RepositoryWriterListener	: public BRepositoryWriterListener {
310d68f6afSOliver Tappepublic:
320d68f6afSOliver Tappe	RepositoryWriterListener(bool verbose, bool quiet)
330d68f6afSOliver Tappe		: fVerbose(verbose), fQuiet(quiet)
340d68f6afSOliver Tappe	{
350d68f6afSOliver Tappe	}
360d68f6afSOliver Tappe
370d68f6afSOliver Tappe	virtual void PrintErrorVarArgs(const char* format, va_list args)
380d68f6afSOliver Tappe	{
390d68f6afSOliver Tappe		vfprintf(stderr, format, args);
400d68f6afSOliver Tappe	}
410d68f6afSOliver Tappe
420d68f6afSOliver Tappe	virtual void OnPackageAdded(const BPackageInfo& packageInfo)
430d68f6afSOliver Tappe	{
440d68f6afSOliver Tappe		if (fQuiet)
450d68f6afSOliver Tappe			return;
460d68f6afSOliver Tappe
470d68f6afSOliver Tappe		printf("%s (%s)\n", packageInfo.Name().String(),
480d68f6afSOliver Tappe			packageInfo.Version().ToString().String());
490d68f6afSOliver Tappe		if (fVerbose) {
5034d56c1bSOliver Tappe			printf("\tsummary:  %s\n", packageInfo.Summary().String());
5134d56c1bSOliver Tappe			printf("\tvendor:   %s\n", packageInfo.Vendor().String());
5234d56c1bSOliver Tappe			printf("\tpackager: %s\n", packageInfo.Packager().String());
5334d56c1bSOliver Tappe			printf("\tchecksum: %s\n", packageInfo.Checksum().String());
540d68f6afSOliver Tappe			if (uint32 flags = packageInfo.Flags()) {
550d68f6afSOliver Tappe				printf("\tflags:\n");
560d68f6afSOliver Tappe				if ((flags & B_PACKAGE_FLAG_APPROVE_LICENSE) != 0)
570d68f6afSOliver Tappe					printf("\t\tapprove_license\n");
580d68f6afSOliver Tappe				if ((flags & B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0)
590d68f6afSOliver Tappe					printf("\t\tsystem_package\n");
600d68f6afSOliver Tappe			}
6134d56c1bSOliver Tappe		} else
6234d56c1bSOliver Tappe			printf("\tchecksum: %s\n", packageInfo.Checksum().String());
630d68f6afSOliver Tappe	}
640d68f6afSOliver Tappe
654dcc5232SOliver Tappe	virtual void OnRepositoryInfoSectionDone(uint32 uncompressedSize)
664dcc5232SOliver Tappe	{
674dcc5232SOliver Tappe		if (fQuiet || !fVerbose)
684dcc5232SOliver Tappe			return;
694dcc5232SOliver Tappe
704dcc5232SOliver Tappe		printf("----- Repository Info Section --------------------\n");
71a85e4649SIngo Weinhold		printf("repository info size:    %10" B_PRIu32 " (uncompressed)\n",
724dcc5232SOliver Tappe			uncompressedSize);
734dcc5232SOliver Tappe	}
744dcc5232SOliver Tappe
754dcc5232SOliver Tappe	virtual void OnPackageAttributesSectionDone(uint32 stringCount,
760d68f6afSOliver Tappe		uint32 uncompressedSize)
770d68f6afSOliver Tappe	{
780d68f6afSOliver Tappe		if (fQuiet || !fVerbose)
790d68f6afSOliver Tappe			return;
800d68f6afSOliver Tappe
814dcc5232SOliver Tappe		printf("----- Package Attribute Section -------------------\n");
82a85e4649SIngo Weinhold		printf("string count:            %10" B_PRIu32 "\n", stringCount);
83a85e4649SIngo Weinhold		printf("package attributes size: %10" B_PRIu32 " (uncompressed)\n",
840d68f6afSOliver Tappe			uncompressedSize);
850d68f6afSOliver Tappe	}
860d68f6afSOliver Tappe
874dcc5232SOliver Tappe	virtual void OnRepositoryDone(uint32 headerSize, uint32 repositoryInfoSize,
88c2388992SOliver Tappe		uint32 licenseCount, uint32 packageCount, uint32 packageAttributesSize,
89c2388992SOliver Tappe		uint64 totalSize)
900d68f6afSOliver Tappe	{
910d68f6afSOliver Tappe		if (fQuiet)
920d68f6afSOliver Tappe			return;
930d68f6afSOliver Tappe
940d68f6afSOliver Tappe		printf("----- Package Repository Info -----\n");
95c2388992SOliver Tappe		if (fVerbose)
96a85e4649SIngo Weinhold			printf("embedded license count   %10" B_PRIu32 "\n", licenseCount);
97a85e4649SIngo Weinhold		printf("package count            %10" B_PRIu32 "\n", packageCount);
980d68f6afSOliver Tappe		printf("-----------------------------------\n");
99a85e4649SIngo Weinhold		printf("header size:             %10" B_PRIu32 "\n", headerSize);
100a85e4649SIngo Weinhold		printf("repository header size:  %10" B_PRIu32 "\n",
101a85e4649SIngo Weinhold			repositoryInfoSize);
102a85e4649SIngo Weinhold		printf("package attributes size: %10" B_PRIu32 "\n",
103a85e4649SIngo Weinhold			packageAttributesSize);
104a85e4649SIngo Weinhold		printf("total size:              %10" B_PRIu64 "\n", totalSize);
1050d68f6afSOliver Tappe		printf("-----------------------------------\n");
1060d68f6afSOliver Tappe	}
1070d68f6afSOliver Tappe
1080d68f6afSOliver Tappeprivate:
1090d68f6afSOliver Tappe	bool fVerbose;
1100d68f6afSOliver Tappe	bool fQuiet;
1110d68f6afSOliver Tappe};
1120d68f6afSOliver Tappe
1130d68f6afSOliver Tappe
1140d68f6afSOliver Tappeint
1150d68f6afSOliver Tappecommand_create(int argc, const char* const* argv)
1160d68f6afSOliver Tappe{
1170d68f6afSOliver Tappe	const char* changeToDirectory = NULL;
1180d68f6afSOliver Tappe	bool quiet = false;
1190d68f6afSOliver Tappe	bool verbose = false;
1200d68f6afSOliver Tappe
1210d68f6afSOliver Tappe	while (true) {
1220d68f6afSOliver Tappe		static struct option sLongOptions[] = {
1230d68f6afSOliver Tappe			{ "help", no_argument, 0, 'h' },
1240d68f6afSOliver Tappe			{ "quiet", no_argument, 0, 'q' },
1250d68f6afSOliver Tappe			{ "verbose", no_argument, 0, 'v' },
1260d68f6afSOliver Tappe			{ 0, 0, 0, 0 }
1270d68f6afSOliver Tappe		};
1280d68f6afSOliver Tappe
1290d68f6afSOliver Tappe		opterr = 0; // don't print errors
1300d68f6afSOliver Tappe		int c = getopt_long(argc, (char**)argv, "+C:hqv", sLongOptions, NULL);
1310d68f6afSOliver Tappe		if (c == -1)
1320d68f6afSOliver Tappe			break;
1330d68f6afSOliver Tappe
1340d68f6afSOliver Tappe		switch (c) {
1350d68f6afSOliver Tappe			case 'C':
1360d68f6afSOliver Tappe				changeToDirectory = optarg;
1370d68f6afSOliver Tappe				break;
1380d68f6afSOliver Tappe
1390d68f6afSOliver Tappe			case 'h':
1400d68f6afSOliver Tappe				print_usage_and_exit(false);
1410d68f6afSOliver Tappe				break;
1420d68f6afSOliver Tappe
1430d68f6afSOliver Tappe			case 'q':
1440d68f6afSOliver Tappe				quiet = true;
1450d68f6afSOliver Tappe				break;
1460d68f6afSOliver Tappe
1470d68f6afSOliver Tappe			case 'v':
1480d68f6afSOliver Tappe				verbose = true;
1490d68f6afSOliver Tappe				break;
1500d68f6afSOliver Tappe
1510d68f6afSOliver Tappe			default:
1520d68f6afSOliver Tappe				print_usage_and_exit(true);
1530d68f6afSOliver Tappe				break;
1540d68f6afSOliver Tappe		}
1550d68f6afSOliver Tappe	}
1560d68f6afSOliver Tappe
1570d68f6afSOliver Tappe	// The remaining arguments are the repository info file plus one or more
1580d68f6afSOliver Tappe	// package files, i.e. at least two more arguments.
15999923424SIngo Weinhold	if (optind + 2 > argc)
1600d68f6afSOliver Tappe		print_usage_and_exit(true);
1610d68f6afSOliver Tappe
1620d68f6afSOliver Tappe	const char* repositoryInfoFileName = argv[optind++];
1630d68f6afSOliver Tappe	const char* const* packageFileNames = argv + optind;
1640d68f6afSOliver Tappe
1650d68f6afSOliver Tappe	RepositoryWriterListener listener(verbose, quiet);
1660d68f6afSOliver Tappe
1670d68f6afSOliver Tappe	BEntry repositoryInfoEntry(repositoryInfoFileName);
1680d68f6afSOliver Tappe	if (!repositoryInfoEntry.Exists()) {
1690d68f6afSOliver Tappe		listener.PrintError(
1700d68f6afSOliver Tappe			"Error: given repository-info file '%s' doesn't exist!\n",
1710d68f6afSOliver Tappe			repositoryInfoFileName);
1720d68f6afSOliver Tappe		return 1;
1730d68f6afSOliver Tappe	}
1740d68f6afSOliver Tappe
1750d68f6afSOliver Tappe	// determine path for 'repo' file from given info file
1760d68f6afSOliver Tappe	BEntry repositoryParentEntry;
1770d68f6afSOliver Tappe	repositoryInfoEntry.GetParent(&repositoryParentEntry);
1780d68f6afSOliver Tappe	BPath repositoryPath;
1790d68f6afSOliver Tappe	if (repositoryParentEntry.GetPath(&repositoryPath) != B_OK) {
1800d68f6afSOliver Tappe		listener.PrintError(
1810d68f6afSOliver Tappe			"Error: can't determine path of given repository-info file!\n");
1820d68f6afSOliver Tappe		return 1;
1830d68f6afSOliver Tappe	}
1840d68f6afSOliver Tappe	repositoryPath.Append("repo");
1850d68f6afSOliver Tappe
1860d68f6afSOliver Tappe	// create repository
1870d68f6afSOliver Tappe	BRepositoryInfo repositoryInfo(repositoryInfoEntry);
1880d68f6afSOliver Tappe	status_t result = repositoryInfo.InitCheck();
1890d68f6afSOliver Tappe	if (result != B_OK) {
1900d68f6afSOliver Tappe		listener.PrintError(
1910d68f6afSOliver Tappe			"Error: can't parse given repository-info file : %s\n",
1920d68f6afSOliver Tappe			strerror(result));
1930d68f6afSOliver Tappe		return 1;
1940d68f6afSOliver Tappe	}
1950d68f6afSOliver Tappe	BRepositoryWriter repositoryWriter(&listener, &repositoryInfo);
1960d68f6afSOliver Tappe	if ((result = repositoryWriter.Init(repositoryPath.Path())) != B_OK) {
1970d68f6afSOliver Tappe		listener.PrintError("Error: can't initialize repository-writer : %s\n",
1980d68f6afSOliver Tappe			strerror(result));
1990d68f6afSOliver Tappe		return 1;
2000d68f6afSOliver Tappe	}
2010d68f6afSOliver Tappe
2020d68f6afSOliver Tappe	// change directory, if requested
2030d68f6afSOliver Tappe	if (changeToDirectory != NULL) {
2040d68f6afSOliver Tappe		if (chdir(changeToDirectory) != 0) {
2050d68f6afSOliver Tappe			listener.PrintError(
2060d68f6afSOliver Tappe				"Error: Failed to change the current working directory to "
2070d68f6afSOliver Tappe				"\"%s\": %s\n", changeToDirectory, strerror(errno));
2080d68f6afSOliver Tappe			return 1;
2090d68f6afSOliver Tappe		}
2100d68f6afSOliver Tappe	}
2110d68f6afSOliver Tappe
2120d68f6afSOliver Tappe	// add all given package files
2130d68f6afSOliver Tappe	for (int i = 0; i < argc - optind; ++i) {
2140d68f6afSOliver Tappe		if (verbose)
2150d68f6afSOliver Tappe			printf("reading package '%s' ...\n", packageFileNames[i]);
2160d68f6afSOliver Tappe		BEntry entry(packageFileNames[i]);
217532b7b60SOliver Tappe		if (!entry.Exists()) {
218532b7b60SOliver Tappe			printf("package '%s' does not exist\n", packageFileNames[i]);
219532b7b60SOliver Tappe			return 1;
220532b7b60SOliver Tappe		}
2210d68f6afSOliver Tappe		result = repositoryWriter.AddPackage(entry);
2220d68f6afSOliver Tappe		if (result != B_OK)
2230d68f6afSOliver Tappe			return 1;
2240d68f6afSOliver Tappe	}
2250d68f6afSOliver Tappe
2260d68f6afSOliver Tappe	// write the repository
2270d68f6afSOliver Tappe	result = repositoryWriter.Finish();
2280d68f6afSOliver Tappe	if (result != B_OK)
2290d68f6afSOliver Tappe		return 1;
2300d68f6afSOliver Tappe
2310d68f6afSOliver Tappe	if (verbose) {
2320d68f6afSOliver Tappe		printf("\nsuccessfully created repository '%s'\n",
2330d68f6afSOliver Tappe			repositoryPath.Path());
2340d68f6afSOliver Tappe	}
2350d68f6afSOliver Tappe
2360d68f6afSOliver Tappe	return 0;
2370d68f6afSOliver Tappe}