archive.c 11.9 KB
Newer Older
1 2
#include "cache.h"
#include "commit.h"
3
#include "tree-walk.h"
4
#include "attr.h"
5
#include "archive.h"
6
#include "parse-options.h"
7
#include "unpack-trees.h"
8 9

static char const * const archive_usage[] = {
10
	"git archive [options] <tree-ish> [<path>...]",
11
	"git archive --list",
12
	"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]",
13 14 15
	"git archive --remote <repo> [--exec <cmd>] --list",
	NULL
};
16

17 18 19 20 21 22 23 24 25
static const struct archiver **archivers;
static int nr_archivers;
static int alloc_archivers;

void register_archiver(struct archiver *ar)
{
	ALLOC_GROW(archivers, nr_archivers + 1, alloc_archivers);
	archivers[nr_archivers++] = ar;
}
26

27 28 29 30 31
static void format_subst(const struct commit *commit,
                         const char *src, size_t len,
                         struct strbuf *buf)
{
	char *to_free = NULL;
32
	struct strbuf fmt = STRBUF_INIT;
33 34
	struct pretty_print_context ctx = {0};
	ctx.date_mode = DATE_NORMAL;
35
	ctx.abbrev = DEFAULT_ABBREV;
36 37 38 39 40 41 42

	if (src == buf->buf)
		to_free = strbuf_detach(buf, NULL);
	for (;;) {
		const char *b, *c;

		b = memmem(src, len, "$Format:", 8);
43
		if (!b)
44
			break;
45
		c = memchr(b + 8, '$', (src + len) - b - 8);
46 47 48 49 50 51 52
		if (!c)
			break;

		strbuf_reset(&fmt);
		strbuf_add(&fmt, b + 8, c - b - 8);

		strbuf_add(buf, src, b - src);
53
		format_commit_message(commit, fmt.buf, buf, &ctx);
54 55 56 57 58 59 60 61
		len -= c + 1 - src;
		src  = c + 1;
	}
	strbuf_add(buf, src, len);
	strbuf_release(&fmt);
	free(to_free);
}

62 63 64
static void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
		unsigned int mode, enum object_type *type,
		unsigned long *sizep, const struct commit *commit)
65 66 67 68 69
{
	void *buffer;

	buffer = read_sha1_file(sha1, type, sizep);
	if (buffer && S_ISREG(mode)) {
70
		struct strbuf buf = STRBUF_INIT;
71 72 73 74
		size_t size = 0;

		strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
		convert_to_working_tree(path, buf.buf, buf.len, &buf);
75 76
		if (commit)
			format_subst(commit, buf.buf, buf.len, &buf);
77 78 79 80 81 82 83
		buffer = strbuf_detach(&buf, &size);
		*sizep = size;
	}

	return buffer;
}

84
static void setup_archive_check(struct git_attr_check *check)
85 86
{
	static struct git_attr *attr_export_ignore;
87
	static struct git_attr *attr_export_subst;
88

89
	if (!attr_export_ignore) {
90 91
		attr_export_ignore = git_attr("export-ignore");
		attr_export_subst = git_attr("export-subst");
92
	}
93
	check[0].attr = attr_export_ignore;
94
	check[1].attr = attr_export_subst;
95
}
96 97 98 99 100 101 102 103 104 105 106 107 108 109

struct archiver_context {
	struct archiver_args *args;
	write_archive_entry_fn_t write_entry;
};

