diff --git a/fast-import.c b/fast-import.c index 50171d69ca..e692f6b430 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");