Blob of vendor/ruby-git/lib/git/diff.rb (raw blob data)

1 module Git
2
3 # object that holds the last X commits on given branch
4 class Diff
5 include Enumerable
6
7 @base = nil
8 @from = nil
9 @to = nil
10 @path = nil
11
12 @full_diff = nil
13 @full_diff_files = nil
14 @stats = nil
15
16 def initialize(base, from = nil, to = nil)
17 @base = base
18 @from = from.to_s
19 @to = to.to_s
20 end
21
22 def path(path)
23 @path = path
24 return self
25 end
26
27 def size
28 cache_stats
29 @stats[:total][:files]
30 end
31
32 def lines
33 cache_stats
34 @stats[:total][:lines]
35 end
36
37 def deletions
38 cache_stats
39 @stats[:total][:deletions]
40 end
41
42 def insertions
43 cache_stats
44 @stats[:total][:insertions]
45 end
46
47 def stats
48 cache_stats
49 @stats
50 end
51
52 # if file is provided and is writable, it will write the patch into the file
53 def patch(file = nil)
54 cache_full
55 @full_diff
56 end
57 alias_method :to_s, :patch
58
59 # enumerable methods
60
61 def [](key)
62 process_full
63 @full_diff_files.assoc(key)[1]
64 end
65
66 def each
67 process_full
68 @full_diff_files.each do |file|
69 yield file[1]
70 end
71 end
72
73 class DiffFile
74 attr_accessor :patch, :path, :mode, :src, :dst, :type
75 @base = nil
76
77 def initialize(base, hash)
78 @base = base
79 @patch = hash[:patch]
80 @path = hash[:path]
81 @mode = hash[:mode]
82 @src = hash[:src]
83 @dst = hash[:dst]
84 @type = hash[:type]
85 end
86
87 def blob(type = :dst)
88 if type == :src
89 @base.object(@src) if @src != '0000000'
90 else
91 @base.object(@dst) if @dst != '0000000'
92 end
93 end
94 end
95
96 private
97
98 def cache_full
99 if !@full_diff
100 @full_diff = @base.lib.diff_full(@from, @to, {:path_limiter => @path})
101 end
102 end
103
104 def process_full
105 if !@full_diff_files
106 cache_full
107 @full_diff_files = process_full_diff
108 end
109 end
110
111 def cache_stats
112 if !@stats
113 @stats = @base.lib.diff_stats(@from, @to, {:path_limiter => @path})
114 end
115 end
116
117 # break up @diff_full
118 def process_full_diff
119 final = {}
120 current_file = nil
121 @full_diff.split("\n").each do |line|
122 if m = /^diff --git a\/(.*?) b\/(.*?)/.match(line)
123 current_file = m[1]
124 final[current_file] = {:patch => line, :path => current_file,
125 :mode => '', :src => '', :dst => '', :type => 'modified'}
126 else
127 if m = /^index (.......)\.\.(.......)( ......)*/.match(line)
128 final[current_file][:src] = m[1]
129 final[current_file][:dst] = m[2]
130 final[current_file][:mode] = m[3].strip if m[3]
131 end
132 if m = /^(.*?) file mode (......)/.match(line)
133 final[current_file][:type] = m[1]
134 final[current_file][:mode] = m[2]
135 end
136 final[current_file][:patch] << "\n" + line
137 end
138 end
139 final.map { |e| [e[0], DiffFile.new(@base, e[1])] }
140 end
141
142 end
143 end