Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Fix #1566: Add pkg-create(8) -l,--level to set compression level
Conrad Meyer committed 6 years ago
commit 8991ebd7afb0cb50fa66996cc05e4702ccce8c5c
parent 83a68a9
10 files changed +147 -31
modified docs/pkg-create.8
@@ -14,7 +14,7 @@
.\"
.\"     @(#)pkg.8
.\"
-
.Dd February 26, 2020
+
.Dd April 13, 2020
.Dt PKG-CREATE 8
.Os
.\" ---------------------------------------------------------------------------
@@ -26,6 +26,7 @@
.Nm
.Op Fl qv
.Op Fl f Ar format
+
.Op Fl l Ar level
.Op Fl o Ar outdir
.Op Fl p Ar plist
.Op Fl r Ar rootdir
@@ -34,6 +35,7 @@
.Nm
.Op Fl qv
.Op Fl f Ar format
+
.Op Fl l Ar level
.Op Fl o Ar outdir
.Op Fl r Ar rootdir
.Op Fl t Ar timestamp
@@ -41,6 +43,7 @@
.Nm
.Op Fl gnqvx
.Op Fl f Ar format
+
.Op Fl l Ar level
.Op Fl o Ar outdir
.Op Fl r Ar rootdir
.Op Fl t Ar timestamp
@@ -48,6 +51,7 @@
.Nm
.Op Fl qv
.Op Fl f Ar format
+
.Op Fl l Ar level
.Op Fl o Ar outdir
.Op Fl r Ar rootdir
.Op Fl t Ar timestamp
@@ -59,6 +63,7 @@
.Op Cm --quiet
.Op Cm --verbose
.Op Cm --format Ar format
+
.Op Cm --level Ar level
.Op Cm --out-dir Ar outdir
.Op Cm --plist Ar plist
.Op Cm --root-dir Ar rootdir
@@ -68,6 +73,7 @@
.Op Cm --quiet
.Op Cm --verbose
.Op Cm --format Ar format
+
.Op Cm --level Ar level
.Op Cm --out-dir Ar outdir
.Op Cm --root-dir Ar rootdir
.Cm --manifest Ar manifest
@@ -76,6 +82,7 @@
.Op Cm --quiet
.Op Cm --verbose
.Op Cm --format Ar format
+
.Op Cm --level Ar level
.Op Cm --out-dir Ar outdir
.Op Cm --root-dir Ar rootdir
.Ar pkg-name ...
@@ -84,6 +91,7 @@
.Op Cm --quiet
.Op Cm --verbose
.Op Cm --format Ar format
+
.Op Cm --level Ar level
.Op Cm --out-dir Ar outdir
.Op Cm --root-dir Ar rootdir
.Cm --all
@@ -159,6 +167,23 @@ which are currently the only supported formats.
If an invalid or no format is specified
.Ar txz
is assumed.
+
.It Fl l Ar level , Cm --level Ar level
+
Set the compression
+
.Ar level
+
for created packages.
+
It can be any valid numeric compression level you might specify to the
+
underlying compression
+
.Ar format .
+
Additionally,
+
.Ar level
+
may be one of the special words
+
.Dv Dq fast
+
or
+
.Dv Dq best .
+
If
+
.Ar level
+
is one of these special words, the fastest or slowest compression level,
+
respectively, for the specified compression format, is used.
.It Fl m Ar metadatadir , Cm --metadata Ar metadatadir
Specify the directory containing the package manifest,
.Pa +MANIFEST
modified libpkg/libpkg.ver
@@ -31,6 +31,7 @@ global:
	pkg_create_new;
	pkg_create_repo;
	pkg_create_set_format;
+
	pkg_create_set_compression_level;
	pkg_create_set_output_dir;
	pkg_create_set_rootdir;
	pkg_create_set_timestamp;
modified libpkg/packing.c
@@ -39,7 +39,7 @@
#include "private/event.h"
#include "private/pkg.h"

-
static const char *packing_set_format(struct archive *a, pkg_formats format);
+
static const char *packing_set_format(struct archive *a, pkg_formats format, int clevel);

