[prev in list] [next in list] [prev in thread] [next in thread] 

List:       rpm-cvs
Subject:    [CVS] RPM: rpm-5_4: rpm/rpmio/ tgit.c
From:       "Jeff Johnson" <jbj () rpm5 ! org>
Date:       2014-04-12 18:54:31
Message-ID: 20140412185431.9CDEB4C0D3 () rpm5 ! org
[Download RAW message or body]

  RPM Package Manager, CVS Repository
  http://rpm5.org/cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Jeff Johnson
  Root:   /v/rpm/cvs                       Email:  jbj@rpm5.org
  Module: rpm                              Date:   12-Apr-2014 20:54:31
  Branch: rpm-5_4                          Handle: 2014041218543100

  Modified files:           (Branch: rpm-5_4)
    rpm/rpmio               tgit.c

  Log:
    - git: add blame command.

  Summary:
    Revision    Changes     Path
    1.1.2.37    +320 -13    rpm/rpmio/tgit.c
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: rpm/rpmio/tgit.c
  ============================================================================
  $ cvs diff -u -r1.1.2.36 -r1.1.2.37 tgit.c
  --- rpm/rpmio/tgit.c	12 Apr 2014 17:10:51 -0000	1.1.2.36
  +++ rpm/rpmio/tgit.c	12 Apr 2014 18:54:31 -0000	1.1.2.37
  @@ -64,13 +64,18 @@
   		: 0.f;
       int kbytes = pd->fetch_progress.received_bytes / 1024;
   
  -    fprintf(fp, "net %3d%% (%4d kb, %5d/%5d)  /  idx %3d%% (%5d/%5d)  /  chk %3d%% (%4lu/%4lu) %s\n",
  -	network_percent, kbytes,
  -	pd->fetch_progress.received_objects, pd->fetch_progress.total_objects,
  -	index_percent, pd->fetch_progress.indexed_objects, pd->fetch_progress.total_objects,
  -	checkout_percent,
  -	(unsigned long)pd->completed_steps, (unsigned long)pd->total_steps,
  -	pd->path);
  +    if (pd->fetch_progress.received_objects == pd->fetch_progress.total_objects)
  +	fprintf(fp, "Resolving deltas %d/%d\r",
  +		pd->fetch_progress.indexed_deltas,
  +		pd->fetch_progress.total_deltas);
  +    else
  +	fprintf(fp, "net %3d%% (%4d kb, %5d/%5d)  /  idx %3d%% (%5d/%5d)  /  chk %3d%% (%4lu/%4lu) %s\n",
  +		network_percent, kbytes,
  +		pd->fetch_progress.received_objects, pd->fetch_progress.total_objects,
  +		index_percent, pd->fetch_progress.indexed_objects, pd->fetch_progress.total_objects,
  +		checkout_percent,
  +		(unsigned long)pd->completed_steps, (unsigned long)pd->total_steps,
  +		pd->path);
   }
   
   static int fetch_progress(const git_transfer_progress *stats, void *payload)
  @@ -333,7 +338,8 @@
       clone_opts.remote_callbacks.payload = &pd;
   
       /* Do the clone */
  -    xx = git_clone(&cloned_repo, url, path, &clone_opts);
  +    xx = chkgit(git, "git_clone",
  +	git_clone(&cloned_repo, url, path, &clone_opts));
       fprintf(fp, "\n");
       if (xx != 0) {
   	const git_error *err = giterr_last();
  @@ -344,8 +350,6 @@
       } else if (cloned_repo)
   	git_repository_free(cloned_repo);
   
  -    xx = 0;
  -
   exit:
       rc = (xx ? RPMRC_FAIL : RPMRC_OK);
   SPEW(0, rc, git);
  @@ -1032,6 +1036,306 @@
   /*==============================================================*/
   #ifdef	REFERENCE
   OPTIONS
  +       -b
  +           Show blank SHA-1 for boundary commits. This can also be controlled
  +           via the blame.blankboundary config option.
  +
  +       --root
  +           Do not treat root commits as boundaries. This can also be
  +           controlled via the blame.showroot config option.
  +
  +       --show-stats
  +           Include additional statistics at the end of blame output.
  +
  +       -L <start>,<end>
  +           Annotate only the given line range. <start> and <end> can take one
  +           of these forms:
  +
  +            ·   number
  +
  +               If <start> or <end> is a number, it specifies an absolute line
  +               number (lines count from 1).
  +
  +            ·   /regex/
  +
  +               This form will use the first line matching the given POSIX
  +               regex. If <end> is a regex, it will search starting at the line
  +               given by <start>.
  +
  +            ·   +offset or -offset
  +
  +               This is only valid for <end> and will specify a number of lines
  +               before or after the line given by <start>.
  +
  +       -l
  +           Show long rev (Default: off).
  +
  +       -t
  +           Show raw timestamp (Default: off).
  +
  +       -S <revs-file>
  +           Use revisions from revs-file instead of calling git-rev-list(1).
  +
  +       --reverse
  +           Walk history forward instead of backward. Instead of showing the
  +           revision in which a line appeared, this shows the last revision in
  +           which a line has existed. This requires a range of revision like
  +           START..END where the path to blame exists in START.
  +
  +       -p, --porcelain
  +           Show in a format designed for machine consumption.
  +
  +       --incremental
  +           Show the result incrementally in a format designed for machine
  +           consumption.
  +
  +       --encoding=<encoding>
  +           Specifies the encoding used to output author names and commit
  +           summaries. Setting it to none makes blame output unconverted data.
  +           For more information see the discussion about encoding in the git-
  +           log(1) manual page.
  +
  +       --contents <file>
  +           When <rev> is not specified, the command annotates the changes
  +           starting backwards from the working tree copy. This flag makes the
  +           command pretend as if the working tree copy has the contents of the
  +           named file (specify - to make the command read from the standard
  +           input).
  +
  +       --date <format>
  +           The value is one of the following alternatives:
  +           {relative,local,default,iso,rfc,short}. If --date is not provided,
  +           the value of the blame.date config variable is used. If the
  +           blame.date config variable is also not set, the iso format is used.
  +           For more information, See the discussion of the --date option at
  +           git-log(1).
  +
  +       -M|<num>|
  +           Detect moved or copied lines within a file. When a commit moves or
  +           copies a block of lines (e.g. the original file has A and then B,
  +           and the commit changes it to B and then A), the traditional blame
  +           algorithm notices only half of the movement and typically blames
  +           the lines that were moved up (i.e. B) to the parent and assigns
  +           blame to the lines that were moved down (i.e. A) to the child
  +           commit. With this option, both groups of lines are blamed on the
  +           parent by running extra passes of inspection.
  +
  +           <num> is optional but it is the lower bound on the number of
  +           alphanumeric characters that git must detect as moving within a
  +           file for it to associate those lines with the parent commit.
  +
  +       -C|<num>|
  +           In addition to -M, detect lines moved or copied from other files
  +           that were modified in the same commit. This is useful when you
  +           reorganize your program and move code around across files. When
  +           this option is given twice, the command additionally looks for
  +           copies from other files in the commit that creates the file. When
  +           this option is given three times, the command additionally looks
  +           for copies from other files in any commit.
  +
  +           <num> is optional but it is the lower bound on the number of
  +           alphanumeric characters that git must detect as moving between
  +           files for it to associate those lines with the parent commit.
  +
  +       -h, --help
  +           Show help message.
  +
  +       -c
  +           Use the same output mode as git-annotate(1) (Default: off).
  +
  +       --score-debug
  +           Include debugging information related to the movement of lines
  +           between files (see -C) and lines moved within a file (see -M). The
  +           first number listed is the score. This is the number of
  +           alphanumeric characters detected as having been moved between or
  +           within files. This must be above a certain threshold for git blame
  +           to consider those lines of code to have been moved.
  +
  +       -f, --show-name
  +           Show the filename in the original commit. By default the filename
  +           is shown if there is any line that came from a file with a
  +           different name, due to rename detection.
  +
  +       -n, --show-number
  +           Show the line number in the original commit (Default: off).
  +
  +       -s
  +           Suppress the author name and timestamp from the output.
  +
  +       -w
  +           Ignore whitespace when comparing the parent's version and the
  +           child's to find where the lines came from.
  +#endif
  +
  +static rpmRC cmd_blame(int argc, char *argv[])
  +{
  +    const char * blame_range = NULL;
  +    enum {
  +	_BLAME_M		= (1 <<  0),
  +	_BLAME_C		= (1 <<  1),
  +	_BLAME_F		= (1 <<  2),
  +    };
  +    int blame_flags = 0;
  +#define	BLAME_ISSET(_a)	(blame_flags & _BLAME_##_a)
  +    struct poptOption blameOpts[] = {
  +     { NULL, 'M', POPT_BIT_SET,		&blame_flags, _BLAME_M,
  +	N_("Find line moves within and across files."), NULL },
  +     { NULL, 'C', POPT_BIT_SET,		&blame_flags, _BLAME_C,
  +	N_("Find line copies within and across files."), NULL },
  +     { NULL, 'F', POPT_BIT_SET,		&blame_flags, _BLAME_F,
  +	N_("Follow only the first parent commits."), NULL },
  +     { NULL, 'L', POPT_ARG_STRING,	&blame_range, 0,
  +	N_("process only lines <n,m>, counting from 1."), N_("<n,m>") },
  +
  +      POPT_AUTOALIAS
  +      POPT_AUTOHELP
  +      POPT_TABLEEND
  +    };
  +    rpmgit git = rpmgitNew(argv, 0, blameOpts);
  +    FILE * fp = stdout;
  +    rpmRC rc = RPMRC_FAIL;
  +
  +    git_blame_options blameopts = GIT_BLAME_OPTIONS_INIT;
  +    git_blame *blame = NULL;
  +    git_blob *blob = NULL;
  +    git_object *obj = NULL;
  +
  +    char spec[1024] = {0};
  +    const char *rawdata;
  +    int break_on_null_hunk;
  +    int line;
  +    int i;
  +
  +    const char *path = NULL;
  +    const char *commitspec = NULL;
  +    int start_line = 0;
  +    int end_line = 0;
  +
  +    int xx = -1;
  +
  +    if (BLAME_ISSET(M))
  +	blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES;
  +    if (BLAME_ISSET(C))
  +	blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES;
  +    if (BLAME_ISSET(F))
  +	blameopts.flags |= GIT_BLAME_FIRST_PARENT;
  +    if (blame_range) {
  +	if (sscanf(blame_range, "%d,%d", &start_line, &end_line) != 2)
  +	    goto exit;
  +    }
  +
  +    if (git->ac == 1) {
  +	path = git->av[0];
  +    } else
  +    if (git->ac == 2) {
  +	path = git->av[1];
  +        commitspec = xstrdup(git->av[0]);
  +    } else
  +    if (git->ac == 3) {
  +	path = git->av[2];
  +	sprintf(spec, "%s..%s", git->av[0], git->av[1]);
  +        commitspec = xstrdup(spec);
  +	spec[0] = '\0';
  +    } else
  +	goto exit;
  +
  +    /*
  +     * The commit range comes in "commitish" form. Use the rev-parse API to
  +     * nail down the end points.
  +     */
  +    if (commitspec) {
  +	git_revspec revspec = {0};
  +	xx = chkgit(git, "git_revparse",
  +		git_revparse(&revspec, git->R, commitspec));
  +	if (revspec.flags & GIT_REVPARSE_SINGLE) {
  +	    git_oid_cpy(&blameopts.newest_commit, git_object_id(revspec.from));
  +	    git_object_free(revspec.from);
  +	} else {
  +	    git_oid_cpy(&blameopts.oldest_commit, git_object_id(revspec.from));
  +	    git_oid_cpy(&blameopts.newest_commit, git_object_id(revspec.to));
  +	    git_object_free(revspec.from);
  +	    git_object_free(revspec.to);
  +	}
  +    }
  +
  +    /* Run the blame. */
  +    xx = chkgit(git, "git_blame_file",
  +		git_blame_file(&blame, git->R, path, &blameopts));
  +
  +    /*
  +     * Get the raw data inside the blob for output. We use the
  +     * `commitish:path/to/file.txt` format to find it.
  +     */
  +    if (git_oid_iszero(&blameopts.newest_commit))
  +	strcpy(spec, "HEAD");
  +    else
  +	git_oid_tostr(spec, sizeof(spec), &blameopts.newest_commit);
  +    strcat(spec, ":");
  +    strcat(spec, path);
  +
  +    xx = chkgit(git, "git_revparse_single",
  +		git_revparse_single(&obj, git->R, spec));
  +    xx = chkgit(git, "git_blob_lookup",
  +		git_blob_lookup(&blob, git->R, git_object_id(obj)));
  +    git_object_free(obj);
  +    obj = NULL;
  +
  +    rawdata = git_blob_rawcontent(blob);
  +
  +    /* Produce the output. */
  +    line = 1;
  +    i = 0;
  +    break_on_null_hunk = 0;
  +    while (i < git_blob_rawsize(blob)) {
  +	const char *eol = strchr(rawdata+i, '\n');
  +	char oid[10] = {0};
  +	const git_blame_hunk *hunk = git_blame_get_hunk_byline(blame, line);
  +
  +	if (break_on_null_hunk && !hunk)
  +	    break;
  +
  +	if (hunk) {
  +	    char sig[128] = {0};
  +	    break_on_null_hunk = 1;
  +
  +	    git_oid_tostr(oid, 10, &hunk->final_commit_id);
  +	    snprintf(sig, 30, "%s <%s>", hunk->final_signature->name, hunk->final_signature->email);
  +
  +	    fprintf(fp, "%s ( %-30s %3d) %.*s\n",
  +                                        oid,
  +                                        sig,
  +                                        line,
  +                                        (int)(eol-rawdata-i),
  +                                        rawdata+i);
  +	}
  +
  +	i = (int)(eol - rawdata + 1);
  +	line++;
  +    }
  +
  +    xx = 0;
  +
  +exit:
  +    rc = (xx ? RPMRC_FAIL : RPMRC_OK);
  +SPEW(0, rc, git);
  +    blame_range = _free(blame_range);
  +    commitspec = _free(commitspec);
  +
  +    if (obj)
  +	git_object_free(obj);
  +    if (blob)
  +	git_blob_free(blob);
  +    if (blame)
  +	git_blame_free(blame);
  +
  +    git = rpmgitFree(git);
  +    return rc;
  +}
  +#undef	BLAME_ISSET
  +
  +/*==============================================================*/
  +#ifdef	REFERENCE
  +OPTIONS
          -d
              Delete a branch. The branch must be fully merged in its upstream
              branch, or in HEAD if no upstream was set with --track or
  @@ -2787,6 +3091,7 @@
       struct poptOption lrOpts[] = {
         POPT_TABLEEND
       };
  +    FILE * fp = stdout;
       rpmRC rc = RPMRC_FAIL;
       rpmgit git = rpmgitNew(argv, 0, lrOpts);
       git_remote * remote = NULL;
  @@ -2811,7 +3116,7 @@
   	    goto exit;
       }
   
  -    /**
  +    /*
        * Connect to the remote and call the printing function for
        * each of the remote references.
        */
  @@ -2835,7 +3140,7 @@
       for (i = 0; i < refs_len; i++) {
   	char oid[GIT_OID_HEXSZ + 1] = {0};
   	git_oid_fmt(oid, &refs[i]->oid);
  -	printf("%s\t%s\n", oid, refs[i]->name);
  +	fprintf(fp, "%s\t%s\n", oid, refs[i]->name);
       }
   
   exit:
  @@ -3245,7 +3550,7 @@
       struct poptOption ipOpts[] = {
         POPT_TABLEEND
       };
  -    FILE * fp = stderr;
  +    FILE * fp = stdout;
       rpmRC rc = RPMRC_FAIL;
       rpmgit git = rpmgitNew(argv, 0, ipOpts);
       git_indexer *idx = NULL;
  @@ -3333,6 +3638,8 @@
   	N_("Add file contents to the index."), NULL },
    { "bisect", '\0',   POPT_ARG_MAINCALL,	cmd_noop, ARGMINMAX(0,0),
   	N_("Find by binary search the change that introduced a bug."), NULL },
  + { "blame", '\0',   POPT_ARG_MAINCALL,	cmd_blame, ARGMINMAX(0,0),
  +	N_("Show revision/author of last modified."), NULL },
    { "branch", '\0',   POPT_ARG_MAINCALL,	cmd_branch, ARGMINMAX(0,0),
   	N_("List, create, or delete branches."), NULL },
    { "checkout", '\0', POPT_ARG_MAINCALL,	cmd_noop, ARGMINMAX(0,0),
  @@ .
______________________________________________________________________
RPM Package Manager                                    http://rpm5.org
CVS Sources Repository                                rpm-cvs@rpm5.org
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic