braid 0.7.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -1
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +7 -0
  5. data/CONTRIBUTING.md +26 -0
  6. data/Gemfile +1 -2
  7. data/LICENSE +3 -1
  8. data/README.md +90 -51
  9. data/Rakefile +6 -14
  10. data/bin/braid +9 -37
  11. data/braid.gemspec +11 -11
  12. data/lib/braid.rb +13 -12
  13. data/lib/braid/command.rb +9 -42
  14. data/lib/braid/commands/add.rb +6 -8
  15. data/lib/braid/commands/list.rb +11 -6
  16. data/lib/braid/commands/push.rb +5 -5
  17. data/lib/braid/commands/remove.rb +1 -3
  18. data/lib/braid/commands/setup.rb +4 -8
  19. data/lib/braid/commands/update.rb +12 -14
  20. data/lib/braid/config.rb +38 -43
  21. data/lib/braid/mirror.rb +19 -63
  22. data/lib/braid/operations.rb +51 -90
  23. data/lib/braid/version.rb +1 -1
  24. data/{test/config_test.rb → spec/config_spec.rb} +14 -17
  25. data/{test → spec}/fixtures/shiny/README +0 -0
  26. data/{test → spec}/fixtures/skit1.1/layouts/layout.liquid +0 -0
  27. data/{test → spec}/fixtures/skit1.2/layouts/layout.liquid +0 -0
  28. data/{test → spec}/fixtures/skit1/layouts/layout.liquid +0 -0
  29. data/{test → spec}/fixtures/skit1/preview.png +0 -0
  30. data/spec/integration/adding_spec.rb +43 -0
  31. data/{test/integration/updating_test.rb → spec/integration/updating_spec.rb} +2 -41
  32. data/spec/integration_helper.rb +47 -0
  33. data/{test/mirror_test.rb → spec/mirror_spec.rb} +6 -33
  34. data/{test/operations_test.rb → spec/operations_spec.rb} +2 -2
  35. data/{test → spec}/test_helper.rb +6 -2
  36. metadata +86 -123
  37. data/lib/core_ext.rb +0 -13
  38. data/test/braid_test.rb +0 -7
  39. data/test/integration/adding_test.rb +0 -80
  40. data/test/integration_helper.rb +0 -70
data/lib/braid.rb CHANGED
@@ -1,12 +1,11 @@
1
- $:.unshift dirname = File.dirname(__FILE__)
2
1
  require 'braid/version'
3
2
 
4
3
  module Braid
5
- CONFIG_FILE = ".braids"
6
- REQUIRED_GIT_VERSION = "1.6"
4
+ CONFIG_FILE = '.braids'
5
+ REQUIRED_GIT_VERSION = '1.6'
7
6
 
8
7
  def self.verbose
9
- @verbose || false
8
+ !!@verbose
10
9
  end
11
10
 
12
11
  def self.verbose=(new_value)
@@ -14,7 +13,7 @@ module Braid
14
13
  end
15
14
 
16
15
  def self.force
17
- @force || false
16
+ !!@force
18
17
  end
19
18
 
20
19
  def self.force=(new_value)
@@ -22,11 +21,11 @@ module Braid
22
21
  end
23
22
 
24
23
  def self.use_local_cache
25
- [nil, "true", "1"].include?(ENV["BRAID_USE_LOCAL_CACHE"])
24
+ [nil, 'true', '1'].include?(ENV['BRAID_USE_LOCAL_CACHE'])
26
25
  end
27
26
 
28
27
  def self.local_cache_dir
29
- File.expand_path(ENV["BRAID_LOCAL_CACHE_DIR"] || "#{ENV["HOME"]}/.braid/cache")
28
+ File.expand_path(ENV['BRAID_LOCAL_CACHE_DIR'] || "#{ENV['HOME']}/.braid/cache")
30
29
  end
31
30
 
32
31
  class BraidError < StandardError
@@ -37,12 +36,14 @@ module Braid
37
36
  end
38
37
  end
39
38
 
40
- require dirname + '/core_ext'
41
39
  require 'braid/operations'
