cocoapods-miBin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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