Commit 86dce91c authored by Fabio Pelosin's avatar Fabio Pelosin

Merge pull request #1999 from mrackwitz/feature_pod_update

#760: pod update PODS
parents 6e9dbbee 37de587e
...@@ -30,4 +30,14 @@ examples/RelativePathProject/RelativePathProject/RelativePathProject.xcodeproj ...@@ -30,4 +30,14 @@ examples/RelativePathProject/RelativePathProject/RelativePathProject.xcodeproj
coverage/ coverage/
.coveralls.yml .coveralls.yml
# IDEs
*.xccheckout *.xccheckout
.idea/
# RVM files
/.rvmrc
/.ruby-version
/.ruby-gemset
# Bundler files
/.bundle
...@@ -2,6 +2,20 @@ ...@@ -2,6 +2,20 @@
To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides/installing_cocoapods.html). To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides/installing_cocoapods.html).
## Master
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/master...0.31.1)
[CocoaPods-Core](https://github.com/CocoaPods/Core/compare/master...0.31.1)
##### Enhancements
* Allow to update only a list of given pods with `pod update [POD_NAMES...]`.
[Marius Rackwitz](https://github.com/mrackwitz)
[CocoaPods#760](https://github.com/CocoaPods/CocoaPods/issues/760)
* `pod update` falls back to `pod install` if no Lockfile is present.
[Marius Rackwitz](https://github.com/mrackwitz)
## 0.31.1 ## 0.31.1
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.31.1...0.31.0) [CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.31.1...0.31.0)
[CocoaPods-Core](https://github.com/CocoaPods/Core/compare/0.31.1...0.31.0) [CocoaPods-Core](https://github.com/CocoaPods/Core/compare/0.31.1...0.31.0)
......
...@@ -77,7 +77,7 @@ end ...@@ -77,7 +77,7 @@ end
namespace :spec do namespace :spec do
def specs(dir) def specs(dir)
FileList["spec/#{dir}/*_spec.rb"].shuffle.join(' ') FileList["spec/#{dir}_spec.rb"].shuffle.join(' ')
end end
#--------------------------------------# #--------------------------------------#
...@@ -89,7 +89,7 @@ namespace :spec do ...@@ -89,7 +89,7 @@ namespace :spec do
#--------------------------------------# #--------------------------------------#
unit_specs_command = "bundle exec bacon #{specs('unit/**')}" unit_specs_command = "bundle exec bacon #{specs('unit/**/*')}"
desc "Run the unit specs" desc "Run the unit specs"
task :unit => :unpack_fixture_tarballs do task :unit => :unpack_fixture_tarballs do
...@@ -104,8 +104,9 @@ namespace :spec do ...@@ -104,8 +104,9 @@ namespace :spec do
#--------------------------------------# #--------------------------------------#
desc "Run the functional specs" desc "Run the functional specs"
task :functional => :unpack_fixture_tarballs do task :functional, [:spec] => :unpack_fixture_tarballs do |t, args|
sh "bundle exec bacon #{specs('functional/**')}" args.with_defaults(:spec => '**/*')
sh "bundle exec bacon #{specs("functional/#{args[:spec]}")}"
end end
#--------------------------------------# #--------------------------------------#
...@@ -130,7 +131,7 @@ namespace :spec do ...@@ -130,7 +131,7 @@ namespace :spec do
ENV['GENERATE_COVERAGE'] = 'true' ENV['GENERATE_COVERAGE'] = 'true'
title 'Running the specs' title 'Running the specs'
sh "bundle exec bacon #{specs('**')}" sh "bundle exec bacon #{specs('**/*')}"
title 'Running Integration tests' title 'Running Integration tests'
sh "bundle exec bacon spec/integration.rb" sh "bundle exec bacon spec/integration.rb"
...@@ -144,7 +145,7 @@ namespace :spec do ...@@ -144,7 +145,7 @@ namespace :spec do
desc "Run all specs and build all examples" desc "Run all specs and build all examples"
task :ci => :unpack_fixture_tarballs do task :ci => :unpack_fixture_tarballs do
title 'Running the specs' title 'Running the specs'
sh "bundle exec bacon #{specs('**')}" sh "bundle exec bacon #{specs('**/*')}"
require 'pathname' require 'pathname'
unless Pathname.new(ENV['HOME']+'/.cocoapods/repos/master').exist? unless Pathname.new(ENV['HOME']+'/.cocoapods/repos/master').exist?
......
...@@ -28,13 +28,15 @@ module Pod ...@@ -28,13 +28,15 @@ module Pod
# Runs the installer. # Runs the installer.
# #
# @param [update] whether the installer should be run in update mode. # @param [Hash, Boolean, nil] update
# Pods that have been requested to be updated or true if all Pods
# should be updated
# #
# @return [void] # @return [void]
# #
def run_install_with_update(update) def run_install_with_update(update)
installer = Installer.new(config.sandbox, config.podfile, config.lockfile) installer = Installer.new(config.sandbox, config.podfile, config.lockfile)
installer.update_mode = update installer.update = update
installer.install! installer.install!
end end
end end
...@@ -76,10 +78,40 @@ module Pod ...@@ -76,10 +78,40 @@ module Pod
self.summary = 'Update outdated project dependencies' self.summary = 'Update outdated project dependencies'
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 = '[POD_NAMES...]'
def initialize(argv)
@pods = argv.arguments! unless argv.arguments.empty?
super
end
def run def run
verify_podfile_exists! verify_podfile_exists!
verify_lockfile_exists!
run_install_with_update(true) if @pods
verify_lockfile_exists!
# Check if all given pods are installed
missing_pods = @pods.select { |pod| !config.lockfile.pod_names.include?(pod) }
if missing_pods.length > 0
raise Informative, (missing_pods.length > 1 \
? "Pods %s are not installed and cannot be updated" \
: "Pod %s is not installed and cannot be updated"
) % missing_pods.map { |p| "`#{p}'" }.join(', ')
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
......
...@@ -64,11 +64,12 @@ module Pod ...@@ -64,11 +64,12 @@ module Pod
@lockfile = lockfile @lockfile = lockfile
end end
# @return [Bool] Whether the installer is in update mode. In update mode # @return [Hash, Boolean, nil] Pods that have been requested to be
# the contents of the Lockfile are not taken into account for # updated or true if all Pods should be updated.
# deciding what Pods to install. # If all Pods should been updated the contents of the Lockfile are
# not taken into account for deciding what Pods to install.
# #
attr_accessor :update_mode attr_accessor :update
# Installs the Pods. # Installs the Pods.
# #
...@@ -169,7 +170,7 @@ module Pod ...@@ -169,7 +170,7 @@ module Pod
end end
analyzer = Analyzer.new(sandbox, podfile, lockfile) analyzer = Analyzer.new(sandbox, podfile, lockfile)
analyzer.update_mode = update_mode analyzer.update = update
@analysis_result = analyzer.analyze @analysis_result = analyzer.analyze
@aggregate_targets = analyzer.result.targets @aggregate_targets = analyzer.result.targets
end end
......
...@@ -33,7 +33,7 @@ module Pod ...@@ -33,7 +33,7 @@ module Pod
@podfile = podfile @podfile = podfile
@lockfile = lockfile @lockfile = lockfile
@update_mode = false @update = false
@allow_pre_downloads = true @allow_pre_downloads = true
@archs_by_target_def = {} @archs_by_target_def = {}
end end
...@@ -91,11 +91,30 @@ module Pod ...@@ -91,11 +91,30 @@ module Pod
# @!group Configuration # @!group Configuration
# @return [Hash, Boolean, nil] Pods that have been requested to be
# updated or true if all Pods should be updated
#
attr_accessor :update
# @return [Bool] Whether the version of the dependencies which did non # @return [Bool] Whether the version of the dependencies which did non
# change in the Podfile should be locked. # change in the Podfile should be locked.
# #
attr_accessor :update_mode def update_mode?
alias_method :update_mode?, :update_mode !!update
end
# @return [Symbol] Whether and how the dependencies in the Podfile
# should be updated.
#
def update_mode
if !update
:none
elsif update == true
:all
elsif update[:pods] != nil
:selected
end
end
# @return [Bool] Whether the analysis allows pre-downloads and thus # @return [Bool] Whether the analysis allows pre-downloads and thus
# modifications to the sandbox. # modifications to the sandbox.
...@@ -219,10 +238,15 @@ module Pod ...@@ -219,10 +238,15 @@ module Pod
# that prevent the resolver to update a Pod. # that prevent the resolver to update a Pod.
# #
def generate_version_locking_dependencies def generate_version_locking_dependencies
if update_mode? if update_mode == :all
[] []
else else
result.podfile_state.unchanged.map do |pod| locking_pods = result.podfile_state.unchanged
if update_mode == :selected
# If selected Pods should been updated, filter them out of the list
locking_pods = locking_pods.select { |pod| !update[:pods].include?(pod) }
end
locking_pods.map do |pod|
lockfile.dependency_to_lock_pod_named(pod) lockfile.dependency_to_lock_pod_named(pod)
end end
end end
...@@ -252,10 +276,14 @@ module Pod ...@@ -252,10 +276,14 @@ module Pod
deps_to_fetch = [] deps_to_fetch = []
deps_to_fetch_if_needed = [] deps_to_fetch_if_needed = []
deps_with_external_source = podfile.dependencies.select { |dep| dep.external_source } deps_with_external_source = podfile.dependencies.select { |dep| dep.external_source }
if update_mode?
if update_mode == :all
deps_to_fetch = deps_with_external_source deps_to_fetch = deps_with_external_source
else else
pods_to_fetch = result.podfile_state.added + result.podfile_state.changed pods_to_fetch = result.podfile_state.added + result.podfile_state.changed
if update_mode == :selected
pods_to_fetch += update[:pods]
end
deps_to_fetch = deps_with_external_source.select { |dep| pods_to_fetch.include?(dep.root_name) } deps_to_fetch = deps_with_external_source.select { |dep| pods_to_fetch.include?(dep.root_name) }
deps_to_fetch_if_needed = deps_with_external_source.select { |dep| result.podfile_state.unchanged.include?(dep.root_name) } deps_to_fetch_if_needed = deps_with_external_source.select { |dep| result.podfile_state.unchanged.include?(dep.root_name) }
deps_to_fetch += deps_to_fetch_if_needed.select { |dep| sandbox.specification(dep.root_name).nil? || !dep.external_source[:local].nil? || !dep.external_source[:path].nil? } deps_to_fetch += deps_to_fetch_if_needed.select { |dep| sandbox.specification(dep.root_name).nil? || !dep.external_source[:local].nil? || !dep.external_source[:path].nil? }
...@@ -316,7 +344,7 @@ module Pod ...@@ -316,7 +344,7 @@ module Pod
def generate_sandbox_state def generate_sandbox_state
sandbox_state = nil sandbox_state = nil
UI.section "Comparing resolved specification to the sandbox manifest" do UI.section "Comparing resolved specification to the sandbox manifest" do
sandbox_analyzer = SandboxAnalyzer.new(sandbox, result.specifications, update_mode, lockfile) sandbox_analyzer = SandboxAnalyzer.new(sandbox, result.specifications, update_mode?, lockfile)
sandbox_state = sandbox_analyzer.analyze sandbox_state = sandbox_analyzer.analyze
sandbox_state.print sandbox_state.print
end end
......
Subproject commit 57b7ab8a5ae08a2e3b93972ee14ce2d7f674c08e Subproject commit d0378da111a5368a28c019e57e4a9f3d3d8e9d94
...@@ -34,13 +34,54 @@ module Pod ...@@ -34,13 +34,54 @@ module Pod
it "tells the user that no Lockfile was found in the current working dir" do it "tells the user that no Lockfile was found in the current working dir" do
file = temporary_directory + 'Podfile' file = temporary_directory + 'Podfile'
File.open(file, 'w') {|f| f.write('platform :ios') } File.open(file, 'w') do |f|
f.puts('platform :ios')
f.puts('pod "Reachability"')
end
Dir.chdir(temporary_directory) do Dir.chdir(temporary_directory) do
exception = lambda { run_command('update','--no-repo-update') }.should.raise Informative exception = lambda { run_command('update', 'Reachability', '--no-repo-update') }.should.raise Informative
exception.message.should.include "No `Podfile.lock' found in the current working directory" exception.message.should.include "No `Podfile.lock' found in the current working directory"
end end
end end
describe "tells the user that the Pods cannot be updated unless they are installed" do
extend SpecHelper::TemporaryRepos
before do
file = temporary_directory + 'Podfile'
File.open(file, 'w') do |f|
f.puts('platform :ios')
f.puts('pod "BananaLib", "1.0"')
end
podfile = Podfile.new do
platform :ios
pod 'BananaLib', '1.0'
end
specs = [
Specification.new do |s|
s.name = 'BananaLib'
s.version = '1.0'
end
]
Lockfile.generate(podfile, specs).write_to_disk(temporary_directory + 'Podfile.lock')
end
it "for a single missing Pod" do
Dir.chdir(temporary_directory) do
exception = lambda { run_command('update', 'Reachability', '--no-repo-update') }.should.raise Informative
exception.message.should.include "Pod `Reachability' 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
#---------------------------------------------------------------------------# #---------------------------------------------------------------------------#
......
...@@ -370,7 +370,11 @@ describe "Integration" do ...@@ -370,7 +370,11 @@ describe "Integration" do
describe "Pod update" do describe "Pod update" do
describe "Updates an existing installation" do describe "Updates an existing installation" do
check "update --no-repo-update", "update" check "update --no-repo-update", "update_all"
end
describe "Updates a selected Pod in an existing installation" do
check "update Reachability --no-repo-update", "update_selected"
end end
end end
......
...@@ -95,14 +95,14 @@ module Pod ...@@ -95,14 +95,14 @@ module Pod
it "considers changed a Pod whose specification is in head mode if in update mode" do it "considers changed a Pod whose specification is in head mode if in update mode" do
@sandbox.stubs(:head_pod?).returns(true) @sandbox.stubs(:head_pod?).returns(true)
@analyzer.stubs(:update_mode).returns(true) @analyzer.stubs(:update_mode?).returns(true)
@analyzer.send(:pod_changed?, 'BananaLib').should == true @analyzer.send(:pod_changed?, 'BananaLib').should == true
end end
it "doesn't consider changed a Pod whose specification is in head mode if not in update mode" do it "doesn't consider changed a Pod whose specification is in head mode if not in update mode" do
@sandbox.stubs(:head_pod?).returns(true) @sandbox.stubs(:head_pod?).returns(true)
@analyzer.stubs(:sandbox_head_version?).returns(true) @analyzer.stubs(:sandbox_head_version?).returns(true)
@analyzer.stubs(:update_mode).returns(false) @analyzer.stubs(:update_mode?).returns(false)
@analyzer.send(:pod_changed?, 'BananaLib').should == false @analyzer.send(:pod_changed?, 'BananaLib').should == false
end end
......
...@@ -117,7 +117,7 @@ module Pod ...@@ -117,7 +117,7 @@ module Pod
end end
it "does not lock the dependencies in update mode" do it "does not lock the dependencies in update mode" do
@analyzer.update_mode = true @analyzer.update = true
@analyzer.analyze @analyzer.analyze
@analyzer.send(:locked_dependencies).map(&:to_s).should == [] @analyzer.send(:locked_dependencies).map(&:to_s).should == []
end end
......
...@@ -113,8 +113,8 @@ module Pod ...@@ -113,8 +113,8 @@ module Pod
end end
it "configures the analyzer to use update mode if appropriate" do it "configures the analyzer to use update mode if appropriate" do
@installer.update_mode = true @installer.update = true
Installer::Analyzer.any_instance.expects(:update_mode=).with(true) Installer::Analyzer.any_instance.expects(:update=).with(true)
@installer.send(:analyze) @installer.send(:analyze)
@installer.aggregate_targets.map(&:name).sort.should == ['Pods'] @installer.aggregate_targets.map(&:name).sort.should == ['Pods']
@installer.pod_targets.map(&:name).sort.should == ['Pods-JSONKit'] @installer.pod_targets.map(&:name).sort.should == ['Pods-JSONKit']
......
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