History

Grep the source, Luke

This is a PoC for grepping the blobs in the current tree.

Lars Hjemli committed 15 years ago

Commit c028b601 parent fdfb6a65 files · +223 −8Browse files

Unified · Split

5 files
  1. cmd.c +4 −1
  2. ui-shared.c +96 −7
  3. ui-shared.h +3 −0
  4. ui-tree.c +119 −0
  5. ui-tree.h +1 −0
cmd.c+4−1
@@ -127,7 +127,10 @@ static void tag_fn(struct cgit_context *ctx) · 126 unmodified lines
127127
128128 static void tree_fn(struct cgit_context *ctx)
129129 {
130− cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
130+ if (ctx->qry.grep)
131+ cgit_grep(ctx->qry.sha1, ctx->qry.path, ctx->qry.grep);
132+ else
133+ cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
131134 }
132135
133136 #define def_cmd(name, want_repo, want_layout, want_vpath, is_clone) \
ui-shared.c+96−7
@@ -246,6 +246,61 @@ static char *repolink(const char *title, const char *class, const char *page, · 245 unmodified lines
246246 return fmt("%s", delim);
247247 }
248248
249+static char *repolink2(const char *title, const char *class, const char *page,
250+ const char *head, const char *path, int lineno)
251+{
252+ char *delim = "?";
253+
254+ html("<a");
255+ if (title) {
256+ html(" title='");
257+ html_attr(title);
258+ html("'");
259+ }
260+ if (class) {
261+ html(" class='");
262+ html_attr(class);
263+ html("'");
264+ }
265+ html(" href='");
266+ if (ctx.cfg.virtual_root) {
267+ html_url_path(ctx.cfg.virtual_root);
268+ if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/')
269+ html("/");
270+ html_url_path(ctx.repo->url);
271+ if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
272+ html("/");
273+ if (page) {
274+ html_url_path(page);
275+ html("/");
276+ if (path)
277+ html_url_path(path);
278+ }
279+ } else {
280+ html(ctx.cfg.script_name);
281+ html("?url=");
282+ html_url_arg(ctx.repo->url);
283+ if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
284+ html("/");
285+ if (page) {
286+ html_url_arg(page);
287+ html("/");
288+ if (path)
289+ html_url_arg(path);
290+ }
291+ delim = "&amp;";
292+ }
293+ if (head && strcmp(head, ctx.repo->defbranch)) {
294+ html(delim);
295+ html("h=");
296+ html_url_arg(head);
297+ delim = "&amp;";
298+ }
299+ if (lineno)
300+ htmlf("#n%d", lineno);
301+ return fmt("%s", delim);
302+}
303+
249304 static void reporevlink(const char *page, const char *name, const char *title,
250305 const char *class, const char *head, const char *rev,
251306 const char *path)
@@ -263,6 +318,23 @@ static void reporevlink(const char *page, const char *name, const char *title, · 11 unmodified lines
263318 html("</a>");
264319 }
265320
321+static void reporevlink2(const char *page, const char *name, const char *title,
322+ const char *class, const char *head, const char *rev,
323+ const char *path, int lineno)
324+{
325+ char *delim;
326+
327+ delim = repolink2(title, class, page, head, path, lineno);
328+ if (rev && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) {
329+ html(delim);
330+ html("id=");
331+ html_url_arg(rev);
332+ }
333+ html("'>");
334+ html_txt(name);
335+ html("</a>");
336+}
337+
266338 void cgit_summary_link(const char *name, const char *title, const char *class,
267339 const char *head)
268340 {
@@ -281,6 +353,13 @@ void cgit_tree_link(const char *name, const char *title, const char *class, · 12 unmodified lines
281353 reporevlink("tree", name, title, class, head, rev, path);
282354 }
283355
356+void cgit_tree_link2(const char *name, const char *title, const char *class,
357+ const char *head, const char *rev, const char *path,
358+ int lineno)
359+{
360+ reporevlink2("tree", name, title, class, head, rev, path, lineno);
361+}
362+
284363 void cgit_plain_link(const char *name, const char *title, const char *class,
285364 const char *head, const char *rev, const char *path)
286365 {
@@ -875,6 +954,9 @@ static void print_header(struct cgit_context *ctx) · 588 unmodified lines
875954
876955 void cgit_print_pageheader(struct cgit_context *ctx)
877956 {
957+ int tree;
958+ char *page;
959+
878960 html("<div id='cgit'>");
879961 if (!ctx->cfg.noheader)
880962 print_header(ctx);
@@ -903,16 +985,23 @@ void cgit_print_pageheader(struct cgit_context *ctx) · 22 unmodified lines
903985 NULL);
904986 html("</td><td class='form'>");
905987 html("<form class='right' method='get' action='");
906− if (ctx->cfg.virtual_root)
907− html_url_path(cgit_fileurl(ctx->qry.repo, "log",
988+ if (ctx->cfg.virtual_root) {
989+ tree = !strcmp(ctx->qry.page, "tree");
990+ page = tree ? "tree" : "log";
991+ html_url_path(cgit_fileurl(ctx->qry.repo, page,
908992 ctx->qry.vpath, NULL));
993+ }
909994 html("'>\n");
910− cgit_add_hidden_formfields(1, 0, "log");
995+ cgit_add_hidden_formfields(1, 0, page);
911996 html("<select name='qt'>\n");
912− html_option("grep", "log msg", ctx->qry.grep);
913− html_option("author", "author", ctx->qry.grep);
914− html_option("committer", "committer", ctx->qry.grep);
915− html_option("range", "range", ctx->qry.grep);
997+ if (tree) {
998+ html_option("grep", "source", ctx->qry.grep);
999+ } else {
1000+ html_option("grep", "log msg", ctx->qry.grep);
1001+ html_option("author", "author", ctx->qry.grep);
1002+ html_option("committer", "committer", ctx->qry.grep);
1003+ html_option("range", "range", ctx->qry.grep);
1004+ }
9161005 html("</select>\n");
9171006 html("<input class='txt' type='text' size='10' name='q' value='");
9181007 html_attr(ctx->qry.search);
ui-shared.h+3−0
@@ -20,6 +20,9 @@ extern void cgit_tag_link(const char *name, const char *title, · 19 unmodified lines
2020 extern void cgit_tree_link(const char *name, const char *title,
2121 const char *class, const char *head,
2222 const char *rev, const char *path);
23+extern void cgit_tree_link2(const char *name, const char *title,
24+ const char *class, const char *head,
25+ const char *rev, const char *path, int lno);
2326 extern void cgit_plain_link(const char *name, const char *title,
2427 const char *class, const char *head,
2528 const char *rev, const char *path);
ui-tree.c+119−0
@@ -277,3 +277,122 @@ void cgit_print_tree(const char *rev, char *path) · 276 unmodified lines
277277 read_tree_recursive(commit->tree, "", 0, 0, paths, walk_tree, NULL);
278278 ls_tail();
279279 }
280+
281+struct grep_data {
282+ regex_t re;
283+ char *path;
284+ int max_hits;
285+};
286+
287+static int grep_blob(const unsigned char *sha1, const char *base, int baselen,
288+ const char *pathname, struct grep_data *grep)
289+{
290+ enum object_type type;
291+ char *buf, *line, *lf, *fullpath;
292+ unsigned long size;
293+ int hits, lno, rc;
294+
295+ type = sha1_object_info(sha1, &size);
296+ if (type == OBJ_BAD) {
297+ cgit_print_error(fmt("Bad object name: %s",
298+ sha1_to_hex(sha1)));
299+ return -1;
300+ }
301+
302+ buf = read_sha1_file(sha1, &type, &size);
303+ if (!buf) {
304+ cgit_print_error(fmt("Error reading object %s",
305+ sha1_to_hex(sha1)));
306+ return -1;
307+ }
308+ hits = 0;
309+ line = buf;
310+ lno = 1;
311+ while (size) {
312+ lf = strchr(line, '\n');
313+ if (lf)
314+ *lf = 0;
315+ rc = regexec(&grep->re, line, 0, NULL, 0);
316+ if (!rc) {
317+ if (!hits) {
318+ fullpath = fmt("%.*s%s", baselen, base,
319+ pathname);
320+ htmlf("<strong>%s</strong><pre>", fullpath);
321+ }
322+ htmlf("%6d: ", lno);
323+ while (isspace(*line))
324+ line++;
325+ cgit_tree_link2(line, NULL, NULL, ctx.qry.head,
326+ ctx.qry.sha1, fullpath, lno);
327+ html("\n");
328+ ++hits;
329+ if (!(--grep->max_hits))
330+ break;
331+ }
332+ if (!lf)
333+ break;
334+ size -= (lf - line);
335+ *lf = '\n';
336+ line = lf + 1;
337+ lno++;
338+ }
339+ if (hits)
340+ html("</pre>");
341+ if (!grep->max_hits) {
342+ cgit_print_error("Too many matches found.");
343+ return -1;
344+ }
345+ return 0;
346+}
347+
348+static int grep_tree(const unsigned char *sha1, const char *base, int baselen,
349+ const char *pathname, unsigned mode, int stage,
350+ void *cbdata)
351+{
352+ int rc;
353+ char *fullpath;
354+ struct grep_data *grep;
355+
356+ grep = cbdata;
357+ fullpath = fmt("%.*s%s", baselen, base, pathname);
358+ if (S_ISDIR(mode)) {
359+ rc = grep->path ? prefixcmp(grep->path, fullpath) : 0;
360+ if (!rc)
361+ return READ_TREE_RECURSIVE;
362+ return (rc > 0 ? -1 : 0);
363+ } else if (S_ISREG(mode)) {
364+ rc = grep->path ? prefixcmp(fullpath, grep->path) : 0;
365+ if (!rc)
366+ return grep_blob(sha1, base, baselen, pathname, grep);
367+ return (rc < 0 ? -1 : 0);
368+ }
369+ return 0;
370+}
371+
372+void cgit_grep(const char *rev, char *path, char *grep)
373+{
374+ unsigned char sha1[20];
375+ struct commit *commit;
376+ struct grep_data data;
377+
378+ if (!rev)
379+ rev = ctx.qry.head;
380+
381+ curr_rev = xstrdup(rev);
382+ if (get_sha1(rev, sha1)) {
383+ cgit_print_error(fmt("Invalid revision name: %s", rev));
384+ return;
385+ }
386+ commit = lookup_commit_reference(sha1);
387+ if (!commit || parse_commit(commit)) {
388+ cgit_print_error(fmt("Invalid commit reference: %s", rev));
389+ return;
390+ }
391+ data.path = path;
392+ data.max_hits = 100;
393+ if (regcomp(&data.re, ctx.qry.search, REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
394+ cgit_print_error("Invalid regex");
395+ return;
396+ }
397+ read_tree_recursive(commit->tree, "", 0, 0, NULL, grep_tree, &data);
398+}
ui-tree.h+1−0
@@ -2,5 +2,6 @@ · 1 unmodified line
22 #define UI_TREE_H
33
44 extern void cgit_print_tree(const char *rev, char *path);
5+extern void cgit_grep(const char *rev, char *path, char *grep);
56
67 #endif /* UI_TREE_H */