git-export-filter: add support for --names option
authorKyle J. McKay <[email protected]>
Thu, 6 Nov 2014 02:41:57 +0000 (5 18:41 -0800)
committerKyle J. McKay <[email protected]>
Thu, 6 Nov 2014 02:41:57 +0000 (5 18:41 -0800)
The --names option will emit all committer, author and tagger
names found in the intput stream rather than a modified fast-import
stream.  This can be useful in building an initial authors file.

git-export-filter.1
git-export-filter.c
git-export-filter.txt

index 45061c6..3491933 100644 (file)
@@ -25,7 +25,7 @@ git-export-filter \- Filter fast\-export data with optional rewrites
                   [\-\-authors\-file=<authors_file> [\-\-require\-authors]]
                   [\-\-branches\-file=<branches_file>] [\-\-trunk\-is\-master]
                   [\-\-convert\-tagger=<email>] [\-\-strip\-at\-suffix]
-                  [\-\-expand\-renames] [\-\-]
+                  [\-\-expand\-renames] [\-\-names] [\-\-]
                   [<input_file>] > <output_file>
 .fi
 .sp
@@ -154,6 +154,17 @@ followed by a filedelete
 instead\&.
 .RE
 .PP
+\-\-names
+.RS 4
+This option may not be combined with any of the others\&. Instead of outputting a modified fast\-import stream, output only the author, committer and tagger names as they are encountered one per line without any timestamp information\&. This can be used to help build an initial authors file\&.
+.sp
+Do note that the names are output as\-is from the input stream whereas this utility expects to match only the email portion when given an authors file with the \-\-authors\-file option\&. This means the name, non\-email portion and surrounding
+\fI<\fR
+and
+\fI>\fR
+characters will have to be removed from the output provided by this option\&. Additionally, of course, duplicate names need to be removed as well\&.
+.RE
+.PP
 <input_file>
 .RS 4
 The fast\-export stream to read\&. If
index ac50f01..ec26661 100644 (file)
@@ -47,7 +47,7 @@ static const char *const gUsage =
 "(use git-export-filter -v -h for detailed help)\n";
 
 static const char *const gVersion =
-"git-export-filter version 1.4.1\n";
+"git-export-filter version 1.5.0\n";
 
 static const char *me = "git-export-filter";
 
@@ -62,10 +62,14 @@ static int opt_require = 0;
 static int opt_trunk_is_master = 0;
 static int opt_strip_at = 0;
 static int opt_no_renames = 0;
+static int opt_names = 0;
 
 static char *pushline = NULL;
 static char *copybuff;
 
+int (*fout)(FILE *out, const char *fmt, ...);
+size_t (*writeout)(const void *ptr, size_t size, size_t nitems, FILE *out);
+
 static void processfile(FILE *in, FILE *out,
                         const transform_t *authors, size_t acount,
                         const transform_t *branches, size_t bcount,
@@ -175,6 +179,21 @@ static int read_transform_file(const char *type, FILE *f, transform_t **ans)
   return -1;
 }
 
+static int foutnone(FILE *out, const char *fmt, ...)
+{
+  (void)out;
+  (void)fmt;
+  return 0;
+}
+
+size_t writeoutnone(const void *ptr, size_t size, size_t nitems, FILE *out)
+{
+  (void)ptr;
+  (void)size;
+  (void)out;
+  return nitems;
+}
+
 int main(int argc, char *argv[])
 {
   transform_t *authors = NULL;
@@ -185,6 +204,8 @@ int main(int argc, char *argv[])
   FILE *outbinary = freopen(NULL, "wb", stdout);
   int optind = 1;
 
+  fout = fprintf;
+  writeout = fwrite;
   if (argc >= 1)
     setupme(argv[0]);
   copybuff = (char *)malloc(COPYSIZE);
@@ -255,6 +276,12 @@ int main(int argc, char *argv[])
       opt_no_renames = 1;
       continue;
     }
