xcoder 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/spec/TestProject/TestProject.xcodeproj/project.pbxproj +801 -433
  2. data/spec/build_phase_spec.rb +1 -1
  3. data/spec/builder_spec.rb +54 -32
  4. data/spec/configuration_list_spec.rb +38 -0
  5. data/spec/configuration_spec.rb +5 -6
  6. data/spec/group_spec.rb +43 -32
  7. data/spec/integration/builder_spec.rb +60 -0
  8. data/spec/integration/cedar_install_spec.rb +107 -0
  9. data/spec/integration/pull_to_refresh_install_spec.rb +36 -0
  10. data/spec/integration/reachability_install_spec.rb +43 -0
  11. data/spec/keychain_spec.rb +2 -2
  12. data/spec/project_spec.rb +55 -6
  13. data/spec/scheme_spec.rb +1 -2
  14. data/spec/spec_helper.rb +2 -1
  15. data/spec/target_spec.rb +93 -3
  16. data/spec/test_report_spec.rb +2 -2
  17. data/spec/workspace_spec.rb +1 -2
  18. metadata +25 -48
  19. data/.gitignore +0 -7
  20. data/.rvmrc +0 -4
  21. data/Gemfile +0 -11
  22. data/Guardfile +0 -13
  23. data/README.md +0 -125
  24. data/Rakefile +0 -16
  25. data/lib/xcode/build_file.rb +0 -22
  26. data/lib/xcode/build_phase.rb +0 -46
  27. data/lib/xcode/builder.rb +0 -182
  28. data/lib/xcode/buildfile.rb +0 -101
  29. data/lib/xcode/configuration.rb +0 -129
  30. data/lib/xcode/core_ext/array.rb +0 -23
  31. data/lib/xcode/core_ext/boolean.rb +0 -21
  32. data/lib/xcode/core_ext/fixnum.rb +0 -5
  33. data/lib/xcode/core_ext/hash.rb +0 -27
  34. data/lib/xcode/core_ext/string.rb +0 -11
  35. data/lib/xcode/file_reference.rb +0 -29
  36. data/lib/xcode/group.rb +0 -118
  37. data/lib/xcode/info_plist.rb +0 -41
  38. data/lib/xcode/keychain.rb +0 -77
  39. data/lib/xcode/parsers/plutil_project_parser.rb +0 -20
  40. data/lib/xcode/project.rb +0 -190
  41. data/lib/xcode/provisioning_profile.rb +0 -53
  42. data/lib/xcode/registry.rb +0 -120
  43. data/lib/xcode/resource.rb +0 -187
  44. data/lib/xcode/scheme.rb +0 -36
  45. data/lib/xcode/shell.rb +0 -21
  46. data/lib/xcode/target.rb +0 -94
  47. data/lib/xcode/test/report_parser.rb +0 -172
  48. data/lib/xcode/testflight.rb +0 -56
  49. data/lib/xcode/variant_group.rb +0 -8
  50. data/lib/xcode/version.rb +0 -3
  51. data/lib/xcode/workspace.rb +0 -40
  52. data/lib/xcoder.rb +0 -105
  53. data/xcoder.gemspec +0 -26