struct packing {
	struct archive *aread;
@@ -49,7 +49,7 @@ struct packing {
};

int
-
packing_init(struct packing **pack, const char *path, pkg_formats format,
+
packing_init(struct packing **pack, const char *path, pkg_formats format, int clevel,
    time_t timestamp)
{
	char archive_path[MAXPATHLEN];
@@ -80,7 +80,7 @@ packing_init(struct packing **pack, const char *path, pkg_formats format,

	(*pack)->awrite = archive_write_new();
	archive_write_set_format_pax_restricted((*pack)->awrite);
-
	ext = packing_set_format((*pack)->awrite, format);
+
	ext = packing_set_format((*pack)->awrite, format, clevel);
	if (ext == NULL) {
		archive_read_close((*pack)->aread);
		archive_read_free((*pack)->aread);
@@ -318,42 +318,101 @@ packing_finish(struct packing *pack)
}

static const char *
-
packing_set_format(struct archive *a, pkg_formats format)
+
packing_set_format(struct archive *a, pkg_formats format, int clevel)
{
	const char *notsupp_fmt = "%s is not supported, trying %s";

+
	pkg_formats elected_format;
+

	switch (format) {
	case TZS:
#ifdef HAVE_ARCHIVE_WRITE_ADD_FILTER_ZSTD
		if (archive_write_add_filter_zstd(a) == ARCHIVE_OK) {
-
			if (archive_write_set_filter_option(a, NULL, "compression-level", "20") != ARCHIVE_OK) {
-
				pkg_emit_error("bad compression-level");
-
			}
-
			return ("tzst");
+
			elected_format = TZS;
+
			goto out;
		}
#endif
		pkg_emit_error(notsupp_fmt, "zstd", "xz");
		/* FALLTHRU */
	case TXZ:
-
		if (archive_write_add_filter_xz(a) == ARCHIVE_OK)
-
			return ("txz");
+
		if (archive_write_add_filter_xz(a) == ARCHIVE_OK) {
+
			elected_format = TXZ;
+
			goto out;
+
		}
		pkg_emit_error(notsupp_fmt, "xz", "bzip2");
		/* FALLTHRU */
	case TBZ:
-
		if (archive_write_add_filter_bzip2(a) == ARCHIVE_OK)
-
			return ("tbz");
+
		if (archive_write_add_filter_bzip2(a) == ARCHIVE_OK) {
+
			elected_format = TBZ;
+
			goto out;
+
		}
		pkg_emit_error(notsupp_fmt, "bzip2", "gzip");
		/* FALLTHRU */
	case TGZ:
-
		if (archive_write_add_filter_gzip(a) == ARCHIVE_OK)
-
			return ("tgz");
+
		if (archive_write_add_filter_gzip(a) == ARCHIVE_OK) {
+
			elected_format = TGZ;
+
			goto out;
+
		}
		pkg_emit_error(notsupp_fmt, "gzip", "plain tar");
		/* FALLTHRU */
	case TAR:
		archive_write_add_filter_none(a);
-
		return ("tar");
+
		elected_format = TAR;
+
		break;
+
	default:
+
		return (NULL);
	}
-
	return (NULL);
+

+
out:
+
	/*
+
	 * N.B., we only want to whine about this if the user actually selected
+
	 * tar and specified a compress level.  If we had to fallback to tar,
+
	 * that's not the user's fault.
+
	 */
+
	if (format == TAR && clevel != 0)
+
		pkg_emit_error("Plain tar and a compression level does not make sense");
+

+
	if (elected_format != TAR && clevel != 0) {
+
		char buf[16];
+

+
		/*
+
		 * A bit of a kludge but avoids dragging in headers for all of
+
		 * these libraries.
+
		 */
+
		if (clevel == INT_MIN) {
+
			switch (elected_format) {
+
			case TZS:
+
				clevel = -5;
+
				break;
+
			case TXZ:
+
			case TBZ:
+
			case TGZ:
+
				clevel = 1;
+
				break;
+
			default:
+
				__unreachable();
+
			}
+
		} else if (clevel == INT_MAX) {
+
			switch (elected_format) {
+
			case TZS:
+
				clevel = 20;
+
				break;
+
			case TXZ:
+
			case TBZ:
+
			case TGZ:
+
				clevel = 9;
+
				break;
+
			default:
+
				__unreachable();
+
			}
+
		}
+

+
		snprintf(buf, sizeof(buf), "%d", clevel);
+
		if (archive_write_set_filter_option(a, NULL, "compression-level", buf) != ARCHIVE_OK)
+
			pkg_emit_error("bad compression-level %d", clevel);
+
	}
+

+
	return (packing_format_to_string(elected_format));
}

pkg_formats
modified libpkg/pkg.h.in
@@ -1698,6 +1698,7 @@ int pkg_namecmp(struct pkg *, struct pkg *);
struct pkg_create *pkg_create_new(void);
void pkg_create_free(struct pkg_create *);
bool pkg_create_set_format(struct pkg_create *, const char *);
+
void pkg_create_set_compression_level(struct pkg_create *, int);
void pkg_create_set_rootdir(struct pkg_create *, const char *);
void pkg_create_set_output_dir(struct pkg_create *, const char *);
void pkg_create_set_timestamp(struct pkg_create *, time_t);
modified libpkg/pkg_create.c
@@ -190,7 +190,7 @@ pkg_create_archive(struct pkg *pkg, struct pkg_create *pc, unsigned required_fla
		return (NULL);
	}

-
	if (packing_init(&pkg_archive, pkg_path, pc->format, pc->timestamp) != EPKG_OK)
+
	if (packing_init(&pkg_archive, pkg_path, pc->format, pc->compression_level, pc->timestamp) != EPKG_OK)
		pkg_archive = NULL;

	free(pkg_path);
@@ -260,6 +260,12 @@ pkg_create_set_format(struct pkg_create *pc, const char *format)
}

void
+
pkg_create_set_compression_level(struct pkg_create *pc, int clevel)
+
{
+
	pc->compression_level = clevel;
+
}
+

+
void
pkg_create_set_rootdir(struct pkg_create *pc, const char *rootdir)
{
	pc->rootdir = rootdir;
modified libpkg/pkg_repo_create.c
@@ -825,7 +825,7 @@ pkg_repo_pack_db(const char *name, const char *archive, char *path,
	sig = NULL;
	pub = NULL;

-
	if (packing_init(&pack, archive, meta->packing_format, (time_t)-1) != EPKG_OK)
+
	if (packing_init(&pack, archive, meta->packing_format, 0, (time_t)-1) != EPKG_OK)
		return (EPKG_FATAL);

	if (rsa != NULL) {
modified libpkg/private/pkg.h
@@ -333,7 +333,7 @@ struct pkg {
};

struct pkg_create {
-
	uint8_t	compression_level;
+
	int compression_level;
	pkg_formats format;
	time_t timestamp;
	const char *rootdir;
@@ -737,7 +737,7 @@ int pkg_jobs_resolv(struct pkg_jobs *jobs);

struct packing;

-
int packing_init(struct packing **pack, const char *path, pkg_formats format, time_t timestamp);
+
int packing_init(struct packing **pack, const char *path, pkg_formats format, int clevel, time_t timestamp);
int packing_append_file_attr(struct packing *pack, const char *filepath,
     const char *newpath, const char *uname, const char *gname, mode_t perm,
     u_long fflags);
modified scripts/completion/_pkg.bash.in
@@ -129,7 +129,7 @@ _pkgng_create () {
    local cur prev opts lopts
    COMPREPLY=()

-
    opts=('-r' '-m' '-f' '-o' '-g' '-x' '-X' '-a')
+
    opts=('-r' '-m' '-f' '-l' '-o' '-g' '-x' '-X' '-a')
    lopts=()
    small_info="Creates software package distributions"
    large_info=""
modified scripts/completion/_pkg.in
@@ -289,6 +289,7 @@ _pkg_args() {
				'(-q --quiet)'{-q,--quiet}'[force quiet output]' \
				'(-v --verbose)'{-v,--verbose}'[be verbose]' \
				'(-f --format)'{-f+,--format=}'[specify package output format]:format:(tar tgz tbz txz tzst)' \
+
				'(-l --level)'{-l+,--level=}'[specify compression level]:level:(integer fast best)' \
				'(-o --out-dir)'{-o+,--out-dir=}'[output directory]:outdir:_files -/' \
				'(-r --root-dir)'{-r+,--root-dir=}'[specify root directory]:rootdir:_files -/' \
				- '(manifest)' \
modified src/create.c
@@ -46,6 +46,7 @@
#include <stdlib.h>
#include <pkg.h>
#include <string.h>
+
#include <strings.h>
#include <unistd.h>
#include <utlist.h>
#include <sysexits.h>
@@ -62,14 +63,14 @@ struct pkg_entry *pkg_head = NULL;
void
usage_create(void)
{
-
	fprintf(stderr, "Usage: pkg create [-Ohqv] [-f format] [-o outdir] "
-
		"[-p plist] [-r rootdir] -m metadatadir\n");
-
	fprintf(stderr, "Usage: pkg create [-Ohqv] [-f format] [-o outdir] "
-
		"[-r rootdir] -M manifest\n");
-
	fprintf(stderr, "       pkg create [-Ohgqvx] [-f format] [-o outdir] "
-
		"[-r rootdir] pkg-name ...\n");
-
	fprintf(stderr, "       pkg create [-Ohqv] [-f format] [-o outdir] "
-
		"[-r rootdir] -a\n\n");
+
	fprintf(stderr, "Usage: pkg create [-Ohqv] [-f format] [-l level] "
+
		"[-o outdir] [-p plist] [-r rootdir] -m metadatadir\n");
+
	fprintf(stderr, "Usage: pkg create [-Ohqv] [-f format] [-l level] "
+
		"[-o outdir] [-r rootdir] -M manifest\n");
+
	fprintf(stderr, "       pkg create [-Ohgqvx] [-f format] [-l level] "
+
		"[-o outdir] [-r rootdir] pkg-name ...\n");
+
	fprintf(stderr, "       pkg create [-Ohqv] [-f format] [-l level] "
+
		"[-o outdir] [-r rootdir] -a\n\n");
	fprintf(stderr, "For more information see 'pkg help create'.\n");
}

@@ -173,9 +174,12 @@ exec_create(int argc, char **argv)
	char		*plist = NULL;
	char	*endptr;
	int		 ch;
+
	int		 level;
	bool		 hash = false;
	time_t		 ts = (time_t)-1;

+
	/* Sentinel values: INT_MIN (fast), 0 (default), INT_MAX (best). */
+
	level = 0;

	/* POLA: pkg create is quiet by default, unless
	 * PKG_CREATE_VERBOSE is set in pkg.conf.  This is for
@@ -188,6 +192,7 @@ exec_create(int argc, char **argv)
		{ "format",	required_argument,	NULL,	'f' },
		{ "glob",	no_argument,		NULL,	'g' },
		{ "hash",	no_argument,		NULL,	'h' },
+
		{ "level",	required_argument,	NULL,	'l' },
		{ "regex",	no_argument,		NULL,	'x' },
		{ "root-dir",	required_argument,	NULL,	'r' },
		{ "metadata",	required_argument,	NULL,	'm' },
@@ -201,7 +206,7 @@ exec_create(int argc, char **argv)
		{ NULL,		0,			NULL,	0   },
	};

-
	while ((ch = getopt_long(argc, argv, "+aghxf:r:m:M:o:p:qvt:", longopts, NULL)) != -1) {
+
	while ((ch = getopt_long(argc, argv, "+aghxf:l:r:m:M:o:p:qvt:", longopts, NULL)) != -1) {
		switch (ch) {
		case 'a':
			match = MATCH_ALL;
@@ -215,6 +220,23 @@ exec_create(int argc, char **argv)
		case 'h':
			hash = true;
			break;
+
		case 'l':
+
			{
+
			const char *errstr;
+

+
			level = strtonum(optarg, -200, 200, &errstr);
+
			if (errstr == NULL)
+
				break;
+
			if (strcasecmp(optarg, "best") == 0) {
+
				level = INT_MAX;
+
				break;
+
			} else if (strcasecmp(optarg, "fast") == 0) {
+
				level = INT_MIN;
+
				break;
+
			}
+
			warnx("Invalid compression level %s", optarg);
+
			return (EX_USAGE);
+
			}
		case 'm':
			metadatadir = optarg;
			break;
@@ -278,6 +300,7 @@ exec_create(int argc, char **argv)
		if (!pkg_create_set_format(pc, format))
			warnx("unknown format %s, using the default", format);
	}
+
	pkg_create_set_compression_level(pc, level);

	pkg_create_set_rootdir(pc, rootdir);
	pkg_create_set_output_dir(pc, outdir);