evilchelu-braid 0.3.5
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 +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +33 -0
- data/README.txt +49 -0
- data/Rakefile +4 -0
- data/bin/braid +218 -0
- data/braid.gemspec +26 -0
- data/config/hoe.rb +68 -0
- data/config/requirements.rb +17 -0
- data/lib/braid/command.rb +53 -0
- data/lib/braid/commands/add.rb +53 -0
- data/lib/braid/commands/diff.rb +10 -0
- data/lib/braid/commands/remove.rb +25 -0
- data/lib/braid/commands/setup.rb +40 -0
- data/lib/braid/commands/update.rb +77 -0
- data/lib/braid/config.rb +148 -0
- data/lib/braid/exceptions.rb +31 -0
- data/lib/braid/operations.rb +266 -0
- data/lib/braid/version.rb +9 -0
- data/lib/braid.rb +27 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/setup.rb +1585 -0
- data/spec/braid_spec.rb +7 -0
- data/spec/config_spec.rb +117 -0
- data/spec/operations_spec.rb +21 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +11 -0
- data/tasks/deployment.rake +27 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +32 -0
- data/tasks/website.rake +9 -0
- metadata +108 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
module Braid
|
2
|
+
class Command
|
3
|
+
include Operations::Mirror
|
4
|
+
include Operations::Helpers
|
5
|
+
|
6
|
+
def self.run(command, *args)
|
7
|
+
klass = Braid::Commands.const_get(command.to_s.capitalize)
|
8
|
+
klass.new.run(*args)
|
9
|
+
rescue => e
|
10
|
+
# FIXME
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.msg(str)
|
14
|
+
puts str
|
15
|
+
end
|
16
|
+
|
17
|
+
def config
|
18
|
+
@config ||= Braid::Config.new
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def msg(str)
|
23
|
+
self.class.msg(str)
|
24
|
+
end
|
25
|
+
|
26
|
+
def in_work_branch
|
27
|
+
# make sure there is a git repository
|
28
|
+
begin
|
29
|
+
old_branch = get_current_branch
|
30
|
+
rescue => e
|
31
|
+
msg "Error occured: #{e.message}"
|
32
|
+
raise e
|
33
|
+
end
|
34
|
+
|
35
|
+
create_work_branch
|
36
|
+
work_head = get_work_head
|
37
|
+
|
38
|
+
begin
|
39
|
+
invoke(:git_checkout, WORK_BRANCH)
|
40
|
+
yield
|
41
|
+
rescue => e
|
42
|
+
msg "Error occured: #{e.message}"
|
43
|
+
if get_current_branch == WORK_BRANCH
|
44
|
+
msg "Resetting '#{WORK_BRANCH}' to '#{work_head}'."
|
45
|
+
invoke(:git_reset_hard, work_head)
|
46
|
+
end
|
47
|
+
raise e
|
48
|
+
ensure
|
49
|
+
invoke(:git_checkout, old_branch)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Braid
|
2
|
+
module Commands
|
3
|
+
class Add < Command
|
4
|
+
def run(remote, options = {})
|
5
|
+
in_work_branch do
|
6
|
+
mirror, params = config.add_from_options(remote, options)
|
7
|
+
local_branch = get_local_branch_name(mirror, params)
|
8
|
+
|
9
|
+
config.update(mirror, { "local_branch" => local_branch })
|
10
|
+
params["local_branch"] = local_branch # TODO check
|
11
|
+
|
12
|
+
msg "Adding #{params["type"]} mirror of '#{params["remote"]}'" + (params["type"] == "git" ? ", branch '#{params["branch"]}'" : "") + "."
|
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
|
+
fetch_remote(params["type"], local_branch)
|
19
|
+
|
20
|
+
validate_revision_option(params, options)
|
21
|
+
target = determine_target_commit(params, options)
|
22
|
+
|
23
|
+
msg "Merging code into '#{mirror}/'."
|
24
|
+
|
25
|
+
unless params["squash"]
|
26
|
+
invoke(:git_merge_ours, target)
|
27
|
+
end
|
28
|
+
invoke(:git_read_tree, target, mirror)
|
29
|
+
|
30
|
+
config.update(mirror, { "revision" => options["revision"] })
|
31
|
+
add_config_file
|
32
|
+
|
33
|
+
revision_message = options["revision"] ? " at #{display_revision(params["type"], options["revision"])}" : ""
|
34
|
+
commit_message = "Add mirror '#{mirror}/'#{revision_message}."
|
35
|
+
invoke(:git_commit, commit_message)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
def setup_remote(mirror)
|
41
|
+
Braid::Command.run(:setup, mirror)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def get_local_branch_name(mirror, params)
|
46
|
+
res = "braid/#{params["type"]}/#{mirror}"
|
47
|
+
res << "/#{params["branch"]}" if params["type"] == "git"
|
48
|
+
res.gsub!("_", '-') # stupid git svn changes all _ to ., weird
|
49
|
+
res
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Braid
|
2
|
+
module Commands
|
3
|
+
class Remove < Command
|
4
|
+
def run(mirror)
|
5
|
+
in_work_branch do
|
6
|
+
params = config.get(mirror)
|
7
|
+
unless params
|
8
|
+
msg "Mirror '#{mirror}/' does not exist."
|
9
|
+
return
|
10
|
+
end
|
11
|
+
|
12
|
+
msg "Removing #{params["type"]} mirror from '#{mirror}/'."
|
13
|
+
|
14
|
+
invoke(:git_rm_r, mirror)
|
15
|
+
|
16
|
+
config.remove(mirror)
|
17
|
+
add_config_file
|
18
|
+
|
19
|
+
commit_message = "Remove mirror '#{mirror}/'."
|
20
|
+
invoke(:git_commit, commit_message)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Braid
|
2
|
+
module Commands
|
3
|
+
class Setup < Command
|
4
|
+
def run(mirror)
|
5
|
+
in_work_branch do
|
6
|
+
mirror ? setup_one(mirror) : setup_all
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
def setup_all
|
12
|
+
msg "Setting up all mirrors."
|
13
|
+
config.mirrors.each do |mirror|
|
14
|
+
setup_one(mirror)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def setup_one(mirror)
|
19
|
+
params = config.get(mirror)
|
20
|
+
unless params
|
21
|
+
msg "Mirror '#{mirror}/' does not exist. Skipping."
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
if find_remote(params["local_branch"])
|
26
|
+
msg "Mirror '#{mirror}/' already has a remote. Skipping."
|
27
|
+
return
|
28
|
+
end
|
29
|
+
|
30
|
+
msg "Setting up remote for '#{mirror}/'."
|
31
|
+
case params["type"]
|
32
|
+
when "git"
|
33
|
+
invoke(:git_remote_add, params["local_branch"], params["remote"], params["branch"])
|
34
|
+
when "svn"
|
35
|
+
invoke(:git_svn_init, params["local_branch"], params["remote"])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Braid
|
2
|
+
module Commands
|
3
|
+
class Update < Command
|
4
|
+
def run(mirror, options = {})
|
5
|
+
in_work_branch do
|
6
|
+
mirror ? update_one(mirror, options) : update_all
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
def update_all
|
12
|
+
msg "Updating all mirrors."
|
13
|
+
config.mirrors.each do |mirror|
|
14
|
+
update_one(mirror)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_one(mirror, options = {})
|
19
|
+
params = config.get(mirror)
|
20
|
+
unless params
|
21
|
+
msg "Mirror '#{mirror}/' does not exist. Skipping."
|
22
|
+
return
|
23
|
+
end
|
24
|
+
local_branch = params["local_branch"]
|
25
|
+
|
26
|
+
if check_for_lock(params, options)
|
27
|
+
msg "Mirror '#{mirror}/' is locked to #{display_revision(params["type"], params["revision"])}. Skipping."
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
# unlock
|
32
|
+
if params["revision"] && options["head"]
|
33
|
+
msg "Unlocking mirror '#{mirror}/'."
|
34
|
+
options["revision"] = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
fetch_remote(params["type"], local_branch)
|
39
|
+
|
40
|
+
validate_revision_option(params, options)
|
41
|
+
target = determine_target_commit(params, options)
|
42
|
+
|
43
|
+
check_merge_status(target)
|
44
|
+
rescue Braid::Commands::MirrorAlreadyUpToDate
|
45
|
+
msg "Mirror '#{mirror}/' is already up to date. Skipping."
|
46
|
+
update_revision(mirror, options["revision"])
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
msg "Updating #{params["type"]} mirror '#{mirror}/'."
|
51
|
+
|
52
|
+
if params["squash"]
|
53
|
+
invoke(:git_rm_r, mirror)
|
54
|
+
invoke(:git_read_tree, target, mirror)
|
55
|
+
else
|
56
|
+
invoke(:git_merge_subtree, target)
|
57
|
+
end
|
58
|
+
|
59
|
+
update_revision(mirror, options["revision"])
|
60
|
+
add_config_file
|
61
|
+
|
62
|
+
revision_message = " to " + (options["revision"] ? display_revision(params["type"], options["revision"]) : "HEAD")
|
63
|
+
commit_message = "Update mirror '#{mirror}/'#{revision_message}."
|
64
|
+
invoke(:git_commit, commit_message)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def check_for_lock(params, options)
|
69
|
+
params["revision"] && !options["revision"] && !options["head"]
|
70
|
+
end
|
71
|
+
|
72
|
+
def update_revision(mirror, revision)
|
73
|
+
config.update(mirror, { "revision" => revision })
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/braid/config.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'yaml/store'
|
3
|
+
|
4
|
+
module Braid
|
5
|
+
class Config
|
6
|
+
attr_accessor :db
|
7
|
+
|
8
|
+
def initialize(config_file = nil)
|
9
|
+
config_file ||= CONFIG_FILE
|
10
|
+
@db = YAML::Store.new(config_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_from_options(remote, options)
|
14
|
+
mirror, params = self.class.options_to_mirror(remote, options)
|
15
|
+
|
16
|
+
raise Braid::Config::RemoteIsRequired unless params["remote"]
|
17
|
+
raise Braid::Config::MirrorTypeIsRequired unless params["type"]
|
18
|
+
raise Braid::Config::BranchIsRequired unless params["type"] == "svn" || params["branch"]
|
19
|
+
raise Braid::Config::MirrorNameIsRequired unless mirror
|
20
|
+
raise Braid::Config::UnknownMirrorType unless MIRROR_TYPES.include?(params["type"])
|
21
|
+
|
22
|
+
params.delete("rails_plugin")
|
23
|
+
params.delete("branch") if params["type"] == "svn"
|
24
|
+
add(mirror, params)
|
25
|
+
[mirror, get(mirror)]
|
26
|
+
end
|
27
|
+
|
28
|
+
def mirrors
|
29
|
+
@db.transaction(true) do
|
30
|
+
@db.roots
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def add(mirror, params)
|
35
|
+
mirror = remove_trailing_slash(mirror)
|
36
|
+
@db.transaction do
|
37
|
+
raise Braid::Config::MirrorNameAlreadyInUse if @db[mirror]
|
38
|
+
@db[mirror] = params.merge("remote" => remove_trailing_slash(params["remote"]))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def get(mirror)
|
43
|
+
mirror = remove_trailing_slash(mirror)
|
44
|
+
@db.transaction(true) do
|
45
|
+
@db[mirror]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def get!(mirror)
|
50
|
+
params = get(mirror)
|
51
|
+
raise Braid::Config::MirrorDoesNotExist unless params
|
52
|
+
params
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_by_remote(remote)
|
56
|
+
remote = remove_trailing_slash(remote)
|
57
|
+
mirror = nil
|
58
|
+
@db.transaction(true) do
|
59
|
+
mirror = @db.roots.detect { |mirror| @db[mirror]["remote"] == remote }
|
60
|
+
end
|
61
|
+
[mirror, get(mirror)]
|
62
|
+
end
|
63
|
+
|
64
|
+
def remove(mirror)
|
65
|
+
mirror = remove_trailing_slash(mirror)
|
66
|
+
@db.transaction do
|
67
|
+
@db.delete(mirror)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def update(mirror, params)
|
72
|
+
mirror = remove_trailing_slash(mirror)
|
73
|
+
@db.transaction do
|
74
|
+
raise Braid::Config::MirrorDoesNotExist unless @db[mirror]
|
75
|
+
tmp = @db[mirror].merge(params)
|
76
|
+
@db[mirror] = tmp.merge("remote" => remove_trailing_slash(tmp["remote"]))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def replace(mirror, params)
|
81
|
+
mirror = remove_trailing_slash(mirror)
|
82
|
+
@db.transaction do
|
83
|
+
raise Braid::Config::MirrorDoesNotExist unless @db[mirror]
|
84
|
+
params["remote"] = remove_trailing_slash(params["remote"]) if params["remote"]
|
85
|
+
@db[mirror] = params
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.options_to_mirror(remote, options = {})
|
90
|
+
remote = remove_trailing_slash(remote)
|
91
|
+
branch = options["branch"] || "master"
|
92
|
+
|
93
|
+
if options["type"]
|
94
|
+
type = options["type"]
|
95
|
+
else
|
96
|
+
type = extract_type_from_path(remote)
|
97
|
+
raise Braid::Config::CannotGuessMirrorType unless type
|
98
|
+
end
|
99
|
+
|
100
|
+
mirror = options["mirror"] || extract_mirror_from_path(remote)
|
101
|
+
|
102
|
+
if options["rails_plugin"]
|
103
|
+
mirror = "vendor/plugins/#{mirror}"
|
104
|
+
end
|
105
|
+
|
106
|
+
squash = !options["full"]
|
107
|
+
|
108
|
+
[remove_trailing_slash(mirror), { "type" => type, "remote" => remote, "branch" => branch, "squash" => squash }]
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
def remove_trailing_slash(path)
|
113
|
+
self.class.send(:remove_trailing_slash, path)
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.remove_trailing_slash(path)
|
117
|
+
# bluh.
|
118
|
+
path.sub(/\/$/, '')
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.extract_type_from_path(path)
|
122
|
+
return nil unless path
|
123
|
+
path = remove_trailing_slash(path)
|
124
|
+
|
125
|
+
# check for git:// and svn:// URLs
|
126
|
+
path_scheme = path.split(":").first
|
127
|
+
return path_scheme if %w[git svn].include?(path_scheme)
|
128
|
+
|
129
|
+
return "svn" if path[-6..-1] == "/trunk"
|
130
|
+
return "git" if path[-4..-1] == ".git"
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.extract_mirror_from_path(path)
|
134
|
+
return nil unless path
|
135
|
+
name = File.basename(path)
|
136
|
+
|
137
|
+
if File.extname(name) == ".git"
|
138
|
+
# strip .git
|
139
|
+
name[0..-5]
|
140
|
+
elsif name == "trunk"
|
141
|
+
# use parent
|
142
|
+
File.basename(File.dirname(path))
|
143
|
+
else
|
144
|
+
name
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Braid
|
2
|
+
class Exception < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
module Commands
|
6
|
+
class ShellExecutionError < Braid::Exception; end
|
7
|
+
class LocalRevisionIsHigherThanRequestedRevision < Braid::Exception; end
|
8
|
+
class MirrorAlreadyUpToDate < Braid::Exception; end
|
9
|
+
class RequestedRevisionIsHigherThanRemoteRevision < Braid::Exception; end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Config
|
13
|
+
class UnknownMirrorType < Braid::Exception; end
|
14
|
+
class MirrorNameAlreadyInUse < Braid::Exception; end
|
15
|
+
class MirrorDoesNotExist < Braid::Exception; end
|
16
|
+
class CannotGuessMirrorType < Braid::Exception; end
|
17
|
+
|
18
|
+
class RemoteIsRequired < Braid::Exception; end
|
19
|
+
class MirrorTypeIsRequired < Braid::Exception; end
|
20
|
+
class BranchIsRequired < Braid::Exception; end
|
21
|
+
class MirrorNameIsRequired < Braid::Exception; end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Git
|
25
|
+
class UnknownRevision < Braid::Exception; end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Svn
|
29
|
+
class UnknownRevision < Braid::Exception; end
|
30
|
+
end
|
31
|
+
end
|