42
40
  require 'braid/mirror'
43
41
  require 'braid/config'
44
42
  require 'braid/command'
45
-
46
- Dir[dirname + '/braid/commands/*'].each do |file|
47
- require file
48
- end
43
+ require 'braid/commands/add'
44
+ require 'braid/commands/diff'
45
+ require 'braid/commands/list'
46
+ require 'braid/commands/push'
47
+ require 'braid/commands/remove'
48
+ require 'braid/commands/setup'
49
+ require 'braid/commands/update'
data/lib/braid/command.rb CHANGED
@@ -31,7 +31,7 @@ module Braid
31
31
  end
32
32
 
33
33
  def config
34
- @config ||= load_and_migrate_config
34
+ @config ||= Config.new
35
35
  end
36
36
 
37
37
  def verbose?
@@ -61,6 +61,8 @@ module Braid
61
61
  end
62
62
 
63
63
  def with_reset_on_error
64
+ bail_on_local_changes!
65
+
64
66
  work_head = git.head
65
67
 
66
68
  begin
@@ -72,65 +74,30 @@ module Braid
72
74
  end
73
75
  end
74
76
 
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
77
  def add_config_file
87
78
  git.add(CONFIG_FILE)
88
79
  end
89
80
 
90
81
  def display_revision(mirror, revision = nil)
91
82
  revision ||= mirror.revision
92
- mirror.type == "svn" ? "r#{revision}" : "'#{revision[0, 7]}'"
83
+ "'#{revision[0, 7]}'"
93
84
  end
94
85
 
95
86
  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
87
+ return git.rev_parse(mirror.remote) unless new_revision
103
88
 
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
89
+ new_revision = git.rev_parse(new_revision)
109
90
  old_revision = mirror.revision
110
91
 
111
92
  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
93
+ raise InvalidRevision, 'mirror is already at requested revision'
123
94
  end
124
95
 
125
96
  new_revision
126
97
  end
127
98
 
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
99
+ def determine_target_revision(new_revision)
100
+ git.rev_parse(new_revision)
134
101
  end
135
102
  end
136
103
  end
@@ -2,14 +2,12 @@ module Braid
2
2
  module Commands
3
3
  class Add < Command
4
4
  def run(url, options = {})
5
- bail_on_local_changes!
6
-
7
5
  with_reset_on_error do
8
6
  mirror = config.add_from_options(url, options)
9
7
 
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}."
8
+ branch_message = (mirror.branch == 'master') ? '' : " branch '#{mirror.branch}'"
9
+ revision_message = options['revision'] ? " at #{display_revision(mirror, options['revision'])}" : ''
10
+ msg "Adding mirror of '#{mirror.url}'#{branch_message}#{revision_message}."
13
11
 
14
12
  # these commands are explained in the subtree merge guide
15
13
  # http://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html
@@ -17,8 +15,8 @@ module Braid
17
15
  setup_remote(mirror)
18
16
  mirror.fetch
19
17
 
20
- new_revision = validate_new_revision(mirror, options["revision"])
21
- target_revision = determine_target_revision(mirror, new_revision)
18
+ new_revision = validate_new_revision(mirror, options['revision'])
19
+ target_revision = determine_target_revision(new_revision)
22
20
 
23
21
  unless mirror.squashed?
24
22
  git.merge_ours(target_revision)
@@ -26,7 +24,7 @@ module Braid
26
24
  git.read_tree_prefix(target_revision, mirror.path)
27
25
 
28
26
  mirror.revision = new_revision
29
- mirror.lock = new_revision if options["revision"]
27
+ mirror.lock = new_revision if options['revision']
30
28
  config.update(mirror)
31
29
  add_config_file
32
30
 
@@ -12,16 +12,21 @@ module Braid
12
12
  options.reject! { |k, v| %w(revision head).include?(k) }
13
13
  print "\n"
14
14
  msg "Listing all mirrors.\n=======================================================\n"
15
- config.mirrors.each_with_index do |path, i|
15
+ config.mirrors.each do |path|
16
16
  mirror = config.get!(path)