static int write_archive_entry(const unsigned char *sha1, const char *base,
		int baselen, const char *filename, unsigned mode, int stage,
		void *context)
{
	static struct strbuf path = STRBUF_INIT;
	struct archiver_context *c = context;
	struct archiver_args *args = c->args;
	write_archive_entry_fn_t write_entry = c->write_entry;
110 111 112
	struct git_attr_check check[2];
	const char *path_without_prefix;
	int convert = 0;
113 114 115 116 117 118 119
	int err;
	enum object_type type;
	unsigned long size;
	void *buffer;

	strbuf_reset(&path);
	strbuf_grow(&path, PATH_MAX);
120
	strbuf_add(&path, args->base, args->baselen);
121 122
	strbuf_add(&path, base, baselen);
	strbuf_addstr(&path, filename);
123
	path_without_prefix = path.buf + args->baselen;
124

125
	setup_archive_check(check);
126
	if (!git_check_attr(path_without_prefix, ARRAY_SIZE(check), check)) {
127 128 129 130
		if (ATTR_TRUE(check[0].value))
			return 0;
		convert = ATTR_TRUE(check[1].value);
	}
131 132 133 134 135 136 137 138

	if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
		strbuf_addch(&path, '/');
		if (args->verbose)
			fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
		err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0);
		if (err)
			return err;
139
		return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
140 141
	}

142 143
	buffer = sha1_file_to_archive(path_without_prefix, sha1, mode,
			&type, &size, convert ? args->commit : NULL);
144 145 146 147 148 149 150 151 152 153 154 155 156
	if (!buffer)
		return error("cannot read %s", sha1_to_hex(sha1));
	if (args->verbose)
		fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
	err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size);
	free(buffer);
	return err;
}

int write_archive_entries(struct archiver_args *args,
		write_archive_entry_fn_t write_entry)
{
	struct archiver_context context;
157 158
	struct unpack_trees_options opts;
	struct tree_desc t;
159
	struct pathspec pathspec;
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
	int err;

	if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
		size_t len = args->baselen;

		while (len > 1 && args->base[len - 2] == '/')
			len--;
		if (args->verbose)
			fprintf(stderr, "%.*s\n", (int)len, args->base);
		err = write_entry(args, args->tree->object.sha1, args->base,
				len, 040777, NULL, 0);
		if (err)
			return err;
	}

	context.args = args;
	context.write_entry = write_entry;

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
	/*
	 * Setup index and instruct attr to read index only
	 */
	if (!args->worktree_attributes) {
		memset(&opts, 0, sizeof(opts));
		opts.index_only = 1;
		opts.head_idx = -1;
		opts.src_index = &the_index;
		opts.dst_index = &the_index;
		opts.fn = oneway_merge;
		init_tree_desc(&t, args->tree->buffer, args->tree->size);
		if (unpack_trees(1, &t, &opts))
			return -1;
		git_attr_set_direction(GIT_ATTR_INDEX, &the_index);
	}

194 195
	init_pathspec(&pathspec, args->pathspec);
	err = read_tree_recursive(args->tree, "", 0, 0, &pathspec,
196
				  write_archive_entry, &context);
197
	free_pathspec(&pathspec);
198 199 200 201
	if (err == READ_TREE_RECURSIVE)
		err = 0;
	return err;
}
R
Rene Scharfe 已提交
202

203 204 205 206
static const struct archiver *lookup_archiver(const char *name)
{
	int i;

207 208 209
	if (!name)
		return NULL;

210 211 212
	for (i = 0; i < nr_archivers; i++) {
		if (!strcmp(name, archivers[i]->name))
			return archivers[i];
213 214 215 216
	}
	return NULL;
}

217 218 219 220 221 222 223 224 225
static int reject_entry(const unsigned char *sha1, const char *base,
			int baselen, const char *filename, unsigned mode,
			int stage, void *context)
{
	return -1;
}

static int path_exists(struct tree *tree, const char *path)
{
226 227 228 229 230 231 232 233
	const char *paths[] = { path, NULL };
	struct pathspec pathspec;
	int ret;

	init_pathspec(&pathspec, paths);
	ret = read_tree_recursive(tree, "", 0, 0, &pathspec, reject_entry, NULL);
	free_pathspec(&pathspec);
	return ret != 0;
234 235
}

236 237 238
static void parse_pathspec_arg(const char **pathspec,
		struct archiver_args *ar_args)
{
239 240 241 242 243 244 245 246
	ar_args->pathspec = pathspec = get_pathspec("", pathspec);
	if (pathspec) {
		while (*pathspec) {
			if (!path_exists(ar_args->tree, *pathspec))
				die("path not found: %s", *pathspec);
			pathspec++;
		}
	}
247 248 249
}

