norbert-braid 0.4.9
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/LICENSE +20 -0
- data/README.rdoc +27 -0
- data/Rakefile +17 -0
- data/bin/braid +223 -0
- data/braid.gemspec +26 -0
- data/lib/braid/command.rb +119 -0
- data/lib/braid/commands/add.rb +44 -0
- data/lib/braid/commands/diff.rb +11 -0
- data/lib/braid/commands/remove.rb +23 -0
- data/lib/braid/commands/setup.rb +33 -0
- data/lib/braid/commands/update.rb +78 -0
- data/lib/braid/config.rb +101 -0
- data/lib/braid/mirror.rb +168 -0
- data/lib/braid/operations.rb +297 -0
- data/lib/braid.rb +23 -0
- data/test/braid_test.rb +7 -0
- data/test/config_test.rb +62 -0
- data/test/mirror_test.rb +94 -0
- data/test/operations_test.rb +69 -0
- data/test/test_helper.rb +15 -0
- metadata +95 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007-2008 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.rdoc
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
= braid
|
2
|
+
A simple tool for tracking vendor branches in git.
|
3
|
+
|
4
|
+
http://evil.che.lu/projects/braid/
|
5
|
+
|
6
|
+
== Requirements
|
7
|
+
|
8
|
+
You will need git 1.5.4.5 or higher to run this version.
|
9
|
+
|
10
|
+
== Installation
|
11
|
+
|
12
|
+
git clone git://github.com/evilchelu/braid.git
|
13
|
+
cd braid
|
14
|
+
gem build braid.gemspec
|
15
|
+
sudo gem install braid-x.y.z.gem
|
16
|
+
|
17
|
+
== Usage
|
18
|
+
|
19
|
+
braid help
|
20
|
+
braid help COMMANDNAME
|
21
|
+
|
22
|
+
For more usage examples and documentation check the project wiki at http://github.com/evilchelu/braid/wikis.
|
23
|
+
Also see the bug tracker at http://evilchelu.lighthouseapp.com/projects/10600-braid for current issues and future plans.
|
24
|
+
|
25
|
+
== Contributing
|
26
|
+
|
27
|
+
If you want to send a patch please fork the project on GitHub and send a pull request.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
task :default => :test
|
5
|
+
|
6
|
+
def test_task(name, pattern)
|
7
|
+
Rake::TestTask.new(name) do |t|
|
8
|
+
ENV['TESTOPTS'] = '--runner=s'
|
9
|
+
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = pattern
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
test_task(:test, "test/*_test.rb")
|
17
|
+
namespace(:test) { test_task(:integration, "test/integration/*_test.rb") }
|
data/bin/braid
ADDED
@@ -0,0 +1,223 @@
|
|
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 help commandname' 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
|
55
|
+
|
56
|
+
run {
|
57
|
+
Braid::Command.run(:add, url, { "type" => type, "path" => path, "branch" => branch, "rails_plugin" => rails_plugin, "revision" => revision, "full" => full })
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
mode(:update) {
|
62
|
+
description <<-TXT
|
63
|
+
Update a braid mirror.
|
64
|
+
|
65
|
+
* get new changes from remote
|
66
|
+
* always creates a merge commit
|
67
|
+
* updates metadata in .braids when revisions are changed
|
68
|
+
|
69
|
+
Defaults to updating all unlocked mirrors if none is specified.
|
70
|
+
TXT
|
71
|
+
|
72
|
+
examples <<-TXT
|
73
|
+
. braid update
|
74
|
+
. braid update local/dir
|
75
|
+
TXT
|
76
|
+
|
77
|
+
mixin :optional_path, :option_revision, :option_head, :option_safe
|
78
|
+
|
79
|
+
run {
|
80
|
+
Braid::Command.run(:update, path, { "revision" => revision, "head" => head , "safe" => safe })
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
mode(:remove) {
|
85
|
+
description <<-TXT
|
86
|
+
Remove a mirror.
|
87
|
+
|
88
|
+
* removes metadata from .braids
|
89
|
+
* removes the local directory and commits the removal
|
90
|
+
* does NOT remove the git and git svn remotes in case you still need them around
|
91
|
+
TXT
|
92
|
+
|
93
|
+
examples <<-TXT
|
94
|
+
. braid remove local/dir
|
95
|
+
TXT
|
96
|
+
|
97
|
+
mixin :argument_path
|
98
|
+
|
99
|
+
run {
|
100
|
+
Braid::Command.run(:remove, path)
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
mode(:setup) {
|
105
|
+
description <<-TXT
|
106
|
+
Set up git and git-svn remotes.
|
107
|
+
TXT
|
108
|
+
|
109
|
+
examples <<-TXT
|
110
|
+
. braid setup local/dir
|
111
|
+
TXT
|
112
|
+
|
113
|
+
mixin :optional_path
|
114
|
+
|
115
|
+
run {
|
116
|
+
Braid::Command.run(:setup, path)
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
mode(:diff) {
|
121
|
+
description <<-TXT
|
122
|
+
Show diff of local changes to mirror.
|
123
|
+
TXT
|
124
|
+
|
125
|
+
examples <<-TXT
|
126
|
+
. braid diff local/dir
|
127
|
+
TXT
|
128
|
+
|
129
|
+
mixin :argument_path
|
130
|
+
|
131
|
+
run {
|
132
|
+
Braid::Command.run(:diff, path)
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
mode(:version) {
|
137
|
+
description 'Show braid version.'
|
138
|
+
|
139
|
+
run {
|
140
|
+
puts "braid #{Braid::VERSION}"
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
mixin(:argument_path) {
|
145
|
+
argument(:path) {
|
146
|
+
attr
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
mixin(:optional_path) {
|
151
|
+
argument(:path) {
|
152
|
+
optional
|
153
|
+
attr
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
mixin(:argument_url) {
|
158
|
+
argument(:url) {
|
159
|
+
attr
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
mixin(:option_type) {
|
164
|
+
option(:type, :t) {
|
165
|
+
optional
|
166
|
+
argument :required
|
167
|
+
desc 'mirror type'
|
168
|
+
attr
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
mixin(:option_branch) {
|
173
|
+
option(:branch, :b) {
|
174
|
+
optional
|
175
|
+
argument :required
|
176
|
+
desc 'remote branch name'
|
177
|
+
attr
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
mixin(:option_rails_plugin) {
|
182
|
+
option(:rails_plugin, :p) {
|
183
|
+
optional
|
184
|
+
desc 'added mirror is a Rails plugin'
|
185
|
+
attr
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
mixin(:option_revision) {
|
190
|
+
option(:revision, :r) {
|
191
|
+
optional
|
192
|
+
argument :required
|
193
|
+
desc 'revision to track'
|
194
|
+
attr
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
mixin(:option_head) {
|
199
|
+
option(:head) {
|
200
|
+
optional
|
201
|
+
desc 'mirror head'
|
202
|
+
attr
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
mixin(:option_full) {
|
207
|
+
option(:full) {
|
208
|
+
optional
|
209
|
+
desc 'include mirror history' # FIXME
|
210
|
+
attr
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
mixin(:option_safe) {
|
215
|
+
option(:safe) {
|
216
|
+
optional
|
217
|
+
desc 'safe on merge errors'
|
218
|
+
attr
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
run { help! }
|
223
|
+
}
|
data/braid.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{braid}
|
3
|
+
s.version = "0.4.9"
|
4
|
+
|
5
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Cristi Balan", "Norbert Crombach"]
|
9
|
+
s.date = %q{2008-09-06}
|
10
|
+
s.default_executable = %q{braid}
|
11
|
+
s.description = %q{A simple tool for tracking vendor branches in git.}
|
12
|
+
s.email = %q{evil@che.lu}
|
13
|
+
s.executables = ["braid"]
|
14
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
15
|
+
s.files = ["LICENSE", "README.rdoc", "Rakefile", "braid.gemspec", "bin/braid", "lib/braid/command.rb", "lib/braid/commands/add.rb", "lib/braid/commands/diff.rb", "lib/braid/commands/remove.rb", "lib/braid/commands/setup.rb", "lib/braid/commands/update.rb", "lib/braid/config.rb", "lib/braid/mirror.rb", "lib/braid/operations.rb", "lib/braid.rb", "test/braid_test.rb", "test/config_test.rb", "test/mirror_test.rb", "test/operations_test.rb", "test/test_helper.rb"]
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.homepage = %q{http://evil.che.lu/projects/braid}
|
18
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "braid", "--main", "README.rdoc"]
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rubyforge_project = %q{braid}
|
21
|
+
s.rubygems_version = %q{1.1.0}
|
22
|
+
s.summary = %q{A simple tool for tracking vendor branches in git.}
|
23
|
+
|
24
|
+
s.add_dependency(%q<main>, [">= 2.8.0"])
|
25
|
+
s.add_dependency(%q<open4>, [">= 0.9.6"])
|
26
|
+
end
|
@@ -0,0 +1,119 @@
|
|
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 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
|
+
private
|
38
|
+
def self.verify_git_version!
|
39
|
+
git.require_version!(REQUIRED_GIT_VERSION)
|
40
|
+
end
|
41
|
+
|
42
|
+
def bail_on_local_changes!
|
43
|
+
git.ensure_clean!
|
44
|
+
end
|
45
|
+
|
46
|
+
def with_reset_on_error
|
47
|
+
work_head = git.head
|
48
|
+
|
49
|
+
begin
|
50
|
+
yield
|
51
|
+
rescue => error
|
52
|
+
msg "Resetting to '#{work_head[0, 7]}'."
|
53
|
+
git.reset_hard(work_head)
|
54
|
+
raise error
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def load_and_migrate_config
|
59
|
+
config = Config.new
|
60
|
+
unless config.valid?
|
61
|
+
msg "Configuration is outdated. Migrating."
|
62
|
+
bail_on_local_changes!
|
63
|
+
config.migrate!
|
64
|
+
git.commit("Upgrade .braids", "-- .braids")
|
65
|
+
end
|
66
|
+
config
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_config_file
|
70
|
+
git.add(CONFIG_FILE)
|
71
|
+
end
|
72
|
+
|
73
|
+
def display_revision(mirror, revision = nil)
|
74
|
+
revision ||= mirror.revision
|
75
|
+
mirror.type == "svn" ? "r#{revision}" : "'#{revision[0, 7]}'"
|
76
|
+
end
|
77
|
+
|
78
|
+
def validate_new_revision(mirror, new_revision)
|
79
|
+
unless new_revision
|
80
|
+
unless mirror.type == "svn"
|
81
|
+
return git.rev_parse(mirror.remote)
|
82
|
+
else
|
83
|
+
return svn.head_revision(mirror.url)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
unless mirror.type == "svn"
|
88
|
+
new_revision = git.rev_parse(new_revision)
|
89
|
+
else
|
90
|
+
new_revision = svn.clean_revision(new_revision)
|
91
|
+
end
|
92
|
+
old_revision = mirror.revision
|
93
|
+
|
94
|
+
if new_revision == old_revision
|
95
|
+
raise InvalidRevision, "mirror is already at requested revision"
|
96
|
+
end
|
97
|
+
|
98
|
+
if mirror.type == "svn"
|
99
|
+
if old_revision && new_revision < old_revision
|
100
|
+
raise InvalidRevision, "local revision is higher than request revision"
|
101
|
+
end
|
102
|
+
|
103
|
+
if svn.head_revision(mirror.url) < new_revision
|
104
|
+
raise InvalidRevision, "requested revision is higher than remote revision"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
new_revision
|
109
|
+
end
|
110
|
+
|
111
|
+
def determine_target_commit(mirror, new_revision)
|
112
|
+
unless mirror.type == "svn"
|
113
|
+
git.rev_parse(new_revision)
|
114
|
+
else
|
115
|
+
git_svn.commit_hash(mirror.remote, new_revision)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,44 @@
|
|
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)}" : ""
|
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_hash = determine_target_commit(mirror, new_revision)
|
22
|
+
|
23
|
+
unless mirror.squashed?
|
24
|
+
git.merge_ours(target_hash)
|
25
|
+
end
|
26
|
+
git.read_tree(target_hash, 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
|
+
commit_message = "Add mirror '#{mirror.path}/'#{revision_message}"
|
34
|
+
git.commit(commit_message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def setup_remote(mirror)
|
40
|
+
Command.run(:setup, mirror.path)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Braid
|
2
|
+
module Commands
|
3
|
+
class Remove < Command
|
4
|
+
def run(path)
|
5
|
+
mirror = config.get!(path)
|
6
|
+
|
7
|
+
bail_on_local_changes!
|
8
|
+
|
9
|
+
with_reset_on_error do
|
10
|
+
msg "Removing mirror from '#{mirror.path}/'."
|
11
|
+
|
12
|
+
git.rm_r(mirror.path)
|
13
|
+
|
14
|
+
config.remove(mirror)
|
15
|
+
add_config_file
|
16
|
+
|
17
|
+
commit_message = "Remove mirror '#{mirror.path}/'"
|
18
|
+
git.commit(commit_message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Braid
|
2
|
+
module Commands
|
3
|
+
class Setup < Command
|
4
|
+
def run(path = nil)
|
5
|
+
path ? setup_one(path) : setup_all
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
def setup_all
|
10
|
+
msg "Setting up all mirrors."
|
11
|
+
config.mirrors.each do |path|
|
12
|
+
setup_one(path)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup_one(path)
|
17
|
+
mirror = config.get!(path)
|
18
|
+
|
19
|
+
if git.remote_exists?(mirror.remote)
|
20
|
+
msg "Mirror '#{mirror.path}/' already has a remote. Skipping."
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
msg "Setting up remote for '#{mirror.path}/'."
|
25
|
+
unless mirror.type == "svn"
|
26
|
+
git.remote_add(mirror.remote, mirror.url, mirror.branch)
|
27
|
+
else
|
28
|
+
git_svn.init(mirror.remote, mirror.url)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Braid
|
2
|
+
module Commands
|
3
|
+
class Update < Command
|
4
|
+
def run(path, options = {})
|
5
|
+
bail_on_local_changes!
|
6
|
+
|
7
|
+
with_reset_on_error do
|
8
|
+
path ? update_one(path, options) : update_all(options)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
def update_all(options = {})
|
14
|
+
options.reject! { |k,v| %w(revision head).include?(k) }
|
15
|
+
msg "Updating all mirrors."
|
16
|
+
config.mirrors.each do |path|
|
17
|
+
update_one(path, options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_one(path, options = {})
|
22
|
+
mirror = config.get!(path)
|
23
|
+
|
24
|
+
# check options for lock modification
|
25
|
+
if mirror.locked?
|
26
|
+
if options["head"]
|
27
|
+
msg "Unlocking mirror '#{mirror.path}/'."
|
28
|
+
mirror.lock = nil
|
29
|
+
elsif !options["revision"]
|
30
|
+
msg "Mirror '#{mirror.path}/' is locked to #{display_revision(mirror, mirror.lock)}. Skipping."
|
31
|
+
return
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
mirror.fetch
|
36
|
+
|
37
|
+
new_revision = validate_new_revision(mirror, options["revision"])
|
38
|
+
target_hash = determine_target_commit(mirror, new_revision)
|
39
|
+
|
40
|
+
if mirror.merged?(target_hash)
|
41
|
+
msg "Mirror '#{mirror.path}/' is already up to date. Skipping."
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
diff = mirror.diff if mirror.squashed? # get diff before setting revision
|
46
|
+
|
47
|
+
mirror.revision = new_revision
|
48
|
+
mirror.lock = new_revision if options["revision"]
|
49
|
+
config.update(mirror)
|
50
|
+
|
51
|
+
msg "Updating mirror '#{mirror.path}/'."
|
52
|
+
if mirror.squashed?
|
53
|
+
git.rm_r(mirror.path)
|
54
|
+
git.read_tree(target_hash, mirror.path)
|
55
|
+
unless diff.empty?
|
56
|
+
git.apply(diff, *(options["safe"] ? ["--reject"] : []))
|
57
|
+
end
|
58
|
+
else
|
59
|
+
git.merge_subtree(target_hash)
|
60
|
+
end
|
61
|
+
|
62
|
+
add_config_file
|
63
|
+
|
64
|
+
revision_message = " to " + (options["revision"] ? display_revision(mirror) : "HEAD")
|
65
|
+
commit_message = "Update mirror '#{mirror.path}/'#{revision_message}"
|
66
|
+
git.commit(commit_message)
|
67
|
+
|
68
|
+
rescue Operations::ShellExecutionError => error
|
69
|
+
if options["safe"]
|
70
|
+
msg "Caught shell error. Breaking."
|
71
|
+
exit(0)
|
72
|
+
else
|
73
|
+
raise error
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|