git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v8 0/6] New git-related helper
@ 2013-05-31  7:37 Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 1/6] Add new git-related helper to contrib Felipe Contreras
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Felipe Contreras @ 2013-05-31  7:37 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Duy Nguyen, Felipe Contreras

Hi,

Since there hasn't been any comments of importance this is basically the same
as v7, plus a few other patches to make it actually usable (for me).

Unfortunately it turns out Ruby's optparse is not suitable for our needs, so I
implemented a very small parser that is.

Felipe Contreras (6):
  Add new git-related helper to contrib
  contrib: related: add option parsing
  contrib: related: add support for multiple patches
  contrib: related: add option to parse from committish
  contrib: related: parse committish like format-patch
  contrib: related: implement custom option parser

 contrib/related/git-related | 247 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 247 insertions(+)
 create mode 100755 contrib/related/git-related

-- 
1.8.3.358.g5a91d05

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v8 1/6] Add new git-related helper to contrib
  2013-05-31  7:37 [PATCH v8 0/6] New git-related helper Felipe Contreras
@ 2013-05-31  7:37 ` Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 2/6] contrib: related: add option parsing Felipe Contreras
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Felipe Contreras @ 2013-05-31  7:37 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Duy Nguyen, Felipe Contreras

This script find people that might be interested in a patch, by going
back through the history for each single hunk modified, and finding
people that reviewed, acknowledge, signed, or authored the code the
patch is modifying.

It does this by running 'git blame' incrementally on each hunk, and then
parsing the commit message. After gathering all the relevant people, it
groups them to show what exactly was their role when the participated in
the development of the relevant commit, and on how many relevant commits
they participated. They are only displayed if they pass a minimum
threshold of participation.

For example:

  % git related 0001-remote-hg-trivial-cleanups.patch
  Felipe Contreras <felipe.contreras@gmail.com>
  Jeff King <peff@peff.net>
  Max Horn <max@quendi.de>
  Junio C Hamano <gitster@pobox.com>

Thus it can be used for 'git send-email' as a cc-cmd.

There might be some other related functions to this script, not just to
be used as a cc-cmd.

Comments-by: Ramkumar Ramachandra <artagnon@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/related/git-related | 120 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)
 create mode 100755 contrib/related/git-related

diff --git a/contrib/related/git-related b/contrib/related/git-related
new file mode 100755
index 0000000..1b9b1e7
--- /dev/null
+++ b/contrib/related/git-related
@@ -0,0 +1,120 @@
+#!/usr/bin/env ruby
+
+# This script finds people that might be interested in a patch
+# usage: git related <file>
+
+$since = '5-years-ago'
+$min_percent = 10
+
+class Commit
+
+  attr_reader :persons
+
+  def initialize(id)
+    @id = id
+    @persons = []
+  end
+
+  def parse(data)
+    msg = nil
+    data.each_line do |line|
+      if not msg
+        case line
+        when /^author ([^<>]+) <(\S+)> (.+)$/
+          @persons << '%s <%s>' % [$1, $2]
+        when /^$/
+          msg = true
+        end
+      else
+        if line =~ /^(Signed-off|Reviewed|Acked)-by: ([^<>]+) <(\S+?)>$/
+          @persons << '%s <%s>' % [$2, $3]
+        end
+      end
+    end
+    @persons.uniq!
+  end
+
+end
+
+class Commits
+
+  def initialize
+    @items = {}
+  end
+
+  def size
+    @items.size
+  end
+
+  def each(&block)
+    @items.each(&block)
+  end
+
+  def import
+    return if @items.empty?
+    File.popen(%w[git cat-file --batch], 'r+') do |p|
+      p.write(@items.keys.join("\n"))
+      p.close_write
+      p.each do |line|
+        if line =~ /^(\h{40}) commit (\d+)/
+          id, len = $1, $2
+          data = p.read($2.to_i)
+          @items[id].parse(data)
+        end
+      end
+    end
+  end
+
+  def get_blame(source, start, len, from)
+    return if len == 0
+    len ||= 1
+    File.popen(['git', 'blame', '--incremental', '-C', '-C',
+               '-L', '%u,+%u' % [start, len],
+               '--since', $since, from + '^',
+               '--', source]) do |p|
+      p.each do |line|
+        if line =~ /^\h{40}/
+          id = $&
+          @items[id] = Commit.new(id)
+        end
+      end
+    end
+  end
+
+  def from_patch(file)
+    from = source = nil
+    File.open(file) do |f|
+      f.each do |line|
+        case line
+        when /^From (\h+) (.+)$/
+          from = $1
+        when /^---\s+(\S+)/
+          source = $1 != '/dev/null' ? $1[2..-1] : nil
+        when /^@@ -(\d+)(?:,(\d+))?/
+          get_blame(source, $1, $2, from) if source and from
+        end
+      end
+    end
+  end
+
+end
+
+exit 1 if ARGV.size != 1
+
+commits = Commits.new
+commits.from_patch(ARGV[0])
+commits.import
+
+count_per_person = Hash.new(0)
+
+commits.each do |id, commit|
+  commit.persons.each do |person|
+    count_per_person[person] += 1
+  end
+end
+
+count_per_person.each do |person, count|
+  percent = count.to_f * 100 / commits.size
+  next if percent < $min_percent
+  puts person
+end
-- 
1.8.3.358.g5a91d05

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v8 2/6] contrib: related: add option parsing
  2013-05-31  7:37 [PATCH v8 0/6] New git-related helper Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 1/6] Add new git-related helper to contrib Felipe Contreras
@ 2013-05-31  7:37 ` Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 3/6] contrib: related: add support for multiple patches Felipe Contreras
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Felipe Contreras @ 2013-05-31  7:37 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Duy Nguyen, Felipe Contreras

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/related/git-related | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/contrib/related/git-related b/contrib/related/git-related
index 1b9b1e7..bde5b99 100755
--- a/contrib/related/git-related
+++ b/contrib/related/git-related
@@ -3,9 +3,25 @@
 # This script finds people that might be interested in a patch
 # usage: git related <file>
 