static void parse_treeish_arg(const char **argv,
250 251
		struct archiver_args *ar_args, const char *prefix,
		int remote)
252 253 254 255 256 257 258 259
{
	const char *name = argv[0];
	const unsigned char *commit_sha1;
	time_t archive_time;
	struct tree *tree;
	const struct commit *commit;
	unsigned char sha1[20];

260 261 262
	/* Remotes are only allowed to fetch actual refs */
	if (remote) {
		char *ref = NULL;
263 264 265 266 267
		const char *colon = strchr(name, ':');
		int refnamelen = colon ? colon - name : strlen(name);

		if (!dwim_ref(name, refnamelen, sha1, &ref))
			die("no such ref: %.*s", refnamelen, name);
268 269
		free(ref);
	}
270 271 272

	if (get_sha1(name, sha1))
		die("Not a valid object name");
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304

	commit = lookup_commit_reference_gently(sha1, 1);
	if (commit) {
		commit_sha1 = commit->object.sha1;
		archive_time = commit->date;
	} else {
		commit_sha1 = NULL;
		archive_time = time(NULL);
	}

	tree = parse_tree_indirect(sha1);
	if (tree == NULL)
		die("not a tree object");

	if (prefix) {
		unsigned char tree_sha1[20];
		unsigned int mode;
		int err;

		err = get_tree_entry(tree->object.sha1, prefix,
				     tree_sha1, &mode);
		if (err || !S_ISDIR(mode))
			die("current working directory is untracked");

		tree = parse_tree_indirect(tree_sha1);
	}
	ar_args->tree = tree;
	ar_args->commit_sha1 = commit_sha1;
	ar_args->commit = commit;
	ar_args->time = archive_time;
}

305 306 307 308 309 310 311
#define OPT__COMPR(s, v, h, p) \
	{ OPTION_SET_INT, (s), NULL, (v), NULL, (h), \
	  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, (p) }
#define OPT__COMPR_HIDDEN(s, v, p) \
	{ OPTION_SET_INT, (s), NULL, (v), NULL, "", \
	  PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, NULL, (p) }

312
static int parse_archive_args(int argc, const char **argv,
313
		const struct archiver **ar, struct archiver_args *args,
314
		const char *name_hint, int is_remote)
315
{
316
	const char *format = NULL;
317 318 319
	const char *base = NULL;
	const char *remote = NULL;
	const char *exec = NULL;
320
	const char *output = NULL;
321 322 323
	int compression_level = -1;
	int verbose = 0;
	int i;
324
	int list = 0;
325
	int worktree_attributes = 0;
326 327 328 329 330
	struct option opts[] = {
		OPT_GROUP(""),
		OPT_STRING(0, "format", &format, "fmt", "archive format"),
		OPT_STRING(0, "prefix", &base, "prefix",
			"prepend prefix to each pathname in the archive"),
331
		OPT_STRING('o', "output", &output, "file",
332
			"write the archive to this file"),
J
Junio C Hamano 已提交
333
		OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
334
			"read .gitattributes in working directory"),
335
		OPT__VERBOSE(&verbose, "report archived files on stderr"),
336 337 338 339 340 341 342 343 344 345 346
		OPT__COMPR('0', &compression_level, "store only", 0),
		OPT__COMPR('1', &compression_level, "compress faster", 1),
		OPT__COMPR_HIDDEN('2', &compression_level, 2),
		OPT__COMPR_HIDDEN('3', &compression_level, 3),
		OPT__COMPR_HIDDEN('4', &compression_level, 4),
		OPT__COMPR_HIDDEN('5', &compression_level, 5),
		OPT__COMPR_HIDDEN('6', &compression_level, 6),
		OPT__COMPR_HIDDEN('7', &compression_level, 7),
		OPT__COMPR_HIDDEN('8', &compression_level, 8),
		OPT__COMPR('9', &compression_level, "compress better", 9),
		OPT_GROUP(""),
J
Junio C Hamano 已提交
347
		OPT_BOOL('l', "list", &list,
348 349 350 351 352 353 354 355 356
			"list supported archive formats"),
		OPT_GROUP(""),
		OPT_STRING(0, "remote", &remote, "repo",
			"retrieve the archive from remote repository <repo>"),
		OPT_STRING(0, "exec", &exec, "cmd",
			"path to the remote git-upload-archive command"),
		OPT_END()
	};

