Commit cd9a2b82 authored by Samuel E. Giddins's avatar Samuel E. Giddins

Allow the specification of plugins in the podfile

parent f6377568
...@@ -14,8 +14,8 @@ gemspec ...@@ -14,8 +14,8 @@ gemspec
gem 'json', '1.7.7' gem 'json', '1.7.7'
group :development do group :development do
#cp_gem 'claide', 'CLAide' cp_gem 'claide', 'CLAide'
cp_gem 'cocoapods-core', 'Core' cp_gem 'cocoapods-core', 'Core', 'seg-podfile-plugins'
cp_gem 'cocoapods-downloader', 'cocoapods-downloader' cp_gem 'cocoapods-downloader', 'cocoapods-downloader'
cp_gem 'cocoapods-plugins', 'cocoapods-plugins' cp_gem 'cocoapods-plugins', 'cocoapods-plugins'
cp_gem 'cocoapods-trunk', 'cocoapods-trunk' cp_gem 'cocoapods-trunk', 'cocoapods-trunk'
......
GIT GIT
remote: https://github.com/CocoaPods/Core.git remote: https://github.com/CocoaPods/CLAide.git
revision: 8d0a5072f64a780dc3f7ef919a66bf82dcfc524d revision: b1eccc296b68b1a432e42ecf0c4b799d8551c75c
branch: master branch: master
specs:
claide (0.7.0)
GIT
remote: https://github.com/CocoaPods/Core.git
revision: e3ab1ae538f10500d5cb0035f458c71d308e68ad
branch: seg-podfile-plugins
specs: specs:
cocoapods-core (0.35.0) cocoapods-core (0.35.0)
activesupport (>= 3.2.15) activesupport (>= 3.2.15)
...@@ -88,7 +95,6 @@ GEM ...@@ -88,7 +95,6 @@ GEM
parser (>= 2.2.0.pre.3, < 3.0) parser (>= 2.2.0.pre.3, < 3.0)
awesome_print (1.2.0) awesome_print (1.2.0)
bacon (1.2.0) bacon (1.2.0)
claide (0.7.0)
clintegracon (0.6.0) clintegracon (0.6.0)
colored (~> 1.2) colored (~> 1.2)
diffy diffy
...@@ -162,6 +168,7 @@ DEPENDENCIES ...@@ -162,6 +168,7 @@ DEPENDENCIES
awesome_print awesome_print
bacon bacon
bundler (~> 1.3) bundler (~> 1.3)
claide!
clintegracon clintegracon
cocoapods! cocoapods!
cocoapods-core! cocoapods-core!
......
...@@ -29,7 +29,7 @@ module Pod ...@@ -29,7 +29,7 @@ module Pod
self.command = 'pod' self.command = 'pod'
self.version = VERSION self.version = VERSION
self.description = 'CocoaPods, the Objective-C library package manager.' self.description = 'CocoaPods, the Objective-C library package manager.'
self.plugin_prefix = 'cocoapods' self.plugin_prefixes = %w(claide cocoapods)
[Install, Update, Outdated, IPC::Podfile, IPC::Repl].each { |c| c.send(:include, ProjectDirectory) } [Install, Update, Outdated, IPC::Podfile, IPC::Repl].each { |c| c.send(:include, ProjectDirectory) }
......
...@@ -16,6 +16,43 @@ module Pod ...@@ -16,6 +16,43 @@ module Pod
# from CocoaPods 1.0). # from CocoaPods 1.0).
# #
module HooksManager module HooksManager
# Represents a single registered hook.
#
class Hook
# @return [String]
# The name of the hook's notification.
#
attr_reader :plugin_name
# @return [String]
# The name of the plugin the hook came from.
#
attr_reader :name
# @return [Proc]
# The block.
#
attr_reader :block
# @param [String] name @see {#name}.
#
# @param [String] plugin_name @see {#plugin_name}.
#
# @param [Proc] block @see {#block}.
#
def initialize(name, plugin_name, block)
raise ArgumentError, 'Missing name' unless name
raise ArgumentError, 'Missing block' unless block
UI.warn '[Hooks] The use of hooks without specifying a `plugin_name` ' \
'has been deprecated.' unless plugin_name
@name = name
@plugin_name = plugin_name
@block = block
end
end
class << self class << self
# @return [Hash{Symbol => Array<Proc>}] The list of the blocks that are # @return [Hash{Symbol => Array<Proc>}] The list of the blocks that are
# registered for each notification name. # registered for each notification name.
...@@ -27,16 +64,16 @@ module Pod ...@@ -27,16 +64,16 @@ module Pod
# @param [Symbol] name # @param [Symbol] name
# The name of the notification. # The name of the notification.
# #
# @param [String] plugin_name
# The name of the plugin the hook comes from.
#
# @param [Proc] block # @param [Proc] block
# The block. # The block.
# #
def register(name, &block) def register(name, plugin_name = nil, &block)
raise ArgumentError, 'Missing name' unless name
raise ArgumentError, 'Missing block' unless block
@registrations ||= {} @registrations ||= {}
@registrations[name] ||= [] @registrations[name] ||= []
@registrations[name] << block @registrations[name] << Hook.new(name, plugin_name, block)
end end
# Runs all the registered blocks for the hook with the given name. # Runs all the registered blocks for the hook with the given name.
...@@ -47,26 +84,30 @@ module Pod ...@@ -47,26 +84,30 @@ module Pod
# @param [Object] context # @param [Object] context
# The context object which should be passed to the blocks. # The context object which should be passed to the blocks.
# #
def run(name, context) # @param [Hash<String, Hash>] whitelisted_plugins
# The plugins that should be run, in the form of a hash keyed by
# plugin name, where the values are the custom options that should
# be passed to the hook's block if it supports taking a second
# argument.
#
def run(name, context, whitelisted_plugins = nil)
raise ArgumentError, 'Missing name' unless name raise ArgumentError, 'Missing name' unless name
raise ArgumentError, 'Missing options' unless context raise ArgumentError, 'Missing options' unless context
if @registrations if registrations
blocks = @registrations[name] hooks = registrations[name]
if blocks if hooks
pretty_name = name.to_s.gsub('_', ' ') UI.message "- Running #{name.to_s.gsub('_', ' ')} hooks" do
UI.message "- Running #{pretty_name} hooks" do hooks.each do |hook|
blocks.each do |block| next if whitelisted_plugins && !whitelisted_plugins.key?(hook.name)
gem_name_lambda = lambda do UI.message "- #{hook.plugin_name || 'unknown plugin'} from " \
file, _line = block.source_location "`#{hook.block.source_location.first}`" do
gem_spec = Gem::Specification.find do |spec| block = hook.block
spec.require_paths.find { |f| file.include? File.join(spec.full_gem_path, f) } if block.arity > 1
block.call(context, whitelisted_plugins[hook.name])
else
block.call(context)
end end
gem_name = (gem_spec && gem_spec.name) || File.basename(file, '.rb')
end
UI.message "- #{gem_name_lambda.call}" do
block.call(context)
end end
end end
end end
......
...@@ -97,6 +97,7 @@ module Pod ...@@ -97,6 +97,7 @@ module Pod
def prepare def prepare
UI.message 'Preparing' do UI.message 'Preparing' do
sandbox.prepare sandbox.prepare
ensure_plugins_are_installed!
Migrator.migrate(sandbox) Migrator.migrate(sandbox)
end end
end end
...@@ -323,7 +324,23 @@ module Pod ...@@ -323,7 +324,23 @@ module Pod
# #
def run_plugins_post_install_hooks def run_plugins_post_install_hooks
context = HooksContext.generate(sandbox, aggregate_targets) context = HooksContext.generate(sandbox, aggregate_targets)
HooksManager.run(:post_install, context) HooksManager.run(:post_install, context, podfile.plugins)
end
# Ensures that all plugins specified in the {#podfile} are loaded.
#
# @return [void]
#
def ensure_plugins_are_installed!
require 'claide/command/plugin_manager'
loaded_plugins = Command::PluginManager.specifications.map(&:name)
podfile.plugins.keys.each do |plugin|
unless loaded_plugins.include? plugin
raise Informative, "Your Podfile requires that the plugin `#{plugin}` be installed. Please install it and try installation again."
end
end
end end
# Prints a warning for any pods that are deprecated # Prints a warning for any pods that are deprecated
......
...@@ -294,7 +294,7 @@ module Pod ...@@ -294,7 +294,7 @@ module Pod
string string
else else
first_space = ' ' * indent first_space = ' ' * indent
indented = CLAide::Helper.wrap_with_indent(string, indent, 9999) indented = CLAide::Command::Banner::TextWrapper.wrap_with_indent(string, indent, 9999)
first_space + indented first_space + indented
end end
end end
......
...@@ -114,7 +114,7 @@ EOS ...@@ -114,7 +114,7 @@ EOS
end end
def installed_plugins def installed_plugins
CLAide::Command::PluginsHelper.specifications. CLAide::Command::PluginManager.specifications.
reduce({}) { |hash, s| hash.tap { |h| h[s.name] = s.version.to_s } } reduce({}) { |hash, s| hash.tap { |h| h[s.name] = s.version.to_s } }
end end
......
...@@ -4,13 +4,17 @@ module Pod ...@@ -4,13 +4,17 @@ module Pod
describe HooksManager do describe HooksManager do
before do before do
@hooks_manager = Pod::HooksManager @hooks_manager = Pod::HooksManager
@hooks_manager.instance_variable_set(:@registrations, nil)
end end
describe 'register' do describe 'register' do
it 'allows to register a block for a notification with a given name' do it 'allows to register a block for a notification with a given name' do
@hooks_manager.register(:post_install) {} @hooks_manager.register(:post_install, 'plugin') {}
@hooks_manager.registrations[:post_install].count.should == 1 @hooks_manager.registrations[:post_install].count.should == 1
@hooks_manager.registrations[:post_install].first.class.should == Proc hook = @hooks_manager.registrations[:post_install].first
hook.class.should == HooksManager::Hook
hook.name.should == :post_install
hook.plugin_name.should == 'plugin'
end end
it 'raises if no name is given' do it 'raises if no name is given' do
...@@ -24,6 +28,11 @@ module Pod ...@@ -24,6 +28,11 @@ module Pod
@hooks_manager.register(:post_install) @hooks_manager.register(:post_install)
end end
end end
it 'warns if no plugin name is given' do
@hooks_manager.register(:post_install) {}
UI.warnings.should.match /hooks without.*deprecated/
end
end end
describe 'run' do describe 'run' do
...@@ -49,6 +58,26 @@ module Pod ...@@ -49,6 +58,26 @@ module Pod
end end
end end
it 'only runs hooks from the allowed plugins' do
@hooks_manager.register(:post_install, 'plugin') do |_options|
raise 'Should not be called'
end
should.not.raise do
@hooks_manager.run(:post_install, Object.new, 'plugin2' => {})
end
end
it 'passed along user-specified options when the hook block has arity 2' do
@hooks_manager.register(:post_install, 'plugin') do |_options, user_options|
user_options['key'].should == 'value'
end
should.not.raise do
@hooks_manager.run(:post_install, Object.new, 'plugin' => {'key' => 'value'})
end
end
it 'raises if no name is given' do it 'raises if no name is given' do
should.raise ArgumentError do should.raise ArgumentError do
@hooks_manager.run(nil, Object.new) {} @hooks_manager.run(nil, Object.new) {}
...@@ -63,16 +92,16 @@ module Pod ...@@ -63,16 +92,16 @@ module Pod
it 'prints a message in verbose mode when any hooks are run' do it 'prints a message in verbose mode when any hooks are run' do
config.verbose = true config.verbose = true
@hooks_manager.register(:post_install) { |_| } @hooks_manager.register(:post_install) {}
@hooks_manager.run(:post_install, Object.new) @hooks_manager.run(:post_install, Object.new)
UI.output.should.match /- Running post install hooks/ UI.output.should.match /- Running post install hooks/
end end
it 'prints a message in verbose mode for each hook run' do it 'prints a message in verbose mode for each hook run' do
config.verbose = true config.verbose = true
@hooks_manager.register(:post_install) { |_| } @hooks_manager.register(:post_install, 'plugin') {}
@hooks_manager.run(:post_install, Object.new) @hooks_manager.run(:post_install, Object.new)
UI.output.should.match /- hooks_manager_spec/ UI.output.should.match %r{- plugin from `spec/unit/hooks_manager_spec.rb`}
end end
end end
end end
......
...@@ -53,6 +53,7 @@ module Pod ...@@ -53,6 +53,7 @@ module Pod
@installer.stubs(:generate_pods_project) @installer.stubs(:generate_pods_project)
@installer.stubs(:integrate_user_project) @installer.stubs(:integrate_user_project)
@installer.stubs(:run_plugins_post_install_hooks) @installer.stubs(:run_plugins_post_install_hooks)
@installer.stubs(:ensure_plugins_are_installed!)
@installer.stubs(:perform_post_install_actions) @installer.stubs(:perform_post_install_actions)
end end
...@@ -501,9 +502,36 @@ module Pod ...@@ -501,9 +502,36 @@ module Pod
it 'runs plugins post install hook' do it 'runs plugins post install hook' do
context = stub context = stub
Installer::HooksContext.expects(:generate).returns(context) Installer::HooksContext.expects(:generate).returns(context)
HooksManager.expects(:run).with(:post_install, context) HooksManager.expects(:run).with(:post_install, context, {})
@installer.send(:run_plugins_post_install_hooks) @installer.send(:run_plugins_post_install_hooks)
end end
it 'only runs the podfile-specified post-install hooks' do
context = stub
Installer::HooksContext.expects(:generate).returns(context)
plugins_hash = {'cocoapods-keys' => {'keyring' => 'Eidolon'}}
@installer.podfile.stubs(:plugins).returns(plugins_hash)
HooksManager.expects(:run).with(:post_install, context, plugins_hash)
@installer.send(:run_plugins_post_install_hooks)
end
it 'raises if a podfile-specified plugin is not loaded' do
@installer.podfile.stubs(:plugins).returns('cocoapods-keys' => {})
Command::PluginManager.stubs(:specifications).returns([])
should.raise Informative do
@installer.send(:ensure_plugins_are_installed!)
end.message.should.match /require.*plugin.*`cocoapods-keys`/
end
it 'does not raise if all podfile-specified plugins are loaded' do
@installer.podfile.stubs(:plugins).returns('cocoapods-keys' => {})
spec = stub
spec.stubs(:name).returns('cocoapods-keys')
Command::PluginManager.stubs(:specifications).returns([spec])
should.not.raise do
@installer.send(:ensure_plugins_are_installed!)
end
end
end 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