Commit 4a56288b authored by Nolan Waite's avatar Nolan Waite

Merge branch 'configure-app-xcodeproj'

parents 99573898 d905c985
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Workspace version="1.0"><FileRef location="group:ConfigureTest.xcodeproj"></FileRef><FileRef location="group:Pods/Pods.xcodeproj"></FileRef></Workspace>
\ No newline at end of file
//
// AppDelegate.h
// ConfigureTest
//
// Created by Eloy Duran on 25-10-11.
// Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@end
//
// AppDelegate.m
// ConfigureTest
//
// Created by Eloy Duran on 25-10-11.
// Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//
#import "AppDelegate.h"
@implementation AppDelegate
@synthesize window = _window;
- (void)dealloc
{
[super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
@end
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2011 __MyCompanyName__. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
//
// Prefix header for all source files of the 'ConfigureTest' target in the 'ConfigureTest' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif
{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw9840\paperh8400
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
\f0\b\fs24 \cf0 Engineering:
\b0 \
Some people\
\
\b Human Interface Design:
\b0 \
Some other people\
\
\b Testing:
\b0 \
Hopefully not nobody\
\
\b Documentation:
\b0 \
Whoever\
\
\b With special thanks to:
\b0 \
Mom\
}
This diff is collapsed.
//
// main.m
// ConfigureTest
//
// Created by Eloy Duran on 25-10-11.
// Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **)argv);
}
platform :osx
dependency 'JSONKit'
......@@ -12,6 +12,7 @@ module Pod
autoload :Executable, 'cocoapods/executable'
autoload :Installer, 'cocoapods/installer'
autoload :Podfile, 'cocoapods/podfile'
autoload :ProjectTemplate, 'cocoapods/project_template'
autoload :Resolver, 'cocoapods/resolver'
autoload :Source, 'cocoapods/source'
autoload :Spec, 'cocoapods/specification'
......@@ -22,6 +23,7 @@ module Pod
autoload :Config, 'cocoapods/xcode/config'
autoload :CopyResourcesScript, 'cocoapods/xcode/copy_resources_script'
autoload :Project, 'cocoapods/xcode/project'
autoload :Workspace, 'cocoapods/xcode/workspace'
end
autoload :Pathname, 'pathname'
......
......@@ -4,10 +4,11 @@ module Pod
def self.banner
%{Installing dependencies of a pod spec:
$ pod install [NAME]
$ pod install [NAME] [PROJECT]
Downloads all dependencies of the specified podspec file `NAME' and
creates an Xcode Pods library project in `./Pods'. In case `NAME' is
Downloads all dependencies of the specified podspec file `NAME',
creates an Xcode Pods library project in `./Pods', and sets up `PROJECT'
to use the specified pods (if `PROJECT' is given). In case `NAME' is
omitted it defaults to either `Podfile' or `*.podspec' in the current
working directory.
}
......@@ -20,9 +21,10 @@ module Pod
def initialize(argv)
config.clean = !argv.option('--no-clean')
if podspec = argv.shift_argument
@podspec = Pathname.new(podspec)
end
projpath = argv.shift_argument
projpath =~ /\.xcodeproj\/?$/ ? @projpath = projpath : podspec = projpath
@podspec = Pathname.new(podspec) if podspec
@projpath ||= argv.shift_argument
super unless argv.empty?
end
......@@ -39,7 +41,9 @@ module Pod
raise Informative, "No `Podfile' or `.podspec' file found in the current working directory."
end
end
Installer.new(spec).install!
installer = Installer.new(spec)
installer.install!
installer.configure_project(@projpath) if @projpath
end
end
end
......
......@@ -29,8 +29,12 @@ module Pod
})
end
def template
@template ||= ProjectTemplate.new(@specification.platform)
end
def xcodeproj
@xcodeproj ||= Xcode::Project.static_library(@specification.platform)
@xcodeproj ||= Xcode::Project.new(template.xcodeproj_path)
end
# TODO move xcconfig related code into the xcconfig method, like copy_resources_script and generate_bridge_support.
......@@ -79,7 +83,11 @@ module Pod
generate_project
root = config.project_pods_root
xcodeproj.create_in(root)
puts " * Copying contents of template directory `#{template.path}' to `#{root}'" if config.verbose?
template.copy_to(root)
pbxproj = File.join(root, 'Pods.xcodeproj')
puts " * Writing Xcode project file to `#{pbxproj}'" if config.verbose?
xcodeproj.save_as(pbxproj)
xcconfig.create_in(root)
if @specification.generate_bridge_support?
path = bridge_support_generator.create_in(root)
......@@ -89,5 +97,57 @@ module Pod
build_specifications.each(&:post_install)
end
def configure_project(projpath)
root = File.dirname(projpath)
xcworkspace = File.join(root, File.basename(projpath, '.xcodeproj') + '.xcworkspace')
workspace = Xcode::Workspace.new_from_xcworkspace(xcworkspace)
pods_projpath = File.join(config.project_pods_root, 'Pods.xcodeproj')
root = Pathname.new(root).expand_path
[projpath, pods_projpath].each do |path|
path = Pathname.new(path).expand_path.relative_path_from(root).to_s
workspace << path unless workspace.include? path
end
workspace.save_as(xcworkspace)
app_project = Xcode::Project.new(projpath)
return if app_project.files.find { |file| file.path =~ /libPods\.a$/ }
configfile = app_project.files.new({
'path' => 'Pods/Pods.xcconfig',
'lastKnownFileType' => 'text.xcconfig'
})
app_project.targets.each do |target|
target.buildConfigurationList.buildConfigurations.each do |config|
config.baseConfigurationReference = configfile
end
end
app_project.main_group << configfile
libfile = app_project.files.new({
'path' => 'libPods.a',
'lastKnownFileType' => 'archive.ar',
'includeInIndex' => '0',
'sourceTree' => 'BUILT_PRODUCTS_DIR'
})
app_project.objects.select_by_class(Xcode::Project::PBXFrameworksBuildPhase).each do |build_phase|
build_phase.files << libfile.build_file
end
app_project.main_group << libfile
copy_resources = app_project.objects.add(Xcode::Project::PBXShellScriptBuildPhase, {
'name' => 'Copy Pods Resources',
'buildActionMask' => '2147483647',
'files' => [],
'inputPaths' => [],
'outputPaths' => [],
'runOnlyForDeploymentPostprocessing' => '0',
'shellPath' => '/bin/sh',
'shellScript' => "${SRCROOT}/Pods/PodsResources.sh\n"
})
app_project.targets.each { |target| target.buildPhases << copy_resources }
app_project.save_as(projpath)
end
end
end
require 'fileutils'
module Pod
class ProjectTemplate
def initialize(platform)
@platform = platform
end
# TODO this is a workaround for an issue with MacRuby with compiled files
# that makes the use of __FILE__ impossible.
#
#TEMPLATES_DIR = Pathname.new(File.expand_path('../../../xcode-project-templates', __FILE__))
file = $LOADED_FEATURES.find { |file| file =~ %r{cocoapods/project_template\.rbo?$} }
TEMPLATES_DIR = Pathname.new(File.expand_path('../../../xcode-project-templates', file))
def path
@path ||= case @platform
when :osx
TEMPLATES_DIR + 'cocoa-static-library'
when :ios
TEMPLATES_DIR + 'cocoa-touch-static-library'
else
raise "No Xcode project template exists for the platform `#{platform.inspect}'"
end
end
def xcodeproj_path
@xcodeproj_path = File.join(path, 'Pods.xcodeproj')
end
def copy_to(pods_root)
FileUtils.cp_r("#{path}/.", pods_root)
end
end
end
......@@ -88,6 +88,10 @@ module Pod
end
file
end
def <<(child)
children << child.uuid
end
end
class PBXFileReference < PBXObject
......@@ -122,7 +126,7 @@ module Pod
# Returns a PBXFileReference instance corresponding to the uuid in the fileRef attribute.
def file
project.objects[fileRef]
@project.objects[fileRef]
end
end
......@@ -140,17 +144,60 @@ module Pod
list_by_class(file_uuids, PBXBuildFile)
end
end
class PBXSourcesBuildPhase < PBXBuildPhase; end
class PBXCopyFilesBuildPhase < PBXBuildPhase; end
class PBXFrameworksBuildPhase < PBXBuildPhase; end
class PBXShellScriptBuildPhase < PBXBuildPhase
attributes_accessor :shellScript
end
class PBXNativeTarget < PBXObject
attributes_accessor :buildPhases
attributes_accessor :buildPhases, :buildConfigurationList
alias_method :build_phase_uuids, :buildPhases
alias_method :build_phase_uuids=, :buildPhases=
alias_method :build_configuration_list_uuid, :buildConfigurationList
alias_method :build_configuration_list_uuid=, :buildConfigurationList=
def buildPhases
list_by_class(build_phase_uuids, PBXBuildPhase)
end
def buildConfigurationList
@project.objects[build_configuration_list_uuid]
end
def buildConfigurationList=(config_list)
self.build_configuration_list_uuid = config_list.uuid
end
end
class XCBuildConfiguration < PBXObject
attributes_accessor :baseConfigurationReference
alias_method :base_configuration_reference_uuid, :baseConfigurationReference
alias_method :base_configuration_reference_uuid=, :baseConfigurationReference=
def baseConfigurationReference
@project.objects[base_configuration_reference_uuid]
end
def baseConfigurationReference=(config)
self.base_configuration_reference_uuid = config.uuid
end
end
class XCConfigurationList < PBXObject
attributes_accessor :buildConfigurations
alias_method :build_configuration_uuids, :buildConfigurations
alias_method :build_configuration_uuids=, :buildConfigurations=
def buildConfigurations
list_by_class(build_configuration_uuids, XCBuildConfiguration)
end
def buildConfigurations=(configs)
self.build_configuration_uuids = configs.map(&:uuid)
end
end
# Missing constants that begin with either `PBX' or `XC' are assumed to be
......@@ -215,42 +262,17 @@ module Pod
end
end
include Pod::Config::Mixin
# TODO this is a workaround for an issue with MacRuby with compiled files
# that makes the use of __FILE__ impossible.
#
#TEMPLATES_DIR = Pathname.new(File.expand_path('../../../../xcode-project-templates', __FILE__))
file = $LOADED_FEATURES.find { |file| file =~ %r{cocoapods/xcode/project\.rbo?$} }
TEMPLATES_DIR = Pathname.new(File.expand_path('../../../../xcode-project-templates', file))
def self.static_library(platform)
case platform
when :osx
new TEMPLATES_DIR + 'cocoa-static-library'
when :ios
new TEMPLATES_DIR + 'cocoa-touch-static-library'
else
raise "No Xcode project template exists for the platform `#{platform.inspect}'"
end
end
def initialize(template_dir)
@template_dir = template_dir
file = template_dir + template_file
@template = NSMutableDictionary.dictionaryWithContentsOfFile(file.to_s)
end
def template_file
'Pods.xcodeproj/project.pbxproj'
def initialize(xcodeproj)
file = File.join(xcodeproj, 'project.pbxproj')
@plist = NSMutableDictionary.dictionaryWithContentsOfFile(file.to_s)
end
def to_hash
@template
@plist
end
def objects_hash
@template['objects']
@plist['objects']
end
def objects
......@@ -261,6 +283,11 @@ module Pod
objects.select_by_class(PBXGroup)
end
def main_group
project = objects[@plist['rootObject']]
objects[project.attributes['mainGroup']]
end
# Shortcut access to the `Pods' PBXGroup.
def pods
groups.find { |g| g.name == 'Pods' }
......@@ -301,12 +328,10 @@ module Pod
source_files
end
def create_in(pods_root)
puts " * Copying contents of template directory `#{@template_dir}' to `#{pods_root}'" if config.verbose?
FileUtils.cp_r("#{@template_dir}/.", pods_root)
pbxproj = pods_root + template_file
puts " * Writing Xcode project file to `#{pbxproj}'" if config.verbose?
@template.writeToFile(pbxproj.to_s, atomically:true)
def save_as(projpath)
projpath = projpath.to_s
FileUtils.mkdir_p(projpath)
@plist.writeToFile(File.join(projpath, 'project.pbxproj'), atomically:true)
end
# TODO add comments, or even constants, describing what these magic numbers are.
......
framework 'Foundation'
require 'fileutils'
module Pod
module Xcode
class Workspace
def initialize(*projpaths)
@projpaths = projpaths
end
def self.new_from_xcworkspace(path)
begin
from_s(File.read(File.join(path, 'contents.xcworkspacedata')))
rescue Errno::ENOENT
new
end
end
def self.from_s(xml)
doc = NSXMLDocument.alloc.initWithXMLString(xml, options:0, error:nil)
projpaths = doc.nodesForXPath("/Workspace/FileRef", error:nil).map do |node|
node.attributeForName("location").stringValue.sub(/^group:/, '')
end
new(*projpaths)
end
attr_reader :projpaths
def <<(projpath)
@projpaths << projpath
end
def include?(projpath)
@projpaths.include?(projpath)
end
TEMPLATE = %q[<?xml version="1.0" encoding="UTF-8"?><Workspace version="1.0"></Workspace>]
def to_s
doc = NSXMLDocument.alloc.initWithXMLString(TEMPLATE, options:0, error:nil)
@projpaths.each do |projpath|
el = NSXMLNode.elementWithName("FileRef")
el.addAttribute(NSXMLNode.attributeWithName("location", stringValue:"group:#{projpath}"))
doc.rootElement.addChild(el)
end
NSString.alloc.initWithData(doc.XMLData, encoding:NSUTF8StringEncoding)
end
def save_as(path)
FileUtils.mkdir_p(path)
File.open(File.join(path, 'contents.xcworkspacedata'), 'w') do |out|
out << to_s
end
end
end
end
end
......@@ -128,9 +128,42 @@ else
installer = Pod::Installer.new(spec)
installer.generate_project
project = Pod::Xcode::Project.new(config.project_pods_root)
project = Pod::Xcode::Project.new(config.project_pods_root + 'Pods.xcodeproj')
project.source_files.should == installer.xcodeproj.source_files
end
it "sets up an existing project with pods" do
basename = platform == :ios ? 'iPhone' : 'Mac'
projpath = temporary_directory + 'ASIHTTPRequest.xcodeproj'
FileUtils.cp_r(fixture("integration/ASIHTTPRequest/#{basename}.xcodeproj"), projpath)
spec = Pod::Podfile.new do
self.platform platform
dependency 'SSZipArchive'
end
installer = SpecHelper::Installer.new(spec)
installer.install!
installer.configure_project(projpath)
xcworkspace = temporary_directory + 'ASIHTTPRequest.xcworkspace'
workspace = Pod::Xcode::Workspace.new_from_xcworkspace(xcworkspace)
workspace.projpaths.sort.should == ['ASIHTTPRequest.xcodeproj', 'Pods/Pods.xcodeproj']
project = Pod::Xcode::Project.new(projpath)
config = project.files.find { |f| f.path =~ /Pods.xcconfig$/ }
config.should.not.equal nil
copy_resources = project.objects.select_by_class(Pod::Xcode::Project::PBXShellScriptBuildPhase).find do |ss|
ss.shellScript['PodsResources.sh']
end
copy_resources.should.not.equal nil
project.targets.each do |target|
bases = target.buildConfigurationList.buildConfigurations.map(&:baseConfigurationReference)
bases.uniq[0].uuid.should == config.uuid
target.buildPhases.map(&:uuid).should.include copy_resources.uuid
end
lib = project.files.find { |f| f.path =~ /libPods.a$/ }
lib.should.not.equal nil
project.objects.select_by_class(Pod::Xcode::Project::PBXFrameworksBuildPhase).each do |build_phase|
build_phase.files.map(&:uuid).should.include lib.build_file.uuid
end
end
end
end
end
......@@ -4,7 +4,8 @@ describe "Pod::Xcode::Project" do
extend SpecHelper::TemporaryDirectory
before do
@project = Pod::Xcode::Project.static_library(:ios)
@template = Pod::ProjectTemplate.new(:ios)
@project = Pod::Xcode::Project.new(@template.xcodeproj_path)
end
def find_objects(conditions)
......@@ -18,8 +19,7 @@ describe "Pod::Xcode::Project" do
end
it "returns an instance initialized from the iOS static library template" do
template_dir = Pod::Xcode::Project::TEMPLATES_DIR + 'cocoa-touch-static-library'
template_file = (template_dir + 'Pods.xcodeproj/project.pbxproj').to_s
template_file = (@template.xcodeproj_path + '/project.pbxproj').to_s
@project.to_hash.should == NSDictionary.dictionaryWithContentsOfFile(template_file)
end
......@@ -178,7 +178,8 @@ describe "Pod::Xcode::Project" do
end
it "saves the template with the adjusted project" do
@project.create_in(temporary_directory)
@template.copy_to(temporary_directory)
@project.save_as(temporary_directory + 'Pods.xcodeproj')
(temporary_directory + 'Pods-Prefix.pch').should.exist
(temporary_directory + 'Pods.xcconfig').should.exist
project_file = (temporary_directory + 'Pods.xcodeproj/project.pbxproj')
......
require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Xcode::Workspace" do
before do
@workspace = Pod::Xcode::Workspace.new('Pods/Pods.xcodeproj', 'App.xcodeproj')
end
it "accepts new projects" do
@workspace << 'Framework.xcodeproj'
@workspace.projpaths.should.include 'Framework.xcodeproj'
end
before do
@doc = NSXMLDocument.alloc.initWithXMLString(@workspace.to_s, options:0, error:nil)
end
it "is the right xml workspace version" do
@doc.rootElement.attributeForName("version").stringValue.should == "1.0"
end
it "refers to the projects in xml" do
@doc.nodesForXPath("/Workspace/FileRef", error:nil).map do |node|
node.attributeForName("location").stringValue.sub(/^group:/, '')
end.sort.should == ['App.xcodeproj', 'Pods/Pods.xcodeproj']
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment