{"thread":{"id":"10188","subject":"Re: [PATCH] Make git-clean a builtin","startedAt":"2007-10-07T23:57:46Z","lastAt":"2007-10-08T03:57:38Z","messageCount":2,"participants":["Johannes Schindelin","Shawn Bohrer"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"55157","messageId":"11918014664038-git-send-email-shawn.bohrer@gmail.com","threadId":"10188","inReplyTo":null,"subject":"[PATCH] Make git-clean a builtin","fromName":"Shawn Bohrer","fromEmail":"shawn.bohrer@gmail.com","sentAt":"2007-10-07T23:57:46Z","receivedAt":"2007-10-07T23:57:46Z","isPatch":true,"sender":{"key":"shawn.bohrer@gmail.com","avatar":"https://gravatar.com/avatar/6eb093ef7d276306d18366254e0c95ff6a5db58231ac7e82fe78c2800aaae1b6?d=mp&s=160"},"body":"This replaces git-clean.sh with builtin-clean.c, and moves git-clean.sh to the\nexamples.\n\nSigned-off-by: Shawn Bohrer <shawn.bohrer@gmail.com>\n---\n\nRewritten to use remove_directory_recursively() per Dscho's suggestion.  Patch\nis now based ontop of 'next'. \n\n Makefile                                      |    3 +-\n builtin-clean.c                               |  161 +++++++++++++++++++++++++\n builtin.h                                     |    1 +\n git-clean.sh => contrib/examples/git-clean.sh |    0 \n git.c                                         |    1 +\n 5 files changed, 165 insertions(+), 1 deletions(-)\n create mode 100644 builtin-clean.c\n rename git-clean.sh => contrib/examples/git-clean.sh (100%)\n\ndiff --git a/Makefile b/Makefile\nindex 62bdac6..bed4c78 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -206,7 +206,7 @@ BASIC_LDFLAGS =\n \n SCRIPT_SH = \\\n \tgit-bisect.sh git-checkout.sh \\\n-\tgit-clean.sh git-clone.sh git-commit.sh \\\n+\tgit-clone.sh git-commit.sh \\\n \tgit-ls-remote.sh \\\n \tgit-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \\\n \tgit-pull.sh git-rebase.sh git-rebase--interactive.sh \\\n@@ -324,6 +324,7 @@ BUILTIN_OBJS = \\\n \tbuiltin-check-attr.o \\\n \tbuiltin-checkout-index.o \\\n \tbuiltin-check-ref-format.o \\\n+\tbuiltin-clean.o \\\n \tbuiltin-commit-tree.o \\\n \tbuiltin-count-objects.o \\\n \tbuiltin-describe.o \\\ndiff --git a/builtin-clean.c b/builtin-clean.c\nnew file mode 100644\nindex 0000000..af61de0\n--- /dev/null\n+++ b/builtin-clean.c\n@@ -0,0 +1,161 @@\n+/*\n+ * \"git clean\" builtin command\n+ *\n+ * Copyright (C) 2007 Shawn Bohrer\n+ *\n+ * Based on git-clean.sh by Pavel Roskin\n+ */\n+\n+#include \"builtin.h\"\n+#include \"cache.h\"\n+#include \"run-command.h\"\n+#include \"dir.h\"\n+\n+static int disabled = 0;\n+static int show_only = 0;\n+static int remove_directories = 0;\n+static int quiet = 0;\n+static int ignored = 0;\n+static int ignored_only = 0;\n+\n+static const char builtin_clean_usage[] =\n+\"git-clean [-d] [-f] [-n] [-q] [-x | -X] [--] <paths>...\";\n+\n+static int git_clean_config(const char *var, const char *value)\n+{\n+\tif (!strcmp(var, \"clean.requireforce\")) {\n+\t\tdisabled = git_config_bool(var, value);\n+\t}\n+\treturn 0;\n+}\n+\n+int cmd_clean(int argc, const char **argv, const char *prefix)\n+{\n+\tint i;\n+\tint j;\n+\tstruct child_process cmd;\n+\tconst char **argv_ls_files;\n+\tchar *buf = NULL;\n+\tchar path[1024];\n+\tFILE *cmd_fout;\n+\tstruct strbuf dir;\n+\n+\tgit_config(git_clean_config);\n+\n+\tfor (i = 1; i < argc; i++) {\n+\t\tconst char *arg = argv[i];\n+\n+\t\tif (arg[0] != '-')\n+\t\t\tbreak;\n+\t\tif (!strcmp(arg, \"--\")) {\n+\t\t\ti++;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-n\")) {\n+\t\t\tshow_only = 1;\n+\t\t\tdisabled = 0;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-f\")) {\n+\t\t\tdisabled = 0;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-d\")) {\n+\t\t\tremove_directories = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-q\")) {\n+\t\t\tquiet = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-x\")) {\n+\t\t\tignored = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-X\")) {\n+\t\t\tignored_only = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tusage(builtin_clean_usage);\n+\t}\n+\n+\tif (ignored && ignored_only)\n+\t\tusage(builtin_clean_usage);\n+\n+\tif (disabled) {\n+\t\tdie(\"clean.requireForce set and -n or -f not given; refusing to clean\");\n+\t}\n+\n+\t/* Paths (argc - i) + 8 (Possible arguments)*/\n+\targv_ls_files = xmalloc((argc - i + 8) * sizeof(const char *));\n+\targv_ls_files[0] = \"ls-files\";\n+\targv_ls_files[1] = \"--others\";\n+\targv_ls_files[2] = \"--directory\";\n+\tj = 3;\n+\tif (!ignored) {\n+\t\targv_ls_files[j++] = \"--exclude-per-directory=.gitignore\";\n+\t\tif (ignored_only)\n+\t\t\targv_ls_files[j++] = \"--ignored\";\n+\t\tif (!access(git_path(\"info/exclude\"), F_OK)) {\n+\t\t\tchar *exclude_path = git_path(\"info/exclude\");\n+\t\t\tint len = strlen(exclude_path);\n+\t\t\tbuf = (char*)malloc(len+16);\n+\t\t\tsprintf(buf, \"--exclude-from=%s\", exclude_path);\n+\t\t\targv_ls_files[j++] = buf;\n+\t\t}\n+\t}\n+\targv_ls_files[j++] = \"--\";\n+\t/* Add remaining paths passed in as arguments */\n+\tif (argc - i)\n+\t\tmemcpy(argv_ls_files + j++, argv + i, (argc - i) * sizeof(const char *));\n+\targv_ls_files[j + argc - i] = NULL;\n+\n+\tmemset(&cmd, 0, sizeof(cmd));\n+\tcmd.argv = argv_ls_files;\n+\tcmd.git_cmd = 1;\n+\tcmd.out = -1;\n+\tif (start_command(&cmd))\n+\t\tdie(\"Could not run sub-command: git ls-files\");\n+\n+\tstrbuf_init(&dir, 0);\n+\tcmd_fout = fdopen(cmd.out, \"r\");\n+\twhile (fgets(path, sizeof(path), cmd_fout) != NULL) {\n+\t\tstruct stat st;\n+\t\tchar *p;\n+\t\tp = strrchr(path, '\\n');\n+\t\tif ( p != NULL )\n+\t\t\t*p = '\\0';\n+\t\tif (!lstat(path, &st) && (S_ISDIR(st.st_mode))) {\n+\t\t\tstrbuf_addstr(&dir, path);\n+\t\t\tif (show_only && remove_directories) {\n+\t\t\t\tprintf(\"Would remove %s\\n\", dir.buf);\n+\t\t\t} else if (quiet && remove_directories) {\n+\t\t\t\tremove_dir_recursively(&dir, 0);\n+\t\t\t} else if (remove_directories) {\n+\t\t\t\tprintf(\"Removing %s\\n\", path);\n+\t\t\t\tremove_dir_recursively(&dir, 0);\n+\t\t\t} else if (show_only) {\n+\t\t\t\tprintf(\"Would not remove %s\\n\", dir.buf);\n+\t\t\t} else {\n+\t\t\t\tprintf(\"Not removing %s\\n\", dir.buf);\n+\t\t\t}\n+\t\t\tstrbuf_reset(&dir);\n+\t\t} else {\n+\t\t\tif (show_only) {\n+\t\t\t\tprintf(\"Would remove %s\\n\", path);\n+\t\t\t\tcontinue;\n+\t\t\t} else if (!quiet) {\n+\t\t\t\tprintf(\"Removing %s\\n\", path);\n+\t\t\t}\n+\t\t\tunlink(path);\n+\t\t}\n+\t}\n+\n+\tstrbuf_release(&dir);\n+\tfclose(cmd_fout);\n+\tfinish_command(&cmd);\n+\tif (buf != NULL)\n+\t\tfree(buf);\n+\tfree(argv_ls_files);\n+\treturn 0;\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 65cc0fb..cdefdc0 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -23,6 +23,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);\n extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);\n extern int cmd_cherry(int argc, const char **argv, const char *prefix);\n extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);\n+extern int cmd_clean(int argc, const char **argv, const char *prefix);\n extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_count_objects(int argc, const char **argv, const char *prefix);\n extern int cmd_describe(int argc, const char **argv, const char *prefix);\ndiff --git a/git-clean.sh b/contrib/examples/git-clean.sh\nsimilarity index 100%\nrename from git-clean.sh\nrename to contrib/examples/git-clean.sh\ndiff --git a/git.c b/git.c\nindex d7c6bca..4e39169 100644\n--- a/git.c\n+++ b/git.c\n@@ -320,6 +320,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"check-attr\", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"cherry\", cmd_cherry, RUN_SETUP },\n \t\t{ \"cherry-pick\", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },\n+\t\t{ \"clean\", cmd_clean, RUN_SETUP },\n \t\t{ \"commit-tree\", cmd_commit_tree, RUN_SETUP },\n \t\t{ \"config\", cmd_config },\n \t\t{ \"count-objects\", cmd_count_objects, RUN_SETUP },\n-- \n1.5.3.GIT\n"},{"id":"55154","messageId":"Pine.LNX.4.64.0710080450570.4174@racer.site","threadId":"10188","inReplyTo":"11918014664038-git-send-email-shawn.bohrer@gmail.com","subject":"Re: [PATCH] Make git-clean a builtin","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-10-08T03:57:38Z","receivedAt":"2007-10-08T03:57:38Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 7 Oct 2007, Shawn Bohrer wrote:\n\n> +\tif (ignored && ignored_only)\n> +\t\tusage(builtin_clean_usage);\n\nMaybe a helpful message in that case, too?  (It is not apparent from the \nusage what the user has done wrong here.)\n\n> +\tif (disabled) {\n> +\t\tdie(\"clean.requireForce set and -n or -f not given; refusing to clean\");\n> +\t}\n\nPlease lose the curly brackets here.  They are absolutely useless, and the \nrest of the git source code avoids unnecessary curly brackets.\n\n> +\t/* Paths (argc - i) + 8 (Possible arguments)*/\n> +\targv_ls_files = xmalloc((argc - i + 8) * sizeof(const char *));\n> +\targv_ls_files[0] = \"ls-files\";\n> +\targv_ls_files[1] = \"--others\";\n> +\targv_ls_files[2] = \"--directory\";\n> [...]\n\nAs Linus already noted, it is probably easy, and much more efficient, to \ncall read_directory() here.  The best example how to use \nread_directory() is... builtin-ls-files.c.\n\n> diff --git a/git.c b/git.c\n> index d7c6bca..4e39169 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -320,6 +320,7 @@ static void handle_internal_command(int argc, const char **argv)\n>  \t\t{ \"check-attr\", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },\n>  \t\t{ \"cherry\", cmd_cherry, RUN_SETUP },\n>  \t\t{ \"cherry-pick\", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },\n> +\t\t{ \"clean\", cmd_clean, RUN_SETUP },\n\nYou definitely want to have NEED_WORK_TREE here, too.\n\nCiao,\nDscho\n"}]}