zabel 1.0.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +69 -21
  4. data/bin/zabel +14 -5
  5. data/lib/zabel.rb +130 -136
  6. data/lib/zabel/version.rb +2 -1
  7. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b4bd5a362ce7f4aa9c80a6e1f385f21cdd60b07c7d76bd27aaacb127a5eb037
4
- data.tar.gz: 842369d90e5a1f878d51b9d439c62de4c123f3fbfd7bd63bca2735f24ac302d9
3
+ metadata.gz: 7bbbbd6d01a9148ff002993ceebe5ed44aba4fd905cb1529689ca40406357aff
4
+ data.tar.gz: b0ef1fd3e75802bc1ab90f99f3c2910263e84c0fa4352536a7e7515a7e8515c5
5
5
  SHA512:
6
- metadata.gz: e44882f989a91d79be7467f1c81af6625f74509219ea8e761814eba5bafa9413263b9e0708ea9d2d42f637da03ccea990eaecfdaf337d540ee12576750aece13
7
- data.tar.gz: 6dbf765804557e693cc30e569ea7cf17ceffaf1c6cfb516eb745e1d972248551bb4490fc14a660c2de55296fedd67f7f3afb585427729623995f5ca479fe97e5
6
+ metadata.gz: 842b4eade28085456376de660c8f353108d488caf3f26dcd6308476c2eab2a60cfa67e1c4f5a248cc9a7c4a29d574ecbaa41273d56dd3d323a05a8453698fd11
7
+ data.tar.gz: 28fdc857de4f92a8c6c806305e858bdd94c5fb2888bc86eaa7fb7f9a3b67ea311ef28bf132ffb4690ab5bea9449f62eb62c5a983fb5f0a9bc1988d38f343cf3b
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,6 +1,20 @@
1
- # Zabel
2
-
3
- Zabel, is a build cacher for Xcode, using Xcodeproj and MD5, to detect and cache products for targets. Zabel is not Bazel.
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.
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)
4
18
 
5
19
  ## Feature
6
20
 
@@ -19,12 +33,17 @@ Zabel, is a build cacher for Xcode, using Xcodeproj and MD5, to detect and cache
19
33
  - support dependent files and implicit dependent targets
20
34
  - support xcodebuild build or archive
21
35
  - support fastlane build or archive
36
+ - support legacy or new build system
22
37
 
23
38
  ## Installation
24
39
 
40
+ Please use Ruby 2.x.
41
+
25
42
  Add this line to your application's Gemfile:
26
43
 
27
44
  ```ruby
45
+ source "https://rubygems.org"
46
+
28
47
  gem 'zabel'
29
48
  ```
30
49
 
@@ -32,27 +51,57 @@ And then execute:
32
51
 
33
52
  $ bundle
34
53
 
54
+ Or install in local path:
55
+
56
+ $ bundle install --path vendor/bundle
57
+
35
58
  Or install it yourself as:
36
59
 
37
- $ gem install zabel
60
+ $ [sudo] gem install zabel
38
61
 
39
62
  ## Usage
40
63
 
41
- 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.
42
65
 
43
- ```
44
- zabel xcodebuild/fastlane xxx
45
- ```
66
+ $ [bundle exec] zabel xcodebuild/fastlane ...
46
67
 
47
68
  ## Advanced usage
48
69
 
49
70
  You can controll your cache keys, which can be more or less. Please ensure that your arguments are same in pre and post.
50
71
 
51
- ```
52
- zabel pre -configuration Release abc
53
- xcodebuild/fastlane xxx
54
- zabel post -configuration Release abc
55
- ```
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
97
+
98
+ ## Changelog
99
+
100
+ - 1.0.4 optimize spec checksums; optimize output log; use CACHE_VERSION; should not cache if dependency error
101
+ - 1.0.3 support bundle install
102
+ - 1.0.2 support legacy build system
103
+ - 1.0.1 support xcodebuild archive and fastlane
104
+ - 1.0.0
56
105
 
57
106
  ## Development
58
107
 
@@ -71,14 +120,6 @@ ruby test/one.rb test/case/simple/Podfile
71
120
  ruby test/one.rb test/todo/modulemap_file/Podfile
