submerge 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/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ == 0.1 / 2007-12-27
2
+
3
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,9 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/submerge
6
+ lib/contrib/revision.rb
7
+ lib/submerge.rb
8
+ lib/svn_helper.rb
9
+ test/test_submerge.rb
data/README.txt ADDED
@@ -0,0 +1,77 @@
1
+ submerge
2
+ by Aaron Suggs
3
+ http://ktheory.com/
4
+
5
+ == DESCRIPTION:
6
+
7
+ Submerge make it easy to perform common merge tasks when working with trunk
8
+ and branches in the subversion SCM.
9
+
10
+ Submerge requires that your present working directory is a subversion
11
+ checkout in order to compute the svn URL of your current checkout.
12
+
13
+ submerge assumes that your project follows the convention of keeping the
14
+ latest changes in
15
+ your-svn-project-url/trunk
16
+ and branches in
17
+ your-svn-project-url/branches/your-branch-name
18
+ and moreover that release branches are named like "RB-/\d+(\.\d+)*/";
19
+ e.g. the release 1.0 branch would have the URL
20
+ your-svn-project-url/branches/RB-1.0
21
+
22
+ == FEATURES/PROBLEMS:
23
+
24
+ == SYNOPSIS:
25
+
26
+ $ submerge [CHANGESET...] [-b BRANCH]
27
+
28
+ CHANGESET may either be a single number, like "2", or a range changesets,
29
+ like "M:N" where M and N are numbers. If no CHANGESET is specified, defaults
30
+ to a single number HEAD. If M or N is not specified in range form, they
31
+ default to HEAD.
32
+ So the following are equivalent:
33
+ submerge
34
+ submerge HEAD
35
+ and
36
+ submerge 2:
37
+ submerge 2:HEAD
38
+ and
39
+ submerge :999
40
+ submerge HEAD:999
41
+
42
+ If BRANCH is not set, defaults to:
43
+ * latest release branch if pwd is a trunk checkout
44
+ * trunk otherwise
45
+
46
+ The -u or --undor option may be used for in
47
+
48
+ == REQUIREMENTS:
49
+
50
+ == INSTALL:
51
+
52
+ gem install submerge
53
+
54
+ == LICENSE:
55
+
56
+ (The MIT License)
57
+
58
+ Copyright (c) 2007 FIX
59
+
60
+ Permission is hereby granted, free of charge, to any person obtaining
61
+ a copy of this software and associated documentation files (the
62
+ 'Software'), to deal in the Software without restriction, including
63
+ without limitation the rights to use, copy, modify, merge, publish,
64
+ distribute, sublicense, and/or sell copies of the Software, and to
65
+ permit persons to whom the Software is furnished to do so, subject to
66
+ the following conditions:
67
+
68
+ The above copyright notice and this permission notice shall be
69
+ included in all copies or substantial portions of the Software.
70
+
71
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
72
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
73
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
74
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
75
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
76
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
77
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ $:.unshift(File.dirname(__FILE__) + "/lib")
6
+ require 'submerge'
7
+
8
+ Hoe.new('submerge', Submerge::VERSION) do |p|
9
+ p.rubyforge_name = 'submerge'
10
+ # p.author = 'Aaron Suggs'
11
+ # p.email = 'aaron@ktheory.om'
12
+ # p.summary = 'A tool for helping merge changesets between branches in the Subversion SCM'
13
+ # p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
14
+ # p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
15
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
16
+ end
17
+
18
+ # vim: syntax=Ruby
data/bin/submerge ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ begin
3
+ require 'submerge'
4
+ rescue LoadError
5
+ require 'rubygems'
6
+ require 'submerge'
7
+ end
8
+ Submerge.new(ARGV).run
@@ -0,0 +1,85 @@
1
+ # Revision class
2
+ # Designed to function in version comparisons, where the
3
+ # version number matches /\d+(\.\d+)*/
4
+
5
+ # Author: Hugh Sasse, De Montfort University <hgs / dmu.ac.uk>
6
+
7
+ # Created: 06-OCT-2000
8
+ # Last Modified: 19-OCT-2005
9
+ # $Id: revision.rb,v 1.3 2000-10-09 10:40:39+01 hgs Exp hgs $
10
+
11
+ class RevisionComparisonError < RuntimeError; end
12
+
13
+ class Revision
14
+ include Comparable
15
+
16
+ DEBUG = false
17
+
18
+ attr :contents
19
+
20
+ def to_i
21
+ @contents.join('').to_i
22
+ end
23
+
24
+ def to_s
25
+ astring = @contents.collect { |j| j.to_s }.join(".")
26
+ end
27
+
28
+ # Convert the Major.Minor to float. MinorMinor version number
29
+ # is difficult to handle because it depends on the size of Minor
30
+ # to determine how far right to shift it. Bacwards
31
+ # compatibility would necessitate 1 decimal place per revision,
32
+ # but if Ruby reaches 1.10.1 this will break. Therefore float
33
+ # comparisons should be deprecated.
34
+ def to_f
35
+ (@contents[0].to_s + '.' + contents[1]..to_s).to_f
36
+ end
37
+
38
+ def [](i)
39
+ return @contents[i]
40
+ end
41
+
42
+ def <=>(x)
43
+ puts "Revision(#{self}).<=> called with (#{x})" if DEBUG
44
+ case x
45
+ when String
46
+ result = self <=> Revision.new(x)
47
+ when Float
48
+ f = self.to_f
49
+ puts "#{f} <=> #{x}" if DEBUG
50
+ result = self.to_f <=> x
51
+ when Revision
52
+ len = [@contents.size, x.contents.size].max
53
+ puts "len is #{len}" if DEBUG
54
+ result = 0
55
+ (0..(len-1)).each do |index|
56
+ puts "result is #{result}" if DEBUG
57
+ if result == 0
58
+ result = ((@contents[index] || 0) <=> (x.contents[index] || 0))
59
+ else
60
+ break
61
+ end
62
+ end
63
+ puts " finally result is #{result}" if DEBUG
64
+ result
65
+ else
66
+ raise RevisionComparisonError.new("self is #{self}, other is #{x}")
67
+ end
68
+ result
69
+ end
70
+
71
+ def initialize(thing)
72
+ if thing.class == Revision
73
+ @contents = thing.contents.dup
74
+ # dup so we get a new copy, not a pointer to it.
75
+ elsif thing.class == String
76
+ result = thing.split(".").collect {|j| j.to_i}
77
+ @contents = result
78
+ elsif thing.class == Float
79
+ @contents = thing.to_s.split(".").collect {|j| j.to_i}
80
+ else
81
+ raise "cannot initialise to #{thing}"
82
+ end
83
+ puts "initialize(#{thing}) => @contents is #{@contents}" if DEBUG
84
+ end
85
+ end
data/lib/submerge.rb ADDED
@@ -0,0 +1,157 @@
1
+ # == Author
2
+ # Aaron Suggs (aaron@zenbe.com)
3
+ #
4
+ # == Copyright
5
+ # Copyright (c) 2007 Zenbe.
6
+ require 'optparse'
7
+ require 'ostruct'
8
+ require 'rdoc/usage'
9
+
10
+ #$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
11
+ begin
12
+ require 'contrib/revision'
13
+ require 'svn_helper'
14
+ rescue
15
+
16
+ require 'rubygems'
17
+ gem 'submerge'
18
+ end
19
+
20
+ class Submerge
21
+ VERSION = '0.1'
22
+
23
+ attr_reader :options
24
+
25
+ def initialize(args)
26
+ # Set default options
27
+ @options = OpenStruct.new
28
+ @options.quiet = false
29
+ @options.verbose = false
30
+
31
+ # Parse options
32
+ opts = OptionParser.new
33
+ opts.on('-v', '--version') { output_version; exit 0 }
34
+ opts.on('-h', '--help', '-?') { output_help; exit 0 }
35
+ opts.on('-V', '--verbose') { @options.verbose = true }
36
+ opts.on('-q', '--quiet') { @options.quiet = true }
37
+ opts.on('-u', '--undo') { @options.undo = true}
38
+ opts.on("-b", "--branch BRANCH", "merge from branch BRANCH") {|branch| @branch = branch}
39
+ opts.parse!(args)
40
+
41
+ begin
42
+ @svn = SvnHelper.new
43
+ rescue => e
44
+ puts e.message
45
+ exit 1
46
+ end
47
+
48
+ @changesets = opts.default_argv
49
+ if @changesets.empty?
50
+ puts "No changesets specified, using HEAD" if @options.verbose
51
+ @changesets << 'HEAD'
52
+ end
53
+ end
54
+
55
+ def run
56
+ parse_changesets
57
+
58
+ @changesets.each do |changeset|
59
+ cmd = "svn merge -r#{changeset} #{source_url}"
60
+ puts cmd unless @options.quiet
61
+ system(cmd)
62
+ end
63
+ end
64
+
65
+ def source_url
66
+ @source_url ||= compute_source_url
67
+ end
68
+
69
+ def compute_source_url
70
+ # Compute the source_url from which to merge
71
+ if @branch
72
+ unless @svn.valid_branch?(@branch)
73
+ puts "Invalid branch #{@branch}"
74
+ exit 1
75
+ end
76
+ url = @svn.branch_url(@branch)
77
+ else
78
+ url = @svn.trunk? ? @svn.latest_release_branch_url : @svn.trunk_url
79
+ end
80
+ puts "Merging from #{url}" unless @options.quiet
81
+ url
82
+ end
83
+
84
+ # Convert all changesets to ranges by merging from prevision changeset.
85
+ # E.g.,
86
+ # "5" => "4:5";
87
+ # "5:" => "5:HEAD"
88
+ def parse_changesets
89
+ @changesets.map! do |changeset|
90
+ if changeset.include?(':')
91
+ # Changeset range
92
+ s,e = changeset.split(':')
93
+ [s,e].each{|rev| rev = (rev.to_i == 0) ? @svn.head_revision : rev}
94
+ "#{s}:#{e}"
95
+ else
96
+ # Single changeset
97
+ rev = (changeset.to_i == 0) ? @svn.head_revision.to_i : changeset.to_i
98
+ @options.undo ? "#{rev}:#{rev-1}" : "#{rev-1}:#{rev}"
99
+ end
100
+ end
101
+ end
102
+
103
+ protected
104
+
105
+ def output_help
106
+ output_version
107
+
108
+ puts %Q{
109
+ USAGE:
110
+ $ submerge [CHANGESET...] [-b BRANCH]
111
+
112
+ CHANGESET may either be a single number, like "2", or a range changesets,
113
+ like "M:N" where M and N are numbers. If no CHANGESET is specified, defaults
114
+ to a single number HEAD. If M or N is not specified in range form, they
115
+ default to HEAD.
116
+ So the following are equivalent:
117
+ submerge
118
+ submerge HEAD
119
+ and
120
+ submerge 2:
121
+ submerge 2:HEAD
122
+ and
123
+ submerge :999
124
+ submerge HEAD:999
125
+
126
+ If BRANCH is not set, defaults to:
127
+ * latest release branch if pwd is a trunk checkout
128
+ * trunk otherwise
129
+
130
+ OPTIONS:
131
+ -h, --help Display help message
132
+ -b, --branch Specify a branch from which to merge
133
+ -q, --quiet Silence output
134
+ -u, --undo Invert merge order for single
135
+
136
+ EXAMPLES:
137
+ If your pwd is a trunk checkout:
138
+ The following command would merge the difference from changeset 999
139
+ from the latest release branch to your pwd:
140
+ submerge 999
141
+ This is equivalent to running
142
+ svn merge -r998:999 your-svn-project-url/branches/latest-release-branch
143
+ The following merges changeset 999 from my-branch:
144
+ submerge 999 -b my-branch
145
+ submerge 2
146
+ Other examples:
147
+ submerge 2:HEAD
148
+ submerge 2 3 100
149
+ submerge 2 -b BRANCH
150
+ }
151
+ exit
152
+ end
153
+
154
+ def output_version
155
+ puts "#{File.basename(__FILE__, '.rb')} version #{VERSION}"
156
+ end
157
+ end
data/lib/svn_helper.rb ADDED
@@ -0,0 +1,71 @@
1
+ # Worlds dumbest svn wrapper
2
+ class SvnNotFound < Exception; end
3
+ class PwdNotSvn < Exception; end
4
+ class UnrecognizedSvnURL < Exception; end
5
+
6
+
7
+ class SvnHelper
8
+ TRUNK_REGEXP = /\/trunk$/ # matches a trunk checkout
9
+ BRANCH_REGEXP = /\/branches\/\S+$/ # matches a branch checkout
10
+ RELEASE_BRANCH_REGEXP = /^RB-([0-9.]+)/ # matches release branch names
11
+
12
+ attr_reader :url
13
+
14
+ def initialize
15
+ begin
16
+ @svn_path = `which svn`
17
+ raise SvnNotFound, "svn not found in path" if @svn_path.empty?
18
+ svn_info = `svn info`
19
+ raise PwdNotSvn, "Current directory does not appear to be under SVN" unless $? == 0
20
+ svn_info.detect{|line| line =~ /^URL: (.*)$/}
21
+ @url = $1 # The current url
22
+ raise UnrecognizedSvnUrl, "SVN url is neither trunk nor a branch: #{@url}" unless trunk? || branch?
23
+ end
24
+ end
25
+
26
+ # Is the current directory a trunk checkout?
27
+ def trunk?
28
+ @url =~ TRUNK_REGEXP
29
+ end
30
+
31
+ # Is the current directory a branch checkout?
32
+ def branch?
33
+ @url =~ BRANCH_REGEXP
34
+ end
35
+
36
+ def base_url
37
+ @base_url ||= @url.gsub(trunk? ? TRUNK_REGEXP : BRANCH_REGEXP, '')
38
+ end
39
+
40
+ def branches
41
+ @branches ||= `svn ls #{base_url}/branches`.split("\n").map{|name| name.sub(/\/$/, '')}
42
+ end
43
+
44
+ def valid_branch?(branch)
45
+ branches.include? branch
46
+ end
47
+
48
+ def latest_release_branch
49
+ begin
50
+ @latest_release ||= branches.inject(Revision.new('0')){|rev, branch| branch =~ RELEASE_BRANCH_REGEXP ? [rev, Revision.new($1)].max : rev}
51
+ raise LatestReleaseBranchNotFound, "could not find a latest release branch\ntry specifying a source with '-b BRANCH' instead" if @latest_release == Revision.new('0')
52
+ @latest_release_branch ||= "RB-#{@latest_release}"
53
+ end
54
+ end
55
+
56
+ def head_revision
57
+ # TODO: there must be a better way to compute this
58
+ @head_revision ||= `svn log --limit 1 -q`.split[1].sub(/^r/, '')
59
+ end
60
+ def trunk_url
61
+ "#{base_url}/trunk"
62
+ end
63
+
64
+ def branch_url(branch)
65
+ "#{base_url}/branches/#{branch}"
66
+ end
67
+
68
+ def latest_release_branch_url
69
+ branch_url(latest_release_branch)
70
+ end
71
+ end
File without changes
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: submerge
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2007-12-27 00:00:00 -05:00
8
+ summary: The author was too lazy to write a summary
9
+ require_paths:
10
+ - lib
11
+ email: ryand-ruby@zenspider.com
12
+ homepage: http://www.zenspider.com/ZSS/Products/submerge/
13
+ rubyforge_project: submerge
14
+ description: The author was too lazy to write a description
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Ryan Davis
31
+ files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - Rakefile
36
+ - bin/submerge
37
+ - lib/contrib/revision.rb
38
+ - lib/submerge.rb
39
+ - lib/svn_helper.rb
40
+ - test/test_submerge.rb
41
+ test_files:
42
+ - test/test_submerge.rb
43
+ rdoc_options:
44
+ - --main
45
+ - README.txt
46
+ extra_rdoc_files:
47
+ - History.txt
48
+ - Manifest.txt
49
+ - README.txt
50
+ executables:
51
+ - submerge
52
+ extensions: []
53
+
54
+ requirements: []
55
+
56
+ dependencies:
57
+ - !ruby/object:Gem::Dependency
58
+ name: hoe
59
+ version_requirement:
60
+ version_requirements: !ruby/object:Gem::Version::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.4.0
65
+ version: