my-cocoapods-packager 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +3 -0
  4. data/.rubocop-cocoapods.yml +71 -0
  5. data/.rubocop.yml +38 -0
  6. data/.travis.yml +9 -0
  7. data/Gemfile +12 -0
  8. data/Gemfile.lock +121 -0
  9. data/LICENSE +22 -0
  10. data/README.md +42 -0
  11. data/Rakefile +12 -0
  12. data/cocoapods-packager.gemspec +22 -0
  13. data/lib/cocoapods-packager/builder.rb +340 -0
  14. data/lib/cocoapods-packager/framework.rb +66 -0
  15. data/lib/cocoapods-packager/mangle.rb +32 -0
  16. data/lib/cocoapods-packager/pod_utils.rb +252 -0
  17. data/lib/cocoapods-packager/spec_builder.rb +63 -0
  18. data/lib/cocoapods-packager/symbols.rb +35 -0
  19. data/lib/cocoapods-packager/user_interface/build_failed_report.rb +15 -0
  20. data/lib/cocoapods_packager.rb +5 -0
  21. data/lib/cocoapods_plugin.rb +8 -0
  22. data/lib/pod/command/package.rb +163 -0
  23. data/scripts/lstconst.sh +9 -0
  24. data/scripts/lstsym.sh +8 -0
  25. data/spec/command/error_spec.rb +74 -0
  26. data/spec/command/package_spec.rb +359 -0
  27. data/spec/command/subspecs_spec.rb +30 -0
  28. data/spec/fixtures/Builder.podspec +25 -0
  29. data/spec/fixtures/CPDColors.podspec +19 -0
  30. data/spec/fixtures/FH.podspec +18 -0
  31. data/spec/fixtures/KFData.podspec +73 -0
  32. data/spec/fixtures/LibraryConsumerDemo/.gitignore +22 -0
  33. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer/AppDelegate.h +17 -0
  34. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer/AppDelegate.m +27 -0
  35. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer/Info.plist +40 -0
  36. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer/main.m +16 -0
  37. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer.xcodeproj/project.pbxproj +340 -0
  38. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  39. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer.xcodeproj/xcshareddata/xcschemes/LibraryConsumer.xcscheme +100 -0
  40. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer.xcworkspace/contents.xcworkspacedata +10 -0
  41. data/spec/fixtures/LibraryConsumerDemo/Podfile +5 -0
  42. data/spec/fixtures/LibraryDemo.podspec +14 -0
  43. data/spec/fixtures/NikeKit.podspec +19 -0
  44. data/spec/fixtures/OpenSans.podspec +18 -0
  45. data/spec/fixtures/PackagerTest/.gitignore +21 -0
  46. data/spec/fixtures/PackagerTest/PackagerTest/CPDAppDelegate.h +15 -0
  47. data/spec/fixtures/PackagerTest/PackagerTest/CPDAppDelegate.m +49 -0
  48. data/spec/fixtures/PackagerTest/PackagerTest/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  49. data/spec/fixtures/PackagerTest/PackagerTest/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  50. data/spec/fixtures/PackagerTest/PackagerTest/PackagerTest-Info.plist +38 -0
  51. data/spec/fixtures/PackagerTest/PackagerTest/PackagerTest-Prefix.pch +16 -0
  52. data/spec/fixtures/PackagerTest/PackagerTest/en.lproj/InfoPlist.strings +2 -0
  53. data/spec/fixtures/PackagerTest/PackagerTest/main.m +18 -0
  54. data/spec/fixtures/PackagerTest/PackagerTest.xcodeproj/project.pbxproj +536 -0
  55. data/spec/fixtures/PackagerTest/PackagerTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  56. data/spec/fixtures/PackagerTest/PackagerTest.xcodeproj/xcshareddata/xcschemes/PackagerTest.xcscheme +110 -0
  57. data/spec/fixtures/PackagerTest/PackagerTest.xcworkspace/contents.xcworkspacedata +1 -0
  58. data/spec/fixtures/PackagerTest/PackagerTestTests/PackagerTestTests-Info.plist +22 -0
  59. data/spec/fixtures/PackagerTest/PackagerTestTests/PackagerTestTests.m +34 -0
  60. data/spec/fixtures/PackagerTest/PackagerTestTests/en.lproj/InfoPlist.strings +2 -0
  61. data/spec/fixtures/PackagerTest/Podfile +10 -0
  62. data/spec/fixtures/PackagerTest/Podfile.lock +32 -0
  63. data/spec/fixtures/Weakly.podspec +13 -0
  64. data/spec/fixtures/a.podspec +19 -0
  65. data/spec/fixtures/foo-bar.podspec +19 -0
  66. data/spec/fixtures/layer-client-messaging-schema.podspec +13 -0
  67. data/spec/integration/project_spec.rb +70 -0
  68. data/spec/pod/utils_spec.rb +58 -0
  69. data/spec/spec_helper.rb +50 -0
  70. data/spec/specification/builder_spec.rb +40 -0
  71. data/spec/specification/spec_builder_spec.rb +61 -0
  72. data/spec/user_interface/build_failed_report_spec.rb +11 -0
  73. metadata +212 -0