357
	argc = parse_options(argc, argv, NULL, opts, archive_usage, 0);
358 359 360 361 362

	if (remote)
		die("Unexpected option --remote");
	if (exec)
		die("Option --exec can only be used together with --remote");
363 364
	if (output)
		die("Unexpected option --output");
365 366 367 368 369

	if (!base)
		base = "";

	if (list) {
370
		for (i = 0; i < nr_archivers; i++)
371 372
			if (!is_remote || archivers[i]->flags & ARCHIVER_REMOTE)
				printf("%s\n", archivers[i]->name);
373
		exit(0);
374 375
	}

376 377 378 379 380
	if (!format && name_hint)
		format = archive_format_from_filename(name_hint);
	if (!format)
		format = "tar";

381
	/* We need at least one parameter -- tree-ish */
382 383
	if (argc < 1)
		usage_with_options(archive_usage, opts);
384
	*ar = lookup_archiver(format);
385
	if (!*ar || (is_remote && !((*ar)->flags & ARCHIVER_REMOTE)))
386 387 388 389
		die("Unknown archive format '%s'", format);

	args->compression_level = Z_DEFAULT_COMPRESSION;
	if (compression_level != -1) {
390
		if ((*ar)->flags & ARCHIVER_WANT_COMPRESSION_LEVELS)
391 392 393 394 395 396 397 398 399
			args->compression_level = compression_level;
		else {
			die("Argument not supported for format '%s': -%d",
					format, compression_level);
		}
	}
	args->verbose = verbose;
	args->base = base;
	args->baselen = strlen(base);
400
	args->worktree_attributes = worktree_attributes;
401

402
	return argc;
403 404
}

R
Rene Scharfe 已提交
405
int write_archive(int argc, const char **argv, const char *prefix,
406
		  int setup_prefix, const char *name_hint, int remote)
R
Rene Scharfe 已提交
407
{
408
	int nongit = 0;
R
Rene Scharfe 已提交
409 410 411 412
	const struct archiver *ar = NULL;
	struct archiver_args args;

	if (setup_prefix && prefix == NULL)
413 414 415
		prefix = setup_git_directory_gently(&nongit);

	git_config(git_default_config, NULL);
416 417
	init_tar_archiver();
	init_zip_archiver();
418

419
	argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
420 421 422 423 424 425 426 427
	if (nongit) {
		/*
		 * We know this will die() with an error, so we could just
		 * die ourselves; but its error message will be more specific
		 * than what we could write here.
		 */
		setup_git_directory();
	}
R
Rene Scharfe 已提交
428

429
	parse_treeish_arg(argv, &args, prefix, remote);
R
Rene Scharfe 已提交
430 431
	parse_pathspec_arg(argv + 1, &args);

432
	return ar->write_archive(ar, &args);
R
Rene Scharfe 已提交
433
}
434

435 436 437 438 439 440 441 442 443 444 445 446 447 448
static int match_extension(const char *filename, const char *ext)
{
	int prefixlen = strlen(filename) - strlen(ext);

	/*
	 * We need 1 character for the '.', and 1 character to ensure that the
	 * prefix is non-empty (k.e., we don't match .tar.gz with no actual
	 * filename).
	 */
	if (prefixlen < 2 || filename[prefixlen-1] != '.')
		return 0;
	return !strcmp(filename + prefixlen, ext);
}

449 450
const char *archive_format_from_filename(const char *filename)
{
451 452 453 454 455
	int i;

	for (i = 0; i < nr_archivers; i++)
		if (match_extension(filename, archivers[i]->name))
			return archivers[i]->name;
456 457
	return NULL;
}