submodule.con commit t5800: testgit helper requires Python support (63a2f61)
   1#include "cache.h"
   2#include "submodule.h"
   3#include "dir.h"
   4#include "diff.h"
   5#include "commit.h"
   6#include "revision.h"
   7#include "run-command.h"
   8#include "diffcore.h"
   9
  10static int add_submodule_odb(const char *path)
  11{
  12        struct strbuf objects_directory = STRBUF_INIT;
  13        struct alternate_object_database *alt_odb;
  14        int ret = 0;
  15
  16        strbuf_addf(&objects_directory, "%s/.git/objects/", path);
  17        if (!is_directory(objects_directory.buf)) {
  18                ret = -1;
  19                goto done;
  20        }
  21        /* avoid adding it twice */
  22        for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)
  23                if (alt_odb->name - alt_odb->base == objects_directory.len &&
  24                                !strncmp(alt_odb->base, objects_directory.buf,
  25                                        objects_directory.len))
  26                        goto done;
  27
  28        alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
  29        alt_odb->next = alt_odb_list;
  30        strcpy(alt_odb->base, objects_directory.buf);
  31        alt_odb->name = alt_odb->base + objects_directory.len;
  32        alt_odb->name[2] = '/';
  33        alt_odb->name[40] = '\0';
  34        alt_odb->name[41] = '\0';
  35        alt_odb_list = alt_odb;
  36        prepare_alt_odb();
  37done:
  38        strbuf_release(&objects_directory);
  39        return ret;
  40}
  41
  42void show_submodule_summary(FILE *f, const char *path,
  43                unsigned char one[20], unsigned char two[20],
  44                unsigned dirty_submodule,
  45                const char *del, const char *add, const char *reset)
  46{
  47        struct rev_info rev;
  48        struct commit *commit, *left = left, *right = right;
  49        struct commit_list *merge_bases, *list;
  50        const char *message = NULL;
  51        struct strbuf sb = STRBUF_INIT;
  52        static const char *format = "  %m %s";
  53        int fast_forward = 0, fast_backward = 0;
  54
  55        if (is_null_sha1(two))
  56                message = "(submodule deleted)";
  57        else if (add_submodule_odb(path))
  58                message = "(not checked out)";
  59        else if (is_null_sha1(one))
  60                message = "(new submodule)";
  61        else if (!(left = lookup_commit_reference(one)) ||
  62                 !(right = lookup_commit_reference(two)))
  63                message = "(commits not present)";
  64
  65        if (!message) {
  66                init_revisions(&rev, NULL);
  67                setup_revisions(0, NULL, &rev, NULL);
  68                rev.left_right = 1;
  69                rev.first_parent_only = 1;
  70                left->object.flags |= SYMMETRIC_LEFT;
  71                add_pending_object(&rev, &left->object, path);
  72                add_pending_object(&rev, &right->object, path);
  73                merge_bases = get_merge_bases(left, right, 1);
  74                if (merge_bases) {
  75                        if (merge_bases->item == left)
  76                                fast_forward = 1;
  77                        else if (merge_bases->item == right)
  78                                fast_backward = 1;
  79                }
  80                for (list = merge_bases; list; list = list->next) {
  81                        list->item->object.flags |= UNINTERESTING;
  82                        add_pending_object(&rev, &list->item->object,
  83                                sha1_to_hex(list->item->object.sha1));
  84                }
  85                if (prepare_revision_walk(&rev))
  86                        message = "(revision walker failed)";
  87        }
  88
  89        if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
  90                fprintf(f, "Submodule %s contains untracked content\n", path);
  91        if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
  92                fprintf(f, "Submodule %s contains modified content\n", path);
  93
  94        if (!hashcmp(one, two)) {
  95                strbuf_release(&sb);
  96                return;
  97        }
  98
  99        strbuf_addf(&sb, "Submodule %s %s..", path,
 100                        find_unique_abbrev(one, DEFAULT_ABBREV));
 101        if (!fast_backward && !fast_forward)
 102                strbuf_addch(&sb, '.');
 103        strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
 104        if (message)
 105                strbuf_addf(&sb, " %s\n", message);
 106        else
 107                strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
 108        fwrite(sb.buf, sb.len, 1, f);
 109
 110        if (!message) {
 111                while ((commit = get_revision(&rev))) {
 112                        struct pretty_print_context ctx = {0};
 113                        ctx.date_mode = rev.date_mode;
 114                        strbuf_setlen(&sb, 0);
 115                        if (commit->object.flags & SYMMETRIC_LEFT) {
 116                                if (del)
 117                                        strbuf_addstr(&sb, del);
 118                        }
 119                        else if (add)
 120                                strbuf_addstr(&sb, add);
 121                        format_commit_message(commit, format, &sb, &ctx);
 122                        if (reset)
 123                                strbuf_addstr(&sb, reset);
 124                        strbuf_addch(&sb, '\n');
 125                        fprintf(f, "%s", sb.buf);
 126                }
 127                clear_commit_marks(left, ~0);
 128                clear_commit_marks(right, ~0);
 129        }
 130        strbuf_release(&sb);
 131}
 132
 133unsigned is_submodule_modified(const char *path, int ignore_untracked)
 134{
 135        int i;
 136        ssize_t len;
 137        struct child_process cp;
 138        const char *argv[] = {
 139                "status",
 140                "--porcelain",
 141                NULL,
 142                NULL,
 143        };
 144        const char *env[LOCAL_REPO_ENV_SIZE + 3];
 145        struct strbuf buf = STRBUF_INIT;
 146        unsigned dirty_submodule = 0;
 147        const char *line, *next_line;
 148
 149        for (i = 0; i < LOCAL_REPO_ENV_SIZE; i++)
 150                env[i] = local_repo_env[i];
 151
 152        strbuf_addf(&buf, "%s/.git/", path);
 153        if (!is_directory(buf.buf)) {
 154                strbuf_release(&buf);
 155                /* The submodule is not checked out, so it is not modified */
 156                return 0;
 157
 158        }
 159        strbuf_reset(&buf);
 160
 161        strbuf_addf(&buf, "GIT_WORK_TREE=%s", path);
 162        env[i++] = strbuf_detach(&buf, NULL);
 163        strbuf_addf(&buf, "GIT_DIR=%s/.git", path);
 164        env[i++] = strbuf_detach(&buf, NULL);
 165        env[i] = NULL;
 166
 167        if (ignore_untracked)
 168                argv[2] = "-uno";
 169
 170        memset(&cp, 0, sizeof(cp));
 171        cp.argv = argv;
 172        cp.env = env;
 173        cp.git_cmd = 1;
 174        cp.no_stdin = 1;
 175        cp.out = -1;
 176        if (start_command(&cp))
 177                die("Could not run git status --porcelain");
 178
 179        len = strbuf_read(&buf, cp.out, 1024);
 180        line = buf.buf;
 181        while (len > 2) {
 182                if ((line[0] == '?') && (line[1] == '?')) {
 183                        dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
 184                        if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
 185                                break;
 186                } else {
 187                        dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
 188                        if (ignore_untracked ||
 189                            (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED))
 190                                break;
 191                }
 192                next_line = strchr(line, '\n');
 193                if (!next_line)
 194                        break;
 195                next_line++;
 196                len -= (next_line - line);
 197                line = next_line;
 198        }
 199        close(cp.out);
 200
 201        if (finish_command(&cp))
 202                die("git status --porcelain failed");
 203
 204        for (i = LOCAL_REPO_ENV_SIZE; env[i]; i++)
 205                free((char *)env[i]);
 206        strbuf_release(&buf);
 207        return dirty_submodule;
 208}