Commit 65cd3d85 authored by Fabio Pelosin's avatar Fabio Pelosin

Merge branch 'xcproject-based-pods' of github.com:pereckerdal/CocoaPods into…

Merge branch 'xcproject-based-pods' of github.com:pereckerdal/CocoaPods into fabio-pods-from-projects

* 'xcproject-based-pods' of github.com:pereckerdal/CocoaPods:
  Test that linked deps get compiled and linked properly
  Test that we do not add linked projects twice
  Add support for multiple Xcode subprojects per spec
  Add support for Xcode subprojects to podspecs
  Fix documentation typo
  Fix unit test

Conflicts:
	lib/cocoapods/installer.rb
	spec/unit/installer_spec.rb
	spec/unit/sources_manager_spec.rb
parents 34a84cd3 df6b1f8a
......@@ -37,6 +37,7 @@ module Pod
autoload :AggregateTargetInstaller, 'cocoapods/installer/target_installer/aggregate_target_installer'
autoload :PodTargetInstaller, 'cocoapods/installer/target_installer/pod_target_installer'
autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
autoload :LinkedDependenciesInstaller, 'cocoapods/installer/linked_dependencies_installer'
include Config::Mixin
......@@ -117,6 +118,7 @@ module Pod
install_file_references
install_libraries
set_target_dependencies
link_linked_dependencies
run_post_install_hooks
write_pod_project
write_lockfiles
......@@ -432,6 +434,19 @@ module Pod
end
end
# Adds the linked dependencies to the pod targets.
#
# @return [void]
#
def link_linked_dependencies
pod_targets.each do |pod_target|
pod_root = pod_for_target(pod_target).root
installer = LinkedDependenciesInstaller.new(pods_project, pod_root, pod_target)
installer.install!
end
end
# Writes the Pods project to the disk.
#
# @return [void]
......@@ -626,6 +641,16 @@ module Pod
analysis_result.sandbox_state
end
# Finds the PodRepresentation object for a given Target.
#
# @param [Target] The target for which the representation should be found.
#
# @return [PodRepresentation] The pod for a given target.
#
def pod_for_target(pod_target)
pod_reps.find { |pod_rep| pod_rep.name == pod_target.root_spec.name }
end
#-------------------------------------------------------------------------#
end
......
......@@ -20,7 +20,7 @@ module Pod
# @param [Sandbox] sandbox @see sandbox
# @param [Array<Library>] libraries @see libraries
# @param [Project] libraries @see libraries
# @param [Project] pods_project @see pods_project
#
def initialize(sandbox, libraries, pods_project)
@sandbox = sandbox
......
module Pod
class Installer
# This class is responsible for adding linked Xcode dependencies as
# subprojects in the correct groups and link the Xcode subproject
# library targets to the respective pod targets.
#
class LinkedDependenciesInstaller
# @return [Project] The Pods project.
#
attr_reader :pods_project
# @return [Pathname] The root path of the pod.
#
attr_reader :pod_root
# @return [PodTarget] The pod target to process.
#
attr_reader :pod_target
# @param [Project] pods_project @see pods_project
# @param [Pathname] pod_root @see pod_root
# @param [PodTarget] pod_target @see pod_target
#
def initialize(pods_project, pod_root, pod_target)
@pods_project = pods_project
@pod_root = pod_root
@pod_target = pod_target
end
# Installs the linked projects for a given pod target.
#
# @return [void]
#
def install!
add_linked_projects
add_libraries_to_target
end
#-----------------------------------------------------------------------#
private
# @!group Installation Steps
# Add the Xcode projects that specs refer to as subprojects to the Pods
# Xcode project, in the appropriate groups.
#
# @return [void]
#
def add_linked_projects
linked_project_specs.each do |path, specs|
specs.each do |spec|
group = pods_project.group_for_spec(spec.name)
pods_project.add_file_reference(path, group)
end
end
end
# Add the linked project targets to the pod target.
#
# @return [void]
#
def add_libraries_to_target
pod_target.spec_consumers.map do |consumer|
xcodeprojs_from_consumer(consumer)
end.flatten.each do |xcodeproj|
linked_project = open_linked_xcode_project(xcodeproj['project'])
# Hide the schemes that would be autogenerated for the subproject's targets.
linked_project.recreate_user_schemes(false)
link_targets_with_target(linked_project, xcodeproj['library_targets'] || [])
end
end
#-----------------------------------------------------------------------#
private
# @!group Private Helpers
# Open an Xcode project refered to by a specific pod. Raises an
# Informative error if it fails to open the Xcode project file.
#
# @param [String] The filename of the Xcode project, relative to
# the pod's root.
#
# @return [Xcodeproj::Project] The opened Xcode project file
#
def open_linked_xcode_project(project_filename)
linked_project = begin
Xcodeproj::Project.open(pod_root + project_filename)
rescue RuntimeError => e
raise Informative, "Could not open project #{project_filename}, specified in #{spec_file}: #{e.message}"
end
linked_project
end
# Link a number of targets within a subproject to a pod target.
#
# @param [Xcodeproj::Project] linked_project The Xcode subproject that
# contains the library targets.
# @param [Array<String>] library_target_names The names of the targets
# that should be linked against.
#
# @return [void]
#
def link_targets_with_target(linked_project, library_target_names)
library_target_names.each do |library_target_name|
library_target = find_named_native_target_in_project(linked_project, library_target_name)
link_target_with_target(pod_target.target, library_target)
end
end
# Make sure a target is linked with another target.
#
# @param [PBXNativeTarget] main_target The target that should link against
# another target.
# @param [PBXNativeTarget] library_target The target that should be linked
# against.
#
# @return [void]
#
def link_target_with_target(main_target, library_target)
frameworks = main_target.project.frameworks_group
lib_name = library_target.product_reference.path.sub(/^lib/, '').sub(/\.a$/, '')
library_ref = frameworks.new_product_ref_for_target(lib_name, :static_library)
main_target.add_dependency(library_target)
main_target.frameworks_build_phase.add_file_reference(library_ref)
end
# @return [Hash<Pathname => Array<Specification>>] A hash of the Xcode
# project paths to the specifications that refer to it.
#
def linked_project_specs
specs_by_path = {}
pod_target.spec_consumers.map do |consumer|
xcodeprojs_from_consumer(consumer).each do |proj|
absolute_path = pod_root + proj['project']
specs_by_path[absolute_path] ||= []
specs_by_path[absolute_path] << consumer.spec
end
end
specs_by_path
end
# Finds the native target in an Xcode project with a given name.
# Raises an Informative error if the native target can't be found.
#
# @param [Project] project The project to search in
# @param [String] target_name The name of the target that we're
# looking for
#
# @return [PBXNativeTarget] The native target with the given name
#
def find_named_native_target_in_project(project, target_name)
target = project.targets.find do |target|
target_name == target.name && target.isa == 'PBXNativeTarget'
end
if target.nil?
raise Informative, "Could not find native target #{target_name} in project #{project.path}, specified in #{spec_file}"
end
target
end
# Takes a Consumer and extracts an array of xcodeproj descriptors.
#
# @param [Specification::Consumer] consumer The consumer to take xcodeprojs from
#
# @return [Array<Hash>] A list of valid xcodeproj specifications
#
def xcodeprojs_from_consumer(consumer)
xcodeprojs = consumer.xcodeprojs
xcodeprojs = [] if xcodeprojs.nil?
xcodeprojs = [xcodeprojs] if xcodeprojs.kind_of?(Hash)
xcodeprojs = xcodeprojs.map do |xcodeproj|
xcodeproj.inject({}) { |memo, (k,v)| memo[k.to_s] = v; memo }
end
xcodeprojs.each do |xcodeproj|
unless xcodeproj.has_key?('project')
raise Informative, "Missing project parameter to xcodeproj specification: #{xcodeproj.inspect}"
end
end
xcodeprojs
end
# @return [String] the path where the pod target's specification is
# defined, if loaded from a file. (May be nil)
#
def spec_file
pod_target.root_spec.defined_in_file
end
#-----------------------------------------------------------------------#
end
end
end
......@@ -252,6 +252,12 @@ module Pod
# @return [Array<Strings>] The paths that can be deleted.
#
def clean_paths
has_xcodeproj = specs_by_platform.any? do |platform, specs|
specs.any? { |spec| spec.consumer(platform).xcodeprojs.present? }
end
return [] if has_xcodeproj
cached_used = used_files
glob_options = File::FNM_DOTMATCH | File::FNM_CASEFOLD
files = Pathname.glob(root + "**/*", glob_options).map(&:to_s)
......
pod 'XcodeprojTestPod', :path => 'XcodeprojTestPod'
../../../XcodeprojTestPod/Subproject/Subproject/Subproject.h
\ No newline at end of file
../../../XcodeprojTestPod/XcodeprojTestPod.h
\ No newline at end of file
../../../XcodeprojTestPod/XcodeprojTestPod.h
\ No newline at end of file
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
2319D2C5F44B42888CB33449 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 46990BAC3A9A4021AF6A0077 /* libPods.a */; };
82AA92B6182BA170001D702E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82AA92B5182BA170001D702E /* Foundation.framework */; };
82AA92B9182BA170001D702E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 82AA92B8182BA170001D702E /* main.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
82AA92B0182BA170001D702E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
46990BAC3A9A4021AF6A0077 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
82AA92B2182BA170001D702E /* XcodeprojTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = XcodeprojTest; sourceTree = BUILT_PRODUCTS_DIR; };
82AA92B5182BA170001D702E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
82AA92B8182BA170001D702E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
95D185A0B0C446B3A4EE4B2A /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
82AA92AF182BA170001D702E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
82AA92B6182BA170001D702E /* Foundation.framework in Frameworks */,
2319D2C5F44B42888CB33449 /* libPods.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
82AA92A9182BA170001D702E = {
isa = PBXGroup;
children = (
82AA92B7182BA170001D702E /* XcodeprojTest */,
82AA92B4182BA170001D702E /* Frameworks */,
82AA92B3182BA170001D702E /* Products */,
95D185A0B0C446B3A4EE4B2A /* Pods.xcconfig */,
);
sourceTree = "<group>";
};
82AA92B3182BA170001D702E /* Products */ = {
isa = PBXGroup;
children = (
82AA92B2182BA170001D702E /* XcodeprojTest */,
);
name = Products;
sourceTree = "<group>";
};
82AA92B4182BA170001D702E /* Frameworks */ = {
isa = PBXGroup;
children = (
82AA92B5182BA170001D702E /* Foundation.framework */,
46990BAC3A9A4021AF6A0077 /* libPods.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
82AA92B7182BA170001D702E /* XcodeprojTest */ = {
isa = PBXGroup;
children = (
82AA92B8182BA170001D702E /* main.m */,
);
path = XcodeprojTest;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
82AA92B1182BA170001D702E /* XcodeprojTest */ = {
isa = PBXNativeTarget;
buildConfigurationList = 82AA92C0182BA170001D702E /* Build configuration list for PBXNativeTarget "XcodeprojTest" */;
buildPhases = (
8B49AD978F3248A4B2C3A321 /* Check Pods Manifest.lock */,
82AA92AE182BA170001D702E /* Sources */,
82AA92AF182BA170001D702E /* Frameworks */,
82AA92B0182BA170001D702E /* CopyFiles */,
6FA806B1A75A43B39CFEF6B1 /* Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = XcodeprojTest;
productName = XcodeprojTest;
productReference = 82AA92B2182BA170001D702E /* XcodeprojTest */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
82AA92AA182BA170001D702E /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0500;
ORGANIZATIONNAME = "Per Eckerdal";
};
buildConfigurationList = 82AA92AD182BA170001D702E /* Build configuration list for PBXProject "XcodeprojTest" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 82AA92A9182BA170001D702E;
productRefGroup = 82AA92B3182BA170001D702E /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
82AA92B1182BA170001D702E /* XcodeprojTest */,
);
};
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
6FA806B1A75A43B39CFEF6B1 /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Pods-resources.sh\"\n";
showEnvVarsInLog = 0;
};
8B49AD978F3248A4B2C3A321 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
82AA92AE182BA170001D702E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
82AA92B9182BA170001D702E /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
82AA92BE182BA170001D702E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
82AA92BF182BA170001D702E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
SDKROOT = macosx;
};
name = Release;
};
82AA92C1182BA170001D702E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 95D185A0B0C446B3A4EE4B2A /* Pods.xcconfig */;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
82AA92C2182BA170001D702E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 95D185A0B0C446B3A4EE4B2A /* Pods.xcconfig */;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
82AA92AD182BA170001D702E /* Build configuration list for PBXProject "XcodeprojTest" */ = {
isa = XCConfigurationList;
buildConfigurations = (
82AA92BE182BA170001D702E /* Debug */,
82AA92BF182BA170001D702E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
82AA92C0182BA170001D702E /* Build configuration list for PBXNativeTarget "XcodeprojTest" */ = {
isa = XCConfigurationList;
buildConfigurations = (
82AA92C1182BA170001D702E /* Debug */,
82AA92C2182BA170001D702E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 82AA92AA182BA170001D702E /* Project object */;
}
#import <Foundation/Foundation.h>
#import <XcodeprojTestPod/XcodeprojTestPod.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
if ([XcodeprojTestPod twenty] == 20) {
NSLog(@"Success");
return 0;
} else {
NSLog(@"Failure!");
return 1;
}
}
return 0;
}
This project is licensed under the MIT license.
Copyright (c) 2013 Per Eckerdal <per.eckerdal@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
82AA928D182B9D5B001D702E /* Subproject.m in Sources */ = {isa = PBXBuildFile; fileRef = 82AA928C182B9D5B001D702E /* Subproject.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
82AA927F182B9D5B001D702E /* libSubproject.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSubproject.a; sourceTree = BUILT_PRODUCTS_DIR; };
82AA9285182B9D5B001D702E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
82AA928B182B9D5B001D702E /* Subproject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Subproject.h; sourceTree = "<group>"; };
82AA928C182B9D5B001D702E /* Subproject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Subproject.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
82AA927C182B9D5B001D702E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
82AA9276182B9D5B001D702E = {
isa = PBXGroup;
children = (
82AA9288182B9D5B001D702E /* Subproject */,
82AA9281182B9D5B001D702E /* Frameworks */,
82AA9280182B9D5B001D702E /* Products */,
);
sourceTree = "<group>";
};
82AA9280182B9D5B001D702E /* Products */ = {
isa = PBXGroup;
children = (
82AA927F182B9D5B001D702E /* libSubproject.a */,
);
name = Products;
sourceTree = "<group>";
};
82AA9281182B9D5B001D702E /* Frameworks */ = {
isa = PBXGroup;
children = (
82AA9285182B9D5B001D702E /* Foundation.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
82AA9288182B9D5B001D702E /* Subproject */ = {
isa = PBXGroup;
children = (
82AA928B182B9D5B001D702E /* Subproject.h */,
82AA928C182B9D5B001D702E /* Subproject.m */,
);
path = Subproject;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
82AA927D182B9D5B001D702E /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
82AA927E182B9D5B001D702E /* Subproject */ = {
isa = PBXNativeTarget;
buildConfigurationList = 82AA92A3182B9D5B001D702E /* Build configuration list for PBXNativeTarget "Subproject" */;
buildPhases = (
82AA927B182B9D5B001D702E /* Sources */,
82AA927C182B9D5B001D702E /* Frameworks */,
82AA927D182B9D5B001D702E /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = Subproject;
productName = Subproject;
productReference = 82AA927F182B9D5B001D702E /* libSubproject.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
82AA9277182B9D5B001D702E /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0500;
ORGANIZATIONNAME = "Per Eckerdal";
};
buildConfigurationList = 82AA927A182B9D5B001D702E /* Build configuration list for PBXProject "Subproject" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 82AA9276182B9D5B001D702E;
productRefGroup = 82AA9280182B9D5B001D702E /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
82AA927E182B9D5B001D702E /* Subproject */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
82AA927B182B9D5B001D702E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
82AA928D182B9D5B001D702E /* Subproject.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
82AA92A1182B9D5B001D702E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
82AA92A2182B9D5B001D702E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
SDKROOT = macosx;
};
name = Release;
};
82AA92A4182B9D5B001D702E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
82AA92A5182B9D5B001D702E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
82AA927A182B9D5B001D702E /* Build configuration list for PBXProject "Subproject" */ = {
isa = XCConfigurationList;
buildConfigurations = (
82AA92A1182B9D5B001D702E /* Debug */,
82AA92A2182B9D5B001D702E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
82AA92A3182B9D5B001D702E /* Build configuration list for PBXNativeTarget "Subproject" */ = {
isa = XCConfigurationList;
buildConfigurations = (
82AA92A4182B9D5B001D702E /* Debug */,
82AA92A5182B9D5B001D702E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 82AA9277182B9D5B001D702E /* Project object */;
}
#import <Foundation/Foundation.h>
@interface Subproject : NSObject
+ (NSInteger)twelve;
@end
#import "Subproject.h"
@implementation Subproject
+ (NSInteger)twelve
{
return 12;
}
@end
#import <Foundation/Foundation.h>
@interface XcodeprojTestPod : NSObject
+ (NSInteger)twenty;
@end
#import "XcodeprojTestPod.h"
#import "Subproject/Subproject/Subproject.h"
@implementation XcodeprojTestPod
+ (NSInteger)twenty
{
return [Subproject twelve] + 8;
}
@end
Pod::Spec.new do |s|
s.name = "XcodeprojTestPod"
s.version = "1.0"
s.summary = "A pod for testing spec.xcodeproj attribute"
s.description = <<-DESC
A pod for testing CocoaPod's ability to add Xcode projects as subprojects
to specs.
DESC
s.homepage = "https://www.github.com/pereckerdal/XcodeprojTestPod"
s.license = 'MIT'
s.author = { "Per Eckerdal" => "per.eckerdal@gmail.com" }
s.platform = :osx
s.source = { :git => 'https://github.com/pereckerdal/XcodeprojTestPod.git',
:tag => "#{s.version}" }
s.xcodeproj = { :project => 'Subproject/Subproject.xcodeproj',
:library_targets => ['Subproject'] }
s.source_files = '*.{h,m}', 'Subproject/**/*.h'
s.public_header_files = '*.h'
end
require 'fileutils'
require 'pathname'
root = Pathname.new(File.dirname(__FILE__)).realpath
excludes = %w(Podfile
clean.rb
XcodeprojTest
XcodeprojTest/main.m
XcodeprojTest.xcodeproj
XcodeprojTest.xcodeproj/project.pbxproj
XcodeprojTest.xcodeproj/project.xcworkspace
XcodeprojTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata
XcodeprojTestPod
XcodeprojTestPod/.gitignore
XcodeprojTestPod/LICENSE
XcodeprojTestPod/Subproject
XcodeprojTestPod/Subproject/Subproject
XcodeprojTestPod/Subproject/Subproject/Subproject.h
XcodeprojTestPod/Subproject/Subproject/Subproject.m
XcodeprojTestPod/Subproject/Subproject.xcodeproj
XcodeprojTestPod/Subproject/Subproject.xcodeproj/project.pbxproj
XcodeprojTestPod/Subproject/Subproject.xcodeproj/project.xcworkspace
XcodeprojTestPod/Subproject/Subproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata
XcodeprojTestPod/XcodeprojTestPod.h
XcodeprojTestPod/XcodeprojTestPod.m
XcodeprojTestPod/XcodeprojTestPod.podspec).map { |p| root+p }
paths_in_dir = Dir[root.to_s+'/**/*'].map do |filename|
Pathname.new(filename).realpath
end
files_to_remove = paths_in_dir.find_all do |path|
!excludes.include?(path)
end
files_to_remove.sort.reverse.each do |file|
unless file.to_s.start_with?(root.to_s)
# Double-check that we don't remove lots of files like crazy
raise Error, "A horrible internal error was about to happen!"
end
if File.directory?(file)
FileUtils.rmdir(file)
else
FileUtils.rm(file)
end
end
require File.expand_path('../../../spec_helper', __FILE__)
def execute_command(command)
if ENV['VERBOSE']
sh(command)
else
output = `#{command} 2>&1`
raise output unless $?.success?
end
end
module Pod
describe Installer::LinkedDependenciesInstaller do
before do
@target_definition = Podfile::TargetDefinition.new('Pods', nil)
@file_accessor = fixture_file_accessor('banana-lib/BananaLib.podspec')
@project = Project.new(config.sandbox.project_path)
@project.add_pod_group('BananaLib', fixture('banana-lib'))
@pod_target = PodTarget.new([@file_accessor.spec], @target_definition, config.sandbox)
@pod_target.file_accessors = [@file_accessor]
@pod_target.target = @project.new_target(:static_library, 'Pod-BananaLib', :ios)
@installer = Installer::LinkedDependenciesInstaller.new(@project, @file_accessor.root, @pod_target)
end
#-------------------------------------------------------------------------#
describe "Installation" do
describe "#install!" do
it "adds libraries to target when installing" do
@installer.expects(:add_libraries_to_target)
@installer.stubs(:add_linked_projects)
@installer.install!
end
it "adds linked projects when installing" do
@installer.expects(:add_linked_projects)
@installer.stubs(:add_libraries_to_target)
@installer.install!
end
end
it "adds subproject libraries to targets" do
spec = @file_accessor.spec
spec.xcodeproj = {
:project => '../SampleProject/Sample Lib/Sample Lib.xcodeproj',
:library_targets => ['Sample Lib']
}
@pod_target.stubs(:spec_consumers).returns([
spec.consumer(:ios)
])
# Add the linked project to the pods project, otherwise add_libraries_to_target will fail
path = SpecHelper::Fixture.fixture('SampleProject/Sample Lib/Sample Lib.xcodeproj')
@project.add_file_reference(path, @project.main_group)
# Check that the schemes are hidden
Xcodeproj::Project.any_instance.expects(:recreate_user_schemes).with(false)
@installer.send(:add_libraries_to_target)
@pod_target.target.frameworks_build_phase.files_references.map(&:path).should.include('libSample Lib.a')
end
it "adds linked projects" do
path = SpecHelper::Fixture.fixture('SampleProject/Sample Lib/Sample Lib.xcodeproj')
@installer.stubs(:linked_project_specs).returns({
path => [@file_accessor.spec]
})
@installer.send(:add_linked_projects)
@project.reference_for_path(path).isa.should.be == 'PBXFileReference'
end
it "does not add linked projects twice" do
path = SpecHelper::Fixture.fixture('SampleProject/Sample Lib/Sample Lib.xcodeproj')
@installer.stubs(:linked_project_specs).returns({
path => [@file_accessor.spec]
})
@installer.send(:add_linked_projects)
@installer.send(:add_linked_projects)
@project.objects.find_all do |child|
child.isa == 'PBXFileReference' && child.real_path == path
end.length.should.be == 1
end
end
#-------------------------------------------------------------------------#
describe "Private Helpers" do
it "opens a linked xcode project by path" do
@installer.send(:open_linked_xcode_project, "../SampleProject/SampleProject.xcodeproj").path.basename.to_s.should == 'SampleProject.xcodeproj'
end
it "does not open a linked xcode project if the path is incorrect" do
should.raise Informative do
@installer.send(:open_linked_xcode_project, "hello")
end.message.should.match /Could not open project/
end
it "links targets by name with the pod target" do
lib_project = Xcodeproj::Project.open(SpecHelper::Fixture.fixture('SampleProject/Sample Lib/Sample Lib.xcodeproj'))
@project.add_file_reference(lib_project.path, @project.main_group)
@installer.send(:link_targets_with_target, lib_project, ['Sample Lib'])
@pod_target.target.frameworks_build_phase.files_references.map(&:path).should.include('libSample Lib.a')
end
it "links a target with another target" do
sample_project = Xcodeproj::Project.open(SpecHelper::Fixture.fixture('SampleProject/SampleProject.xcodeproj'))
lib_project = Xcodeproj::Project.open(SpecHelper::Fixture.fixture('SampleProject/Sample Lib/Sample Lib.xcodeproj'))
sample_project.main_group.new_file(lib_project.path)
app_target = @installer.send(:find_named_native_target_in_project, sample_project, 'TestRunner')
lib_target = @installer.send(:find_named_native_target_in_project, lib_project, 'Sample Lib')
# Change the name of the lib_target product in order to test that we link
# against that and not just the target name.
lib_target.product_reference.path = 'libLib.a'
@installer.send(:link_target_with_target, app_target, lib_target)
app_target.dependencies.map(&:target).should.include(lib_target)
app_target.frameworks_build_phase.files_references.map(&:path).should.include('libLib.a')
end
it "finds that no specs specifies linked projects" do
@pod_target.stubs(:spec_consumers).returns([
@file_accessor.spec.consumer(:ios)
])
@installer.send(:linked_project_specs).should.be == {}
end
it "finds specs that specify linked projects" do
spec = @file_accessor.spec
spec.xcodeproj = { :project => 'hello' }
@pod_target.stubs(:spec_consumers).returns([
spec.consumer(:ios)
])
@installer.send(:linked_project_specs).should.be == {
(@file_accessor.root + 'hello') => [spec]
}
end
it "finds a native target in a project" do
project = Xcodeproj::Project.open(SpecHelper::Fixture.fixture('SampleProject/SampleProject.xcodeproj'))
@installer.send(:find_named_native_target_in_project, project, 'SampleProject').isa.should == 'PBXNativeTarget'
end
it "does not find a nonexistent native target in a project" do
project = Xcodeproj::Project.open(SpecHelper::Fixture.fixture('SampleProject/SampleProject.xcodeproj'))
should.raise Informative do
@installer.send(:find_named_native_target_in_project, project, 'SampleProject_nonexistent')
end.message.should.match /Could not find native target/
end
it "extracts a single xcodeproj from a consumer object" do
spec = @file_accessor.spec
spec.xcodeproj = { :project => 'hello' }
@installer.send(:xcodeprojs_from_consumer, spec.consumer(:ios)).should.be == [{ "project" => "hello" }]
end
it "extracts two xcodeprojs from a consumer object" do
spec = @file_accessor.spec
spec.xcodeprojs = [{ :project => 'hello' }, { 'project' => 'hello2' }]
xcodeprojs = @installer.send(:xcodeprojs_from_consumer, spec.consumer(:ios))
xcodeprojs.should.be == [{ "project" => "hello" }, { "project" => "hello2" }]
end
it "finds the spec file path correctly" do
@installer.send(:spec_file).should.be == @file_accessor.spec.defined_in_file
end
end
#-------------------------------------------------------------------------#
describe "Functional Tests" do
it "actually compiles and links properly" do
load(fixture('XcodeprojTest/clean.rb'))
begin
Dir.chdir(fixture('XcodeprojTest')) do
pod_command = 'bundle exec ../../../bin/sandbox-pod'
execute_command "#{pod_command} install --verbose --no-repo-update 2>&1"
# Create the XcodeprojTest scheme, in order to be able to build with xcodebuild
testproj = Xcodeproj::Project.open(fixture('XcodeprojTest/XcodeprojTest.xcodeproj'))
testproj.recreate_user_schemes
execute_command "xcodebuild -workspace XcodeprojTest.xcworkspace -scheme XcodeprojTest -configuration Release install DSTROOT=$(pwd)"
`./usr/local/bin/XcodeprojTest 2>&1`.should.match /Success/
$?.success?.should.be.true
end
ensure
load(fixture('XcodeprojTest/clean.rb'))
end
end
end
#-------------------------------------------------------------------------#
end
end
......@@ -189,6 +189,14 @@ module Pod
]
end
it "returns no clean paths for specs that have linked projects" do
spec = fixture_spec('banana-lib/BananaLib.podspec')
spec.xcodeproj = { :project => 'hello' }
specs_by_platform = { :ios => [spec] }
@installer = Installer::PodSourceInstaller.new(config.sandbox, specs_by_platform)
@installer.send(:clean_paths).should.be == []
end
it "returns the used files" do
@installer.send(:download_source)
paths = @installer.send(:used_files)
......
......@@ -74,6 +74,7 @@ module Pod
@installer.stubs(:install_file_references)
@installer.stubs(:install_libraries)
@installer.stubs(:link_aggregate_target)
@installer.stubs(:link_linked_dependencies)
@installer.stubs(:write_lockfiles)
@installer.stubs(:aggregate_targets).returns([])
@installer.unstub(:generate_pods_project)
......@@ -553,6 +554,26 @@ module Pod
libs.map(&:name).should == ['Pods']
end
end
#-------------------------------------------------------------------------#
describe "Private helpers" do
before do
@installer.send(:analyze)
@specs = @installer.pod_targets.map(&:specs).flatten
@spec = @specs.find { |spec| spec && spec.name == 'JSONKit' }
end
it "finds a pod from a given pod target" do
pod_target = @installer.pod_targets.find { |x| x.specs.first.root.name == 'JSONKit' }
@installer.send(:pod_for_target, pod_target).name.should == 'JSONKit'
end
end
#-------------------------------------------------------------------------#
end
end
......@@ -116,7 +116,7 @@ module Pod
set_up_test_repo_for_update
SourcesManager.update(test_repo_path.basename.to_s, true)
UI.output.should.match /is up to date/
UI.output.should.match /(Already)|(is) up.to.date/
end
it "uses the only fast forward git option" do
......
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