Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Workspace] Support file reference types #150

Merged
merged 6 commits into from
Apr 17, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@

## 0.14.1

###### Enhancements

* Add support for absolute, group and container project references in workspaces
[Kyle Fuller](https://github.com/kylef)
[#118](https://github.com/CocoaPods/Xcodeproj/issues/118)

###### Bug Fixes

* [Gem] On MRI 1.8.7 /dev/tty is considered writable when not configured,
Expand Down
41 changes: 21 additions & 20 deletions lib/xcodeproj/workspace.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'fileutils'
require 'rexml/document'
require 'xcodeproj/workspace/file_reference'

module Xcodeproj

Expand All @@ -9,15 +10,16 @@ module Xcodeproj
class Workspace

# @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 +52,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 +71,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 +95,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 +125,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
87 changes: 87 additions & 0 deletions lib/xcodeproj/workspace/file_reference.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
module Xcodeproj
class Workspace
# Describes a file reference of a 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

# @param [#to_s] path @see path
# @param [#to_s] type @see type
#
def initialize(path, type="group")
@path = path.to_s
@type = type.to_s
end

# @return [Bool] Wether a file reference is equal to another.
#
def ==(other)
path == other.path && type == other.type
end
alias_method :eql?, :==

# @return [Fixnum] A hash identical for equals objects.
#
def hash
[path, type].hash
end

# Returns a file reference given XML representation.
#
# @param [REXML::Element] xml_node
# the XML representation.
#
# @return [FileReference] The new file reference instance.
#
def self.from_node(xml_node)
type, path = xml_node.attribute('location').value.split(':', 2)
new(path, type)
end

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

# Returns the absolute path of a file reference given the path of the
# directory containing workspace.
#
# @param [#to_s] workspace_dir_path
# The Path of the directory containing the workspace.
#
# @return [String] The absolute path to the project.
#
def absolute_path(workspace_dir_path)
workspace_dir_path = workspace_dir_path.to_s
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'
raise "Developer workspace file reference type is not yet " \
"#{self}"
else
raise "Unsupported workspace file reference type #{type}"
end
end
end
end
end
50 changes: 50 additions & 0 deletions spec/workspace/file_reference_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require File.expand_path('../../spec_helper', __FILE__)

module Xcodeproj
describe Workspace do
before do
@subject = Workspace::FileReference.new('project.xcodeproj', 'group')
end

it 'properly implements equality comparison' do
@subject.should == @subject.dup
@subject.should.eql @subject.dup
@subject.hash.should == @subject.dup.hash
end

it 'can be initialized by the XML representation' do
node = REXML::Element.new("FileRef")
node.attributes['location'] = "group:project.xcodeproj"
result = Workspace::FileReference.from_node(node)
result.should == @subject
end

it 'returns the XML representation' do
result = @subject.to_node
result.class.should == REXML::Element
result.to_s.should == "<FileRef location='group:project.xcodeproj'/>"
end

it 'can be converted back and forth without loss of information' do
result = Workspace::FileReference.from_node(@subject.to_node)
result.should == @subject
end

it 'returns the absolute path for group types' do
result = @subject.absolute_path('/path/to/')
result.should == "/path/to/project.xcodeproj"
end

it 'returns the absolute path for container types' do
@subject.stubs(:type).returns('container')
result = @subject.absolute_path('/path/to/')
result.should == "/path/to/project.xcodeproj"
end

it 'returns the absolute path for absolute types' do
@subject.stubs(:type).returns('absolute')
result = @subject.absolute_path('/path/to/')
result.should == File.expand_path(@subject.path)
end
end
end
34 changes: 18 additions & 16 deletions spec/workspace_spec.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
require File.expand_path('../spec_helper', __FILE__)

describe "Xcodeproj::Workspace" do
describe Xcodeproj::Workspace do
describe "from new" do
before do
@workspace = Xcodeproj::Workspace.new('Pods/Pods.xcodeproj', 'App.xcodeproj')
end

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