xcake 0.1.5

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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +1 -0
  3. data/.gitignore +35 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +6 -0
  6. data/.yardopts +3 -0
  7. data/CODE_OF_CONDUCT.md +13 -0
  8. data/Cakefile +8 -0
  9. data/Gemfile +4 -0
  10. data/Gemfile.lock +87 -0
  11. data/LICENSE +201 -0
  12. data/LICENSE.txt +21 -0
  13. data/README.md +107 -0
  14. data/Rakefile +6 -0
  15. data/bin/console +15 -0
  16. data/bin/setup +7 -0
  17. data/bin/xcake +5 -0
  18. data/docs/Cakefile.md +166 -0
  19. data/docs/Getting Started.md +89 -0
  20. data/lib/fastlane_plugin.rb +5 -0
  21. data/lib/xcake.rb +33 -0
  22. data/lib/xcake/command.rb +22 -0
  23. data/lib/xcake/configurable.rb +128 -0
  24. data/lib/xcake/configuration.rb +50 -0
  25. data/lib/xcake/configuration/sugar.rb +29 -0
  26. data/lib/xcake/fastlane/xcake.rb +46 -0
  27. data/lib/xcake/generator/build_phase.rb +81 -0
  28. data/lib/xcake/generator/build_phase/compile_source_build_phase.rb +18 -0
  29. data/lib/xcake/generator/build_phase/copy_resources_build_phase.rb +17 -0
  30. data/lib/xcake/generator/build_phase/copy_xcassets_build_phase.rb +21 -0
  31. data/lib/xcake/generator/build_phase/header_file_build_phase.rb +13 -0
  32. data/lib/xcake/generator/build_phase_registry.rb +39 -0
  33. data/lib/xcake/generator/configuration.rb +40 -0
  34. data/lib/xcake/generator/path.rb +41 -0
  35. data/lib/xcake/generator/project.rb +59 -0
  36. data/lib/xcake/generator/target.rb +48 -0
  37. data/lib/xcake/node.rb +144 -0
  38. data/lib/xcake/project.rb +164 -0
  39. data/lib/xcake/project_structure_resolver.rb +53 -0
  40. data/lib/xcake/target.rb +202 -0
  41. data/lib/xcake/version.rb +3 -0
  42. data/lib/xcake/visitable.rb +23 -0
  43. data/lib/xcake/visitor.rb +78 -0
  44. data/lib/xcake/xcode/project.rb +78 -0
  45. data/lib/xcake/xcode/scheme.rb +11 -0
  46. data/lib/xcake/xcode/scheme_list.rb +110 -0
  47. data/xcake.gemspec +31 -0
  48. metadata +192 -0
