hg-port 0.0.0 → 0.0.1
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.
- data/bin/hg-port +66 -76
- data/lib/hg-port.rb +12 -0
- data/lib/hg-port/gem_info.rb +12 -0
- data/lib/hg-port/option_parser_with_required_args.rb +48 -0
- data/lib/hg-port/version.rb +54 -0
- data/lib/hg-port/version_template.rb +29 -0
- metadata +7 -2
data/bin/hg-port
CHANGED
@@ -1,12 +1,54 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'pathname'
|
3
|
+
require 'yaml'
|
3
4
|
require 'tempfile'
|
4
|
-
|
5
5
|
THIS_PATH = Pathname.new(__FILE__).realpath
|
6
6
|
THIS_DIR = THIS_PATH.dirname
|
7
7
|
THIS_BASE_NAME = THIS_PATH.basename
|
8
|
+
LIB_DIR = File.join(THIS_DIR, '..', 'lib', 'hg-port')
|
9
|
+
require File.join(LIB_DIR, 'gem_info')
|
10
|
+
require File.join(LIB_DIR, 'option_parser_with_required_args')
|
11
|
+
require File.join(LIB_DIR, 'version')
|
12
|
+
require File.join(LIB_DIR, 'version_template')
|
8
13
|
|
9
14
|
module Helper
|
15
|
+
def self.option_parser
|
16
|
+
@option_parser ||= OptionParserWithRequiredArgs.new do |p|
|
17
|
+
p.banner = "Usage: #{THIS_BASE_NAME} [options]"
|
18
|
+
|
19
|
+
p.on_required(:merge_version, '--merge-version MERGE-VERSION', 'Merge version at which forward port will begin') do |options, value|
|
20
|
+
options.merge_version = value
|
21
|
+
end
|
22
|
+
|
23
|
+
p.on_tail '-h', '--help', 'Show help' do
|
24
|
+
puts p
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
p.on_tail '--version', 'Show version' do
|
29
|
+
puts HGPort::GemInfo.version_string
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.read_config
|
36
|
+
config_file_name = nil
|
37
|
+
[
|
38
|
+
`hg root`.chomp,
|
39
|
+
ENV['HOME']
|
40
|
+
].each do |path|
|
41
|
+
temp = File.join(path, '.hgportrc')
|
42
|
+
if File.exist?(temp)
|
43
|
+
config_file_name = temp
|
44
|
+
break
|
45
|
+
end
|
46
|
+
end
|
47
|
+
raise RuntimeError.new('No configuration file found') unless config_file_name
|
48
|
+
|
49
|
+
YAML.load(File.open(config_file_name))
|
50
|
+
end
|
51
|
+
|
10
52
|
def self.fail(message, lines)
|
11
53
|
display_output(lines)
|
12
54
|
raise RuntimeError.new(message)
|
@@ -27,7 +69,7 @@ Switches:
|
|
27
69
|
--merge-version <version-branch>
|
28
70
|
|
29
71
|
Available versions:
|
30
|
-
#{versions.collect { |version| " #{version}" }.join("\n")}
|
72
|
+
#{versions.reverse.collect { |version| " #{version}" }.join("\n")}
|
31
73
|
|
32
74
|
EOS
|
33
75
|
end
|
@@ -62,74 +104,8 @@ module HGHelper
|
|
62
104
|
end
|
63
105
|
end
|
64
106
|
|
65
|
-
|
66
|
-
|
67
|
-
include Comparable
|
68
|
-
|
69
|
-
attr_reader :major, :minor
|
70
|
-
|
71
|
-
def self.parse(str)
|
72
|
-
return nil if str !~ /^v([0-9]+)\.([0-9]+)$/
|
73
|
-
new(Integer($1), Integer($2))
|
74
|
-
end
|
75
|
-
|
76
|
-
def <=>(other)
|
77
|
-
return 1 if other.nil?
|
78
|
-
|
79
|
-
delta = major - other.major
|
80
|
-
return 1 if delta > 0
|
81
|
-
return -1 if delta < 0
|
82
|
-
|
83
|
-
delta = minor - other.minor
|
84
|
-
return 1 if delta > 0
|
85
|
-
return -1 if delta < 0
|
86
|
-
0
|
87
|
-
end
|
88
|
-
|
89
|
-
def to_s
|
90
|
-
"v#{major}.#{minor}"
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def initialize(major, minor)
|
96
|
-
@major = major
|
97
|
-
@minor = minor
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
class Options
|
102
|
-
attr_reader :merge_version
|
103
|
-
|
104
|
-
def self.parse(args, versions)
|
105
|
-
merge_version = nil
|
106
|
-
while arg = args.shift
|
107
|
-
case arg
|
108
|
-
when '--merge-version' then
|
109
|
-
temp = args.shift or raise RuntimeError.new('Value required for --merge-version')
|
110
|
-
merge_version = Version.parse(temp) or raise RuntimeError.new("Invalid value \"#{temp}\" for --merge-version")
|
111
|
-
else
|
112
|
-
raise RuntimeError.new("Unsupported switch \"#{arg}\"")
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
if !merge_version || !versions.include?(merge_version)
|
117
|
-
Helper.display_usage(versions)
|
118
|
-
return nil
|
119
|
-
end
|
120
|
-
|
121
|
-
new(merge_version)
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
def initialize(merge_version)
|
127
|
-
@merge_version = merge_version
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def get_versions(branches)
|
132
|
-
branches.collect { |branch| Version.parse(branch)}.compact.sort
|
107
|
+
def get_versions(version_template, branches)
|
108
|
+
branches.collect { |branch| HGPort::Version.parse(version_template, branch)}.compact.sort
|
133
109
|
end
|
134
110
|
|
135
111
|
def forward_port(dir, merge_version, version)
|
@@ -138,7 +114,6 @@ def forward_port(dir, merge_version, version)
|
|
138
114
|
|
139
115
|
# Build commit message from preview
|
140
116
|
status, lines = HGHelper.run_hg(dir, "hg merge --preview #{merge_version}")
|
141
|
-
puts "LINES: #{lines.inspect}"
|
142
117
|
commit_message = <<-EOS
|
143
118
|
Automatic forward port from #{merge_version} to #{version}
|
144
119
|
|
@@ -188,15 +163,30 @@ end
|
|
188
163
|
|
189
164
|
dir = '.'
|
190
165
|
|
191
|
-
|
192
|
-
|
193
|
-
|
166
|
+
config = Helper.read_config
|
167
|
+
raise RuntimeError.new('No version template specified') unless config.include?('version_template')
|
168
|
+
|
169
|
+
version_template = HGPort::VersionTemplate.new(config['version_template'])
|
170
|
+
branches = HGHelper.get_branches(dir)
|
171
|
+
versions = get_versions(version_template, branches)
|
172
|
+
|
173
|
+
options = nil
|
174
|
+
begin
|
175
|
+
options, free_args = Helper.option_parser.run(ARGV)
|
176
|
+
rescue OptionParserWithRequiredArgs::RunError => e
|
177
|
+
$stderr.puts e.message
|
178
|
+
exit 1
|
179
|
+
end
|
180
|
+
|
181
|
+
exit 0 if ENV.include?('HG_PORT_TEST')
|
194
182
|
|
195
|
-
|
183
|
+
merge_version = HGPort::Version.parse(version_template, options.merge_version) or raise RuntimeError.new("Invalid merge version \"#{options.merge_version}\"")
|
184
|
+
current_branch_version = HGPort::Version.parse(version_template, HGHelper.current_branch(dir))
|
185
|
+
unless current_branch_version && merge_version == current_branch_version
|
196
186
|
raise RuntimeError.new("Check out merge version \"#{options.merge_version}\" before attempting a forward port")
|
197
187
|
end
|
198
188
|
|
199
|
-
merge_and_later_versions = versions.select { |version| version >=
|
189
|
+
merge_and_later_versions = versions.select { |version| version >= merge_version }
|
200
190
|
merge_and_later_versions.each_with_index do |version, index|
|
201
191
|
next if index == 0
|
202
192
|
unless forward_port(dir, merge_and_later_versions[index - 1], version)
|
data/lib/hg-port.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
class OptionParserWithRequiredArgs < OptionParser
|
5
|
+
class RunError < Exception; end
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@required_arg_names = []
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def on_required(arg_sym, *args, &block)
|
13
|
+
on *args, &block
|
14
|
+
@required_arg_names << arg_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def on(*args, &block)
|
18
|
+
super *args do |value|
|
19
|
+
block.call(@options, value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_tail(*args, &block)
|
24
|
+
super *args do
|
25
|
+
block.call(@options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def run(args)
|
30
|
+
@options = OpenStruct.new
|
31
|
+
cloned_args = args.clone
|
32
|
+
begin
|
33
|
+
parse!(cloned_args)
|
34
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
|
35
|
+
message = $!.to_s + "\n\n" + self.to_s
|
36
|
+
raise RunError.new(message)
|
37
|
+
end
|
38
|
+
|
39
|
+
missing_arg_names = @required_arg_names.select { |arg_name| @options.send(arg_name).nil? }
|
40
|
+
if !missing_arg_names.empty?
|
41
|
+
message = "missing required option: #{missing_arg_names.join(', ')}\n\n" + self.to_s
|
42
|
+
raise RunError.new(message)
|
43
|
+
end
|
44
|
+
|
45
|
+
[@options, cloned_args]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module HGPort
|
2
|
+
class Version
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
attr_reader :major, :minor, :patch
|
6
|
+
|
7
|
+
def self.parse(template, str)
|
8
|
+
values = template.parse(str)
|
9
|
+
return nil if values.nil?
|
10
|
+
major = values[:major]
|
11
|
+
minor = values[:minor]
|
12
|
+
patch = values[:patch]
|
13
|
+
return nil if major.nil? || minor.nil? || patch.nil?
|
14
|
+
|
15
|
+
new(template, major, minor, patch)
|
16
|
+
end
|
17
|
+
|
18
|
+
def <=>(other)
|
19
|
+
return 1 if other.nil?
|
20
|
+
|
21
|
+
delta = major - other.major
|
22
|
+
return 1 if delta > 0
|
23
|
+
return -1 if delta < 0
|
24
|
+
|
25
|
+
delta = minor - other.minor
|
26
|
+
return 1 if delta > 0
|
27
|
+
return -1 if delta < 0
|
28
|
+
|
29
|
+
delta = patch - other.patch
|
30
|
+
return 1 if delta > 0
|
31
|
+
return -1 if delta < 0
|
32
|
+
|
33
|
+
0
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
@template.expand(
|
38
|
+
:major => major,
|
39
|
+
:minor => minor,
|
40
|
+
:patch => patch
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def initialize(template, major, minor, patch)
|
47
|
+
@template = template
|
48
|
+
@major = major
|
49
|
+
@minor = minor
|
50
|
+
@patch = patch
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module HGPort
|
2
|
+
class VersionTemplate
|
3
|
+
def initialize(template_str)
|
4
|
+
@template_str = template_str
|
5
|
+
|
6
|
+
@keys = []
|
7
|
+
pattern = Regexp.escape(@template_str).gsub(/(:\w+)/) do |colon_key|
|
8
|
+
key = colon_key[1..-1]
|
9
|
+
@keys << key.to_sym
|
10
|
+
"(?<#{key}>[0-9]+)"
|
11
|
+
end
|
12
|
+
|
13
|
+
@regexp = Regexp.new("^#{pattern}$")
|
14
|
+
end
|
15
|
+
|
16
|
+
def expand(values)
|
17
|
+
@template_str.gsub(/(:\w+)/) do |colon_key|
|
18
|
+
key_sym = colon_key[1..-1].to_sym
|
19
|
+
values[key_sym] || $1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse(str)
|
24
|
+
match = @regexp.match(str)
|
25
|
+
match ? @keys.inject({}) { |memo, key| memo[key] = Integer(match[key]); memo } : nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hg-port
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-26 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Script to automate forward porting in Mercurial
|
15
15
|
email: rcook@rcook.org
|
@@ -19,6 +19,11 @@ extensions: []
|
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
21
|
- MIT-LICENSE.txt
|
22
|
+
- lib/hg-port/option_parser_with_required_args.rb
|
23
|
+
- lib/hg-port/gem_info.rb
|
24
|
+
- lib/hg-port/version_template.rb
|
25
|
+
- lib/hg-port/version.rb
|
26
|
+
- lib/hg-port.rb
|
22
27
|
- bin/hg-port
|
23
28
|
homepage: https://bitbucket.org/rcook/hg-port
|
24
29
|
licenses:
|