Skip to content

Commit

Permalink
[Workspace] Support file reference types
Browse files Browse the repository at this point in the history
The following types are supported by Xcode:

- Absolute Path (absolute)
- Relative to Group (group)
- Relative to Workspace (container)
- Relative to Developer Directory (developer)
  • Loading branch information
kylef committed Mar 14, 2014
1 parent 840e6f3 commit 46a66dc
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 35 deletions.
98 changes: 78 additions & 20 deletions lib/xcodeproj/workspace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,75 @@ module Xcodeproj
#
class Workspace

class FileReference
# @return [String] the path to the project
#
attr_reader :path

# @return [String] the type of reference to the project
#
# This can be of the following values:
# - absolute
# - group
# - container
# - developer (unsupported)
attr_reader :type

def self.from_node(node)
type, path = node.attribute('location').value.split(':', 2)
new(path, type)
end

def initialize(path, type=nil)
@path = path
@type = type || "group"
end

def ==(other)
@path == other.path && @type == other.type
end

def to_node
REXML::Element.new("FileRef").tap do |element|
element.attributes['location'] = "#{@type}:#{@path}"
end
end

# Get the absolute path to a project in a workspace
#
# @param [String] workspace_dir_path
# path of workspaces dir
#
# @return [String] The absolute path to the project
#
def absolute_path(workspace_dir_path)
case @type
when 'group'
File.expand_path(File.join(workspace_dir_path, @path))
when 'container'
File.expand_path(File.join(workspace_dir_path, @path))
when 'absolute'
File.expand_path(@path)
when 'developer'
# TODO
raise "Developer file reference type is not yet supported"
else
raise "Unsupported workspace file reference type #{@type}"
end
end
end

# @return [Array<String>] the paths of the projects contained in the
# @return [Array<FileReference>] the paths of the projects contained in the
# workspace.
#
attr_reader :projpaths
attr_reader :file_references
attr_reader :schemes

# @param [Array] projpaths @see projpaths
# @param [Array] file_references @see file_references
#
def initialize(*projpaths)
@projpaths = projpaths.flatten
def initialize(*file_references)
@file_references = file_references.flatten
@schemes = {}
end

Expand Down Expand Up @@ -50,10 +109,10 @@ def self.new_from_xcworkspace(path)
#
def self.from_s(xml, workspace_path='')
document = REXML::Document.new(xml)
projpaths = document.get_elements("/Workspace/FileRef").map do |node|
node.attribute("location").value.sub(/^group:/, '')
file_references = document.get_elements("/Workspace/FileRef").map do |node|
FileReference.from_node(node)
end
instance = new(projpaths)
instance = new(file_references)
instance.load_schemes(workspace_path)
instance
end
Expand All @@ -69,19 +128,20 @@ def self.from_s(xml, workspace_path='')
# @return [void]
#
def <<(projpath)
@projpaths << projpath
@file_references << projpath
load_schemes_from_project File.expand_path(projpath)
end

# Checks if the workspace contains the project with the given path.
# Checks if the workspace contains the project with the given file
# reference.
#
# @param [String] projpath
# The path of the project to add.
# @param [FileReference] file_reference
# The file_reference to the project.
#
# @return [Boolean] whether the project is contained in the workspace.
#
def include?(projpath)
@projpaths.include?(projpath)
def include?(file_reference)
@file_references.include?(file_reference)
end

# The template to generate a workspace XML representation.
Expand All @@ -92,10 +152,8 @@ def include?(projpath)
#
def to_s
REXML::Document.new(TEMPLATE).tap do |document|
@projpaths.each do |projpath|
document.root << REXML::Element.new("FileRef").tap do |el|
el.attributes['location'] = "group:#{projpath}"
end
@file_references.each do |file_reference|
document.root << file_reference.to_node
end
end.to_s
end
Expand Down Expand Up @@ -124,9 +182,9 @@ def save_as(path)
# @return [void]
#
def load_schemes workspace_dir_path
@projpaths.each do |projpath|
project_full_path = File.expand_path(File.join(workspace_dir_path, projpath))
load_schemes_from_project project_full_path
@file_references.each do |file_reference|
project_full_path = file_reference.absolute_path(workspace_dir_path)
load_schemes_from_project(project_full_path)
end
end

Expand Down
32 changes: 17 additions & 15 deletions spec/workspace_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

it "accepts new projects" do
@workspace << 'Framework.xcodeproj'
@workspace.projpaths.should.include 'Framework.xcodeproj'
@workspace.file_references.should.include 'Framework.xcodeproj'
end
end

describe "converted to XML" do
before do
@workspace = Xcodeproj::Workspace.new('Pods/Pods.xcodeproj', 'App.xcodeproj')
pods_project_file_reference = Xcodeproj::Workspace::FileReference.new('Pods/Pods.xcodeproj')
project_file_reference = Xcodeproj::Workspace::FileReference.new('App.xcodeproj')
@workspace = Xcodeproj::Workspace.new(pods_project_file_reference, project_file_reference)
@doc = REXML::Document.new(@workspace.to_s)
end

Expand All @@ -35,9 +37,9 @@
end

it "contains all of the projects in the workspace" do
@workspace.projpaths.should.include "libPusher.xcodeproj"
@workspace.projpaths.should.include "libPusher-OSX/libPusher-OSX.xcodeproj"
@workspace.projpaths.should.include "Pods/Pods.xcodeproj"
@workspace.file_references.should.include Xcodeproj::Workspace::FileReference.new("libPusher.xcodeproj")
@workspace.file_references.should.include Xcodeproj::Workspace::FileReference.new("libPusher-OSX/libPusher-OSX.xcodeproj")
@workspace.file_references.should.include Xcodeproj::Workspace::FileReference.new("Pods/Pods.xcodeproj")
end
end

Expand All @@ -47,36 +49,36 @@
end

it "contains no projects" do
@workspace.projpaths.should.be.empty
@workspace.file_references.should.be.empty
end
end

describe "load schemes for all projects from workspace file" do
before do
@workspace = Xcodeproj::Workspace.new_from_xcworkspace(fixture_path("SharedSchemes/SharedSchemes.xcworkspace"))
end

it "returns data type should be hash" do
@workspace.schemes.should.instance_of Hash
end
it "schemes count should be greater or equal to projpaths count" do
@workspace.schemes.count.should >= @workspace.projpaths.count

it "schemes count should be greater or equal to file_references count" do
@workspace.schemes.count.should >= @workspace.file_references.count
end

it "contains only test data schemes" do
@workspace.schemes.keys.sort.should == ['Pods', 'SharedSchemes', 'SharedSchemesForTest']
end
end

describe "built from a workspace file with XML entities in a project path" do
before do
@workspace = Xcodeproj::Workspace.new_from_xcworkspace(fixture_path("Otto's Remote.xcworkspace"))
end

it "contains all of the projects in the workspace" do
@workspace.projpaths.should.include "Otto's Remote.xcodeproj"
@workspace.projpaths.should.include "Pods/Pods.xcodeproj"
@workspace.file_references.should.include Xcodeproj::Workspace::FileReference.new("Otto's Remote.xcodeproj")
@workspace.file_references.should.include Xcodeproj::Workspace::FileReference.new("Pods/Pods.xcodeproj")
end
end
end

0 comments on commit 46a66dc

Please sign in to comment.