|
| 1 | +#include "cache.h" |
| 2 | +#include "refs.h" |
| 3 | + |
| 4 | +static const char *notnull(const char *arg, const char *name) |
| 5 | +{ |
| 6 | + if (!arg) |
| 7 | + die("%s required", name); |
| 8 | + return arg; |
| 9 | +} |
| 10 | + |
| 11 | +static unsigned int arg_flags(const char *arg, const char *name) |
| 12 | +{ |
| 13 | + return atoi(notnull(arg, name)); |
| 14 | +} |
| 15 | + |
| 16 | +static const char **get_store(const char **argv, struct ref_store **refs) |
| 17 | +{ |
| 18 | + const char *gitdir; |
| 19 | + |
| 20 | + if (!argv[0]) { |
| 21 | + die("ref store required"); |
| 22 | + } else if (!strcmp(argv[0], "main")) { |
| 23 | + *refs = get_main_ref_store(); |
| 24 | + } else if (skip_prefix(argv[0], "submodule:", &gitdir)) { |
| 25 | + struct strbuf sb = STRBUF_INIT; |
| 26 | + int ret; |
| 27 | + |
| 28 | + ret = strbuf_git_path_submodule(&sb, gitdir, "objects/"); |
| 29 | + if (ret) |
| 30 | + die("strbuf_git_path_submodule failed: %d", ret); |
| 31 | + add_to_alternates_memory(sb.buf); |
| 32 | + strbuf_release(&sb); |
| 33 | + |
| 34 | + *refs = get_submodule_ref_store(gitdir); |
| 35 | + } else |
| 36 | + die("unknown backend %s", argv[0]); |
| 37 | + |
| 38 | + if (!*refs) |
| 39 | + die("no ref store"); |
| 40 | + |
| 41 | + /* consume store-specific optional arguments if needed */ |
| 42 | + |
| 43 | + return argv + 1; |
| 44 | +} |
| 45 | + |
| 46 | + |
| 47 | +static int cmd_pack_refs(struct ref_store *refs, const char **argv) |
| 48 | +{ |
| 49 | + unsigned int flags = arg_flags(*argv++, "flags"); |
| 50 | + |
| 51 | + return refs_pack_refs(refs, flags); |
| 52 | +} |
| 53 | + |
| 54 | +static int cmd_peel_ref(struct ref_store *refs, const char **argv) |
| 55 | +{ |
| 56 | + const char *refname = notnull(*argv++, "refname"); |
| 57 | + unsigned char sha1[20]; |
| 58 | + int ret; |
| 59 | + |
| 60 | + ret = refs_peel_ref(refs, refname, sha1); |
| 61 | + if (!ret) |
| 62 | + puts(sha1_to_hex(sha1)); |
| 63 | + return ret; |
| 64 | +} |
| 65 | + |
| 66 | +static int cmd_create_symref(struct ref_store *refs, const char **argv) |
| 67 | +{ |
| 68 | + const char *refname = notnull(*argv++, "refname"); |
| 69 | + const char *target = notnull(*argv++, "target"); |
| 70 | + const char *logmsg = *argv++; |
| 71 | + |
| 72 | + return refs_create_symref(refs, refname, target, logmsg); |
| 73 | +} |
| 74 | + |
| 75 | +static int cmd_delete_refs(struct ref_store *refs, const char **argv) |
| 76 | +{ |
| 77 | + unsigned int flags = arg_flags(*argv++, "flags"); |
| 78 | + struct string_list refnames = STRING_LIST_INIT_NODUP; |
| 79 | + |
| 80 | + while (*argv) |
| 81 | + string_list_append(&refnames, *argv++); |
| 82 | + |
| 83 | + return refs_delete_refs(refs, &refnames, flags); |
| 84 | +} |
| 85 | + |
| 86 | +static int cmd_rename_ref(struct ref_store *refs, const char **argv) |
| 87 | +{ |
| 88 | + const char *oldref = notnull(*argv++, "oldref"); |
| 89 | + const char *newref = notnull(*argv++, "newref"); |
| 90 | + const char *logmsg = *argv++; |
| 91 | + |
| 92 | + return refs_rename_ref(refs, oldref, newref, logmsg); |
| 93 | +} |
| 94 | + |
| 95 | +static int each_ref(const char *refname, const struct object_id *oid, |
| 96 | + int flags, void *cb_data) |
| 97 | +{ |
| 98 | + printf("%s %s 0x%x\n", oid_to_hex(oid), refname, flags); |
| 99 | + return 0; |
| 100 | +} |
| 101 | + |
| 102 | +static int cmd_for_each_ref(struct ref_store *refs, const char **argv) |
| 103 | +{ |
| 104 | + const char *prefix = notnull(*argv++, "prefix"); |
| 105 | + |
| 106 | + return refs_for_each_ref_in(refs, prefix, each_ref, NULL); |
| 107 | +} |
| 108 | + |
| 109 | +static int cmd_resolve_ref(struct ref_store *refs, const char **argv) |
| 110 | +{ |
| 111 | + unsigned char sha1[20]; |
| 112 | + const char *refname = notnull(*argv++, "refname"); |
| 113 | + int resolve_flags = arg_flags(*argv++, "resolve-flags"); |
| 114 | + int flags; |
| 115 | + const char *ref; |
| 116 | + |
| 117 | + ref = refs_resolve_ref_unsafe(refs, refname, resolve_flags, |
| 118 | + sha1, &flags); |
| 119 | + printf("%s %s 0x%x\n", sha1_to_hex(sha1), ref, flags); |
| 120 | + return ref ? 0 : 1; |
| 121 | +} |
| 122 | + |
| 123 | +static int cmd_verify_ref(struct ref_store *refs, const char **argv) |
| 124 | +{ |
| 125 | + const char *refname = notnull(*argv++, "refname"); |
| 126 | + struct strbuf err = STRBUF_INIT; |
| 127 | + int ret; |
| 128 | + |
| 129 | + ret = refs_verify_refname_available(refs, refname, NULL, NULL, &err); |
| 130 | + if (err.len) |
| 131 | + puts(err.buf); |
| 132 | + return ret; |
| 133 | +} |
| 134 | + |
| 135 | +static int cmd_for_each_reflog(struct ref_store *refs, const char **argv) |
| 136 | +{ |
| 137 | + return refs_for_each_reflog(refs, each_ref, NULL); |
| 138 | +} |
| 139 | + |
| 140 | +static int each_reflog(struct object_id *old_oid, struct object_id *new_oid, |
| 141 | + const char *committer, unsigned long timestamp, |
| 142 | + int tz, const char *msg, void *cb_data) |
| 143 | +{ |
| 144 | + printf("%s %s %s %lu %d %s\n", |
| 145 | + oid_to_hex(old_oid), oid_to_hex(new_oid), |
| 146 | + committer, timestamp, tz, msg); |
| 147 | + return 0; |
| 148 | +} |
| 149 | + |
| 150 | +static int cmd_for_each_reflog_ent(struct ref_store *refs, const char **argv) |
| 151 | +{ |
| 152 | + const char *refname = notnull(*argv++, "refname"); |
| 153 | + |
| 154 | + return refs_for_each_reflog_ent(refs, refname, each_reflog, refs); |
| 155 | +} |
| 156 | + |
| 157 | +static int cmd_for_each_reflog_ent_reverse(struct ref_store *refs, const char **argv) |
| 158 | +{ |
| 159 | + const char *refname = notnull(*argv++, "refname"); |
| 160 | + |
| 161 | + return refs_for_each_reflog_ent_reverse(refs, refname, each_reflog, refs); |
| 162 | +} |
| 163 | + |
| 164 | +static int cmd_reflog_exists(struct ref_store *refs, const char **argv) |
| 165 | +{ |
| 166 | + const char *refname = notnull(*argv++, "refname"); |
| 167 | + |
| 168 | + return !refs_reflog_exists(refs, refname); |
| 169 | +} |
| 170 | + |
| 171 | +static int cmd_create_reflog(struct ref_store *refs, const char **argv) |
| 172 | +{ |
| 173 | + const char *refname = notnull(*argv++, "refname"); |
| 174 | + int force_create = arg_flags(*argv++, "force-create"); |
| 175 | + struct strbuf err = STRBUF_INIT; |
| 176 | + int ret; |
| 177 | + |
| 178 | + ret = refs_create_reflog(refs, refname, force_create, &err); |
| 179 | + if (err.len) |
| 180 | + puts(err.buf); |
| 181 | + return ret; |
| 182 | +} |
| 183 | + |
| 184 | +static int cmd_delete_reflog(struct ref_store *refs, const char **argv) |
| 185 | +{ |
| 186 | + const char *refname = notnull(*argv++, "refname"); |
| 187 | + |
| 188 | + return refs_delete_reflog(refs, refname); |
| 189 | +} |
| 190 | + |
| 191 | +static int cmd_reflog_expire(struct ref_store *refs, const char **argv) |
| 192 | +{ |
| 193 | + die("not supported yet"); |
| 194 | +} |
| 195 | + |
| 196 | +static int cmd_delete_ref(struct ref_store *refs, const char **argv) |
| 197 | +{ |
| 198 | + const char *msg = notnull(*argv++, "msg"); |
| 199 | + const char *refname = notnull(*argv++, "refname"); |
| 200 | + const char *sha1_buf = notnull(*argv++, "old-sha1"); |
| 201 | + unsigned int flags = arg_flags(*argv++, "flags"); |
| 202 | + unsigned char old_sha1[20]; |
| 203 | + |
| 204 | + if (get_sha1_hex(sha1_buf, old_sha1)) |
| 205 | + die("not sha-1"); |
| 206 | + |
| 207 | + return refs_delete_ref(refs, msg, refname, old_sha1, flags); |
| 208 | +} |
| 209 | + |
| 210 | +static int cmd_update_ref(struct ref_store *refs, const char **argv) |
| 211 | +{ |
| 212 | + const char *msg = notnull(*argv++, "msg"); |
| 213 | + const char *refname = notnull(*argv++, "refname"); |
| 214 | + const char *new_sha1_buf = notnull(*argv++, "old-sha1"); |
| 215 | + const char *old_sha1_buf = notnull(*argv++, "old-sha1"); |
| 216 | + unsigned int flags = arg_flags(*argv++, "flags"); |
| 217 | + unsigned char old_sha1[20]; |
| 218 | + unsigned char new_sha1[20]; |
| 219 | + |
| 220 | + if (get_sha1_hex(old_sha1_buf, old_sha1) || |
| 221 | + get_sha1_hex(new_sha1_buf, new_sha1)) |
| 222 | + die("not sha-1"); |
| 223 | + |
| 224 | + return refs_update_ref(refs, msg, refname, |
| 225 | + new_sha1, old_sha1, |
| 226 | + flags, UPDATE_REFS_DIE_ON_ERR); |
| 227 | +} |
| 228 | + |
| 229 | +struct command { |
| 230 | + const char *name; |
| 231 | + int (*func)(struct ref_store *refs, const char **argv); |
| 232 | +}; |
| 233 | + |
| 234 | +static struct command commands[] = { |
| 235 | + { "pack-refs", cmd_pack_refs }, |
| 236 | + { "peel-ref", cmd_peel_ref }, |
| 237 | + { "create-symref", cmd_create_symref }, |
| 238 | + { "delete-refs", cmd_delete_refs }, |
| 239 | + { "rename-ref", cmd_rename_ref }, |
| 240 | + { "for-each-ref", cmd_for_each_ref }, |
| 241 | + { "resolve-ref", cmd_resolve_ref }, |
| 242 | + { "verify-ref", cmd_verify_ref }, |
| 243 | + { "for-each-reflog", cmd_for_each_reflog }, |
| 244 | + { "for-each-reflog-ent", cmd_for_each_reflog_ent }, |
| 245 | + { "for-each-reflog-ent-reverse", cmd_for_each_reflog_ent_reverse }, |
| 246 | + { "reflog-exists", cmd_reflog_exists }, |
| 247 | + { "create-reflog", cmd_create_reflog }, |
| 248 | + { "delete-reflog", cmd_delete_reflog }, |
| 249 | + { "reflog-expire", cmd_reflog_expire }, |
| 250 | + /* |
| 251 | + * backend transaction functions can't be tested separately |
| 252 | + */ |
| 253 | + { "delete-ref", cmd_delete_ref }, |
| 254 | + { "update-ref", cmd_update_ref }, |
| 255 | + { NULL, NULL } |
| 256 | +}; |
| 257 | + |
| 258 | +int cmd_main(int argc, const char **argv) |
| 259 | +{ |
| 260 | + struct ref_store *refs; |
| 261 | + const char *func; |
| 262 | + struct command *cmd; |
| 263 | + |
| 264 | + setup_git_directory(); |
| 265 | + |
| 266 | + argv = get_store(argv + 1, &refs); |
| 267 | + |
| 268 | + func = *argv++; |
| 269 | + if (!func) |
| 270 | + die("ref function required"); |
| 271 | + for (cmd = commands; cmd->name; cmd++) { |
| 272 | + if (!strcmp(func, cmd->name)) |
| 273 | + return cmd->func(refs, argv); |
| 274 | + } |
| 275 | + die("unknown function %s", func); |
| 276 | + return 0; |
| 277 | +} |
0 commit comments