carthage_remote_cache 0.0.8 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,10 @@
1
- require 'concurrent'
1
+ require "concurrent"
2
2
 
3
3
  class UploadCommand
4
4
  def self.new_with_defaults(options)
5
5
  shell = ShellWrapper.new
6
6
  config = Configuration.new(shell)
7
- networking = Networking.new(config)
7
+ networking = Networking.new(config, options[:is_retry_enabled])
8
8
  api = API.new(shell, config, networking, options)
9
9
 
10
10
  UploadCommand.new(
@@ -62,7 +62,7 @@ class UploadCommand
62
62
  def upload(carthage_dependency)
63
63
  version_file = carthage_dependency.new_version_file
64
64
 
65
- if @api.version_file_matches_server?(carthage_dependency, version_file)
65
+ if @api.version_file_matches_server?(carthage_dependency, version_file, nil)
66
66
  $LOG.debug("Version file #{version_file.path} matches server version, skipping upload")
67
67
  @mutex.synchronize do
68
68
  @number_of_skipped_archives += version_file.number_of_frameworks
@@ -72,9 +72,9 @@ class UploadCommand
72
72
 
73
73
  @networking.upload_version_file(carthage_dependency)
74
74
 
75
- version_file.frameworks_by_platform.each do |platform, framework_names|
76
- for framework_name in framework_names
77
- archive_size = @api.create_and_upload_archive(carthage_dependency, framework_name, platform)
75
+ version_file.frameworks_by_platform.each do |platform, frameworks|
76
+ for framework in frameworks
77
+ archive_size = @api.create_and_upload_archive(carthage_dependency, framework, platform)
78
78
  @mutex.synchronize do
79
79
  @number_of_uploaded_archives += 1
80
80
  @total_archive_size += archive_size
@@ -2,7 +2,7 @@ class VerifyCommand
2
2
  def self.new_with_defaults(options)
3
3
  shell = ShellWrapper.new
4
4
  config = Configuration.new(shell)
5
- networking = Networking.new(config)
5
+ networking = Networking.new(config, options[:is_retry_enabled])
6
6
  api = API.new(shell, config, networking, options)
7
7
 
8
8
  VerifyCommand.new(api: api)
data/lib/commands.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  lib = File.expand_path("..", __FILE__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
- require 'commands/download_command'
5
- require 'commands/init_command'
6
- require 'commands/server_command'
7
- require 'commands/upload_command'
8
- require 'commands/verify_command'
4
+ require "commands/download_command"
5
+ require "commands/init_command"
6
+ require "commands/server_command"
7
+ require "commands/upload_command"
8
+ require "commands/verify_command"
data/lib/configuration.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'uri'
1
+ require "uri"
2
2
 
3
3
  class Configuration
4
4
  class UserConfig
data/lib/constants.rb CHANGED
@@ -1,12 +1,14 @@
1
- CARTHAGE_DIR = 'Carthage'
2
- CARTHAGE_BUILD_DIR = File.join(CARTHAGE_DIR, 'Build')
3
- CARTFILE_RESOLVED = 'Cartfile.resolved'
4
- CARTRCFILE = 'Cartrcfile'
1
+ CARTHAGE_DIR = "Carthage"
2
+ CARTHAGE_BUILD_DIR = File.join(CARTHAGE_DIR, "Build")
3
+ CARTFILE_RESOLVED = "Cartfile.resolved"
4
+ CARTRCFILE = "Cartrcfile"
5
5
  THREAD_POOL_SIZE = 8
6
6
 
7
7
  SERVER_DEFAULT_PORT = 9292
8
- SERVER_CACHE_DIR = File.join(Dir.home, '.carthagerc_server')
8
+ SERVER_CACHE_DIR = File.join(Dir.home, ".carthagerc_server")
9
9
 
10
10
  ARCHIVE_CHECKSUM_HEADER_REST_CLIENT = :archive_checksum
11
- ARCHIVE_CHECKSUM_HEADER_SINATRA_IN = 'HTTP_ARCHIVE_CHECKSUM'
12
- ARCHIVE_CHECKSUM_HEADER_SINATRA_OUT = 'Archive-Checksum'
11
+ ARCHIVE_CHECKSUM_HEADER_SINATRA_IN = "HTTP_ARCHIVE_CHECKSUM"
12
+ ARCHIVE_CHECKSUM_HEADER_SINATRA_OUT = "Archive-Checksum"
13
+
14
+ PLATFORMS = [:iOS, :macOS, :tvOS, :watchOS]
data/lib/crc32.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'digest'
2
- require 'zlib'
1
+ require "digest"
2
+ require "zlib"
3
3
 
4
4
  class Digest::CRC32 < Digest::Class
5
5
  include Digest::Instance
@@ -17,6 +17,6 @@ class Digest::CRC32 < Digest::Class
17
17
  end
18
18
 
19
19
  def finish
20
- [@crc32].pack('N')
20
+ [@crc32].pack("N")
21
21
  end
22
22
  end
data/lib/errors.rb CHANGED
@@ -51,7 +51,7 @@ class FrameworkValidationError < AppError
51
51
  end
52
52
 
53
53
  def to_s
54
- header = ['Framework', CARTHAGE_BUILD_DIR, CARTFILE_RESOLVED]
54
+ header = ["Framework", CARTHAGE_BUILD_DIR, CARTFILE_RESOLVED]
55
55
  rows = @errors.map { |e| [e.framework_name, e.build_version, e.cartfile_resolved_version] }
56
56
  table = Table.new(header, rows)
57
57
  <<~EOS
@@ -69,3 +69,14 @@ end
69
69
  class MissingFrameworkDirectoryError < AppError; end
70
70
 
71
71
  class ServerVersionMismatchError < AppError; end
72
+
73
+ class PlatformMismatchError < AppError
74
+ def initialize(platform)
75
+ @platform = platform
76
+ end
77
+
78
+ def to_s
79
+ platforms = PLATFORMS.map(&:to_s).join(", ")
80
+ "Platform '#{@platform}' doesn't match any of: #{platforms}"
81
+ end
82
+ end
data/lib/framework.rb ADDED
@@ -0,0 +1,19 @@
1
+ # Example data:
2
+ # - "name" : "Sentry",
3
+ # - "linking" : "dynamic"
4
+ class Framework
5
+ attr_reader :name
6
+
7
+ def self.parse(json)
8
+ Framework.new(json["name"], json["linking"])
9
+ end
10
+
11
+ def initialize(name, linking)
12
+ @name = name
13
+ @linking = linking
14
+ end
15
+
16
+ def make_archive(platform)
17
+ FrameworkCarthageArchive.new(name, platform)
18
+ end
19
+ end
@@ -0,0 +1,57 @@
1
+ require "fileutils"
2
+
3
+ class FrameworkCarthageArchive < CarthageArchive
4
+
5
+ # Aggregate following files:
6
+ # - Carthage/Build/iOS/Alamofire.framework
7
+ # - Carthage/Build/iOS/Alamofire.framework/Alamofire
8
+ # - Carthage/Build/iOS/618BEB79-4C7F-3692-B140-131FB983AC5E.bcsymbolmap
9
+ # into Alamofire-iOS.zip
10
+ def compress_archive(shell, carthage_build_dir = CARTHAGE_BUILD_DIR)
11
+ $LOG.debug("Archiving #{@framework_name} for #{@platform}")
12
+
13
+ platform_path = File.join(carthage_build_dir, platform_to_carthage_dir_string(@platform))
14
+ framework_path = File.join(platform_path, "#{@framework_name}.framework")
15
+ raise MissingFrameworkDirectoryError.new, "Archive can't be created, no framework directory at #{framework_path}" unless Dir.exist?(framework_path)
16
+
17
+ # It's very likely, that binary releases don't contain DSYMs.
18
+ dsym_path = File.join(platform_path, "#{@framework_name}.framework.dSYM")
19
+ unless File.exist?(dsym_path)
20
+ $LOG.error("DSYM File #{dsym_path} not found, continuing")
21
+ dsym_path = nil
22
+ end
23
+
24
+ binary_path = File.join(framework_path, @framework_name)
25
+ raise AppError.new, "Binary #{binary_path} is missing, failed to read .bcsymbolmap files" unless File.exist?(binary_path)
26
+
27
+ bcsymbolmap_paths = find_bcsymbolmap_paths(shell, platform_path, binary_path)
28
+
29
+ input_paths = []
30
+ input_paths << framework_path
31
+ input_paths << dsym_path unless dsym_path.nil?
32
+ input_paths += bcsymbolmap_paths
33
+
34
+ $LOG.debug("Adding > #{input_paths.inspect}")
35
+
36
+ delete_archive
37
+ shell.archive(input_paths, @archive_path)
38
+ $LOG.debug("Created #{@archive_path} archive, file size: #{formatted_archive_size}")
39
+ end
40
+
41
+ private
42
+
43
+ def find_bcsymbolmap_paths(shell, platform_path, binary_path)
44
+ raw_dwarfdump = shell.dwarfdump(binary_path)
45
+ uuids = parse_uuids(raw_dwarfdump)
46
+ bcsymbolmap_paths = uuids.map { |uuid| File.join(platform_path, "#{uuid}.bcsymbolmap") }.select { |path| File.exist?(path) }
47
+ bcsymbolmap_paths
48
+ end
49
+
50
+ # Example dwarfdump link:
51
+ # UUID: 618BEB79-4C7F-3692-B140-131FB983AC5E (i386) Carthage/Build/iOS/CocoaLumberjackSwift.framework/CocoaLumberjackSwift
52
+ def parse_uuids(raw_dwarfdump)
53
+ lines = raw_dwarfdump.split("\n")
54
+ uuids = lines.map { |line| line[/^UUID: ([A-Z0-9\-]+)\s+\(.*$/, 1] }
55
+ uuids.compact
56
+ end
57
+ end
data/lib/log.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'logger'
1
+ require "logger"
2
2
 
3
3
  $LOG = Logger.new(STDOUT)
4
4
  $LOG.level = Logger::INFO
data/lib/networking.rb CHANGED
@@ -1,9 +1,10 @@
1
- require 'rest-client'
2
- require 'uri'
1
+ require "rest-client"
2
+ require "uri"
3
3
 
4
4
  class Networking
5
- def initialize(config)
5
+ def initialize(config, is_retry_enabled)
6
6
  @config = config
7
+ @is_retry_enabled = is_retry_enabled
7
8
  end
8
9
 
9
10
  # Version
@@ -11,11 +12,13 @@ class Networking
11
12
  def get_server_version
12
13
  url = new_version_url
13
14
  $LOG.debug("Fetching server version from #{url}")
14
- server_version = RestClient.get(url) do |response, request, result|
15
- if response.code == 200
16
- response.strip
17
- else
18
- raise AppError.new, "Failed to read server version from #{url}, response:\n #{response[0...300]}"
15
+ server_version = perform_network_request do
16
+ RestClient.get(url) do |response, request, result|
17
+ if response.code == 200
18
+ response.strip
19
+ else
20
+ raise AppError.new, "Failed to read server version from #{url}, response:\n #{response[0...300]}"
21
+ end
19
22
  end
20
23
  end
21
24
  server_version
@@ -24,15 +27,22 @@ class Networking
24
27
  # Version Files
25
28
 
26
29
  # @return VersionFile or nil
27
- def download_version_file(carthage_dependency)
30
+ def download_version_file(carthage_dependency, platforms)
28
31
  url = new_version_file_url(carthage_dependency)
29
- $LOG.debug("Downloading version file from #{url}")
30
- version_file = RestClient.get(url) do |response, request, result|
31
- if response.code == 200
32
- File.write(carthage_dependency.version_filename, response.to_s)
33
- VersionFile.new(carthage_dependency.version_filename)
34
- else
35
- nil
32
+ params = {}
33
+ unless platforms.nil?
34
+ params[:platform] = platforms.map(&:to_s).join(",")
35
+ end
36
+
37
+ version_file = perform_network_request do
38
+ $LOG.debug("Downloading version file from #{url}, params: #{params}")
39
+ RestClient.get(url, { params: params }) do |response, request, result|
40
+ if response.code == 200
41
+ File.write(carthage_dependency.version_filename, response.to_s)
42
+ VersionFile.new(carthage_dependency.version_filename)
43
+ else
44
+ nil
45
+ end
36
46
  end
37
47
  end
38
48
  version_file
@@ -41,10 +51,12 @@ class Networking
41
51
  # @raise AppError on upload failure
42
52
  def upload_version_file(carthage_dependency)
43
53
  url = new_version_file_url(carthage_dependency)
44
- $LOG.debug("Uploading #{carthage_dependency.version_filename}")
45
- RestClient.post(url, :version_file => File.new(carthage_dependency.version_filepath)) do |response, request, result|
46
- unless response.code == 200
47
- raise AppError.new, "Version file upload #{carthage_dependency.version_filename} failed, response:\n #{response[0..300]}"
54
+ perform_network_request do
55
+ $LOG.debug("Uploading #{carthage_dependency.version_filename}")
56
+ RestClient.post(url, :version_file => File.new(carthage_dependency.version_filepath)) do |response, request, result|
57
+ unless response.code == 200
58
+ raise AppError.new, "Version file upload #{carthage_dependency.version_filename} failed, response:\n #{response[0..300]}"
59
+ end
48
60
  end
49
61
  end
50
62
  end
@@ -52,16 +64,18 @@ class Networking
52
64
  # Archives
53
65
 
54
66
  # @return Hash with CarthageArchive and checksum or nil
55
- def download_framework_archive(carthage_dependency, framework_name, platform)
56
- url = new_framework_url(carthage_dependency, framework_name, platform)
57
- $LOG.debug("Downloading framework from #{url}")
58
- archive = RestClient.get(url) do |response, request, result|
59
- if response.code == 200
60
- archive = CarthageArchive.new(framework_name, platform)
61
- File.write(archive.archive_path, response.to_s)
62
- {:archive => archive, :checksum => response.headers[ARCHIVE_CHECKSUM_HEADER_REST_CLIENT]}
63
- else
64
- nil
67
+ def download_framework_archive(carthage_dependency, framework, platform)
68
+ url = new_framework_url(carthage_dependency, framework.name, platform)
69
+ archive = perform_network_request do
70
+ $LOG.debug("Downloading framework from #{url}")
71
+ RestClient.get(url) do |response, request, result|
72
+ if response.code == 200
73
+ archive = framework.make_archive(platform)
74
+ File.write(archive.archive_path, response.to_s)
75
+ { :archive => archive, :checksum => response.headers[ARCHIVE_CHECKSUM_HEADER_REST_CLIENT] }
76
+ else
77
+ nil
78
+ end
65
79
  end
66
80
  end
67
81
  archive
@@ -70,12 +84,14 @@ class Networking
70
84
  # @raise AppError when upload fails
71
85
  def upload_framework_archive(zipfile_name, carthage_dependency, framework_name, platform, checksum)
72
86
  url = new_framework_url(carthage_dependency, framework_name, platform)
73
- params = {:framework_file => File.new(zipfile_name)}
74
- headers = {ARCHIVE_CHECKSUM_HEADER_REST_CLIENT => checksum}
75
- $LOG.debug("Uploading framework to #{url}, headers: #{headers}")
76
- RestClient.post(url, params, headers) do |response, request, result|
77
- unless response.code == 200
78
- raise AppError.new, "Framework upload #{zipfile_name} failed, response:\n #{response[0..300]}"
87
+ params = { :framework_file => File.new(zipfile_name) }
88
+ headers = { ARCHIVE_CHECKSUM_HEADER_REST_CLIENT => checksum }
89
+ perform_network_request do
90
+ $LOG.debug("Uploading framework to #{url}, headers: #{headers}")
91
+ RestClient.post(url, params, headers) do |response, request, result|
92
+ unless response.code == 200
93
+ raise AppError.new, "Framework upload #{zipfile_name} failed, response:\n #{response[0..300]}"
94
+ end
79
95
  end
80
96
  end
81
97
  end
@@ -83,12 +99,12 @@ class Networking
83
99
  private
84
100
 
85
101
  def new_version_url
86
- new_server_url(['version'])
102
+ new_server_url(["version"])
87
103
  end
88
104
 
89
105
  def new_version_file_url(carthage_dependency)
90
106
  new_server_url([
91
- 'versions',
107
+ "versions",
92
108
  @config.xcodebuild_version,
93
109
  @config.swift_version,
94
110
  carthage_dependency.guessed_framework_basename,
@@ -99,7 +115,7 @@ class Networking
99
115
 
100
116
  def new_framework_url(carthage_dependency, framework_name, platform)
101
117
  new_server_url([
102
- 'frameworks',
118
+ "frameworks",
103
119
  @config.xcodebuild_version,
104
120
  @config.swift_version,
105
121
  carthage_dependency.guessed_framework_basename,
@@ -115,13 +131,37 @@ class Networking
115
131
  :scheme => @config.server_uri.scheme,
116
132
  :host => @config.server_uri.host,
117
133
  :port => @config.server_uri.port,
118
- :path => '/' + sanitized_path_slices.join('/'),
134
+ :path => "/" + sanitized_path_slices.join("/"),
119
135
  )
120
136
  uri.to_s
121
137
  end
122
138
 
123
139
  # Mangle identifiers for URL paths.
124
140
  def sanitized(input)
125
- input.gsub(/\//, '_')
141
+ input.gsub(/\//, "_")
142
+ end
143
+
144
+ def perform_network_request
145
+ if @is_retry_enabled
146
+ retries_remaining = 3
147
+ sleep_time_seconds = 5
148
+ begin
149
+ result = yield
150
+ rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
151
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
152
+ if retries_remaining > 0
153
+ $LOG.warn("Network request failed - remaining retries: #{retries_remaining}, sleeping for: #{sleep_time_seconds}s, error: #{e.message}")
154
+ sleep(sleep_time_seconds)
155
+ retries_remaining -= 1
156
+ sleep_time_seconds *= 3
157
+ retry
158
+ else
159
+ raise e
160
+ end
161
+ end
162
+ result
163
+ else
164
+ yield
165
+ end
126
166
  end
127
167
  end
data/lib/server/config.ru CHANGED
@@ -1,6 +1,6 @@
1
- require 'rubygems'
2
- require 'bundler'
1
+ require "rubygems"
2
+ require "bundler"
3
3
  Bundler.require
4
4
 
5
- require './server_app.rb'
5
+ require "./server_app.rb"
6
6
  run Sinatra::Application
@@ -1,14 +1,21 @@
1
- require 'sinatra'
2
- require 'fileutils'
3
- require 'carthage_remote_cache'
4
-
5
- get '/' do
6
- "Welcome to carthage_remote_cache"
1
+ require "json"
2
+ require "sinatra"
3
+ require "fileutils"
4
+ require "carthage_remote_cache"
5
+
6
+ get "/" do
7
+ <<-eos
8
+ <html>
9
+ <p>Welcome to <strong>carthage_remote_cache</strong> (#{VERSION})</p>
10
+ <p>To browse cache contents visit <a href="/browser/">/browser/</a></p>
11
+ </html>
12
+ eos
7
13
  end
8
14
 
9
- version_path = '/version'
10
- versions_path = '/versions/:xcodebuild_version/:swift_version/:dependency_name/:version/:version_filename'
11
- frameworks_path = '/frameworks/:xcodebuild_version/:swift_version/:dependency_name/:version/:framework_name/:platform'
15
+ version_path = "/version"
16
+ versions_path = "/versions/:xcodebuild_version/:swift_version/:dependency_name/:version/:version_filename"
17
+ frameworks_path = "/frameworks/:xcodebuild_version/:swift_version/:dependency_name/:version/:framework_name/:platform"
18
+ browser_path = "/browser/*"
12
19
 
13
20
  get version_path do
14
21
  status(200)
@@ -16,13 +23,25 @@ get version_path do
16
23
  end
17
24
 
18
25
  get versions_path do
26
+ if params.key?(:platform)
27
+ begin
28
+ platforms = platform_to_symbols(params[:platform])
29
+ rescue AppError => e
30
+ status(400)
31
+ return JSON.pretty_generate({ "error" => e.message })
32
+ end
33
+ else
34
+ platforms = PLATFORMS
35
+ end
36
+
19
37
  dirname = params_to_framework_dir(params)
20
38
  filename = params[:version_filename]
21
39
  filepath = File.join(dirname, filename)
22
40
 
23
41
  if File.exist?(filepath)
24
42
  status(200)
25
- send_file(filepath)
43
+ version_file = VersionFile.new(filepath, platforms)
44
+ JSON.pretty_generate(version_file.json)
26
45
  else
27
46
  status(404)
28
47
  end
@@ -39,7 +58,7 @@ post versions_path do
39
58
  File.delete(target_filename) if File.exist?(target_filename)
40
59
 
41
60
  $LOG.info("Writing: #{target_filename}")
42
- File.open(target_filename, 'wb') do |target_file|
61
+ File.open(target_filename, "wb") do |target_file|
43
62
  target_file.write(source_file.read)
44
63
  end
45
64
 
@@ -75,7 +94,7 @@ post frameworks_path do
75
94
  File.delete(target_filename) if File.exist?(target_filename)
76
95
 
77
96
  $LOG.info("Writing: #{target_filename}")
78
- File.open(target_filename, 'wb') do |target_file|
97
+ File.open(target_filename, "wb") do |target_file|
79
98
  target_file.write(source_file.read)
80
99
  end
81
100
 
@@ -91,6 +110,44 @@ post frameworks_path do
91
110
  end
92
111
  end
93
112
 
113
+ # Full blown file browser.
114
+ get browser_path do
115
+ url_path = "/" + params["splat"][0]
116
+ path = File.join(SERVER_CACHE_DIR, url_path)
117
+
118
+ if File.file?(path)
119
+ status(200)
120
+ send_file(path)
121
+ else
122
+ html = "<html>"
123
+
124
+ # Current directory
125
+ html += "<h2>#{url_path}</h2>"
126
+
127
+ # ".." link
128
+ if url_path != "/"
129
+ parent = File.dirname(url_path)
130
+ parent += "/" if parent != "/"
131
+ html += "<p><a href=\"/browser#{parent}\">..</a></p>"
132
+ end
133
+
134
+ # Child links
135
+ for name in Dir.children(path).select { |name| name != ".DS_Store" }.sort
136
+ child_path = File.join(path, name)
137
+ html += "<p>"
138
+ if File.file?(child_path)
139
+ html += "<a href=\"#{name}\">#{name}</a> #{format_file_size(File.size(child_path))}"
140
+ else
141
+ html += "<a href=\"#{name}/\">#{name}/</a>"
142
+ end
143
+ html += " <span style=\"color:#777\">#{File.ctime(child_path).to_s}</span>"
144
+ html += "</p>"
145
+ end
146
+
147
+ html
148
+ end
149
+ end
150
+
94
151
  private
95
152
 
96
153
  def params_to_framework_dir(params)
data/lib/shell_wrapper.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'open3'
1
+ require "open3"
2
2
 
3
3
  class ShellWrapper
4
4
  # @return
data/lib/table.rb CHANGED
@@ -32,8 +32,8 @@ class Table
32
32
  end
33
33
 
34
34
  def separator_line
35
- dashes = @column_sizes.map { |size| '-' * size }
36
- '+' + dashes.join('+') + '+'
35
+ dashes = @column_sizes.map { |size| "-" * size }
36
+ "+" + dashes.join("+") + "+"
37
37
  end
38
38
 
39
39
  def header_line
@@ -41,7 +41,7 @@ class Table
41
41
  column_size = @column_sizes[index] - 1
42
42
  " %-#{column_size}.#{column_size}s" % column
43
43
  end
44
- '|' + columns.join('|') + '|'
44
+ "|" + columns.join("|") + "|"
45
45
  end
46
46
 
47
47
  def row_line(row)
@@ -53,6 +53,6 @@ class Table
53
53
  "%#{column_size}.#{column_size}s " % column
54
54
  end
55
55
  end
56
- '|' + columns.join('|') + '|'
56
+ "|" + columns.join("|") + "|"
57
57
  end
58
58
  end
data/lib/utils.rb CHANGED
@@ -15,7 +15,7 @@ end
15
15
  def quote(input)
16
16
  if input.is_a? String
17
17
  if input.empty?
18
- ''
18
+ ""
19
19
  else
20
20
  '"' + input + '"'
21
21
  end
@@ -23,7 +23,7 @@ def quote(input)
23
23
  input
24
24
  .map { |e| quote(e) }
25
25
  .select { |e| !e.empty? }
26
- .join(' ')
26
+ .join(" ")
27
27
  else
28
28
  raise AppError.new, "Unsupported type #{input}"
29
29
  end
@@ -32,13 +32,13 @@ end
32
32
  def platform_to_api_string(platform)
33
33
  case platform
34
34
  when :iOS
35
- 'iOS'
35
+ "iOS"
36
36
  when :macOS
37
- 'macOS'
37
+ "macOS"
38
38
  when :tvOS
39
- 'tvOS'
39
+ "tvOS"
40
40
  when :watchOS
41
- 'watchOS'
41
+ "watchOS"
42
42
  else
43
43
  raise AppError.new, "Unrecognized platform #{platform.inspect}"
44
44
  end
@@ -47,20 +47,34 @@ end
47
47
  def platform_to_carthage_dir_string(platform)
48
48
  case platform
49
49
  when :iOS
50
- 'iOS'
50
+ "iOS"
51
51
  when :macOS
52
- 'Mac'
52
+ "Mac"
53
53
  when :tvOS
54
- 'tvOS'
54
+ "tvOS"
55
55
  when :watchOS
56
- 'watchOS'
56
+ "watchOS"
57
57
  else
58
58
  raise AppError.new, "Unrecognized platform #{platform.inspect}"
59
59
  end
60
60
  end
61
61
 
62
+ def platform_to_symbols(string)
63
+ platforms = string.split(",").map(&:to_sym)
64
+ for platform in platforms
65
+ if !PLATFORMS.include?(platform)
66
+ raise PlatformMismatchError.new(platform)
67
+ end
68
+ end
69
+ platforms
70
+ end
71
+
62
72
  # @return string in "x.y MB" format
63
73
  def format_file_size(bytes)
64
- megabytes = bytes / 1000.0 / 1000.0
65
- "#{megabytes.round(1)} MB"
74
+ if bytes == 0
75
+ "0.0 MB"
76
+ else
77
+ megabytes = [0.1, bytes / 1000.0 / 1000.0].max
78
+ "#{megabytes.round(1)} MB"
79
+ end
66
80
  end
data/lib/version.rb CHANGED
@@ -1 +1 @@
1
- VERSION = '0.0.8'
1
+ VERSION = "0.0.11"