+require 'optparse'
+
 $since = '5-years-ago'
 $min_percent = 10
 
+OptionParser.new do |opts|
+  opts.program_name = 'git related'
+  opts.banner = 'usage: git related [options] <file>'
+
+  opts.on('-p', '--min-percent N', Integer,
+          'Minium percentage of role participation') do |v|
+    $min_percent = v
+  end
+  opts.on('-d', '--since DATE',
+          'How far back to search for relevant commits') do |v|
+    $since = v
+  end
+end.parse!
+
 class Commit
 
   attr_reader :persons
-- 
1.8.3.358.g5a91d05

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v8 3/6] contrib: related: add support for multiple patches
  2013-05-31  7:37 [PATCH v8 0/6] New git-related helper Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 1/6] Add new git-related helper to contrib Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 2/6] contrib: related: add option parsing Felipe Contreras
@ 2013-05-31  7:37 ` Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 4/6] contrib: related: add option to parse from committish Felipe Contreras
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Felipe Contreras @ 2013-05-31  7:37 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Duy Nguyen, Felipe Contreras

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/related/git-related | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/contrib/related/git-related b/contrib/related/git-related
index bde5b99..0de1c6c 100755
--- a/contrib/related/git-related
+++ b/contrib/related/git-related
@@ -10,7 +10,7 @@ $min_percent = 10
 
 OptionParser.new do |opts|
   opts.program_name = 'git related'
-  opts.banner = 'usage: git related [options] <file>'
+  opts.banner = 'usage: git related [options] <files>'
 
   opts.on('-p', '--min-percent N', Integer,
           'Minium percentage of role participation') do |v|
@@ -56,6 +56,7 @@ class Commits
 
   def initialize
     @items = {}
+    @main_commits = {}
   end
 
   def size
@@ -91,23 +92,27 @@ class Commits
       p.each do |line|
         if line =~ /^\h{40}/
           id = $&
-          @items[id] = Commit.new(id)
+          @items[id] = Commit.new(id) if not @main_commits.include?(id)
         end
       end
     end
   end
 
-  def from_patch(file)
-    from = source = nil
-    File.open(file) do |f|
-      f.each do |line|
-        case line
-        when /^From (\h+) (.+)$/
-          from = $1
-        when /^---\s+(\S+)/
-          source = $1 != '/dev/null' ? $1[2..-1] : nil
-        when /^@@ -(\d+)(?:,(\d+))?/
-          get_blame(source, $1, $2, from) if source and from
+  def from_patches(files)
+    source = nil
+    files.each do |file|
+      from = nil
+      File.open(file) do |f|
+        f.each do |line|
+          case line
+          when /^From (\h+) (.+)$/
+            from = $1
+            @main_commits[from] = true
+          when /^---\s+(\S+)/
+            source = $1 != '/dev/null' ? $1[2..-1] : nil
+          when /^@@ -(\d+)(?:,(\d+))?/
+            get_blame(source, $1, $2, from) if source and from
+          end
         end
       end
     end
@@ -115,10 +120,8 @@ class Commits
 
 end
 
-exit 1 if ARGV.size != 1
-
 commits = Commits.new
-commits.from_patch(ARGV[0])
+commits.from_patches(ARGV)
 commits.import
 
 count_per_person = Hash.new(0)
-- 
1.8.3.358.g5a91d05

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v8 4/6] contrib: related: add option to parse from committish
  2013-05-31  7:37 [PATCH v8 0/6] New git-related helper Felipe Contreras
                   ` (2 preceding siblings ...)
  2013-05-31  7:37 ` [PATCH v8 3/6] contrib: related: add support for multiple patches Felipe Contreras
@ 2013-05-31  7:37 ` Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 5/6] contrib: related: parse committish like format-patch Felipe Contreras
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Felipe Contreras @ 2013-05-31  7:37 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Duy Nguyen, Felipe Contreras

