diff options
Diffstat (limited to 'archive.c')
-rw-r--r-- | archive.c | 110 |
1 files changed, 81 insertions, 29 deletions
@@ -1,8 +1,17 @@ -#include "cache.h" +#include "git-compat-util.h" +#include "abspath.h" +#include "alloc.h" #include "config.h" +#include "convert.h" +#include "environment.h" +#include "gettext.h" +#include "hex.h" +#include "pretty.h" +#include "setup.h" #include "refs.h" #include "object-store.h" #include "commit.h" +#include "tree.h" #include "tree-walk.h" #include "attr.h" #include "archive.h" @@ -59,7 +68,8 @@ static void format_subst(const struct commit *commit, strbuf_add(&fmt, b + 8, c - b - 8); strbuf_add(buf, src, b - src); - format_commit_message(commit, fmt.buf, buf, ctx); + repo_format_commit_message(the_repository, commit, fmt.buf, + buf, ctx); len -= c + 1 - src; src = c + 1; } @@ -84,7 +94,7 @@ static void *object_file_to_archive(const struct archiver_args *args, (args->tree ? &args->tree->object.oid : NULL), oid); path += args->baselen; - buffer = read_object_file(oid, type, sizep); + buffer = repo_read_object_file(the_repository, oid, type, sizep); if (buffer && S_ISREG(mode)) { struct strbuf buf = STRBUF_INIT; size_t size = 0; @@ -120,7 +130,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate, static struct attr_check *check; if (!check) check = attr_check_initl("export-ignore", "export-subst", NULL); - git_check_attr(istate, path, check); + git_check_attr(istate, NULL, path, check); return check; } @@ -166,6 +176,29 @@ static int write_archive_entry(const struct object_id *oid, const char *base, args->convert = check_attr_export_subst(check); } + if (args->prefix) { + static struct strbuf new_path = STRBUF_INIT; + static struct strbuf buf = STRBUF_INIT; + const char *rel; + + rel = relative_path(path_without_prefix, args->prefix, &buf); + + /* + * We don't add an entry for the current working + * directory when we are at the root; skip it also when + * we're in a subdirectory or submodule. Skip entries + * higher up as well. + */ + if (!strcmp(rel, "./") || starts_with(rel, "../")) + return S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0; + + /* rel can refer to path, so don't edit it in place */ + strbuf_reset(&new_path); + strbuf_add(&new_path, args->base, args->baselen); + strbuf_addstr(&new_path, rel); + strbuf_swap(&path, &new_path); + } + if (args->verbose) fprintf(stderr, "%.*s\n", (int)path.len, path.buf); @@ -401,6 +434,27 @@ static int reject_entry(const struct object_id *oid UNUSED, return ret; } +static int reject_outside(const struct object_id *oid UNUSED, + struct strbuf *base, const char *filename, + unsigned mode, void *context) +{ + struct archiver_args *args = context; + struct strbuf buf = STRBUF_INIT; + struct strbuf path = STRBUF_INIT; + int ret = 0; + + if (S_ISDIR(mode)) + return READ_TREE_RECURSIVE; + + strbuf_addbuf(&path, base); + strbuf_addstr(&path, filename); + if (starts_with(relative_path(path.buf, args->prefix, &buf), "../")) + ret = -1; + strbuf_release(&buf); + strbuf_release(&path); + return ret; +} + static int path_exists(struct archiver_args *args, const char *path) { const char *paths[] = { path, NULL }; @@ -408,8 +462,13 @@ static int path_exists(struct archiver_args *args, const char *path) int ret; ctx.args = args; - parse_pathspec(&ctx.pathspec, 0, 0, "", paths); + parse_pathspec(&ctx.pathspec, 0, PATHSPEC_PREFER_CWD, + args->prefix, paths); ctx.pathspec.recursive = 1; + if (args->prefix && read_tree(args->repo, args->tree, &ctx.pathspec, + reject_outside, args)) + die(_("pathspec '%s' matches files outside the " + "current directory"), path); ret = read_tree(args->repo, args->tree, &ctx.pathspec, reject_entry, &ctx); @@ -425,9 +484,8 @@ static void parse_pathspec_arg(const char **pathspec, * Also if pathspec patterns are dependent, we're in big * trouble as we test each one separately */ - parse_pathspec(&ar_args->pathspec, 0, - PATHSPEC_PREFER_FULL, - "", pathspec); + parse_pathspec(&ar_args->pathspec, 0, PATHSPEC_PREFER_CWD, + ar_args->prefix, pathspec); ar_args->pathspec.recursive = 1; if (pathspec) { while (*pathspec) { @@ -439,8 +497,7 @@ static void parse_pathspec_arg(const char **pathspec, } static void parse_treeish_arg(const char **argv, - struct archiver_args *ar_args, const char *prefix, - int remote) + struct archiver_args *ar_args, int remote) { const char *name = argv[0]; const struct object_id *commit_oid; @@ -455,13 +512,14 @@ static void parse_treeish_arg(const char **argv, const char *colon = strchrnul(name, ':'); int refnamelen = colon - name; - if (!dwim_ref(name, refnamelen, &oid, &ref, 0)) + if (!repo_dwim_ref(the_repository, name, refnamelen, &oid, &ref, 0)) die(_("no such ref: %.*s"), refnamelen, name); } else { - dwim_ref(name, strlen(name), &oid, &ref, 0); + repo_dwim_ref(the_repository, name, strlen(name), &oid, &ref, + 0); } - if (get_oid(name, &oid)) + if (repo_get_oid(the_repository, name, &oid)) die(_("not a valid object name: %s"), name); commit = lookup_commit_reference_gently(ar_args->repo, &oid, 1); @@ -472,25 +530,13 @@ static void parse_treeish_arg(const char **argv, commit_oid = NULL; archive_time = time(NULL); } + if (ar_args->mtime_option) + archive_time = approxidate(ar_args->mtime_option); tree = parse_tree_indirect(&oid); if (!tree) die(_("not a tree object: %s"), oid_to_hex(&oid)); - if (prefix) { - struct object_id tree_oid; - unsigned short mode; - int err; - - err = get_tree_entry(ar_args->repo, - &tree->object.oid, - prefix, &tree_oid, - &mode); - if (err || !S_ISDIR(mode)) - die(_("current working directory is untracked")); - - tree = parse_tree_indirect(&tree_oid); - } ar_args->refname = ref; ar_args->tree = tree; ar_args->commit_oid = commit_oid; @@ -498,7 +544,7 @@ static void parse_treeish_arg(const char **argv, ar_args->time = archive_time; } -static void extra_file_info_clear(void *util, const char *str) +static void extra_file_info_clear(void *util, const char *str UNUSED) { struct extra_file_info *info = util; free(info->base); @@ -586,6 +632,7 @@ static int parse_archive_args(int argc, const char **argv, const char *remote = NULL; const char *exec = NULL; const char *output = NULL; + const char *mtime_option = NULL; int compression_level = -1; int verbose = 0; int i; @@ -607,6 +654,9 @@ static int parse_archive_args(int argc, const char **argv, OPT_BOOL(0, "worktree-attributes", &worktree_attributes, N_("read .gitattributes in working directory")), OPT__VERBOSE(&verbose, N_("report archived files on stderr")), + { OPTION_STRING, 0, "mtime", &mtime_option, N_("time"), + N_("set modification time of archive entries"), + PARSE_OPT_NONEG }, OPT_NUMBER_CALLBACK(&compression_level, N_("set compression level"), number_callback), OPT_GROUP(""), @@ -668,6 +718,7 @@ static int parse_archive_args(int argc, const char **argv, args->base = base; args->baselen = strlen(base); args->worktree_attributes = worktree_attributes; + args->mtime_option = mtime_option; return argc; } @@ -703,13 +754,14 @@ int write_archive(int argc, const char **argv, const char *prefix, setup_git_directory(); } - parse_treeish_arg(argv, &args, prefix, remote); + parse_treeish_arg(argv, &args, remote); parse_pathspec_arg(argv + 1, &args); rc = ar->write_archive(ar, &args); string_list_clear_func(&args.extra_files, extra_file_info_clear); free(args.refname); + clear_pathspec(&args.pathspec); return rc; } |