carthage_cashier 0.1.5
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 +7 -0
- data/bin/carthage_cashier +4 -0
- data/lib/carthage_cashier/version.rb +3 -0
- data/lib/carthage_cashier.rb +303 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ed209e2c77954e6b2435489dc0ef54f5be908d70
|
4
|
+
data.tar.gz: b4e5262718c6f7294bf2f73dd6c234f1efc08a16
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 73c629e59733e2989541abdcddec71db8eff6f92dac1bfbf10a9f4243b497f593050d4c359139e74b3eb644c75011da77330b6624a95c420afd23f5bdfe59903
|
7
|
+
data.tar.gz: 85c23e597a2b8e0ab7f9929ce7e97a8c3269012c701eb4124b00d66bab25155112f4bb5186cc188c79bea9664699c03ffd3833373d3b0b45ea4175437b7c6840
|
@@ -0,0 +1,303 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "carthage_cache/version"
|
4
|
+
require "fileutils"
|
5
|
+
require 'digest'
|
6
|
+
require 'optparse'
|
7
|
+
require 'xcodeproject'
|
8
|
+
|
9
|
+
module CarthageCashier
|
10
|
+
|
11
|
+
# Constants
|
12
|
+
COMPILER_VER = /(?<=\()(.*)(?= )/.match(`xcrun swift -version`)[0]
|
13
|
+
CARTHAGE_RESOLVED_FILE="Cartfile.resolved"
|
14
|
+
CARTHAGE_CACHE_DIR="#{ENV['HOME']}/.carthage_cache"
|
15
|
+
|
16
|
+
module Platform
|
17
|
+
IOS = "iOS"
|
18
|
+
TVOS = "tvOS"
|
19
|
+
OSX = "OSX"
|
20
|
+
WATCHOS = "watchOS"
|
21
|
+
ALL = [IOS, TVOS, OSX, WATCHOS]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse args
|
25
|
+
OPTIONS = {}
|
26
|
+
|
27
|
+
def self.setup_opts_parser()
|
28
|
+
opts_parser = OptionParser.new do |opts|
|
29
|
+
opts.banner = "Usage: carthage_cache.rb [OPTIONS] project_root"
|
30
|
+
opts.separator ""
|
31
|
+
opts.separator "Uses cache to load appropriate dependencies. If cached version of the current version is not available,"
|
32
|
+
opts.separator "bootstraps it and saves back to cache for further use. Also takes into account compiler version."
|
33
|
+
opts.separator ""
|
34
|
+
opts.separator "Specific options:"
|
35
|
+
|
36
|
+
opts.on("-c", "--[no-]clean", "This option will clean (delete) all cached files for all projects.") do |v|
|
37
|
+
OPTIONS[:clean] = v
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on("-w", "--[no-]whole", "Uses MD5 of Cartfile.resolved to check cache and restores the whole image of the folder if available. (worse)") do |v|
|
41
|
+
OPTIONS[:whole] = v
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on("-f", "--[no-]force", "Force bootstrap dependencies without using cached versions and save the built products to cache.") do |v|
|
45
|
+
OPTIONS[:force] = v
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
49
|
+
puts opts
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
return opts_parser
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.get_cache_paths()
|
58
|
+
base_path = "#{CARTHAGE_CACHE_DIR}/#{COMPILER_VER}"
|
59
|
+
paths = {}
|
60
|
+
|
61
|
+
if OPTIONS[:whole]
|
62
|
+
paths["WHOLE"] = "#{base_path}/whole"
|
63
|
+
else
|
64
|
+
Platform::ALL.each do |platform|
|
65
|
+
paths[platform] = "#{base_path}/intelligent/#{platform}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return paths
|
70
|
+
end
|
71
|
+
|
72
|
+
# Gets the names and hashes from resolved cartfile
|
73
|
+
def self.parse_resolved_cartfile(path)
|
74
|
+
dependencies = {}
|
75
|
+
|
76
|
+
# Open file and read line by line
|
77
|
+
File.open(path) do |file|
|
78
|
+
file.each_line do |line|
|
79
|
+
|
80
|
+
# Run regex on line
|
81
|
+
result = /^git(?>hub)? ".*(?<=\/)([^"]*)" "(.*)"$/.match(line)
|
82
|
+
|
83
|
+
# If we found match (0) and name capture group (1) and hash/version capture group (2)
|
84
|
+
if !result.nil? && result.length == 3
|
85
|
+
dependencies[result[2]] = result[1].chomp('.git')
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
return dependencies
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.find_xcodeproj_files()
|
95
|
+
projects = XcodeProject::Project.find("Carthage/Checkouts/**")
|
96
|
+
|
97
|
+
# Filter out example, test projects
|
98
|
+
projects.each do |p|
|
99
|
+
projects.delete p unless /[Dd]emo$|[Ee]xample$|[Tt]est[s]*$/.match(p.name).nil?
|
100
|
+
end
|
101
|
+
|
102
|
+
return projects
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.parse_product_name_mappings(xcodeproj_files, dependencies)
|
106
|
+
names = {}
|
107
|
+
|
108
|
+
xcodeproj_files.each do |xp|
|
109
|
+
data = xp.read
|
110
|
+
|
111
|
+
next unless data.targets.first.config("Release").build_settings["DEFINES_MODULE"]
|
112
|
+
product_name = data.targets.first.config("Release").build_settings["PRODUCT_NAME"]
|
113
|
+
|
114
|
+
# If the proj is using target name
|
115
|
+
if product_name == "$(TARGET_NAME)"
|
116
|
+
product_name = data.targets.first.name
|
117
|
+
end
|
118
|
+
|
119
|
+
key = nil
|
120
|
+
file_path = xp.file_path.to_s
|
121
|
+
dependencies.values.each do |name|
|
122
|
+
next unless file_path.include? name
|
123
|
+
key = name
|
124
|
+
break
|
125
|
+
end
|
126
|
+
|
127
|
+
next unless key.nil? == false
|
128
|
+
names[key] = product_name unless names.values.include?(product_name)
|
129
|
+
end
|
130
|
+
|
131
|
+
return names
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.cache_built_dependencies(dependencies)
|
135
|
+
puts("Caching built dependencies.")
|
136
|
+
|
137
|
+
cache_paths = get_cache_paths
|
138
|
+
|
139
|
+
if OPTIONS[:whole] == true
|
140
|
+
cache_path = "#{cache_paths.values.first}/#{Digest::MD5.file CARTHAGE_RESOLVED_FILE}/"
|
141
|
+
|
142
|
+
# Get target dir
|
143
|
+
src_dir = Dir.getwd + "/Carthage/Build/"
|
144
|
+
|
145
|
+
# Create the target dir if needed and copy files
|
146
|
+
FileUtils.mkdir_p cache_path unless File.exists? cache_path
|
147
|
+
FileUtils.cp_r Dir["#{src_dir}/*"], cache_path
|
148
|
+
else
|
149
|
+
xcodeproj_files = find_xcodeproj_files
|
150
|
+
products_name_mapping = parse_product_name_mappings xcodeproj_files, dependencies
|
151
|
+
|
152
|
+
dependencies.each do |d_ver, d_name|
|
153
|
+
next unless products_name_mapping.keys.include?(d_name)
|
154
|
+
product_name = products_name_mapping[d_name]
|
155
|
+
|
156
|
+
get_cache_paths.each do |platform, path|
|
157
|
+
target_dir = "#{path}/#{d_name}/#{d_ver}"
|
158
|
+
src_dir = "Carthage/Build/#{platform}"
|
159
|
+
fmwk_path = "#{src_dir}/#{product_name}.framework"
|
160
|
+
|
161
|
+
next unless fmwk_path.empty? == false
|
162
|
+
next unless Dir.exist? src_dir
|
163
|
+
|
164
|
+
# Create the target dir if needed and copy files
|
165
|
+
if File.exists? target_dir
|
166
|
+
FileUtils.rm_rf target_dir
|
167
|
+
end
|
168
|
+
FileUtils.mkdir_p target_dir
|
169
|
+
FileUtils.cp_r fmwk_path, target_dir
|
170
|
+
FileUtils.cp_r "#{fmwk_path}.dSYM", target_dir
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Steps
|
175
|
+
# 1. Find .xcodeproj in Carthage/Checkouts after running carthage checkout
|
176
|
+
# 2. Parse Product Name to be able to find corresponding .framework
|
177
|
+
# 3. Copy that from each platform folder to cache
|
178
|
+
# Question: How to figure out .bcsymbolmap files? Relation to .framework? Metadata? Timestamp?
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.copy_dependencies_from_cache(dependencies)
|
184
|
+
uncached = {}
|
185
|
+
cache_paths = get_cache_paths
|
186
|
+
|
187
|
+
# Whole cache
|
188
|
+
if OPTIONS[:whole]
|
189
|
+
cache_path = "#{cache_paths.values.first}/#{Digest::MD5.file CARTHAGE_RESOLVED_FILE}/"
|
190
|
+
if Dir.exist? cache_path
|
191
|
+
found = true
|
192
|
+
|
193
|
+
# Get target dir
|
194
|
+
target_dir = Dir.getwd + "/Carthage/Build"
|
195
|
+
|
196
|
+
# Create the target dir if needed and copy files
|
197
|
+
if File.exists? target_dir
|
198
|
+
FileUtils.rm_rf target_dir
|
199
|
+
end
|
200
|
+
FileUtils.mkdir_p target_dir
|
201
|
+
FileUtils.cp_r Dir["#{cache_path}/*"], target_dir
|
202
|
+
else
|
203
|
+
uncached.replace dependencies
|
204
|
+
end
|
205
|
+
else
|
206
|
+
# Intelligent cache
|
207
|
+
dependencies.each do |d_ver, d_name|
|
208
|
+
found = false
|
209
|
+
|
210
|
+
cache_paths.each do |platform, path|
|
211
|
+
dep_cache_path = "#{path}/#{d_name}/#{d_ver}"
|
212
|
+
|
213
|
+
if Dir.exist? dep_cache_path
|
214
|
+
found = true
|
215
|
+
|
216
|
+
target_dir = Dir.getwd + "/Carthage/Build/#{platform}"
|
217
|
+
|
218
|
+
# Create the target dir if needed and copy files
|
219
|
+
FileUtils.mkdir_p target_dir unless File.exists? target_dir
|
220
|
+
FileUtils.cp_r Dir["#{dep_cache_path}/*"], target_dir
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# If not found, put it in uncached
|
225
|
+
uncached[d_ver] = d_name unless found
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
puts "Copied dependencies from cache: #{dependencies.values - uncached.values}"
|
230
|
+
return uncached
|
231
|
+
end
|
232
|
+
|
233
|
+
def self.boostrap_and_cache(dependencies = {})
|
234
|
+
|
235
|
+
if dependencies.count == 0
|
236
|
+
success = system("carthage bootstrap")
|
237
|
+
else
|
238
|
+
# Pass only some deps to carthage bootstrap, so we don't build everything
|
239
|
+
success = system("carthage bootstrap #{dependencies.values.join(" ")}")
|
240
|
+
end
|
241
|
+
|
242
|
+
# Check result and cache if appropriate
|
243
|
+
if success
|
244
|
+
cache_built_dependencies dependencies
|
245
|
+
exit 0
|
246
|
+
else
|
247
|
+
puts("ERROR: Carthage bootstrap failed, can't cache built dependencies.")
|
248
|
+
exit 1
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# -----------
|
253
|
+
# MAIN
|
254
|
+
# -----------
|
255
|
+
|
256
|
+
|
257
|
+
def self.run(arguments = ARGV)
|
258
|
+
opts_parser = setup_opts_parser
|
259
|
+
opts_parser.parse!(arguments)
|
260
|
+
|
261
|
+
# Clean cache
|
262
|
+
if OPTIONS[:clean]
|
263
|
+
puts "Cleaning all cached files."
|
264
|
+
FileUtils.rm_rf(CARTHAGE_CACHE_DIR)
|
265
|
+
exit 0
|
266
|
+
end
|
267
|
+
|
268
|
+
# Safety check
|
269
|
+
if arguments.count != 1
|
270
|
+
puts opts_parser.help
|
271
|
+
exit 1
|
272
|
+
end
|
273
|
+
|
274
|
+
# Change to project dir
|
275
|
+
Dir.chdir arguments[0]
|
276
|
+
|
277
|
+
# Get Cartfile.resolved
|
278
|
+
if !File.exist?(CARTHAGE_RESOLVED_FILE)
|
279
|
+
puts("No #{CARTHAGE_RESOLVED_FILE} found in specified directory. Bootstrapping instead.")
|
280
|
+
boostrap_and_cache
|
281
|
+
end
|
282
|
+
|
283
|
+
# Get dependencies
|
284
|
+
deps = parse_resolved_cartfile CARTHAGE_RESOLVED_FILE
|
285
|
+
|
286
|
+
# Force bootstrap or try loading dependencies from cache
|
287
|
+
if OPTIONS[:force]
|
288
|
+
puts "Force bootstrapping and caching results."
|
289
|
+
boostrap_and_cache deps
|
290
|
+
else
|
291
|
+
remaining_deps = copy_dependencies_from_cache deps
|
292
|
+
if remaining_deps.count == 0
|
293
|
+
puts "Loaded all dependencies from cache."
|
294
|
+
exit 0
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# Bootstrapping remaining dependencies
|
299
|
+
puts "Following dependencies not cached, bootstrapping them now: #{remaining_deps.values}"
|
300
|
+
boostrap_and_cache remaining_deps
|
301
|
+
|
302
|
+
end
|
303
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carthage_cashier
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dominik Hadl
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-08-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: xcodeproject
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.12'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- doha@nodes.dk
|
58
|
+
executables:
|
59
|
+
- carthage_cashier
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- bin/carthage_cashier
|
64
|
+
- lib/carthage_cashier.rb
|
65
|
+
- lib/carthage_cashier/version.rb
|
66
|
+
homepage: https://www.github.com/nodes-ios/carthage_cache
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.5.1
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Caches files produced by carthage for faster build times, especially on CI
|
90
|
+
servers.
|
91
|
+
test_files: []
|