cocoapods-miBin 0.1.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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rakeTasks +7 -0
  4. data/Gemfile +13 -0
  5. data/Gemfile.lock +104 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +522 -0
  8. data/Rakefile +13 -0
  9. data/cocoapods-miBin.gemspec +27 -0
  10. data/lib/cocoapods-miBin.rb +4 -0
  11. data/lib/cocoapods-miBin/command.rb +3 -0
  12. data/lib/cocoapods-miBin/command/bin.rb +60 -0
  13. data/lib/cocoapods-miBin/command/bin/archive.rb +134 -0
  14. data/lib/cocoapods-miBin/command/bin/init.rb +71 -0
  15. data/lib/cocoapods-miBin/command/bin/lib.rb +14 -0
  16. data/lib/cocoapods-miBin/command/bin/lib/lint.rb +69 -0
  17. data/lib/cocoapods-miBin/command/bin/list.rb +50 -0
  18. data/lib/cocoapods-miBin/command/bin/open.rb +61 -0
  19. data/lib/cocoapods-miBin/command/bin/repo.rb +15 -0
  20. data/lib/cocoapods-miBin/command/bin/repo/push.rb +116 -0
  21. data/lib/cocoapods-miBin/command/bin/repo/update.rb +42 -0
  22. data/lib/cocoapods-miBin/command/bin/search.rb +69 -0
  23. data/lib/cocoapods-miBin/command/bin/spec.rb +15 -0
  24. data/lib/cocoapods-miBin/command/bin/spec/create.rb +75 -0
  25. data/lib/cocoapods-miBin/command/bin/spec/lint.rb +111 -0
  26. data/lib/cocoapods-miBin/command/bin/umbrella.rb +55 -0
  27. data/lib/cocoapods-miBin/config/config.rb +81 -0
  28. data/lib/cocoapods-miBin/config/config_asker.rb +58 -0
  29. data/lib/cocoapods-miBin/gem_version.rb +11 -0
  30. data/lib/cocoapods-miBin/helpers.rb +5 -0
  31. data/lib/cocoapods-miBin/helpers/framework.rb +64 -0
  32. data/lib/cocoapods-miBin/helpers/framework_builder.rb +227 -0
  33. data/lib/cocoapods-miBin/helpers/sources_helper.rb +33 -0
  34. data/lib/cocoapods-miBin/helpers/spec_creator.rb +159 -0
  35. data/lib/cocoapods-miBin/helpers/spec_files_helper.rb +77 -0
  36. data/lib/cocoapods-miBin/native.rb +21 -0
  37. data/lib/cocoapods-miBin/native/acknowledgements.rb +27 -0
  38. data/lib/cocoapods-miBin/native/analyzer.rb +53 -0
  39. data/lib/cocoapods-miBin/native/installation_options.rb +26 -0
  40. data/lib/cocoapods-miBin/native/installer.rb +116 -0
  41. data/lib/cocoapods-miBin/native/linter.rb +26 -0
  42. data/lib/cocoapods-miBin/native/path_source.rb +33 -0
  43. data/lib/cocoapods-miBin/native/pod_source_installer.rb +19 -0
  44. data/lib/cocoapods-miBin/native/pod_target.rb +8 -0
  45. data/lib/cocoapods-miBin/native/podfile.rb +79 -0
  46. data/lib/cocoapods-miBin/native/podfile_env.rb +36 -0
  47. data/lib/cocoapods-miBin/native/podspec_finder.rb +25 -0
  48. data/lib/cocoapods-miBin/native/resolver.rb +200 -0
  49. data/lib/cocoapods-miBin/native/sandbox_analyzer.rb +34 -0
  50. data/lib/cocoapods-miBin/native/source.rb +35 -0
  51. data/lib/cocoapods-miBin/native/sources_manager.rb +20 -0
  52. data/lib/cocoapods-miBin/native/specification.rb +31 -0
  53. data/lib/cocoapods-miBin/native/validator.rb +16 -0
  54. data/lib/cocoapods-miBin/source_provider_hook.rb +21 -0
  55. data/lib/cocoapods_plugin.rb +5 -0
  56. data/spec/command/bin_spec.rb +12 -0
  57. data/spec/spec_helper.rb +50 -0
  58. metadata +173 -0
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pod
4
+ class Command
5
+ class Bin < Command
6
+ class Umbrella < Bin
7
+ self.summary = '生成伞头文件 .'
8
+
9
+ self.arguments = [
10
+ CLAide::Argument.new('PATH', false)
11
+ ]
12
+
13
+ def initialize(argv)
14
+ @path = Pathname.new(argv.shift_argument || '.')
15
+ @spec_file = code_spec_files.first
16
+ super
17
+ end
18
+
19
+ def validate!
20
+ super
21
+ if @spec_file.nil?
22
+ help! '[!] No `Podspec` found in the project directory.'
23
+ end
24
+ end
25
+
26
+ def run
27
+ pod_name = @spec_file.to_s.split('.').first
28
+
29
+ @path += "#{pod_name}.h" if @path.directory?
30
+
31
+ UI.puts "Generateing umbrella file for #{pod_name}"
32
+
33
+ header_generator = Pod::Generator::Header.new(Platform.ios)
34
+ spec = Pod::Specification.from_file(Pathname.new(@spec_file))
35
+ public_header_files = spec.consumer(:ios).public_header_files
36
+ if public_header_files.empty?
37
+ public_header_files = spec.consumer(:ios).source_files
38
+ end
39
+ public_header_files = Pathname.glob(public_header_files).map(&:basename).select do |pathname|
40
+ pathname.extname.to_s == '.h' &&
41
+ pathname.basename('.h').to_s != pod_name
42
+ end
43
+
44
+ header_generator.imports = public_header_files
45
+
46
+ UI.puts "Save umbrella file to #{@path.expand_path}"
47
+
48
+ header_generator.save_as(@path)
49
+
50
+ UI.puts 'Done!'.green
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module CBin
6
+ class Config
7
+ def config_file
8
+ File.expand_path("#{Pod::Config.instance.home_dir}/bin.yml")
9
+ end
10
+
11
+ def template_hash
12
+ {
13
+ 'code_repo_url' => { description: '源码私有源 Git 地址', default: 'git@git.n.xiaomi.com:hanyunhui/xmspec.git' },
14
+ 'binary_repo_url' => { description: '二进制私有源 Git 地址', default: 'git@git.n.xiaomi.com:xmmodule/xmspec-binary.git' },
15
+ 'binary_download_url' => { description: '二进制下载地址,内部会依次传入组件名称与版本,替换字符串中的 %s ', default: 'https://ios.home.mi.com/down/mihome/frameworks/%s/%s/%s_binary.zip' },
16
+ # 'binary_type' => { description: '二进制打包类型', default: 'framework', selection: %w[framework library] },
17
+ 'download_file_type' => { description: '下载二进制文件类型', default: 'zip', selection: %w[zip tgz tar tbz txz dmg] }
18
+ }
19
+ end
20
+
21
+ def sync_config(config)
22
+ File.open(config_file, 'w+') do |f|
23
+ f.write(config.to_yaml)
24
+ end
25
+ end
26
+
27
+ def default_config
28
+ @default_config ||= Hash[template_hash.map { |k, v| [k, v[:default]] }]
29
+ end
30
+
31
+ private
32
+
33
+ def load_config
34
+ default_config
35
+ #if File.exist?(config_file)
36
+ # YAML.load_file(config_file)
37
+ #else
38
+ # default_config
39
+ #end
40
+ end
41
+
42
+ def config
43
+ @config ||= begin
44
+ @config = OpenStruct.new load_config
45
+ validate!
46
+ @config
47
+ end
48
+ end
49
+
50
+ def validate!
51
+ template_hash.each do |k, v|
52
+ selection = v[:selection]
53
+ next if !selection || selection.empty?
54
+
55
+ config_value = @config.send(k)
56
+ next unless config_value
57
+ unless selection.include?(config_value)
58
+ raise Pod::Informative, "#{k} 字段的值必须限定在可选值 [ #{selection.join(' / ')} ] 内".red
59
+ end
60
+ end
61
+ end
62
+
63
+ def respond_to_missing?(method, include_private = false)
64
+ config.respond_to?(method) || super
65
+ end
66
+
67
+ def method_missing(method, *args, &block)
68
+ if config.respond_to?(method)
69
+ config.send(method, *args)
70
+ elsif template_hash.keys.include?(method.to_s)
71
+ raise Pod::Informative, "#{method} 字段必须在配置文件 #{config_file} 中设置, 请执行 init 命令配置或手动修改配置文件".red
72
+ else
73
+ super
74
+ end
75
+ end
76
+ end
77
+
78
+ def self.config
79
+ @config ||= Config.new
80
+ end
81
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'cocoapods-miBin/config/config'
5
+
6
+ module CBin
7
+ class Config
8
+ class Asker
9
+ def show_prompt
10
+ print ' > '.green
11
+ end
12
+
13
+ def ask_with_answer(question, pre_answer, selection)
14
+ print "\n#{question}\n"
15
+
16
+ print_selection_info = lambda {
17
+ print "可选值:[ #{selection.join(' / ')} ]\n" if selection
18
+ }
19
+ print_selection_info.call
20
+ print "旧值:#{pre_answer}\n" unless pre_answer.nil?
21
+
22
+ answer = ''
23
+ loop do
24
+ show_prompt
25
+ answer = STDIN.gets.chomp.strip
26
+
27
+ if answer == '' && !pre_answer.nil?
28
+ answer = pre_answer
29
+ print answer.yellow
30
+ print "\n"
31
+ end
32
+
33
+ next if answer.empty?
34
+ break if !selection || selection.include?(answer)
35
+
36
+ print_selection_info.call
37
+ end
38
+
39
+ answer
40
+ end
41
+
42
+ def wellcome_message
43
+ print <<~EOF
44
+
45
+ 开始设置二进制化初始信息.
46
+ 所有的信息都会保存在 #{CBin.config.config_file} 文件中.
47
+ 你可以在对应目录下手动添加编辑该文件. 文件包含的配置信息样式如下:
48
+
49
+ #{CBin.config.default_config.to_yaml}
50
+ EOF
51
+ end
52
+
53
+ def done_message
54
+ print "\n设置完成.\n".green
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CBin
4
+ VERSION = '0.1.0'
5
+ end
6
+
7
+ module Pod
8
+ def self.match_version?(*version)
9
+ Gem::Dependency.new('', *version).match?('', Pod::VERSION)
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods-miBin/helpers/sources_helper'
4
+ require 'cocoapods-miBin/helpers/spec_creator'
5
+ require 'cocoapods-miBin/helpers/spec_files_helper'
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # copy from https://github.com/CocoaPods/cocoapods-packager
4
+
5
+ module CBin
6
+ class Framework
7
+ attr_reader :headers_path
8
+ attr_reader :module_map_path
9
+ attr_reader :resources_path
10
+ attr_reader :root_path
11
+ attr_reader :versions_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
28
+ (Pathname.new(@fwk_path) + Pathname.new('Resources')).delete
29
+ end
30
+
31
+ private
32
+
33
+ def make_current_version
34
+ current_version_path = @versions_path + Pathname.new('../Current')
35
+ `ln -sf A #{current_version_path}`
36
+ `ln -sf Versions/Current/Headers #{@fwk_path}/`
37
+ `ln -sf Versions/Current/Resources #{@fwk_path}/`
38
+ `ln -sf Versions/Current/#{@name} #{@fwk_path}/`
39
+ end
40
+
41
+ def make_framework
42
+ @fwk_path = @root_path + Pathname.new(@name + '.framework')
43
+ @fwk_path.mkdir unless @fwk_path.exist?
44
+
45
+ @module_map_path = @fwk_path + Pathname.new('Modules')
46
+ @versions_path = @fwk_path + Pathname.new('Versions/A')
47
+ end
48
+
49
+ def make_headers
50
+ @headers_path = @versions_path + Pathname.new('Headers')
51
+ @headers_path.mkpath unless @headers_path.exist?
52
+ end
53
+
54
+ def make_resources
55
+ @resources_path = @versions_path + Pathname.new('Resources')
56
+ @resources_path.mkpath unless @resources_path.exist?
57
+ end
58
+
59
+ def make_root
60
+ @root_path = Pathname.new(@platform)
61
+ @root_path.mkpath unless @root_path.exist?
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ # copy from https://github.com/CocoaPods/cocoapods-packager
4
+
5
+ require 'cocoapods-miBin/helpers/framework.rb'
6
+
7
+ module CBin
8
+ class Framework
9
+ class Builder
10
+ include Pod
11
+
12
+ def initialize(spec, file_accessor, platform, source_dir)
13
+ @spec = spec
14
+ @source_dir = source_dir
15
+ @file_accessor = file_accessor
16
+ @platform = platform
17
+ @vendored_libraries = (file_accessor.vendored_static_frameworks + file_accessor.vendored_static_libraries).map(&:to_s)
18
+ end
19
+
20
+ def build
21
+ UI.section("Building static framework #{@spec}") do
22
+ defines = compile
23
+
24
+ build_sim_libraries(defines)
25
+ #output = framework.versions_path + Pathname.new(@spec.name)
26
+ #build_static_library_for_ios(output)
27
+ #
28
+ #copy_headers
29
+ #copy_license
30
+ #copy_resources
31
+ package_framework
32
+ #cp_to_source_dir
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def package_framework
39
+ `mkdir -p #{@source_dir}/#{@spec.name}_binary`
40
+ @vendored_libraries.each do |libs|
41
+ #puts libs
42
+ #puts libs.class
43
+ lib_base_name = File.basename(libs)
44
+ `cp -fa #{libs} #{@source_dir}/#{@spec.name}_binary/#{lib_base_name}`
45
+ end
46
+ sim_path = Pathname.new("#{@source_dir}/bin-archive/#{@spec.name}/build-simulator/#{@spec.name}.framework/#{@spec.name}")
47
+ arm_path = Pathname.new("#{@source_dir}/bin-archive/#{@spec.name}/build/#{@spec.name}.framework/#{@spec.name}")
48
+ arm_framework_path = Pathname.new("#{@source_dir}/bin-archive/#{@spec.name}/build/#{@spec.name}.framework")
49
+ #puts sim_path
50
+ #puts arm_path
51
+ `cp -fa #{arm_framework_path} #{@source_dir}/#{@spec.name}_binary`
52
+ `lipo -create #{arm_path} #{sim_path} -output #{@source_dir}/#{@spec.name}_binary/#{@spec.name}.framework/#{@spec.name}`
53
+
54
+ end
55
+
56
+ def cp_to_source_dir
57
+ target_dir = "#{@source_dir}/#{@spec.name}.framework"
58
+ FileUtils.rm_rf(target_dir) if File.exist?(target_dir)
59
+
60
+ `cp -fa #{@platform}/#{@spec.name}.framework #{@source_dir}`
61
+ end
62
+
63
+ def build_sim_libraries(defines)
64
+ UI.message 'Building simulator libraries'
65
+ xcodebuild(defines, '-sdk iphonesimulator', 'build-simulator')
66
+ end
67
+
68
+ def copy_headers
69
+ public_headers = @file_accessor.public_headers
70
+ UI.message "Copying public headers #{public_headers.map(&:basename).map(&:to_s)}"
71
+
72
+ public_headers.each do |h|
73
+ `ditto #{h} #{framework.headers_path}/#{h.basename}`
74
+ end
75
+
76
+ # If custom 'module_map' is specified add it to the framework distribution
77
+ # otherwise check if a header exists that is equal to 'spec.name', if so
78
+ # create a default 'module_map' one using it.
79
+ if !@spec.module_map.nil?
80
+ module_map_file = @file_accessor.module_map
81
+ if Pathname(module_map_file).exist?
82
+ module_map = File.read(module_map_file)
83
+ end
84
+ elsif public_headers.map(&:basename).map(&:to_s).include?("#{@spec.name}.h")
85
+ module_map = <<-MAP
86
+ framework module #{@spec.name} {
87
+ umbrella header "#{@spec.name}.h"
88
+
89
+ export *
90
+ module * { export * }
91
+ }
92
+ MAP
93
+ end
94
+
95
+ unless module_map.nil?
96
+ UI.message "Writing module map #{module_map}"
97
+ unless framework.module_map_path.exist?
98
+ framework.module_map_path.mkpath
99
+ end
100
+ File.write("#{framework.module_map_path}/module.modulemap", module_map)
101
+ end
102
+ end
103
+
104
+ def copy_license
105
+ UI.message 'Copying license'
106
+ license_file = @spec.license[:file] || 'LICENSE'
107
+ `cp "#{license_file}" .` if Pathname(license_file).exist?
108
+ end
109
+
110
+ def copy_resources
111
+ bundles = Dir.glob('./build/*.bundle')
112
+
113
+ bundle_names = [@spec, *@spec.recursive_subspecs].flat_map do |spec|
114
+ consumer = spec.consumer(@platform)
115
+ consumer.resource_bundles.keys +
116
+ consumer.resources.map do |r|
117
+ File.basename(r, '.bundle') if File.extname(r) == 'bundle'
118
+ end
119
+ end.compact.uniq
120
+
121
+ bundles.select! do |bundle|
122
+ bundle_name = File.basename(bundle, '.bundle')
123
+ bundle_names.include?(bundle_name)
124
+ end
125
+
126
+ if bundles.count > 0
127
+ UI.message "Copying bundle files #{bundles}"
128
+ bundle_files = bundles.join(' ')
129
+ `cp -rp #{bundle_files} #{framework.resources_path} 2>&1`
130
+ end
131
+
132
+ resources = [@spec, *@spec.recursive_subspecs].flat_map do |spec|
133
+ expand_paths(spec.consumer(@platform).resources)
134
+ end.compact.uniq
135
+
136
+ if resources.count == 0 && bundles.count == 0
137
+ framework.delete_resources
138
+ return
139
+ end
140
+ if resources.count > 0
141
+ UI.message "Copying resources #{resources}"
142
+ `cp -rp #{resources.join(' ')} #{framework.resources_path}`
143
+ end
144
+ end
145
+
146
+ def static_libs_in_sandbox(build_dir = 'build')
147
+ Dir.glob("#{build_dir}/lib#{target_name}.a")
148
+ end
149
+
150
+ def build_static_library_for_ios(output)
151
+ UI.message "Building ios libraries with archs #{ios_architectures}"
152
+ static_libs = static_libs_in_sandbox('build') + static_libs_in_sandbox('build-simulator') + @vendored_libraries
153
+ libs = ios_architectures.map do |arch|
154
+ library = "build/package-#{arch}.a"
155
+ `libtool -arch_only #{arch} -static -o #{library} #{static_libs.join(' ')}`
156
+ library
157
+ end
158
+
159
+ `lipo -create -output #{output} #{libs.join(' ')}`
160
+ end
161
+
162
+ def ios_build_options
163
+ "ARCHS=\'#{ios_architectures.join(' ')}\' OTHER_CFLAGS=\'-fembed-bitcode -Qunused-arguments\'"
164
+ end
165
+
166
+ def ios_architectures
167
+ archs = %w[x86_64 arm64 armv7 armv7s i386]
168
+ @vendored_libraries.each do |library|
169
+ if File.extname(Pathname.new(library)) == ".framework"
170
+ file_base = File.basename(library,".framework")
171
+ archs = `lipo -info #{library}/#{file_base}`.split & archs
172
+ elsif
173
+ archs = `lipo -info #{library}`.split & archs
174
+ end
175
+ end
176
+ archs
177
+ end
178
+
179
+ def compile
180
+ defines = "GCC_PREPROCESSOR_DEFINITIONS='$(inherited)'"
181
+ defines += ' '
182
+ defines += @spec.consumer(@platform).compiler_flags.join(' ')
183
+
184
+ options = ios_build_options
185
+ xcodebuild(defines, options)
186
+
187
+ defines
188
+ end
189
+
190
+ def target_name
191
+ if @spec.available_platforms.count > 1
192
+ "#{@spec.name}-#{Platform.string_name(@spec.consumer(@platform).platform_name)}"
193
+ else
194
+ @spec.name
195
+ end
196
+ end
197
+
198
+ def xcodebuild(defines = '', args = '', build_dir = 'build')
199
+ command = "xcodebuild #{defines} #{args} CONFIGURATION_BUILD_DIR=#{build_dir} clean build -configuration Release -target #{target_name} -project ./Pods.xcodeproj 2>&1"
200
+ output = `#{command}`.lines.to_a
201
+ if $?.exitstatus != 0
202
+ raise <<~EOF
203
+ Build command failed: #{command}
204
+ Output:
205
+ #{output.map { |line| " #{line}" }.join}
206
+ EOF
207
+
208
+ Process.exit
209
+ end
210
+ end
211
+
212
+ def expand_paths(path_specs)
213
+ path_specs.map do |path_spec|
214
+ Dir.glob(File.join(@source_dir, path_spec))
215
+ end
216
+ end
217
+
218
+ def framework
219
+ @framework ||= begin
220
+ framework = Framework.new(@spec.name, @platform.name.to_s)
221
+ framework.make
222
+ framework
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end