rpatch 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +16 -7
- data/lib/rpatch/entry.rb +18 -12
- data/lib/rpatch/hunk.rb +181 -119
- data/lib/rpatch/patch.rb +29 -20
- data/lib/rpatch/runner.rb +5 -2
- data/lib/rpatch/utils.rb +121 -0
- data/lib/rpatch/version.rb +1 -1
- data/spec/patch_file_regexp_spec.rb +6 -8
- data/spec/patch_file_spec.rb +10 -3
- data/spec/patch_hunk_with_location_spec.rb +149 -0
- data/spec/patch_hunk_with_qmark_exp_spec.rb +152 -0
- data/spec/patch_hunk_with_regex_spec.rb +72 -0
- data/t/t0000-patch-file.sh +27 -28
- data/t/t0010-patch-special-direction.sh +336 -0
- data/t/t0100-patch-directory.sh +89 -42
- metadata +59 -73
data/lib/rpatch/patch.rb
CHANGED
@@ -2,9 +2,13 @@
|
|
2
2
|
#
|
3
3
|
|
4
4
|
require 'rpatch/error'
|
5
|
+
require 'rpatch/utils'
|
5
6
|
require 'rpatch/entry'
|
6
7
|
|
7
8
|
module Rpatch
|
9
|
+
|
10
|
+
REGEXP_VALID_HUNK_PREFIX = /^(@@| |-|\+|RE: |RE:-|\/ |\/-|<$|>$|\?( |-|\+|\/ |\/-|\/\+))/
|
11
|
+
|
8
12
|
class Patch
|
9
13
|
attr_reader :name, :level, :patch_entries
|
10
14
|
|
@@ -27,7 +31,7 @@ module Rpatch
|
|
27
31
|
end
|
28
32
|
patch_status
|
29
33
|
rescue Exception => e
|
30
|
-
|
34
|
+
Tty.error e.message
|
31
35
|
patch_status = false
|
32
36
|
end
|
33
37
|
end
|
@@ -55,7 +59,7 @@ module Rpatch
|
|
55
59
|
patch_entry.patch_on_file(input, output) || patch_status = false
|
56
60
|
end
|
57
61
|
rescue Exception => e
|
58
|
-
|
62
|
+
Tty.error e.message
|
59
63
|
patch_status = false
|
60
64
|
end
|
61
65
|
end
|
@@ -83,7 +87,7 @@ module Rpatch
|
|
83
87
|
level = $2
|
84
88
|
end
|
85
89
|
unless filename.start_with? '#'
|
86
|
-
apply_one(path, filename, level) || patch_status = false
|
90
|
+
apply_one(path, File.join(quilt_dir, filename), level) || patch_status = false
|
87
91
|
end
|
88
92
|
end
|
89
93
|
end
|
@@ -101,19 +105,19 @@ module Rpatch
|
|
101
105
|
entry_names = find_new_entry(lines[i..i+6])
|
102
106
|
if entry_names
|
103
107
|
@patch_entries << PatchEntry.new(entry_names[0], entry_names[1], @level)
|
104
|
-
while not lines[i] =~
|
108
|
+
while not lines[i] =~ /^@@/ and lines[i]
|
105
109
|
i += 1
|
106
110
|
end
|
107
111
|
break unless i < lines.size
|
108
112
|
end
|
109
113
|
|
110
114
|
if @patch_entries.any?
|
111
|
-
if lines[i] =~
|
115
|
+
if lines[i] =~ REGEXP_VALID_HUNK_PREFIX
|
112
116
|
@patch_entries.last.feed_line lines[i]
|
113
117
|
elsif lines[i] =~ /^(Binary files |Only in)/
|
114
118
|
# ignore
|
115
119
|
else
|
116
|
-
raise PatchFormatError, "Line #{i} of patch \"#{name}\" is invalid.\n
|
120
|
+
raise PatchFormatError, "Line #{i} of patch \"#{name}\" is invalid.\n=> #{lines[i].inspect}"
|
117
121
|
end
|
118
122
|
end
|
119
123
|
|
@@ -132,22 +136,27 @@ module Rpatch
|
|
132
136
|
end
|
133
137
|
|
134
138
|
def find_new_entry(lines)
|
135
|
-
return nil if lines[0] =~ /^(@@| |-|\+|RE: |RE:-)/
|
136
139
|
old = new = nil
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
140
|
+
lines = lines.dup
|
141
|
+
while lines.first
|
142
|
+
case lines.first
|
143
|
+
when /^--- (.+?)([\s]+[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.*)?$/
|
144
|
+
old = $1
|
145
|
+
when /^\+\+\+ (.+?)([\s]+[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.*)?$/
|
146
|
+
new = $1
|
147
|
+
when REGEXP_VALID_HUNK_PREFIX
|
148
|
+
break
|
149
|
+
when /^(diff |new file mode|index )/
|
150
|
+
# Ignore GNU/Git diff header
|
151
|
+
when /^(Index:|=+)/
|
152
|
+
# Ignore quilt patch header
|
153
|
+
else
|
154
|
+
# Ignore comments in the header
|
155
|
+
end
|
156
|
+
lines.shift
|
149
157
|
end
|
150
|
-
|
158
|
+
|
159
|
+
if lines.first =~ /^@@/ and old and new
|
151
160
|
[old, new]
|
152
161
|
else
|
153
162
|
nil
|
data/lib/rpatch/runner.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'optparse'
|
2
|
-
require 'rpatch/
|
2
|
+
require 'rpatch/utils'
|
3
3
|
require 'rpatch/version'
|
4
|
+
require 'rpatch/patch'
|
4
5
|
|
5
6
|
module Rpatch
|
6
7
|
class Runner
|
@@ -13,10 +14,12 @@ module Rpatch
|
|
13
14
|
OptionParser.new do |opts|
|
14
15
|
opts.banner = "Usage: rpatch [options] [originalfile [patchfile]]"
|
15
16
|
opts.on("-p", "--strip num", "Patch level") {|v| patch_level = v.to_i}
|
16
|
-
opts.on("-
|
17
|
+
opts.on("-V", "--version", "Show version") do
|
17
18
|
puts "Version #{Rpatch::VERSION}"
|
18
19
|
exit 0
|
19
20
|
end
|
21
|
+
opts.on("-v", "--verbose", "More verbose") {Tty.options[:verbose] += 1}
|
22
|
+
opts.on("-q", "--quiet", "Less verbose") {Tty.options[:verbose] -= 1}
|
20
23
|
opts.on_tail("-h", "--help", "Show this message") do
|
21
24
|
puts opts
|
22
25
|
exit 0
|
data/lib/rpatch/utils.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'rpatch/error'
|
2
|
+
|
3
|
+
module Rpatch
|
4
|
+
|
5
|
+
class Tty
|
6
|
+
class << self
|
7
|
+
def options
|
8
|
+
@options ||= {:verbose => 0}
|
9
|
+
end
|
10
|
+
def blue; bold 34; end
|
11
|
+
def white; bold 39; end
|
12
|
+
def red; underline 31; end
|
13
|
+
def yellow; underline 33 ; end
|
14
|
+
def reset; escape 0; end
|
15
|
+
def em; underline 39; end
|
16
|
+
def green; color 92 end
|
17
|
+
def gray; bold 30 end
|
18
|
+
|
19
|
+
def width
|
20
|
+
@width = begin
|
21
|
+
w = %x{stty size 2>/dev/null}.chomp.split.last.to_i.nonzero?
|
22
|
+
w ||= %x{tput cols 2>/dev/null}.to_i
|
23
|
+
w < 1 ? 80 : w
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def die(*messages)
|
28
|
+
error messages
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
|
32
|
+
def tty_puts(*args)
|
33
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
34
|
+
|
35
|
+
case (opts[:type] || :notice).to_s.downcase.to_sym
|
36
|
+
when :error
|
37
|
+
# always show errors
|
38
|
+
when :warning
|
39
|
+
return if verbose < -1
|
40
|
+
when :notice
|
41
|
+
return if verbose < 0
|
42
|
+
when :info
|
43
|
+
return if verbose < 1
|
44
|
+
when :debug
|
45
|
+
return if verbose < 2
|
46
|
+
end
|
47
|
+
|
48
|
+
lines = args.map{|m| m.to_s.split($/)}.flatten
|
49
|
+
prompt = opts[:type] ? "#{opts[:type].to_s.upcase}: " : ""
|
50
|
+
if opts[:type]
|
51
|
+
if STDERR.tty?
|
52
|
+
STDERR.write "#{Tty.red}#{prompt}#{Tty.reset}"
|
53
|
+
else
|
54
|
+
STDERR.write "#{prompt}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if STDERR.tty? and opts[:color] and Tty.respond_to? opts[:color]
|
58
|
+
STDERR.puts "#{Tty.send(opts[:color])}#{lines.shift}#{Tty.reset}"
|
59
|
+
else
|
60
|
+
STDERR.puts lines.shift
|
61
|
+
end
|
62
|
+
spaces = " " * prompt.size
|
63
|
+
lines.each do |line|
|
64
|
+
STDERR.write spaces
|
65
|
+
if STDERR.tty? and opts[:color] and Tty.respond_to? opts[:color]
|
66
|
+
STDERR.puts "#{Tty.send(opts[:color])}#{line}#{Tty.reset}"
|
67
|
+
else
|
68
|
+
STDERR.puts line
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def error(*messages)
|
74
|
+
tty_puts(*messages << {:type => :error, :color => :red})
|
75
|
+
end
|
76
|
+
|
77
|
+
def warning(*messages)
|
78
|
+
tty_puts(*messages << {:type => :warning, :color => :yellow})
|
79
|
+
end
|
80
|
+
|
81
|
+
def notice(*messages)
|
82
|
+
tty_puts(*messages << {:type => nil})
|
83
|
+
end
|
84
|
+
|
85
|
+
def info(*messages)
|
86
|
+
tty_puts(*messages << {:type => :info, :color => :green})
|
87
|
+
end
|
88
|
+
|
89
|
+
def debug(*messages)
|
90
|
+
tty_puts(*messages << {:type => :debug, :color => :blue})
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def verbose
|
96
|
+
options[:verbose]
|
97
|
+
end
|
98
|
+
|
99
|
+
def color n
|
100
|
+
escape "0;#{n}"
|
101
|
+
end
|
102
|
+
def bold n
|
103
|
+
escape "1;#{n}"
|
104
|
+
end
|
105
|
+
def underline n
|
106
|
+
escape "4;#{n}"
|
107
|
+
end
|
108
|
+
def escape n
|
109
|
+
"\033[#{n}m" if $stdout.tty?
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class String
|
117
|
+
def charat(n)
|
118
|
+
result = self.send "[]", n
|
119
|
+
RUBY_VERSION < "1.9" ? result.chr : result
|
120
|
+
end
|
121
|
+
end
|
data/lib/rpatch/version.rb
CHANGED
@@ -5,23 +5,24 @@ require 'spec_helper'
|
|
5
5
|
require 'stringio'
|
6
6
|
|
7
7
|
describe Rpatch::Patch do
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
it "regexp patterns test" do
|
10
|
+
diff = <<-EOF
|
10
11
|
diff -ru before/readme.txt after/readme.txt
|
11
12
|
--- a/readme.txt 2013-11-03 22:17:02.000000000 +0800
|
12
13
|
+++ b/readme.txt 2013-11-03 21:10:46.000000000 +0800
|
13
14
|
@@ remove two leading lines
|
14
15
|
-I have a script to patch text files, it's more like
|
15
|
-
|
16
|
+
/-.* Why not (patch|GNU patch)?
|
16
17
|
When I hack files using GNU patch,
|
17
|
-
|
18
|
+
/ sometimes fail because .*
|
18
19
|
@@ add copyright
|
19
20
|
+/*
|
20
21
|
+ * Copyright (c) 2013 Jiang Xin
|
21
22
|
+ */
|
22
23
|
+
|
23
24
|
When I hack files using GNU patch,
|
24
|
-
|
25
|
+
/ sometimes fail because .*
|
25
26
|
@@ add notes
|
26
27
|
+If patch can ignore blank lines, support regex patterns
|
27
28
|
+in patch, it will be nice.
|
@@ -32,9 +33,7 @@ RE: sometimes fail because .*
|
|
32
33
|
+--
|
33
34
|
+jiangxin
|
34
35
|
EOF
|
35
|
-
end
|
36
36
|
|
37
|
-
it "patch on file" do
|
38
37
|
before = <<-EOF
|
39
38
|
I have a script to patch text files, it's more like
|
40
39
|
"grep" and "seed -s". Why not GNU patch?
|
@@ -69,5 +68,4 @@ jiangxin
|
|
69
68
|
patch.apply_to(inputfile, outputfile)
|
70
69
|
output.should == after
|
71
70
|
end
|
72
|
-
|
73
71
|
end
|
data/spec/patch_file_spec.rb
CHANGED
@@ -171,9 +171,16 @@ jiangxin
|
|
171
171
|
before = ''
|
172
172
|
|
173
173
|
diff = <<-EOF
|
174
|
-
|
175
|
-
|
176
|
-
|
174
|
+
Test for patching for new file
|
175
|
+
|
176
|
+
* note 1
|
177
|
+
* note 2
|
178
|
+
* note 3
|
179
|
+
|
180
|
+
Index: a/readme.txt
|
181
|
+
===================================================================
|
182
|
+
--- /dev/null 2013-11-03 22:17:02.000000000 +0800
|
183
|
+
+++ b/readme.txt 2013-11-03 21:10:46.000000000 +0800
|
177
184
|
@@ initial
|
178
185
|
+hello
|
179
186
|
+world
|
@@ -0,0 +1,149 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe Rpatch::PatchHunk do
|
7
|
+
|
8
|
+
it "patch has default location direction" do
|
9
|
+
diff = <<-EOF
|
10
|
+
+foo
|
11
|
+
+bar
|
12
|
+
EOF
|
13
|
+
|
14
|
+
before = <<-EOF
|
15
|
+
hello
|
16
|
+
world
|
17
|
+
EOF
|
18
|
+
|
19
|
+
after = <<-EOF
|
20
|
+
foo
|
21
|
+
bar
|
22
|
+
hello
|
23
|
+
world
|
24
|
+
EOF
|
25
|
+
|
26
|
+
hunk = Rpatch::PatchHunk.new('@@ description')
|
27
|
+
diff.split($/).each {|line| hunk.feed_line line.chomp}
|
28
|
+
|
29
|
+
hunk.match_after_patch(before.split($/)).should eq nil
|
30
|
+
hunk.match_before_patch(before.split($/)).should eq [0, 0]
|
31
|
+
result = hunk.patch(before.split($/))
|
32
|
+
(result * "\n" + "\n").should eq after
|
33
|
+
end
|
34
|
+
|
35
|
+
it "patch has head location direction" do
|
36
|
+
diff = <<-EOF
|
37
|
+
<
|
38
|
+
+foo
|
39
|
+
+bar
|
40
|
+
EOF
|
41
|
+
|
42
|
+
before = <<-EOF
|
43
|
+
hello
|
44
|
+
world
|
45
|
+
EOF
|
46
|
+
|
47
|
+
after = <<-EOF
|
48
|
+
foo
|
49
|
+
bar
|
50
|
+
hello
|
51
|
+
world
|
52
|
+
EOF
|
53
|
+
|
54
|
+
hunk = Rpatch::PatchHunk.new('@@ description')
|
55
|
+
diff.split($/).each {|line| hunk.feed_line line.chomp}
|
56
|
+
|
57
|
+
hunk.match_after_patch(before.split($/)).should eq nil
|
58
|
+
hunk.match_before_patch(before.split($/)).should eq [0, 0]
|
59
|
+
result = hunk.patch(before.split($/))
|
60
|
+
(result * "\n" + "\n").should eq after
|
61
|
+
end
|
62
|
+
|
63
|
+
it "patch has tail location direction" do
|
64
|
+
diff = <<-EOF
|
65
|
+
>
|
66
|
+
+foo
|
67
|
+
+bar
|
68
|
+
EOF
|
69
|
+
|
70
|
+
before = <<-EOF
|
71
|
+
hello
|
72
|
+
world
|
73
|
+
EOF
|
74
|
+
|
75
|
+
after = <<-EOF
|
76
|
+
hello
|
77
|
+
world
|
78
|
+
foo
|
79
|
+
bar
|
80
|
+
EOF
|
81
|
+
|
82
|
+
hunk = Rpatch::PatchHunk.new('@@ description')
|
83
|
+
diff.split($/).each {|line| hunk.feed_line line.chomp}
|
84
|
+
|
85
|
+
hunk.match_after_patch(before.split($/)).should eq nil
|
86
|
+
hunk.match_before_patch(before.split($/)).should eq [2, 0]
|
87
|
+
result = hunk.patch(before.split($/))
|
88
|
+
(result * "\n" + "\n").should eq after
|
89
|
+
end
|
90
|
+
|
91
|
+
it "patch has head location direction (2)" do
|
92
|
+
diff = <<-EOF
|
93
|
+
<
|
94
|
+
hello
|
95
|
+
+foo
|
96
|
+
+bar
|
97
|
+
EOF
|
98
|
+
|
99
|
+
before = <<-EOF
|
100
|
+
hello
|
101
|
+
hello
|
102
|
+
EOF
|
103
|
+
|
104
|
+
after = <<-EOF
|
105
|
+
hello
|
106
|
+
foo
|
107
|
+
bar
|
108
|
+
hello
|
109
|
+
EOF
|
110
|
+
|
111
|
+
hunk = Rpatch::PatchHunk.new('@@ description')
|
112
|
+
diff.split($/).each {|line| hunk.feed_line line.chomp}
|
113
|
+
|
114
|
+
hunk.match_after_patch(before.split($/)).should eq nil
|
115
|
+
hunk.match_before_patch(before.split($/)).should eq [0, 1]
|
116
|
+
result = hunk.patch(before.split($/))
|
117
|
+
(result * "\n" + "\n").should eq after
|
118
|
+
end
|
119
|
+
|
120
|
+
it "patch has tail location direction (2)" do
|
121
|
+
diff = <<-EOF
|
122
|
+
>
|
123
|
+
hello
|
124
|
+
+foo
|
125
|
+
+bar
|
126
|
+
EOF
|
127
|
+
|
128
|
+
before = <<-EOF
|
129
|
+
hello
|
130
|
+
hello
|
131
|
+
EOF
|
132
|
+
|
133
|
+
after = <<-EOF
|
134
|
+
hello
|
135
|
+
hello
|
136
|
+
foo
|
137
|
+
bar
|
138
|
+
EOF
|
139
|
+
|
140
|
+
hunk = Rpatch::PatchHunk.new('@@ description')
|
141
|
+
diff.split($/).each {|line| hunk.feed_line line.chomp}
|
142
|
+
|
143
|
+
hunk.match_after_patch(before.split($/)).should eq nil
|
144
|
+
hunk.match_before_patch(before.split($/)).should eq [1, 1]
|
145
|
+
result = hunk.patch(before.split($/))
|
146
|
+
(result * "\n" + "\n").should eq after
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|