X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-prune.c;h=bb8ead92cf41c3cbdbc421a1490fb40ce19f11c3;hb=1f1300b4f16591feaa1387e967752af33d4fffda;hp=6228c7907b183fb686c9f4cc54347c3dc16f3ec4;hpb=551029af305e04bed638771a3932e376243dddcb;p=git.git diff --git a/builtin-prune.c b/builtin-prune.c index 6228c7907..bb8ead92c 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -1,27 +1,30 @@ #include "cache.h" -#include "refs.h" -#include "tag.h" #include "commit.h" -#include "tree.h" -#include "blob.h" -#include "tree-walk.h" #include "diff.h" #include "revision.h" #include "builtin.h" -#include "cache-tree.h" +#include "reachable.h" static const char prune_usage[] = "git-prune [-n]"; static int show_only; -static struct rev_info revs; +static unsigned long expire; static int prune_object(char *path, const char *filename, const unsigned char *sha1) { - if (show_only) { - printf("would prune %s/%s\n", path, filename); - return 0; + const char *fullpath = mkpath("%s/%s", path, filename); + if (expire) { + struct stat st; + if (lstat(fullpath, &st)) + return error("Could not stat '%s'", fullpath); + if (st.st_mtime > expire) + return 0; } - unlink(mkpath("%s/%s", path, filename)); - rmdir(path); + if (show_only) { + enum object_type type = sha1_object_info(sha1, NULL); + printf("%s %s\n", sha1_to_hex(sha1), + (type > 0) ? typename(type) : "unknown"); + } else + unlink(fullpath); return 0; } @@ -64,6 +67,8 @@ static int prune_dir(int i, char *path) } fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name); } + if (!show_only) + rmdir(path); closedir(dir); return 0; } @@ -78,148 +83,48 @@ static void prune_object_dir(const char *path) } } -static void process_blob(struct blob *blob, - struct object_array *p, - struct name_path *path, - const char *name) -{ - struct object *obj = &blob->object; - - if (obj->flags & SEEN) - return; - obj->flags |= SEEN; - /* Nothing to do, really .. The blob lookup was the important part */ -} - -static void process_tree(struct tree *tree, - struct object_array *p, - struct name_path *path, - const char *name) +/* + * Write errors (particularly out of space) can result in + * failed temporary packs (and more rarely indexes and other + * files begining with "tmp_") accumulating in the + * object directory. + */ +static void remove_temporary_files(void) { - struct object *obj = &tree->object; - struct tree_desc desc; - struct name_entry entry; - struct name_path me; + DIR *dir; + struct dirent *de; + char* dirname=get_object_directory(); - if (obj->flags & SEEN) + dir = opendir(dirname); + if (!dir) { + fprintf(stderr, "Unable to open object directory %s\n", + dirname); return; - obj->flags |= SEEN; - if (parse_tree(tree) < 0) - die("bad tree object %s", sha1_to_hex(obj->sha1)); - name = xstrdup(name); - add_object(obj, p, path, name); - me.up = path; - me.elem = name; - me.elem_len = strlen(name); - - desc.buf = tree->buffer; - desc.size = tree->size; - - while (tree_entry(&desc, &entry)) { - if (S_ISDIR(entry.mode)) - process_tree(lookup_tree(entry.sha1), p, &me, entry.path); - else - process_blob(lookup_blob(entry.sha1), p, &me, entry.path); } - free(tree->buffer); - tree->buffer = NULL; -} - -static void process_tag(struct tag *tag, struct object_array *p, const char *name) -{ - struct object *obj = &tag->object; - struct name_path me; - - if (obj->flags & SEEN) - return; - obj->flags |= SEEN; - - me.up = NULL; - me.elem = "tag:/"; - me.elem_len = 5; - - if (parse_tag(tag) < 0) - die("bad tag object %s", sha1_to_hex(obj->sha1)); - add_object(tag->tagged, p, NULL, name); -} - -static void walk_commit_list(struct rev_info *revs) -{ - int i; - struct commit *commit; - struct object_array objects = { 0, 0, NULL }; - - /* Walk all commits, process their trees */ - while ((commit = get_revision(revs)) != NULL) - process_tree(commit->tree, &objects, NULL, ""); - - /* Then walk all the pending objects, recursively processing them too */ - for (i = 0; i < revs->pending.nr; i++) { - struct object_array_entry *pending = revs->pending.objects + i; - struct object *obj = pending->item; - const char *name = pending->name; - if (obj->type == OBJ_TAG) { - process_tag((struct tag *) obj, &objects, name); - continue; - } - if (obj->type == OBJ_TREE) { - process_tree((struct tree *)obj, &objects, NULL, name); - continue; - } - if (obj->type == OBJ_BLOB) { - process_blob((struct blob *)obj, &objects, NULL, name); - continue; + while ((de = readdir(dir)) != NULL) { + if (!prefixcmp(de->d_name, "tmp_")) { + char name[PATH_MAX]; + int c = snprintf(name, PATH_MAX, "%s/%s", + dirname, de->d_name); + if (c < 0 || c >= PATH_MAX) + continue; + if (expire) { + struct stat st; + if (stat(name, &st) != 0 || st.st_mtime >= expire) + continue; + } + printf("Removing stale temporary file %s\n", name); + if (!show_only) + unlink(name); } - die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name); } -} - -static int add_one_ref(const char *path, const unsigned char *sha1) -{ - struct object *object = parse_object(sha1); - if (!object) - die("bad object ref: %s:%s", path, sha1_to_hex(sha1)); - add_pending_object(&revs, object, ""); - return 0; -} - -static void add_one_tree(const unsigned char *sha1) -{ - struct tree *tree = lookup_tree(sha1); - add_pending_object(&revs, &tree->object, ""); -} - -static void add_cache_tree(struct cache_tree *it) -{ - int i; - - if (it->entry_count >= 0) - add_one_tree(it->sha1); - for (i = 0; i < it->subtree_nr; i++) - add_cache_tree(it->down[i]->cache_tree); -} - -static void add_cache_refs(void) -{ - int i; - - read_cache(); - for (i = 0; i < active_nr; i++) { - lookup_blob(active_cache[i]->sha1); - /* - * We could add the blobs to the pending list, but quite - * frankly, we don't care. Once we've looked them up, and - * added them as objects, we've really done everything - * there is to do for a blob - */ - } - if (active_cache_tree) - add_cache_tree(active_cache_tree); + closedir(dir); } int cmd_prune(int argc, const char **argv, const char *prefix) { int i; + struct rev_info revs; for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -227,33 +132,27 @@ int cmd_prune(int argc, const char **argv, const char *prefix) show_only = 1; continue; } + if (!strcmp(arg, "--expire")) { + if (++i < argc) { + expire = approxidate(argv[i]); + continue; + } + } + else if (!prefixcmp(arg, "--expire=")) { + expire = approxidate(arg + 9); + continue; + } usage(prune_usage); } - /* - * Set up revision parsing, and mark us as being interested - * in all object types, not just commits. - */ + save_commit_buffer = 0; init_revisions(&revs, prefix); - revs.tag_objects = 1; - revs.blob_objects = 1; - revs.tree_objects = 1; - - /* Add all external refs */ - for_each_ref(add_one_ref); - - /* Add all refs from the index file */ - add_cache_refs(); - - /* - * Set up the revision walk - this will move all commits - * from the pending list to the commit walking list. - */ - prepare_revision_walk(&revs); - - walk_commit_list(&revs); + mark_reachable_objects(&revs, 1); prune_object_dir(get_object_directory()); + sync(); + prune_packed_objects(show_only); + remove_temporary_files(); return 0; }