zabel 1.0.2 → 1.0.6
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 +4 -4
- data/.gitignore +1 -0
- data/README.md +63 -20
- data/bin/zabel +16 -5
- data/lib/zabel/version.rb +2 -1
- data/lib/zabel.rb +147 -126
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d607380cd6e2e4d34fcb94ba8ba98cd8b4b792d00ea1393368fdb9eb6e46197
|
4
|
+
data.tar.gz: b9a4e213159f537272a37f17091624fc170c8f3869ae403dd116329d5ec8c129
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1c16e2711fa4409171b2d91e0fe2acd785645660ba895fd7f0571a3d6196187c42391563bdda1e9018572027acbbd71ad59f4d6180f6cfd6ca3f8ebb5bf7392
|
7
|
+
data.tar.gz: ba49030026e2103abdfe462e9ec4d2ebd1c3ccb5a38ff2ecbe4553a00109ac6b8e1a26e382a8c52d28bfe07282c241326743c2ebd5fdec36cf6f32fafe3fbf7b
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,21 @@
|
|
1
|
-
# Zabel
|
2
|
-
|
3
1
|
Zabel, is a build cacher for Xcode, using Xcodeproj and MD5, to detect and cache products for targets. Designed for CI by now. Zabel is not Bazel.
|
4
2
|
|
3
|
+
WARNING: BE CAREFUL IN PRODUCTION ENVIRONMENT.
|
4
|
+
|
5
|
+
- [Feature](https://github.com/WeijunDeng/Zabel#feature)
|
6
|
+
- [Installation](https://github.com/WeijunDeng/Zabel#installation)
|
7
|
+
- [Usage](https://github.com/WeijunDeng/Zabel#usage)
|
8
|
+
- [Advanced usage](https://github.com/WeijunDeng/Zabel#advanced-usage)
|
9
|
+
- [Options](https://github.com/WeijunDeng/Zabel#options)
|
10
|
+
- [Changelog](https://github.com/WeijunDeng/Zabel#changelog)
|
11
|
+
- [Development](https://github.com/WeijunDeng/Zabel#development)
|
12
|
+
- [Test](https://github.com/WeijunDeng/Zabel#test)
|
13
|
+
- [Contributing](https://github.com/WeijunDeng/Zabel#contributing)
|
14
|
+
- [License](https://github.com/WeijunDeng/Zabel#license)
|
15
|
+
- [Code of Conduct](https://github.com/WeijunDeng/Zabel#code-of-conduct)
|
16
|
+
- [FAQ](https://github.com/WeijunDeng/Zabel#faq)
|
17
|
+
- [TODO](https://github.com/WeijunDeng/Zabel#todo)
|
18
|
+
|
5
19
|
## Feature
|
6
20
|
|
7
21
|
- only support Cocoapods targets now
|
@@ -23,9 +37,13 @@ Zabel, is a build cacher for Xcode, using Xcodeproj and MD5, to detect and cache
|
|
23
37
|
|
24
38
|
## Installation
|
25
39
|
|
40
|
+
Please use Ruby 2.x.
|
41
|
+
|
26
42
|
Add this line to your application's Gemfile:
|
27
43
|
|
28
44
|
```ruby
|
45
|
+
source "https://rubygems.org"
|
46
|
+
|
29
47
|
gem 'zabel'
|
30
48
|
```
|
31
49
|
|
@@ -33,30 +51,56 @@ And then execute:
|
|
33
51
|
|
34
52
|
$ bundle
|
35
53
|
|
54
|
+
Or install in local path:
|
55
|
+
|
56
|
+
$ bundle install --path vendor/bundle
|
57
|
+
|
36
58
|
Or install it yourself as:
|
37
59
|
|
38
|
-
$ gem install zabel
|
60
|
+
$ [sudo] gem install zabel
|
39
61
|
|
40
62
|
## Usage
|
41
63
|
|
42
|
-
Simply add zabel before your xcodebuild/fastlane command. Please ensure that your command can work without zabel.
|
64
|
+
Simply add zabel before your xcodebuild/fastlane command. Please ensure that your command can work without zabel.
|
43
65
|
|
44
|
-
|
45
|
-
zabel xcodebuild/fastlane xxx
|
46
|
-
```
|
66
|
+
$ [bundle exec] zabel xcodebuild/fastlane ...
|
47
67
|
|
48
68
|
## Advanced usage
|
49
69
|
|
50
70
|
You can controll your cache keys, which can be more or less. Please ensure that your arguments are same in pre and post.
|
51
71
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
72
|
+
$ [bundle exec] zabel pre -configuration Debug ...
|
73
|
+
$ xcodebuild/fastlane ...
|
74
|
+
$ [bundle exec] zabel post -configuration Debug ...
|
75
|
+
|
76
|
+
Importantly, configuration argument must be set with zabel.
|
77
|
+
|
78
|
+
## Options
|
79
|
+
|
80
|
+
You can customize some options by yourself.
|
81
|
+
|
82
|
+
Zabel stores caches in `~/zabel` by default. You can change this path.
|
83
|
+
|
84
|
+
$ export ZABEL_CACHE_ROOT=xxx
|
85
|
+
|
86
|
+
Zabel uses LRU to clear unuse old caches, to keep max count with 10000 by default. You can change this number.
|
87
|
+
|
88
|
+
$ export ZABEL_CACHE_COUNT=12345
|
89
|
+
|
90
|
+
Zable caches targets which count of source files is greater than or equal 1 by default. You can set this value to 0 or more than 1 to achieve higher total speed.
|
91
|
+
|
92
|
+
$ export ZABEL_MIN_SOURCE_FILE_COUNT=10
|
93
|
+
|
94
|
+
Zabel detects module map dependecy by default. However, there are bugs of xcodebuild or swift-frontend, which emits unnecessary, incorrect and even cycle modulemap dependencies. Cycle dependency targets will be miss every time. To test by run "ruby test/one.rb test/todo/modulemap_file/Podfile". You can disable this feature.
|
95
|
+
|
96
|
+
$ export ZABEL_NOT_DETECT_MODULE_MAP_DEPENDENCY=YES
|
57
97
|
|
58
98
|
## Changelog
|
59
99
|
|
100
|
+
- 1.0.6 fix build phase bug
|
101
|
+
- 1.0.5 fix script error
|
102
|
+
- 1.0.4 optimize spec checksums; optimize output log; use CACHE_VERSION; should not cache if dependency error
|
103
|
+
- 1.0.3 support bundle install
|
60
104
|
- 1.0.2 support legacy build system
|
61
105
|
- 1.0.1 support xcodebuild archive and fastlane
|
62
106
|
- 1.0.0
|
@@ -78,14 +122,6 @@ ruby test/one.rb test/case/simple/Podfile
|
|
78
122
|
ruby test/one.rb test/todo/modulemap_file/Podfile
|
79
123
|
```
|
80
124
|
|
81
|
-
## TODO
|
82
|
-
|
83
|
-
- support more projects and targets, not only Pods
|
84
|
-
- support and test more clang arguments
|
85
|
-
- support intermediate cache such as .o and .gcno
|
86
|
-
- try to support local development
|
87
|
-
- try to support remote cache server
|
88
|
-
|
89
125
|
## Contributing
|
90
126
|
|
91
127
|
Bug reports and pull requests are welcome on GitHub at https://github.com/WeijunDeng/Zabel. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
@@ -120,4 +156,11 @@ Q: What about dependencies ?
|
|
120
156
|
|
121
157
|
A: Simple dependent files (headers) and implicit dependent targets will be detected. If dependent files of a target change, this target will be recompiled. If dependent targets of a target miss cache, this target and dependent targets will be recompiled.
|
122
158
|
|
159
|
+
## TODO
|
160
|
+
|
161
|
+
- support more projects and targets, not only Pods
|
162
|
+
- support and test more clang arguments
|
163
|
+
- support intermediate cache such as .o and .gcno
|
164
|
+
- try to support local development
|
165
|
+
- try to support remote cache server
|
123
166
|
|
data/bin/zabel
CHANGED
@@ -15,17 +15,28 @@ elsif ARGV[0] == Zabel::STAGE_POST
|
|
15
15
|
elsif ARGV.include?("-configuration") or ARGV.include?("--configuration")
|
16
16
|
total_start_time = Time.now
|
17
17
|
|
18
|
+
puts ARGV.to_s
|
19
|
+
|
18
20
|
Zabel::zabel_pre(ARGV)
|
19
21
|
|
20
22
|
build_start_time = Time.now
|
21
23
|
exit 1 unless system(*ARGV)
|
22
|
-
puts "[ZABEL]
|
24
|
+
puts "[ZABEL/I] duration = #{(Time.now - build_start_time).to_i} s in stage build"
|
23
25
|
|
24
26
|
Zabel::zabel_post(ARGV)
|
25
27
|
|
26
|
-
puts "[ZABEL]
|
27
|
-
|
28
|
-
puts "
|
29
|
-
puts "
|
28
|
+
puts "[ZABEL/I] duration = #{(Time.now - total_start_time).to_i} s in stage all"
|
29
|
+
elsif ARGV.size == 0 or (ARGV.size == 1 and ARGV[0].include?("v"))
|
30
|
+
puts "ver: #{Zabel::VERSION}"
|
31
|
+
puts "exe: #{$0}"
|
30
32
|
puts "url: https://github.com/WeijunDeng/Zabel"
|
33
|
+
else
|
34
|
+
puts "Usage: "
|
35
|
+
puts "IMPORTANT: configuration must be set."
|
36
|
+
puts "For example:"
|
37
|
+
puts "zabel xcodebuild archive -workspace app.xcworkspace -scheme app -configuration Debug ..."
|
38
|
+
puts "zabel fastlane gym --workspace app.xcworkspace --scheme app --configuration Debug ..."
|
39
|
+
puts ""
|
40
|
+
puts "Advanced usage:"
|
41
|
+
puts "zabel pre -configuration Debug && xcodebuild/fastlane ... && zabel post -configuration Debug"
|
31
42
|
end
|
data/lib/zabel/version.rb
CHANGED
data/lib/zabel.rb
CHANGED
@@ -23,6 +23,7 @@ module Zabel
|
|
23
23
|
|
24
24
|
STATUS_HIT = "hit"
|
25
25
|
STATUS_MISS = "miss"
|
26
|
+
STATUS_MISS_AND_READY = "miss_ready"
|
26
27
|
|
27
28
|
STAGE_CLEAN = "clean"
|
28
29
|
STAGE_EXTRACT = "extract"
|
@@ -74,10 +75,6 @@ module Zabel
|
|
74
75
|
return 1
|
75
76
|
end
|
76
77
|
|
77
|
-
def self.zabel_should_extract_once
|
78
|
-
return false
|
79
|
-
end
|
80
|
-
|
81
78
|
def self.zabel_get_projects
|
82
79
|
# TODO: to support more project, not only Pods
|
83
80
|
pods_project = Xcodeproj::Project.open("Pods/Pods.xcodeproj")
|
@@ -103,6 +100,7 @@ module Zabel
|
|
103
100
|
|
104
101
|
def self.zabel_can_cache_target(target)
|
105
102
|
if target.name.start_with? "Pods-"
|
103
|
+
puts "[ZABEL/I] skip #{target.name}"
|
106
104
|
return false
|
107
105
|
end
|
108
106
|
if target.class == Xcodeproj::Project::Object::PBXNativeTarget
|
@@ -111,7 +109,11 @@ module Zabel
|
|
111
109
|
target.product_type == "com.apple.product-type.library.static" or
|
112
110
|
target.product_type == "com.apple.product-type.framework"
|
113
111
|
return true
|
112
|
+
else
|
113
|
+
puts "[ZABEL/I] skip #{target.name} #{target.class} #{target.product_type}"
|
114
114
|
end
|
115
|
+
else
|
116
|
+
puts "[ZABEL/I] skip #{target.name} #{target.class}"
|
115
117
|
end
|
116
118
|
return false
|
117
119
|
end
|
@@ -129,15 +131,19 @@ module Zabel
|
|
129
131
|
file = file.gsub("\\ ", " ")
|
130
132
|
|
131
133
|
unless File.exist? file
|
132
|
-
puts "[ZABEL]
|
134
|
+
puts "[ZABEL/E] #{target.name} #{file} should exist in dependency file #{dependency_file} in #{intermediate_dir}/**/*.d"
|
133
135
|
return []
|
134
136
|
end
|
135
137
|
|
136
138
|
if file.start_with? intermediate_dir + "/" or
|
137
|
-
file.start_with? product_dir + "/"
|
138
|
-
file.start_with? xcframeworks_build_dir + "/"
|
139
|
+
file.start_with? product_dir + "/"
|
139
140
|
next
|
140
141
|
end
|
142
|
+
|
143
|
+
if xcframeworks_build_dir and xcframeworks_build_dir.size > 0 and file.start_with? xcframeworks_build_dir + "/"
|
144
|
+
next
|
145
|
+
end
|
146
|
+
|
141
147
|
|
142
148
|
dependency_files.push file
|
143
149
|
end
|
@@ -198,11 +204,11 @@ module Zabel
|
|
198
204
|
file_time_hash[file] = File.mtime(file)
|
199
205
|
end
|
200
206
|
file_list = file_list.sort_by {|file| - file_time_hash[file].to_f}
|
201
|
-
puts "[ZABEL]
|
207
|
+
puts "[ZABEL/I] keep cache " + file_list.size.to_s + " " + Open3.capture3("du -sh #{zabel_get_cache_root}")[0].to_s
|
202
208
|
|
203
209
|
if file_list.size > 1
|
204
|
-
puts "[ZABEL]
|
205
|
-
puts "[ZABEL]
|
210
|
+
puts "[ZABEL/I] keep oldest " + file_time_hash[file_list.last].to_s + " " + file_list.last
|
211
|
+
puts "[ZABEL/I] keep newest " + file_time_hash[file_list.first].to_s + " " + file_list.first
|
206
212
|
end
|
207
213
|
|
208
214
|
if file_list.size > zabel_get_cache_count
|
@@ -246,7 +252,7 @@ module Zabel
|
|
246
252
|
project_configuration_content = project_configuration.pretty_print.to_yaml
|
247
253
|
project_xcconfig = ""
|
248
254
|
if project_configuration.base_configuration_reference
|
249
|
-
config_file_path = project_configuration.base_configuration_reference.real_path
|
255
|
+
config_file_path = project_configuration.base_configuration_reference.real_path.to_s
|
250
256
|
if File.exist? config_file_path
|
251
257
|
project_xcconfig = File.read(config_file_path).lines.reject{|line|line.include? "_SEARCH_PATHS"}.sort.join("")
|
252
258
|
end
|
@@ -256,18 +262,18 @@ module Zabel
|
|
256
262
|
target_configuration_content = target_configuration.pretty_print.to_yaml
|
257
263
|
target_xcconfig = ""
|
258
264
|
if target_configuration.base_configuration_reference
|
259
|
-
config_file_path = target_configuration.base_configuration_reference.real_path
|
265
|
+
config_file_path = target_configuration.base_configuration_reference.real_path.to_s
|
260
266
|
if File.exist? config_file_path
|
261
267
|
target_xcconfig = File.read(config_file_path).lines.reject{|line|line.include? "_SEARCH_PATHS"}.sort.join("")
|
262
268
|
end
|
263
269
|
end
|
264
|
-
|
270
|
+
|
265
271
|
first_configuration = []
|
266
272
|
build_phases = []
|
267
273
|
build_phases.push target.source_build_phase if target.methods.include? :source_build_phase
|
268
274
|
build_phases.push target.resources_build_phase if target.methods.include? :resources_build_phase
|
269
275
|
build_phases.each do | build_phase |
|
270
|
-
|
276
|
+
build_phase.files_references.each do | files_reference |
|
271
277
|
files_reference.build_files.each do |build_file|
|
272
278
|
if build_file.settings and build_file.settings.class == Hash
|
273
279
|
first_configuration.push File.basename(build_file.file_ref.real_path.to_s) + "\n" + build_file.settings.to_yaml
|
@@ -293,22 +299,33 @@ module Zabel
|
|
293
299
|
|
294
300
|
source_md5_list = []
|
295
301
|
# zabel built-in verison, which will be changed for incompatibility in the future
|
296
|
-
source_md5_list.push "Zabel version : #{Zabel::
|
302
|
+
source_md5_list.push "Zabel cache version : #{Zabel::CACHE_VERSION}"
|
297
303
|
source_md5_list.push "ARGV : #{key_argv.to_s}"
|
298
304
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
305
|
+
# TODO: to get a explicit spec name from a target.
|
306
|
+
target_possible_spec_names = []
|
307
|
+
target_possible_spec_names.push target_configuration.build_settings["PRODUCT_NAME"] if target_configuration.build_settings["PRODUCT_NAME"]
|
308
|
+
target_possible_spec_names.push target_configuration.build_settings["IBSC_MODULE"] if target_configuration.build_settings["IBSC_MODULE"]
|
309
|
+
target_possible_spec_names.push File.basename(target_configuration.build_settings["CONFIGURATION_BUILD_DIR"]) if target_configuration.build_settings["CONFIGURATION_BUILD_DIR"]
|
310
|
+
if target_xcconfig.lines.detect { | line | line.start_with? "CONFIGURATION_BUILD_DIR = "}
|
311
|
+
target_possible_spec_names.push File.basename(target_xcconfig.lines.detect { | line | line.start_with? "CONFIGURATION_BUILD_DIR = "}.strip)
|
312
|
+
end
|
313
|
+
if target_xcconfig.lines.detect { | line | line.start_with? "PODS_TARGET_SRCROOT = "}
|
314
|
+
target_possible_spec_names.push File.basename(target_xcconfig.lines.detect { | line | line.start_with? "PODS_TARGET_SRCROOT = "}.strip)
|
315
|
+
end
|
316
|
+
|
317
|
+
target_match_spec_names = []
|
318
|
+
target_possible_spec_names.uniq.sort.each do | spec_name |
|
319
|
+
if spec_name.size > 0 and $zabel_podfile_spec_checksums.has_key? spec_name
|
306
320
|
source_md5_list.push "SPEC CHECKSUM : #{spec_name} #{$zabel_podfile_spec_checksums[spec_name]}"
|
307
|
-
|
321
|
+
target_match_spec_names.push spec_name
|
308
322
|
end
|
309
323
|
end
|
310
|
-
|
311
|
-
|
324
|
+
|
325
|
+
unless target_match_spec_names.size == 1
|
326
|
+
puts "[ZABEL/E] #{target.name} #{target_possible_spec_names.to_s} #{target_match_spec_names.to_s} SPEC CHECKSUM should be found"
|
327
|
+
puts target_configuration.build_settings.to_s
|
328
|
+
puts target_xcconfig
|
312
329
|
end
|
313
330
|
|
314
331
|
source_md5_list.push "Project : #{File.basename(project.path)}"
|
@@ -342,10 +359,6 @@ module Zabel
|
|
342
359
|
command = "rm -rf Pods/*.xcodeproj/*.#{FILE_NAME_TARGET_CONTEXT}"
|
343
360
|
puts command
|
344
361
|
raise unless system command
|
345
|
-
|
346
|
-
command = "rm -rf Pods/zabel.xcodeproj"
|
347
|
-
puts command
|
348
|
-
raise unless system command
|
349
362
|
end
|
350
363
|
|
351
364
|
def self.zabel_add_cache(target, target_context, message)
|
@@ -366,7 +379,7 @@ module Zabel
|
|
366
379
|
end
|
367
380
|
|
368
381
|
unless full_product_name and full_product_name.size > 0 and File.exist? "#{product_dir}/#{full_product_name}"
|
369
|
-
puts "[ZABEL]
|
382
|
+
puts "[ZABEL/E] #{target.name} #{product_dir}/#{full_product_name} should exist"
|
370
383
|
return false
|
371
384
|
end
|
372
385
|
|
@@ -379,12 +392,12 @@ module Zabel
|
|
379
392
|
|
380
393
|
puts command
|
381
394
|
unless system command
|
382
|
-
puts "[ZABEL]
|
395
|
+
puts "[ZABEL/E] #{command} should succeed"
|
383
396
|
return false
|
384
397
|
end
|
385
398
|
|
386
399
|
if File.exist? target_cache_dir
|
387
|
-
puts "[ZABEL]
|
400
|
+
puts "[ZABEL/E] #{target_cache_dir} should not exist"
|
388
401
|
raise unless system "rm -rf \"#{target_cache_dir}\""
|
389
402
|
return false
|
390
403
|
end
|
@@ -392,7 +405,7 @@ module Zabel
|
|
392
405
|
command = "mkdir -p \"#{target_cache_dir}\""
|
393
406
|
unless system command
|
394
407
|
puts command
|
395
|
-
puts "[ZABEL]
|
408
|
+
puts "[ZABEL/E] #{command} should succeed"
|
396
409
|
return false
|
397
410
|
end
|
398
411
|
|
@@ -402,11 +415,11 @@ module Zabel
|
|
402
415
|
puts command
|
403
416
|
unless system command
|
404
417
|
puts command
|
405
|
-
puts "[ZABEL]
|
418
|
+
puts "[ZABEL/E] #{command} should succeed"
|
406
419
|
return false
|
407
420
|
end
|
408
421
|
unless File.exist? cache_product_path
|
409
|
-
puts "[ZABEL]
|
422
|
+
puts "[ZABEL/E] #{cache_product_path} should exist after mv"
|
410
423
|
return false
|
411
424
|
end
|
412
425
|
|
@@ -422,6 +435,7 @@ module Zabel
|
|
422
435
|
target_context.delete(:target_status)
|
423
436
|
target_context.delete(:potential_hit_target_cache_dirs)
|
424
437
|
target_context.delete(:target_md5_content)
|
438
|
+
target_context.delete(:miss_dependency_list)
|
425
439
|
[BUILD_KEY_SYMROOT, BUILD_KEY_CONFIGURATION_BUILD_DIR, BUILD_KEY_OBJROOT, BUILD_KEY_TARGET_TEMP_DIR, BUILD_KEY_PODS_XCFRAMEWORKS_BUILD_DIR, BUILD_KEY_SRCROOT].each do | key |
|
426
440
|
target_context.delete(key)
|
427
441
|
end
|
@@ -442,7 +456,7 @@ module Zabel
|
|
442
456
|
configuration_name = argv[argv.index("--configuration") + 1]
|
443
457
|
end
|
444
458
|
unless configuration_name and configuration_name.size > 0
|
445
|
-
raise "[ZABEL]
|
459
|
+
raise "[ZABEL/E] -configuration or --configuration should be set"
|
446
460
|
end
|
447
461
|
|
448
462
|
start_time = Time.now
|
@@ -454,17 +468,30 @@ module Zabel
|
|
454
468
|
post_targets_context = {}
|
455
469
|
|
456
470
|
projects.each do | project |
|
471
|
+
project_configuration = project.build_configurations.detect { | config | config.name == configuration_name}
|
472
|
+
unless project_configuration
|
473
|
+
puts "[ZABEL/E] #{project.path} should have config #{configuration_name}"
|
474
|
+
next
|
475
|
+
end
|
457
476
|
project.native_targets.each do | target |
|
477
|
+
target_context_file = "#{project.path}/#{target.name}.#{FILE_NAME_TARGET_CONTEXT}"
|
478
|
+
unless File.exist? target_context_file
|
479
|
+
next
|
480
|
+
end
|
458
481
|
if zabel_can_cache_target(target)
|
459
|
-
|
460
|
-
target_context_file = "#{project.path}/#{target.name}.#{FILE_NAME_TARGET_CONTEXT}"
|
461
|
-
unless File.exist? target_context_file
|
462
|
-
next
|
463
|
-
end
|
464
|
-
|
465
482
|
target_context = YAML.load(File.read(target_context_file))
|
466
|
-
|
467
|
-
if target_context[:target_status] ==
|
483
|
+
|
484
|
+
if target_context[:target_status] == STATUS_MISS_AND_READY
|
485
|
+
environment_valid = true
|
486
|
+
[BUILD_KEY_SYMROOT, BUILD_KEY_CONFIGURATION_BUILD_DIR, BUILD_KEY_OBJROOT, BUILD_KEY_TARGET_TEMP_DIR, BUILD_KEY_SRCROOT, BUILD_KEY_FULL_PRODUCT_NAME].sort.each do | key |
|
487
|
+
unless target_context.has_key? key and target_context[key] and target_context[key].size > 0
|
488
|
+
puts "[ZABEL/E] #{target.name} should have #{key} in #{target_context.to_s}"
|
489
|
+
environment_valid = false
|
490
|
+
break
|
491
|
+
end
|
492
|
+
end
|
493
|
+
next unless environment_valid
|
494
|
+
|
468
495
|
source_files = zabel_get_target_source_files(target)
|
469
496
|
|
470
497
|
product_dir = target_context[BUILD_KEY_CONFIGURATION_BUILD_DIR]
|
@@ -473,7 +500,7 @@ module Zabel
|
|
473
500
|
|
474
501
|
dependency_files = zabel_get_dependency_files(target, intermediate_dir, product_dir, xcframeworks_build_dir)
|
475
502
|
if source_files.size > 0 and dependency_files.size == 0 and target.product_type != "com.apple.product-type.bundle"
|
476
|
-
puts "[ZABEL]
|
503
|
+
puts "[ZABEL/E] #{target.name} should have dependent files"
|
477
504
|
next
|
478
505
|
end
|
479
506
|
target_context[:dependency_files] = dependency_files - source_files
|
@@ -481,7 +508,7 @@ module Zabel
|
|
481
508
|
target_context[:target_md5_content] = target_md5_content
|
482
509
|
target_md5 = Digest::MD5.hexdigest(target_md5_content)
|
483
510
|
unless target_context[:target_md5] == target_md5
|
484
|
-
puts "[ZABEL]
|
511
|
+
puts "[ZABEL/E] #{target.name} md5 should not be changed after build"
|
485
512
|
next
|
486
513
|
end
|
487
514
|
if target_context[BUILD_KEY_SRCROOT] and target_context[BUILD_KEY_SRCROOT].size > 0 and
|
@@ -489,19 +516,19 @@ module Zabel
|
|
489
516
|
if File.exist? Dir.pwd + "/" + zabel_get_content_without_pwd("#{target_context[BUILD_KEY_SRCROOT]}/#{target_context[BUILD_KEY_MODULEMAP_FILE]}")
|
490
517
|
target_context[BUILD_KEY_MODULEMAP_FILE] = zabel_get_content_without_pwd("#{target_context[BUILD_KEY_SRCROOT]}/#{target_context[BUILD_KEY_MODULEMAP_FILE]}")
|
491
518
|
else
|
492
|
-
puts "[ZABEL]
|
519
|
+
puts "[ZABEL/E] #{target.name} #{target_context[BUILD_KEY_MODULEMAP_FILE]} should be supported"
|
493
520
|
next
|
494
521
|
end
|
495
522
|
end
|
496
523
|
elsif target_context[:target_status] == STATUS_HIT
|
497
524
|
if target_context[BUILD_KEY_MODULEMAP_FILE] and target_context[BUILD_KEY_MODULEMAP_FILE].size > 0
|
498
525
|
if not File.exist? Dir.pwd + "/" + target_context[BUILD_KEY_MODULEMAP_FILE]
|
499
|
-
puts "[ZABEL]
|
526
|
+
puts "[ZABEL/E] #{target.name} #{target_context[BUILD_KEY_MODULEMAP_FILE]} should be supported"
|
500
527
|
next
|
501
528
|
end
|
502
529
|
end
|
503
530
|
else
|
504
|
-
puts "[ZABEL]
|
531
|
+
puts "[ZABEL/E] #{target.name} should be hit or miss"
|
505
532
|
next
|
506
533
|
end
|
507
534
|
|
@@ -514,7 +541,7 @@ module Zabel
|
|
514
541
|
project.native_targets.each do | target |
|
515
542
|
if post_targets_context.has_key? target
|
516
543
|
target_context = post_targets_context[target]
|
517
|
-
next unless target_context[:target_status] ==
|
544
|
+
next unless target_context[:target_status] == STATUS_MISS_AND_READY
|
518
545
|
|
519
546
|
dependency_targets_set = Set.new
|
520
547
|
implicit_dependencies = []
|
@@ -559,9 +586,17 @@ module Zabel
|
|
559
586
|
|
560
587
|
target_context[:dependency_files] = target_context[:dependency_files] - implicit_dependencies
|
561
588
|
dependency_files_md5 = []
|
589
|
+
should_not_cache = false
|
562
590
|
target_context[:dependency_files].each do | file |
|
591
|
+
if file.start_with? target_context[BUILD_KEY_OBJROOT] + "/" or file.start_with? target_context[BUILD_KEY_SYMROOT] + "/"
|
592
|
+
puts "[ZABEL/W] #{target.name} #{file} dependecy should not include build path"
|
593
|
+
should_not_cache = true
|
594
|
+
break
|
595
|
+
end
|
563
596
|
dependency_files_md5.push [zabel_get_content_without_pwd(file), zabel_get_file_md5(file)]
|
564
597
|
end
|
598
|
+
next if should_not_cache
|
599
|
+
|
565
600
|
target_context[:dependency_files_md5] = dependency_files_md5.sort.uniq
|
566
601
|
|
567
602
|
dependency_targets_md5 = dependency_targets_set.to_a.map { | target | [target.name, post_targets_context[target][:target_md5]]}
|
@@ -582,13 +617,13 @@ module Zabel
|
|
582
617
|
|
583
618
|
zabel_keep
|
584
619
|
|
585
|
-
puts "[ZABEL]
|
620
|
+
puts "[ZABEL/I] total add #{add_count}"
|
586
621
|
|
587
|
-
puts "[ZABEL]
|
622
|
+
puts "[ZABEL/I] duration = #{(Time.now - start_time).to_i} s in stage post"
|
588
623
|
|
589
624
|
end
|
590
625
|
|
591
|
-
def self.zabel_get_potential_hit_target_cache_dirs(target, target_md5)
|
626
|
+
def self.zabel_get_potential_hit_target_cache_dirs(target, target_md5, miss_dependency_list)
|
592
627
|
dependency_start_time = Time.now
|
593
628
|
target_cache_dirs = Dir.glob(zabel_get_cache_root + "/" + target.name + "-" + target_md5 + "-*")
|
594
629
|
file_time_hash = {}
|
@@ -607,12 +642,12 @@ module Zabel
|
|
607
642
|
dependency_md5 = item[1]
|
608
643
|
|
609
644
|
unless File.exist? dependency_file
|
610
|
-
|
645
|
+
miss_dependency_list.push "[ZABEL/W] #{target.name} #{dependency_file} file should exist to be hit"
|
611
646
|
dependency_miss = true
|
612
647
|
break
|
613
648
|
end
|
614
649
|
unless zabel_get_file_md5(dependency_file) == dependency_md5
|
615
|
-
|
650
|
+
miss_dependency_list.push "[ZABEL/W] #{target.name} #{dependency_file} md5 #{zabel_get_file_md5(dependency_file)} should match #{dependency_md5} to be hit"
|
616
651
|
dependency_miss = true
|
617
652
|
break
|
618
653
|
end
|
@@ -621,14 +656,14 @@ module Zabel
|
|
621
656
|
if not target_context[:target_md5] == target_md5
|
622
657
|
command = "rm -rf \"#{target_cache_dir}\""
|
623
658
|
raise unless system command
|
624
|
-
puts "[ZABEL]
|
659
|
+
puts "[ZABEL/E] #{target.name} #{target_cache_dir} target md5 should match to be verified"
|
625
660
|
dependency_miss = false
|
626
661
|
next
|
627
662
|
end
|
628
663
|
if not target_context[:product_md5] == zabel_get_file_md5(target_cache_dir + "/" + FILE_NAME_PRODUCT)
|
629
664
|
command = "rm -rf \"#{target_cache_dir}\""
|
630
665
|
raise unless system command
|
631
|
-
puts "[ZABEL]
|
666
|
+
puts "[ZABEL/E] #{target.name} #{target_cache_dir} product md5 should match to be verified"
|
632
667
|
dependency_miss = false
|
633
668
|
next
|
634
669
|
end
|
@@ -645,23 +680,7 @@ module Zabel
|
|
645
680
|
return potential_hit_target_cache_dirs
|
646
681
|
end
|
647
682
|
|
648
|
-
|
649
|
-
# and this is faster, without searching deeply.
|
650
|
-
def self.zabel_fast_add_dependency(project, target_target, target, subproject_reference)
|
651
|
-
container_proxy = project.new(Xcodeproj::Project::PBXContainerItemProxy)
|
652
|
-
container_proxy.container_portal = subproject_reference.uuid
|
653
|
-
container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
|
654
|
-
container_proxy.remote_global_id_string = target.uuid
|
655
|
-
container_proxy.remote_info = target.name
|
656
|
-
|
657
|
-
dependency = project.new(Xcodeproj::Project::PBXTargetDependency)
|
658
|
-
dependency.name = target.name
|
659
|
-
dependency.target_proxy = container_proxy
|
660
|
-
|
661
|
-
target_target.dependencies << dependency
|
662
|
-
end
|
663
|
-
|
664
|
-
def self.zabel_disable_build_and_inject_extract(project, target, inject_project, inject_target, inject_scripts, target_context)
|
683
|
+
def self.zabel_disable_build_and_inject_extract(project, target, target_context)
|
665
684
|
target_cache_dir = target_context[:hit_target_cache_dir]
|
666
685
|
|
667
686
|
# touch to update mtime
|
@@ -674,34 +693,24 @@ module Zabel
|
|
674
693
|
build_phase.class == Xcodeproj::Project::Object::PBXResourcesBuildPhase
|
675
694
|
}
|
676
695
|
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
subproject_reference = nil
|
681
|
-
project.main_group.files.each do | file |
|
682
|
-
if file.class == Xcodeproj::Project::Object::PBXFileReference and File.basename(file.path) == File.basename(inject_project.path)
|
683
|
-
subproject_reference = file
|
684
|
-
break
|
685
|
-
end
|
686
|
-
end
|
687
|
-
|
688
|
-
unless subproject_reference
|
689
|
-
subproject_reference = project.main_group.new_reference(inject_project.path, :group)
|
690
|
-
end
|
691
|
-
|
692
|
-
zabel_fast_add_dependency(project, target, inject_target, subproject_reference)
|
693
|
-
|
694
|
-
inject_scripts.push extract_script
|
695
|
-
else
|
696
|
-
inject_phase = target.new_shell_script_build_phase("zabel_extract_#{target.name}")
|
697
|
-
inject_phase.shell_script = extract_script
|
698
|
-
inject_phase.show_env_vars_in_log = '1'
|
696
|
+
zabel_exec = "\"#{$0}\""
|
697
|
+
if ENV["BUNDLE_BIN_PATH"] and ENV["BUNDLE_BIN_PATH"].size > 0 and ENV["BUNDLE_GEMFILE"] and ENV["BUNDLE_GEMFILE"].size > 0
|
698
|
+
zabel_exec = "cd \"#{File.dirname(ENV["BUNDLE_GEMFILE"])}\" && \"#{ENV["BUNDLE_BIN_PATH"]}\" exe zabel"
|
699
699
|
end
|
700
|
+
extract_script = "#{zabel_exec} #{STAGE_EXTRACT} \"#{target_cache_dir}\" \"#{target_context[:build_product_dir]}\" \"#{target_context[:build_intermediate_dir]}\""
|
701
|
+
|
702
|
+
inject_phase = target.new_shell_script_build_phase("zabel_extract_#{target.name}")
|
703
|
+
inject_phase.shell_script = extract_script
|
704
|
+
inject_phase.show_env_vars_in_log = '1'
|
700
705
|
end
|
701
706
|
|
702
707
|
def self.zabel_inject_printenv(project, target)
|
708
|
+
zabel_exec = "\"#{$0}\""
|
709
|
+
if ENV["BUNDLE_BIN_PATH"] and ENV["BUNDLE_BIN_PATH"].size > 0 and ENV["BUNDLE_GEMFILE"] and ENV["BUNDLE_GEMFILE"].size > 0
|
710
|
+
zabel_exec = "cd \"#{File.dirname(ENV["BUNDLE_GEMFILE"])}\" && \"#{ENV["BUNDLE_BIN_PATH"]}\" exe zabel"
|
711
|
+
end
|
703
712
|
inject_phase = target.new_shell_script_build_phase("zabel_printenv_#{target.name}")
|
704
|
-
inject_phase.shell_script = "#{
|
713
|
+
inject_phase.shell_script = "#{zabel_exec} #{STAGE_PRINTENV} #{target.name} \"#{project.path}\""
|
705
714
|
inject_phase.show_env_vars_in_log = '1'
|
706
715
|
end
|
707
716
|
|
@@ -715,7 +724,7 @@ module Zabel
|
|
715
724
|
configuration_name = argv[argv.index("--configuration") + 1]
|
716
725
|
end
|
717
726
|
unless configuration_name and configuration_name.size > 0
|
718
|
-
raise "[ZABEL]
|
727
|
+
raise "[ZABEL/E] -configuration or --configuration should be set"
|
719
728
|
end
|
720
729
|
|
721
730
|
start_time = Time.now
|
@@ -728,15 +737,6 @@ module Zabel
|
|
728
737
|
|
729
738
|
zabel_clean_temp_files
|
730
739
|
|
731
|
-
if zabel_should_extract_once
|
732
|
-
inject_project = Xcodeproj::Project.new("Pods/zabel.xcodeproj")
|
733
|
-
inject_target = inject_project.new_aggregate_target("zabel")
|
734
|
-
inject_phase = inject_target.new_shell_script_build_phase("zabel_extract")
|
735
|
-
inject_phase.show_env_vars_in_log = '1'
|
736
|
-
inject_project.save
|
737
|
-
inject_scripts = []
|
738
|
-
end
|
739
|
-
|
740
740
|
projects = zabel_get_projects
|
741
741
|
|
742
742
|
pre_targets_context = {}
|
@@ -747,19 +747,32 @@ module Zabel
|
|
747
747
|
iteration_count = 0
|
748
748
|
|
749
749
|
projects.each do | project |
|
750
|
+
project_configuration = project.build_configurations.detect { | config | config.name == configuration_name}
|
751
|
+
unless project_configuration
|
752
|
+
puts "[ZABEL/E] #{project.path} should have config #{configuration_name}"
|
753
|
+
next
|
754
|
+
end
|
750
755
|
project.native_targets.each do | target |
|
751
756
|
if zabel_can_cache_target(target)
|
752
757
|
source_files = zabel_get_target_source_files(target)
|
753
|
-
|
758
|
+
unless source_files.size >= zabel_get_min_source_file_count
|
759
|
+
puts "[ZABEL/I] skip #{target.name} #{source_files.size} < #{zabel_get_min_source_file_count}"
|
760
|
+
next
|
761
|
+
end
|
754
762
|
target_md5_content = zabel_get_target_md5_content(project, target, configuration_name, argv, source_files)
|
755
763
|
target_md5 = Digest::MD5.hexdigest(target_md5_content)
|
756
|
-
|
764
|
+
miss_dependency_list = []
|
765
|
+
potential_hit_target_cache_dirs = zabel_get_potential_hit_target_cache_dirs(target, target_md5, miss_dependency_list)
|
757
766
|
|
758
767
|
target_context = {}
|
759
768
|
target_context[:target_md5] = target_md5
|
760
769
|
target_context[:potential_hit_target_cache_dirs] = potential_hit_target_cache_dirs
|
770
|
+
target_context[:miss_dependency_list] = miss_dependency_list
|
761
771
|
if potential_hit_target_cache_dirs.size == 0
|
762
|
-
|
772
|
+
if miss_dependency_list.size > 0
|
773
|
+
puts miss_dependency_list.uniq.join("\n")
|
774
|
+
end
|
775
|
+
puts "[ZABEL/I] miss #{target.name} #{target_md5} in iteration #{iteration_count}"
|
763
776
|
target_context[:target_status] = STATUS_MISS
|
764
777
|
miss_count = miss_count + 1
|
765
778
|
end
|
@@ -803,7 +816,7 @@ module Zabel
|
|
803
816
|
end
|
804
817
|
end
|
805
818
|
if hit_target_cache_dir
|
806
|
-
puts "[ZABEL]
|
819
|
+
puts "[ZABEL/I] hit #{target.name} #{target_context[:target_md5]} in iteration #{iteration_count} potential #{potential_hit_target_cache_dirs.size}"
|
807
820
|
target_context[:target_status] = STATUS_HIT
|
808
821
|
target_context[:hit_target_cache_dir] = hit_target_cache_dir
|
809
822
|
hit_count = hit_count + 1
|
@@ -823,11 +836,15 @@ module Zabel
|
|
823
836
|
target_context = pre_targets_context[target]
|
824
837
|
|
825
838
|
if target_context[:target_status] == STATUS_HIT
|
826
|
-
zabel_disable_build_and_inject_extract(project, target,
|
839
|
+
zabel_disable_build_and_inject_extract(project, target, target_context)
|
827
840
|
else
|
828
841
|
unless target_context[:target_status] == STATUS_MISS
|
829
842
|
target_context[:target_status] = STATUS_MISS
|
830
|
-
|
843
|
+
miss_dependency_list = target_context[:miss_dependency_list]
|
844
|
+
if miss_dependency_list.size > 0
|
845
|
+
puts miss_dependency_list.uniq.join("\n")
|
846
|
+
end
|
847
|
+
puts "[ZABEL/I] miss #{target.name} #{target_context[:target_md5]} in iteration #{iteration_count}"
|
831
848
|
miss_count = miss_count + 1
|
832
849
|
end
|
833
850
|
zabel_inject_printenv(project, target)
|
@@ -844,25 +861,29 @@ module Zabel
|
|
844
861
|
zabel_clean_backup_project(project)
|
845
862
|
end
|
846
863
|
end
|
847
|
-
|
848
|
-
if zabel_should_extract_once and inject_scripts.size > 0
|
849
|
-
inject_scripts = (["startTime_s=`date +%s`"] + inject_scripts + ["echo \"[ZABEL]<INFO> duration = $[ `date +%s` - $startTime_s ] s in stage #{STAGE_EXTRACT}\""]).flatten
|
850
|
-
inject_phase.shell_script = inject_scripts.join("\n")
|
851
|
-
inject_project.save
|
852
|
-
end
|
853
864
|
|
854
|
-
puts "[ZABEL]
|
865
|
+
puts "[ZABEL/I] total #{hit_count + miss_count} hit #{hit_count} miss #{miss_count} iteration #{iteration_count}"
|
855
866
|
|
856
|
-
puts "[ZABEL]
|
867
|
+
puts "[ZABEL/I] duration = #{(Time.now - start_time).to_i} s in stage pre"
|
857
868
|
end
|
858
869
|
|
859
870
|
def self.zabel_extract
|
871
|
+
puts "[ZABEL/D] #{Time.now.to_f.to_s}"
|
872
|
+
start_time = Time.now
|
873
|
+
|
860
874
|
target_cache_dir = ARGV[1]
|
861
875
|
|
862
876
|
cache_product_path = target_cache_dir + "/#{FILE_NAME_PRODUCT}"
|
863
877
|
|
864
878
|
start_time = Time.now
|
865
879
|
|
880
|
+
[BUILD_KEY_SYMROOT, BUILD_KEY_CONFIGURATION_BUILD_DIR, BUILD_KEY_OBJROOT, BUILD_KEY_TARGET_TEMP_DIR, BUILD_KEY_SRCROOT, BUILD_KEY_FULL_PRODUCT_NAME].sort.each do | key |
|
881
|
+
unless ENV.has_key? key and ENV[key] and ENV[key].size > 0
|
882
|
+
raise "[ZABEL/E] #{target.name} should have #{key}"
|
883
|
+
break
|
884
|
+
end
|
885
|
+
end
|
886
|
+
|
866
887
|
if ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR] != ENV[BUILD_KEY_TARGET_BUILD_DIR]
|
867
888
|
command = "mkdir -p \"#{ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR]}\" && cd \"#{File.dirname(ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR])}/\" && tar -xf \"#{cache_product_path}\""
|
868
889
|
puts command
|
@@ -888,9 +909,13 @@ module Zabel
|
|
888
909
|
puts command
|
889
910
|
raise unless system command
|
890
911
|
end
|
912
|
+
|
913
|
+
puts "[ZABEL/I] duration = #{(Time.now - start_time).to_i} s in stage extract"
|
914
|
+
puts "[ZABEL/D] #{Time.now.to_f.to_s}"
|
891
915
|
end
|
892
916
|
|
893
917
|
def self.zabel_printenv
|
918
|
+
puts ARGV.to_s
|
894
919
|
target_name = ARGV[1]
|
895
920
|
project_path = ARGV[2]
|
896
921
|
|
@@ -902,15 +927,11 @@ module Zabel
|
|
902
927
|
target_context[key] = ENV[key]
|
903
928
|
end
|
904
929
|
end
|
930
|
+
target_context[:target_status] = STATUS_MISS_AND_READY
|
905
931
|
File.write("#{project_path}/#{target_name}.#{FILE_NAME_TARGET_CONTEXT}", target_context.to_yaml)
|
906
932
|
end
|
907
933
|
|
908
934
|
def self.zabel_clean
|
909
|
-
if File.exist? "Pods/zabel.xcodeproj"
|
910
|
-
command = "rm -rf Pods/*.xcodeproj"
|
911
|
-
puts command
|
912
|
-
raise unless system command
|
913
|
-
end
|
914
935
|
zabel_clean_temp_files
|
915
936
|
end
|
916
937
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zabel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dengweijun
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: xcodeproj
|