-rw-r--r-- | cgit.c | 1 | ||||
-rw-r--r-- | cgit.h | 1 | ||||
-rw-r--r-- | cmd.c | 2 | ||||
-rw-r--r-- | ui-snapshot.c | 94 | ||||
-rw-r--r-- | ui-snapshot.h | 2 |
5 files changed, 85 insertions, 15 deletions
@@ -241,32 +241,33 @@ static int prepare_repo_cmd(struct cgit_context *ctx) setup_git_directory_gently(&nongit); if (nongit) { ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, "config error"); tmp = fmt("Not a git repository: '%s'", ctx->repo->path); ctx->repo = NULL; cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error(tmp); cgit_print_docend(); return 1; } ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); if (!ctx->qry.head) { + ctx->qry.nohead = 1; ctx->qry.head = find_default_branch(ctx->repo); ctx->repo->defbranch = ctx->qry.head; } if (!ctx->qry.head) { cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error("Repository seems to be empty"); cgit_print_docend(); return 1; } if (get_sha1(ctx->qry.head, sha1)) { tmp = xstrdup(ctx->qry.head); ctx->qry.head = ctx->repo->defbranch; @@ -107,32 +107,33 @@ struct reflist { struct cgit_query { int has_symref; int has_sha1; char *raw; char *repo; char *page; char *search; char *grep; char *head; char *sha1; char *sha2; char *path; char *name; char *mimetype; char *url; int ofs; + int nohead; }; struct cgit_config { char *agefile; char *cache_root; char *clone_prefix; char *css; char *favicon; char *footer; char *index_header; char *index_info; char *logo; char *logo_link; char *module_link; char *repo_group; char *robots; @@ -93,33 +93,33 @@ static void patch_fn(struct cgit_context *ctx) } static void plain_fn(struct cgit_context *ctx) { cgit_print_plain(ctx); } static void refs_fn(struct cgit_context *ctx) { cgit_print_refs(); } static void snapshot_fn(struct cgit_context *ctx) { cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1, cgit_repobasename(ctx->repo->url), ctx->qry.path, - ctx->repo->snapshots); + ctx->repo->snapshots, ctx->qry.nohead); } static void summary_fn(struct cgit_context *ctx) { cgit_print_summary(); } static void tag_fn(struct cgit_context *ctx) { cgit_print_tag(ctx->qry.sha1); } static void tree_fn(struct cgit_context *ctx) { cgit_print_tree(ctx->qry.sha1, ctx->qry.path); } diff --git a/ui-snapshot.c b/ui-snapshot.c index 7a597ff..9c4d086 100644 --- a/ui-snapshot.c +++ b/ui-snapshot.c @@ -51,32 +51,48 @@ static int write_tar_gzip_archive(struct archiver_args *args) return write_compressed_tar_archive(args,"gzip"); } static int write_tar_bzip2_archive(struct archiver_args *args) { return write_compressed_tar_archive(args,"bzip2"); } const struct cgit_snapshot_format cgit_snapshot_formats[] = { { ".zip", "application/x-zip", write_zip_archive, 0x1 }, { ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 }, { ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 }, { ".tar", "application/x-tar", write_tar_archive, 0x8 }, {} }; +static const struct cgit_snapshot_format *get_format(const char *filename) +{ + const struct cgit_snapshot_format *fmt; + int fl, sl; + + fl = strlen(filename); + for(fmt = cgit_snapshot_formats; fmt->suffix; fmt++) { + sl = strlen(fmt->suffix); + if (sl >= fl) + continue; + if (!strcmp(fmt->suffix, filename + fl - sl)) + return fmt; + } + return NULL; +} + static int make_snapshot(const struct cgit_snapshot_format *format, const char *hex, const char *prefix, const char *filename) { struct archiver_args args; struct commit *commit; unsigned char sha1[20]; if(get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return 1; } commit = lookup_commit_reference(sha1); if(!commit) { cgit_print_error(fmt("Not a commit reference: %s", hex)); return 1; @@ -85,36 +101,88 @@ static int make_snapshot(const struct cgit_snapshot_format *format, if (prefix) { args.base = fmt("%s/", prefix); args.baselen = strlen(prefix) + 1; } else { args.base = ""; args.baselen = 0; } args.tree = commit->tree; args.time = commit->date; ctx.page.mimetype = xstrdup(format->mimetype); ctx.page.filename = xstrdup(filename); cgit_print_http_headers(&ctx); format->write_func(&args); return 0; } +char *dwim_filename = NULL; +const char *dwim_refname = NULL; + +static int ref_cb(const char *refname, const unsigned char *sha1, int flags, + void *cb_data) +{ + const char *r = refname; + while (r && *r) { + fprintf(stderr, " cmp %s with %s:", dwim_filename, r); + if (!strcmp(dwim_filename, r)) { + fprintf(stderr, "MATCH!\n"); + dwim_refname = refname; + return 1; + } + fprintf(stderr, "no match\n"); + if (isdigit(*r)) + break; + r++; + } + return 0; +} + +/* Try to guess the requested revision by combining repo name and tag name + * and comparing this to the requested snapshot name. E.g. the requested + * snapshot is "cgit-0.7.2.tar.gz" while repo name is "cgit" and tag name + * is "v0.7.2". First, the reponame is stripped off, leaving "-0.7.2.tar.gz". + * Next, any '-' and '_' characters are stripped, leaving "0.7.2.tar.gz". + * Finally, the requested format suffix is removed and we end up with "0.7.2". + * Then we test each tag against this dwimmed filename, and for each tag + * we even try to remove any leading characters which are non-digits. I.e. + * we first compare with "v0.7.2", then with "0.7.2" and we've got a match. + */ +static const char *get_ref_from_filename(const char *url, const char *filename, + const struct cgit_snapshot_format *fmt) +{ + const char *reponame = cgit_repobasename(url); + fprintf(stderr, "reponame=%s, filename=%s\n", reponame, filename); + if (prefixcmp(filename, reponame)) + return NULL; + filename += strlen(reponame); + while (filename && (*filename == '-' || *filename == '_')) + filename++; + dwim_filename = xstrdup(filename); + dwim_filename[strlen(filename) - strlen(fmt->suffix)] = '\0'; + for_each_tag_ref(ref_cb, NULL); + return dwim_refname; +} + void cgit_print_snapshot(const char *head, const char *hex, const char *prefix, - const char *filename, int snapshots) + const char *filename, int snapshots, int dwim) { const struct cgit_snapshot_format* f; - int sl, fnl; - fnl = strlen(filename); - if (!hex) - hex = head; - for (f = cgit_snapshot_formats; f->suffix; f++) { - if (!(snapshots & f->bit)) - continue; - sl = strlen(f->suffix); - if(fnl < sl || strcmp(&filename[fnl-sl], f->suffix)) - continue; - make_snapshot(f, hex, prefix, filename); + f = get_format(filename); + if (!f) { + ctx.page.mimetype = "text/html"; + cgit_print_http_headers(&ctx); + cgit_print_docstart(&ctx); + cgit_print_pageheader(&ctx); + cgit_print_error(fmt("Unsupported snapshot format: %s", filename)); + cgit_print_docend(); return; } - cgit_print_error(fmt("Unsupported snapshot format: %s", filename)); + + if (!hex && dwim) + hex = get_ref_from_filename(ctx.repo->url, filename, f); + + if (!hex) + hex = head; + + make_snapshot(f, hex, prefix, filename); } diff --git a/ui-snapshot.h b/ui-snapshot.h index 6e03761..3540303 100644 --- a/ui-snapshot.h +++ b/ui-snapshot.h @@ -1,8 +1,8 @@ #ifndef UI_SNAPSHOT_H #define UI_SNAPSHOT_H extern void cgit_print_snapshot(const char *head, const char *hex, const char *prefix, const char *filename, - int snapshot); + int snapshot, int dwim); #endif /* UI_SNAPSHOT_H */ |