@@ -0,0 +1,48 @@
1
+ require 'xcodeproj'
2
+
3
+ module Xcake
4
+ module Generator
5
+ class Target
6
+
7
+ include Visitor
8
+
9
+ attr_accessor :project
10
+ attr_accessor :root_node
11
+ attr_accessor :target
12
+ attr_accessor :native_target
13
+
14
+ def initialize(project, root_node)
15
+ @project = project
16
+ @root_node = root_node
17
+ end
18
+
19
+ def visit_target(target)
20
+
21
+ puts "Creating target #{target.name}..."
22
+
23
+ @target = target
24
+ @native_target = @project.new_target(target)
25
+
26
+ Dir.glob(target.include_files).each do |file|
27
+ @root_node.create_children_with_path(file, @native_target)
28
+ end if target.include_files
29
+
30
+ Dir.glob(target.exclude_files).each do |file|
31
+ @root_node.remove_children_with_path(file, @native_target)
32
+ end if target.exclude_files
33
+ end
34
+
35
+ def leave_target(target)
36
+ @native_target.add_system_frameworks(target.system_frameworks) if target.system_frameworks
37
+ end
38
+
39
+ def visit_configuration(configuration)
40
+ generator = Configuration.new(@project, @native_target)
41
+ configuration.accept(generator)
42
+ end
43
+
44
+ def leave_configuration(configuration)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,144 @@
1
+ require 'xcodeproj'
2
+
3
+ module Xcake
4
+ # This class is used to represent a
5
+ # node (File or Directory) in the File System.
6
+ #
7
+ # This tracks which target the node should be
8
+ # added to.
9
+ class Node
10
+
11
+ include Visitable
12
+
13
+ # @return [String] the component of this node in the path.
14
+ #
15
+ attr_accessor :component
16
+
17
+ # @return [String] the path to this node relative to the Cakefile.
18
+ #
19
+ attr_accessor :path
20
+
21
+ # @return [String] the parent node.
22
+ #
23
+ attr_accessor :parent
24
+
25
+ # @return [Array<Node>] the child nodes.
26
+ #
27
+ attr_accessor :children
28
+
29
+ # @return [Array<PBXNativeTarget>] the targets for the node
30
+ #
31
+ attr_accessor :targets
32
+
33
+ def initialize
34
+ self.children = []
35
+ self.targets = []
36
+ end
37
+
38
+ # Creates child nodes for the path and
39
+ # target.
40
+ #
41
+ # @param [String] path
42
+ # path to create children for
43
+ #
44
+ # @param [PBXNativeTarget] target
45
+ # target to add for the child nodes
46
+ #
47
+ def create_children_with_path(path, target)
48
+
49
+ components = path.split('/').keep_if do |c|
50
+ c != "."
51
+ end
52
+
53
+ create_children_with_components(components, target)
54
+ end
55
+
56
+ # Removes child nodes for the path and
57
+ # target.
58
+ #
59
+ # @param [String] path
60
+ # path to remove children for
61
+ #
62
+ # @param [PBXNativeTarget] target
63
+ # target to remove for child nodes
64
+ #
65
+ def remove_children_with_path(path, target)
66
+
67
+ components = path.split('/').keep_if do |c|
68
+ c != "."
69
+ end
70
+
71
+ remove_children_with_components(components, target)
72
+ end
73
+
74
+ protected
75
+
76
+ def create_children_with_components(components, target)
77
+
78
+ component = components.shift
79
+ child = children.find do |c|
80
+ c.component == component
81
+ end
82
+
83
+ if child == nil
84
+
85
+ child = Node.new
86
+
87
+ child.component = component
88
+
89
+ if self.path
90
+ child.path = "#{self.path}/#{component}"
91
+ else
92
+ child.path = "#{component}"
93
+ end
94
+
95
+ child.parent = self
96
+
97
+ children << child
98
+ end
99
+
100
+ child.targets << target unless child.targets.include? target
101
+
102
+ child.create_children_with_components(components, target) if components.count > 0
103
+
104
+ child
105
+ end
106
+
107
+ def remove_children_with_components(components, target)
108
+
109
+ component = components.shift
110
+
111
+ child = children.find do |c|
112
+ c.component == component
113
+ end
114
+
115
+ if child != nil
116
+
117
+ child.remove_children_with_components(components, target)
118
+
119
+ child.targets.keep_if do |t|
120
+ t != target
121
+ end
122
+
123
+ children.keep_if do |c|
124
+ c != child ||
125
+ c.children.count > 0 ||
126
+ c.targets.count > 0
127
+ end
128
+ end
129
+ end
130
+
131
+ public
132
+
133
+ def accept(visitor)
134
+
135
+ visitor.visit(self)
136
+
137
+ children.each do |c|
138
+ c.accept(visitor)
139
+ end
140
+
141
+ visitor.leave(self)
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,164 @@
1
+ require 'xcodeproj'
2
+
3
+ module Xcake
4
+ # This class is used to describe the overall
5
+ # Xcode project structure; This forms part of the DSL
6
+ # and is usally stored in files named `Cakefile`.
7
+ #
8
+ # The Project creates a hiearchy of targets and configurations
9
+ # necessary to generate a xcode project.
10
+ class Project
11
+
12
+ include Configurable
13
+ include Visitable
14
+
15
+ # @!group Configuring a project
16
+
17
+ # @return [String] the name of the project file. This is used as
18
+ # the filename.
19
+ #
20
+ attr_accessor :project_name
21
+
22
+ # @return [Array<Target>] the list of targets for the project.
23
+ #
24
+ attr_accessor :targets
25
+
26
+ # @!group Creating a project
27
+
28
+ # @param [String] name
29
+ # the name of the project file. This is used as the filename.
30
+ #
31
+ # @param [Proc] block
32
+ # an optional block that configures the project through the DSL.
33
+ #
34
+ # @example Creating a Project.
35
+ #
36
+ # Project.new do |c|
37
+ # c.application_for :ios, 8.0
38
+ # end
39
+ #
40
+ def initialize(name="Project", &block)
41
+
42
+ self.project_name = name
43
+ self.targets = []
44
+
45
+ block.call(self) if block_given?
46
+ end
47
+
48
+ # @!group Working with a project
49
+
50
+ # Defines a new target.
51
+ #
52
+ # @param [Proc] block
53
+ # an optional block that configures the target through the DSL.
54
+ #
55
+ # @return [Target] the target
56
+ # the newly created target
57
+ #
58
+ def target(&block)
59
+ target = Target.new(&block)
60
+ self.targets << target
61
+
62
+ target
63
+ end
64
+
65
+ # Defines a new application target.
66
+ #
67
+ # @param [Symbol] platform
68
+ # platform for the application, can be either `:ios` or `:osx`.
69
+ #
70
+ # @param [Float] deployment_target
71
+ # the minimum deployment version for the platform.
72
+ #
73
+ # @param [Symbol] language
74
+ # language for application, can be either `:objc` or `:swift`.
75
+ #
76
+ # @param [Proc] block
77
+ # an optional block that configures the target through the DSL.
78
+ #
79
+ # @return [Target] the application target
80
+ # the newly created application target
81
+ #
82
+ def application_for(platform, deployment_target, language=:objc, &block)
83
+
84
+ application_target = target do |t|
85
+ t.type = :application
86
+ t.platform = platform
87
+ t.deployment_target = deployment_target
88
+ t.language = language
89
+
90
+ block.call(t) if block_given?
91
+ end
92
+
93
+ application_target
94
+ end
95
+
96
+ # Defines a new unit test target.
97
+ #
98
+ # @param [Target] host_target
99
+ # host target for which the unit tests are for.
100
+ #
101
+ # @param [Proc] block
102
+ # an optional block that configures the target through the DSL.
103
+ #
104
+ # @return [Target] the unit test target
105
+ # the newly created unit test target
106
+ #
107
+ def unit_tests_for(host_target, &block)
108
+
109
+ unit_test_target = target do |t|
110
+
111
+ t.name = "#{host_target.name}Tests"
112
+
113
+ t.type = :unit_test_bundle
114
+ t.platform = host_target.platform
115
+ t.deployment_target = host_target.deployment_target
116
+ t.language = host_target.language
117
+
118
+ t.all_configurations.settings["TEST_HOST"] = "$(BUILT_PRODUCTS_DIR)/#{host_target.name}.app/#{host_target.name}"
119
+ t.all_configurations.settings["BUNDLE_LOADER"] = "$(TEST_HOST)"
120
+
121
+ block.call(t) if block_given?
122
+ end
123
+
124
+ unit_test_target
125
+ end
126
+
127
+ protected
128
+
129
+ # Configurable
130
+ def default_settings
131
+ common_settings = Xcodeproj::Constants::PROJECT_DEFAULT_BUILD_SETTINGS
132
+ settings = Xcodeproj::Project::ProjectHelper.deep_dup(common_settings[:all])
133
+ end
134
+
135
+ def default_debug_settings
136
+ common_settings = Xcodeproj::Constants::PROJECT_DEFAULT_BUILD_SETTINGS
137
+ default_settings.merge!(Xcodeproj::Project::ProjectHelper.deep_dup(common_settings[:debug]))
138
+ end
139
+
140
+ def default_release_settings
141
+ common_settings = Xcodeproj::Constants::PROJECT_DEFAULT_BUILD_SETTINGS
142
+ default_settings.merge!(Xcodeproj::Project::ProjectHelper.deep_dup(common_settings[:release]))
143
+ end
144
+
145
+ public
146
+
147
+ # Visitable
148
+ def accept(visitor)
149
+ visitor.visit(self)
150
+
151
+ flatten_configurations.each do |c|
152
+ visitor.visit(c)
153
+ visitor.leave(c)
154
+ end
155
+
156
+ self.targets.each do |t|
157
+ visitor.visit(t)
158
+ visitor.leave(t)
159
+ end
160
+
161
+ visitor.leave(self)
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,53 @@
1
+ module Xcake
2
+ # This class handles resolving the structure
3
+ # of a project. Making sure that the structure of the
4
+ # project is one Xcode can open and makes sense.
5
+ #
6
+ # As part of this it will create default configurations
7
+ # if none are provided and will make sure both the project
8
+ # and targets have all of the same configurations.
9
+ class ProjectStructureResolver
10
+
11
+ include Visitor
12
+
13
+ # @return [Project] the project to resolve structure for
14
+ attr_accessor :project
15
+
16
+ protected
17
+
18
+ def visit_project(project)
19
+
20
+ puts "Resolving Project..."
21
+
22
+ @project = project
23
+
24
+ @project.debug_configuration :debug if @project.debug_configurations.count == 0
25
+ @project.release_configuration :release if @project.release_configurations.count == 0
26
+ end
27
+
28
+ def leave_project(project)
29
+ end
30
+
31
+ def visit_target(target)
32
+
33
+ puts "Resolving target #{target.name}..."
34
+
35
+ @project.debug_configurations.each do |b|
36
+ target.debug_configuration(b.name)
37
+ end
38
+
39
+ @project.release_configurations.each do |b|
40
+ target.release_configuration(b.name)
41
+ end
42
+ end
43
+
44
+ def leave_target(target)
45
+ end
46
+
47
+ def visit_configuration(configuration)
48
+ end
49
+
50
+ def leave_configuration(configuration)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,202 @@
1
+ module Xcake
2
+ # This class is used to describe a target for a
3
+ # Xcode project; This forms part of the DSL
4
+ # and is usally stored in files named `Cakefile`.
5
+ #
6
+ class Target
7
+ include Configurable
8
+ include Visitable
9
+
10
+ # @return [String] the name of the target.
11
+ #
12
+ attr_accessor :name
13
+
14
+ # @return [String] the type of the target.
15
+ # Can be `:application`, `:dynamic_library`,
16
+ # `framework` or `:static_library`.
17
+ #
18
+ attr_accessor :type
19
+
20
+ # @return [String] the platform for the target.
21
+ # Can be `:ios`, `:osx`.
22
+ #
23
+ attr_accessor :platform
24
+
25
+ # @return [String] the minimum deployment version
26
+ # for the target's platform.
27
+ #
28
+ attr_accessor :deployment_target
29
+
30
+ # @return [String] the language for the target.
31
+ # Can be `:objc`, `:swift`.
32
+ #
33
+ attr_accessor :language
34
+
35
+ # @!group File patterns
36
+
37
+ #
38
+ # File patterns do not support traversing the parent directory ( `..` ).
39
+ # File patterns may contain the following wildcard patterns:
40
+ #
41
+ # ---
42
+ #
43
+ # ### Pattern: *
44
+ #
45
+ # Matches any file. Can be restricted by other values in the glob.
46
+ #
47
+ # * `*` will match all files
48
+ # * `c*` will match all files beginning with `c`
49
+ # * `*c` will match all files ending with `c`
50
+ # * `*c*` will match all files that have `c` in them (including at the
51
+ # beginning or end)
52
+ #
53
+ # Equivalent to `/.*/x` in regexp.
54
+ #
55
+ # **Note** this will not match Unix-like hidden files (dotfiles). In
56
+ # order to include those in the match results, you must use something
57
+ # like `{*,.*}`.
58
+ #
59
+ # ---
60
+ #
61
+ # ### Pattern: **
62
+ #
63
+ # Matches directories recursively.
64
+ #
65
+ # ---
66
+ #
67
+ # ### Pattern: ?
68
+ #
69
+ # Matches any one character. Equivalent to `/.{1}/` in regexp.
70
+ #
71
+ # ---
72
+ #
73
+ # ### Pattern: [set]
74
+ #
75
+ # Matches any one character in set.
76
+ #
77
+ # Behaves exactly like character sets in Regexp, including set negation
78
+ # (`[^a-z]`).
79
+ #
80
+ # ---
81
+ #
82
+ # ### Pattern: {p,q}
83
+ #
84
+ # Matches either literal `p` or literal `q`.
85
+ #
86
+ # Matching literals may be more than one character in length. More than
87
+ # two literals may be specified.
88
+ #
89
+ # Equivalent to pattern alternation in regexp.
90
+ #
91
+ # ---
92
+ #
93
+ # ### Pattern: \
94
+ #
95
+ # Escapes the next meta-character.
96
+ #
97
+ # ---
98
+ #
99
+ # ### Examples
100
+ #
101
+ # Consider these to be evaluated in the source root of
102
+ # [JSONKit](https://github.com/johnezang/JSONKit).
103
+ #
104
+ # "JSONKit.?" #=> ["JSONKit.h", "JSONKit.m"]
105
+ # "*.[a-z][a-z]" #=> ["CHANGELOG.md", "README.md"]
106
+ # "*.[^m]*" #=> ["JSONKit.h"]
107
+ # "*.{h,m}" #=> ["JSONKit.h", "JSONKit.m"]
108
+ # "*" #=> ["CHANGELOG.md", "JSONKit.h"]
109
+
110
+ #-----------------------------------------------------------------------#
111
+
112
+ # @return [String] files to include for the target.
113
+ # Supports regular expressions,
114
+ # Defaults to: "./<Target Name>/*\*/\*.*"
115
+ #
116
+ # @example
117
+ #
118
+ # spec.include_files = "Classes/**/*.{h,m}"
119
+ #
120
+ attr_accessor :include_files
121
+
122
+ # @return [String] files to exclude for the target.
123
+ # Supports regular expressions
124
+ #
125
+ # @example
126
+ #
127
+ # spec.exclude_files = "Classes/**/unused.{h,m}"
128
+ #
129
+ attr_accessor :exclude_files
130
+
131
+ # @!group Frameworks
132
+
133
+ # @return [Array<String>] system frameworks to include for the target
134
+ # Defaults to:
135
+ # - ["Foundation", "UIKit"] for iOS
136
+ # - ["Cocoa"] for OSX
137
+ #
138
+ # @example
139
+ #
140
+ # spec.system_frameworks = ["Foundation"]
141
+ #
142
+ attr_accessor :system_frameworks
143
+
144
+ # @param [Proc] block
145
+ # an optional block that configures the project through the DSL.
146
+ #
147
+ # @example Creating a Target.
148
+ #
149
+ # Target.new do |t|
150
+ # t.name "test"
151
+ # end
152
+ #
153
+ def initialize(&block)
154
+ block.call(self) if block_given?
155
+ end
156
+
157
+ def include_files
158
+ @include_files ||= "./#{self.name}/**/*.*"
159
+ end
160
+
161
+ def system_frameworks
162
+ @system_frameworks ||= default_system_frameworks_for self.platform
163
+ end
164
+
165
+ protected
166
+
167
+ def default_system_frameworks_for(platform)
168
+ (platform == :ios) ? ['Foundation', 'UIKit'] : ['Cocoa']
169
+ end
170
+
171
+ #Configurable
172
+
173
+ def default_settings
174
+ {
175
+ "INFOPLIST_FILE" => "./$(PRODUCT_NAME)/Supporting Files/Info.plist"
176
+ }
177
+ end
178
+
179
+ def default_debug_settings
180
+ Xcodeproj::Project::ProjectHelper.common_build_settings(:debug, platform, deployment_target.to_s, type, language).merge!(default_settings)
181
+ end
182
+
183
+ def default_release_settings
184
+ Xcodeproj::Project::ProjectHelper.common_build_settings(:release, platform, deployment_target.to_s, type, language).merge!(default_settings)
185
+ end
186
+
187
+ #Visitable
188
+
189
+ public
190
+
191
+ def accept(visitor)
192
+ visitor.visit(self)
193
+
194
+ flatten_configurations.each do |c|
195
+ visitor.visit(c)
196
+ visitor.leave(c)
197
+ end
198
+
199
+ visitor.leave(self)
200
+ end
201
+ end
202
+ end