For example master..feature-a.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/related/git-related | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/contrib/related/git-related b/contrib/related/git-related
index 0de1c6c..3573237 100755
--- a/contrib/related/git-related
+++ b/contrib/related/git-related
@@ -7,10 +7,12 @@ require 'optparse'
 
 $since = '5-years-ago'
 $min_percent = 10
+$files = []
+$rev_args = []
 
 OptionParser.new do |opts|
   opts.program_name = 'git related'
-  opts.banner = 'usage: git related [options] <files>'
+  opts.banner = 'usage: git related [options] <files | rev-list options>'
 
   opts.on('-p', '--min-percent N', Integer,
           'Minium percentage of role participation') do |v|
@@ -118,10 +120,42 @@ class Commits
     end
   end
 
+  def from_rev_args(args)
+    source = nil
+    File.popen(%w[git rev-list --reverse] + args) do |p|
+      p.each do |e|
+        id = e.chomp
+        @main_commits[id] = true
+        File.popen(%w[git show -C --oneline] + [id]) do |p|
+          p.each do |e|
+            case e
+            when /^---\s+(\S+)/
+              source = $1 != '/dev/null' ? $1[2..-1] : nil
+            when /^@@ -(\d+)(?:,(\d+))?/
+              get_blame(source, $1, $2, id) if source
+            end
+          end
+        end
+      end
+    end
+  end
+
+end
+
+ARGV.each do |e|
+  if File.exists?(e)
+    $files << e
+  else
+    $rev_args << e
+  end
 end
 
 commits = Commits.new
-commits.from_patches(ARGV)
+if $files.empty?
+  commits.from_rev_args($rev_args)
+else
+  commits.from_patches($files)
+end
 commits.import
 
 count_per_person = Hash.new(0)
-- 
1.8.3.358.g5a91d05

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v8 5/6] contrib: related: parse committish like format-patch
  2013-05-31  7:37 [PATCH v8 0/6] New git-related helper Felipe Contreras
                   ` (3 preceding siblings ...)
  2013-05-31  7:37 ` [PATCH v8 4/6] contrib: related: add option to parse from committish Felipe Contreras
