Merge branch 'tb/repack-simplify'
Simplify the logic to deal with a repack operation that ended up creating the same packfile. * tb/repack-simplify: builtin/repack.c: don't move existing packs out of the way builtin/repack.c: keep track of what pack-objects wrote repack: make "exts" array available outside cmd_repack()
This commit is contained in:
commit
39d38a5c5f
153
builtin/repack.c
153
builtin/repack.c
@ -202,6 +202,37 @@ static int write_oid(const struct object_id *oid, struct packed_git *pack,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
unsigned optional:1;
|
||||
} exts[] = {
|
||||
{".pack"},
|
||||
{".idx"},
|
||||
{".bitmap", 1},
|
||||
{".promisor", 1},
|
||||
};
|
||||
|
||||
static unsigned populate_pack_exts(char *name)
|
||||
{
|
||||
struct stat statbuf;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
unsigned ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(exts); i++) {
|
||||
strbuf_reset(&path);
|
||||
strbuf_addf(&path, "%s-%s%s", packtmp, name, exts[i].name);
|
||||
|
||||
if (stat(path.buf, &statbuf))
|
||||
continue;
|
||||
|
||||
ret |= (1 << i);
|
||||
}
|
||||
|
||||
strbuf_release(&path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void repack_promisor_objects(const struct pack_objects_args *args,
|
||||
struct string_list *names)
|
||||
{
|
||||
@ -230,11 +261,12 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
|
||||
|
||||
out = xfdopen(cmd.out, "r");
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
struct string_list_item *item;
|
||||
char *promisor_name;
|
||||
int fd;
|
||||
if (line.len != the_hash_algo->hexsz)
|
||||
die(_("repack: Expecting full hex object ID lines only from pack-objects."));
|
||||
string_list_append(names, line.buf);
|
||||
item = string_list_append(names, line.buf);
|
||||
|
||||
/*
|
||||
* pack-objects creates the .pack and .idx files, but not the
|
||||
@ -253,6 +285,9 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
|
||||
if (fd < 0)
|
||||
die_errno(_("unable to create '%s'"), promisor_name);
|
||||
close(fd);
|
||||
|
||||
item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
|
||||
|
||||
free(promisor_name);
|
||||
}
|
||||
fclose(out);
|
||||
@ -265,22 +300,13 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
|
||||
|
||||
int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct {
|
||||
const char *name;
|
||||
unsigned optional:1;
|
||||
} exts[] = {
|
||||
{".pack"},
|
||||
{".idx"},
|
||||
{".bitmap", 1},
|
||||
{".promisor", 1},
|
||||
};
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
struct string_list_item *item;
|
||||
struct string_list names = STRING_LIST_INIT_DUP;
|
||||
struct string_list rollback = STRING_LIST_INIT_NODUP;
|
||||
struct string_list existing_packs = STRING_LIST_INIT_DUP;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
int i, ext, ret, failed;
|
||||
int i, ext, ret;
|
||||
FILE *out;
|
||||
|
||||
/* variables to be filled by option parsing */
|
||||
@ -429,113 +455,42 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
if (!names.nr && !po_args.quiet)
|
||||
printf_ln(_("Nothing new to pack."));
|
||||
|
||||
for_each_string_list_item(item, &names) {
|
||||
item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
|
||||
}
|
||||
|
||||
close_object_store(the_repository->objects);
|
||||
|
||||
/*
|
||||
* Ok we have prepared all new packfiles.
|
||||
* First see if there are packs of the same name and if so
|
||||
* if we can move them out of the way (this can happen if we
|
||||
* repacked immediately after packing fully.
|
||||
*/
|
||||
failed = 0;
|
||||
for_each_string_list_item(item, &names) {
|
||||
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
|
||||
char *fname, *fname_old;
|
||||
|
||||
fname = mkpathdup("%s/pack-%s%s", packdir,
|
||||
item->string, exts[ext].name);
|
||||
if (!file_exists(fname)) {
|
||||
free(fname);
|
||||
continue;
|
||||
}
|
||||
|
||||
fname_old = mkpathdup("%s/old-%s%s", packdir,
|
||||
item->string, exts[ext].name);
|
||||
if (file_exists(fname_old))
|
||||
if (unlink(fname_old))
|
||||
failed = 1;
|
||||
|
||||
if (!failed && rename(fname, fname_old)) {
|
||||
free(fname);
|
||||
free(fname_old);
|
||||
failed = 1;
|
||||
break;
|
||||
} else {
|
||||
string_list_append(&rollback, fname);
|
||||
free(fname_old);
|
||||
}
|
||||
}
|
||||
if (failed)
|
||||
break;
|
||||
}
|
||||
if (failed) {
|
||||
struct string_list rollback_failure = STRING_LIST_INIT_DUP;
|
||||
for_each_string_list_item(item, &rollback) {
|
||||
char *fname, *fname_old;
|
||||
fname = mkpathdup("%s/%s", packdir, item->string);
|
||||
fname_old = mkpathdup("%s/old-%s", packdir, item->string);
|
||||
if (rename(fname_old, fname))
|
||||
string_list_append(&rollback_failure, fname);
|
||||
free(fname);
|
||||
free(fname_old);
|
||||
}
|
||||
|
||||
if (rollback_failure.nr) {
|
||||
int i;
|
||||
fprintf(stderr,
|
||||
_("WARNING: Some packs in use have been renamed by\n"
|
||||
"WARNING: prefixing old- to their name, in order to\n"
|
||||
"WARNING: replace them with the new version of the\n"
|
||||
"WARNING: file. But the operation failed, and the\n"
|
||||
"WARNING: attempt to rename them back to their\n"
|
||||
"WARNING: original names also failed.\n"
|
||||
"WARNING: Please rename them in %s manually:\n"), packdir);
|
||||
for (i = 0; i < rollback_failure.nr; i++)
|
||||
fprintf(stderr, "WARNING: old-%s -> %s\n",
|
||||
rollback_failure.items[i].string,
|
||||
rollback_failure.items[i].string);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now the ones with the same name are out of the way... */
|
||||
for_each_string_list_item(item, &names) {
|
||||
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
|
||||
char *fname, *fname_old;
|
||||
struct stat statbuffer;
|
||||
int exists = 0;
|
||||
fname = mkpathdup("%s/pack-%s%s",
|
||||
packdir, item->string, exts[ext].name);
|
||||
fname_old = mkpathdup("%s-%s%s",
|
||||
packtmp, item->string, exts[ext].name);
|
||||
if (!stat(fname_old, &statbuffer)) {
|
||||
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||
chmod(fname_old, statbuffer.st_mode);
|
||||
exists = 1;
|
||||
}
|
||||
if (exists || !exts[ext].optional) {
|
||||
|
||||
if (((uintptr_t)item->util) & (1 << ext)) {
|
||||
struct stat statbuffer;
|
||||
if (!stat(fname_old, &statbuffer)) {
|
||||
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||
chmod(fname_old, statbuffer.st_mode);
|
||||
}
|
||||
|
||||
if (rename(fname_old, fname))
|
||||
die_errno(_("renaming '%s' failed"), fname_old);
|
||||
}
|
||||
} else if (!exts[ext].optional)
|
||||
die(_("missing required file: %s"), fname_old);
|
||||
else if (unlink(fname) < 0 && errno != ENOENT)
|
||||
die_errno(_("could not unlink: %s"), fname);
|
||||
|
||||
free(fname);
|
||||
free(fname_old);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the "old-" files */
|
||||
for_each_string_list_item(item, &names) {
|
||||
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
|
||||
char *fname;
|
||||
fname = mkpathdup("%s/old-%s%s",
|
||||
packdir,
|
||||
item->string,
|
||||
exts[ext].name);
|
||||
if (remove_path(fname))
|
||||
warning(_("failed to remove '%s'"), fname);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
|
||||
/* End of pack replacement. */
|
||||
|
||||
reprepare_packed_git(the_repository);
|
||||
|
Loading…
Reference in New Issue
Block a user