xcoder 0.1.0 → 0.1.1

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 (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
@@ -1,20 +0,0 @@
1
- require 'json'
2
- require 'plist'
3
-
4
- module Xcode
5
-
6
- module PLUTILProjectParser
7
- extend self
8
-
9
- #
10
- # Using the sytem tool plutil, the specified project file is parsed and
11
- # converted to XML, and then converted into a ruby hash object.
12
- #
13
- def parse path
14
- xml = `plutil -convert xml1 -o - "#{path}"`
15
- Plist::parse_xml(xml)
16
- end
17
-
18
- end
19
-
20
- end
data/lib/xcode/project.rb DELETED
@@ -1,190 +0,0 @@
1
- require 'plist'
2
- require 'xcode/parsers/plutil_project_parser'
3
- require 'xcode/resource'
4
- require 'xcode/target'
5
- require 'xcode/configuration'
6
- require 'xcode/scheme'
7
- require 'xcode/group'
8
- require 'xcode/file_reference'
9
- require 'xcode/registry'
10
- require 'xcode/build_phase'
11
- require 'xcode/variant_group'
12
-
13
- module Xcode
14
- class Project
15
-
16
- attr_reader :name, :sdk, :path, :schemes, :registry
17
-
18
- #
19
- # Initialized with a specific path and sdk.
20
- #
21
- # This initialization is not often used. Instead projects are generated
22
- # through the Xcode#project method.
23
- #
24
- # @see Xcode
25
- #
26
- # @param [String] path of the project to open.
27
- # @param [String] sdk the sdk value of the project. This will default to
28
- # `iphoneos`.
29
- #
30
- def initialize(path, sdk=nil)
31
- @sdk = sdk || "iphoneos" # FIXME: should support OSX/simulator too
32
- @path = File.expand_path path
33
- @schemes = []
34
- @groups = []
35
- @name = File.basename(@path).gsub(/\.xcodeproj/,'')
36
-
37
- # Parse the Xcode project file and create the registry
38
-
39
- @registry = parse_pbxproj
40
- @project = Xcode::Resource.new registry.root, @registry
41
-
42
- @schemes = parse_schemes
43
- end
44
-
45
- #
46
- # Returns the main group of the project where all the files reside.
47
- #
48
- # @return [PBXGroup]
49
- # @see PBXGroup
50
- #
51
- def groups
52
- @project.mainGroup
53
- end
54
-
55
- #
56
- # Save the current project at the current path that it exists.
57
- #
58
- def save!
59
- save @path
60
- end
61
-
62
- #
63
- # Saves the current project at the specified path.
64
- #
65
- # @note currently this does not support saving the workspaces associated
66
- # with the project to their new location.
67
- #
68
- # @param [String] path the path to save the project
69
- #
70
- def save(path)
71
- Dir.mkdir(path) unless File.exists?(path)
72
-
73
- project_filepath = "#{path}/project.pbxproj"
74
-
75
- # @toodo Save the workspace when the project is saved
76
- # FileUtils.cp_r "#{path}/project.xcworkspace", "#{path}/project.xcworkspace"
77
-
78
- File.open(project_filepath,'w') do |file|
79
-
80
- # The Hash#to_xcplist saves a semi-colon at the end which needs to be removed
81
- # to ensure the project file can be opened.
82
-
83
- file.puts %{// !$*UTF8*$!"\n#{@registry.to_xcplist.gsub(/\};\s*\z/,'}')}}
84
-
85
- end
86
- end
87
-
88
-
89
- #
90
- # Return the scheme with the specified name. Raises an error if no schemes
91
- # match the specified name.
92
- #
93
- # @note if two schemes match names, the first matching scheme is return.
94
- #
95
- # @param [String] name of the specific scheme
96
- # @return [Scheme] the specific scheme that matches the name specified
97
- #
98
- def scheme(name)
99
- scheme = @schemes.select {|t| t.name == name.to_s}.first
100
- raise "No such scheme #{name}, available schemes are #{@schemes.map {|t| t.name}.join(', ')}" if scheme.nil?
101
- yield scheme if block_given?
102
- scheme
103
- end
104
-
105
- #
106
- # All the targets specified within the project.
107
- #
108
- # @return [Array<PBXNativeTarget>] an array of all the available targets for
109
- # the specific project.
110
- #
111
- def targets
112
- @project.targets.map do |target|
113
- target.project = self
114
- target
115
- end
116
- end
117
-
118
- #
119
- # Return the target with the specified name. Raises an error if no targets
120
- # match the specified name.
121
- #
122
- # @note if two targets match names, the first matching target is returned.
123
- #
124
- # @param [String] name of the specific target
125
- # @return [PBXNativeTarget] the specific target that matches the name specified
126
- #
127
- def target(name)
128
- target = targets.select {|t| t.name == name.to_s}.first
129
- raise "No such target #{name}, available targets are #{targets.map {|t| t.name}.join(', ')}" if target.nil?
130
- yield target if block_given?
131
- target
132
- end
133
-
134
- def describe
135
- puts "Project #{name} contains"
136
- targets.each do |t|
137
- puts " + target:#{t.name}"
138
- t.configs.each do |c|
139
- puts " + config:#{c.name}"
140
- end
141
- end
142
- schemes.each do |s|
143
- puts " + scheme #{s.name}"
144
- puts " + Launch action => target:#{s.launch.target.name}, config:#{s.launch.name}" unless s.launch.nil?
145
- puts " + Test action => target:#{s.test.target.name}, config:#{s.test.name}" unless s.test.nil?
146
- end
147
- end
148
-
149
- private
150
-
151
- #
152
- # Parse all the scheme files that can be found within the project. Schemes
153
- # can be defined as `shared` schemes and then `user` specific schemes. Parsing
154
- # the schemes will load the shared ones and then the current acting user's
155
- # schemes.
156
- #
157
- def parse_schemes
158
- shared_schemes = Dir["#{@path}/xcshareddata/xcschemes/*.xcscheme"]
159
- user_specific_schemes = Dir["#{@path}/xcuserdata/#{ENV['USER']}.xcuserdatad/xcschemes/*.xcscheme"]
160
-
161
- (shared_schemes + user_specific_schemes).map do |scheme|
162
- Xcode::Scheme.new(self, scheme)
163
- end
164
- end
165
-
166
- #
167
- # Using the sytem tool plutil, the specified project file is parsed and
168
- # converted to JSON, which is then converted to a hash object.
169
- #
170
- # This content contains all the data within the project file and is used
171
- # to create the Registry.
172
- #
173
- # @return [Resource] a resource mapped to the root resource within the project
174
- # this is generally the project file which contains details about the main
175
- # group, targets, etc.
176
- #
177
- # @see Registry
178
- #
179
- def parse_pbxproj
180
- registry = Xcode::PLUTILProjectParser.parse "#{@path}/project.pbxproj"
181
-
182
- class << registry
183
- include Xcode::Registry
184
- end
185
-
186
- registry
187
- end
188
-
189
- end
190
- end
@@ -1,53 +0,0 @@
1
- module Xcode
2
- class ProvisioningProfile
3
- attr_reader :path, :name, :uuid, :identifiers
4
- def initialize(path)
5
-
6
- raise "Provisioning profile '#{path}' does not exist" unless File.exists? path
7
-
8
- @path = path
9
- @identifiers = []
10
-
11
- # TODO: im sure this could be done in a nicer way. maybe read out the XML-like stuff and use the plist -> json converter
12
- uuid = nil
13
- File.open(path, "rb") do |f|
14
- input = f.read
15
- input=~/<key>UUID<\/key>.*?<string>(.*?)<\/string>/im
16
- @uuid = $1.strip
17
-
18
- input=~/<key>Name<\/key>.*?<string>(.*?)<\/string>/im
19
- @name = $1.strip
20
-
21
- input=~/<key>ApplicationIdentifierPrefix<\/key>.*?<array>(.*?)<\/array>/im
22
- $1.split(/<string>/).each do |id|
23
- next if id.nil? or id.strip==""
24
- @identifiers << id.gsub(/<\/string>/,'').strip
25
- end
26
- end
27
-
28
- end
29
-
30
- def self.profiles_path
31
- File.expand_path "~/Library/MobileDevice/Provisioning\\ Profiles/"
32
- end
33
-
34
- def install_path
35
- "#{ProvisioningProfile.profiles_path}/#{self.uuid}.mobileprovision"
36
- end
37
-
38
- def install
39
- Xcode::Shell.execute("cp #{self.path} #{self.install_path}")
40
- end
41
-
42
- def uninstall
43
- Xcode::Shell.execute("rm -f #{self.install_path}")
44
- end
45
-
46
- def self.installed_profiles
47
- Dir["#{self.profiles_path}/*.mobileprovision"].map do |file|
48
- ProvisioningProfile.new(file)
49
- end
50
- end
51
-
52
- end
53
- end
@@ -1,120 +0,0 @@
1
- module Xcode
2
-
3
- #
4
- # The Registry represents the parsed data from the Xcode Project file. Namely
5
- # the registry is a Hash that provides additional functionality to allow the
6
- # the ability to query, add, and remove resources from the object hash.
7
- #
8
- # Opening the Xcode project file in a text-editor you'll notice that it is a
9
- # big hash/plist with a file core keys. The most important key is the 'objects'
10
- # dictionary which maintains the master-list of Identifiers to properties. All
11
- # objects are represented here and all other resources use the reference
12
- # to make the connection to the objects.
13
- #
14
- # @see Project
15
- #
16
- module Registry
17
-
18
- #
19
- # This method is used internally to determine if the value that is being
20
- # retrieved is an identifier.
21
- #
22
- # @todo this should likely be moved to the Regsitry which knows much more
23
- # about identifiers and what makes them valid.
24
- # @param [String] value is the specified value in the form of an identifier
25
- #
26
- def self.is_identifier? value
27
- value =~ /^[0-9A-F]{24}$/
28
- end
29
-
30
- #
31
- # Objects within the registry contain an `isa` property, which translates
32
- # to modules which can be mixed in to provide additional functionality.
33
- #
34
- # @param [String] isa the type of the object.
35
- #
36
- def self.isa_to_module isa
37
-
38
- { 'XCBuildConfiguration' => Configuration,
39
- 'PBXFileReference' => FileReference,
40
- 'PBXGroup' => Group,
41
- 'PBXNativeTarget' => Target,
42
- 'PBXAggregateTarget' => Target,
43
- 'PBXFrameworksBuildPhase' => BuildPhase,
44
- 'PBXSourcesBuildPhase' => BuildPhase,
45
- 'PBXResourcesBuildPhase' => BuildPhase,
46
- 'PBXBuildFile' => BuildFile,
47
- 'PBXVariantGroup' => VariantGroup }[isa]
48
-
49
- end
50
-
51
- #
52
- # This is the root object of the project. This is generally an identifier
53
- # pointing to a project.
54
- #
55
- def root
56
- self['rootObject']
57
- end
58
-
59
-
60
- #
61
- # This is a hash of all the objects within the project. The keys are the
62
- # unique identifiers which are 24 length hexadecimal strings. The values
63
- # are the objects that the keys represent.
64
- #
65
- # @return [Hash] that contains all the objects in the project.
66
- #
67
- def objects
68
- self['objects']
69
- end
70
-
71
- #
72
- #
73
- # @return [String] the object associated with this identifier; nil if no
74
- # object matches the identifier.
75
- #
76
- def object(identifier)
77
- objects[identifier]
78
- end
79
-
80
- #
81
- # Provides a method to generically add objects to the registry. This will
82
- # create a unqiue identifier and add the specified parameters to the
83
- # registry. As all objecst within a the project maintain a reference to this
84
- # registry they can immediately query for newly created items.
85
- #
86
- # @note generally this method should not be called directly and instead
87
- # resources should provide the ability to assist with generating the
88
- # correct objects for the registry.
89
- #
90
- # @param [Hash] object_properties a hash that contains all the properties
91
- # that are known for the particular item.
92
- #
93
- def add_object(object_properties)
94
- # define a new group within the object list
95
- # add it as a child
96
-
97
- range = ('A'..'F').to_a + (0..9).to_a
98
-
99
- new_identifier = 24.times.inject("") {|ident| "#{ident}#{range.sample}" }
100
-
101
- # TODO ensure identifier does not collide with other identifiers
102
-
103
- objects[new_identifier] = object_properties
104
-
105
- new_identifier
106
- end
107
-
108
- #
109
- # @note removing an item from the regitry does not remove all references
110
- # to the item within the project. At this time, this could leave resources
111
- # with references to resources that are invalid.
112
- #
113
- # @param [String] identifier of the object to remove from the registry.
114
- #
115
- def remove_object(identifier)
116
- objects.delete identifier
117
- end
118
-
119
- end
120
- end
@@ -1,187 +0,0 @@
1
-
2
- module Xcode
3
-
4
- #
5
- # Resources are not represented as a true entity within an Xcode project.
6
- # When traversing through groups, targets, configurations, etc. you will find
7
- # yourself interacting with these objects. As they represent a class that
8
- # acts as a shim around the hash data is parsed from the project.
9
- #
10
- # A resource do some things that should be explained:
11
- #
12
- # When a resource is created it requires an identifier and an instance of
13
- # of the Registry. It finds the properties hash of that given identifier
14
- # within the registry and creates a bunch of read-only methods that allow for
15
- # easy access to those elements. This is not unlike an OpenStruct.
16
- #
17
- # @example of accessing the contents of a file reference
18
- #
19
- # file_resource.properties # =>
20
- #
21
- # { 'isa' => 'PBXFileReference',
22
- # 'lastKnownFileType' => 'sourcecode.c.h',
23
- # 'path' => IOSAppDelegate.h',
24
- # 'sourceTree' => "<group>" }
25
- #
26
- # file_resource.isa # => 'PBXFileReference'
27
- # file_resource.sourceTree # => "<group>"
28
- #
29
- #
30
- # To provide additional convenience when traversing through the
31
- # various objects, the read-only method will check to see if the value
32
- # being returned matches that of a unique identifier. If it does, instead of
33
- # providing that identifier as a result and then having additional code to
34
- # perform the look up, it does it automatically.
35
- #
36
- # @example of how this would have to been done without this indirection
37
- #
38
- # project = Xcode.project('MyProject')
39
- # main_group = project.groups
40
- # child_identifier = group.children.first
41
- # subgroup = project.registry['objects'][child_identifier]
42
- #
43
- # @example of hot this works currently because of this indirection
44
- #
45
- # group = Xcode.project('MyProject.xcodeproj').mainGroup
46
- # subgroup = group.group('Models')
47
- #
48
- #
49
- # Next, as most every one of these objects is a Hash that contain the properties
50
- # instead of objects it would likely be better to encapsulate these resources
51
- # within specific classes that provide additional functionality. So that when
52
- # a group resource or a file resource is returned you can perform unique
53
- # functionality with it automatically.
54
- #
55
- # This is done by using the 'isa' property field which contains the type of
56
- # content object. Instead of creating an object and encapsulating if a module
57
- # that matches the name of the 'isa', that module of functionality is
58
- # automatically mixed-in to provide that functionality.
59
- #
60
- class Resource
61
-
62
- # The unique identifier for this resource
63
- attr_accessor :identifier
64
-
65
- # The properties hash that is known about the resource
66
- attr_accessor :properties
67
-
68
- # The registry of all objects within the project file which all resources
69
- # have a reference to so that they can retrieve any items they may own that
70
- # are simply referenced by identifiers.
71
- attr_accessor :registry
72
-
73
- #
74
- # Definiing a property allows the creation of an alias to the actual value.
75
- # This level of indirection allows for the replacement of values which are
76
- # identifiers with a resource representation of it.
77
- #
78
- # @note This is used internally by the resource when it is created.
79
- #
80
- # @param [String] name of the property
81
- # @param [String] value of the property
82
- #
83
- def define_property name, value
84
-
85
- # Save the properties within the resource within a custom hash. This
86
- # provides access to them without the indirection that we are about to
87
- # set up.
88
-
89
- @properties[name] = value
90
-
91
- # Generate a getter method for this property based on the given name.
92
-
93
- self.class.send :define_method, name do
94
-
95
- # Retrieve the value that is current stored for this name.
96
-
97
- raw_value = @properties[name]
98
-
99
- # If the value is an array then we want to examine each element within
100
- # the array to see if any of them are identifiers that we should replace
101
- # finally returning all of the items as their resource representations
102
- # or as their raw values.
103
- #
104
- # If the value is not an array then we want to examine that item and
105
- # return the resource representation or the raw value.
106
-
107
- if raw_value.is_a?(Array)
108
-
109
- Array(raw_value).map do |sub_value|
110
-
111
- if Registry.is_identifier? sub_value
112
- Resource.new sub_value, @registry
113
- else
114
- sub_value
115
- end
116
- end
117
-
118
- else
119
-
120
- if Registry.is_identifier? raw_value
121
- Resource.new raw_value, @registry
122
- else
123
- raw_value
124
- end
125
-
126
- end
127
-
128
- end
129
-
130
- end
131
-
132
- #
133
- # Within the code, a single resource is created and that is with the root
134
- # projet object. All other resources are created through the indirecation of
135
- # the above property methods.
136
- #
137
- # @param [String] identifier the unique identifier for this resource.
138
- # @param [Types] details Description
139
- #
140
- def initialize identifier, details
141
- @registry = details
142
- @properties = {}
143
- @identifier = identifier
144
-
145
- # Create property methods for all of the key-value pairs found in the
146
- # registry for specified identifier.
147
-
148
- Array(details.object(@identifier)).each do |key,value|
149
- send :define_property, key, value
150
- end
151
-
152
- #
153
- # Based on the `isa` property find if there is a constant within
154
- # the Xcode module that matches and if it does, then we want to
155
- # automatically include module into the Resource object.
156
- #
157
- constant = Registry.isa_to_module(isa)
158
-
159
- self.extend(constant) if constant
160
-
161
- end
162
-
163
- #
164
- # @return [String] a representation with the identifier and the properties
165
- # for this resource.
166
- #
167
- def to_s
168
- "#{isa} #{@identifier} #{@properties}"
169
- end
170
-
171
- #
172
- # This will generate the resource in the format that is supported by the
173
- # Xcode project file. Which requires each key value pair to be represented.
174
- #
175
- # @return [String] a string representation of the object so that it can
176
- # be persisted to an Xcode project file.
177
- #
178
- def to_xcplist
179
- %{
180
- #{@identifier} = { #{ @properties.map {|k,v| "#{k} = \"#{v}\"" }.join("; ") } }
181
-
182
- }
183
- end
184
-
185
- end
186
-
187
- end