bash-completion: Add comments to remind about required arguments
[gitweb.git] / builtin-prune.c
index b5e768421ba548efaf0dd62ca876c15911df55d2..7b4ec80e62997fe70f53c92380cd4d66e80d62a0 100644 (file)
@@ -4,11 +4,32 @@
 #include "revision.h"
 #include "builtin.h"
 #include "reachable.h"
+#include "parse-options.h"
 
-static const char prune_usage[] = "git-prune [-n]";
+static const char * const prune_usage[] = {
+       "git prune [-n] [-v] [--expire <time>] [--] [<head>...]",
+       NULL
+};
 static int show_only;
+static int verbose;
 static unsigned long expire;
 
+static int prune_tmp_object(const char *path, const char *filename)
+{
+       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;
+       }
+       printf("Removing stale temporary file %s\n", fullpath);
+       if (!show_only)
+               unlink(fullpath);
+       return 0;
+}
+
 static int prune_object(char *path, const char *filename, const unsigned char *sha1)
 {
        const char *fullpath = mkpath("%s/%s", path, filename);
@@ -19,11 +40,12 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
                if (st.st_mtime > expire)
                        return 0;
        }
-       if (show_only) {
+       if (show_only || verbose) {
                enum object_type type = sha1_object_info(sha1, NULL);
                printf("%s %s\n", sha1_to_hex(sha1),
                       (type > 0) ? typename(type) : "unknown");
-       } else
+       }
+       if (!show_only)
                unlink(fullpath);
        return 0;
 }
@@ -65,6 +87,10 @@ static int prune_dir(int i, char *path)
                        prune_object(path, de->d_name, sha1);
                        continue;
                }
+               if (!prefixcmp(de->d_name, "tmp_obj_")) {
+                       prune_tmp_object(path, de->d_name);
+                       continue;
+               }
                fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
        }
        if (!show_only)
@@ -83,37 +109,66 @@ static void prune_object_dir(const char *path)
        }
 }
 
-int cmd_prune(int argc, const char **argv, const char *prefix)
+/*
+ * 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
+ * and the pack directories.
+ */
+static void remove_temporary_files(const char *path)
 {
-       int i;
-       struct rev_info revs;
+       DIR *dir;
+       struct dirent *de;
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
-               if (!strcmp(arg, "-n")) {
-                       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);
+       dir = opendir(path);
+       if (!dir) {
+               fprintf(stderr, "Unable to open directory %s\n", path);
+               return;
        }
+       while ((de = readdir(dir)) != NULL)
+               if (!prefixcmp(de->d_name, "tmp_"))
+                       prune_tmp_object(path, de->d_name);
+       closedir(dir);
+}
+
+int cmd_prune(int argc, const char **argv, const char *prefix)
+{
+       struct rev_info revs;
+       const struct option options[] = {
+               OPT_BOOLEAN('n', NULL, &show_only,
+                           "do not remove, show only"),
+               OPT_BOOLEAN('v', NULL, &verbose,
+                       "report pruned objects"),
+               OPT_DATE(0, "expire", &expire,
+                        "expire objects older than <time>"),
+               OPT_END()
+       };
+       char *s;
 
        save_commit_buffer = 0;
        init_revisions(&revs, prefix);
-       mark_reachable_objects(&revs, 1);
 
+       argc = parse_options(argc, argv, options, prune_usage, 0);
+       while (argc--) {
+               unsigned char sha1[20];
+               const char *name = *argv++;
+
+               if (!get_sha1(name, sha1)) {
+                       struct object *object = parse_object(sha1);
+                       if (!object)
+                               die("bad object: %s", name);
+                       add_pending_object(&revs, object, "");
+               }
+               else
+                       die("unrecognized argument: %s", name);
+       }
+       mark_reachable_objects(&revs, 1);
        prune_object_dir(get_object_directory());
 
-       sync();
        prune_packed_objects(show_only);
+       remove_temporary_files(get_object_directory());
+       s = xstrdup(mkpath("%s/pack", get_object_directory()));
+       remove_temporary_files(s);
+       free(s);
        return 0;
 }