shallow.con commit Merge branch 'po/remote-set-head-usage' (c766e6f)
   1#include "cache.h"
   2#include "commit.h"
   3#include "tag.h"
   4#include "pkt-line.h"
   5
   6static int is_shallow = -1;
   7static struct stat shallow_stat;
   8static char *alternate_shallow_file;
   9
  10void set_alternate_shallow_file(const char *path)
  11{
  12        if (is_shallow != -1)
  13                die("BUG: is_repository_shallow must not be called before set_alternate_shallow_file");
  14        free(alternate_shallow_file);
  15        alternate_shallow_file = path ? xstrdup(path) : NULL;
  16}
  17
  18int register_shallow(const unsigned char *sha1)
  19{
  20        struct commit_graft *graft =
  21                xmalloc(sizeof(struct commit_graft));
  22        struct commit *commit = lookup_commit(sha1);
  23
  24        hashcpy(graft->sha1, sha1);
  25        graft->nr_parent = -1;
  26        if (commit && commit->object.parsed)
  27                commit->parents = NULL;
  28        return register_commit_graft(graft, 0);
  29}
  30
  31int is_repository_shallow(void)
  32{
  33        FILE *fp;
  34        char buf[1024];
  35        const char *path = alternate_shallow_file;
  36
  37        if (is_shallow >= 0)
  38                return is_shallow;
  39
  40        if (!path)
  41                path = git_path("shallow");
  42        /*
  43         * fetch-pack sets '--shallow-file ""' as an indicator that no
  44         * shallow file should be used. We could just open it and it
  45         * will likely fail. But let's do an explicit check instead.
  46         */
  47        if (!*path ||
  48            stat(path, &shallow_stat) ||
  49            (fp = fopen(path, "r")) == NULL) {
  50                is_shallow = 0;
  51                return is_shallow;
  52        }
  53        is_shallow = 1;
  54
  55        while (fgets(buf, sizeof(buf), fp)) {
  56                unsigned char sha1[20];
  57                if (get_sha1_hex(buf, sha1))
  58                        die("bad shallow line: %s", buf);
  59                register_shallow(sha1);
  60        }
  61        fclose(fp);
  62        return is_shallow;
  63}
  64
  65struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
  66                int shallow_flag, int not_shallow_flag)
  67{
  68        int i = 0, cur_depth = 0;
  69        struct commit_list *result = NULL;
  70        struct object_array stack = OBJECT_ARRAY_INIT;
  71        struct commit *commit = NULL;
  72
  73        while (commit || i < heads->nr || stack.nr) {
  74                struct commit_list *p;
  75                if (!commit) {
  76                        if (i < heads->nr) {
  77                                commit = (struct commit *)
  78                                        deref_tag(heads->objects[i++].item, NULL, 0);
  79                                if (!commit || commit->object.type != OBJ_COMMIT) {
  80                                        commit = NULL;
  81                                        continue;
  82                                }
  83                                if (!commit->util)
  84                                        commit->util = xmalloc(sizeof(int));
  85                                *(int *)commit->util = 0;
  86                                cur_depth = 0;
  87                        } else {
  88                                commit = (struct commit *)
  89                                        stack.objects[--stack.nr].item;
  90                                cur_depth = *(int *)commit->util;
  91                        }
  92                }
  93                if (parse_commit(commit))
  94                        die("invalid commit");
  95                cur_depth++;
  96                if (cur_depth >= depth) {
  97                        commit_list_insert(commit, &result);
  98                        commit->object.flags |= shallow_flag;
  99                        commit = NULL;
 100                        continue;
 101                }
 102                commit->object.flags |= not_shallow_flag;
 103                for (p = commit->parents, commit = NULL; p; p = p->next) {
 104                        if (!p->item->util) {
 105                                int *pointer = xmalloc(sizeof(int));
 106                                p->item->util = pointer;
 107                                *pointer =  cur_depth;
 108                        } else {
 109                                int *pointer = p->item->util;
 110                                if (cur_depth >= *pointer)
 111                                        continue;
 112                                *pointer = cur_depth;
 113                        }
 114                        if (p->next)
 115                                add_object_array(&p->item->object,
 116                                                NULL, &stack);
 117                        else {
 118                                commit = p->item;
 119                                cur_depth = *(int *)commit->util;
 120                        }
 121                }
 122        }
 123
 124        return result;
 125}
 126
 127void check_shallow_file_for_update(void)
 128{
 129        struct stat st;
 130
 131        if (!is_shallow)
 132                return;
 133        else if (is_shallow == -1)
 134                die("BUG: shallow must be initialized by now");
 135
 136        if (stat(git_path("shallow"), &st))
 137                die("shallow file was removed during fetch");
 138        else if (st.st_mtime != shallow_stat.st_mtime
 139#ifdef USE_NSEC
 140                 || ST_MTIME_NSEC(st) != ST_MTIME_NSEC(shallow_stat)
 141#endif
 142                   )
 143                die("shallow file was changed during fetch");
 144}
 145
 146struct write_shallow_data {
 147        struct strbuf *out;
 148        int use_pack_protocol;
 149        int count;
 150};
 151
 152static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
 153{
 154        struct write_shallow_data *data = cb_data;
 155        const char *hex = sha1_to_hex(graft->sha1);
 156        if (graft->nr_parent != -1)
 157                return 0;
 158        data->count++;
 159        if (data->use_pack_protocol)
 160                packet_buf_write(data->out, "shallow %s", hex);
 161        else {
 162                strbuf_addstr(data->out, hex);
 163                strbuf_addch(data->out, '\n');
 164        }
 165        return 0;
 166}
 167
 168int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
 169{
 170        struct write_shallow_data data;
 171        data.out = out;
 172        data.use_pack_protocol = use_pack_protocol;
 173        data.count = 0;
 174        for_each_commit_graft(write_one_shallow, &data);
 175        return data.count;
 176}
 177
 178char *setup_temporary_shallow(void)
 179{
 180        struct strbuf sb = STRBUF_INIT;
 181        int fd;
 182
 183        if (write_shallow_commits(&sb, 0)) {
 184                struct strbuf path = STRBUF_INIT;
 185                strbuf_addstr(&path, git_path("shallow_XXXXXX"));
 186                fd = xmkstemp(path.buf);
 187                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
 188                        die_errno("failed to write to %s",
 189                                  path.buf);
 190                close(fd);
 191                strbuf_release(&sb);
 192                return strbuf_detach(&path, NULL);
 193        }
 194        /*
 195         * is_repository_shallow() sees empty string as "no shallow
 196         * file".
 197         */
 198        return xstrdup("");
 199}
 200
 201void setup_alternate_shallow(struct lock_file *shallow_lock,
 202                             const char **alternate_shallow_file)
 203{
 204        struct strbuf sb = STRBUF_INIT;
 205        int fd;
 206
 207        check_shallow_file_for_update();
 208        fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
 209                                       LOCK_DIE_ON_ERROR);
 210        if (write_shallow_commits(&sb, 0)) {
 211                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
 212                        die_errno("failed to write to %s",
 213                                  shallow_lock->filename);
 214                *alternate_shallow_file = shallow_lock->filename;
 215        } else
 216                /*
 217                 * is_repository_shallow() sees empty string as "no
 218                 * shallow file".
 219                 */
 220                *alternate_shallow_file = "";
 221        strbuf_release(&sb);
 222}