akcache 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4f40c3531c36cdfba8d66f1a6a25fcb516ed15a30efe06583b3d223e46798bca
4
+ data.tar.gz: 42fe053a9c1e6e1eed2780870d19770065cf916435796750a40239f6a7829030
5
+ SHA512:
6
+ metadata.gz: bc2fbd4f27fd460612ccece726184cb9e5e1e71a4e616fbbf229728ab97ed0761f6a93c492ff0e617bf3bddf0bf38bd2793595ac945060c151bc6ffd35df699b
7
+ data.tar.gz: 5a8b8c3bc42ee52c60671106a8845551f04f1eb753a2b558065abccfa5041ffabaf00780029c705c46d278ff041fbda47a2d88e397b2b06c33582331f9bf5790
@@ -0,0 +1,18 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - name: Set up Ruby
11
+ uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: 2.6.3
14
+ - name: Run the default task
15
+ run: |
16
+ gem install bundler -v 2.2.6
17
+ bundle install
18
+ bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
@@ -0,0 +1,12 @@
1
+ {
2
+ "configurations": [
3
+ {
4
+ "type": "ruby-debug",
5
+ "request": "launch",
6
+ "name": "Launch File",
7
+ "program": "${workspaceFolder}/${command:AskForProgramName}",
8
+ "programArgs": [],
9
+ "useBundler": false
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,84 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ * Demonstrating empathy and kindness toward other people
14
+ * Being respectful of differing opinions, viewpoints, and experiences
15
+ * Giving and gracefully accepting constructive feedback
16
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ * Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ * The use of sexualized language or imagery, and sexual attention or
22
+ advances of any kind
23
+ * Trolling, insulting or derogatory comments, and personal or political attacks
24
+ * Public or private harassment
25
+ * Publishing others' private information, such as a physical or email
26
+ address, without their explicit permission
27
+ * Other conduct which could reasonably be considered inappropriate in a
28
+ professional setting
29
+
30
+ ## Enforcement Responsibilities
31
+
32
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
33
+
34
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
35
+
36
+ ## Scope
37
+
38
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
39
+
40
+ ## Enforcement
41
+
42
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at yusheng@akulaku.com. All complaints will be reviewed and investigated promptly and fairly.
43
+
44
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
+
46
+ ## Enforcement Guidelines
47
+
48
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
49
+
50
+ ### 1. Correction
51
+
52
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
53
+
54
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
55
+
56
+ ### 2. Warning
57
+
58
+ **Community Impact**: A violation through a single incident or series of actions.
59
+
60
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
61
+
62
+ ### 3. Temporary Ban
63
+
64
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
65
+
66
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
67
+
68
+ ### 4. Permanent Ban
69
+
70
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
+
72
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
73
+
74
+ ## Attribution
75
+
76
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
77
+ available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
78
+
79
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
80
+
81
+ [homepage]: https://www.contributor-covenant.org
82
+
83
+ For answers to common questions about this code of conduct, see the FAQ at
84
+ https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in kcache.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rubocop", "~> 1.7"
data/Gemfile.lock ADDED
@@ -0,0 +1,55 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ kcache (1.0.0)
5
+ xcodeproj (~> 1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ CFPropertyList (3.0.4)
11
+ rexml
12
+ ast (2.4.2)
13
+ atomos (0.1.3)
14
+ claide (1.0.3)
15
+ colored2 (3.1.2)
16
+ nanaimo (0.3.0)
17
+ parallel (1.20.1)
18
+ parser (3.0.2.0)
19
+ ast (~> 2.4.1)
20
+ rainbow (3.0.0)
21
+ rake (13.0.6)
22
+ regexp_parser (2.1.1)
23
+ rexml (3.2.5)
24
+ rubocop (1.18.4)
25
+ parallel (~> 1.10)
26
+ parser (>= 3.0.0.0)
27
+ rainbow (>= 2.2.2, < 4.0)
28
+ regexp_parser (>= 1.8, < 3.0)
29
+ rexml
30
+ rubocop-ast (>= 1.8.0, < 2.0)
31
+ ruby-progressbar (~> 1.7)
32
+ unicode-display_width (>= 1.4.0, < 3.0)
33
+ rubocop-ast (1.8.0)
34
+ parser (>= 3.0.1.1)
35
+ ruby-progressbar (1.11.0)
36
+ unicode-display_width (2.0.0)
37
+ xcodeproj (1.21.0)
38
+ CFPropertyList (>= 2.3.3, < 4.0)
39
+ atomos (~> 0.1.3)
40
+ claide (>= 1.0.2, < 2.0)
41
+ colored2 (~> 3.1)
42
+ nanaimo (~> 0.3.0)
43
+ rexml (~> 3.2.4)
44
+
45
+ PLATFORMS
46
+ universal-darwin-20
47
+ universal-darwin-21
48
+
49
+ DEPENDENCIES
50
+ kcache!
51
+ rake (~> 13.0)
52
+ rubocop (~> 1.7)
53
+
54
+ BUNDLED WITH
55
+ 2.2.6
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 yusheng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Kcache
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/kcache`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'kcache'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install kcache
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/kcache. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/kcache/blob/master/CODE_OF_CONDUCT.md).
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
40
+
41
+ ## Code of Conduct
42
+
43
+ Everyone interacting in the Kcache project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/kcache/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
5
+
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: :rubocop
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "kcache"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/kcache ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'kcache'
4
+
5
+ manager = CacheManager.new
6
+
7
+ if ARGV[0] == "xcodebuild" or ARGV[0] == "fastlane"
8
+ manager.project_task_begin
9
+ raise unless system(*ARGV)
10
+ manager.project_task_end
11
+
12
+ elsif ARGV[0] == "inject"
13
+
14
+ manager.set_prama_to_yaml
15
+
16
+ elsif ARGV[0] == "copy"
17
+
18
+ manager.copy_cache
19
+
20
+ elsif ARGV[0] == "begin"
21
+ manager.project_task_begin
22
+
23
+ elsif ARGV[0] == "end"
24
+ manager.project_task_end
25
+
26
+ elsif ARGV[0] == "pod"
27
+ start_time = Time.now
28
+ raise unless system(*ARGV)
29
+ puts "<INFO> duration = #{((Time.now - start_time)*1000).to_i} ms in pod action"
30
+
31
+ else
32
+ puts "<ERROR> please input prama (build) befor your command"
33
+ end
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/kcache.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require_relative "lib/kcache/version"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "akcache"
10
+ spec.version = Kcache::VERSION
11
+ spec.authors = ["yusheng"]
12
+ spec.email = ["1433233832@qq.com"]
13
+
14
+ spec.summary = "a cache tool"
15
+ spec.description = "a cache tool that can promote xcode build time"
16
+ spec.homepage = "https://github.com/yusheng00"
17
+ spec.license = "MIT"
18
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
19
+
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = spec.homepage
22
+ spec.metadata["changelog_uri"] = spec.homepage
23
+
24
+ # Specify which files should be added to the gem when it is released.
25
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
26
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
27
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
28
+ end
29
+ spec.bindir = "bin"
30
+ spec.executables = "kcache"
31
+ spec.require_paths = ["lib"]
32
+
33
+ # Uncomment to register a new dependency of your gem
34
+ spec.add_dependency "xcodeproj", "~> 1.0"
35
+
36
+ # For more information and examples about making a new gem, checkout our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kcache
4
+ VERSION = "1.0.0"
5
+ end
data/lib/kcache.rb ADDED
@@ -0,0 +1,743 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "kcache/version"
4
+ require 'yaml'
5
+ require 'json/ext'
6
+ require 'xcodeproj'
7
+ require 'pathname'
8
+ require "find"
9
+ require 'set'
10
+
11
+ #配置
12
+ Target_Build_Configuration = "Release"
13
+
14
+ TARGET_CACHE_CONFIG = "target_cache_config.yml"
15
+
16
+ CACHE_STATUS_MISS = "miss"
17
+ CACHE_STATUS_READY = "ready"
18
+ CACHE_STATUS_HIT = "hit"
19
+
20
+ FILE_NAME_PRODUCT = "product.tar"
21
+ FILE_NAME_CONTEXT = "context.yml"
22
+ FILE_NAME_TARGET_CONTEXT = "target_context.yml"
23
+
24
+ #Xcode编译相关常量
25
+ MODULEMAP_FILE = "MODULEMAP_FILE"
26
+ FULL_PRODUCT_NAME = "FULL_PRODUCT_NAME"
27
+ CONFIGURATION_BUILD_DIR = "CONFIGURATION_BUILD_DIR"
28
+ CONFIGURATION_TEMP_DIR = "CONFIGURATION_TEMP_DIR"
29
+ TARGET_TEMP_DIR = "TARGET_TEMP_DIR"
30
+ TARGET_BUILD_DIR = "TARGET_BUILD_DIR"
31
+
32
+ PODS_XCFRAMEWORKS_BUILD_DIR = "PODS_XCFRAMEWORKS_BUILD_DIR"
33
+ SYMROOT = "SYMROOT"
34
+ SRCROOT = "SRCROOT"
35
+ OBJROOT = "OBJROOT"
36
+
37
+
38
+ #变量
39
+ $podfile_spec_checksums = nil
40
+ $file_md5_hash = {}
41
+
42
+
43
+ class CacheManager
44
+
45
+ def get_cache_root
46
+ return Dir.home + "/ysCache"
47
+ end
48
+
49
+ def get_content_without_pwd(content)
50
+ content = content.gsub("#{Dir.pwd}/", "").gsub(/#{Dir.pwd}(\W|$)/, '\1')
51
+ return content
52
+ end
53
+
54
+ def get_file_md5(file)
55
+ if $file_md5_hash.has_key? file
56
+ return $file_md5_hash[file]
57
+ end
58
+ md5 = Digest::MD5.hexdigest(File.read(file))
59
+ $file_md5_hash[file] = md5
60
+ return md5
61
+ end
62
+
63
+
64
+ def get_projects
65
+ pods_project = Xcodeproj::Project.open("Pods/Pods.xcodeproj")
66
+ super_project_paths = get_super_project(pods_project)
67
+ super_projects = []
68
+ super_project_paths.each do | path |
69
+ next if path.end_with? "Pods/Pods.xcodeproj"
70
+ project = Xcodeproj::Project.open(path)
71
+ super_projects.push project
72
+ end
73
+ return (super_projects + [pods_project])
74
+ end
75
+
76
+ def get_super_project(project)
77
+ wrapper_projects = project.files.select{|file|file.last_known_file_type=="wrapper.pb-project"}
78
+ wrapper_project_paths = []
79
+ wrapper_projects.each do | wrapper_project_file |
80
+ wrapper_project_file_path = wrapper_project_file.real_path.to_s
81
+ wrapper_project_paths.push wrapper_project_file_path
82
+ end
83
+ return wrapper_project_paths.uniq
84
+ end
85
+
86
+ def backup_project(project)
87
+ command = "cp \"#{project.path}/project.pbxproj\" \"#{project.path}/project.ysTest_backup_pbxproj\""
88
+ raise unless system command
89
+ end
90
+
91
+ def clean_temp_files
92
+ command = "rm -rf Pods/*.xcodeproj/project.ysTest_backup_pbxproj"
93
+ raise unless system command
94
+
95
+ command = "rm -rf Pods/*.xcodeproj/*.#{FILE_NAME_TARGET_CONTEXT}"
96
+ raise unless system command
97
+ end
98
+
99
+ def restore_project(project)
100
+ if File.exist? "#{project.path}/project.ysTest_backup_pbxproj"
101
+ command = "mv \"#{project.path}/project.ysTest_backup_pbxproj\" \"#{project.path}/project.pbxproj\""
102
+ raise unless system command
103
+ end
104
+ end
105
+
106
+
107
+ def can_cache_target(target)
108
+ if target.product_type == "com.apple.product-type.bundle" or
109
+ target.product_type == "com.apple.product-type.library.static" or
110
+ target.product_type == "com.apple.product-type.framework"
111
+ return true
112
+ end
113
+ return false
114
+ end
115
+
116
+ def get_target_dependency_files(target, intermediate_dir, product_dir, xcframeworks_build_dir, src_path)
117
+ dependency_files = []
118
+ Dir.glob("#{intermediate_dir}/**/*.d").each do | dependency_file |
119
+ content = File.read(dependency_file)
120
+ files = content.scan(/(?:\S(?:\\ )*)+/).flatten.uniq
121
+ files = files - ["dependencies:", "\\", ":"]
122
+ files.each do | file |
123
+ file = file.gsub("\\ ", " ")
124
+ if file.start_with? target.name
125
+ file = src_path + "/" + file
126
+ end
127
+ unless File.exist? file
128
+ puts "<ERROR> #{target.name} #{file} should exist in dependency file #{dependency_file}"
129
+ return []
130
+ end
131
+
132
+ if file.start_with? intermediate_dir + "/" or
133
+ file.start_with? product_dir + "/"
134
+ next
135
+ end
136
+
137
+ if xcframeworks_build_dir and xcframeworks_build_dir.size > 0 and file.start_with? xcframeworks_build_dir + "/"
138
+ next
139
+ end
140
+ dependency_files.push file
141
+ end
142
+ end
143
+
144
+ return dependency_files.uniq
145
+ end
146
+
147
+
148
+ def get_target_source_files(target)
149
+ files = []
150
+ #获取所有可执行文件(.m .swift .cpp .mm)
151
+ target.source_build_phase.files.each do | file |
152
+ file_path = file.file_ref.real_path.to_s
153
+ files.push file_path
154
+ end
155
+ #获取所有头文件(.h)
156
+ target.headers_build_phase.files.each do | file |
157
+ file_path = file.file_ref.real_path.to_s
158
+ files.push file_path
159
+ end
160
+ #获取所有资源文件(.png,.strings .json .html)
161
+ target.resources_build_phase.files.each do | file |
162
+ file_path = file.file_ref.real_path.to_s
163
+ files.push file_path
164
+ end
165
+ expand_files = []
166
+ files.uniq.each do | file |
167
+ next unless File.exist? file
168
+ if File.file? file
169
+ expand_files.push file
170
+ else
171
+ Find.find(file).each do | file_in_dir |
172
+ if File.file? file_in_dir
173
+ expand_files.push file_in_dir
174
+ end
175
+ end
176
+ end
177
+ end
178
+ return expand_files.uniq
179
+ end
180
+
181
+
182
+ def generate_target_all_infomation(project, target, source_files)
183
+
184
+ if $podfile_spec_checksums == nil and File.exist? "Podfile.lock"
185
+ podfile_lock = YAML.load(File.read("Podfile.lock"))
186
+ $podfile_spec_checksums = podfile_lock["SPEC CHECKSUMS"]
187
+ end
188
+
189
+ project_configuration = project.build_configurations.detect { | config | config.name == Target_Build_Configuration}
190
+ project_configuration_content = project_configuration.pretty_print.to_yaml
191
+
192
+ project_xcconfig = ""
193
+ if project_configuration.base_configuration_reference
194
+ config_file_path = project_configuration.base_configuration_reference.real_path
195
+ if File.exist? config_file_path
196
+ project_xcconfig = File.read(config_file_path).lines.reject{|line|line.include? "_SEARCH_PATHS"}.sort.join("")
197
+ end
198
+ end
199
+
200
+ target_configuration = target.build_configurations.detect { | config | config.name == Target_Build_Configuration}
201
+ target_configuration_content = target_configuration.pretty_print.to_yaml
202
+
203
+ target_xcconfig = ""
204
+ if target_configuration.base_configuration_reference
205
+ config_file_path = target_configuration.base_configuration_reference.real_path
206
+ if File.exist? config_file_path
207
+ target_xcconfig = File.read(config_file_path).lines.reject{|line|line.include? "_SEARCH_PATHS"}.sort.join("")
208
+ end
209
+ end
210
+
211
+
212
+ files_configuration = []
213
+ build_phases = []
214
+ build_phases.push target.source_build_phase if target.methods.include? :source_build_phase
215
+ build_phases.push target.resources_build_phase if target.methods.include? :resources_build_phase
216
+ build_phases.each do | build_phase |
217
+ target.source_build_phase.files_references.each do | files_reference |
218
+ files_reference.build_files.each do |build_file|
219
+ if build_file.settings and build_file.settings.class == Hash
220
+ files_configuration.push File.basename(build_file.file_ref.real_path.to_s) + "\n" + build_file.settings.to_yaml
221
+ end
222
+ end
223
+ end
224
+ end
225
+ files_configuration = files_configuration.sort.uniq.join("\n")
226
+
227
+
228
+ source_md5_list = []
229
+ has_found_checksum = false
230
+ split_parts = target.name.split("-")
231
+ split_parts.each_with_index do | part, index |
232
+ spec_name = split_parts[0..index].join("-")
233
+ if $podfile_spec_checksums.has_key? spec_name
234
+ source_md5_list.push "SPEC CHECKSUM : #{spec_name} #{$podfile_spec_checksums[spec_name]}"
235
+ has_found_checksum = true
236
+ end
237
+ end
238
+
239
+ if has_found_checksum
240
+ if target.name.start_with? "AK" or target.name.start_with? "EUR"
241
+
242
+ source_md5_list.push "Project : #{File.basename(project.path)}"
243
+ source_md5_list.push "Project configuration : "
244
+ source_md5_list.push project_configuration_content.strip
245
+ source_md5_list.push "Project xcconfig : "
246
+ source_md5_list.push project_xcconfig.strip
247
+
248
+ source_md5_list.push "Target : #{target.name}, #{target.product_type}"
249
+ source_md5_list.push "Target configuration : "
250
+ source_md5_list.push target_configuration_content.strip
251
+ source_md5_list.push "Target xcconfig : "
252
+ source_md5_list.push target_xcconfig.strip
253
+ source_md5_list.push "Files settings : "
254
+ source_md5_list.push files_configuration.strip
255
+
256
+ source_md5_list.push "Files MD5 : "
257
+ source_files.uniq.sort.each do | file |
258
+ path = get_content_without_pwd(file)
259
+ if target.name == "AKULocalizedStrings" or target.name == "EURLocalizedStrings"
260
+ if file.include? ".swift"
261
+ source_md5_list.push path + " : " + get_file_md5(path)
262
+ end
263
+ else
264
+ source_md5_list.push path + " : " + get_file_md5(path)
265
+ end
266
+ end
267
+ end
268
+ source_md5_content = source_md5_list.join("\n")
269
+ return source_md5_content
270
+
271
+ end
272
+ end
273
+
274
+
275
+
276
+ def get_target_cache(target, target_md5)
277
+
278
+ dependency_start_time = Time.now
279
+
280
+ target_cache_dirs = Dir.glob(get_cache_root + "/" + target.name + "-" + target_md5 + "-*")
281
+
282
+ hit_results = []
283
+
284
+ target_cache_dirs.each do |target_cache_dir|
285
+ unless File.exist? target_cache_dir + "/" + FILE_NAME_PRODUCT
286
+ puts "<ERROR> #{target.name} target cache dir missed files: #{target_cache_dir}"
287
+ next
288
+ end
289
+ unless File.exist? target_cache_dir + "/" + FILE_NAME_CONTEXT
290
+ puts "<ERROR> #{target.name} target cache dir missed files: #{target_cache_dir}"
291
+ next
292
+ end
293
+
294
+ target_context = YAML.load(File.read(target_cache_dir + "/" + FILE_NAME_CONTEXT))
295
+
296
+ if target_context[:target_md5] != target_md5 or target_context[:product_md5] != get_file_md5(target_cache_dir + "/" + FILE_NAME_PRODUCT)
297
+ command = "rm -rf \"#{target_cache_dir}\""
298
+ raise unless system command
299
+ puts "<ERROR> #{target.name} target md5 dose not match: #{target_cache_dir}"
300
+ end
301
+
302
+ dependency_exit = true
303
+
304
+ if target_context[:dependency_files_md5]
305
+ target_context[:dependency_files_md5].each do | item |
306
+ dependency_file = item[0]
307
+ dependency_md5 = item[1]
308
+ unless File.exist? dependency_file
309
+ # puts "<WARNING> #{target.name} dependency file miss: #{dependency_file}"
310
+ dependency_exit = false
311
+ break
312
+ end
313
+ unless get_file_md5(dependency_file) == dependency_md5
314
+ # puts "<WARNING> #{target.name} dependency file md5 dose not match: #{dependency_file}"
315
+ dependency_exit = false
316
+ break
317
+ end
318
+ end
319
+ end
320
+
321
+ if dependency_exit
322
+ hit_results.push target_cache_dir
323
+ end
324
+ end
325
+
326
+ return hit_results
327
+
328
+ end
329
+
330
+ def set_prama_to_yaml
331
+ target_name = ARGV[1]
332
+ project_path = ARGV[2]
333
+ if File.exist? "#{project_path}/#{target_name}.#{FILE_NAME_TARGET_CONTEXT}"
334
+ target_context = YAML.load(File.read("#{project_path}/#{target_name}.#{FILE_NAME_TARGET_CONTEXT}"))
335
+
336
+ [SYMROOT, OBJROOT, SRCROOT, CONFIGURATION_BUILD_DIR, CONFIGURATION_TEMP_DIR, TARGET_BUILD_DIR, TARGET_TEMP_DIR, PODS_XCFRAMEWORKS_BUILD_DIR, MODULEMAP_FILE, FULL_PRODUCT_NAME].sort.each do | key |
337
+ if ENV[key]
338
+ target_context[key] = ENV[key]
339
+ end
340
+ end
341
+ target_context[:target_status] = CACHE_STATUS_READY
342
+ File.write("#{project_path}/#{target_name}.#{FILE_NAME_TARGET_CONTEXT}", target_context.to_yaml)
343
+ end
344
+ end
345
+
346
+ def inject_flag_action(project, target)
347
+ command_exec = "kcache"
348
+ inject_phase = target.new_shell_script_build_phase("ys_inject_#{target.name}")
349
+ inject_phase.shell_script = "#{command_exec} #{"inject"} #{target.name} \"#{project.path}\""
350
+ inject_phase.show_env_vars_in_log = '1'
351
+ end
352
+
353
+ def inject_copy_action(project, target, target_context)
354
+ target_cache_dir = target_context[:hit_target_cache_dir]
355
+ target_product_dir = target_context[:build_product_dir]
356
+ build_intermediate_dir = target_context[:build_intermediate_dir]
357
+
358
+ target.build_phases.delete_if { | build_phase |
359
+ build_phase.class == Xcodeproj::Project::Object::PBXHeadersBuildPhase or
360
+ build_phase.class == Xcodeproj::Project::Object::PBXSourcesBuildPhase or
361
+ build_phase.class == Xcodeproj::Project::Object::PBXResourcesBuildPhase
362
+ }
363
+
364
+ # if target.name == "EURLocalizedStrings"
365
+ # target.build_phases.delete_if { |phase|
366
+ # phase.class == Xcodeproj::Project::Object::PBXShellScriptBuildPhase
367
+ # }
368
+ # end
369
+
370
+ command_exec = "kcache"
371
+ inject_phase = target.new_shell_script_build_phase("ys_copy_#{target.name}")
372
+ inject_phase.shell_script = "#{command_exec} #{"copy"} \"#{target_cache_dir}\" \"#{target_product_dir}\" \"#{build_intermediate_dir}\""
373
+ inject_phase.show_env_vars_in_log = '1'
374
+ end
375
+
376
+ def copy_cache
377
+
378
+ puts "<INFO> #{Time.now.to_f.to_s}"
379
+ start_time = Time.now
380
+ target_cache_dir = ARGV[1]
381
+ cache_product_path = target_cache_dir + "/#{FILE_NAME_PRODUCT}"
382
+
383
+ [SYMROOT, CONFIGURATION_BUILD_DIR, CONFIGURATION_TEMP_DIR, OBJROOT, TARGET_BUILD_DIR, TARGET_TEMP_DIR, SRCROOT, FULL_PRODUCT_NAME].sort.each do | key |
384
+ unless ENV.has_key? key and ENV[key] and ENV[key].size > 0
385
+ raise "<INFO> #{target.name} should have #{key}"
386
+ break
387
+ end
388
+ end
389
+
390
+ command = "mkdir -p \"#{ENV[CONFIGURATION_BUILD_DIR]}\" && cd \"#{File.dirname(ENV[CONFIGURATION_BUILD_DIR])}/\" && tar -xf \"#{cache_product_path}\""
391
+ raise unless system command
392
+
393
+ if ENV[CONFIGURATION_BUILD_DIR] != ENV[TARGET_BUILD_DIR]
394
+
395
+ command = "rm -rf \"#{ENV[TARGET_BUILD_DIR]+"/"+ENV[FULL_PRODUCT_NAME]}\""
396
+ raise unless system command
397
+
398
+ command = "mkdir -p \"#{File.dirname(ENV[TARGET_BUILD_DIR]+"/"+ENV[FULL_PRODUCT_NAME])}\""
399
+ raise unless system command
400
+
401
+ command = "mv \"#{ENV[CONFIGURATION_BUILD_DIR]+"/"+ENV[FULL_PRODUCT_NAME]}\" \"#{ENV[TARGET_BUILD_DIR]+"/"+ENV[FULL_PRODUCT_NAME]}\""
402
+ raise unless system command
403
+
404
+ command = "/bin/ln -sfh \"#{ENV[TARGET_BUILD_DIR]+"/"+ENV[FULL_PRODUCT_NAME]}\" \"#{ENV[CONFIGURATION_BUILD_DIR]+"/"+ENV[FULL_PRODUCT_NAME]}\""
405
+ raise unless system command
406
+ end
407
+
408
+ puts "<INFO> duration = #{((Time.now - start_time)*1000).to_i} ms in copy cache action"
409
+ puts "<INFO> #{Time.now.to_f.to_s}"
410
+ end
411
+
412
+
413
+ def add_cache(target, target_info)
414
+ target_md5 = target_info[:target_md5]
415
+ product_dir = target_info[CONFIGURATION_BUILD_DIR]
416
+ # intermediate_dir = target_info[TARGET_TEMP_DIR]
417
+ full_product_name = target_info[FULL_PRODUCT_NAME]
418
+
419
+ Dir.glob("#{product_dir}/**/*.modulemap").each do | modulemap |
420
+ modulemap_content = File.read(modulemap)
421
+ if modulemap_content.include? File.dirname(modulemap) + "/"
422
+ modulemap_content = modulemap_content.gsub(File.dirname(modulemap) + "/", "")
423
+ File.write(modulemap, modulemap_content)
424
+ end
425
+ end
426
+
427
+ unless full_product_name and full_product_name.size > 0 and File.exist? "#{product_dir}/#{full_product_name}"
428
+ puts "<ERROR> #{target.name} #{product_dir}/#{full_product_name} should exist"
429
+ return false
430
+ end
431
+
432
+ zip_start_time = Time.now
433
+
434
+ command = "cd \"#{File.dirname(product_dir)}\" && tar -L -c -f #{target.name}.#{FILE_NAME_PRODUCT} #{File.basename(product_dir)}/#{full_product_name}"
435
+ if target.product_type == "com.apple.product-type.library.static"
436
+ command = "cd \"#{File.dirname(product_dir)}\" && tar --exclude=*.bundle --exclude=*.framework -L -c -f #{target.name}.#{FILE_NAME_PRODUCT} #{File.basename(product_dir)}"
437
+ end
438
+
439
+ unless system command
440
+ puts "<INFO> #{command} should succeed"
441
+ return false
442
+ end
443
+
444
+ target_cache_dir = get_cache_root + "/" + target.name + "-" + target_md5 + "-" + (Time.now.to_f * 1000).to_i.to_s
445
+ if File.exist? target_cache_dir
446
+ puts "<INFO> #{target_cache_dir} should not exist"
447
+ raise unless system "rm -rf \"#{target_cache_dir}\""
448
+ return false
449
+ end
450
+
451
+ command = "mkdir -p \"#{target_cache_dir}\""
452
+ unless system command
453
+ puts "<INFO> #{command} should succeed"
454
+ return false
455
+ end
456
+
457
+ cache_product_path = target_cache_dir + "/#{FILE_NAME_PRODUCT}"
458
+ command = "mv \"#{File.dirname(product_dir)}/#{target.name}.#{FILE_NAME_PRODUCT}\" \"#{cache_product_path}\""
459
+ unless system command
460
+ puts "<INFO> #{command} should succeed"
461
+ return false
462
+ end
463
+ unless File.exist? cache_product_path
464
+ puts "<INFO> #{cache_product_path} should exist after mv"
465
+ return false
466
+ end
467
+
468
+ target_info[:product_md5] = get_file_md5(cache_product_path)
469
+ target_info[:build_product_dir] = target_info[CONFIGURATION_BUILD_DIR].gsub(target_info[SYMROOT] + "/", "")
470
+ target_info[:build_intermediate_dir] = target_info[TARGET_TEMP_DIR].gsub(target_info[OBJROOT] + "/", "")
471
+ if target_info[MODULEMAP_FILE]
472
+ target_info[MODULEMAP_FILE] = get_content_without_pwd(target_info[MODULEMAP_FILE])
473
+ end
474
+
475
+ target_info = target_info.clone
476
+ target_info.delete(:dependency_files)
477
+ target_info.delete(:target_status)
478
+ target_info.delete(:hit_target_cache_dir)
479
+ target_info.delete(:target_md5_content)
480
+ [SYMROOT, CONFIGURATION_BUILD_DIR, CONFIGURATION_TEMP_DIR, OBJROOT, TARGET_TEMP_DIR, TARGET_BUILD_DIR, PODS_XCFRAMEWORKS_BUILD_DIR, SRCROOT].each do | key |
481
+ target_info.delete(key)
482
+ end
483
+
484
+ File.write(target_cache_dir + "/" + FILE_NAME_CONTEXT, target_info.to_yaml)
485
+
486
+ return true
487
+
488
+ end
489
+
490
+ def project_task_begin
491
+
492
+ clean_temp_files
493
+ projects = get_projects
494
+ total_count = 0
495
+ hit_count = 0
496
+ miss_count = 0
497
+ error_count = 0
498
+ hit_target_md5_cache_set = Set.new
499
+
500
+ pre_targets_info = {}
501
+ projects.each do |project|
502
+ project.native_targets.each do |target|
503
+ target.build_phases.delete_if { |phase|
504
+ phase.class == Xcodeproj::Project::Object::PBXShellScriptBuildPhase and phase.name.include? "ys_"
505
+ }
506
+ if can_cache_target(target)
507
+ total_count = total_count + 1
508
+ source_files = get_target_source_files(target)
509
+ target_md5_content = generate_target_all_infomation(project, target, source_files)
510
+ unless target_md5_content
511
+ puts "<ERROR> target md5 content can not generate: #{target.name}"
512
+ error_count = error_count + 1
513
+ next
514
+ end
515
+
516
+ target_md5 = Digest::MD5.hexdigest(target_md5_content)
517
+ hit_target_cache_dirs = get_target_cache(target, target_md5)
518
+ target_info = {}
519
+ target_info[:target_md5] = target_md5
520
+
521
+ if hit_target_cache_dirs.count == 0
522
+ puts "<INFO> #{target.name} #{target_md5} does not hit any cache"
523
+ target_info[:target_status] = CACHE_STATUS_MISS
524
+ inject_flag_action(project, target)
525
+ miss_count = miss_count + 1
526
+ File.write("#{project.path}/#{target.name}.#{FILE_NAME_TARGET_CONTEXT}", target_info.to_yaml)
527
+ else
528
+ target_info[:hit_target_cache_dir] = hit_target_cache_dirs
529
+ hit_target_md5_cache_set.add "#{target.name}-#{target_info[:target_md5]}"
530
+ end
531
+ pre_targets_info[target] = target_info
532
+ end
533
+ end
534
+ end
535
+
536
+ projects.each do |project|
537
+ project.native_targets.each do |target|
538
+ target_info = pre_targets_info[target]
539
+ next unless target_info and target_info[:target_status] != CACHE_STATUS_MISS
540
+ hit_target_cache_dirs = target_info[:hit_target_cache_dir]
541
+ next unless hit_target_cache_dirs and hit_target_cache_dirs.count > 0
542
+ target_md5 = target_info[:target_md5]
543
+
544
+ really_hit_dir = ""
545
+ hit_target_cache_dirs.each do |hit_target_cache_dir|
546
+ all_dependency_target_exist = true
547
+ hit_targets_info = YAML.load(File.read(hit_target_cache_dir + "/" + FILE_NAME_CONTEXT))
548
+ if hit_targets_info[:dependency_targets_md5]
549
+ hit_targets_info[:dependency_targets_md5].each do | item |
550
+ dependency_target = item[0]
551
+ dependency_target_md5 = item[1]
552
+ unless hit_target_md5_cache_set.include? "#{dependency_target}-#{dependency_target_md5}"
553
+ puts "<INFO> #{target.name} #{target_md5} hit cache, but dependency target #{dependency_target}-#{dependency_target_md5} dose not hit"
554
+ all_dependency_target_exist = false
555
+ break
556
+ end
557
+ end
558
+
559
+ if all_dependency_target_exist
560
+ really_hit_dir = hit_target_cache_dir
561
+ break
562
+ end
563
+ end
564
+ end
565
+
566
+ if really_hit_dir.length > 0
567
+ puts "<INFO> #{target.name} #{target_md5} hit cache"
568
+ hit_count = hit_count + 1
569
+ hit_target_info = YAML.load(File.read(really_hit_dir + "/" + FILE_NAME_CONTEXT))
570
+ target_info = target_info.merge!(hit_target_info)
571
+ target_info[:target_status] = CACHE_STATUS_HIT
572
+ target_info[:hit_target_cache_dir] = really_hit_dir
573
+ inject_copy_action(project, target, target_info)
574
+ else
575
+ puts "<INFO> #{target.name} #{target_md5} miss cache for reason dependency miss"
576
+ target_info[:target_status] = CACHE_STATUS_MISS
577
+ target_info.delete(:hit_target_cache_dir)
578
+ inject_flag_action(project, target)
579
+ miss_count = miss_count + 1
580
+ end
581
+ File.write("#{project.path}/#{target.name}.#{FILE_NAME_TARGET_CONTEXT}", target_info.to_yaml)
582
+
583
+ end
584
+
585
+ backup_project(project)
586
+ project.save
587
+ end
588
+ puts "<INFO> total count: #{total_count}, hit count: #{hit_count}, miss_count: #{miss_count}, error_count: #{error_count}"
589
+ end
590
+
591
+
592
+ def project_task_end
593
+
594
+ projects = get_projects
595
+ post_targets_context = {}
596
+ total_add_count = 0
597
+
598
+ projects.each do |project|
599
+ project.native_targets.each do | target |
600
+ target_context_file = "#{project.path}/#{target.name}.#{FILE_NAME_TARGET_CONTEXT}"
601
+ next unless File.exist? target_context_file
602
+ if can_cache_target(target)
603
+ target_info = YAML.load(File.read(target_context_file))
604
+ if target_info[:target_status] == CACHE_STATUS_READY
605
+ # 保证编译前后MD5不变
606
+ source_files = get_target_source_files(target)
607
+ target_md5_content = generate_target_all_infomation(project, target, source_files)
608
+ target_md5 = Digest::MD5.hexdigest(target_md5_content)
609
+ unless target_info[:target_md5] == target_md5
610
+ puts "<ERROR> #{target.name} md5 should not be changed after build"
611
+ next
612
+ end
613
+
614
+ target_info[:target_md5_content] = target_md5_content
615
+
616
+ product_dir = target_info[CONFIGURATION_BUILD_DIR]
617
+ intermediate_dir = target_info[TARGET_TEMP_DIR].to_s
618
+ xcframeworks_build_dir = target_info[PODS_XCFRAMEWORKS_BUILD_DIR]
619
+ src_path = target_info[SRCROOT]
620
+
621
+ unless intermediate_dir.length > 0
622
+ puts "<ERROR> #{target.name} should have intermediate_dir"
623
+ next
624
+ end
625
+ dependency_files = get_target_dependency_files(target, intermediate_dir, product_dir, xcframeworks_build_dir, src_path)
626
+ if source_files.size > 0 and dependency_files.size == 0 and target.product_type != "com.apple.product-type.bundle"
627
+ puts "<ERROR> #{target.name} should have dependency files"
628
+ next
629
+ end
630
+ target_info[:dependency_files] = dependency_files - source_files
631
+
632
+ module_file_path = target_info[MODULEMAP_FILE]
633
+
634
+ if src_path and src_path.size > 0 and module_file_path and module_file_path.size > 0
635
+ if File.exist? Dir.pwd + "/" + get_content_without_pwd("#{src_path}/#{module_file_path}")
636
+ target_info[MODULEMAP_FILE] = get_content_without_pwd("#{src_path}/#{module_file_path}")
637
+ else
638
+ puts "<ERROR> #{target.name} #{module_file_path} should be supported"
639
+ next
640
+ end
641
+ end
642
+ elsif target_info[:target_status] == CACHE_STATUS_HIT
643
+ module_file_path = target_info[MODULEMAP_FILE]
644
+ if module_file_path and module_file_path.size > 0
645
+ if not File.exist? Dir.pwd + "/" + target_info[MODULEMAP_FILE]
646
+ puts "<ERROR> #{target.name} #{module_file_path} should be supported"
647
+ next
648
+ end
649
+ end
650
+ end
651
+ post_targets_context[target] = target_info
652
+
653
+ end
654
+ end
655
+ end
656
+
657
+ projects.each do |project|
658
+ project.native_targets.each do | target |
659
+ if post_targets_context.has_key? target
660
+ target_info = post_targets_context[target]
661
+ next unless target_info[:target_status] == CACHE_STATUS_READY
662
+
663
+ dependency_targets_set = Set.new
664
+ implicit_dependencies = []
665
+
666
+ post_targets_context.each do | other_target, other_target_context |
667
+ next if target == other_target
668
+ next if target.product_type == "com.apple.product-type.bundle"
669
+ next if other_target.product_type == "com.apple.product-type.bundle"
670
+
671
+ configuration_build_dir = other_target_context[CONFIGURATION_BUILD_DIR]
672
+ target_temp_dir = other_target_context[TARGET_TEMP_DIR]
673
+ build_product_dir = other_target_context[:build_product_dir]
674
+ build_intermediate_dir = other_target_context[:build_intermediate_dir]
675
+
676
+ target_info[:dependency_files].each do | dependency |
677
+ if configuration_build_dir and configuration_build_dir.size > 0 and dependency.start_with? configuration_build_dir + "/"
678
+ dependency_targets_set.add other_target
679
+ implicit_dependencies.push dependency
680
+ end
681
+
682
+ if target_temp_dir and target_temp_dir.size > 0 and dependency.start_with? target_temp_dir + "/"
683
+ dependency_targets_set.add other_target
684
+ implicit_dependencies.push dependency
685
+ end
686
+
687
+ if build_product_dir and build_product_dir.size > 0 and dependency.start_with? target_info[SYMROOT] + "/" + build_product_dir + "/"
688
+ dependency_targets_set.add other_target
689
+ implicit_dependencies.push dependency
690
+ end
691
+
692
+ if build_intermediate_dir and build_intermediate_dir.size > 0 and dependency.start_with? target_info[OBJROOT] + "/" + build_intermediate_dir + "/"
693
+ dependency_targets_set.add other_target
694
+ implicit_dependencies.push dependency
695
+ end
696
+
697
+ end
698
+ target_info[:dependency_files] = target_info[:dependency_files] - implicit_dependencies
699
+
700
+ end
701
+ target_info[:dependency_files] = target_info[:dependency_files] - implicit_dependencies
702
+
703
+ dependency_files_md5 = []
704
+
705
+ should_cache = true
706
+ if target_info and target_info[:dependency_files].size > 0
707
+ target_info[:dependency_files].each do | file |
708
+ if file.start_with? target_info[OBJROOT] + "/" or file.start_with? target_info[SYMROOT] + "/"
709
+ puts "#{target.name} #{file} dependecy should not include build path"
710
+ should_cache = false
711
+ break
712
+ end
713
+ dependency_files_md5.push [get_content_without_pwd(file), get_file_md5(file)]
714
+ end
715
+ end
716
+ next unless should_cache
717
+
718
+ target_info[:dependency_files_md5] = dependency_files_md5.sort.uniq
719
+ dependency_targets_md5 = dependency_targets_set.to_a.map { | target | [target.name, post_targets_context[target][:target_md5]]}
720
+ target_info[:dependency_targets_md5] = dependency_targets_md5
721
+
722
+ if add_cache(target, target_info)
723
+ puts "<INFO> #{target} is being added to cache dir"
724
+ total_add_count = total_add_count + 1
725
+ target.build_phases.delete_if { |phase|
726
+ phase.class == Xcodeproj::Project::Object::PBXShellScriptBuildPhase and phase.name.include? "ys_"
727
+ }
728
+ end
729
+
730
+ end
731
+ end
732
+ restore_project(project)
733
+ end
734
+
735
+ puts "<INFO> total add cache count: #{total_add_count}"
736
+ end
737
+
738
+
739
+ end
740
+
741
+
742
+
743
+
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: akcache
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - yusheng
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: xcodeproj
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ description: a cache tool that can promote xcode build time
28
+ email:
29
+ - 1433233832@qq.com
30
+ executables:
31
+ - kcache
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".github/workflows/main.yml"
36
+ - ".gitignore"
37
+ - ".rubocop.yml"
38
+ - ".vscode/launch.json"
39
+ - CODE_OF_CONDUCT.md
40
+ - Gemfile
41
+ - Gemfile.lock
42
+ - LICENSE.txt
43
+ - README.md
44
+ - Rakefile
45
+ - bin/console
46
+ - bin/kcache
47
+ - bin/setup
48
+ - kcache.gemspec
49
+ - lib/kcache.rb
50
+ - lib/kcache/version.rb
51
+ homepage: https://github.com/yusheng00
52
+ licenses:
53
+ - MIT
54
+ metadata:
55
+ homepage_uri: https://github.com/yusheng00
56
+ source_code_uri: https://github.com/yusheng00
57
+ changelog_uri: https://github.com/yusheng00
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.4.0
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubygems_version: 3.0.6
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: a cache tool
77
+ test_files: []