carthage_cache_res 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +17 -0
- data/CODEOWNERS +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +216 -0
- data/Rakefile +12 -0
- data/bin/console +11 -0
- data/bin/setup +7 -0
- data/carthage_cache_res.gemspec +43 -0
- data/exe/carthage_cache_res +107 -0
- data/lib/carthage_cache_res.rb +22 -0
- data/lib/carthage_cache_res/application.rb +93 -0
- data/lib/carthage_cache_res/archive_builder.rb +57 -0
- data/lib/carthage_cache_res/archive_installer.rb +53 -0
- data/lib/carthage_cache_res/archiver.rb +24 -0
- data/lib/carthage_cache_res/build_collector.rb +86 -0
- data/lib/carthage_cache_res/carthage_cache_lock.rb +28 -0
- data/lib/carthage_cache_res/carthage_resolved_file.rb +49 -0
- data/lib/carthage_cache_res/configuration.rb +122 -0
- data/lib/carthage_cache_res/configuration_validator.rb +134 -0
- data/lib/carthage_cache_res/configurator.rb +79 -0
- data/lib/carthage_cache_res/configurator_wizard.rb +49 -0
- data/lib/carthage_cache_res/description.rb +3 -0
- data/lib/carthage_cache_res/project.rb +66 -0
- data/lib/carthage_cache_res/repository.rb +58 -0
- data/lib/carthage_cache_res/shell_command_executor.rb +11 -0
- data/lib/carthage_cache_res/swift_version_resolver.rb +17 -0
- data/lib/carthage_cache_res/terminal.rb +25 -0
- data/lib/carthage_cache_res/version.rb +3 -0
- metadata +212 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
module CarthageCacheRes
|
2
|
+
|
3
|
+
class MissingConfigurationKey < Struct.new(:keyname, :solution)
|
4
|
+
|
5
|
+
def self.missing_bucket_name
|
6
|
+
solution = "You need to specify the AWS S3 bucket to be used.\n" \
|
7
|
+
"You can either pass the '--bucket-name' option or " \
|
8
|
+
" add ':bucket_name: YOUR_BUCKET_NAME' to " \
|
9
|
+
".carthage_cache_res.yml file.\nYou can also run " \
|
10
|
+
"'carthage_cache_res config' to generate the config file."
|
11
|
+
self.new(:bucket_name, solution)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.missing_aws_key(keyname, name)
|
15
|
+
solution = "You need to specify the AWS #{name} to be used.\n" \
|
16
|
+
"You can either define a environmental variable " \
|
17
|
+
"AWS_REGION or add ':#{keyname}: YOUR_KEY_VALUE' " \
|
18
|
+
"under the :aws_s3_client_options: key in the " \
|
19
|
+
".carthage_cache_res.yml file.\nYou can also run " \
|
20
|
+
"'carthage_cache_res config' to generate the config file."
|
21
|
+
self.new("aws_s3_client_options.#{keyname}", solution)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.missing_aws_region
|
25
|
+
missing_aws_key("region", "region")
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.missing_aws_access_key_id
|
29
|
+
missing_aws_key("access_key_id", "access key ID")
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.missing_aws_secret_access_key
|
33
|
+
missing_aws_key("secret_access_key", "secret access key")
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class ValidationResult
|
39
|
+
|
40
|
+
def self.valid
|
41
|
+
self.new(nil)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.invalid(error)
|
45
|
+
self.new(error)
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :error
|
49
|
+
|
50
|
+
def initialize(error)
|
51
|
+
@error = error
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid?
|
55
|
+
@error == nil
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class ConfigurationValidator
|
61
|
+
|
62
|
+
attr_reader :config
|
63
|
+
|
64
|
+
def initialize(config)
|
65
|
+
@config = config
|
66
|
+
end
|
67
|
+
|
68
|
+
def valid?
|
69
|
+
validate.valid?
|
70
|
+
end
|
71
|
+
|
72
|
+
def read_only?
|
73
|
+
(config.aws_access_key_id.nil? || config.aws_secret_access_key.nil?) && config.aws_profile.nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate
|
77
|
+
return missing_bucket_name unless has_bucket_name?
|
78
|
+
return missing_aws_region unless has_aws_region?
|
79
|
+
|
80
|
+
return missing_aws_access_key_id if is_missing_aws_access_key_id?
|
81
|
+
return missing_aws_secret_access_key if is_missing_aws_secret_access_key?
|
82
|
+
|
83
|
+
ValidationResult.valid
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def is_missing_aws_access_key_id?
|
89
|
+
!has_aws_profile? && !has_aws_access_key_id? && has_aws_secret_access_key?
|
90
|
+
end
|
91
|
+
|
92
|
+
def is_missing_aws_secret_access_key?
|
93
|
+
!has_aws_profile? && has_aws_access_key_id? && !has_aws_secret_access_key?
|
94
|
+
end
|
95
|
+
|
96
|
+
def has_bucket_name?
|
97
|
+
config.bucket_name
|
98
|
+
end
|
99
|
+
|
100
|
+
def has_aws_region?
|
101
|
+
config.aws_region
|
102
|
+
end
|
103
|
+
|
104
|
+
def has_aws_access_key_id?
|
105
|
+
config.aws_access_key_id
|
106
|
+
end
|
107
|
+
|
108
|
+
def has_aws_secret_access_key?
|
109
|
+
config.aws_secret_access_key
|
110
|
+
end
|
111
|
+
|
112
|
+
def has_aws_profile?
|
113
|
+
config.aws_profile
|
114
|
+
end
|
115
|
+
|
116
|
+
def missing_bucket_name
|
117
|
+
ValidationResult.invalid(MissingConfigurationKey.missing_bucket_name)
|
118
|
+
end
|
119
|
+
|
120
|
+
def missing_aws_region
|
121
|
+
ValidationResult.invalid(MissingConfigurationKey.missing_aws_region)
|
122
|
+
end
|
123
|
+
|
124
|
+
def missing_aws_access_key_id
|
125
|
+
ValidationResult.invalid(MissingConfigurationKey.missing_aws_access_key_id)
|
126
|
+
end
|
127
|
+
|
128
|
+
def missing_aws_secret_access_key
|
129
|
+
ValidationResult.invalid(MissingConfigurationKey.missing_aws_secret_access_key)
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module CarthageCacheRes
|
4
|
+
|
5
|
+
class Configurator
|
6
|
+
|
7
|
+
CONFIG_FILE_NAME = ".carthage_cache_res.yml"
|
8
|
+
|
9
|
+
attr_reader :config_file_path
|
10
|
+
attr_reader :base_config
|
11
|
+
attr_reader :terminal
|
12
|
+
|
13
|
+
def initialize(terminal, project_path, base_config = {})
|
14
|
+
@config_file_path = File.join(project_path, CONFIG_FILE_NAME)
|
15
|
+
@base_config = merge_config(base_config)
|
16
|
+
@terminal = terminal
|
17
|
+
end
|
18
|
+
|
19
|
+
def config
|
20
|
+
@config ||= load_config!
|
21
|
+
end
|
22
|
+
|
23
|
+
def save_config(config)
|
24
|
+
raise "Invalid configuration" unless config.valid?
|
25
|
+
File.open(config_file_path, 'w') { |f| f.write config.to_yaml }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def config_file_exist?
|
31
|
+
File.exist?(config_file_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_config!
|
35
|
+
config = load_config
|
36
|
+
validate!(config)
|
37
|
+
config
|
38
|
+
end
|
39
|
+
|
40
|
+
def load_config
|
41
|
+
if config_file_exist?
|
42
|
+
config = Configuration.parse(File.read(config_file_path))
|
43
|
+
config = base_config.merge(config)
|
44
|
+
else
|
45
|
+
base_config
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate!(config)
|
50
|
+
validator = ConfigurationValidator.new(config)
|
51
|
+
result = validator.validate
|
52
|
+
unless result.valid?
|
53
|
+
terminal.error "error: #{result.error.solution}"
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def remove_nil_keys(hash)
|
59
|
+
hash.inject({}) do |new_hash, (k,v)|
|
60
|
+
unless v.nil? || (v.respond_to?(:empty?) && v.empty?)
|
61
|
+
if v.class == Hash
|
62
|
+
cleaned_hashed = remove_nil_keys(v)
|
63
|
+
new_hash[k] = cleaned_hashed unless cleaned_hashed.empty?
|
64
|
+
else
|
65
|
+
new_hash[k] = v
|
66
|
+
end
|
67
|
+
end
|
68
|
+
new_hash
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def merge_config(config)
|
73
|
+
new_config = Configuration.default.hash_object.merge(config)
|
74
|
+
Configuration.new(remove_nil_keys(new_config))
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module CarthageCacheRes
|
2
|
+
|
3
|
+
class ConfiguratorWizard
|
4
|
+
|
5
|
+
def initialize(ask_proc, password_proc)
|
6
|
+
@ask_proc = ask_proc
|
7
|
+
@password_proc = password_proc
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
config = Configuration.new
|
12
|
+
config.bucket_name = ask("What is the Amazon S3 bucket name?", ENV["CARTHAGE_CACHE_DEFAULT_BUCKET_NAME"])
|
13
|
+
config.archive_base_path = ask("What base path do you want to use as archive's prefix? (default none)", nil)
|
14
|
+
config.prune_on_publish = confirm("Do you want to prune unused framework when publishing?")
|
15
|
+
config.aws_region = ask("What is the Amazon S3 region?")
|
16
|
+
config.aws_access_key_id = password("What is the AWS access key?")
|
17
|
+
config.aws_secret_access_key = password(" What is the AWS secret access key?")
|
18
|
+
config.aws_session_token = ask("What is the AWS session token (optional)?", nil, "*")
|
19
|
+
config
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def ask(message, default_value = nil, mask = nil)
|
25
|
+
message = "#{message} [#{default_value}]" if default_value
|
26
|
+
if mask
|
27
|
+
answer = @ask_proc.call(message) { |q| q.echo = mask }
|
28
|
+
else
|
29
|
+
answer = @ask_proc.call(message)
|
30
|
+
end
|
31
|
+
|
32
|
+
if answer.empty?
|
33
|
+
default_value
|
34
|
+
else
|
35
|
+
answer
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def confirm(message)
|
40
|
+
ask("#{message} [N/y]", 'N').downcase == 'y'
|
41
|
+
end
|
42
|
+
|
43
|
+
def password(message)
|
44
|
+
@password_proc.call(message)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module CarthageCacheRes
|
2
|
+
|
3
|
+
class Project
|
4
|
+
|
5
|
+
attr_reader :cartfile
|
6
|
+
attr_reader :project_path
|
7
|
+
attr_reader :archive_base_path
|
8
|
+
attr_reader :cache_dir_name
|
9
|
+
attr_reader :terminal
|
10
|
+
attr_reader :tmpdir_base_path
|
11
|
+
|
12
|
+
def initialize(project_path, cache_dir_name, archive_base_path, terminal, tmpdir, swift_version_resolver = SwiftVersionResolver.new)
|
13
|
+
@project_path = project_path
|
14
|
+
@cache_dir_name = cache_dir_name
|
15
|
+
@archive_base_path = archive_base_path
|
16
|
+
@terminal = terminal
|
17
|
+
@tmpdir_base_path = tmpdir
|
18
|
+
@cartfile = CartfileResolvedFile.new(cartfile_resolved_path, terminal, swift_version_resolver)
|
19
|
+
end
|
20
|
+
|
21
|
+
def archive_filename
|
22
|
+
@archive_filename ||= "#{archive_key}.zip"
|
23
|
+
end
|
24
|
+
|
25
|
+
def archive_path
|
26
|
+
if @archive_base_path.nil?
|
27
|
+
@archive_path ||= archive_filename
|
28
|
+
else
|
29
|
+
@archive_path ||= File.join(archive_base_path, archive_filename)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def archive_key
|
34
|
+
cartfile.digest
|
35
|
+
end
|
36
|
+
|
37
|
+
def tmpdir
|
38
|
+
@tmpdir ||= create_tmpdir
|
39
|
+
end
|
40
|
+
|
41
|
+
def carthage_build_directory
|
42
|
+
@carthage_build_directory ||= File.join(project_path, "Carthage", "Build")
|
43
|
+
end
|
44
|
+
|
45
|
+
def all_frameworks
|
46
|
+
cartfile.frameworks
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def cartfile_resolved_path
|
52
|
+
@carfile_resolved_path ||= File.join(project_path, "Cartfile.resolved")
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_tmpdir
|
56
|
+
dir = File.join(tmpdir_base_path, cache_dir_name)
|
57
|
+
unless File.exist?(dir)
|
58
|
+
terminal.vputs "Creating carthage cache directory at '#{dir}'."
|
59
|
+
FileUtils.mkdir_p(dir)
|
60
|
+
end
|
61
|
+
dir
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "aws-sdk"
|
2
|
+
|
3
|
+
module CarthageCacheRes
|
4
|
+
|
5
|
+
class AWSRepository
|
6
|
+
|
7
|
+
attr_reader :client
|
8
|
+
attr_reader :bucket_name
|
9
|
+
|
10
|
+
def initialize(bucket_name, client_options = {})
|
11
|
+
@client = ::Aws::S3::Client.new(client_options)
|
12
|
+
@bucket_name = bucket_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def archive_exist?(archive_filename)
|
16
|
+
::Aws::S3::Object.new(bucket_name, archive_filename, client: client).exists?
|
17
|
+
end
|
18
|
+
|
19
|
+
def download(archive_filename, destination_path)
|
20
|
+
resp = client.get_object(
|
21
|
+
response_target: destination_path,
|
22
|
+
bucket: bucket_name,
|
23
|
+
key: archive_filename)
|
24
|
+
end
|
25
|
+
|
26
|
+
def upload(archive_filename, archive_path)
|
27
|
+
File.open(archive_path, 'rb') do |file|
|
28
|
+
client.put_object(bucket: bucket_name, key: archive_filename, body: file)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class HTTPRepository
|
35
|
+
|
36
|
+
attr_reader :base_url
|
37
|
+
|
38
|
+
def initialize(bucket_name, client_options = {})
|
39
|
+
region = client_options[:region]
|
40
|
+
bucket_name = bucket_name
|
41
|
+
@base_url = "https://s3-#{region}.amazonaws.com/#{bucket_name}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def archive_exist?(archive_filename)
|
45
|
+
system "wget", "--method=HEAD", "#{base_url}/#{archive_filename}", "-q"
|
46
|
+
end
|
47
|
+
|
48
|
+
def download(archive_filename, destination_path)
|
49
|
+
system "wget", "--output-document=#{destination_path}", "#{base_url}/#{archive_filename}", "-q"
|
50
|
+
end
|
51
|
+
|
52
|
+
def upload(archive_filename, archive_path)
|
53
|
+
raise "carthage_cache_res is working in read-only mode. Please configure AWS credentials first"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CarthageCacheRes
|
2
|
+
|
3
|
+
class SwiftVersionResolver
|
4
|
+
|
5
|
+
def initialize(executor = ShellCommandExecutor.new)
|
6
|
+
@executor = executor
|
7
|
+
end
|
8
|
+
|
9
|
+
def swift_version
|
10
|
+
output = @executor.execute('xcrun swift -version').chomp
|
11
|
+
version_string = /(\d+\.)?(\d+\.)?(\d+)/.match(output).to_s
|
12
|
+
Gem::Version.new(version_string)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CarthageCacheRes
|
2
|
+
|
3
|
+
class Terminal
|
4
|
+
|
5
|
+
attr_reader :verbose
|
6
|
+
|
7
|
+
def initialize(verbose = false)
|
8
|
+
@verbose = verbose
|
9
|
+
end
|
10
|
+
|
11
|
+
def puts(message)
|
12
|
+
Kernel.puts(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
def vputs(message)
|
16
|
+
puts(message) if verbose
|
17
|
+
end
|
18
|
+
|
19
|
+
def error(message)
|
20
|
+
STDERR.puts(message)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|