@ 2013-05-31  7:37 ` Felipe Contreras
  2013-05-31  7:37 ` [PATCH v8 6/6] contrib: related: implement custom option parser Felipe Contreras
  2013-05-31  7:48 ` [PATCH v8 0/6] New git-related helper Felipe Contreras
  6 siblings, 0 replies; 8+ messages in thread
From: Felipe Contreras @ 2013-05-31  7:37 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Duy Nguyen, Felipe Contreras

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/related/git-related | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/contrib/related/git-related b/contrib/related/git-related
index 3573237..585572b 100755
--- a/contrib/related/git-related
+++ b/contrib/related/git-related
@@ -121,6 +121,21 @@ class Commits
   end
 
   def from_rev_args(args)
+    revs = []
+
+    File.popen(%w[git rev-parse --revs-only --default HEAD --symbolic] + args).each do |rev|
+      revs << rev.chomp
+    end
+
+    case revs.size
+    when 1
+      r = revs[0]
+      r = '^' + r if r[0] != '-'
+      args = [ r, 'HEAD' ]
+    else
+      args = revs
+    end
+
     source = nil
     File.popen(%w[git rev-list --reverse] + args) do |p|
       p.each do |e|
-- 
1.8.3.358.g5a91d05

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v8 6/6] contrib: related: implement custom option parser
  2013-05-31  7:37 [PATCH v8 0/6] New git-related helper Felipe Contreras
                   ` (4 preceding siblings ...)
  2013-05-31  7:37 ` [PATCH v8 5/6] contrib: related: parse committish like format-patch Felipe Contreras
@ 2013-05-31  7:37 ` Felipe Contreras
  2013-05-31  7:48 ` [PATCH v8 0/6] New git-related helper Felipe Contreras
  6 siblings, 0 replies; 8+ messages in thread
From: Felipe Contreras @ 2013-05-31  7:37 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Duy Nguyen, Felipe Contreras

Ruby's option parser is not extensible enough to keep unknown options.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/related/git-related | 83 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 71 insertions(+), 12 deletions(-)

diff --git a/contrib/related/git-related b/contrib/related/git-related
index 585572b..c933898 100755
--- a/contrib/related/git-related
+++ b/contrib/related/git-related
@@ -3,26 +3,85 @@
 # This script finds people that might be interested in a patch
 # usage: git related <file>
 
-require 'optparse'
-
 $since = '5-years-ago'
 $min_percent = 10
 $files = []
 $rev_args = []
 
-OptionParser.new do |opts|
-  opts.program_name = 'git related'
-  opts.banner = 'usage: git related [options] <files | rev-list options>'
+class SimpleParser
+  attr_writer :usage
+
+  class Option
+    attr_reader :short, :long, :help
+
+    def initialize(short, long, help, &block)
+      @block = block
+      @short = short
+      @long = long
+      @help = help
+    end
+
+    def call(v)
+      @block.call(v)
+    end
+  end
 
-  opts.on('-p', '--min-percent N', Integer,
-          'Minium percentage of role participation') do |v|
-    $min_percent = v
+  def initialize
+    @list = {}
+  end
+
+  def on(short=nil, long=nil, help=nil, &block)
+    opt = Option.new(short, long, help, &block)
+    @list[short] = opt if short
+    @list[long] = opt if long
+  end
+
+  def parse
+    i = 0
+    if ARGV.member?('-h') or ARGV.member?('--help')
+      usage
+      exit 1
+    end
+    while cur = ARGV[i] do
+      if cur =~ /^(-.+?)(?:=(.*))?$/
+        opt = @list[$1]
+        if opt
+          v = $2 || ARGV.delete_at(i + 1)
+          opt.call(v)
+          ARGV.delete_at(i)
+          next
+        end
+      end
+      i += 1
+    end
   end
-  opts.on('-d', '--since DATE',
-          'How far back to search for relevant commits') do |v|
-    $since = v
+
+  def usage
+    puts 'usage: %s' % @usage
+    @list.values.uniq.each do |opt|
+      s = '    '
+      s << [opt.short, opt.long].compact.join(', ')
+      s << '%*s%s' % [26 - s.size, '', opt.help] if opt.help
+      puts s
+    end
   end
-end.parse!
+
+end
+
+opts = SimpleParser.new
+opts.usage = 'usage: git related [options] <files | rev-list options>'
+
+opts.on('-p', '--min-percent',
+        'Minium percentage of role participation') do |v|
+  $min_percent = v.to_i
+end
+
+opts.on('-d', '--since',
+        'How far back to search for relevant commits') do |v|
+  $since = v
+end
+
+opts.parse
 
 class Commit
 
-- 
1.8.3.358.g5a91d05

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v8 0/6] New git-related helper
  2013-05-31  7:37 [PATCH v8 0/6] New git-related helper Felipe Contreras
                   ` (5 preceding siblings ...)
  2013-05-31  7:37 ` [PATCH v8 6/6] contrib: related: implement custom option parser Felipe Contreras
@ 2013-05-31  7:48 ` Felipe Contreras
  6 siblings, 0 replies; 8+ messages in thread
From: Felipe Contreras @ 2013-05-31  7:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Duy Nguyen, Felipe Contreras

On Fri, May 31, 2013 at 2:37 AM, Felipe Contreras
<felipe.contreras@gmail.com> wrote:

> Since there hasn't been any comments of importance this is basically the same
> as v7, plus a few other patches to make it actually usable (for me).
>
> Unfortunately it turns out Ruby's optparse is not suitable for our needs, so I
> implemented a very small parser that is.

Nevermind, we can drop the option parsing changes for later, it's not
important at the moment.

-- 
Felipe Contreras

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-05-31  7:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-31  7:37 [PATCH v8 0/6] New git-related helper Felipe Contreras
2013-05-31  7:37 ` [PATCH v8 1/6] Add new git-related helper to contrib Felipe Contreras
2013-05-31  7:37 ` [PATCH v8 2/6] contrib: related: add option parsing Felipe Contreras
2013-05-31  7:37 ` [PATCH v8 3/6] contrib: related: add support for multiple patches Felipe Contreras
2013-05-31  7:37 ` [PATCH v8 4/6] contrib: related: add option to parse from committish Felipe Contreras
2013-05-31  7:37 ` [PATCH v8 5/6] contrib: related: parse committish like format-patch Felipe Contreras
2013-05-31  7:37 ` [PATCH v8 6/6] contrib: related: implement custom option parser Felipe Contreras
2013-05-31  7:48 ` [PATCH v8 0/6] New git-related helper Felipe Contreras

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).