rpatch 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|