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 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
- project = Xcode.project(:MyProject).target(:Target).config(:Debug)
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
@@ -33,6 +33,7 @@ module Xcode
33
33
  cmd << "-project \"#{@target.project.path}\""
34
34
  cmd << "-target \"#{@target.name}\""
35
35
  cmd << "-configuration \"#{@config.name}\""
36
+ cmd << "CODE_SIGN_IDENTITY=\"#{@identity}\""
36
37
  Xcode::Shell.execute(cmd)
37
38
  end
38
39
 
@@ -23,7 +23,7 @@ module Xcode
23
23
  value
24
24
  end
25
25
  end
26
-
26
+
27
27
  def info_plist_location
28
28
  @json['buildSettings']['INFOPLIST_FILE']
29
29
  end
@@ -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[name.to_s.to_sym]
20
- raise "No such target #{name}, available targets are #{@targets.keys}" if target.nil?
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
- config = Xcode::Configuration.new(target, json['objects'][buildConfiguration])
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[target.name.to_sym] = target
67
+ @targets << target
44
68
  end
45
69
  end
46
70
 
@@ -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[name.to_s.to_sym]
21
- raise "No such config #{name}, available configs are #{@configs.keys}" if config.nil?
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
@@ -1,3 +1,3 @@
1
1
  module Xcode
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -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
- if @@projects.nil?
16
- @@projects = parse_projects
17
- end
18
- @@projects.each do |p|
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: #{@@projects.map {|p| p.name}.join(', ') }"
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.import_certificate(cert, password, keychain="~/Library/Keychains/login.keychain")
25
- cmd = []
26
- cmd << "security"
27
- cmd << "import '#{cert}'"
28
- cmd << "-k #{keychain}"
29
- cmd << "-P #{password}"
30
- cmd << "-T /usr/bin/codesign"
31
- Xcode::Shell.execute(cmd)
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
@@ -20,4 +20,5 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_runtime_dependency "json"
22
22
  s.add_runtime_dependency "plist"
23
+ s.add_runtime_dependency "nokogiri"
23
24
  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.9
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-08 00:00:00.000000000Z
12
+ date: 2011-11-10 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
16
- requirement: &70283870191140 !ruby/object:Gem::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: *70283870191140
24
+ version_requirements: *70260671242760
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: plist
27
- requirement: &70283870190720 !ruby/object:Gem::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: *70283870190720
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