17
- print " #{i + 1}) #{path.to_s}"
18
- print " [LOCKED]" if mirror.locked?
17
+ print path.to_s
18
+ print ' [LOCKED]' if mirror.locked?
19
19
  setup_remote(mirror)
20
20
  msg "Fetching new commits for '#{mirror.path}'." if verbose?
21
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
22
+ new_revision = validate_new_revision(mirror, options['revision'])
23
+ print ' (Remote Modified)' if new_revision.to_s != mirror.base_revision.to_s
24
+ local_file_count = git.read_ls_files(mirror.path).split.size
25
+ if 0 == local_file_count
26
+ print ' (Removed Locally)'
27
+ elsif !mirror.diff.empty?
28
+ print ' (Locally Modified)'
29
+ end
25
30
  print "\n"
26
31
  end
27
32
  print "\n"
@@ -11,13 +11,13 @@ module Braid
11
11
 
12
12
  base_revision = git.rev_parse(mirror.remote)
13
13
  unless mirror.merged?(base_revision)
14
- msg "Mirror is not up to date. Stopping."
14
+ msg 'Mirror is not up to date. Stopping.'
15
15
  return
16
16
  end
17
17
 
18
18
  diff = mirror.diff
19
19
  if diff.empty?
20
- msg "No local changes found. Stopping."
20
+ msg 'No local changes found. Stopping.'
21
21
  return
22
22
  end
23
23
 
@@ -31,14 +31,14 @@ module Braid
31
31
  remote_url = File.expand_path(remote_url)
32
32
  end
33
33
  Dir.chdir(clone_dir) do
34
- msg "Cloning mirror with local changes."
34
+ msg 'Cloning mirror with local changes.'
35
35
  git.init
36
36
  git.fetch(source_dir)
37
37
  git.fetch(remote_url, "+refs/heads/#{mirror.branch}")
38
38
  git.checkout(base_revision)
39
39
  git.apply(diff)
40
- system("git commit -v")
41
- msg "Pushing changes to remote."
40
+ system('git commit -v')
41
+ msg 'Pushing changes to remote.'
42
42
  git.push(remote_url, "HEAD:#{mirror.branch}")
43
43
  end
44
44
  FileUtils.rm_r(clone_dir)
@@ -4,8 +4,6 @@ module Braid
4
4
  def run(path, options = {})
5
5
  mirror = config.get!(path)
6
6
 
7
- bail_on_local_changes!
8
-
9
7
  with_reset_on_error do
10
8
  msg "Removing mirror from '#{mirror.path}'."
11
9
 
@@ -24,7 +22,7 @@ module Braid
24
22
  end
25
23
 
26
24
  git.commit("Remove mirror '#{mirror.path}'")
27
- msg "Removed mirror." if verbose?
25
+ msg 'Removed mirror.' if verbose?
28
26
  end
29
27
  end
30
28
  end
@@ -6,9 +6,9 @@ module Braid
6
6
  end
7
7
 
8
8
  protected
9
-
9
+
10
10
  def setup_all
11
- msg "Setting up all mirrors."
11
+ msg 'Setting up all mirrors.'
12
12
  config.mirrors.each do |path|
13
13
  setup_one(path)
14
14
  end
@@ -28,12 +28,8 @@ module Braid
28
28
  end
29
29
 
30
30
  msg "Setup: Creating remote for '#{mirror.path}'."
31
- unless mirror.type == "svn"
32
- url = use_local_cache? ? git_cache.path(mirror.url) : mirror.url
33
- git.remote_add(mirror.remote, url, mirror.branch)
34
- else
35
- git_svn.init(mirror.remote, mirror.url)
36
- end
31
+ url = use_local_cache? ? git_cache.path(mirror.url) : mirror.url
32
+ git.remote_add(mirror.remote, url, mirror.branch)
37
33
  end
38
34
  end
39
35
  end
@@ -2,8 +2,6 @@ module Braid
2
2
  module Commands
3
3
  class Update < Command
4
4
  def run(path, options = {})