72
121
  ```
73
122
 
74
- ## TODO
75
-
76
- - support more projects and targets, not only Pods
77
- - support and test more clang arguments
78
- - support intermediate cache such as .o and .gcno
79
- - try to support local development
80
- - try to support remote cache server
81
-
82
123
  ## Contributing
83
124
 
84
125
  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.
@@ -113,4 +154,11 @@ Q: What about dependencies ?
113
154
 
114
155
  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.
115
156
 
157
+ ## TODO
158
+
159
+ - support more projects and targets, not only Pods
160
+ - support and test more clang arguments
161
+ - support intermediate cache such as .o and .gcno
162
+ - try to support local development
163
+ - try to support remote cache server
116
164
 
data/bin/zabel CHANGED
@@ -19,13 +19,22 @@ elsif ARGV.include?("-configuration") or ARGV.include?("--configuration")
19
19
 
20
20
  build_start_time = Time.now
21
21
  exit 1 unless system(*ARGV)
22
- puts "[ZABEL]<INFO> duration = #{(Time.now - build_start_time).to_i} s in stage build"
22
+ puts "[ZABEL/I] duration = #{(Time.now - build_start_time).to_i} s in stage build"
23
23
 
24
24
  Zabel::zabel_post(ARGV)
25
25
 
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}"
26
+ puts "[ZABEL/I] duration = #{(Time.now - total_start_time).to_i} s in stage all"
27
+ elsif ARGV.size == 0 or (ARGV.size == 1 and ARGV[0].include?("v"))
28
+ puts "ver: #{Zabel::VERSION}"
29
+ puts "exe: #{$0}"
30
30
  puts "url: https://github.com/WeijunDeng/Zabel"
31
+ else
32
+ puts "Usage: "
33
+ puts "IMPORTANT: configuration must be set."
34
+ puts "For example:"
35
+ puts "zabel xcodebuild archive -workspace app.xcworkspace -scheme app -configuration Debug ..."
36
+ puts "zabel fastlane gym --workspace app.xcworkspace --scheme app --configuration Debug ..."
37
+ puts ""
38
+ puts "Advanced usage:"
39
+ puts "zabel pre -configuration Debug && xcodebuild/fastlane ... && zabel post -configuration Debug"
31
40
  end
data/lib/zabel.rb CHANGED
@@ -13,6 +13,7 @@ module Zabel
13
13
 
14
14
  BUILD_KEY_SYMROOT = "SYMROOT"
15
15
  BUILD_KEY_CONFIGURATION_BUILD_DIR = "CONFIGURATION_BUILD_DIR"
16
+ BUILD_KEY_TARGET_BUILD_DIR = "TARGET_BUILD_DIR"
16
17
  BUILD_KEY_OBJROOT = "OBJROOT"
17
18
  BUILD_KEY_TARGET_TEMP_DIR = "TARGET_TEMP_DIR"
18
19
  BUILD_KEY_PODS_XCFRAMEWORKS_BUILD_DIR = "PODS_XCFRAMEWORKS_BUILD_DIR"
@@ -73,19 +74,6 @@ module Zabel
73
74
  return 1
74
75
  end
75
76
 
76
- def self.zabel_should_extract_once
77
- # By default, to achieve better compatibility, zabel extracts target cache ondemand,
78
- # which means it depends on original dependencies of targets and it is in parallel.
79
- # However, extracting once in a shell script build phase rather than multiple shell script build phases,
80
- # is a little bit faster in some cases.
81
- # You can enable this by set "export ZABEL_EXTRACT_ONCE=YES"
82
- should_extract_once = ENV["ZABEL_EXTRACT_ONCE"]
83
- if should_extract_once == "YES"
84
- return true
85
- end
86
- return false
87
- end
88
-
89
77
  def self.zabel_get_projects
90
78
  # TODO: to support more project, not only Pods
91
79
  pods_project = Xcodeproj::Project.open("Pods/Pods.xcodeproj")
@@ -111,6 +99,7 @@ module Zabel
111
99
 
112
100
  def self.zabel_can_cache_target(target)
113
101
  if target.name.start_with? "Pods-"
102
+ puts "[ZABEL/I] skip #{target.name}"
114
103
  return false
115
104
  end
116
105
  if target.class == Xcodeproj::Project::Object::PBXNativeTarget
@@ -119,7 +108,11 @@ module Zabel
119
108
  target.product_type == "com.apple.product-type.library.static" or
120
109
  target.product_type == "com.apple.product-type.framework"
121
110
  return true
111
+ else
112
+ puts "[ZABEL/I] skip #{target.name} #{target.class} #{target.product_type}"
122
113
  end
114
+ else
115
+ puts "[ZABEL/I] skip #{target.name} #{target.class}"
123
116
  end
124
117
  return false
125
118
  end
@@ -137,7 +130,7 @@ module Zabel
137
130
  file = file.gsub("\\ ", " ")
138
131
 
139
132
  unless File.exist? file
140
- puts "[ZABEL]<ERROR> #{target.name} #{file} should exist in dependency file #{dependency_file}"
133
+ puts "[ZABEL/E] #{target.name} #{file} should exist in dependency file #{dependency_file}"
141
134
  return []
142
135
  end
143
136
 
@@ -206,11 +199,11 @@ module Zabel
206
199
  file_time_hash[file] = File.mtime(file)
207
200
  end
208
201
  file_list = file_list.sort_by {|file| - file_time_hash[file].to_f}
209
- puts "[ZABEL]<INFO> keep cache " + file_list.size.to_s + " " + Open3.capture3("du -sh #{zabel_get_cache_root}")[0].to_s
202
+ puts "[ZABEL/I] keep cache " + file_list.size.to_s + " " + Open3.capture3("du -sh #{zabel_get_cache_root}")[0].to_s
210
203
 
211
204
  if file_list.size > 1
212
- puts "[ZABEL]<INFO> keep oldest " + file_time_hash[file_list.last].to_s + " " + file_list.last
213
- puts "[ZABEL]<INFO> keep newest " + file_time_hash[file_list.first].to_s + " " + file_list.first
205
+ puts "[ZABEL/I] keep oldest " + file_time_hash[file_list.last].to_s + " " + file_list.last
206
+ puts "[ZABEL/I] keep newest " + file_time_hash[file_list.first].to_s + " " + file_list.first
214
207
  end
215
208
 
216
209
  if file_list.size > zabel_get_cache_count
@@ -254,7 +247,7 @@ module Zabel
254
247
  project_configuration_content = project_configuration.pretty_print.to_yaml
255
248
  project_xcconfig = ""
256
249
  if project_configuration.base_configuration_reference
257
- config_file_path = project_configuration.base_configuration_reference.real_path
250
+ config_file_path = project_configuration.base_configuration_reference.real_path.to_s
258
251
  if File.exist? config_file_path
259
252
  project_xcconfig = File.read(config_file_path).lines.reject{|line|line.include? "_SEARCH_PATHS"}.sort.join("")
260
253
  end
@@ -263,8 +256,10 @@ module Zabel
263
256
  target_configuration = target.build_configurations.detect { | config | config.name == configuration_name}
264
257
  target_configuration_content = target_configuration.pretty_print.to_yaml
265
258
  target_xcconfig = ""
259
+ target_spec_name = ""
266
260
  if target_configuration.base_configuration_reference
267
- config_file_path = target_configuration.base_configuration_reference.real_path
261
+ config_file_path = target_configuration.base_configuration_reference.real_path.to_s
262
+ target_spec_name = File.basename(File.dirname(config_file_path))
268
263
  if File.exist? config_file_path
269
264
  target_xcconfig = File.read(config_file_path).lines.reject{|line|line.include? "_SEARCH_PATHS"}.sort.join("")
270
265
  end
@@ -301,22 +296,15 @@ module Zabel
301
296
 
302
297
  source_md5_list = []
303
298
  # zabel built-in verison, which will be changed for incompatibility in the future
304
- source_md5_list.push "Zabel version : #{Zabel::VERSION}"
299
+ source_md5_list.push "Zabel cache version : #{Zabel::CACHE_VERSION}"
305
300
  source_md5_list.push "ARGV : #{key_argv.to_s}"
306
301
 
307
- has_found_checksum = false
308
- split_parts = target.name.split("-")
309
- split_parts.each_with_index do | part, index |
310
- spec_name = split_parts[0..index].join("-")
311
- # TODO: to get a explicit spec name from a target.
312
- # Now all potential spec names are push into md5 for safety.
313
- if $zabel_podfile_spec_checksums.has_key? spec_name
314
- source_md5_list.push "SPEC CHECKSUM : #{spec_name} #{$zabel_podfile_spec_checksums[spec_name]}"
315
- has_found_checksum = true
316
- end
317
- end
318
- unless has_found_checksum
319
- puts "[ZABEL]<ERROR> #{target.name} SPEC CHECKSUM should be found"
302
+ # TODO: to get a explicit spec name from a target.
303
+ if target_spec_name.size > 0 and $zabel_podfile_spec_checksums.has_key? target_spec_name
304
+ source_md5_list.push "SPEC CHECKSUM : #{target_spec_name} #{$zabel_podfile_spec_checksums[target_spec_name]}"
305
+ has_found_checksum = true
306
+ else
307
+ puts "[ZABEL/E] #{target.name} #{target_spec_name} SPEC CHECKSUM should be found"
320
308
  end
321
309
 
322
310
  source_md5_list.push "Project : #{File.basename(project.path)}"
@@ -350,10 +338,6 @@ module Zabel
350
338
  command = "rm -rf Pods/*.xcodeproj/*.#{FILE_NAME_TARGET_CONTEXT}"
351
339
  puts command
352
340
  raise unless system command
353
-
354
- command = "rm -rf Pods/zabel.xcodeproj"
355
- puts command
356
- raise unless system command
357
341
  end
358
342
 
359
343
  def self.zabel_add_cache(target, target_context, message)
@@ -374,7 +358,7 @@ module Zabel
374
358
  end
375
359
 
376
360
  unless full_product_name and full_product_name.size > 0 and File.exist? "#{product_dir}/#{full_product_name}"
377
- puts "[ZABEL]<ERROR> #{target.name} #{product_dir}/#{full_product_name} should exist"
361
+ puts "[ZABEL/E] #{target.name} #{product_dir}/#{full_product_name} should exist"
378
362
  return false
379
363
  end
380
364
 
@@ -387,12 +371,12 @@ module Zabel
387
371
 
388
372
  puts command
389
373
  unless system command
390
- puts "[ZABEL]<ERROR> #{command} should succeed"
374
+ puts "[ZABEL/E] #{command} should succeed"
391
375
  return false
392
376
  end
393
377
 
394
378
  if File.exist? target_cache_dir
395
- puts "[ZABEL]<ERROR> #{target_cache_dir} should not exist"
379
+ puts "[ZABEL/E] #{target_cache_dir} should not exist"
396
380
  raise unless system "rm -rf \"#{target_cache_dir}\""
397
381
  return false
398
382
  end
@@ -400,7 +384,7 @@ module Zabel
400
384
  command = "mkdir -p \"#{target_cache_dir}\""
401
385
  unless system command
402
386
  puts command
403
- puts "[ZABEL]<ERROR> #{command} should succeed"
387
+ puts "[ZABEL/E] #{command} should succeed"
404
388
  return false
405
389
  end
406
390
 
@@ -410,11 +394,11 @@ module Zabel
410
394
  puts command
411
395
  unless system command
412
396
  puts command
413
- puts "[ZABEL]<ERROR> #{command} should succeed"
397
+ puts "[ZABEL/E] #{command} should succeed"
414
398
  return false
415
399
  end
416
400
  unless File.exist? cache_product_path
417
- puts "[ZABEL]<ERROR> #{cache_product_path} should exist after mv"
401
+ puts "[ZABEL/E] #{cache_product_path} should exist after mv"
418
402
  return false
419
403
  end
420
404
 
@@ -430,6 +414,7 @@ module Zabel
430
414
  target_context.delete(:target_status)
431
415
  target_context.delete(:potential_hit_target_cache_dirs)
432
416
  target_context.delete(:target_md5_content)
417
+ target_context.delete(:miss_dependency_list)
433
418
  [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 |
434
419
  target_context.delete(key)
435
420
  end
@@ -450,7 +435,7 @@ module Zabel
450
435
  configuration_name = argv[argv.index("--configuration") + 1]
451
436
  end
452
437
  unless configuration_name and configuration_name.size > 0
453
- raise "[ZABEL]<ERROR> -configuration or --configuration should be set"
438
+ raise "[ZABEL/E] -configuration or --configuration should be set"
454
439
  end
455
440
 
456
441
  start_time = Time.now
@@ -462,14 +447,17 @@ module Zabel
462
447
  post_targets_context = {}
463
448
 
464
449
  projects.each do | project |
450
+ project_configuration = project.build_configurations.detect { | config | config.name == configuration_name}
451
+ unless project_configuration
452
+ puts "[ZABEL/E] #{project.path} should have config #{configuration_name}"
453
+ next
454
+ end
465
455
  project.native_targets.each do | target |
456
+ target_context_file = "#{project.path}/#{target.name}.#{FILE_NAME_TARGET_CONTEXT}"
457
+ unless File.exist? target_context_file
458
+ next
459
+ end
466
460
  if zabel_can_cache_target(target)
467
-
468
- target_context_file = "#{project.path}/#{target.name}.#{FILE_NAME_TARGET_CONTEXT}"
469
- unless File.exist? target_context_file
470
- next
471
- end
472
-
473
461
  target_context = YAML.load(File.read(target_context_file))
474
462
 
475
463
  if target_context[:target_status] == STATUS_MISS
@@ -481,7 +469,7 @@ module Zabel
481
469
 
482
470
  dependency_files = zabel_get_dependency_files(target, intermediate_dir, product_dir, xcframeworks_build_dir)
483
471
  if source_files.size > 0 and dependency_files.size == 0 and target.product_type != "com.apple.product-type.bundle"
484
- puts "[ZABEL]<ERROR> #{target.name} should have dependent files"
472
+ puts "[ZABEL/E] #{target.name} should have dependent files"
485
473
  next
486
474
  end
487
475
  target_context[:dependency_files] = dependency_files - source_files
@@ -489,7 +477,7 @@ module Zabel
489
477
  target_context[:target_md5_content] = target_md5_content
490
478
  target_md5 = Digest::MD5.hexdigest(target_md5_content)
491
479
  unless target_context[:target_md5] == target_md5
492
- puts "[ZABEL]<ERROR> #{target.name} md5 should not be changed after build"
480
+ puts "[ZABEL/E] #{target.name} md5 should not be changed after build"
493
481
  next
494
482
  end
495
483
  if target_context[BUILD_KEY_SRCROOT] and target_context[BUILD_KEY_SRCROOT].size > 0 and
@@ -497,19 +485,19 @@ module Zabel
497
485
  if File.exist? Dir.pwd + "/" + zabel_get_content_without_pwd("#{target_context[BUILD_KEY_SRCROOT]}/#{target_context[BUILD_KEY_MODULEMAP_FILE]}")
498
486
  target_context[BUILD_KEY_MODULEMAP_FILE] = zabel_get_content_without_pwd("#{target_context[BUILD_KEY_SRCROOT]}/#{target_context[BUILD_KEY_MODULEMAP_FILE]}")
499
487
  else
500
- puts "[ZABEL]<ERROR> #{target.name} #{target_context[BUILD_KEY_MODULEMAP_FILE]} should be supported"
488
+ puts "[ZABEL/E] #{target.name} #{target_context[BUILD_KEY_MODULEMAP_FILE]} should be supported"
501
489
  next
502
490
  end
503
491
  end
504
492
  elsif target_context[:target_status] == STATUS_HIT
505
493
  if target_context[BUILD_KEY_MODULEMAP_FILE] and target_context[BUILD_KEY_MODULEMAP_FILE].size > 0
506
494
  if not File.exist? Dir.pwd + "/" + target_context[BUILD_KEY_MODULEMAP_FILE]
507
- puts "[ZABEL]<ERROR> #{target.name} #{target_context[BUILD_KEY_MODULEMAP_FILE]} should be supported"
495
+ puts "[ZABEL/E] #{target.name} #{target_context[BUILD_KEY_MODULEMAP_FILE]} should be supported"
508
496
  next
509
497
  end
510
498
  end
511
499
  else
512
- puts "[ZABEL]<ERROR> #{target.name} should be hit or miss"
500
+ puts "[ZABEL/E] #{target.name} should be hit or miss"
513
501
  next
514
502
  end
515
503
 
@@ -567,9 +555,17 @@ module Zabel
567
555
 
568
556
  target_context[:dependency_files] = target_context[:dependency_files] - implicit_dependencies
569
557
  dependency_files_md5 = []
558
+ should_not_cache = false
570
559
  target_context[:dependency_files].each do | file |
560
+ if file.start_with? target_context[BUILD_KEY_OBJROOT] + "/" or file.start_with? target_context[BUILD_KEY_SYMROOT] + "/"
561
+ puts "[ZABEL/W] #{target.name} #{file} dependecy should not include build path"
562
+ should_not_cache = true
563
+ break
564
+ end
571
565
  dependency_files_md5.push [zabel_get_content_without_pwd(file), zabel_get_file_md5(file)]
572
566
  end
567
+ next if should_not_cache
568
+
573
569
  target_context[:dependency_files_md5] = dependency_files_md5.sort.uniq
574
570
 
575
571
  dependency_targets_md5 = dependency_targets_set.to_a.map { | target | [target.name, post_targets_context[target][:target_md5]]}
@@ -590,13 +586,13 @@ module Zabel
590
586
 
591
587
  zabel_keep
592
588
 
593
- puts "[ZABEL]<INFO> total add #{add_count}"
589
+ puts "[ZABEL/I] total add #{add_count}"
594
590
 
595
- puts "[ZABEL]<INFO> duration = #{(Time.now - start_time).to_i} s in stage post"
591
+ puts "[ZABEL/I] duration = #{(Time.now - start_time).to_i} s in stage post"
596
592
 
597
593
  end
598
594
 
599
- def self.zabel_get_potential_hit_target_cache_dirs(target, target_md5)
595
+ def self.zabel_get_potential_hit_target_cache_dirs(target, target_md5, miss_dependency_list)
600
596
  dependency_start_time = Time.now
601
597
  target_cache_dirs = Dir.glob(zabel_get_cache_root + "/" + target.name + "-" + target_md5 + "-*")
602
598
  file_time_hash = {}
@@ -615,12 +611,12 @@ module Zabel
615
611
  dependency_md5 = item[1]
616
612
 
617
613
  unless File.exist? dependency_file
618
- puts "[ZABEL]<WARNING> #{target.name} #{dependency_file} file should exist to be hit"
614
+ miss_dependency_list.push "[ZABEL/W] #{target.name} #{dependency_file} file should exist to be hit"
619
615
  dependency_miss = true
620
616
  break
621
617
  end
622
618
  unless zabel_get_file_md5(dependency_file) == dependency_md5
623
- puts "[ZABEL]<WARNING> #{target.name} #{dependency_file} md5 should match to be hit"
619
+ miss_dependency_list.push "[ZABEL/W] #{target.name} #{dependency_file} md5 #{zabel_get_file_md5(dependency_file)} should match #{dependency_md5} to be hit"
624
620
  dependency_miss = true
625
621
  break
626
622
  end
@@ -629,14 +625,14 @@ module Zabel
629
625
  if not target_context[:target_md5] == target_md5
630
626
  command = "rm -rf \"#{target_cache_dir}\""
631
627
  raise unless system command
632
- puts "[ZABEL]<ERROR> #{target.name} #{target_cache_dir} target md5 should match to be verified"
628
+ puts "[ZABEL/E] #{target.name} #{target_cache_dir} target md5 should match to be verified"
633
629
  dependency_miss = false
634
630
  next
635
631
  end
636
632
  if not target_context[:product_md5] == zabel_get_file_md5(target_cache_dir + "/" + FILE_NAME_PRODUCT)
637
633
  command = "rm -rf \"#{target_cache_dir}\""
638
634
  raise unless system command
639
- puts "[ZABEL]<ERROR> #{target.name} #{target_cache_dir} product md5 should match to be verified"
635
+ puts "[ZABEL/E] #{target.name} #{target_cache_dir} product md5 should match to be verified"
640
636
  dependency_miss = false
641
637
  next
642
638
  end
@@ -653,23 +649,7 @@ module Zabel
653
649
  return potential_hit_target_cache_dirs
654
650
  end
655
651
 
656
- # see https://github.com/CocoaPods/Xcodeproj/blob/master/lib/xcodeproj/project/object/native_target.rb#L239
657
- # and this is faster, without searching deeply.
658
- def self.zabel_fast_add_dependency(project, target_target, target, subproject_reference)
659
- container_proxy = project.new(Xcodeproj::Project::PBXContainerItemProxy)
660
- container_proxy.container_portal = subproject_reference.uuid
661
- container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
662
- container_proxy.remote_global_id_string = target.uuid
663
- container_proxy.remote_info = target.name
664
-
665
- dependency = project.new(Xcodeproj::Project::PBXTargetDependency)
666
- dependency.name = target.name
667
- dependency.target_proxy = container_proxy
668
-
669
- target_target.dependencies << dependency
670
- end
671
-
672
- def self.zabel_disable_build_and_inject_extract(project, target, inject_project, inject_target, inject_scripts, target_context)
652
+ def self.zabel_disable_build_and_inject_extract(project, target, target_context)
673
653
  target_cache_dir = target_context[:hit_target_cache_dir]
674
654
 
675
655
  # touch to update mtime
@@ -682,34 +662,24 @@ module Zabel
682
662
  build_phase.class == Xcodeproj::Project::Object::PBXResourcesBuildPhase
683
663
  }
684
664
 
685
- extract_script = "#{$0} #{STAGE_EXTRACT} \"#{target_cache_dir}\" \"#{target_context[:build_product_dir]}\" \"#{target_context[:build_intermediate_dir]}\""
686
-
687
- if zabel_should_extract_once
688
- subproject_reference = nil
689
- project.main_group.files.each do | file |
690
- if file.class == Xcodeproj::Project::Object::PBXFileReference and File.basename(file.path) == File.basename(inject_project.path)
691
- subproject_reference = file
692
- break
693
- end
694
- end
695
-
696
- unless subproject_reference
697
- subproject_reference = project.main_group.new_reference(inject_project.path, :group)
698
- end
699
-
700
- zabel_fast_add_dependency(project, target, inject_target, subproject_reference)
701
-
702
- inject_scripts.push extract_script
703
- else
704
- inject_phase = target.new_shell_script_build_phase("zabel_extract_#{target.name}")
705
- inject_phase.shell_script = extract_script
706
- inject_phase.show_env_vars_in_log = '1'
665
+ zabel_exec = "\"#{$0}\""
666
+ if ENV["BUNDLE_BIN_PATH"] and ENV["BUNDLE_BIN_PATH"].size > 0 and ENV["BUNDLE_GEMFILE"] and ENV["BUNDLE_GEMFILE"].size > 0
667
+ zabel_exec = "cd \"#{File.dirname(ENV["BUNDLE_GEMFILE"])}\" && \"#{ENV["BUNDLE_BIN_PATH"]}\" exe zabel"
707
668
  end
669
+ extract_script = "#{zabel_exec} #{STAGE_EXTRACT} \"#{target_cache_dir}\" \"#{target_context[:build_product_dir]}\" \"#{target_context[:build_intermediate_dir]}\""
670
+
671
+ inject_phase = target.new_shell_script_build_phase("zabel_extract_#{target.name}")
672
+ inject_phase.shell_script = extract_script
673
+ inject_phase.show_env_vars_in_log = '1'
708
674
  end
709
675
 
710
676
  def self.zabel_inject_printenv(project, target)
677
+ zabel_exec = "\"#{$0}\""
678
+ if ENV["BUNDLE_BIN_PATH"] and ENV["BUNDLE_BIN_PATH"].size > 0 and ENV["BUNDLE_GEMFILE"] and ENV["BUNDLE_GEMFILE"].size > 0
679
+ zabel_exec = "cd \"#{File.dirname(ENV["BUNDLE_GEMFILE"])}\" && \"#{ENV["BUNDLE_BIN_PATH"]}\" exe zabel"
680
+ end
711
681
  inject_phase = target.new_shell_script_build_phase("zabel_printenv_#{target.name}")
712
- inject_phase.shell_script = "#{$0} #{STAGE_PRINTENV} #{target.name} \"#{project.path}\""
682
+ inject_phase.shell_script = "#{zabel_exec} #{STAGE_PRINTENV} #{target.name} \"#{project.path}\""
713
683
  inject_phase.show_env_vars_in_log = '1'
714
684
  end
715
685
 
@@ -723,7 +693,7 @@ module Zabel
723
693
  configuration_name = argv[argv.index("--configuration") + 1]
724
694
  end
725
695
  unless configuration_name and configuration_name.size > 0
726
- raise "[ZABEL]<ERROR> -configuration or --configuration should be set"
696
+ raise "[ZABEL/E] -configuration or --configuration should be set"
727
697
  end
728
698
 
729
699
  start_time = Time.now
@@ -736,15 +706,6 @@ module Zabel
736
706
 
737
707
  zabel_clean_temp_files
738
708
 
739
- if zabel_should_extract_once
740
- inject_project = Xcodeproj::Project.new("Pods/zabel.xcodeproj")
741
- inject_target = inject_project.new_aggregate_target("zabel")
742
- inject_phase = inject_target.new_shell_script_build_phase("zabel_extract")
743
- inject_phase.show_env_vars_in_log = '1'
744
- inject_project.save
745
- inject_scripts = []
746
- end
747
-
748
709
  projects = zabel_get_projects
749
710
 
750
711
  pre_targets_context = {}
@@ -755,19 +716,32 @@ module Zabel
755
716
  iteration_count = 0
756
717
 
757
718
  projects.each do | project |
719
+ project_configuration = project.build_configurations.detect { | config | config.name == configuration_name}
720
+ unless project_configuration
721
+ puts "[ZABEL/E] #{project.path} should have config #{configuration_name}"
722
+ next
723
+ end
758
724
  project.native_targets.each do | target |
759
725
  if zabel_can_cache_target(target)
760
726
  source_files = zabel_get_target_source_files(target)
761
- next unless source_files.size >= zabel_get_min_source_file_count
727
+ unless source_files.size >= zabel_get_min_source_file_count
728
+ puts "[ZABEL/I] skip #{target.name} #{source_files.size} >= #{zabel_get_min_source_file_count}"
729
+ next
730
+ end
762
731
  target_md5_content = zabel_get_target_md5_content(project, target, configuration_name, argv, source_files)
763
732
  target_md5 = Digest::MD5.hexdigest(target_md5_content)
764
- potential_hit_target_cache_dirs = zabel_get_potential_hit_target_cache_dirs(target, target_md5)
733
+ miss_dependency_list = []
734
+ potential_hit_target_cache_dirs = zabel_get_potential_hit_target_cache_dirs(target, target_md5, miss_dependency_list)
765
735
 
766
736
  target_context = {}
767
737
  target_context[:target_md5] = target_md5
768
738
  target_context[:potential_hit_target_cache_dirs] = potential_hit_target_cache_dirs
739
+ target_context[:miss_dependency_list] = miss_dependency_list
769
740
  if potential_hit_target_cache_dirs.size == 0
770
- puts "[ZABEL]<INFO> miss #{target.name} #{target_md5} in iteration #{iteration_count}"
741
+ if miss_dependency_list.size > 0
742
+ puts miss_dependency_list.uniq.join("\n")
743
+ end
744
+ puts "[ZABEL/I] miss #{target.name} #{target_md5} in iteration #{iteration_count}"
771
745
  target_context[:target_status] = STATUS_MISS
772
746
  miss_count = miss_count + 1
773
747
  end
@@ -811,7 +785,7 @@ module Zabel
811
785
  end
812
786
  end
813
787
  if hit_target_cache_dir
814
- puts "[ZABEL]<INFO> hit #{target.name} #{target_context[:target_md5]} in iteration #{iteration_count} potential #{potential_hit_target_cache_dirs.size}"
788
+ puts "[ZABEL/I] hit #{target.name} #{target_context[:target_md5]} in iteration #{iteration_count} potential #{potential_hit_target_cache_dirs.size}"
815
789
  target_context[:target_status] = STATUS_HIT
816
790
  target_context[:hit_target_cache_dir] = hit_target_cache_dir
817
791
  hit_count = hit_count + 1
@@ -831,11 +805,15 @@ module Zabel
831
805
  target_context = pre_targets_context[target]
832
806
 
833
807
  if target_context[:target_status] == STATUS_HIT
834
- zabel_disable_build_and_inject_extract(project, target, inject_project, inject_target, inject_scripts, target_context)
808
+ zabel_disable_build_and_inject_extract(project, target, target_context)
835
809
  else
836
810
  unless target_context[:target_status] == STATUS_MISS
837
811
  target_context[:target_status] = STATUS_MISS
838
- puts "[ZABEL]<INFO> miss #{target.name} #{target_context[:target_md5]} in iteration #{iteration_count}"
812
+ miss_dependency_list = target_context[:miss_dependency_list]
813
+ if miss_dependency_list.size > 0
814
+ puts miss_dependency_list.uniq.join("\n")
815
+ end
816
+ puts "[ZABEL/I] miss #{target.name} #{target_context[:target_md5]} in iteration #{iteration_count}"
839
817
  miss_count = miss_count + 1
840
818
  end
841
819
  zabel_inject_printenv(project, target)
@@ -852,29 +830,50 @@ module Zabel
852
830
  zabel_clean_backup_project(project)
853
831
  end
854
832
  end
855
-
856
- if zabel_should_extract_once and inject_scripts.size > 0
857
- inject_scripts = (["startTime_s=`date +%s`"] + inject_scripts + ["echo \"[ZABEL]<INFO> duration = $[ `date +%s` - $startTime_s ] s in stage #{STAGE_EXTRACT}\""]).flatten
858
- inject_phase.shell_script = inject_scripts.join("\n")
859
- inject_project.save
860
- end
861
833
 
862
- puts "[ZABEL]<INFO> total #{hit_count + miss_count} hit #{hit_count} miss #{miss_count} iteration #{iteration_count}"
834
+ puts "[ZABEL/I] total #{hit_count + miss_count} hit #{hit_count} miss #{miss_count} iteration #{iteration_count}"
863
835
 
864
- puts "[ZABEL]<INFO> duration = #{(Time.now - start_time).to_i} s in stage pre"
836
+ puts "[ZABEL/I] duration = #{(Time.now - start_time).to_i} s in stage pre"
865
837
  end
866
838
 
867
839
  def self.zabel_extract
840
+ puts "[ZABEL/D] #{Time.now.to_f.to_s}"
841
+ start_time = Time.now
842
+
868
843
  target_cache_dir = ARGV[1]
869
- product_path = ARGV[2]
870
844
 
871
845
  cache_product_path = target_cache_dir + "/#{FILE_NAME_PRODUCT}"
872
846
 
873
847
  start_time = Time.now
874
- command = "mkdir -p \"#{ENV[BUILD_KEY_SYMROOT]}/#{product_path}\" && cd \"#{ENV[BUILD_KEY_SYMROOT]}/#{product_path}/..\" && tar -xf \"#{cache_product_path}\""
875
- puts command
876
- raise unless system command
877
-
848
+
849
+ if ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR] != ENV[BUILD_KEY_TARGET_BUILD_DIR]
850
+ command = "mkdir -p \"#{ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR]}\" && cd \"#{File.dirname(ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR])}/\" && tar -xf \"#{cache_product_path}\""
851
+ puts command
852
+ raise unless system command
853
+
854
+ command = "rm -rf \"#{ENV[BUILD_KEY_TARGET_BUILD_DIR]+"/"+ENV[BUILD_KEY_FULL_PRODUCT_NAME]}\""
855
+ puts command
856
+ raise unless system command
857
+
858
+ command = "mkdir -p \"#{File.dirname(ENV[BUILD_KEY_TARGET_BUILD_DIR]+"/"+ENV[BUILD_KEY_FULL_PRODUCT_NAME])}\""
859
+ puts command
860
+ raise unless system command
861
+
862
+ command = "mv \"#{ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR]+"/"+ENV[BUILD_KEY_FULL_PRODUCT_NAME]}\" \"#{ENV[BUILD_KEY_TARGET_BUILD_DIR]+"/"+ENV[BUILD_KEY_FULL_PRODUCT_NAME]}\""
863
+ puts command
864
+ raise unless system command
865
+
866
+ command = "/bin/ln -sfh \"#{ENV[BUILD_KEY_TARGET_BUILD_DIR]+"/"+ENV[BUILD_KEY_FULL_PRODUCT_NAME]}\" \"#{ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR]+"/"+ENV[BUILD_KEY_FULL_PRODUCT_NAME]}\""
867
+ puts command
868
+ raise unless system command
869
+ else
870
+ command = "mkdir -p \"#{ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR]}\" && cd \"#{File.dirname(ENV[BUILD_KEY_CONFIGURATION_BUILD_DIR])}/\" && tar -xf \"#{cache_product_path}\""
871
+ puts command
872
+ raise unless system command
873
+ end
874
+
875
+ puts "[ZABEL/I] duration = #{(Time.now - start_time).to_i} s in stage extract"
876
+ puts "[ZABEL/D] #{Time.now.to_f.to_s}"
878
877
  end
879
878
 
880
879
  def self.zabel_printenv
@@ -893,11 +892,6 @@ module Zabel
893
892
  end
894
893
 
895
894
  def self.zabel_clean
896
- if File.exist? "Pods/zabel.xcodeproj"
897
- command = "rm -rf Pods/*.xcodeproj"
898
- puts command
899
- raise unless system command
900
- end
901
895
  zabel_clean_temp_files
902
896
  end
903
897
 
data/lib/zabel/version.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  module Zabel
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.4"
3
+ CACHE_VERSION = "1"
3
4
  end
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.1
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - dengweijun
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-31 00:00:00.000000000 Z
11
+ date: 2021-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xcodeproj