carthage_remote_cache 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +5 -0
- data/Gemfile.lock +41 -3
- data/Guardfile +6 -0
- data/README.md +58 -10
- data/Rakefile +8 -4
- data/bin/carthagerc +67 -62
- data/carthage_remote_cache.gemspec +20 -11
- data/lib/api.rb +37 -32
- data/lib/carthage_archive.rb +84 -77
- data/lib/carthage_dependency.rb +72 -48
- data/lib/carthage_remote_cache.rb +2 -0
- data/lib/commands/download_command.rb +66 -48
- data/lib/commands/init_command.rb +18 -20
- data/lib/commands/server_command.rb +11 -13
- data/lib/commands/upload_command.rb +58 -43
- data/lib/configuration.rb +78 -76
- data/lib/constants.rb +1 -1
- data/lib/errors.rb +8 -8
- data/lib/networking.rb +75 -77
- data/lib/server/server_app.rb +44 -44
- data/lib/shell_wrapper.rb +32 -0
- data/lib/utils.rb +49 -41
- data/lib/version.rb +1 -0
- data/lib/version_file.rb +71 -73
- metadata +77 -3
data/lib/configuration.rb
CHANGED
@@ -1,82 +1,84 @@
|
|
1
1
|
require 'uri'
|
2
2
|
|
3
3
|
class Configuration
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
def version_files
|
79
|
-
@carthage_dependencies.map { |d| VersionFile.new(d.version_filepath) }
|
4
|
+
class UserConfig
|
5
|
+
attr_accessor :server
|
6
|
+
end
|
7
|
+
|
8
|
+
@@user_config = UserConfig.new
|
9
|
+
|
10
|
+
def self.setup
|
11
|
+
yield(@@user_config)
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :xcodebuild_version, :swift_version, :carthage_dependencies, :server_uri
|
15
|
+
|
16
|
+
def self.new_with_defaults
|
17
|
+
Configuration.new(ShellWrapper.new)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(shell)
|
21
|
+
initialize_env(shell)
|
22
|
+
initialize_cartrcfile
|
23
|
+
end
|
24
|
+
|
25
|
+
def all_framework_names
|
26
|
+
version_files.flat_map { |vf| vf.framework_names }.uniq.sort
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
<<~EOS
|
31
|
+
Xcodebuild: #{@xcodebuild_version}
|
32
|
+
---
|
33
|
+
Swift: #{@swift_version}
|
34
|
+
---
|
35
|
+
Server: #{@server_uri.to_s}
|
36
|
+
---
|
37
|
+
Cartfile.resolved:
|
38
|
+
#{@carthage_dependencies.join("\n")}
|
39
|
+
---
|
40
|
+
Local Build Frameworks:
|
41
|
+
#{framework_names_with_platforms.join("\n")}
|
42
|
+
EOS
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def initialize_env(shell)
|
48
|
+
xcodebuild_raw_version = shell.xcodebuild_version
|
49
|
+
@xcodebuild_version = xcodebuild_raw_version[/Build version (.*)$/, 1]
|
50
|
+
raise AppError.new, "Could not parse build version from '#{xcodebuild_raw_version}'" if @xcodebuild_version.nil?
|
51
|
+
|
52
|
+
swift_raw_version = shell.swift_version
|
53
|
+
@swift_version = swift_raw_version[/Apple Swift version (.*) \(/, 1]
|
54
|
+
raise AppError.new, "Could not parse swift version from '#{raw_swift_version}'" if @swift_version.nil?
|
55
|
+
|
56
|
+
raise AppError.new, "Misssing #{CARTFILE_RESOLVED}" unless File.exist?(CARTFILE_RESOLVED)
|
57
|
+
@carthage_dependencies = File.readlines(CARTFILE_RESOLVED)
|
58
|
+
.map { |line| CarthageDependency.parse_cartfile_resolved_line(line) }
|
59
|
+
.compact
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize_cartrcfile
|
63
|
+
raise AppError.new, "Configuration file #{CARTRCFILE} was not found, consider creating one by running `carthagerc init`" unless File.exist?(CARTRCFILE)
|
64
|
+
|
65
|
+
# Populate class variable @@user_config.
|
66
|
+
load File.join(Dir.pwd, CARTRCFILE)
|
67
|
+
|
68
|
+
raise AppError.new, "Missing 'server' configuration in #{CARTRCFILE}" if @@user_config.server.nil? || @@user_config.server.empty?
|
69
|
+
@server_uri = URI.parse(@@user_config.server)
|
70
|
+
end
|
71
|
+
|
72
|
+
def framework_names_with_platforms
|
73
|
+
lines = version_files.flat_map do |vf|
|
74
|
+
vf.platforms_by_framework.flat_map do |framework_name, platforms|
|
75
|
+
"#{framework_name} #{vf.version} #{platforms}"
|
76
|
+
end
|
80
77
|
end
|
78
|
+
lines.sort
|
79
|
+
end
|
81
80
|
|
81
|
+
def version_files
|
82
|
+
@carthage_dependencies.map { |d| VersionFile.new(d.version_filepath) }
|
83
|
+
end
|
82
84
|
end
|
data/lib/constants.rb
CHANGED
data/lib/errors.rb
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
class AppError < StandardError; end
|
3
3
|
|
4
4
|
class MultipleErrorsError < AppError
|
5
|
+
def initialize(errors)
|
6
|
+
@errors = errors
|
7
|
+
end
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def message
|
11
|
-
@errors.map { |e| e.message }.join("\n")
|
12
|
-
end
|
13
|
-
|
9
|
+
def message
|
10
|
+
@errors.map { |e| e.message }.join("\n")
|
11
|
+
end
|
14
12
|
end
|
15
13
|
|
16
14
|
class OutdatedFrameworkBuildError < AppError; end
|
15
|
+
|
16
|
+
class MissingFrameworkDirectoryError < AppError; end
|
data/lib/networking.rb
CHANGED
@@ -2,95 +2,93 @@ require 'rest-client'
|
|
2
2
|
require 'uri'
|
3
3
|
|
4
4
|
class Networking
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
5
8
|
|
6
|
-
|
7
|
-
@config = config
|
8
|
-
end
|
9
|
-
|
10
|
-
# Version Files
|
9
|
+
# Version Files
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
version_file
|
11
|
+
def download_version_file(carthage_dependency)
|
12
|
+
url = new_version_file_url(carthage_dependency)
|
13
|
+
$LOG.debug("Downloading version file from #{url}")
|
14
|
+
version_file = RestClient.get(url) do |response, request, result|
|
15
|
+
if response.code == 200
|
16
|
+
File.write(carthage_dependency.version_filename, response.to_s)
|
17
|
+
VersionFile.new(carthage_dependency.version_filename)
|
18
|
+
else
|
19
|
+
nil
|
20
|
+
end
|
24
21
|
end
|
22
|
+
version_file
|
23
|
+
end
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
def upload_version_file(carthage_dependency)
|
26
|
+
url = new_version_file_url(carthage_dependency)
|
27
|
+
$LOG.debug("Uploading #{carthage_dependency.version_filename}")
|
28
|
+
RestClient.post(url, :version_file => File.new(carthage_dependency.version_filepath))
|
29
|
+
end
|
31
30
|
|
32
|
-
|
31
|
+
# Archives
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
archive
|
42
|
-
else
|
43
|
-
nil
|
44
|
-
end
|
45
|
-
end
|
33
|
+
def download_framework_archive(carthage_dependency, framework_name, platform)
|
34
|
+
url = new_framework_url(carthage_dependency, framework_name, platform)
|
35
|
+
$LOG.debug("Downloading framework from #{url}")
|
36
|
+
archive = RestClient.get(url) do |response, request, result|
|
37
|
+
if response.code == 200
|
38
|
+
archive = CarthageArchive.new(framework_name, platform)
|
39
|
+
File.write(archive.archive_path, response.to_s)
|
46
40
|
archive
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
47
44
|
end
|
45
|
+
archive
|
46
|
+
end
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
def upload_framework_archive(zipfile_name, carthage_dependency, framework_name, platform)
|
49
|
+
url = new_framework_url(carthage_dependency, framework_name, platform)
|
50
|
+
$LOG.debug("Uploading framework to #{url}")
|
51
|
+
RestClient.post(url, :framework_file => File.new(zipfile_name))
|
52
|
+
end
|
54
53
|
|
55
|
-
|
54
|
+
private
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
56
|
+
def new_version_file_url(carthage_dependency)
|
57
|
+
new_server_url([
|
58
|
+
'versions',
|
59
|
+
@config.xcodebuild_version,
|
60
|
+
@config.swift_version,
|
61
|
+
carthage_dependency.guessed_framework_basename,
|
62
|
+
carthage_dependency.version,
|
63
|
+
carthage_dependency.version_filename,
|
64
|
+
])
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
def new_server_url(path_slices)
|
81
|
-
sanitized_path_slices = path_slices.map { |p| sanitized(p) }
|
82
|
-
uri = URI::HTTP.build(
|
83
|
-
:scheme => @config.server_uri.scheme,
|
84
|
-
:host => @config.server_uri.host,
|
85
|
-
:port => @config.server_uri.port,
|
86
|
-
:path => '/' + sanitized_path_slices.join('/')
|
87
|
-
)
|
88
|
-
uri.to_s
|
89
|
-
end
|
67
|
+
def new_framework_url(carthage_dependency, framework_name, platform)
|
68
|
+
new_server_url([
|
69
|
+
'frameworks',
|
70
|
+
@config.xcodebuild_version,
|
71
|
+
@config.swift_version,
|
72
|
+
carthage_dependency.guessed_framework_basename,
|
73
|
+
carthage_dependency.version,
|
74
|
+
framework_name,
|
75
|
+
platform_to_api_string(platform),
|
76
|
+
])
|
77
|
+
end
|
90
78
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
79
|
+
def new_server_url(path_slices)
|
80
|
+
sanitized_path_slices = path_slices.map { |p| sanitized(p) }
|
81
|
+
uri = URI::HTTP.build(
|
82
|
+
:scheme => @config.server_uri.scheme,
|
83
|
+
:host => @config.server_uri.host,
|
84
|
+
:port => @config.server_uri.port,
|
85
|
+
:path => '/' + sanitized_path_slices.join('/'),
|
86
|
+
)
|
87
|
+
uri.to_s
|
88
|
+
end
|
95
89
|
|
90
|
+
# Mangle identifiers for URL paths.
|
91
|
+
def sanitized(input)
|
92
|
+
input.gsub(/\//, '_')
|
93
|
+
end
|
96
94
|
end
|
data/lib/server/server_app.rb
CHANGED
@@ -3,78 +3,78 @@ require 'fileutils'
|
|
3
3
|
require 'carthage_remote_cache'
|
4
4
|
|
5
5
|
get '/' do
|
6
|
-
|
6
|
+
"Welcome to carthage_remote_cache"
|
7
7
|
end
|
8
8
|
|
9
9
|
versions_path = '/versions/:xcodebuild_version/:swift_version/:dependency_name/:version/:version_filename'
|
10
10
|
frameworks_path = '/frameworks/:xcodebuild_version/:swift_version/:dependency_name/:version/:framework_name/:platform'
|
11
11
|
|
12
12
|
get versions_path do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
dirname = params_to_framework_dir(params)
|
14
|
+
filename = params[:version_filename]
|
15
|
+
filepath = File.join(dirname, filename)
|
16
|
+
|
17
|
+
if File.exist?(filepath)
|
18
|
+
status(200)
|
19
|
+
send_file(filepath)
|
20
|
+
else
|
21
|
+
status(404)
|
22
|
+
end
|
23
23
|
end
|
24
24
|
|
25
25
|
post versions_path do
|
26
|
-
|
27
|
-
|
26
|
+
dirname = params_to_framework_dir(params)
|
27
|
+
filename = params[:version_filename]
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
source_file = params[:version_file][:tempfile]
|
30
|
+
target_filename = File.join(dirname, filename)
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
33
|
+
File.delete(target_filename) if File.exist?(target_filename)
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
$LOG.info("Writing: #{target_filename}")
|
36
|
+
File.open(target_filename, 'wb') do |target_file|
|
37
|
+
target_file.write(source_file.read)
|
38
|
+
end
|
39
39
|
|
40
|
-
|
40
|
+
status(200)
|
41
41
|
end
|
42
42
|
|
43
43
|
# Retrieve .zip framework archive.
|
44
44
|
get frameworks_path do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
45
|
+
dirname = params_to_framework_dir(params)
|
46
|
+
archive = CarthageArchive.new(params[:framework_name], params[:platform].to_sym)
|
47
|
+
filename = File.join(dirname, archive.archive_filename)
|
48
|
+
|
49
|
+
if File.exist?(filename)
|
50
|
+
status(200)
|
51
|
+
send_file(filename)
|
52
|
+
else
|
53
|
+
status(404)
|
54
|
+
end
|
55
55
|
end
|
56
56
|
|
57
57
|
# Upload framework archive. Overwrites already cached archive if exists.
|
58
58
|
post frameworks_path do
|
59
|
-
|
60
|
-
|
59
|
+
filename = params[:framework_file][:filename]
|
60
|
+
source_file = params[:framework_file][:tempfile]
|
61
61
|
|
62
|
-
|
63
|
-
|
62
|
+
dirname = params_to_framework_dir(params)
|
63
|
+
target_filename = File.join(dirname, filename)
|
64
64
|
|
65
|
-
|
66
|
-
|
65
|
+
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
66
|
+
File.delete(target_filename) if File.exist?(target_filename)
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
$LOG.info("Writing: #{target_filename}")
|
69
|
+
File.open(target_filename, 'wb') do |target_file|
|
70
|
+
target_file.write(source_file.read)
|
71
|
+
end
|
72
72
|
|
73
|
-
|
73
|
+
status(200)
|
74
74
|
end
|
75
75
|
|
76
76
|
private
|
77
77
|
|
78
78
|
def params_to_framework_dir(params)
|
79
|
-
|
79
|
+
File.join(SERVER_CACHE_DIR, params[:xcodebuild_version], params[:swift_version], params[:dependency_name], params[:version])
|
80
80
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class ShellWrapper
|
2
|
+
# @return
|
3
|
+
# Xcode 9.2
|
4
|
+
# Build version 9C40b
|
5
|
+
def xcodebuild_version
|
6
|
+
sh("xcodebuild -version")
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return
|
10
|
+
# Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2)
|
11
|
+
# Target: x86_64-apple-macosx10.9
|
12
|
+
def swift_version
|
13
|
+
sh("swift -version")
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return
|
17
|
+
# UUID: 69BD256A-C658-3D96-9D5A-FF4B8ED6900C (i386) Carthage/Build/iOS/Attributions.framework/Attributions
|
18
|
+
# UUID: BA1067DB-915A-3DA2-AC16-8C2F2947095E (x86_64) Carthage/Build/iOS/Attributions.framework/Attributions
|
19
|
+
# UUID: DF7DA357-FF4B-3BB8-BCC3-7CE5B97E52E0 (armv7) Carthage/Build/iOS/Attributions.framework/Attributions
|
20
|
+
# UUID: 824033E6-7ABA-3568-A90B-6AF6AFAF4BB9 (arm64) Carthage/Build/iOS/Attributions.framework/Attributions
|
21
|
+
def dwarfdump(path)
|
22
|
+
sh("/usr/bin/xcrun dwarfdump --uuid \"#{path}\"")
|
23
|
+
end
|
24
|
+
|
25
|
+
def archive(input_paths, output_path)
|
26
|
+
sh("zip -r #{quote output_path} #{quote input_paths}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def unpack(archive_path)
|
30
|
+
sh("unzip -o #{quote archive_path}")
|
31
|
+
end
|
32
|
+
end
|
data/lib/utils.rb
CHANGED
@@ -1,62 +1,70 @@
|
|
1
|
+
# Execute arbitrary system command.
|
2
|
+
# @return command output, bails on failure
|
1
3
|
def sh(cmd)
|
2
|
-
|
3
|
-
|
4
|
-
|
4
|
+
output = `#{cmd}`
|
5
|
+
bail("Command `#{cmd}` failed!") unless $?.success?
|
6
|
+
output.strip
|
5
7
|
end
|
6
8
|
|
7
9
|
# Exits Ruby process, only to be called:
|
8
10
|
# 1. If sh / system calls fail
|
9
11
|
# 2. From top level `carthagerc` script
|
10
12
|
def bail(message, code = 1)
|
11
|
-
|
12
|
-
|
13
|
+
$stderr.puts(message.strip + "\n")
|
14
|
+
Process.exit(code)
|
13
15
|
end
|
14
16
|
|
15
17
|
# Quote command line arguments with double quotes.
|
16
18
|
# Useful for file paths with spaces.
|
17
19
|
def quote(input)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
else
|
22
|
-
'"' + input + '"'
|
23
|
-
end
|
24
|
-
elsif input.is_a? Array
|
25
|
-
input
|
26
|
-
.map { |e| quote(e) }
|
27
|
-
.select { |e| !e.empty? }
|
28
|
-
.join(' ')
|
20
|
+
if input.is_a? String
|
21
|
+
if input.empty?
|
22
|
+
''
|
29
23
|
else
|
30
|
-
|
24
|
+
'"' + input + '"'
|
31
25
|
end
|
26
|
+
elsif input.is_a? Array
|
27
|
+
input
|
28
|
+
.map { |e| quote(e) }
|
29
|
+
.select { |e| !e.empty? }
|
30
|
+
.join(' ')
|
31
|
+
else
|
32
|
+
raise AppError.new, "Unsupported type #{input}"
|
33
|
+
end
|
32
34
|
end
|
33
35
|
|
34
36
|
def platform_to_api_string(platform)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
case platform
|
38
|
+
when :iOS
|
39
|
+
'iOS'
|
40
|
+
when :macOS
|
41
|
+
'macOS'
|
42
|
+
when :tvOS
|
43
|
+
'tvOS'
|
44
|
+
when :watchOS
|
45
|
+
'watchOS'
|
46
|
+
else
|
47
|
+
raise AppError.new, "Unrecognized platform #{platform.inspect}"
|
48
|
+
end
|
47
49
|
end
|
48
50
|
|
49
51
|
def platform_to_carthage_dir_string(platform)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
52
|
+
case platform
|
53
|
+
when :iOS
|
54
|
+
'iOS'
|
55
|
+
when :macOS
|
56
|
+
'Mac'
|
57
|
+
when :tvOS
|
58
|
+
'tvOS'
|
59
|
+
when :watchOS
|
60
|
+
'watchOS'
|
61
|
+
else
|
62
|
+
raise AppError.new, "Unrecognized platform #{platform.inspect}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return string in "x.y MB" format
|
67
|
+
def format_file_size(bytes)
|
68
|
+
megabytes = bytes / 1000.0 / 1000.0
|
69
|
+
"#{megabytes.round(1)} MB"
|
62
70
|
end
|
data/lib/version.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
VERSION = '0.0.4'
|