000051929861dbc16609052d73f2424d07d9698c galt Mon Mar 8 11:40:57 2010 -0800 added error checking for system() call, removed some uglyf prints, cleaned up some comments diff --git git-reports.c git-reports.c index 3b1cf55..81f48c6 100644 --- git-reports.c +++ git-reports.c @@ -1,827 +1,821 @@ /* git-reports.c for creating git equivalent of cvs-reports. * * Copyright Galt Barber 2010. * * Anyone is free to use it. * Just include me in your credits. * Likewise cvs-reports was created by Mark Diekhans. */ #include "common.h" #include "options.h" #include "dystring.h" #include "errabort.h" #include "hash.h" #include "linefile.h" #include "htmshell.h" #include "portable.h" static char const rcsid[] = "$Id: git-reports.c,v 1.1 2010/03/02 08:43:07 galt Exp $"; struct hash *userHash = NULL; struct slName *users = NULL; char *startTag = NULL; char *endTag = NULL; char *startDate = NULL; char *endDate = NULL; char *title = NULL; char *repoDir = NULL; char *outDir = NULL; char *outPrefix = NULL; char gitCmd[1024]; char *tempMakeDiffName = NULL; struct files { struct files *next; char type; char *path; int linesChanged; }; struct commit { struct commit *next; int commitNumber; // used for sorting fileviews char *commitId; char *author; char *date; char *comment; struct files *files; }; struct comFile { struct comFile *next; struct files *f; struct commit *commit; }; void usage(char *msg) /* Explain usage and exit. */ { errAbort( "%s\n\n" "git-reports - produce source code reports useful for code-review on git repository \n" "\n" "Usage:\n" " git-reports startTag endTag startDate endDate title repoDir outDir outPrefix\n" "where " " startTag and endTag are repository tags marking the beginning and end of the git range\n" " startDate and endDate and title are just strings that get printed on the report\n" " title is usually the branch number, e.g. v225\n" " repoDir is where the git repository (use absolute path)\n" " outDir is the output directory (use absolute path).\n" " outPrefix is typically \"branch\" or \"review\" directory.\n" " --help - this help screen\n", msg); } static struct optionSpec options[] = { {"-help", OPTION_BOOLEAN}, {NULL, 0}, }; +void runShell(char *cmd) +/* Run a command and do simple error-checking */ +{ +int exitCode = system(cmd); +if (exitCode != 0) + errAbort("system command [%s] failed with exitCode %d", cmd, exitCode); +} struct commit* getCommits() /* Get all commits from startTag to endTag */ { int numCommits = 0; safef(gitCmd,sizeof(gitCmd), "" "git log origin/%s..origin/%s --name-status > commits.tmp" , startTag, endTag); -system(gitCmd); -// TODO error handling +runShell(gitCmd); struct lineFile *lf = lineFileOpen("commits.tmp", TRUE); int lineSize; char *line; struct commit *commits = NULL, *commit = NULL; struct files *files = NULL, *f = NULL; char *sep = ""; while (lineFileNext(lf, &line, &lineSize)) { boolean isMerge = FALSE; char *w = nextWord(&line); AllocVar(commit); if (!sameString("commit", w)) errAbort("expected keyword commit parsing commits.tmp\n"); commit->commitId = cloneString(nextWord(&line)); commit->commitNumber = ++numCommits; lineFileNext(lf, &line, &lineSize); w = nextWord(&line); if (sameString("Merge:", w)) { isMerge = TRUE; lineFileNext(lf, &line, &lineSize); w = nextWord(&line); } if (!sameString("Author:", w)) errAbort("expected keyword Author: parsing commits.tmp\n"); commit->author = cloneString(nextWord(&line)); lineFileNext(lf, &line, &lineSize); w = nextWord(&line); if (!sameString("Date:", w)) errAbort("expected keyword Date: parsing commits.tmp\n"); commit->date = cloneString(line); lineFileNext(lf, &line, &lineSize); if (!sameString("", line)) errAbort("expected blank line parsing commits.tmp\n"); /* collect the comment-lines */ struct dyString *dy = NULL; dy = dyStringNew(0); sep = ""; files = NULL; while (lineFileNext(lf, &line, &lineSize)) { if (sameString("", line)) break; w = skipLeadingSpaces(line); dyStringPrintf(dy, "%s%s", w, sep); sep = "\n"; } commit->comment = cloneString(dy->string); freeDyString(&dy); if (!isMerge) { /* collect the files-list */ while (lineFileNext(lf, &line, &lineSize)) { if (sameString("", line)) break; AllocVar(f); w = nextWord(&line); f->type = w[0]; f->path = cloneString(line); slAddHead(&files, f); } slReverse(&files); } commit->files = files; slAddHead(&commits, commit); verbose(2, "commitId: %s\n" "author: %s\n" "date: %s\n" "comment: [%s]\n" "file(s): \n" , commit->commitId , commit->author , commit->date , commit->comment); for (f=commit->files; f; f = f->next) { verbose(2, "%c %s\n", f->type, f->path); // anything other than M? if (f->type != 'M') verbose(2, "special type: %c %s\n", f->type, f->path); } verbose(2, "------------\n"); } lineFileClose(&lf); slReverse(&commits); unlink("commits.tmp"); return commits; } int makeHtml(char *diffPath, char *htmlPath, char *path, char *commitId) /* Make a color-coded html diff * Return the number of lines changed */ { int linesChanged = 0; FILE *h = mustOpen(htmlPath, "w"); struct lineFile *lf = lineFileOpen(diffPath, TRUE); int lineSize; char *line; char *xline = NULL; boolean inBody = FALSE; boolean inBlock = TRUE; int blockP = 0, blockN = 0; fprintf(h, "\n
\n\n", path, commitId); while (lineFileNext(lf, &line, &lineSize)) { xline = htmlEncode(line); if (line[0] == '-') { fprintf(h, "%s\n", xline); if (inBody) { inBlock = TRUE; ++blockN; } } else if (line[0] == '+') { fprintf(h, "%s\n", xline); if (inBody) { inBlock = TRUE; ++blockP; } } else { if (line[0] == '@') fprintf(h, "%s\n", xline); else fprintf(h, "%s\n", xline); if (inBody) { if (inBlock) { inBlock = FALSE; if (blockP >= blockN) linesChanged += blockP; else linesChanged += blockN; blockP = 0; blockN = 0; } } } if (line[0] == '@') inBody = TRUE; freeMem(xline); } // what if there is no last trailing line to end the last block? if (inBody) { if (inBlock) { inBlock = FALSE; if (blockP >= blockN) linesChanged += blockP; else linesChanged += blockN; blockP = 0; blockN = 0; } } lineFileClose(&lf); fprintf(h, "\n