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.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +63 -20
  4. data/bin/zabel +16 -5
  5. data/lib/zabel/version.rb +2 -1
  6. data/lib/zabel.rb +147 -126
  7. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89413297b2ba01b9d67f3bd364566b73ad66164fbcffba18c13f799a35f0b760
4
- data.tar.gz: 31e676f429656820d38993ffc31b5a6521bd510dedaab32464f5ab3a69ddf3f8
3
+ metadata.gz: 8d607380cd6e2e4d34fcb94ba8ba98cd8b4b792d00ea1393368fdb9eb6e46197
4
+ data.tar.gz: b9a4e213159f537272a37f17091624fc170c8f3869ae403dd116329d5ec8c129
5
5
  SHA512:
6
- metadata.gz: 8644fe694d350d9799affc0eb50f0cc668380dbbf32361d5fb48a29c02cf330bfe63d2769311e3c64f6f33e351b0d028429022cf0a9d6099c9664e5d3db58cf9
7
- data.tar.gz: 56102a92ef122f2cd71c80f6c5e61b561cff1c14021d7dbd77ee4175b708a62f5dc64f2e1150324582f25a02cbbd553782ee9b34517b1b4beeb998e24db457ba
6
+ metadata.gz: d1c16e2711fa4409171b2d91e0fe2acd785645660ba895fd7f0571a3d6196187c42391563bdda1e9018572027acbbd71ad59f4d6180f6cfd6ca3f8ebb5bf7392
7
+ data.tar.gz: ba49030026e2103abdfe462e9ec4d2ebd1c3ccb5a38ff2ecbe4553a00109ac6b8e1a26e382a8c52d28bfe07282c241326743c2ebd5fdec36cf6f32fafe3fbf7b
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  tmp
9
+ bundle
9
10
  Pods
10
11
  build*
11
12
  cache
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
- zabel pre -configuration Release abc
54
- xcodebuild/fastlane xxx
55
- zabel post -configuration Release abc
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]<INFO> duration = #{(Time.now - build_start_time).to_i} s in stage build"
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]<INFO> duration = #{(Time.now - total_start_time).to_i} s in stage all"
27
- else
28
- puts "version: #{Zabel::VERSION}"
29
- puts "exec: #{$0}"
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
@@ -1,3 +1,4 @@
1
1
  module Zabel
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.6"
3
+ CACHE_VERSION = "1"
3
4
  end
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]<ERROR> #{target.name} #{file} should exist in dependency file #{dependency_file}"
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 + "/" or
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]<INFO> keep cache " + file_list.size.to_s + " " + Open3.capture3("du -sh #{zabel_get_cache_root}")[0].to_s
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]<INFO> keep oldest " + file_time_hash[file_list.last].to_s + " " + file_list.last
205
- puts "[ZABEL]<INFO> keep newest " + file_time_hash[file_list.first].to_s + " " + file_list.first
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
- target.source_build_phase.files_references.each do | files_reference |
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::VERSION}"
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
- has_found_checksum = false
300
- split_parts = target.name.split("-")
301
- split_parts.each_with_index do | part, index |
302
- spec_name = split_parts[0..index].join("-")
303
- # TODO: to get a explicit spec name from a target.
304
- # Now all potential spec names are push into md5 for safety.
305
- if $zabel_podfile_spec_checksums.has_key? spec_name
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
- has_found_checksum = true
321
+ target_match_spec_names.push spec_name
308
322
  end
309
323
  end
310
- unless has_found_checksum
311
- puts "[ZABEL]<ERROR> #{target.name} SPEC CHECKSUM should be found"
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]<ERROR> #{target.name} #{product_dir}/#{full_product_name} should exist"
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]<ERROR> #{command} should succeed"
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]<ERROR> #{target_cache_dir} should not exist"
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]<ERROR> #{command} should succeed"
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]<ERROR> #{command} should succeed"
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]<ERROR> #{cache_product_path} should exist after mv"
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]<ERROR> -configuration or --configuration should be set"
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] == STATUS_MISS
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]<ERROR> #{target.name} should have dependent files"
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]<ERROR> #{target.name} md5 should not be changed after build"
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]<ERROR> #{target.name} #{target_context[BUILD_KEY_MODULEMAP_FILE]} should be supported"
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]<ERROR> #{target.name} #{target_context[BUILD_KEY_MODULEMAP_FILE]} should be supported"
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]<ERROR> #{target.name} should be hit or miss"
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] == STATUS_MISS
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]<INFO> total add #{add_count}"
620
+ puts "[ZABEL/I] total add #{add_count}"
586
621
 
587
- puts "[ZABEL]<INFO> duration = #{(Time.now - start_time).to_i} s in stage post"
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
- puts "[ZABEL]<WARNING> #{target.name} #{dependency_file} file should exist to be hit"
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
- puts "[ZABEL]<WARNING> #{target.name} #{dependency_file} md5 should match to be hit"
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]<ERROR> #{target.name} #{target_cache_dir} target md5 should match to be verified"
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]<ERROR> #{target.name} #{target_cache_dir} product md5 should match to be verified"
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
- # see https://github.com/CocoaPods/Xcodeproj/blob/master/lib/xcodeproj/project/object/native_target.rb#L239
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
- extract_script = "#{$0} #{STAGE_EXTRACT} \"#{target_cache_dir}\" \"#{target_context[:build_product_dir]}\" \"#{target_context[:build_intermediate_dir]}\""
678
-
679
- if zabel_should_extract_once
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 = "#{$0} #{STAGE_PRINTENV} #{target.name} \"#{project.path}\""
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]<ERROR> -configuration or --configuration should be set"
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
- next unless source_files.size >= zabel_get_min_source_file_count
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
- potential_hit_target_cache_dirs = zabel_get_potential_hit_target_cache_dirs(target, target_md5)
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
- puts "[ZABEL]<INFO> miss #{target.name} #{target_md5} in iteration #{iteration_count}"
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]<INFO> hit #{target.name} #{target_context[:target_md5]} in iteration #{iteration_count} potential #{potential_hit_target_cache_dirs.size}"
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, inject_project, inject_target, inject_scripts, target_context)
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
- puts "[ZABEL]<INFO> miss #{target.name} #{target_context[:target_md5]} in iteration #{iteration_count}"
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]<INFO> total #{hit_count + miss_count} hit #{hit_count} miss #{miss_count} iteration #{iteration_count}"
865
+ puts "[ZABEL/I] total #{hit_count + miss_count} hit #{hit_count} miss #{miss_count} iteration #{iteration_count}"
855
866
 
856
- puts "[ZABEL]<INFO> duration = #{(Time.now - start_time).to_i} s in stage pre"
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.2
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-08-01 00:00:00.000000000 Z
11
+ date: 2021-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xcodeproj