Commit 1f06a58c authored by Samuel E. Giddins's avatar Samuel E. Giddins

Merge pull request #5017 from CocoaPods/mr-no-repo-update-by-default

[Command::Project] No repo update by default on install
parents 917dcf2d 0054a3a2
......@@ -6,6 +6,19 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
## Master
##### Breaking
* Running `pod install` doesn't imply an automatic spec repo update.
The old behavior can be achieved by passing in the option `--repo-update`
or running `pod repo update`.
[Marius Rackwitz](https://github.com/mrackwitz)
[#5004](https://github.com/CocoaPods/CocoaPods/issues/5004)
* Remove the configuration variable `skip_repo_update` as the default behavior
varies now between `pod install` and `pod (update|outdated)`.
[Marius Rackwitz](https://github.com/mrackwitz)
[#5017](https://github.com/CocoaPods/CocoaPods/issues/5017)
##### Enhancements
* The master specs repo will no longer perform 'no-op' git fetches. This should
......
......@@ -14,17 +14,22 @@ module Pod
end
class Command < CLAide::Command
require 'cocoapods/command/options/repo_update'
require 'cocoapods/command/options/project_directory'
include Options
require 'cocoapods/command/cache'
require 'cocoapods/command/env'
require 'cocoapods/command/init'
require 'cocoapods/command/install'
require 'cocoapods/command/inter_process_communication'
require 'cocoapods/command/lib'
require 'cocoapods/command/list'
require 'cocoapods/command/outdated'
require 'cocoapods/command/project'
require 'cocoapods/command/repo'
require 'cocoapods/command/setup'
require 'cocoapods/command/spec'
require 'cocoapods/command/init'
require 'cocoapods/command/cache'
require 'cocoapods/command/env'
require 'cocoapods/command/update'
self.abstract_command = true
self.command = 'pod'
......@@ -32,9 +37,6 @@ module Pod
self.description = 'CocoaPods, the Cocoa library package manager.'
self.plugin_prefixes = %w(claide cocoapods)
[Install, Update, Outdated, IPC::Podfile, IPC::Repl].each { |c| c.send(:include, ProjectDirectory) }
[Outdated].each { |c| c.send(:include, Project) }
def self.options
[
['--silent', 'Show nothing'],
......@@ -102,6 +104,14 @@ module Pod
private
# Returns a new {Installer} parametrized from the {Config}.
#
# @return [Installer]
#
def installer_for_config
Installer.new(config.sandbox, config.podfile, config.lockfile)
end
# Checks that the podfile exists.
#
# @raise If the podfile does not exists.
......
module Pod
class Command
class Install < Command
include RepoUpdate
include ProjectDirectory
self.summary = 'Install project dependencies to Podfile.lock versions'
self.description = <<-DESC
Downloads all dependencies defined in `Podfile` and creates an Xcode
Pods library project in `./Pods`.
The Xcode project file should be specified in your `Podfile` like this:
project 'path/to/XcodeProject.xcodeproj'
If no project is specified, then a search for an Xcode project will
be made. If more than one Xcode project is found, the command will
raise an error.
This will configure the project to reference the Pods static library,
add a build configuration file, and add a post build script to copy
Pod resources.
DESC
def self.options
[
['--repo-update', 'Force running `pod repo update` before install'],
].concat(super).reject { |(name, _)| name == '--no-repo-update' }
end
def run
verify_podfile_exists!
installer = installer_for_config
installer.repo_update = repo_update?(:default => false)
installer.update = false
installer.install!
end
end
end
end
......@@ -37,6 +37,8 @@ module Pod
#-----------------------------------------------------------------------#
class Podfile < IPC
include ProjectDirectory
self.summary = 'Converts a Podfile to YAML'
self.description = 'Converts a Podfile to YAML and prints it to STDOUT.'
self.arguments = [
......@@ -123,6 +125,8 @@ module Pod
#-----------------------------------------------------------------------#
class Repl < IPC
include ProjectDirectory
END_OF_OUTPUT_SIGNAL = "\n\r"
self.summary = 'The repl listens to commands on standard input'
......
module Pod
class Command
module Options
# Provides support for commands to take a user-specified `project directory`
#
module ProjectDirectory
module Options
def options
[
['--project-directory=/project/dir/', 'The path to the root of the project directory'],
].concat(super)
end
end
def self.included(base)
base.extend(Options)
end
def initialize(argv)
if project_directory = argv.option('project-directory')
@project_directory = Pathname.new(project_directory).expand_path
end
config.installation_root = @project_directory
super
end
def validate!
super
if @project_directory && !@project_directory.directory?
raise Informative, "`#{@project_directory}` is not a valid directory."
end
end
end
end
end
end
module Pod
class Command
module Options
# Provides support for commands to skip updating the spec repositories.
#
module RepoUpdate
module Options
def options
[
['--no-repo-update', 'Skip running `pod repo update` before install'],
].concat(super)
end
end
def self.included(base)
base.extend(Options)
end
def repo_update?(default: false)
if @repo_update.nil?
default
else
@repo_update
end
end
def initialize(argv)
@repo_update = argv.flag?('repo-update')
super
end
end
end
end
end
module Pod
class Command
class Outdated < Command
include RepoUpdate
include ProjectDirectory
self.summary = 'Show outdated project dependencies'
self.description = <<-DESC
......@@ -90,7 +93,7 @@ module Pod
def spec_sets
@spec_sets ||= begin
analyzer.send(:update_repositories) unless config.skip_repo_update?
analyzer.send(:update_repositories) if repo_update?(:default => true)
aggregate = Source::Aggregate.new(analyzer.sources)
installed_pods.map do |pod_name|
aggregate.search(Dependency.new(pod_name))
......
module Pod
class Command
# Provides support for commands to take a user-specified `project directory`
#
module ProjectDirectory
module Options
def options
[
['--project-directory=/project/dir/', 'The path to the root of the project directory'],
].concat(super)
end
end
def self.included(base)
base.extend(Options)
end
def initialize(argv)
if project_directory = argv.option('project-directory')
@project_directory = Pathname.new(project_directory).expand_path
end
config.installation_root = @project_directory
super
end
def validate!
super
if @project_directory && !@project_directory.directory?
raise Informative,
"`#{@project_directory}` is not a valid directory."
end
end
end
# Provides support for the common behaviour of the `install` and `update`
# commands.
#
module Project
module Options
def options
[
['--no-repo-update', 'Skip running `pod repo update` before install'],
].concat(super)
end
end
def self.included(base)
base.extend Options
end
def initialize(argv)
config.skip_repo_update = !argv.flag?('repo-update', !config.skip_repo_update)
super
end
# Runs the installer.
#
# @param [Hash, Boolean, nil] update
# Pods that have been requested to be updated or true if all Pods
# should be updated
#
# @return [void]
#
def run_install_with_update(update)
installer = Installer.new(config.sandbox, config.podfile, config.lockfile)
installer.update = update
installer.install!
end
end
#-------------------------------------------------------------------------#
class Install < Command
include Project
self.summary = 'Install project dependencies to Podfile.lock versions'
self.description = <<-DESC
Downloads all dependencies defined in `Podfile` and creates an Xcode
Pods library project in `./Pods`.
The Xcode project file should be specified in your `Podfile` like this:
project 'path/to/XcodeProject'
If no project is specified, then a search for an Xcode project will
be made. If more than one Xcode project is found, the command will
raise an error.
This will configure the project to reference the Pods static library,
add a build configuration file, and add a post build script to copy
Pod resources.
DESC
def run
verify_podfile_exists!
run_install_with_update(false)
end
end
#-------------------------------------------------------------------------#
class Update < Command
include Project
self.summary = 'Update outdated project dependencies and create new ' \
'Podfile.lock'
self.description = <<-DESC
Updates the Pods identified by the specified `POD_NAMES`. If no
`POD_NAMES` are specified it updates all the Pods ignoring the contents
of the Podfile.lock.
This command is reserved to the update of dependencies and pod install
should be used to install changes to the Podfile.
DESC
self.arguments = [
CLAide::Argument.new('POD_NAMES', false, true),
]
def initialize(argv)
@pods = argv.arguments! unless argv.arguments.empty?
super
end
def run
verify_podfile_exists!
if @pods
verify_lockfile_exists!
# Check if all given pods are installed
lockfile_roots = config.lockfile.pod_names.map { |p| Specification.root_name(p) }
missing_pods = @pods.map { |p| Specification.root_name(p) }.select do |pod|
!lockfile_roots.include?(pod)
end
unless missing_pods.empty?
message = if missing_pods.length > 1
"Pods `#{missing_pods.join('`, `')}` are not " \
'installed and cannot be updated'
else
"The `#{missing_pods.first}` Pod is not installed " \
'and cannot be updated'
end
raise Informative, message
end
run_install_with_update(:pods => @pods)
else
UI.puts 'Update all pods'.yellow unless @pods
run_install_with_update(true)
end
end
end
end
end
module Pod
class Command
class Update < Command
include RepoUpdate
include ProjectDirectory
self.summary = 'Update outdated project dependencies and create new ' \
'Podfile.lock'
self.description = <<-DESC
Updates the Pods identified by the specified `POD_NAMES`. If no
`POD_NAMES` are specified it updates all the Pods ignoring the contents
of the Podfile.lock.
This command is reserved to the update of dependencies and pod install
should be used to install changes to the Podfile.
DESC
self.arguments = [
CLAide::Argument.new('POD_NAMES', false, true),
]
def initialize(argv)
@pods = argv.arguments! unless argv.arguments.empty?
super
end
# Check if all given pods are installed
#
def verify_pods_are_installed!
lockfile_roots = config.lockfile.pod_names.map { |p| Specification.root_name(p) }
missing_pods = @pods.map { |p| Specification.root_name(p) }.select do |pod|
!lockfile_roots.include?(pod)
end
unless missing_pods.empty?
message = if missing_pods.length > 1
"Pods `#{missing_pods.join('`, `')}` are not " \
'installed and cannot be updated'
else
"The `#{missing_pods.first}` Pod is not installed " \
'and cannot be updated'
end
raise Informative, message
end
end
def run
verify_podfile_exists!
installer = installer_for_config
installer.repo_update = repo_update?(:default => true)
if @pods
verify_lockfile_exists!
verify_pods_are_installed!
installer.update = { :pods => @pods }
else
UI.puts 'Update all pods'.yellow
installer.update = true
end
installer.install!
end
end
end
end
......@@ -14,7 +14,6 @@ module Pod
DEFAULTS = {
:verbose => false,
:silent => false,
:skip_repo_update => false,
:skip_download_cache => !ENV['COCOAPODS_SKIP_CACHE'].nil?,
:new_version_message => ENV['COCOAPODS_SKIP_UPDATE_MESSAGE'].nil?,
......@@ -69,11 +68,6 @@ module Pod
# @!group Installation
# @return [Bool] Whether the installer should skip the repos update.
#
attr_accessor :skip_repo_update
alias_method :skip_repo_update?, :skip_repo_update
# @return [Bool] Whether the installer should skip the download cache.
#
attr_accessor :skip_download_cache
......
......@@ -84,6 +84,11 @@ module Pod
#
attr_accessor :update
# @return [Bool] Whether the spec repos should be updated.
#
attr_accessor :repo_update
alias_method :repo_update?, :repo_update
# @return [Boolean] Whether default plugins should be used during
# installation. Defaults to true.
#
......@@ -140,7 +145,7 @@ module Pod
UI.section 'Updating local specs repositories' do
analyzer.update_repositories
end unless config.skip_repo_update?
end if repo_update?
UI.section 'Analyzing dependencies' do
analyze(analyzer)
......
......@@ -212,7 +212,7 @@ module Pod
public
# Updates the git source repositories unless the config indicates to skip it.
# Updates the git source repositories.
#
def update_repositories
sources.each do |source|
......
......@@ -349,7 +349,6 @@ module Pod
@original_config = Config.instance.clone
config.installation_root = validation_dir
config.silent = !config.verbose
config.skip_repo_update = true
end
def tear_down_validation_environment
......
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe Command::Install do
it 'tells the user that no Podfile or podspec was found in the project dir' do
exception = lambda { run_command('install', '--no-repo-update') }.should.raise Informative
exception.message.should.include "No `Podfile' found in the project directory."
end
describe 'updates of the spec repos' do
before do
file = temporary_directory + 'Podfile'
File.open(file, 'w') do |f|
f.puts('platform :ios')
f.puts('pod "Reachability"')
end
Installer.any_instance.expects(:install!)
end
it "doesn't update the spec repos by default" do
Installer.any_instance.expects(:repo_update=).with(false)
run_command('install')
end
it 'updates the spec repos if that option was given' do
Installer.any_instance.expects(:repo_update=).with(true)
run_command('install', '--repo-update')
end
end
end
end
......@@ -6,7 +6,6 @@ module Pod
before do
Command::Outdated.any_instance.stubs(:unlocked_pods).returns([])
config.stubs(:skip_repo_update?).returns(true)
end
it 'tells the user that no Podfile was found in the project dir' do
......@@ -55,7 +54,6 @@ module Pod
pod 'AFNetworking'
end
config.stubs(:podfile).returns(podfile)
config.stubs(:skip_repo_update?).returns(false)
lockfile = mock
lockfile.stubs(:version).returns(Version.new('1.0'))
lockfile.stubs(:pod_names).returns(%w(AFNetworking))
......@@ -69,8 +67,6 @@ module Pod
source 'https://github.com/CocoaPods/Specs.git'
pod 'AFNetworking'
end
config.unstub(:skip_repo_update?)
config.skip_repo_update = false
lockfile = mock
lockfile.stubs(:version).returns(Version.new('1.0'))
lockfile.stubs(:pod_names).returns(%w(AFNetworking))
......
......@@ -44,8 +44,6 @@ module Pod
end
describe 'with a git based spec repository with a remote' do
extend SpecHelper::TemporaryRepos
before do
config.repos_dir = tmp_repos_path
......
......@@ -194,8 +194,6 @@ module Pod
#-------------------------------------------------------------------------#
describe 'lint subcommand' do
extend SpecHelper::TemporaryRepos
it "complains if it can't find any spec to lint" do
Dir.chdir(temporary_directory) do
lambda { command('spec', 'lint').run }.should.raise Informative
......
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe Command::Project do
it 'tells the user that no Podfile or podspec was found in the current working dir' do
Command::Install.new(CLAide::ARGV.new(['--no-repo-update']))
config.skip_repo_update.should.be.true
end
end
#---------------------------------------------------------------------------#
describe Command::Install do
it 'tells the user that no Podfile or podspec was found in the project dir' do
exception = lambda { run_command('install', '--no-repo-update') }.should.raise Informative
exception.message.should.include "No `Podfile' found in the project directory."
end
end
#---------------------------------------------------------------------------#
describe Command::Update do
extend SpecHelper::TemporaryRepos
it 'tells the user that no Podfile was found in the project dir' do
exception = lambda { run_command('update', '--no-repo-update') }.should.raise Informative
exception.message.should.include "No `Podfile' found in the project directory."
end
it 'tells the user that no Lockfile was found in the project dir' do
describe 'with Podfile' do
extend SpecHelper::TemporaryRepos
before do
file = temporary_directory + 'Podfile'
File.open(file, 'w') do |f|
f.puts('platform :ios')
f.puts('pod "Reachability"')
f.puts('pod "BananaLib", "1.0"')
end
Dir.chdir(temporary_directory) do
exception = lambda { run_command('update', 'Reachability', '--no-repo-update') }.should.raise Informative
exception.message.should.include "No `Podfile.lock' found in the project directory"
end
describe 'updates of the spec repos' do
before do
Installer.any_instance.expects(:install!)
end
it 'updates the spec repos by default' do
Installer.any_instance.expects(:repo_update=).with(true)
run_command('update')
end
describe 'tells the user that the Pods cannot be updated unless they are installed' do
extend SpecHelper::TemporaryRepos
it "doesn't update the spec repos if that option was given" do
Installer.any_instance.expects(:repo_update=).with(false)
run_command('update', '--no-repo-update')
end
end
before do
file = temporary_directory + 'Podfile'
File.open(file, 'w') do |f|
f.puts('platform :ios')
f.puts('pod "BananaLib", "1.0"')
it 'tells the user that no Lockfile was found in the project dir' do
exception = lambda { run_command('update', 'BananaLib', '--no-repo-update') }.should.raise Informative
exception.message.should.include "No `Podfile.lock' found in the project directory"
end
describe 'tells the user that the Pods cannot be updated unless they are installed' do
before do
podfile = Podfile.new do
platform :ios
pod 'BananaLib', '1.0'
......@@ -64,22 +56,17 @@ module Pod
end
it 'for a single missing Pod' do
Dir.chdir(temporary_directory) do
should.raise Informative do
run_command('update', 'Reachability', '--no-repo-update')
end.message.should.include 'The `Reachability` Pod is not ' \
'installed and cannot be updated'
end
end
it 'for multiple missing Pods' do
Dir.chdir(temporary_directory) do
exception = lambda { run_command('update', 'Reachability', 'BananaLib2', '--no-repo-update') }.should.raise Informative
exception.message.should.include 'Pods `Reachability`, `BananaLib2` are not installed and cannot be updated'
end
end
end
end
#---------------------------------------------------------------------------#
end
......@@ -11,7 +11,6 @@ module Bacon
c.silent = true
c.repos_dir = fixture('spec-repos')
c.installation_root = SpecHelper.temporary_directory
c.skip_repo_update = true
c.cache_root = SpecHelper.temporary_directory + 'Cache'
end
......
......@@ -76,12 +76,26 @@ module SpecHelper
#--------------------------------------#
def tmp_repos_path
SpecHelper.temporary_directory + 'cocoapods/repos'
TemporaryRepos.tmp_repos_path
end
module_function :tmp_repos_path
def self.tmp_repos_path
SpecHelper.temporary_directory + 'cocoapods/repos'
end
def self.extended(base)
# Make Context methods available
# WORKAROUND: Bacon auto-inherits singleton methods to child contexts
# by using the runtime and won't include methods in modules included
# by the parent context. We have to ensure that the methods will be
# accessible by the child contexts by defining them as singleton methods.
TemporaryRepos.instance_methods.each do |method|
unbound_method = base.method(method).unbind
base.define_singleton_method method do |*args, &b|
unbound_method.bind(self).call(*args, &b)
end
end
base.before do
tmp_repos_path.mkpath
end
......
......@@ -66,7 +66,6 @@ module Pod
#--------------------------------------#
it 'does not update unused sources' do
config.skip_repo_update = false
@analyzer.stubs(:sources).returns(SourcesManager.master)
SourcesManager.expects(:update).once.with('master')
@analyzer.update_repositories
......@@ -77,7 +76,6 @@ module Pod
source 'https://github.com/CocoaPods/Specs.git'
# No dependencies specified
end
config.skip_repo_update = false
config.verbose = true
SourcesManager.expects(:update).never
......@@ -96,7 +94,6 @@ module Pod
project 'SampleProject/SampleProject'
pod 'BananaLib', '1.0'
end
config.skip_repo_update = false
config.verbose = true
source = Source.new(non_git_repo)
......@@ -118,7 +115,6 @@ module Pod
pod 'BananaLib', '1.0', :source => repo_url
pod 'JSONKit', :source => repo_url
end
config.skip_repo_update = false
config.verbose = true
# Note that we are explicitly ignoring 'repo_1' since it isn't used.
......
......@@ -105,7 +105,6 @@ module Pod
end
it 'runs source provider hooks before analyzing' do
config.skip_repo_update = true
@installer.unstub(:resolve_dependencies)
@installer.stubs(:validate_build_configurations)
@installer.stubs(:clean_sandbox)
......@@ -136,7 +135,6 @@ module Pod
@installer.stubs(:clean_sandbox)
@installer.stubs(:ensure_plugins_are_installed!)
@installer.stubs(:analyze)
config.skip_repo_update = true
analyzer = Installer::Analyzer.new(config.sandbox, @installer.podfile, @installer.lockfile)
analyzer.stubs(:analyze)
......@@ -376,14 +374,13 @@ module Pod
describe 'Dependencies Resolution' do
describe 'updating spec repos' do
it 'does not updates the repositories if config indicates to skip them' do
config.skip_repo_update = true
it 'does not updates the repositories by default' do
SourcesManager.expects(:update).never
@installer.send(:resolve_dependencies)
end
it 'updates the repositories by default' do
config.skip_repo_update = false
it 'updates the repositories if that was requested' do
@installer.repo_update = true
SourcesManager.expects(:update).once
@installer.send(:resolve_dependencies)
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