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/mirror.rb CHANGED
@@ -1,21 +1,15 @@
1
1
  module Braid
2
2
  class Mirror
3
- TYPES = %w(git svn)
4
- ATTRIBUTES = %w(url remote type branch squashed revision lock)
3
+ ATTRIBUTES = %w(url remote branch squashed revision lock)
5
4
 
6
5
  class UnknownType < BraidError
7
6
  def message
8
7
  "unknown type: #{super}"
9
8
  end
10
9
  end
11
- class CannotGuessType < BraidError
12
- def message
13
- "cannot guess type: #{super}"
14
- end
15
- end
16
10
  class PathRequired < BraidError
17
11
  def message
18
- "path is required"
12
+ 'path is required'
19
13
  end
20
14
  end
21
15
 
@@ -31,27 +25,16 @@ module Braid
31
25
  def self.new_from_options(url, options = {})
32
26
  url = url.sub(/\/$/, '')
33
27
 
34
- branch = options["branch"] || "master"
35
-
36
- if type = options["type"] || extract_type_from_url(url)
37
- raise UnknownType, type unless TYPES.include?(type)
38
- else
39
- raise CannotGuessType, url
40
- end
28
+ branch = options['branch'] || 'master'
41
29
 
42
- unless path = options["path"] || extract_path_from_url(url)
30
+ unless path = options['path'] || extract_path_from_url(url)
43
31
  raise PathRequired
44
32
  end
45
33
 
46
- if options["rails_plugin"]
47
- path = "vendor/plugins/#{path}"
48
- end
49
-
50
- remote = "#{branch}/braid/#{path}".gsub("_", '-') # stupid git svn changes all _ to ., weird
51
- squashed = !options["full"]
52
- branch = nil if type == "svn"
34
+ remote = "#{branch}/braid/#{path}"
35
+ squashed = !options['full']
53
36
 
54
- attributes = {"url" => url, "remote" => remote, "type" => type, "branch" => branch, "squashed" => squashed}
37
+ attributes = {'url' => url, 'remote' => remote, 'branch' => branch, 'squashed' => squashed}
55
38
  self.new(path, attributes)
56
39
  end
57
40
 
@@ -59,11 +42,6 @@ module Braid
59
42
  path == comparison.path && attributes == comparison.attributes
60
43
  end
61
44
 
62
- def type
63
- # override Object#type
64
- attributes["type"]
65
- end
66
-
67
45
  def locked?
68
46
  !!lock
69
47
  end
@@ -79,23 +57,20 @@ module Braid
79
57
  if squashed?
80
58
  !!base_revision && git.merge_base(commit, base_revision) == commit
81
59
  else
82
- git.merge_base(commit, "HEAD") == commit
60
+ git.merge_base(commit, 'HEAD') == commit
83
61
  end
84
62
  end
85
63
 
86
64
  def diff
65
+ fetch
87
66
  remote_hash = git.rev_parse("#{base_revision}:")
88
67
  local_hash = git.tree_hash(path)
89
- remote_hash != local_hash ? git.diff_tree(remote_hash, local_hash) : ""
68
+ remote_hash != local_hash ? git.diff_tree(remote_hash, local_hash) : ''
90
69
  end
91
70
 
92
71
  def fetch
93
- unless type == "svn"
94
- git_cache.fetch(url) if cached?
95
- git.fetch(remote)
96
- else
97
- git_svn.fetch(remote)
98
- end
72
+ git_cache.fetch(url) if cached?
73
+ git.fetch(remote)
99
74
  end
100
75
 
101
76
  def cached?
@@ -104,11 +79,7 @@ module Braid
104
79
 
105
80
  def base_revision
106
81
  if revision
107
- unless type == "svn"
108
- git.rev_parse(revision)
109
- else
110
- git_svn.commit_hash(remote, revision)
111
- end
82
+ git.rev_parse(revision)
112
83
  else
113
84
  inferred_revision
114
85
  end
@@ -119,10 +90,10 @@ module Braid
119
90
  end
120
91
 
121
92
  def remote