data/.gitignore DELETED
@@ -1,7 +0,0 @@
1
- *.gem
2
- .bundle
3
- Gemfile.lock
4
- pkg/*
5
- spec/TestProject/TestProject.xcodeproj/xcuserdata
6
- spec/TestProject/TestProject.xcodeproj/project.xcworkspace/
7
- spec/TestProject/build
data/.rvmrc DELETED
@@ -1,4 +0,0 @@
1
- rvm use 1.9.2@xcoder
2
- rvm_install_on_use_flag=1
3
- rvm_project_rvmrc=1
4
- rvm_gemset_create_on_use_flag=1
data/Gemfile DELETED
@@ -1,11 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gemspec
4
- gem 'rspec'
5
- gem 'builder'
6
- gem 'json'
7
- gem 'plist'
8
- gem 'rest-client'
9
- gem 'guard'
10
- gem 'guard-rspec'
11
- gem 'ruby-debug19'
data/Guardfile DELETED
@@ -1,13 +0,0 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
3
-
4
- guard 'rspec', :version => 2, :cli => "--color --format d --fail-fast" do
5
- watch(%r{^spec/.+_spec\.rb$})
6
- # As the registry and resource file affect most every file, the entire
7
- # suite should be run when they are changed
8
- watch(%r{^lib/xcode/(?:registry|resource)\.rb$}) { "spec" }
9
- watch(%r{^lib/xcode/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
10
- watch('spec/spec_helper.rb') { "spec" }
11
-
12
- end
13
-
data/README.md DELETED
@@ -1,125 +0,0 @@
1
- # XCoder
2
-
3
- A ruby wrapper around various xcode tools and the project.pbxproj
4
-
5
- ## Example Usage
6
-
7
- You will need to install the gem:
8
-
9
- gem install xcoder
10
-
11
- and then require the gem in your project/rakefile/etc
12
-
13
- require 'xcoder'
14
-
15
- ### Load a project
16
-
17
- project = Xcode.project('MyProject') # Can be the name, the file (e.g. MyProject.xcodeproj) or the path
18
-
19
- ### Finding all projects from the current directory down
20
-
21
- Xcode.find_projects.each {|p| puts p.name }
22
-
23
- ### Find a configuration for a target on a project
24
-
25
- config = Xcode.project(:MyProject).target(:Target).config(:Debug) # returns an Xcode::Configuration object
26
-
27
- ### Building a configuration
28
-
29
- builder = config.builder
30
- builder.profile = 'Profiles/MyAdHoc.mobileprovision' # This will remove old profiles and install the profile
31
- builder.identity = 'iPhone Developer: Ray Hilton' # The name of the identity to use to sign the IPA (optional)
32
- builder.build
33
-
34
- ### Packaging a built .app
35
-
36
- After performing the above build, you can create a versioned, well named .ipa and .dSYM.zip
37
-
38
- builder.package
39
-
40
- This will produce something like: MyProject-Debug-1.0.ipa and MyProject-Debug-1.0.dSYM.zip
41
-
42
- ### Incrementing the build number
43
-
44
- config.info_plist do |info|
45
- info.version = info.version.to_i + 1
46
- info.save
47
- end
48
-
49
- ### Working with workspaces
50
-
51
- Loading workspaces can be done in a similar way to projects:
52
-
53
- Xcode.workspaces.each do |w|
54
- w.describe # prints a recursive description of the
55
- # structure of the workspace and its projects
56
- end
57
-
58
- Or, if you know the name:
59
-
60
- workspace = Xcode.workspace('MyWorkspace') # Can be the name, the file (e.g. MyWorkspace.xcworkspace) or the path
61
-
62
-
63
- ### Schemes
64
-
65
- There is basic support for schemes, you can enumerate them from a project like so:
66
-
67
- project.schemes.each do |s|
68
- s.builder.build
69
- end
70
-
71
- Or, access them by name:
72
-
73
- builder = project.scheme('MyScheme').builder
74
-
75
- Note: The builder behaves the same as the builder for the target/config approach and will force xcodebuild to use the local build/ directory (as per xcode3) rather than a generated temporary directory in DerivedData. This may or may not be a good thing.
76
-
77
- Note: Shared schemes and user (current logged in user) specific schemes are both loaded. They may share names and other similarities that make them hard to distinguish. Currently the priority loading order is shared schemes and then user specific schemes.
78
-
79
- ### Provisioning profiles
80
-
81
- The library provides a mechanism to install/uninstall a provisioning profile. This normally happens as part of a build (if a profile is provided to the builder, see above), but you can do this manually:
82
-
83
- Xcode::ProvisioningProfile.new("Myprofile.mobileprovision").install # installs profile into ~/Library
84
-
85
- Or enumerate installed profiles:
86
-
87
- Xcode::ProvisioningProfile.installed_profiles.each do |p|
88
- p.uninstall # Removes the profile from ~/Library/
89
- end
90
-
91
- ### Security / Keychain
92
-
93
- The missing component here is to be able to manipulate keychains. This is quite possible through the command line 'security' tool, but will probably only be necessary once per project, and so I have no plans to support this. If you can think of a use-case, please raise and issue for it!
94
-
95
- ### Testflight
96
-
97
- The common output of this build/package process is to upload to testflight. This is pretty simple with xcoder:
98
-
99
- builder.upload(API_TOKEN, TEAM_TOKEN) do |tf|
100
- tf.notes = "some release notes"
101
- tf.notify = true # Whether to send a notification to users, default is true
102
- tf.lists << "AList" # The lists to distribute the build to
103
- end
104
-
105
- You can also optionally set a .proxy= property or just set the HTTP_PROXY environment variable.
106
-
107
- ### OCUnit to JUnit
108
-
109
- You can invoke your test target/bundle from the builder
110
-
111
- builder.test do |report|
112
- report.write 'test-reports', :junit
113
- end
114
-
115
- This will invoke the test target, capture the output and write the junit reports to the test-reports directory. Currently only junit is supported.
116
-
117
- ## Tests
118
-
119
- There are some basic RSpec tests in the project which I suspect /wont/ work on machines without my identity installed.
120
-
121
- Currently these tests only assert the basic project file parsing and build code and do not perform file modification tests (e.g. for info plists) or provisioning profile/keychain importing
122
-
123
- ## Feedback
124
-
125
- Please raise issues if you find defects or have a feature request.
data/Rakefile DELETED
@@ -1,16 +0,0 @@
1
- require "bundler/gem_tasks"
2
-
3
- task :default => :specs
4
-
5
- task :specs do
6
- system "rspec -c spec"
7
- end
8
-
9
- namespace :test_project do
10
-
11
- task :reset do
12
- system "git co -- spec/TestProject"
13
- end
14
-
15
- end
16
-
@@ -1,22 +0,0 @@
1
- module Xcode
2
-
3
- #
4
- # PBXBuildFile are entries within the project that create a link between the
5
- # file and the PBXFileReference. One is created for each file added to a build
6
- # target.
7
- #
8
- module BuildFile
9
-
10
- #
11
- # Create the properties hash for a build file with the given file reference
12
- # identifier.
13
- #
14
- # @param [String] file_identifier the unique identifier for the file
15
- # @return [Hash] the properties hash for a default BuildFile.
16
- #
17
- def self.with_properties file_identifier
18
- { 'isa' => "PBXBuildFile", 'fileRef' => file_identifier }
19
- end
20
-
21
- end
22
- end
@@ -1,46 +0,0 @@
1
- module Xcode
2
-
3
- module BuildPhase
4
-
5
- #
6
- # Return the files that are referenced by the build files. This traverses
7
- # the level of indirection to make it easier to get to the FileReference.
8
- #
9
- # Another method, file, exists which will return the BuildFile references.
10
- #
11
- # @return [Array<FileReference>] the files referenced by the build files.
12
- #
13
- def build_files
14
- files.map {|file| file.fileRef }
15
- end
16
-
17
- #
18
- # Find the first file that has the name or path that matches the specified
19
- # parameter.
20
- #
21
- # @param [String] name the name or the path of the file.
22
- # @return [FileReference] the file referenced that matches the name or path;
23
- # nil if no file is found.
24
- #
25
- def build_file(name)
26
- build_files.find {|file| file.name == name || file.path == name }
27
- end
28
-
29
- #
30
- # Add the specified file to the Build Phase.
31
- #
32
- # First a BuildFile entry is created for the file and then the build file
33
- # entry is added to the particular build phase. A BuildFile identifier must
34
- # exist for each target.
35
- #
36
- # @param [FileReference] file the FileReference Resource to add to the build
37
- # phase.
38
- #
39
- def add_build_file(file)
40
- build_identifier = @registry.add_object BuildFile.with_properties(file.identifier)
41
- @properties['files'] << build_identifier
42
- end
43
-
44
- end
45
-
46
- end
data/lib/xcode/builder.rb DELETED
@@ -1,182 +0,0 @@
1
- require 'xcode/shell'
2
- require 'xcode/provisioning_profile'
3
- require 'xcode/test/report_parser.rb'
4
- require 'xcode/testflight'
5
-
6
- module Xcode
7
- class Builder
8
- attr_accessor :profile, :identity, :build_path, :keychain, :sdk
9
-
10
- def initialize(config)
11
- if config.is_a? Xcode::Scheme
12
- @scheme = config
13
- config = config.launch
14
- end
15
-
16
- puts "CONFIG: #{config}"
17
- @target = config.target
18
- @sdk = @target.project.sdk
19
- @config = config
20
- @build_path = "#{File.dirname(@target.project.path)}/build/"
21
- end
22
-
23
- def install_profile
24
- return nil if @profile.nil?
25
- # TODO: remove other profiles for the same app?
26
- p = ProvisioningProfile.new(@profile)
27
-
28
- ProvisioningProfile.installed_profiles.each do |installed|
29
- if installed.identifiers==p.identifiers and installed.uuid==p.uuid
30
- installed.uninstall
31
- end
32
- end
33
-
34
- p.install
35
- p
36
- end
37
-
38
- def build(sdk=@sdk)
39
- cmd = build_command(@sdk)
40
- Xcode::Shell.execute(cmd)
41
- end
42
-
43
- def test
44
- cmd = build_command('iphonesimulator')
45
- cmd << "TEST_AFTER_BUILD=YES"
46
- cmd << "TEST_HOST=''"
47
-
48
- parser = Xcode::Test::ReportParser.new
49
- Xcode::Shell.execute(cmd, false) do |line|
50
- puts line
51
- parser << line
52
- end
53
-
54
- yield(parser) if block_given?
55
-
56
- exit parser.exit_code if parser.exit_code!=0
57
-
58
- parser
59
- end
60
-
61
- def upload(api_token, team_token)
62
- testflight = Xcode::Testflight.new(api_token, team_token)
63
- yield(testflight) if block_given?
64
- testflight.upload(ipa_path, dsym_zip_path)
65
- end
66
-
67
- def clean
68
- cmd = []
69
- cmd << "xcodebuild"
70
- cmd << "-project \"#{@target.project.path}\""
71
-
72
- cmd << "-scheme #{@scheme.name}" unless @scheme.nil?
73
- cmd << "-target \"#{@target.name}\"" if @scheme.nil?
74
- cmd << "-configuration \"#{@config.name}\"" if @scheme.nil?
75
-
76
- cmd << "OBJROOT=\"#{@build_path}\""
77
- cmd << "SYMROOT=\"#{@build_path}\""
78
- cmd << "clean"
79
- Xcode::Shell.execute(cmd)
80
-
81
- # FIXME: Totally not safe
82
- # cmd = []
83
- # cmd << "rm -Rf #{build_path}"
84
- # Xcode::Shell.execute(cmd)
85
- end
86
-
87
- def sign
88
- cmd = []
89
- cmd << "codesign"
90
- cmd << "--force"
91
- cmd << "--sign \"#{@identity}\""
92
- cmd << "--resource-rules=\"#{app_path}/ResourceRules.plist\""
93
- cmd << "--entitlements \"#{entitlements_path}\""
94
- cmd << "\"#{ipa_path}\""
95
- Xcode::Shell.execute(cmd)
96
- end
97
-
98
- def package
99
- #package IPA
100
- cmd = []
101
- cmd << "xcrun"
102
- cmd << "-sdk #{@target.project.sdk.nil? ? "iphoneos" : @target.project.sdk}"
103
- cmd << "PackageApplication"
104
- cmd << "-v \"#{app_path}\""
105
- cmd << "-o \"#{ipa_path}\""
106
-
107
- # cmd << "OTHER_CODE_SIGN_FLAGS=\"--keychain #{@keychain.path}\"" unless @keychain.nil?
108
- #
109
- # unless @identity.nil?
110
- # cmd << "--sign \"#{@identity}\""
111
- # end
112
-
113
- unless @profile.nil?
114
- cmd << "--embed \"#{@profile}\""
115
- end
116
-
117
- Xcode::Shell.execute(cmd)
118
-
119
- # package dSYM
120
- cmd = []
121
- cmd << "zip"
122
- cmd << "-r"
123
- cmd << "-T"
124
- cmd << "-y \"#{dsym_zip_path}\""
125
- cmd << "\"#{dsym_path}\""
126
- Xcode::Shell.execute(cmd)
127
- end
128
-
129
- def configuration_build_path
130
- "#{build_path}/#{@config.name}-#{@sdk}"
131
- end
132
-
133
- def entitlements_path
134
- "#{build_path}/#{@target.name}.build/#{name}-#{@target.project.sdk}/#{@target.name}.build/#{@config.product_name}.xcent"
135
- end
136
-
137
- def app_path
138
- "#{configuration_build_path}/#{@config.product_name}.app"
139
- end
140
-
141
- def product_version_basename
142
- version = @config.info_plist.version
143
- version = "SNAPSHOT" if version.nil? or version==""
144
- "#{configuration_build_path}/#{@config.product_name}-#{@config.name}-#{version}"
145
- end
146
-
147
- def ipa_path
148
- "#{product_version_basename}.ipa"
149
- end
150
-
151
- def dsym_path
152
- "#{app_path}.dSYM"
153
- end
154
-
155
- def dsym_zip_path
156
- "#{product_version_basename}.dSYM.zip"
157
- end
158
-
159
-
160
- private
161
-
162
- def build_command(sdk=@sdk)
163
- profile = install_profile
164
- cmd = []
165
- cmd << "xcodebuild"
166
- cmd << "-sdk #{sdk}" unless sdk.nil?
167
- cmd << "-project \"#{@target.project.path}\""
168
-
169
- cmd << "-scheme #{@scheme.name}" unless @scheme.nil?
170
- cmd << "-target \"#{@target.name}\"" if @scheme.nil?
171
- cmd << "-configuration \"#{@config.name}\"" if @scheme.nil?
172
-
173
- cmd << "OTHER_CODE_SIGN_FLAGS=\"--keychain #{@keychain.path}\"" unless @keychain.nil?
174
- cmd << "CODE_SIGN_IDENTITY=\"#{@identity}\"" unless @identity.nil?
175
- cmd << "OBJROOT=\"#{@build_path}\""
176
- cmd << "SYMROOT=\"#{@build_path}\""
177
- cmd << "PROVISIONING_PROFILE=#{profile.uuid}" unless profile.nil?
178
- cmd
179
- end
180
-
181
- end
182
- end
@@ -1,101 +0,0 @@
1
- module Xcode
2
- class Buildfile
3
-
4
- def initialize
5
- @values = {}
6
- @before = {:clean => [], :build => [], :package => []}
7
- @after = {:clean => [], :build => [], :package => []}
8
- end
9
-
10
- def method_missing(method, *args)
11
- @values[method.to_sym] = args[0]
12
- end
13
-
14
- def before(event, &block)
15
- @before[event]<< block
16
- end
17
-
18
- def after(event, &block)
19
- @after[event]<< block
20
- end
21
-
22
- def getBinding
23
- binding()
24
- end
25
-
26
- def self.load(file)
27
- file = File.expand_path file
28
- raise "Unable to find the buildfile #{file}" if !File.exists? file
29
-
30
-
31
- puts "Loading Buildfile: #{file}"
32
- bc = Xcode::Buildfile.new
33
- eval(File.read(file), bc.getBinding, file)
34
- bc
35
- end
36
-
37
- def build
38
- label = "#{@values[:target]}"
39
- puts "[#{label}] Loading project #{@values[:project]}, target #{@values[:target]}, config #{@values[:config]}"
40
- config = Xcode.project(@values[:project]).target(@values[:target]).config(@values[:config])
41
- config.info_plist do |info|
42
- puts "[#{label}] Update info plist version to #{@values[:version]}"
43
- info.version = @values[:version]
44
- end
45
- builder = config.builder
46
-
47
- # unless @values[:identity].nil?
48
- # builder.identity = @values[:identity]
49
- # puts "[#{label}] Set build identity to #{@values[:identity]}"
50
- # end
51
-
52
- unless @values[:profile].nil?
53
- builder.profile = @values[:profile]
54
- puts "[#{label}] Set build profile to #{@values[:profile]}"
55
- end
56
-
57
- Keychain.temp_keychain(@values[:project]) do |kc|
58
- kc.import @values[:certificate], @values[:password]
59
-
60
- builder.identity = @values[:identity] || kc.certificates.first
61
- builder.keychain = kc
62
-
63
- puts "[#{label}] CLEAN"
64
- @before[:clean].each do |b|
65
- b.call(builder)
66
- end
67
- builder.clean
68
- @after[:clean].each do |b|
69
- b.call(builder)
70
- end
71
-
72
- puts "[#{label}] BUILD"
73
- @before[:build].each do |b|
74
- b.call(builder)
75
- end
76
- builder.build
77
- @after[:build].each do |b|
78
- b.call(builder)
79
- end
80
-
81
- puts "[#{label}] PACKAGE"
82
- @before[:package].each do |b|
83
- b.call(builder)
84
- end
85
- builder.package
86
- @after[:package].each do |b|
87
- b.call(builder)
88
- end
89
- end
90
-
91
-
92
- if @values.has_key? :testflight_api_token and @values.has_key? :testflight_team_token
93
- puts "[#{label}] Uploading to testflight"
94
- `curl -X POST http://testflightapp.com/api/builds.json -F file=@"#{builder.ipa_path}" -F dsym=@"#{builder.dsym_zip_path}" -F api_token='#{@values[:testflight_api_token]}' -F team_token='#{@values[:testflight_team_token]}' -F notify=True -F notes=\"#{@values[:testflight_notes]}\" -F distribution_lists='#{@values[:testflight_lists].join(',')}'`
95
- end
96
-
97
- builder
98
- end
99
-
100
- end
101
- end