From a21bc66e55847ea84578e6367c942c4a760d34ab Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Tue, 2 Aug 2016 19:13:28 -0300 Subject: [PATCH] eeshow/: make "related" work also for repositories (WIP) For now, we only support the case where the file doesn't exists in any other repo, which is a common situation with sub-sheets. --- eeshow/file.c | 92 ++++++++++++++++++++++++++--------- eeshow/file.h | 2 + eeshow/git-file.c | 120 +++++++++++++++++++++++++++++++++++++++++----- eeshow/git-file.h | 3 +- 4 files changed, 183 insertions(+), 34 deletions(-) diff --git a/eeshow/file.c b/eeshow/file.c index c6f949e..386149a 100644 --- a/eeshow/file.c +++ b/eeshow/file.c @@ -10,6 +10,7 @@ * (at your option) any later version. */ +#include #include #include #include @@ -28,28 +29,42 @@ bool file_cat(const struct file *file, void *user, const char *line) } +char *file_graft_relative(const char *base, const char *name) +{ + const char *slash; + char *res; + unsigned len; + + if (*name == '/') + return NULL; + + slash = strrchr(base, '/'); + if (!slash) + return NULL; + + len = slash + 1 - base; + res = alloc_size(len + strlen(name) + 1); + memcpy(res, base, len); + strcpy(res + len, name); + + return res; +} + + static bool try_related(struct file *file) { - const char *related; - const char *slash; char *tmp; - unsigned len; if (!file->related) return 0; + + tmp = file_graft_relative(file->related->name, file->name); + if (!tmp) + return NULL; + if (*file->name == '/') return 0; - related = file->related->name; - slash = strrchr(related, '/'); - if (!slash) - return 0; - - len = slash + 1 - related; - tmp = alloc_size(len + strlen(file->name) + 1); - memcpy(tmp, related, len); - strcpy(tmp + len, file->name); - file->file = fopen(tmp, "r"); if (!file->file) { free(tmp); @@ -90,15 +105,52 @@ static bool try_related(struct file *file) * @@@ explicit revision should always win over related. */ +static void *open_vcs(struct file *file) +{ + char *colon; + + colon = strchr(file->name, ':'); + if (colon) { + char *tmp; + + tmp = stralloc(file->name); + tmp[colon - file->name] = 0; + file->vcs = vcs_git_open(tmp, colon + 1, + file->related ? file->related->vcs : NULL); + if (file->vcs) { + free(tmp); + return file->vcs; + } + if (verbose > 1) + fprintf(stderr, "could not open %s:%s\n", + tmp, colon + 1); + return NULL; + } else { + file->vcs = vcs_git_open(NULL, file->name, + file->related ? file->related->vcs : NULL); + if (file->vcs) + return file->vcs; + if (verbose > 1) + fprintf(stderr, "could not open %s\n", file->name); + return 0; + } +} + + void file_open(struct file *file, const char *name, const struct file *related) { - char *colon, *tmp; - file->name = stralloc(name); file->lineno = 0; file->related = related; + file->file = NULL; file->vcs = NULL; + if (related && related->vcs) { + file->vcs = open_vcs(file); + if (file->vcs) + return; + } + file->file = fopen(name, "r"); if (file->file) { if (verbose) @@ -112,21 +164,17 @@ void file_open(struct file *file, const char *name, const struct file *related) if (verbose) perror(name); - colon = strchr(name, ':'); - if (!colon) { + if (!strchr(name, ':')) { if (!verbose) perror(name); exit(1); } - tmp = stralloc(name); - tmp[colon - name] = 0; - file->vcs = vcs_git_open(tmp, colon + 1); + file->vcs = open_vcs(file); if (!file->vcs) { - fprintf(stderr, "could not open %s:%s\n", tmp, colon + 1); + fprintf(stderr, "could not open %s\n", name); exit(1); } - free(tmp); } diff --git a/eeshow/file.h b/eeshow/file.h index 43db8b7..ff28d92 100644 --- a/eeshow/file.h +++ b/eeshow/file.h @@ -28,6 +28,8 @@ struct file { bool file_cat(const struct file *file, void *user, const char *line); +char *file_graft_relative(const char *base, const char *name); + void file_open(struct file *file, const char *name, const struct file *related); void file_read(struct file *file, diff --git a/eeshow/git-file.c b/eeshow/git-file.c index 261de53..acc1e4f 100644 --- a/eeshow/git-file.c +++ b/eeshow/git-file.c @@ -27,6 +27,13 @@ struct vcs_git { + const char *name; + const char *revision; + const struct vcs_git *related; + + git_repository *repo; + git_tree *tree; + const void *data; unsigned size; }; @@ -305,6 +312,18 @@ static const void *get_data(git_repository *repo, git_tree_entry *entry, exit(1); } + if (verbose > 2) { + git_buf buf = { 0 } ; + + if (git_object_short_id(&buf, obj)) { + const git_error *e = giterr_last(); + + fprintf(stderr, "%s\n", e->message); + exit(1); + } + fprintf(stderr, "object %s\n", buf.ptr); + git_buf_free(&buf); + } blob = (git_blob *) obj; *size = git_blob_rawsize(blob); return git_blob_rawcontent(blob); @@ -326,12 +345,78 @@ static bool send_line(const char *s, unsigned len, } -struct vcs_git *vcs_git_open(const char *revision, const char *name) +static bool related_same_repo(struct vcs_git *vcs_git) +{ + /* @@@ use same revision */ + fprintf(stderr, "related_same_repo is no yet implemented\n"); + return 0; +} + + +static bool related_other_repo(struct vcs_git *vcs_git) +{ + /* @@@ find revision <= date of revision in related */ + fprintf(stderr, "related_other_repo is no yet implemented\n"); + return 0; +} + + +static bool related_only_repo(struct vcs_git *vcs_git) +{ + const struct vcs_git *related = vcs_git->related; + char *tmp; + git_tree_entry *entry; + + if (verbose > 1) + fprintf(stderr, "trying graft \"%s\" \"%s\"\n", + related->name, vcs_git->name); + tmp = file_graft_relative(related->name, vcs_git->name); + if (!tmp) + return 0; + + vcs_git->repo = related->repo; + vcs_git->tree = related->tree; + + /* @@@ code below also exists in vcs_git_open */ + + entry = find_file(vcs_git->repo, vcs_git->tree, tmp); + if (verbose) + fprintf(stderr, "reading %s\n", tmp); + + vcs_git->data = get_data(vcs_git->repo, entry, &vcs_git->size); + + free((char *) vcs_git->name); + vcs_git->name = tmp; + + return 1; +} + + +static bool try_related(struct vcs_git *vcs_git) +{ + if (!vcs_git->related) + return 0; + if (vcs_git->revision) + return 0; + + vcs_git->repo = select_repo(vcs_git->name); + if (vcs_git->repo) { + if (!strcmp(git_repository_path(vcs_git->related->repo), + git_repository_path(vcs_git->repo))) + return related_same_repo(vcs_git); + else + return related_other_repo(vcs_git); + } + + return related_only_repo(vcs_git); +} + + +struct vcs_git *vcs_git_open(const char *revision, const char *name, + const struct vcs_git *related) { static bool initialized = 0; struct vcs_git *vcs_git = alloc_type(struct vcs_git); - git_repository *repo; - git_tree *tree; git_tree_entry *entry; if (!initialized) { @@ -339,21 +424,30 @@ struct vcs_git *vcs_git_open(const char *revision, const char *name) initialized = 1; } - repo = select_repo(name); - if (!repo) { - fprintf(stderr, "%s:%s not found\n", revision, name); + vcs_git->name = stralloc(name); + vcs_git->revision = revision ? stralloc(revision) : NULL; + vcs_git->related = related; + + if (try_related(vcs_git)) + return vcs_git; + + vcs_git->repo = select_repo(name); + if (!vcs_git->repo) { + fprintf(stderr, "%s: not found\n", name); exit(1); } if (verbose > 1) fprintf(stderr, "using repository %s\n", - git_repository_path(repo)); + git_repository_path(vcs_git->repo)); - tree = pick_revision(repo, revision); - entry = find_file(repo, tree, name); + if (!revision) + revision = "HEAD"; + vcs_git->tree = pick_revision(vcs_git->repo, revision); + entry = find_file(vcs_git->repo, vcs_git->tree, name); if (verbose) fprintf(stderr, "reading %s:%s\n", revision, name); - vcs_git->data = get_data(repo, entry, &vcs_git->size); + vcs_git->data = get_data(vcs_git->repo, entry, &vcs_git->size); return vcs_git; } @@ -384,5 +478,9 @@ void vcs_git_read(void *ctx, struct file *file, void vcs_git_close(void *ctx) { - free(ctx); + struct vcs_git *vcs_git = ctx; + + free((char *) vcs_git->name); + free((char *) vcs_git->revision); + free(vcs_git); } diff --git a/eeshow/git-file.h b/eeshow/git-file.h index 9214d93..1b4c0ff 100644 --- a/eeshow/git-file.h +++ b/eeshow/git-file.h @@ -29,7 +29,8 @@ struct vcs_git; struct file; -struct vcs_git *vcs_git_open(const char *revision, const char *name); +struct vcs_git *vcs_git_open(const char *revision, const char *name, + const struct vcs_git *related); void vcs_git_read(void *ctx, struct file *file, bool (*parse)(const struct file *file, void *user, const char *line), void *user);