@@ -0,0 +1,63 @@
1
+ module Pod
2
+ class SpecBuilder
3
+ def initialize(spec, source, embedded, dynamic)
4
+ @spec = spec
5
+ @source = source.nil? ? '{ :path => \'.\' }' : source
6
+ @embedded = embedded
7
+ @dynamic = dynamic
8
+ end
9
+
10
+ def framework_path
11
+ if @embedded
12
+ @spec.name + '.embeddedframework' + '/' + @spec.name + '.framework'
13
+ else
14
+ @spec.name + '.framework'
15
+ end
16
+ end
17
+
18
+ def spec_platform(platform)
19
+ fwk_base = platform.name.to_s + '/' + framework_path
20
+ spec = <<RB
21
+ s.#{platform.name}.deployment_target = '#{platform.deployment_target}'
22
+ s.#{platform.name}.vendored_framework = '#{fwk_base}'
23
+ RB
24
+
25
+ %w(frameworks weak_frameworks libraries requires_arc xcconfig).each do |attribute|
26
+ attributes_hash = @spec.attributes_hash[platform.name.to_s]
27
+ next if attributes_hash.nil?
28
+ value = attributes_hash[attribute]
29
+ next if value.nil?
30
+
31
+ value = "'#{value}'" if value.class == String
32
+ spec += " s.#{platform.name}.#{attribute} = #{value}\n"
33
+ end
34
+ spec
35
+ end
36
+
37
+ def spec_metadata
38
+ spec = spec_header
39
+ spec
40
+ end
41
+
42
+ def spec_close
43
+ "end\n"
44
+ end
45
+
46
+ private
47
+
48
+ def spec_header
49
+ spec = "Pod::Spec.new do |s|\n"
50
+
51
+ %w(name version summary license authors homepage description social_media_url
52
+ docset_url documentation_url screenshots frameworks weak_frameworks libraries requires_arc
53
+ deployment_target xcconfig).each do |attribute|
54
+ value = @spec.attributes_hash[attribute]
55
+ next if value.nil?
56
+ value = value.dump if value.class == String
57
+ spec += " s.#{attribute} = #{value}\n"
58
+ end
59
+
60
+ spec + " s.source = #{@source}\n\n"
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,35 @@
1
+ module Symbols
2
+ def symbols_from_library(library)
3
+ syms = `nm -gU #{library}`.split("\n")
4
+ result = classes_from_symbols(syms)
5
+ result += constants_from_symbols(syms)
6
+
7
+ result.reject { |e| e == 'llvm.cmdline' || e == 'llvm.embedded.module' }
8
+ end
9
+
10
+ module_function :symbols_from_library
11
+
12
+ private
13
+
14
+ def classes_from_symbols(syms)
15
+ classes = syms.select { |klass| klass[/OBJC_CLASS_\$_/] }
16
+ classes = classes.uniq
17
+ classes.map! { |klass| klass.gsub(/^.*\$_/, '') }
18
+ end
19
+
20
+ def constants_from_symbols(syms)
21
+ consts = syms.select { |const| const[/ S /] }
22
+ consts = consts.select { |const| const !~ /OBJC|\.eh/ }
23
+ consts = consts.uniq
24
+ consts = consts.map! { |const| const.gsub(/^.* _/, '') }
25
+
26
+ other_consts = syms.select { |const| const[/ T /] }
27
+ other_consts = other_consts.uniq
28
+ other_consts = other_consts.map! { |const| const.gsub(/^.* _/, '') }
29
+
30
+ consts + other_consts
31
+ end
32
+
33
+ module_function :classes_from_symbols
34
+ module_function :constants_from_symbols
35
+ end
@@ -0,0 +1,15 @@
1
+ module Pod
2
+ module UserInterface
3
+ module BuildFailedReport
4
+ class << self
5
+ def report(command, output)
6
+ <<-EOF
7
+ Build command failed: #{command}
8
+ Output:
9
+ #{output.map { |line| " #{line}" }.join}
10
+ EOF
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Pod
2
+ module Packager
3
+ VERSION = '1.5.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require 'pod/command/package'
2
+ require 'cocoapods-packager/user_interface/build_failed_report'
3
+ require 'cocoapods-packager/builder'
4
+ require 'cocoapods-packager/framework'
5
+ require 'cocoapods-packager/mangle'
6
+ require 'cocoapods-packager/pod_utils'
7
+ require 'cocoapods-packager/spec_builder'
8
+ require 'cocoapods-packager/symbols'
@@ -0,0 +1,163 @@
1
+ require 'tmpdir'
2
+ module Pod
3
+ class Command
4
+ class Package < Command
5
+ self.summary = 'Package a podspec into a static library.'
6
+ self.arguments = [
7
+ CLAide::Argument.new('NAME', true),
8
+ CLAide::Argument.new('SOURCE', false)
9
+ ]
10
+
11
+ def self.options
12
+ [
13
+ ['--force', 'Overwrite existing files.'],
14
+ ['--no-mangle', 'Do not mangle symbols of depedendant Pods.'],
15
+ ['--embedded', 'Generate embedded frameworks.'],
16
+ ['--library', 'Generate static libraries.'],
17
+ ['--dynamic', 'Generate dynamic framework.'],
18
+ ['--bundle-identifier', 'Bundle identifier for dynamic framework'],
19
+ ['--exclude-deps', 'Exclude symbols from dependencies.'],
20
+ ['--configuration', 'Build the specified configuration (e.g. Debug). Defaults to Release'],
21
+ ['--subspecs', 'Only include the given subspecs'],
22
+ ['--spec-sources=private,https://github.com/CocoaPods/Specs.git', 'The sources to pull dependant ' \
23
+ 'pods from (defaults to https://github.com/CocoaPods/Specs.git)']
24
+ ]
25
+ end
26
+
27
+ def initialize(argv)
28
+ @embedded = argv.flag?('embedded')
29
+ @force = argv.flag?('force')
30
+ @library = argv.flag?('library')
31
+ @dynamic = argv.flag?('dynamic')
32
+ @mangle = argv.flag?('mangle', true)
33
+ @bundle_identifier = argv.option('bundle-identifier', nil)
34
+ @exclude_deps = argv.flag?('exclude-deps', false)
35
+ @name = argv.shift_argument
36
+ @source = argv.shift_argument
37
+ @spec_sources = argv.option('spec-sources', 'https://github.com/CocoaPods/Specs.git').split(',')
38
+
39
+ subspecs = argv.option('subspecs')
40
+ @subspecs = subspecs.split(',') unless subspecs.nil?
41
+
42
+ @config = argv.option('configuration', 'Release')
43
+
44
+ @source_dir = Dir.pwd
45
+ @spec = spec_with_path(@name)
46
+ @spec = spec_with_name(@name) unless @spec
47
+ super
48
+ end
49
+
50
+ def validate!
51
+ super
52
+ help! 'A podspec name or path is required.' unless @spec
53
+ help! 'podspec has binary-only depedencies, mangling not possible.' if @mangle && binary_only?(@spec)
54
+ help! '--bundle-identifier option can only be used for dynamic frameworks' if @bundle_identifier && !@dynamic
55
+ help! '--exclude-deps option can only be used for static libraries' if @exclude_deps && @dynamic
56
+ end
57
+
58
+ def run
59
+ if @path.nil? || @spec.nil?
60
+ help! 'Unable to find a podspec with path or name.'
61
+ return
62
+ end
63
+
64
+ target_dir, work_dir = create_working_directory
65
+ return if target_dir.nil?
66
+ build_package
67
+
68
+ `mv "#{work_dir}" "#{target_dir}"`
69
+ Dir.chdir(@source_dir)
70
+ end
71
+
72
+ private
73
+
74
+ def build_in_sandbox(platform)
75
+ config.installation_root = Pathname.new(Dir.pwd)
76
+ config.sandbox_root = 'Pods'
77
+
78
+ static_sandbox = build_static_sandbox(@dynamic)
79
+ static_installer = install_pod(platform.name, static_sandbox)
80
+
81
+ if @dynamic
82
+ dynamic_sandbox = build_dynamic_sandbox(static_sandbox, static_installer)
83
+ install_dynamic_pod(dynamic_sandbox, static_sandbox, static_installer)
84
+ end
85
+
86
+ begin
87
+ perform_build(platform, static_sandbox, dynamic_sandbox)
88
+
89
+ ensure # in case the build fails; see Builder#xcodebuild.
90
+ Pathname.new(config.sandbox_root).rmtree
91
+ FileUtils.rm_f('Podfile.lock')
92
+ end
93
+ end
94
+
95
+ def build_package
96
+ builder = SpecBuilder.new(@spec, @source, @embedded, @dynamic)
97
+ newspec = builder.spec_metadata
98
+
99
+ @spec.available_platforms.each do |platform|
100
+ build_in_sandbox(platform)
101
+
102
+ newspec += builder.spec_platform(platform)
103
+ end
104
+
105
+ newspec += builder.spec_close
106
+ File.open(@spec.name + '.podspec', 'w') { |file| file.write(newspec) }
107
+ end
108
+
109
+ def create_target_directory
110
+ target_dir = "#{@source_dir}/#{@spec.name}-#{@spec.version}"
111
+ if File.exist? target_dir
112
+ if @force
113
+ Pathname.new(target_dir).rmtree
114
+ else
115
+ UI.puts "Target directory '#{target_dir}' already exists."
116
+ return nil
117
+ end
118
+ end
119
+ target_dir
120
+ end
121
+
122
+ def create_working_directory
123
+ target_dir = create_target_directory
124
+ return if target_dir.nil?
125
+
126
+ work_dir = Dir.tmpdir + '/cocoapods-' + Array.new(8) { rand(36).to_s(36) }.join
127
+ Pathname.new(work_dir).mkdir
128
+ `cp #{@path} #{work_dir}`
129
+ Dir.chdir(work_dir)
130
+
131
+ [target_dir, work_dir]
132
+ end
133
+
134
+ def perform_build(platform, static_sandbox, dynamic_sandbox)
135
+ static_sandbox_root = config.sandbox_root.to_s
136
+
137
+ if @dynamic
138
+ static_sandbox_root = "#{static_sandbox_root}/#{static_sandbox.root.to_s.split('/').last}"
139
+ dynamic_sandbox_root = "#{config.sandbox_root}/#{dynamic_sandbox.root.to_s.split('/').last}"
140
+ end
141
+
142
+ builder = Pod::Builder.new(
143
+ @source_dir,
144
+ static_sandbox_root,
145
+ dynamic_sandbox_root,
146
+ static_sandbox.public_headers.root,
147
+ @spec,
148
+ @embedded,
149
+ @mangle,
150
+ @dynamic,
151
+ @config,
152
+ @bundle_identifier,
153
+ @exclude_deps
154
+ )
155
+
156
+ builder.build(platform, @library)
157
+
158
+ return unless @embedded
159
+ builder.link_embedded_resources
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,9 @@
1
+ #!/bin/sh
2
+
3
+ #
4
+ # List symbols for all constants
5
+ #
6
+
7
+ nm "$@"|grep ' S '|grep -v 'OBJC\|\.eh$'| \
8
+ cut -d_ -f2-|sort|uniq
9
+ nm "$@"|grep ' T '|cut -d_ -f2-|sort|uniq
data/scripts/lstsym.sh ADDED
@@ -0,0 +1,8 @@
1
+ #!/bin/sh
2
+
3
+ #
4
+ # List symbols for all Objective-C classes
5
+ #
6
+
7
+ nm "$@"| grep 'OBJC_CLASS_\$_'|grep -v '_NS\|_UI'| \
8
+ rev|cut -d' ' -f-1|rev|sort|uniq|cut -d'_' -f5-
@@ -0,0 +1,74 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ module Pod
4
+ describe 'Packager' do
5
+ after do
6
+ Dir.glob("CPDColors-*").each { |dir| Pathname.new(dir).rmtree }
7
+ Dir.glob("layer-client-messaging-schema-*").each { |dir| Pathname.new(dir).rmtree }
8
+ Dir.glob("OpenSans-*").each { |dir| Pathname.new(dir).rmtree }
9
+ Dir.glob("Weakly-*").each { |dir| Pathname.new(dir).rmtree }
10
+ end
11
+
12
+ it 'presents the help if a directory is provided' do
13
+ should.raise CLAide::Help do
14
+ command = Command.parse(%w{ package spec })
15
+ end.message.should.match /is a directory/
16
+ end
17
+
18
+ it 'presents the help if a random file is provided instead of a specification' do
19
+ should.raise CLAide::Help do
20
+ command = Command.parse(%w{ package README.md })
21
+ end.message.should.match /is not a podspec/
22
+ end
23
+
24
+ it 'presents the help if a podspec with binary-only dependencies is used' do
25
+ command = Command.parse(%w{ package spec/fixtures/CPDColors.podspec })
26
+ should.raise CLAide::Help do
27
+ command.validate!
28
+ end.message.should.match /binary-only/
29
+ end
30
+
31
+ it 'presents the help if only --bundle-identifier is specified' do
32
+ command = Command.parse(%w{ package spec/fixtures/NikeKit.podspec --bundle-identifier=com.example.NikeKit })
33
+ should.raise CLAide::Help do
34
+ command.validate!
35
+ end.message.should.match /--bundle-identifier option can only be used for dynamic frameworks/
36
+ end
37
+
38
+ it 'presents the help if both --exclude-deps and --dynamic are specified' do
39
+ command = Command.parse(%w{ package spec/fixtures/NikeKit.podspec --exclude-deps --dynamic })
40
+ should.raise CLAide::Help do
41
+ command.validate!
42
+ end.message.should.match /--exclude-deps option can only be used for static libraries/
43
+ end
44
+
45
+ it 'can package a podspec with only resources' do
46
+ command = Command.parse(%w{ package spec/fixtures/layer-client-messaging-schema.podspec --no-mangle })
47
+ command.run
48
+
49
+ true.should == true # To make the test pass without any shoulds
50
+ end
51
+
52
+ it 'can package a podspec with binary-only dependencies if --no-mangle is specified' do
53
+ command = Command.parse(%w{ package spec/fixtures/CPDColors.podspec --no-mangle })
54
+ command.run
55
+
56
+ true.should == true # To make the test pass without any shoulds
57
+ end
58
+
59
+ it 'can package a podspec with resource bundles' do
60
+ command = Command.parse(%w{ package spec/fixtures/OpenSans.podspec })
61
+ command.run
62
+
63
+ bundles = Dir.glob('OpenSans-*/ios/OpenSans.framework/Versions/A/Resources/*.bundle')
64
+ bundles.count.should == 1
65
+ end
66
+
67
+ it 'can package a podspec with weak frameworks without strong linking' do
68
+ command = Command.parse(%w{ package spec/fixtures/Weakly.podspec })
69
+ command.run
70
+
71
+ `otool -l Weakly-*/ios/Weakly.framework/Weakly`.should.not.match /AssetsLibrary/
72
+ end
73
+ end
74
+ end