+    if (!strcmp(A, "--names")) {
+      opt_names = 1;
+      fout = foutnone;
+      writeout = writeoutnone;
+      continue;
+    }
     if (!strcmp(A, "-V") || !strcmp(A, "--version")) {
       opt_version = 1;
       continue;
@@ -295,7 +322,9 @@ int main(int argc, char *argv[])
     exit(0);
   if (opt_require && !authorsfile)
     die("--require-authors requires the --authors-file option");
-
+  if (opt_names && (opt_require || authorsfile || branchesfile || convertid ||
+                    opt_trunk_is_master || opt_strip_at || opt_no_renames))
+    die("--names may not be used together with any other options");
   if (authorsfile) {
     FILE *af = fopen(authorsfile, "rb");
     if (!af)
@@ -399,11 +428,11 @@ static void processfile(FILE *in, FILE *out,
     else if (strncmp(line, "reset ", 6) == 0)
       processreset(in, out, line+6, branches, bcount);
     else if (!strcmp(line, "checkpoint") || !strcmp(line, "done"))
-      fprintf(out, "%s\n\n", line);
+      fout(out, "%s\n\n", line);
     else if (!strncmp(line, "progress ", 9) ||
              !strncmp(line, "cat-blob ", 9) || !strncmp(line, "ls ", 3) ||
              !strncmp(line, "feature ", 8) || !strncmp(line, "option ", 7))
-      fprintf(out, "%s\n\n", line);
+      fout(out, "%s\n\n", line);
     else
       die("unrecognized input command: %s", line);
    }
@@ -487,7 +516,7 @@ static void copydatapart(FILE *in, FILE *out, const char *data, int nolf)
       if (!cnt)
         break;
       if (out)
-        if (fwrite(copybuff, cnt, 1, out) != 1)
+        if (writeout(copybuff, cnt, 1, out) != 1)
           die("failed writing data to output");
       if (cnt == dlen)
         lastchar = copybuff[cnt - 1];
@@ -496,7 +525,7 @@ static void copydatapart(FILE *in, FILE *out, const char *data, int nolf)
     if (dlen)
       die("unexpected EOF reading data %s", data);
     if (out && (!nolf || lastchar != '\n'))
-      fprintf(out, "\n");
+      fout(out, "\n");
   } else if (l < 3 || data[0] != '<' || data[1] != '<')
     die("Invalid data line: data %s", data);
   else {
@@ -506,10 +535,10 @@ static void copydatapart(FILE *in, FILE *out, const char *data, int nolf)
       if (!line)
         die("unexpected EOF reading data %s", data);
       if (out)
-        fprintf(out, "%s\n", line);
+        fout(out, "%s\n", line);
       if (strcmp(line, data+2) == 0) {
         if (out && !nolf)
-          fprintf(out, "\n");
+          fout(out, "\n");
         break;
       }
     }
@@ -527,7 +556,7 @@ static void copydata(FILE *in, FILE *out, int nolf, const char *err)
   if (!line || strncmp(line, "data ", 5) != 0)
     die(err);
   if (out)
-    fprintf(out, "%s\n", line);
+    fout(out, "%s\n", line);
   copydatapart(in, out, line+5, nolf);
 }
 
@@ -536,16 +565,16 @@ static void processblob(FILE *in, FILE *out)
   const char *line = nextline(in);
   if (!line)
     die("error reading blob header");
-  fprintf(out, "blob\n");
+  fout(out, "blob\n");
   if (strncmp(line, "mark ", 5) == 0) {
-    fprintf(out, "%s\n", line);
+    fout(out, "%s\n", line);
     line = nextline(in);
     if (!line)
       die("error reading blob header");
   }
   if (strncmp(line, "data ", 5) != 0)
     die("blob missing data line");
-  fprintf(out, "%s\n", line);
+  fout(out, "%s\n", line);
   copydatapart(in, out, line+5, 0);
 }
 