122
- if (attributes["remote"] && attributes["remote"] =~ /^braid\//)
123
- attributes["remote"] = "#{branch}/#{attributes["remote"]}"
93
+ if (attributes['remote'] && attributes['remote'] =~ /^braid\//)
94
+ attributes['remote'] = "#{branch}/#{attributes['remote']}"
124
95
  else
125
- attributes["remote"]
96
+ attributes['remote']
126
97
  end
127
98
  end
128
99
 
@@ -141,8 +112,8 @@ module Braid
141
112
  end
142
113
 
143
114
  def inferred_revision
144
- local_commits = git.rev_list("HEAD", "-- #{path}").split("\n")
145
- remote_hashes = git.rev_list("--pretty=format:\"%T\"", remote).split("commit ").map do |chunk|
115
+ local_commits = git.rev_list('HEAD', "-- #{path}").split("\n")
116
+ remote_hashes = git.rev_list("--pretty=format:\"%T\"", remote).split('commit ').map do |chunk|
146
117
  chunk.split("\n", 2).map { |value| value.strip }
147
118
  end
148
119
  hash = nil
@@ -156,28 +127,13 @@ module Braid
156
127
  hash
157
128
  end
158
129
 
159
- def self.extract_type_from_url(url)
160
- return nil unless url
161
- url.sub!(/\/$/, '')
162
-
163
- # check for git:// and svn:// URLs
164
- url_scheme = url.split(":").first
165
- return url_scheme if TYPES.include?(url_scheme)
166
-
167
- return "svn" if url[-6..-1] == "/trunk"
168
- return "git" if url[-4..-1] == ".git"
169
- end
170
-
171
130
  def self.extract_path_from_url(url)
172
131
  return nil unless url
173
132
  name = File.basename(url)
174
133
 
175
- if File.extname(name) == ".git"
134
+ if File.extname(name) == '.git'
176
135
  # strip .git
177
136
  name[0..-5]
178
- elsif name == "trunk"
179
- # use parent
180
- File.basename(File.dirname(url))
181
137
  else
182
138
  name
183
139
  end
@@ -1,9 +1,11 @@
1
1
  require 'singleton'
2
2
  require 'rubygems'
3
- require defined?(JRUBY_VERSION) ? 'open3' : 'open4'
4
3
  require 'tempfile'
5
4
 
6
5
  module Braid
6
+ USE_OPEN3 = defined?(JRUBY_VERSION) || Gem.win_platform?
7
+ require USE_OPEN3 ? 'open3' : 'open4'
8
+
7
9
  module Operations
8
10
  class ShellExecutionError < BraidError
9
11
  def initialize(err = nil)
@@ -32,16 +34,16 @@ module Braid
32
34
  end
33
35
  class LocalChangesPresent < BraidError
34
36
  def message
35
- "local changes are present"
37
+ 'local changes are present'
36
38
  end
37
39
  end
38
40
  class MergeError < BraidError
39
41
  def message
40
- "could not merge"
42
+ 'could not merge'
41
43
  end
42
44
  end
43
45
 
44
- # The command proxy is meant to encapsulate commands such as git, git-svn and svn, that work with subcommands.
46
+ # The command proxy is meant to encapsulate commands such as git, that work with subcommands.
45
47
  class Proxy
46
48
  include Singleton
47
49
 
@@ -52,12 +54,12 @@ module Braid
52
54
  # hax!
53
55
  def version
54
56
  status, out, err = exec!("#{self.class.command} --version")
55
- out.sub(/^.* version/, "").strip
57
+ out.sub(/^.* version/, '').strip
56
58
  end
57
59
 
58
60
  def require_version(required)
59
- required = required.split(".")
60
- actual = version.split(".")
61
+ required = required.split('.')
62
+ actual = version.split('.')
61
63
 
62
64
  actual.each_with_index do |actual_piece, idx|
63
65
  required_piece = required[idx]
@@ -103,14 +105,21 @@ module Braid
103
105
  ENV['LANG'] = 'C'
104
106
 
105
107
  out, err = nil
108
+ status, pid = 0
106
109
  log(cmd)
107
110
 
108
- if defined?(JRUBY_VERSION)
109
- Open3.popen3(cmd) do |stdin, stdout, stderr|
111
+ if USE_OPEN3
112
+ status = nil
113
+ Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thread|
114
+ # Under old jrubies this may sometimes throw an exception
115
+ stdin.close rescue nil
110
116
  out = stdout.read
111
117
  err = stderr.read
118
+ # Under earlier jrubies this is not correctly passed so add in check
119
+ status = wait_thread.value if wait_thread # Process::Status object returned.
112
120
  end
113
- status = $?.exitstatus
121
+ # Handle earlier jrubies such as 1.6.7.2
122
+ status = $?.exitstatus if status.nil?
114
123
  else
115
124
  status = Open4.popen4(cmd) do |pid, stdin, stdout, stderr|
116
125
  out = stdout.read
@@ -130,7 +139,7 @@ module Braid
130
139
  end
131
140
 
132
141
  def sh(cmd, message = nil)
133
- message ||= "could not fetch" if cmd =~ /fetch/
142
+ message ||= 'could not fetch' if cmd =~ /fetch/
134
143
  log(cmd)
135
144
  `#{cmd}`
136
145
  raise ShellExecutionError, message unless $?.exitstatus == 0
@@ -152,11 +161,12 @@ module Braid
152
161
 
153
162
  class Git < Proxy
154
163
  def commit(message, *args)
155
- cmd = "git commit --no-verify"
164
+ cmd = 'git commit --no-verify'
156
165
  if message # allow nil
157
166
  message_file = Tempfile.new("braid_commit")
158
167
  message_file.print("Braid: #{message}")
159
168
  message_file.flush
169
+ message_file.close
160
170
  cmd << " -F #{message_file.path}"
161
171
  end
162
172
  cmd << " #{args.join(' ')}" unless args.empty?
@@ -175,7 +185,7 @@ module Braid
175
185
  def fetch(remote = nil, *args)
176
186
  args.unshift "-n #{remote}" if remote
177
187
  # open4 messes with the pipes of index-pack
178
- sh("git fetch #{args.join(' ')} 2>&1 >/dev/null")
188
+ sh("git fetch #{args.join(' ')} 2>&1 > #{Gem.win_platform? ? 'nul' : '/dev/null'}")
179
189
  end
180
190
 
181
191
  def checkout(treeish)
@@ -198,42 +208,38 @@ module Braid
198
208
 
199
209
  # Implies tracking.
200
210
  def remote_add(remote, path, branch)
201
- invoke(:remote, "add", "-t #{branch} -m #{branch}", remote, path)
211
+ invoke(:remote, 'add', "-t #{branch} -m #{branch}", remote, path)
202
212
  true
203
213
  end
204
214
 
205
215
  def remote_rm(remote)
206
- invoke(:remote, "rm", remote)
216
+ invoke(:remote, 'rm', remote)
207
217
  true
208
218
  end
209
219
 
210
- # Checks git and svn remotes.
220
+ # Checks git remotes.
211
221
  def remote_url(remote)
212
222
  key = "remote.#{remote}.url"
213
- begin
214
- invoke(:config, key)
215
- rescue ShellExecutionError
216
- invoke(:config, "svn-#{key}")
217
- end
223
+ invoke(:config, key)
218
224
  rescue ShellExecutionError
219
225
  nil
220
226
  end
221
227
 
222
228
  def reset_hard(target)
223
- invoke(:reset, "--hard", target)
229
+ invoke(:reset, '--hard', target)
224
230
  true
225
231
  end
226
232
 
227
233
  # Implies no commit.
228
234
  def merge_ours(opt)
229
- invoke(:merge, "-s ours --no-commit", opt)
235
+ invoke(:merge, '-s ours --no-commit', opt)
230
236
  true
231
237
  end
232
238
 
233
239
  # Implies no commit.
234
240
  def merge_subtree(opt)
235
241
  # TODO which options are needed?
236
- invoke(:merge, "-s subtree --no-commit --no-ff", opt)
242
+ invoke(:merge, '-s subtree --no-commit --no-ff', opt)
237
243
  true
238
244
  rescue ShellExecutionError
239
245
  raise MergeError
@@ -246,18 +252,22 @@ module Braid
246
252
  raise MergeError
247
253
  end
248
254
 
255
+ def read_ls_files(prefix)
256
+ invoke('ls-files', prefix)
257
+ end
258
+
249
259
  def read_tree_prefix(treeish, prefix)
250
260
  invoke(:read_tree, "--prefix=#{prefix}/ -u", treeish)
251
261
  true
252
262
  end
253
263
 
254
264
  def rm_r(path)
255
- invoke(:rm, "-r", path)
265
+ invoke(:rm, '-r', path)
256
266
  true
257
267
  end
258
268
 
259
- def tree_hash(path, treeish = "HEAD")
260
- out = invoke(:ls_tree, treeish, "-d", path)
269
+ def tree_hash(path, treeish = 'HEAD')
270
+ out = invoke(:ls_tree, treeish, '-d', path)
261
271
  out.split[2]
262
272
  end
263
273
 
@@ -269,7 +279,7 @@ module Braid
269
279
  end
270
280
 
271
281
  def status_clean?
272
- status, out, err = exec("git status")
282
+ status, out, err = exec('git status')
273
283
  !out.split("\n").grep(/nothing to commit/).empty?
274
284
  end
275
285
 
@@ -278,7 +288,7 @@ module Braid
278
288
  end
279
289
 
280
290
  def head
281
- rev_parse("HEAD")
291
+ rev_parse('HEAD')
282
292
  end
283
293
 
284
294
  def branch
@@ -287,17 +297,22 @@ module Braid
287
297
  end
288
298
 
289
299
  def apply(diff, *args)
290
- err = nil
300
+ status, err = nil, nil
301
+
302
+ command = "git apply --index --whitespace=nowarn #{args.join(' ')} -"
291
303
 
292
- if defined?(JRUBY_VERSION)
293
- Open3.popen3("git apply --index --whitespace=nowarn #{args.join(' ')} -") do |stdin, stdout, stderr|
304
+ if USE_OPEN3
305
+ Open3.popen3(command) do |stdin, stdout, stderr, wait_thread|
294
306
  stdin.puts(diff)
295
307
  stdin.close
296
308
  err = stderr.read
309
+ # Under earlier jrubies this is not correctly passed so add in check
310
+ status = wait_thread.value if wait_thread # Process::Status object returned.
297
311
  end
298
- status = $?.exitstatus
312
+ # Handle earlier jrubies such as 1.6.7.2
313
+ status = $?.exitstatus if status.nil?
299
314
  else
300
- status = Open4.popen4("git apply --index --whitespace=nowarn #{args.join(' ')} -") do |pid, stdin, stdout, stderr|
315
+ status = Open4.popen4(command) do |pid, stdin, stdout, stderr|
301
316
  stdin.puts(diff)
302
317
  stdin.close
303
318
  err = stderr.read
@@ -320,52 +335,6 @@ module Braid
320
335
  end
321
336
  end
322
337
 
323
- class GitSvn < Proxy
324
- def self.command;
325
- "git svn";
326
- end
327
-
328
- def commit_hash(remote, revision)
329
- out = invoke(:log, "--show-commit --oneline", "-r #{revision}", remote)
330
- part = out.to_s.split("|")[1]
331
- part.strip!
332
- raise UnknownRevision, "r#{revision}" unless part
333
- git.rev_parse(part)
334
- end
335
-
336
- def fetch(remote)
337
- sh("git svn fetch #{remote} 2>&1 >/dev/null")
338
- end
339
-
340
- def init(remote, path)
341
- invoke(:init, "-R", remote, "--id=#{remote}", path)
342
- true
343
- end
344
-
345
- private
346
-
347
- def command(name)
348
- "#{self.class.command} #{name}"
349
- end
350
-
351
- def git
352
- Git.instance
353
- end
354
- end
355
-
356
- class Svn < Proxy
357
- def clean_revision(revision)
358
- revision.to_i if revision
359
- end
360
-
361
- def head_revision(path)
362
- # not using svn info because it's retarded and doesn't show the actual last changed rev for the url
363
- # git svn has no clue on how to get the actual HEAD revision number on it's own
364
- status, out, err = exec!("svn log -q --limit 1 #{path}")
365
- out.split(/\n/).find { |x| x.match /^r\d+/ }.split(" | ")[0][1..-1].to_i
366
- end
367
- end
368
-
369
338
  class GitCache
370
339
  include Singleton
371
340
 
@@ -383,12 +352,12 @@ module Braid
383
352
  end
384
353
  else
385
354
  FileUtils.mkdir_p(local_cache_dir)
386
- git.clone("--mirror", url, dir)
355
+ git.clone('--mirror', url, dir)
387
356
  end
388
357
  end
389
358
 
390
359
  def path(url)
391
- File.join(local_cache_dir, url.gsub(/[\/:@]/, "_"))
360
+ File.join(local_cache_dir, url.gsub(/[\/:@]/, '_'))
392
361
  end
393
362
 
394
363
  private
@@ -407,14 +376,6 @@ module Braid
407
376
  Git.instance
408
377
  end
409
378
 
410
- def git_svn
411
- GitSvn.instance
412
- end
413
-
414
- def svn
415
- Svn.instance
416
- end
417
-
418
379
  def git_cache
419
380
  GitCache.instance
420
381
  end