From 72303d44e9d8f3fc9bef039b472a2bd259509420 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 24 Aug 2006 03:12:13 -0400 Subject: [PATCH] Implemented 'tag' command in fast-import. Tags received from the frontend are generated in memory in a simple linked list in the order that the tag commands were sent by the frontend. If multiple different tag objects for the same tag name get generated the last one sent by the frontend will be the one that gets written out at termination. Multiple tag objects for the same name will cause all older tags of the same name to be lost. Signed-off-by: Shawn O. Pearce --- fast-import.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/fast-import.c b/fast-import.c index 50171d69c..e692f6b43 100644 --- a/fast-import.c +++ b/fast-import.c @@ -185,6 +185,13 @@ struct branch unsigned char sha1[20]; }; +struct tag +{ + struct tag *next_tag; + const char *name; + unsigned char sha1[20]; +}; + /* Stats and misc. counters */ static unsigned long max_depth = 10; @@ -234,6 +241,10 @@ static unsigned long branch_table_sz = 1039; static struct branch **branch_table; static struct branch *active_branches; +/* Tag data */ +static struct tag *first_tag; +static struct tag *last_tag; + /* Input stream parsing */ static struct strbuf command_buf; static unsigned long next_mark; @@ -970,6 +981,21 @@ static void dump_branches() } } +static void dump_tags() +{ + static const char *msg = "fast-import"; + struct tag *t; + struct ref_lock *lock; + char path[PATH_MAX]; + + for (t = first_tag; t; t = t->next_tag) { + sprintf(path, "refs/tags/%s", t->name); + lock = lock_any_ref_for_update(path, NULL, 0); + if (!lock || write_ref_sha1(lock, t->sha1, msg) < 0) + die("Can't write %s", path); + } +} + static void read_next_command() { read_line(&command_buf, stdin, '\n'); @@ -1306,6 +1332,102 @@ static void cmd_new_branch() die("An lf did not terminate the branch command as expected."); } +static void cmd_new_tag() +{ + char *str_uq; + const char *endp; + char *sp; + const char *from; + char *tagger; + struct branch *s; + void *msg; + size_t msglen; + char *body; + struct tag *t; + unsigned char sha1[20]; + + /* Obtain the new tag name from the rest of our command */ + sp = strchr(command_buf.buf, ' ') + 1; + str_uq = unquote_c_style(sp, &endp); + if (str_uq) { + if (*endp) + die("Garbage after tag name in: %s", command_buf.buf); + sp = str_uq; + } + t = pool_alloc(sizeof(struct tag)); + t->next_tag = NULL; + t->name = pool_strdup(sp); + if (last_tag) + last_tag->next_tag = t; + else + first_tag = t; + last_tag = t; + if (str_uq) + free(str_uq); + read_next_command(); + + /* from ... */ + if (strncmp("from ", command_buf.buf, 5)) + die("Expected from command, got %s", command_buf.buf); + + from = strchr(command_buf.buf, ' ') + 1; + str_uq = unquote_c_style(from, &endp); + if (str_uq) { + if (*endp) + die("Garbage after string in: %s", command_buf.buf); + from = str_uq; + } + + s = lookup_branch(from); + if (s) { + memcpy(sha1, s->sha1, 20); + } else if (*from == ':') { + unsigned long idnum = strtoul(from + 1, NULL, 10); + struct object_entry *oe = find_mark(idnum); + if (oe->type != OBJ_COMMIT) + die("Mark :%lu not a commit", idnum); + memcpy(sha1, oe->sha1, 20); + } else if (!get_sha1(from, sha1)) { + unsigned long size; + char *buf; + + buf = read_object_with_reference(sha1, + type_names[OBJ_COMMIT], &size, sha1); + if (!buf || size < 46) + die("Not a valid commit: %s", from); + free(buf); + } else + die("Invalid ref name or SHA1 expression: %s", from); + + if (str_uq) + free(str_uq); + read_next_command(); + + /* tagger ... */ + if (strncmp("tagger ", command_buf.buf, 7)) + die("Expected tagger command, got %s", command_buf.buf); + tagger = strdup(command_buf.buf); + + /* tag payload/message */ + read_next_command(); + msg = cmd_data(&msglen); + + /* build the tag object */ + body = xmalloc(67 + strlen(t->name) + strlen(tagger) + msglen); + sp = body; + sp += sprintf(sp, "object %s\n", sha1_to_hex(sha1)); + sp += sprintf(sp, "type %s\n", type_names[OBJ_COMMIT]); + sp += sprintf(sp, "tag %s\n", t->name); + sp += sprintf(sp, "%s\n\n", tagger); + memcpy(sp, msg, msglen); + sp += msglen; + free(tagger); + free(msg); + + store_object(OBJ_TAG, body, sp - body, NULL, t->sha1, 0); + free(body); +} + static const char fast_import_usage[] = "git-fast-import [--objects=n] [--depth=n] [--active-branches=n] temp.pack"; @@ -1367,6 +1489,8 @@ int main(int argc, const char **argv) cmd_new_branch(); else if (!strncmp("commit ", command_buf.buf, 7)) cmd_new_commit(); + else if (!strncmp("tag ", command_buf.buf, 4)) + cmd_new_tag(); else die("Unsupported command: %s", command_buf.buf); } @@ -1375,6 +1499,7 @@ int main(int argc, const char **argv) close(pack_fd); write_index(idx_name); dump_branches(); + dump_tags(); fprintf(stderr, "%s statistics:\n", argv[0]); fprintf(stderr, "---------------------------------------------------\n"); -- 2.30.2