5
- bail_on_local_changes!
6
-
7
5
  with_reset_on_error do
8
6
  path ? update_one(path, options) : update_all(options)
9
7
  end
@@ -13,7 +11,7 @@ module Braid
13
11
 
14
12
  def update_all(options = {})
15
13
  options.reject! { |k, v| %w(revision head).include?(k) }
16
- msg "Updating all mirrors."
14
+ msg 'Updating all mirrors.'
17
15
  config.mirrors.each do |path|
18
16
  update_one(path, options)
19
17
  end
@@ -27,10 +25,10 @@ module Braid
27
25
 
28
26
  # check options for lock modification
29
27
  if mirror.locked?
30
- if options["head"]
28
+ if options['head']
31
29
  msg "Unlocking mirror '#{mirror.path}'." if verbose?
32
30
  mirror.lock = nil
33
- elsif !options["revision"]
31
+ elsif !options['revision']
34
32
  msg "Mirror '#{mirror.path}' is locked to #{display_revision(mirror, mirror.lock)}. Use --head to force."
35
33
  return
36
34
  end
@@ -40,8 +38,8 @@ module Braid
40
38
  msg "Fetching new commits for '#{mirror.path}'." if verbose?
41
39
  mirror.fetch
42
40
 
43
- new_revision = validate_new_revision(mirror, options["revision"])
44
- target_revision = determine_target_revision(mirror, new_revision)
41
+ new_revision = validate_new_revision(mirror, options['revision'])
42
+ target_revision = determine_target_revision(new_revision)
45
43
 
46
44
  if mirror.merged?(target_revision)
47
45
  msg "Mirror '#{mirror.path}' is already up to date."
@@ -54,26 +52,26 @@ module Braid
54
52
  end
55
53
 
56
54
  mirror.revision = new_revision
57
- mirror.lock = new_revision if options["revision"]
55
+ mirror.lock = new_revision if options['revision']
58
56
 
59
57
  msg "Merging in mirror '#{mirror.path}'." if verbose?
60
58
  begin
61
59
  if mirror.squashed?
62
- local_hash = git.rev_parse("HEAD")
60
+ local_hash = git.rev_parse('HEAD')
63
61
  if !diff.empty?
64
62
  base_hash = generate_tree_hash(mirror, base_revision)
65
63
  else
66
64
  base_hash = local_hash
67
65
  end
68
66
  remote_hash = generate_tree_hash(mirror, target_revision)
69
- ENV["GITHEAD_#{local_hash}"] = "HEAD"
67
+ ENV["GITHEAD_#{local_hash}"] = 'HEAD'
70
68
  ENV["GITHEAD_#{remote_hash}"] = target_revision
71
69
  git.merge_recursive(base_hash, local_hash, remote_hash)
72
70
  else
73
71
  git.merge_subtree(target_revision)
74
72
  end
75
73
  rescue Operations::MergeError => error
76
- msg "Caught merge error. Breaking."
74
+ msg 'Caught merge error. Breaking.'
77
75
  end
78
76
 
79
77
  config.update(mirror)
@@ -81,7 +79,7 @@ module Braid
81
79
 
82
80
  commit_message = "Update mirror '#{mirror.path}' to #{display_revision(mirror)}"
83
81
  if error
84
- File.open(".git/MERGE_MSG", 'w') { |f| f.puts(commit_message) }
82
+ File.open('.git/MERGE_MSG', 'w') { |f| f.puts(commit_message) }
85
83
  return
86
84
  end
87
85
 
@@ -93,8 +91,8 @@ module Braid
93
91
  git.rm_r(mirror.path)
94
92
  git.read_tree_prefix(revision, mirror.path)
95
93
  success = git.commit("Temporary commit for mirror '#{mirror.path}'")
96
- hash = git.rev_parse("HEAD")
97
- git.reset_hard("HEAD^") if success
94
+ hash = git.rev_parse('HEAD')
95
+ git.reset_hard('HEAD^') if success
98
96
  hash
99
97
  end
100
98
  end
