rubycut-babushka 0.10.8 → 0.15.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +17 -15
  3. data/README.markdown +163 -41
  4. data/Rakefile +1 -1
  5. data/bin/babushka +1 -1
  6. data/deps/apt.rb +44 -0
  7. data/deps/babushka.rb +54 -42
  8. data/deps/deprecated.rb +16 -0
  9. data/deps/dev.rb +28 -3
  10. data/deps/git.rb +27 -12
  11. data/deps/homebrew.rb +2 -2
  12. data/deps/packages.rb +14 -15
  13. data/deps/pkg_managers.rb +21 -75
  14. data/deps/ruby.rb +5 -19
  15. data/deps/rubygems.rb +3 -3
  16. data/deps/system.rb +2 -2
  17. data/deps/templates/app.rb +60 -41
  18. data/deps/templates/bin.rb +16 -0
  19. data/deps/templates/installer.rb +9 -9
  20. data/deps/templates/lib.rb +17 -0
  21. data/deps/templates/managed.rb +1 -38
  22. data/deps/templates/src.rb +16 -8
  23. data/deps/templates/task.rb +11 -0
  24. data/deps/templates/tmbundle.rb +16 -2
  25. data/lib/babushka.rb +2 -3
  26. data/lib/babushka/accepts_block_for.rb +5 -3
  27. data/lib/babushka/asset.rb +172 -0
  28. data/lib/babushka/base.rb +37 -8
  29. data/lib/babushka/bug_reporter.rb +6 -6
  30. data/lib/babushka/cmdline.rb +11 -10
  31. data/lib/babushka/cmdline/handler.rb +7 -3
  32. data/lib/babushka/cmdline/helpers.rb +15 -23
  33. data/lib/babushka/cmdline/parser.rb +1 -1
  34. data/lib/babushka/core_patches/object.rb +1 -1
  35. data/lib/babushka/core_patches/string.rb +8 -3
  36. data/lib/babushka/current_ruby.rb +44 -0
  37. data/lib/babushka/dep.rb +111 -185
  38. data/lib/babushka/dep_context.rb +8 -3
  39. data/lib/babushka/dep_definer.rb +45 -15
  40. data/lib/babushka/dep_pool.rb +5 -8
  41. data/lib/babushka/{meta_dep.rb → dep_template.rb} +21 -2
  42. data/lib/babushka/dsl.rb +3 -0
  43. data/lib/babushka/git_repo.rb +143 -49
  44. data/lib/babushka/helpers/git_helpers.rb +7 -6
  45. data/lib/babushka/helpers/log_helpers.rb +51 -13
  46. data/lib/babushka/helpers/path_helpers.rb +5 -7
  47. data/lib/babushka/helpers/run_helpers.rb +15 -55
  48. data/lib/babushka/helpers/shell_helpers.rb +18 -26
  49. data/lib/babushka/helpers/uri_helpers.rb +9 -18
  50. data/lib/babushka/lambda_chooser.rb +20 -13
  51. data/lib/babushka/parameter.rb +20 -4
  52. data/lib/babushka/path_checker.rb +72 -0
  53. data/lib/babushka/pkg_helper.rb +38 -13
  54. data/lib/babushka/pkg_helpers/apt_helper.rb +15 -8
  55. data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +15 -14
  56. data/lib/babushka/pkg_helpers/binports_helper.rb +7 -7
  57. data/lib/babushka/pkg_helpers/brew_helper.rb +17 -25
  58. data/lib/babushka/pkg_helpers/gem_helper.rb +36 -27
  59. data/lib/babushka/pkg_helpers/npm_helper.rb +9 -9
  60. data/lib/babushka/pkg_helpers/pacman_helper.rb +5 -4
  61. data/lib/babushka/pkg_helpers/pip_helper.rb +14 -10
  62. data/lib/babushka/pkg_helpers/unknown_pkg_helper.rb +19 -0
  63. data/lib/babushka/pkg_helpers/yum_helper.rb +1 -1
  64. data/lib/babushka/popen.rb +13 -10
  65. data/lib/babushka/prompt.rb +14 -1
  66. data/lib/babushka/renderable.rb +11 -9
  67. data/lib/babushka/resource.rb +5 -166
  68. data/lib/babushka/run_reporter.rb +12 -3
  69. data/lib/babushka/shell.rb +54 -44
  70. data/lib/babushka/source.rb +41 -20
  71. data/lib/babushka/source_pool.rb +20 -13
  72. data/lib/babushka/system_definitions.rb +11 -3
  73. data/lib/babushka/system_detector.rb +31 -0
  74. data/lib/babushka/system_matcher.rb +53 -0
  75. data/lib/babushka/system_profile.rb +67 -89
  76. data/lib/babushka/task.rb +36 -8
  77. data/lib/babushka/{meta_dep_context.rb → templated_dep_context.rb} +1 -1
  78. data/lib/babushka/vars.rb +46 -4
  79. data/lib/babushka/version_of.rb +35 -17
  80. data/lib/babushka/version_str.rb +12 -8
  81. data/lib/components.rb +9 -8
  82. data/lib/fancypath/fancypath.rb +109 -83
  83. data/lib/inkan/inkan.rb +14 -14
  84. data/lib/{babushka → levenshtein}/levenshtein.rb +0 -0
  85. data/spec/acceptance/acceptance.rb +4 -4
  86. data/spec/acceptance_helper.rb +10 -6
  87. data/spec/babushka/accepts_for_spec.rb +137 -142
  88. data/spec/babushka/accepts_for_support.rb +13 -6
  89. data/spec/babushka/asset_spec.rb +165 -0
  90. data/spec/babushka/cmdline/help_spec.rb +11 -9
  91. data/spec/babushka/cmdline/meet_spec.rb +15 -0
  92. data/spec/babushka/cmdline/version_spec.rb +1 -1
  93. data/spec/babushka/core_patches_spec.rb +9 -0
  94. data/spec/babushka/current_ruby_spec.rb +73 -0
  95. data/spec/babushka/dep_context_spec.rb +27 -13
  96. data/spec/babushka/dep_definer_spec.rb +108 -16
  97. data/spec/babushka/dep_spec.rb +87 -104
  98. data/spec/babushka/dep_template_spec.rb +176 -0
  99. data/spec/babushka/deps_spec.rb +48 -19
  100. data/spec/babushka/gem_helper_spec.rb +46 -59
  101. data/spec/babushka/git_repo_spec.rb +242 -51
  102. data/spec/babushka/ip_spec.rb +11 -11
  103. data/spec/babushka/lambda_chooser_spec.rb +47 -9
  104. data/spec/babushka/parameter_spec.rb +21 -0
  105. data/spec/babushka/path_checker_spec.rb +35 -0
  106. data/spec/babushka/path_helpers_spec.rb +51 -50
  107. data/spec/babushka/prompt_spec.rb +4 -4
  108. data/spec/babushka/renderable_spec.rb +61 -28
  109. data/spec/babushka/shell_helpers_spec.rb +110 -85
  110. data/spec/babushka/shell_spec.rb +15 -0
  111. data/spec/babushka/source_pool_spec.rb +204 -210
  112. data/spec/babushka/source_spec.rb +125 -42
  113. data/spec/babushka/source_support.rb +1 -1
  114. data/spec/babushka/system_profile_spec.rb +86 -49
  115. data/spec/babushka/task_spec.rb +80 -13
  116. data/spec/babushka/vars_spec.rb +2 -1
  117. data/spec/babushka/version_of_spec.rb +29 -2
  118. data/spec/babushka/version_str_spec.rb +91 -65
  119. data/spec/babushka/xml_string_spec.rb +1 -1
  120. data/spec/deps/bad/broken.rb +2 -2
  121. data/spec/deps/bad/working.rb +0 -1
  122. data/spec/deps/good/{meta.rb → template.rb} +0 -0
  123. data/spec/deps/good/test.rb +0 -3
  124. data/spec/deps/outer/deps.rb +0 -2
  125. data/spec/fancypath/fancypath_spec.rb +30 -0
  126. data/spec/inkan/inkan_spec.rb +34 -32
  127. data/spec/spec_helper.rb +7 -50
  128. data/spec/system_detector_spec.rb +70 -0
  129. metadata +163 -177
  130. data/deps/os_x.rb +0 -33
  131. data/deps/templates/ppa.rb +0 -24
  132. data/lib/babushka/core_patches/io.rb +0 -8
  133. data/lib/babushka/dep_runner.rb +0 -85
  134. data/lib/babushka/helpers/suggest_helpers.rb +0 -16
  135. data/lib/babushka/pkg_helpers/base_helper.rb +0 -19
  136. data/lib/babushka/pkg_helpers/macports_helper.rb +0 -22
  137. data/spec/babushka/dep_definer_support.rb +0 -36
  138. data/spec/babushka/meta_dep_definer_spec.rb +0 -127
  139. data/spec/babushka/meta_dep_wrapper_spec.rb +0 -32
  140. data/spec/babushka/resource_spec.rb +0 -141
  141. data/spec/babushka/run_helpers_spec.rb +0 -26
  142. data/spec/babushka/source_pool_support.rb +0 -31
