shallow.con commit Merge branch 'jc/ref-excludes' (10167eb)
   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                parse_commit_or_die(commit);
  94                cur_depth++;
  95                if (cur_depth >= depth) {
  96                        commit_list_insert(commit, &result);
  97                        commit->object.flags |= shallow_flag;
  98                        commit = NULL;
  99                        continue;
 100                }
 101                commit->object.flags |= not_shallow_flag;
 102                for (p = commit->parents, commit = NULL; p; p = p->next) {
 103                        if (!p->item->util) {
 104                                int *pointer = xmalloc(sizeof(int));
 105                                p->item->util = pointer;
 106                                *pointer =  cur_depth;
 107                        } else {
 108                                int *pointer = p->item->util;
 109                                if (cur_depth >= *pointer)
 110                                        continue;
 111                                *pointer = cur_depth;
 112                        }
 113                        if (p->next)
 114                                add_object_array(&p->item->object,
 115                                                NULL, &stack);
 116                        else {
 117                                commit = p->item;
 118                                cur_depth = *(int *)commit->util;
 119                        }
 120                }
 121        }
 122
 123        return result;
 124}
 125
 126void check_shallow_file_for_update(void)
 127{
 128        struct stat st;
 129
 130        if (!is_shallow)
 131                return;
 132        else if (is_shallow == -1)
 133                die("BUG: shallow must be initialized by now");
 134
 135        if (stat(git_path("shallow"), &st))
 136                die("shallow file was removed during fetch");
 137        else if (st.st_mtime != shallow_stat.st_mtime
 138#ifdef USE_NSEC
 139                 || ST_MTIME_NSEC(st) != ST_MTIME_NSEC(shallow_stat)
 140#endif
 141                   )
 142                die("shallow file was changed during fetch");
 143}
 144
 145struct write_shallow_data {
 146        struct strbuf *out;
 147        int use_pack_protocol;
 148        int count;
 149};
 150
 151static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
 152{
 153        struct write_shallow_data *data = cb_data;
 154        const char *hex = sha1_to_hex(graft->sha1);
 155        if (graft->nr_parent != -1)
 156                return 0;
 157        data->count++;
 158        if (data->use_pack_protocol)
 159                packet_buf_write(data->out, "shallow %s", hex);
 160        else {
 161                strbuf_addstr(data->out, hex);
 162                strbuf_addch(data->out, '\n');
 163        }
 164        return 0;
 165}
 166
 167int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
 168{
 169        struct write_shallow_data data;
 170        data.out = out;
 171        data.use_pack_protocol = use_pack_protocol;
 172        data.count = 0;
 173        for_each_commit_graft(write_one_shallow, &data);
 174        return data.count;
 175}
 176
 177char *setup_temporary_shallow(void)
 178{
 179        struct strbuf sb = STRBUF_INIT;
 180        int fd;
 181
 182        if (write_shallow_commits(&sb, 0)) {
 183                struct strbuf path = STRBUF_INIT;
 184                strbuf_addstr(&path, git_path("shallow_XXXXXX"));
 185                fd = xmkstemp(path.buf);
 186                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
 187                        die_errno("failed to write to %s",
 188                                  path.buf);
 189                close(fd);
 190                strbuf_release(&sb);
 191                return strbuf_detach(&path, NULL);
 192        }
 193        /*
 194         * is_repository_shallow() sees empty string as "no shallow
 195         * file".
 196         */
 197        return xstrdup("");
 198}
 199
 200void setup_alternate_shallow(struct lock_file *shallow_lock,
 201                             const char **alternate_shallow_file)
 202{
 203        struct strbuf sb = STRBUF_INIT;
 204        int fd;
 205
 206        check_shallow_file_for_update();
 207        fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
 208                                       LOCK_DIE_ON_ERROR);
 209        if (write_shallow_commits(&sb, 0)) {
 210                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
 211                        die_errno("failed to write to %s",
 212                                  shallow_lock->filename);
 213                *alternate_shallow_file = shallow_lock->filename;
 214        } else
 215                /*
 216                 * is_repository_shallow() sees empty string as "no
 217                 * shallow file".
 218                 */
 219                *alternate_shallow_file = "";
 220        strbuf_release(&sb);
 221}