@@ -554,10 +583,10 @@ static void processreset(FILE *in, FILE *out, const char *ref,
 {
   char *line;
   const char *newref = translateref(ref, branches, bcount);
-  fprintf(out, "reset %s\n", newref);
+  fout(out, "reset %s\n", newref);
   line = nextline(in);
   if (strncmp(line, "from ", 5) == 0)
-    fprintf(out, "%s\n\n", line);
+    fout(out, "%s\n\n", line);
   else
     pushline = line;
 }
@@ -583,19 +612,21 @@ static void processtag(FILE *in, FILE *out, const char *tag,
     die("tag missing tagger line");
   if (!splitauthor(line+7, &name, &email, &when))
     die("tag has bad tagger line");
+  if (opt_names)
+    fprintf(out, "%s<%s>\n", name, email);
   if (convertid && strcmp(convertid, email) == 0) {
-    fprintf(out, "reset refs/tags/%s", tagline+4);
-    fprintf(out, "%s\n", fromline);
+    fout(out, "reset refs/tags/%s", tagline+4);
+    fout(out, "%s\n", fromline);
     out = NULL;
   } else {
-    fprintf(out, "%s%s", tagline, fromline);
+    fout(out, "%s%s", tagline, fromline);
     newauth = translateuser(email, authors, acount);
     if (newauth != email)
-      fprintf(out, "tagger %s %s\n", newauth, when);
+      fout(out, "tagger %s %s\n", newauth, when);
     else {
       if (opt_require)
         die("missing authors file author: \"%s\"", email);
-      fprintf(out, "tagger %s<%s> %s\n", name, email, when);
+      fout(out, "tagger %s<%s> %s\n", name, email, when);
     }
   }
   copydata(in, out, 0, "tag missing data line");
@@ -639,12 +670,12 @@ static void processcommit(FILE *in, FILE *out, const char *ref,
   char *line;
   const char *newref = translateref(ref, branches, bcount);
   const char *newauth;
-  fprintf(out, "commit %s\n", newref);
+  fout(out, "commit %s\n", newref);
   line = nextline(in);
   if (!line)
     die("error reading commit header");
   if (strncmp(line, "mark ", 5) == 0) {
-    fprintf(out, "%s\n", line);
+    fout(out, "%s\n", line);
     line = nextline(in);
     if (!line)
       die("error reading commit header");
@@ -652,13 +683,15 @@ static void processcommit(FILE *in, FILE *out, const char *ref,
   if (strncmp(line, "author ", 7) == 0) {
     if (!splitauthor(line+7, &name, &email, &when))
       die("commit has bad author line");
+    if (opt_names)
+      fprintf(out, "%s<%s>\n", name, email);
     newauth = translateuser(email, authors, acount);
     if (newauth != email)
-      fprintf(out, "author %s %s\n", newauth, when);
+      fout(out, "author %s %s\n", newauth, when);
     else {
       if (opt_require)
         die("missing authors file author: \"%s\"", email);
-      fprintf(out, "author %s<%s> %s\n", name, email, when);
+      fout(out, "author %s<%s> %s\n", name, email, when);
     }
     line = nextline(in);
     if (!line)
@@ -668,26 +701,28 @@ static void processcommit(FILE *in, FILE *out, const char *ref,
     die("commit missing committer line");
   if (!splitauthor(line+10, &name, &email, &when))
     die("commit has bad committer line");
+  if (opt_names)
+    fprintf(out, "%s<%s>\n", name, email);
   newauth = translateuser(email, authors, acount);
   if (newauth != email)
-    fprintf(out, "committer %s %s\n", newauth, when);
+    fout(out, "committer %s %s\n", newauth, when);
   else {
     if (opt_require)
       die("missing authors file author: \"%s\"", email);
-    fprintf(out, "committer %s<%s> %s\n", name, email, when);
+    fout(out, "committer %s<%s> %s\n", name, email, when);
   }
   copydata(in, out, 1, "commit missing data line");
   line = nextline(in);
   if (!line)
     die("error reading commit header");
   if (strncmp(line, "from ", 5) == 0) {
-    fprintf(out, "%s\n", line);
+    fout(out, "%s\n", line);
     line = nextline(in);
     if (!line)
       die("error reading commit header");
   }
   while (strncmp(line, "merge ", 6) == 0) {
-    fprintf(out, "%s\n", line);
+    fout(out, "%s\n", line);
     line = nextline(in);
     if (!line)
       die("error reading commit header");
@@ -697,14 +732,14 @@ static void processcommit(FILE *in, FILE *out, const char *ref,
          !strncmp(line, "R ", 2)        || !strncmp(line, "N ", 2) ||
          !strncmp(line, "cat-blob ", 9) || !strncmp(line, "ls ", 3)) {
     if (!opt_no_renames || strncmp(line, "R ", 2)) {
-      fprintf(out, "%s\n", line);
+      fout(out, "%s\n", line);
     } else {
       /* expand rename into copy + delete */
       const char *space2 = find_second_space(line);
       if (!space2)
         die("error reading 'R' line");
-      fprintf(out, "C %s\n", line+2);
-      fprintf(out, "D %.*s\n", (int)(space2 - line) - 2, line+2);
+      fout(out, "C %s\n", line+2);
+      fout(out, "D %.*s\n", (int)(space2 - line) - 2, line+2);
     }
     if (strncmp(line, "N inline", 8) == 0 || is_inline_modify(line))
       copydata(in, out, 1, "inline N or M missing data line");
@@ -713,5 +748,5 @@ static void processcommit(FILE *in, FILE *out, const char *ref,
       die("error reading commit header");
   }
   pushline = line;
-  fprintf(out, "\n");
+  fout(out, "\n");
 }
index 8b978f2..b3cc395 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
                  [--authors-file=<authors_file> [--require-authors]]
                  [--branches-file=<branches_file>] [--trunk-is-master]
                  [--convert-tagger=<email>] [--strip-at-suffix]
-                 [--expand-renames] [--]
+                 [--expand-renames] [--names] [--]
                  [<input_file>] > <output_file>
 
 
@@ -110,6 +110,20 @@ generates in the fast-export data and will need this option to use a standard
        filerename 'R' are replaced with a filecopy 'C' followed by a
        filedelete 'D' instead.
 
+--names::
+       This option may not be combined with any of the others.  Instead of
+       outputting a modified fast-import stream, output only the author,
+       committer and tagger names as they are encountered one per line
+       without any timestamp information.  This can be used to help build
+       an initial authors file.
++
+Do note that the names are output as-is from the input stream whereas this
+utility expects to match only the email portion when given an authors file
+with the --authors-file option.  This means the name, non-email portion and
+surrounding '<' and '>' characters will have to be removed from the output
+provided by this option.  Additionally, of course, duplicate names need to
+be removed as well.
+
 <input_file>::
        The fast-export stream to read.  If `<input_file>` is omitted, then
        standard input will be read.