@@ -1,18 +1,15 @@
1
1
  module Babushka
2
- class ResourceError < StandardError
3
- end
4
2
  class Resource
5
- include LogHelpers
6
3
  extend LogHelpers
7
- include ShellHelpers
8
4
  extend ShellHelpers
9
- include PathHelpers
10
5
  extend PathHelpers
11
6
 
12
7
  def self.get url, &block
13
8
  filename = URI.unescape(url.to_s).p.basename
14
9
  if filename.to_s.blank?
15
10
  log_error "Not a valid URL to download: #{url}"
11
+ elsif url.to_s[%r{^git://}]
12
+ GitHelpers.git(url, &block)
16
13
  else
17
14
  download_path = in_download_dir {|path|
18
15
  downloaded_file = download(url, filename)
@@ -25,7 +22,7 @@ module Babushka
25
22
  def self.extract url, &block
26
23
  get url do |download_path|
27
24
  in_build_dir {
28
- Resource.for(download_path).extract(&block)
25
+ Asset.for(download_path).extract(&block)
29
26
  }
30
27
  end
31
28
  end
@@ -45,171 +42,13 @@ module Babushka
45
42
  download URI.escape(location), location.p.basename
46
43
  else
47
44
  success = log_block "Downloading #{url}" do
48
- shell %Q{curl -# -o "#{filename}.tmp" "#{url}" && mv -f "#{filename}.tmp" "#{filename}"}, :progress => /[\d\.]+%/
45
+ shell('curl', '-#', '-o', "#{filename}.tmp", url.to_s, :progress => /[\d\.]+%/) &&
46
+ shell('mv', '-f', "#{filename}.tmp", filename)
49
47
  end
50
48
  filename if success
51
49
  end
52
50
  end
53
51
  end
54
52
 
55
- def self.detect_type_by_extension path
56
- TYPES.keys.detect {|key|
57
- TYPES[key][:exts].any? {|extension|
58
- path.has_extension? extension
59
- }
60
- }
61
- end
62
-
63
- def self.detect_type_by_contents path
64
- TYPES.keys.detect {|key|
65
- shell("file '#{path}'")[TYPES[key][:file_match]]
66
- }
67
- end
68
-
69
- def self.type path
70
- detect_type_by_extension(path) || detect_type_by_contents(path)
71
- end
72
-
73
- TYPES = {
74
- :deb => {:file_match => 'Debian binary package', :exts => %w[deb]},
75
- :pkg => {:file_match => 'xar archive', :exts => %w[pkg]},
76
- :tar => {:file_match => 'tar archive', :exts => %w[tar]},
77
- :gzip => {:file_match => 'gzip compressed data', :exts => %w[tgz tar.gz]},
78
- :bzip2 => {:file_match => 'bzip2 compressed data', :exts => %w[tbz2 tar.bz2]},
79
- :zip => {:file_match => 'Zip archive data', :exts => %w[zip]},
80
- :dmg => {:file_match => 'VAX COFF executable not stripped', :exts => %w[dmg]}
81
- }
82
-
83
- attr_reader :path, :name
84
-
85
- def initialize path, opts = {}
86
- @path = path.p
87
- @name = TYPES[type][:exts].inject(filename) {|fn,t| fn.gsub(/\.#{t}$/, '') }
88
- end
89
-
90
- def filename
91
- path.basename.to_s
92
- end
93
-
94
- def type
95
- self.class.type path
96
- end
97
-
98
- def supported?
99
- !type.nil?
100
- end
101
-
102
- def extract &block
103
- cd(archive_prefix, :create => true) { process_extract(&block) }
104
- end
105
-
106
- def process_extract &block
107
- shell("mkdir -p '#{name}'") and
108
- cd(name) {
109
- unless log_shell("Extracting #{filename}", extract_command)
110
- log_error "Couldn't extract #{path} - probably a bad download."
111
- else
112
- cd(content_subdir) {
113
- block.nil? or block.call(self)
114
- }
115
- end
116
- }
117
- end
118
-
119
- def content_subdir
120
- identity_dirs.reject {|dir|
121
- %w[app pkg bundle tmbundle prefPane].map {|i|
122
- /\.#{i}$/
123
- }.any? {|dont_descend|
124
- dir[dont_descend]
125
- }
126
- }.first
127
- end
128
-
129
- def identity_dirs
130
- everything = Dir.glob('*')
131
- if everything.length == 1 && File.directory?(everything.first)
132
- everything
133
- else
134
- Dir.glob('*/').map {|dir| dir.chomp('/') }.select {|dir|
135
- dir.downcase.gsub(/[ \-_\.]/, '') == name.downcase.gsub(/[ \-_\.]/, '')
136
- }
137
- end
138
- end
139
-
140
- def archive_prefix
141
- BuildPrefix
142
- end
143
- end
144
-
145
- class FileResource < Resource
146
- def extract &block
147
- in_download_dir {
148
- block.call(self)
149
- }
150
- end
151
- end
152
-
153
- class TarResource < Resource
154
- def extract_command
155
- "tar -#{extract_option(type)}xf '#{path}'"
156
- end
157
- def extract_option type
158
- {
159
- :tar => '',
160
- :gzip => 'z',
161
- :bzip2 => 'j'
162
- }[type]
163
- end
164
- end
165
-
166
- class ZipResource < Resource
167
- def extract_command
168
- "unzip -o '#{path}'"
169
- end
170
- end
171
-
172
- class DmgResource < Resource
173
- def extract &block
174
- in_download_dir {
175
- output = log_shell "Attaching #{filename}", "hdiutil attach '#{filename.p.basename}'"
176
- if output.nil?
177
- log_error "Couldn't mount #{filename.p}."
178
- elsif (path = mountpoint_for(output)).nil?
179
- raise "Couldn't find where `hdiutil` mounted #{filename.p}."
180
- else
181
- cd(path) {
182
- block.call(self)
183
- }.tap {
184
- log_shell "Detaching #{filename}", "hdiutil detach '#{path}'"
185
- }
186
- end
187
- }
188
- end
189
-
190
- def mountpoint_for output
191
- output.scan(/\s+(\/Volumes\/[^\n]+)/).flatten.first
192
- end
193
- end
194
-
195
- class Resource
196
- CLASSES = {
197
- :deb => FileResource,
198
- :pkg => FileResource,
199
- :tar => TarResource,
200
- :gzip => TarResource,
201
- :bzip2 => TarResource,
202
- :zip => ZipResource,
203
- :dmg => DmgResource
204
- }
205
-
206
- def self.for path, opts = {}
207
- path = path.p
208
- filename = path.basename.to_s
209
- raise ResourceError, "The archive #{filename} does not exist." unless path.exists?
210
- klass = CLASSES[type(path)]
211
- raise ResourceError, "Don't know how to extract #{filename}." if klass.nil?
212
- klass.new(path, opts)
213
- end
214
53
  end
215
54
  end
@@ -24,7 +24,16 @@ module Babushka
24
24
 
25
25
  def post_report report
26
26
  submit_report_to_webservice(report.p.read).tap {|result|
27
- report.p.rm if result
27
+ if result.is_a?(Net::HTTPSuccess) || result.is_a?(Net::HTTPNotAcceptable)
28
+ # Remove the run on success, and on validation error: retrying
29
+ # won't help that anyway.
30
+ report.p.rm
31
+ else
32
+ # Wait for a moment before trying again, so persistent problems don't
33
+ # slam babushka.me (if it's rejecting the data) or peg our CPU (if
34
+ # the network is down).
35
+ sleep 1
36
+ end
28
37
  }
29
38
  end
30
39
 
@@ -33,8 +42,8 @@ module Babushka
33
42
  Net::HTTP.start('babushka.me') {|http|
34
43
  http.open_timeout = http.read_timeout = 5
35
44
  http.post '/runs.json', data
36
- }.is_a?(Net::HTTPSuccess)
37
- rescue Errno::ECONNREFUSED, SocketError
45
+ }
46
+ rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED, SocketError
38
47
  log_error "Couldn't connect to the babushka webservice." unless Base.task.running?
39
48
  rescue Timeout::Error, Errno::ETIMEDOUT
40
49
  debug "Timeout while submitting run report."
@@ -2,6 +2,8 @@ module Babushka
2
2
  class Shell
3
3
  include LogHelpers
4
4
 
5
+ BUF_SIZE = 1024 * 16
6
+
5
7
  class ShellCommandFailed < StandardError
6
8
  attr_reader :cmd, :stdout, :stderr
7
9
  def initialize cmd, stdout, stderr
@@ -15,17 +17,28 @@ module Babushka
15
17
  end
16
18
  end
17
19
 
18
- attr_reader :cmd, :opts, :env, :result, :stdout, :stderr
20
+ attr_reader :cmd, :opts, :env, :input, :result, :stdout, :stderr
19
21
 
20
22
  def initialize *cmd
21
23
  @opts = cmd.extract_options!
22
- raise "You can't use :spinner and :progress together in Babushka::Shell." if opts[:spinner] && opts[:progress]
24
+ raise ArgumentError, "You can't use :spinner and :progress together in Babushka::Shell." if opts[:spinner] && opts[:progress]
25
+ raise ArgumentError, "wrong number of arguments (0 for 1+)" if cmd.empty?
23
26
  @env = cmd.first.is_a?(Hash) ? cmd.shift : {}
24
27
  @cmd = cmd
28
+ @input = if opts[:input].respond_to?(:read)
29
+ opts[:input]
30
+ elsif !opts[:input].nil?
31
+ StringIO.new(opts[:input])
32
+ end
33
+
25
34
  @progress = nil
35
+ @spinner_offset = -1
36
+ @should_spin = opts[:spinner] && !Base.task.opt(:debug)
26
37
  end
27
38
 
28
- def ok?; result == 0 end
39
+ def ok?
40
+ result == 0
41
+ end
29
42
 
30
43
  def run &block
31
44
  @stdout, @stderr = '', ''
@@ -45,63 +58,60 @@ module Babushka
45
58
 
46
59
  def invoke
47
60
  debug "$ #{@cmd.join(' ')}".colorize('grey')
48
- Babushka::Open3.popen3 @cmd, popen_opts do |stdin,stdout,stderr,thread|
49
- unless @opts[:input].nil?
50
- stdin << @opts[:input]
51
- stdin.close
61
+ Babushka::Open3.popen3 @cmd, popen_opts do |pipe_in, pipe_out, pipe_err, thread|
62
+ read_fds = [pipe_err, pipe_out].reject {|p| p.closed? }
63
+ write_fds = if input.nil?
64
+ pipe_in.close
65
+ []
66
+ else
67
+ [pipe_in]
52
68
  end
53
69
 
54
- spinner_offset = -1
55
- should_spin = @opts[:spinner] && !Base.task.opt(:debug)
70
+ until read_fds.empty?
71
+ to_read, to_write, _ = IO.select(read_fds, write_fds, [])
56
72
 
57
- # For very short-running commands, check for output in a tight loop.
58
- # The sleep below would at least halve the speed of quick #shell calls.
59
- # This means really quick calls (e.g. `whoami`, `pwd`, etc) aren't
60
- # delayed, but the CPU is only pegged for a fraction of a second on
61
- # slower calls (e.g. `gem env`, `make`, etc).
62
- 1_000.times { break if stdout.ready_for_read? || stderr.ready_for_read? }
73
+ read_from(pipe_out, stdout) if to_read.include?(pipe_out)
74
+ read_from(pipe_err, stderr, :stderr) if to_read.include?(pipe_err)
63
75
 
64
- loop {
65
- read_from stdout, @stdout do
66
- print " #{%w[| / - \\][spinner_offset = ((spinner_offset + 1) % 4)]}\b\b" if should_spin
67
- end
68
- read_from stderr, @stderr, :stderr
76
+ read_fds.reject! {|p| p.closed? }
69
77
 
70
- if stdout.closed? && stderr.closed?
71
- break
78
+ if input.nil? || to_write.empty?
79
+ # Nothing to write.
80
+ elsif (buf = input.read(BUF_SIZE)).nil?
81
+ pipe_in.close
82
+ write_fds.delete(pipe_in)
72
83
  else
73
- # We sleep here because otherwise babushka itself would peg the CPU
74
- # while waiting for output from long-running shell commands.
75
- sleep 0.05
84
+ pipe_in.write(buf)
76
85
  end
77
- }
86
+ end
78
87
  end
79
88
  end
80
89
 
81
90
  def read_from io, buf, log_as = nil
82
- while !io.closed? && io.ready_for_read?
83
- output = nil
84
- # Only try reading up to a backspace if we're looking for progress output.
85
- output = io.gets("\r") if @opts[:progress]
86
- output = io.gets if output.nil?
87
-
88
- if output.nil?
89
- io.close
90
- else
91
- debug output.chomp, :log => @opts[:log], :as => log_as
92
- buf << output
93
- if @opts[:progress] && (@progress = output[@opts[:progress]])
94
- print " #{@progress}#{"\b" * (@progress.length + 1)}"
95
- end
96
- yield if block_given?
91
+ output = nil
92
+ # Try reading less than a full line (up to just a backspace) if we're
93
+ # looking for progress output.
94
+ output = io.gets("\r") if opts[:progress]
95
+ output = io.gets if output.nil?
96
+
97
+ if output.nil?
98
+ io.close
99
+ else
100
+ debug output.chomp, :log => opts[:log], :as => log_as
101
+ buf << output
102
+
103
+ if @should_spin
104
+ print " #{%w[| / - \\][@spinner_offset = ((@spinner_offset + 1) % 4)]}\b\b"
105
+ elsif opts[:progress] && (@progress = output[opts[:progress]])
106
+ print " #{@progress}#{"\b" * (@progress.length + 1)}"
97
107
  end
98
108
  end
99
109
  end
100
110
 
101
111
  def popen_opts
102
- {}.tap {|opts|
103
- opts[:chdir] = @opts[:cd].p.to_s if @opts[:cd]
104
- opts[:env] = @env if @env
112
+ {}.tap {|opts_to_pass|
113
+ opts_to_pass[:chdir] = opts[:cd].p.to_s if opts[:cd]
114
+ opts_to_pass[:env] = env if env
105
115
  }
106
116
  end
107
117
  end
@@ -1,8 +1,9 @@
1
1
  module Babushka
2
2
  class SourceError < StandardError
3
3
  end
4
+ class SourceLoadError < LoadError
5
+ end
4
6
  class Source
5
- include GitHelpers
6
7
  include LogHelpers
7
8
  extend LogHelpers
8
9
  extend ShellHelpers
@@ -22,11 +23,14 @@ module Babushka
22
23
  end
23
24
 
24
25
  def self.for_path path
25
- remote = cd(path) { shell "git config remote.origin.url" }
26
- if remote.nil?
27
- Source.new path # local source
28
- else
29
- Source.new remote, :name => path.basename # remote source with custom path
26
+ @sources ||= {}
27
+ @sources[default_name_for_uri(path)] ||= begin
28
+ remote = shell "git config remote.origin.url", :cd => path
29
+ if remote.nil?
30
+ Source.new path # local source
31
+ else
32
+ Source.new remote, :name => default_name_for_uri(path) # remote source with custom path
33
+ end
30
34
  end
31
35
  end
32
36
 
@@ -44,8 +48,10 @@ module Babushka
44
48
  [nil, :implicit]
45
49
  elsif path.to_s.sub(/^\w+:\/\//, '')[/^[^\/]+[@:]/]
46
50
  [path.to_s, :private]
47
- elsif path.to_s[/^(git|https?|file):\/\//]
51
+ elsif path.to_s[/^git:\/\//]
48
52
  [path.to_s, :public]
53
+ elsif path.to_s[/^\w+:\/\//]
54
+ [path.to_s, :private]
49
55
  else
50
56
  [path.p, :local]
51
57
  end
@@ -85,8 +91,9 @@ module Babushka
85
91
  def prefix
86
92
  self.class.source_prefix
87
93
  end
94
+
88
95
  def path
89
- if implicit? || local?
96
+ @path ||= if implicit? || local?
90
97
  @uri
91
98
  else
92
99
  prefix / name
@@ -100,6 +107,7 @@ module Babushka
100
107
  def updated_at
101
108
  Time.now - File.mtime(path)
102
109
  end
110
+
103
111
  def description_pieces
104
112
  [
105
113
  name,
@@ -108,21 +116,27 @@ module Babushka
108
116
  ("#{updated_at.round.xsecs} ago" if cloneable?)
109
117
  ]
110
118
  end
119
+
111
120
  def type
112
121
  @type
113
122
  end
123
+
114
124
  def cloneable?
115
125
  [:public, :private].include? type
116
126
  end
127
+
117
128
  def cloned?
118
- File.directory? path / '.git'
129
+ cloneable? && File.directory?(path / '.git')
119
130
  end
131
+
120
132
  def present?
121
133
  cloneable? ? cloned? : path.exists?
122
134
  end
135
+
123
136
  def local?
124
137
  type == :local
125
138
  end
139
+
126
140
  def implicit?
127
141
  type == :implicit
128
142
  end
@@ -145,10 +159,15 @@ module Babushka
145
159
  end
146
160
  end
147
161
 
148
- def load!
162
+ def clear!
163
+ deps.clear!
164
+ templates.clear!
165
+ end
166
+
167
+ def load! should_update = false
149
168
  unless @currently_loading
150
169
  @currently_loading = true
151
- update! if cloneable?
170
+ update! if cloneable? && (!cloned? || should_update)
152
171
  load_deps! unless implicit? # implicit sources can't be loaded.
153
172
  @currently_loading = false
154
173
  end
@@ -158,18 +177,15 @@ module Babushka
158
177
  unless @loaded
159
178
  path.p.glob('**/*.rb').each {|f|
160
179
  Base.sources.load_context :source => self, :path => f do
161
- begin
162
- load f
163
- rescue Exception => e
164
- log_error "#{e.backtrace.first}: #{e.message}"
165
- log "Check #{(e.backtrace.detect {|l| l[f] } || f).sub(/\:in [^:]+$/, '')}."
166
- debug e.backtrace * "\n"
167
- end
180
+ load f
168
181
  end
169
182
  }
170
- debug "Loaded #{deps.count} deps from #{path}." unless deps.count.zero?
183
+ debug "Loaded #{deps.count} deps from #{path}."
171
184
  @loaded = true
172
185
  end
186
+ rescue StandardError, SyntaxError => e
187
+ clear!
188
+ raise SourceLoadError.new(e.message).tap {|raised| raised.set_backtrace(e.backtrace) }
173
189
  end
174
190
 
175
191
  def update!
@@ -184,15 +200,20 @@ module Babushka
184
200
  elsif repo.exists? && repo.dirty?
185
201
  log "Not updating #{name} (#{path}) because there are local changes."
186
202
  elsif repo.exists? && repo.ahead?
203
+ @updated = false # So the ahead? check doesn't run again, for when there's no network.
187
204
  log "Not updating #{name} (#{path}) because it's ahead of origin."
188
205
  else
189
- git(uri, :to => path, :log => true).tap {|result|
206
+ GitHelpers.git(uri, :to => path, :log => true).tap {|result|
190
207
  log "Marking #{uri} as offline for this run." unless result
191
208
  @updated = result || false
192
209
  }
193
210
  end
194
211
  end
195
212
 
213
+ def remove!
214
+ !cloneable? || !path.exists? || path.rm
215
+ end
216
+
196
217
  private
197
218
 
198
219
  def raise_unless_addable!