realityforge-braid 0.7.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.
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ *.gem
2
+ *.rbc
3
+ *.sw?
4
+ .DS_Store
5
+ .bundle
6
+ .idea
7
+ Gemfile.lock
8
+ coverage
9
+ nbproject
10
+ pkg
11
+ pkg/*
12
+ rdoc
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007-2010 Cristi Balan, Norbert Crombach
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # Braid
2
+
3
+ Braid is a simple tool to help track git and svn vendor branches in a git repository.
4
+
5
+ The project homepage is [here](http://github.com/evilchelu/braid/wikis/home).
6
+
7
+ ## Requirements
8
+
9
+ * git 1.6+ (and git-svn if you want to mirror svn repositories)
10
+ * main >= 4.2.0
11
+ * open4 >= 1.0.1 (unless using jruby)
12
+
13
+ ## Installing using rubygems - official releases
14
+
15
+ gem install braid
16
+
17
+ ## Installing from source
18
+
19
+ git clone git://github.com/evilchelu/braid.git
20
+ cd braid
21
+ bundle install
22
+ rake install # possibly requiring sudo
23
+
24
+ ## Quick usage - ruby project
25
+
26
+ Let's assume we're writing something like gitnub that needs grit in lib/grit. Initialize the repo (nothing braid related here):
27
+
28
+ git init gritty
29
+ cd gritty
30
+ touch README
31
+ git add README
32
+ git commit -m "initial commit"
33
+
34
+ Now let's vendor grit:
35
+
36
+ braid add git://github.com/mojombo/grit.git lib/grit
37
+
38
+ And you're done! Braid vendored grit into lib/grit. Feel free to inspect the changes with git log or git show.
39
+
40
+ If further down the line, you want to bring new changes from grit in your repository, just update the mirror:
41
+
42
+ braid update lib/grit
43
+
44
+ ## Quick usage - rails project
45
+
46
+ Let's assume you want to start a new rails app called shiny. Initialize the repo (nothing braid related here):
47
+
48
+ git init shiny
49
+ cd shiny
50
+ touch README
51
+ git add README
52
+ git commit -m "initial commit"
53
+
54
+ Vendor rails (this might take a while because the rails repo is huge!):
55
+
56
+ braid add git://github.com/rails/rails.git vendor/rails
57
+
58
+ Create your new rails app (nothing braid related here):
59
+
60
+ ruby vendor/rails/railties/bin/rails .
61
+ git add .
62
+ git commit -m "rails ."
63
+
64
+ Add any plugins you might need:
65
+
66
+ braid add git://github.com/thoughtbot/shoulda.git -p
67
+ braid add git://github.com/thoughtbot/factory_girl.git -p
68
+ braid add git://github.com/mbleigh/subdomain-fu.git -p
69
+
70
+ And you're done! Braid vendored rails and your plugins. Feel free to inspect the changes with git log or git show.
71
+
72
+ If further down the line, you want to bring new changes from rails in your repository, just update the mirror:
73
+
74
+ braid update vendor/rails
75
+
76
+ Or, if you want all mirrors updated:
77
+
78
+ braid update
79
+
80
+ ## More usage
81
+
82
+ Use the built in help system to find out about all commands and options:
83
+
84
+ braid help
85
+ braid help add # or braid add --help
86
+
87
+ You may also want to read [Usage and examples](http://github.com/evilchelu/braid/wikis/usage-and-examples).
88
+
89
+ ## Troubleshooting
90
+
91
+ Check [Troubleshooting](http://github.com/evilchelu/braid/wikis/troubleshooting) if you're having issues.
92
+
93
+ ## Contributing
94
+
95
+ We appreciate any patches, error reports and usage ideas you may have. Please submit a lighthouse ticket or start a thread on the mailing list.
96
+
97
+ Bugs and feature requests: [braid project on lighthouse](http://evilchelu.lighthouseapp.com/projects/10600-braid)
98
+
99
+ Discussions and community support: [braid-gem google group](http://groups.google.com/group/braid-gem)
100
+
101
+ ## Authors
102
+
103
+ * Cristi Balan (evilchelu)
104
+ * Norbert Crombach (norbert)
105
+
106
+ ## Contributors (alphabetically)
107
+
108
+ * Alan Harper
109
+ * Christoph Sturm
110
+ * Dennis Muhlestein
111
+ * Ferdinand Svehla
112
+ * Michael Klishin
113
+ * Roman Heinrich
114
+ * Travis Tilley
115
+ * Tyler Rick
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+
7
+ task :default => :test
8
+
9
+ def test_task(name, pattern)
10
+ Rake::TestTask.new(name) do |t|
11
+ ENV['TESTOPTS'] = '--runner=s'
12
+
13
+ t.libs << 'lib'
14
+ t.pattern = pattern
15
+ t.verbose = true
16
+ end
17
+ end
18
+
19
+ test_task(:test, "test/*_test.rb")
20
+ namespace(:test) { test_task(:integration, "test/integration/*_test.rb") }
data/bin/braid ADDED
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
4
+ require 'braid'
5
+
6
+ require 'rubygems'
7
+ require 'main'
8
+
9
+ Home = File.expand_path(ENV['HOME'] || '~')
10
+
11
+ # mostly blantantly stolen from ara's punch script
12
+ # main kicks ass!
13
+ Main {
14
+ description <<-TXT
15
+ braid is a simple tool to help track git or svn repositories inside a git repository.
16
+
17
+ Run 'braid commandname help' for more details.
18
+
19
+ All operations will be executed in the braid/track branch.
20
+ You can then merge back or cherry-pick changes.
21
+ TXT
22
+
23
+ mode(:add) {
24
+ description <<-TXT
25
+ Add a new mirror to be tracked.
26
+
27
+ * adds metadata about the mirror to .braids
28
+ * adds the git or git svn remotes to .git/config
29
+ * fetches and merges remote code into given directory
30
+
31
+ --type defaults:
32
+
33
+ * svn://path # => svn
34
+ * git://path # => git
35
+ * http://path/trunk # => svn
36
+ * http://path.git # => git
37
+
38
+ Name defaults:
39
+
40
+ * remote/path # => path
41
+ * remote/path/trunk # => path
42
+ * remote/path.git # => path
43
+ TXT
44
+
45
+ examples <<-TXT
46
+ . braid add svn://remote/path
47
+ . braid add svn://remote/path local/dir
48
+ . braid add git://remote/path local/dir
49
+ . braid add http://remote/path.git local/dir
50
+ . braid add http://remote/path --type git local/dir
51
+ . braid add svn://remote/path --branch notmaster
52
+ TXT
53
+
54
+ mixin :argument_url, :option_type, :optional_path, :option_branch, :option_rails_plugin, :option_revision, :option_full, :option_verbose
55
+
56
+ run {
57
+ Braid.verbose = verbose
58
+ Braid::Command.run(:add, url, {"type" => type, "path" => path, "branch" => branch, "rails_plugin" => rails_plugin, "revision" => revision, "full" => full})
59
+ }
60
+ }
61
+
62
+ mode(:update) {
63
+ description <<-TXT
64
+ Update a braid mirror.
65
+
66
+ * get new changes from remote
67
+ * always creates a merge commit
68
+ * updates metadata in .braids when revisions are changed
69
+
70
+ Defaults to updating all unlocked mirrors if none is specified.
71
+ TXT
72
+
73
+ examples <<-TXT
74
+ . braid update
75
+ . braid update local/dir
76
+ TXT
77
+
78
+ mixin :optional_path, :option_revision, :option_head, :option_verbose
79
+
80
+ run {
81
+ Braid.verbose = verbose
82
+ Braid::Command.run(:update, path, {"revision" => revision, "head" => head})
83
+ }
84
+ }
85
+
86
+ mode(:remove) {
87
+ description <<-TXT
88
+ Remove a mirror.
89
+
90
+ * removes metadata from .braids
91
+ * removes the local directory and commits the removal
92
+ * removes the git remote by default, --keep can be used to supress that
93
+ TXT
94
+
95
+ examples <<-TXT
96
+ . braid remove local/dir
97
+ TXT
98
+
99
+ mixin :argument_path, :option_verbose, :option_keep_remote
100
+
101
+ run {
102
+ options = {
103
+ :keep => keep
104
+ }
105
+ Braid.verbose = verbose
106
+ Braid::Command.run(:remove, path, options)
107
+ }
108
+ }
109
+
110
+ mode(:diff) {
111
+ description <<-TXT
112
+ Show diff of local changes to mirror.
113
+ TXT
114
+
115
+ mixin :argument_path, :option_verbose
116
+
117
+ run {
118
+ Braid::Command.run(:diff, path)
119
+ }
120
+ }
121
+
122
+ mode(:push) {
123
+ description <<-TXT
124
+ Push local mirror changes to remote.
125
+ TXT
126
+
127
+ mixin :argument_path, :option_verbose
128
+
129
+ run {
130
+ Braid.verbose = verbose
131
+ Braid::Command.run(:push, path)
132
+ }
133
+ }
134
+
135
+ mode(:setup) {
136
+ description <<-TXT
137
+ Set up git and git-svn remotes.
138
+ TXT
139
+
140
+ mixin :optional_path, :option_verbose, :option_force
141
+
142
+ run {
143
+ Braid.verbose = verbose
144
+ Braid.force = force
145
+ Braid::Command.run(:setup, path)
146
+ }
147
+ }
148
+
149
+ mode(:version) {
150
+ description 'Show braid version.'
151
+
152
+ run {
153
+ puts "braid #{Braid::VERSION}"
154
+ }
155
+ }
156
+
157
+ mode(:list) {
158
+ description 'Show all tracked mirrors (and if updates are available).'
159
+
160
+ mixin :option_verbose
161
+
162
+ run {
163
+ Braid.verbose = verbose
164
+ Braid::Command.run(:list)
165
+ }
166
+ }
167
+
168
+ mixin(:argument_path) {
169
+ argument(:path) {
170
+ attr
171
+ }
172
+ }
173
+
174
+ mixin(:optional_path) {
175
+ argument(:path) {
176
+ optional
177
+ attr
178
+ }
179
+ }
180
+
181
+ mixin(:argument_url) {
182
+ argument(:url) {
183
+ attr
184
+ }
185
+ }
186
+
187
+ mixin(:option_type) {
188
+ option(:type, :t) {
189
+ optional
190
+ argument :required
191
+ desc 'mirror type'
192
+ attr
193
+ }
194
+ }
195
+
196
+ mixin(:option_branch) {
197
+ option(:branch, :b) {
198
+ optional
199
+ argument :required
200
+ desc 'remote branch name'
201
+ attr
202
+ }
203
+ }
204
+
205
+ mixin(:option_rails_plugin) {
206
+ option(:rails_plugin, :p) {
207
+ optional
208
+ desc 'added mirror is a Rails plugin'
209
+ attr
210
+ }
211
+ }
212
+
213
+ mixin(:option_revision) {
214
+ option(:revision, :r) {
215
+ optional
216
+ argument :required
217
+ desc 'revision to track'
218
+ attr
219
+ }
220
+ }
221
+
222
+ mixin(:option_head) {
223
+ option(:head) {
224
+ optional
225
+ desc 'mirror head'
226
+ attr
227
+ }
228
+ }
229
+
230
+ mixin(:option_full) {
231
+ option(:full) {
232
+ optional
233
+ desc 'include mirror history' # FIXME
234
+ attr
235
+ }
236
+ }
237
+
238
+ mixin(:option_verbose) {
239
+ option(:verbose, :v) {
240
+ optional
241
+ desc 'log shell commands'
242
+ attr
243
+ }
244
+ }
245
+
246
+ mixin(:option_force) {
247
+ option(:force, :f) {
248
+ optional
249
+ desc 'force'
250
+ attr
251
+ }
252
+ }
253
+
254
+ mixin(:option_keep_remote) {
255
+ option(:keep) {
256
+ optional
257
+ desc 'do not remove the remote'
258
+ attr
259
+ }
260
+ }
261
+
262
+ run { help! }
263
+ }
data/braid.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'braid/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{realityforge-braid}
7
+ s.version = Braid::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+
10
+ s.authors = ["Cristi Balan", "Norbert Crombach"]
11
+ s.email = %q{evil@che.lu}
12
+
13
+ s.homepage = %q{http://evil.che.lu/projects/braid}
14
+ s.summary = %q{A simple tool for tracking vendor branches in git.}
15
+ s.description = %q{A simple tool for tracking vendor branches in git.}
16
+
17
+ s.rubyforge_project = %q{braid}
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
22
+ s.default_executable = %q{braid}
23
+ s.require_paths = ["lib"]
24
+
25
+ s.has_rdoc = false
26
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "braid", "--main"]
27
+
28
+ s.add_dependency(%q<main>, [">= 4.7.3"])
29
+ s.add_dependency(%q<open4>, [">= 1.0.1"]) unless defined?(JRUBY_VERSION)
30
+
31
+ s.add_development_dependency(%q<test-spec>, [">= 0.10.0"])
32
+ s.add_development_dependency(%q<mocha>, [">= 0.9.11"])
33
+ end
@@ -0,0 +1,136 @@
1
+ module Braid
2
+ class Command
3
+ class InvalidRevision < BraidError
4
+ end
5
+
6
+ extend Operations::VersionControl
7
+ include Operations::VersionControl
8
+
9
+ def self.run(command, *args)
10
+ verify_git_version!
11
+
12
+ klass = Commands.const_get(command.to_s.capitalize)
13
+ klass.new.run(*args)
14
+
15
+ rescue BraidError => error
16
+ case error
17
+ when Operations::ShellExecutionError
18
+ msg "Shell error: #{error.message}"
19
+ else
20
+ msg "Error: #{error.message}"
21
+ end
22
+ exit(1)
23
+ end
24
+
25
+ def self.msg(str)
26
+ puts "Braid: #{str}"
27
+ end
28
+
29
+ def msg(str)
30
+ self.class.msg(str)
31
+ end
32
+
33
+ def config
34
+ @config ||= load_and_migrate_config
35
+ end
36
+
37
+ def verbose?
38
+ Braid.verbose
39
+ end
40
+
41
+ def force?
42
+ Braid.force
43
+ end
44
+
45
+ private
46
+
47
+ def setup_remote(mirror)
48
+ Command.run(:setup, mirror.path)
49
+ end
50
+
51
+ def use_local_cache?
52
+ Braid.use_local_cache
53
+ end
54
+
55
+ def self.verify_git_version!
56
+ git.require_version!(REQUIRED_GIT_VERSION)
57
+ end
58
+
59
+ def bail_on_local_changes!
60
+ git.ensure_clean!
61
+ end
62
+
63
+ def with_reset_on_error
64
+ work_head = git.head
65
+
66
+ begin
67
+ yield
68
+ rescue => error
69
+ msg "Resetting to '#{work_head[0, 7]}'."
70
+ git.reset_hard(work_head)
71
+ raise error
72
+ end
73
+ end
74
+
75
+ def load_and_migrate_config
76
+ config = Config.new
77
+ unless config.valid?
78
+ msg "Configuration is outdated. Migrating."
79
+ bail_on_local_changes!
80
+ config.migrate!
81
+ git.commit("Upgrade .braids", "-- .braids")
82
+ end
83
+ config
84
+ end
85
+
86
+ def add_config_file
87
+ git.add(CONFIG_FILE)
88
+ end
89
+
90
+ def display_revision(mirror, revision = nil)
91
+ revision ||= mirror.revision
92
+ mirror.type == "svn" ? "r#{revision}" : "'#{revision[0, 7]}'"
93
+ end
94
+
95
+ def validate_new_revision(mirror, new_revision)
96
+ unless new_revision
97
+ unless mirror.type == "svn"
98
+ return git.rev_parse(mirror.remote)
99
+ else
100
+ return svn.head_revision(mirror.url)
101
+ end
102
+ end
103
+
104
+ unless mirror.type == "svn"
105
+ new_revision = git.rev_parse(new_revision)
106
+ else
107
+ new_revision = svn.clean_revision(new_revision)
108
+ end
109
+ old_revision = mirror.revision
110
+
111
+ if new_revision == old_revision
112
+ raise InvalidRevision, "mirror is already at requested revision"
113
+ end
114
+
115
+ if mirror.type == "svn"
116
+ if old_revision && new_revision < old_revision
117
+ raise InvalidRevision, "local revision is higher than request revision"
118
+ end
119
+
120
+ if svn.head_revision(mirror.url) < new_revision
121
+ raise InvalidRevision, "requested revision is higher than remote revision"
122
+ end
123
+ end
124
+
125
+ new_revision
126
+ end
127
+
128
+ def determine_target_revision(mirror, new_revision)
129
+ unless mirror.type == "svn"
130
+ git.rev_parse(new_revision)
131
+ else
132
+ git_svn.commit_hash(mirror.remote, new_revision)
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,40 @@
1
+ module Braid
2
+ module Commands
3
+ class Add < Command
4
+ def run(url, options = {})
5
+ bail_on_local_changes!
6
+
7
+ with_reset_on_error do
8
+ mirror = config.add_from_options(url, options)
9
+
10
+ branch_message = (mirror.type == "svn" || mirror.branch == "master") ? "" : " branch '#{mirror.branch}'"
11
+ revision_message = options["revision"] ? " at #{display_revision(mirror, options["revision"])}" : ""
12
+ msg "Adding #{mirror.type} mirror of '#{mirror.url}'#{branch_message}#{revision_message}."
13
+
14
+ # these commands are explained in the subtree merge guide
15
+ # http://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html
16
+
17
+ setup_remote(mirror)
18
+ mirror.fetch
19
+
20
+ new_revision = validate_new_revision(mirror, options["revision"])
21
+ target_revision = determine_target_revision(mirror, new_revision)
22
+
23
+ unless mirror.squashed?
24
+ git.merge_ours(target_revision)
25
+ end
26
+ git.read_tree_prefix(target_revision, mirror.path)
27
+
28
+ mirror.revision = new_revision
29
+ mirror.lock = new_revision if options["revision"]
30
+ config.update(mirror)
31
+ add_config_file
32
+
33
+ git.commit("Add mirror '#{mirror.path}' at #{display_revision(mirror)}")
34
+ msg "Added mirror at #{display_revision(mirror)}."
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ module Braid
2
+ module Commands
3
+ class Diff < Command
4
+ def run(path)
5
+ mirror = config.get!(path)
6
+ setup_remote(mirror)
7
+
8
+ diff = mirror.diff
9
+ puts diff unless diff.empty?
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,32 @@
1
+ module Braid
2
+ module Commands
3
+ class List < Command
4
+ def run(path = nil, options = {})
5
+ with_reset_on_error do
6
+ path ? list_one(path, options) : list_all(options)
7
+ end
8
+ end
9
+
10
+ protected
11
+ def list_all(options = {})
12
+ options.reject! { |k, v| %w(revision head).include?(k) }
13
+ print "\n"
14
+ msg "Listing all mirrors.\n=======================================================\n"
15
+ config.mirrors.each_with_index do |path, i|
16
+ mirror = config.get!(path)
17
+ print " #{i + 1}) #{path.to_s}"
18
+ print " [LOCKED]" if mirror.locked?
19
+ setup_remote(mirror)
20
+ msg "Fetching new commits for '#{mirror.path}'." if verbose?
21
+ mirror.fetch
22
+ new_revision = validate_new_revision(mirror, options["revision"])
23
+ target_revision = determine_target_revision(mirror, new_revision)
24
+ print " !!! UPDATE AVAILABLE !!!" if new_revision.to_s != mirror.base_revision.to_s
25
+ print "\n"
26
+ end
27
+ print "\n"
28
+ end
29
+
30
+ end
31
+ end
32
+ end