cocoapods-yaml 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +13 -0
- data/README.md +129 -0
- data/lib/cocoapods/yaml.rb +27 -0
- data/lib/cocoapods_plugin.rb +64 -0
- data/lib/core/check/import.rb +74 -0
- data/lib/core/check/item.rb +220 -0
- data/lib/core/check/podspec.rb +195 -0
- data/lib/core/check/project.rb +405 -0
- data/lib/core/check/simulator_arch.rb +145 -0
- data/lib/core/check/util.rb +37 -0
- data/lib/core/check/xcodeproj.rb +81 -0
- data/lib/core/command/trim_mode.rb +53 -0
- data/lib/core/command/yaml_init.rb +28 -0
- data/lib/core/command/yaml_relation.rb +43 -0
- data/lib/core/dep/find.rb +164 -0
- data/lib/core/indirect/indirect.rb +72 -0
- data/lib/core/logger.rb +85 -0
- data/lib/core/modify/source_patcher.rb +204 -0
- data/lib/core/my_constants.rb +16 -0
- data/lib/core/podfilelock.rb +17 -0
- data/lib/core/reference/project.rb +201 -0
- data/lib/core/reference/unused.rb +30 -0
- data/lib/core/setup/podfile_setup.rb +107 -0
- data/lib/core/thin/installer.rb +171 -0
- data/lib/core/thin/local.rb +40 -0
- data/lib/core/thin/pod_target.rb +32 -0
- data/lib/core/thin/shell.rb +180 -0
- data/lib/core/variable.rb +2 -0
- data/lib/core/yaml/yaml_dependencies.rb +774 -0
- data/lib/core/yaml/yaml_pod.rb +63 -0
- data/lib/core_helper.rb +10 -0
- data/lib/version.rb +7 -0
- metadata +133 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 82dbb70f4e4aed183d28e3155d99048f2fb4fab56b2c6937d705c0ff2254216f
|
|
4
|
+
data.tar.gz: 9dd087ceaa7cb278628592b8941965cee7e8708c543b5a6f889ad074d06a8f85
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 3559c6d25653e343f7c6776fdd0f7a7cd047ea24482f4171759e272a9cedb5cc6c922d8a9414e9971a7b3b0946c5ddb40e827e49545764f5a4bc176e3d1cbd6b
|
|
7
|
+
data.tar.gz: 05acafb2d925b7a0c9d785ceb623fe8d4a24264d2b3d1c090170db54d11061ae8c1e7567de6867e792493febcf58ed93460ee704ca067970ea0fcc5ff62a343b
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 - 2026-10-16
|
|
4
|
+
|
|
5
|
+
以 YAML 文件按 target 管理 CocoaPods 依赖的插件首个正式版本,安装后由 CocoaPods 自动加载。
|
|
6
|
+
|
|
7
|
+
- 每个 App/扩展 target 一个依赖文件,二方/三方组件统一维护,支持源地址变量复用
|
|
8
|
+
- 本地覆盖文件支持按组件名覆盖任意依赖做联调,新组件直接写入即自动集成
|
|
9
|
+
- 支持按源码引用关系自动裁剪未使用的依赖,加速编译,兼容 Xcode 16 与 Swift 工程
|
|
10
|
+
- 自动注册私有 specs 源并屏蔽官方 CDN 源,避免网络问题与多版本告警
|
|
11
|
+
- 内置 import 写法检查、依赖完整性检查、模拟器架构检查与三方库编译兼容补丁
|
|
12
|
+
- Debug 包内自动生成依赖清单,便于排查组件版本问题
|
|
13
|
+
- 提供依赖关系查询等辅助命令
|
data/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# cocoapods-yaml
|
|
2
|
+
|
|
3
|
+
以 YAML 文件按 target 管理 CocoaPods 依赖的插件。符合 `cocoapods-*` 插件命名约定,安装后由 CocoaPods 自动加载,Podfile 直接使用 `yaml_dependencies!` DSL
|
|
4
|
+
|
|
5
|
+
与 [pod-binary-pack](https://rubygems.org/gems/pod-binary-pack) 配套使用:本插件负责壳工程依赖管理与裁剪安装,后者负责组件二进制化打包与双私有源发布。
|
|
6
|
+
|
|
7
|
+
## 功能特性
|
|
8
|
+
|
|
9
|
+
- **按 target 管理依赖**:每个 App/扩展 target 一个依赖文件,二方/三方组件统一维护,支持 YAML 锚点变量复用源地址
|
|
10
|
+
- **本地覆盖联调**:`LocalDependencies.yaml` 按 pod 名覆盖任意依赖(path 联调),不提交 git;全新组件直接写入即自动集成主 App target
|
|
11
|
+
- **未使用依赖裁剪**:按源码 import 引用关系裁剪未使用依赖,加速编译;兼容 Xcode 16+ 同步分组与 Swift import
|
|
12
|
+
- **私有源管理**:自动注册私有 specs 源并屏蔽官方 CDN trunk,间接依赖优先命中二进制源
|
|
13
|
+
- **内置检查**:import 写法、podspec 依赖完整性、模拟器架构兼容、三方库源码编译兼容补丁,post_install 自动执行
|
|
14
|
+
- **Debug 依赖清单**:依赖清单 json 仅打入 Debug 包,便于排查组件版本
|
|
15
|
+
|
|
16
|
+
## 接入
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
# Podfile
|
|
20
|
+
platform :ios, '15.0'
|
|
21
|
+
|
|
22
|
+
yaml_dependencies! do |target_name|
|
|
23
|
+
# target_name: 当前集成的 target 名称(App/扩展),每个声明了依赖的 target 回调一次
|
|
24
|
+
# 可按 target 定制,例如扩展用静态库:
|
|
25
|
+
# use_frameworks! :linkage => :static if target_name == 'ShareExtension'
|
|
26
|
+
use_frameworks!
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
未接入的工程可执行 `pod yaml init` 自动生成模板 Podfile 与依赖文件(已有 Podfile 会先备份为 `Podfile.bak.时间戳` 再替换)。
|
|
31
|
+
|
|
32
|
+
## 依赖文件
|
|
33
|
+
|
|
34
|
+
放在工程根目录,两类:
|
|
35
|
+
|
|
36
|
+
| 文件 | 是否提交 git | 用途 |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `<Target>Dependencies.yaml` | 是 | 各 target 的依赖清单,二方/三方统一维护 |
|
|
39
|
+
| `LocalDependencies.yaml` | 否(自动加入 .gitignore) | 本地覆盖联调、临时引入新组件;`TRIM_UNUSED_POD`/`ENABLE_TRUNK` 开关 |
|
|
40
|
+
|
|
41
|
+
`<Target>Dependencies.yaml` 示例:
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
SOURCES:
|
|
45
|
+
- &binary git@gitee.com:xxx/specs.git # 二进制源(第一个,默认)
|
|
46
|
+
- &source git@gitee.com:xxx/specs.git # 源码源(备选)
|
|
47
|
+
|
|
48
|
+
PODS:
|
|
49
|
+
- pod: Masonry # 默认源 + 版本号引用
|
|
50
|
+
version: 1.1.0
|
|
51
|
+
- pod: BSDebugPlugins # 锚点引用源码源 + 仅 Debug 集成
|
|
52
|
+
version: 1.0.0-SNAPSHOT
|
|
53
|
+
source: *source
|
|
54
|
+
configurations: [Debug]
|
|
55
|
+
- pod: CocoaService # git 分支引用
|
|
56
|
+
git: git@gitee.com:xxx/CocoaService.git
|
|
57
|
+
branch: master
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### PODS 字段
|
|
61
|
+
|
|
62
|
+
| 字段 | 说明 |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| `pod` | 必填,组件名 |
|
|
65
|
+
| `version` / `path` / `podspec` / `git`+`tag` / `git`+`branch` | 引用方式,五选一 |
|
|
66
|
+
| `source` | 显式指定 specs 源,默认取 `SOURCES` 第一个 |
|
|
67
|
+
| `subspecs` | 仅集成指定 subspec(数组);与 `configurations` 互斥(CocoaPods 限制,插件自动展开为多条声明) |
|
|
68
|
+
| `configurations` | 仅在指定 Build Configuration 集成,如 `[Debug]` |
|
|
69
|
+
| `inhibit_warnings` | 屏蔽警告,target 文件默认 true、本地覆盖默认 false |
|
|
70
|
+
|
|
71
|
+
`LocalDependencies.yaml` 的引用方式与字段规则相同,并额外支持顶层开关:
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
TRIM_UNUSED_POD: false # 是否裁剪未使用依赖
|
|
75
|
+
ENABLE_TRUNK: false # 是否恢复官方 CDN trunk 源
|
|
76
|
+
PODS: []
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 本地覆盖与联调
|
|
80
|
+
|
|
81
|
+
- **同名覆盖**:LocalDependencies 中按 pod 名声明,覆盖任意 `<Target>Dependencies.yaml` 中的同名组件(通常写 `path` 做本地联调)
|
|
82
|
+
- **全新组件**:target 依赖文件都未声明的组件写入 LocalDependencies 后自动加入主 App target(不会被裁剪);App 扩展 target 不自动注入,需在对应依赖文件显式声明
|
|
83
|
+
- path 引用的本地仓库自动开启 SNAPSHOT tag 强制同步(`git fetch/pull` 自动前移被删除重建的 tag)
|
|
84
|
+
|
|
85
|
+
## 未使用依赖裁剪
|
|
86
|
+
|
|
87
|
+
开发模式下可开启,移除未被源码引用的依赖库以加速编译:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pod install --trim # 单次开启(优先于配置文件)
|
|
91
|
+
pod install --full # 单次关闭
|
|
92
|
+
pod update --trim # update 同样支持
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
或在 `LocalDependencies.yaml` 中设置 `TRIM_UNUSED_POD: true` 长期开启。
|
|
96
|
+
|
|
97
|
+
## 私有源管理
|
|
98
|
+
|
|
99
|
+
插件按各 target 依赖文件 `SOURCES` 的声明顺序注册 Podfile 顶层 source(二进制源优先,间接依赖优先命中二进制产物),并屏蔽官方 CDN trunk——trunk 既会因网络问题导致 `pod install` 失败,也会与私有源同名 podspec 产生多版本告警。确需 trunk 时在 `LocalDependencies.yaml` 设置 `ENABLE_TRUNK: true`。
|
|
100
|
+
|
|
101
|
+
## 内置检查(post_install 自动执行)
|
|
102
|
+
|
|
103
|
+
| 检查 | 说明 |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| import 检查 | 引号形式 import 在本组件找不到头文件时给出建议写法;多组件同名头文件列出候选;GBK 源文件容错 |
|
|
106
|
+
| podspec 检查 | 代码实际需要的模块 vs podspec 声明,报告可能缺失/未使用的依赖(含嵌套 subspec 与平台级声明);`DISABLE_CHECK_PODSPEC: true` 可关闭 |
|
|
107
|
+
| 模拟器架构检查 | 报告缺 arm64 模拟器 slice(需 Rosetta)或完全无模拟器 slice 的二进制依赖,Apple Silicon 链接失败根因预警 |
|
|
108
|
+
| 源码兼容补丁 | 三方库源码微调兼容新版 Xcode(YYText 链式比较、废弃头 `<netinet6/in6.h>`、FBRetainCycleDetector 等);命中文件警告输出,`COCOAPODS_YAML_SKIP_SOURCE_PATCH=1` 整体关闭 |
|
|
109
|
+
|
|
110
|
+
另自动完成:间接依赖及其引用方输出、Debug 依赖清单 json 生成与注入(Release 不入包)、yaml 文件加入 Pods 工程引用、孤儿依赖文件清理提示。
|
|
111
|
+
|
|
112
|
+
## 命令
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pod yaml init # 初始化/备份替换 Podfile 与依赖文件模板
|
|
116
|
+
pod yaml relation [组件名] # 从 Podfile.lock 查询正/反向依赖
|
|
117
|
+
# --forward 只看正向;--sort 按依赖数量排序
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 环境变量
|
|
121
|
+
|
|
122
|
+
| 变量 | 说明 |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| `COCOAPODS_YAML_VERBOSE` | 非空时输出调试细节(等效 `pod install --verbose`) |
|
|
125
|
+
| `COCOAPODS_YAML_SKIP_SOURCE_PATCH` | 非空时跳过全部三方库源码兼容补丁 |
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../core_helper'
|
|
4
|
+
require_relative '../version'
|
|
5
|
+
core_path = Core::CoreHelper.core_path
|
|
6
|
+
|
|
7
|
+
require "#{core_path}/logger"
|
|
8
|
+
require "#{core_path}/yaml/yaml_dependencies"
|
|
9
|
+
|
|
10
|
+
# 裁剪未使用依赖的下载流程补丁,是否裁剪由TRIM_UNUSED_POD/pod install/update --trim判定
|
|
11
|
+
require "#{core_path}/thin/installer"
|
|
12
|
+
|
|
13
|
+
module Pod
|
|
14
|
+
class Podfile
|
|
15
|
+
# DSL入口: 在Podfile中通过 yaml_dependencies! 接入
|
|
16
|
+
# block的参数为当前集成的target名(App/扩展),可按target定制 use_frameworks! 等配置
|
|
17
|
+
def yaml_dependencies!
|
|
18
|
+
plugin('cocoapods-yaml')
|
|
19
|
+
|
|
20
|
+
yaml_dep = Pod::YamlDependencies.new
|
|
21
|
+
CocoaPods::Yaml.log.info("cocoapods-yaml版本:#{CocoaPods::Yaml::VERSION}")
|
|
22
|
+
yaml_dep.install_yaml_dep(self) do |target_name|
|
|
23
|
+
yield(target_name) if block_given?
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# CocoaPods 插件入口:gem 以 cocoapods- 开头时,本文件会被 pod 命令自动加载,
|
|
4
|
+
# 因此 Podfile 无需手动 require,直接使用 yaml_dependencies! DSL 即可。
|
|
5
|
+
|
|
6
|
+
require 'cocoapods'
|
|
7
|
+
|
|
8
|
+
require_relative 'cocoapods/yaml'
|
|
9
|
+
|
|
10
|
+
require "#{Core::CoreHelper.core_path}/command/yaml_init"
|
|
11
|
+
require "#{Core::CoreHelper.core_path}/command/yaml_relation"
|
|
12
|
+
require "#{Core::CoreHelper.core_path}/command/trim_mode"
|
|
13
|
+
require "#{Core::CoreHelper.core_path}/check/project"
|
|
14
|
+
require "#{Core::CoreHelper.core_path}/check/podspec"
|
|
15
|
+
require "#{Core::CoreHelper.core_path}/check/simulator_arch"
|
|
16
|
+
require "#{Core::CoreHelper.core_path}/modify/source_patcher"
|
|
17
|
+
require "#{Core::CoreHelper.core_path}/reference/project"
|
|
18
|
+
require "#{Core::CoreHelper.core_path}/indirect/indirect"
|
|
19
|
+
require "#{Core::CoreHelper.core_path}/reference/unused"
|
|
20
|
+
require "#{Core::CoreHelper.core_path}/check/import"
|
|
21
|
+
|
|
22
|
+
# pod install/update 在工程目录但缺少Podfile时自动生成模板(零风险初始化);
|
|
23
|
+
# 已有Podfile但未接入时仅提示 pod yaml init,不自动替换
|
|
24
|
+
if ARGV.include?('install') || ARGV.include?('update')
|
|
25
|
+
CocoaPods::Yaml::PodfileSetup.auto_on_install
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module CocoapodsPlugin
|
|
29
|
+
|
|
30
|
+
Pod::HooksManager.register('cocoapods-yaml', :post_install) do |context|
|
|
31
|
+
|
|
32
|
+
project = Xcodeproj::XCodeProject.new
|
|
33
|
+
|
|
34
|
+
# 检查import
|
|
35
|
+
checker1 = Xcodeproj::ImportChecker.new(project)
|
|
36
|
+
checker1.check_import
|
|
37
|
+
|
|
38
|
+
# 检查podspec
|
|
39
|
+
checker2 = Xcodeproj::PodspecChecker.new(project)
|
|
40
|
+
checker2.check_podspec
|
|
41
|
+
|
|
42
|
+
# 模拟器架构兼容检查:找出模拟器产物不含arm64 slice的组件
|
|
43
|
+
# (Apple Silicon 上按默认 arm64 编译模拟器时链接失败的根因)
|
|
44
|
+
Xcodeproj::SimulatorArchChecker.new.check
|
|
45
|
+
|
|
46
|
+
# 三方库源码编译兼容补丁(netinet6 头替换、FBRetainCycleDetector 历史兼容等),
|
|
47
|
+
# 同时覆盖普通 pod 与打包期 :path 开发 pod
|
|
48
|
+
ModifyCode::SourcePatcher.patch(context.sandbox)
|
|
49
|
+
|
|
50
|
+
# 间接依赖
|
|
51
|
+
PodfileLock::Indirect.new.log_indirect
|
|
52
|
+
|
|
53
|
+
# 添加yaml到Pods工程引用和gitignore
|
|
54
|
+
Project::ProjectManager.yaml_reference
|
|
55
|
+
|
|
56
|
+
# 生成Debug包内依赖清单json并注入资源脚本(仅Debug)
|
|
57
|
+
Project::ProjectManager.dependency_manifest(context)
|
|
58
|
+
|
|
59
|
+
# 裁剪未使用依赖的开关提示
|
|
60
|
+
Unused::UnusedManager.check_unused
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require_relative 'project'
|
|
2
|
+
|
|
3
|
+
module Xcodeproj
|
|
4
|
+
class ImportChecker
|
|
5
|
+
|
|
6
|
+
# @return [XCodeProject]
|
|
7
|
+
attr_accessor :project
|
|
8
|
+
|
|
9
|
+
# @param project::[XCodeProject]
|
|
10
|
+
def initialize(project)
|
|
11
|
+
@project = project
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# 检查import规范
|
|
15
|
+
def check_import
|
|
16
|
+
CocoaPods::Yaml.log.step("import检查中...")
|
|
17
|
+
start = (Time.now.to_f * 1000).to_i
|
|
18
|
+
module_count = 0
|
|
19
|
+
file_count = 0
|
|
20
|
+
|
|
21
|
+
project.module_items.each do |module_name, module_item|
|
|
22
|
+
unless module_item.is_development_module
|
|
23
|
+
next
|
|
24
|
+
end
|
|
25
|
+
module_count += 1
|
|
26
|
+
|
|
27
|
+
messages = []
|
|
28
|
+
|
|
29
|
+
did_check_imports = {}
|
|
30
|
+
module_item.init_import_info
|
|
31
|
+
|
|
32
|
+
module_item.import_items.each do |import_item|
|
|
33
|
+
# 同一组件内同名import只检查一次(无论本组件能否找到头文件),避免重复告警与重复全量扫描
|
|
34
|
+
next if did_check_imports.key?(import_item.import_file_name)
|
|
35
|
+
did_check_imports[import_item.import_file_name] = true
|
|
36
|
+
file_count += 1
|
|
37
|
+
|
|
38
|
+
need_module_item = project.module_items[import_item.module_name]
|
|
39
|
+
real_path = need_module_item&.header_files&.[](import_item.import_file_name)
|
|
40
|
+
next if real_path
|
|
41
|
+
|
|
42
|
+
# 本组件找不到,去其他组件查找所属模块
|
|
43
|
+
expect_modules = find_modules_with_header_file(import_item.import_file_name)
|
|
44
|
+
if expect_modules.size == 1
|
|
45
|
+
messages << "#{import_item.file_path.basename} 第#{import_item.line_index}行 #{import_item.import_name} => #import <#{expect_modules.first}/#{import_item.import_file_name}>"
|
|
46
|
+
elsif expect_modules.size > 1
|
|
47
|
+
# 多个组件含同名头文件时无法确定归属,给出候选而不是猜测一个可能错误的组件
|
|
48
|
+
messages << "#{import_item.file_path.basename} 第#{import_item.line_index}行 #{import_item.import_name} 在本组件找不到该头文件,且组件#{expect_modules.join('、')}均含同名头文件,请手动确认正确写法"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if messages.size >0
|
|
53
|
+
CocoaPods::Yaml.log.warn("组件#{module_item.module_name}存在以下情况, 请检查:")
|
|
54
|
+
messages.each { |message| CocoaPods::Yaml.log.info(" #{message}") }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
duration = ((Time.now.to_f * 1000).to_i - start)*0.001
|
|
60
|
+
# 本检查器只解析开发组件源码中的引号形式import(#import "X.h"),尖括号形式由podspec检查器负责
|
|
61
|
+
CocoaPods::Yaml.log.detail("import检查完毕! 共检查#{module_count}个组件(#{file_count}处引号import,去重后) 耗时:#{duration.round(2)}秒")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
# 根据头文件名查找所有包含该头文件的组件(按头文件basename匹配)
|
|
66
|
+
# @return [Array<String>] 组件名列表;0个=无匹配,1个=可确定归属,>1个=重名无法确定
|
|
67
|
+
def find_modules_with_header_file(header_file_name)
|
|
68
|
+
project.module_items.each_with_object([]) do |(_module_name, module_item), result|
|
|
69
|
+
result << module_item.module_name if module_item.header_files[header_file_name]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
|
|
2
|
+
module Xcodeproj
|
|
3
|
+
class ImportItem
|
|
4
|
+
attr_accessor :import_name
|
|
5
|
+
attr_accessor :module_name
|
|
6
|
+
attr_accessor :file_path
|
|
7
|
+
attr_accessor :import_file_name
|
|
8
|
+
attr_accessor :line_index
|
|
9
|
+
attr_accessor :belong_module
|
|
10
|
+
def initialize
|
|
11
|
+
@import_name = nil
|
|
12
|
+
@module_name = nil
|
|
13
|
+
@file_path = nil
|
|
14
|
+
@import_file_name = nil
|
|
15
|
+
@line_index = nil
|
|
16
|
+
@belong_module = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class ModuleItem
|
|
22
|
+
|
|
23
|
+
public
|
|
24
|
+
# 组名名
|
|
25
|
+
attr_accessor :module_name
|
|
26
|
+
|
|
27
|
+
# 组件路径
|
|
28
|
+
attr_accessor :module_path
|
|
29
|
+
|
|
30
|
+
# podspec路径
|
|
31
|
+
attr_accessor :podspec_path
|
|
32
|
+
|
|
33
|
+
# 组件目录的所有被引用的文件数组
|
|
34
|
+
attr_accessor :header_files
|
|
35
|
+
|
|
36
|
+
# 组件目录的所有被引用的文件数组
|
|
37
|
+
attr_accessor :source_files
|
|
38
|
+
|
|
39
|
+
# 是否是开发模块
|
|
40
|
+
attr_accessor :is_development_module
|
|
41
|
+
|
|
42
|
+
# [ImportItem]
|
|
43
|
+
attr_accessor :import_items
|
|
44
|
+
|
|
45
|
+
# [ImportItem]
|
|
46
|
+
attr_accessor :absolute_import_items
|
|
47
|
+
|
|
48
|
+
# [String]
|
|
49
|
+
attr_accessor :frameworks
|
|
50
|
+
|
|
51
|
+
def initialize(module_name)
|
|
52
|
+
@module_name = module_name
|
|
53
|
+
@module_path = nil
|
|
54
|
+
@podspec_path = nil
|
|
55
|
+
@header_files = {}
|
|
56
|
+
@source_files = {}
|
|
57
|
+
@import_items = []
|
|
58
|
+
@absolute_import_items = []
|
|
59
|
+
@is_development_module = false
|
|
60
|
+
@frameworks = []
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# 生成 import <XX/YY.h>的信息
|
|
64
|
+
# 生成 include <XX/YY.h>的信息
|
|
65
|
+
def init_absolute_import_info
|
|
66
|
+
source_files.each_value do |source_file_path|
|
|
67
|
+
if File.directory?(source_file_path)
|
|
68
|
+
next
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
line_array = safe_readlines(source_file_path)
|
|
72
|
+
line_array.each_with_index { |line, line_index|
|
|
73
|
+
line = line.gsub(" ", "")
|
|
74
|
+
|
|
75
|
+
# 进入实现体后不再解析import(import按约定只出现在文件头部),
|
|
76
|
+
# 该判断必须在#import前缀过滤之前,否则@implementation行已被next而永远不可达
|
|
77
|
+
if line.start_with?("@implementation")
|
|
78
|
+
break
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# 处理特殊情况
|
|
82
|
+
if line.start_with?("#import\"NBSAppAgent.h\"")
|
|
83
|
+
line = "#import<tingyunApp/NBSAppAgent.h>"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
if not line.start_with?("#import<") and not line.start_with?("#include<")
|
|
87
|
+
next
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# 前一行用于识别条件编译(#if/#else)内的import
|
|
91
|
+
pre_index = line_index-1 < 0 ? 0 : line_index-1
|
|
92
|
+
pre_line = line_array[pre_index]
|
|
93
|
+
|
|
94
|
+
import_item = other_module_import(line, source_file_path, line_index, @module_name, pre_line)
|
|
95
|
+
if import_item
|
|
96
|
+
absolute_import_items << import_item
|
|
97
|
+
end
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
absolute_import_items
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# 生成 import "XXX.h"的信息
|
|
105
|
+
def init_import_info
|
|
106
|
+
source_files.each_value do |source_file_path|
|
|
107
|
+
if File.directory?(source_file_path)
|
|
108
|
+
next
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
line_array = safe_readlines(source_file_path)
|
|
112
|
+
line_array.each_with_index { |line, line_index|
|
|
113
|
+
line = line.gsub(" ", "")
|
|
114
|
+
|
|
115
|
+
# 进入实现体后不再解析import,判断必须在#import前缀过滤之前(否则该行已被next)
|
|
116
|
+
if line.start_with?("@implementation")
|
|
117
|
+
break
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
unless line.start_with?("#import")
|
|
121
|
+
next
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# 前一行的内容
|
|
125
|
+
pre_index = line_index-1 < 0 ? 0 : line_index-1
|
|
126
|
+
pre_line = line_array[pre_index]
|
|
127
|
+
|
|
128
|
+
if line.start_with?("#import\"") #本组件
|
|
129
|
+
import_item = own_module_import(line, source_file_path, line_index, @module_name, pre_line)
|
|
130
|
+
if import_item
|
|
131
|
+
import_items << import_item
|
|
132
|
+
end
|
|
133
|
+
elsif line.start_with?("#import<") #其他组件
|
|
134
|
+
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
import_items
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
# 生成自己模块的import item
|
|
145
|
+
# @param line 以 import" 开头
|
|
146
|
+
def own_module_import(line, file_path, line_index, module_name, pre_line)
|
|
147
|
+
line_split_array = line.split("\"")
|
|
148
|
+
if line_split_array.size <= 1
|
|
149
|
+
return nil
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
import_content = "#{line_split_array[0]}\"#{line_split_array[1]}\"" # import"XXX.h" 或import"XXX.AAA.h" 防止后边有其他内容
|
|
153
|
+
|
|
154
|
+
# 特殊处理
|
|
155
|
+
if import_content == "#import\"NBSAppAgent.h\""
|
|
156
|
+
return nil
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
pre_line = pre_line.gsub(" ", "").gsub("\n", "")
|
|
160
|
+
if pre_line.start_with?("#if") or pre_line == "#else"
|
|
161
|
+
return nil
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
import_file_name = import_content
|
|
165
|
+
import_file_name = import_file_name.gsub("#import\"", "")
|
|
166
|
+
import_file_name = import_file_name.gsub("\"", "")
|
|
167
|
+
# 统一取basename与header_files的键(头文件名)对齐,兼容 #import "Sub/X.h" 带子目录的写法
|
|
168
|
+
import_file_name = File.basename(import_file_name) # 变成 XX.h
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
import_item = ImportItem.new # (import_name, module_name, file_name, line_index, podfile)
|
|
172
|
+
import_item.import_name = import_content.gsub("#import\"", "#import \"")
|
|
173
|
+
import_item.module_name = module_name
|
|
174
|
+
import_item.file_path = file_path
|
|
175
|
+
import_item.import_file_name = import_file_name
|
|
176
|
+
import_item.line_index = line_index + 1
|
|
177
|
+
|
|
178
|
+
import_item
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def other_module_import(line, file_path, line_index, module_name, pre_line)
|
|
183
|
+
line = line.gsub("\n","")
|
|
184
|
+
line_split_array = line.split("/") #import<XX/YY.h> 或 #import<XX/YY/ZZ.h>
|
|
185
|
+
if line_split_array.size <= 1
|
|
186
|
+
return nil
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
pre_line = pre_line.gsub(" ", "").gsub("\n", "")
|
|
190
|
+
if pre_line.start_with?("#if") or pre_line == "#else"
|
|
191
|
+
return nil
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
import_file_name = line_split_array[line_split_array.size-1].gsub(">", "")
|
|
195
|
+
belong_module = line_split_array[0].gsub("#import<", "").gsub("#include<", "")
|
|
196
|
+
import_name = line.gsub("#import<", "#import <").gsub("#include<", "#include <")
|
|
197
|
+
|
|
198
|
+
import_item = ImportItem.new # (import_name, module_name, file_name, line_index, podfile)
|
|
199
|
+
import_item.import_name = import_name
|
|
200
|
+
import_item.module_name = module_name
|
|
201
|
+
import_item.file_path = file_path
|
|
202
|
+
import_item.import_file_name = import_file_name
|
|
203
|
+
import_item.line_index = line_index + 1
|
|
204
|
+
import_item.belong_module = belong_module
|
|
205
|
+
|
|
206
|
+
import_item
|
|
207
|
+
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# 容错读取源码行:历史工程可能存在GBK等非UTF-8文件。
|
|
211
|
+
# 注意: 直接给IO.readlines传encoding: 'utf-8'在内外编码相同时不会转码,非法字节仍会透传,
|
|
212
|
+
# 这里先按二进制读取,再显式做一次同编码转换替换非法字节,
|
|
213
|
+
# 避免后续字符串处理抛invalid byte sequence中断整个post_install钩子
|
|
214
|
+
def safe_readlines(file_path)
|
|
215
|
+
content = File.read(file_path, mode: 'rb')
|
|
216
|
+
content.encode!('UTF-8', 'UTF-8', invalid: :replace, undef: :replace, replace: '?')
|
|
217
|
+
content.lines
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|