xcoder 0.0.7 → 0.0.8
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.
- data/README.md +8 -5
- data/lib/xcode/builder.rb +129 -0
- data/lib/xcode/configuration.rb +3 -81
- data/lib/xcode/project.rb +3 -1
- data/lib/xcode/provisioning_profile.rb +50 -0
- data/lib/xcode/version.rb +1 -1
- data/lib/xcoder.rb +10 -20
- metadata +8 -6
data/README.md
CHANGED
@@ -18,18 +18,21 @@ and then require the gem in your project/rakefile/etc
|
|
18
18
|
|
19
19
|
### Find a configuration for a target on a project
|
20
20
|
|
21
|
-
project = Xcode.
|
22
|
-
config = project.target(:Target).config(:Debug)
|
23
|
-
|
21
|
+
project = Xcode.project(:MyProject).target(:Target).config(:Debug)
|
24
22
|
|
25
23
|
### Building a configuration
|
26
24
|
|
27
|
-
config.
|
25
|
+
builder = config.builder
|
26
|
+
builder.profile = 'Profiles/MyAdHoc.mobileprovision' # This will remove old profiles and install the profile
|
27
|
+
builder.identity = 'iPhone Developer: Ray Hilton' # The name of the identity to use to sign the IPA (optional)
|
28
|
+
builder.build
|
28
29
|
|
29
30
|
### Packaging a built .app
|
30
31
|
|
31
|
-
|
32
|
+
builder.package
|
32
33
|
|
34
|
+
This will produce a .ipa and a .dSYM.zip
|
35
|
+
|
33
36
|
### Incrementing the build number
|
34
37
|
|
35
38
|
config.info_plist do |info|
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'xcode/shell'
|
2
|
+
require 'xcode/provisioning_profile'
|
3
|
+
|
4
|
+
module Xcode
|
5
|
+
class Builder
|
6
|
+
attr_accessor :profile, :identity
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@target = config.target
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def install_profile
|
14
|
+
return if @profile.nil?
|
15
|
+
# TODO: remove other profiles for the same app?
|
16
|
+
p = ProvisioningProfile.new(@profile)
|
17
|
+
|
18
|
+
ProvisioningProfile.installed_profiles.each do |installed|
|
19
|
+
if installed.identifiers==p.identifiers and installed.uuid==p.uuid
|
20
|
+
installed.uninstall
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
p.install
|
25
|
+
end
|
26
|
+
|
27
|
+
def build
|
28
|
+
install_profile
|
29
|
+
|
30
|
+
cmd = []
|
31
|
+
cmd << "xcodebuild"
|
32
|
+
cmd << "-sdk #{@target.project.sdk}" unless @target.project.sdk.nil?
|
33
|
+
cmd << "-project \"#{@target.project.path}\""
|
34
|
+
cmd << "-target \"#{@target.name}\""
|
35
|
+
cmd << "-configuration \"#{@config.name}\""
|
36
|
+
Xcode::Shell.execute(cmd)
|
37
|
+
end
|
38
|
+
|
39
|
+
def clean
|
40
|
+
cmd = []
|
41
|
+
cmd << "xcodebuild"
|
42
|
+
cmd << "-project \"#{@target.project.path}\""
|
43
|
+
cmd << "-target \"#{@target.name}\""
|
44
|
+
cmd << "-configuration \"#{@config.name}\""
|
45
|
+
cmd << "clean"
|
46
|
+
Xcode::Shell.execute(cmd)
|
47
|
+
|
48
|
+
# FIXME: Totally not safe
|
49
|
+
# cmd = []
|
50
|
+
# cmd << "rm -Rf #{build_path}"
|
51
|
+
# Xcode::Shell.execute(cmd)
|
52
|
+
end
|
53
|
+
|
54
|
+
def sign
|
55
|
+
cmd = []
|
56
|
+
cmd << "codesign"
|
57
|
+
cmd << "--force"
|
58
|
+
cmd << "--sign \"#{@identity}\""
|
59
|
+
cmd << "--resource-rules=\"#{app_path}/ResourceRules.plist\""
|
60
|
+
cmd << "--entitlements \"#{entitlements_path}\""
|
61
|
+
cmd << "\"#{ipa_path}\""
|
62
|
+
Xcode::Shell.execute(cmd)
|
63
|
+
end
|
64
|
+
|
65
|
+
def package
|
66
|
+
#package IPA
|
67
|
+
cmd = []
|
68
|
+
cmd << "xcrun"
|
69
|
+
cmd << "-sdk #{@target.project.sdk.nil? ? "iphoneos" : @target.project.sdk}"
|
70
|
+
cmd << "PackageApplication"
|
71
|
+
cmd << "-v \"#{app_path}\""
|
72
|
+
cmd << "-o \"#{ipa_path}\""
|
73
|
+
|
74
|
+
unless @identity.nil?
|
75
|
+
cmd << "--sign \"#{@identity}\""
|
76
|
+
end
|
77
|
+
|
78
|
+
unless @profile.nil?
|
79
|
+
cmd << "--embed \"#{@profile}\""
|
80
|
+
end
|
81
|
+
|
82
|
+
Xcode::Shell.execute(cmd)
|
83
|
+
|
84
|
+
# package dSYM
|
85
|
+
cmd = []
|
86
|
+
cmd << "zip"
|
87
|
+
cmd << "-r"
|
88
|
+
cmd << "-T"
|
89
|
+
cmd << "-y #{dsym_zip_path}"
|
90
|
+
cmd << "#{dsym_path}"
|
91
|
+
Xcode::Shell.execute(cmd)
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_path
|
95
|
+
"#{File.dirname(@target.project.path)}/build/"
|
96
|
+
end
|
97
|
+
|
98
|
+
def configuration_build_path
|
99
|
+
"#{build_path}/#{@config.name}-#{@target.project.sdk}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def entitlements_path
|
103
|
+
"#{build_path}/#{@target.name}.build/#{name}-#{@target.project.sdk}/#{@target.name}.build/#{@config.product_name}.xcent"
|
104
|
+
end
|
105
|
+
|
106
|
+
def app_path
|
107
|
+
"#{configuration_build_path}/#{@config.product_name}.app"
|
108
|
+
end
|
109
|
+
|
110
|
+
def product_version_basename
|
111
|
+
version = @config.info_plist.version
|
112
|
+
version = "SNAPSHOT" if version.nil? or version==""
|
113
|
+
"#{configuration_build_path}/#{@config.product_name}-#{@config.name}-#{version}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def ipa_path
|
117
|
+
"#{product_version_basename}.ipa"
|
118
|
+
end
|
119
|
+
|
120
|
+
def dsym_path
|
121
|
+
"#{app_path}.dSYM"
|
122
|
+
end
|
123
|
+
|
124
|
+
def dsym_zip_path
|
125
|
+
"#{product_version_basename}.dSYM.zip"
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
data/lib/xcode/configuration.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'xcode/
|
1
|
+
require 'xcode/builder'
|
2
2
|
|
3
3
|
module Xcode
|
4
4
|
class Configuration
|
@@ -43,86 +43,8 @@ module Xcode
|
|
43
43
|
info
|
44
44
|
end
|
45
45
|
|
46
|
-
def
|
47
|
-
|
48
|
-
cmd << "xcodebuild"
|
49
|
-
cmd << "-sdk #{@target.project.sdk}" unless @target.project.sdk.nil?
|
50
|
-
cmd << "-project \"#{@target.project.path}\""
|
51
|
-
cmd << "-target \"#{@target.name}\""
|
52
|
-
cmd << "-configuration \"#{name}\""
|
53
|
-
Xcode::Shell.execute(cmd)
|
46
|
+
def builder
|
47
|
+
Xcode::Builder.new(self)
|
54
48
|
end
|
55
|
-
|
56
|
-
def clean
|
57
|
-
cmd = []
|
58
|
-
cmd << "xcodebuild"
|
59
|
-
# cmd << "-sdk #{@target.project.sdk}" unless @target.project.sdk.nil?
|
60
|
-
cmd << "-project \"#{@target.project.path}\""
|
61
|
-
cmd << "-target \"#{@target.name}\""
|
62
|
-
cmd << "-configuration \"#{name}\""
|
63
|
-
cmd << "clean"
|
64
|
-
Xcode::Shell.execute(cmd)
|
65
|
-
end
|
66
|
-
|
67
|
-
def sign(identity)
|
68
|
-
cmd = []
|
69
|
-
cmd << "codesign"
|
70
|
-
cmd << "--force"
|
71
|
-
cmd << "--sign \"#{identity}\""
|
72
|
-
cmd << "--resource-rules=\"#{app_path}/ResourceRules.plist\""
|
73
|
-
cmd << "--entitlements \"#{entitlements_path}\""
|
74
|
-
cmd << "\"#{ipa_path}\""
|
75
|
-
Xcode::Shell.execute(cmd)
|
76
|
-
end
|
77
|
-
|
78
|
-
def entitlements_path
|
79
|
-
"#{File.dirname(@target.project.path)}/build/#{@target.name}.build/#{name}-#{@target.project.sdk}/#{@target.name}.build/#{product_name}.xcent"
|
80
|
-
end
|
81
|
-
|
82
|
-
def app_path
|
83
|
-
"#{File.dirname(@target.project.path)}/build/#{name}-#{@target.project.sdk}/#{product_name}.app"
|
84
|
-
end
|
85
|
-
|
86
|
-
def ipa_path
|
87
|
-
"#{File.dirname(@target.project.path)}/build/#{name}-#{@target.project.sdk}/#{product_name}-#{name}-#{info_plist.version}.ipa"
|
88
|
-
end
|
89
|
-
|
90
|
-
def package(options={})
|
91
|
-
cmd = []
|
92
|
-
cmd << "xcrun"
|
93
|
-
cmd << "-sdk #{@target.project.sdk.nil? ? "iphoneos" : @target.project.sdk}"
|
94
|
-
cmd << "PackageApplication"
|
95
|
-
cmd << "-v \"#{app_path}\""
|
96
|
-
cmd << "-o \"#{ipa_path}\""
|
97
|
-
|
98
|
-
if options.has_key? :sign
|
99
|
-
cmd << "--sign \"#{options[:sign]}\""
|
100
|
-
end
|
101
|
-
|
102
|
-
if options.has_key? :profile
|
103
|
-
cmd << "--embed \"#{options[:profile]}\""
|
104
|
-
end
|
105
|
-
|
106
|
-
Xcode::Shell.execute(cmd)
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def execute(bits, show_output=true)
|
112
|
-
out = []
|
113
|
-
cmd = bits.join(' ')
|
114
|
-
puts "EXECUTE: #{cmd}"
|
115
|
-
IO.popen (cmd) do |f|
|
116
|
-
f.each do |line|
|
117
|
-
puts line if show_output
|
118
|
-
out << line
|
119
|
-
end
|
120
|
-
end
|
121
|
-
#Process.wait
|
122
|
-
raise "Error (#{$?.exitstatus}) executing '#{cmd}'\n\n #{out.join(" ")}" if $?.exitstatus>0
|
123
|
-
#puts "RETURN: #{out.inspect}"
|
124
|
-
out
|
125
|
-
end
|
126
|
-
|
127
49
|
end
|
128
50
|
end
|
data/lib/xcode/project.rb
CHANGED
@@ -4,11 +4,12 @@ require 'xcode/configuration'
|
|
4
4
|
|
5
5
|
module Xcode
|
6
6
|
class Project
|
7
|
-
attr_reader :targets, :sdk, :path
|
7
|
+
attr_reader :name, :targets, :sdk, :path
|
8
8
|
def initialize(path, sdk=nil)
|
9
9
|
@sdk = sdk || "iphoneos" # FIXME: should support OSX/simulator too
|
10
10
|
@path = File.expand_path path
|
11
11
|
@targets = {}
|
12
|
+
@name = File.basename(@path).gsub(/\.xcodeproj/,'')
|
12
13
|
|
13
14
|
parse_pbxproj
|
14
15
|
# parse_configurations
|
@@ -27,6 +28,7 @@ module Xcode
|
|
27
28
|
json = JSON.parse(`plutil -convert json -o - "#{@path}/project.pbxproj"`)
|
28
29
|
|
29
30
|
root = json['objects'][json['rootObject']]
|
31
|
+
|
30
32
|
root['targets'].each do |target_id|
|
31
33
|
target = Xcode::Target.new(self, json['objects'][target_id])
|
32
34
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Xcode
|
2
|
+
class ProvisioningProfile
|
3
|
+
attr_reader :path, :name, :uuid, :identifiers
|
4
|
+
def initialize(path)
|
5
|
+
@path = path
|
6
|
+
@identifiers = []
|
7
|
+
|
8
|
+
# TODO: im sure this could be done in a nicer way. maybe read out the XML-like stuff and use the plist -> json converter
|
9
|
+
uuid = nil
|
10
|
+
File.open(path, "rb") do |f|
|
11
|
+
input = f.read
|
12
|
+
input=~/<key>UUID<\/key>.*?<string>(.*?)<\/string>/im
|
13
|
+
@uuid = $1.strip
|
14
|
+
|
15
|
+
input=~/<key>Name<\/key>.*?<string>(.*?)<\/string>/im
|
16
|
+
@name = $1.strip
|
17
|
+
|
18
|
+
input=~/<key>ApplicationIdentifierPrefix<\/key>.*?<array>(.*?)<\/array>/im
|
19
|
+
$1.split(/<string>/).each do |id|
|
20
|
+
next if id.nil? or id.strip==""
|
21
|
+
@identifiers << id.gsub(/<\/string>/,'').strip
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.profiles_path
|
28
|
+
File.expand_path "~/Library/MobileDevice/Provisioning\\ Profiles/"
|
29
|
+
end
|
30
|
+
|
31
|
+
def install_path
|
32
|
+
"#{ProvisioningProfile.profiles_path}/#{self.uuid}.mobileprovision"
|
33
|
+
end
|
34
|
+
|
35
|
+
def install
|
36
|
+
Xcode::Shell.execute("cp #{self.path} #{self.install_path}")
|
37
|
+
end
|
38
|
+
|
39
|
+
def uninstall
|
40
|
+
Xcode::Shell.execute("rm -f #{self.install_path}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.installed_profiles
|
44
|
+
Dir["#{self.profiles_path}/*.mobileprovision"].map do |file|
|
45
|
+
ProvisioningProfile.new(file)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/lib/xcode/version.rb
CHANGED
data/lib/xcoder.rb
CHANGED
@@ -10,13 +10,16 @@ module Xcode
|
|
10
10
|
@@projects = nil
|
11
11
|
@@sdks = nil
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
def self.project(name)
|
14
|
+
name = name.to_s
|
15
|
+
if @@projects.nil?
|
16
|
+
@@projects = parse_projects
|
17
|
+
end
|
18
|
+
@@projects.each do |p|
|
19
|
+
return p if p.name == name
|
20
|
+
end
|
21
|
+
raise "Unable to find project named #{name}. However, I did find these projects: #{@@projects.map {|p| p.name}.join(', ') }"
|
22
|
+
end
|
20
23
|
|
21
24
|
def self.import_certificate(cert, password, keychain="~/Library/Keychains/login.keychain")
|
22
25
|
cmd = []
|
@@ -28,19 +31,6 @@ module Xcode
|
|
28
31
|
Xcode::Shell.execute(cmd)
|
29
32
|
end
|
30
33
|
|
31
|
-
def self.import_provisioning_profile(profile)
|
32
|
-
uuid = nil
|
33
|
-
File.open(profile, "rb") do |f|
|
34
|
-
input = f.read
|
35
|
-
input=~/<key>UUID<\/key>.*<string>(.*)<\/string>/im
|
36
|
-
uuid = $1.strip
|
37
|
-
end
|
38
|
-
|
39
|
-
puts "Importing profile #{profile} with UUID #{uuid}"
|
40
|
-
|
41
|
-
Xcode::Shell.execute("cp #{profile} ~/Library/MobileDevice/Provisioning\\ Profiles/#{uuid}.mobileprovision")
|
42
|
-
end
|
43
|
-
|
44
34
|
def self.find_projects(dir='.')
|
45
35
|
parse_projects(dir)
|
46
36
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xcoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-11-08 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
16
|
-
requirement: &
|
16
|
+
requirement: &70359983645620 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70359983645620
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: plist
|
27
|
-
requirement: &
|
27
|
+
requirement: &70359983645200 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70359983645200
|
36
36
|
description: Provides a ruby based object-model for parsing project structures and
|
37
37
|
invoking builds
|
38
38
|
email:
|
@@ -46,9 +46,11 @@ files:
|
|
46
46
|
- Gemfile
|
47
47
|
- README.md
|
48
48
|
- Rakefile
|
49
|
+
- lib/xcode/builder.rb
|
49
50
|
- lib/xcode/configuration.rb
|
50
51
|
- lib/xcode/info_plist.rb
|
51
52
|
- lib/xcode/project.rb
|
53
|
+
- lib/xcode/provisioning_profile.rb
|
52
54
|
- lib/xcode/shell.rb
|
53
55
|
- lib/xcode/target.rb
|
54
56
|
- lib/xcode/version.rb
|