Commit eb59c774 authored by Samuel Giddins's avatar Samuel Giddins

Specify installation options via the podfile

parent 6f6cd265
......@@ -7,7 +7,7 @@ GIT
GIT
remote: https://github.com/CocoaPods/Core.git
revision: 3114804fac0ab28cd17ceb7d6fc29d0ca9c88e6e
revision: 93db7951de84e96562f5b47882f6307983155bf8
branch: seg-podfile-refactor
specs:
cocoapods-core (0.39.0)
......
......@@ -39,8 +39,6 @@ module Pod
module Options
def options
[
['--no-clean', 'Leave SCM dirs like `.git` and `.svn` intact after downloading'],
['--no-integrate', 'Skip integration of the Pods libraries in the Xcode project(s)'],
['--no-repo-update', 'Skip running `pod repo update` before install'],
].concat(super)
end
......@@ -51,8 +49,6 @@ module Pod
end
def initialize(argv)
config.clean = argv.flag?('clean', config.clean)
config.integrate_targets = argv.flag?('integrate', config.integrate_targets)
config.skip_repo_update = !argv.flag?('repo-update', !config.skip_repo_update)
super
end
......
......@@ -17,11 +17,6 @@ module Pod
:skip_repo_update => false,
:skip_download_cache => !ENV['COCOAPODS_SKIP_CACHE'].nil?,
:clean => true,
:integrate_targets => true,
:deduplicate_targets => true,
:deterministic_uuids => ENV['COCOAPODS_DISABLE_DETERMINISTIC_UUIDS'].nil?,
:lock_pod_source => true,
:new_version_message => ENV['COCOAPODS_SKIP_UPDATE_MESSAGE'].nil?,
:cache_root => Pathname.new(Dir.home) + 'Library/Caches/CocoaPods',
......@@ -74,34 +69,6 @@ module Pod
# @!group Installation
# @return [Bool] Whether the installer should clean after the installation.
#
attr_accessor :clean
alias_method :clean?, :clean
# @return [Bool] Whether the installer should remove write permissions for
# installed pod source files after the installation.
#
attr_accessor :lock_pod_source
alias_method :lock_pod_source?, :lock_pod_source
# @return [Bool] Whether CocoaPods should integrate a user target and build
# the workspace or just create the Pods project.
#
attr_accessor :integrate_targets
alias_method :integrate_targets?, :integrate_targets
# @return [Bool] Whether CocoaPods should deduplicate pod targets.
#
attr_accessor :deduplicate_targets
alias_method :deduplicate_targets?, :deduplicate_targets
# @return [Bool] Whether CocoaPods should give the pods project
# deterministic UUIDs.
#
attr_accessor :deterministic_uuids
alias_method :deterministic_uuids?, :deterministic_uuids
# @return [Bool] Whether the installer should skip the repos update.
#
attr_accessor :skip_repo_update
......
......@@ -27,7 +27,8 @@ module Pod
def self.download(
request,
target,
cache_path: !Config.instance.skip_download_cache && Config.instance.clean? && Config.instance.cache_root + 'Pods'
can_cache: true,
cache_path: can_cache && !Config.instance.skip_download_cache && Config.instance.cache_root + 'Pods'
)
if cache_path
cache = Cache.new(cache_path)
......
......@@ -17,6 +17,9 @@ module Pod
#
attr_reader :podfile_path
attr_accessor :can_cache
alias_method :can_cache?, :can_cache
# Initialize a new instance
#
# @param [String] name @see name
......@@ -27,6 +30,7 @@ module Pod
@name = name
@params = params
@podfile_path = podfile_path
@can_cache = true
end
# @return [Bool] whether an external source source is equal to another
......@@ -105,7 +109,7 @@ module Pod
title = "Pre-downloading: `#{name}` #{description}"
UI.titled_section(title, :verbose_prefix => '-> ') do
target = sandbox.pod_dir(name)
download_result = Downloader.download(download_request, target)
download_result = Downloader.download(download_request, target, :can_cache => can_cache)
spec = download_result.spec
raise Informative, "Unable to find a specification for '#{name}'." unless spec
......
......@@ -32,6 +32,7 @@ module Pod
autoload :AggregateTargetInstaller, 'cocoapods/installer/target_installer/aggregate_target_installer'
autoload :Analyzer, 'cocoapods/installer/analyzer'
autoload :FileReferencesInstaller, 'cocoapods/installer/file_references_installer'
autoload :InstallationOptions, 'cocoapods/installer/installation_options'
autoload :PostInstallHooksContext, 'cocoapods/installer/post_install_hooks_context'
autoload :PreInstallHooksContext, 'cocoapods/installer/pre_install_hooks_context'
autoload :SourceProviderHooksContext, 'cocoapods/installer/source_provider_hooks_context'
......@@ -44,6 +45,9 @@ module Pod
autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
include Config::Mixin
include InstallationOptions::Mixin
delegate_installation_options { podfile }
# @return [Sandbox] The sandbox where the Pods should be installed.
#
......@@ -109,7 +113,7 @@ module Pod
verify_no_static_framework_transitive_dependencies
verify_framework_usage
generate_pods_project
integrate_user_project if config.integrate_targets?
integrate_user_project if integrate_targets?
perform_post_install_actions
end
......@@ -221,7 +225,9 @@ module Pod
end
def create_analyzer
Analyzer.new(sandbox, podfile, lockfile)
Analyzer.new(sandbox, podfile, lockfile).tap do |analyzer|
analyzer.installation_options = installation_options
end
end
# Ensures that the white-listed build configurations are known to prevent
......@@ -318,7 +324,7 @@ module Pod
end
@pod_installers ||= []
pod_installer = PodSourceInstaller.new(sandbox, specs_by_platform)
pod_installer = PodSourceInstaller.new(sandbox, specs_by_platform, can_cache: clean?)
@pod_installers << pod_installer
pod_installer
end
......@@ -340,7 +346,7 @@ module Pod
# @todo Why the @pod_installers might be empty?
#
def clean_pod_sources
return unless config.clean?
return unless clean?
return unless @pod_installers
@pod_installers.each(&:clean!)
end
......@@ -362,7 +368,7 @@ module Pod
# @todo Why the @pod_installers might be empty?
#
def lock_pod_sources
return unless config.lock_pod_source?
return unless lock_pod_sources?
return unless @pod_installers
@pod_installers.each do |installer|
pod_target = pod_targets.find { |target| target.pod_name == installer.name }
......@@ -706,7 +712,7 @@ module Pod
pods_project.development_pods.remove_from_project if pods_project.development_pods.empty?
pods_project.sort(:groups_position => :below)
pods_project.recreate_user_schemes(false)
if config.deterministic_uuids?
if deterministic_uuids?
UI.message('- Generating deterministic UUIDs') { pods_project.predictabilize_uuids }
end
pods_project.save
......
......@@ -5,6 +5,9 @@ module Pod
#
class Analyzer
include Config::Mixin
include InstallationOptions::Mixin
delegate_installation_options { podfile }
autoload :AnalysisResult, 'cocoapods/installer/analyzer/analysis_result'
autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
......@@ -57,7 +60,7 @@ module Pod
validate_podfile!
validate_lockfile_version!
@result = AnalysisResult.new
if config.integrate_targets?
if integrate_targets?
@result.target_inspections = inspect_targets_to_integrate
else
verify_platforms_specified!
......@@ -249,7 +252,7 @@ module Pod
target = AggregateTarget.new(target_definition, sandbox)
target.host_requires_frameworks |= target_definition.uses_frameworks?
if config.integrate_targets?
if integrate_targets?
target_inspection = result.target_inspections[target_definition]
raise "missing inspection: #{target_definition.name}" unless target_inspection
target.user_project = target_inspection.project
......@@ -282,7 +285,7 @@ module Pod
# @return [Array<PodTarget>]
#
def generate_pod_targets(specs_by_target)
if config.deduplicate_targets?
if deduplicate_targets?
dedupe_cache = {}
all_specs = specs_by_target.flat_map do |target_definition, dependent_specs|
......@@ -377,7 +380,7 @@ module Pod
def generate_pod_target(target_definitions, pod_specs)
pod_target = PodTarget.new(pod_specs, target_definitions, sandbox)
if config.integrate_targets?
if integrate_targets?
target_inspections = result.target_inspections.select { |t, _| target_definitions.include?(t) }.values
pod_target.user_build_configurations = target_inspections.map(&:build_configurations).reduce({}, &:merge)
pod_target.archs = target_inspections.flat_map(&:archs).compact.uniq.sort
......@@ -462,6 +465,7 @@ module Pod
else
source = ExternalSources.from_dependency(dependency, podfile.defined_in_file)
end
source.can_cache = clean?
source.fetch(sandbox)
end
......@@ -650,7 +654,7 @@ module Pod
# @return [void]
#
def verify_platforms_specified!
unless config.integrate_targets?
unless integrate_targets?
podfile.target_definition_list.each do |target_definition|
if !target_definition.empty? && target_definition.platform.nil?
raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.'
......
require 'active_support/hash_with_indifferent_access'
module Pod
class Installer
class InstallationOptions
def self.from_podfile(podfile)
name = podfile.installation_method['name']
unless name.downcase == 'cocoapods'
raise Informative "currently need to specify a cocoapods install, you chose #{name}"
end
options = podfile.installation_method['options']
new(options)
end
def self.option(name, default, boolean: true)
name = name.to_s
raise 'existing' if defaults.key?(name)
defaults[name] = default
attr_accessor name
alias_method "#{name}?", name if boolean
end
def self.defaults
@defaults ||= {}
end
def self.all_options
defaults.keys
end
def initialize(options)
options = ActiveSupport::HashWithIndifferentAccess.new(options)
unknown_keys = options.keys - self.class.all_options.map(&:to_s)
raise Informative, "Unknown installation options: #{unknown_keys.to_sentence}" unless unknown_keys.empty?
self.class.defaults.each do |key, default|
value = options.fetch(key, default)
send("#{key}=", value)
end
end
option :clean, true
option :deduplicate_targets, true
option :deterministic_uuids, true
option :integrate_targets, true
option :lock_pod_sources, true
module Mixin
def Mixin.included(mod)
mod.send(:attr_accessor, :installation_options)
def mod.delegate_installation_options(&blk)
define_method(:installation_options) do
@installation_options ||= InstallationOptions.from_podfile(instance_eval(&blk))
end
end
end
def respond_to_missing?(name, *args)
installation_options.respond_to?(name, *args) || super
end
def method_missing(name, *args, &blk)
if installation_options.respond_to?(name)
installation_options.send(name, *args, &blk)
else
super
end
end
end
end
end
end
......@@ -17,14 +17,21 @@ module Pod
#
attr_reader :specs_by_platform
# @return [Boolean] Whether the installer is allowed to touch the cache.
#
attr_reader :can_cache
alias_method :can_cache?, :can_cache
# Initialize a new instance
#
# @param [Sandbox] sandbox @see sandbox
# @param [Hash{Symbol=>Array}] specs_by_platform @see specs_by_platform
# @param [Boolean] can_cache @see can_cache
#
def initialize(sandbox, specs_by_platform)
def initialize(sandbox, specs_by_platform, can_cache: true)
@sandbox = sandbox
@specs_by_platform = specs_by_platform
@can_cache = can_cache
end
# @return [String] A string suitable for debugging.
......@@ -110,7 +117,7 @@ module Pod
# @return [void]
#
def download_source
download_result = Downloader.download(download_request, root)
download_result = Downloader.download(download_request, root, :can_cache => can_cache?)
if (@specific_source = download_result.checkout_options) && specific_source != root_spec.source
sandbox.store_checkout_source(root_spec.name, specific_source)
......
......@@ -354,9 +354,7 @@ module Pod
@original_config = Config.instance.clone
config.installation_root = validation_dir
config.silent = !config.verbose
config.integrate_targets = true
config.skip_repo_update = true
config.deterministic_uuids = false
end
def tear_down_validation_environment
......@@ -664,6 +662,7 @@ module Pod
local = local?
urls = source_urls
Pod::Podfile.new do
install! 'cocoapods', :deterministic_uuids => false
urls.each { |u| source(u) }
target 'App' do
use_frameworks!(use_frameworks)
......
......@@ -176,22 +176,6 @@ module Pod
@config.should.not.be.verbose
end
it 'cleans SCM dirs in dependency checkouts' do
@config.should.clean
end
it 'locks pod source files' do
@config.should.lock_pod_source
end
it 'integrates a user target' do
@config.should.integrate_targets
end
it 'de-duplicates targets' do
@config.should.deduplicate_targets
end
it 'returns the cache root' do
@config.cache_root.should == Pathname.new(File.join(ENV['HOME'], 'Library/Caches/CocoaPods'))
end
......
......@@ -247,7 +247,7 @@ module Pod
end
it 'generates the integration library appropriately if the installation will not integrate' do
config.integrate_targets = false
@analyzer.integrate_targets = false
target = @analyzer.analyze.targets.first
target.client_root.should == config.installation_root
......@@ -262,11 +262,11 @@ module Pod
aggregate = Pod::Source::Aggregate.new(repos)
Pod::SourcesManager.stubs(:aggregate).returns(aggregate)
aggregate.sources.first.stubs(:url).returns(SpecHelper.test_repo_url)
config.integrate_targets = false
end
it 'does not require a platform for an empty target' do
podfile = Pod::Podfile.new do
install! 'cocoapods', :integrate_targets => false
source SpecHelper.test_repo_url
xcodeproj 'SampleProject/SampleProject'
target 'TestRunner' do
......@@ -281,6 +281,7 @@ module Pod
it 'does not raise if a target with dependencies inherits the platform from its parent' do
podfile = Pod::Podfile.new do
install! 'cocoapods', :integrate_targets => false
source SpecHelper.test_repo_url
xcodeproj 'SampleProject/SampleProject'
platform :osx
......@@ -295,6 +296,7 @@ module Pod
it 'raises if a target with dependencies does not have a platform' do
podfile = Pod::Podfile.new do
install! 'cocoapods', :integrate_targets => false
source SpecHelper.test_repo_url
xcodeproj 'SampleProject/SampleProject'
target 'TestRunner' do
......@@ -659,6 +661,7 @@ module Pod
ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file).returns(downloader)
downloader.expects(:fetch)
downloader.expects(:can_cache=).with(true).once
@analyzer.send(:fetch_external_sources)
end
......@@ -670,6 +673,7 @@ module Pod
ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file).returns(downloader)
downloader.expects(:fetch)
downloader.expects(:can_cache=).with(true).once
@analyzer.send(:fetch_external_sources)
end
......@@ -680,6 +684,7 @@ module Pod
ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file).returns(downloader)
downloader.expects(:fetch)
downloader.expects(:can_cache=).with(true).once
@analyzer.send(:fetch_external_sources)
end
......@@ -691,6 +696,7 @@ module Pod
ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file).returns(downloader)
downloader.expects(:fetch)
downloader.expects(:can_cache=).with(true).once
@analyzer.send(:fetch_external_sources)
end
......@@ -702,6 +708,20 @@ module Pod
ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file).returns(downloader)
downloader.expects(:fetch)
downloader.expects(:can_cache=).with(true).once
@analyzer.send(:fetch_external_sources)
end
it 'does not use the cache when the podfile instructs not to clean' do
@analyzer.result.podfile_state.unchanged << 'BananaLib'
@sandbox_manifest.send(:checkout_options_data).delete('BananaLib')
downloader = stub('DownloaderSource')
ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file).returns(downloader)
downloader.expects(:fetch)
downloader.expects(:can_cache=).with(false).once
@analyzer.clean = false
@analyzer.send(:fetch_external_sources)
end
......
......@@ -51,8 +51,8 @@ module Pod
CocoaPodsStats::Sender.any_instance.stubs(:send)
podfile = generate_podfile
lockfile = generate_lockfile
config.integrate_targets = false
@installer = Installer.new(config.sandbox, podfile, lockfile)
@installer.integrate_targets = false
end
#-------------------------------------------------------------------------#
......@@ -150,13 +150,13 @@ module Pod
end
it 'integrates the user targets if the corresponding config is set' do
config.integrate_targets = true
@installer.integrate_targets = true
@installer.expects(:integrate_user_project)
@installer.install!
end
it "doesn't integrates the user targets if the corresponding config is not set" do
config.integrate_targets = false
@installer.integrate_targets = false
@installer.expects(:integrate_user_project).never
@installer.install!
end
......@@ -243,9 +243,9 @@ module Pod
end
end
lockfile = generate_lockfile
config.integrate_targets = false
@installer = Installer.new(config.sandbox, podfile, lockfile)
@installer.integrate_targets = false
@installer.install!
target = @installer.aggregate_targets.first
......@@ -277,9 +277,9 @@ module Pod
target 'SampleProject'
end
lockfile = generate_lockfile
config.integrate_targets = false
@installer = Installer.new(config.sandbox, podfile, lockfile)
@installer.integrate_targets = false
should.raise(Informative) { @installer.install! }.message.should.match /conflict.*monkey/
end
......@@ -309,8 +309,8 @@ module Pod
before do
fixture_path = ROOT + 'spec/fixtures'
config.repos_dir = fixture_path + 'spec-repos'
config.integrate_targets = false
@podfile = Pod::Podfile.new do
install! 'cocoapods', 'integrate_targets' => false
platform :ios, '8.0'
xcodeproj 'SampleProject/SampleProject'
use_frameworks!
......@@ -362,9 +362,9 @@ module Pod
target 'SampleProject'
end
lockfile = generate_lockfile
config.integrate_targets = false
@installer = Installer.new(config.sandbox, podfile, lockfile)
@installer.integrate_targets = false
should.raise(Informative) { @installer.install! }.message.should.match /use_frameworks/
end
end
......@@ -543,7 +543,7 @@ module Pod
describe '#clean' do
it 'it cleans only if the config instructs to do it' do
config.clean = false
@installer.clean = false
@installer.send(:clean_pod_sources)
Installer::PodSourceInstaller.any_instance.expects(:install!).never
end
......@@ -562,14 +562,14 @@ module Pod
end
it "creates build configurations for all of the user's targets" do
config.integrate_targets = true
@installer.integrate_targets = true
@installer.send(:analyze)
@installer.send(:prepare_pods_project)
@installer.pods_project.build_configurations.map(&:name).sort.should == ['App Store', 'Debug', 'Release', 'Test']
end
it 'sets STRIP_INSTALLED_PRODUCT to NO for all configurations for the whole project' do
config.integrate_targets = true
@installer.integrate_targets = true
@installer.send(:analyze)
@installer.send(:prepare_pods_project)
@installer.pods_project.build_settings('Debug')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
......@@ -924,8 +924,8 @@ module Pod
podfile = Pod::Podfile.new do
platform :ios
end
config.integrate_targets = false
@installer = Installer.new(config.sandbox, podfile)
@installer.integrate_targets = false
end
it 'runs the pre install hooks' 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