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.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +38 -0
- data/.ruby-version +2 -0
- data/.travis.yml +1 -1
- data/Dockerfile +7 -0
- data/Gemfile.lock +41 -41
- data/Guardfile +2 -2
- data/README.md +38 -5
- data/Rakefile +2 -2
- data/bin/carthagerc +18 -8
- data/carthage_remote_cache.gemspec +4 -4
- data/dev/start_server +1 -1
- data/lib/api.rb +10 -10
- data/lib/carthage_archive.rb +13 -51
- data/lib/carthage_remote_cache.rb +18 -14
- data/lib/commands/download_command.rb +10 -9
- data/lib/commands/server_command.rb +2 -2
- data/lib/commands/upload_command.rb +6 -6
- data/lib/commands/verify_command.rb +1 -1
- data/lib/commands.rb +5 -5
- data/lib/configuration.rb +1 -1
- data/lib/constants.rb +9 -7
- data/lib/crc32.rb +3 -3
- data/lib/errors.rb +12 -1
- data/lib/framework.rb +19 -0
- data/lib/framework_carthage_archive.rb +57 -0
- data/lib/log.rb +1 -1
- data/lib/networking.rb +81 -41
- data/lib/server/config.ru +3 -3
- data/lib/server/server_app.rb +69 -12
- data/lib/shell_wrapper.rb +1 -1
- data/lib/table.rb +4 -4
- data/lib/utils.rb +26 -12
- data/lib/version.rb +1 -1
- data/lib/version_file.rb +66 -20
- data/lib/xcframework.rb +29 -0
- data/lib/xcframework_carthage_archive.rb +17 -0
- metadata +36 -18
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
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,
|
76
|
-
for
|
77
|
-
archive_size = @api.create_and_upload_archive(carthage_dependency,
|
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
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
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
data/lib/constants.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
CARTHAGE_DIR =
|
2
|
-
CARTHAGE_BUILD_DIR = File.join(CARTHAGE_DIR,
|
3
|
-
CARTFILE_RESOLVED =
|
4
|
-
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,
|
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 =
|
12
|
-
ARCHIVE_CHECKSUM_HEADER_SINATRA_OUT =
|
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
|
2
|
-
require
|
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(
|
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 = [
|
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
data/lib/networking.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
require
|
2
|
-
require
|
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 =
|
15
|
-
|
16
|
-
response.
|
17
|
-
|
18
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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,
|
56
|
-
url = new_framework_url(carthage_dependency,
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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([
|
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
|
-
|
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
|
-
|
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 =>
|
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
data/lib/server/server_app.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
|
5
|
-
|
6
|
-
|
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 =
|
10
|
-
versions_path =
|
11
|
-
frameworks_path =
|
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
|
-
|
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,
|
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,
|
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
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|
|
36
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
35
|
+
"iOS"
|
36
36
|
when :macOS
|
37
|
-
|
37
|
+
"macOS"
|
38
38
|
when :tvOS
|
39
|
-
|
39
|
+
"tvOS"
|
40
40
|
when :watchOS
|
41
|
-
|
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
|
-
|
50
|
+
"iOS"
|
51
51
|
when :macOS
|
52
|
-
|
52
|
+
"Mac"
|
53
53
|
when :tvOS
|
54
|
-
|
54
|
+
"tvOS"
|
55
55
|
when :watchOS
|
56
|
-
|
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
|
-
|
65
|
-
|
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 =
|
1
|
+
VERSION = "0.0.11"
|