xcoder 0.1.15 → 0.1.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +6 -0
  2. data/.rbenv-version +1 -0
  3. data/.rvmrc +1 -1
  4. data/Gemfile +10 -2
  5. data/README.md +110 -9
  6. data/Rakefile +2 -2
  7. data/bin/xcoder +74 -0
  8. data/lib/xcode/builder.rb +1 -2
  9. data/lib/xcode/builder/base_builder.rb +231 -102
  10. data/lib/xcode/builder/build_parser.rb +146 -0
  11. data/lib/xcode/builder/project_target_config_builder.rb +2 -2
  12. data/lib/xcode/builder/scheme_builder.rb +29 -12
  13. data/lib/xcode/buildspec.rb +286 -0
  14. data/lib/xcode/configuration_list.rb +24 -24
  15. data/lib/xcode/deploy/ftp.rb +56 -0
  16. data/lib/xcode/deploy/kickfolio.rb +18 -0
  17. data/lib/xcode/deploy/s3.rb +38 -0
  18. data/lib/xcode/deploy/ssh.rb +43 -0
  19. data/lib/xcode/deploy/templates/index.rhtml +22 -0
  20. data/lib/xcode/deploy/templates/manifest.rhtml +31 -0
  21. data/lib/xcode/deploy/testflight.rb +32 -27
  22. data/lib/xcode/deploy/web_assets.rb +39 -0
  23. data/lib/xcode/info_plist.rb +16 -0
  24. data/lib/xcode/keychain.rb +33 -10
  25. data/lib/xcode/platform.rb +65 -0
  26. data/lib/xcode/project.rb +7 -3
  27. data/lib/xcode/provisioning_profile.rb +38 -2
  28. data/lib/xcode/scheme.rb +44 -17
  29. data/lib/xcode/shell/command.rb +79 -5
  30. data/lib/xcode/terminal_output.rb +116 -0
  31. data/lib/xcode/test/formatters/junit_formatter.rb +7 -2
  32. data/lib/xcode/test/formatters/stdout_formatter.rb +34 -25
  33. data/lib/xcode/test/parsers/kif_parser.rb +87 -0
  34. data/lib/xcode/test/parsers/ocunit_parser.rb +3 -3
  35. data/lib/xcode/version.rb +1 -1
  36. data/lib/xcode/workspace.rb +13 -5
  37. data/lib/xcoder.rb +33 -31
  38. data/spec/TestProject/TestProject.xcodeproj/project.pbxproj +1627 -1015
  39. data/spec/TestWorkspace.xcworkspace/contents.xcworkspacedata +7 -0
  40. data/spec/builder_spec.rb +87 -71
  41. data/spec/deploy_spec.rb +63 -0
  42. data/spec/ocunit_parser_spec.rb +1 -1
  43. data/xcoder.gemspec +3 -1
  44. metadata +95 -19
  45. data/lib/xcode/buildfile.rb +0 -101
  46. data/lib/xcode/shell.rb +0 -26
  47. data/spec/deploy_testflight_spec.rb +0 -27
@@ -1,9 +1,9 @@
1
1
  module Xcode
2
2
  module ConfigurationList
3
-
4
- #
3
+
4
+ #
5
5
  # @example configuration list
6
- #
6
+ #
7
7
  # 7165D47D146B4EA100DE2F0E /* Build configuration list for PBXNativeTarget "TestProject" */ = {
8
8
  # isa = XCConfigurationList;
9
9
  # buildConfigurations = (
@@ -13,73 +13,73 @@ module Xcode
13
13
  # defaultConfigurationIsVisible = 0;
14
14
  # defaultConfigurationName = Release;
15
15
  # };
16
- def self.configration_list
16
+ def self.configuration_list
17
17
  { 'isa' => 'XCConfigurationList',
18
18
  'buildConfigurations' => [],
19
19
  'defaultConfigurationIsVisible' => '0',
20
20
  'defaultConfigurationName' => '' }
21
21
  end
22
-
22
+
23
23
  #
24
24
  # @return [Hash] a hash of symbol names to configuration names.
25
- #
25
+ #
26
26
  def self.symbol_config_name_to_config_name
27
27
  { :debug => 'Debug', :release => 'Release' }
28
28
  end
29
-
29
+
30
30
  #
31
31
  # Create a configuration for this ConfigurationList. This configuration needs
32
32
  # to have a name.
33
- #
33
+ #
34
34
  # @note unique names are currently not enforced but likely necessary for the
35
35
  # the target to be build successfully.
36
- #
36
+ #
37
37
  # @param [Types] name Description
38
38
  #
39
39
  def create_config(name)
