braid 0.7.1 → 1.0.0

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.
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)