xcoder 0.0.9 → 0.0.10
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 +27 -2
- data/lib/xcode/builder.rb +1 -0
- data/lib/xcode/configuration.rb +1 -1
- data/lib/xcode/keychain.rb +29 -0
- data/lib/xcode/project.rb +32 -8
- data/lib/xcode/scheme.rb +33 -0
- data/lib/xcode/target.rb +3 -3
- data/lib/xcode/version.rb +1 -1
- data/lib/xcode/workspace.rb +33 -0
- data/lib/xcoder.rb +37 -13
- data/xcoder.gemspec +1 -0
- metadata +20 -6
data/README.md
CHANGED
|
@@ -12,13 +12,17 @@ and then require the gem in your project/rakefile/etc
|
|
|
12
12
|
|
|
13
13
|
require 'xcoder'
|
|
14
14
|
|
|
15
|
+
### Load a project
|
|
16
|
+
|
|
17
|
+
project = Xcode.project('MyProject') # Can be the name, the file (e.g. MyProject.xcodeproj) or the path
|
|
18
|
+
|
|
15
19
|
### Finding all projects from the current directory down
|
|
16
20
|
|
|
17
21
|
Xcode.find_projects.each {|p| puts p.name }
|
|
18
22
|
|
|
19
23
|
### Find a configuration for a target on a project
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
config = Xcode.project(:MyProject).target(:Target).config(:Debug) # returns an Xcode::Configuration object
|
|
22
26
|
|
|
23
27
|
### Building a configuration
|
|
24
28
|
|
|
@@ -38,4 +42,25 @@ This will produce a .ipa and a .dSYM.zip
|
|
|
38
42
|
config.info_plist do |info|
|
|
39
43
|
info.version = info.version.to_i + 1
|
|
40
44
|
info.save
|
|
41
|
-
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
### Working with workspaces
|
|
48
|
+
|
|
49
|
+
Loading workspaces can be done in a similar way to projects:
|
|
50
|
+
|
|
51
|
+
Xcode.workspaces.each do |w|
|
|
52
|
+
w.describe # prints a recursive description of the structure of the workspace and its projects
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
Or, if you know the name:
|
|
56
|
+
|
|
57
|
+
workspace = Xcode.workspace('MyWorkspace') # Can be the name, the file (e.g. MyWorkspace.xcworkspace) or the path
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### Schemes
|
|
61
|
+
|
|
62
|
+
There is basic support for schemes, you can access them from a project like so:
|
|
63
|
+
|
|
64
|
+
config = project.scheme('MyScheme').launch # Gets the Launch action for specified scheme. Can also specify 'test' to get the test action
|
|
65
|
+
|
|
66
|
+
The 'launch' and 'test' methods access the different actions within the scheme, and they map to a Xcode::Configuration object (i.e., the schemes map to a target and configuration in a traditional XCode3 project style).
|
data/lib/xcode/builder.rb
CHANGED
data/lib/xcode/configuration.rb
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Xcode
|
|
2
|
+
class Keychain
|
|
3
|
+
def initialize(path)
|
|
4
|
+
@path = File.expand_path path
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def import(cert, password)
|
|
8
|
+
cmd = []
|
|
9
|
+
cmd << "security"
|
|
10
|
+
cmd << "import '#{cert}'"
|
|
11
|
+
cmd << "-k #{@path}"
|
|
12
|
+
cmd << "-P #{password}"
|
|
13
|
+
cmd << "-T /usr/bin/codesign"
|
|
14
|
+
Xcode::Shell.execute(cmd)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def unlock(password)
|
|
18
|
+
cmd = []
|
|
19
|
+
cmd << "security"
|
|
20
|
+
cmd << "unlock-keychain #{@path}"
|
|
21
|
+
cmd << "-p #{password}"
|
|
22
|
+
Xcode::Shell.execute(cmd)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.login_keychain
|
|
26
|
+
Xcode::Keychain.new("~/Library/Keychains/login.keychain")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/xcode/project.rb
CHANGED
|
@@ -1,29 +1,54 @@
|
|
|
1
1
|
require 'json'
|
|
2
2
|
require 'xcode/target'
|
|
3
3
|
require 'xcode/configuration'
|
|
4
|
+
require 'xcode/scheme'
|
|
4
5
|
|
|
5
6
|
module Xcode
|
|
6
7
|
class Project
|
|
7
|
-
attr_reader :name, :targets, :sdk, :path
|
|
8
|
+
attr_reader :name, :targets, :sdk, :path, :schemes
|
|
8
9
|
def initialize(path, sdk=nil)
|
|
9
10
|
@sdk = sdk || "iphoneos" # FIXME: should support OSX/simulator too
|
|
10
11
|
@path = File.expand_path path
|
|
11
|
-
@targets =
|
|
12
|
+
@targets = []
|
|
13
|
+
@schemes = []
|
|
12
14
|
@name = File.basename(@path).gsub(/\.xcodeproj/,'')
|
|
13
15
|
|
|
14
16
|
parse_pbxproj
|
|
17
|
+
parse_schemes
|
|
15
18
|
# parse_configurations
|
|
16
19
|
end
|
|
17
|
-
|
|
20
|
+
|
|
18
21
|
def target(name)
|
|
19
|
-
target = @targets
|
|
20
|
-
raise "No such target #{name}, available targets are #{@targets.
|
|
22
|
+
target = @targets.select {|t| t.name == name.to_s}.first
|
|
23
|
+
raise "No such target #{name}, available targets are #{@targets.map {|t| t.name}.join(', ')}" if target.nil?
|
|
21
24
|
yield target if block_given?
|
|
22
25
|
target
|
|
23
26
|
end
|
|
24
27
|
|
|
28
|
+
def describe
|
|
29
|
+
puts "Project #{name} contains"
|
|
30
|
+
targets.each do |t|
|
|
31
|
+
puts " + target:#{t.name}"
|
|
32
|
+
t.configs.each do |c|
|
|
33
|
+
puts " + config:#{c.name}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
schemes.each do |s|
|
|
37
|
+
puts " + scheme #{s.name}"
|
|
38
|
+
puts " + Launch action => target:#{s.launch.target.name}, config:#{s.launch.name}" unless s.launch.nil?
|
|
39
|
+
puts " + Test action => target:#{s.test.target.name}, config:#{s.test.name}" unless s.test.nil?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
25
43
|
private
|
|
26
44
|
|
|
45
|
+
def parse_schemes
|
|
46
|
+
# schemes are in project/xcshareddata/xcschemes/*.xcscheme
|
|
47
|
+
Dir["#{@path}/xcshareddata/xcschemes/*.xcscheme"].each do |scheme|
|
|
48
|
+
@schemes << Xcode::Scheme.new(self, scheme)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
27
52
|
def parse_pbxproj
|
|
28
53
|
json = JSON.parse(`plutil -convert json -o - "#{@path}/project.pbxproj"`)
|
|
29
54
|
|
|
@@ -36,11 +61,10 @@ module Xcode
|
|
|
36
61
|
buildConfigurations = json['objects'][buildConfigurationList]['buildConfigurations']
|
|
37
62
|
|
|
38
63
|
buildConfigurations.each do |buildConfiguration|
|
|
39
|
-
|
|
40
|
-
target.configs[config.name.to_sym] = config
|
|
64
|
+
target.configs << Xcode::Configuration.new(target, json['objects'][buildConfiguration])
|
|
41
65
|
end
|
|
42
66
|
|
|
43
|
-
@targets
|
|
67
|
+
@targets << target
|
|
44
68
|
end
|
|
45
69
|
end
|
|
46
70
|
|
data/lib/xcode/scheme.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
|
|
3
|
+
module Xcode
|
|
4
|
+
|
|
5
|
+
# Schemes are an XML file that describe build, test, launch and profile actions
|
|
6
|
+
# For the purposes of Xcoder, we want to be able to build and test
|
|
7
|
+
# The scheme's build action only describes a target, so we need to look at launch for the config
|
|
8
|
+
class Scheme
|
|
9
|
+
attr_reader :project, :path, :name, :launch, :test
|
|
10
|
+
def initialize(project, path)
|
|
11
|
+
@project = project
|
|
12
|
+
@path = File.expand_path(path)
|
|
13
|
+
@name = File.basename(path).gsub(/\.xcscheme$/,'')
|
|
14
|
+
doc = Nokogiri::XML(open(@path))
|
|
15
|
+
|
|
16
|
+
@launch = parse_action(doc, 'launch')
|
|
17
|
+
@test = parse_action(doc, 'test')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def parse_action(doc, action_name)
|
|
24
|
+
action = doc.xpath("//#{action_name.capitalize}Action").first
|
|
25
|
+
buildableReference = action.xpath('BuildableProductRunnable/BuildableReference').first
|
|
26
|
+
return nil if buildableReference.nil?
|
|
27
|
+
|
|
28
|
+
target_name = buildableReference['BlueprintName']
|
|
29
|
+
@project.target(target_name).config(action['buildConfiguration'])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/xcode/target.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Xcode
|
|
|
5
5
|
def initialize(project, json)
|
|
6
6
|
@project = project
|
|
7
7
|
@json = json
|
|
8
|
-
@configs =
|
|
8
|
+
@configs = []
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def productName
|
|
@@ -17,8 +17,8 @@ module Xcode
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def config(name)
|
|
20
|
-
config = @configs
|
|
21
|
-
raise "No such config #{name}, available configs are #{@configs.
|
|
20
|
+
config = @configs.select {|c| c.name == name.to_s}.first
|
|
21
|
+
raise "No such config #{name}, available configs are #{@configs.map {|c| c.name}.join(', ')}" if config.nil?
|
|
22
22
|
yield config if block_given?
|
|
23
23
|
config
|
|
24
24
|
end
|
data/lib/xcode/version.rb
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'xcode/project'
|
|
2
|
+
|
|
3
|
+
module Xcode
|
|
4
|
+
class Workspace
|
|
5
|
+
attr_reader :projects, :name, :path
|
|
6
|
+
def initialize(path)
|
|
7
|
+
path = "#{path}.xcworkspace" unless path=~/\.xcworkspace/
|
|
8
|
+
path = "#{path}/contents.xcworkspacedata" unless path=~/xcworkspacedata$/
|
|
9
|
+
|
|
10
|
+
@name = File.basename(path.gsub(/\.xcworkspace\/contents\.xcworkspacedata/,''))
|
|
11
|
+
@projects = []
|
|
12
|
+
@path = File.expand_path path
|
|
13
|
+
|
|
14
|
+
File.open(@path).read.split(/<FileRef/).each do |line|
|
|
15
|
+
if line=~/location\s*=\s*\"group\:(.+?)\"/
|
|
16
|
+
project_path = "#{workspace_root}/#{$1}"
|
|
17
|
+
@projects << Xcode::Project.new(project_path)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def describe
|
|
23
|
+
puts "Workspace #{name} contains:"
|
|
24
|
+
projects.each do |p|
|
|
25
|
+
p.describe
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def workspace_root
|
|
30
|
+
File.dirname(File.dirname(@path))
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/xcoder.rb
CHANGED
|
@@ -5,30 +5,44 @@ require "xcode/project"
|
|
|
5
5
|
require "xcode/info_plist"
|
|
6
6
|
require "xcode/shell"
|
|
7
7
|
require 'plist'
|
|
8
|
+
require 'xcode/keychain'
|
|
9
|
+
require 'xcode/workspace'
|
|
8
10
|
|
|
9
11
|
module Xcode
|
|
10
12
|
@@projects = nil
|
|
13
|
+
@@workspaces = nil
|
|
11
14
|
@@sdks = nil
|
|
12
15
|
|
|
16
|
+
def self.projects
|
|
17
|
+
@@projects = parse_projects if @@projects.nil?
|
|
18
|
+
@@projects
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.workspaces
|
|
22
|
+
@@workspaces = parse_workspaces if @@workspaces.nil?
|
|
23
|
+
@@workspaces
|
|
24
|
+
end
|
|
25
|
+
|
|
13
26
|
def self.project(name)
|
|
14
27
|
name = name.to_s
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
28
|
+
|
|
29
|
+
return Xcode::Project.new(name) if name=~/\.xcodeproj/
|
|
30
|
+
|
|
31
|
+
self.projects.each do |p|
|
|
19
32
|
return p if p.name == name
|
|
20
33
|
end
|
|
21
|
-
raise "Unable to find project named #{name}. However, I did find these projects: #{
|
|
34
|
+
raise "Unable to find a project named #{name}. However, I did find these projects: #{self.projects.map {|p| p.name}.join(', ') }"
|
|
22
35
|
end
|
|
23
36
|
|
|
24
|
-
def self.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
def self.workspace(name)
|
|
38
|
+
name = name.to_s
|
|
39
|
+
|
|
40
|
+
return Xcode::Workspace.new(name) if name=~/\.xcworkspace/
|
|
41
|
+
|
|
42
|
+
self.workspaces.each do |p|
|
|
43
|
+
return p if p.name == name
|
|
44
|
+
end
|
|
45
|
+
raise "Unable to find a workspace named #{name}. However, I did find these workspaces: #{self.workspaces.map {|p| p.name}.join(', ') }"
|
|
32
46
|
end
|
|
33
47
|
|
|
34
48
|
def self.find_projects(dir='.')
|
|
@@ -61,6 +75,16 @@ module Xcode
|
|
|
61
75
|
end
|
|
62
76
|
end
|
|
63
77
|
end
|
|
78
|
+
|
|
79
|
+
def self.parse_workspaces(dir='.')
|
|
80
|
+
projects = []
|
|
81
|
+
Find.find(dir) do |path|
|
|
82
|
+
if path=~/\.xcworkspace$/ and !(path=~/\.xcodeproj\//)
|
|
83
|
+
projects << Xcode::Workspace.new(path)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
projects
|
|
87
|
+
end
|
|
64
88
|
|
|
65
89
|
def self.parse_projects(dir='.')
|
|
66
90
|
projects = []
|
data/xcoder.gemspec
CHANGED
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.10
|
|
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-11-
|
|
12
|
+
date: 2011-11-10 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: json
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &70260671242760 !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: *70260671242760
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: plist
|
|
27
|
-
requirement: &
|
|
27
|
+
requirement: &70260671242340 !ruby/object:Gem::Requirement
|
|
28
28
|
none: false
|
|
29
29
|
requirements:
|
|
30
30
|
- - ! '>='
|
|
@@ -32,7 +32,18 @@ dependencies:
|
|
|
32
32
|
version: '0'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
|
-
version_requirements: *
|
|
35
|
+
version_requirements: *70260671242340
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: nokogiri
|
|
38
|
+
requirement: &70260671241920 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ! '>='
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
type: :runtime
|
|
45
|
+
prerelease: false
|
|
46
|
+
version_requirements: *70260671241920
|
|
36
47
|
description: Provides a ruby based object-model for parsing project structures and
|
|
37
48
|
invoking builds
|
|
38
49
|
email:
|
|
@@ -49,11 +60,14 @@ files:
|
|
|
49
60
|
- lib/xcode/builder.rb
|
|
50
61
|
- lib/xcode/configuration.rb
|
|
51
62
|
- lib/xcode/info_plist.rb
|
|
63
|
+
- lib/xcode/keychain.rb
|
|
52
64
|
- lib/xcode/project.rb
|
|
53
65
|
- lib/xcode/provisioning_profile.rb
|
|
66
|
+
- lib/xcode/scheme.rb
|
|
54
67
|
- lib/xcode/shell.rb
|
|
55
68
|
- lib/xcode/target.rb
|
|
56
69
|
- lib/xcode/version.rb
|
|
70
|
+
- lib/xcode/workspace.rb
|
|
57
71
|
- lib/xcoder.rb
|
|
58
72
|
- xcoder.gemspec
|
|
59
73
|
homepage: https://github.com/rayh/xcoder
|