40
-
40
+
41
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
42
+
43
+ # @todo a configuration has additional fields that are ususally set with
44
44
  # some target information for the title.
45
-
45
+
46
46
  new_config = @registry.add_object(Configuration.default_properties(name))
47
47
  @properties['buildConfigurations'] << new_config.identifier
48
-
48
+
49
49
  yield new_config if block_given?
50
-
50
+
51
51
  new_config.save!
52
52
  end
53
-
53
+
54
54
  #
55
55
  # @return [BuildConfiguration] the build configuration that is set to default;
56
56
  # nil if no configuration has been set as default.
57
- #
57
+ #
58
58
  def default_config
59
59
  build_configurations.find {|config| config.name == default_configuration_name }
60
60
  end
61
-
61
+
62
62
  #
63
63
  # @return [String] the name of the default build configuration; nil if no
64
64
  # configuration has been set as default.
65
- #
65
+ #
66
66
  def default_config_name
67
67
  default_configuration_name
68
68
  end
69
-
69
+
70
70
  #
71
71
  # @todo allow the ability for a configuration to set itself as default and/or
72
72
  # let a configuration be specified as a parameter here. Though we need
73
73
  # to check to see that the configuration is part of the this configuration
74
74
  # list.
75
- #
76
- # @param [String] name of the build configuration to set as the default
75
+ #
76
+ # @param [String] name of the build configuration to set as the default
77
77
  # configuration; specify nil if you want to remove any default configuration.
78
78
  #
79
79
  def set_default_config(name)
80
80
  # @todo ensure that the name specified is one of the available configurations
81
81
  @properties['defaultConfigurationName'] = name
82
82
  end
83
-
83
+
84
84
  end
