]> git.ipfire.org Git - thirdparty/git.git/blobdiff - archive.c
refs: unify parse_worktree_ref() and ref_type()
[thirdparty/git.git] / archive.c
index ff2bb54f6229293157a14660729874791eba661e..61a79e4a2270dfc0e738ee97dd5cb5a9054ba79f 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -9,10 +9,11 @@
 #include "parse-options.h"
 #include "unpack-trees.h"
 #include "dir.h"
+#include "quote.h"
 
 static char const * const archive_usage[] = {
        N_("git archive [<options>] <tree-ish> [<path>...]"),
-       N_("git archive --list"),
+       "git archive --list",
        N_("git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"),
        N_("git archive --remote <repo> [--exec <cmd>] --list"),
        NULL
@@ -185,13 +186,13 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
 
        buffer = object_file_to_archive(args, path.buf, oid, mode, &type, &size);
        if (!buffer)
-               return error(_("cannot read %s"), oid_to_hex(oid));
+               return error(_("cannot read '%s'"), oid_to_hex(oid));
        err = write_entry(args, oid, path.buf, path.len, mode, buffer, size);
        free(buffer);
        return err;
 }
 
-static void queue_directory(const unsigned char *sha1,
+static void queue_directory(const struct object_id *oid,
                struct strbuf *base, const char *filename,
                unsigned mode, struct archiver_context *c)
 {
@@ -203,7 +204,7 @@ static void queue_directory(const unsigned char *sha1,
        d->mode    = mode;
        c->bottom  = d;
        d->len = xsnprintf(d->path, len, "%.*s%s/", (int)base->len, base->buf, filename);
-       oidread(&d->oid, sha1);
+       oidcpy(&d->oid, oid);
 }
 
 static int write_directory(struct archiver_context *c)
@@ -250,8 +251,7 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 
                if (check_attr_export_ignore(check))
                        return 0;
-               queue_directory(oid->hash, base, filename,
-                               mode, c);
+               queue_directory(oid, base, filename, mode, c);
                return READ_TREE_RECURSIVE;
        }
 
@@ -264,6 +264,7 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 struct extra_file_info {
        char *base;
        struct stat stat;
+       void *content;
 };
 
 int write_archive_entries(struct archiver_args *args,
@@ -332,19 +333,27 @@ int write_archive_entries(struct archiver_args *args,
 
                put_be64(fake_oid.hash, i + 1);
 
-               strbuf_reset(&path_in_archive);
-               if (info->base)
-                       strbuf_addstr(&path_in_archive, info->base);
-               strbuf_addstr(&path_in_archive, basename(path));
-
-               strbuf_reset(&content);
-               if (strbuf_read_file(&content, path, info->stat.st_size) < 0)
-                       err = error_errno(_("could not read '%s'"), path);
-               else
-                       err = write_entry(args, &fake_oid, path_in_archive.buf,
-                                         path_in_archive.len,
-                                         info->stat.st_mode,
-                                         content.buf, content.len);
+               if (!info->content) {
+                       strbuf_reset(&path_in_archive);
+                       if (info->base)
+                               strbuf_addstr(&path_in_archive, info->base);
+                       strbuf_addstr(&path_in_archive, basename(path));
+
+                       strbuf_reset(&content);
+                       if (strbuf_read_file(&content, path, info->stat.st_size) < 0)
+                               err = error_errno(_("cannot read '%s'"), path);
+                       else
+                               err = write_entry(args, &fake_oid, path_in_archive.buf,
+                                                 path_in_archive.len,
+                                                 canon_mode(info->stat.st_mode),
+                                                 content.buf, content.len);
+               } else {
+                       err = write_entry(args, &fake_oid,
+                                         path, strlen(path),
+                                         canon_mode(info->stat.st_mode),
+                                         info->content, info->stat.st_size);
+               }
+
                if (err)
                        break;
        }
@@ -373,7 +382,8 @@ struct path_exists_context {
        struct archiver_args *args;
 };
 
-static int reject_entry(const struct object_id *oid, struct strbuf *base,
+static int reject_entry(const struct object_id *oid UNUSED,
+                       struct strbuf *base,
                        const char *filename, unsigned mode,
                        void *context)
 {
@@ -466,7 +476,7 @@ static void parse_treeish_arg(const char **argv,
        }
 
        tree = parse_tree_indirect(&oid);
-       if (tree == NULL)
+       if (!tree)
                die(_("not a tree object: %s"), oid_to_hex(&oid));
 
        if (prefix) {
@@ -494,6 +504,7 @@ static void extra_file_info_clear(void *util, const char *str)
 {
        struct extra_file_info *info = util;
        free(info->base);
+       free(info->content);
        free(info);
 }
 
@@ -515,14 +526,49 @@ static int add_file_cb(const struct option *opt, const char *arg, int unset)
        if (!arg)
                return -1;
 
-       path = prefix_filename(args->prefix, arg);
-       item = string_list_append_nodup(&args->extra_files, path);
-       item->util = info = xmalloc(sizeof(*info));
+       info = xmalloc(sizeof(*info));
        info->base = xstrdup_or_null(base);
-       if (stat(path, &info->stat))
-               die(_("File not found: %s"), path);
-       if (!S_ISREG(info->stat.st_mode))
-               die(_("Not a regular file: %s"), path);
+
+       if (!strcmp(opt->long_name, "add-file")) {
+               path = prefix_filename(args->prefix, arg);
+               if (stat(path, &info->stat))
+                       die(_("File not found: %s"), path);
+               if (!S_ISREG(info->stat.st_mode))
+                       die(_("Not a regular file: %s"), path);
+               info->content = NULL; /* read the file later */
+       } else if (!strcmp(opt->long_name, "add-virtual-file")) {
+               struct strbuf buf = STRBUF_INIT;
+               const char *p = arg;
+
+               if (*p != '"')
+                       p = strchr(p, ':');
+               else if (unquote_c_style(&buf, p, &p) < 0)
+                       die(_("unclosed quote: '%s'"), arg);
+
+               if (!p || *p != ':')
+                       die(_("missing colon: '%s'"), arg);
+
+               if (p == arg)
+                       die(_("empty file name: '%s'"), arg);
+
+               path = buf.len ?
+                       strbuf_detach(&buf, NULL) : xstrndup(arg, p - arg);
+
+               if (args->prefix) {
+                       char *save = path;
+                       path = prefix_filename(args->prefix, path);
+                       free(save);
+               }
+               memset(&info->stat, 0, sizeof(info->stat));
+               info->stat.st_mode = S_IFREG | 0644;
+               info->content = xstrdup(p + 1);
+               info->stat.st_size = strlen(info->content);
+       } else {
+               BUG("add_file_cb() called for %s", opt->long_name);
+       }
+       item = string_list_append_nodup(&args->extra_files, path);
+       item->util = info;
+
        return 0;
 }
 
@@ -555,6 +601,9 @@ static int parse_archive_args(int argc, const char **argv,
                { OPTION_CALLBACK, 0, "add-file", args, N_("file"),
                  N_("add untracked file to archive"), 0, add_file_cb,
                  (intptr_t)&base },
+               { OPTION_CALLBACK, 0, "add-virtual-file", args,
+                 N_("path:content"), N_("add untracked file to archive"), 0,
+                 add_file_cb, (intptr_t)&base },
                OPT_STRING('o', "output", &output, N_("file"),
                        N_("write the archive to this file")),
                OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
@@ -578,11 +627,11 @@ static int parse_archive_args(int argc, const char **argv,
        if (remote)
                die(_("Unexpected option --remote"));
        if (exec)
-               die(_("Option --exec can only be used together with --remote"));
+               die(_("the option '%s' requires '%s'"), "--exec", "--remote");
        if (output)
                die(_("Unexpected option --output"));
        if (is_remote && args->extra_files.nr)
-               die(_("Options --add-file and --remote cannot be used together"));
+               die(_("options '%s' and '%s' cannot be used together"), "--add-file", "--remote");
 
        if (!base)
                base = "";
@@ -645,7 +694,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
        args.pretty_ctx = &ctx;
        args.repo = repo;
        args.prefix = prefix;
-       string_list_init(&args.extra_files, 1);
+       string_list_init_dup(&args.extra_files);
        argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
        if (!startup_info->have_repository) {
                /*