xcoder 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,101 @@
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
@@ -0,0 +1,161 @@
1
+ require 'xcode/builder'
2
+
3
+ module Xcode
4
+
5
+ #
6
+ # Projects have a number of build configurations. These configurations are
7
+ # usually the default 'Debug' and 'Release'. However, custom ones can be
8
+ # defined.
9
+ #
10
+ # @see https://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/Building/Building.html
11
+ #
12
+ # Each configuration is defined and then a reference of that configuration is
13
+ # maintained in the Target through the XCConfigurationList.
14
+ #
15
+ # @example Xcode configuration
16
+ #
17
+ # E21D8ABB14E0F817002E56AA /* Debug */ = {
18
+ # isa = XCBuildConfiguration;
19
+ # buildSettings = {
20
+ # "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
21
+ # GCC_PRECOMPILE_PREFIX_HEADER = YES;
22
+ # GCC_PREFIX_HEADER = "newtarget/newtarget-Prefix.pch";
23
+ # INFOPLIST_FILE = "newtarget/newtarget-Info.plist";
24
+ # PRODUCT_NAME = "$(TARGET_NAME)";
25
+ # WRAPPER_EXTENSION = app;
26
+ # };
27
+ # name = Debug;
28
+ # };
29
+ #
30
+ module Configuration
31
+
32
+ def self.default_properties(name)
33
+ { 'isa' => 'XCBuildConfiguration',
34
+ 'buildSettings' => {
35
+ "SDKROOT" => "iphoneos",
36
+ "OTHER_CFLAGS" => "-DNS_BLOCK_ASSERTIONS=1",
37
+ "TARGETED_DEVICE_FAMILY" => "1,2",
38
+ "GCC_C_LANGUAGE_STANDARD" => "gnu99",
39
+ "ALWAYS_SEARCH_USER_PATHS" => "NO",
40
+ "GCC_VERSION" => "com.apple.compilers.llvm.clang.1_0",
41
+ "ARCHS" => "$(ARCHS_STANDARD_32_BIT)",
42
+ "GCC_WARN_ABOUT_MISSING_PROTOTYPES" => "YES",
43
+ "GCC_WARN_ABOUT_RETURN_TYPE" => "YES",
44
+ "CODE_SIGN_IDENTITY[sdk=>iphoneos*]" => "iPhone Developer",
45
+ "GCC_PRECOMPILE_PREFIX_HEADER" => "YES",
46
+ "VALIDATE_PRODUCT" => "YES",
47
+ "IPHONEOS_DEPLOYMENT_TARGET" => "5.0",
48
+ "COPY_PHASE_STRIP" => "YES",
49
+ "GCC_PREFIX_HEADER" => "#{name}/#{name}-Prefix.pch",
50
+ "INFOPLIST_FILE" => "#{name}/#{name}-Info.plist",
51
+ "PRODUCT_NAME" => "$(TARGET_NAME)",
52
+ "WRAPPER_EXTENSION" => "app" },
53
+ "name" => name }
54
+ end
55
+
56
+ #
57
+ # The configuration is defined within a target.
58
+ # @see PBXNativeTarget
59
+ #
60
+ attr_accessor :target
61
+
62
+ #
63
+ # @return the location for the InfoPlist file for the configuration.
64
+ # @see InfoPlist
65
+ #
66
+ def info_plist_location
67
+ build_settings['INFOPLIST_FILE']
68
+ end
69
+
70
+ #
71
+ # Opens the info plist associated with the configuration and allows you to
72
+ # edit the configuration.
73
+ #
74
+ # @example Editing the configuration
75
+ #
76
+ # config = Xcode.project('MyProject.xcodeproj').target('Application').config('Debug')
77
+ # config.info_plist do |plist|
78
+ # puts plist.version # => 1.0
79
+ # plist.version = 1.1
80
+ # marketing_version = 12.1
81
+ # end
82
+ #
83
+ # @see InfoPlist
84
+ #
85
+ def info_plist
86
+ # puts @json.inspect
87
+ info = Xcode::InfoPlist.new(self, info_plist_location)
88
+ yield info if block_given?
89
+ info.save
90
+ info
91
+ end
92
+
93
+ #
94
+ # @return the name of the product that this configuration will generate.
95
+ #
96
+ def product_name
97
+ substitute(build_settings['PRODUCT_NAME'])
98
+ end
99
+
100
+ #
101
+ # Retrieve the configuration value for the given name
102
+ #
103
+ # @param [String] name of the configuration settings to return
104
+ # @return [String,Array,Hash] the value stored for the specified configuration
105
+ #
106
+ def get(name)
107
+ build_settings[name]
108
+ end
109
+
110
+ #
111
+ # Set the configuration value for the given name
112
+ #
113
+ # @param [String] name of the the configuration setting
114
+ # @param [String,Array,Hash] value the value to store for the specific setting
115
+ #
116
+ def set(name, value)
117
+ build_settings[name] = value
118
+ end
119
+
120
+
121
+ #
122
+ # Create a builder for this given project->target->configuration.
123
+ #
124
+ # @return [Builder] this is a builder for the configuration.
125
+ # @see Builder
126
+ #
127
+ def builder
128
+ puts "Making a Builder with #{self} #{self.methods}"
129
+ Xcode::Builder.new(self)
130
+ end
131
+
132
+
133
+ private
134
+
135
+ #
136
+ # Within the configuration properties variables reference the target,
137
+ # i.e."$(TARGET_NAME)". This method will find and replace the target
138
+ # constant with the appropriate value.
139
+ #
140
+ # @param [String] value is a property of the configuration that may contain
141
+ # the target variable to replace.
142
+ #
143
+ # @return [String] a string without the variable reference.
144
+ #
145
+ def substitute(value)
146
+ if value=~/\$\(.*\)/
147
+ value.gsub(/\$\((.*)\)/) do |match|
148
+ case match
149
+ when "$(TARGET_NAME)"
150
+ @target.name
151
+ else
152
+ raise "Unknown substitution variable #{match}"
153
+ end
154
+ end
155
+ else
156
+ value
157
+ end
158
+ end
159
+
160
+ end
161
+ end
@@ -0,0 +1,85 @@
1
+ module Xcode
2
+ module ConfigurationList
3
+
4
+ #
5
+ # @example configuration list
6
+ #
7
+ # 7165D47D146B4EA100DE2F0E /* Build configuration list for PBXNativeTarget "TestProject" */ = {
8
+ # isa = XCConfigurationList;
9
+ # buildConfigurations = (
10
+ # 7165D47E146B4EA100DE2F0E /* Debug */,
11
+ # 7165D47F146B4EA100DE2F0E /* Release */,
12
+ # );
13
+ # defaultConfigurationIsVisible = 0;
14
+ # defaultConfigurationName = Release;
15
+ # };
16
+ def self.configration_list
17
+ { 'isa' => 'XCConfigurationList',
18
+ 'buildConfigurations' => [],
19
+ 'defaultConfigurationIsVisible' => '0',
20
+ 'defaultConfigurationName' => '' }
21
+ end
22
+
23
+ #
24
+ # @return [Hash] a hash of symbol names to configuration names.
25
+ #
26
+ def self.symbol_config_name_to_config_name
27
+ { :debug => 'Debug', :release => 'Release' }
28
+ end
29
+
30
+ #
31
+ # Create a configuration for this ConfigurationList. This configuration needs
32
+ # to have a name.
33
+ #
34
+ # @note unique names are currently not enforced but likely necessary for the
35
+ # the target to be build successfully.
36
+ #
37
+ # @param [Types] name Description
38
+ #
39
+ def create_config(name)
40
+
41
+ name = ConfigurationList.symbol_config_name_to_config_name[name] if ConfigurationList.symbol_config_name_to_config_name[name]
42
+
43
+ # @todo a configuration has additional fields that are ususally set with
44
+ # some target information for the title.
45
+
46
+ new_config = @registry.add_object(Configuration.default_properties(name))
47
+ @properties['buildConfigurations'] << new_config.identifier
48
+
49
+ yield new_config if block_given?
50
+
51
+ new_config.save!
52
+ end
53
+
54
+ #
55
+ # @return [BuildConfiguration] the build configuration that is set to default;
56
+ # nil if no configuration has been set as default.
57
+ #
58
+ def default_config
59
+ build_configurations.find {|config| config.name == default_configuration_name }
60
+ end
61
+
62
+ #
63
+ # @return [String] the name of the default build configuration; nil if no
64
+ # configuration has been set as default.
65
+ #
66
+ def default_config_name
67
+ default_configuration_name
68
+ end
69
+
70
+ #
71
+ # @todo allow the ability for a configuration to set itself as default and/or
72
+ # let a configuration be specified as a parameter here. Though we need
73
+ # to check to see that the configuration is part of the this configuration
74
+ # list.
75
+ #
76
+ # @param [String] name of the build configuration to set as the default
77
+ # configuration; specify nil if you want to remove any default configuration.
78
+ #
79
+ def set_default_config(name)
80
+ # @todo ensure that the name specified is one of the available configurations
81
+ @properties['defaultConfigurationName'] = name
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,23 @@
1
+ class Array
2
+
3
+ #
4
+ # Arrays in an Xcode project take a particular format.
5
+ #
6
+ # @note the last element in the array can have a comma; it is optional.
7
+ #
8
+ # @example output format:
9
+ #
10
+ # (
11
+ # ITEM1,
12
+ # ITEM2,
13
+ # ITEM3
14
+ # )
15
+ #
16
+ def to_xcplist
17
+ plist_of_items = map {|item| item.to_xcplist }.join(",\n")
18
+
19
+ %{(
20
+ #{plist_of_items}
21
+ )}
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+
2
+
3
+ class TrueClass
4
+
5
+ #
6
+ # Xcode project's expect boolean trues to be the word YES.
7
+ #
8
+ def to_xcplist
9
+ "YES"
10
+ end
11
+ end
12
+
13
+ class FalseClass
14
+
15
+ #
16
+ # Xcode project's expect boolean trues to be the word NO.
17
+ #
18
+ def to_xcplist
19
+ "NO"
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ class Fixnum
2
+ def to_xcplist
3
+ to_s
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ class Hash
2
+
3
+ #
4
+ # Hashes in an Xcode project take a particular format.
5
+ #
6
+ # @note the keys are represeted in this output with quotes; this is actually
7
+ # optional for certain keys based on their format. This is done to ensure
8
+ # that all keys that do not conform are ensured proper output.
9
+ #
10
+ # @example output format:
11
+ #
12
+ # {
13
+ # "KEY" = "VALUE";
14
+ # "KEY" = "VALUE";
15
+ # "KEY" = "VALUE";
16
+ # }
17
+ #
18
+ def to_xcplist
19
+ plist_of_items = map do |k,v|
20
+ "\"#{k}\" = #{v.to_xcplist};"
21
+ end.join("\n")
22
+
23
+ %{{
24
+ #{plist_of_items}
25
+ }}
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ require 'json'
2
+
3
+ class String
4
+
5
+ #
6
+ # Xcode format for a string is exactly the same as you would expect in JSON
7
+ #
8
+ def to_xcplist
9
+ to_json
10
+ end
11
+
12
+ #
13
+ # Similar to ActiveRecord's underscore method. Return a string version
14
+ # underscored. This is used specifically to convert the property keys into
15
+ # Ruby friendly names as they are used for creating method names.
16
+ #
17
+ # @return [String] convert camel-cased words, generating underscored, ruby
18
+ # friend names.
19
+ def underscore
20
+ self.gsub(/::/, '/').
21
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
22
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
23
+ tr("-", "_").
24
+ downcase
25
+ end
26
+ end