85
- end
85
+ end
@@ -0,0 +1,56 @@
1
+ require 'net/ftp'
2
+ require 'xcode/deploy/web_assets'
3
+
4
+ module Xcode
5
+ module Deploy
6
+ class Ftp
7
+ attr_accessor :host, :username, :password, :dir
8
+
9
+ def initialize(builder, options = {})
10
+ @builder = builder
11
+ @username = options[:username]
12
+ @password = options[:password]
13
+ @dir = options[:dir]
14
+ @host = options[:host]
15
+ @base_url = options[:base_url]
16
+ end
17
+
18
+ # Support templating of member data.
19
+ def get_binding
20
+ binding
21
+ end
22
+
23
+ def remote_installation_path
24
+ File.join(@dir, @builder.product_name)
25
+ end
26
+
27
+ def deploy
28
+ WebAssets.generate @builder, @base_url do |dir|
29
+ puts "Connecting to #{@remote_host} with username #{@username}"
30
+ Net::FTP.open(@host, @username, @password) do |ftp|
31
+ begin
32
+ puts "Creating folder #{remote_installation_path}"
33
+ ftp.mkdir(remote_installation_path)
34
+ rescue Net::FTPError
35
+ puts "It looks like the folder is already there."
36
+ end
37
+
38
+ puts "Changing to remote folder #{remote_installation_path}"
39
+ files = ftp.chdir(remote_installation_path)
40
+
41
+ Dir["#{dir}/*"].each do |f|
42
+ filename = File.basename(f)
43
+ puts "Uploading #{filename}"
44
+ ftp.putbinaryfile(f, filename, 1024)
45
+ end
46
+
47
+ filename = File.basename("#{@builder.ipa_path}")
48
+ puts "Uploading #{filename}"
49
+ ftp.putbinaryfile("#{@builder.ipa_path}", filename, 1024)
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,18 @@
1
+ module Xcode
2
+ module Deploy
3
+ class Kickfolio
4
+
5
+ def initialize(bundler, options={})
6
+ @bundler = bundler
7
+ @options = options
8
+ end
9
+
10
+ def deploy
11
+ RestClient.post "https://kickfolio.com/api/apps/#{@options[:app_id]}",
12
+ {:bundle_url => @options[:url], :auth_token => @options[:api_key]},
13
+ :content_type => 'application/json'
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ require 'xcode/deploy/web_assets'
2
+ require 'aws-sdk'
3
+
4
+ module Xcode
5
+ module Deploy
6
+ class S3
7
+ def initialize(builder, options)
8
+ @builder = builder
9
+ @options = options
10
+ end
11
+
12
+ def bucket
13
+ return @bucket unless @bucket.nil?
14
+ s3 = AWS::S3.new @options
15
+ @bucket = s3.buckets.create(@options[:bucket]) rescue s3.buckets[@options[:bucket]]
16
+ @bucket
17
+ end
18
+
19
+ def upload(path)
20
+ obj_path = File.join(@options[:dir]||'', File.basename(path))
21
+ puts "Uploading #{path} => #{bucket.name}/#{obj_path}"
22
+ bucket.objects[obj_path].
23
+ write(File.open(path), :acl => :public_read)
24
+ end
25
+
26
+ def deploy
27
+ remote_ipa = upload @builder.ipa_path
28
+ base_url = remote_ipa.public_url(:secure => false).to_s.split("/")[0..-2].join("/")
29
+
30
+ WebAssets.generate @builder, base_url do |dir|
31
+ Dir["#{dir}/*"].each do |path|
32
+ upload path
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,43 @@
1
+ require 'net/ssh'
2
+ require 'net/scp'
3
+ require 'xcode/deploy/web_assets'
4
+
5
+ module Xcode
6
+ module Deploy
7
+ class Ssh
8
+ attr_accessor :host, :username, :password, :dir
9
+
10
+ def initialize(builder, options)
11
+ @builder = builder
12
+ @username = options[:username]
13
+ @password = options[:password]
14
+ @dir = options[:dir]
15
+ @host = options[:host]
16
+ @base_url = options[:base_url]
17
+ end
18
+
19
+ def remote_installation_path
20
+ File.join(@dir, @builder.product_name)
21
+ end
22
+
23
+ def deploy
24
+ WebAssets.generate @builder, @base_url do |dist_path|
25
+ puts "Copying files to #{@remote_host}:#{remote_installation_path}"
26
+ Net::SSH.start(@host, @username, :password => @password) do |ssh|
27
+ puts "Creating folder with mkdir #{remote_installation_path}"
28
+ ssh.exec!("mkdir #{remote_installation_path}")
29
+ end
30
+ Net::SCP.start(@host, @username, :password => @password) do |scp|
31
+ puts "Copying files from folder #{dist_path}"
32
+ Dir["#{dist_path}/*"].each do |f|
33
+ puts "Copying #{f} to remote host in folder #{remote_installation_path}"
34
+ scp.upload! "#{f}", "#{remote_installation_path}"
35
+ end
36
+ scp.upload! "#{@options[:ipa_path]}", "#{remote_installation_path}"
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
6
+ <title>Beta Download</title>
7
+ <style type="text/css">
8
+ body {background:#fff;margin:0;padding:0;font-family:arial,helvetica,sans-serif;text-align:center;padding:10px;color:#333;font-size:16px;}
9
+ #container {width:300px;margin:0 auto;}
10
+ h1 {margin:0;padding:0;font-size:14px;}
11
+ p {font-size:13px;}
12
+ .link {background:#ecf5ff;border-top:1px solid #fff;border:1px solid #dfebf8;margin-top:.5em;padding:.3em;}
13
+ .link a {text-decoration:none;font-size:15px;display:block;color:#069;}
14
+ </style>
15
+ </head>
16
+ <body>
17
+ <div id="container">
18
+ <div class="link"><a href="itms-services://?action=download-manifest&url=<%= manifest_url %>">Tap Here to Install<br /><%= product_name %><br />On Your Device</a></div>
19
+ <p><strong>Link didn't work?</strong><br />
20
+ Make sure you're visiting this page on your device, not your computer.</p>
21
+ </body>
22
+ </html>
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>items</key>
6
+ <array>
7
+ <dict>
8
+ <key>assets</key>
9
+ <array>
10
+ <dict>
11
+ <key>kind</key>
12
+ <string>software-package</string>
13
+ <key>url</key>
14
+ <string><%= deployment_url %></string>
15
+ </dict>
16
+ </array>
17
+ <key>metadata</key>
18
+ <dict>
19
+ <key>bundle-identifier</key>
20
+ <string><%= bundle_identifier %></string>
21
+ <key>bundle-version</key>
22
+ <string><%= bundle_version %></string>
23
+ <key>kind</key>
24
+ <string>software</string>
25
+ <key>title</key>
26
+ <string><%= product_name %></string>
27
+ </dict>
28
+ </dict>
29
+ </array>
30
+ </dict>
31
+ </plist>
@@ -1,60 +1,65 @@
1
1
  require 'rest-client'
2
- require 'json'
3
2
 
4
3
  module Xcode
5
4
  module Deploy
6
5
  class Testflight
7
- attr_accessor :api_token, :team_token, :notify, :proxy, :notes, :lists
8
-
9
- def initialize(api_token, team_token)
10
- @api_token = api_token
11
- @team_token = team_token
12
- @notify = true
13
- @notes = nil
14
- @lists = []
6
+ attr_accessor :api_token, :team_token, :notify, :proxy, :notes, :lists, :builder
7
+ @@defaults = {}
8
+
9
+ def self.defaults(defaults={})
10
+ @@defaults = defaults
11
+ end
12
+
13
+ def initialize(builder, options={})
14
+ @builder = builder
15
+ @api_token = options[:api_token]||@@defaults[:api_token]
16
+ @team_token = options[:team_token]||@@defaults[:team_token]
17
+ @notify = options.has_key?(:notify) ? options[:notify] : true
18
+ @notes = options[:notes]
19
+ @lists = options[:lists]||[]
15
20
  @proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
16
21
  end
17
-
18
- def upload(ipa_path, dsymzip_path=nil)
22
+
23
+ def deploy
19
24
  puts "Uploading to Testflight..."
20
-
25
+
21
26
  # RestClient.proxy = @proxy || ENV['http_proxy'] || ENV['HTTP_PROXY']
22
27
  # RestClient.log = '/tmp/restclient.log'
23
- #
28
+ #
24
29
  # response = RestClient.post('http://testflightapp.com/api/builds.json',
25
- # :file => File.new(ipa_path),
26
- # :dsym => File.new(dsymzip_path),
30
+ # :file => File.new(builder.ipa_path),
31
+ # :dsym => File.new(builder.dsym_zip_path),
27
32
  # :api_token => @api_token,
28
33
  # :team_token => @team_token,
29
34
  # :notes => @notes,
30
35
  # :notify => @notify ? 'True' : 'False',
31
36
  # :distribution_lists => @lists.join(',')
32
37
  # )
33
- #
38
+ #
34
39
  # json = JSON.parse(response)
35
40
  # puts " + Done, got: #{json.inspect}"
36
41
  # json
37
-
42
+
38
43
  cmd = Xcode::Shell::Command.new 'curl'
39
- cmd << "--proxy #{@proxy}" unless @proxy.nil? or @proxy==''
44
+ cmd << "--proxy #{@proxy}" unless @proxy.nil? or @proxy==''
40
45
  cmd << "-X POST http://testflightapp.com/api/builds.json"
41
- cmd << "-F file=@\"#{ipa_path}\""
42
- cmd << "-F dsym=@\"#{dsymzip_path}\"" unless dsymzip_path.nil?
46
+ cmd << "-F file=@\"#{@builder.ipa_path}\""
47
+ cmd << "-F dsym=@\"#{@builder.dsym_zip_path}\"" unless @builder.dsym_zip_path.nil?
43
48
  cmd << "-F api_token='#{@api_token}'"
44
49
  cmd << "-F team_token='#{@team_token}'"
45
50
  cmd << "-F notes=\"#{@notes}\"" unless @notes.nil?
46
51
  cmd << "-F notify=#{@notify ? 'True' : 'False'}"
47
52
  cmd << "-F distribution_lists='#{@lists.join(',')}'" unless @lists.count==0
48
-
49
- response = Xcode::Shell.execute(cmd)
50
-
51
- json = JSON.parse(response.join(''))
53
+
54
+ response = cmd.execute
55
+
56
+ json = MultiJson.load(response.join(''))
52
57
  puts " + Done, got: #{json.inspect}"
53
-
58
+
54
59
  yield(json) if block_given?
55
-
60
+
56
61
  json
57
62
  end
58
63
  end
59
64
  end
60
- end
65
+ end
@@ -0,0 +1,39 @@
1
+ require 'erb'
2
+ require 'ostruct'
3
+ require 'tmpdir'
4
+
5
+ module Xcode
6
+ module Deploy
7
+ module WebAssets
8
+ class BindingContext < OpenStruct
9
+ def get_binding
10
+ return binding()
11
+ end
12
+ end
13
+
14
+ def self.generate(builder, base_url, &block)
15
+ Dir.mktmpdir do |dist_path|
16
+
17
+ context = BindingContext.new
18
+ context.product_name = builder.product_name
19
+ context.manifest_url = "#{base_url}/manifest.plist"
20
+ context.deployment_url = "#{base_url}/#{builder.ipa_name}"
21
+ context.bundle_version = builder.bundle_version
22
+ context.bundle_identifier = builder.bundle_identifier
23
+
24
+ rhtml = ERB.new(File.read("#{File.dirname(__FILE__)}/templates/manifest.rhtml"))
25
+ File.open("#{dist_path}/manifest.plist", "w") do |io|
26
+ io.write(rhtml.result(context.get_binding))
27
+ end
28
+
29
+ rhtml = ERB.new(File.read("#{File.dirname(__FILE__)}/templates/index.rhtml"))
30
+ File.open("#{dist_path}/index.html", "w") do |io|
31
+ io.write(rhtml.result(context.get_binding))
32
+ end
33
+
34
+ yield dist_path
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end