├── .gitignore
├── README.md
├── cocoapods-imy-bin
├── .gitignore
├── .rakeTasks
├── BinArchive.json
├── Gemfile
├── Gemfile.lock
├── LICENSE.txt
├── README.md
├── Rakefile
├── cocoapods-imy-bin-0.3.1.2.gem
├── cocoapods-imy-bin.gemspec
├── lib
│ ├── cocoapods-imy-bin.rb
│ ├── cocoapods-imy-bin
│ │ ├── command.rb
│ │ ├── command
│ │ │ ├── bin.rb
│ │ │ └── bin
│ │ │ │ ├── archive.rb
│ │ │ │ ├── auto.rb
│ │ │ │ ├── code.rb
│ │ │ │ ├── imy.rb
│ │ │ │ ├── init.rb
│ │ │ │ ├── initHotKey.rb
│ │ │ │ ├── install.rb
│ │ │ │ ├── lib
│ │ │ │ └── lint.rb
│ │ │ │ ├── repo
│ │ │ │ └── update.rb
│ │ │ │ ├── spec
│ │ │ │ ├── create.rb
│ │ │ │ └── push.rb
│ │ │ │ └── update.rb
│ │ ├── config
│ │ │ ├── config.rb
│ │ │ ├── config_asker.rb
│ │ │ ├── config_builder.rb
│ │ │ ├── config_hot_key.rb
│ │ │ └── config_hot_key_asker.rb
│ │ ├── gem_version.rb
│ │ ├── helpers.rb
│ │ ├── helpers
│ │ │ ├── Info.plist
│ │ │ ├── build_helper.rb
│ │ │ ├── build_utils.rb
│ │ │ ├── framework.rb
│ │ │ ├── framework_builder.rb
│ │ │ ├── library.rb
│ │ │ ├── library_builder.rb
│ │ │ ├── sources_helper.rb
│ │ │ ├── spec_creator.rb
│ │ │ ├── spec_files_helper.rb
│ │ │ ├── spec_source_creator.rb
│ │ │ └── upload_helper.rb
│ │ ├── native.rb
│ │ ├── native
│ │ │ ├── acknowledgements.rb
│ │ │ ├── analyzer.rb
│ │ │ ├── file_accessor.rb
│ │ │ ├── installation_options.rb
│ │ │ ├── installer.rb
│ │ │ ├── linter.rb
│ │ │ ├── path_source.rb
│ │ │ ├── pod_source_installer.rb
│ │ │ ├── pod_target_installer.rb
│ │ │ ├── podfile.rb
│ │ │ ├── podfile_env.rb
│ │ │ ├── podfile_generator.rb
│ │ │ ├── podspec_finder.rb
│ │ │ ├── resolver.rb
│ │ │ ├── sandbox_analyzer.rb
│ │ │ ├── source.rb
│ │ │ ├── sources_manager.rb
│ │ │ ├── specification.rb
│ │ │ ├── target_validator.rb
│ │ │ └── validator.rb
│ │ └── source_provider_hook.rb
│ └── cocoapods_plugin.rb
└── spec
│ ├── command
│ └── bin_spec.rb
│ └── spec_helper.rb
├── img
├── Podfile.png
├── Podfile_local.png
└── time.png
├── 使用教程.md
└── 演示视频
├── 二进制源码调试演示.mp4
├── 使用二进制.mp4
└── 制作二进制组件.mp4
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea/
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # 只要两行代码,即可提升10倍以上编译速度
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ### 特色:
12 |
13 | 1. **无入侵、无感知、不影响现有业务,不影响现有代码框架、完全绿色产品,~**
14 | 2. **轻量级,只要项目能编译通过就能使用,无视组件化、无视耦合**
15 | 3. **完全自动化,不需要维护Pods库,一键使用、无需手动操作,**
16 | 4. **一步步教你使用,新手也能欢乐玩转**
17 | 5. **提供几个特色服务**
18 | 6. **支持 使用与不使用 use_frameworks!**
19 | 7. **少数支持swift项目二进制化编译的开源项目之一**
20 |
21 |
22 |
23 | 关于 插件具体的架构部署实践和更详细的资源,可以参考
24 |
25 | > [iOS编译速度如何稳定提高10倍以上](https://juejin.cn/post/6903407900006449160)
26 | >
27 | > [iOS美团同款"ZSource"二进制调试实现](https://juejin.im/post/5f066cfa5188252e893a136e)
28 | >
29 | > [iOS教你如何像RN一样实时编译](https://juejin.im/post/6850037272415813645)
30 | >
31 | > [Swift编译慢?请看这里,全套开源](https://juejin.im/post/6890419459639476237)
32 | >
33 | > [OC-Demo](https://github.com/su350380433/cocoapods-imy-bin-demo)
34 | >
35 | > [Swift-OC-Demo](https://github.com/su350380433/Swift-OC-Demo)
36 |
37 |
38 |
39 |
40 |
41 | ### 更新
42 |
43 | - 2021-01-12
44 |
45 | v0.3.1.3 fix some bugs
46 |
47 | - 2020-11-02
48 |
49 | v0.3.0.11 支持纯Swift、纯Object-C、Swift-OC混编
50 |
51 |
52 | ## 一、使用教程
53 |
54 | [使用教程](./使用教程.md)
55 |
56 |
57 |
58 |
59 | ## 二、感谢
60 |
61 |
62 |
63 | **[cocoapods-bin](https://github.com/tripleCC/cocoapods-bin)**
64 |
65 | [美团 iOS 工程 zsource 命令背后的那些事儿](https://tech.meituan.com/2019/08/08/the-things-behind-the-ios-project-zsource-command.html)
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | pkg
3 | .idea/
4 | examples/
5 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/.rakeTasks:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/BinArchive.json:
--------------------------------------------------------------------------------
1 | {
2 | "archive-white-pod-list" : [
3 | "YYTargetDemo",
4 | "YYModel"
5 | ],
6 | "ignore-git-list": [
7 | "git@gitlab.xxx.com:Github-iOS"
8 | ],
9 | "ignore-http-list": [
10 | "https://gitlab.xxx.com/Github-iOS"
11 | ],
12 | "//": "xcode_build_path 设置编译缓存完整路径",
13 | "xcode_build_path" : "xcode-build/Build/Intermediates.noindex/ArchiveIntermediates/#{target_name}/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/",
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/Gemfile:
--------------------------------------------------------------------------------
1 | SKIP_UNRELEASED_VERSIONS = false
2 |
3 | # Specify your gem's dependencies in cocoapods-imy-bin.gemspec
4 |
5 |
6 | def cp_gem(name, repo_name, branch = 'master', path: false)
7 | return gem name if SKIP_UNRELEASED_VERSIONS
8 | opts = if path
9 | { :path => "../#{repo_name}" }
10 | else
11 | url = "https://github.com/CocoaPods/#{repo_name}.git"
12 | { :git => url, :branch => branch }
13 | end
14 | gem name, opts
15 | end
16 |
17 | source 'https://rubygems.org'
18 |
19 |
20 | group :development do
21 |
22 | cp_gem 'cocoapods', 'cocoapods',path: 'CocoaPods'
23 | cp_gem 'xcodeproj', 'xcodeproj',path: 'Xcodeproj'
24 | cp_gem 'cocoapods-imy-bin', 'cocoapods-imy-bin',path: 'cocoapods-imy-bin'
25 |
26 | gem 'cocoapods-generate', '1.6.0'
27 | gem 'mocha'
28 | gem 'bacon'
29 | gem 'mocha-on-bacon'
30 | gem 'prettybacon'
31 |
32 | end
33 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: ../cocoapods
3 | specs:
4 | cocoapods (1.8.4)
5 | activesupport (>= 4.0.2, < 5)
6 | claide (>= 1.0.2, < 2.0)
7 | cocoapods-core (= 1.8.4)
8 | cocoapods-deintegrate (>= 1.0.3, < 2.0)
9 | cocoapods-downloader (>= 1.2.2, < 2.0)
10 | cocoapods-plugins (>= 1.0.0, < 2.0)
11 | cocoapods-search (>= 1.0.0, < 2.0)
12 | cocoapods-stats (>= 1.0.0, < 2.0)
13 | cocoapods-trunk (>= 1.4.0, < 2.0)
14 | cocoapods-try (>= 1.1.0, < 2.0)
15 | colored2 (~> 3.1)
16 | escape (~> 0.0.4)
17 | fourflusher (>= 2.3.0, < 3.0)
18 | gh_inspector (~> 1.0)
19 | molinillo (~> 0.6.6)
20 | nap (~> 1.0)
21 | ruby-macho (~> 1.4)
22 | xcodeproj (>= 1.11.1, < 2.0)
23 |
24 | PATH
25 | remote: ../xcodeproj
26 | specs:
27 | xcodeproj (1.15.0)
28 | CFPropertyList (>= 2.3.3, < 4.0)
29 | atomos (~> 0.1.3)
30 | claide (>= 1.0.2, < 2.0)
31 | colored2 (~> 3.1)
32 | nanaimo (~> 0.2.6)
33 |
34 | PATH
35 | remote: .
36 | specs:
37 | cocoapods-imy-bin (0.2.0)
38 | cocoapods
39 | cocoapods-generate (= 1.6.0)
40 | parallel
41 |
42 | GEM
43 | remote: https://rubygems.org/
44 | specs:
45 | CFPropertyList (3.0.2)
46 | activesupport (4.2.11.3)
47 | i18n (~> 0.7)
48 | minitest (~> 5.1)
49 | thread_safe (~> 0.3, >= 0.3.4)
50 | tzinfo (~> 1.1)
51 | algoliasearch (1.27.3)
52 | httpclient (~> 2.8, >= 2.8.3)
53 | json (>= 1.5.1)
54 | atomos (0.1.3)
55 | bacon (1.2.0)
56 | claide (1.0.3)
57 | cocoapods-core (1.8.4)
58 | activesupport (>= 4.0.2, < 6)
59 | algoliasearch (~> 1.0)
60 | concurrent-ruby (~> 1.1)
61 | fuzzy_match (~> 2.0.4)
62 | nap (~> 1.0)
63 | cocoapods-deintegrate (1.0.4)
64 | cocoapods-disable-podfile-validations (0.1.1)
65 | cocoapods-downloader (1.3.0)
66 | cocoapods-generate (1.6.0)
67 | cocoapods-disable-podfile-validations (~> 0.1.1)
68 | cocoapods-plugins (1.0.0)
69 | nap
70 | cocoapods-search (1.0.0)
71 | cocoapods-stats (1.1.0)
72 | cocoapods-trunk (1.5.0)
73 | nap (>= 0.8, < 2.0)
74 | netrc (~> 0.11)
75 | cocoapods-try (1.2.0)
76 | colored2 (3.1.2)
77 | concurrent-ruby (1.1.6)
78 | escape (0.0.4)
79 | fourflusher (2.3.1)
80 | fuzzy_match (2.0.4)
81 | gh_inspector (1.1.3)
82 | httpclient (2.8.3)
83 | i18n (0.9.5)
84 | concurrent-ruby (~> 1.0)
85 | json (2.3.0)
86 | minitest (5.14.1)
87 | mocha (1.11.2)
88 | mocha-on-bacon (0.2.3)
89 | mocha (>= 0.13.0)
90 | molinillo (0.6.6)
91 | nanaimo (0.2.6)
92 | nap (1.1.0)
93 | netrc (0.11.0)
94 | parallel (1.19.1)
95 | prettybacon (0.0.2)
96 | bacon (~> 1.2)
97 | ruby-macho (1.4.0)
98 | thread_safe (0.3.6)
99 | tzinfo (1.2.7)
100 | thread_safe (~> 0.1)
101 |
102 | PLATFORMS
103 | ruby
104 |
105 | DEPENDENCIES
106 | bacon
107 | cocoapods!
108 | cocoapods-generate (= 1.6.0)
109 | cocoapods-imy-bin!
110 | mocha
111 | mocha-on-bacon
112 | prettybacon
113 | xcodeproj!
114 |
115 | BUNDLED WITH
116 | 2.1.4
117 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018 tripleCC
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/Rakefile:
--------------------------------------------------------------------------------
1 | require 'bundler/gem_tasks'
2 |
3 | def specs(dir)
4 | FileList["spec/#{dir}/*_spec.rb"].shuffle.join(' ')
5 | end
6 |
7 | desc 'Runs all the specs'
8 | task :specs do
9 | sh "bundle exec bacon #{specs('**')}"
10 | end
11 |
12 | task :default => :specs
13 |
14 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/cocoapods-imy-bin-0.3.1.2.gem:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetYouDevs/cocoapods-imy-bin/36b201004ea3610e3278429c48d3cf49b4b650d2/cocoapods-imy-bin/cocoapods-imy-bin-0.3.1.2.gem
--------------------------------------------------------------------------------
/cocoapods-imy-bin/cocoapods-imy-bin.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require 'cocoapods-imy-bin/gem_version.rb'
5 |
6 | Gem::Specification.new do |spec|
7 | spec.name = 'cocoapods-imy-bin'
8 | spec.version = CBin::VERSION
9 | spec.authors = ['苏良锦']
10 | spec.email = ['suliangjin@xiaoyouzi.com']
11 | spec.description = %q{cocoapods-imy-bin is a plugin which helps develpers switching pods between source code and binary.}
12 | spec.summary = %q{cocoapods-imy-bin is a plugin which helps develpers switching pods between source code and binary.}
13 | spec.homepage = 'https://github.com/su350380433/cocaopods-imy-bin'
14 | spec.license = 'MIT'
15 |
16 | spec.files = Dir["lib/**/*.rb","spec/**/*.rb","lib/**/*.plist"] + %w{README.md LICENSE.txt }
17 |
18 | #spec.files = `git ls-files`.split($/)
19 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21 | spec.require_paths = ['lib']
22 |
23 | spec.add_dependency 'parallel'
24 | spec.add_dependency 'cocoapods'
25 | spec.add_dependency "cocoapods-generate",'~>2.0.1'
26 |
27 | spec.add_development_dependency 'bundler'
28 | spec.add_development_dependency 'rake'
29 | end
30 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/gem_version'
2 | require 'cocoapods-imy-bin/native/sources_manager'
3 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'cocoapods-imy-bin/command/bin'
3 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'cocoapods-imy-bin/command/bin/initHotKey'
3 | require 'cocoapods-imy-bin/command/bin/init'
4 | require 'cocoapods-imy-bin/command/bin/archive'
5 | require 'cocoapods-imy-bin/command/bin/auto'
6 | require 'cocoapods-imy-bin/command/bin/code'
7 | require 'cocoapods-imy-bin/command/bin/update'
8 | require 'cocoapods-imy-bin/command/bin/install'
9 | require 'cocoapods-imy-bin/command/bin/imy'
10 |
11 | require 'cocoapods-imy-bin/helpers'
12 |
13 | module Pod
14 | class Command
15 | # This is an example of a cocoapods plugin adding a top-level subcommand
16 | # to the 'pod' command.
17 | #
18 | # You can also create subcommands of existing or new commands. Say you
19 | # wanted to add a subcommand to `list` to show newly deprecated pods,
20 | # (e.g. `pod list deprecated`), there are a few things that would need
21 | # to change.
22 | #
23 | # - move this file to `lib/pod/command/list/deprecated.rb` and update
24 | # the class to exist in the the Pod::Command::List namespace
25 | # - change this class to extend from `List` instead of `Command`. This
26 | # tells the plugin system that it is a subcommand of `list`.
27 | # - edit `lib/cocoapods_plugins.rb` to require this file
28 | #
29 | # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
30 | # in the `plugins.json` file, once your plugin is released.
31 | #
32 | class Bin < Command
33 | include CBin::SourcesHelper
34 | include CBin::SpecFilesHelper
35 |
36 | self.abstract_command = true
37 | self.summary = '组件二进制化插件.'
38 | self.description = <<-DESC
39 | 组件二进制化插件。利用源码私有源与二进制私有源实现对组件依赖类型的切换。
40 | DESC
41 |
42 | def initialize(argv)
43 | require 'cocoapods-imy-bin/native'
44 |
45 | @help = argv.flag?('help')
46 | super
47 | end
48 |
49 | def validate!
50 | super
51 | # 这里由于 --help 是在 validate! 方法中提取的,会导致 --help 失效
52 | # pod lib create 也有这个问题
53 | banner! if @help
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/archive.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/native/podfile'
2 | require 'cocoapods/command/gen'
3 | require 'cocoapods/generate'
4 | require 'cocoapods-imy-bin/helpers/framework_builder'
5 | require 'cocoapods-imy-bin/helpers/library_builder'
6 | require 'cocoapods-imy-bin/helpers/build_helper'
7 | require 'cocoapods-imy-bin/helpers/spec_source_creator'
8 | require 'cocoapods-imy-bin/config/config_builder'
9 | require 'cocoapods-imy-bin/command/bin/lib/lint'
10 |
11 | module Pod
12 | class Command
13 | class Bin < Command
14 | class Archive < Bin
15 |
16 | @@missing_binary_specs = []
17 |
18 | self.summary = '将组件归档为静态库 .a.'
19 | self.description = <<-DESC
20 | 将组件归档为静态库 framework,仅支持 iOS 平台
21 | 此静态 framework 不包含依赖组件的 symbol
22 | DESC
23 |
24 | def self.options
25 | [
26 | ['--all-make', '对该组件的依赖库,全部制作为二进制组件'],
27 | ['--code-dependencies', '使用源码依赖'],
28 | ['--no-clean', '保留构建中间产物'],
29 | ['--sources', '私有源地址,多个用分号区分'],
30 | ['--framework-output', '输出framework文件'],
31 | ['--no-zip', '不压缩静态库 为 zip'],
32 | ['--configuration', 'Build the specified configuration (e.g. Debug). Defaults to Release'],
33 | ['--env', "该组件上传的环境 %w[dev debug_iphoneos release_iphoneos]"]
34 | ].concat(Pod::Command::Gen.options).concat(super).uniq
35 | end
36 |
37 | self.arguments = [
38 | CLAide::Argument.new('NAME.podspec', false)
39 | ]
40 |
41 | def initialize(argv)
42 | @env = argv.option('env') || 'dev'
43 | CBin.config.set_configuration_env(@env)
44 | UI.warn "====== cocoapods-imy-bin #{CBin::VERSION} 版本 ======== \n "
45 | UI.warn "====== #{@env} 环境 ======== \n "
46 |
47 | @code_dependencies = argv.flag?('code-dependencies')
48 | @framework_output = argv.flag?('framework-output', false )
49 | @clean = argv.flag?('no-clean', false)
50 | @zip = argv.flag?('zip', true)
51 | @all_make = argv.flag?('all-make', false )
52 | @sources = argv.option('sources') || []
53 | @platform = Platform.new(:ios)
54 |
55 | @config = argv.option('configuration', 'Release')
56 |
57 | @framework_path
58 | super
59 |
60 | @additional_args = argv.remainder!
61 | @build_finshed = false
62 | end
63 |
64 | def run
65 | #清除之前的缓存
66 | zip_dir = CBin::Config::Builder.instance.zip_dir
67 | FileUtils.rm_rf(zip_dir) if File.exist?(zip_dir)
68 |
69 | @spec = Specification.from_file(spec_file)
70 | generate_project
71 |
72 | source_specs = Array.new
73 | source_specs.concat(build_root_spec)
74 | source_specs.concat(build_dependencies) if @all_make
75 |
76 | source_specs
77 | end
78 |
79 | def build_root_spec
80 | source_specs = []
81 | builder = CBin::Build::Helper.new(@spec,
82 | @platform,
83 | @framework_output,
84 | @zip,
85 | @spec,
86 | CBin::Config::Builder.instance.white_pod_list.include?(@spec.name),
87 | @config)
88 | builder.build
89 | builder.clean_workspace if @clean && !@all_make
90 | source_specs << @spec unless CBin::Config::Builder.instance.white_pod_list.include?(@spec.name)
91 |
92 | source_specs
93 | end
94 |
95 | def build_dependencies
96 | @build_finshed = true
97 | #如果没要求,就清空依赖库数据
98 | source_specs = []
99 | @@missing_binary_specs.uniq.each do |spec|
100 | next if spec.name.include?('/')
101 | next if spec.name == @spec.name
102 | #过滤白名单
103 | next if CBin::Config::Builder.instance.white_pod_list.include?(spec.name)
104 | #过滤 git
105 | if spec.source[:git] && spec.source[:git]
106 | spec_git = spec.source[:git]
107 | spec_git_res = false
108 | CBin::Config::Builder.instance.ignore_git_list.each do |ignore_git|
109 | spec_git_res = spec_git.include?(ignore_git)
110 | break if spec_git_res
111 | end
112 | next if spec_git_res
113 | end
114 | UI.warn "#{spec.name}.podspec 带有 vendored_frameworks 字段,请检查是否有效!!!" if spec.attributes_hash['vendored_frameworks']
115 | next if spec.attributes_hash['vendored_frameworks'] && @spec.name != spec.name #过滤带有vendored_frameworks的
116 | next if spec.attributes_hash['ios.vendored_frameworks'] && @spec.name != spec.name #过滤带有vendored_frameworks的
117 | #获取没有制作二进制版本的spec集合
118 | source_specs << spec
119 | end
120 |
121 | fail_build_specs = []
122 | source_specs.uniq.each do |spec|
123 | begin
124 | builder = CBin::Build::Helper.new(spec,
125 | @platform,
126 | @framework_output,
127 | @zip,
128 | @spec,
129 | false ,
130 | @config)
131 | builder.build
132 | rescue Object => exception
133 | UI.puts exception
134 | fail_build_specs << spec
135 | end
136 | end
137 |
138 | if fail_build_specs.any?
139 | fail_build_specs.uniq.each do |spec|
140 | UI.warn "【#{spec.name} | #{spec.version}】组件二进制版本编译失败 ."
141 | end
142 | end
143 | source_specs - fail_build_specs
144 | end
145 |
146 | # 解析器传过来的
147 | def Archive.missing_binary_specs(missing_binary_specs)
148 | @@missing_binary_specs = missing_binary_specs unless @build_finshed
149 | end
150 |
151 | private
152 |
153 | def generate_project
154 | Podfile.execute_with_bin_plugin do
155 | Podfile.execute_with_use_binaries(!@code_dependencies) do
156 | argvs = [
157 | "--sources=#{sources_option(@code_dependencies, @sources)}",
158 | "--gen-directory=#{CBin::Config::Builder.instance.gen_dir}",
159 | '--clean',
160 | *@additional_args
161 | ]
162 |
163 | podfile= File.join(Pathname.pwd, "Podfile")
164 | if File.exist?(podfile)
165 | argvs += ['--use-podfile']
166 | end
167 |
168 | argvs << spec_file if spec_file
169 |
170 | gen = Pod::Command::Gen.new(CLAide::ARGV.new(argvs))
171 | gen.validate!
172 | gen.run
173 | end
174 | end
175 | end
176 |
177 |
178 | def spec_file
179 | @spec_file ||= begin
180 | if @podspec
181 | find_spec_file(@podspec)
182 | else
183 | if code_spec_files.empty?
184 | raise Informative, '当前目录下没有找到可用源码 podspec.'
185 | end
186 |
187 | spec_file = code_spec_files.first
188 | spec_file
189 | end
190 | end
191 | end
192 |
193 |
194 |
195 | end
196 | end
197 | end
198 | end
199 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/auto.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'cocoapods-imy-bin/command/bin/auto'
3 | require 'cocoapods-imy-bin/helpers/upload_helper'
4 |
5 | module Pod
6 | class Command
7 | class Bin < Command
8 | class Auto < Bin
9 | self.summary = '打开 workspace 工程.'
10 |
11 | self.arguments = [
12 | CLAide::Argument.new('NAME.podspec', false)
13 | ]
14 | def self.options
15 | [
16 | ['--code-dependencies', '使用源码依赖'],
17 | ['--allow-prerelease', '允许使用 prerelease 的版本'],
18 | ['--no-clean', '保留构建中间产物'],
19 | ['--framework-output', '输出framework文件'],
20 | ['--no-zip', '不压缩静态 framework 为 zip'],
21 | ['--all-make', '对该组件的依赖库,全部制作为二进制组件'],
22 | ['--configuration', 'Build the specified configuration (e.g. Release ). Defaults to Debug'],
23 | ['--env', "该组件上传的环境 %w[dev debug_iphoneos release_iphoneos]"]
24 | ].concat(Pod::Command::Gen.options).concat(super).uniq
25 | end
26 |
27 | def initialize(argv)
28 |
29 | @env = argv.option('env') || 'dev'
30 | CBin.config.set_configuration_env(@env)
31 |
32 | @podspec = argv.shift_argument || find_podspec
33 | @specification = Specification.from_file(@podspec)
34 |
35 | @code_dependencies = argv.flag?('code-dependencies')
36 | @allow_prerelease = argv.flag?('allow-prerelease')
37 | @framework_output = argv.flag?('framework-output', false )
38 | @clean = argv.flag?('clean', true)
39 | @zip = argv.flag?('zip', true)
40 | @all_make = argv.flag?('all-make', false )
41 | @verbose = argv.flag?('verbose',true)
42 |
43 | @config = argv.option('configuration', 'Debug')
44 | @additional_args = argv.remainder!
45 |
46 | super
47 | end
48 |
49 | def validate!
50 | help! "未找到 podspec文件" unless @podspec
51 | super
52 | end
53 |
54 | def run
55 | @specification = Specification.from_file(@podspec)
56 |
57 | source_specs = run_archive
58 |
59 | fail_push_specs = []
60 | source_specs.uniq.each do |spec|
61 | begin
62 | fail_push_specs << spec unless CBin::Upload::Helper.new(spec,@code_dependencies,@sources).upload
63 | rescue Object => exception
64 | UI.puts exception
65 | fail_push_specs << spec
66 | end
67 | end
68 |
69 | if fail_push_specs.any?
70 | fail_push_specs.uniq.each do |spec|
71 | UI.warn "【#{spec.name} | #{spec.version}】组件spec push失败 ."
72 | end
73 | end
74 |
75 | success_specs = source_specs - fail_push_specs
76 | if success_specs.any?
77 | auto_success = ""
78 | success_specs.uniq.each do |spec|
79 | auto_success += "#{spec.name} | #{spec.version}\n"
80 | UI.warn "===【 #{spec.name} | #{spec.version} 】二进制组件制作完成 !!! "
81 | end
82 | puts "============== auto_success"
83 | puts auto_success
84 | ENV['auto_success'] = auto_success
85 | end
86 | #pod repo update
87 | UI.section("\nUpdating Spec Repositories\n".yellow) do
88 | Pod::Command::Bin::Repo::Update.new(CLAide::ARGV.new([])).run
89 | end
90 |
91 | end
92 |
93 | #制作二进制包
94 |
95 | def run_archive
96 | argvs = [
97 | "--sources=#{sources_option(@code_dependencies, @sources)},https:\/\/cdn.cocoapods.org",
98 | @additional_args
99 | ]
100 |
101 | argvs << spec_file if spec_file
102 | argvs.delete(Array.new)
103 |
104 | unless @clean
105 | argvs += ['--no-clean']
106 | end
107 | if @code_dependencies
108 | argvs += ['--code-dependencies']
109 | end
110 | if @verbose
111 | argvs += ['--verbose']
112 | end
113 | if @allow_prerelease
114 | argvs += ['--allow-prerelease']
115 | end
116 | if @framework_output
117 | argvs += ['--framework-output']
118 | end
119 | if @all_make
120 | argvs += ['--all-make']
121 | end
122 | if @env
123 | argvs += ["--env=#{@env}"]
124 | end
125 | argvs += ["--configuration=#{@config}"]
126 |
127 | archive = Pod::Command::Bin::Archive.new(CLAide::ARGV.new(argvs))
128 | archive.validate!
129 | source_specs = archive.run
130 | source_specs
131 | end
132 |
133 |
134 | def code_podsepc_extname
135 | '.podsepc'
136 | end
137 |
138 | def binary_podsepc_json
139 | "#{@specification.name}.binary.podspec.json"
140 | end
141 |
142 | def binary_template_podsepc
143 | "#{@specification.name}.binary-template.podspec"
144 | end
145 |
146 | def template_spec_file
147 | @template_spec_file ||= begin
148 | if @template_podspec
149 | find_spec_file(@template_podspec)
150 | else
151 | binary_template_spec_file
152 | end
153 | end
154 | end
155 |
156 | def spec_file
157 | @spec_file ||= begin
158 | if @podspec
159 | find_spec_file(@podspec) || @podspec
160 | else
161 | if code_spec_files.empty?
162 | raise Informative, '当前目录下没有找到可用源码 podspec.'
163 | end
164 |
165 | spec_file = if @binary
166 | code_spec = Pod::Specification.from_file(code_spec_files.first)
167 | if template_spec_file
168 | template_spec = Pod::Specification.from_file(template_spec_file)
169 | end
170 | create_binary_spec_file(code_spec, template_spec)
171 | else
172 | code_spec_files.first
173 | end
174 | spec_file
175 | end
176 | end
177 | end
178 |
179 | #Dir.glob 可替代
180 | def find_podspec
181 | name = nil
182 | Pathname.pwd.children.each do |child|
183 | puts child
184 | if File.file?(child)
185 | if child.extname == '.podspec'
186 | name = File.basename(child)
187 | unless name.include?("binary-template")
188 | return name
189 | end
190 | end
191 | end
192 | end
193 | return name
194 | end
195 |
196 | end
197 | end
198 | end
199 | end
200 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/code.rb:
--------------------------------------------------------------------------------
1 |
2 | module Pod
3 | class Command
4 | class Bin < Command
5 | class Code < Bin
6 | self.summary = '通过将二进制对应源码放置在临时目录中,让二进制出现断点时可以跳到对应的源码,方便调试。'
7 |
8 | self.description = <<-DESC
9 | 通过将二进制对应源码放置在临时目录中,让二进制出现断点时可以跳到对应的源码,方便调试。
10 | 在不删除二进制的情况下为某个组件添加源码调试能力,多个组件名称用空格分隔
11 | DESC
12 |
13 | self.arguments = [
14 | CLAide::Argument.new('NAME', false)
15 | ]
16 | def self.options
17 | [
18 | ['--all-clean', '删除所有已经下载的源码'],
19 | ['--clean', '删除所有指定下载的源码'],
20 | ['--list', '展示所有一级下载的源码以及其大小'],
21 | ['--source', '源码路径,本地路径,会去自动链接本地源码']
22 | ]
23 | end
24 |
25 | def initialize(argv)
26 | @codeSource = argv.option('source') || nil
27 | @names = argv.arguments! unless argv.arguments.empty?
28 | @list = argv.flag?('list', false )
29 | @all_clean = argv.flag?('all-clean', false )
30 | @clean = argv.flag?('clean', false )
31 |
32 | @config = Pod::Config.instance
33 |
34 | super
35 | end
36 |
37 |
38 | def run
39 |
40 | podfile_lock = File.join(Pathname.pwd,"Podfile.lock")
41 | raise "podfile.lock,不存在,请先pod install/update" unless File.exist?(podfile_lock)
42 | @lockfile ||= Lockfile.from_file(Pathname.new(podfile_lock) )
43 |
44 | if @list
45 | list
46 | elsif @clean
47 | clean
48 | elsif @all_clean
49 | all_clean
50 | elsif @names
51 | add
52 | end
53 |
54 | if @list && @clean && @names
55 | raise "请选择您要执行的命令。"
56 | end
57 | end
58 |
59 | #==========================begin add ==============
60 |
61 | def add
62 | if @names == nil
63 | raise "请输入要调试组件名,多个组件名称用空格分隔"
64 | end
65 |
66 | @names.each do |name|
67 | lib_file = get_lib_path(name)
68 | unless File.exist?(lib_file)
69 | raise "找不到 #{lib_file}"
70 | end
71 | UI.puts "#{lib_file}"
72 |
73 | target_path = @codeSource || download_source(name)
74 |
75 | link(lib_file,target_path,name)
76 | end
77 | end
78 |
79 | #下载源码到本地
80 | def download_source(name)
81 | target_path = File.join(source_root, name)
82 | UI.puts target_path
83 | FileUtils.rm_rf(target_path)
84 |
85 | find_dependency = find_dependency(name)
86 |
87 | spec = fetch_external_source(find_dependency, @config.podfile,@config.lockfile, @config.sandbox,true )
88 |
89 | download_request = Pod::Downloader::Request.new(:name => name, :spec => spec)
90 | Downloader.download(download_request, Pathname.new(target_path), :can_cache => true)
91 |
92 | target_path
93 | end
94 |
95 | #找出依赖
96 | def find_dependency (name)
97 | find_dependency = nil
98 | @config.podfile.dependencies.each do |dependency|
99 | if dependency.root_name.downcase == name.downcase
100 | find_dependency = dependency
101 | break
102 | end
103 | end
104 | find_dependency
105 | end
106 |
107 | # 获取external_source 下的仓库
108 | # @return spec
109 | def fetch_external_source(dependency ,podfile , lockfile, sandbox,use_lockfile_options)
110 | source = ExternalSources.from_dependency(dependency, podfile.defined_in_file, true)
111 | source.fetch(sandbox)
112 | end
113 |
114 |
115 | #==========================link begin ==============
116 |
117 | #链接,.a文件位置, 源码目录,工程名=IMYFoundation
118 | def link(lib_file,target_path,basename)
119 | dir = (`dwarfdump "#{lib_file}" | grep "AT_comp_dir" | head -1 | cut -d \\" -f2 `)
120 | sub_path = "#{basename}/bin-archive/#{basename}"
121 | dir = dir.gsub(sub_path, "").chomp
122 | # UI.puts "dir = #{dir}"
123 |
124 | unless File.exist?(dir)
125 | # UI.puts "不存在 = #{dir}"
126 | begin
127 | FileUtils.mkdir_p(dir)
128 | rescue SystemCallError
129 | #判断用户目录是否存在
130 | array = dir.split('/')
131 | if array.length > 3
132 | root_path = '/' + array[1] + '/' + array[2]
133 | unless File.exist?(root_path)
134 | raise "由于权限不足,请手动创建#{root_path} 后重试"
135 | end
136 | end
137 | end
138 | end
139 |
140 | if Pathname.new(lib_file).extname == ".a"
141 | FileUtils.rm_rf(File.join(dir,basename))
142 | `ln -s #{target_path} #{dir}`
143 | else
144 | FileUtils.rm_rf(File.join(dir,basename))
145 | `ln -s #{target_path} #{dir}/#{basename}`
146 | end
147 |
148 | check(lib_file,dir,basename)
149 | end
150 |
151 | def check(lib_file,dir,basename)
152 | file = `dwarfdump "#{lib_file}" | grep -E "DW_AT_decl_file.*#{basename}.*\\.m|\\.c" | head -1 | cut -d \\" -f2`
153 | if File.exist?(file)
154 | raise "#{file} 不存在 请检测代码源是否正确~"
155 | end
156 | UI.puts "link successfully!"
157 | UI.puts "view linked source at path: #{dir}"
158 | end
159 |
160 | def get_lib_path(name)
161 | dir = Pathname.new(File.join(Pathname.pwd,"Pods",name))
162 | lib_name = "lib#{name}.a"
163 | lib_path = File.join(dir,lib_name)
164 |
165 | unless File.exist?(lib_path)
166 | lib_path = File.join(dir.children.first,lib_name)
167 | end
168 |
169 | lib_path
170 | end
171 |
172 | #源码地址
173 | # def get_gitlib_iOS_path(name)
174 | # "git@gitlab.xxx.com:iOS/#{name}.git"
175 | # end
176 | #要转换的地址,Github-iOS默认都是静态库
177 | # def git_gitlib_iOS_path
178 | # 'git@gitlab.xxx.com:Github-iOS/'
179 | # end
180 |
181 |
182 | #要转换的地址,Github-iOS默认都是静态库
183 | # def http_gitlib_GitHub_iOS_path
184 | # 'https://gitlab.xxx.com/Github-iOS/'
185 | # end
186 |
187 | #要转换的地址,iOS默认都是静态库
188 | # def http_gitlib_iOS_path
189 | # 'https://gitlab.xxx.com/iOS/'
190 | # end
191 |
192 | #==========================list begin ==============
193 |
194 | def list
195 | Dir.entries(source_root).each do |sub|
196 | UI.puts "- #{sub}" unless sub.include?('.')
197 | end
198 | UI.puts "加载完成"
199 | end
200 |
201 |
202 | #==========================clean begin ==============
203 | def all_clean
204 | FileUtils.rm_rf(source_root) if File.directory?(source_root)
205 | UI.puts "清理完成 #{source_root}"
206 | end
207 |
208 | def clean
209 | raise "请输入要删除的组件库" if @names.nil?
210 | @names.each do |name|
211 | full_path = File.join(source_root,name)
212 | if File.directory?(full_path)
213 | FileUtils.rm_rf(full_path)
214 | else
215 | UI.puts "找不到 #{full_path}".yellow
216 | end
217 | end
218 | UI.puts "清理完成 #{@names.to_s}"
219 | end
220 |
221 | private
222 |
223 | def source_root
224 | dir = File.join(@config.cache_root,"Source")
225 | FileUtils.mkdir_p(dir) unless File.exist? dir
226 | dir
227 | end
228 |
229 | end
230 | end
231 | end
232 | end
233 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/imy.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/config/config_hot_key_asker'
2 |
3 | module Pod
4 | class Command
5 | class Bin < Command
6 | class Imy < Bin
7 | self.summary = '快捷键'
8 | self.description = <<-DESC
9 | 创建 文件,在其中保存插件需要的配置信息,
10 | 如二进制私有源地址、源码私有源地址等。
11 | DESC
12 |
13 | self.arguments = [
14 | CLAide::Argument.new('1', false)
15 | ]
16 |
17 | def self.options
18 | [
19 | ].concat(super)
20 | end
21 |
22 | def initialize(argv)
23 | @hot_key = argv.shift_argument || '1'
24 | super
25 | end
26 |
27 | def run
28 | CBin.config_hot_key.set_hot_key_index(@hot_key)
29 | UI.puts "cd #{CBin.config_hot_key.hot_key_dir}".yellow
30 |
31 | if Dir.exist?(CBin.config_hot_key.hot_key_dir)
32 | Dir.chdir(CBin.config_hot_key.hot_key_dir) do
33 | UI.puts " #{CBin.config_hot_key.hot_key_cmd}".yellow
34 | system CBin.config_hot_key.hot_key_cmd
35 | end
36 | else
37 | raise "配置项中文件目录不存在 #{CBin.config_hot_key.hot_key_dir}"
38 | end
39 |
40 |
41 | end
42 |
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/init.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/config/config_asker'
2 |
3 | module Pod
4 | class Command
5 | class Bin < Command
6 | class Init < Bin
7 | self.summary = '初始化插件的快捷键.'
8 | self.description = <<-DESC
9 | 创建 文件,在其中保存插件需要的配置信息,
10 | 如快捷键1 快捷键2 所对应执行的命令
11 | DESC
12 |
13 | def self.options
14 | [
15 | ['--bin-url=URL', '配置文件地址,直接从此地址下载配置文件']
16 | ].concat(super)
17 | end
18 |
19 | def initialize(argv)
20 | @bin_url = argv.option('bin-url')
21 | super
22 | end
23 |
24 | def run
25 | if @bin_url.nil?
26 | config_with_asker
27 | else
28 | config_with_url(@bin_url)
29 | end
30 | end
31 |
32 | private
33 |
34 | def config_with_url(url)
35 | require 'open-uri'
36 |
37 | UI.puts "开始下载配置文件...\n"
38 | file = open(url)
39 | contents = YAML.safe_load(file.read)
40 |
41 | UI.puts "开始同步配置文件...\n"
42 | CBin.config.sync_config(contents.to_hash)
43 | UI.puts "设置完成.\n".green
44 | rescue Errno::ENOENT => e
45 | raise Informative, "配置文件路径 #{url} 无效,请确认后重试."
46 | end
47 |
48 | def config_with_asker
49 | asker = CBin::Config::Asker.new
50 | asker.wellcome_message
51 |
52 | config = {}
53 | template_hash = CBin.config.template_hash
54 | template_hash.each do |k, v|
55 | default = begin
56 | CBin.config.send(k)
57 | rescue StandardError
58 | nil
59 | end
60 | config[k] = asker.ask_with_answer(v[:description], default, v[:selection])
61 | end
62 |
63 | CBin.config.sync_config(config)
64 | asker.done_message
65 | end
66 | end
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/initHotKey.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'cocoapods-imy-bin/config/config_hot_key_asker'
3 |
4 | module Pod
5 | class Command
6 | class Bin < Command
7 | class Inithk < Bin
8 | self.summary = '初始化快捷键配置.'
9 | self.description = <<-DESC
10 | 创建 文件,在其中保存插件需要的配置信息,
11 | 如二进制私有源地址、源码私有源地址等。
12 | DESC
13 |
14 | def self.options
15 | [
16 | ['--bin-url=URL', '配置文件地址,直接从此地址下载配置文件']
17 | ].concat(super)
18 | end
19 |
20 | def initialize(argv)
21 | @bin_url = argv.option('bin-url')
22 | super
23 | end
24 |
25 | def run
26 | if @bin_url.nil?
27 | config_with_asker
28 | else
29 | config_with_url(@bin_url)
30 | end
31 | end
32 |
33 | private
34 |
35 | def config_with_url(url)
36 | require 'open-uri'
37 |
38 | UI.puts "开始下载配置文件...\n"
39 | file = open(url)
40 | contents = YAML.safe_load(file.read)
41 |
42 | UI.puts "开始同步配置文件...\n"
43 | CBin.config_hot_key.sync_config(contents.to_hash)
44 | UI.puts "设置完成.\n".green
45 | rescue Errno::ENOENT => e
46 | raise Informative, "配置文件路径 #{url} 无效,请确认后重试."
47 | end
48 |
49 | def config_with_asker
50 | asker = CBin::Config_Hot_Key::Asker.new
51 | asker.wellcome_message
52 |
53 | config = {}
54 | template_hash = CBin.config_hot_key.template_hash
55 | template_hash.each do |k, v|
56 | default = begin
57 | CBin.config_hot_key.send(k)
58 | rescue StandardError
59 | nil
60 | end
61 | config[k] = asker.ask_with_answer(v[:description], default, v[:selection])
62 | end
63 |
64 | CBin.config_hot_key.sync_config(config)
65 | asker.done_message
66 | end
67 | end
68 | end
69 | end
70 | end
71 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/install.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'cocoapods-imy-bin/command/bin/update'
3 | module Pod
4 | class Command
5 | class Bin < Command
6 | class Install < Bin
7 | include Pod
8 |
9 | self.summary = 'pod install 拦截器,会加载本地Podfile_local文件,DSL加载到原始Podfile文件中。'
10 |
11 | self.description = <<-DESC
12 | pod install 拦截器,会加载本地Podfile_local文件
13 | 会通过DSL加载到原始Podfile文件中
14 | 支持 pod 'xxx' 各种写法
15 | 支持 post_install/pre_install钩子,采用覆盖做法
16 | DESC
17 | def self.options
18 | [
19 | ['--repo-update', 'Force running `pod repo update` before install'],
20 | ['--deployment', 'Disallow any changes to the Podfile or the Podfile.lock during installation'],
21 | ['--clean-install', 'Ignore the contents of the project cache and force a full pod installation. This only ' \
22 | 'applies to projects that have enabled incremental installation']
23 | ].concat(super).reject { |(name, _)| name == '--no-repo-update' }
24 | end
25 |
26 | def initialize(argv)
27 | @update = argv.flag?('update')
28 | super
29 | @additional_args = argv.remainder!
30 | end
31 |
32 | def run
33 | Update.load_local_podfile
34 | argvs = [
35 | *@additional_args
36 | ]
37 | gen = Pod::Command::Install.new(CLAide::ARGV.new(argvs))
38 | gen.validate!
39 | gen.run
40 | end
41 | end
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/lib/lint.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/config/config'
2 | require 'cocoapods-imy-bin/native/podfile'
3 |
4 | module Pod
5 | class Command
6 | class Bin < Command
7 | class Lib < Bin
8 | class Lint < Lib
9 | self.summary = 'lint 组件.'
10 | self.description = <<-DESC
11 | lint 二进制组件 / 源码组件
12 | DESC
13 |
14 | self.arguments = [
15 | CLAide::Argument.new('NAME.podspec', false)
16 | ]
17 |
18 | # lib lint 不会下载 source,所以不能进行二进制 lint
19 | # 要 lint 二进制版本,需要进行 spec lint,此 lint 会去下载 source
20 | def self.options
21 | [
22 | ['--code-dependencies', '使用源码依赖进行 lint'],
23 | ['--loose-options', '添加宽松的 options, 包括 --use-libraries (可能会造成 entry point (start) undefined)'],
24 | ['--allow-prerelease', '允许使用 prerelease 的版本 lint']
25 | ].concat(Pod::Command::Lib::Lint.options).concat(super).uniq
26 | end
27 |
28 | def initialize(argv)
29 | @loose_options = argv.flag?('loose-options')
30 | @code_dependencies = argv.flag?('code-dependencies')
31 | @sources = argv.option('sources') || []
32 | @allow_prerelease = argv.flag?('allow-prerelease')
33 | @podspec = argv.shift_argument
34 | super
35 |
36 | @additional_args = argv.remainder!
37 | end
38 |
39 | def run
40 | Podfile.execute_with_bin_plugin do
41 | Podfile.execute_with_allow_prerelease(@allow_prerelease) do
42 | Podfile.execute_with_use_binaries(!@code_dependencies) do
43 | argvs = [
44 | @podspec || code_spec_files.first,
45 | "--sources=#{sources_option(@code_dependencies, @sources)}",
46 | *@additional_args
47 | ]
48 |
49 | if @loose_options
50 | argvs << '--allow-warnings'
51 | if code_spec&.all_dependencies&.any?
52 | argvs << '--use-libraries'
53 | end
54 | end
55 |
56 | lint = Pod::Command::Lib::Lint.new(CLAide::ARGV.new(argvs))
57 | lint.validate!
58 | lint.run
59 | end
60 | end
61 | end
62 | end
63 |
64 |
65 | end
66 | end
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/repo/update.rb:
--------------------------------------------------------------------------------
1 | require 'parallel'
2 |
3 | module Pod
4 | class Command
5 | class Bin < Command
6 | class Repo < Bin
7 | class Update < Repo
8 | self.summary = '更新私有源'
9 |
10 | self.arguments = [
11 | CLAide::Argument.new('NAME', false)
12 | ]
13 |
14 | def self.options
15 | [
16 | ['--all', '更新所有私有源,默认只更新二进制相关私有源']
17 | ].concat(super)
18 | end
19 |
20 | def initialize(argv)
21 | @all = argv.flag?('all')
22 | @name = argv.shift_argument
23 | super
24 | end
25 |
26 | def run
27 | show_output = !config.silent?
28 | if @name || @all
29 | config.sources_manager.update(@name, show_output)
30 | else
31 | Parallel.each(valid_sources, in_threads: 4) do |source|
32 | UI.puts "更新私有源仓库 #{source.to_s}".yellow
33 | source.update(show_output)
34 | end
35 | end
36 | end
37 |
38 |
39 | end
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/spec/create.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/helpers'
2 |
3 | module Pod
4 | class Command
5 | class Bin < Command
6 | class Spec < Bin
7 | class Create < Spec
8 | self.summary = '创建二进制 spec.'
9 | self.description = <<-DESC
10 | 根据源码 podspec 文件,创建对应的二进制 podspec 文件.
11 | DESC
12 |
13 | def self.options
14 | [
15 | ['--platforms=ios', '生成二进制 spec 支持的平台'],
16 | ['--template-podspec=A.binary-template.podspec', '生成拥有 subspec 的二进制 spec 需要的模版 podspec, 插件会更改 version 和 source'],
17 | ['--no-overwrite', '不允许覆盖']
18 | ].concat(super)
19 | end
20 |
21 | def initialize(argv)
22 | @platforms = argv.option('platforms', 'ios')
23 | @allow_overwrite = argv.flag?('overwrite', true)
24 | @template_podspec = argv.option('template-podspec')
25 | @podspec = argv.shift_argument
26 | super
27 | end
28 |
29 | def run
30 | UI.puts "开始读取 podspec 文件...\n"
31 |
32 | code_spec = Pod::Specification.from_file(spec_file)
33 | if template_spec_file
34 | template_spec = Pod::Specification.from_file(template_spec_file)
35 | end
36 |
37 | if binary_spec && !@allow_overwrite
38 | UI.warn "二进制 podspec 文件 #{binary_spec_files.first} 已存在.\n"
39 | else
40 | UI.puts "开始生成二进制 podspec 文件...\n"
41 | spec_file = create_binary_spec_file(code_spec, template_spec)
42 | UI.puts "创建二进制 podspec 文件 #{spec_file} 成功.\n".green
43 | end
44 | end
45 |
46 | def template_spec_file
47 | @template_spec_file ||= begin
48 | if @template_podspec
49 | find_spec_file(@template_podspec)
50 | else
51 | binary_template_spec_file
52 | end
53 | end
54 | end
55 |
56 | def spec_file
57 | @spec_file ||= begin
58 | if @podspec
59 | find_spec_file(@podspec)
60 | else
61 | if code_spec_files.empty?
62 | raise Informative, '当前目录下没有找到可用源码 podspec.'
63 | end
64 |
65 | code_spec_files.first
66 | end
67 | end
68 | end
69 | end
70 | end
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/spec/push.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/config/config'
2 | require 'cocoapods-imy-bin/native/podfile'
3 |
4 | module Pod
5 | class Command
6 | class Bin < Command
7 | class Repo < Bin
8 | class Push < Repo
9 | self.summary = '发布组件.'
10 | self.description = <<-DESC
11 | 发布二进制组件 / 源码组件
12 | DESC
13 |
14 | self.arguments = [
15 | CLAide::Argument.new('NAME.podspec', false)
16 | ]
17 |
18 | def self.options
19 | [
20 | ['--binary', '发布组件的二进制版本'],
21 | ['--template-podspec=A.binary-template.podspec', '生成拥有 subspec 的二进制 spec 需要的模版 podspec, 插件会更改 version 和 source'],
22 | ['--reserve-created-spec', '保留生成的二进制 spec 文件'],
23 | ['--code-dependencies', '使用源码依赖进行 lint'],
24 | ['--loose-options', '添加宽松的 options, 包括 --use-libraries (可能会造成 entry point (start) undefined)'],
25 | ['--allow-prerelease', '允许使用 prerelease 的版本 lint']
26 | ].concat(Pod::Command::Repo::Push.options).concat(super).uniq
27 | end
28 |
29 | def initialize(argv)
30 | @podspec = argv.shift_argument
31 | @binary = argv.flag?('binary')
32 | @loose_options = argv.flag?('loose-options')
33 | @code_dependencies = argv.flag?('code-dependencies')
34 | @sources = argv.option('sources') || []
35 | @reserve_created_spec = argv.flag?('reserve-created-spec')
36 | @template_podspec = argv.option('template-podspec')
37 | @allow_prerelease = argv.flag?('allow-prerelease')
38 | super
39 |
40 | @additional_args = argv.remainder!
41 | end
42 |
43 | def run
44 | Podfile.execute_with_bin_plugin do
45 | Podfile.execute_with_allow_prerelease(@allow_prerelease) do
46 | Podfile.execute_with_use_binaries(!@code_dependencies) do
47 | argvs = [
48 | repo,
49 | "--sources=#{sources_option(@code_dependencies, @sources)}",
50 | *@additional_args
51 | ]
52 |
53 | argvs << spec_file if spec_file
54 |
55 | if @loose_options
56 | argvs += ['--allow-warnings', '--use-json']
57 | if code_spec&.all_dependencies&.any?
58 | argvs << '--use-libraries'
59 | end
60 | end
61 |
62 | push = Pod::Command::Repo::Push.new(CLAide::ARGV.new(argvs))
63 | push.validate!
64 | push.run
65 | end
66 | end
67 | end
68 | ensure
69 | clear_binary_spec_file_if_needed unless @reserve_created_spec
70 | end
71 |
72 | private
73 |
74 | def template_spec_file
75 | @template_spec_file ||= begin
76 | if @template_podspec
77 | find_spec_file(@template_podspec)
78 | else
79 | binary_template_spec_file
80 | end
81 | end
82 | end
83 |
84 | def spec_file
85 | @spec_file ||= begin
86 | if @podspec
87 | find_spec_file(@podspec)
88 | else
89 | if code_spec_files.empty?
90 | raise Informative, '当前目录下没有找到可用源码 podspec.'
91 | end
92 |
93 | spec_file = if @binary
94 | code_spec = Pod::Specification.from_file(code_spec_files.first)
95 | if template_spec_file
96 | template_spec = Pod::Specification.from_file(template_spec_file)
97 | end
98 | create_binary_spec_file(code_spec, template_spec)
99 | else
100 | code_spec_files.first
101 | end
102 | spec_file
103 | end
104 | end
105 | end
106 |
107 | def repo
108 | @binary ? binary_source.name : code_source.name
109 | end
110 | end
111 | end
112 | end
113 | end
114 | end
115 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/command/bin/update.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'cocoapods'
3 | require 'cocoapods-imy-bin/native/podfile_env'
4 | require 'cocoapods-imy-bin/native/podfile'
5 |
6 | module Pod
7 | class Command
8 | class Bin < Command
9 | class Update < Bin
10 | include Pod
11 | include Pod::Podfile::DSL
12 |
13 | self.summary = 'pod update 拦截器,会加载本地Podfile_local文件,DSL加载到原始Podfile文件中。'
14 |
15 | self.description = <<-DESC
16 | pod update 拦截器,会加载本地Podfile_local文件
17 | 会通过DSL加载到原始Podfile文件中
18 | 支持 pod 'xxx' 各种写法
19 | 支持 post_install/pre_install钩子,采用覆盖做法
20 | DESC
21 | def self.options
22 | [
23 | ["--sources=#{Pod::TrunkSource::TRUNK_REPO_URL}", 'The sources from which to update dependent pods. ' \
24 | 'Multiple sources must be comma-delimited'],
25 | ['--exclude-pods=podName', 'Pods to exclude during update. Multiple pods must be comma-delimited'],
26 | ['--clean-install', 'Ignore the contents of the project cache and force a full pod installation. This only ' \
27 | 'applies to projects that have enabled incremental installation'],
28 | ['--project-directory=/project/dir/', 'The path to the root of the project directory'],
29 | ['--no-repo-update', 'Skip running `pod repo update` before install']
30 | ].concat(super)
31 | end
32 |
33 | def initialize(argv)
34 | @update = argv.flag?('update')
35 | super
36 | @additional_args = argv.remainder!
37 | end
38 |
39 | def run
40 | Update.load_local_podfile
41 |
42 | argvs = [
43 | *@additional_args
44 | ]
45 |
46 | gen = Pod::Command::Update.new(CLAide::ARGV.new(argvs))
47 | gen.validate!
48 | gen.run
49 | end
50 |
51 | def self.load_local_podfile
52 | # 同步 Podfile_local 文件
53 | project_root = Pod::Config.instance.project_root
54 | path = File.join(project_root.to_s, 'Podfile_local')
55 | unless File.exist?(path)
56 | path = File.join(project_root.to_s, 'Podfile_local')
57 | end
58 |
59 | if File.exist?(path)
60 | contents = File.open(path, 'r:utf-8', &:read)
61 |
62 | podfile = Pod::Config.instance.podfile
63 | local_podfile = Podfile.from_file(path)
64 |
65 | if local_podfile
66 | local_pre_install_callback = nil
67 | local_post_install_callback = nil
68 | local_podfile.instance_eval do
69 | local_pre_install_callback = @pre_install_callback
70 | local_post_install_callback = @post_install_callback
71 | end
72 | end
73 |
74 | podfile.instance_eval do
75 | begin
76 |
77 | # podfile HASH_KEYS才有plugins字段,否则会被限制
78 | if local_podfile.plugins.any?
79 | hash_plugins = podfile.plugins || {}
80 | hash_plugins = hash_plugins.merge(local_podfile.plugins)
81 | set_hash_value(%w[plugins].first, hash_plugins)
82 |
83 | # 加入源码白名单,避免本地库被二进制了
84 | podfile.set_use_source_pods(local_podfile.use_source_pods) if local_podfile.use_source_pods
85 | podfile.use_binaries!(local_podfile.use_binaries?)
86 | end
87 |
88 | # 在target把local-target中到dependencies值删除了,再设置
89 | # 把本地和原始到dependencies 合并,设置dependencies
90 | local_podfile&.target_definition_list&.each do |local_target|
91 | next if local_target.name == 'Pods'
92 |
93 | target_definition_list.each do |target|
94 |
95 | unless target.name == local_target.name &&
96 | (local_target.to_hash['dependencies'] &&local_target.to_hash['dependencies'].any?)
97 | next
98 | end
99 |
100 |
101 |
102 | target.instance_exec do
103 | # 在target把local-target中到dependencies值删除了,再设置
104 |
105 | local_dependencies = local_target.to_hash['dependencies']
106 | target_dependencies = target.to_hash['dependencies']
107 |
108 | local_dependencies.each do |local_dependency|
109 | unless local_dependency.is_a?(Hash) && local_dependency.keys.first
110 | next
111 | end
112 |
113 | target_dependencies.each do |target_dependency|
114 | dp_hash_equal = target_dependency.is_a?(Hash) &&
115 | target_dependency.keys.first &&
116 | target_dependency.keys.first == local_dependency.keys.first
117 | dp_str_equal = target_dependency.is_a?(String) &&
118 | target_dependency == local_dependency.keys.first
119 | next unless dp_hash_equal || dp_str_equal
120 |
121 | target_dependencies.delete target_dependency
122 | break
123 | end
124 | end
125 | # 把本地和原始到dependencies 合并,设置dependencies
126 | local_dependencies.each do |d|
127 | UI.message "Development Pod #{d.to_yaml}"
128 | if podfile.plugins.keys.include?('cocoapods-imy-bin')
129 | podfile.set_use_source_pods(d.keys.first) if (d.is_a?(Hash) && d.keys.first)
130 | end
131 | end
132 | new_dependencies = target_dependencies + local_dependencies
133 | set_hash_value(%w[dependencies].first, new_dependencies)
134 |
135 | end
136 | end
137 |
138 | end
139 |
140 | if local_pre_install_callback
141 | @pre_install_callback = local_pre_install_callback
142 | end
143 | if local_post_install_callback
144 | @post_install_callback = local_post_install_callback
145 | end
146 | rescue Exception => e
147 | message = "Invalid `#{path}` file: #{e.message}"
148 | raise Pod::DSLError.new(message, path, e, contents)
149 | end
150 | end
151 |
152 | end
153 | end
154 | end
155 | end
156 | end
157 | end
158 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/config/config.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 | require 'cocoapods-imy-bin/native/podfile'
3 | require 'cocoapods-imy-bin/native/podfile_env'
4 | require 'cocoapods/generate'
5 |
6 | module CBin
7 | class Config
8 | def config_file
9 | config_file_with_configuration_env(configuration_env)
10 | end
11 |
12 | def template_hash
13 | {
14 | 'configuration_env' => { description: '编译环境', default: 'dev', selection: %w[dev debug_iphoneos release_iphoneos] },
15 | 'code_repo_url' => { description: '源码私有源 Git 地址', default: 'git@github.com:su350380433/example_spec_source.git' },
16 | 'binary_repo_url' => { description: '二进制私有源 Git 地址', default: 'git@github.com:su350380433/example_spec_bin_dev.git' },
17 | 'binary_download_url' => { description: '二进制下载地址,内部会依次传入组件名称与版本,替换字符串中的 %s ', default: 'http://localhost:8080/frameworks/%s/%s/zip' },
18 | # 'binary_type' => { description: '二进制打包类型', default: 'framework', selection: %w[framework library] },
19 | 'download_file_type' => { description: '下载二进制文件类型', default: 'zip', selection: %w[zip tgz tar tbz txz dmg] }
20 | }
21 | end
22 |
23 | def config_file_with_configuration_env(configuration_env)
24 | file = config_dev_file
25 | if configuration_env == "release_iphoneos"
26 | file = config_release_iphoneos_file
27 | puts "\n====== #{configuration_env} 环境 ========"
28 | elsif configuration_env == "debug_iphoneos"
29 | file = config_debug_iphoneos_file
30 | puts "\n====== #{configuration_env} 环境 ========"
31 | elsif configuration_env == "dev"
32 | puts "\n====== #{configuration_env} 环境 ========"
33 | else
34 | raise "\n===== #{configuration_env} 参数有误,请检查%w[dev debug_iphoneos release_iphoneos]===="
35 | end
36 |
37 | File.expand_path("#{Pod::Config.instance.home_dir}/#{file}")
38 | end
39 |
40 | def configuration_env
41 | #如果是dev 再去 podfile的配置文件中获取,确保是正确的, pod update时会用到
42 | if @configuration_env == "dev" || @configuration_env == nil
43 | if Pod::Config.instance.podfile
44 | configuration_env ||= Pod::Config.instance.podfile.configuration_env
45 | end
46 | configuration_env ||= "dev"
47 | @configuration_env = configuration_env
48 | end
49 | @configuration_env
50 | end
51 |
52 | #上传的url
53 | def binary_upload_url
54 | cut_string = "/%s/%s/zip"
55 | binary_download_url[0,binary_download_url.length - cut_string.length]
56 | end
57 |
58 | def set_configuration_env(env)
59 | @configuration_env = env
60 | end
61 |
62 | #包含arm64 armv7架构,xcodebuild 是Debug模式
63 | def config_debug_iphoneos_file
64 | "bin_debug_iphoneos.yml"
65 | end
66 | #包含arm64 armv7架构,xcodebuild 是Release模式
67 | def config_release_iphoneos_file
68 | "bin_release_iphoneos.yml"
69 | end
70 | #包含x86 arm64 armv7架构,xcodebuild 是Release模式
71 | def config_dev_file
72 | "bin_dev.yml"
73 | end
74 |
75 | def sync_config(config)
76 | File.open(config_file_with_configuration_env(config['configuration_env']), 'w+') do |f|
77 | f.write(config.to_yaml)
78 | end
79 | end
80 |
81 | def default_config
82 | @default_config ||= Hash[template_hash.map { |k, v| [k, v[:default]] }]
83 | end
84 |
85 | private
86 |
87 | def load_config
88 | if File.exist?(config_file)
89 | YAML.load_file(config_file)
90 | else
91 | default_config
92 | end
93 | end
94 |
95 | def config
96 | @config ||= begin
97 | puts "====== cocoapods-imy-bin #{CBin::VERSION} 版本 ======== \n"
98 | @config = OpenStruct.new load_config
99 | validate!
100 | @config
101 | end
102 | end
103 |
104 | def validate!
105 | template_hash.each do |k, v|
106 | selection = v[:selection]
107 | next if !selection || selection.empty?
108 |
109 | config_value = @config.send(k)
110 | next unless config_value
111 | unless selection.include?(config_value)
112 | raise Pod::Informative, "#{k} 字段的值必须限定在可选值 [ #{selection.join(' / ')} ] 内".red
113 | end
114 | end
115 | end
116 |
117 | def respond_to_missing?(method, include_private = false)
118 | config.respond_to?(method) || super
119 | end
120 |
121 | def method_missing(method, *args, &block)
122 | if config.respond_to?(method)
123 | config.send(method, *args)
124 | elsif template_hash.keys.include?(method.to_s)
125 | raise Pod::Informative, "#{method} 字段必须在配置文件 #{config_file} 中设置, 请执行 init 命令配置或手动修改配置文件".red
126 | else
127 | super
128 | end
129 | end
130 | end
131 |
132 | def self.config
133 | @config ||= Config.new
134 | end
135 |
136 |
137 | end
138 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/config/config_asker.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 | require 'cocoapods-imy-bin/config/config'
3 |
4 | module CBin
5 | class Config
6 | class Asker
7 | def show_prompt
8 | print ' > '.green
9 | end
10 |
11 | def ask_with_answer(question, pre_answer, selection)
12 | print "\n#{question}\n"
13 |
14 | print_selection_info = lambda {
15 | print "可选值:[ #{selection.join(' / ')} ]\n" if selection
16 | }
17 | print_selection_info.call
18 | print "旧值:#{pre_answer}\n" unless pre_answer.nil?
19 |
20 | answer = ''
21 | loop do
22 | show_prompt
23 | answer = STDIN.gets.chomp.strip
24 |
25 | if answer == '' && !pre_answer.nil?
26 | answer = pre_answer
27 | print answer.yellow
28 | print "\n"
29 | end
30 |
31 | next if answer.empty?
32 | break if !selection || selection.include?(answer)
33 |
34 | print_selection_info.call
35 | end
36 |
37 | answer
38 | end
39 |
40 | def wellcome_message
41 | print <<~EOF
42 |
43 | 开始设置二进制化初始信息.
44 | 所有的信息都会保存在 #{CBin.config.config_file} 文件中.
45 | %w[bin_dev.yml bin_debug_iphoneos.yml bin_release_iphoneos.yml]
46 | 你可以在对应目录下手动添加编辑该文件. 文件包含的配置信息样式如下:
47 |
48 | #{CBin.config.default_config.to_yaml}
49 | EOF
50 | end
51 |
52 | def done_message
53 | print "\n设置完成.\n".green
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/config/config_builder.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 | module CBin
4 | class Config
5 | class Builder
6 |
7 | include Pod
8 |
9 | def self.instance
10 | @instance ||= new
11 | end
12 |
13 | def initialize
14 | load_build_config
15 | # clean
16 | end
17 |
18 | # 加载配置项
19 | def load_build_config
20 | @white_pod_list = []
21 | @ignore_git_list = []
22 | project_root = Pod::Config.instance.project_root
23 | path = File.join(project_root.to_s, 'BinArchive.json')
24 |
25 | if File.exist?(path)
26 | config = JSON.parse(File.read(path))
27 | @white_pod_list = config['archive-white-pod-list']
28 | UI.warn "====== archive-white-pod-list = #{@white_pod_list}" if @white_pod_list
29 | @ignore_git_list = config['ignore-git-list']
30 | UI.warn "====== ignore_git_list = #{@ignore_git_list}" if @ignore_git_list
31 | @ignore_http_list = config['ignore-http-list']
32 |
33 | @xcode_build_name = config['xcode_build_path']
34 | @root_dir = config['root_dir'] unless config['root_dir'].nil?
35 | end
36 |
37 | end
38 |
39 | def clean
40 | #清除之前的缓存
41 | FileUtils.rm_rf(Dir.glob("#{zip_dir}/*")) if File.exist?(zip_dir)
42 | FileUtils.rm_rf(Dir.glob("#{binary_json_dir}/*")) if File.exist?(binary_json_dir)
43 | FileUtils.rm_rf(Dir.glob("#{local_psec_dir}/*")) if File.exist?(local_psec_dir)
44 | end
45 |
46 | # 制作二进制打包 工程目录
47 | def gen_name
48 | 'bin-archive'
49 | end
50 |
51 | # 制作二进制打包 工程目录
52 | def gen_dir
53 | @gen_dir ||= begin
54 | dir = File.join(root_dir,gen_name)
55 | Dir.mkdir(dir) unless File.exist?dir
56 | Pathname.new(dir)
57 | end
58 | end
59 |
60 |
61 | def framework_name(spec)
62 | "#{spec.name}.framework"
63 | end
64 |
65 | def framework_name_version(spec)
66 | "#{spec.name}.framework_#{spec.version}"
67 | end
68 |
69 | def framework_zip_file(spec)
70 | File.join(zip_dir_name, framework_name_version(spec))
71 | end
72 |
73 | def framework_file(spec)
74 | File.join(zip_dir_name, framework_name(spec))
75 | end
76 |
77 | def library_name(spec)
78 | library_name_version(spec.name, spec.version)
79 | end
80 |
81 | def library_name_version(name,version)
82 | "bin_#{name}_#{version}"
83 | end
84 | def library_file(spec)
85 | File.join(zip_dir_name, library_name(spec))
86 | end
87 |
88 | def zip_dir_name
89 | "bin-zip"
90 | end
91 |
92 | def zip_dir
93 | @zip_dir ||= begin
94 | dir = File.join(root_dir,zip_dir_name)
95 | Dir.mkdir(dir) unless File.exist?dir
96 | Pathname.new(dir)
97 | end
98 | end
99 |
100 | #本地
101 | def local_spec_dir_name
102 | "bin-spec"
103 | end
104 |
105 | def local_psec_dir
106 | @local_psec_dir ||= begin
107 | dir = File.join(root_dir,local_spec_dir_name)
108 | Dir.mkdir(dir) unless File.exist?dir
109 | Pathname.new(dir)
110 | end
111 | end
112 |
113 | def binary_json_dir_name
114 | "bin-json"
115 | end
116 |
117 | def binary_json_dir
118 | @binary_json_dir ||= begin
119 | dir = File.join(root_dir,binary_json_dir_name)
120 | Dir.mkdir(dir) unless File.exist?dir
121 | Pathname.new(dir)
122 | end
123 | end
124 |
125 |
126 |
127 | #编译target名,如 seeyou
128 | def target_name
129 | @target_name ||= begin
130 | target_name_str = Pod::Config.instance.podfile.root_target_definitions.first.children.first.to_s
131 | target_name_str[5,target_name_str.length]
132 | end
133 | end
134 |
135 | #编译缓存文件目录,如Xcodebuild的编译缓存目录
136 | # 如果有配置, 配置完整路径,会使用
137 | def xcode_build_name
138 | @xcode_build_name ||= begin
139 | project_root = Pod::Config.instance.project_root
140 | path = File.join(project_root.to_s, 'BinArchive.json')
141 |
142 | if File.exist?(path)
143 | config = JSON.parse(File.read(path))
144 | @xcode_build_name = config['xcode_build_path']
145 | end
146 | #默认值,在美柚上使用默认
147 | if @xcode_build_name.nil? || Dir.exist?(@xcode_build_name)
148 | @xcode_build_name = "xcode-build/Build/Intermediates.noindex/ArchiveIntermediates/#{target_name}/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/"
149 | end
150 | puts @xcode_build_name
151 | @xcode_build_name
152 | end
153 | end
154 |
155 |
156 | #完整的xcodebuild 输出路径
157 | def xcode_build_dir
158 | @xcode_build_dir ||= begin
159 | temp_xcode_build_name = xcode_build_name
160 | if File.exist?(temp_xcode_build_name)
161 | Pathname.new(temp_xcode_build_name)
162 | else
163 | dir = File.join(root_dir,xcode_build_name)
164 | Pathname.new(dir)
165 | end
166 | end
167 | end
168 | #完整的xcodebuild BuildProductsPath输出路径,
169 | def xcode_BuildProductsPath_dir
170 | @xcode_BuildProductsPath_dir ||= begin
171 | temp_xcode_BuildProductsPath_dir = "xcode-build/Build/Intermediates.noindex/ArchiveIntermediates/#{target_name}/BuildProductsPath/"
172 | full_path = File.join(root_dir, temp_xcode_BuildProductsPath_dir)
173 |
174 | if (File.exist?(full_path))
175 | Dir.chdir(full_path) do
176 | iphoneos = Dir.glob('*-iphoneos')
177 | if iphoneos.length > 0
178 | full_path = File.join(full_path,iphoneos.first)
179 | else
180 | UI.warn "====== 找不到 *-iphoneos @xcode_BuildProductsPath_dir = #{@xcode_BuildProductsPath_dir}"
181 | end
182 | end
183 | end
184 | Pathname.new(full_path)
185 | end
186 | end
187 |
188 |
189 | #处理编译产物后存储根目录,会存放spec、 json、zip的父目录,默认是工程的同级目录下,"#{basename}-build-temp"
190 | def root_dir
191 | @root_dir ||= begin
192 | basename = File.basename(Pod::Config.instance.installation_root)
193 | parent_dir = File.dirname(Pod::Config.instance.installation_root)
194 | root_name = File.join(parent_dir,"#{basename}-build-temp")
195 | Dir.mkdir(root_name) unless File.exist?root_name
196 | Pathname.new(root_name)
197 | end
198 |
199 | end
200 |
201 | #制作二进制 白名单
202 | def white_pod_list
203 | @white_pod_list
204 | end
205 | #忽略制作二进制组件的 git
206 | def ignore_git_list
207 | @ignore_git_list
208 | end
209 |
210 | def ignore_http_list
211 | @ignore_http_list
212 | end
213 |
214 | end
215 | end
216 | end
217 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/config/config_hot_key.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 | require 'cocoapods-imy-bin/native/podfile'
3 | require 'cocoapods-imy-bin/native/podfile_env'
4 | require 'cocoapods/generate'
5 |
6 | module CBin
7 | class Config_Hot_Key
8 |
9 | def config_file
10 | config_file_with_hot_key_index(hot_key_index)
11 | end
12 |
13 | def template_hash
14 | {
15 | 'hot_key_index' => { description: '快捷键', default: '1', selection: %w[1 2 3...] },
16 | 'hot_key_dir' => { description: '快捷键执行目录', default: '' },
17 | 'hot_key_cmd' => { description: '快捷键执行命令', default: 'pod bin update --no-repo-update' }
18 | }
19 | end
20 |
21 | def config_file_with_hot_key_index(hot_key_index)
22 | file = config_file_whith_hot_key_index(hot_key_index)
23 | raise "\n===== #{hot_key_index} 参数有误,请检查%w[1 2 3...]===" unless (hot_key_index.to_i).is_a?(Integer)
24 | File.expand_path("#{Pod::Config.instance.home_dir}/#{file}")
25 | end
26 |
27 | def hot_key_index
28 | @hot_key_index = 1 if @hot_key_index.is_a?(NilClass)
29 | @hot_key_index
30 | end
31 |
32 | def set_hot_key_index(hot_key_index)
33 | @hot_key_index = hot_key_index
34 | end
35 |
36 | def config_file_whith_hot_key_index(hot_key_index)
37 | "hot_key_#{hot_key_index}.yml"
38 | end
39 |
40 | def sync_config(config)
41 | File.open(config_file_with_hot_key_index(config['hot_key_index']), 'w+') do |f|
42 | f.write(config.to_yaml)
43 | end
44 | end
45 |
46 | def default_config
47 | @default_config ||= Hash[template_hash.map { |k, v| [k, v[:default]] }]
48 | end
49 |
50 | private
51 |
52 | def load_config
53 | file = config_file
54 | if (!file.nil?) && File.exist?(config_file)
55 | YAML.load_file(config_file)
56 | else
57 | default_config
58 | end
59 | end
60 |
61 | def config
62 | @config ||= begin
63 | puts "====== cocoapods-imy-bin #{CBin::VERSION} 版本 ======== \n"
64 | @config = OpenStruct.new load_config
65 | validate!
66 | @config
67 | end
68 | end
69 |
70 | def validate!
71 | template_hash.each do |k, v|
72 | selection = v[:selection]
73 | next if !selection || selection.empty?
74 |
75 | config_value = @config.send(k)
76 | next unless config_value
77 | unless selection.include?(config_value)
78 | raise Pod::Informative, "#{k} 字段的值必须限定在可选值 [ #{selection.join(' / ')} ] 内".red
79 | end
80 | end
81 | end
82 |
83 | def respond_to_missing?(method, include_private = false)
84 | config.respond_to?(method) || super
85 | end
86 |
87 | def method_missing(method, *args, &block)
88 | if config.respond_to?(method)
89 | config.send(method, *args)
90 | elsif template_hash.keys.include?(method.to_s)
91 | raise Pod::Informative, "#{method} 字段必须在配置文件 #{config_file} 中设置, 请执行 init 命令配置或手动修改配置文件".red
92 | else
93 | super
94 | end
95 | end
96 | end
97 |
98 | def self.config_hot_key
99 | @config_hot_key ||= Config_Hot_Key.new
100 | end
101 |
102 | end
103 |
104 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/config/config_hot_key_asker.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 | require 'cocoapods-imy-bin/config/config_hot_key'
3 |
4 | module CBin
5 | class Config_Hot_Key
6 | class Asker
7 | def show_prompt
8 | print ' > '.green
9 | end
10 |
11 | def ask_with_answer(question, pre_answer, selection)
12 | print "\n#{question}\n"
13 |
14 | print_selection_info = lambda {
15 | print "可选值:[ #{selection.join(' / ')} ]\n" if selection
16 | }
17 | print_selection_info.call
18 | print "旧值:#{pre_answer}\n" unless pre_answer.nil?
19 |
20 | answer = ''
21 | loop do
22 | show_prompt
23 | answer = STDIN.gets.chomp.strip
24 |
25 | if answer == '' && !pre_answer.nil?
26 | answer = pre_answer
27 | print answer.yellow
28 | print "\n"
29 | end
30 |
31 | next if answer.empty?
32 | break if !selection || selection.include?(answer)
33 |
34 | print_selection_info.call
35 | end
36 |
37 | answer
38 | end
39 |
40 | def wellcome_message
41 | print <<~EOF
42 |
43 | 开始设置快捷键 pod bin imy.
44 | 所有的信息都会保存在 #{CBin.config_hot_key.config_file} 文件中.
45 | %w[hot_key.yaml]
46 | 你可以在对应目录下手动添加编辑该文件. 文件包含的配置信息样式如下:
47 |
48 | #{CBin.config_hot_key.default_config.to_yaml}
49 | EOF
50 | end
51 |
52 | def done_message
53 | print "\n设置完成.\n".green
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/gem_version.rb:
--------------------------------------------------------------------------------
1 |
2 | module CBin
3 | VERSION = '0.3.1.2'
4 | end
5 |
6 | module Pod
7 | def self.match_version?(*version)
8 | Gem::Dependency.new('', *version).match?('', Pod::VERSION)
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/helpers/sources_helper'
2 | require 'cocoapods-imy-bin/helpers/spec_creator'
3 | require 'cocoapods-imy-bin/helpers/spec_files_helper'
4 | require 'cocoapods-imy-bin/helpers/spec_source_creator'
5 | require 'cocoapods-imy-bin/helpers/build_utils'
6 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetYouDevs/cocoapods-imy-bin/36b201004ea3610e3278429c48d3cf49b4b650d2/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/Info.plist
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/build_helper.rb:
--------------------------------------------------------------------------------
1 | # copy from https://github.com/CocoaPods/cocoapods-packager
2 |
3 | require 'cocoapods-imy-bin/native/podfile'
4 | require 'cocoapods/command/gen'
5 | require 'cocoapods/generate'
6 | require 'cocoapods-imy-bin/helpers/framework_builder'
7 | require 'cocoapods-imy-bin/helpers/library_builder'
8 | require 'cocoapods-imy-bin/config/config_builder'
9 |
10 | module CBin
11 | class Build
12 | class Helper
13 | include Pod
14 | #class var
15 | @@build_defines = ""
16 | #Debug下还待完成
17 | def initialize(spec,
18 | platform,
19 | framework_output,
20 | zip,
21 | rootSpec,
22 | skip_archive = false,
23 | build_model="Release")
24 | @spec = spec
25 | @platform = platform
26 | @build_model = build_model
27 | @rootSpec = rootSpec
28 | @isRootSpec = rootSpec.name == spec.name
29 | @skip_archive = skip_archive
30 | @framework_output = framework_output
31 | @zip = zip
32 |
33 | @framework_path
34 | end
35 |
36 | def build
37 | UI.section("Building static framework #{@spec}") do
38 |
39 | build_static_framework
40 | unless @skip_archive
41 | unless CBin::Build::Utils.is_framework(@spec)
42 | build_static_library
43 | zip_static_library
44 | else
45 | zip_static_framework
46 | end
47 | end
48 |
49 | end
50 |
51 | end
52 |
53 | def build_static_framework
54 | source_dir = Dir.pwd
55 | file_accessor = Sandbox::FileAccessor.new(Pathname.new('.').expand_path, @spec.consumer(@platform))
56 | Dir.chdir(workspace_directory) do
57 | builder = CBin::Framework::Builder.new(@spec, file_accessor, @platform, source_dir, @isRootSpec, @build_model )
58 | @@build_defines = builder.build if @isRootSpec
59 | begin
60 | @framework_path = builder.lipo_build(@@build_defines) unless @skip_archive
61 | rescue
62 | @skip_archive = true
63 | end
64 | end
65 | end
66 |
67 | def build_static_library
68 | source_dir = zip_dir
69 | file_accessor = Sandbox::FileAccessor.new(Pathname.new('.').expand_path, @spec.consumer(@platform))
70 | Dir.chdir(workspace_directory) do
71 | builder = CBin::Library::Builder.new(@spec, file_accessor, @platform, source_dir,@framework_path)
72 | builder.build
73 | end
74 | end
75 |
76 | def zip_static_framework
77 | Dir.chdir(File.join(workspace_directory,@framework_path.root_path)) do
78 | output_name = File.join(zip_dir, framework_name_zip)
79 | unless File.exist?(framework_name)
80 | UI.puts "没有需要压缩的 framework 文件:#{framework_name}"
81 | return
82 | end
83 |
84 | UI.puts "Compressing #{framework_name} into #{output_name}"
85 | `zip --symlinks -r #{output_name} #{framework_name}`
86 | end
87 | end
88 |
89 | def zip_static_library
90 | Dir.chdir(zip_dir) do
91 | output_library = "#{library_name}.zip"
92 | unless File.exist?(library_name)
93 | raise Informative, "没有需要压缩的 library 文件:#{library_name}"
94 | end
95 |
96 | UI.puts "Compressing #{library_name} into #{output_library}"
97 |
98 | `zip --symlinks -r #{output_library} #{library_name}`
99 | end
100 |
101 | end
102 |
103 |
104 | def clean_workspace
105 | UI.puts 'Cleaning workspace'
106 |
107 | FileUtils.rm_rf(gen_name)
108 | Dir.chdir(zip_dir) do
109 | FileUtils.rm_rf(framework_name) if @zip
110 | FileUtils.rm_rf(library_name)
111 | FileUtils.rm_rf(framework_name) unless @framework_output
112 | FileUtils.rm_rf("#{framework_name}.zip") unless @framework_output
113 | end
114 | end
115 |
116 | def framework_name
117 | CBin::Config::Builder.instance.framework_name(@spec)
118 | end
119 |
120 | def framework_name_zip
121 | CBin::Config::Builder.instance.framework_name_version(@spec) + ".zip"
122 | end
123 |
124 | def library_name
125 | CBin::Config::Builder.instance.library_name(@spec)
126 | end
127 |
128 | def workspace_directory
129 | File.expand_path("#{gen_name}/#{@rootSpec.name}")
130 | end
131 |
132 | def zip_dir
133 | CBin::Config::Builder.instance.zip_dir
134 | end
135 |
136 | def gen_name
137 | CBin::Config::Builder.instance.gen_dir
138 | end
139 |
140 |
141 | def spec_file
142 | @spec_file ||= begin
143 | if @podspec
144 | find_spec_file(@podspec)
145 | else
146 | if code_spec_files.empty?
147 | raise Informative, '当前目录下没有找到可用源码 podspec.'
148 | end
149 |
150 | spec_file = code_spec_files.first
151 | spec_file
152 | end
153 | end
154 | end
155 |
156 | end
157 | end
158 | end
159 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/build_utils.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 | require 'cocoapods-imy-bin/config/config'
3 |
4 | module CBin
5 | class Build
6 |
7 | class Utils
8 |
9 | def Utils.is_framework(spec)
10 | if Utils.uses_frameworks?
11 | return true
12 | end
13 |
14 | return Utils.is_swift_module(spec)
15 | end
16 |
17 | def Utils.spec_header_dir(spec)
18 |
19 | header_dir = "./Headers/Public/#{spec.name}"
20 | header_dir = "./Pods/Headers/Public/#{spec.name}" unless File.exist?(header_dir)
21 |
22 | unless File.exist?(header_dir)
23 | # 一些库名称中使用了中划线如AAA-BBB,public header中库名称会默认处理成下划线AAA_BBB
24 | module_name = spec.name.gsub("-", "_")
25 | header_dir = "./Pods/Headers/Public/#{module_name}"
26 | end
27 |
28 | # 暂时只支持:ios
29 | consumer = Pod::Specification::Consumer.new(spec, :ios)
30 | unless consumer.header_dir.nil?
31 | header_dir = File.join(header_dir, consumer.header_dir)
32 | end
33 |
34 | header_dir
35 | end
36 |
37 | def Utils.spec_module_dir(spec)
38 | if spec.module_name.nil?
39 | module_dir = "./Headers/Public/#{spec.name}"
40 | module_dir = "./Pods/Headers/Public/#{spec.name}" unless File.exist?(module_dir)
41 | unless File.exist?(module_dir)
42 | # 一些库名称中使用了中划线如AAA-BBB,public header中库名称会默认处理成下划线AAA_BBB
43 | module_name = spec.name.gsub("-", "_")
44 | module_dir = "./Pods/Headers/Public/#{module_name}"
45 | end
46 | else
47 | module_dir = "./Headers/Public/#{spec.module_name}"
48 | module_dir = "./Pods/Headers/Public/#{spec.module_name}" unless File.exist?(module_dir)
49 | end
50 |
51 | module_dir
52 | end
53 |
54 | def Utils.is_swift_module(spec)
55 |
56 | is_framework = false
57 | dir = File.join(CBin::Config::Builder.instance.gen_dir, CBin::Config::Builder.instance.target_name)
58 | #auto 走这里
59 | if File.exist?(dir)
60 | Dir.chdir(dir) do
61 | spec_module_dir = Utils.spec_module_dir(spec)
62 | return false unless File.exist?(spec_module_dir)
63 | is_framework = File.exist?(File.join(spec_module_dir, "#{spec.name}-umbrella.h"))
64 | end
65 | end
66 |
67 | if $ARGV[1] == "local"
68 | is_framework = File.exist?(File.join(CBin::Config::Builder.instance.xcode_build_dir, "#{spec.name}.framework"))
69 | unless is_framework
70 | is_framework = File.exist?(File.join(CBin::Config::Builder.instance.xcode_BuildProductsPath_dir, "#{spec.name}","Swift Compatibility Header"))
71 | end
72 | end
73 |
74 | is_framework
75 | end
76 |
77 | def Utils.uses_frameworks?
78 | uses_frameworks = false
79 | Pod::Config.instance.podfile.target_definitions.each do |key,value|
80 | if key != "Pods"
81 | uses_frameworks = value.uses_frameworks?
82 | if uses_frameworks
83 | break ;
84 | end
85 | end
86 | end
87 |
88 | return uses_frameworks
89 | end
90 |
91 | end
92 |
93 | end
94 | end
95 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/framework.rb:
--------------------------------------------------------------------------------
1 | # copy from https://github.com/CocoaPods/cocoapods-packager
2 |
3 | module CBin
4 | class Framework
5 | attr_reader :headers_path
6 | attr_reader :module_map_path
7 | attr_reader :resources_path
8 | attr_reader :root_path
9 | attr_reader :versions_path
10 | attr_reader :swift_module_path
11 | attr_reader :fwk_path
12 |
13 | def initialize(name, platform)
14 | @name = name
15 | @platform = platform
16 | end
17 |
18 | def make
19 | make_root
20 | make_framework
21 | make_headers
22 | make_resources
23 | make_current_version
24 | end
25 |
26 | def delete_resources
27 | Pathname.new(@resources_path).rmtree if File.exist? (@resources_path)
28 | (Pathname.new(@fwk_path) + Pathname.new('Resources')).delete if File.exist?(Pathname.new(@fwk_path) + Pathname.new('Resources'))
29 | end
30 |
31 | def remove_current_version
32 | FileUtils.rm_f(File.join(@fwk_path,@name))
33 | FileUtils.rm_f(File.join(@fwk_path,"Headers"))
34 | FileUtils.rm_f(File.join(@fwk_path,"Resources"))
35 |
36 | FileUtils.cp_r("#{@versions_path}/.", @fwk_path)
37 | # FileUtils.remove_dir(@versions_path)
38 | FileUtils.remove_dir("#{@fwk_path}/Versions")
39 |
40 | # current_version_path = @versions_path + Pathname.new('../Current')
41 | # `ln -sf A #{current_version_path}`
42 | # `ln -sf Versions/Current/Headers #{@fwk_path}/`
43 | # `ln -sf Versions/Current/Resources #{@fwk_path}/`
44 | # `ln -sf Versions/Current/#{@name} #{@fwk_path}/`
45 | end
46 |
47 | private
48 |
49 | def make_current_version
50 | current_version_path = @versions_path + Pathname.new('../Current')
51 | `ln -sf A #{current_version_path}`
52 | `ln -sf Versions/Current/Headers #{@fwk_path}/`
53 | `ln -sf Versions/Current/Resources #{@fwk_path}/`
54 | `ln -sf Versions/Current/#{@name} #{@fwk_path}/`
55 | end
56 |
57 |
58 |
59 | def make_framework
60 | @fwk_path = @root_path + Pathname.new(@name + '.framework')
61 | @fwk_path.mkdir unless @fwk_path.exist?
62 |
63 | @module_map_path = @fwk_path + Pathname.new('Modules')
64 | @swift_module_path = @module_map_path + Pathname.new(@name + '.swiftmodule')
65 |
66 |
67 | @versions_path = @fwk_path + Pathname.new('Versions/A')
68 | end
69 |
70 | def make_headers
71 | @headers_path = @versions_path + Pathname.new('Headers')
72 | @headers_path.mkpath unless @headers_path.exist?
73 | end
74 |
75 | def make_resources
76 | @resources_path = @versions_path + Pathname.new('Resources')
77 | @resources_path.mkpath unless @resources_path.exist?
78 | end
79 |
80 | def make_root
81 | @root_path = Pathname.new(@platform)
82 | @root_path.mkpath unless @root_path.exist?
83 | end
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/framework_builder.rb:
--------------------------------------------------------------------------------
1 | # copy from https://github.com/CocoaPods/cocoapods-packager
2 |
3 | require 'cocoapods-imy-bin/helpers/framework.rb'
4 | require 'English'
5 | require 'cocoapods-imy-bin/config/config_builder'
6 | require 'shellwords'
7 |
8 | module CBin
9 | class Framework
10 | class Builder
11 | include Pod
12 | #Debug下还待完成
13 | def initialize(spec, file_accessor, platform, source_dir, isRootSpec = true, build_model="Debug")
14 | @spec = spec
15 | @source_dir = source_dir
16 | @file_accessor = file_accessor
17 | @platform = platform
18 | @build_model = build_model
19 | @isRootSpec = isRootSpec
20 | #vendored_static_frameworks 只有 xx.framework 需要拼接为 xx.framework/xx by slj
21 | vendored_static_frameworks = file_accessor.vendored_static_frameworks.map do |framework|
22 | path = framework
23 | extn = File.extname path
24 | if extn.downcase == '.framework'
25 | path = File.join(path,File.basename(path, extn))
26 | end
27 | path
28 | end
29 |
30 | @vendored_libraries = (vendored_static_frameworks + file_accessor.vendored_static_libraries).map(&:to_s)
31 | end
32 |
33 | def build
34 | defines = compile
35 | build_sim_libraries(defines)
36 |
37 | defines
38 | end
39 |
40 | def lipo_build(defines)
41 | UI.section("Building static Library #{@spec}") do
42 | # defines = compile
43 |
44 | # build_sim_libraries(defines)
45 | output = framework.versions_path + Pathname.new(@spec.name)
46 |
47 | build_static_library_for_ios(output)
48 |
49 | copy_headers
50 | copy_license
51 | copy_resources
52 |
53 | cp_to_source_dir
54 | end
55 | framework
56 | end
57 |
58 | private
59 |
60 | def cp_to_source_dir
61 | framework_name = "#{@spec.name}.framework"
62 | target_dir = File.join(CBin::Config::Builder.instance.zip_dir,framework_name)
63 | FileUtils.rm_rf(target_dir) if File.exist?(target_dir)
64 |
65 | zip_dir = CBin::Config::Builder.instance.zip_dir
66 | FileUtils.mkdir_p(zip_dir) unless File.exist?(zip_dir)
67 |
68 | `cp -fa #{@platform}/#{framework_name} #{target_dir}`
69 | end
70 |
71 | #模拟器,目前只支持 debug x86-64
72 | def build_sim_libraries(defines)
73 | UI.message 'Building simulator libraries'
74 |
75 | # archs = %w[i386 x86_64]
76 | archs = ios_architectures_sim
77 | archs.map do |arch|
78 | xcodebuild(defines, "-sdk iphonesimulator ARCHS=\'#{arch}\' ", "build-#{arch}",@build_model)
79 | end
80 |
81 | end
82 |
83 |
84 | def static_libs_in_sandbox(build_dir = 'build')
85 | file = Dir.glob("#{build_dir}/lib#{target_name}.a")
86 | unless file
87 | UI.warn "file no find = #{build_dir}/lib#{target_name}.a"
88 | end
89 | file
90 | end
91 |
92 | def build_static_library_for_ios(output)
93 | UI.message "Building ios libraries with archs #{ios_architectures}"
94 | static_libs = static_libs_in_sandbox('build') + static_libs_in_sandbox('build-simulator') + @vendored_libraries
95 | # if is_debug_model
96 | ios_architectures.map do |arch|
97 | static_libs += static_libs_in_sandbox("build-#{arch}") + @vendored_libraries
98 | end
99 | ios_architectures_sim do |arch|
100 | static_libs += static_libs_in_sandbox("build-#{arch}") + @vendored_libraries
101 | end
102 | # end
103 |
104 | build_path = Pathname("build")
105 | build_path.mkpath unless build_path.exist?
106 |
107 | # if is_debug_model
108 | libs = (ios_architectures + ios_architectures_sim) .map do |arch|
109 | library = "build-#{arch}/lib#{@spec.name}.a"
110 | library
111 | end
112 | # else
113 | # libs = ios_architectures.map do |arch|
114 | # library = "build/package-#{@spec.name}-#{arch}.a"
115 | # # libtool -arch_only arm64 -static -o build/package-armv64.a build/libIMYFoundation.a build-simulator/libIMYFoundation.a
116 | # # 从liBFoundation.a 文件中,提取出 arm64 架构的文件,命名为build/package-armv64.a
117 | # UI.message "libtool -arch_only #{arch} -static -o #{library} #{static_libs.join(' ')}"
118 | # `libtool -arch_only #{arch} -static -o #{library} #{static_libs.join(' ')}`
119 | # library
120 | # end
121 | # end
122 |
123 | UI.message "lipo -create -output #{output} #{libs.join(' ')}"
124 | `lipo -create -output #{output} #{libs.join(' ')}`
125 | end
126 |
127 | def ios_build_options
128 | "ARCHS=\'#{ios_architectures.join(' ')}\' OTHER_CFLAGS=\'-fembed-bitcode -Qunused-arguments\'"
129 | end
130 |
131 | def ios_architectures
132 | # >armv7
133 | # iPhone4
134 | # iPhone4S
135 | # >armv7s 去掉
136 | # iPhone5
137 | # iPhone5C
138 | # >arm64
139 | # iPhone5S(以上)
140 | # >i386
141 | # iphone5,iphone5s以下的模拟器
142 | # >x86_64
143 | # iphone6以上的模拟器
144 | archs = %w[arm64 armv7]
145 | # archs = %w[x86_64 arm64 armv7s i386]
146 | # @vendored_libraries.each do |library|
147 | # archs = `lipo -info #{library}`.split & archs
148 | # end
149 | archs
150 | end
151 |
152 | def ios_architectures_sim
153 |
154 | archs = %w[x86_64]
155 | # TODO 处理是否需要 i386
156 | archs
157 | end
158 |
159 | def compile
160 | defines = "GCC_PREPROCESSOR_DEFINITIONS='$(inherited)'"
161 | defines += ' '
162 | defines += @spec.consumer(@platform).compiler_flags.join(' ')
163 |
164 | options = ios_build_options
165 | # if is_debug_model
166 | archs = ios_architectures
167 | # archs = %w[arm64 armv7 armv7s]
168 | archs.map do |arch|
169 | xcodebuild(defines, "ARCHS=\'#{arch}\' OTHER_CFLAGS=\'-fembed-bitcode -Qunused-arguments\'","build-#{arch}",@build_model)
170 | end
171 | # else
172 | # xcodebuild(defines,options)
173 | # end
174 |
175 | defines
176 | end
177 |
178 | def is_debug_model
179 | @build_model == "Debug"
180 | end
181 |
182 | def target_name
183 | #区分多平台,如配置了多平台,会带上平台的名字
184 | # 如libwebp-iOS
185 | if @spec.available_platforms.count > 1
186 | "#{@spec.name}-#{Platform.string_name(@spec.consumer(@platform).platform_name)}"
187 | else
188 | @spec.name
189 | end
190 | end
191 |
192 | def xcodebuild(defines = '', args = '', build_dir = 'build', build_model = 'Debug')
193 |
194 | unless File.exist?("Pods.xcodeproj") #cocoapods-generate v2.0.0
195 | command = "xcodebuild #{defines} #{args} CONFIGURATION_BUILD_DIR=#{File.join(File.expand_path("..", build_dir), File.basename(build_dir))} clean build -configuration #{build_model} -target #{target_name} -project ./Pods/Pods.xcodeproj 2>&1"
196 | else
197 | command = "xcodebuild #{defines} #{args} CONFIGURATION_BUILD_DIR=#{build_dir} clean build -configuration #{build_model} -target #{target_name} -project ./Pods.xcodeproj 2>&1"
198 | end
199 |
200 | UI.message "command = #{command}"
201 | output = `#{command}`.lines.to_a
202 |
203 | if $CHILD_STATUS.exitstatus != 0
204 | raise <<~EOF
205 | Build command failed: #{command}
206 | Output:
207 | #{output.map { |line| " #{line}" }.join}
208 | EOF
209 |
210 | Process.exit
211 | end
212 | end
213 |
214 | def copy_headers
215 | #走 podsepc中的public_headers
216 | public_headers = Array.new
217 |
218 | #by slj 如果没有头文件,去 "Headers/Public"拿
219 | # if public_headers.empty?
220 | spec_header_dir = CBin::Build::Utils.spec_header_dir(@spec)
221 | raise "copy_headers #{spec_header_dir} no exist " unless File.exist?(spec_header_dir)
222 |
223 | Dir.chdir(spec_header_dir) do
224 | headers = Dir.glob('**/*.h')
225 | headers.each do |h|
226 | public_headers << Pathname.new(File.join(Dir.pwd,h))
227 | end
228 | end
229 | # end
230 |
231 | # UI.message "Copying public headers #{public_headers.map(&:basename).map(&:to_s)}"
232 |
233 | public_headers.each do |h|
234 | `ditto #{h} #{framework.headers_path}/#{h.basename}`
235 | end
236 |
237 | # If custom 'module_map' is specified add it to the framework distribution
238 | # otherwise check if a header exists that is equal to 'spec.name', if so
239 | # create a default 'module_map' one using it.
240 | if !@spec.module_map.nil?
241 | module_map_file = @file_accessor.module_map
242 | if Pathname(module_map_file).exist?
243 | module_map = File.read(module_map_file)
244 | end
245 | elsif public_headers.map(&:basename).map(&:to_s).include?("#{@spec.name}.h")
246 | module_map = <<-MAP
247 | framework module #{@spec.name} {
248 | umbrella header "#{@spec.name}.h"
249 |
250 | export *
251 | module * { export * }
252 | }
253 | MAP
254 | else
255 | # by ChildhoodAndy
256 | # try to read modulemap file from module dir
257 | module_map_file = File.join(CBin::Build::Utils.spec_module_dir(@spec), "#{@spec.name}.modulemap")
258 | if Pathname(module_map_file).exist?
259 | module_map = File.read(module_map_file)
260 | end
261 | end
262 |
263 | unless module_map.nil?
264 | UI.message "Writing module map #{module_map}"
265 | unless framework.module_map_path.exist?
266 | framework.module_map_path.mkpath
267 | end
268 | File.write("#{framework.module_map_path}/module.modulemap", module_map)
269 | end
270 | end
271 |
272 | def copy_license
273 | UI.message 'Copying license'
274 | license_file = @spec.license[:file] || 'LICENSE'
275 | `cp "#{license_file}" .` if Pathname(license_file).exist?
276 | end
277 |
278 | def copy_resources
279 | resource_dir = './build/*.bundle'
280 | resource_dir = './build-armv7/*.bundle' if File.exist?('./build-armv7')
281 | resource_dir = './build-arm64/*.bundle' if File.exist?('./build-arm64')
282 |
283 | bundles = Dir.glob(resource_dir)
284 |
285 | bundle_names = [@spec, *@spec.recursive_subspecs].flat_map do |spec|
286 | consumer = spec.consumer(@platform)
287 | consumer.resource_bundles.keys +
288 | consumer.resources.map do |r|
289 | File.basename(r, '.bundle') if File.extname(r) == 'bundle'
290 | end
291 | end.compact.uniq
292 |
293 | bundles.select! do |bundle|
294 | bundle_name = File.basename(bundle, '.bundle')
295 | bundle_names.include?(bundle_name)
296 | end
297 |
298 | if bundles.count > 0
299 | UI.message "Copying bundle files #{bundles}"
300 | bundle_files = bundles.join(' ')
301 | `cp -rp #{bundle_files} #{framework.resources_path} 2>&1`
302 | end
303 |
304 | real_source_dir = @source_dir
305 | unless @isRootSpec
306 | spec_source_dir = File.join(Dir.pwd,"#{@spec.name}")
307 | unless File.exist?(spec_source_dir)
308 | spec_source_dir = File.join(Dir.pwd,"Pods/#{@spec.name}")
309 | end
310 | raise "copy_resources #{spec_source_dir} no exist " unless File.exist?(spec_source_dir)
311 |
312 | real_source_dir = spec_source_dir
313 | end
314 | resources = [@spec, *@spec.recursive_subspecs].flat_map do |spec|
315 | expand_paths(real_source_dir, spec.consumer(@platform).resources)
316 | end.compact.uniq
317 |
318 | if resources.count == 0 && bundles.count == 0
319 | framework.delete_resources
320 | return
321 | end
322 |
323 | if resources.count > 0
324 | #把 路径转义。 避免空格情况下拷贝失败
325 | escape_resource = []
326 | resources.each do |source|
327 | escape_resource << Shellwords.join(source)
328 | end
329 | UI.message "Copying resources #{escape_resource}"
330 | `cp -rp #{escape_resource.join(' ')} #{framework.resources_path}`
331 | end
332 | end
333 |
334 | def expand_paths(source_dir, path_specs)
335 | path_specs.map do |path_spec|
336 | Dir.glob(File.join(source_dir, path_spec))
337 | end
338 | end
339 |
340 | def framework
341 | @framework ||= begin
342 | framework = Framework.new(@spec.name, @platform.name.to_s)
343 | framework.make
344 | framework
345 | end
346 | end
347 |
348 |
349 | end
350 | end
351 | end
352 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/library.rb:
--------------------------------------------------------------------------------
1 | # copy from https://github.com/CocoaPods/cocoapods-packager
2 |
3 | module CBin
4 | class Library
5 | attr_reader :headers_path
6 | attr_reader :resources_path
7 | attr_reader :root_path
8 | attr_reader :versions_path
9 | attr_reader :name_path
10 |
11 | def initialize(name, platform, version)
12 | @name = name
13 | @platform = platform
14 | @version = version
15 | end
16 |
17 | def make
18 | make_root
19 | make_library
20 | make_headers
21 | make_resources
22 | end
23 |
24 | def delete_resources
25 | Pathname.new(@resources_path).rmtree
26 | (Pathname.new(@fwk_path) + Pathname.new('Resources')).delete
27 | end
28 |
29 | private
30 |
31 | def make_library
32 | @name_path = CBin::Config::Builder.instance.library_name_version(@name,@version)
33 | @fwk_path = @root_path + Pathname.new(@name_path)
34 | @fwk_path.mkdir unless @fwk_path.exist?
35 |
36 | @versions_path = @fwk_path
37 | end
38 |
39 | def make_headers
40 | @headers_path = @versions_path + Pathname.new('Headers')
41 | @headers_path.mkpath unless @headers_path.exist?
42 | end
43 |
44 | def make_resources
45 | @resources_path = @versions_path + Pathname.new('Resources')
46 | @resources_path.mkpath unless @resources_path.exist?
47 | end
48 |
49 | def make_root
50 | @root_path = Pathname.new(@platform)
51 | @root_path.mkpath unless @root_path.exist?
52 | end
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/library_builder.rb:
--------------------------------------------------------------------------------
1 |
2 | # copy from https://github.com/CocoaPods/cocoapods-packager
3 |
4 | require 'cocoapods-imy-bin/helpers/framework.rb'
5 | require 'cocoapods-imy-bin/helpers/library.rb'
6 |
7 | require 'English'
8 |
9 | module CBin
10 | class Library
11 | class Builder
12 | include Pod
13 |
14 | def initialize(spec, file_accessor, platform, source_dir,framework_path)
15 | @spec = spec
16 | @source_dir = source_dir
17 | @file_accessor = file_accessor
18 | @platform = platform
19 | @framework = framework_path
20 | @source_files = "#{@source_dir}/#{library.name_path}"
21 | @source_zip_file = "#{@source_files}.zip"
22 | end
23 |
24 | def build
25 | UI.section("Building static library #{@spec}") do
26 |
27 | clean_source_dir
28 |
29 | copy_headers
30 | copy_library
31 | copy_resources
32 |
33 | cp_to_source_dir
34 | end
35 | end
36 |
37 | private
38 |
39 | def clean_source_dir
40 | FileUtils.rm_rf(@source_files) if File.exist?(@source_files)
41 | FileUtils.rm_rf(@source_zip_file) if File.exist?(@source_zip_file)
42 | end
43 |
44 | def cp_to_source_dir
45 | target_dir = library.versions_path
46 | dest_file = "#{@source_dir}/#{library.name_path}"
47 | FileUtils.rm_rf(dest_file) if File.exist?(dest_file)
48 |
49 | `cp -fa #{target_dir} #{dest_file}/`
50 | end
51 |
52 | def copy_headers
53 | FileUtils.cp_r(framework.headers_path,library.versions_path) if File.exist?(framework.headers_path)
54 | end
55 |
56 | def copy_library
57 | src_file = "#{framework.versions_path}/#{@spec.name}"
58 | unless File.exist?(src_file)
59 | raise Informative, "framework没有文件:#{src_file}"
60 | end
61 |
62 | dest_file = "#{library.versions_path}/#{@spec.name}"
63 | rename_dest_file = "#{library.versions_path}/lib#{@spec.name}.a"
64 | FileUtils.cp_r(src_file,dest_file)
65 | File.rename(dest_file, rename_dest_file ) if File.exist?(dest_file)
66 | end
67 |
68 | def copy_resources
69 | FileUtils.cp_r(framework.resources_path,library.versions_path) if File.exist?(framework.resources_path)
70 | end
71 |
72 |
73 | def framework
74 | @framework ||= begin
75 | framework = Framework.new(@spec.name, @platform.name.to_s)
76 | framework.make
77 | framework
78 | end
79 | end
80 |
81 | def library
82 | @library ||= begin
83 | library = Library.new(@spec.name, @platform.name.to_s,@spec.version)
84 | library.make
85 | library
86 | end
87 | end
88 | end
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/sources_helper.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods-imy-bin/native/sources_manager.rb'
4 |
5 | module CBin
6 | module SourcesHelper
7 | def sources_manager
8 | Pod::Config.instance.sources_manager
9 | end
10 |
11 | def binary_source
12 | sources_manager.binary_source
13 | end
14 |
15 | def code_source
16 | sources_manager.code_source
17 | end
18 |
19 | # 优先采用对应依赖的 source
20 | # cocoapods 内部会先匹配前面符合的 specification
21 | # 只允许二进制的 specification subspec 比源码的 specification subspec 多
22 | #
23 | def valid_sources(code_dependencies = false)
24 | sources = [code_source]
25 | unless code_dependencies
26 | sources << binary_source
27 | sources.reverse!
28 | end
29 | sources
30 | end
31 |
32 | def sources_option(code_dependencies, additional_sources)
33 | (valid_sources(code_dependencies).map(&:url) + Array(additional_sources)).join(',')
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/spec_creator.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods'
4 | require 'cocoapods-imy-bin/config/config'
5 |
6 | module CBin
7 | class Specification
8 | class Creator
9 | attr_reader :code_spec
10 | attr_reader :template_spec
11 | attr_reader :spec
12 |
13 | def initialize(code_spec, template_spec, platforms = 'ios')
14 | @code_spec = code_spec
15 | @template_spec = template_spec
16 | @platforms = Array(platforms)
17 | validate!
18 | end
19 |
20 | def validate!
21 | raise Pod::Informative, '源码 podspec 不能为空 .' unless code_spec
22 | if code_spec.subspecs.any? && template_spec.nil?
23 | raise Pod::Informative, "不支持自动生成存在 subspec 的二进制 podspec , 需要提供模版文件 #{code_spec.name}.binary.podspec.template ."
24 | end
25 | end
26 |
27 | def create
28 | spec = template_spec ? create_from_code_spec_and_template_spec : create_from_code_spec
29 |
30 | Pod::UI.message '生成二进制 podspec 内容: '
31 | spec.to_pretty_json.split("\n").each do |text|
32 | Pod::UI.message text
33 | end
34 |
35 | spec
36 | end
37 |
38 | def write_spec_file(file = filename)
39 | create unless spec
40 |
41 | File.open(file, 'w+') do |f|
42 | f.write(spec.to_pretty_json)
43 | end
44 |
45 | @filename = file
46 | end
47 |
48 | def clear_spec_file
49 | File.delete(filename) if File.exist?(filename)
50 | end
51 |
52 | def filename
53 | @filename ||= "#{spec.name}.binary.podspec.json"
54 | end
55 |
56 | private
57 |
58 | def create_from_code_spec
59 | @spec = code_spec.dup
60 | # vendored_frameworks | resources | source | source_files | public_header_files
61 | # license | resource_bundles | vendored_libraries
62 |
63 | # Project Linkin
64 | @spec.vendored_frameworks = "#{code_spec.root.name}.framework"
65 |
66 | # Resources
67 | extnames = []
68 | extnames << '*.bundle' if code_spec_consumer.resource_bundles.any?
69 | if code_spec_consumer.resources.any?
70 | extnames += code_spec_consumer.resources.map { |r| File.basename(r) }
71 | end
72 | if extnames.any?
73 | @spec.resources = framework_contents('Resources').flat_map { |r| extnames.map { |e| "#{r}/#{e}" } }
74 | end
75 |
76 | # Source Location
77 | @spec.source = binary_source
78 |
79 | # Source Code
80 | @spec.source_files = framework_contents('Headers/*')
81 | @spec.public_header_files = framework_contents('Headers/*')
82 |
83 | # Unused for binary
84 | spec_hash = @spec.to_hash
85 | # spec_hash.delete('license')
86 | spec_hash.delete('resource_bundles')
87 | spec_hash.delete('exclude_files')
88 | spec_hash.delete('preserve_paths')
89 | # 这里不确定 vendored_libraries 指定的时动态/静态库
90 | # 如果是静态库的话,需要移除,否则就不移除
91 | # 最好是静态库都独立成 Pod ,cocoapods-package 打静态库去 collect 目标文件时好做过滤
92 | # 这里统一只对命名后缀 .a 文件做处理
93 | # spec_hash.delete('vendored_libraries')
94 | # libraries 只能假设为动态库不做处理了,如果有例外,需要开发者自行处理
95 | spec_hash.delete('vendored_libraries')
96 | spec_hash['vendored_libraries'] = binary_vendored_libraries
97 |
98 | # vendored_libraries = Array(vendored_libraries).reject { |l| l.end_with?('.a') }
99 | # if vendored_libraries.any?
100 | # spec_hash['vendored_libraries'] = vendored_libraries
101 | # end
102 |
103 | # Filter platforms
104 | platforms = spec_hash['platforms']
105 | selected_platforms = platforms.select { |k, _v| @platforms.include?(k) }
106 | spec_hash['platforms'] = selected_platforms.empty? ? platforms : selected_platforms
107 |
108 | @spec = Pod::Specification.from_hash(spec_hash)
109 | @spec
110 | end
111 |
112 | def create_from_code_spec_and_template_spec
113 | @spec = template_spec.dup
114 |
115 | @spec.version = code_spec.version
116 | @spec.source = binary_source
117 |
118 | @spec.source_files = binary_source_files
119 | @spec.public_header_files = binary_public_header_files
120 | @spec.vendored_libraries = binary_vendored_libraries
121 |
122 | @spec.resources = binary_resources if @spec.attributes_hash.keys.include?("resources")
123 |
124 |
125 |
126 | @spec
127 | end
128 |
129 | def binary_source
130 | { http: format(CBin.config.binary_download_url, code_spec.root.name, code_spec.version), type: CBin.config.download_file_type }
131 | end
132 |
133 | def code_spec_consumer(_platform = :ios)
134 | code_spec.consumer(:ios)
135 | end
136 |
137 | def framework_contents(name)
138 | ["#{code_spec.root.name}.framework", "#{code_spec.root.name}.framework/Versions/A"].map { |path| "#{path}/#{name}" }
139 | end
140 |
141 | def binary_source_files
142 | { http: format(CBin.config.binary_download_url, code_spec.root.name, code_spec.version), type: CBin.config.download_file_type }
143 | end
144 |
145 | def binary_source_files
146 | "bin_#{code_spec.name}_#{code_spec.version}/Headers/*"
147 | end
148 |
149 | def binary_public_header_files
150 | "bin_#{code_spec.name}_#{code_spec.version}/Headers/*.h"
151 | end
152 |
153 | def binary_vendored_libraries
154 | "bin_#{code_spec.name}_#{code_spec.version}/*.a"
155 | end
156 |
157 | def binary_resources
158 | "bin_#{code_spec.name}_#{code_spec.version}/Resources/*"
159 | end
160 |
161 | end
162 | end
163 | end
164 | #模板框架begin
165 | # s.source_files = "bin_#{s.name}_#{s.version}/Headers/*"
166 | # s.public_header_files = "bin_#{s.name}_#{s.version}/Headers/*.h"
167 | # s.vendored_libraries = "bin_#{s.name}_#{s.version}/*.a"
168 | #有图片资源的,要带上
169 | #s.resources = 'bin_#{s.name}_#{s.version}/Resources/*.{json,png,jpg,gif,js,xib,eot,svg,ttf,woff,db,sqlite,mp3,bundle}'
170 | #模板框架end
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/spec_files_helper.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods-imy-bin/native/sources_manager.rb'
4 | require 'cocoapods-imy-bin/helpers/spec_creator'
5 |
6 | module CBin
7 | module SpecFilesHelper
8 | def spec_files
9 | @spec_files ||= Pathname.glob('*.podspec{,.json}')
10 | end
11 |
12 | def binary_spec_files
13 | @binary_spec_files ||= Pathname.glob('*.binary.podspec{,.json}')
14 | end
15 |
16 | def binary_template_spec_files
17 | @binary_spec_template_files ||= Pathname.glob('*.binary-template.podspec{,.json}')
18 | end
19 |
20 | def binary_template_spec_file
21 | @binary_spec_template_file ||= binary_template_spec_files.first
22 | end
23 |
24 | def code_spec_files
25 | @code_spec_files ||= spec_files - binary_spec_files - binary_template_spec_files
26 | end
27 |
28 | def code_spec
29 | if code_spec_files.first
30 | Pod::Specification.from_file(code_spec_files.first)
31 | end
32 | end
33 |
34 | def binary_spec
35 | if binary_spec_files.first
36 | Pod::Specification.from_file(binary_spec_files.first)
37 | end
38 | end
39 |
40 | def binary_template_spec
41 | if binary_template_spec_file
42 | Pod::Specification.from_file(binary_template_spec_file)
43 | end
44 | end
45 |
46 | def find_spec_file(podspec)
47 | path = Pathname(podspec)
48 | raise Pod::Informative, "无法找到 #{podspec}" unless path.exist?
49 |
50 | path
51 | end
52 |
53 | def create_binary_spec_file(code_spec, template_spec)
54 | # 1. code spec 是否有 subpsec
55 | # 1.1 有,查找 template spec,并生成
56 | # 1.2 没有,是否有 template spec
57 | # 1.2.1 有,根据 template spec 生成
58 | # 1.2.2 没有,根据 code spec 生成
59 |
60 | unless code_spec
61 | raise Pod::Informative, '没有二进制 podspec 的情况下,必须要提供源码 podspec.'
62 | end
63 | if code_spec.subspecs.any? && template_spec.nil?
64 | raise Pod::Informative, '拥有 subspec 的组件,在生成二进制 podspec 时,必须要提供模版 podspec.'
65 | end
66 |
67 | @spec_creator = CBin::Specification::Creator.new(code_spec, template_spec)
68 | @spec_creator.create
69 | @spec_creator.write_spec_file
70 | @spec_creator.filename
71 | end
72 |
73 | def clear_binary_spec_file_if_needed
74 | @spec_creator&.clear_spec_file
75 | end
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/spec_source_creator.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods'
4 | require 'cocoapods-imy-bin/config/config'
5 |
6 | module CBin
7 | class SpecificationSource
8 | class Creator
9 | attr_reader :code_spec
10 | attr_reader :spec
11 |
12 | def initialize(code_spec, platforms = 'ios')
13 | @code_spec = code_spec
14 | @platforms = Array(platforms)
15 | validate!
16 | end
17 |
18 | def validate!
19 | raise Pod::Informative, '源码 podspec 不能为空 .' unless code_spec
20 | end
21 |
22 | def create
23 | # spec = nil
24 | if CBin::Build::Utils.is_framework(@code_spec)
25 | spec = create_framework_from_code_spec
26 | else
27 | spec = create_from_code_spec
28 | end
29 |
30 | spec
31 | end
32 |
33 | def write_spec_file(file = filename)
34 | create unless spec
35 |
36 | FileUtils.mkdir_p(CBin::Config::Builder.instance.binary_json_dir) unless File.exist?(CBin::Config::Builder.instance.binary_json_dir)
37 | FileUtils.rm_rf(file) if File.exist?(file)
38 |
39 | File.open(file, 'w+') do |f|
40 | # f.write("# MARK: converted automatically by plugin cocoapods-imy-bin @slj \r\n")
41 | f.write(spec.to_pretty_json)
42 | end
43 |
44 | @filename = file
45 | end
46 |
47 | def clear_spec_file
48 | File.delete(filename) if File.exist?(filename)
49 | end
50 |
51 | def filename
52 | @filename ||= "#{CBin::Config::Builder.instance.binary_json_dir_name}/#{spec.name}.binary.podspec.json"
53 | end
54 |
55 | private
56 |
57 | def create_from_code_spec
58 | @spec = code_spec.dup
59 | # vendored_frameworks | resources | source | source_files | public_header_files
60 | # license | resource_bundles | vendored_libraries
61 |
62 | # Project Linkin
63 | # @spec.vendored_frameworks = "#{code_spec.root.name}.framework"
64 |
65 | # Resources
66 | extnames = []
67 | extnames << '*.bundle' if code_spec_consumer.resource_bundles.any?
68 | if code_spec_consumer.resources.any?
69 | extnames += code_spec_consumer.resources.map { |r| File.basename(r) }
70 | end
71 | if extnames.any?
72 | @spec.resources = framework_contents('Resources').flat_map { |r| extnames.map { |e| "#{r}/#{e}" } }
73 | end
74 |
75 | # Source Location
76 | @spec.source = binary_source
77 |
78 | # Source Code
79 | # @spec.source_files = framework_contents('Headers/*')
80 | # @spec.public_header_files = framework_contents('Headers/*')
81 |
82 | # Unused for binary
83 | spec_hash = @spec.to_hash
84 | # spec_hash.delete('license')
85 | spec_hash.delete('resource_bundles')
86 | spec_hash.delete('exclude_files')
87 | spec_hash.delete('preserve_paths')
88 | spec_hash.delete('vendored_frameworks')
89 | spec_hash.delete('vendored_framework')
90 |
91 | # 这里不确定 vendored_libraries 指定的时动态/静态库
92 | # 如果是静态库的话,需要移除,否则就不移除
93 | # 最好是静态库都独立成 Pod ,cocoapods-package 打静态库去 collect 目标文件时好做过滤
94 | # 这里统一只对命名后缀 .a 文件做处理
95 | # spec_hash.delete('vendored_libraries')
96 | # libraries 只能假设为动态库不做处理了,如果有例外,需要开发者自行处理
97 | spec_hash.delete('vendored_libraries')
98 |
99 | # vendored_libraries = Array(vendored_libraries).reject { |l| l.end_with?('.a') }
100 | # if vendored_libraries.any?
101 | # spec_hash['vendored_libraries'] = vendored_libraries
102 | # end
103 |
104 | # Filter platforms
105 | platforms = spec_hash['platforms']
106 | selected_platforms = platforms.select { |k, _v| @platforms.include?(k) }
107 | spec_hash['platforms'] = selected_platforms.empty? ? platforms : selected_platforms
108 |
109 | @spec = Pod::Specification.from_hash(spec_hash)
110 |
111 | #把命令 prepare_command 移除掉,如ReactiveCocoa会执行修改重命令的脚步
112 | @spec.prepare_command = "" if @spec.prepare_command
113 | @spec.version = code_spec.version
114 | @spec.source = binary_source
115 | @spec.source_files = binary_source_files
116 | @spec.public_header_files = binary_public_header_files
117 | @spec.vendored_libraries = binary_vendored_libraries
118 | @spec.resources = binary_resources if @spec.attributes_hash.keys.include?("resources")
119 | @spec.description = <<-EOF
120 | 「 converted automatically by plugin cocoapods-imy-bin @厦门美柚 - slj 」
121 | #{@spec.description}
122 | EOF
123 |
124 | # 处理一下 subspecs ,使用相同的配置
125 | if @spec.subspecs
126 | @spec.subspecs.each do |subspec|
127 | subspec.source_files = binary_source_files
128 | subspec.public_header_files = binary_public_header_files
129 | subspec.vendored_libraries = binary_vendored_libraries
130 | subspec.resources = binary_resources if @spec.attributes_hash.keys.include?("resources")
131 | end
132 | end
133 | @spec
134 | end
135 |
136 | def create_framework_from_code_spec
137 | @spec = code_spec.dup
138 | # vendored_frameworks | resources | source | source_files | public_header_files
139 | # license | resource_bundles | vendored_libraries
140 |
141 | # Project Linkin
142 | @spec.vendored_frameworks = "#{code_spec.root.name}.framework"
143 |
144 | # Resources
145 | extnames = []
146 | extnames << '*.bundle' if code_spec_consumer.resource_bundles.any?
147 | if code_spec_consumer.resources.any?
148 | extnames += code_spec_consumer.resources.map { |r| File.basename(r) }
149 | end
150 | if extnames.any?
151 | @spec.resources = framework_contents('Resources').flat_map { |r| extnames.map { |e| "#{r}/#{e}" } }
152 | end
153 |
154 | # Source Location
155 | @spec.source = binary_source
156 |
157 | # Source Code
158 | # @spec.source_files = framework_contents('Headers/*')
159 | # @spec.public_header_files = framework_contents('Headers/*')
160 |
161 | # Unused for binary
162 | spec_hash = @spec.to_hash
163 | # spec_hash.delete('license')
164 | spec_hash.delete('resource_bundles')
165 | spec_hash.delete('exclude_files')
166 | spec_hash.delete('preserve_paths')
167 | # 这里不确定 vendored_libraries 指定的时动态/静态库
168 | # 如果是静态库的话,需要移除,否则就不移除
169 | # 最好是静态库都独立成 Pod ,cocoapods-package 打静态库去 collect 目标文件时好做过滤
170 | # 这里统一只对命名后缀 .a 文件做处理
171 | # spec_hash.delete('vendored_libraries')
172 | # libraries 只能假设为动态库不做处理了,如果有例外,需要开发者自行处理
173 | vendored_libraries = spec_hash.delete('vendored_libraries')
174 | vendored_libraries = Array(vendored_libraries).reject { |l| l.end_with?('.a') }
175 | if vendored_libraries.any?
176 | spec_hash['vendored_libraries'] = vendored_libraries
177 | end
178 |
179 | # Filter platforms
180 | platforms = spec_hash['platforms']
181 | selected_platforms = platforms.select { |k, _v| @platforms.include?(k) }
182 | spec_hash['platforms'] = selected_platforms.empty? ? platforms : selected_platforms
183 |
184 | @spec = Pod::Specification.from_hash(spec_hash)
185 | @spec.description = <<-EOF
186 | 「 converted automatically by plugin cocoapods-imy-bin @厦门美柚 - slj 」
187 | #{@spec.description}
188 | EOF
189 | @spec
190 | end
191 |
192 |
193 | def binary_source
194 | { http: format(CBin.config.binary_download_url, code_spec.root.name, code_spec.version), type: CBin.config.download_file_type }
195 | end
196 |
197 | def code_spec_consumer(_platform = :ios)
198 | code_spec.consumer(:ios)
199 | end
200 |
201 | def framework_contents(name)
202 | ["#{code_spec.root.name}.framework", "#{code_spec.root.name}.framework/Versions/A"].map { |path| "#{path}/#{name}" }
203 | end
204 |
205 | def binary_source_files
206 | { http: format(CBin.config.binary_download_url, code_spec.root.name, code_spec.version), type: CBin.config.download_file_type }
207 | end
208 |
209 | def binary_source_files
210 | "bin_#{code_spec.name}_#{code_spec.version}/Headers/*"
211 | end
212 |
213 | def binary_public_header_files
214 | "bin_#{code_spec.name}_#{code_spec.version}/Headers/*.h"
215 | end
216 |
217 | def binary_vendored_libraries
218 | "bin_#{code_spec.name}_#{code_spec.version}/*.a"
219 | end
220 |
221 | def binary_resources
222 | "bin_#{code_spec.name}_#{code_spec.version}/Resources/*"
223 | end
224 |
225 | end
226 | end
227 | end
228 | #模板框架begin
229 | # s.source_files = "bin_#{s.name}_#{s.version}/Headers/*"
230 | # s.public_header_files = "bin_#{s.name}_#{s.version}/Headers/*.h"
231 | # s.vendored_libraries = "bin_#{s.name}_#{s.version}/*.a"
232 | #有图片资源的,要带上
233 | #s.resources = 'bin_#{s.name}_#{s.version}/Resources/*.{json,png,jpg,gif,js,xib,eot,svg,ttf,woff,db,sqlite,mp3,bundle}'
234 | #模板框架end
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/helpers/upload_helper.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | # copy from https://github.com/CocoaPods/cocoapods-packager
4 |
5 | require 'cocoapods-imy-bin/native/podfile'
6 | require 'cocoapods/command/gen'
7 | require 'cocoapods/generate'
8 | require 'cocoapods-imy-bin/helpers/framework_builder'
9 | require 'cocoapods-imy-bin/helpers/library_builder'
10 | require 'cocoapods-imy-bin/helpers/sources_helper'
11 | require 'cocoapods-imy-bin/command/bin/spec/push'
12 |
13 | module CBin
14 | class Upload
15 | class Helper
16 | include CBin::SourcesHelper
17 |
18 | def initialize(spec,code_dependencies,sources)
19 | @spec = spec
20 | @code_dependencies = code_dependencies
21 | @sources = sources
22 | end
23 |
24 | def upload
25 | Dir.chdir(CBin::Config::Builder.instance.root_dir) do
26 | # 创建binary-template.podsepc
27 | # 上传二进制文件
28 | # 上传二进制 podspec
29 | res_zip = curl_zip
30 | if res_zip
31 | filename = spec_creator
32 | push_binary_repo(filename)
33 | end
34 | res_zip
35 | end
36 | end
37 |
38 | def spec_creator
39 | spec_creator = CBin::SpecificationSource::Creator.new(@spec)
40 | spec_creator.create
41 | spec_creator.write_spec_file
42 | spec_creator.filename
43 | end
44 |
45 | #推送二进制
46 | # curl http://ci.xxx:9192/frameworks -F "name=IMYFoundation" -F "version=7.7.4.2" -F "annotate=IMYFoundation_7.7.4.2_log" -F "file=@bin-zip/bin_IMYFoundation_7.7.4.2.zip"
47 | def curl_zip
48 | zip_file = "#{CBin::Config::Builder.instance.library_file(@spec)}.zip"
49 | res = File.exist?(zip_file)
50 | unless res
51 | zip_file = CBin::Config::Builder.instance.framework_zip_file(@spec) + ".zip"
52 | res = File.exist?(zip_file)
53 | end
54 | if res
55 | command = "curl #{CBin.config.binary_upload_url} -F \"name=#{@spec.name}\" -F \"version=#{@spec.version}\" -F \"annotate=#{@spec.name}_#{@spec.version}_log\" -F \"file=@#{zip_file}\""
56 | print < 1.4')
4 | require 'cocoapods-imy-bin/native/podfile'
5 | require 'cocoapods-imy-bin/native/installation_options'
6 | require 'cocoapods-imy-bin/native/specification'
7 | require 'cocoapods-imy-bin/native/path_source'
8 | require 'cocoapods-imy-bin/native/analyzer'
9 | require 'cocoapods-imy-bin/native/installer'
10 | require 'cocoapods-imy-bin/native/podfile_generator'
11 | require 'cocoapods-imy-bin/native/pod_source_installer'
12 | require 'cocoapods-imy-bin/native/linter'
13 | require 'cocoapods-imy-bin/native/resolver'
14 | require 'cocoapods-imy-bin/native/source'
15 | require 'cocoapods-imy-bin/native/validator'
16 | require 'cocoapods-imy-bin/native/acknowledgements'
17 | require 'cocoapods-imy-bin/native/sandbox_analyzer'
18 | require 'cocoapods-imy-bin/native/podspec_finder'
19 | require 'cocoapods-imy-bin/native/file_accessor'
20 | require 'cocoapods-imy-bin/native/pod_target_installer'
21 | require 'cocoapods-imy-bin/native/target_validator'
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/acknowledgements.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | module Pod
4 | module Generator
5 | class Acknowledgements
6 | def license_text(spec)
7 | return nil unless spec.license
8 |
9 | text = spec.license[:text]
10 | unless text
11 | if license_file = spec.license[:file]
12 | license_path = file_accessor(spec).root + license_file
13 | if File.exist?(license_path)
14 | text = IO.read(license_path)
15 | else
16 | # UI.warn "Unable to read the license file `#{license_file}` " \
17 | # "for the spec `#{spec}`"
18 | end
19 | elsif license_file = file_accessor(spec).license
20 | text = IO.read(license_file)
21 | end
22 | end
23 | text
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/analyzer.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'parallel'
4 | require 'cocoapods'
5 |
6 | module Pod
7 | class Installer
8 | class Analyzer
9 | # > 1.6.0
10 | # all_specs[dep.name] 为 nil 会崩溃
11 | # 主要原因是 all_specs 分析错误
12 | # 查看 source 是否正确
13 | #
14 | # def dependencies_for_specs(specs, platform, all_specs)
15 | # return [] if specs.empty? || all_specs.empty?
16 |
17 | # dependent_specs = Set.new
18 |
19 | # specs.each do |s|
20 | # s.dependencies(platform).each do |dep|
21 | # all_specs[dep.name].each do |spec|
22 | # dependent_specs << spec
23 | # end
24 | # end
25 | # end
26 |
27 | # dependent_specs - specs
28 | # end
29 |
30 | # > 1.5.3 版本
31 | # rewrite update_repositories
32 | #
33 | alias old_update_repositories update_repositories
34 | def update_repositories
35 | if installation_options.update_source_with_multi_processes
36 | # 并发更新私有源
37 | # 这里多线程会导致 pod update 额外输出 --verbose 的内容
38 | # 不知道为什么?
39 | Parallel.each(sources.uniq(&:url), in_processes: 4) do |source|
40 | if source.git?
41 | config.sources_manager.update(source.name, true)
42 | else
43 | UI.message "Skipping `#{source.name}` update because the repository is not a git source repository."
44 | end
45 | end
46 | @specs_updated = true
47 | else
48 | old_update_repositories
49 | end
50 | end
51 |
52 |
53 | end
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/file_accessor.rb:
--------------------------------------------------------------------------------
1 | require 'macho'
2 | require 'cocoapods'
3 |
4 | module Pod
5 | class Sandbox
6 | class FileAccessor
7 |
8 | # swift动态库 需要设置为true
9 | def dynamic_binary?(binary)
10 | @cached_dynamic_binary_results ||= {}
11 | return @cached_dynamic_binary_results[binary] unless @cached_dynamic_binary_results[binary].nil?
12 | return false unless binary.file?
13 |
14 | @cached_dynamic_binary_results[binary] = MachO.open(binary).dylib?
15 | rescue MachO::MachOError
16 | @cached_dynamic_binary_results[binary] = true
17 |
18 | end
19 |
20 | # def expanded_paths(patterns, options = {})
21 | # return [] if patterns.empty?
22 | # path_list.glob(patterns, options).flatten.compact.uniq
23 | # end
24 |
25 | #-----------------------------------------------------------------------#
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/installation_options.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'cocoapods'
3 |
4 | module Pod
5 | class Installer
6 | class InstallationOptions
7 | def self.env_option(key, default = true)
8 | option key, ENV[key.to_s].nil? ? default : ENV[key.to_s] == 'true'
9 | end
10 |
11 | # 不同 source 存在相同 spec 名时,默认不警告
12 | defaults.delete('warn_for_multiple_pod_sources')
13 | env_option :warn_for_multiple_pod_sources, false
14 |
15 | # 是否警告不安全 source (如 http )
16 | env_option :warn_for_unsecure_source, false
17 |
18 | # 是否多线程执行 install_pod_sources
19 | env_option :install_with_multi_threads, true
20 |
21 | # 是否多进程执行 update_repositories
22 | env_option :update_source_with_multi_processes, true
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/installer.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods/installer/project_cache/target_metadata.rb'
2 | require 'parallel'
3 | require 'cocoapods'
4 | require 'xcodeproj'
5 | require 'cocoapods-imy-bin/native/pod_source_installer'
6 |
7 | module Pod
8 | class Installer
9 | alias old_create_pod_installer create_pod_installer
10 | def create_pod_installer(pod_name)
11 | installer = old_create_pod_installer(pod_name)
12 | installer.installation_options = installation_options
13 | installer
14 | end
15 |
16 | alias old_install_pod_sources install_pod_sources
17 | def install_pod_sources
18 | if installation_options.install_with_multi_threads
19 | if Pod.match_version?('~> 1.4.0')
20 | install_pod_sources_for_version_in_1_4_0
21 | elsif Pod.match_version?('~> 1.5')
22 | install_pod_sources_for_version_above_1_5_0
23 | else
24 | old_install_pod_sources
25 | end
26 | else
27 | old_install_pod_sources
28 | end
29 | end
30 |
31 | # rewrite install_pod_sources
32 | def install_pod_sources_for_version_in_1_4_0
33 | @installed_specs = []
34 | pods_to_install = sandbox_state.added | sandbox_state.changed
35 | title_options = { verbose_prefix: '-> '.green }
36 | Parallel.each(root_specs.sort_by(&:name), in_threads: 4) do |spec|
37 | if pods_to_install.include?(spec.name)
38 | if sandbox_state.changed.include?(spec.name) && sandbox.manifest
39 | previous = sandbox.manifest.version(spec.name)
40 | title = "Installing #{spec.name} #{spec.version} (was #{previous})"
41 | else
42 | title = "Installing #{spec}"
43 | end
44 | UI.titled_section(title.green, title_options) do
45 | install_source_of_pod(spec.name)
46 | end
47 | else
48 | UI.titled_section("Using #{spec}", title_options) do
49 | create_pod_installer(spec.name)
50 | end
51 | end
52 | end
53 | end
54 |
55 | def install_pod_sources_for_version_above_1_5_0
56 | @installed_specs = []
57 | pods_to_install = sandbox_state.added | sandbox_state.changed
58 | title_options = { verbose_prefix: '-> '.green }
59 | # 多进程下载,多线程时 log 会显著交叉,多进程好点,但是多进程需要利用文件锁对 cache 进行保护
60 | # in_processes: 10
61 | Parallel.each(root_specs.sort_by(&:name), in_threads: 4) do |spec|
62 | if pods_to_install.include?(spec.name)
63 | if sandbox_state.changed.include?(spec.name) && sandbox.manifest
64 | current_version = spec.version
65 | previous_version = sandbox.manifest.version(spec.name)
66 | has_changed_version = current_version != previous_version
67 | current_repo = analysis_result.specs_by_source.detect do |key, values|
68 | break key if values.map(&:name).include?(spec.name)
69 | end
70 | current_repo &&= current_repo.url || current_repo.name
71 | previous_spec_repo = sandbox.manifest.spec_repo(spec.name)
72 | has_changed_repo = !previous_spec_repo.nil? && current_repo && (current_repo != previous_spec_repo)
73 | title = "Installing #{spec.name} #{spec.version}"
74 | if has_changed_version && has_changed_repo
75 | title += " (was #{previous_version} and source changed to `#{current_repo}` from `#{previous_spec_repo}`)"
76 | end
77 | if has_changed_version && !has_changed_repo
78 | title += " (was #{previous_version})"
79 | end
80 | if !has_changed_version && has_changed_repo
81 | title += " (source changed to `#{current_repo}` from `#{previous_spec_repo}`)"
82 | end
83 | else
84 | title = "Installing #{spec}"
85 | end
86 | UI.titled_section(title.green, title_options) do
87 | install_source_of_pod(spec.name)
88 | end
89 | else
90 | UI.titled_section("Using #{spec}", title_options) do
91 | create_pod_installer(spec.name)
92 | end
93 | end
94 | end
95 | end
96 |
97 | alias old_write_lockfiles write_lockfiles
98 | def write_lockfiles
99 | old_write_lockfiles
100 | if File.exist?('Podfile_local')
101 |
102 | project = Xcodeproj::Project.open(config.sandbox.project_path)
103 | #获取主group
104 | group = project.main_group
105 | group.set_source_tree('SOURCE_ROOT')
106 | #向group中添加 文件引用
107 | file_ref = group.new_reference(config.sandbox.root + '../Podfile_local')
108 | #podfile_local排序
109 | podfile_local_group = group.children.last
110 | group.children.pop
111 | group.children.unshift(podfile_local_group)
112 | #保存
113 | project.save
114 | end
115 | end
116 | end
117 |
118 | module Downloader
119 | class Cache
120 | # 多线程锁
121 | @@lock = Mutex.new
122 |
123 | # 后面如果要切到进程的话,可以在 cache root 里面新建一个文件
124 | # 利用这个文件 lock
125 | # https://stackoverflow.com/questions/23748648/using-fileflock-as-ruby-global-lock-mutex-for-processes
126 |
127 | # rmtree 在多进程情况下可能 Directory not empty @ dir_s_rmdir 错误
128 | # old_ensure_matching_version 会移除不是同一个 CocoaPods 版本的组件缓存
129 | alias old_ensure_matching_version ensure_matching_version
130 | def ensure_matching_version
131 | @@lock.synchronize { old_ensure_matching_version }
132 | end
133 | end
134 | end
135 | end
136 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/linter.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods-imy-bin/native/specification'
4 |
5 | module Pod
6 | class Specification
7 | class Linter
8 | # !@group Lint steps
9 |
10 | # Checks that the spec's root name matches the filename.
11 | #
12 | # @return [void]
13 | #
14 | def validate_root_name
15 | if spec.root.name && file
16 | acceptable_names = Specification::VALID_EXTNAME.map { |extname| "#{spec.root.name}#{extname}" }
17 | names_match = acceptable_names.include?(file.basename.to_s)
18 | unless names_match
19 | results.add_error('name', 'The name of the spec should match the ' \
20 | 'name of the file.')
21 | end
22 | end
23 | end
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/path_source.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods-imy-bin/native/specification'
4 |
5 | module Pod
6 | module ExternalSources
7 | # Provides support for fetching a specification file from a path local to
8 | # the machine running the installation.
9 | #
10 | class PathSource < AbstractExternalSource
11 | def normalized_podspec_path(declared_path)
12 | extension = File.extname(declared_path)
13 |
14 | if extension == '.podspec' || extension == '.json'
15 | path_with_ext = declared_path
16 | else
17 | # 默认先从 binary podspec 找起,因为 binary podspec 的 subspec 可能比 code podspec 多
18 | # 这里可能出现 code subspec 和 binary subspec 对应不上的情况,导致 lint 失败
19 | # 所以不要在 code podspec 同一目录下保留 binary podspec
20 | path_with_ext = Specification::VALID_EXTNAME
21 | .map { |extname| "#{declared_path}/#{name}#{extname}" }
22 | .find { |file| File.exist?(file) } || "#{declared_path}/#{name}.podspec"
23 | end
24 |
25 | UI.message "获取的 podspec 路径为 `#{path_with_ext}`"
26 |
27 | podfile_dir = File.dirname(podfile_path || '')
28 |
29 | File.expand_path(path_with_ext, podfile_dir)
30 | end
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/pod_source_installer.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods-imy-bin/native/installation_options'
4 |
5 | module Pod
6 | class Installer
7 | class PodSourceInstaller
8 | attr_accessor :installation_options
9 |
10 | alias old_verify_source_is_secure verify_source_is_secure
11 | def verify_source_is_secure(root_spec)
12 | # http source 默认不警告
13 | if installation_options.warn_for_unsecure_source?
14 | old_verify_source_is_secure(root_spec)
15 | end
16 | end
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/pod_target_installer.rb:
--------------------------------------------------------------------------------
1 | module Pod
2 | class Installer
3 | class Xcode
4 | class PodsProjectGenerator
5 | # Creates the target for the Pods libraries in the Pods project and the
6 | # relative support files.
7 | #
8 | class PodTargetInstaller < TargetInstaller
9 | require 'cocoapods/installer/xcode/pods_project_generator/app_host_installer'
10 |
11 | # Adds a shell script phase, intended only for library targets that contain swift,
12 | # to copy the ObjC compatibility header (the -Swift.h file that the swift compiler generates)
13 | # to the built products directory. Additionally, the script phase copies the module map, appending a `.Swift`
14 | # submodule that references the (moved) compatibility header. Since the module map has been moved, the umbrella header
15 | # is _also_ copied, so that it is sitting next to the module map. This is necessary for a successful archive build.
16 | #
17 | # @param [PBXNativeTarget] native_target
18 | # the native target to add the Swift static library script phase into.
19 | #
20 | # @return [Void]
21 | #
22 | alias old_add_swift_library_compatibility_header_phase add_swift_library_compatibility_header_phase
23 |
24 | def add_swift_library_compatibility_header_phase(native_target)
25 | UI.warn("========= swift add_swift_library_compatibility_header_phase")
26 | if $ARGV[1] == "auto"
27 | UI.warn("========= auto swift add_swift_library_compatibility_header_phase")
28 |
29 | if custom_module_map
30 | raise Informative, 'Using Swift static libraries with custom module maps is currently not supported. ' \
31 | "Please build `#{target.label}` as a framework or remove the custom module map."
32 | end
33 |
34 | build_phase = native_target.new_shell_script_build_phase('Copy generated compatibility header')
35 |
36 | relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root)
37 | relative_umbrella_header_path = target.umbrella_header_path.relative_path_from(target.sandbox.root)
38 |
39 | build_phase.shell_script = <<-SH.strip_heredoc
40 | COMPATIBILITY_HEADER_PATH="${BUILT_PRODUCTS_DIR}/Swift Compatibility Header/${PRODUCT_MODULE_NAME}-Swift.h"
41 | MODULE_MAP_PATH="${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.modulemap"
42 |
43 | ditto "${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h" "${COMPATIBILITY_HEADER_PATH}"
44 | ditto "${PODS_ROOT}/#{relative_module_map_path}" "${MODULE_MAP_PATH}"
45 | ditto "${PODS_ROOT}/#{relative_umbrella_header_path}" "${BUILT_PRODUCTS_DIR}"
46 |
47 | COPY_PATH="${PODS_CONFIGURATION_BUILD_DIR}/${PRODUCT_MODULE_NAME}"
48 | UMBRELLA_PATH="${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}-umbrella.h"
49 | SWIFTMODULE_PATH="${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.swiftmodule"
50 |
51 | ditto "${MODULE_MAP_PATH}" "${PODS_CONFIGURATION_BUILD_DIR}/${PRODUCT_MODULE_NAME}/${PRODUCT_MODULE_NAME}.modulemap"
52 | ditto "${COMPATIBILITY_HEADER_PATH}" "${COPY_PATH}/Swift Compatibility Header/${PRODUCT_MODULE_NAME}-Swift.h"
53 | ditto "${COMPATIBILITY_HEADER_PATH}" "${COPY_PATH}"
54 | ditto "${UMBRELLA_PATH}" "${COPY_PATH}"
55 | ditto "${SWIFTMODULE_PATH}" "${COPY_PATH}/${PRODUCT_MODULE_NAME}.swiftmodule"
56 | ditto "${SWIFTMODULE_PATH}" "${COPY_PATH}/${PRODUCT_MODULE_NAME}.swiftmodule"
57 |
58 | if [ ${PRODUCT_MODULE_NAME} != ${PRODUCT_NAME} ] ; then
59 | ditto "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}-umbrella.h" "${COPY_PATH}"
60 | ditto "${COPY_PATH}" "${PODS_CONFIGURATION_BUILD_DIR}/${PRODUCT_NAME}"
61 | fi
62 |
63 | MODULE_MAP_SEARCH_PATH = "${PODS_CONFIGURATION_BUILD_DIR}/${PRODUCT_MODULE_NAME}/${PRODUCT_MODULE_NAME}.modulemap"
64 |
65 | if [${MODULE_MAP_PATH} != ${MODULE_MAP_SEARCH_PATH}] ; then
66 | printf "\\n\\nmodule ${PRODUCT_MODULE_NAME}.Swift {\\n header \\"${COPY_PATH}/Swift Compatibility Header/${PRODUCT_MODULE_NAME}-Swift.h\\"\\n requires objc\\n}\\n" >> "${MODULE_MAP_SEARCH_PATH}"
67 | fi
68 |
69 | printf "\\n\\nmodule ${PRODUCT_MODULE_NAME}.Swift {\\n header \\"${COMPATIBILITY_HEADER_PATH}\\"\\n requires objc\\n}\\n" >> "${MODULE_MAP_PATH}"
70 |
71 | SH
72 | build_phase.input_paths = %W(
73 | ${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h
74 | ${PODS_ROOT}/#{relative_module_map_path}
75 | ${PODS_ROOT}/#{relative_umbrella_header_path}
76 | )
77 | build_phase.output_paths = %W(
78 | ${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.modulemap
79 | ${BUILT_PRODUCTS_DIR}/#{relative_umbrella_header_path.basename}
80 | ${BUILT_PRODUCTS_DIR}/Swift\ Compatibility\ Header/${PRODUCT_MODULE_NAME}-Swift.h
81 | )
82 | else
83 | UI.warn("========= null swift add_swift_library_compatibility_header_phase")
84 | old_add_swift_library_compatibility_header_phase(native_target)
85 | end
86 |
87 | end
88 |
89 | #-----------------------------------------------------------------------#
90 | end
91 | end
92 | end
93 | end
94 | end
95 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/podfile.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods'
4 | require 'cocoapods-imy-bin/native/podfile_env'
5 |
6 | module Pod
7 | class Podfile
8 | # TREAT_DEVELOPMENTS_AS_NORMAL = 'treat_developments_as_normal'.freeze
9 |
10 | module DSL
11 | def allow_prerelease!
12 | set_internal_hash_value(ALLOW_PRERELEASE, true)
13 | end
14 |
15 | def use_binaries!(flag = true)
16 | set_internal_hash_value(USE_BINARIES, flag)
17 | end
18 |
19 | def use_binaries_with_spec_selector!(&block)
20 | raise Informative, '必须提供选择需要二进制组件的 block !' unless block_given?
21 |
22 | set_internal_hash_value(USE_BINARIES_SELECTOR, block)
23 | end
24 |
25 | def set_use_source_pods(pods)
26 | hash_pods_use_source = get_internal_hash_value(USE_SOURCE_PODS) || []
27 | hash_pods_use_source += Array(pods)
28 | set_internal_hash_value(USE_SOURCE_PODS, hash_pods_use_source)
29 | end
30 |
31 | # 0 dev
32 | # 1 debug_iphoneos
33 | # 2 release_iphoneos
34 | # 需要在podfile_env 先定义 CONFIGURATION_ENV
35 | def set_configuration_env(env = "dev")
36 | set_internal_hash_value(CONFIGURATION_ENV, env)
37 | end
38 | end
39 |
40 | alias old_plugins plugins
41 | def plugins
42 | if ENV[USE_PLUGINS]
43 | env_plugins = ENV[USE_PLUGINS].split(',').each_with_object({}) do |name, result|
44 | result[name] = {}
45 | end
46 | env_plugins.merge!(old_plugins)
47 | else
48 | old_plugins
49 | end
50 | end
51 |
52 | def use_binaries_selector
53 | get_internal_hash_value(USE_BINARIES_SELECTOR, nil)
54 | end
55 |
56 | def allow_prerelease?
57 | get_internal_hash_value(ALLOW_PRERELEASE, false) || ENV[ALLOW_PRERELEASE] == 'true'
58 | end
59 |
60 | def use_binaries?
61 | get_internal_hash_value(USE_BINARIES, false) || ENV[USE_BINARIES] == 'true'
62 | end
63 |
64 | def use_source_pods
65 | get_internal_hash_value(USE_SOURCE_PODS, []) + String(ENV[USE_SOURCE_PODS]).split('|').uniq
66 | end
67 |
68 | def configuration_env
69 | get_internal_hash_value(CONFIGURATION_ENV, "dev") || ENV[CONFIGURATION_ENV] == "dev"
70 | end
71 |
72 | private
73 |
74 | def valid_bin_plugin
75 | unless plugins.keys.include?('cocoapods-imy-bin')
76 | raise Pod::Informative, 'You should add `plugin \'cocoapods-imy-bin\'` before using its DSL'
77 | end
78 | end
79 |
80 | # set_hash_value 有 key 限制
81 | def set_internal_hash_value(key, value)
82 | valid_bin_plugin
83 |
84 | internal_hash[key] = value
85 | end
86 |
87 | def get_internal_hash_value(key, default = nil)
88 | internal_hash.fetch(key, default)
89 | end
90 | end
91 | end
92 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/podfile_env.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | module Pod
4 | class Podfile
5 | USE_BINARIES = 'use_binaries'
6 | USE_SOURCE_PODS = 'use_source_pods'
7 | USE_BINARIES_SELECTOR = 'use_binaries_selector'
8 | ALLOW_PRERELEASE = 'allow_prerelease'
9 | USE_PLUGINS = 'use_plugins'
10 | CONFIGURATION_ENV = 'configuration_env'
11 |
12 | module ENVExecutor
13 | def execute_with_bin_plugin(&block)
14 | execute_with_key(USE_PLUGINS, -> { 'cocoapods-imy-bin' }, &block)
15 | end
16 |
17 | def execute_with_allow_prerelease(allow_prerelease, &block)
18 | execute_with_key(ALLOW_PRERELEASE, -> { allow_prerelease ? 'true' : 'false' }, &block)
19 | end
20 |
21 | def execute_with_use_binaries(use_binaries, &block)
22 | execute_with_key(USE_BINARIES, -> { use_binaries ? 'true' : 'false' }, &block)
23 | end
24 |
25 | def execute_with_key(key, value_returner)
26 | origin_value = ENV[key]
27 | ENV[key] = value_returner.call
28 |
29 | yield if block_given?
30 |
31 | ENV[key] = origin_value
32 | end
33 | end
34 |
35 | extend ENVExecutor
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/podfile_generator.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'parallel'
4 | require 'cocoapods'
5 | require 'cocoapods-imy-bin/native/pod_source_installer'
6 |
7 |
8 | require 'parallel'
9 | require 'cocoapods'
10 |
11 | module Pod
12 | module Generate
13 | # Generates podfiles for pod specifications given a configuration.
14 | #
15 | class PodfileGenerator
16 | # @return [Podfile] a podfile suitable for installing the given spec
17 | #
18 | # @param [Specification] spec
19 | #
20 | alias old_podfile_for_spec podfile_for_spec
21 |
22 | def podfile_for_spec(spec)
23 | generator = self
24 | dir = configuration.gen_dir_for_pod(spec.name)
25 |
26 | Pod::Podfile.new do
27 | project "#{spec.name}.xcodeproj"
28 | workspace "#{spec.name}.xcworkspace"
29 |
30 | plugin 'cocoapods-generate'
31 |
32 | install! 'cocoapods', generator.installation_options
33 |
34 | generator.podfile_plugins.each do |name, options|
35 | plugin(*[name, options].compact)
36 | end
37 |
38 | use_frameworks!(generator.use_frameworks_value)
39 |
40 | if (supported_swift_versions = generator.supported_swift_versions)
41 | supports_swift_versions(supported_swift_versions)
42 | end
43 |
44 | # Explicitly set sources
45 | generator.configuration.sources.each do |source_url|
46 | source(source_url)
47 | end
48 |
49 | self.defined_in_file = dir.join('CocoaPods.podfile.yaml')
50 |
51 | test_specs = spec.recursive_subspecs.select(&:test_specification?)
52 | app_specs = if spec.respond_to?(:app_specification?)
53 | spec.recursive_subspecs.select(&:app_specification?)
54 | else
55 | []
56 | end
57 |
58 | # Stick all of the transitive dependencies in an abstract target.
59 | # This allows us to force CocoaPods to use the versions / sources / external sources
60 | # that we want.
61 | # By using an abstract target,
62 |
63 | # 会导致多个dependencies出现, 注释by slj
64 | # abstract_target 'Transitive Dependencies' do
65 | # pods_for_transitive_dependencies = [spec.name]
66 | # .concat(test_specs.map(&:name))
67 | # .concat(test_specs.flat_map { |ts| ts.dependencies.flat_map(&:name) })
68 | # .concat(app_specs.map(&:name))
69 | # .concat(app_specs.flat_map { |as| as.dependencies.flat_map(&:name) })
70 | #
71 | # dependencies = generator
72 | # .transitive_dependencies_by_pod
73 | # .values_at(*pods_for_transitive_dependencies)
74 | # .compact
75 | # .flatten(1)
76 | # .uniq
77 | # .sort_by(&:name)
78 | # .reject { |d| d.root_name == spec.root.name }
79 | #
80 | # dependencies.each do |dependency|
81 | # pod_args = generator.pod_args_for_dependency(self, dependency)
82 | # pod(*pod_args)
83 | # end
84 | # end
85 |
86 | # Add platform-specific concrete targets that inherit the
87 | # `pod` declaration for the local pod.
88 | spec_platform_names = spec.available_platforms.map(&:string_name).flatten.each.reject do |platform_name|
89 | !generator.configuration.platforms.nil? && !generator.configuration.platforms.include?(platform_name.downcase)
90 | end
91 |
92 | spec_platform_names.sort.each do |platform_name|
93 | target "App-#{platform_name}" do
94 | current_target_definition.swift_version = generator.swift_version if generator.swift_version
95 | end
96 | end
97 |
98 | # this block has to come _before_ inhibit_all_warnings! / use_modular_headers!,
99 | # and the local `pod` declaration
100 | # 会导致多个dependencies出现, 注释by slj
101 |
102 |
103 | inhibit_all_warnings! if generator.inhibit_all_warnings?
104 | use_modular_headers! if generator.use_modular_headers?
105 |
106 | # This is the pod declaration for the local pod,
107 | # it will be inherited by the concrete target definitions below
108 |
109 | pod_options = generator.dependency_compilation_kwargs(spec.name)
110 | pod_options[:path] = spec.defined_in_file.relative_path_from(dir).to_s
111 | # generator.configuration.podfile.dependencies[0].external_source
112 |
113 |
114 | { testspecs: test_specs, appspecs: app_specs }.each do |key, specs|
115 | pod_options[key] = specs.map { |s| s.name.sub(%r{^#{Regexp.escape spec.root.name}/}, '') }.sort unless specs.empty?
116 | end
117 |
118 | pod spec.name, **pod_options
119 |
120 | if Pod::Config.instance.podfile
121 | target_definitions['Pods'].instance_exec do
122 | target_definition = nil
123 | Pod::Config.instance.podfile.target_definition_list.each do |target|
124 | if target.label == "Pods-#{spec.name}"
125 | target_definition = target
126 | break
127 | end
128 | end
129 | # setting modular_headers_for
130 | if(target_definition && target_definition.use_modular_headers_hash.values.any?)
131 | target_definition.use_modular_headers_hash.values.each do |f|
132 | f.each { | pod_name| self.set_use_modular_headers_for_pod(pod_name, true) }
133 | end
134 | end
135 |
136 |
137 | if target_definition
138 | value = target_definition.to_hash['dependencies']
139 | next if value.blank?
140 | #删除 本地库中的 spec.name,因为本地的./spec.name地址是错的
141 | value.each do |f|
142 | if f.is_a?(Hash) && f.keys.first == spec.name
143 | value.delete f
144 | break
145 | end
146 | end
147 | old_value = self.to_hash['dependencies'].first
148 | value << old_value unless (old_value == nil || value.include?(old_value))
149 |
150 | set_hash_value(%w(dependencies).first, value)
151 |
152 | value = target_definition.to_hash['configuration_pod_whitelist']
153 | next if value.blank?
154 | set_hash_value(%w(configuration_pod_whitelist).first, value)
155 |
156 |
157 | end
158 |
159 |
160 | end
161 |
162 | end
163 |
164 | # if generator.configuration && generator.configuration.podfile
165 | # #变量本地podfile下的dependencies 写入新的验证文件中,指定依赖源
166 | # generator.configuration.podfile.dependencies.each { |dependencies|
167 | # #如果不存在dependencies.external_source,就不变量
168 | # next unless dependencies.external_source
169 | #
170 | # dependencies.external_source.each { |key_d, value|
171 | # pod_options = generator.dependency_compilation_kwargs(dependencies.name)
172 | # pod_options[key_d] = value.to_s
173 | # { testspecs: test_specs, appspecs: app_specs }.each do |key, specs|
174 | # pod_options[key] = specs.map { |s| s.name.sub(%r{^#{Regexp.escape spec.root.name}/}, '') }.sort unless specs.empty?
175 | # end
176 | # # 过滤 dependencies.name == spec.name
177 | # pod(dependencies.name, **pod_options) unless dependencies.name == spec.name
178 | # }
179 | # }
180 | # end
181 |
182 |
183 | # Implement local-sources option to set up dependencies to podspecs in the local filesystem.
184 | next if generator.configuration.local_sources.empty?
185 | generator.transitive_local_dependencies(spec, generator.configuration.local_sources).each do |dependency, podspec_file|
186 | pod_options = generator.dependency_compilation_kwargs(dependency.name)
187 | pod_options[:path] = if podspec_file[0] == '/' # absolute path
188 | podspec_file
189 | else
190 | '../../' + podspec_file
191 | end
192 | pod dependency.name, **pod_options
193 | end
194 | end
195 | end
196 | end
197 | end
198 | end
199 |
200 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/podspec_finder.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods-imy-bin/native/specification'
4 |
5 | module Pod
6 | class Sandbox
7 | class PodspecFinder
8 | def podspecs
9 | return @specs_by_name if @specs_by_name
10 |
11 | @specs_by_name = {}
12 | spec_files = Pathname.glob(root + '{,*}.podspec{,.json}')
13 | # pod 指向分支时,如果目标组件有 subspec ,并且有 template spec ,request 之后使用的 spec 不应该为 template spec
14 | # 这里做下过滤
15 | spec_files = spec_files.reject { |p| Specification::DEFAULT_TEMPLATE_EXTNAME.find { |e| p.to_s.end_with?(e) } }
16 | spec_files.sort_by { |p| -p.to_path.split(File::SEPARATOR).size }.each do |file|
17 | spec = Specification.from_file(file)
18 | spec.validate_cocoapods_version
19 | @specs_by_name[spec.name] = spec
20 | end
21 | @specs_by_name
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/resolver.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'parallel'
4 | require 'cocoapods'
5 | require 'cocoapods-imy-bin/native/podfile'
6 | require 'cocoapods-imy-bin/native/sources_manager'
7 | require 'cocoapods-imy-bin/native/installation_options'
8 | require 'cocoapods-imy-bin/gem_version'
9 | require 'cocoapods-imy-bin/command/bin/archive'
10 |
11 | module Pod
12 | class Resolver
13 | if Pod.match_version?('~> 1.6')
14 | # 其实不用到 resolver_specs_by_target 再改 spec
15 | # 在这个方法里面,通过修改 dependency 的 source 应该也可以
16 | # 就是有一点,如果改了之后,对应的 source 没有符合 dependency 的版本
17 | # 分析依赖阶段就会报错了,没法像 resolver_specs_by_target 一样
18 | # 没有对应的二进制版本时还可以转到源码源码
19 | #
20 | def aggregate_for_dependency(dependency)
21 | sources_manager = Config.instance.sources_manager
22 | if dependency&.podspec_repo
23 | sources_manager.aggregate_for_dependency(dependency)
24 | # 采用 lock 中的 source ,会导致插件对 source 的先后调整失效
25 | # elsif (locked_vertex = @locked_dependencies.vertex_named(dependency.name)) && (locked_dependency = locked_vertex.payload) && locked_dependency.podspec_repo
26 | # sources_manager.aggregate_for_dependency(locked_dependency)
27 | else
28 | @aggregate ||= Source::Aggregate.new(sources)
29 | end
30 | end
31 | end
32 |
33 | if Pod.match_version?('~> 1.4')
34 | def specifications_for_dependency(dependency, additional_requirements_frozen = [])
35 | additional_requirements = additional_requirements_frozen.dup.compact
36 | requirement = Requirement.new(dependency.requirement.as_list + additional_requirements.flat_map(&:as_list))
37 | if podfile.allow_prerelease? && !requirement.prerelease?
38 | requirement = Requirement.new(dependency.requirement.as_list.map { |r| r + '.a' } + additional_requirements.flat_map(&:as_list))
39 | end
40 |
41 | options = if Pod.match_version?('~> 1.7')
42 | podfile.installation_options
43 | else
44 | installation_options
45 | end
46 |
47 | if Pod.match_version?('~> 1.8')
48 | specifications = find_cached_set(dependency)
49 | .all_specifications(options.warn_for_multiple_pod_sources, requirement)
50 | else
51 | specifications = find_cached_set(dependency)
52 | .all_specifications(options.warn_for_multiple_pod_sources)
53 | .select { |s| requirement.satisfied_by? s.version }
54 | end
55 |
56 | specifications
57 | .map { |s| s.subspec_by_name(dependency.name, false, true) }
58 | .compact
59 | end
60 | end
61 |
62 | if Pod.match_version?('~> 1.6')
63 | alias old_valid_possibility_version_for_root_name? valid_possibility_version_for_root_name?
64 |
65 | def valid_possibility_version_for_root_name?(requirement, activated, spec)
66 | return true if podfile.allow_prerelease?
67 |
68 | old_valid_possibility_version_for_root_name?(requirement, activated, spec)
69 | end
70 | elsif Pod.match_version?('~> 1.4')
71 | def requirement_satisfied_by?(requirement, activated, spec)
72 | version = spec.version
73 | return false unless requirement.requirement.satisfied_by?(version)
74 |
75 | shared_possibility_versions, prerelease_requirement = possibility_versions_for_root_name(requirement, activated)
76 | if !shared_possibility_versions.empty? && !shared_possibility_versions.include?(version)
77 | return false
78 | end
79 | if !podfile.allow_prerelease? && version.prerelease? && !prerelease_requirement
80 | return false
81 | end
82 | unless spec_is_platform_compatible?(activated, requirement, spec)
83 | return false
84 | end
85 |
86 | true
87 | end
88 | end
89 |
90 | # >= 1.4.0 才有 resolver_specs_by_target 以及 ResolverSpecification
91 | # >= 1.5.0 ResolverSpecification 才有 source,供 install 或者其他操作时,输入 source 变更
92 | #
93 | if Pod.match_version?('~> 1.4')
94 | old_resolver_specs_by_target = instance_method(:resolver_specs_by_target)
95 | define_method(:resolver_specs_by_target) do
96 | specs_by_target = old_resolver_specs_by_target.bind(self).call
97 |
98 | sources_manager = Config.instance.sources_manager
99 | use_source_pods = podfile.use_source_pods
100 |
101 | missing_binary_specs = []
102 | specs_by_target.each do |target, rspecs|
103 | # use_binaries 并且 use_source_pods 不包含 本地可过滤
104 | use_binary_rspecs = if podfile.use_binaries? || podfile.use_binaries_selector
105 | rspecs.select do |rspec|
106 | ([rspec.name, rspec.root.name] & use_source_pods).empty? &&
107 | (podfile.use_binaries_selector.nil? || podfile.use_binaries_selector.call(rspec.spec))
108 | end
109 | else
110 | []
111 | end
112 |
113 | # Parallel.map(rspecs, in_threads: 8) do |rspec|
114 | specs_by_target[target] = rspecs.map do |rspec|
115 | # 含有 subspecs 的组件暂不处理
116 | # next rspec if rspec.spec.subspec? || rspec.spec.subspecs.any?
117 |
118 | # developments 组件采用默认输入的 spec (development pods 的 source 为 nil)
119 | # 可以使 :podspec => "htts://IMYFoundation.podspec"可以走下去,by slj
120 | # unless rspec.spec.respond_to?(:spec_source) && rspec.spec.spec_source
121 | # next rspec
122 | # end
123 |
124 | # 采用二进制依赖并且不为开发组件
125 | use_binary = use_binary_rspecs.include?(rspec)
126 | source = use_binary ? sources_manager.binary_source : sources_manager.code_source
127 |
128 | spec_version = rspec.spec.version
129 | UI.message 'cocoapods-imy-bin 插件'
130 | UI.message "- 开始处理 #{rspec.spec.name} #{spec_version} 组件."
131 |
132 | begin
133 | # 从新 source 中获取 spec,在bin archive中会异常,因为找不到
134 | specification = source.specification(rspec.root.name, spec_version)
135 | UI.message "#{rspec.root.name} #{spec_version} \r\n specification =#{specification} "
136 | # 组件是 subspec
137 | if rspec.spec.subspec?
138 | specification = specification.subspec_by_name(rspec.name, false, true)
139 | end
140 | # 这里可能出现分析依赖的 source 和切换后的 source 对应 specification 的 subspec 对应不上
141 | # 造成 subspec_by_name 返回 nil,这个是正常现象
142 | next unless specification
143 |
144 | used_by_only = if Pod.match_version?('~> 1.7')
145 | rspec.used_by_non_library_targets_only
146 | else
147 | rspec.used_by_tests_only
148 | end
149 | # used_by_only = rspec.respond_to?(:used_by_tests_only) ? rspec.used_by_tests_only : rspec.used_by_non_library_targets_only
150 | # 组装新的 rspec ,替换原 rspec
151 | if use_binary
152 | rspec = if Pod.match_version?('~> 1.4.0')
153 | ResolverSpecification.new(specification, used_by_only)
154 | else
155 | ResolverSpecification.new(specification, used_by_only, source)
156 | end
157 | UI.message "组装新的 rspec ,替换原 rspec #{rspec.root.name} #{spec_version} \r\n specification =#{specification} \r\n #{rspec} "
158 |
159 | end
160 |
161 | rescue Pod::StandardError => e
162 | # 没有从新的 source 找到对应版本组件,直接返回原 rspec
163 |
164 | # missing_binary_specs << rspec.spec if use_binary
165 | missing_binary_specs << rspec.spec
166 | rspec
167 | end
168 |
169 | rspec
170 | end.compact
171 | end
172 |
173 | if missing_binary_specs.any?
174 | missing_binary_specs.uniq.each do |spec|
175 | UI.message "【#{spec.name} | #{spec.version}】组件无对应二进制版本 , 将采用源码依赖."
176 | end
177 | Pod::Command::Bin::Archive.missing_binary_specs(missing_binary_specs)
178 |
179 | #缓存没有二进制组件到spec文件,local_psec_dir 目录
180 | sources_sepc = []
181 | des_dir = CBin::Config::Builder.instance.local_psec_dir
182 | FileUtils.rm_f(des_dir) if File.exist?des_dir
183 | Dir.mkdir des_dir unless File.exist?des_dir
184 | missing_binary_specs.uniq.each do |spec|
185 | next if spec.name.include?('/')
186 |
187 | spec_git_res = false
188 | CBin::Config::Builder.instance.ignore_git_list.each do |ignore_git|
189 | spec_git_res = spec.source[:git] && spec.source[:git].include?(ignore_git)
190 | break if spec_git_res
191 | end
192 | next if spec_git_res
193 |
194 | #获取没有制作二进制版本的spec集合
195 | sources_sepc << spec
196 | unless spec.defined_in_file.nil?
197 | FileUtils.cp("#{spec.defined_in_file}", "#{des_dir}")
198 | end
199 | end
200 | end
201 |
202 | specs_by_target
203 | end
204 | end
205 | end
206 |
207 | if Pod.match_version?('~> 1.4.0')
208 | # 1.4.0 没有 spec_source
209 | class Specification
210 | class Set
211 | class LazySpecification < BasicObject
212 | attr_reader :spec_source
213 |
214 | old_initialize = instance_method(:initialize)
215 | define_method(:initialize) do |name, version, source|
216 | old_initialize.bind(self).call(name, version, source)
217 |
218 | @spec_source = source
219 | end
220 |
221 | def respond_to?(method, include_all = false)
222 | return super unless method == :spec_source
223 |
224 | true
225 | end
226 | end
227 | end
228 | end
229 | end
230 | end
231 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/sandbox_analyzer.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | module Pod
4 | class Installer
5 | class Analyzer
6 | class SandboxAnalyzer
7 | # def pod_changed?(pod)
8 | # spec = root_spec(pod)
9 | # 有 subspec 的情况下,root spec 对应的 used_files 可能始终为空
10 | # 要添加为空 && 没有 subspec 的情况
11 | # file_accessors = spec.available_platforms.map { |platform| Sandbox::FileAccessor.new(sandbox.pod_dir(pod), spec.consumer(platform)) }
12 | # files = [
13 | # file_accessors.map(&:vendored_frameworks),
14 | # file_accessors.map(&:vendored_libraries),
15 | # file_accessors.map(&:resource_bundle_files),
16 | # file_accessors.map(&:prefix_header),
17 | # file_accessors.map(&:resources),
18 | # file_accessors.map(&:source_files),
19 | # file_accessors.map(&:module_map),
20 | # ]
21 | # used_files = files.flatten.compact.map(&:to_s).uniq
22 | # p pod if used_files.empty?
23 |
24 | # return true if spec.version != sandbox_version(pod)
25 | # return true if spec.checksum != sandbox_checksum(pod)
26 | # return true if resolved_spec_names(pod) != sandbox_spec_names(pod)
27 | # return true if sandbox.predownloaded?(pod)
28 | # return true if folder_empty?(pod)
29 | # false
30 | # end
31 | end
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/source.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods'
4 |
5 | module Pod
6 | class Source
7 | # Returns the path of the specification with the given name and version.
8 | #
9 | # @param [String] name
10 | # the name of the Pod.
11 | #
12 | # @param [Version,String] version
13 | # the version for the specification.
14 | #
15 | # @return [Pathname] The path of the specification.
16 | #
17 | def specification_path(name, version)
18 | raise ArgumentError, 'No name' unless name
19 | raise ArgumentError, 'No version' unless version
20 |
21 | path = pod_path(name) + version.to_s
22 |
23 | specification_path = Specification::VALID_EXTNAME
24 | .map { |extname| "#{name}#{extname}" }
25 | .map { |file| path + file }
26 | .find(&:exist?)
27 |
28 | unless specification_path
29 | raise StandardError, "Unable to find the specification #{name} " \
30 | "(#{version}) in the #{self.name} source."
31 | end
32 | specification_path
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/sources_manager.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods'
4 | require 'cocoapods-imy-bin/config/config'
5 |
6 | module Pod
7 | class Source
8 | class Manager
9 | # 源码 source
10 | def code_source
11 | source_with_name_or_url(CBin.config.code_repo_url)
12 | end
13 |
14 | # 二进制 source
15 | def binary_source
16 | source_with_name_or_url(CBin.config.binary_repo_url)
17 | end
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/specification.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | require 'cocoapods-imy-bin/native/sources_manager'
4 |
5 | module Pod
6 | class Specification
7 | VALID_EXTNAME = %w[.binary.podspec.json .binary.podspec .podspec.json .podspec].freeze
8 | DEFAULT_TEMPLATE_EXTNAME = %w[.binary-template.podspec .binary-template.podspec.json].freeze
9 |
10 | # TODO
11 | # 可以在这里根据组件依赖二进制或源码调整 sources 的先后顺序
12 | # 如果是源码,则调整 code_source 到最前面
13 | # 如果是二进制,则调整 binary_source 到最前面
14 | # 这样 CocoaPods 分析时,就会优先获取到对应源的 podspec
15 | #
16 | # 先要把 Podfile 里面的配置数据保存到单例中,再在这里判断,就不需要 resolver 了
17 | # 但是现在这个插件依旧可用,重构需要时间 = = ,没什么动力去重构了呀。。。
18 | #
19 | # class Set
20 | # old_initialize = instance_method(:initialize)
21 | # define_method(:initialize) do |name, sources|
22 | # if name == 'TDFAdaptationKit'
23 | # sources_manager = Pod::Config.instance.sources_manager
24 | # # sources = [sources_manager.binary_source, *sources].uniq
25 | # sources = [sources_manager.code_source, *sources].uniq
26 | # end
27 | # old_initialize.bind(self).call(name, sources)
28 | # end
29 | # end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/target_validator.rb:
--------------------------------------------------------------------------------
1 | module Pod
2 | class Installer
3 | class Xcode
4 | # The {Xcode::TargetValidator} ensures that the pod and aggregate target
5 | # configuration is valid for installation.
6 | #
7 | class TargetValidator
8 |
9 |
10 |
11 | def verify_swift_pods_have_module_dependencies
12 | error_messages = []
13 | pod_targets.each do |pod_target|
14 | next unless pod_target.uses_swift?
15 |
16 | non_module_dependencies = []
17 | pod_target.dependent_targets.each do |dependent_target|
18 | next if !dependent_target.should_build? || dependent_target.defines_module?
19 | non_module_dependencies << dependent_target.name
20 | end
21 |
22 | next if non_module_dependencies.empty?
23 |
24 | error_messages << "The Swift pod `#{pod_target.name}` depends upon #{non_module_dependencies.map { |d| "`#{d}`" }.to_sentence}, " \
25 | "which #{non_module_dependencies.count == 1 ? 'does' : 'do'} not define modules. " \
26 | 'To opt into those targets generating module maps '\
27 | '(which is necessary to import them from Swift when building as static libraries), ' \
28 | 'you may set `use_modular_headers!` globally in your Podfile, '\
29 | 'or specify `:modular_headers => true` for particular dependencies.'
30 | end
31 | return false
32 |
33 | # raise Informative, 'The following Swift pods cannot yet be integrated '\
34 | # "as static libraries:\n\n#{error_messages.join("\n\n")}"
35 | end
36 |
37 |
38 | end
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/native/validator.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | module Pod
4 | class Validator
5 | # def validate_source_url(spec)
6 | # return if spec.source.nil? || spec.source[:http].nil?
7 | # url = URI(spec.source[:http])
8 | # return if url.scheme == 'https' || url.scheme == 'file'
9 | # warning('http', "The URL (`#{url}`) doesn't use the encrypted HTTPs protocol. " \
10 | # 'It is crucial for Pods to be transferred over a secure protocol to protect your users from man-in-the-middle attacks. '\
11 | # 'This will be an error in future releases. Please update the URL to use https.')
12 | # end
13 | #
14 | # Perform analysis for a given spec (or subspec)
15 | #
16 | def perform_extensive_analysis(spec)
17 | return true
18 | end
19 |
20 | #覆盖
21 | def check_file_patterns
22 | FILE_PATTERNS.each do |attr_name|
23 | next if %i(source_files resources).include? attr_name
24 | if respond_to?("_validate_#{attr_name}", true)
25 | send("_validate_#{attr_name}")
26 | else
27 | validate_nonempty_patterns(attr_name, :error)
28 | end
29 | end
30 |
31 | _validate_header_mappings_dir
32 | if consumer.spec.root?
33 | _validate_license
34 | _validate_module_map
35 | end
36 | end
37 |
38 | def validate_source_url(spec); end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods-imy-bin/source_provider_hook.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/native/sources_manager'
2 | require 'cocoapods-imy-bin/command/bin/repo/update'
3 | require 'cocoapods/user_interface'
4 |
5 | Pod::HooksManager.register('cocoapods-imy-bin', :pre_install) do |_context, _|
6 | require 'cocoapods-imy-bin/native'
7 |
8 | # pod bin repo update 更新二进制私有源
9 | Pod::Command::Bin::Repo::Update.new(CLAide::ARGV.new([])).run
10 |
11 | # 有插件/本地库 且是dev环境下,默认进入源码白名单 过滤 archive命令
12 | if _context.podfile.plugins.keys.include?('cocoapods-imy-bin') && _context.podfile.configuration_env == 'dev'
13 | dependencies = _context.podfile.dependencies
14 | dependencies.each do |d|
15 | next unless d.respond_to?(:external_source) &&
16 | d.external_source.is_a?(Hash) &&
17 | !d.external_source[:path].nil? &&
18 | $ARGV[1] != 'archive'
19 | _context.podfile.set_use_source_pods d.name
20 | end
21 | end
22 |
23 | # 同步 BinPodfile 文件
24 | project_root = Pod::Config.instance.project_root
25 | path = File.join(project_root.to_s, 'BinPodfile')
26 |
27 | next unless File.exist?(path)
28 |
29 | contents = File.open(path, 'r:utf-8', &:read)
30 | podfile = Pod::Config.instance.podfile
31 | podfile.instance_eval do
32 | begin
33 | eval(contents, nil, path)
34 | rescue Exception => e
35 | message = "Invalid `#{path}` file: #{e.message}"
36 | raise Pod::DSLError.new(message, path, e, contents)
37 | end
38 | end
39 | end
40 |
41 | Pod::HooksManager.register('cocoapods-imy-bin', :source_provider) do |context, _|
42 | sources_manager = Pod::Config.instance.sources_manager
43 | podfile = Pod::Config.instance.podfile
44 |
45 | if podfile
46 | # 添加源码私有源 && 二进制私有源
47 | added_sources = [sources_manager.code_source]
48 | if podfile.use_binaries? || podfile.use_binaries_selector
49 | added_sources << sources_manager.binary_source
50 | added_sources.reverse!
51 | end
52 | added_sources.each { |source| context.add_source(source) }
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/lib/cocoapods_plugin.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-imy-bin/gem_version.rb'
2 | require 'cocoapods-imy-bin/command'
3 | require 'cocoapods-imy-bin/source_provider_hook'
4 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/spec/command/bin_spec.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../spec_helper', __FILE__)
2 |
3 | module Pod
4 | describe Command::Bin do
5 | describe 'CLAide' do
6 | it 'registers it self' do
7 | Command.parse(%w{ bin }).should.be.instance_of Command::Bin
8 | end
9 | end
10 | end
11 | end
12 |
13 |
--------------------------------------------------------------------------------
/cocoapods-imy-bin/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require 'pathname'
2 | ROOT = Pathname.new(File.expand_path('../../', __FILE__))
3 | $:.unshift((ROOT + 'lib').to_s)
4 | $:.unshift((ROOT + 'spec').to_s)
5 |
6 | require 'bundler/setup'
7 | require 'bacon'
8 | require 'mocha-on-bacon'
9 | require 'pretty_bacon'
10 | require 'pathname'
11 | require 'cocoapods'
12 |
13 | Mocha::Configuration.prevent(:stubbing_non_existent_method)
14 |
15 | require 'cocoapods_plugin'
16 |
17 | #-----------------------------------------------------------------------------#
18 |
19 | module Pod
20 |
21 | # Disable the wrapping so the output is deterministic in the tests.
22 | #
23 | UI.disable_wrap = true
24 |
25 | # Redirects the messages to an internal store.
26 | #
27 | module UI
28 | @output = ''
29 | @warnings = ''
30 |
31 | class << self
32 | attr_accessor :output
33 | attr_accessor :warnings
34 |
35 | def puts(message = '')
36 | @output << "#{message}\n"
37 | end
38 |
39 | def warn(message = '', actions = [])
40 | @warnings << "#{message}\n"
41 | end
42 |
43 | def print(message)
44 | @output << message
45 | end
46 | end
47 | end
48 | end
49 |
50 | #-----------------------------------------------------------------------------#
51 |
--------------------------------------------------------------------------------
/img/Podfile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetYouDevs/cocoapods-imy-bin/36b201004ea3610e3278429c48d3cf49b4b650d2/img/Podfile.png
--------------------------------------------------------------------------------
/img/Podfile_local.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetYouDevs/cocoapods-imy-bin/36b201004ea3610e3278429c48d3cf49b4b650d2/img/Podfile_local.png
--------------------------------------------------------------------------------
/img/time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetYouDevs/cocoapods-imy-bin/36b201004ea3610e3278429c48d3cf49b4b650d2/img/time.png
--------------------------------------------------------------------------------
/使用教程.md:
--------------------------------------------------------------------------------
1 | ## 一、概要
2 |
3 |
4 | cocoapods-imy-bin功能点:
5 |
6 | 1. 组件二进制化,`无入侵式`支持组件二进制化,完全自动化,无需手动操作。致力于解决Ci打包速度慢、研发编译慢等编译问题。
7 | 2. 本地配置文件 - `Podfile_local`
8 | 3. 二进制源码调试`pod bin code`,类似[美团 iOS 工程 zsource 命令背后的那些事儿](https://juejin.im/post/6847897745987125262)的效果。
9 | 4. 命令快捷键`pod bin imy`,如游戏快捷键,根据配置会在特定目录执行特定命令(如任意终端目录下,执行某个特定目录的pod update --no-repo-update命令),减少其他繁琐操作。支持任意个快捷键。
10 |
11 | cocoapods-imy-bin插件所关联的组件二进制化策略:
12 |
13 | 预先将打包成 `.a` 的组件保存到静态服务器上,并在 `install` 时,去下载组件对应的二进制版本,以减少组件编译时间,达到加快 App 打包、组件发布等操作的目的。
14 |
15 |
16 |
17 | ## 二、准备工作
18 |
19 |
20 |
21 | ### 1、安装插件
22 |
23 | ```shell
24 | sudo gem install cocoapods-imy-bin
25 | ```
26 |
27 |
28 |
29 | ## 三、使用二进制组件
30 |
31 |
32 | ### 1、环境搭建
33 |
34 |
35 |
36 | [环境搭建详细教程](https://github.com/su350380433/cocoapods-imy-bin-demo)
37 |
38 | 使用二进制时,本插件需要提供以下资源:
39 |
40 | - 静态资源服务器( [binary-server](https://github.com/su350380433/binary-server),附详细使用教程)
41 | - 二进制私有源仓库(保存组件二进制版本 podspec)
42 |
43 |
44 |
45 | ### 2、初始化插件
46 |
47 | ``` shell
48 | xx:Demo slj$ pod bin init
49 |
50 | ====== dev 环境 ========
51 |
52 | 开始设置二进制化初始信息.
53 | 所有的信息都会保存在 /Users/slj/.cocoapods/bin_dev.yml 文件中.
54 | %w[bin_dev.yml bin_debug_iphoneos.yml bin_release_iphoneos.yml]
55 | 你可以在对应目录下手动添加编辑该文件. 文件包含的配置信息样式如下:
56 |
57 | ---
58 | configuration_env: dev
59 | code_repo_url: git@github.com:su350380433/example_spec_source.git
60 | binary_repo_url: git@github.com:su350380433/example_spec_bin_dev.git
61 | binary_download_url: http://localhost:8080/frameworks/%s/%s/zip
62 | download_file_type: zip
63 |
64 |
65 | 编译环境
66 | 可选值:[ dev / debug_iphoneos / release_iphoneos ]
67 | 旧值:dev
68 | ```
69 |
70 | 按提示输入`所属环境`、源码私有源、二进制私有源、二进制下载地址、下载文件类型后,插件就配置完成了。其中 `binary_download_url` 需要预留组件名称与组件版本占位符,插件内部会依次替换 `%s` 为相应组件的值。
71 |
72 | `cococapods-imy-bin` 也支持从 url 下载配置文件,方便对多台机器进行配置:
73 |
74 | ```shell
75 | ➜ ~ pod bin init --bin-url=https://github.com/su350380433/cocoapods-imy-bin-configs/raw/master/bin_dev.yml
76 | ```
77 |
78 | 配置文件模版内容如下,根据不同团队的需求定制即可:
79 |
80 | ```shell
81 | ---
82 | configuration_env: dev
83 | code_repo_url: git@github.com:su350380433/example_spec_source.git
84 | binary_repo_url: git@github.com:su350380433/example_spec_bin_dev.git
85 | binary_download_url: http://localhost:8080/frameworks/%s/%s/zip
86 | download_file_type: zip
87 |
88 | ```
89 |
90 | 配置时,不需要手动添加源码和二进制私有源的 repo,插件在找不到对应 repo 时会主动 clone。
91 |
92 | 记得启动 `sudo mongod`服务,静态资源服务。
93 |
94 |
95 |
96 |
97 | ## 四、制作二进制组件
98 |
99 |
100 |
101 | [视频演示](https://github.com/MeetYouDevs/cocoapods-imy-bin/tree/master/%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91)
102 |
103 | ### 1、制作命令
104 |
105 | 可以直接使用插件的 `pod bin auto`命令,在插件初始化配置完成后,目录下只要有包含podspec文件,根据podspec文件的version版本号会自动化执行build、组装二进制组件、制作二进制podspec、上传二进制文件、上传二进制podspec到私有源仓库。
106 |
107 | ```shell
108 | pod bin auto
109 | ```
110 |
111 |
112 |
113 | ### 2. 二进制Podspec
114 |
115 | 会自动生成、上传,无需关心。
116 |
117 |
118 |
119 |
120 | ### 3、查看结果
121 |
122 | 二进制存储服务:[http://localhost:8080/frameworks/](http://localhost:8080/frameworks/)(默认本地8080端口)
123 |
124 | 二进制私有源参考:[https://github.com/su350380433/example_spec_bin_dev](https://github.com/su350380433/example_spec_bin_dev)(自定义)
125 |
126 |
127 |
128 |
129 | ### 4、使用二进制
130 |
131 |
132 |
133 | [视频演示](https://github.com/MeetYouDevs/cocoapods-imy-bin/tree/master/%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91)
134 |
135 | 在Podfile文件中,加入这两行代码,对已经制作二进制的就会生效,自动转换二进制组件依赖。
136 |
137 | ``` ruby
138 | plugin 'cocoapods-imy-bin'
139 | use_binaries!
140 | ```
141 |
142 |
143 |
144 |
145 | ## 五、扩展功能
146 |
147 |
148 |
149 | ### 1、本地配置文件 - Podfile_local
150 |
151 | 本地组件配置文件 Podfile_local,目前已支持Podfile下的大部分功能,可以把一些本地配置的语句放到Podfile_local。
152 |
153 |
154 |
155 | 场景:
156 |
157 | 1. 不希望把本地采用的源码/二进制配置、本地库传到远程仓库。
158 | 2. 避免直接修改Podfile文件,引起更新代码时冲突、或者误提交。
159 |
160 | 如Podfile本地库的写法:
161 |
162 | ```ruby
163 | pod YYModel :path => '../' #提交的时候往往要修改回来才提交,操作繁琐
164 | ```
165 |
166 | 用法:
167 |
168 | 在与Podfile同级目录下,新增一个`Podfile_local`文件
169 |
170 | ```ruby
171 | #target 'Seeyou' do 不同的项目注意修改下Seeyou的值
172 | #:path => '../IMYYQHome',根据实际情况自行修改,与之前在podfile写法一致
173 |
174 |
175 | plugin 'cocoapods-imy-bin'
176 | #是否启用二进制插件,想开启把下面注释去掉
177 | # use_binaries!
178 |
179 | #设置使用【源码】版本的组件。
180 | #set_use_source_pods ['YYKit','SDWebImaage']
181 |
182 | #需要替换Podfile里面的组件才写到这里
183 | #在这里面的所写的组件库依赖,默认切换为【源码】依赖
184 | target 'Seeyou' do
185 | #本地库引用
186 | #pod 'YYModel', :path => '../YYModel'
187 |
188 | #覆盖、自定义组件
189 | #pod 'YYCache', :podspec => 'http://覆盖、自定义/'
190 | end
191 | ```
192 |
193 | ```ruby
194 | 以前的 pod update --no-repo-update 命令加个前缀 `bin` 变成
195 | ```
196 |
197 | ```shell
198 | pod bin update --no-repo-update
199 | ```
200 |
201 | or
202 |
203 | ```shell
204 | pod bin install
205 | ```
206 |
207 | 支持 pod install/update 命令参数
208 |
209 | 并将其加入 .gitignore ,再也不用担心我误提交或者冲突了,Podfile_local 中的配置选项优先级比 Podfile 高,支持和 Podfile 相同的配置语句,同时支持**pre_install** or **post_install**。
210 |
211 |
212 | 如果您不习惯Podfile_local的使用方式,可以把命令写在Podfile里面,pod时不需要加bin,依旧是 pod update/install。
213 |
214 |
215 |
216 |
217 | ### 2、二进制源码调试
218 |
219 |
220 |
221 | [视频演示](https://github.com/MeetYouDevs/cocoapods-imy-bin/tree/master/%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91)
222 |
223 | 在项目根目录下,输入命令:
224 |
225 | ```ruby
226 | pod bin code YYModel
227 | ```
228 |
229 | `YYModel`为需要源码调试的组件库名称。成功之后像平时一样单步调试,控制台打印变量。让我们同时拥有使用二进制的便利和源码调试的能力。
230 |
231 | ``` shell
232 | $ pod bin code --help [11:37:50]
233 | Usage:
234 |
235 | $ pod bin code [NAME]
236 |
237 | 通过将二进制对应源码放置在临时目录中,让二进制出现断点时可以跳到对应的源码,方便调试。 在不删除二进制的情况下为某个组件添加源码调试能力,多个组件名称用空格分隔
238 |
239 | Options:
240 |
241 | --all-clean 删除所有已经下载的源码
242 | --clean 删除所有指定下载的源码
243 | --list 展示所有一级下载的源码以及其大小
244 | --source 源码路径,本地路径,会去自动链接本地源码
245 | ```
246 |
247 | 效果与演示参考[链接1](https://juejin.im/post/5eccceb9f265da76f30e4e13#heading-48)、[视频](https://github.com/MeetYouDevs/cocoapods-imy-bin/tree/master/%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91)
248 |
249 |
250 |
251 |
252 | ### 3、快捷键命令
253 |
254 |
255 |
256 | 在任意的终端执行命令,都能执行特定目录下特定命令
257 |
258 | 使用命令:
259 |
260 | ```shell
261 | pod bin imy
262 | ```
263 |
264 | or
265 |
266 | ``` shell
267 | pod bin imy 2 #2 是自定义的快捷键
268 | ```
269 |
270 | 使用场景:
271 |
272 | 1. 在任意目录下,执行项目A的pod update --no-repo-update命令
273 |
274 | 命令快捷键配置
275 |
276 | ```shell
277 | $ pod bin inithk [11:37:58]
278 |
279 | 开始设置快捷键 pod bin imy.
280 | 所有的信息都会保存在 /Users/ci/.cocoapods/hot_key_1.yml 文件中.
281 | %w[hot_key.yaml]
282 | 你可以在对应目录下手动添加编辑该文件. 文件包含的配置信息样式如下:
283 |
284 | ---
285 | hot_key_index: '1'
286 | hot_key_dir: '/User/ci/自定义目录'
287 | hot_key_cmd: pod bin update --no-repo-update
288 |
289 |
290 | 快捷键
291 | 可选值:[ 1 / 2 / 3... ]
292 | 旧值:1
293 | ```
294 |
295 |
296 |
297 |
298 | ## 六、 DSL参数解释
299 |
300 |
301 |
302 | 首先,开发者需要在 Podfile 中需要使用 `plugin 'cocoapods-imy-bin'` 语句引入插件
303 |
304 | ```ruby
305 | plugin 'cocoapods-imy-bin'
306 | ```
307 |
308 | 顺带可以删除 Podfile 中的 source ,因为插件内部会自动帮你添加两个私有源。
309 |
310 | `cocoapods-bin `插件提供二进制相关的配置语句有 `use_binaries!`、`use_binaries_with_spec_selector!` 以及 `set_use_source_pods`,下面会分别介绍。
311 |
312 | ##### use_binaries!
313 |
314 | 全部组件使用二进制版本。
315 |
316 | 支持传入布尔值控制是否使用二进制版本,比如 DEBUG 包使用二进制版本,正式包使用源码版本,Podfile 关联语句可以这样写:
317 |
318 | ```ruby
319 | use_binaries! (ENV['DEBUG'].nil? || ENV['DEBUG'] == 'true')
320 | ```
321 |
322 | ##### set_use_source_pods
323 |
324 | 设置使用源码版本的组件。
325 |
326 | 实际开发中,可能需要查看 YYModel 组件的源码,这时候可以这么设置:
327 |
328 | ```ruby
329 | set_use_source_pods ['YYModel']
330 | ```
331 |
332 | 如果 CocoaPods 版本为 1.5.3 ,终端会输出以下内容,表示 YYModel 的参照源从二进制私有源切换到了源码私有源:
333 |
334 | ```ruby
335 | Analyzing dependencies
336 | Fetching podspec for `A` from `../`
337 | Downloading dependencies
338 | Using A (0.1.0)
339 | Installing YYModel 1.0.4.2 (source changed to `git@git.xxxxxx.net:ios/cocoapods-spec.git` from `git@git.xxxxxx.net:ios/cocoapods-spec-binary.git`)
340 | Generating Pods project
341 | Integrating client project
342 | Sending stats
343 | Pod installation complete! There is 1 dependency from the Podfile and 2 total pods installed.
344 | ```
345 |
346 | ##### use_binaries_with_spec_selector!
347 |
348 | 过滤出需要使用二进制版本组件。
349 |
350 | 假如开发者只需要 `YYModel` 的二进制版本,那么他可以在 Podfile 中添加以下代码:
351 |
352 | ```ruby
353 | use_binaries_with_spec_selector! do |spec|
354 | spec.name == 'YYModel'
355 | end
356 | ```
357 |
358 | **需要注意的是,如果组件有 subspec ,使用组件名作为判断条件应如下**:
359 |
360 | ```ruby
361 | use_binaries_with_spec_selector! do |spec|
362 | spec.name.start_with? == '组件名'
363 | end
364 | ```
365 |
366 | 如果像上个代码块一样,**直接对比组件名,则插件会忽略此组件的所有 subspec,导致资源拉取错误**,这种场景下,最好通过 `set_use_source_pods` 语句配置依赖。
367 |
368 | 一个实际应用是,三方组件采用二进制版本,团队编写的组件依旧采用源码版本。如果三方组件都在 `cocoapods-repo` 组下,就可以使用以下代码过滤出三方组件:
369 |
370 | ```ruby
371 | use_binaries_with_spec_selector! do |spec|
372 | git = spec.source && spec.source['git']
373 | git && git.include?('cocoapods-repo')
374 | end
375 | ```
376 |
377 | ##### 切换Dev/Debug_iPhoneos/Release_iPhoneos环境初始化设置
378 |
379 |
380 | ```shell
381 | #dev 初始化插件配置 默认dev环境
382 | pod bin init --bin-url=https://gitlab.xxx.com/cocoapods-imy-bin-config/raw/master/bin_dev.yml
383 |
384 | #Debug_iPhoneos 初始化插件配置
385 | pod bin init --bin-url=https://gitlab.xxx.com/cocoapods-imy-bin-config/raw/master/bin_debug_iphoneos.yml
386 |
387 |
388 | #release_iPhoneos 初始化插件配置
389 | pod bin init --bin-url=https://gitlab.xxx.com/cocoapods-imy-bin-config/raw/master/bin_release_iphoneos.yml
390 | ```
391 |
392 | 使用时在podfile 或者 podfile_local指定设置
393 |
394 | ```shell
395 | #在podfile 或者 podfile_local 文件下加这句话
396 | set_configuration_env('debug_iphoneos')
397 | ```
398 |
399 | ##### 其他设置
400 |
401 | 插件默认开启多线程下载组件资源,如果要禁用这个功能,Podfile 添加以下代码即可:
402 |
403 | ```ruby
404 | install! 'cocoapods', { install_with_multi_threads: false }
405 | ```
406 |
407 |
408 |
409 |
410 | ## 七、感谢
411 |
412 |
413 |
414 | **[cocoapods-bin](https://github.com/tripleCC/cocoapods-bin)**
415 |
416 | [美团 iOS 工程 zsource 命令背后的那些事儿](https://tech.meituan.com/2019/08/08/the-things-behind-the-ios-project-zsource-command.html)
417 |
418 | #### 您有什么更好的想法,可以提出来,我们一起来实现,共创一个强大的工具平台,同时也欢迎给我们提PR。
419 |
420 |
--------------------------------------------------------------------------------
/演示视频/二进制源码调试演示.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetYouDevs/cocoapods-imy-bin/36b201004ea3610e3278429c48d3cf49b4b650d2/演示视频/二进制源码调试演示.mp4
--------------------------------------------------------------------------------
/演示视频/使用二进制.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetYouDevs/cocoapods-imy-bin/36b201004ea3610e3278429c48d3cf49b4b650d2/演示视频/使用二进制.mp4
--------------------------------------------------------------------------------
/演示视频/制作二进制组件.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetYouDevs/cocoapods-imy-bin/36b201004ea3610e3278429c48d3cf49b4b650d2/演示视频/制作二进制组件.mp4
--------------------------------------------------------------------------------