]> git.ipfire.org Git - thirdparty/git.git/blobdiff - archive.c
unicode: update the width tables to Unicode 15.1
[thirdparty/git.git] / archive.c
index a3bbb091256dd7077e257f20f532d47516e4a960..9aeaf2bd87dfb884479f6e6a1b609d082ac39896 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
@@ -119,7 +120,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;
 }
 
@@ -165,18 +166,16 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
                args->convert = check_attr_export_subst(check);
        }
 
+       if (args->verbose)
+               fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
+
        if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
-               if (args->verbose)
-                       fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
                err = write_entry(args, oid, path.buf, path.len, mode, NULL, 0);
                if (err)
                        return err;
                return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
        }
 
-       if (args->verbose)
-               fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
-
        /* Stream it? */
        if (S_ISREG(mode) && !args->convert &&
            oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
@@ -185,7 +184,7 @@ 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;
@@ -263,6 +262,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,
@@ -331,19 +331,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;
        }
@@ -372,7 +380,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)
 {
@@ -463,9 +472,11 @@ 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 == NULL)
+       if (!tree)
                die(_("not a tree object: %s"), oid_to_hex(&oid));
 
        if (prefix) {
@@ -489,10 +500,11 @@ 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);
+       free(info->content);
        free(info);
 }
 
@@ -514,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;
 }
 
@@ -541,6 +588,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;
@@ -554,11 +602,17 @@ 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,
                        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(""),
@@ -577,11 +631,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 = "";
@@ -620,6 +674,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;
 }
@@ -662,6 +717,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
 
        string_list_clear_func(&args.extra_files, extra_file_info_clear);
        free(args.refname);
+       clear_pathspec(&args.pathspec);
 
        return rc;
 }