data/lib/braid/config.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'yaml'
2
+ require 'json'
2
3
  require 'yaml/store'
3
4
 
4
5
  module Braid
@@ -15,7 +16,18 @@ module Braid
15
16
  end
16
17
 
17
18
  def initialize(config_file = CONFIG_FILE)
18
- @db = YAML::Store.new(config_file)
19
+ @config_file = config_file
20
+ begin
21
+ store = YAML::Store.new(@config_file)
22
+ @db = {}
23
+ store.transaction(true) do
24
+ store.roots.each do |path|
25
+ @db[path] = store[path]
26
+ end
27
+ end
28
+ rescue
29
+ @db = JSON.parse(@config_file)
30
+ end
19
31
  end
20
32
 
21
33
  def add_from_options(url, options)
@@ -26,17 +38,13 @@ module Braid
26
38
  end
27
39
 
28
40
  def mirrors
29
- @db.transaction(true) do
30
- @db.roots
31
- end
41
+ @db.keys
32
42
  end
33
43
 
34
44
  def get(path)
35
- @db.transaction(true) do
36
- if attributes = @db[path.to_s.sub(/\/$/, '')]
37
- Mirror.new(path, attributes)
38
- end
39
- end
45
+ key = path.to_s.sub(/\/$/, '')
46
+ attributes = @db[key]
47
+ return attributes ? Mirror.new(path, attributes) : nil
40
48
  end
41
49
 
42
50
  def get!(path)
@@ -46,52 +54,39 @@ module Braid
46
54
  end
47
55
 
48
56
  def add(mirror)
49
- @db.transaction do
50
- raise PathAlreadyInUse, mirror.path if @db[mirror.path]
51
- write_mirror(mirror)
52
- end
57
+ raise PathAlreadyInUse, mirror.path if get(mirror.path)
58
+ write_mirror(mirror)
53
59
  end
54
60
 
55
61
  def remove(mirror)
56
- @db.transaction do
57
- @db.delete(mirror.path)
58
- end
62
+ @db.delete(mirror.path)
63
+ write_db
59
64
  end
60
65
 
61
66
  def update(mirror)
62
- @db.transaction do
63
- raise MirrorDoesNotExist, mirror.path unless @db[mirror.path]
64
- @db.delete(mirror.path)
65
- write_mirror(mirror)
66
- end
67
+ raise MirrorDoesNotExist, mirror.path unless get(mirror.path)
68
+ @db.delete(mirror.path)
69
+ write_mirror(mirror)
67
70
  end
68
71
 
69
- def valid?
70
- @db.transaction(true) do
71
- !@db.roots.any? do |path|
72
- @db[path]["url"].nil?
73
- end
74
- end
72
+ private
73
+ def write_mirror(mirror)
74
+ @db[mirror.path] = clean_attributes(mirror.attributes)
75
+ write_db
75
76
  end
76
77
 
77
- def migrate!
78
- @db.transaction do
79
- @db.roots.each do |path|
80
- attributes = @db[path]
81
- if attributes["local_branch"]
82
- attributes["url"] = attributes.delete("remote")
83
- attributes["remote"] = attributes.delete("local_branch")
84
- attributes["squashed"] = attributes.delete("squash")
85
- attributes["lock"] = attributes["revision"] # so far this has always been true
86
- end
87
- @db[path] = clean_attributes(attributes)
78
+ def write_db
79
+ new_db = {}
80
+ @db.keys.sort.each do |key|
81
+ new_db[key] = @db[key]
82
+ new_db[key].keys.each do |k|
83
+ new_db[key].delete(k) if !Braid::Mirror::ATTRIBUTES.include?(k)
88
84
  end
89
85
  end
90
- end
91
-
92
- private
93
- def write_mirror(mirror)
94
- @db[mirror.path] = clean_attributes(mirror.attributes)
86
+ File.open(@config_file, "wb") do |f|
87
+ f.write JSON.pretty_generate(new_db)
88
+ f.write "\n"
89
+ end
95
90
  end
96
91
 
97
92
  def clean_attributes(hash)