mirror of
https://github.com/git/git
synced 2024-08-25 02:35:46 +00:00
Merge branch 'rs/archive-add-file'
"git archive" learns the "--add-file" option to include untracked files into a snapshot from a tree-ish. * rs/archive-add-file: Makefile: use git-archive --add-file archive: add --add-file archive: read short blobs in archive.c::write_archive_entry()
This commit is contained in:
commit
f6b06b4590
|
@ -55,6 +55,12 @@ OPTIONS
|
||||||
--output=<file>::
|
--output=<file>::
|
||||||
Write the archive to <file> instead of stdout.
|
Write the archive to <file> instead of stdout.
|
||||||
|
|
||||||
|
--add-file=<file>::
|
||||||
|
Add a non-tracked file to the archive. Can be repeated to add
|
||||||
|
multiple files. The path of the file in the archive is built
|
||||||
|
by concatenating the value for `--prefix` (if any) and the
|
||||||
|
basename of <file>.
|
||||||
|
|
||||||
--worktree-attributes::
|
--worktree-attributes::
|
||||||
Look for attributes in .gitattributes files in the working tree
|
Look for attributes in .gitattributes files in the working tree
|
||||||
as well (see <<ATTRIBUTES>>).
|
as well (see <<ATTRIBUTES>>).
|
||||||
|
|
41
Makefile
41
Makefile
|
@ -3057,32 +3057,29 @@ quick-install-html:
|
||||||
# With GNU tar, "--mode=u+rwX,og+rX,og-w" would be a good idea, for example.
|
# With GNU tar, "--mode=u+rwX,og+rX,og-w" would be a good idea, for example.
|
||||||
TAR_DIST_EXTRA_OPTS =
|
TAR_DIST_EXTRA_OPTS =
|
||||||
GIT_TARNAME = git-$(GIT_VERSION)
|
GIT_TARNAME = git-$(GIT_VERSION)
|
||||||
|
GIT_ARCHIVE_EXTRA_FILES = \
|
||||||
|
--prefix=$(GIT_TARNAME)/ \
|
||||||
|
--add-file=configure \
|
||||||
|
--add-file=$(GIT_TARNAME)/version \
|
||||||
|
--prefix=$(GIT_TARNAME)/git-gui/ \
|
||||||
|
--add-file=$(GIT_TARNAME)/git-gui/version
|
||||||
|
ifdef DC_SHA1_SUBMODULE
|
||||||
|
GIT_ARCHIVE_EXTRA_FILES += \
|
||||||
|
--prefix=$(GIT_TARNAME)/sha1collisiondetection/ \
|
||||||
|
--add-file=sha1collisiondetection/LICENSE.txt \
|
||||||
|
--prefix=$(GIT_TARNAME)/sha1collisiondetection/lib/ \
|
||||||
|
--add-file=sha1collisiondetection/lib/sha1.c \
|
||||||
|
--add-file=sha1collisiondetection/lib/sha1.h \
|
||||||
|
--add-file=sha1collisiondetection/lib/ubc_check.c \
|
||||||
|
--add-file=sha1collisiondetection/lib/ubc_check.h
|
||||||
|
endif
|
||||||
dist: git-archive$(X) configure
|
dist: git-archive$(X) configure
|
||||||
./git-archive --format=tar \
|
|
||||||
--prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
|
|
||||||
@mkdir -p $(GIT_TARNAME)
|
@mkdir -p $(GIT_TARNAME)
|
||||||
@cp configure $(GIT_TARNAME)
|
|
||||||
@echo $(GIT_VERSION) > $(GIT_TARNAME)/version
|
@echo $(GIT_VERSION) > $(GIT_TARNAME)/version
|
||||||
@$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
|
@$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
|
||||||
$(TAR) rf $(GIT_TARNAME).tar $(TAR_DIST_EXTRA_OPTS) \
|
./git-archive --format=tar \
|
||||||
$(GIT_TARNAME)/configure \
|
$(GIT_ARCHIVE_EXTRA_FILES) \
|
||||||
$(GIT_TARNAME)/version \
|
--prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
|
||||||
$(GIT_TARNAME)/git-gui/version
|
|
||||||
ifdef DC_SHA1_SUBMODULE
|
|
||||||
@mkdir -p $(GIT_TARNAME)/sha1collisiondetection/lib
|
|
||||||
@cp sha1collisiondetection/LICENSE.txt \
|
|
||||||
$(GIT_TARNAME)/sha1collisiondetection/
|
|
||||||
@cp sha1collisiondetection/LICENSE.txt \
|
|
||||||
$(GIT_TARNAME)/sha1collisiondetection/
|
|
||||||
@cp sha1collisiondetection/lib/sha1.[ch] \
|
|
||||||
$(GIT_TARNAME)/sha1collisiondetection/lib/
|
|
||||||
@cp sha1collisiondetection/lib/ubc_check.[ch] \
|
|
||||||
$(GIT_TARNAME)/sha1collisiondetection/lib/
|
|
||||||
$(TAR) rf $(GIT_TARNAME).tar $(TAR_DIST_EXTRA_OPTS) \
|
|
||||||
$(GIT_TARNAME)/sha1collisiondetection/LICENSE.txt \
|
|
||||||
$(GIT_TARNAME)/sha1collisiondetection/lib/sha1.[ch] \
|
|
||||||
$(GIT_TARNAME)/sha1collisiondetection/lib/ubc_check.[ch]
|
|
||||||
endif
|
|
||||||
@$(RM) -r $(GIT_TARNAME)
|
@$(RM) -r $(GIT_TARNAME)
|
||||||
gzip -f -9 $(GIT_TARNAME).tar
|
gzip -f -9 $(GIT_TARNAME).tar
|
||||||
|
|
||||||
|
|
|
@ -242,13 +242,12 @@ static void write_extended_header(struct archiver_args *args,
|
||||||
static int write_tar_entry(struct archiver_args *args,
|
static int write_tar_entry(struct archiver_args *args,
|
||||||
const struct object_id *oid,
|
const struct object_id *oid,
|
||||||
const char *path, size_t pathlen,
|
const char *path, size_t pathlen,
|
||||||
unsigned int mode)
|
unsigned int mode,
|
||||||
|
void *buffer, unsigned long size)
|
||||||
{
|
{
|
||||||
struct ustar_header header;
|
struct ustar_header header;
|
||||||
struct strbuf ext_header = STRBUF_INIT;
|
struct strbuf ext_header = STRBUF_INIT;
|
||||||
unsigned int old_mode = mode;
|
unsigned long size_in_header;
|
||||||
unsigned long size, size_in_header;
|
|
||||||
void *buffer;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
|
@ -282,20 +281,6 @@ static int write_tar_entry(struct archiver_args *args,
|
||||||
} else
|
} else
|
||||||
memcpy(header.name, path, pathlen);
|
memcpy(header.name, path, pathlen);
|
||||||
|
|
||||||
if (S_ISREG(mode) && !args->convert &&
|
|
||||||
oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
|
|
||||||
size > big_file_threshold)
|
|
||||||
buffer = NULL;
|
|
||||||
else if (S_ISLNK(mode) || S_ISREG(mode)) {
|
|
||||||
enum object_type type;
|
|
||||||
buffer = object_file_to_archive(args, path, oid, old_mode, &type, &size);
|
|
||||||
if (!buffer)
|
|
||||||
return error(_("cannot read %s"), oid_to_hex(oid));
|
|
||||||
} else {
|
|
||||||
buffer = NULL;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISLNK(mode)) {
|
if (S_ISLNK(mode)) {
|
||||||
if (size > sizeof(header.linkname)) {
|
if (size > sizeof(header.linkname)) {
|
||||||
xsnprintf(header.linkname, sizeof(header.linkname),
|
xsnprintf(header.linkname, sizeof(header.linkname),
|
||||||
|
@ -326,7 +311,6 @@ static int write_tar_entry(struct archiver_args *args,
|
||||||
else
|
else
|
||||||
err = stream_blocked(args->repo, oid);
|
err = stream_blocked(args->repo, oid);
|
||||||
}
|
}
|
||||||
free(buffer);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,8 @@ static int entry_is_binary(struct index_state *istate, const char *path,
|
||||||
static int write_zip_entry(struct archiver_args *args,
|
static int write_zip_entry(struct archiver_args *args,
|
||||||
const struct object_id *oid,
|
const struct object_id *oid,
|
||||||
const char *path, size_t pathlen,
|
const char *path, size_t pathlen,
|
||||||
unsigned int mode)
|
unsigned int mode,
|
||||||
|
void *buffer, unsigned long size)
|
||||||
{
|
{
|
||||||
struct zip_local_header header;
|
struct zip_local_header header;
|
||||||
uintmax_t offset = zip_offset;
|
uintmax_t offset = zip_offset;
|
||||||
|
@ -299,10 +300,8 @@ static int write_zip_entry(struct archiver_args *args,
|
||||||
enum zip_method method;
|
enum zip_method method;
|
||||||
unsigned char *out;
|
unsigned char *out;
|
||||||
void *deflated = NULL;
|
void *deflated = NULL;
|
||||||
void *buffer;
|
|
||||||
struct git_istream *stream = NULL;
|
struct git_istream *stream = NULL;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
unsigned long size;
|
|
||||||
int is_binary = -1;
|
int is_binary = -1;
|
||||||
const char *path_without_prefix = path + args->baselen;
|
const char *path_without_prefix = path + args->baselen;
|
||||||
unsigned int creator_version = 0;
|
unsigned int creator_version = 0;
|
||||||
|
@ -328,13 +327,8 @@ static int write_zip_entry(struct archiver_args *args,
|
||||||
method = ZIP_METHOD_STORE;
|
method = ZIP_METHOD_STORE;
|
||||||
attr2 = 16;
|
attr2 = 16;
|
||||||
out = NULL;
|
out = NULL;
|
||||||
size = 0;
|
|
||||||
compressed_size = 0;
|
compressed_size = 0;
|
||||||
buffer = NULL;
|
|
||||||
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
|
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
|
||||||
enum object_type type = oid_object_info(args->repo, oid,
|
|
||||||
&size);
|
|
||||||
|
|
||||||
method = ZIP_METHOD_STORE;
|
method = ZIP_METHOD_STORE;
|
||||||
attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
|
attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
|
||||||
(mode & 0111) ? ((mode) << 16) : 0;
|
(mode & 0111) ? ((mode) << 16) : 0;
|
||||||
|
@ -343,21 +337,16 @@ static int write_zip_entry(struct archiver_args *args,
|
||||||
if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
|
if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
|
||||||
method = ZIP_METHOD_DEFLATE;
|
method = ZIP_METHOD_DEFLATE;
|
||||||
|
|
||||||
if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
|
if (!buffer) {
|
||||||
size > big_file_threshold) {
|
enum object_type type;
|
||||||
stream = open_istream(args->repo, oid, &type, &size,
|
stream = open_istream(args->repo, oid, &type, &size,
|
||||||
NULL);
|
NULL);
|
||||||
if (!stream)
|
if (!stream)
|
||||||
return error(_("cannot stream blob %s"),
|
return error(_("cannot stream blob %s"),
|
||||||
oid_to_hex(oid));
|
oid_to_hex(oid));
|
||||||
flags |= ZIP_STREAM;
|
flags |= ZIP_STREAM;
|
||||||
out = buffer = NULL;
|
out = NULL;
|
||||||
} else {
|
} else {
|
||||||
buffer = object_file_to_archive(args, path, oid, mode,
|
|
||||||
&type, &size);
|
|
||||||
if (!buffer)
|
|
||||||
return error(_("cannot read %s"),
|
|
||||||
oid_to_hex(oid));
|
|
||||||
crc = crc32(crc, buffer, size);
|
crc = crc32(crc, buffer, size);
|
||||||
is_binary = entry_is_binary(args->repo->index,
|
is_binary = entry_is_binary(args->repo->index,
|
||||||
path_without_prefix,
|
path_without_prefix,
|
||||||
|
@ -511,7 +500,6 @@ static int write_zip_entry(struct archiver_args *args,
|
||||||
}
|
}
|
||||||
|
|
||||||
free(deflated);
|
free(deflated);
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
if (compressed_size > 0xffffffff || size > 0xffffffff ||
|
if (compressed_size > 0xffffffff || size > 0xffffffff ||
|
||||||
offset > 0xffffffff) {
|
offset > 0xffffffff) {
|
||||||
|
|
117
archive.c
117
archive.c
|
@ -70,10 +70,12 @@ static void format_subst(const struct commit *commit,
|
||||||
free(to_free);
|
free(to_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *object_file_to_archive(const struct archiver_args *args,
|
static void *object_file_to_archive(const struct archiver_args *args,
|
||||||
const char *path, const struct object_id *oid,
|
const char *path,
|
||||||
unsigned int mode, enum object_type *type,
|
const struct object_id *oid,
|
||||||
unsigned long *sizep)
|
unsigned int mode,
|
||||||
|
enum object_type *type,
|
||||||
|
unsigned long *sizep)
|
||||||
{
|
{
|
||||||
void *buffer;
|
void *buffer;
|
||||||
const struct commit *commit = args->convert ? args->commit : NULL;
|
const struct commit *commit = args->convert ? args->commit : NULL;
|
||||||
|
@ -145,6 +147,9 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
|
||||||
write_archive_entry_fn_t write_entry = c->write_entry;
|
write_archive_entry_fn_t write_entry = c->write_entry;
|
||||||
int err;
|
int err;
|
||||||
const char *path_without_prefix;
|
const char *path_without_prefix;
|
||||||
|
unsigned long size;
|
||||||
|
void *buffer;
|
||||||
|
enum object_type type;
|
||||||
|
|
||||||
args->convert = 0;
|
args->convert = 0;
|
||||||
strbuf_reset(&path);
|
strbuf_reset(&path);
|
||||||
|
@ -167,7 +172,7 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
|
||||||
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
||||||
err = write_entry(args, oid, path.buf, path.len, mode);
|
err = write_entry(args, oid, path.buf, path.len, mode, NULL, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
|
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
|
||||||
|
@ -175,7 +180,19 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
|
||||||
|
|
||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
||||||
return write_entry(args, oid, path.buf, path.len, mode);
|
|
||||||
|
/* Stream it? */
|
||||||
|
if (S_ISREG(mode) && !args->convert &&
|
||||||
|
oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
|
||||||
|
size > big_file_threshold)
|
||||||
|
return write_entry(args, oid, path.buf, path.len, mode, NULL, size);
|
||||||
|
|
||||||
|
buffer = object_file_to_archive(args, path.buf, oid, mode, &type, &size);
|
||||||
|
if (!buffer)
|
||||||
|
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 unsigned char *sha1,
|
||||||
|
@ -249,6 +266,11 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
|
||||||
stage, context);
|
stage, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct extra_file_info {
|
||||||
|
char *base;
|
||||||
|
struct stat stat;
|
||||||
|
};
|
||||||
|
|
||||||
int write_archive_entries(struct archiver_args *args,
|
int write_archive_entries(struct archiver_args *args,
|
||||||
write_archive_entry_fn_t write_entry)
|
write_archive_entry_fn_t write_entry)
|
||||||
{
|
{
|
||||||
|
@ -256,6 +278,10 @@ int write_archive_entries(struct archiver_args *args,
|
||||||
struct unpack_trees_options opts;
|
struct unpack_trees_options opts;
|
||||||
struct tree_desc t;
|
struct tree_desc t;
|
||||||
int err;
|
int err;
|
||||||
|
struct strbuf path_in_archive = STRBUF_INIT;
|
||||||
|
struct strbuf content = STRBUF_INIT;
|
||||||
|
struct object_id fake_oid = null_oid;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
|
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
|
||||||
size_t len = args->baselen;
|
size_t len = args->baselen;
|
||||||
|
@ -265,7 +291,7 @@ int write_archive_entries(struct archiver_args *args,
|
||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
fprintf(stderr, "%.*s\n", (int)len, args->base);
|
fprintf(stderr, "%.*s\n", (int)len, args->base);
|
||||||
err = write_entry(args, &args->tree->object.oid, args->base,
|
err = write_entry(args, &args->tree->object.oid, args->base,
|
||||||
len, 040777);
|
len, 040777, NULL, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -301,6 +327,33 @@ int write_archive_entries(struct archiver_args *args,
|
||||||
free(context.bottom);
|
free(context.bottom);
|
||||||
context.bottom = next;
|
context.bottom = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < args->extra_files.nr; i++) {
|
||||||
|
struct string_list_item *item = args->extra_files.items + i;
|
||||||
|
char *path = item->string;
|
||||||
|
struct extra_file_info *info = item->util;
|
||||||
|
|
||||||
|
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 (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strbuf_release(&path_in_archive);
|
||||||
|
strbuf_release(&content);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,6 +493,42 @@ static void parse_treeish_arg(const char **argv,
|
||||||
ar_args->time = archive_time;
|
ar_args->time = archive_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void extra_file_info_clear(void *util, const char *str)
|
||||||
|
{
|
||||||
|
struct extra_file_info *info = util;
|
||||||
|
free(info->base);
|
||||||
|
free(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_file_cb(const struct option *opt, const char *arg, int unset)
|
||||||
|
{
|
||||||
|
struct archiver_args *args = opt->value;
|
||||||
|
const char **basep = (const char **)opt->defval;
|
||||||
|
const char *base = *basep;
|
||||||
|
char *path;
|
||||||
|
struct string_list_item *item;
|
||||||
|
struct extra_file_info *info;
|
||||||
|
|
||||||
|
if (unset) {
|
||||||
|
string_list_clear_func(&args->extra_files,
|
||||||
|
extra_file_info_clear);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define OPT__COMPR(s, v, h, p) \
|
#define OPT__COMPR(s, v, h, p) \
|
||||||
OPT_SET_INT_F(s, NULL, v, h, p, PARSE_OPT_NONEG)
|
OPT_SET_INT_F(s, NULL, v, h, p, PARSE_OPT_NONEG)
|
||||||
#define OPT__COMPR_HIDDEN(s, v, p) \
|
#define OPT__COMPR_HIDDEN(s, v, p) \
|
||||||
|
@ -464,6 +553,9 @@ static int parse_archive_args(int argc, const char **argv,
|
||||||
OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
|
OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
|
||||||
OPT_STRING(0, "prefix", &base, N_("prefix"),
|
OPT_STRING(0, "prefix", &base, N_("prefix"),
|
||||||
N_("prepend prefix to each pathname in the archive")),
|
N_("prepend prefix to each pathname in the archive")),
|
||||||
|
{ OPTION_CALLBACK, 0, "add-file", args, N_("file"),
|
||||||
|
N_("add untracked file to archive"), 0, add_file_cb,
|
||||||
|
(intptr_t)&base },
|
||||||
OPT_STRING('o', "output", &output, N_("file"),
|
OPT_STRING('o', "output", &output, N_("file"),
|
||||||
N_("write the archive to this file")),
|
N_("write the archive to this file")),
|
||||||
OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
|
OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
|
||||||
|
@ -498,6 +590,8 @@ static int parse_archive_args(int argc, const char **argv,
|
||||||
die(_("Option --exec can only be used together with --remote"));
|
die(_("Option --exec can only be used together with --remote"));
|
||||||
if (output)
|
if (output)
|
||||||
die(_("Unexpected option --output"));
|
die(_("Unexpected option --output"));
|
||||||
|
if (is_remote && args->extra_files.nr)
|
||||||
|
die(_("Options --add-file and --remote cannot be used together"));
|
||||||
|
|
||||||
if (!base)
|
if (!base)
|
||||||
base = "";
|
base = "";
|
||||||
|
@ -544,11 +638,14 @@ int write_archive(int argc, const char **argv, const char *prefix,
|
||||||
{
|
{
|
||||||
const struct archiver *ar = NULL;
|
const struct archiver *ar = NULL;
|
||||||
struct archiver_args args;
|
struct archiver_args args;
|
||||||
|
int rc;
|
||||||
|
|
||||||
git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
|
git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
|
||||||
git_config(git_default_config, NULL);
|
git_config(git_default_config, NULL);
|
||||||
|
|
||||||
args.repo = repo;
|
args.repo = repo;
|
||||||
|
args.prefix = prefix;
|
||||||
|
string_list_init(&args.extra_files, 1);
|
||||||
argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
|
argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
|
||||||
if (!startup_info->have_repository) {
|
if (!startup_info->have_repository) {
|
||||||
/*
|
/*
|
||||||
|
@ -562,7 +659,11 @@ int write_archive(int argc, const char **argv, const char *prefix,
|
||||||
parse_treeish_arg(argv, &args, prefix, remote);
|
parse_treeish_arg(argv, &args, prefix, remote);
|
||||||
parse_pathspec_arg(argv + 1, &args);
|
parse_pathspec_arg(argv + 1, &args);
|
||||||
|
|
||||||
return ar->write_archive(ar, &args);
|
rc = ar->write_archive(ar, &args);
|
||||||
|
|
||||||
|
string_list_clear_func(&args.extra_files, extra_file_info_clear);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int match_extension(const char *filename, const char *ext)
|
static int match_extension(const char *filename, const char *ext)
|
||||||
|
|
|
@ -9,6 +9,7 @@ struct repository;
|
||||||
struct archiver_args {
|
struct archiver_args {
|
||||||
struct repository *repo;
|
struct repository *repo;
|
||||||
const char *refname;
|
const char *refname;
|
||||||
|
const char *prefix;
|
||||||
const char *base;
|
const char *base;
|
||||||
size_t baselen;
|
size_t baselen;
|
||||||
struct tree *tree;
|
struct tree *tree;
|
||||||
|
@ -20,6 +21,7 @@ struct archiver_args {
|
||||||
unsigned int worktree_attributes : 1;
|
unsigned int worktree_attributes : 1;
|
||||||
unsigned int convert : 1;
|
unsigned int convert : 1;
|
||||||
int compression_level;
|
int compression_level;
|
||||||
|
struct string_list extra_files;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* main api */
|
/* main api */
|
||||||
|
@ -49,12 +51,9 @@ void init_archivers(void);
|
||||||
typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
|
typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
|
||||||
const struct object_id *oid,
|
const struct object_id *oid,
|
||||||
const char *path, size_t pathlen,
|
const char *path, size_t pathlen,
|
||||||
unsigned int mode);
|
unsigned int mode,
|
||||||
|
void *buffer, unsigned long size);
|
||||||
|
|
||||||
int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
|
int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
|
||||||
void *object_file_to_archive(const struct archiver_args *args,
|
|
||||||
const char *path, const struct object_id *oid,
|
|
||||||
unsigned int mode, enum object_type *type,
|
|
||||||
unsigned long *sizep);
|
|
||||||
|
|
||||||
#endif /* ARCHIVE_H */
|
#endif /* ARCHIVE_H */
|
||||||
|
|
|
@ -94,6 +94,16 @@ check_tar() {
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_added() {
|
||||||
|
dir=$1
|
||||||
|
path_in_fs=$2
|
||||||
|
path_in_archive=$3
|
||||||
|
|
||||||
|
test_expect_success " validate extra file $path_in_archive" '
|
||||||
|
diff -r $path_in_fs $dir/$path_in_archive
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
test_expect_success 'setup' '
|
test_expect_success 'setup' '
|
||||||
test_oid_cache <<-EOF
|
test_oid_cache <<-EOF
|
||||||
obj sha1:19f9c8273ec45a8938e6999cb59b3ff66739902a
|
obj sha1:19f9c8273ec45a8938e6999cb59b3ff66739902a
|
||||||
|
@ -164,6 +174,25 @@ test_expect_success 'git-archive --prefix=olde-' '
|
||||||
|
|
||||||
check_tar with_olde-prefix olde-
|
check_tar with_olde-prefix olde-
|
||||||
|
|
||||||
|
test_expect_success 'git archive --add-file' '
|
||||||
|
echo untracked >untracked &&
|
||||||
|
git archive --add-file=untracked HEAD >with_untracked.tar
|
||||||
|
'
|
||||||
|
|
||||||
|
check_tar with_untracked
|
||||||
|
check_added with_untracked untracked untracked
|
||||||
|
|
||||||
|
test_expect_success 'git archive --add-file twice' '
|
||||||
|
echo untracked >untracked &&
|
||||||
|
git archive --prefix=one/ --add-file=untracked \
|
||||||
|
--prefix=two/ --add-file=untracked \
|
||||||
|
--prefix= HEAD >with_untracked2.tar
|
||||||
|
'
|
||||||
|
|
||||||
|
check_tar with_untracked2
|
||||||
|
check_added with_untracked2 untracked one/untracked
|
||||||
|
check_added with_untracked2 untracked two/untracked
|
||||||
|
|
||||||
test_expect_success 'git archive on large files' '
|
test_expect_success 'git archive on large files' '
|
||||||
test_config core.bigfilethreshold 1 &&
|
test_config core.bigfilethreshold 1 &&
|
||||||
git archive HEAD >b3.tar &&
|
git archive HEAD >b3.tar &&
|
||||||
|
|
|
@ -72,6 +72,16 @@ check_zip() {
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_added() {
|
||||||
|
dir=$1
|
||||||
|
path_in_fs=$2
|
||||||
|
path_in_archive=$3
|
||||||
|
|
||||||
|
test_expect_success UNZIP " validate extra file $path_in_archive" '
|
||||||
|
diff -r $path_in_fs $dir/$path_in_archive
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'populate workdir' \
|
'populate workdir' \
|
||||||
'mkdir a &&
|
'mkdir a &&
|
||||||
|
@ -188,4 +198,22 @@ test_expect_success 'git archive --format=zip on large files' '
|
||||||
|
|
||||||
check_zip large-compressed
|
check_zip large-compressed
|
||||||
|
|
||||||
|
test_expect_success 'git archive --format=zip --add-file' '
|
||||||
|
echo untracked >untracked &&
|
||||||
|
git archive --format=zip --add-file=untracked HEAD >with_untracked.zip
|
||||||
|
'
|
||||||
|
|
||||||
|
check_zip with_untracked
|
||||||
|
check_added with_untracked untracked untracked
|
||||||
|
|
||||||
|
test_expect_success 'git archive --format=zip --add-file twice' '
|
||||||
|
echo untracked >untracked &&
|
||||||
|
git archive --format=zip --prefix=one/ --add-file=untracked \
|
||||||
|
--prefix=two/ --add-file=untracked \
|
||||||
|
--prefix= HEAD >with_untracked2.zip
|
||||||
|
'
|
||||||
|
check_zip with_untracked2
|
||||||
|
check_added with_untracked2 untracked one/untracked
|
||||||
|
check_added with_untracked2 untracked two/untracked
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
Loading…
Reference in a new issue