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/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