xcake 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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