a157f4fce31b8aee4a230c721624e9f98fd66333
galt
Sun Mar 7 12:07:58 2010 -0800
suppress commitIds as too-much-info, add UL/LI tags to allow text to wrap, htmlEncode the commit-comment, also substitute
for newlines in comment
diff --git git-reports.c git-reports.c
index 178b3e1..3b1cf55 100644
--- git-reports.c
+++ git-reports.c
@@ -1,807 +1,827 @@
/* 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},
};
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
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", 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