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
@@ -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