| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | require "cgi" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # We abuse Homebrew's download strategies considerably here. | 
					
						
							|  |  |  | # * Our downloader instances only invoke the fetch and | 
					
						
							|  |  |  | #   clear_cache methods, ignoring stage | 
					
						
							|  |  |  | # * Our overridden fetch methods are expected to return | 
					
						
							|  |  |  | #   a value: the successfully downloaded file. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  | module Hbc | 
					
						
							|  |  |  |   class AbstractDownloadStrategy | 
					
						
							|  |  |  |     attr_reader :cask, :name, :url, :uri_object, :version | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def initialize(cask, command = SystemCommand) | 
					
						
							|  |  |  |       @cask       = cask | 
					
						
							|  |  |  |       @command    = command | 
					
						
							|  |  |  |       # TODO: this excess of attributes is a function of integrating | 
					
						
							|  |  |  |       #       with Homebrew's classes. Later we should be able to remove | 
					
						
							|  |  |  |       #       these in favor of @cask | 
					
						
							|  |  |  |       @name       = cask.token | 
					
						
							|  |  |  |       @url        = cask.url.to_s | 
					
						
							|  |  |  |       @uri_object = cask.url | 
					
						
							|  |  |  |       @version    = cask.version | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     # All download strategies are expected to implement these methods | 
					
						
							|  |  |  |     def fetch; end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def cached_location; end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def clear_cache; end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |   class HbVCSDownloadStrategy < AbstractDownloadStrategy | 
					
						
							|  |  |  |     REF_TYPES = [:branch, :revision, :revisions, :tag].freeze | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def initialize(cask, command = SystemCommand) | 
					
						
							|  |  |  |       super | 
					
						
							|  |  |  |       @ref_type, @ref = extract_ref | 
					
						
							|  |  |  |       @clone = Hbc.cache.join(cache_filename) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def extract_ref | 
					
						
							| 
									
										
										
										
											2016-10-23 14:44:14 +02:00
										 |  |  |       key = REF_TYPES.find do |type| | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |         uri_object.respond_to?(type) && uri_object.send(type) | 
					
						
							| 
									
										
										
										
											2016-10-23 14:44:14 +02:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |       [key, key ? uri_object.send(key) : nil] | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def cache_filename | 
					
						
							|  |  |  |       "#{name}--#{cache_tag}" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def cache_tag | 
					
						
							|  |  |  |       "__UNKNOWN__" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def cached_location | 
					
						
							|  |  |  |       @clone | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def clear_cache | 
					
						
							|  |  |  |       cached_location.rmtree if cached_location.exist? | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |   class CurlDownloadStrategy < AbstractDownloadStrategy | 
					
						
							|  |  |  |     # TODO: should be part of url object | 
					
						
							|  |  |  |     def mirrors | 
					
						
							|  |  |  |       @mirrors ||= [] | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def tarball_path | 
					
						
							|  |  |  |       @tarball_path ||= Hbc.cache.join("#{name}--#{version}#{ext}") | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def temporary_path | 
					
						
							| 
									
										
										
										
											2016-10-14 20:03:34 +02:00
										 |  |  |       @temporary_path ||= tarball_path.sub(/$/, ".incomplete") | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def cached_location | 
					
						
							|  |  |  |       tarball_path | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def clear_cache | 
					
						
							|  |  |  |       [cached_location, temporary_path].each do |f| | 
					
						
							|  |  |  |         next unless f.exist? | 
					
						
							|  |  |  |         raise CurlDownloadStrategyError, "#{f} is in use by another process" if Utils.file_locked?(f) | 
					
						
							|  |  |  |         f.unlink | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def downloaded_size | 
					
						
							|  |  |  |       temporary_path.size? || 0
 | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def _fetch | 
					
						
							|  |  |  |       odebug "Calling curl with args #{cask_curl_args.utf8_inspect}" | 
					
						
							|  |  |  |       curl(*cask_curl_args) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def fetch | 
					
						
							|  |  |  |       ohai "Downloading #{@url}" | 
					
						
							|  |  |  |       if tarball_path.exist? | 
					
						
							|  |  |  |         puts "Already downloaded: #{tarball_path}" | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         had_incomplete_download = temporary_path.exist? | 
					
						
							|  |  |  |         begin | 
					
						
							| 
									
										
										
										
											2016-10-25 16:46:59 +09:00
										 |  |  |           File.open(temporary_path, "a+") do |f| | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |             f.flock(File::LOCK_EX) | 
					
						
							|  |  |  |             _fetch | 
					
						
							|  |  |  |             f.flock(File::LOCK_UN) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         rescue ErrorDuringExecution | 
					
						
							|  |  |  |           # 33 == range not supported | 
					
						
							|  |  |  |           # try wiping the incomplete download and retrying once | 
					
						
							|  |  |  |           if $CHILD_STATUS.exitstatus == 33 && had_incomplete_download | 
					
						
							|  |  |  |             ohai "Trying a full download" | 
					
						
							|  |  |  |             temporary_path.unlink | 
					
						
							|  |  |  |             had_incomplete_download = false | 
					
						
							|  |  |  |             retry | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           msg = @url | 
					
						
							|  |  |  |           msg.concat("\nThe incomplete download is cached at #{temporary_path}") if temporary_path.exist? | 
					
						
							|  |  |  |           raise CurlDownloadStrategyError, msg | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |         ignore_interrupts { temporary_path.rename(tarball_path) } | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |       tarball_path | 
					
						
							|  |  |  |     rescue CurlDownloadStrategyError | 
					
						
							|  |  |  |       raise if mirrors.empty? | 
					
						
							|  |  |  |       puts "Trying a mirror..." | 
					
						
							|  |  |  |       @url = mirrors.shift | 
					
						
							|  |  |  |       retry | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     private | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def cask_curl_args | 
					
						
							|  |  |  |       default_curl_args.tap do |args| | 
					
						
							|  |  |  |         args.concat(user_agent_args) | 
					
						
							|  |  |  |         args.concat(cookies_args) | 
					
						
							|  |  |  |         args.concat(referer_args) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def default_curl_args | 
					
						
							|  |  |  |       [url, "-C", downloaded_size, "-o", temporary_path] | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def user_agent_args | 
					
						
							|  |  |  |       if uri_object.user_agent | 
					
						
							|  |  |  |         ["-A", uri_object.user_agent] | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         [] | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def cookies_args | 
					
						
							|  |  |  |       if uri_object.cookies | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |           "-b", | 
					
						
							|  |  |  |           # sort_by is for predictability between Ruby versions | 
					
						
							|  |  |  |           uri_object | 
					
						
							|  |  |  |             .cookies | 
					
						
							|  |  |  |             .sort_by(&:to_s) | 
					
						
							|  |  |  |             .map { |key, value| "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}" } | 
					
						
							|  |  |  |             .join(";"), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         [] | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def referer_args | 
					
						
							|  |  |  |       if uri_object.referer | 
					
						
							|  |  |  |         ["-e", uri_object.referer] | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         [] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def ext | 
					
						
							|  |  |  |       Pathname.new(@url).extname | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |   class CurlPostDownloadStrategy < CurlDownloadStrategy | 
					
						
							|  |  |  |     def cask_curl_args | 
					
						
							|  |  |  |       super | 
					
						
							|  |  |  |       default_curl_args.concat(post_args) | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def post_args | 
					
						
							|  |  |  |       if uri_object.data | 
					
						
							|  |  |  |         # sort_by is for predictability between Ruby versions | 
					
						
							|  |  |  |         uri_object | 
					
						
							|  |  |  |           .data | 
					
						
							|  |  |  |           .sort_by(&:to_s) | 
					
						
							|  |  |  |           .map { |key, value| ["-d", "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"] } | 
					
						
							|  |  |  |           .flatten | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         ["-X", "POST"] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |   class SubversionDownloadStrategy < HbVCSDownloadStrategy | 
					
						
							|  |  |  |     def cache_tag | 
					
						
							|  |  |  |       # TODO: pass versions as symbols, support :head here | 
					
						
							|  |  |  |       version == "head" ? "svn-HEAD" : "svn" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def repo_valid? | 
					
						
							|  |  |  |       @clone.join(".svn").directory? | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def repo_url | 
					
						
							| 
									
										
										
										
											2016-10-14 20:03:34 +02:00
										 |  |  |       `svn info '#{@clone}' 2>/dev/null`.strip[/^URL: (.+)$/, 1] | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     # super does not provide checks for already-existing downloads | 
					
						
							|  |  |  |     def fetch | 
					
						
							|  |  |  |       if tarball_path.exist? | 
					
						
							|  |  |  |         puts "Already downloaded: #{tarball_path}" | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											2016-10-14 20:03:34 +02:00
										 |  |  |         @url = @url.sub(/^svn\+/, "") if @url =~ %r{^svn\+http://} | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |         ohai "Checking out #{@url}" | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |         clear_cache unless @url.chomp("/") == repo_url || quiet_system("svn", "switch", @url, @clone) | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |         if @clone.exist? && !repo_valid? | 
					
						
							|  |  |  |           puts "Removing invalid SVN repo from cache" | 
					
						
							|  |  |  |           clear_cache | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |         case @ref_type | 
					
						
							|  |  |  |         when :revision | 
					
						
							|  |  |  |           fetch_repo @clone, @url, @ref | 
					
						
							|  |  |  |         when :revisions | 
					
						
							|  |  |  |           # nil is OK for main_revision, as fetch_repo will then get latest | 
					
						
							|  |  |  |           main_revision = @ref[:trunk] | 
					
						
							|  |  |  |           fetch_repo @clone, @url, main_revision, true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           fetch_externals do |external_name, external_url| | 
					
						
							|  |  |  |             fetch_repo @clone + external_name, external_url, @ref[external_name], true | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           fetch_repo @clone, @url | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |         compress | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |       tarball_path | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     # This primary reason for redefining this method is the trust_cert | 
					
						
							|  |  |  |     # option, controllable from the Cask definition. We also force | 
					
						
							|  |  |  |     # consistent timestamps.  The rest of this method is similar to | 
					
						
							|  |  |  |     # Homebrew's, but translated to local idiom. | 
					
						
							|  |  |  |     def fetch_repo(target, url, revision = uri_object.revision, ignore_externals = false) | 
					
						
							|  |  |  |       # Use "svn up" when the repository already exists locally. | 
					
						
							|  |  |  |       # This saves on bandwidth and will have a similar effect to verifying the | 
					
						
							|  |  |  |       # cache as it will make any changes to get the right revision. | 
					
						
							|  |  |  |       svncommand = target.directory? ? "up" : "checkout" | 
					
						
							|  |  |  |       args = [svncommand] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # SVN shipped with XCode 3.1.4 can't force a checkout. | 
					
						
							|  |  |  |       args << "--force" unless MacOS.version == :leopard | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # make timestamps consistent for checksumming | 
					
						
							|  |  |  |       args.concat(%w[--config-option config:miscellany:use-commit-times=yes]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if uri_object.trust_cert | 
					
						
							|  |  |  |         args << "--trust-server-cert" | 
					
						
							|  |  |  |         args << "--non-interactive" | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |       args << url unless target.directory? | 
					
						
							|  |  |  |       args << target | 
					
						
							|  |  |  |       args << "-r" << revision if revision | 
					
						
							|  |  |  |       args << "--ignore-externals" if ignore_externals | 
					
						
							|  |  |  |       @command.run!("/usr/bin/svn", | 
					
						
							|  |  |  |                     args:         args, | 
					
						
							|  |  |  |                     print_stderr: false) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def tarball_path | 
					
						
							|  |  |  |       @tarball_path ||= cached_location.dirname.join(cached_location.basename.to_s + "-#{@cask.version}.tar") | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def shell_quote(str) | 
					
						
							|  |  |  |       # Oh god escaping shell args. | 
					
						
							|  |  |  |       # See http://notetoself.vrensk.com/2008/08/escaping-single-quotes-in-ruby-harder-than-expected/ | 
					
						
							| 
									
										
										
										
											2016-10-14 20:03:34 +02:00
										 |  |  |       str.gsub(/\\|'/) { |c| "\\#{c}" } | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |     def fetch_externals | 
					
						
							|  |  |  |       `svn propget svn:externals '#{shell_quote(@url)}'`.chomp.each_line do |line| | 
					
						
							| 
									
										
										
										
											2016-10-14 20:03:34 +02:00
										 |  |  |         name, url = line.split(/\s+/) | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |         yield name, url | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # TODO/UPDATE: the tar approach explained below is fragile | 
					
						
							|  |  |  |     # against challenges such as case-sensitive filesystems, | 
					
						
							|  |  |  |     # and must be re-implemented. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # Seems nutty: we "download" the contents into a tape archive. | 
					
						
							|  |  |  |     # Why? | 
					
						
							|  |  |  |     # * A single file is tractable to the rest of the Cask toolchain, | 
					
						
							|  |  |  |     # * An alternative would be to create a Directory container type. | 
					
						
							|  |  |  |     #   However, some type of file-serialization trick would still be | 
					
						
							|  |  |  |     #   needed in order to enable calculating a single checksum over | 
					
						
							|  |  |  |     #   a directory.  So, in that alternative implementation, the | 
					
						
							|  |  |  |     #   special cases would propagate outside this class, including | 
					
						
							|  |  |  |     #   the use of tar or equivalent. | 
					
						
							|  |  |  |     # * SubversionDownloadStrategy.cached_location is not versioned | 
					
						
							|  |  |  |     # * tarball_path provides a needed return value for our overridden | 
					
						
							|  |  |  |     #   fetch method. | 
					
						
							|  |  |  |     # * We can also take this private opportunity to strip files from | 
					
						
							|  |  |  |     #   the download which are protocol-specific. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def compress | 
					
						
							|  |  |  |       Dir.chdir(cached_location) do | 
					
						
							|  |  |  |         @command.run!("/usr/bin/tar", | 
					
						
							|  |  |  |                       args:         ['-s/^\.//', "--exclude", ".svn", "-cf", Pathname.new(tarball_path), "--", "."], | 
					
						
							|  |  |  |                       print_stderr: false) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       clear_cache | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |