From 5010cb5fcca30269ad25f2eb38b31455af3205d7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 30 Apr 2006 23:28:15 -0700 Subject: built-in "git grep" This attempts to set up built-in "git grep" to further reduce our dependence on the shell, while at the same time optionally allowing to run grep against object database. You could do funky things like these: git grep --cached -e pattern ;# grep from index git grep -e pattern master ;# or in a rev git grep -e pattern master next ;# or in multiple revs git grep -e pattern pu^@ ;# even like this with an ;# extension from another topic ;-) git grep -e pattern master..next ;# or even from rev ranges git grep -e pattern master~20:Documentation ;# or an arbitrary tree git grep -e pattern next:git-commit.sh ;# or an arbitrary blob Right now, it does not understand and/or obey many options grep should accept, and the pattern must be given with -e option due to the way the parameter parser is structured, both of which obviously need to be fixed for usability. But this is going in the right direction. The shell script version is one of the worst Portability offender in the git barebone Porcelainish; it uses xargs -0 to pass paths around and shell arrays to sift flags and parameters. Signed-off-by: Junio C Hamano --- git.c | 1 + 1 file changed, 1 insertion(+) (limited to 'git.c') diff --git a/git.c b/git.c index 01b7e28b8c..893bddd768 100644 --- a/git.c +++ b/git.c @@ -46,6 +46,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "log", cmd_log }, { "whatchanged", cmd_whatchanged }, { "show", cmd_show }, + { "grep", cmd_grep }, }; int i; -- cgit v1.3 From 5fb61b8dcfdf7bcec0793c071813e255d1803859 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 18 May 2006 14:19:20 -0700 Subject: Make "git rev-list" be a builtin This was surprisingly easy. The diff is truly minimal: rename "main()" to "cmd_rev_list()" in rev-list.c, and rename the whole file to reflect its new built-in status. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- Makefile | 6 +- builtin-rev-list.c | 358 +++++++++++++++++++++++++++++++++++++++++++++++++++++ builtin.h | 1 + git.c | 1 + rev-list.c | 357 ---------------------------------------------------- 5 files changed, 363 insertions(+), 360 deletions(-) create mode 100644 builtin-rev-list.c delete mode 100644 rev-list.c (limited to 'git.c') diff --git a/Makefile b/Makefile index 9ba608c805..6efc8e0275 100644 --- a/Makefile +++ b/Makefile @@ -158,7 +158,7 @@ PROGRAMS = \ git-ls-files$X git-ls-tree$X git-mailinfo$X git-merge-base$X \ git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \ git-peek-remote$X git-prune-packed$X git-read-tree$X \ - git-receive-pack$X git-rev-list$X git-rev-parse$X \ + git-receive-pack$X git-rev-parse$X \ git-send-pack$X git-show-branch$X git-shell$X \ git-show-index$X git-ssh-fetch$X \ git-ssh-upload$X git-tar-tree$X git-unpack-file$X \ @@ -170,7 +170,7 @@ PROGRAMS = \ BUILT_INS = git-log$X git-whatchanged$X git-show$X \ git-count-objects$X git-diff$X git-push$X \ - git-grep$X + git-grep$X git-rev-list$X # what 'all' will build and 'install' will install, in gitexecdir ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) @@ -218,7 +218,7 @@ LIB_OBJS = \ BUILTIN_OBJS = \ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ - builtin-grep.o + builtin-grep.o builtin-rev-list.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz diff --git a/builtin-rev-list.c b/builtin-rev-list.c new file mode 100644 index 0000000000..446802d377 --- /dev/null +++ b/builtin-rev-list.c @@ -0,0 +1,358 @@ +#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" + +/* bits #0-15 in revision.h */ + +#define COUNTED (1u<<16) + +static const char rev_list_usage[] = +"git-rev-list [OPTION] ... [ -- paths... ]\n" +" limiting output:\n" +" --max-count=nr\n" +" --max-age=epoch\n" +" --min-age=epoch\n" +" --sparse\n" +" --no-merges\n" +" --remove-empty\n" +" --all\n" +" ordering output:\n" +" --topo-order\n" +" --date-order\n" +" formatting output:\n" +" --parents\n" +" --objects | --objects-edge\n" +" --unpacked\n" +" --header | --pretty\n" +" --abbrev=nr | --no-abbrev\n" +" --abbrev-commit\n" +" special purpose:\n" +" --bisect" +; + +static struct rev_info revs; + +static int bisect_list = 0; +static int show_timestamp = 0; +static int hdr_termination = 0; +static const char *header_prefix; + +static void show_commit(struct commit *commit) +{ + if (show_timestamp) + printf("%lu ", commit->date); + if (header_prefix) + fputs(header_prefix, stdout); + if (commit->object.flags & BOUNDARY) + putchar('-'); + if (revs.abbrev_commit && revs.abbrev) + fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev), + stdout); + else + fputs(sha1_to_hex(commit->object.sha1), stdout); + if (revs.parents) { + struct commit_list *parents = commit->parents; + while (parents) { + struct object *o = &(parents->item->object); + parents = parents->next; + if (o->flags & TMP_MARK) + continue; + printf(" %s", sha1_to_hex(o->sha1)); + o->flags |= TMP_MARK; + } + /* TMP_MARK is a general purpose flag that can + * be used locally, but the user should clean + * things up after it is done with them. + */ + for (parents = commit->parents; + parents; + parents = parents->next) + parents->item->object.flags &= ~TMP_MARK; + } + if (revs.commit_format == CMIT_FMT_ONELINE) + putchar(' '); + else + putchar('\n'); + + if (revs.verbose_header) { + static char pretty_header[16384]; + pretty_print_commit(revs.commit_format, commit, ~0, + pretty_header, sizeof(pretty_header), + revs.abbrev); + printf("%s%c", pretty_header, hdr_termination); + } + fflush(stdout); +} + +static struct object_list **process_blob(struct blob *blob, + struct object_list **p, + struct name_path *path, + const char *name) +{ + struct object *obj = &blob->object; + + if (!revs.blob_objects) + return p; + if (obj->flags & (UNINTERESTING | SEEN)) + return p; + obj->flags |= SEEN; + return add_object(obj, p, path, name); +} + +static struct object_list **process_tree(struct tree *tree, + struct object_list **p, + struct name_path *path, + const char *name) +{ + struct object *obj = &tree->object; + struct tree_entry_list *entry; + struct name_path me; + + if (!revs.tree_objects) + return p; + if (obj->flags & (UNINTERESTING | SEEN)) + return p; + if (parse_tree(tree) < 0) + die("bad tree object %s", sha1_to_hex(obj->sha1)); + obj->flags |= SEEN; + p = add_object(obj, p, path, name); + me.up = path; + me.elem = name; + me.elem_len = strlen(name); + entry = tree->entries; + tree->entries = NULL; + while (entry) { + struct tree_entry_list *next = entry->next; + if (entry->directory) + p = process_tree(entry->item.tree, p, &me, entry->name); + else + p = process_blob(entry->item.blob, p, &me, entry->name); + free(entry); + entry = next; + } + return p; +} + +static void show_commit_list(struct rev_info *revs) +{ + struct commit *commit; + struct object_list *objects = NULL, **p = &objects, *pending; + + while ((commit = get_revision(revs)) != NULL) { + p = process_tree(commit->tree, p, NULL, ""); + show_commit(commit); + } + for (pending = revs->pending_objects; pending; pending = pending->next) { + struct object *obj = pending->item; + const char *name = pending->name; + if (obj->flags & (UNINTERESTING | SEEN)) + continue; + if (obj->type == tag_type) { + obj->flags |= SEEN; + p = add_object(obj, p, NULL, name); + continue; + } + if (obj->type == tree_type) { + p = process_tree((struct tree *)obj, p, NULL, name); + continue; + } + if (obj->type == blob_type) { + p = process_blob((struct blob *)obj, p, NULL, name); + continue; + } + die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name); + } + while (objects) { + /* An object with name "foo\n0000000..." can be used to + * confuse downstream git-pack-objects very badly. + */ + const char *ep = strchr(objects->name, '\n'); + if (ep) { + printf("%s %.*s\n", sha1_to_hex(objects->item->sha1), + (int) (ep - objects->name), + objects->name); + } + else + printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name); + objects = objects->next; + } +} + +/* + * This is a truly stupid algorithm, but it's only + * used for bisection, and we just don't care enough. + * + * We care just barely enough to avoid recursing for + * non-merge entries. + */ +static int count_distance(struct commit_list *entry) +{ + int nr = 0; + + while (entry) { + struct commit *commit = entry->item; + struct commit_list *p; + + if (commit->object.flags & (UNINTERESTING | COUNTED)) + break; + if (!revs.prune_fn || (commit->object.flags & TREECHANGE)) + nr++; + commit->object.flags |= COUNTED; + p = commit->parents; + entry = p; + if (p) { + p = p->next; + while (p) { + nr += count_distance(p); + p = p->next; + } + } + } + + return nr; +} + +static void clear_distance(struct commit_list *list) +{ + while (list) { + struct commit *commit = list->item; + commit->object.flags &= ~COUNTED; + list = list->next; + } +} + +static struct commit_list *find_bisection(struct commit_list *list) +{ + int nr, closest; + struct commit_list *p, *best; + + nr = 0; + p = list; + while (p) { + if (!revs.prune_fn || (p->item->object.flags & TREECHANGE)) + nr++; + p = p->next; + } + closest = 0; + best = list; + + for (p = list; p; p = p->next) { + int distance; + + if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) + continue; + + distance = count_distance(p); + clear_distance(list); + if (nr - distance < distance) + distance = nr - distance; + if (distance > closest) { + best = p; + closest = distance; + } + } + if (best) + best->next = NULL; + return best; +} + +static void mark_edge_parents_uninteresting(struct commit *commit) +{ + struct commit_list *parents; + + for (parents = commit->parents; parents; parents = parents->next) { + struct commit *parent = parents->item; + if (!(parent->object.flags & UNINTERESTING)) + continue; + mark_tree_uninteresting(parent->tree); + if (revs.edge_hint && !(parent->object.flags & SHOWN)) { + parent->object.flags |= SHOWN; + printf("-%s\n", sha1_to_hex(parent->object.sha1)); + } + } +} + +static void mark_edges_uninteresting(struct commit_list *list) +{ + for ( ; list; list = list->next) { + struct commit *commit = list->item; + + if (commit->object.flags & UNINTERESTING) { + mark_tree_uninteresting(commit->tree); + continue; + } + mark_edge_parents_uninteresting(commit); + } +} + +int cmd_rev_list(int argc, const char **argv, char **envp) +{ + struct commit_list *list; + int i; + + init_revisions(&revs); + revs.abbrev = 0; + revs.commit_format = CMIT_FMT_UNSPECIFIED; + argc = setup_revisions(argc, argv, &revs, NULL); + + for (i = 1 ; i < argc; i++) { + const char *arg = argv[i]; + + if (!strcmp(arg, "--header")) { + revs.verbose_header = 1; + continue; + } + if (!strcmp(arg, "--timestamp")) { + show_timestamp = 1; + continue; + } + if (!strcmp(arg, "--bisect")) { + bisect_list = 1; + continue; + } + usage(rev_list_usage); + + } + if (revs.commit_format != CMIT_FMT_UNSPECIFIED) { + /* The command line has a --pretty */ + hdr_termination = '\n'; + if (revs.commit_format == CMIT_FMT_ONELINE) + header_prefix = ""; + else + header_prefix = "commit "; + } + else if (revs.verbose_header) + /* Only --header was specified */ + revs.commit_format = CMIT_FMT_RAW; + + list = revs.commits; + + if ((!list && + (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && + !revs.pending_objects)) || + revs.diff) + usage(rev_list_usage); + + save_commit_buffer = revs.verbose_header; + track_object_refs = 0; + if (bisect_list) + revs.limited = 1; + + prepare_revision_walk(&revs); + if (revs.tree_objects) + mark_edges_uninteresting(revs.commits); + + if (bisect_list) + revs.commits = find_bisection(revs.commits); + + show_commit_list(&revs); + + return 0; +} diff --git a/builtin.h b/builtin.h index 7744f7d2f6..7dff121520 100644 --- a/builtin.h +++ b/builtin.h @@ -24,5 +24,6 @@ extern int cmd_count_objects(int argc, const char **argv, char **envp); extern int cmd_push(int argc, const char **argv, char **envp); extern int cmd_grep(int argc, const char **argv, char **envp); +extern int cmd_rev_list(int argc, const char **argv, char **envp); #endif diff --git a/git.c b/git.c index a94d9ee5a7..c94e3a531b 100644 --- a/git.c +++ b/git.c @@ -50,6 +50,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "count-objects", cmd_count_objects }, { "diff", cmd_diff }, { "grep", cmd_grep }, + { "rev-list", cmd_rev_list }, }; int i; diff --git a/rev-list.c b/rev-list.c deleted file mode 100644 index 8b0ec388fa..0000000000 --- a/rev-list.c +++ /dev/null @@ -1,357 +0,0 @@ -#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" - -/* bits #0-15 in revision.h */ - -#define COUNTED (1u<<16) - -static const char rev_list_usage[] = -"git-rev-list [OPTION] ... [ -- paths... ]\n" -" limiting output:\n" -" --max-count=nr\n" -" --max-age=epoch\n" -" --min-age=epoch\n" -" --sparse\n" -" --no-merges\n" -" --remove-empty\n" -" --all\n" -" ordering output:\n" -" --topo-order\n" -" --date-order\n" -" formatting output:\n" -" --parents\n" -" --objects | --objects-edge\n" -" --unpacked\n" -" --header | --pretty\n" -" --abbrev=nr | --no-abbrev\n" -" --abbrev-commit\n" -" special purpose:\n" -" --bisect" -; - -struct rev_info revs; - -static int bisect_list = 0; -static int show_timestamp = 0; -static int hdr_termination = 0; -static const char *header_prefix; - -static void show_commit(struct commit *commit) -{ - if (show_timestamp) - printf("%lu ", commit->date); - if (header_prefix) - fputs(header_prefix, stdout); - if (commit->object.flags & BOUNDARY) - putchar('-'); - if (revs.abbrev_commit && revs.abbrev) - fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev), - stdout); - else - fputs(sha1_to_hex(commit->object.sha1), stdout); - if (revs.parents) { - struct commit_list *parents = commit->parents; - while (parents) { - struct object *o = &(parents->item->object); - parents = parents->next; - if (o->flags & TMP_MARK) - continue; - printf(" %s", sha1_to_hex(o->sha1)); - o->flags |= TMP_MARK; - } - /* TMP_MARK is a general purpose flag that can - * be used locally, but the user should clean - * things up after it is done with them. - */ - for (parents = commit->parents; - parents; - parents = parents->next) - parents->item->object.flags &= ~TMP_MARK; - } - if (revs.commit_format == CMIT_FMT_ONELINE) - putchar(' '); - else - putchar('\n'); - - if (revs.verbose_header) { - static char pretty_header[16384]; - pretty_print_commit(revs.commit_format, commit, ~0, - pretty_header, sizeof(pretty_header), - revs.abbrev); - printf("%s%c", pretty_header, hdr_termination); - } - fflush(stdout); -} - -static struct object_list **process_blob(struct blob *blob, - struct object_list **p, - struct name_path *path, - const char *name) -{ - struct object *obj = &blob->object; - - if (!revs.blob_objects) - return p; - if (obj->flags & (UNINTERESTING | SEEN)) - return p; - obj->flags |= SEEN; - return add_object(obj, p, path, name); -} - -static struct object_list **process_tree(struct tree *tree, - struct object_list **p, - struct name_path *path, - const char *name) -{ - struct object *obj = &tree->object; - struct tree_entry_list *entry; - struct name_path me; - - if (!revs.tree_objects) - return p; - if (obj->flags & (UNINTERESTING | SEEN)) - return p; - if (parse_tree(tree) < 0) - die("bad tree object %s", sha1_to_hex(obj->sha1)); - obj->flags |= SEEN; - p = add_object(obj, p, path, name); - me.up = path; - me.elem = name; - me.elem_len = strlen(name); - entry = tree->entries; - tree->entries = NULL; - while (entry) { - struct tree_entry_list *next = entry->next; - if (entry->directory) - p = process_tree(entry->item.tree, p, &me, entry->name); - else - p = process_blob(entry->item.blob, p, &me, entry->name); - free(entry); - entry = next; - } - return p; -} - -static void show_commit_list(struct rev_info *revs) -{ - struct commit *commit; - struct object_list *objects = NULL, **p = &objects, *pending; - - while ((commit = get_revision(revs)) != NULL) { - p = process_tree(commit->tree, p, NULL, ""); - show_commit(commit); - } - for (pending = revs->pending_objects; pending; pending = pending->next) { - struct object *obj = pending->item; - const char *name = pending->name; - if (obj->flags & (UNINTERESTING | SEEN)) - continue; - if (obj->type == tag_type) { - obj->flags |= SEEN; - p = add_object(obj, p, NULL, name); - continue; - } - if (obj->type == tree_type) { - p = process_tree((struct tree *)obj, p, NULL, name); - continue; - } - if (obj->type == blob_type) { - p = process_blob((struct blob *)obj, p, NULL, name); - continue; - } - die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name); - } - while (objects) { - /* An object with name "foo\n0000000..." can be used to - * confuse downstream git-pack-objects very badly. - */ - const char *ep = strchr(objects->name, '\n'); - if (ep) { - printf("%s %.*s\n", sha1_to_hex(objects->item->sha1), - (int) (ep - objects->name), - objects->name); - } - else - printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name); - objects = objects->next; - } -} - -/* - * This is a truly stupid algorithm, but it's only - * used for bisection, and we just don't care enough. - * - * We care just barely enough to avoid recursing for - * non-merge entries. - */ -static int count_distance(struct commit_list *entry) -{ - int nr = 0; - - while (entry) { - struct commit *commit = entry->item; - struct commit_list *p; - - if (commit->object.flags & (UNINTERESTING | COUNTED)) - break; - if (!revs.prune_fn || (commit->object.flags & TREECHANGE)) - nr++; - commit->object.flags |= COUNTED; - p = commit->parents; - entry = p; - if (p) { - p = p->next; - while (p) { - nr += count_distance(p); - p = p->next; - } - } - } - - return nr; -} - -static void clear_distance(struct commit_list *list) -{ - while (list) { - struct commit *commit = list->item; - commit->object.flags &= ~COUNTED; - list = list->next; - } -} - -static struct commit_list *find_bisection(struct commit_list *list) -{ - int nr, closest; - struct commit_list *p, *best; - - nr = 0; - p = list; - while (p) { - if (!revs.prune_fn || (p->item->object.flags & TREECHANGE)) - nr++; - p = p->next; - } - closest = 0; - best = list; - - for (p = list; p; p = p->next) { - int distance; - - if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) - continue; - - distance = count_distance(p); - clear_distance(list); - if (nr - distance < distance) - distance = nr - distance; - if (distance > closest) { - best = p; - closest = distance; - } - } - if (best) - best->next = NULL; - return best; -} - -static void mark_edge_parents_uninteresting(struct commit *commit) -{ - struct commit_list *parents; - - for (parents = commit->parents; parents; parents = parents->next) { - struct commit *parent = parents->item; - if (!(parent->object.flags & UNINTERESTING)) - continue; - mark_tree_uninteresting(parent->tree); - if (revs.edge_hint && !(parent->object.flags & SHOWN)) { - parent->object.flags |= SHOWN; - printf("-%s\n", sha1_to_hex(parent->object.sha1)); - } - } -} - -static void mark_edges_uninteresting(struct commit_list *list) -{ - for ( ; list; list = list->next) { - struct commit *commit = list->item; - - if (commit->object.flags & UNINTERESTING) { - mark_tree_uninteresting(commit->tree); - continue; - } - mark_edge_parents_uninteresting(commit); - } -} - -int main(int argc, const char **argv) -{ - struct commit_list *list; - int i; - - init_revisions(&revs); - revs.abbrev = 0; - revs.commit_format = CMIT_FMT_UNSPECIFIED; - argc = setup_revisions(argc, argv, &revs, NULL); - - for (i = 1 ; i < argc; i++) { - const char *arg = argv[i]; - - if (!strcmp(arg, "--header")) { - revs.verbose_header = 1; - continue; - } - if (!strcmp(arg, "--timestamp")) { - show_timestamp = 1; - continue; - } - if (!strcmp(arg, "--bisect")) { - bisect_list = 1; - continue; - } - usage(rev_list_usage); - - } - if (revs.commit_format != CMIT_FMT_UNSPECIFIED) { - /* The command line has a --pretty */ - hdr_termination = '\n'; - if (revs.commit_format == CMIT_FMT_ONELINE) - header_prefix = ""; - else - header_prefix = "commit "; - } - else if (revs.verbose_header) - /* Only --header was specified */ - revs.commit_format = CMIT_FMT_RAW; - - list = revs.commits; - - if ((!list && - (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && - !revs.pending_objects)) || - revs.diff) - usage(rev_list_usage); - - save_commit_buffer = revs.verbose_header; - track_object_refs = 0; - if (bisect_list) - revs.limited = 1; - - prepare_revision_walk(&revs); - if (revs.tree_objects) - mark_edges_uninteresting(revs.commits); - - if (bisect_list) - revs.commits = find_bisection(revs.commits); - - show_commit_list(&revs); - - return 0; -} -- cgit v1.3 From 9370bae2cef351617272aa142fbe4ce039833d13 Mon Sep 17 00:00:00 2001 From: Lukas Sandström Date: Thu, 18 May 2006 14:15:55 +0200 Subject: Make git-check-format-ref a builtin. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Sandström Signed-off-by: Junio C Hamano --- Makefile | 6 +++--- builtin-check-ref-format.c | 14 ++++++++++++++ builtin.h | 1 + check-ref-format.c | 17 ----------------- git.c | 1 + 5 files changed, 19 insertions(+), 20 deletions(-) create mode 100644 builtin-check-ref-format.c delete mode 100644 check-ref-format.c (limited to 'git.c') diff --git a/Makefile b/Makefile index 6efc8e0275..2149fb8cea 100644 --- a/Makefile +++ b/Makefile @@ -164,13 +164,13 @@ PROGRAMS = \ git-ssh-upload$X git-tar-tree$X git-unpack-file$X \ git-unpack-objects$X git-update-index$X git-update-server-info$X \ git-upload-pack$X git-verify-pack$X git-write-tree$X \ - git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \ + git-update-ref$X git-symbolic-ref$X \ git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ git-describe$X git-merge-tree$X git-blame$X git-imap-send$X BUILT_INS = git-log$X git-whatchanged$X git-show$X \ git-count-objects$X git-diff$X git-push$X \ - git-grep$X git-rev-list$X + git-grep$X git-rev-list$X git-check-ref-format$X # what 'all' will build and 'install' will install, in gitexecdir ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) @@ -218,7 +218,7 @@ LIB_OBJS = \ BUILTIN_OBJS = \ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ - builtin-grep.o builtin-rev-list.o + builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c new file mode 100644 index 0000000000..4a23936aff --- /dev/null +++ b/builtin-check-ref-format.c @@ -0,0 +1,14 @@ +/* + * GIT - The information manager from hell + */ + +#include "cache.h" +#include "refs.h" +#include "builtin.h" + +int cmd_check_ref_format(int argc, const char **argv, char **envp) +{ + if (argc != 2) + usage("git check-ref-format refname"); + return !!check_ref_format(argv[1]); +} diff --git a/builtin.h b/builtin.h index 7dff121520..ff559dec7e 100644 --- a/builtin.h +++ b/builtin.h @@ -25,5 +25,6 @@ extern int cmd_count_objects(int argc, const char **argv, char **envp); extern int cmd_push(int argc, const char **argv, char **envp); extern int cmd_grep(int argc, const char **argv, char **envp); extern int cmd_rev_list(int argc, const char **argv, char **envp); +extern int cmd_check_ref_format(int argc, const char **argv, char **envp); #endif diff --git a/check-ref-format.c b/check-ref-format.c deleted file mode 100644 index a0adb3dcb3..0000000000 --- a/check-ref-format.c +++ /dev/null @@ -1,17 +0,0 @@ -/* - * GIT - The information manager from hell - */ - -#include "cache.h" -#include "refs.h" - -#include - -int main(int ac, char **av) -{ - if (ac != 2) - usage("git-check-ref-format refname"); - if (check_ref_format(av[1])) - exit(1); - return 0; -} diff --git a/git.c b/git.c index c94e3a531b..d0650bb409 100644 --- a/git.c +++ b/git.c @@ -51,6 +51,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "diff", cmd_diff }, { "grep", cmd_grep }, { "rev-list", cmd_rev_list }, + { "check-ref-format", cmd_check_ref_format } }; int i; -- cgit v1.3 From c3c8835fbb182d971d71939b9a3ec7c8b86d6caf Mon Sep 17 00:00:00 2001 From: Timo Hirvonen Date: Fri, 19 May 2006 13:03:57 +0300 Subject: Builtin git-init-db Basically this just renames init-db.c to builtin-init-db.c and makes some strings const. Signed-off-by: Timo Hirvonen Signed-off-by: Junio C Hamano --- Makefile | 13 ++- builtin-init-db.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ builtin.h | 1 + git.c | 1 + init-db.c | 291 ----------------------------------------------------- 5 files changed, 301 insertions(+), 298 deletions(-) create mode 100644 builtin-init-db.c delete mode 100644 init-db.c (limited to 'git.c') diff --git a/Makefile b/Makefile index 2149fb8cea..a4e96435a0 100644 --- a/Makefile +++ b/Makefile @@ -154,7 +154,7 @@ PROGRAMS = \ git-convert-objects$X git-diff-files$X \ git-diff-index$X git-diff-stages$X \ git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \ - git-hash-object$X git-index-pack$X git-init-db$X git-local-fetch$X \ + git-hash-object$X git-index-pack$X git-local-fetch$X \ git-ls-files$X git-ls-tree$X git-mailinfo$X git-merge-base$X \ git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \ git-peek-remote$X git-prune-packed$X git-read-tree$X \ @@ -170,7 +170,8 @@ PROGRAMS = \ BUILT_INS = git-log$X git-whatchanged$X git-show$X \ git-count-objects$X git-diff$X git-push$X \ - git-grep$X git-rev-list$X git-check-ref-format$X + git-grep$X git-rev-list$X git-check-ref-format$X \ + git-init-db$X # what 'all' will build and 'install' will install, in gitexecdir ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) @@ -218,7 +219,8 @@ LIB_OBJS = \ BUILTIN_OBJS = \ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ - builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o + builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \ + builtin-init-db.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz @@ -473,6 +475,7 @@ strip: $(PROGRAMS) git$X git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) $(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \ + -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' \ $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \ $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) @@ -565,10 +568,6 @@ git-http-push$X: revision.o http.o http-push.o $(LIB_FILE) $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -init-db.o: init-db.c - $(CC) -c $(ALL_CFLAGS) \ - -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c - $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)): $(GITLIBS) $(DIFF_OBJS): diffcore.h diff --git a/builtin-init-db.c b/builtin-init-db.c new file mode 100644 index 0000000000..2a1384ccb0 --- /dev/null +++ b/builtin-init-db.c @@ -0,0 +1,293 @@ +/* + * GIT - The information manager from hell + * + * Copyright (C) Linus Torvalds, 2005 + */ +#include "cache.h" +#include "builtin.h" + +#ifndef DEFAULT_GIT_TEMPLATE_DIR +#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/" +#endif + +static void safe_create_dir(const char *dir, int share) +{ + if (mkdir(dir, 0777) < 0) { + if (errno != EEXIST) { + perror(dir); + exit(1); + } + } + else if (share && adjust_shared_perm(dir)) + die("Could not make %s writable by group\n", dir); +} + +static int copy_file(const char *dst, const char *src, int mode) +{ + int fdi, fdo, status; + + mode = (mode & 0111) ? 0777 : 0666; + if ((fdi = open(src, O_RDONLY)) < 0) + return fdi; + if ((fdo = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) { + close(fdi); + return fdo; + } + status = copy_fd(fdi, fdo); + close(fdo); + + if (!status && adjust_shared_perm(dst)) + return -1; + + return status; +} + +static void copy_templates_1(char *path, int baselen, + char *template, int template_baselen, + DIR *dir) +{ + struct dirent *de; + + /* Note: if ".git/hooks" file exists in the repository being + * re-initialized, /etc/core-git/templates/hooks/update would + * cause git-init-db to fail here. I think this is sane but + * it means that the set of templates we ship by default, along + * with the way the namespace under .git/ is organized, should + * be really carefully chosen. + */ + safe_create_dir(path, 1); + while ((de = readdir(dir)) != NULL) { + struct stat st_git, st_template; + int namelen; + int exists = 0; + + if (de->d_name[0] == '.') + continue; + namelen = strlen(de->d_name); + if ((PATH_MAX <= baselen + namelen) || + (PATH_MAX <= template_baselen + namelen)) + die("insanely long template name %s", de->d_name); + memcpy(path + baselen, de->d_name, namelen+1); + memcpy(template + template_baselen, de->d_name, namelen+1); + if (lstat(path, &st_git)) { + if (errno != ENOENT) + die("cannot stat %s", path); + } + else + exists = 1; + + if (lstat(template, &st_template)) + die("cannot stat template %s", template); + + if (S_ISDIR(st_template.st_mode)) { + DIR *subdir = opendir(template); + int baselen_sub = baselen + namelen; + int template_baselen_sub = template_baselen + namelen; + if (!subdir) + die("cannot opendir %s", template); + path[baselen_sub++] = + template[template_baselen_sub++] = '/'; + path[baselen_sub] = + template[template_baselen_sub] = 0; + copy_templates_1(path, baselen_sub, + template, template_baselen_sub, + subdir); + closedir(subdir); + } + else if (exists) + continue; + else if (S_ISLNK(st_template.st_mode)) { + char lnk[256]; + int len; + len = readlink(template, lnk, sizeof(lnk)); + if (len < 0) + die("cannot readlink %s", template); + if (sizeof(lnk) <= len) + die("insanely long symlink %s", template); + lnk[len] = 0; + if (symlink(lnk, path)) + die("cannot symlink %s %s", lnk, path); + } + else if (S_ISREG(st_template.st_mode)) { + if (copy_file(path, template, st_template.st_mode)) + die("cannot copy %s to %s", template, path); + } + else + error("ignoring template %s", template); + } +} + +static void copy_templates(const char *git_dir, int len, const char *template_dir) +{ + char path[PATH_MAX]; + char template_path[PATH_MAX]; + int template_len; + DIR *dir; + + if (!template_dir) + template_dir = DEFAULT_GIT_TEMPLATE_DIR; + strcpy(template_path, template_dir); + template_len = strlen(template_path); + if (template_path[template_len-1] != '/') { + template_path[template_len++] = '/'; + template_path[template_len] = 0; + } + dir = opendir(template_path); + if (!dir) { + fprintf(stderr, "warning: templates not found %s\n", + template_dir); + return; + } + + /* Make sure that template is from the correct vintage */ + strcpy(template_path + template_len, "config"); + repository_format_version = 0; + git_config_from_file(check_repository_format_version, + template_path); + template_path[template_len] = 0; + + if (repository_format_version && + repository_format_version != GIT_REPO_VERSION) { + fprintf(stderr, "warning: not copying templates of " + "a wrong format version %d from '%s'\n", + repository_format_version, + template_dir); + closedir(dir); + return; + } + + memcpy(path, git_dir, len); + path[len] = 0; + copy_templates_1(path, len, + template_path, template_len, + dir); + closedir(dir); +} + +static void create_default_files(const char *git_dir, const char *template_path) +{ + unsigned len = strlen(git_dir); + static char path[PATH_MAX]; + unsigned char sha1[20]; + struct stat st1; + char repo_version_string[10]; + + if (len > sizeof(path)-50) + die("insane git directory %s", git_dir); + memcpy(path, git_dir, len); + + if (len && path[len-1] != '/') + path[len++] = '/'; + + /* + * Create .git/refs/{heads,tags} + */ + strcpy(path + len, "refs"); + safe_create_dir(path, 1); + strcpy(path + len, "refs/heads"); + safe_create_dir(path, 1); + strcpy(path + len, "refs/tags"); + safe_create_dir(path, 1); + + /* First copy the templates -- we might have the default + * config file there, in which case we would want to read + * from it after installing. + */ + path[len] = 0; + copy_templates(path, len, template_path); + + git_config(git_default_config); + + /* + * Create the default symlink from ".git/HEAD" to the "master" + * branch, if it does not exist yet. + */ + strcpy(path + len, "HEAD"); + if (read_ref(path, sha1) < 0) { + if (create_symref(path, "refs/heads/master") < 0) + exit(1); + } + + /* This forces creation of new config file */ + sprintf(repo_version_string, "%d", GIT_REPO_VERSION); + git_config_set("core.repositoryformatversion", repo_version_string); + + path[len] = 0; + strcpy(path + len, "config"); + + /* Check filemode trustability */ + if (!lstat(path, &st1)) { + struct stat st2; + int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && + !lstat(path, &st2) && + st1.st_mode != st2.st_mode); + git_config_set("core.filemode", + filemode ? "true" : "false"); + } +} + +static const char init_db_usage[] = +"git-init-db [--template=] [--shared]"; + +/* + * If you want to, you can share the DB area with any number of branches. + * That has advantages: you can save space by sharing all the SHA1 objects. + * On the other hand, it might just make lookup slower and messier. You + * be the judge. The default case is to have one DB per managed directory. + */ +int cmd_init_db(int argc, const char **argv, char **envp) +{ + const char *git_dir; + const char *sha1_dir; + const char *template_dir = NULL; + char *path; + int len, i; + + for (i = 1; i < argc; i++, argv++) { + const char *arg = argv[1]; + if (!strncmp(arg, "--template=", 11)) + template_dir = arg+11; + else if (!strcmp(arg, "--shared")) + shared_repository = 1; + else + die(init_db_usage); + } + + /* + * Set up the default .git directory contents + */ + git_dir = getenv(GIT_DIR_ENVIRONMENT); + if (!git_dir) { + git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; + fprintf(stderr, "defaulting to local storage area\n"); + } + safe_create_dir(git_dir, 0); + + /* Check to see if the repository version is right. + * Note that a newly created repository does not have + * config file, so this will not fail. What we are catching + * is an attempt to reinitialize new repository with an old tool. + */ + check_repository_format(); + + create_default_files(git_dir, template_dir); + + /* + * And set up the object store. + */ + sha1_dir = get_object_directory(); + len = strlen(sha1_dir); + path = xmalloc(len + 40); + memcpy(path, sha1_dir, len); + + safe_create_dir(sha1_dir, 1); + strcpy(path+len, "/pack"); + safe_create_dir(path, 1); + strcpy(path+len, "/info"); + safe_create_dir(path, 1); + + if (shared_repository) + git_config_set("core.sharedRepository", "true"); + + return 0; +} diff --git a/builtin.h b/builtin.h index ff559dec7e..60541262c4 100644 --- a/builtin.h +++ b/builtin.h @@ -26,5 +26,6 @@ extern int cmd_push(int argc, const char **argv, char **envp); extern int cmd_grep(int argc, const char **argv, char **envp); extern int cmd_rev_list(int argc, const char **argv, char **envp); extern int cmd_check_ref_format(int argc, const char **argv, char **envp); +extern int cmd_init_db(int argc, const char **argv, char **envp); #endif diff --git a/git.c b/git.c index d0650bb409..3216d311b2 100644 --- a/git.c +++ b/git.c @@ -51,6 +51,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "diff", cmd_diff }, { "grep", cmd_grep }, { "rev-list", cmd_rev_list }, + { "init-db", cmd_init_db }, { "check-ref-format", cmd_check_ref_format } }; int i; diff --git a/init-db.c b/init-db.c deleted file mode 100644 index ff294960f2..0000000000 --- a/init-db.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * GIT - The information manager from hell - * - * Copyright (C) Linus Torvalds, 2005 - */ -#include "cache.h" - -#ifndef DEFAULT_GIT_TEMPLATE_DIR -#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/" -#endif - -static void safe_create_dir(const char *dir, int share) -{ - if (mkdir(dir, 0777) < 0) { - if (errno != EEXIST) { - perror(dir); - exit(1); - } - } - else if (share && adjust_shared_perm(dir)) - die("Could not make %s writable by group\n", dir); -} - -static int copy_file(const char *dst, const char *src, int mode) -{ - int fdi, fdo, status; - - mode = (mode & 0111) ? 0777 : 0666; - if ((fdi = open(src, O_RDONLY)) < 0) - return fdi; - if ((fdo = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) { - close(fdi); - return fdo; - } - status = copy_fd(fdi, fdo); - close(fdo); - - if (!status && adjust_shared_perm(dst)) - return -1; - - return status; -} - -static void copy_templates_1(char *path, int baselen, - char *template, int template_baselen, - DIR *dir) -{ - struct dirent *de; - - /* Note: if ".git/hooks" file exists in the repository being - * re-initialized, /etc/core-git/templates/hooks/update would - * cause git-init-db to fail here. I think this is sane but - * it means that the set of templates we ship by default, along - * with the way the namespace under .git/ is organized, should - * be really carefully chosen. - */ - safe_create_dir(path, 1); - while ((de = readdir(dir)) != NULL) { - struct stat st_git, st_template; - int namelen; - int exists = 0; - - if (de->d_name[0] == '.') - continue; - namelen = strlen(de->d_name); - if ((PATH_MAX <= baselen + namelen) || - (PATH_MAX <= template_baselen + namelen)) - die("insanely long template name %s", de->d_name); - memcpy(path + baselen, de->d_name, namelen+1); - memcpy(template + template_baselen, de->d_name, namelen+1); - if (lstat(path, &st_git)) { - if (errno != ENOENT) - die("cannot stat %s", path); - } - else - exists = 1; - - if (lstat(template, &st_template)) - die("cannot stat template %s", template); - - if (S_ISDIR(st_template.st_mode)) { - DIR *subdir = opendir(template); - int baselen_sub = baselen + namelen; - int template_baselen_sub = template_baselen + namelen; - if (!subdir) - die("cannot opendir %s", template); - path[baselen_sub++] = - template[template_baselen_sub++] = '/'; - path[baselen_sub] = - template[template_baselen_sub] = 0; - copy_templates_1(path, baselen_sub, - template, template_baselen_sub, - subdir); - closedir(subdir); - } - else if (exists) - continue; - else if (S_ISLNK(st_template.st_mode)) { - char lnk[256]; - int len; - len = readlink(template, lnk, sizeof(lnk)); - if (len < 0) - die("cannot readlink %s", template); - if (sizeof(lnk) <= len) - die("insanely long symlink %s", template); - lnk[len] = 0; - if (symlink(lnk, path)) - die("cannot symlink %s %s", lnk, path); - } - else if (S_ISREG(st_template.st_mode)) { - if (copy_file(path, template, st_template.st_mode)) - die("cannot copy %s to %s", template, path); - } - else - error("ignoring template %s", template); - } -} - -static void copy_templates(const char *git_dir, int len, char *template_dir) -{ - char path[PATH_MAX]; - char template_path[PATH_MAX]; - int template_len; - DIR *dir; - - if (!template_dir) - template_dir = DEFAULT_GIT_TEMPLATE_DIR; - strcpy(template_path, template_dir); - template_len = strlen(template_path); - if (template_path[template_len-1] != '/') { - template_path[template_len++] = '/'; - template_path[template_len] = 0; - } - dir = opendir(template_path); - if (!dir) { - fprintf(stderr, "warning: templates not found %s\n", - template_dir); - return; - } - - /* Make sure that template is from the correct vintage */ - strcpy(template_path + template_len, "config"); - repository_format_version = 0; - git_config_from_file(check_repository_format_version, - template_path); - template_path[template_len] = 0; - - if (repository_format_version && - repository_format_version != GIT_REPO_VERSION) { - fprintf(stderr, "warning: not copying templates of " - "a wrong format version %d from '%s'\n", - repository_format_version, - template_dir); - closedir(dir); - return; - } - - memcpy(path, git_dir, len); - path[len] = 0; - copy_templates_1(path, len, - template_path, template_len, - dir); - closedir(dir); -} - -static void create_default_files(const char *git_dir, char *template_path) -{ - unsigned len = strlen(git_dir); - static char path[PATH_MAX]; - unsigned char sha1[20]; - struct stat st1; - char repo_version_string[10]; - - if (len > sizeof(path)-50) - die("insane git directory %s", git_dir); - memcpy(path, git_dir, len); - - if (len && path[len-1] != '/') - path[len++] = '/'; - - /* - * Create .git/refs/{heads,tags} - */ - strcpy(path + len, "refs"); - safe_create_dir(path, 1); - strcpy(path + len, "refs/heads"); - safe_create_dir(path, 1); - strcpy(path + len, "refs/tags"); - safe_create_dir(path, 1); - - /* First copy the templates -- we might have the default - * config file there, in which case we would want to read - * from it after installing. - */ - path[len] = 0; - copy_templates(path, len, template_path); - - git_config(git_default_config); - - /* - * Create the default symlink from ".git/HEAD" to the "master" - * branch, if it does not exist yet. - */ - strcpy(path + len, "HEAD"); - if (read_ref(path, sha1) < 0) { - if (create_symref(path, "refs/heads/master") < 0) - exit(1); - } - - /* This forces creation of new config file */ - sprintf(repo_version_string, "%d", GIT_REPO_VERSION); - git_config_set("core.repositoryformatversion", repo_version_string); - - path[len] = 0; - strcpy(path + len, "config"); - - /* Check filemode trustability */ - if (!lstat(path, &st1)) { - struct stat st2; - int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && - !lstat(path, &st2) && - st1.st_mode != st2.st_mode); - git_config_set("core.filemode", - filemode ? "true" : "false"); - } -} - -static const char init_db_usage[] = -"git-init-db [--template=] [--shared]"; - -/* - * If you want to, you can share the DB area with any number of branches. - * That has advantages: you can save space by sharing all the SHA1 objects. - * On the other hand, it might just make lookup slower and messier. You - * be the judge. The default case is to have one DB per managed directory. - */ -int main(int argc, char **argv) -{ - const char *git_dir; - const char *sha1_dir; - char *path, *template_dir = NULL; - int len, i; - - for (i = 1; i < argc; i++, argv++) { - char *arg = argv[1]; - if (!strncmp(arg, "--template=", 11)) - template_dir = arg+11; - else if (!strcmp(arg, "--shared")) - shared_repository = 1; - else - die(init_db_usage); - } - - /* - * Set up the default .git directory contents - */ - git_dir = getenv(GIT_DIR_ENVIRONMENT); - if (!git_dir) { - git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; - fprintf(stderr, "defaulting to local storage area\n"); - } - safe_create_dir(git_dir, 0); - - /* Check to see if the repository version is right. - * Note that a newly created repository does not have - * config file, so this will not fail. What we are catching - * is an attempt to reinitialize new repository with an old tool. - */ - check_repository_format(); - - create_default_files(git_dir, template_dir); - - /* - * And set up the object store. - */ - sha1_dir = get_object_directory(); - len = strlen(sha1_dir); - path = xmalloc(len + 40); - memcpy(path, sha1_dir, len); - - safe_create_dir(sha1_dir, 1); - strcpy(path+len, "/pack"); - safe_create_dir(path, 1); - strcpy(path+len, "/info"); - safe_create_dir(path, 1); - - if (shared_repository) - git_config_set("core.sharedRepository", "true"); - - return 0; -} -- cgit v1.3