xcoder 0.0.1
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/.gitignore +4 -0
- data/Gemfile +3 -0
- data/README.md +39 -0
- data/Rakefile +1 -0
- data/lib/xcode/configuration.rb +56 -0
- data/lib/xcode/info_plist.rb +37 -0
- data/lib/xcode/project.rb +80 -0
- data/lib/xcode/target.rb +28 -0
- data/lib/xcode/version.rb +3 -0
- data/lib/xcoder.rb +59 -0
- data/xcoder.gemspec +23 -0
- metadata +79 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# XCoder
|
2
|
+
|
3
|
+
A ruby wrapper around various xcode tools and the project.pbxproj
|
4
|
+
|
5
|
+
## Example Usage
|
6
|
+
|
7
|
+
You will need to install the gem:
|
8
|
+
|
9
|
+
`gem install xcoder`
|
10
|
+
|
11
|
+
and then require the gem in your project/rakefile/etc
|
12
|
+
|
13
|
+
`require 'xcoder'`
|
14
|
+
|
15
|
+
### Finding all projects from the current directory down
|
16
|
+
|
17
|
+
`Xcode.find_projects.each {|p| puts p.name }`
|
18
|
+
|
19
|
+
### Find a configuration for a target on a project
|
20
|
+
|
21
|
+
`
|
22
|
+
project = Xcode.find_projects.first
|
23
|
+
config = project.target(:Target).config(:Debug)
|
24
|
+
`
|
25
|
+
|
26
|
+
### Building a configuration
|
27
|
+
|
28
|
+
`config.build`
|
29
|
+
|
30
|
+
### Packaging a built .app
|
31
|
+
|
32
|
+
`config.package :sign => 'Developer Identity Name', :profile => 'Profile.mobileprovision'`
|
33
|
+
|
34
|
+
### Incrementing the build number
|
35
|
+
|
36
|
+
config.info_plist do |info|
|
37
|
+
info.version = info.version.to_i + 1
|
38
|
+
info.save
|
39
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Xcode
|
2
|
+
class Configuration
|
3
|
+
attr_reader :target
|
4
|
+
|
5
|
+
def initialize(target, json)
|
6
|
+
@target = target
|
7
|
+
@json = json
|
8
|
+
end
|
9
|
+
|
10
|
+
def info_plist_location
|
11
|
+
@json['buildSettings']['INFOPLIST_FILE']
|
12
|
+
end
|
13
|
+
|
14
|
+
def name
|
15
|
+
@json['name']
|
16
|
+
end
|
17
|
+
|
18
|
+
def info_plist
|
19
|
+
puts @json.inspect
|
20
|
+
info = Xcode::InfoPlist.new(self, info_plist_location)
|
21
|
+
yield info if block_given?
|
22
|
+
info
|
23
|
+
end
|
24
|
+
|
25
|
+
def build
|
26
|
+
cmd = []
|
27
|
+
cmd << "-target #{@target.name}"
|
28
|
+
cmd << "-configuration #{name}"
|
29
|
+
@target.project.execute_xcodebuild(cmd.join(' '))
|
30
|
+
end
|
31
|
+
|
32
|
+
def app_path
|
33
|
+
"#{File.dirname(@target.project.path)}/build/#{name}-#{@target.project.sdk}/#{@target.productName}.app"
|
34
|
+
end
|
35
|
+
|
36
|
+
def ipa_path
|
37
|
+
"#{File.dirname(@target.project.path)}/build/#{name}-#{@target.project.sdk}/#{@target.productName}.ipa"
|
38
|
+
end
|
39
|
+
|
40
|
+
def package(options={})
|
41
|
+
cmd = []
|
42
|
+
cmd << "-v #{app_path}"
|
43
|
+
cmd << "-o #{ipa_path}"
|
44
|
+
|
45
|
+
if options.has_key? :sign
|
46
|
+
cmd << "--sign #{options[:sign]}"
|
47
|
+
end
|
48
|
+
|
49
|
+
if options.has_key? :profile
|
50
|
+
cmd << "--embed #{options[:profile]}"
|
51
|
+
end
|
52
|
+
|
53
|
+
@target.project.execute_package_application(cmd.join(' '))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'plist'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module Xcode
|
5
|
+
class InfoPlist
|
6
|
+
def initialize(project, plist_location)
|
7
|
+
@project = project
|
8
|
+
|
9
|
+
@plist_location = File.expand_path(plist_location)
|
10
|
+
unless File.exists?(@plist_location)
|
11
|
+
puts 'Plist not found ' + @plist_location
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
@plist = Plist::parse_xml(@plist_location)
|
15
|
+
end
|
16
|
+
|
17
|
+
def marketing_version
|
18
|
+
@plist['CFBundleShortVersionString']
|
19
|
+
end
|
20
|
+
|
21
|
+
def marketing_version=(version)
|
22
|
+
@plist['CFBundleShortVersionString'] = version
|
23
|
+
end
|
24
|
+
|
25
|
+
def version
|
26
|
+
@plist['CFBundleVersion']
|
27
|
+
end
|
28
|
+
|
29
|
+
def version=(version)
|
30
|
+
@plist['CFBundleVersion'] = version.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def save
|
34
|
+
File.open(@plist_location, 'w') {|f| f << @plist.to_plist}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'xcode/target'
|
3
|
+
require 'xcode/configuration'
|
4
|
+
|
5
|
+
module Xcode
|
6
|
+
class Project
|
7
|
+
attr_reader :targets, :sdk, :path
|
8
|
+
def initialize(path, sdk=nil)
|
9
|
+
@sdk = sdk || "iphoneos" # FIXME: should support OSX/simulator too
|
10
|
+
@path = File.expand_path path
|
11
|
+
@targets = {}
|
12
|
+
|
13
|
+
parse_pbxproj
|
14
|
+
# parse_configurations
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_package_application(options=nil)
|
18
|
+
cmd = []
|
19
|
+
cmd << "xcrun"
|
20
|
+
cmd << "-sdk #{@sdk.nil? ? "iphoneos" : @sdk}"
|
21
|
+
cmd << "PackageApplication"
|
22
|
+
cmd << options unless options.nil?
|
23
|
+
|
24
|
+
execute(cmd.join(' '), true)
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute_xcodebuild(cmd_line=nil, show_output=true)
|
28
|
+
cmd = []
|
29
|
+
cmd << "xcodebuild"
|
30
|
+
cmd << "-sdk #{@sdk}" unless @sdk.nil?
|
31
|
+
cmd << "-project #{@path}"
|
32
|
+
cmd << cmd_line unless cmd_line.nil?
|
33
|
+
yield cmd if block_given?
|
34
|
+
|
35
|
+
execute(cmd.join(' '), show_output)
|
36
|
+
end
|
37
|
+
|
38
|
+
def target(name)
|
39
|
+
target = @targets[name.to_s.to_sym]
|
40
|
+
raise "No such target #{name}, available targets are #{@targets.keys}" if target.nil?
|
41
|
+
yield target if block_given?
|
42
|
+
target
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def parse_pbxproj
|
48
|
+
json = JSON.parse(`plutil -convert json -o - "#{@path}/project.pbxproj"`)
|
49
|
+
|
50
|
+
root = json['objects'][json['rootObject']]
|
51
|
+
root['targets'].each do |target_id|
|
52
|
+
target = Xcode::Target.new(self, json['objects'][target_id])
|
53
|
+
|
54
|
+
buildConfigurationList = json['objects'][target_id]['buildConfigurationList']
|
55
|
+
buildConfigurations = json['objects'][buildConfigurationList]['buildConfigurations']
|
56
|
+
|
57
|
+
buildConfigurations.each do |buildConfiguration|
|
58
|
+
config = Xcode::Configuration.new(target, json['objects'][buildConfiguration])
|
59
|
+
target.configs[config.name.to_sym] = config
|
60
|
+
end
|
61
|
+
|
62
|
+
@targets[target.name.to_sym] = target
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def execute(cmd, show_output=false)
|
67
|
+
out = []
|
68
|
+
puts "EXECUTE: #{cmd}"
|
69
|
+
IO.popen (cmd) do |f|
|
70
|
+
f.each do |line|
|
71
|
+
puts line if show_output
|
72
|
+
out << line
|
73
|
+
end
|
74
|
+
end
|
75
|
+
#puts "RETURN: #{out.inspect}"
|
76
|
+
out
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/lib/xcode/target.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Xcode
|
2
|
+
class Target
|
3
|
+
attr_reader :configs, :project
|
4
|
+
|
5
|
+
def initialize(project, json)
|
6
|
+
@project = project
|
7
|
+
@json = json
|
8
|
+
@configs = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def productName
|
12
|
+
@json['productName']
|
13
|
+
end
|
14
|
+
|
15
|
+
def name
|
16
|
+
@json['name']
|
17
|
+
end
|
18
|
+
|
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?
|
22
|
+
yield config if block_given?
|
23
|
+
config
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/xcoder.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'fileutils'
|
3
|
+
require "xcode/version"
|
4
|
+
require "xcode/project"
|
5
|
+
require "xcode/info_plist"
|
6
|
+
|
7
|
+
module Xcode
|
8
|
+
@@projects = nil
|
9
|
+
@@sdks = nil
|
10
|
+
|
11
|
+
# def self.project(name)
|
12
|
+
# parse_projects if @@projects.nil?
|
13
|
+
# @@projects.each do |p|
|
14
|
+
# return p if p.name == name
|
15
|
+
# end
|
16
|
+
# raise "Unable to find project named #{name}"
|
17
|
+
# end
|
18
|
+
|
19
|
+
def self.find_projects(dir='.')
|
20
|
+
parse_projects(dir)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.is_sdk_available?(sdk)
|
24
|
+
parse_sdks if @@sdks.nil?
|
25
|
+
@@sdks.values.include? sdk
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.available_sdks
|
29
|
+
parse_sdks if @@sdks.nil?
|
30
|
+
@@sdks
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def self.parse_sdks
|
35
|
+
@@sdks = {}
|
36
|
+
parsing = false
|
37
|
+
`xcodebuild -showsdks`.split("\n").each do |l|
|
38
|
+
l.strip!
|
39
|
+
if l=~/(.*)\s+SDKs:/
|
40
|
+
parsing = true
|
41
|
+
elsif l=~/^\s*$/
|
42
|
+
parsing = false
|
43
|
+
elsif parsing
|
44
|
+
l=~/([^\t]+)\t+\-sdk (.*)/
|
45
|
+
@@sdks[$1.strip] = $2.strip unless $1.nil? and $2.nil?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.parse_projects(dir='.')
|
51
|
+
projects = []
|
52
|
+
Find.find(dir) do |path|
|
53
|
+
if path=~/(.*)\.xcodeproj$/
|
54
|
+
projects << Xcode::Project.new(path)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
projects
|
58
|
+
end
|
59
|
+
end
|
data/xcoder.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "xcode/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "xcoder"
|
7
|
+
s.version = Xcode::VERSION
|
8
|
+
s.authors = ["Ray Hilton"]
|
9
|
+
s.email = ["ray@wirestorm.net"]
|
10
|
+
s.homepage = "https://github.com/rayh/xcoder"
|
11
|
+
s.summary = %q{Ruby wrapper around xcodebuild, xcrun, agvtool and pbxproj files}
|
12
|
+
s.description = %q{Provides a ruby based object-model for parsing project structures and invoking builds}
|
13
|
+
|
14
|
+
s.rubyforge_project = "xcoder"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_runtime_dependency "json"
|
22
|
+
s.add_runtime_dependency "plist"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xcoder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ray Hilton
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-18 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: &70220191343000 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70220191343000
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: plist
|
27
|
+
requirement: &70220191371480 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70220191371480
|
36
|
+
description: Provides a ruby based object-model for parsing project structures and
|
37
|
+
invoking builds
|
38
|
+
email:
|
39
|
+
- ray@wirestorm.net
|
40
|
+
executables: []
|
41
|
+
extensions: []
|
42
|
+
extra_rdoc_files: []
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- Gemfile
|
46
|
+
- README.md
|
47
|
+
- Rakefile
|
48
|
+
- lib/xcode/configuration.rb
|
49
|
+
- lib/xcode/info_plist.rb
|
50
|
+
- lib/xcode/project.rb
|
51
|
+
- lib/xcode/target.rb
|
52
|
+
- lib/xcode/version.rb
|
53
|
+
- lib/xcoder.rb
|
54
|
+
- xcoder.gemspec
|
55
|
+
homepage: https://github.com/rayh/xcoder
|
56
|
+
licenses: []
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project: xcoder
|
75
|
+
rubygems_version: 1.8.6
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Ruby wrapper around xcodebuild, xcrun, agvtool and pbxproj files
|
79
|
+
test_files: []
|