Initial non-working
This commit is contained in:
1
.vagrant
Normal file
1
.vagrant
Normal file
@@ -0,0 +1 @@
|
||||
{"active":{"build":"b1db3058-5d8a-4211-a238-bbadc7486980","control_basevm":"ac323559-4a20-4bec-bea4-df8c51b84e82"}}
|
||||
1
01apt-cacher-ng-proxy
Normal file
1
01apt-cacher-ng-proxy
Normal file
@@ -0,0 +1 @@
|
||||
Acquire::http { Proxy "http://192.168.242.99:3142"; };
|
||||
3
Gemfile
Normal file
3
Gemfile
Normal file
@@ -0,0 +1,3 @@
|
||||
source "https://rubygems.org"
|
||||
gem "vagrant", "~>1.0"
|
||||
gem " librarian-puppet-simple"
|
||||
105
Puppetfile
Normal file
105
Puppetfile
Normal file
@@ -0,0 +1,105 @@
|
||||
# the account where the Openstack modules should come from
|
||||
#
|
||||
# this file also accepts a few environment variables
|
||||
#
|
||||
git_protocol=ENV['git_protocol'] || 'git'
|
||||
|
||||
#
|
||||
# this modulefile has been configured to use two sets of repos.
|
||||
# The downstream repos that Cisco has forked, or the upstream repos
|
||||
# that they are derived from (and should be maintained in sync with)
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# this is just targeting the upstream stackforge modules
|
||||
# right now, and the logic for using downstream does not
|
||||
# work yet
|
||||
#
|
||||
|
||||
if ENV['repos_to_use'] == 'downstream'
|
||||
# this assumes downstream which is the Cisco branches
|
||||
branch_name = 'origin/grizzly'
|
||||
openstack_module_branch = branch_name
|
||||
openstack_module_account = 'CiscoSystems'
|
||||
else
|
||||
# use the upstream modules where they exist
|
||||
branch_name = 'origin/grizzly'
|
||||
openstack_module_branch = 'master'
|
||||
openstack_module_account = 'stackforge'
|
||||
end
|
||||
|
||||
base_url = "#{git_protocol}://github.com"
|
||||
|
||||
#
|
||||
# Installer Manifests
|
||||
#
|
||||
user_name = 'CiscoSystems'
|
||||
release = 'grizzly'
|
||||
manifest_branch = 'multi-node'
|
||||
mod 'manifests', :git => "#{base_url}/#{user_name}/#{release}-manifests", :ref => manifest_branch
|
||||
|
||||
#
|
||||
# the stackforge openstack modules
|
||||
#
|
||||
|
||||
openstack_repo_prefix = "#{base_url}/#{openstack_module_account}/puppet"
|
||||
|
||||
mod 'stackforge/openstack', :git => "#{openstack_repo_prefix}-openstack", :ref => openstack_module_branch
|
||||
# openstack core modules
|
||||
mod 'stackforge/cinder', :git => "#{openstack_repo_prefix}-cinder", :ref => openstack_module_branch
|
||||
mod 'stackforge/glance', :git => "#{openstack_repo_prefix}-glance", :ref => openstack_module_branch
|
||||
mod 'stackforge/keystone', :git => "#{openstack_repo_prefix}-keystone", :ref => openstack_module_branch
|
||||
mod 'stackforge/horizon', :git => "#{openstack_repo_prefix}-horizon", :ref => openstack_module_branch
|
||||
mod 'stackforge/nova', :git => "#{openstack_repo_prefix}-nova", :ref => openstack_module_branch
|
||||
mod 'stackforge/quantum', :git => "#{openstack_repo_prefix}-quantum", :ref => openstack_module_branch
|
||||
mod 'stackforge/swift', :git => "#{openstack_repo_prefix}-swift", :ref => openstack_module_branch
|
||||
|
||||
#
|
||||
# the rest of the modules just come straight from their respective Cisco branches at the moment.
|
||||
#
|
||||
|
||||
#
|
||||
# coe specific modules
|
||||
#
|
||||
mod 'CiscoSystems/coe', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-coe", :ref => 'origin/grizzly'
|
||||
mod 'CiscoSystems/openstack_admin', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-openstack_admin", :ref => 'origin/grizzly'
|
||||
|
||||
|
||||
# middleware modules
|
||||
mod 'CiscoSystems/apache', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-apache", :ref => branch_name
|
||||
mod 'CiscoSystems/memcached', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-memcached", :ref => branch_name
|
||||
#
|
||||
# I cannot remember if this is necessary
|
||||
#
|
||||
mod 'CiscoSystems/mysql', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-mysql", :ref => 'master'
|
||||
mod 'CiscoSystems/rabbitmq', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-rabbitmq", :ref => branch_name
|
||||
|
||||
# linux tools
|
||||
mod 'CiscoSystems/apt', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-apt", :ref => branch_name
|
||||
mod 'CiscoSystems/apt-cacher-ng', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-apt-cacher-ng", :ref => branch_name
|
||||
mod 'CiscoSystems/cobbler', :git => "#{git_protocol}://github.com/bodepd/puppet-cobbler", :ref => 'origin/fix_cobbler_sync_issue'
|
||||
mod 'CiscoSystems/collectd', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-collectd", :ref => branch_name
|
||||
mod 'CiscoSystems/corosync', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-corosync", :ref => branch_name
|
||||
mod 'CiscoSystems/dnsmasq', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-dnsmasq", :ref => branch_name
|
||||
mod 'CiscoSystems/drbd', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-drbd", :ref => branch_name
|
||||
mod 'CiscoSystems/graphite', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-graphite", :ref => branch_name
|
||||
mod 'CiscoSystems/monit', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-monit", :ref => branch_name
|
||||
mod 'CiscoSystems/naginator', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-naginator", :ref => branch_name
|
||||
mod 'CiscoSystems/ntp', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-ntp", :ref => branch_name
|
||||
mod 'CiscoSystems/pip', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-pip", :ref => branch_name
|
||||
mod 'CiscoSystems/puppet', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-puppet", :ref => branch_name
|
||||
mod 'CiscoSystems/rsync', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-rsync", :ref => branch_name
|
||||
mod 'CiscoSystems/sysctl', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-sysctl", :ref => branch_name
|
||||
mod 'CiscoSystems/vswitch', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-vswitch", :ref => branch_name
|
||||
mod 'CiscoSystems/xinetd', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-xinetd", :ref => branch_name
|
||||
mod 'CiscoSystems/network', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-network", :ref => branch_name
|
||||
mod 'CiscoSystems/filemapper', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-filemapper", :ref => branch_name
|
||||
mod 'CiscoSystems/boolean', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-boolean", :ref => branch_name
|
||||
#mod 'CiscoSystems/ssh', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-ssh", :ref => branch_name
|
||||
|
||||
# puppet utilities
|
||||
mod 'CiscoSystems/concat', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-concat", :ref => branch_name
|
||||
# need the latest changes here
|
||||
mod 'CiscoSystems/inifile', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-inifile", :ref => branch_name
|
||||
mod 'CiscoSystems/stdlib', :git => "#{git_protocol}://github.com/CiscoSystems/puppet-stdlib", :ref => branch_name
|
||||
69
README.md
Normal file
69
README.md
Normal file
@@ -0,0 +1,69 @@
|
||||
Grizzly-manifests
|
||||
================
|
||||
|
||||
Project for building out OpenStack COE.
|
||||
|
||||
## Installing dependencies
|
||||
|
||||
This setup requires that a few additional dependencies are installed:
|
||||
|
||||
* virtualbox
|
||||
* vagrant
|
||||
|
||||
## User instructions
|
||||
|
||||
git clone https://github.com/CiscoSystems/grizzly-manifests
|
||||
cp grizzly-manifests/* /etc/puppet/manifests
|
||||
|
||||
## Developer instructions
|
||||
|
||||
Developers should be started by installing the following simple utility:
|
||||
(I will eventually just have it bundled as a gem)
|
||||
|
||||
mkdir vendor
|
||||
export GEM_HOME=`pwd`/vendor
|
||||
gem install thor --no-ri --no-rdoc
|
||||
git clone git://github.com/bodepd/librarian-puppet-simple vendor/librarian-puppet-simple
|
||||
export PATH=`pwd`/vendor/librarian-puppet-simple/bin/:$PATH
|
||||
|
||||
Once this library is installed, you can run the following command from this project's
|
||||
root directory:
|
||||
|
||||
librarian-puppet install --verbose
|
||||
|
||||
Add the basebox
|
||||
|
||||
vagrant box add blank blank.box
|
||||
|
||||
This command will clone all required modules into the modules directory.
|
||||
|
||||
## Spinning up virtual machines with vagrant
|
||||
|
||||
Now that you have set up the puppet content, the next step is to build
|
||||
out your multi-node environment using vagrant.
|
||||
|
||||
First, deploy the apt-ng-cacher instance:
|
||||
|
||||
vagrant up cache
|
||||
|
||||
Next, bring up the build server:
|
||||
|
||||
vagrant up build
|
||||
|
||||
Now, bring up the blank boxes so that they can PXE boot against the master
|
||||
|
||||
vagrant up control
|
||||
|
||||
vagrant up compute
|
||||
|
||||
|
||||
Now, you have created a fully functional openstack environment, now have a look at some services:
|
||||
|
||||
* service dashboard: http://192.168.242.100/
|
||||
* horizon: http://192.168.242.10/ (username: admin, password: Cisco123)
|
||||
|
||||
Log into your controller at: ssh localadmin@192.168.242.10 (password ubuntu)
|
||||
|
||||
and run through the 'Deploy Your First VM' section of this document:
|
||||
|
||||
http://docwiki.cisco.com/wiki/OpenStack:Folsom-Multinode#Creating_a_build_server
|
||||
184
Vagrantfile
vendored
Normal file
184
Vagrantfile
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# Four networks:
|
||||
# 0 - VM host NAT
|
||||
# 1 - COE build/deploy
|
||||
# 2 - COE openstack internal
|
||||
# 3 - COE openstack external (public)
|
||||
|
||||
|
||||
def parse_vagrant_config(
|
||||
config_file=File.expand_path(File.join(File.dirname(__FILE__), 'config.yaml'))
|
||||
)
|
||||
require 'yaml'
|
||||
config = {
|
||||
'gui_mode' => false,
|
||||
'operatingsystem' => 'ubuntu',
|
||||
'verbose' => false,
|
||||
'update_repos' => true
|
||||
}
|
||||
if File.exists?(config_file)
|
||||
overrides = YAML.load_file(config_file)
|
||||
config.merge!(overrides)
|
||||
end
|
||||
config
|
||||
end
|
||||
|
||||
Vagrant::Config.run do |config|
|
||||
require 'fileutils'
|
||||
|
||||
if !File.symlink?("templates")
|
||||
File.symlink("./modules/manifests/templates", "./templates")
|
||||
end
|
||||
|
||||
if !File.symlink?("manifests")
|
||||
File.symlink("./modules/manifests/manifests", "./manifests")
|
||||
end
|
||||
|
||||
if !File.file?("./manifests/site.pp") && File.file?("./manifests/site.pp.example")
|
||||
FileUtils.mv("./manifests/site.pp.example", "./manifests/site.pp")
|
||||
end
|
||||
|
||||
v_config = parse_vagrant_config
|
||||
|
||||
apt_cache_proxy = 'Acquire::http { Proxy \"http://%s:3142\"; };' % v_config['apt_cache']
|
||||
|
||||
config.vm.define :cache do |cache_config|
|
||||
cache_config.vm.box = "precise64"
|
||||
cache_config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
|
||||
cache_config.vm.network :hostonly, "192.168.242.99"
|
||||
cache_config.vm.network :hostonly, "10.2.3.99"
|
||||
cache_config.vm.network :hostonly, "10.3.3.99"
|
||||
cache_config.vm.customize ['modifyvm', :id, '--name', 'cache']
|
||||
cache_config.vm.host_name = 'cache'
|
||||
cache_config.vm.provision :shell do |shell|
|
||||
shell.inline = "apt-get update; apt-get install apt-cacher-ng -y; cp /vagrant/01apt-cacher-ng-proxy /etc/apt/apt.conf.d; apt-get update;sysctl -w net.ipv4.ip_forward=1;"#iptables –A FORWARD –i eth0 –o eth2 –j ACCEPT;iptables –A FORWARD –i eth2 –o eth0 –j ACCEPT;iptables –t nat –A POSTROUTING –o eth0 –j MASQUERADE"
|
||||
end
|
||||
end
|
||||
|
||||
# Cobbler based "build" server
|
||||
config.vm.define :build do |build_config|
|
||||
build_config.vm.box = "precise64"
|
||||
build_config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
|
||||
build_config.vm.customize ["modifyvm", :id, "--name", 'build-server']
|
||||
build_config.vm.host_name = 'build-server'
|
||||
build_config.vm.network :hostonly, "192.168.242.100"
|
||||
build_config.vm.network :hostonly, "10.2.3.100"
|
||||
build_config.vm.customize ["modifyvm", :id, "--nicpromisc3", "allow-all"]
|
||||
build_config.vm.network :hostonly, "10.3.3.100"
|
||||
|
||||
# Use user-provided sources.list if available
|
||||
build_config.vm.provision :shell do |shell|
|
||||
shell.inline = 'if [ -f /vagrant/sources.list ]; then cp /vagrant/sources.list /etc/apt; fi;'
|
||||
end
|
||||
|
||||
# configure apt and basic packages needed for install
|
||||
build_config.vm.provision :shell do |shell|
|
||||
shell.inline = "cp /vagrant/dhclient.conf /etc/dhcp;echo \"%s\" > /etc/apt/apt.conf.d/01apt-cacher-ng-proxy; apt-get update; dhclient -r eth0 && dhclient eth0; apt-get install -y git vim puppet curl; cp /vagrant/templates/* /etc/puppet/templates" % apt_cache_proxy
|
||||
end
|
||||
|
||||
# pre-import the ubuntu image from an appropriate mirror
|
||||
build_config.vm.provision :shell do |shell|
|
||||
shell.inline = "if [ -f /vagrant/sources.list ]; then apt-get install -y cobbler; cobbler-ubuntu-import -m $(cat /vagrant/sources.list | grep deb | cut -d ' ' -f 2 | grep http | grep -v security | head -1) precise-x86_64; fi;"
|
||||
end
|
||||
|
||||
# now run puppet to install the build server
|
||||
build_config.vm.provision(:puppet, :pp_path => "/etc/puppet") do |puppet|
|
||||
puppet.manifests_path = 'manifests'
|
||||
puppet.manifest_file = "site.pp"
|
||||
puppet.module_path = 'modules'
|
||||
puppet.options = ['--verbose', '--trace', '--debug']
|
||||
end
|
||||
|
||||
# Configure puppet
|
||||
build_config.vm.provision :shell do |shell|
|
||||
shell.inline = 'if [ ! -h /etc/puppet/modules ]; then rmdir /etc/puppet/modules;ln -s /etc/puppet/modules-0 /etc/puppet/modules; fi;puppet plugin download --server build-server.domain.name;service apache2 restart'
|
||||
end
|
||||
|
||||
# enable ip forwarding and NAT so that the build server can act
|
||||
# as an external gateway for the quantum router.
|
||||
build_config.vm.provision :shell do |shell|
|
||||
shell.inline = "ip addr add 172.16.2.1/24 dev eth2; sysctl -w net.ipv4.ip_forward=1; iptables -A FORWARD -o eth0 -i eth1 -s 172.16.2.0/24 -m conntrack --ctstate NEW -j ACCEPT; iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT; iptables -t nat -F POSTROUTING; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE"
|
||||
end
|
||||
end
|
||||
|
||||
# Openstack control server
|
||||
config.vm.define :control_pxe do |control_config|
|
||||
control_config.vm.customize(['modifyvm', :id ,'--nicbootprio2','1'])
|
||||
control_config.vm.box = 'blank'
|
||||
control_config.vm.boot_mode = 'gui'
|
||||
control_config.ssh.port = 2727
|
||||
control_config.vm.network :hostonly, "192.168.242.10", :mac => "001122334455"
|
||||
control_config.vm.network :hostonly, "10.2.3.10"
|
||||
control_config.vm.network :hostonly, "10.3.3.10"
|
||||
end
|
||||
|
||||
config.vm.define :control_basevm do |control_config|
|
||||
node_name = "control-server-#{Time.now.strftime('%Y%m%d%m%s')}.domain.name"
|
||||
control_config.vm.box = "precise64"
|
||||
control_config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
|
||||
control_config.vm.customize ["modifyvm", :id, "--name", 'control-server']
|
||||
control_config.vm.customize ["modifyvm", :id, "--memory", 1024]
|
||||
control_config.vm.host_name = node_name
|
||||
# you cannot boot this at the same time as the control_pxe b/c they have the same ip address
|
||||
control_config.vm.network :hostonly, "192.168.242.10"
|
||||
control_config.vm.network :hostonly, "10.2.3.10"
|
||||
control_config.vm.customize ["modifyvm", :id, "--nicpromisc3", "allow-all"]
|
||||
control_config.vm.network :hostonly, "10.3.3.10"
|
||||
|
||||
# Use user-provided sources.list if available
|
||||
control_config.vm.provision :shell do |shell|
|
||||
shell.inline = 'if [ -f /vagrant/sources.list ]; then cp /vagrant/sources.list /etc/apt; fi;'
|
||||
end
|
||||
|
||||
control_config.vm.provision :shell do |shell|
|
||||
shell.inline = 'echo "192.168.242.100 build-server build-server.domain.name" >> /etc/hosts;echo \"%s\" > /etc/apt/apt.conf.d/01apt-cacher-ng-proxy; apt-get update;apt-get install ubuntu-cloud-keyring' % apt_cache_proxy
|
||||
end
|
||||
|
||||
control_config.vm.provision(:puppet_server) do |puppet|
|
||||
puppet.puppet_server = 'build-server.domain.name'
|
||||
puppet.options = ['-t', '--pluginsync', '--trace', "--certname #{node_name}"]
|
||||
end
|
||||
# TODO install from puppet
|
||||
end
|
||||
|
||||
# Openstack compute server
|
||||
config.vm.define :compute_pxe do |compute_config|
|
||||
compute_config.vm.customize(['modifyvm', :id ,'--nicbootprio2','1'])
|
||||
compute_config.vm.box = 'blank'
|
||||
compute_config.vm.boot_mode = 'gui'
|
||||
compute_config.ssh.port = 2728
|
||||
compute_config.vm.network :hostonly, "192.168.242.21", :mac => "001122334466"
|
||||
compute_config.vm.network :hostonly, "10.2.3.21"
|
||||
compute_config.vm.network :hostonly, "10.3.3.21"
|
||||
end
|
||||
|
||||
config.vm.define :compute_basevm do |compute_config|
|
||||
node_name = "compute-server02-#{Time.now.strftime('%Y%m%d%m%s')}.domain.name"
|
||||
compute_config.vm.box = "precise64"
|
||||
compute_config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
|
||||
compute_config.vm.customize ["modifyvm", :id, "--name", 'compute-server02']
|
||||
compute_config.vm.host_name = node_name
|
||||
compute_config.vm.customize ["modifyvm", :id, "--memory", 2512]
|
||||
compute_config.vm.network :hostonly, "192.168.242.21"
|
||||
compute_config.vm.network :hostonly, "10.2.3.21"
|
||||
compute_config.vm.network :hostonly, "10.3.3.21"
|
||||
|
||||
# Use user-provided sources.list if available
|
||||
compute_config.vm.provision :shell do |shell|
|
||||
shell.inline = 'if [ -f /vagrant/sources.list ]; then cp /vagrant/sources.list /etc/apt; fi;'
|
||||
end
|
||||
|
||||
compute_config.vm.provision :shell do |shell|
|
||||
shell.inline = 'echo "192.168.242.100 build-server build-server.domain.name" >> /etc/hosts;echo \"%s\" > /etc/apt/apt.conf.d/01apt-cacher-ng-proxy; apt-get update;apt-get install ubuntu-cloud-keyring' % apt_cache_proxy
|
||||
end
|
||||
|
||||
compute_config.vm.provision(:puppet_server) do |puppet|
|
||||
puppet.puppet_server = 'build-server.domain.name'
|
||||
puppet.options = ['-t', '--pluginsync', '--trace', "--certname #{node_name}"]
|
||||
end
|
||||
# TODO install from puppet
|
||||
end
|
||||
|
||||
end
|
||||
2
config.yaml
Normal file
2
config.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
apt_cache: '192.168.1.16'
|
||||
55
dhclient.conf
Normal file
55
dhclient.conf
Normal file
@@ -0,0 +1,55 @@
|
||||
# Configuration file for /sbin/dhclient, which is included in Debian's
|
||||
# dhcp3-client package.
|
||||
#
|
||||
# This is a sample configuration file for dhclient. See dhclient.conf's
|
||||
# man page for more information about the syntax of this file
|
||||
# and a more comprehensive list of the parameters understood by
|
||||
# dhclient.
|
||||
#
|
||||
# Normally, if the DHCP server provides reasonable information and does
|
||||
# not leave anything out (like the domain name, for example), then
|
||||
# few changes must be made to this file, if any.
|
||||
#
|
||||
|
||||
option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
|
||||
|
||||
send host-name "<hostname>";
|
||||
#send dhcp-client-identifier 1:0:a0:24:ab:fb:9c;
|
||||
#send dhcp-lease-time 3600;
|
||||
supersede domain-name "domain.name";
|
||||
#prepend domain-name-servers 127.0.0.1;
|
||||
request subnet-mask, broadcast-address, time-offset, routers,
|
||||
domain-name-servers, host-name,
|
||||
netbios-name-servers, netbios-scope, interface-mtu,
|
||||
rfc3442-classless-static-routes, ntp-servers,
|
||||
dhcp6.domain-search, dhcp6.fqdn,
|
||||
dhcp6.name-servers, dhcp6.sntp-servers;
|
||||
#require subnet-mask, domain-name-servers;
|
||||
#timeout 60;
|
||||
#retry 60;
|
||||
#reboot 10;
|
||||
#select-timeout 5;
|
||||
#initial-interval 2;
|
||||
#script "/etc/dhcp3/dhclient-script";
|
||||
#media "-link0 -link1 -link2", "link0 link1";
|
||||
#reject 192.33.137.209;
|
||||
|
||||
#alias {
|
||||
# interface "eth0";
|
||||
# fixed-address 192.5.5.213;
|
||||
# option subnet-mask 255.255.255.255;
|
||||
#}
|
||||
|
||||
#lease {
|
||||
# interface "eth0";
|
||||
# fixed-address 192.33.137.200;
|
||||
# medium "link0 link1";
|
||||
# option host-name "andare.swiftmedia.com";
|
||||
# option subnet-mask 255.255.255.0;
|
||||
# option broadcast-address 192.33.137.255;
|
||||
# option routers 192.33.137.250;
|
||||
# option domain-name-servers 127.0.0.1;
|
||||
# renew 2 2000/1/12 00:00:01;
|
||||
# rebind 2 2000/1/12 00:00:01;
|
||||
# expire 2 2000/1/12 00:00:01;
|
||||
#}
|
||||
130
install_os_puppet
Executable file
130
install_os_puppet
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/bin/bash
|
||||
# install_os_puppet by Cisco Systems, Inc. is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
||||
#
|
||||
# This script runs the basic steps for preparing to auto-deploy OpenStack as per the Cisco Edition process
|
||||
# The manual steps are documented at http://docwiki.cisco.com/wiki/OpenStack:Folsom
|
||||
#
|
||||
# This script: updates apt, and makes sure that the system is up to date with the current Ubuntu baseline
|
||||
# It then downloads the current set of Cisco validated puppet modules and a set of baseline manifests from the
|
||||
# Cisco github repository
|
||||
# If a proxy is necessary in order to download files from the internet, then either a proxy target can be passed
|
||||
# to the script, or the environmet variables can be pre-set before running the script locally.
|
||||
#
|
||||
|
||||
|
||||
set -o errexit
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
usage: $0 options
|
||||
|
||||
OPTIONS:
|
||||
-h Show this message
|
||||
-p http proxy i.e. -p http://username:password@host:port/
|
||||
EOF
|
||||
}
|
||||
|
||||
# wrapper all commands with sudo in case this is not run as root
|
||||
# also map in a proxy in case it was passed as a command line argument
|
||||
function run_cmd () {
|
||||
if [ -z "$PROXY" ]; then
|
||||
sudo $*
|
||||
else
|
||||
sudo env http_proxy=$PROXY https_proxy=$PROXY $*
|
||||
fi
|
||||
}
|
||||
|
||||
# Define some useful APT parameters to make sure you get the latest versions of code
|
||||
|
||||
APT_CONFIG="-o Acquire::http::No-Cache=True -o Acquire::BrokenProxy=true -o Acquire::Retries=3"
|
||||
|
||||
# check if the environment is set up for http and https proxies
|
||||
if [ -n "$http_proxy" ]; then
|
||||
if [ -z "$https_proxy" ]; then
|
||||
echo "Please set https_proxy env variable."
|
||||
exit 1
|
||||
fi
|
||||
PROXY=$http_proxy
|
||||
fi
|
||||
|
||||
# parse CLI options
|
||||
while getopts "h:p:" OPTION
|
||||
do
|
||||
case $OPTION in
|
||||
h)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
p)
|
||||
PROXY=$OPTARG
|
||||
export http_proxy=$PROXY
|
||||
export https_proxy=$PROXY
|
||||
esac
|
||||
done
|
||||
|
||||
# Make sure the apt repository list is up to date
|
||||
echo -e "\n\nUpdate apt repository...\n\n"
|
||||
if ! run_cmd apt-get $APT_CONFIG update; then
|
||||
echo "Can't update apt repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install prerequisite packages
|
||||
echo "Installing prerequisite apps: git, puppet, ipmitool, python-software-properties.."
|
||||
if ! run_cmd apt-get $APT_CONFIG install -qym git puppet ipmitool python-software-properties; then
|
||||
echo "Can't install prerequisites!..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Grab the Cisco puppet global manifests (site.pp, etc.), try to update a previously downloaded set first
|
||||
echo "Cloning grizzly-manifests multi-node repository branch from github.com..."
|
||||
if [ -d /root/cisco-grizzly-manifests ] ; then
|
||||
echo -e "Looks like perhaps you ran this script before? We'll try to update your os-docs directory, just in case..."
|
||||
if ! run_cmd git --git-dir=/root/cisco-grizzly-manifests/.git/ pull ; then
|
||||
echo "That did not work. Perhaps rename your os-docs directory, and try again?"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get a new set, as there was no previous download
|
||||
if [ ! -d /root/cisco-grizzly-manifests ] ; then
|
||||
if ! run_cmd git clone -b multi-node https://github.com/CiscoSystems/grizzly-manifests /root/cisco-grizzly-manifests ; then
|
||||
echo "Can't run git clone!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Copying manifests examples to manifest dir..."
|
||||
if ! run_cmd cp /root/cisco-grizzly-manifests/manifests/* /etc/puppet/manifests/ ;then
|
||||
echo "Can't copy sample manifests!!!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Update APT again, to capture any changes and updates driven by the newly loaded code
|
||||
echo -e "\n\nUpdated apt repository...\n\n"
|
||||
if ! run_cmd apt-get $APT_CONFIG update; then
|
||||
echo "Can't update apt repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure the distro is up to date
|
||||
echo -e "\n\nUpdate packages...\n\n"
|
||||
if ! run_cmd apt-get $APT_CONFIG dist-upgrade -y; then
|
||||
echo "Can't update packages"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Change to the manifests directory, as the puppet-modules.sh script expects to find a file in the local
|
||||
# directory that lists the modules to download
|
||||
cd /etc/puppet/manifests
|
||||
|
||||
# Load the lateast modules.
|
||||
echo -e "\n\nInstalling Cisco Validated puppet openstack modules...\n\n"
|
||||
if ! run_cmd sh puppet-modules.sh ; then
|
||||
echo "Can't install puppet modules..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n\nSUCCESS!!!!\n\n Now, go edit your site.pp file in /etc/puppet/manifests, and then run 'puppet apply -v /etc/puppet/manifests/site.pp"
|
||||
|
||||
exit 0
|
||||
1
modules/apache
Submodule
1
modules/apache
Submodule
Submodule modules/apache added at cf880ad942
1
modules/apt
Submodule
1
modules/apt
Submodule
Submodule modules/apt added at 07da427488
1
modules/apt-cacher-ng
Submodule
1
modules/apt-cacher-ng
Submodule
Submodule modules/apt-cacher-ng added at 4f97174880
1
modules/boolean
Submodule
1
modules/boolean
Submodule
Submodule modules/boolean added at 3084373e8d
1
modules/cinder
Submodule
1
modules/cinder
Submodule
Submodule modules/cinder added at 9686bb830b
1
modules/cobbler
Submodule
1
modules/cobbler
Submodule
Submodule modules/cobbler added at b128cf87f0
1
modules/coe
Submodule
1
modules/coe
Submodule
Submodule modules/coe added at e79e5bc96b
1
modules/collectd
Submodule
1
modules/collectd
Submodule
Submodule modules/collectd added at e9746ad5b8
1
modules/concat
Submodule
1
modules/concat
Submodule
Submodule modules/concat added at 031bf26128
1
modules/corosync
Submodule
1
modules/corosync
Submodule
Submodule modules/corosync added at 33b46ee789
1
modules/dnsmasq
Submodule
1
modules/dnsmasq
Submodule
Submodule modules/dnsmasq added at fa08eff8ca
1
modules/drbd
Submodule
1
modules/drbd
Submodule
Submodule modules/drbd added at 902dc3ea43
1
modules/filemapper
Submodule
1
modules/filemapper
Submodule
Submodule modules/filemapper added at a7fce7c520
1
modules/glance
Submodule
1
modules/glance
Submodule
Submodule modules/glance added at 94f25c83da
1
modules/graphite
Submodule
1
modules/graphite
Submodule
Submodule modules/graphite added at 8fae5e124f
1
modules/horizon
Submodule
1
modules/horizon
Submodule
Submodule modules/horizon added at 12d0a244cc
1
modules/inifile
Submodule
1
modules/inifile
Submodule
Submodule modules/inifile added at 6c6f9a4fa8
1
modules/keystone
Submodule
1
modules/keystone
Submodule
Submodule modules/keystone added at 594f4e94e7
1
modules/manifests
Submodule
1
modules/manifests
Submodule
Submodule modules/manifests added at 4e642c377d
1
modules/memcached
Submodule
1
modules/memcached
Submodule
Submodule modules/memcached added at 03f99c2b69
1
modules/monit
Submodule
1
modules/monit
Submodule
Submodule modules/monit added at 58bba3de31
1
modules/mysql
Submodule
1
modules/mysql
Submodule
Submodule modules/mysql added at 10c369e331
1
modules/naginator
Submodule
1
modules/naginator
Submodule
Submodule modules/naginator added at 12163dc7eb
1
modules/network
Submodule
1
modules/network
Submodule
Submodule modules/network added at e9d5528db5
1
modules/nova
Submodule
1
modules/nova
Submodule
Submodule modules/nova added at 8487b41c21
1
modules/ntp
Submodule
1
modules/ntp
Submodule
Submodule modules/ntp added at b1b3132f84
1
modules/openstack
Submodule
1
modules/openstack
Submodule
Submodule modules/openstack added at aed432f502
1
modules/openstack_admin
Submodule
1
modules/openstack_admin
Submodule
Submodule modules/openstack_admin added at 9471eb84ed
1
modules/pip
Submodule
1
modules/pip
Submodule
Submodule modules/pip added at a3a4f851e3
1
modules/puppet
Submodule
1
modules/puppet
Submodule
Submodule modules/puppet added at 70905fd780
1
modules/quantum
Submodule
1
modules/quantum
Submodule
Submodule modules/quantum added at c91a1ec310
1
modules/rabbitmq
Submodule
1
modules/rabbitmq
Submodule
Submodule modules/rabbitmq added at 4fcb71991f
1
modules/rsync
Submodule
1
modules/rsync
Submodule
Submodule modules/rsync added at 5c866fc8ca
1
modules/stdlib
Submodule
1
modules/stdlib
Submodule
Submodule modules/stdlib added at 96e19d05f3
1
modules/swift
Submodule
1
modules/swift
Submodule
Submodule modules/swift added at 4c990fd894
1
modules/sysctl
Submodule
1
modules/sysctl
Submodule
Submodule modules/sysctl added at 7e20e7f050
1
modules/vswitch
Submodule
1
modules/vswitch
Submodule
Submodule modules/vswitch added at cf31f73cb4
1
modules/xinetd
Submodule
1
modules/xinetd
Submodule
Submodule modules/xinetd added at 452ddd9af8
61
sources.list
Normal file
61
sources.list
Normal file
@@ -0,0 +1,61 @@
|
||||
# deb http://au.archive.ubuntu.com/ubuntu/ precise main restricted
|
||||
|
||||
# deb http://au.archive.ubuntu.com/ubuntu/ precise-updates main restricted
|
||||
# deb http://security.ubuntu.com/ubuntu precise-security main restricted
|
||||
|
||||
# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
|
||||
# newer versions of the distribution.
|
||||
deb http://au.archive.ubuntu.com/ubuntu/ precise main restricted
|
||||
deb-src http://au.archive.ubuntu.com/ubuntu/ precise main restricted
|
||||
|
||||
## Major bug fix updates produced after the final release of the
|
||||
## distribution.
|
||||
deb http://au.archive.ubuntu.com/ubuntu/ precise-updates main restricted
|
||||
deb-src http://au.archive.ubuntu.com/ubuntu/ precise-updates main restricted
|
||||
|
||||
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
|
||||
## team. Also, please note that software in universe WILL NOT receive any
|
||||
## review or updates from the Ubuntu security team.
|
||||
deb http://au.archive.ubuntu.com/ubuntu/ precise universe
|
||||
deb-src http://au.archive.ubuntu.com/ubuntu/ precise universe
|
||||
deb http://au.archive.ubuntu.com/ubuntu/ precise-updates universe
|
||||
deb-src http://au.archive.ubuntu.com/ubuntu/ precise-updates universe
|
||||
|
||||
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
|
||||
## team, and may not be under a free licence. Please satisfy yourself as to
|
||||
## your rights to use the software. Also, please note that software in
|
||||
## multiverse WILL NOT receive any review or updates from the Ubuntu
|
||||
## security team.
|
||||
deb http://au.archive.ubuntu.com/ubuntu/ precise multiverse
|
||||
deb-src http://au.archive.ubuntu.com/ubuntu/ precise multiverse
|
||||
deb http://au.archive.ubuntu.com/ubuntu/ precise-updates multiverse
|
||||
deb-src http://au.archive.ubuntu.com/ubuntu/ precise-updates multiverse
|
||||
|
||||
## N.B. software from this repository may not have been tested as
|
||||
## extensively as that contained in the main release, although it includes
|
||||
## newer versions of some applications which may provide useful features.
|
||||
## Also, please note that software in backports WILL NOT receive any review
|
||||
## or updates from the Ubuntu security team.
|
||||
deb http://au.archive.ubuntu.com/ubuntu/ precise-backports main restricted universe multiverse
|
||||
deb-src http://au.archive.ubuntu.com/ubuntu/ precise-backports main restricted universe multiverse
|
||||
|
||||
deb http://security.ubuntu.com/ubuntu precise-security main restricted
|
||||
deb-src http://security.ubuntu.com/ubuntu precise-security main restricted
|
||||
deb http://security.ubuntu.com/ubuntu precise-security universe
|
||||
deb-src http://security.ubuntu.com/ubuntu precise-security universe
|
||||
deb http://security.ubuntu.com/ubuntu precise-security multiverse
|
||||
deb-src http://security.ubuntu.com/ubuntu precise-security multiverse
|
||||
|
||||
## Uncomment the following two lines to add software from Canonical's
|
||||
## 'partner' repository.
|
||||
## This software is not part of Ubuntu, but is offered by Canonical and the
|
||||
## respective vendors as a service to Ubuntu users.
|
||||
# deb http://archive.canonical.com/ubuntu precise partner
|
||||
# deb-src http://archive.canonical.com/ubuntu precise partner
|
||||
|
||||
## Uncomment the following two lines to add software from Ubuntu's
|
||||
## 'extras' repository.
|
||||
## This software is not part of Ubuntu, but is offered by third-party
|
||||
## developers who want to ship their latest software.
|
||||
# deb http://extras.ubuntu.com/ubuntu precise main
|
||||
# deb-src http://extras.ubuntu.com/ubuntu precise main
|
||||
19
vendor/bin/thor
vendored
Executable file
19
vendor/bin/thor
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
|
||||
#
|
||||
# This file was generated by RubyGems.
|
||||
#
|
||||
# The application 'thor' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require 'rubygems'
|
||||
|
||||
version = ">= 0"
|
||||
|
||||
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
|
||||
version = $1
|
||||
ARGV.shift
|
||||
end
|
||||
|
||||
gem 'thor', version
|
||||
load Gem.bin_path('thor', 'thor', version)
|
||||
BIN
vendor/cache/thor-0.18.1.gem
vendored
Normal file
BIN
vendor/cache/thor-0.18.1.gem
vendored
Normal file
Binary file not shown.
5
vendor/gems/thor-0.18.1/.document
vendored
Normal file
5
vendor/gems/thor-0.18.1/.document
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
lib/*.rb
|
||||
lib/**/*.rb
|
||||
-
|
||||
CHANGELOG.rdoc
|
||||
LICENSE.md
|
||||
139
vendor/gems/thor-0.18.1/CHANGELOG.md
vendored
Normal file
139
vendor/gems/thor-0.18.1/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
## 0.18.1, release 2013-03-30
|
||||
* Revert regressions found in 0.18.0
|
||||
|
||||
## 0.18.0, release 2013-03-26
|
||||
* Remove rake2thor
|
||||
* Only display colors if output medium supports colors
|
||||
* Pass parent_options to subcommands
|
||||
* Fix non-dash-prefixed aliases
|
||||
* Make error messages more helpful
|
||||
* Rename "task" to "command"
|
||||
* Add the method to allow for custom package name
|
||||
|
||||
## 0.17.0, release 2013-01-24
|
||||
* Add better support for tasks that accept arbitrary additional arguments (e.g. things like `bundle exec`)
|
||||
* Add #stop_on_unknown_option!
|
||||
* Only strip from stdin.gets if it wasn't ended with EOF
|
||||
* Allow "send" as a task name
|
||||
* Allow passing options as arguments after "--"
|
||||
* Autoload Thor::Group
|
||||
|
||||
## 0.16.0, release 2012-08-14
|
||||
* Add enum to string arguments
|
||||
|
||||
## 0.15.4, release 2012-06-29
|
||||
* Fix regression when destination root contains reserved regexp characters
|
||||
|
||||
## 0.15.3, release 2012-06-18
|
||||
* Support strict_args_position! for backwards compatibility
|
||||
* Escape Dir glob characters in paths
|
||||
|
||||
## 0.15.2, released 2012-05-07
|
||||
* Added print_in_columns
|
||||
* Exposed terminal_width as a public API
|
||||
|
||||
## 0.15.1, release 2012-05-06
|
||||
* Fix Ruby 1.8 truncation bug with unicode chars
|
||||
* Fix shell delegate methods to pass their block
|
||||
* Don't output trailing spaces when printing the last column in a table
|
||||
|
||||
## 0.15, released 2012-04-29
|
||||
* Alias method_options to options
|
||||
* Refactor say to allow multiple colors
|
||||
* Exposed error as a public API
|
||||
* Exposed file_collision as a public API
|
||||
* Exposed print_wrapped as a public API
|
||||
* Exposed set_color as a public API
|
||||
* Fix number-formatting bugs in print_table
|
||||
* Fix "indent" typo in print_table
|
||||
* Fix Errno::EPIPE when piping tasks to `head`
|
||||
* More friendly error messages
|
||||
|
||||
## 0.14, released 2010-07-25
|
||||
* Added CreateLink class and #link_file method
|
||||
* Made Thor::Actions#run use system as default method for system calls
|
||||
* Allow use of private methods from superclass as tasks
|
||||
* Added mute(&block) method which allows to run block without any output
|
||||
* Removed config[:pretend]
|
||||
* Enabled underscores for command line switches
|
||||
* Added Thor::Base.basename which is used by both Thor.banner and Thor::Group.banner
|
||||
* Deprecated invoke() without arguments
|
||||
* Added :only and :except to check_unknown_options
|
||||
|
||||
## 0.13, released 2010-02-03
|
||||
* Added :lazy_default which is only triggered if a switch is given
|
||||
* Added Thor::Shell::HTML
|
||||
* Added subcommands
|
||||
* Decoupled Thor::Group and Thor, so it's easier to vendor
|
||||
* Added check_unknown_options! in case you want error messages to be raised in valid switches
|
||||
* run(command) should return the results of command
|
||||
|
||||
## 0.12, released 2010-01-02
|
||||
* Methods generated by attr_* are automatically not marked as tasks
|
||||
* inject_into_file does not add the same content twice, unless :force is set
|
||||
* Removed rr in favor to rspec mock framework
|
||||
* Improved output for thor -T
|
||||
* [#7] Do not force white color on status
|
||||
* [#8] Yield a block with the filename on directory
|
||||
|
||||
## 0.11, released 2009-07-01
|
||||
* Added a rake compatibility layer. It allows you to use spec and rdoc tasks on
|
||||
Thor classes.
|
||||
* BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
|
||||
since it may cause wrong behavior in the invocation system.
|
||||
* thor help now show information about any class/task. All those calls are
|
||||
possible:
|
||||
|
||||
thor help describe
|
||||
thor help describe:amazing
|
||||
Or even with default namespaces:
|
||||
|
||||
thor help :spec
|
||||
* Thor::Runner now invokes the default task if none is supplied:
|
||||
|
||||
thor describe # invokes the default task, usually help
|
||||
* Thor::Runner now works with mappings:
|
||||
|
||||
thor describe -h
|
||||
* Added some documentation and code refactoring.
|
||||
|
||||
## 0.9.8, released 2008-10-20
|
||||
* Fixed some tiny issues that were introduced lately.
|
||||
|
||||
## 0.9.7, released 2008-10-13
|
||||
* Setting global method options on the initialize method works as expected:
|
||||
All other tasks will accept these global options in addition to their own.
|
||||
* Added 'group' notion to Thor task sets (class Thor); by default all tasks
|
||||
are in the 'standard' group. Running 'thor -T' will only show the standard
|
||||
tasks - adding --all will show all tasks. You can also filter on a specific
|
||||
group using the --group option: thor -T --group advanced
|
||||
|
||||
## 0.9.6, released 2008-09-13
|
||||
* Generic improvements
|
||||
|
||||
## 0.9.5, released 2008-08-27
|
||||
* Improve Windows compatibility
|
||||
* Update (incorrect) README and task.thor sample file
|
||||
* Options hash is now frozen (once returned)
|
||||
* Allow magic predicates on options object. For instance: `options.force?`
|
||||
* Add support for :numeric type
|
||||
* BACKWARDS INCOMPATIBLE: Refactor Thor::Options. You cannot access shorthand forms in options hash anymore (for instance, options[:f])
|
||||
* Allow specifying optional args with default values: method_options(:user => "mislav")
|
||||
* Don't write options for nil or false values. This allows, for example, turning color off when running specs.
|
||||
* Exit with the status of the spec command to help CI stuff out some.
|
||||
|
||||
## 0.9.4, released 2008-08-13
|
||||
* Try to add Windows compatibility.
|
||||
* BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore
|
||||
* Allow options at the beginning of the argument list as well as the end.
|
||||
* Make options available with symbol keys in addition to string keys.
|
||||
* Allow true to be passed to Thor#method_options to denote a boolean option.
|
||||
* If loading a thor file fails, don't give up, just print a warning and keep going.
|
||||
* Make sure that we re-raise errors if they happened further down the pipe than we care about.
|
||||
* Only delete the old file on updating when the installation of the new one is a success
|
||||
* Make it Ruby 1.8.5 compatible.
|
||||
* Don't raise an error if a boolean switch is defined multiple times.
|
||||
* Thor::Options now doesn't parse through things that look like options but aren't.
|
||||
* Add URI detection to install task, and make sure we don't append ".thor" to URIs
|
||||
* Add rake2thor to the gem binfiles.
|
||||
* Make sure local Thorfiles override system-wide ones.
|
||||
20
vendor/gems/thor-0.18.1/LICENSE.md
vendored
Normal file
20
vendor/gems/thor-0.18.1/LICENSE.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2008 Yehuda Katz, Eric Hodel, et al.
|
||||
|
||||
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.
|
||||
35
vendor/gems/thor-0.18.1/README.md
vendored
Normal file
35
vendor/gems/thor-0.18.1/README.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
[](https://rubygems.org/gems/thor)
|
||||
[](http://travis-ci.org/wycats/thor)
|
||||
[](https://gemnasium.com/wycats/thor)
|
||||
[](https://codeclimate.com/github/wycats/thor)
|
||||
[](https://coveralls.io/r/wycats/thor)
|
||||
|
||||
Thor
|
||||
====
|
||||
|
||||
Description
|
||||
-----------
|
||||
Thor is a simple and efficient tool for building self-documenting command line
|
||||
utilities. It removes the pain of parsing command line options, writing
|
||||
"USAGE:" banners, and can also be used as an alternative to the [Rake][rake]
|
||||
build tool. The syntax is Rake-like, so it should be familiar to most Rake
|
||||
users.
|
||||
|
||||
[rake]: https://github.com/jimweirich/rake
|
||||
|
||||
Installation
|
||||
------------
|
||||
gem install thor
|
||||
|
||||
Usage and documentation
|
||||
-----------------------
|
||||
Please see the [wiki][] for basic usage and other documentation on using Thor. You can also checkout the [official homepage][homepage].
|
||||
|
||||
[wiki]: https://github.com/wycats/thor/wiki
|
||||
[homepage]: http://whatisthor.com/
|
||||
|
||||
License
|
||||
-------
|
||||
Released under the MIT License. See the [LICENSE][] file for further details.
|
||||
|
||||
[license]: LICENSE.md
|
||||
30
vendor/gems/thor-0.18.1/Thorfile
vendored
Normal file
30
vendor/gems/thor-0.18.1/Thorfile
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# encoding: utf-8
|
||||
$:.unshift File.expand_path("../lib", __FILE__)
|
||||
|
||||
require 'bundler'
|
||||
require 'thor/rake_compat'
|
||||
|
||||
class Default < Thor
|
||||
include Thor::RakeCompat
|
||||
Bundler::GemHelper.install_tasks
|
||||
|
||||
desc "build", "Build thor-#{Thor::VERSION}.gem into the pkg directory"
|
||||
def build
|
||||
Rake::Task["build"].execute
|
||||
end
|
||||
|
||||
desc "install", "Build and install thor-#{Thor::VERSION}.gem into system gems"
|
||||
def install
|
||||
Rake::Task["install"].execute
|
||||
end
|
||||
|
||||
desc "release", "Create tag v#{Thor::VERSION} and build and push thor-#{Thor::VERSION}.gem to Rubygems"
|
||||
def release
|
||||
Rake::Task["release"].execute
|
||||
end
|
||||
|
||||
desc "spec", "Run RSpec code examples"
|
||||
def spec
|
||||
exec "rspec --color --format=documentation spec"
|
||||
end
|
||||
end
|
||||
6
vendor/gems/thor-0.18.1/bin/thor
vendored
Executable file
6
vendor/gems/thor-0.18.1/bin/thor
vendored
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env ruby
|
||||
# -*- mode: ruby -*-
|
||||
|
||||
require 'thor/runner'
|
||||
$thor_runner = true
|
||||
Thor::Runner.start
|
||||
473
vendor/gems/thor-0.18.1/lib/thor.rb
vendored
Normal file
473
vendor/gems/thor-0.18.1/lib/thor.rb
vendored
Normal file
@@ -0,0 +1,473 @@
|
||||
require 'set'
|
||||
require 'thor/base'
|
||||
|
||||
class Thor
|
||||
class << self
|
||||
# Allows for custom "Command" package naming.
|
||||
#
|
||||
# === Parameters
|
||||
# name<String>
|
||||
# options<Hash>
|
||||
#
|
||||
def package_name(name, options={})
|
||||
@package_name = name.nil? || name == '' ? nil : name
|
||||
end
|
||||
|
||||
# Sets the default command when thor is executed without an explicit command to be called.
|
||||
#
|
||||
# ==== Parameters
|
||||
# meth<Symbol>:: name of the default command
|
||||
#
|
||||
def default_command(meth=nil)
|
||||
@default_command = case meth
|
||||
when :none
|
||||
'help'
|
||||
when nil
|
||||
@default_command || from_superclass(:default_command, 'help')
|
||||
else
|
||||
meth.to_s
|
||||
end
|
||||
end
|
||||
alias default_task default_command
|
||||
|
||||
# Registers another Thor subclass as a command.
|
||||
#
|
||||
# ==== Parameters
|
||||
# klass<Class>:: Thor subclass to register
|
||||
# command<String>:: Subcommand name to use
|
||||
# usage<String>:: Short usage for the subcommand
|
||||
# description<String>:: Description for the subcommand
|
||||
def register(klass, subcommand_name, usage, description, options={})
|
||||
if klass <= Thor::Group
|
||||
desc usage, description, options
|
||||
define_method(subcommand_name) { |*args| invoke(klass, args) }
|
||||
else
|
||||
desc usage, description, options
|
||||
subcommand subcommand_name, klass
|
||||
end
|
||||
end
|
||||
|
||||
# Defines the usage and the description of the next command.
|
||||
#
|
||||
# ==== Parameters
|
||||
# usage<String>
|
||||
# description<String>
|
||||
# options<String>
|
||||
#
|
||||
def desc(usage, description, options={})
|
||||
if options[:for]
|
||||
command = find_and_refresh_command(options[:for])
|
||||
command.usage = usage if usage
|
||||
command.description = description if description
|
||||
else
|
||||
@usage, @desc, @hide = usage, description, options[:hide] || false
|
||||
end
|
||||
end
|
||||
|
||||
# Defines the long description of the next command.
|
||||
#
|
||||
# ==== Parameters
|
||||
# long description<String>
|
||||
#
|
||||
def long_desc(long_description, options={})
|
||||
if options[:for]
|
||||
command = find_and_refresh_command(options[:for])
|
||||
command.long_description = long_description if long_description
|
||||
else
|
||||
@long_desc = long_description
|
||||
end
|
||||
end
|
||||
|
||||
# Maps an input to a command. If you define:
|
||||
#
|
||||
# map "-T" => "list"
|
||||
#
|
||||
# Running:
|
||||
#
|
||||
# thor -T
|
||||
#
|
||||
# Will invoke the list command.
|
||||
#
|
||||
# ==== Parameters
|
||||
# Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
|
||||
#
|
||||
def map(mappings=nil)
|
||||
@map ||= from_superclass(:map, {})
|
||||
|
||||
if mappings
|
||||
mappings.each do |key, value|
|
||||
if key.respond_to?(:each)
|
||||
key.each {|subkey| @map[subkey] = value}
|
||||
else
|
||||
@map[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@map
|
||||
end
|
||||
|
||||
# Declares the options for the next command to be declared.
|
||||
#
|
||||
# ==== Parameters
|
||||
# Hash[Symbol => Object]:: The hash key is the name of the option and the value
|
||||
# is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
|
||||
# or :required (string). If you give a value, the type of the value is used.
|
||||
#
|
||||
def method_options(options=nil)
|
||||
@method_options ||= {}
|
||||
build_options(options, @method_options) if options
|
||||
@method_options
|
||||
end
|
||||
|
||||
alias options method_options
|
||||
|
||||
# Adds an option to the set of method options. If :for is given as option,
|
||||
# it allows you to change the options from a previous defined command.
|
||||
#
|
||||
# def previous_command
|
||||
# # magic
|
||||
# end
|
||||
#
|
||||
# method_option :foo => :bar, :for => :previous_command
|
||||
#
|
||||
# def next_command
|
||||
# # magic
|
||||
# end
|
||||
#
|
||||
# ==== Parameters
|
||||
# name<Symbol>:: The name of the argument.
|
||||
# options<Hash>:: Described below.
|
||||
#
|
||||
# ==== Options
|
||||
# :desc - Description for the argument.
|
||||
# :required - If the argument is required or not.
|
||||
# :default - Default value for this argument. It cannot be required and have default values.
|
||||
# :aliases - Aliases for this option.
|
||||
# :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
|
||||
# :banner - String to show on usage notes.
|
||||
# :hide - If you want to hide this option from the help.
|
||||
#
|
||||
def method_option(name, options={})
|
||||
scope = if options[:for]
|
||||
find_and_refresh_command(options[:for]).options
|
||||
else
|
||||
method_options
|
||||
end
|
||||
|
||||
build_option(name, options, scope)
|
||||
end
|
||||
alias option method_option
|
||||
|
||||
# Prints help information for the given command.
|
||||
#
|
||||
# ==== Parameters
|
||||
# shell<Thor::Shell>
|
||||
# command_name<String>
|
||||
#
|
||||
def command_help(shell, command_name)
|
||||
meth = normalize_command_name(command_name)
|
||||
command = all_commands[meth]
|
||||
handle_no_command_error(meth) unless command
|
||||
|
||||
shell.say "Usage:"
|
||||
shell.say " #{banner(command)}"
|
||||
shell.say
|
||||
class_options_help(shell, nil => command.options.map { |_, o| o })
|
||||
if command.long_description
|
||||
shell.say "Description:"
|
||||
shell.print_wrapped(command.long_description, :indent => 2)
|
||||
else
|
||||
shell.say command.description
|
||||
end
|
||||
end
|
||||
alias task_help command_help
|
||||
|
||||
# Prints help information for this class.
|
||||
#
|
||||
# ==== Parameters
|
||||
# shell<Thor::Shell>
|
||||
#
|
||||
def help(shell, subcommand = false)
|
||||
list = printable_commands(true, subcommand)
|
||||
Thor::Util.thor_classes_in(self).each do |klass|
|
||||
list += klass.printable_commands(false)
|
||||
end
|
||||
list.sort!{ |a,b| a[0] <=> b[0] }
|
||||
|
||||
if @package_name
|
||||
shell.say "#{@package_name} commands:"
|
||||
else
|
||||
shell.say "Commands:"
|
||||
end
|
||||
|
||||
shell.print_table(list, :indent => 2, :truncate => true)
|
||||
shell.say
|
||||
class_options_help(shell)
|
||||
end
|
||||
|
||||
# Returns commands ready to be printed.
|
||||
def printable_commands(all = true, subcommand = false)
|
||||
(all ? all_commands : commands).map do |_, command|
|
||||
next if command.hidden?
|
||||
item = []
|
||||
item << banner(command, false, subcommand)
|
||||
item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" : "")
|
||||
item
|
||||
end.compact
|
||||
end
|
||||
alias printable_tasks printable_commands
|
||||
|
||||
def subcommands
|
||||
@subcommands ||= from_superclass(:subcommands, [])
|
||||
end
|
||||
alias subtasks subcommands
|
||||
|
||||
def subcommand(subcommand, subcommand_class)
|
||||
self.subcommands << subcommand.to_s
|
||||
subcommand_class.subcommand_help subcommand
|
||||
|
||||
define_method(subcommand) do |*args|
|
||||
args, opts = Thor::Arguments.split(args)
|
||||
invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
|
||||
end
|
||||
end
|
||||
alias subtask subcommand
|
||||
|
||||
# Extend check unknown options to accept a hash of conditions.
|
||||
#
|
||||
# === Parameters
|
||||
# options<Hash>: A hash containing :only and/or :except keys
|
||||
def check_unknown_options!(options={})
|
||||
@check_unknown_options ||= Hash.new
|
||||
options.each do |key, value|
|
||||
if value
|
||||
@check_unknown_options[key] = Array(value)
|
||||
else
|
||||
@check_unknown_options.delete(key)
|
||||
end
|
||||
end
|
||||
@check_unknown_options
|
||||
end
|
||||
|
||||
# Overwrite check_unknown_options? to take subcommands and options into account.
|
||||
def check_unknown_options?(config) #:nodoc:
|
||||
options = check_unknown_options
|
||||
return false unless options
|
||||
|
||||
command = config[:current_command]
|
||||
return true unless command
|
||||
|
||||
name = command.name
|
||||
|
||||
if subcommands.include?(name)
|
||||
false
|
||||
elsif options[:except]
|
||||
!options[:except].include?(name.to_sym)
|
||||
elsif options[:only]
|
||||
options[:only].include?(name.to_sym)
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Stop parsing of options as soon as an unknown option or a regular
|
||||
# argument is encountered. All remaining arguments are passed to the command.
|
||||
# This is useful if you have a command that can receive arbitrary additional
|
||||
# options, and where those additional options should not be handled by
|
||||
# Thor.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# To better understand how this is useful, let's consider a command that calls
|
||||
# an external command. A user may want to pass arbitrary options and
|
||||
# arguments to that command. The command itself also accepts some options,
|
||||
# which should be handled by Thor.
|
||||
#
|
||||
# class_option "verbose", :type => :boolean
|
||||
# stop_on_unknown_option! :exec
|
||||
# check_unknown_options! :except => :exec
|
||||
#
|
||||
# desc "exec", "Run a shell command"
|
||||
# def exec(*args)
|
||||
# puts "diagnostic output" if options[:verbose]
|
||||
# Kernel.exec(*args)
|
||||
# end
|
||||
#
|
||||
# Here +exec+ can be called with +--verbose+ to get diagnostic output,
|
||||
# e.g.:
|
||||
#
|
||||
# $ thor exec --verbose echo foo
|
||||
# diagnostic output
|
||||
# foo
|
||||
#
|
||||
# But if +--verbose+ is given after +echo+, it is passed to +echo+ instead:
|
||||
#
|
||||
# $ thor exec echo --verbose foo
|
||||
# --verbose foo
|
||||
#
|
||||
# ==== Parameters
|
||||
# Symbol ...:: A list of commands that should be affected.
|
||||
def stop_on_unknown_option!(*command_names)
|
||||
@stop_on_unknown_option ||= Set.new
|
||||
@stop_on_unknown_option.merge(command_names)
|
||||
end
|
||||
|
||||
def stop_on_unknown_option?(command) #:nodoc:
|
||||
!!@stop_on_unknown_option && @stop_on_unknown_option.include?(command.name.to_sym)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# The method responsible for dispatching given the args.
|
||||
def dispatch(meth, given_args, given_opts, config) #:nodoc:
|
||||
# There is an edge case when dispatching from a subcommand.
|
||||
# A problem occurs invoking the default command. This case occurs
|
||||
# when arguments are passed and a default command is defined, and
|
||||
# the first given_args does not match the default command.
|
||||
# Thor use "help" by default so we skip that case.
|
||||
# Note the call to retrieve_command_name. It's called with
|
||||
# given_args.dup since that method calls args.shift. Then lookup
|
||||
# the command normally. If the first item in given_args is not
|
||||
# a command then use the default command. The given_args will be
|
||||
# intact later since dup was used.
|
||||
if config[:invoked_via_subcommand] && given_args.size >= 1 && default_command != "help" && given_args.first != default_command
|
||||
meth ||= retrieve_command_name(given_args.dup)
|
||||
command = all_commands[normalize_command_name(meth)]
|
||||
command ||= all_commands[normalize_command_name(default_command)]
|
||||
else
|
||||
meth ||= retrieve_command_name(given_args)
|
||||
command = all_commands[normalize_command_name(meth)]
|
||||
end
|
||||
|
||||
if command
|
||||
args, opts = Thor::Options.split(given_args)
|
||||
if stop_on_unknown_option?(command) && !args.empty?
|
||||
# given_args starts with a non-option, so we treat everything as
|
||||
# ordinary arguments
|
||||
args.concat opts
|
||||
opts.clear
|
||||
end
|
||||
else
|
||||
args, opts = given_args, nil
|
||||
command = Thor::DynamicCommand.new(meth)
|
||||
end
|
||||
|
||||
opts = given_opts || opts || []
|
||||
config.merge!(:current_command => command, :command_options => command.options)
|
||||
|
||||
instance = new(args, opts, config)
|
||||
yield instance if block_given?
|
||||
args = instance.args
|
||||
trailing = args[Range.new(arguments.size, -1)]
|
||||
instance.invoke_command(command, trailing || [])
|
||||
end
|
||||
|
||||
# The banner for this class. You can customize it if you are invoking the
|
||||
# thor class by another ways which is not the Thor::Runner. It receives
|
||||
# the command that is going to be invoked and a boolean which indicates if
|
||||
# the namespace should be displayed as arguments.
|
||||
#
|
||||
def banner(command, namespace = nil, subcommand = false)
|
||||
"#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}"
|
||||
end
|
||||
|
||||
def baseclass #:nodoc:
|
||||
Thor
|
||||
end
|
||||
|
||||
def create_command(meth) #:nodoc:
|
||||
if @usage && @desc
|
||||
base_class = @hide ? Thor::HiddenCommand : Thor::Command
|
||||
commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
|
||||
@usage, @desc, @long_desc, @method_options, @hide = nil
|
||||
true
|
||||
elsif self.all_commands[meth] || meth == "method_missing"
|
||||
true
|
||||
else
|
||||
puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " <<
|
||||
"Call desc if you want this method to be available as command or declare it inside a " <<
|
||||
"no_commands{} block. Invoked from #{caller[1].inspect}."
|
||||
false
|
||||
end
|
||||
end
|
||||
alias create_task create_command
|
||||
|
||||
def initialize_added #:nodoc:
|
||||
class_options.merge!(method_options)
|
||||
@method_options = nil
|
||||
end
|
||||
|
||||
# Retrieve the command name from given args.
|
||||
def retrieve_command_name(args) #:nodoc:
|
||||
meth = args.first.to_s unless args.empty?
|
||||
if meth && (map[meth] || meth !~ /^\-/)
|
||||
args.shift
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
alias retrieve_task_name retrieve_command_name
|
||||
|
||||
# receives a (possibly nil) command name and returns a name that is in
|
||||
# the commands hash. In addition to normalizing aliases, this logic
|
||||
# will determine if a shortened command is an unambiguous substring of
|
||||
# a command or alias.
|
||||
#
|
||||
# +normalize_command_name+ also converts names like +animal-prison+
|
||||
# into +animal_prison+.
|
||||
def normalize_command_name(meth) #:nodoc:
|
||||
return default_command.to_s.gsub('-', '_') unless meth
|
||||
|
||||
possibilities = find_command_possibilities(meth)
|
||||
if possibilities.size > 1
|
||||
raise ArgumentError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
|
||||
elsif possibilities.size < 1
|
||||
meth = meth || default_command
|
||||
elsif map[meth]
|
||||
meth = map[meth]
|
||||
else
|
||||
meth = possibilities.first
|
||||
end
|
||||
|
||||
meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
|
||||
end
|
||||
alias normalize_task_name normalize_command_name
|
||||
|
||||
# this is the logic that takes the command name passed in by the user
|
||||
# and determines whether it is an unambiguous substrings of a command or
|
||||
# alias name.
|
||||
def find_command_possibilities(meth)
|
||||
len = meth.to_s.length
|
||||
possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
|
||||
unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
|
||||
|
||||
if possibilities.include?(meth)
|
||||
[meth]
|
||||
elsif unique_possibilities.size == 1
|
||||
unique_possibilities
|
||||
else
|
||||
possibilities
|
||||
end
|
||||
end
|
||||
alias find_task_possibilities find_command_possibilities
|
||||
|
||||
def subcommand_help(cmd)
|
||||
desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
|
||||
class_eval <<-RUBY
|
||||
def help(command = nil, subcommand = true); super; end
|
||||
RUBY
|
||||
end
|
||||
alias subtask_help subcommand_help
|
||||
|
||||
end
|
||||
|
||||
include Thor::Base
|
||||
|
||||
map HELP_MAPPINGS => :help
|
||||
|
||||
desc "help [COMMAND]", "Describe available commands or one specific command"
|
||||
def help(command = nil, subcommand = false)
|
||||
command ? self.class.command_help(shell, command) : self.class.help(shell, subcommand)
|
||||
end
|
||||
end
|
||||
318
vendor/gems/thor-0.18.1/lib/thor/actions.rb
vendored
Normal file
318
vendor/gems/thor-0.18.1/lib/thor/actions.rb
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
require 'fileutils'
|
||||
require 'uri'
|
||||
require 'thor/core_ext/io_binary_read'
|
||||
require 'thor/actions/create_file'
|
||||
require 'thor/actions/create_link'
|
||||
require 'thor/actions/directory'
|
||||
require 'thor/actions/empty_directory'
|
||||
require 'thor/actions/file_manipulation'
|
||||
require 'thor/actions/inject_into_file'
|
||||
|
||||
class Thor
|
||||
module Actions
|
||||
attr_accessor :behavior
|
||||
|
||||
def self.included(base) #:nodoc:
|
||||
base.extend ClassMethods
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Hold source paths for one Thor instance. source_paths_for_search is the
|
||||
# method responsible to gather source_paths from this current class,
|
||||
# inherited paths and the source root.
|
||||
#
|
||||
def source_paths
|
||||
@_source_paths ||= []
|
||||
end
|
||||
|
||||
# Stores and return the source root for this class
|
||||
def source_root(path=nil)
|
||||
@_source_root = path if path
|
||||
@_source_root
|
||||
end
|
||||
|
||||
# Returns the source paths in the following order:
|
||||
#
|
||||
# 1) This class source paths
|
||||
# 2) Source root
|
||||
# 3) Parents source paths
|
||||
#
|
||||
def source_paths_for_search
|
||||
paths = []
|
||||
paths += self.source_paths
|
||||
paths << self.source_root if self.source_root
|
||||
paths += from_superclass(:source_paths, [])
|
||||
paths
|
||||
end
|
||||
|
||||
# Add runtime options that help actions execution.
|
||||
#
|
||||
def add_runtime_options!
|
||||
class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
|
||||
:desc => "Overwrite files that already exist"
|
||||
|
||||
class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
|
||||
:desc => "Run but do not make any changes"
|
||||
|
||||
class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
|
||||
:desc => "Suppress status output"
|
||||
|
||||
class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
|
||||
:desc => "Skip files that already exist"
|
||||
end
|
||||
end
|
||||
|
||||
# Extends initializer to add more configuration options.
|
||||
#
|
||||
# ==== Configuration
|
||||
# behavior<Symbol>:: The actions default behavior. Can be :invoke or :revoke.
|
||||
# It also accepts :force, :skip and :pretend to set the behavior
|
||||
# and the respective option.
|
||||
#
|
||||
# destination_root<String>:: The root directory needed for some actions.
|
||||
#
|
||||
def initialize(args=[], options={}, config={})
|
||||
self.behavior = case config[:behavior].to_s
|
||||
when "force", "skip"
|
||||
_cleanup_options_and_set(options, config[:behavior])
|
||||
:invoke
|
||||
when "revoke"
|
||||
:revoke
|
||||
else
|
||||
:invoke
|
||||
end
|
||||
|
||||
super
|
||||
self.destination_root = config[:destination_root]
|
||||
end
|
||||
|
||||
# Wraps an action object and call it accordingly to the thor class behavior.
|
||||
#
|
||||
def action(instance) #:nodoc:
|
||||
if behavior == :revoke
|
||||
instance.revoke!
|
||||
else
|
||||
instance.invoke!
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the root for this thor class (also aliased as destination root).
|
||||
#
|
||||
def destination_root
|
||||
@destination_stack.last
|
||||
end
|
||||
|
||||
# Sets the root for this thor class. Relatives path are added to the
|
||||
# directory where the script was invoked and expanded.
|
||||
#
|
||||
def destination_root=(root)
|
||||
@destination_stack ||= []
|
||||
@destination_stack[0] = File.expand_path(root || '')
|
||||
end
|
||||
|
||||
# Returns the given path relative to the absolute root (ie, root where
|
||||
# the script started).
|
||||
#
|
||||
def relative_to_original_destination_root(path, remove_dot=true)
|
||||
path = path.dup
|
||||
if path.gsub!(@destination_stack[0], '.')
|
||||
remove_dot ? (path[2..-1] || '') : path
|
||||
else
|
||||
path
|
||||
end
|
||||
end
|
||||
|
||||
# Holds source paths in instance so they can be manipulated.
|
||||
#
|
||||
def source_paths
|
||||
@source_paths ||= self.class.source_paths_for_search
|
||||
end
|
||||
|
||||
# Receives a file or directory and search for it in the source paths.
|
||||
#
|
||||
def find_in_source_paths(file)
|
||||
relative_root = relative_to_original_destination_root(destination_root, false)
|
||||
|
||||
source_paths.each do |source|
|
||||
source_file = File.expand_path(file, File.join(source, relative_root))
|
||||
return source_file if File.exists?(source_file)
|
||||
end
|
||||
|
||||
message = "Could not find #{file.inspect} in any of your source paths. "
|
||||
|
||||
unless self.class.source_root
|
||||
message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. "
|
||||
end
|
||||
|
||||
if source_paths.empty?
|
||||
message << "Currently you have no source paths."
|
||||
else
|
||||
message << "Your current source paths are: \n#{source_paths.join("\n")}"
|
||||
end
|
||||
|
||||
raise Error, message
|
||||
end
|
||||
|
||||
# Do something in the root or on a provided subfolder. If a relative path
|
||||
# is given it's referenced from the current root. The full path is yielded
|
||||
# to the block you provide. The path is set back to the previous path when
|
||||
# the method exits.
|
||||
#
|
||||
# ==== Parameters
|
||||
# dir<String>:: the directory to move to.
|
||||
# config<Hash>:: give :verbose => true to log and use padding.
|
||||
#
|
||||
def inside(dir='', config={}, &block)
|
||||
verbose = config.fetch(:verbose, false)
|
||||
pretend = options[:pretend]
|
||||
|
||||
say_status :inside, dir, verbose
|
||||
shell.padding += 1 if verbose
|
||||
@destination_stack.push File.expand_path(dir, destination_root)
|
||||
|
||||
# If the directory doesnt exist and we're not pretending
|
||||
if !File.exist?(destination_root) && !pretend
|
||||
FileUtils.mkdir_p(destination_root)
|
||||
end
|
||||
|
||||
if pretend
|
||||
# In pretend mode, just yield down to the block
|
||||
block.arity == 1 ? yield(destination_root) : yield
|
||||
else
|
||||
FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
|
||||
end
|
||||
|
||||
@destination_stack.pop
|
||||
shell.padding -= 1 if verbose
|
||||
end
|
||||
|
||||
# Goes to the root and execute the given block.
|
||||
#
|
||||
def in_root
|
||||
inside(@destination_stack.first) { yield }
|
||||
end
|
||||
|
||||
# Loads an external file and execute it in the instance binding.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String>:: The path to the file to execute. Can be a web address or
|
||||
# a relative path from the source root.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# apply "http://gist.github.com/103208"
|
||||
#
|
||||
# apply "recipes/jquery.rb"
|
||||
#
|
||||
def apply(path, config={})
|
||||
verbose = config.fetch(:verbose, true)
|
||||
is_uri = path =~ /^https?\:\/\//
|
||||
path = find_in_source_paths(path) unless is_uri
|
||||
|
||||
say_status :apply, path, verbose
|
||||
shell.padding += 1 if verbose
|
||||
|
||||
if is_uri
|
||||
contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read }
|
||||
else
|
||||
contents = open(path) {|io| io.read }
|
||||
end
|
||||
|
||||
instance_eval(contents, path)
|
||||
shell.padding -= 1 if verbose
|
||||
end
|
||||
|
||||
# Executes a command returning the contents of the command.
|
||||
#
|
||||
# ==== Parameters
|
||||
# command<String>:: the command to be executed.
|
||||
# config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with
|
||||
# to append an executable to command executation.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# inside('vendor') do
|
||||
# run('ln -s ~/edge rails')
|
||||
# end
|
||||
#
|
||||
def run(command, config={})
|
||||
return unless behavior == :invoke
|
||||
|
||||
destination = relative_to_original_destination_root(destination_root, false)
|
||||
desc = "#{command} from #{destination.inspect}"
|
||||
|
||||
if config[:with]
|
||||
desc = "#{File.basename(config[:with].to_s)} #{desc}"
|
||||
command = "#{config[:with]} #{command}"
|
||||
end
|
||||
|
||||
say_status :run, desc, config.fetch(:verbose, true)
|
||||
|
||||
unless options[:pretend]
|
||||
config[:capture] ? `#{command}` : system("#{command}")
|
||||
end
|
||||
end
|
||||
|
||||
# Executes a ruby script (taking into account WIN32 platform quirks).
|
||||
#
|
||||
# ==== Parameters
|
||||
# command<String>:: the command to be executed.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
def run_ruby_script(command, config={})
|
||||
return unless behavior == :invoke
|
||||
run command, config.merge(:with => Thor::Util.ruby_command)
|
||||
end
|
||||
|
||||
# Run a thor command. A hash of options can be given and it's converted to
|
||||
# switches.
|
||||
#
|
||||
# ==== Parameters
|
||||
# command<String>:: the command to be invoked
|
||||
# args<Array>:: arguments to the command
|
||||
# config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output.
|
||||
# Other options are given as parameter to Thor.
|
||||
#
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# thor :install, "http://gist.github.com/103208"
|
||||
# #=> thor install http://gist.github.com/103208
|
||||
#
|
||||
# thor :list, :all => true, :substring => 'rails'
|
||||
# #=> thor list --all --substring=rails
|
||||
#
|
||||
def thor(command, *args)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
verbose = config.key?(:verbose) ? config.delete(:verbose) : true
|
||||
pretend = config.key?(:pretend) ? config.delete(:pretend) : false
|
||||
capture = config.key?(:capture) ? config.delete(:capture) : false
|
||||
|
||||
args.unshift(command)
|
||||
args.push Thor::Options.to_switches(config)
|
||||
command = args.join(' ').strip
|
||||
|
||||
run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Allow current root to be shared between invocations.
|
||||
#
|
||||
def _shared_configuration #:nodoc:
|
||||
super.merge!(:destination_root => self.destination_root)
|
||||
end
|
||||
|
||||
def _cleanup_options_and_set(options, key) #:nodoc:
|
||||
case options
|
||||
when Array
|
||||
%w(--force -f --skip -s).each { |i| options.delete(i) }
|
||||
options << "--#{key}"
|
||||
when Hash
|
||||
[:force, :skip, "force", "skip"].each { |i| options.delete(i) }
|
||||
options.merge!(key => true)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
105
vendor/gems/thor-0.18.1/lib/thor/actions/create_file.rb
vendored
Normal file
105
vendor/gems/thor-0.18.1/lib/thor/actions/create_file.rb
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
require 'thor/actions/empty_directory'
|
||||
|
||||
class Thor
|
||||
module Actions
|
||||
|
||||
# Create a new file relative to the destination root with the given data,
|
||||
# which is the return value of a block or a data string.
|
||||
#
|
||||
# ==== Parameters
|
||||
# destination<String>:: the relative path to the destination root.
|
||||
# data<String|NilClass>:: the data to append to the file.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# create_file "lib/fun_party.rb" do
|
||||
# hostname = ask("What is the virtual hostname I should use?")
|
||||
# "vhost.name = #{hostname}"
|
||||
# end
|
||||
#
|
||||
# create_file "config/apache.conf", "your apache config"
|
||||
#
|
||||
def create_file(destination, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
data = args.first
|
||||
action CreateFile.new(self, destination, block || data.to_s, config)
|
||||
end
|
||||
alias :add_file :create_file
|
||||
|
||||
# CreateFile is a subset of Template, which instead of rendering a file with
|
||||
# ERB, it gets the content from the user.
|
||||
#
|
||||
class CreateFile < EmptyDirectory #:nodoc:
|
||||
attr_reader :data
|
||||
|
||||
def initialize(base, destination, data, config={})
|
||||
@data = data
|
||||
super(base, destination, config)
|
||||
end
|
||||
|
||||
# Checks if the content of the file at the destination is identical to the rendered result.
|
||||
#
|
||||
# ==== Returns
|
||||
# Boolean:: true if it is identical, false otherwise.
|
||||
#
|
||||
def identical?
|
||||
exists? && File.binread(destination) == render
|
||||
end
|
||||
|
||||
# Holds the content to be added to the file.
|
||||
#
|
||||
def render
|
||||
@render ||= if data.is_a?(Proc)
|
||||
data.call
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
def invoke!
|
||||
invoke_with_conflict_check do
|
||||
FileUtils.mkdir_p(File.dirname(destination))
|
||||
File.open(destination, 'wb') { |f| f.write render }
|
||||
end
|
||||
given_destination
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Now on conflict we check if the file is identical or not.
|
||||
#
|
||||
def on_conflict_behavior(&block)
|
||||
if identical?
|
||||
say_status :identical, :blue
|
||||
else
|
||||
options = base.options.merge(config)
|
||||
force_or_skip_or_conflict(options[:force], options[:skip], &block)
|
||||
end
|
||||
end
|
||||
|
||||
# If force is true, run the action, otherwise check if it's not being
|
||||
# skipped. If both are false, show the file_collision menu, if the menu
|
||||
# returns true, force it, otherwise skip.
|
||||
#
|
||||
def force_or_skip_or_conflict(force, skip, &block)
|
||||
if force
|
||||
say_status :force, :yellow
|
||||
block.call unless pretend?
|
||||
elsif skip
|
||||
say_status :skip, :yellow
|
||||
else
|
||||
say_status :conflict, :red
|
||||
force_or_skip_or_conflict(force_on_collision?, true, &block)
|
||||
end
|
||||
end
|
||||
|
||||
# Shows the file collision menu to the user and gets the result.
|
||||
#
|
||||
def force_on_collision?
|
||||
base.shell.file_collision(destination){ render }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
60
vendor/gems/thor-0.18.1/lib/thor/actions/create_link.rb
vendored
Normal file
60
vendor/gems/thor-0.18.1/lib/thor/actions/create_link.rb
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
require 'thor/actions/create_file'
|
||||
|
||||
class Thor
|
||||
module Actions
|
||||
|
||||
# Create a new file relative to the destination root from the given source.
|
||||
#
|
||||
# ==== Parameters
|
||||
# destination<String>:: the relative path to the destination root.
|
||||
# source<String|NilClass>:: the relative path to the source root.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
# :: give :symbolic => false for hard link.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# create_link "config/apache.conf", "/etc/apache.conf"
|
||||
#
|
||||
def create_link(destination, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
source = args.first
|
||||
action CreateLink.new(self, destination, source, config)
|
||||
end
|
||||
alias :add_link :create_link
|
||||
|
||||
# CreateLink is a subset of CreateFile, which instead of taking a block of
|
||||
# data, just takes a source string from the user.
|
||||
#
|
||||
class CreateLink < CreateFile #:nodoc:
|
||||
attr_reader :data
|
||||
|
||||
# Checks if the content of the file at the destination is identical to the rendered result.
|
||||
#
|
||||
# ==== Returns
|
||||
# Boolean:: true if it is identical, false otherwise.
|
||||
#
|
||||
def identical?
|
||||
exists? && File.identical?(render, destination)
|
||||
end
|
||||
|
||||
def invoke!
|
||||
invoke_with_conflict_check do
|
||||
FileUtils.mkdir_p(File.dirname(destination))
|
||||
# Create a symlink by default
|
||||
config[:symbolic] = true if config[:symbolic].nil?
|
||||
File.unlink(destination) if exists?
|
||||
if config[:symbolic]
|
||||
File.symlink(render, destination)
|
||||
else
|
||||
File.link(render, destination)
|
||||
end
|
||||
end
|
||||
given_destination
|
||||
end
|
||||
|
||||
def exists?
|
||||
super || File.symlink?(destination)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
119
vendor/gems/thor-0.18.1/lib/thor/actions/directory.rb
vendored
Normal file
119
vendor/gems/thor-0.18.1/lib/thor/actions/directory.rb
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
require 'thor/actions/empty_directory'
|
||||
|
||||
class Thor
|
||||
module Actions
|
||||
# Copies recursively the files from source directory to root directory.
|
||||
# If any of the files finishes with .tt, it's considered to be a template
|
||||
# and is placed in the destination without the extension .tt. If any
|
||||
# empty directory is found, it's copied and all .empty_directory files are
|
||||
# ignored. If any file name is wrapped within % signs, the text within
|
||||
# the % signs will be executed as a method and replaced with the returned
|
||||
# value. Let's suppose a doc directory with the following files:
|
||||
#
|
||||
# doc/
|
||||
# components/.empty_directory
|
||||
# README
|
||||
# rdoc.rb.tt
|
||||
# %app_name%.rb
|
||||
#
|
||||
# When invoked as:
|
||||
#
|
||||
# directory "doc"
|
||||
#
|
||||
# It will create a doc directory in the destination with the following
|
||||
# files (assuming that the `app_name` method returns the value "blog"):
|
||||
#
|
||||
# doc/
|
||||
# components/
|
||||
# README
|
||||
# rdoc.rb
|
||||
# blog.rb
|
||||
#
|
||||
# <b>Encoded path note:</b> Since Thor internals use Object#respond_to? to check if it can
|
||||
# expand %something%, this `something` should be a public method in the class calling
|
||||
# #directory. If a method is private, Thor stack raises PrivateMethodEncodedError.
|
||||
#
|
||||
# ==== Parameters
|
||||
# source<String>:: the relative path to the source root.
|
||||
# destination<String>:: the relative path to the destination root.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
# If :recursive => false, does not look for paths recursively.
|
||||
# If :mode => :preserve, preserve the file mode from the source.
|
||||
# If :exclude_pattern => /regexp/, prevents copying files that match that regexp.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# directory "doc"
|
||||
# directory "doc", "docs", :recursive => false
|
||||
#
|
||||
def directory(source, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
destination = args.first || source
|
||||
action Directory.new(self, source, destination || source, config, &block)
|
||||
end
|
||||
|
||||
class Directory < EmptyDirectory #:nodoc:
|
||||
attr_reader :source
|
||||
|
||||
def initialize(base, source, destination=nil, config={}, &block)
|
||||
@source = File.expand_path(base.find_in_source_paths(source.to_s))
|
||||
@block = block
|
||||
super(base, destination, { :recursive => true }.merge(config))
|
||||
end
|
||||
|
||||
def invoke!
|
||||
base.empty_directory given_destination, config
|
||||
execute!
|
||||
end
|
||||
|
||||
def revoke!
|
||||
execute!
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def execute!
|
||||
lookup = Util.escape_globs(source)
|
||||
lookup = config[:recursive] ? File.join(lookup, '**') : lookup
|
||||
lookup = file_level_lookup(lookup)
|
||||
|
||||
files(lookup).sort.each do |file_source|
|
||||
next if File.directory?(file_source)
|
||||
next if config[:exclude_pattern] && file_source.match(config[:exclude_pattern])
|
||||
file_destination = File.join(given_destination, file_source.gsub(source, '.'))
|
||||
file_destination.gsub!('/./', '/')
|
||||
|
||||
case file_source
|
||||
when /\.empty_directory$/
|
||||
dirname = File.dirname(file_destination).gsub(/\/\.$/, '')
|
||||
next if dirname == given_destination
|
||||
base.empty_directory(dirname, config)
|
||||
when /\.tt$/
|
||||
destination = base.template(file_source, file_destination[0..-4], config, &@block)
|
||||
else
|
||||
destination = base.copy_file(file_source, file_destination, config, &@block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if RUBY_VERSION < '2.0'
|
||||
def file_level_lookup(previous_lookup)
|
||||
File.join(previous_lookup, '{*,.[a-z]*}')
|
||||
end
|
||||
|
||||
def files(lookup)
|
||||
Dir[lookup]
|
||||
end
|
||||
else
|
||||
def file_level_lookup(previous_lookup)
|
||||
File.join(previous_lookup, '*')
|
||||
end
|
||||
|
||||
def files(lookup)
|
||||
Dir.glob(lookup, File::FNM_DOTMATCH)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
137
vendor/gems/thor-0.18.1/lib/thor/actions/empty_directory.rb
vendored
Normal file
137
vendor/gems/thor-0.18.1/lib/thor/actions/empty_directory.rb
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
class Thor
|
||||
module Actions
|
||||
|
||||
# Creates an empty directory.
|
||||
#
|
||||
# ==== Parameters
|
||||
# destination<String>:: the relative path to the destination root.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# empty_directory "doc"
|
||||
#
|
||||
def empty_directory(destination, config={})
|
||||
action EmptyDirectory.new(self, destination, config)
|
||||
end
|
||||
|
||||
# Class which holds create directory logic. This is the base class for
|
||||
# other actions like create_file and directory.
|
||||
#
|
||||
# This implementation is based in Templater actions, created by Jonas Nicklas
|
||||
# and Michael S. Klishin under MIT LICENSE.
|
||||
#
|
||||
class EmptyDirectory #:nodoc:
|
||||
attr_reader :base, :destination, :given_destination, :relative_destination, :config
|
||||
|
||||
# Initializes given the source and destination.
|
||||
#
|
||||
# ==== Parameters
|
||||
# base<Thor::Base>:: A Thor::Base instance
|
||||
# source<String>:: Relative path to the source of this file
|
||||
# destination<String>:: Relative path to the destination of this file
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
def initialize(base, destination, config={})
|
||||
@base, @config = base, { :verbose => true }.merge(config)
|
||||
self.destination = destination
|
||||
end
|
||||
|
||||
# Checks if the destination file already exists.
|
||||
#
|
||||
# ==== Returns
|
||||
# Boolean:: true if the file exists, false otherwise.
|
||||
#
|
||||
def exists?
|
||||
::File.exists?(destination)
|
||||
end
|
||||
|
||||
def invoke!
|
||||
invoke_with_conflict_check do
|
||||
::FileUtils.mkdir_p(destination)
|
||||
end
|
||||
end
|
||||
|
||||
def revoke!
|
||||
say_status :remove, :red
|
||||
::FileUtils.rm_rf(destination) if !pretend? && exists?
|
||||
given_destination
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Shortcut for pretend.
|
||||
#
|
||||
def pretend?
|
||||
base.options[:pretend]
|
||||
end
|
||||
|
||||
# Sets the absolute destination value from a relative destination value.
|
||||
# It also stores the given and relative destination. Let's suppose our
|
||||
# script is being executed on "dest", it sets the destination root to
|
||||
# "dest". The destination, given_destination and relative_destination
|
||||
# are related in the following way:
|
||||
#
|
||||
# inside "bar" do
|
||||
# empty_directory "baz"
|
||||
# end
|
||||
#
|
||||
# destination #=> dest/bar/baz
|
||||
# relative_destination #=> bar/baz
|
||||
# given_destination #=> baz
|
||||
#
|
||||
def destination=(destination)
|
||||
if destination
|
||||
@given_destination = convert_encoded_instructions(destination.to_s)
|
||||
@destination = ::File.expand_path(@given_destination, base.destination_root)
|
||||
@relative_destination = base.relative_to_original_destination_root(@destination)
|
||||
end
|
||||
end
|
||||
|
||||
# Filenames in the encoded form are converted. If you have a file:
|
||||
#
|
||||
# %file_name%.rb
|
||||
#
|
||||
# It calls #file_name from the base and replaces %-string with the
|
||||
# return value (should be String) of #file_name:
|
||||
#
|
||||
# user.rb
|
||||
#
|
||||
# The method referenced can be either public or private.
|
||||
#
|
||||
def convert_encoded_instructions(filename)
|
||||
filename.gsub(/%(.*?)%/) do |initial_string|
|
||||
method = $1.strip
|
||||
base.respond_to?(method, true) ? base.send(method) : initial_string
|
||||
end
|
||||
end
|
||||
|
||||
# Receives a hash of options and just execute the block if some
|
||||
# conditions are met.
|
||||
#
|
||||
def invoke_with_conflict_check(&block)
|
||||
if exists?
|
||||
on_conflict_behavior(&block)
|
||||
else
|
||||
say_status :create, :green
|
||||
block.call unless pretend?
|
||||
end
|
||||
|
||||
destination
|
||||
end
|
||||
|
||||
# What to do when the destination file already exists.
|
||||
#
|
||||
def on_conflict_behavior(&block)
|
||||
say_status :exist, :blue
|
||||
end
|
||||
|
||||
# Shortcut to say_status shell method.
|
||||
#
|
||||
def say_status(status, color)
|
||||
base.shell.say_status status, relative_destination, color if config[:verbose]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
314
vendor/gems/thor-0.18.1/lib/thor/actions/file_manipulation.rb
vendored
Normal file
314
vendor/gems/thor-0.18.1/lib/thor/actions/file_manipulation.rb
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
require 'erb'
|
||||
require 'open-uri'
|
||||
|
||||
class Thor
|
||||
module Actions
|
||||
|
||||
# Copies the file from the relative source to the relative destination. If
|
||||
# the destination is not given it's assumed to be equal to the source.
|
||||
#
|
||||
# ==== Parameters
|
||||
# source<String>:: the relative path to the source root.
|
||||
# destination<String>:: the relative path to the destination root.
|
||||
# config<Hash>:: give :verbose => false to not log the status, and
|
||||
# :mode => :preserve, to preserve the file mode from the source.
|
||||
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# copy_file "README", "doc/README"
|
||||
#
|
||||
# copy_file "doc/README"
|
||||
#
|
||||
def copy_file(source, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
destination = args.first || source
|
||||
source = File.expand_path(find_in_source_paths(source.to_s))
|
||||
|
||||
create_file destination, nil, config do
|
||||
content = File.binread(source)
|
||||
content = block.call(content) if block
|
||||
content
|
||||
end
|
||||
if config[:mode] == :preserve
|
||||
mode = File.stat(source).mode
|
||||
chmod(destination, mode, config)
|
||||
end
|
||||
end
|
||||
|
||||
# Links the file from the relative source to the relative destination. If
|
||||
# the destination is not given it's assumed to be equal to the source.
|
||||
#
|
||||
# ==== Parameters
|
||||
# source<String>:: the relative path to the source root.
|
||||
# destination<String>:: the relative path to the destination root.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# link_file "README", "doc/README"
|
||||
#
|
||||
# link_file "doc/README"
|
||||
#
|
||||
def link_file(source, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
destination = args.first || source
|
||||
source = File.expand_path(find_in_source_paths(source.to_s))
|
||||
|
||||
create_link destination, source, config
|
||||
end
|
||||
|
||||
# Gets the content at the given address and places it at the given relative
|
||||
# destination. If a block is given instead of destination, the content of
|
||||
# the url is yielded and used as location.
|
||||
#
|
||||
# ==== Parameters
|
||||
# source<String>:: the address of the given content.
|
||||
# destination<String>:: the relative path to the destination root.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# get "http://gist.github.com/103208", "doc/README"
|
||||
#
|
||||
# get "http://gist.github.com/103208" do |content|
|
||||
# content.split("\n").first
|
||||
# end
|
||||
#
|
||||
def get(source, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
destination = args.first
|
||||
|
||||
source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^https?\:\/\//
|
||||
render = open(source) {|input| input.binmode.read }
|
||||
|
||||
destination ||= if block_given?
|
||||
block.arity == 1 ? block.call(render) : block.call
|
||||
else
|
||||
File.basename(source)
|
||||
end
|
||||
|
||||
create_file destination, render, config
|
||||
end
|
||||
|
||||
# Gets an ERB template at the relative source, executes it and makes a copy
|
||||
# at the relative destination. If the destination is not given it's assumed
|
||||
# to be equal to the source removing .tt from the filename.
|
||||
#
|
||||
# ==== Parameters
|
||||
# source<String>:: the relative path to the source root.
|
||||
# destination<String>:: the relative path to the destination root.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# template "README", "doc/README"
|
||||
#
|
||||
# template "doc/README"
|
||||
#
|
||||
def template(source, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
destination = args.first || source.sub(/\.tt$/, '')
|
||||
|
||||
source = File.expand_path(find_in_source_paths(source.to_s))
|
||||
context = instance_eval('binding')
|
||||
|
||||
create_file destination, nil, config do
|
||||
content = ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context)
|
||||
content = block.call(content) if block
|
||||
content
|
||||
end
|
||||
end
|
||||
|
||||
# Changes the mode of the given file or directory.
|
||||
#
|
||||
# ==== Parameters
|
||||
# mode<Integer>:: the file mode
|
||||
# path<String>:: the name of the file to change mode
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# chmod "script/server", 0755
|
||||
#
|
||||
def chmod(path, mode, config={})
|
||||
return unless behavior == :invoke
|
||||
path = File.expand_path(path, destination_root)
|
||||
say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
||||
FileUtils.chmod_R(mode, path) unless options[:pretend]
|
||||
end
|
||||
|
||||
# Prepend text to a file. Since it depends on insert_into_file, it's reversible.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String>:: path of the file to be changed
|
||||
# data<String>:: the data to prepend to the file, can be also given as a block.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"'
|
||||
#
|
||||
# prepend_to_file 'config/environments/test.rb' do
|
||||
# 'config.gem "rspec"'
|
||||
# end
|
||||
#
|
||||
def prepend_to_file(path, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
config.merge!(:after => /\A/)
|
||||
insert_into_file(path, *(args << config), &block)
|
||||
end
|
||||
alias_method :prepend_file, :prepend_to_file
|
||||
|
||||
# Append text to a file. Since it depends on insert_into_file, it's reversible.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String>:: path of the file to be changed
|
||||
# data<String>:: the data to append to the file, can be also given as a block.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# append_to_file 'config/environments/test.rb', 'config.gem "rspec"'
|
||||
#
|
||||
# append_to_file 'config/environments/test.rb' do
|
||||
# 'config.gem "rspec"'
|
||||
# end
|
||||
#
|
||||
def append_to_file(path, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
config.merge!(:before => /\z/)
|
||||
insert_into_file(path, *(args << config), &block)
|
||||
end
|
||||
alias_method :append_file, :append_to_file
|
||||
|
||||
# Injects text right after the class definition. Since it depends on
|
||||
# insert_into_file, it's reversible.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String>:: path of the file to be changed
|
||||
# klass<String|Class>:: the class to be manipulated
|
||||
# data<String>:: the data to append to the class, can be also given as a block.
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n"
|
||||
#
|
||||
# inject_into_class "app/controllers/application_controller.rb", ApplicationController do
|
||||
# " filter_parameter :password\n"
|
||||
# end
|
||||
#
|
||||
def inject_into_class(path, klass, *args, &block)
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
config.merge!(:after => /class #{klass}\n|class #{klass} .*\n/)
|
||||
insert_into_file(path, *(args << config), &block)
|
||||
end
|
||||
|
||||
# Run a regular expression replacement on a file.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String>:: path of the file to be changed
|
||||
# flag<Regexp|String>:: the regexp or string to be replaced
|
||||
# replacement<String>:: the replacement, can be also given as a block
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
|
||||
#
|
||||
# gsub_file 'README', /rake/, :green do |match|
|
||||
# match << " no more. Use thor!"
|
||||
# end
|
||||
#
|
||||
def gsub_file(path, flag, *args, &block)
|
||||
return unless behavior == :invoke
|
||||
config = args.last.is_a?(Hash) ? args.pop : {}
|
||||
|
||||
path = File.expand_path(path, destination_root)
|
||||
say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
||||
|
||||
unless options[:pretend]
|
||||
content = File.binread(path)
|
||||
content.gsub!(flag, *args, &block)
|
||||
File.open(path, 'wb') { |file| file.write(content) }
|
||||
end
|
||||
end
|
||||
|
||||
# Uncomment all lines matching a given regex. It will leave the space
|
||||
# which existed before the comment hash in tact but will remove any spacing
|
||||
# between the comment hash and the beginning of the line.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String>:: path of the file to be changed
|
||||
# flag<Regexp|String>:: the regexp or string used to decide which lines to uncomment
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# uncomment_lines 'config/initializers/session_store.rb', /active_record/
|
||||
#
|
||||
def uncomment_lines(path, flag, *args)
|
||||
flag = flag.respond_to?(:source) ? flag.source : flag
|
||||
|
||||
gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args)
|
||||
end
|
||||
|
||||
# Comment all lines matching a given regex. It will leave the space
|
||||
# which existed before the beginning of the line in tact and will insert
|
||||
# a single space after the comment hash.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String>:: path of the file to be changed
|
||||
# flag<Regexp|String>:: the regexp or string used to decide which lines to comment
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# comment_lines 'config/initializers/session_store.rb', /cookie_store/
|
||||
#
|
||||
def comment_lines(path, flag, *args)
|
||||
flag = flag.respond_to?(:source) ? flag.source : flag
|
||||
|
||||
gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args)
|
||||
end
|
||||
|
||||
# Removes a file at the given location.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String>:: path of the file to be changed
|
||||
# config<Hash>:: give :verbose => false to not log the status.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# remove_file 'README'
|
||||
# remove_file 'app/controllers/application_controller.rb'
|
||||
#
|
||||
def remove_file(path, config={})
|
||||
return unless behavior == :invoke
|
||||
path = File.expand_path(path, destination_root)
|
||||
|
||||
say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
||||
::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
|
||||
end
|
||||
alias :remove_dir :remove_file
|
||||
|
||||
private
|
||||
attr_accessor :output_buffer
|
||||
def concat(string)
|
||||
@output_buffer.concat(string)
|
||||
end
|
||||
|
||||
def capture(*args, &block)
|
||||
with_output_buffer { block.call(*args) }
|
||||
end
|
||||
|
||||
def with_output_buffer(buf = '') #:nodoc:
|
||||
self.output_buffer, old_buffer = buf, output_buffer
|
||||
yield
|
||||
output_buffer
|
||||
ensure
|
||||
self.output_buffer = old_buffer
|
||||
end
|
||||
end
|
||||
end
|
||||
109
vendor/gems/thor-0.18.1/lib/thor/actions/inject_into_file.rb
vendored
Normal file
109
vendor/gems/thor-0.18.1/lib/thor/actions/inject_into_file.rb
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
require 'thor/actions/empty_directory'
|
||||
|
||||
class Thor
|
||||
module Actions
|
||||
|
||||
# Injects the given content into a file. Different from gsub_file, this
|
||||
# method is reversible.
|
||||
#
|
||||
# ==== Parameters
|
||||
# destination<String>:: Relative path to the destination root
|
||||
# data<String>:: Data to add to the file. Can be given as a block.
|
||||
# config<Hash>:: give :verbose => false to not log the status and the flag
|
||||
# for injection (:after or :before) or :force => true for
|
||||
# insert two or more times the same content.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
|
||||
#
|
||||
# insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
|
||||
# gems = ask "Which gems would you like to add?"
|
||||
# gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
|
||||
# end
|
||||
#
|
||||
def insert_into_file(destination, *args, &block)
|
||||
if block_given?
|
||||
data, config = block, args.shift
|
||||
else
|
||||
data, config = args.shift, args.shift
|
||||
end
|
||||
action InjectIntoFile.new(self, destination, data, config)
|
||||
end
|
||||
alias_method :inject_into_file, :insert_into_file
|
||||
|
||||
class InjectIntoFile < EmptyDirectory #:nodoc:
|
||||
attr_reader :replacement, :flag, :behavior
|
||||
|
||||
def initialize(base, destination, data, config)
|
||||
super(base, destination, { :verbose => true }.merge(config))
|
||||
|
||||
@behavior, @flag = if @config.key?(:after)
|
||||
[:after, @config.delete(:after)]
|
||||
else
|
||||
[:before, @config.delete(:before)]
|
||||
end
|
||||
|
||||
@replacement = data.is_a?(Proc) ? data.call : data
|
||||
@flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
|
||||
end
|
||||
|
||||
def invoke!
|
||||
say_status :invoke
|
||||
|
||||
content = if @behavior == :after
|
||||
'\0' + replacement
|
||||
else
|
||||
replacement + '\0'
|
||||
end
|
||||
|
||||
replace!(/#{flag}/, content, config[:force])
|
||||
end
|
||||
|
||||
def revoke!
|
||||
say_status :revoke
|
||||
|
||||
regexp = if @behavior == :after
|
||||
content = '\1\2'
|
||||
/(#{flag})(.*)(#{Regexp.escape(replacement)})/m
|
||||
else
|
||||
content = '\2\3'
|
||||
/(#{Regexp.escape(replacement)})(.*)(#{flag})/m
|
||||
end
|
||||
|
||||
replace!(regexp, content, true)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def say_status(behavior)
|
||||
status = if behavior == :invoke
|
||||
if flag == /\A/
|
||||
:prepend
|
||||
elsif flag == /\z/
|
||||
:append
|
||||
else
|
||||
:insert
|
||||
end
|
||||
else
|
||||
:subtract
|
||||
end
|
||||
|
||||
super(status, config[:verbose])
|
||||
end
|
||||
|
||||
# Adds the content to the file.
|
||||
#
|
||||
def replace!(regexp, string, force)
|
||||
unless base.options[:pretend]
|
||||
content = File.binread(destination)
|
||||
if force || !content.include?(replacement)
|
||||
content.gsub!(regexp, string)
|
||||
File.open(destination, 'wb') { |file| file.write(content) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
652
vendor/gems/thor-0.18.1/lib/thor/base.rb
vendored
Normal file
652
vendor/gems/thor-0.18.1/lib/thor/base.rb
vendored
Normal file
@@ -0,0 +1,652 @@
|
||||
require 'thor/command'
|
||||
require 'thor/core_ext/hash_with_indifferent_access'
|
||||
require 'thor/core_ext/ordered_hash'
|
||||
require 'thor/error'
|
||||
require 'thor/invocation'
|
||||
require 'thor/parser'
|
||||
require 'thor/shell'
|
||||
require 'thor/util'
|
||||
|
||||
class Thor
|
||||
autoload :Actions, 'thor/actions'
|
||||
autoload :RakeCompat, 'thor/rake_compat'
|
||||
autoload :Group, 'thor/group'
|
||||
|
||||
# Shortcuts for help.
|
||||
HELP_MAPPINGS = %w(-h -? --help -D)
|
||||
|
||||
# Thor methods that should not be overwritten by the user.
|
||||
THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
|
||||
action add_file create_file in_root inside run run_ruby_script)
|
||||
|
||||
module Base
|
||||
attr_accessor :options, :parent_options, :args
|
||||
|
||||
# It receives arguments in an Array and two hashes, one for options and
|
||||
# other for configuration.
|
||||
#
|
||||
# Notice that it does not check if all required arguments were supplied.
|
||||
# It should be done by the parser.
|
||||
#
|
||||
# ==== Parameters
|
||||
# args<Array[Object]>:: An array of objects. The objects are applied to their
|
||||
# respective accessors declared with <tt>argument</tt>.
|
||||
#
|
||||
# options<Hash>:: An options hash that will be available as self.options.
|
||||
# The hash given is converted to a hash with indifferent
|
||||
# access, magic predicates (options.skip?) and then frozen.
|
||||
#
|
||||
# config<Hash>:: Configuration for this Thor class.
|
||||
#
|
||||
def initialize(args=[], options={}, config={})
|
||||
parse_options = self.class.class_options
|
||||
|
||||
# The start method splits inbound arguments at the first argument
|
||||
# that looks like an option (starts with - or --). It then calls
|
||||
# new, passing in the two halves of the arguments Array as the
|
||||
# first two parameters.
|
||||
|
||||
if options.is_a?(Array)
|
||||
command_options = config.delete(:command_options) # hook for start
|
||||
parse_options = parse_options.merge(command_options) if command_options
|
||||
array_options, hash_options = options, {}
|
||||
else
|
||||
# Handle the case where the class was explicitly instantiated
|
||||
# with pre-parsed options.
|
||||
array_options, hash_options = [], options
|
||||
end
|
||||
|
||||
# Let Thor::Options parse the options first, so it can remove
|
||||
# declared options from the array. This will leave us with
|
||||
# a list of arguments that weren't declared.
|
||||
stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command]
|
||||
opts = Thor::Options.new(parse_options, hash_options, stop_on_unknown)
|
||||
self.options = opts.parse(array_options)
|
||||
self.options = config[:class_options].merge(self.options) if config[:class_options]
|
||||
|
||||
# If unknown options are disallowed, make sure that none of the
|
||||
# remaining arguments looks like an option.
|
||||
opts.check_unknown! if self.class.check_unknown_options?(config)
|
||||
|
||||
# Add the remaining arguments from the options parser to the
|
||||
# arguments passed in to initialize. Then remove any positional
|
||||
# arguments declared using #argument (this is primarily used
|
||||
# by Thor::Group). Tis will leave us with the remaining
|
||||
# positional arguments.
|
||||
to_parse = args
|
||||
to_parse += opts.remaining unless self.class.strict_args_position?(config)
|
||||
|
||||
thor_args = Thor::Arguments.new(self.class.arguments)
|
||||
thor_args.parse(to_parse).each { |k,v| __send__("#{k}=", v) }
|
||||
@args = thor_args.remaining
|
||||
end
|
||||
|
||||
class << self
|
||||
def included(base) #:nodoc:
|
||||
base.send :extend, ClassMethods
|
||||
base.send :include, Invocation
|
||||
base.send :include, Shell
|
||||
end
|
||||
|
||||
# Returns the classes that inherits from Thor or Thor::Group.
|
||||
#
|
||||
# ==== Returns
|
||||
# Array[Class]
|
||||
#
|
||||
def subclasses
|
||||
@subclasses ||= []
|
||||
end
|
||||
|
||||
# Returns the files where the subclasses are kept.
|
||||
#
|
||||
# ==== Returns
|
||||
# Hash[path<String> => Class]
|
||||
#
|
||||
def subclass_files
|
||||
@subclass_files ||= Hash.new{ |h,k| h[k] = [] }
|
||||
end
|
||||
|
||||
# Whenever a class inherits from Thor or Thor::Group, we should track the
|
||||
# class and the file on Thor::Base. This is the method responsable for it.
|
||||
#
|
||||
def register_klass_file(klass) #:nodoc:
|
||||
file = caller[1].match(/(.*):\d+/)[1]
|
||||
Thor::Base.subclasses << klass unless Thor::Base.subclasses.include?(klass)
|
||||
|
||||
file_subclasses = Thor::Base.subclass_files[File.expand_path(file)]
|
||||
file_subclasses << klass unless file_subclasses.include?(klass)
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def attr_reader(*) #:nodoc:
|
||||
no_commands { super }
|
||||
end
|
||||
|
||||
def attr_writer(*) #:nodoc:
|
||||
no_commands { super }
|
||||
end
|
||||
|
||||
def attr_accessor(*) #:nodoc:
|
||||
no_commands { super }
|
||||
end
|
||||
|
||||
# If you want to raise an error for unknown options, call check_unknown_options!
|
||||
# This is disabled by default to allow dynamic invocations.
|
||||
def check_unknown_options!
|
||||
@check_unknown_options = true
|
||||
end
|
||||
|
||||
def check_unknown_options #:nodoc:
|
||||
@check_unknown_options ||= from_superclass(:check_unknown_options, false)
|
||||
end
|
||||
|
||||
def check_unknown_options?(config) #:nodoc:
|
||||
!!check_unknown_options
|
||||
end
|
||||
|
||||
# If true, option parsing is suspended as soon as an unknown option or a
|
||||
# regular argument is encountered. All remaining arguments are passed to
|
||||
# the command as regular arguments.
|
||||
def stop_on_unknown_option?(command_name) #:nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
# If you want only strict string args (useful when cascading thor classes),
|
||||
# call strict_args_position! This is disabled by default to allow dynamic
|
||||
# invocations.
|
||||
def strict_args_position!
|
||||
@strict_args_position = true
|
||||
end
|
||||
|
||||
def strict_args_position #:nodoc:
|
||||
@strict_args_position ||= from_superclass(:strict_args_position, false)
|
||||
end
|
||||
|
||||
def strict_args_position?(config) #:nodoc:
|
||||
!!strict_args_position
|
||||
end
|
||||
|
||||
# Adds an argument to the class and creates an attr_accessor for it.
|
||||
#
|
||||
# Arguments are different from options in several aspects. The first one
|
||||
# is how they are parsed from the command line, arguments are retrieved
|
||||
# from position:
|
||||
#
|
||||
# thor command NAME
|
||||
#
|
||||
# Instead of:
|
||||
#
|
||||
# thor command --name=NAME
|
||||
#
|
||||
# Besides, arguments are used inside your code as an accessor (self.argument),
|
||||
# while options are all kept in a hash (self.options).
|
||||
#
|
||||
# Finally, arguments cannot have type :default or :boolean but can be
|
||||
# optional (supplying :optional => :true or :required => false), although
|
||||
# you cannot have a required argument after a non-required argument. If you
|
||||
# try it, an error is raised.
|
||||
#
|
||||
# ==== Parameters
|
||||
# name<Symbol>:: The name of the argument.
|
||||
# options<Hash>:: Described below.
|
||||
#
|
||||
# ==== Options
|
||||
# :desc - Description for the argument.
|
||||
# :required - If the argument is required or not.
|
||||
# :optional - If the argument is optional or not.
|
||||
# :type - The type of the argument, can be :string, :hash, :array, :numeric.
|
||||
# :default - Default value for this argument. It cannot be required and have default values.
|
||||
# :banner - String to show on usage notes.
|
||||
#
|
||||
# ==== Errors
|
||||
# ArgumentError:: Raised if you supply a required argument after a non required one.
|
||||
#
|
||||
def argument(name, options={})
|
||||
is_thor_reserved_word?(name, :argument)
|
||||
no_commands { attr_accessor name }
|
||||
|
||||
required = if options.key?(:optional)
|
||||
!options[:optional]
|
||||
elsif options.key?(:required)
|
||||
options[:required]
|
||||
else
|
||||
options[:default].nil?
|
||||
end
|
||||
|
||||
remove_argument name
|
||||
|
||||
arguments.each do |argument|
|
||||
next if argument.required?
|
||||
raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " <<
|
||||
"the non-required argument #{argument.human_name.inspect}."
|
||||
end if required
|
||||
|
||||
options[:required] = required
|
||||
|
||||
arguments << Thor::Argument.new(name, options)
|
||||
end
|
||||
|
||||
# Returns this class arguments, looking up in the ancestors chain.
|
||||
#
|
||||
# ==== Returns
|
||||
# Array[Thor::Argument]
|
||||
#
|
||||
def arguments
|
||||
@arguments ||= from_superclass(:arguments, [])
|
||||
end
|
||||
|
||||
# Adds a bunch of options to the set of class options.
|
||||
#
|
||||
# class_options :foo => false, :bar => :required, :baz => :string
|
||||
#
|
||||
# If you prefer more detailed declaration, check class_option.
|
||||
#
|
||||
# ==== Parameters
|
||||
# Hash[Symbol => Object]
|
||||
#
|
||||
def class_options(options=nil)
|
||||
@class_options ||= from_superclass(:class_options, {})
|
||||
build_options(options, @class_options) if options
|
||||
@class_options
|
||||
end
|
||||
|
||||
# Adds an option to the set of class options
|
||||
#
|
||||
# ==== Parameters
|
||||
# name<Symbol>:: The name of the argument.
|
||||
# options<Hash>:: Described below.
|
||||
#
|
||||
# ==== Options
|
||||
# :desc:: -- Description for the argument.
|
||||
# :required:: -- If the argument is required or not.
|
||||
# :default:: -- Default value for this argument.
|
||||
# :group:: -- The group for this options. Use by class options to output options in different levels.
|
||||
# :aliases:: -- Aliases for this option. <b>Note:</b> Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead.
|
||||
# :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
|
||||
# :banner:: -- String to show on usage notes.
|
||||
# :hide:: -- If you want to hide this option from the help.
|
||||
#
|
||||
def class_option(name, options={})
|
||||
build_option(name, options, class_options)
|
||||
end
|
||||
|
||||
# Removes a previous defined argument. If :undefine is given, undefine
|
||||
# accessors as well.
|
||||
#
|
||||
# ==== Parameters
|
||||
# names<Array>:: Arguments to be removed
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# remove_argument :foo
|
||||
# remove_argument :foo, :bar, :baz, :undefine => true
|
||||
#
|
||||
def remove_argument(*names)
|
||||
options = names.last.is_a?(Hash) ? names.pop : {}
|
||||
|
||||
names.each do |name|
|
||||
arguments.delete_if { |a| a.name == name.to_s }
|
||||
undef_method name, "#{name}=" if options[:undefine]
|
||||
end
|
||||
end
|
||||
|
||||
# Removes a previous defined class option.
|
||||
#
|
||||
# ==== Parameters
|
||||
# names<Array>:: Class options to be removed
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# remove_class_option :foo
|
||||
# remove_class_option :foo, :bar, :baz
|
||||
#
|
||||
def remove_class_option(*names)
|
||||
names.each do |name|
|
||||
class_options.delete(name)
|
||||
end
|
||||
end
|
||||
|
||||
# Defines the group. This is used when thor list is invoked so you can specify
|
||||
# that only commands from a pre-defined group will be shown. Defaults to standard.
|
||||
#
|
||||
# ==== Parameters
|
||||
# name<String|Symbol>
|
||||
#
|
||||
def group(name=nil)
|
||||
@group = case name
|
||||
when nil
|
||||
@group || from_superclass(:group, 'standard')
|
||||
else
|
||||
name.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the commands for this Thor class.
|
||||
#
|
||||
# ==== Returns
|
||||
# OrderedHash:: An ordered hash with commands names as keys and Thor::Command
|
||||
# objects as values.
|
||||
#
|
||||
def commands
|
||||
@commands ||= Thor::CoreExt::OrderedHash.new
|
||||
end
|
||||
alias tasks commands
|
||||
|
||||
# Returns the commands for this Thor class and all subclasses.
|
||||
#
|
||||
# ==== Returns
|
||||
# OrderedHash:: An ordered hash with commands names as keys and Thor::Command
|
||||
# objects as values.
|
||||
#
|
||||
def all_commands
|
||||
@all_commands ||= from_superclass(:all_commands, Thor::CoreExt::OrderedHash.new)
|
||||
@all_commands.merge(commands)
|
||||
end
|
||||
alias all_tasks all_commands
|
||||
|
||||
# Removes a given command from this Thor class. This is usually done if you
|
||||
# are inheriting from another class and don't want it to be available
|
||||
# anymore.
|
||||
#
|
||||
# By default it only remove the mapping to the command. But you can supply
|
||||
# :undefine => true to undefine the method from the class as well.
|
||||
#
|
||||
# ==== Parameters
|
||||
# name<Symbol|String>:: The name of the command to be removed
|
||||
# options<Hash>:: You can give :undefine => true if you want commands the method
|
||||
# to be undefined from the class as well.
|
||||
#
|
||||
def remove_command(*names)
|
||||
options = names.last.is_a?(Hash) ? names.pop : {}
|
||||
|
||||
names.each do |name|
|
||||
commands.delete(name.to_s)
|
||||
all_commands.delete(name.to_s)
|
||||
undef_method name if options[:undefine]
|
||||
end
|
||||
end
|
||||
alias remove_task remove_command
|
||||
|
||||
# All methods defined inside the given block are not added as commands.
|
||||
#
|
||||
# So you can do:
|
||||
#
|
||||
# class MyScript < Thor
|
||||
# no_commands do
|
||||
# def this_is_not_a_command
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# You can also add the method and remove it from the command list:
|
||||
#
|
||||
# class MyScript < Thor
|
||||
# def this_is_not_a_command
|
||||
# end
|
||||
# remove_command :this_is_not_a_command
|
||||
# end
|
||||
#
|
||||
def no_commands
|
||||
@no_commands = true
|
||||
yield
|
||||
ensure
|
||||
@no_commands = false
|
||||
end
|
||||
alias no_tasks no_commands
|
||||
|
||||
# Sets the namespace for the Thor or Thor::Group class. By default the
|
||||
# namespace is retrieved from the class name. If your Thor class is named
|
||||
# Scripts::MyScript, the help method, for example, will be called as:
|
||||
#
|
||||
# thor scripts:my_script -h
|
||||
#
|
||||
# If you change the namespace:
|
||||
#
|
||||
# namespace :my_scripts
|
||||
#
|
||||
# You change how your commands are invoked:
|
||||
#
|
||||
# thor my_scripts -h
|
||||
#
|
||||
# Finally, if you change your namespace to default:
|
||||
#
|
||||
# namespace :default
|
||||
#
|
||||
# Your commands can be invoked with a shortcut. Instead of:
|
||||
#
|
||||
# thor :my_command
|
||||
#
|
||||
def namespace(name=nil)
|
||||
@namespace = case name
|
||||
when nil
|
||||
@namespace || Thor::Util.namespace_from_thor_class(self)
|
||||
else
|
||||
@namespace = name.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Parses the command and options from the given args, instantiate the class
|
||||
# and invoke the command. This method is used when the arguments must be parsed
|
||||
# from an array. If you are inside Ruby and want to use a Thor class, you
|
||||
# can simply initialize it:
|
||||
#
|
||||
# script = MyScript.new(args, options, config)
|
||||
# script.invoke(:command, first_arg, second_arg, third_arg)
|
||||
#
|
||||
def start(given_args=ARGV, config={})
|
||||
config[:shell] ||= Thor::Base.shell.new
|
||||
dispatch(nil, given_args.dup, nil, config)
|
||||
rescue Thor::Error => e
|
||||
ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
|
||||
exit(1) if exit_on_failure?
|
||||
rescue Errno::EPIPE
|
||||
# This happens if a thor command is piped to something like `head`,
|
||||
# which closes the pipe when it's done reading. This will also
|
||||
# mean that if the pipe is closed, further unnecessary
|
||||
# computation will not occur.
|
||||
exit(0)
|
||||
end
|
||||
|
||||
# Allows to use private methods from parent in child classes as commands.
|
||||
#
|
||||
# ==== Parameters
|
||||
# names<Array>:: Method names to be used as commands
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# public_command :foo
|
||||
# public_command :foo, :bar, :baz
|
||||
#
|
||||
def public_command(*names)
|
||||
names.each do |name|
|
||||
class_eval "def #{name}(*); super end"
|
||||
end
|
||||
end
|
||||
alias public_task public_command
|
||||
|
||||
def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc:
|
||||
if has_namespace
|
||||
raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace."
|
||||
else
|
||||
raise UndefinedCommandError, "Could not find command #{command.inspect}."
|
||||
end
|
||||
end
|
||||
alias handle_no_task_error handle_no_command_error
|
||||
|
||||
def handle_argument_error(command, error, args, arity) #:nodoc:
|
||||
msg = "ERROR: #{basename} #{command.name} was called with "
|
||||
msg << 'no arguments' if args.empty?
|
||||
msg << 'arguments ' << args.inspect if !args.empty?
|
||||
msg << "\nUsage: #{self.banner(command).inspect}."
|
||||
raise InvocationError, msg
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Prints the class options per group. If an option does not belong to
|
||||
# any group, it's printed as Class option.
|
||||
#
|
||||
def class_options_help(shell, groups={}) #:nodoc:
|
||||
# Group options by group
|
||||
class_options.each do |_, value|
|
||||
groups[value.group] ||= []
|
||||
groups[value.group] << value
|
||||
end
|
||||
|
||||
# Deal with default group
|
||||
global_options = groups.delete(nil) || []
|
||||
print_options(shell, global_options)
|
||||
|
||||
# Print all others
|
||||
groups.each do |group_name, options|
|
||||
print_options(shell, options, group_name)
|
||||
end
|
||||
end
|
||||
|
||||
# Receives a set of options and print them.
|
||||
def print_options(shell, options, group_name=nil)
|
||||
return if options.empty?
|
||||
|
||||
list = []
|
||||
padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
|
||||
|
||||
options.each do |option|
|
||||
unless option.hide
|
||||
item = [ option.usage(padding) ]
|
||||
item.push(option.description ? "# #{option.description}" : "")
|
||||
|
||||
list << item
|
||||
list << [ "", "# Default: #{option.default}" ] if option.show_default?
|
||||
list << [ "", "# Possible values: #{option.enum.join(', ')}" ] if option.enum
|
||||
end
|
||||
end
|
||||
|
||||
shell.say(group_name ? "#{group_name} options:" : "Options:")
|
||||
shell.print_table(list, :indent => 2)
|
||||
shell.say ""
|
||||
end
|
||||
|
||||
# Raises an error if the word given is a Thor reserved word.
|
||||
def is_thor_reserved_word?(word, type) #:nodoc:
|
||||
return false unless THOR_RESERVED_WORDS.include?(word.to_s)
|
||||
raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
|
||||
end
|
||||
|
||||
# Build an option and adds it to the given scope.
|
||||
#
|
||||
# ==== Parameters
|
||||
# name<Symbol>:: The name of the argument.
|
||||
# options<Hash>:: Described in both class_option and method_option.
|
||||
# scope<Hash>:: Options hash that is being built up
|
||||
def build_option(name, options, scope) #:nodoc:
|
||||
scope[name] = Thor::Option.new(name, options)
|
||||
end
|
||||
|
||||
# Receives a hash of options, parse them and add to the scope. This is a
|
||||
# fast way to set a bunch of options:
|
||||
#
|
||||
# build_options :foo => true, :bar => :required, :baz => :string
|
||||
#
|
||||
# ==== Parameters
|
||||
# Hash[Symbol => Object]
|
||||
def build_options(options, scope) #:nodoc:
|
||||
options.each do |key, value|
|
||||
scope[key] = Thor::Option.parse(key, value)
|
||||
end
|
||||
end
|
||||
|
||||
# Finds a command with the given name. If the command belongs to the current
|
||||
# class, just return it, otherwise dup it and add the fresh copy to the
|
||||
# current command hash.
|
||||
def find_and_refresh_command(name) #:nodoc:
|
||||
command = if command = commands[name.to_s]
|
||||
command
|
||||
elsif command = all_commands[name.to_s]
|
||||
commands[name.to_s] = command.clone
|
||||
else
|
||||
raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
|
||||
end
|
||||
end
|
||||
alias find_and_refresh_task find_and_refresh_command
|
||||
|
||||
# Everytime someone inherits from a Thor class, register the klass
|
||||
# and file into baseclass.
|
||||
def inherited(klass)
|
||||
Thor::Base.register_klass_file(klass)
|
||||
klass.instance_variable_set(:@no_commands, false)
|
||||
end
|
||||
|
||||
# Fire this callback whenever a method is added. Added methods are
|
||||
# tracked as commands by invoking the create_command method.
|
||||
def method_added(meth)
|
||||
meth = meth.to_s
|
||||
|
||||
if meth == "initialize"
|
||||
initialize_added
|
||||
return
|
||||
end
|
||||
|
||||
# Return if it's not a public instance method
|
||||
return unless public_method_defined?(meth.to_sym)
|
||||
|
||||
return if @no_commands || !create_command(meth)
|
||||
|
||||
is_thor_reserved_word?(meth, :command)
|
||||
Thor::Base.register_klass_file(self)
|
||||
end
|
||||
|
||||
# Retrieves a value from superclass. If it reaches the baseclass,
|
||||
# returns default.
|
||||
def from_superclass(method, default=nil)
|
||||
if self == baseclass || !superclass.respond_to?(method, true)
|
||||
default
|
||||
else
|
||||
value = superclass.send(method)
|
||||
|
||||
if value
|
||||
if value.is_a?(TrueClass) || value.is_a?(Symbol)
|
||||
value
|
||||
else
|
||||
value.dup
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# A flag that makes the process exit with status 1 if any error happens.
|
||||
def exit_on_failure?
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# The basename of the program invoking the thor class.
|
||||
#
|
||||
def basename
|
||||
File.basename($0).split(' ').first
|
||||
end
|
||||
|
||||
# SIGNATURE: Sets the baseclass. This is where the superclass lookup
|
||||
# finishes.
|
||||
def baseclass #:nodoc:
|
||||
end
|
||||
|
||||
# SIGNATURE: Creates a new command if valid_command? is true. This method is
|
||||
# called when a new method is added to the class.
|
||||
def create_command(meth) #:nodoc:
|
||||
end
|
||||
alias create_task create_command
|
||||
|
||||
# SIGNATURE: Defines behavior when the initialize method is added to the
|
||||
# class.
|
||||
def initialize_added #:nodoc:
|
||||
end
|
||||
|
||||
# SIGNATURE: The hook invoked by start.
|
||||
def dispatch(command, given_args, given_opts, config) #:nodoc:
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
136
vendor/gems/thor-0.18.1/lib/thor/command.rb
vendored
Normal file
136
vendor/gems/thor-0.18.1/lib/thor/command.rb
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
class Thor
|
||||
class Command < Struct.new(:name, :description, :long_description, :usage, :options)
|
||||
FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
|
||||
|
||||
def initialize(name, description, long_description, usage, options=nil)
|
||||
super(name.to_s, description, long_description, usage, options || {})
|
||||
end
|
||||
|
||||
def initialize_copy(other) #:nodoc:
|
||||
super(other)
|
||||
self.options = other.options.dup if other.options
|
||||
end
|
||||
|
||||
def hidden?
|
||||
false
|
||||
end
|
||||
|
||||
# By default, a command invokes a method in the thor class. You can change this
|
||||
# implementation to create custom commands.
|
||||
def run(instance, args=[])
|
||||
arity = nil
|
||||
|
||||
if private_method?(instance)
|
||||
instance.class.handle_no_command_error(name)
|
||||
elsif public_method?(instance)
|
||||
arity = instance.method(name).arity
|
||||
instance.__send__(name, *args)
|
||||
elsif local_method?(instance, :method_missing)
|
||||
instance.__send__(:method_missing, name.to_sym, *args)
|
||||
else
|
||||
instance.class.handle_no_command_error(name)
|
||||
end
|
||||
rescue ArgumentError => e
|
||||
handle_argument_error?(instance, e, caller) ?
|
||||
instance.class.handle_argument_error(self, e, args, arity) : (raise e)
|
||||
rescue NoMethodError => e
|
||||
handle_no_method_error?(instance, e, caller) ?
|
||||
instance.class.handle_no_command_error(name) : (raise e)
|
||||
end
|
||||
|
||||
# Returns the formatted usage by injecting given required arguments
|
||||
# and required options into the given usage.
|
||||
def formatted_usage(klass, namespace = true, subcommand = false)
|
||||
if namespace
|
||||
namespace = klass.namespace
|
||||
formatted = "#{namespace.gsub(/^(default)/,'')}:"
|
||||
end
|
||||
formatted = "#{klass.namespace.split(':').last} " if subcommand
|
||||
|
||||
formatted ||= ""
|
||||
|
||||
# Add usage with required arguments
|
||||
formatted << if klass && !klass.arguments.empty?
|
||||
usage.to_s.gsub(/^#{name}/) do |match|
|
||||
match << " " << klass.arguments.map{ |a| a.usage }.compact.join(' ')
|
||||
end
|
||||
else
|
||||
usage.to_s
|
||||
end
|
||||
|
||||
# Add required options
|
||||
formatted << " #{required_options}"
|
||||
|
||||
# Strip and go!
|
||||
formatted.strip
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def not_debugging?(instance)
|
||||
!(instance.class.respond_to?(:debugging) && instance.class.debugging)
|
||||
end
|
||||
|
||||
def required_options
|
||||
@required_options ||= options.map{ |_, o| o.usage if o.required? }.compact.sort.join(" ")
|
||||
end
|
||||
|
||||
# Given a target, checks if this class name is a public method.
|
||||
def public_method?(instance) #:nodoc:
|
||||
!(instance.public_methods & [name.to_s, name.to_sym]).empty?
|
||||
end
|
||||
|
||||
def private_method?(instance)
|
||||
!(instance.private_methods & [name.to_s, name.to_sym]).empty?
|
||||
end
|
||||
|
||||
def local_method?(instance, name)
|
||||
methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false)
|
||||
!(methods & [name.to_s, name.to_sym]).empty?
|
||||
end
|
||||
|
||||
def sans_backtrace(backtrace, caller) #:nodoc:
|
||||
saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) }
|
||||
saned -= caller
|
||||
end
|
||||
|
||||
def handle_argument_error?(instance, error, caller)
|
||||
not_debugging?(instance) && error.message =~ /wrong number of arguments/ && begin
|
||||
saned = sans_backtrace(error.backtrace, caller)
|
||||
# Ruby 1.9 always include the called method in the backtrace
|
||||
saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9")
|
||||
end
|
||||
end
|
||||
|
||||
def handle_no_method_error?(instance, error, caller)
|
||||
not_debugging?(instance) &&
|
||||
error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
|
||||
end
|
||||
end
|
||||
Task = Command
|
||||
|
||||
# A command that is hidden in help messages but still invocable.
|
||||
class HiddenCommand < Command
|
||||
def hidden?
|
||||
true
|
||||
end
|
||||
end
|
||||
HiddenTask = HiddenCommand
|
||||
|
||||
# A dynamic command that handles method missing scenarios.
|
||||
class DynamicCommand < Command
|
||||
def initialize(name, options=nil)
|
||||
super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options)
|
||||
end
|
||||
|
||||
def run(instance, args=[])
|
||||
if (instance.methods & [name.to_s, name.to_sym]).empty?
|
||||
super
|
||||
else
|
||||
instance.class.handle_no_command_error(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
DynamicTask = DynamicCommand
|
||||
|
||||
end
|
||||
80
vendor/gems/thor-0.18.1/lib/thor/core_ext/hash_with_indifferent_access.rb
vendored
Normal file
80
vendor/gems/thor-0.18.1/lib/thor/core_ext/hash_with_indifferent_access.rb
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
class Thor
|
||||
module CoreExt #:nodoc:
|
||||
|
||||
# A hash with indifferent access and magic predicates.
|
||||
#
|
||||
# hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true
|
||||
#
|
||||
# hash[:foo] #=> 'bar'
|
||||
# hash['foo'] #=> 'bar'
|
||||
# hash.foo? #=> true
|
||||
#
|
||||
class HashWithIndifferentAccess < ::Hash #:nodoc:
|
||||
|
||||
def initialize(hash={})
|
||||
super()
|
||||
hash.each do |key, value|
|
||||
self[convert_key(key)] = value
|
||||
end
|
||||
end
|
||||
|
||||
def [](key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
super(convert_key(key), value)
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
def values_at(*indices)
|
||||
indices.collect { |key| self[convert_key(key)] }
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
dup.merge!(other)
|
||||
end
|
||||
|
||||
def merge!(other)
|
||||
other.each do |key, value|
|
||||
self[convert_key(key)] = value
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# Convert to a Hash with String keys.
|
||||
def to_hash
|
||||
Hash.new(default).merge!(self)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def convert_key(key)
|
||||
key.is_a?(Symbol) ? key.to_s : key
|
||||
end
|
||||
|
||||
# Magic predicates. For instance:
|
||||
#
|
||||
# options.force? # => !!options['force']
|
||||
# options.shebang # => "/usr/lib/local/ruby"
|
||||
# options.test_framework?(:rspec) # => options[:test_framework] == :rspec
|
||||
#
|
||||
def method_missing(method, *args, &block)
|
||||
method = method.to_s
|
||||
if method =~ /^(\w+)\?$/
|
||||
if args.empty?
|
||||
!!self[$1]
|
||||
else
|
||||
self[$1] == args.first
|
||||
end
|
||||
else
|
||||
self[method]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
12
vendor/gems/thor-0.18.1/lib/thor/core_ext/io_binary_read.rb
vendored
Normal file
12
vendor/gems/thor-0.18.1/lib/thor/core_ext/io_binary_read.rb
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
class IO #:nodoc:
|
||||
class << self
|
||||
|
||||
def binread(file, *args)
|
||||
raise ArgumentError, "wrong number of arguments (#{1 + args.size} for 1..3)" unless args.size < 3
|
||||
File.open(file, 'rb') do |f|
|
||||
f.read(*args)
|
||||
end
|
||||
end unless method_defined? :binread
|
||||
|
||||
end
|
||||
end
|
||||
100
vendor/gems/thor-0.18.1/lib/thor/core_ext/ordered_hash.rb
vendored
Normal file
100
vendor/gems/thor-0.18.1/lib/thor/core_ext/ordered_hash.rb
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
class Thor
|
||||
module CoreExt #:nodoc:
|
||||
|
||||
if RUBY_VERSION >= '1.9'
|
||||
class OrderedHash < ::Hash
|
||||
end
|
||||
else
|
||||
# This class is based on the Ruby 1.9 ordered hashes.
|
||||
#
|
||||
# It keeps the semantics and most of the efficiency of normal hashes
|
||||
# while also keeping track of the order in which elements were set.
|
||||
#
|
||||
class OrderedHash #:nodoc:
|
||||
include Enumerable
|
||||
|
||||
Node = Struct.new(:key, :value, :next, :prev)
|
||||
|
||||
def initialize
|
||||
@hash = {}
|
||||
end
|
||||
|
||||
def [](key)
|
||||
@hash[key] && @hash[key].value
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
if node = @hash[key]
|
||||
node.value = value
|
||||
else
|
||||
node = Node.new(key, value)
|
||||
|
||||
if @first.nil?
|
||||
@first = @last = node
|
||||
else
|
||||
node.prev = @last
|
||||
@last.next = node
|
||||
@last = node
|
||||
end
|
||||
end
|
||||
|
||||
@hash[key] = node
|
||||
value
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
if node = @hash[key]
|
||||
prev_node = node.prev
|
||||
next_node = node.next
|
||||
|
||||
next_node.prev = prev_node if next_node
|
||||
prev_node.next = next_node if prev_node
|
||||
|
||||
@first = next_node if @first == node
|
||||
@last = prev_node if @last == node
|
||||
|
||||
value = node.value
|
||||
end
|
||||
|
||||
@hash.delete(key)
|
||||
value
|
||||
end
|
||||
|
||||
def keys
|
||||
self.map { |k, v| k }
|
||||
end
|
||||
|
||||
def values
|
||||
self.map { |k, v| v }
|
||||
end
|
||||
|
||||
def each
|
||||
return unless @first
|
||||
yield [@first.key, @first.value]
|
||||
node = @first
|
||||
yield [node.key, node.value] while node = node.next
|
||||
self
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
hash = self.class.new
|
||||
|
||||
self.each do |key, value|
|
||||
hash[key] = value
|
||||
end
|
||||
|
||||
other.each do |key, value|
|
||||
hash[key] = value
|
||||
end
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
def empty?
|
||||
@hash.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
28
vendor/gems/thor-0.18.1/lib/thor/error.rb
vendored
Normal file
28
vendor/gems/thor-0.18.1/lib/thor/error.rb
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
class Thor
|
||||
# Thor::Error is raised when it's caused by wrong usage of thor classes. Those
|
||||
# errors have their backtrace suppressed and are nicely shown to the user.
|
||||
#
|
||||
# Errors that are caused by the developer, like declaring a method which
|
||||
# overwrites a thor keyword, it SHOULD NOT raise a Thor::Error. This way, we
|
||||
# ensure that developer errors are shown with full backtrace.
|
||||
class Error < StandardError
|
||||
end
|
||||
|
||||
# Raised when a command was not found.
|
||||
class UndefinedCommandError < Error
|
||||
end
|
||||
UndefinedTaskError = UndefinedCommandError
|
||||
|
||||
# Raised when a command was found, but not invoked properly.
|
||||
class InvocationError < Error
|
||||
end
|
||||
|
||||
class UnknownArgumentError < Error
|
||||
end
|
||||
|
||||
class RequiredArgumentMissingError < InvocationError
|
||||
end
|
||||
|
||||
class MalformattedArgumentError < InvocationError
|
||||
end
|
||||
end
|
||||
282
vendor/gems/thor-0.18.1/lib/thor/group.rb
vendored
Normal file
282
vendor/gems/thor-0.18.1/lib/thor/group.rb
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
require 'thor/base'
|
||||
|
||||
# Thor has a special class called Thor::Group. The main difference to Thor class
|
||||
# is that it invokes all commands at once. It also include some methods that allows
|
||||
# invocations to be done at the class method, which are not available to Thor
|
||||
# commands.
|
||||
class Thor::Group
|
||||
class << self
|
||||
# The description for this Thor::Group. If none is provided, but a source root
|
||||
# exists, tries to find the USAGE one folder above it, otherwise searches
|
||||
# in the superclass.
|
||||
#
|
||||
# ==== Parameters
|
||||
# description<String>:: The description for this Thor::Group.
|
||||
#
|
||||
def desc(description=nil)
|
||||
@desc = case description
|
||||
when nil
|
||||
@desc || from_superclass(:desc, nil)
|
||||
else
|
||||
description
|
||||
end
|
||||
end
|
||||
|
||||
# Prints help information.
|
||||
#
|
||||
# ==== Options
|
||||
# short:: When true, shows only usage.
|
||||
#
|
||||
def help(shell)
|
||||
shell.say "Usage:"
|
||||
shell.say " #{banner}\n"
|
||||
shell.say
|
||||
class_options_help(shell)
|
||||
shell.say self.desc if self.desc
|
||||
end
|
||||
|
||||
# Stores invocations for this class merging with superclass values.
|
||||
#
|
||||
def invocations #:nodoc:
|
||||
@invocations ||= from_superclass(:invocations, {})
|
||||
end
|
||||
|
||||
# Stores invocation blocks used on invoke_from_option.
|
||||
#
|
||||
def invocation_blocks #:nodoc:
|
||||
@invocation_blocks ||= from_superclass(:invocation_blocks, {})
|
||||
end
|
||||
|
||||
# Invoke the given namespace or class given. It adds an instance
|
||||
# method that will invoke the klass and command. You can give a block to
|
||||
# configure how it will be invoked.
|
||||
#
|
||||
# The namespace/class given will have its options showed on the help
|
||||
# usage. Check invoke_from_option for more information.
|
||||
#
|
||||
def invoke(*names, &block)
|
||||
options = names.last.is_a?(Hash) ? names.pop : {}
|
||||
verbose = options.fetch(:verbose, true)
|
||||
|
||||
names.each do |name|
|
||||
invocations[name] = false
|
||||
invocation_blocks[name] = block if block_given?
|
||||
|
||||
class_eval <<-METHOD, __FILE__, __LINE__
|
||||
def _invoke_#{name.to_s.gsub(/\W/, '_')}
|
||||
klass, command = self.class.prepare_for_invocation(nil, #{name.inspect})
|
||||
|
||||
if klass
|
||||
say_status :invoke, #{name.inspect}, #{verbose.inspect}
|
||||
block = self.class.invocation_blocks[#{name.inspect}]
|
||||
_invoke_for_class_method klass, command, &block
|
||||
else
|
||||
say_status :error, %(#{name.inspect} [not found]), :red
|
||||
end
|
||||
end
|
||||
METHOD
|
||||
end
|
||||
end
|
||||
|
||||
# Invoke a thor class based on the value supplied by the user to the
|
||||
# given option named "name". A class option must be created before this
|
||||
# method is invoked for each name given.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# class GemGenerator < Thor::Group
|
||||
# class_option :test_framework, :type => :string
|
||||
# invoke_from_option :test_framework
|
||||
# end
|
||||
#
|
||||
# ==== Boolean options
|
||||
#
|
||||
# In some cases, you want to invoke a thor class if some option is true or
|
||||
# false. This is automatically handled by invoke_from_option. Then the
|
||||
# option name is used to invoke the generator.
|
||||
#
|
||||
# ==== Preparing for invocation
|
||||
#
|
||||
# In some cases you want to customize how a specified hook is going to be
|
||||
# invoked. You can do that by overwriting the class method
|
||||
# prepare_for_invocation. The class method must necessarily return a klass
|
||||
# and an optional command.
|
||||
#
|
||||
# ==== Custom invocations
|
||||
#
|
||||
# You can also supply a block to customize how the option is going to be
|
||||
# invoked. The block receives two parameters, an instance of the current
|
||||
# class and the klass to be invoked.
|
||||
#
|
||||
def invoke_from_option(*names, &block)
|
||||
options = names.last.is_a?(Hash) ? names.pop : {}
|
||||
verbose = options.fetch(:verbose, :white)
|
||||
|
||||
names.each do |name|
|
||||
unless class_options.key?(name)
|
||||
raise ArgumentError, "You have to define the option #{name.inspect} " <<
|
||||
"before setting invoke_from_option."
|
||||
end
|
||||
|
||||
invocations[name] = true
|
||||
invocation_blocks[name] = block if block_given?
|
||||
|
||||
class_eval <<-METHOD, __FILE__, __LINE__
|
||||
def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
|
||||
return unless options[#{name.inspect}]
|
||||
|
||||
value = options[#{name.inspect}]
|
||||
value = #{name.inspect} if TrueClass === value
|
||||
klass, command = self.class.prepare_for_invocation(#{name.inspect}, value)
|
||||
|
||||
if klass
|
||||
say_status :invoke, value, #{verbose.inspect}
|
||||
block = self.class.invocation_blocks[#{name.inspect}]
|
||||
_invoke_for_class_method klass, command, &block
|
||||
else
|
||||
say_status :error, %(\#{value} [not found]), :red
|
||||
end
|
||||
end
|
||||
METHOD
|
||||
end
|
||||
end
|
||||
|
||||
# Remove a previously added invocation.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# remove_invocation :test_framework
|
||||
#
|
||||
def remove_invocation(*names)
|
||||
names.each do |name|
|
||||
remove_command(name)
|
||||
remove_class_option(name)
|
||||
invocations.delete(name)
|
||||
invocation_blocks.delete(name)
|
||||
end
|
||||
end
|
||||
|
||||
# Overwrite class options help to allow invoked generators options to be
|
||||
# shown recursively when invoking a generator.
|
||||
#
|
||||
def class_options_help(shell, groups={}) #:nodoc:
|
||||
get_options_from_invocations(groups, class_options) do |klass|
|
||||
klass.send(:get_options_from_invocations, groups, class_options)
|
||||
end
|
||||
super(shell, groups)
|
||||
end
|
||||
|
||||
# Get invocations array and merge options from invocations. Those
|
||||
# options are added to group_options hash. Options that already exists
|
||||
# in base_options are not added twice.
|
||||
#
|
||||
def get_options_from_invocations(group_options, base_options) #:nodoc:
|
||||
invocations.each do |name, from_option|
|
||||
value = if from_option
|
||||
option = class_options[name]
|
||||
option.type == :boolean ? name : option.default
|
||||
else
|
||||
name
|
||||
end
|
||||
next unless value
|
||||
|
||||
klass, _ = prepare_for_invocation(name, value)
|
||||
next unless klass && klass.respond_to?(:class_options)
|
||||
|
||||
value = value.to_s
|
||||
human_name = value.respond_to?(:classify) ? value.classify : value
|
||||
|
||||
group_options[human_name] ||= []
|
||||
group_options[human_name] += klass.class_options.values.select do |class_option|
|
||||
base_options[class_option.name.to_sym].nil? && class_option.group.nil? &&
|
||||
!group_options.values.flatten.any? { |i| i.name == class_option.name }
|
||||
end
|
||||
|
||||
yield klass if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
# Returns commands ready to be printed.
|
||||
def printable_commands(*)
|
||||
item = []
|
||||
item << banner
|
||||
item << (desc ? "# #{desc.gsub(/\s+/m,' ')}" : "")
|
||||
[item]
|
||||
end
|
||||
alias printable_tasks printable_commands
|
||||
|
||||
def handle_argument_error(command, error, args, arity) #:nodoc:
|
||||
msg = "#{basename} #{command.name} takes #{arity} argument"
|
||||
msg << "s" if arity > 1
|
||||
msg << ", but it should not."
|
||||
raise error, msg
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# The method responsible for dispatching given the args.
|
||||
def dispatch(command, given_args, given_opts, config) #:nodoc:
|
||||
if Thor::HELP_MAPPINGS.include?(given_args.first)
|
||||
help(config[:shell])
|
||||
return
|
||||
end
|
||||
|
||||
args, opts = Thor::Options.split(given_args)
|
||||
opts = given_opts || opts
|
||||
|
||||
instance = new(args, opts, config)
|
||||
yield instance if block_given?
|
||||
|
||||
if command
|
||||
instance.invoke_command(all_commands[command])
|
||||
else
|
||||
instance.invoke_all
|
||||
end
|
||||
end
|
||||
|
||||
# The banner for this class. You can customize it if you are invoking the
|
||||
# thor class by another ways which is not the Thor::Runner.
|
||||
def banner
|
||||
"#{basename} #{self_command.formatted_usage(self, false)}"
|
||||
end
|
||||
|
||||
# Represents the whole class as a command.
|
||||
def self_command #:nodoc:
|
||||
Thor::DynamicCommand.new(self.namespace, class_options)
|
||||
end
|
||||
alias self_task self_command
|
||||
|
||||
def baseclass #:nodoc:
|
||||
Thor::Group
|
||||
end
|
||||
|
||||
def create_command(meth) #:nodoc:
|
||||
commands[meth.to_s] = Thor::Command.new(meth, nil, nil, nil, nil)
|
||||
true
|
||||
end
|
||||
alias create_task create_command
|
||||
end
|
||||
|
||||
include Thor::Base
|
||||
|
||||
protected
|
||||
|
||||
# Shortcut to invoke with padding and block handling. Use internally by
|
||||
# invoke and invoke_from_option class methods.
|
||||
def _invoke_for_class_method(klass, command=nil, *args, &block) #:nodoc:
|
||||
with_padding do
|
||||
if block
|
||||
case block.arity
|
||||
when 3
|
||||
block.call(self, klass, command)
|
||||
when 2
|
||||
block.call(self, klass)
|
||||
when 1
|
||||
instance_exec(klass, &block)
|
||||
end
|
||||
else
|
||||
invoke klass, command, *args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
172
vendor/gems/thor-0.18.1/lib/thor/invocation.rb
vendored
Normal file
172
vendor/gems/thor-0.18.1/lib/thor/invocation.rb
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
class Thor
|
||||
module Invocation
|
||||
def self.included(base) #:nodoc:
|
||||
base.extend ClassMethods
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# This method is responsible for receiving a name and find the proper
|
||||
# class and command for it. The key is an optional parameter which is
|
||||
# available only in class methods invocations (i.e. in Thor::Group).
|
||||
def prepare_for_invocation(key, name) #:nodoc:
|
||||
case name
|
||||
when Symbol, String
|
||||
Thor::Util.find_class_and_command_by_namespace(name.to_s, !key)
|
||||
else
|
||||
name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Make initializer aware of invocations and the initialization args.
|
||||
def initialize(args=[], options={}, config={}, &block) #:nodoc:
|
||||
@_invocations = config[:invocations] || Hash.new { |h,k| h[k] = [] }
|
||||
@_initializer = [ args, options, config ]
|
||||
super
|
||||
end
|
||||
|
||||
# Receives a name and invokes it. The name can be a string (either "command" or
|
||||
# "namespace:command"), a Thor::Command, a Class or a Thor instance. If the
|
||||
# command cannot be guessed by name, it can also be supplied as second argument.
|
||||
#
|
||||
# You can also supply the arguments, options and configuration values for
|
||||
# the command to be invoked, if none is given, the same values used to
|
||||
# initialize the invoker are used to initialize the invoked.
|
||||
#
|
||||
# When no name is given, it will invoke the default command of the current class.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# class A < Thor
|
||||
# def foo
|
||||
# invoke :bar
|
||||
# invoke "b:hello", ["José"]
|
||||
# end
|
||||
#
|
||||
# def bar
|
||||
# invoke "b:hello", ["José"]
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# class B < Thor
|
||||
# def hello(name)
|
||||
# puts "hello #{name}"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# You can notice that the method "foo" above invokes two commands: "bar",
|
||||
# which belongs to the same class and "hello" which belongs to the class B.
|
||||
#
|
||||
# By using an invocation system you ensure that a command is invoked only once.
|
||||
# In the example above, invoking "foo" will invoke "b:hello" just once, even
|
||||
# if it's invoked later by "bar" method.
|
||||
#
|
||||
# When class A invokes class B, all arguments used on A initialization are
|
||||
# supplied to B. This allows lazy parse of options. Let's suppose you have
|
||||
# some rspec commands:
|
||||
#
|
||||
# class Rspec < Thor::Group
|
||||
# class_option :mock_framework, :type => :string, :default => :rr
|
||||
#
|
||||
# def invoke_mock_framework
|
||||
# invoke "rspec:#{options[:mock_framework]}"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# As you noticed, it invokes the given mock framework, which might have its
|
||||
# own options:
|
||||
#
|
||||
# class Rspec::RR < Thor::Group
|
||||
# class_option :style, :type => :string, :default => :mock
|
||||
# end
|
||||
#
|
||||
# Since it's not rspec concern to parse mock framework options, when RR
|
||||
# is invoked all options are parsed again, so RR can extract only the options
|
||||
# that it's going to use.
|
||||
#
|
||||
# If you want Rspec::RR to be initialized with its own set of options, you
|
||||
# have to do that explicitly:
|
||||
#
|
||||
# invoke "rspec:rr", [], :style => :foo
|
||||
#
|
||||
# Besides giving an instance, you can also give a class to invoke:
|
||||
#
|
||||
# invoke Rspec::RR, [], :style => :foo
|
||||
#
|
||||
def invoke(name=nil, *args)
|
||||
if name.nil?
|
||||
warn "[Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}"
|
||||
return invoke_all
|
||||
end
|
||||
|
||||
args.unshift(nil) if Array === args.first || NilClass === args.first
|
||||
command, args, opts, config = args
|
||||
|
||||
klass, command = _retrieve_class_and_command(name, command)
|
||||
raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
|
||||
|
||||
args, opts, config = _parse_initialization_options(args, opts, config)
|
||||
klass.send(:dispatch, command, args, opts, config) do |instance|
|
||||
instance.parent_options = options
|
||||
end
|
||||
end
|
||||
|
||||
# Invoke the given command if the given args.
|
||||
def invoke_command(command, *args) #:nodoc:
|
||||
current = @_invocations[self.class]
|
||||
|
||||
unless current.include?(command.name)
|
||||
current << command.name
|
||||
command.run(self, *args)
|
||||
end
|
||||
end
|
||||
alias invoke_task invoke_command
|
||||
|
||||
# Invoke all commands for the current instance.
|
||||
def invoke_all #:nodoc:
|
||||
self.class.all_commands.map { |_, command| invoke_command(command) }
|
||||
end
|
||||
|
||||
# Invokes using shell padding.
|
||||
def invoke_with_padding(*args)
|
||||
with_padding { invoke(*args) }
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Configuration values that are shared between invocations.
|
||||
def _shared_configuration #:nodoc:
|
||||
{ :invocations => @_invocations }
|
||||
end
|
||||
|
||||
# This method simply retrieves the class and command to be invoked.
|
||||
# If the name is nil or the given name is a command in the current class,
|
||||
# use the given name and return self as class. Otherwise, call
|
||||
# prepare_for_invocation in the current class.
|
||||
def _retrieve_class_and_command(name, sent_command=nil) #:nodoc:
|
||||
case
|
||||
when name.nil?
|
||||
[self.class, nil]
|
||||
when self.class.all_commands[name.to_s]
|
||||
[self.class, name.to_s]
|
||||
else
|
||||
klass, command = self.class.prepare_for_invocation(nil, name)
|
||||
[klass, command || sent_command]
|
||||
end
|
||||
end
|
||||
alias _retrieve_class_and_task _retrieve_class_and_command
|
||||
|
||||
# Initialize klass using values stored in the @_initializer.
|
||||
def _parse_initialization_options(args, opts, config) #:nodoc:
|
||||
stored_args, stored_opts, stored_config = @_initializer
|
||||
|
||||
args ||= stored_args.dup
|
||||
opts ||= stored_opts.dup
|
||||
|
||||
config ||= {}
|
||||
config = stored_config.merge(_shared_configuration).merge!(config)
|
||||
|
||||
[ args, opts, config ]
|
||||
end
|
||||
end
|
||||
end
|
||||
4
vendor/gems/thor-0.18.1/lib/thor/parser.rb
vendored
Normal file
4
vendor/gems/thor-0.18.1/lib/thor/parser.rb
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
require 'thor/parser/argument'
|
||||
require 'thor/parser/arguments'
|
||||
require 'thor/parser/option'
|
||||
require 'thor/parser/options'
|
||||
74
vendor/gems/thor-0.18.1/lib/thor/parser/argument.rb
vendored
Normal file
74
vendor/gems/thor-0.18.1/lib/thor/parser/argument.rb
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
class Thor
|
||||
class Argument #:nodoc:
|
||||
VALID_TYPES = [ :numeric, :hash, :array, :string ]
|
||||
|
||||
attr_reader :name, :description, :enum, :required, :type, :default, :banner
|
||||
alias :human_name :name
|
||||
|
||||
def initialize(name, options={})
|
||||
class_name = self.class.name.split("::").last
|
||||
|
||||
type = options[:type]
|
||||
|
||||
raise ArgumentError, "#{class_name} name can't be nil." if name.nil?
|
||||
raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type)
|
||||
|
||||
@name = name.to_s
|
||||
@description = options[:desc]
|
||||
@required = options.key?(:required) ? options[:required] : true
|
||||
@type = (type || :string).to_sym
|
||||
@default = options[:default]
|
||||
@banner = options[:banner] || default_banner
|
||||
@enum = options[:enum]
|
||||
|
||||
validate! # Trigger specific validations
|
||||
end
|
||||
|
||||
def usage
|
||||
required? ? banner : "[#{banner}]"
|
||||
end
|
||||
|
||||
def required?
|
||||
required
|
||||
end
|
||||
|
||||
def show_default?
|
||||
case default
|
||||
when Array, String, Hash
|
||||
!default.empty?
|
||||
else
|
||||
default
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def validate!
|
||||
if required? && !default.nil?
|
||||
raise ArgumentError, "An argument cannot be required and have default value."
|
||||
elsif @enum && !@enum.is_a?(Array)
|
||||
raise ArgumentError, "An argument cannot have an enum other than an array."
|
||||
end
|
||||
end
|
||||
|
||||
def valid_type?(type)
|
||||
self.class::VALID_TYPES.include?(type.to_sym)
|
||||
end
|
||||
|
||||
def default_banner
|
||||
case type
|
||||
when :boolean
|
||||
nil
|
||||
when :string, :default
|
||||
human_name.upcase
|
||||
when :numeric
|
||||
"N"
|
||||
when :hash
|
||||
"key:value"
|
||||
when :array
|
||||
"one two three"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
171
vendor/gems/thor-0.18.1/lib/thor/parser/arguments.rb
vendored
Normal file
171
vendor/gems/thor-0.18.1/lib/thor/parser/arguments.rb
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
class Thor
|
||||
class Arguments #:nodoc:
|
||||
NUMERIC = /(\d*\.\d+|\d+)/
|
||||
|
||||
# Receives an array of args and returns two arrays, one with arguments
|
||||
# and one with switches.
|
||||
#
|
||||
def self.split(args)
|
||||
arguments = []
|
||||
|
||||
args.each do |item|
|
||||
break if item =~ /^-/
|
||||
arguments << item
|
||||
end
|
||||
|
||||
return arguments, args[Range.new(arguments.size, -1)]
|
||||
end
|
||||
|
||||
def self.parse(*args)
|
||||
to_parse = args.pop
|
||||
new(*args).parse(to_parse)
|
||||
end
|
||||
|
||||
# Takes an array of Thor::Argument objects.
|
||||
#
|
||||
def initialize(arguments=[])
|
||||
@assigns, @non_assigned_required = {}, []
|
||||
@switches = arguments
|
||||
|
||||
arguments.each do |argument|
|
||||
if argument.default != nil
|
||||
@assigns[argument.human_name] = argument.default
|
||||
elsif argument.required?
|
||||
@non_assigned_required << argument
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def parse(args)
|
||||
@pile = args.dup
|
||||
|
||||
@switches.each do |argument|
|
||||
break unless peek
|
||||
@non_assigned_required.delete(argument)
|
||||
@assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name)
|
||||
end
|
||||
|
||||
check_requirement!
|
||||
@assigns
|
||||
end
|
||||
|
||||
def remaining
|
||||
@pile
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def no_or_skip?(arg)
|
||||
arg =~ /^--(no|skip)-([-\w]+)$/
|
||||
$2
|
||||
end
|
||||
|
||||
def last?
|
||||
@pile.empty?
|
||||
end
|
||||
|
||||
def peek
|
||||
@pile.first
|
||||
end
|
||||
|
||||
def shift
|
||||
@pile.shift
|
||||
end
|
||||
|
||||
def unshift(arg)
|
||||
unless arg.kind_of?(Array)
|
||||
@pile.unshift(arg)
|
||||
else
|
||||
@pile = arg + @pile
|
||||
end
|
||||
end
|
||||
|
||||
def current_is_value?
|
||||
peek && peek.to_s !~ /^-/
|
||||
end
|
||||
|
||||
# Runs through the argument array getting strings that contains ":" and
|
||||
# mark it as a hash:
|
||||
#
|
||||
# [ "name:string", "age:integer" ]
|
||||
#
|
||||
# Becomes:
|
||||
#
|
||||
# { "name" => "string", "age" => "integer" }
|
||||
#
|
||||
def parse_hash(name)
|
||||
return shift if peek.is_a?(Hash)
|
||||
hash = {}
|
||||
|
||||
while current_is_value? && peek.include?(?:)
|
||||
key, value = shift.split(':',2)
|
||||
hash[key] = value
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
# Runs through the argument array getting all strings until no string is
|
||||
# found or a switch is found.
|
||||
#
|
||||
# ["a", "b", "c"]
|
||||
#
|
||||
# And returns it as an array:
|
||||
#
|
||||
# ["a", "b", "c"]
|
||||
#
|
||||
def parse_array(name)
|
||||
return shift if peek.is_a?(Array)
|
||||
array = []
|
||||
|
||||
while current_is_value?
|
||||
array << shift
|
||||
end
|
||||
array
|
||||
end
|
||||
|
||||
# Check if the peek is numeric format and return a Float or Integer.
|
||||
# Otherwise raises an error.
|
||||
#
|
||||
def parse_numeric(name)
|
||||
return shift if peek.is_a?(Numeric)
|
||||
|
||||
unless peek =~ NUMERIC && $& == peek
|
||||
raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}"
|
||||
end
|
||||
|
||||
$&.index('.') ? shift.to_f : shift.to_i
|
||||
end
|
||||
|
||||
# Parse string:
|
||||
# for --string-arg, just return the current value in the pile
|
||||
# for --no-string-arg, nil
|
||||
#
|
||||
def parse_string(name)
|
||||
if no_or_skip?(name)
|
||||
nil
|
||||
else
|
||||
value = shift
|
||||
if @switches.is_a?(Hash) && switch = @switches[name]
|
||||
if switch.enum && !switch.enum.include?(value)
|
||||
raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
|
||||
end
|
||||
end
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
# Raises an error if @non_assigned_required array is not empty.
|
||||
#
|
||||
def check_requirement!
|
||||
unless @non_assigned_required.empty?
|
||||
names = @non_assigned_required.map do |o|
|
||||
o.respond_to?(:switch_name) ? o.switch_name : o.human_name
|
||||
end.join("', '")
|
||||
|
||||
class_name = self.class.name.split('::').last.downcase
|
||||
raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
121
vendor/gems/thor-0.18.1/lib/thor/parser/option.rb
vendored
Normal file
121
vendor/gems/thor-0.18.1/lib/thor/parser/option.rb
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
class Thor
|
||||
class Option < Argument #:nodoc:
|
||||
attr_reader :aliases, :group, :lazy_default, :hide
|
||||
|
||||
VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
|
||||
|
||||
def initialize(name, options={})
|
||||
options[:required] = false unless options.key?(:required)
|
||||
super
|
||||
@lazy_default = options[:lazy_default]
|
||||
@group = options[:group].to_s.capitalize if options[:group]
|
||||
@aliases = Array(options[:aliases])
|
||||
@hide = options[:hide]
|
||||
end
|
||||
|
||||
# This parse quick options given as method_options. It makes several
|
||||
# assumptions, but you can be more specific using the option method.
|
||||
#
|
||||
# parse :foo => "bar"
|
||||
# #=> Option foo with default value bar
|
||||
#
|
||||
# parse [:foo, :baz] => "bar"
|
||||
# #=> Option foo with default value bar and alias :baz
|
||||
#
|
||||
# parse :foo => :required
|
||||
# #=> Required option foo without default value
|
||||
#
|
||||
# parse :foo => 2
|
||||
# #=> Option foo with default value 2 and type numeric
|
||||
#
|
||||
# parse :foo => :numeric
|
||||
# #=> Option foo without default value and type numeric
|
||||
#
|
||||
# parse :foo => true
|
||||
# #=> Option foo with default value true and type boolean
|
||||
#
|
||||
# The valid types are :boolean, :numeric, :hash, :array and :string. If none
|
||||
# is given a default type is assumed. This default type accepts arguments as
|
||||
# string (--foo=value) or booleans (just --foo).
|
||||
#
|
||||
# By default all options are optional, unless :required is given.
|
||||
#
|
||||
def self.parse(key, value)
|
||||
if key.is_a?(Array)
|
||||
name, *aliases = key
|
||||
else
|
||||
name, aliases = key, []
|
||||
end
|
||||
|
||||
name = name.to_s
|
||||
default = value
|
||||
|
||||
type = case value
|
||||
when Symbol
|
||||
default = nil
|
||||
if VALID_TYPES.include?(value)
|
||||
value
|
||||
elsif required = (value == :required)
|
||||
:string
|
||||
end
|
||||
when TrueClass, FalseClass
|
||||
:boolean
|
||||
when Numeric
|
||||
:numeric
|
||||
when Hash, Array, String
|
||||
value.class.name.downcase.to_sym
|
||||
end
|
||||
self.new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases)
|
||||
end
|
||||
|
||||
def switch_name
|
||||
@switch_name ||= dasherized? ? name : dasherize(name)
|
||||
end
|
||||
|
||||
def human_name
|
||||
@human_name ||= dasherized? ? undasherize(name) : name
|
||||
end
|
||||
|
||||
def usage(padding=0)
|
||||
sample = if banner && !banner.to_s.empty?
|
||||
"#{switch_name}=#{banner}"
|
||||
else
|
||||
switch_name
|
||||
end
|
||||
|
||||
sample = "[#{sample}]" unless required?
|
||||
|
||||
if aliases.empty?
|
||||
(" " * padding) << sample
|
||||
else
|
||||
"#{aliases.join(', ')}, #{sample}"
|
||||
end
|
||||
end
|
||||
|
||||
VALID_TYPES.each do |type|
|
||||
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||
def #{type}?
|
||||
self.type == #{type.inspect}
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def validate!
|
||||
raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
|
||||
end
|
||||
|
||||
def dasherized?
|
||||
name.index('-') == 0
|
||||
end
|
||||
|
||||
def undasherize(str)
|
||||
str.sub(/^-{1,2}/, '')
|
||||
end
|
||||
|
||||
def dasherize(str)
|
||||
(str.length > 1 ? "--" : "-") + str.gsub('_', '-')
|
||||
end
|
||||
end
|
||||
end
|
||||
218
vendor/gems/thor-0.18.1/lib/thor/parser/options.rb
vendored
Normal file
218
vendor/gems/thor-0.18.1/lib/thor/parser/options.rb
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
class Thor
|
||||
class Options < Arguments #:nodoc:
|
||||
LONG_RE = /^(--\w+(?:-\w+)*)$/
|
||||
SHORT_RE = /^(-[a-z])$/i
|
||||
EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
|
||||
SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args
|
||||
SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i
|
||||
OPTS_END = '--'.freeze
|
||||
|
||||
# Receives a hash and makes it switches.
|
||||
def self.to_switches(options)
|
||||
options.map do |key, value|
|
||||
case value
|
||||
when true
|
||||
"--#{key}"
|
||||
when Array
|
||||
"--#{key} #{value.map{ |v| v.inspect }.join(' ')}"
|
||||
when Hash
|
||||
"--#{key} #{value.map{ |k,v| "#{k}:#{v}" }.join(' ')}"
|
||||
when nil, false
|
||||
""
|
||||
else
|
||||
"--#{key} #{value.inspect}"
|
||||
end
|
||||
end.join(" ")
|
||||
end
|
||||
|
||||
# Takes a hash of Thor::Option and a hash with defaults.
|
||||
#
|
||||
# If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
|
||||
# an unknown option or a regular argument.
|
||||
def initialize(hash_options={}, defaults={}, stop_on_unknown=false)
|
||||
@stop_on_unknown = stop_on_unknown
|
||||
options = hash_options.values
|
||||
super(options)
|
||||
|
||||
# Add defaults
|
||||
defaults.each do |key, value|
|
||||
@assigns[key.to_s] = value
|
||||
@non_assigned_required.delete(hash_options[key])
|
||||
end
|
||||
|
||||
@shorts, @switches, @extra = {}, {}, []
|
||||
|
||||
options.each do |option|
|
||||
@switches[option.switch_name] = option
|
||||
|
||||
option.aliases.each do |short|
|
||||
name = short.to_s.sub(/^(?!\-)/, '-')
|
||||
@shorts[name] ||= option.switch_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def remaining
|
||||
@extra
|
||||
end
|
||||
|
||||
def peek
|
||||
return super unless @parsing_options
|
||||
|
||||
result = super
|
||||
if result == OPTS_END
|
||||
shift
|
||||
@parsing_options = false
|
||||
super
|
||||
else
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
def parse(args)
|
||||
@pile = args.dup
|
||||
@parsing_options = true
|
||||
|
||||
while peek
|
||||
if parsing_options?
|
||||
match, is_switch = current_is_switch?
|
||||
shifted = shift
|
||||
|
||||
if is_switch
|
||||
case shifted
|
||||
when SHORT_SQ_RE
|
||||
unshift($1.split('').map { |f| "-#{f}" })
|
||||
next
|
||||
when EQ_RE, SHORT_NUM
|
||||
unshift($2)
|
||||
switch = $1
|
||||
when LONG_RE, SHORT_RE
|
||||
switch = $1
|
||||
end
|
||||
|
||||
switch = normalize_switch(switch)
|
||||
option = switch_option(switch)
|
||||
@assigns[option.human_name] = parse_peek(switch, option)
|
||||
elsif @stop_on_unknown
|
||||
@parsing_options = false
|
||||
@extra << shifted
|
||||
@extra << shift while peek
|
||||
break
|
||||
elsif match
|
||||
@extra << shifted
|
||||
@extra << shift while peek && peek !~ /^-/
|
||||
else
|
||||
@extra << shifted
|
||||
end
|
||||
else
|
||||
@extra << shift
|
||||
end
|
||||
end
|
||||
|
||||
check_requirement!
|
||||
|
||||
assigns = Thor::CoreExt::HashWithIndifferentAccess.new(@assigns)
|
||||
assigns.freeze
|
||||
assigns
|
||||
end
|
||||
|
||||
def check_unknown!
|
||||
# an unknown option starts with - or -- and has no more --'s afterward.
|
||||
unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ }
|
||||
raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty?
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Check if the current value in peek is a registered switch.
|
||||
#
|
||||
# Two booleans are returned. The first is true if the current value
|
||||
# starts with a hyphen; the second is true if it is a registered switch.
|
||||
def current_is_switch?
|
||||
case peek
|
||||
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
|
||||
[true, switch?($1)]
|
||||
when SHORT_SQ_RE
|
||||
[true, $1.split('').any? { |f| switch?("-#{f}") }]
|
||||
else
|
||||
[false, false]
|
||||
end
|
||||
end
|
||||
|
||||
def current_is_switch_formatted?
|
||||
case peek
|
||||
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def current_is_value?
|
||||
peek && (!parsing_options? || super)
|
||||
end
|
||||
|
||||
def switch?(arg)
|
||||
switch_option(normalize_switch(arg))
|
||||
end
|
||||
|
||||
def switch_option(arg)
|
||||
if match = no_or_skip?(arg)
|
||||
@switches[arg] || @switches["--#{match}"]
|
||||
else
|
||||
@switches[arg]
|
||||
end
|
||||
end
|
||||
|
||||
# Check if the given argument is actually a shortcut.
|
||||
#
|
||||
def normalize_switch(arg)
|
||||
(@shorts[arg] || arg).tr('_', '-')
|
||||
end
|
||||
|
||||
def parsing_options?
|
||||
peek
|
||||
@parsing_options
|
||||
end
|
||||
|
||||
# Parse boolean values which can be given as --foo=true, --foo or --no-foo.
|
||||
#
|
||||
def parse_boolean(switch)
|
||||
if current_is_value?
|
||||
if ["true", "TRUE", "t", "T", true].include?(peek)
|
||||
shift
|
||||
true
|
||||
elsif ["false", "FALSE", "f", "F", false].include?(peek)
|
||||
shift
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
else
|
||||
@switches.key?(switch) || !no_or_skip?(switch)
|
||||
end
|
||||
end
|
||||
|
||||
# Parse the value at the peek analyzing if it requires an input or not.
|
||||
#
|
||||
def parse_peek(switch, option)
|
||||
if parsing_options? && (current_is_switch_formatted? || last?)
|
||||
if option.boolean?
|
||||
# No problem for boolean types
|
||||
elsif no_or_skip?(switch)
|
||||
return nil # User set value to nil
|
||||
elsif option.string? && !option.required?
|
||||
# Return the default if there is one, else the human name
|
||||
return option.lazy_default || option.default || option.human_name
|
||||
elsif option.lazy_default
|
||||
return option.lazy_default
|
||||
else
|
||||
raise MalformattedArgumentError, "No value provided for option '#{switch}'"
|
||||
end
|
||||
end
|
||||
|
||||
@non_assigned_required.delete(option)
|
||||
send(:"parse_#{option.type}", switch)
|
||||
end
|
||||
end
|
||||
end
|
||||
72
vendor/gems/thor-0.18.1/lib/thor/rake_compat.rb
vendored
Normal file
72
vendor/gems/thor-0.18.1/lib/thor/rake_compat.rb
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
require 'rake'
|
||||
require 'rake/dsl_definition'
|
||||
|
||||
class Thor
|
||||
# Adds a compatibility layer to your Thor classes which allows you to use
|
||||
# rake package tasks. For example, to use rspec rake tasks, one can do:
|
||||
#
|
||||
# require 'thor/rake_compat'
|
||||
# require 'rspec/core/rake_task'
|
||||
#
|
||||
# class Default < Thor
|
||||
# include Thor::RakeCompat
|
||||
#
|
||||
# RSpec::Core::RakeTask.new(:spec) do |t|
|
||||
# t.spec_opts = ['--options', "./.rspec"]
|
||||
# t.spec_files = FileList['spec/**/*_spec.rb']
|
||||
# end
|
||||
# end
|
||||
#
|
||||
module RakeCompat
|
||||
include Rake::DSL if defined?(Rake::DSL)
|
||||
|
||||
def self.rake_classes
|
||||
@rake_classes ||= []
|
||||
end
|
||||
|
||||
def self.included(base)
|
||||
# Hack. Make rakefile point to invoker, so rdoc task is generated properly.
|
||||
rakefile = File.basename(caller[0].match(/(.*):\d+/)[1])
|
||||
Rake.application.instance_variable_set(:@rakefile, rakefile)
|
||||
self.rake_classes << base
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# override task on (main), for compatibility with Rake 0.9
|
||||
self.instance_eval do
|
||||
alias rake_namespace namespace
|
||||
|
||||
def task(*)
|
||||
task = super
|
||||
|
||||
if klass = Thor::RakeCompat.rake_classes.last
|
||||
non_namespaced_name = task.name.split(':').last
|
||||
|
||||
description = non_namespaced_name
|
||||
description << task.arg_names.map{ |n| n.to_s.upcase }.join(' ')
|
||||
description.strip!
|
||||
|
||||
klass.desc description, Rake.application.last_description || non_namespaced_name
|
||||
Rake.application.last_description = nil
|
||||
klass.send :define_method, non_namespaced_name do |*args|
|
||||
Rake::Task[task.name.to_sym].invoke(*args)
|
||||
end
|
||||
end
|
||||
|
||||
task
|
||||
end
|
||||
|
||||
def namespace(name)
|
||||
if klass = Thor::RakeCompat.rake_classes.last
|
||||
const_name = Thor::Util.camel_case(name.to_s).to_sym
|
||||
klass.const_set(const_name, Class.new(Thor))
|
||||
new_klass = klass.const_get(const_name)
|
||||
Thor::RakeCompat.rake_classes << new_klass
|
||||
end
|
||||
|
||||
super
|
||||
Thor::RakeCompat.rake_classes.pop
|
||||
end
|
||||
end
|
||||
|
||||
322
vendor/gems/thor-0.18.1/lib/thor/runner.rb
vendored
Normal file
322
vendor/gems/thor-0.18.1/lib/thor/runner.rb
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
require 'thor'
|
||||
require 'thor/group'
|
||||
require 'thor/core_ext/io_binary_read'
|
||||
|
||||
require 'fileutils'
|
||||
require 'open-uri'
|
||||
require 'yaml'
|
||||
require 'digest/md5'
|
||||
require 'pathname'
|
||||
|
||||
class Thor::Runner < Thor #:nodoc:
|
||||
map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
|
||||
|
||||
# Override Thor#help so it can give information about any class and any method.
|
||||
#
|
||||
def help(meth = nil)
|
||||
if meth && !self.respond_to?(meth)
|
||||
initialize_thorfiles(meth)
|
||||
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
||||
self.class.handle_no_command_error(command, false) if klass.nil?
|
||||
klass.start(["-h", command].compact, :shell => self.shell)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# If a command is not found on Thor::Runner, method missing is invoked and
|
||||
# Thor::Runner is then responsible for finding the command in all classes.
|
||||
#
|
||||
def method_missing(meth, *args)
|
||||
meth = meth.to_s
|
||||
initialize_thorfiles(meth)
|
||||
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
||||
self.class.handle_no_command_error(command, false) if klass.nil?
|
||||
args.unshift(command) if command
|
||||
klass.start(args, :shell => self.shell)
|
||||
end
|
||||
|
||||
desc "install NAME", "Install an optionally named Thor file into your system commands"
|
||||
method_options :as => :string, :relative => :boolean, :force => :boolean
|
||||
def install(name)
|
||||
initialize_thorfiles
|
||||
|
||||
# If a directory name is provided as the argument, look for a 'main.thor'
|
||||
# command in said directory.
|
||||
begin
|
||||
if File.directory?(File.expand_path(name))
|
||||
base, package = File.join(name, "main.thor"), :directory
|
||||
contents = open(base) {|input| input.read }
|
||||
else
|
||||
base, package = name, :file
|
||||
contents = open(name) {|input| input.read }
|
||||
end
|
||||
rescue OpenURI::HTTPError
|
||||
raise Error, "Error opening URI '#{name}'"
|
||||
rescue Errno::ENOENT
|
||||
raise Error, "Error opening file '#{name}'"
|
||||
end
|
||||
|
||||
say "Your Thorfile contains:"
|
||||
say contents
|
||||
|
||||
unless options["force"]
|
||||
return false if no?("Do you wish to continue [y/N]?")
|
||||
end
|
||||
|
||||
as = options["as"] || begin
|
||||
first_line = contents.split("\n")[0]
|
||||
(match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
|
||||
end
|
||||
|
||||
unless as
|
||||
basename = File.basename(name)
|
||||
as = ask("Please specify a name for #{name} in the system repository [#{basename}]:")
|
||||
as = basename if as.empty?
|
||||
end
|
||||
|
||||
location = if options[:relative] || name =~ /^https?:\/\//
|
||||
name
|
||||
else
|
||||
File.expand_path(name)
|
||||
end
|
||||
|
||||
thor_yaml[as] = {
|
||||
:filename => Digest::MD5.hexdigest(name + as),
|
||||
:location => location,
|
||||
:namespaces => Thor::Util.namespaces_in_content(contents, base)
|
||||
}
|
||||
|
||||
save_yaml(thor_yaml)
|
||||
say "Storing thor file in your system repository"
|
||||
destination = File.join(thor_root, thor_yaml[as][:filename])
|
||||
|
||||
if package == :file
|
||||
File.open(destination, "w") { |f| f.puts contents }
|
||||
else
|
||||
FileUtils.cp_r(name, destination)
|
||||
end
|
||||
|
||||
thor_yaml[as][:filename] # Indicate success
|
||||
end
|
||||
|
||||
desc "version", "Show Thor version"
|
||||
def version
|
||||
require 'thor/version'
|
||||
say "Thor #{Thor::VERSION}"
|
||||
end
|
||||
|
||||
desc "uninstall NAME", "Uninstall a named Thor module"
|
||||
def uninstall(name)
|
||||
raise Error, "Can't find module '#{name}'" unless thor_yaml[name]
|
||||
say "Uninstalling #{name}."
|
||||
FileUtils.rm_rf(File.join(thor_root, "#{thor_yaml[name][:filename]}"))
|
||||
|
||||
thor_yaml.delete(name)
|
||||
save_yaml(thor_yaml)
|
||||
|
||||
puts "Done."
|
||||
end
|
||||
|
||||
desc "update NAME", "Update a Thor file from its original location"
|
||||
def update(name)
|
||||
raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location]
|
||||
|
||||
say "Updating '#{name}' from #{thor_yaml[name][:location]}"
|
||||
|
||||
old_filename = thor_yaml[name][:filename]
|
||||
self.options = self.options.merge("as" => name)
|
||||
|
||||
if File.directory? File.expand_path(name)
|
||||
FileUtils.rm_rf(File.join(thor_root, old_filename))
|
||||
|
||||
thor_yaml.delete(old_filename)
|
||||
save_yaml(thor_yaml)
|
||||
|
||||
filename = install(name)
|
||||
else
|
||||
filename = install(thor_yaml[name][:location])
|
||||
end
|
||||
|
||||
unless filename == old_filename
|
||||
File.delete(File.join(thor_root, old_filename))
|
||||
end
|
||||
end
|
||||
|
||||
desc "installed", "List the installed Thor modules and commands"
|
||||
method_options :internal => :boolean
|
||||
def installed
|
||||
initialize_thorfiles(nil, true)
|
||||
display_klasses(true, options["internal"])
|
||||
end
|
||||
|
||||
desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)"
|
||||
method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
|
||||
def list(search="")
|
||||
initialize_thorfiles
|
||||
|
||||
search = ".*#{search}" if options["substring"]
|
||||
search = /^#{search}.*/i
|
||||
group = options[:group] || "standard"
|
||||
|
||||
klasses = Thor::Base.subclasses.select do |k|
|
||||
(options[:all] || k.group == group) && k.namespace =~ search
|
||||
end
|
||||
|
||||
display_klasses(false, false, klasses)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.banner(command, all = false, subcommand = false)
|
||||
"thor " + command.formatted_usage(self, all, subcommand)
|
||||
end
|
||||
|
||||
def thor_root
|
||||
Thor::Util.thor_root
|
||||
end
|
||||
|
||||
def thor_yaml
|
||||
@thor_yaml ||= begin
|
||||
yaml_file = File.join(thor_root, "thor.yml")
|
||||
yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file)
|
||||
yaml || {}
|
||||
end
|
||||
end
|
||||
|
||||
# Save the yaml file. If none exists in thor root, creates one.
|
||||
#
|
||||
def save_yaml(yaml)
|
||||
yaml_file = File.join(thor_root, "thor.yml")
|
||||
|
||||
unless File.exists?(yaml_file)
|
||||
FileUtils.mkdir_p(thor_root)
|
||||
yaml_file = File.join(thor_root, "thor.yml")
|
||||
FileUtils.touch(yaml_file)
|
||||
end
|
||||
|
||||
File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml }
|
||||
end
|
||||
|
||||
def self.exit_on_failure?
|
||||
true
|
||||
end
|
||||
|
||||
# Load the Thorfiles. If relevant_to is supplied, looks for specific files
|
||||
# in the thor_root instead of loading them all.
|
||||
#
|
||||
# By default, it also traverses the current path until find Thor files, as
|
||||
# described in thorfiles. This look up can be skipped by suppliying
|
||||
# skip_lookup true.
|
||||
#
|
||||
def initialize_thorfiles(relevant_to=nil, skip_lookup=false)
|
||||
thorfiles(relevant_to, skip_lookup).each do |f|
|
||||
Thor::Util.load_thorfile(f, nil, options[:debug]) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
|
||||
end
|
||||
end
|
||||
|
||||
# Finds Thorfiles by traversing from your current directory down to the root
|
||||
# directory of your system. If at any time we find a Thor file, we stop.
|
||||
#
|
||||
# We also ensure that system-wide Thorfiles are loaded first, so local
|
||||
# Thorfiles can override them.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# If we start at /Users/wycats/dev/thor ...
|
||||
#
|
||||
# 1. /Users/wycats/dev/thor
|
||||
# 2. /Users/wycats/dev
|
||||
# 3. /Users/wycats <-- we find a Thorfile here, so we stop
|
||||
#
|
||||
# Suppose we start at c:\Documents and Settings\james\dev\thor ...
|
||||
#
|
||||
# 1. c:\Documents and Settings\james\dev\thor
|
||||
# 2. c:\Documents and Settings\james\dev
|
||||
# 3. c:\Documents and Settings\james
|
||||
# 4. c:\Documents and Settings
|
||||
# 5. c:\ <-- no Thorfiles found!
|
||||
#
|
||||
def thorfiles(relevant_to=nil, skip_lookup=false)
|
||||
thorfiles = []
|
||||
|
||||
unless skip_lookup
|
||||
Pathname.pwd.ascend do |path|
|
||||
thorfiles = Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten
|
||||
break unless thorfiles.empty?
|
||||
end
|
||||
end
|
||||
|
||||
files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Thor::Util.thor_root_glob)
|
||||
files += thorfiles
|
||||
files -= ["#{thor_root}/thor.yml"]
|
||||
|
||||
files.map! do |file|
|
||||
File.directory?(file) ? File.join(file, "main.thor") : file
|
||||
end
|
||||
end
|
||||
|
||||
# Load Thorfiles relevant to the given method. If you provide "foo:bar" it
|
||||
# will load all thor files in the thor.yaml that has "foo" e "foo:bar"
|
||||
# namespaces registered.
|
||||
#
|
||||
def thorfiles_relevant_to(meth)
|
||||
lookup = [ meth, meth.split(":")[0...-1].join(":") ]
|
||||
|
||||
files = thor_yaml.select do |k, v|
|
||||
v[:namespaces] && !(v[:namespaces] & lookup).empty?
|
||||
end
|
||||
|
||||
files.map { |k, v| File.join(thor_root, "#{v[:filename]}") }
|
||||
end
|
||||
|
||||
# Display information about the given klasses. If with_module is given,
|
||||
# it shows a table with information extracted from the yaml file.
|
||||
#
|
||||
def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
|
||||
klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
|
||||
|
||||
raise Error, "No Thor commands available" if klasses.empty?
|
||||
show_modules if with_modules && !thor_yaml.empty?
|
||||
|
||||
list = Hash.new { |h,k| h[k] = [] }
|
||||
groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
|
||||
|
||||
# Get classes which inherit from Thor
|
||||
(klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) }
|
||||
|
||||
# Get classes which inherit from Thor::Base
|
||||
groups.map! { |k| k.printable_commands(false).first }
|
||||
list["root"] = groups
|
||||
|
||||
# Order namespaces with default coming first
|
||||
list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
|
||||
list.each { |n, commands| display_commands(n, commands) unless commands.empty? }
|
||||
end
|
||||
|
||||
def display_commands(namespace, list) #:nodoc:
|
||||
list.sort!{ |a,b| a[0] <=> b[0] }
|
||||
|
||||
say shell.set_color(namespace, :blue, true)
|
||||
say "-" * namespace.size
|
||||
|
||||
print_table(list, :truncate => true)
|
||||
say
|
||||
end
|
||||
alias display_tasks display_commands
|
||||
|
||||
def show_modules #:nodoc:
|
||||
info = []
|
||||
labels = ["Modules", "Namespaces"]
|
||||
|
||||
info << labels
|
||||
info << [ "-" * labels[0].size, "-" * labels[1].size ]
|
||||
|
||||
thor_yaml.each do |name, hash|
|
||||
info << [ name, hash[:namespaces].join(", ") ]
|
||||
end
|
||||
|
||||
print_table info
|
||||
say ""
|
||||
end
|
||||
end
|
||||
88
vendor/gems/thor-0.18.1/lib/thor/shell.rb
vendored
Normal file
88
vendor/gems/thor-0.18.1/lib/thor/shell.rb
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
require 'rbconfig'
|
||||
|
||||
class Thor
|
||||
module Base
|
||||
# Returns the shell used in all Thor classes. If you are in a Unix platform
|
||||
# it will use a colored log, otherwise it will use a basic one without color.
|
||||
#
|
||||
def self.shell
|
||||
@shell ||= if ENV['THOR_SHELL'] && ENV['THOR_SHELL'].size > 0
|
||||
Thor::Shell.const_get(ENV['THOR_SHELL'])
|
||||
elsif ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) && !(ENV['ANSICON']))
|
||||
Thor::Shell::Basic
|
||||
else
|
||||
Thor::Shell::Color
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the shell used in all Thor classes.
|
||||
#
|
||||
def self.shell=(klass)
|
||||
@shell = klass
|
||||
end
|
||||
end
|
||||
|
||||
module Shell
|
||||
SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
|
||||
|
||||
autoload :Basic, 'thor/shell/basic'
|
||||
autoload :Color, 'thor/shell/color'
|
||||
autoload :HTML, 'thor/shell/html'
|
||||
|
||||
# Add shell to initialize config values.
|
||||
#
|
||||
# ==== Configuration
|
||||
# shell<Object>:: An instance of the shell to be used.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# class MyScript < Thor
|
||||
# argument :first, :type => :numeric
|
||||
# end
|
||||
#
|
||||
# MyScript.new [1.0], { :foo => :bar }, :shell => Thor::Shell::Basic.new
|
||||
#
|
||||
def initialize(args=[], options={}, config={})
|
||||
super
|
||||
self.shell = config[:shell]
|
||||
self.shell.base ||= self if self.shell.respond_to?(:base)
|
||||
end
|
||||
|
||||
# Holds the shell for the given Thor instance. If no shell is given,
|
||||
# it gets a default shell from Thor::Base.shell.
|
||||
def shell
|
||||
@shell ||= Thor::Base.shell.new
|
||||
end
|
||||
|
||||
# Sets the shell for this thor class.
|
||||
def shell=(shell)
|
||||
@shell = shell
|
||||
end
|
||||
|
||||
# Common methods that are delegated to the shell.
|
||||
SHELL_DELEGATED_METHODS.each do |method|
|
||||
module_eval <<-METHOD, __FILE__, __LINE__
|
||||
def #{method}(*args,&block)
|
||||
shell.#{method}(*args,&block)
|
||||
end
|
||||
METHOD
|
||||
end
|
||||
|
||||
# Yields the given block with padding.
|
||||
def with_padding
|
||||
shell.padding += 1
|
||||
yield
|
||||
ensure
|
||||
shell.padding -= 1
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Allow shell to be shared between invocations.
|
||||
#
|
||||
def _shared_configuration #:nodoc:
|
||||
super.merge!(:shell => self.shell)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
393
vendor/gems/thor-0.18.1/lib/thor/shell/basic.rb
vendored
Normal file
393
vendor/gems/thor-0.18.1/lib/thor/shell/basic.rb
vendored
Normal file
@@ -0,0 +1,393 @@
|
||||
require 'tempfile'
|
||||
|
||||
class Thor
|
||||
module Shell
|
||||
class Basic
|
||||
attr_accessor :base
|
||||
attr_reader :padding
|
||||
|
||||
# Initialize base, mute and padding to nil.
|
||||
#
|
||||
def initialize #:nodoc:
|
||||
@base, @mute, @padding = nil, false, 0
|
||||
end
|
||||
|
||||
# Mute everything that's inside given block
|
||||
#
|
||||
def mute
|
||||
@mute = true
|
||||
yield
|
||||
ensure
|
||||
@mute = false
|
||||
end
|
||||
|
||||
# Check if base is muted
|
||||
#
|
||||
def mute?
|
||||
@mute
|
||||
end
|
||||
|
||||
# Sets the output padding, not allowing less than zero values.
|
||||
#
|
||||
def padding=(value)
|
||||
@padding = [0, value].max
|
||||
end
|
||||
|
||||
# Asks something to the user and receives a response.
|
||||
#
|
||||
# If asked to limit the correct responses, you can pass in an
|
||||
# array of acceptable answers. If one of those is not supplied,
|
||||
# they will be shown a message stating that one of those answers
|
||||
# must be given and re-asked the question.
|
||||
#
|
||||
# ==== Example
|
||||
# ask("What is your name?")
|
||||
#
|
||||
# ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
|
||||
#
|
||||
def ask(statement, *args)
|
||||
options = args.last.is_a?(Hash) ? args.pop : {}
|
||||
|
||||
options[:limited_to] ? ask_filtered(statement, options[:limited_to], *args) : ask_simply(statement, *args)
|
||||
end
|
||||
|
||||
# Say (print) something to the user. If the sentence ends with a whitespace
|
||||
# or tab character, a new line is not appended (print + flush). Otherwise
|
||||
# are passed straight to puts (behavior got from Highline).
|
||||
#
|
||||
# ==== Example
|
||||
# say("I know you knew that.")
|
||||
#
|
||||
def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)\Z/))
|
||||
message = message.to_s
|
||||
|
||||
message = set_color(message, *color) if color && can_display_colors?
|
||||
|
||||
spaces = " " * padding
|
||||
|
||||
if force_new_line
|
||||
stdout.puts(spaces + message)
|
||||
else
|
||||
stdout.print(spaces + message)
|
||||
end
|
||||
stdout.flush
|
||||
end
|
||||
|
||||
# Say a status with the given color and appends the message. Since this
|
||||
# method is used frequently by actions, it allows nil or false to be given
|
||||
# in log_status, avoiding the message from being shown. If a Symbol is
|
||||
# given in log_status, it's used as the color.
|
||||
#
|
||||
def say_status(status, message, log_status=true)
|
||||
return if quiet? || log_status == false
|
||||
spaces = " " * (padding + 1)
|
||||
color = log_status.is_a?(Symbol) ? log_status : :green
|
||||
|
||||
status = status.to_s.rjust(12)
|
||||
status = set_color status, color, true if color
|
||||
|
||||
stdout.puts "#{status}#{spaces}#{message}"
|
||||
stdout.flush
|
||||
end
|
||||
|
||||
# Make a question the to user and returns true if the user replies "y" or
|
||||
# "yes".
|
||||
#
|
||||
def yes?(statement, color=nil)
|
||||
!!(ask(statement, color) =~ is?(:yes))
|
||||
end
|
||||
|
||||
# Make a question the to user and returns true if the user replies "n" or
|
||||
# "no".
|
||||
#
|
||||
def no?(statement, color=nil)
|
||||
!yes?(statement, color)
|
||||
end
|
||||
|
||||
# Prints values in columns
|
||||
#
|
||||
# ==== Parameters
|
||||
# Array[String, String, ...]
|
||||
#
|
||||
def print_in_columns(array)
|
||||
return if array.empty?
|
||||
colwidth = (array.map{|el| el.to_s.size}.max || 0) + 2
|
||||
array.each_with_index do |value, index|
|
||||
# Don't output trailing spaces when printing the last column
|
||||
if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
|
||||
stdout.puts value
|
||||
else
|
||||
stdout.printf("%-#{colwidth}s", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Prints a table.
|
||||
#
|
||||
# ==== Parameters
|
||||
# Array[Array[String, String, ...]]
|
||||
#
|
||||
# ==== Options
|
||||
# indent<Integer>:: Indent the first column by indent value.
|
||||
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
|
||||
#
|
||||
def print_table(array, options={})
|
||||
return if array.empty?
|
||||
|
||||
formats, indent, colwidth = [], options[:indent].to_i, options[:colwidth]
|
||||
options[:truncate] = terminal_width if options[:truncate] == true
|
||||
|
||||
formats << "%-#{colwidth + 2}s" if colwidth
|
||||
start = colwidth ? 1 : 0
|
||||
|
||||
colcount = array.max{|a,b| a.size <=> b.size }.size
|
||||
|
||||
maximas = []
|
||||
|
||||
start.upto(colcount - 1) do |index|
|
||||
maxima = array.map {|row| row[index] ? row[index].to_s.size : 0 }.max
|
||||
maximas << maxima
|
||||
if index == colcount - 1
|
||||
# Don't output 2 trailing spaces when printing the last column
|
||||
formats << "%-s"
|
||||
else
|
||||
formats << "%-#{maxima + 2}s"
|
||||
end
|
||||
end
|
||||
|
||||
formats[0] = formats[0].insert(0, " " * indent)
|
||||
formats << "%s"
|
||||
|
||||
array.each do |row|
|
||||
sentence = ""
|
||||
|
||||
row.each_with_index do |column, index|
|
||||
maxima = maximas[index]
|
||||
|
||||
if column.is_a?(Numeric)
|
||||
if index == row.size - 1
|
||||
# Don't output 2 trailing spaces when printing the last column
|
||||
f = "%#{maxima}s"
|
||||
else
|
||||
f = "%#{maxima}s "
|
||||
end
|
||||
else
|
||||
f = formats[index]
|
||||
end
|
||||
sentence << f % column.to_s
|
||||
end
|
||||
|
||||
sentence = truncate(sentence, options[:truncate]) if options[:truncate]
|
||||
stdout.puts sentence
|
||||
end
|
||||
end
|
||||
|
||||
# Prints a long string, word-wrapping the text to the current width of the
|
||||
# terminal display. Ideal for printing heredocs.
|
||||
#
|
||||
# ==== Parameters
|
||||
# String
|
||||
#
|
||||
# ==== Options
|
||||
# indent<Integer>:: Indent each line of the printed paragraph by indent value.
|
||||
#
|
||||
def print_wrapped(message, options={})
|
||||
indent = options[:indent] || 0
|
||||
width = terminal_width - indent
|
||||
paras = message.split("\n\n")
|
||||
|
||||
paras.map! do |unwrapped|
|
||||
unwrapped.strip.gsub(/\n/, " ").squeeze(" ").
|
||||
gsub(/.{1,#{width}}(?:\s|\Z)/){($& + 5.chr).
|
||||
gsub(/\n\005/,"\n").gsub(/\005/,"\n")}
|
||||
end
|
||||
|
||||
paras.each do |para|
|
||||
para.split("\n").each do |line|
|
||||
stdout.puts line.insert(0, " " * indent)
|
||||
end
|
||||
stdout.puts unless para == paras.last
|
||||
end
|
||||
end
|
||||
|
||||
# Deals with file collision and returns true if the file should be
|
||||
# overwritten and false otherwise. If a block is given, it uses the block
|
||||
# response as the content for the diff.
|
||||
#
|
||||
# ==== Parameters
|
||||
# destination<String>:: the destination file to solve conflicts
|
||||
# block<Proc>:: an optional block that returns the value to be used in diff
|
||||
#
|
||||
def file_collision(destination)
|
||||
return true if @always_force
|
||||
options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
|
||||
|
||||
while true
|
||||
answer = ask %[Overwrite #{destination}? (enter "h" for help) #{options}]
|
||||
|
||||
case answer
|
||||
when is?(:yes), is?(:force), ""
|
||||
return true
|
||||
when is?(:no), is?(:skip)
|
||||
return false
|
||||
when is?(:always)
|
||||
return @always_force = true
|
||||
when is?(:quit)
|
||||
say 'Aborting...'
|
||||
raise SystemExit
|
||||
when is?(:diff)
|
||||
show_diff(destination, yield) if block_given?
|
||||
say 'Retrying...'
|
||||
else
|
||||
say file_collision_help
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This code was copied from Rake, available under MIT-LICENSE
|
||||
# Copyright (c) 2003, 2004 Jim Weirich
|
||||
def terminal_width
|
||||
if ENV['THOR_COLUMNS']
|
||||
result = ENV['THOR_COLUMNS'].to_i
|
||||
else
|
||||
result = unix? ? dynamic_width : 80
|
||||
end
|
||||
(result < 10) ? 80 : result
|
||||
rescue
|
||||
80
|
||||
end
|
||||
|
||||
# Called if something goes wrong during the execution. This is used by Thor
|
||||
# internally and should not be used inside your scripts. If something went
|
||||
# wrong, you can always raise an exception. If you raise a Thor::Error, it
|
||||
# will be rescued and wrapped in the method below.
|
||||
#
|
||||
def error(statement)
|
||||
stderr.puts statement
|
||||
end
|
||||
|
||||
# Apply color to the given string with optional bold. Disabled in the
|
||||
# Thor::Shell::Basic class.
|
||||
#
|
||||
def set_color(string, *args) #:nodoc:
|
||||
string
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def can_display_colors?
|
||||
false
|
||||
end
|
||||
|
||||
def lookup_color(color)
|
||||
return color unless color.is_a?(Symbol)
|
||||
self.class.const_get(color.to_s.upcase)
|
||||
end
|
||||
|
||||
def stdout
|
||||
$stdout
|
||||
end
|
||||
|
||||
def stdin
|
||||
$stdin
|
||||
end
|
||||
|
||||
def stderr
|
||||
$stderr
|
||||
end
|
||||
|
||||
def is?(value) #:nodoc:
|
||||
value = value.to_s
|
||||
|
||||
if value.size == 1
|
||||
/\A#{value}\z/i
|
||||
else
|
||||
/\A(#{value}|#{value[0,1]})\z/i
|
||||
end
|
||||
end
|
||||
|
||||
def file_collision_help #:nodoc:
|
||||
<<HELP
|
||||
Y - yes, overwrite
|
||||
n - no, do not overwrite
|
||||
a - all, overwrite this and all others
|
||||
q - quit, abort
|
||||
d - diff, show the differences between the old and the new
|
||||
h - help, show this help
|
||||
HELP
|
||||
end
|
||||
|
||||
def show_diff(destination, content) #:nodoc:
|
||||
diff_cmd = ENV['THOR_DIFF'] || ENV['RAILS_DIFF'] || 'diff -u'
|
||||
|
||||
Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
|
||||
temp.write content
|
||||
temp.rewind
|
||||
system %(#{diff_cmd} "#{destination}" "#{temp.path}")
|
||||
end
|
||||
end
|
||||
|
||||
def quiet? #:nodoc:
|
||||
mute? || (base && base.options[:quiet])
|
||||
end
|
||||
|
||||
# Calculate the dynamic width of the terminal
|
||||
def dynamic_width
|
||||
@dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
|
||||
end
|
||||
|
||||
def dynamic_width_stty
|
||||
%x{stty size 2>/dev/null}.split[1].to_i
|
||||
end
|
||||
|
||||
def dynamic_width_tput
|
||||
%x{tput cols 2>/dev/null}.to_i
|
||||
end
|
||||
|
||||
def unix?
|
||||
RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
|
||||
end
|
||||
|
||||
def truncate(string, width)
|
||||
as_unicode do
|
||||
chars = string.chars.to_a
|
||||
if chars.length <= width
|
||||
chars.join
|
||||
else
|
||||
( chars[0, width-3].join ) + "..."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if "".respond_to?(:encode)
|
||||
def as_unicode
|
||||
yield
|
||||
end
|
||||
else
|
||||
def as_unicode
|
||||
old, $KCODE = $KCODE, "U"
|
||||
yield
|
||||
ensure
|
||||
$KCODE = old
|
||||
end
|
||||
end
|
||||
|
||||
def ask_simply(statement, color=nil)
|
||||
say("#{statement} ", color)
|
||||
stdin.gets.tap{|text| text.strip! if text}
|
||||
end
|
||||
|
||||
def ask_filtered(statement, answer_set, *args)
|
||||
correct_answer = nil
|
||||
until correct_answer
|
||||
answer = ask_simply("#{statement} #{answer_set.inspect}", *args)
|
||||
correct_answer = answer_set.include?(answer) ? answer : nil
|
||||
answers = answer_set.map(&:inspect).join(", ")
|
||||
say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
|
||||
end
|
||||
correct_answer
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
148
vendor/gems/thor-0.18.1/lib/thor/shell/color.rb
vendored
Normal file
148
vendor/gems/thor-0.18.1/lib/thor/shell/color.rb
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
require 'thor/shell/basic'
|
||||
|
||||
class Thor
|
||||
module Shell
|
||||
# Inherit from Thor::Shell::Basic and add set_color behavior. Check
|
||||
# Thor::Shell::Basic to see all available methods.
|
||||
#
|
||||
class Color < Basic
|
||||
# Embed in a String to clear all previous ANSI sequences.
|
||||
CLEAR = "\e[0m"
|
||||
# The start of an ANSI bold sequence.
|
||||
BOLD = "\e[1m"
|
||||
|
||||
# Set the terminal's foreground ANSI color to black.
|
||||
BLACK = "\e[30m"
|
||||
# Set the terminal's foreground ANSI color to red.
|
||||
RED = "\e[31m"
|
||||
# Set the terminal's foreground ANSI color to green.
|
||||
GREEN = "\e[32m"
|
||||
# Set the terminal's foreground ANSI color to yellow.
|
||||
YELLOW = "\e[33m"
|
||||
# Set the terminal's foreground ANSI color to blue.
|
||||
BLUE = "\e[34m"
|
||||
# Set the terminal's foreground ANSI color to magenta.
|
||||
MAGENTA = "\e[35m"
|
||||
# Set the terminal's foreground ANSI color to cyan.
|
||||
CYAN = "\e[36m"
|
||||
# Set the terminal's foreground ANSI color to white.
|
||||
WHITE = "\e[37m"
|
||||
|
||||
# Set the terminal's background ANSI color to black.
|
||||
ON_BLACK = "\e[40m"
|
||||
# Set the terminal's background ANSI color to red.
|
||||
ON_RED = "\e[41m"
|
||||
# Set the terminal's background ANSI color to green.
|
||||
ON_GREEN = "\e[42m"
|
||||
# Set the terminal's background ANSI color to yellow.
|
||||
ON_YELLOW = "\e[43m"
|
||||
# Set the terminal's background ANSI color to blue.
|
||||
ON_BLUE = "\e[44m"
|
||||
# Set the terminal's background ANSI color to magenta.
|
||||
ON_MAGENTA = "\e[45m"
|
||||
# Set the terminal's background ANSI color to cyan.
|
||||
ON_CYAN = "\e[46m"
|
||||
# Set the terminal's background ANSI color to white.
|
||||
ON_WHITE = "\e[47m"
|
||||
|
||||
# Set color by using a string or one of the defined constants. If a third
|
||||
# option is set to true, it also adds bold to the string. This is based
|
||||
# on Highline implementation and it automatically appends CLEAR to the end
|
||||
# of the returned String.
|
||||
#
|
||||
# Pass foreground, background and bold options to this method as
|
||||
# symbols.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# set_color "Hi!", :red, :on_white, :bold
|
||||
#
|
||||
# The available colors are:
|
||||
#
|
||||
# :bold
|
||||
# :black
|
||||
# :red
|
||||
# :green
|
||||
# :yellow
|
||||
# :blue
|
||||
# :magenta
|
||||
# :cyan
|
||||
# :white
|
||||
# :on_black
|
||||
# :on_red
|
||||
# :on_green
|
||||
# :on_yellow
|
||||
# :on_blue
|
||||
# :on_magenta
|
||||
# :on_cyan
|
||||
# :on_white
|
||||
def set_color(string, *colors)
|
||||
if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
|
||||
ansi_colors = colors.map { |color| lookup_color(color) }
|
||||
"#{ansi_colors.join}#{string}#{CLEAR}"
|
||||
else
|
||||
# The old API was `set_color(color, bold=boolean)`. We
|
||||
# continue to support the old API because you should never
|
||||
# break old APIs unnecessarily :P
|
||||
foreground, bold = colors
|
||||
foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol)
|
||||
|
||||
bold = bold ? BOLD : ""
|
||||
"#{bold}#{foreground}#{string}#{CLEAR}"
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def can_display_colors?
|
||||
stdout.tty?
|
||||
end
|
||||
|
||||
# Overwrite show_diff to show diff with colors if Diff::LCS is
|
||||
# available.
|
||||
#
|
||||
def show_diff(destination, content) #:nodoc:
|
||||
if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
|
||||
actual = File.binread(destination).to_s.split("\n")
|
||||
content = content.to_s.split("\n")
|
||||
|
||||
Diff::LCS.sdiff(actual, content).each do |diff|
|
||||
output_diff_line(diff)
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def output_diff_line(diff) #:nodoc:
|
||||
case diff.action
|
||||
when '-'
|
||||
say "- #{diff.old_element.chomp}", :red, true
|
||||
when '+'
|
||||
say "+ #{diff.new_element.chomp}", :green, true
|
||||
when '!'
|
||||
say "- #{diff.old_element.chomp}", :red, true
|
||||
say "+ #{diff.new_element.chomp}", :green, true
|
||||
else
|
||||
say " #{diff.old_element.chomp}", nil, true
|
||||
end
|
||||
end
|
||||
|
||||
# Check if Diff::LCS is loaded. If it is, use it to create pretty output
|
||||
# for diff.
|
||||
#
|
||||
def diff_lcs_loaded? #:nodoc:
|
||||
return true if defined?(Diff::LCS)
|
||||
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
|
||||
|
||||
@diff_lcs_loaded = begin
|
||||
require 'diff/lcs'
|
||||
true
|
||||
rescue LoadError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
127
vendor/gems/thor-0.18.1/lib/thor/shell/html.rb
vendored
Normal file
127
vendor/gems/thor-0.18.1/lib/thor/shell/html.rb
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
require 'thor/shell/basic'
|
||||
|
||||
class Thor
|
||||
module Shell
|
||||
# Inherit from Thor::Shell::Basic and add set_color behavior. Check
|
||||
# Thor::Shell::Basic to see all available methods.
|
||||
#
|
||||
class HTML < Basic
|
||||
# The start of an HTML bold sequence.
|
||||
BOLD = "font-weight: bold"
|
||||
|
||||
# Set the terminal's foreground HTML color to black.
|
||||
BLACK = 'color: black'
|
||||
# Set the terminal's foreground HTML color to red.
|
||||
RED = 'color: red'
|
||||
# Set the terminal's foreground HTML color to green.
|
||||
GREEN = 'color: green'
|
||||
# Set the terminal's foreground HTML color to yellow.
|
||||
YELLOW = 'color: yellow'
|
||||
# Set the terminal's foreground HTML color to blue.
|
||||
BLUE = 'color: blue'
|
||||
# Set the terminal's foreground HTML color to magenta.
|
||||
MAGENTA = 'color: magenta'
|
||||
# Set the terminal's foreground HTML color to cyan.
|
||||
CYAN = 'color: cyan'
|
||||
# Set the terminal's foreground HTML color to white.
|
||||
WHITE = 'color: white'
|
||||
|
||||
# Set the terminal's background HTML color to black.
|
||||
ON_BLACK = 'background-color: black'
|
||||
# Set the terminal's background HTML color to red.
|
||||
ON_RED = 'background-color: red'
|
||||
# Set the terminal's background HTML color to green.
|
||||
ON_GREEN = 'background-color: green'
|
||||
# Set the terminal's background HTML color to yellow.
|
||||
ON_YELLOW = 'background-color: yellow'
|
||||
# Set the terminal's background HTML color to blue.
|
||||
ON_BLUE = 'background-color: blue'
|
||||
# Set the terminal's background HTML color to magenta.
|
||||
ON_MAGENTA = 'background-color: magenta'
|
||||
# Set the terminal's background HTML color to cyan.
|
||||
ON_CYAN = 'background-color: cyan'
|
||||
# Set the terminal's background HTML color to white.
|
||||
ON_WHITE = 'background-color: white'
|
||||
|
||||
# Set color by using a string or one of the defined constants. If a third
|
||||
# option is set to true, it also adds bold to the string. This is based
|
||||
# on Highline implementation and it automatically appends CLEAR to the end
|
||||
# of the returned String.
|
||||
#
|
||||
def set_color(string, *colors)
|
||||
if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
|
||||
html_colors = colors.map { |color| lookup_color(color) }
|
||||
"<span style=\"#{html_colors.join("; ")};\">#{string}</span>"
|
||||
else
|
||||
color, bold = colors
|
||||
html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
||||
styles = [html_color]
|
||||
styles << BOLD if bold
|
||||
"<span style=\"#{styles.join("; ")};\">#{string}</span>"
|
||||
end
|
||||
end
|
||||
|
||||
# Ask something to the user and receives a response.
|
||||
#
|
||||
# ==== Example
|
||||
# ask("What is your name?")
|
||||
#
|
||||
# TODO: Implement #ask for Thor::Shell::HTML
|
||||
def ask(statement, color=nil)
|
||||
raise NotImplementedError, "Implement #ask for Thor::Shell::HTML"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def can_display_colors?
|
||||
true
|
||||
end
|
||||
|
||||
# Overwrite show_diff to show diff with colors if Diff::LCS is
|
||||
# available.
|
||||
#
|
||||
def show_diff(destination, content) #:nodoc:
|
||||
if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
|
||||
actual = File.binread(destination).to_s.split("\n")
|
||||
content = content.to_s.split("\n")
|
||||
|
||||
Diff::LCS.sdiff(actual, content).each do |diff|
|
||||
output_diff_line(diff)
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def output_diff_line(diff) #:nodoc:
|
||||
case diff.action
|
||||
when '-'
|
||||
say "- #{diff.old_element.chomp}", :red, true
|
||||
when '+'
|
||||
say "+ #{diff.new_element.chomp}", :green, true
|
||||
when '!'
|
||||
say "- #{diff.old_element.chomp}", :red, true
|
||||
say "+ #{diff.new_element.chomp}", :green, true
|
||||
else
|
||||
say " #{diff.old_element.chomp}", nil, true
|
||||
end
|
||||
end
|
||||
|
||||
# Check if Diff::LCS is loaded. If it is, use it to create pretty output
|
||||
# for diff.
|
||||
#
|
||||
def diff_lcs_loaded? #:nodoc:
|
||||
return true if defined?(Diff::LCS)
|
||||
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
|
||||
|
||||
@diff_lcs_loaded = begin
|
||||
require 'diff/lcs'
|
||||
true
|
||||
rescue LoadError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
270
vendor/gems/thor-0.18.1/lib/thor/util.rb
vendored
Normal file
270
vendor/gems/thor-0.18.1/lib/thor/util.rb
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
require 'rbconfig'
|
||||
|
||||
class Thor
|
||||
module Sandbox #:nodoc:
|
||||
end
|
||||
|
||||
# This module holds several utilities:
|
||||
#
|
||||
# 1) Methods to convert thor namespaces to constants and vice-versa.
|
||||
#
|
||||
# Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz"
|
||||
#
|
||||
# 2) Loading thor files and sandboxing:
|
||||
#
|
||||
# Thor::Util.load_thorfile("~/.thor/foo")
|
||||
#
|
||||
module Util
|
||||
|
||||
class << self
|
||||
|
||||
# Receives a namespace and search for it in the Thor::Base subclasses.
|
||||
#
|
||||
# ==== Parameters
|
||||
# namespace<String>:: The namespace to search for.
|
||||
#
|
||||
def find_by_namespace(namespace)
|
||||
namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/
|
||||
Thor::Base.subclasses.find { |klass| klass.namespace == namespace }
|
||||
end
|
||||
|
||||
# Receives a constant and converts it to a Thor namespace. Since Thor
|
||||
# commands can be added to a sandbox, this method is also responsable for
|
||||
# removing the sandbox namespace.
|
||||
#
|
||||
# This method should not be used in general because it's used to deal with
|
||||
# older versions of Thor. On current versions, if you need to get the
|
||||
# namespace from a class, just call namespace on it.
|
||||
#
|
||||
# ==== Parameters
|
||||
# constant<Object>:: The constant to be converted to the thor path.
|
||||
#
|
||||
# ==== Returns
|
||||
# String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
|
||||
#
|
||||
def namespace_from_thor_class(constant)
|
||||
constant = constant.to_s.gsub(/^Thor::Sandbox::/, "")
|
||||
constant = snake_case(constant).squeeze(":")
|
||||
constant
|
||||
end
|
||||
|
||||
# Given the contents, evaluate it inside the sandbox and returns the
|
||||
# namespaces defined in the sandbox.
|
||||
#
|
||||
# ==== Parameters
|
||||
# contents<String>
|
||||
#
|
||||
# ==== Returns
|
||||
# Array[Object]
|
||||
#
|
||||
def namespaces_in_content(contents, file=__FILE__)
|
||||
old_constants = Thor::Base.subclasses.dup
|
||||
Thor::Base.subclasses.clear
|
||||
|
||||
load_thorfile(file, contents)
|
||||
|
||||
new_constants = Thor::Base.subclasses.dup
|
||||
Thor::Base.subclasses.replace(old_constants)
|
||||
|
||||
new_constants.map!{ |c| c.namespace }
|
||||
new_constants.compact!
|
||||
new_constants
|
||||
end
|
||||
|
||||
# Returns the thor classes declared inside the given class.
|
||||
#
|
||||
def thor_classes_in(klass)
|
||||
stringfied_constants = klass.constants.map { |c| c.to_s }
|
||||
Thor::Base.subclasses.select do |subclass|
|
||||
next unless subclass.name
|
||||
stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", ''))
|
||||
end
|
||||
end
|
||||
|
||||
# Receives a string and convert it to snake case. SnakeCase returns snake_case.
|
||||
#
|
||||
# ==== Parameters
|
||||
# String
|
||||
#
|
||||
# ==== Returns
|
||||
# String
|
||||
#
|
||||
def snake_case(str)
|
||||
return str.downcase if str =~ /^[A-Z_]+$/
|
||||
str.gsub(/\B[A-Z]/, '_\&').squeeze('_') =~ /_*(.*)/
|
||||
return $+.downcase
|
||||
end
|
||||
|
||||
# Receives a string and convert it to camel case. camel_case returns CamelCase.
|
||||
#
|
||||
# ==== Parameters
|
||||
# String
|
||||
#
|
||||
# ==== Returns
|
||||
# String
|
||||
#
|
||||
def camel_case(str)
|
||||
return str if str !~ /_/ && str =~ /[A-Z]+.*/
|
||||
str.split('_').map { |i| i.capitalize }.join
|
||||
end
|
||||
|
||||
# Receives a namespace and tries to retrieve a Thor or Thor::Group class
|
||||
# from it. It first searches for a class using the all the given namespace,
|
||||
# if it's not found, removes the highest entry and searches for the class
|
||||
# again. If found, returns the highest entry as the class name.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# class Foo::Bar < Thor
|
||||
# def baz
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# class Baz::Foo < Thor::Group
|
||||
# end
|
||||
#
|
||||
# Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default command
|
||||
# Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil
|
||||
# Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"
|
||||
#
|
||||
# ==== Parameters
|
||||
# namespace<String>
|
||||
#
|
||||
def find_class_and_command_by_namespace(namespace, fallback = true)
|
||||
if namespace.include?(?:) # look for a namespaced command
|
||||
pieces = namespace.split(":")
|
||||
command = pieces.pop
|
||||
klass = Thor::Util.find_by_namespace(pieces.join(":"))
|
||||
end
|
||||
unless klass # look for a Thor::Group with the right name
|
||||
klass, command = Thor::Util.find_by_namespace(namespace), nil
|
||||
end
|
||||
if !klass && fallback # try a command in the default namespace
|
||||
command = namespace
|
||||
klass = Thor::Util.find_by_namespace('')
|
||||
end
|
||||
return klass, command
|
||||
end
|
||||
alias find_class_and_task_by_namespace find_class_and_command_by_namespace
|
||||
|
||||
# Receives a path and load the thor file in the path. The file is evaluated
|
||||
# inside the sandbox to avoid namespacing conflicts.
|
||||
#
|
||||
def load_thorfile(path, content=nil, debug=false)
|
||||
content ||= File.binread(path)
|
||||
|
||||
begin
|
||||
Thor::Sandbox.class_eval(content, path)
|
||||
rescue Exception => e
|
||||
$stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}")
|
||||
if debug
|
||||
$stderr.puts(*e.backtrace)
|
||||
else
|
||||
$stderr.puts(e.backtrace.first)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def user_home
|
||||
@@user_home ||= if ENV["HOME"]
|
||||
ENV["HOME"]
|
||||
elsif ENV["USERPROFILE"]
|
||||
ENV["USERPROFILE"]
|
||||
elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
|
||||
File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"])
|
||||
elsif ENV["APPDATA"]
|
||||
ENV["APPDATA"]
|
||||
else
|
||||
begin
|
||||
File.expand_path("~")
|
||||
rescue
|
||||
if File::ALT_SEPARATOR
|
||||
"C:/"
|
||||
else
|
||||
"/"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the root where thor files are located, depending on the OS.
|
||||
#
|
||||
def thor_root
|
||||
File.join(user_home, ".thor").gsub(/\\/, '/')
|
||||
end
|
||||
|
||||
# Returns the files in the thor root. On Windows thor_root will be something
|
||||
# like this:
|
||||
#
|
||||
# C:\Documents and Settings\james\.thor
|
||||
#
|
||||
# If we don't #gsub the \ character, Dir.glob will fail.
|
||||
#
|
||||
def thor_root_glob
|
||||
files = Dir["#{escape_globs(thor_root)}/*"]
|
||||
|
||||
files.map! do |file|
|
||||
File.directory?(file) ? File.join(file, "main.thor") : file
|
||||
end
|
||||
end
|
||||
|
||||
# Where to look for Thor files.
|
||||
#
|
||||
def globs_for(path)
|
||||
path = escape_globs(path)
|
||||
["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
|
||||
end
|
||||
|
||||
# Return the path to the ruby interpreter taking into account multiple
|
||||
# installations and windows extensions.
|
||||
#
|
||||
def ruby_command
|
||||
@ruby_command ||= begin
|
||||
ruby_name = RbConfig::CONFIG['ruby_install_name']
|
||||
ruby = File.join(RbConfig::CONFIG['bindir'], ruby_name)
|
||||
ruby << RbConfig::CONFIG['EXEEXT']
|
||||
|
||||
# avoid using different name than ruby (on platforms supporting links)
|
||||
if ruby_name != 'ruby' && File.respond_to?(:readlink)
|
||||
begin
|
||||
alternate_ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby')
|
||||
alternate_ruby << RbConfig::CONFIG['EXEEXT']
|
||||
|
||||
# ruby is a symlink
|
||||
if File.symlink? alternate_ruby
|
||||
linked_ruby = File.readlink alternate_ruby
|
||||
|
||||
# symlink points to 'ruby_install_name'
|
||||
ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
|
||||
end
|
||||
rescue NotImplementedError
|
||||
# just ignore on windows
|
||||
end
|
||||
end
|
||||
|
||||
# escape string in case path to ruby executable contain spaces.
|
||||
ruby.sub!(/.*\s.*/m, '"\&"')
|
||||
ruby
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a string that has had any glob characters escaped.
|
||||
# The glob characters are `* ? { } [ ]`.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# Thor::Util.escape_globs('[apps]') # => '\[apps\]'
|
||||
#
|
||||
# ==== Parameters
|
||||
# String
|
||||
#
|
||||
# ==== Returns
|
||||
# String
|
||||
#
|
||||
def escape_globs(path)
|
||||
path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
3
vendor/gems/thor-0.18.1/lib/thor/version.rb
vendored
Normal file
3
vendor/gems/thor-0.18.1/lib/thor/version.rb
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
class Thor
|
||||
VERSION = "0.18.1"
|
||||
end
|
||||
170
vendor/gems/thor-0.18.1/spec/actions/create_file_spec.rb
vendored
Normal file
170
vendor/gems/thor-0.18.1/spec/actions/create_file_spec.rb
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
require 'helper'
|
||||
require 'thor/actions'
|
||||
|
||||
describe Thor::Actions::CreateFile do
|
||||
before do
|
||||
::FileUtils.rm_rf(destination_root)
|
||||
end
|
||||
|
||||
def create_file(destination=nil, config={}, options={})
|
||||
@base = MyCounter.new([1, 2], options, { :destination_root => destination_root })
|
||||
@base.stub!(:file_name).and_return('rdoc')
|
||||
|
||||
@action = Thor::Actions::CreateFile.new(@base, destination, "CONFIGURATION",
|
||||
{ :verbose => !@silence }.merge(config))
|
||||
end
|
||||
|
||||
def invoke!
|
||||
capture(:stdout) { @action.invoke! }
|
||||
end
|
||||
|
||||
def revoke!
|
||||
capture(:stdout) { @action.revoke! }
|
||||
end
|
||||
|
||||
def silence!
|
||||
@silence = true
|
||||
end
|
||||
|
||||
describe "#invoke!" do
|
||||
it "creates a file" do
|
||||
create_file("doc/config.rb")
|
||||
invoke!
|
||||
expect(File.exists?(File.join(destination_root, "doc/config.rb"))).to be_true
|
||||
end
|
||||
|
||||
it "does not create a file if pretending" do
|
||||
create_file("doc/config.rb", {}, :pretend => true)
|
||||
invoke!
|
||||
expect(File.exists?(File.join(destination_root, "doc/config.rb"))).to be_false
|
||||
end
|
||||
|
||||
it "shows created status to the user" do
|
||||
create_file("doc/config.rb")
|
||||
expect(invoke!).to eq(" create doc/config.rb\n")
|
||||
end
|
||||
|
||||
it "does not show any information if log status is false" do
|
||||
silence!
|
||||
create_file("doc/config.rb")
|
||||
expect(invoke!).to be_empty
|
||||
end
|
||||
|
||||
it "returns the given destination" do
|
||||
capture(:stdout) do
|
||||
expect(create_file("doc/config.rb").invoke!).to eq("doc/config.rb")
|
||||
end
|
||||
end
|
||||
|
||||
it "converts encoded instructions" do
|
||||
create_file("doc/%file_name%.rb.tt")
|
||||
invoke!
|
||||
expect(File.exists?(File.join(destination_root, "doc/rdoc.rb.tt"))).to be_true
|
||||
end
|
||||
|
||||
describe "when file exists" do
|
||||
before do
|
||||
create_file("doc/config.rb")
|
||||
invoke!
|
||||
end
|
||||
|
||||
describe "and is identical" do
|
||||
it "shows identical status" do
|
||||
create_file("doc/config.rb")
|
||||
invoke!
|
||||
expect(invoke!).to eq(" identical doc/config.rb\n")
|
||||
end
|
||||
end
|
||||
|
||||
describe "and is not identical" do
|
||||
before do
|
||||
File.open(File.join(destination_root, 'doc/config.rb'), 'w'){ |f| f.write("FOO = 3") }
|
||||
end
|
||||
|
||||
it "shows forced status to the user if force is given" do
|
||||
expect(create_file("doc/config.rb", {}, :force => true)).not_to be_identical
|
||||
expect(invoke!).to eq(" force doc/config.rb\n")
|
||||
end
|
||||
|
||||
it "shows skipped status to the user if skip is given" do
|
||||
expect(create_file("doc/config.rb", {}, :skip => true)).not_to be_identical
|
||||
expect(invoke!).to eq(" skip doc/config.rb\n")
|
||||
end
|
||||
|
||||
it "shows forced status to the user if force is configured" do
|
||||
expect(create_file("doc/config.rb", :force => true)).not_to be_identical
|
||||
expect(invoke!).to eq(" force doc/config.rb\n")
|
||||
end
|
||||
|
||||
it "shows skipped status to the user if skip is configured" do
|
||||
expect(create_file("doc/config.rb", :skip => true)).not_to be_identical
|
||||
expect(invoke!).to eq(" skip doc/config.rb\n")
|
||||
end
|
||||
|
||||
it "shows conflict status to ther user" do
|
||||
expect(create_file("doc/config.rb")).not_to be_identical
|
||||
$stdin.should_receive(:gets).and_return('s')
|
||||
file = File.join(destination_root, 'doc/config.rb')
|
||||
|
||||
content = invoke!
|
||||
expect(content).to match(/conflict doc\/config\.rb/)
|
||||
expect(content).to match(/Overwrite #{file}\? \(enter "h" for help\) \[Ynaqdh\]/)
|
||||
expect(content).to match(/skip doc\/config\.rb/)
|
||||
end
|
||||
|
||||
it "creates the file if the file collision menu returns true" do
|
||||
create_file("doc/config.rb")
|
||||
$stdin.should_receive(:gets).and_return('y')
|
||||
expect(invoke!).to match(/force doc\/config\.rb/)
|
||||
end
|
||||
|
||||
it "skips the file if the file collision menu returns false" do
|
||||
create_file("doc/config.rb")
|
||||
$stdin.should_receive(:gets).and_return('n')
|
||||
expect(invoke!).to match(/skip doc\/config\.rb/)
|
||||
end
|
||||
|
||||
it "executes the block given to show file content" do
|
||||
create_file("doc/config.rb")
|
||||
$stdin.should_receive(:gets).and_return('d')
|
||||
$stdin.should_receive(:gets).and_return('n')
|
||||
@base.shell.should_receive(:system).with(/diff -u/)
|
||||
invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#revoke!" do
|
||||
it "removes the destination file" do
|
||||
create_file("doc/config.rb")
|
||||
invoke!
|
||||
revoke!
|
||||
expect(File.exists?(@action.destination)).to be_false
|
||||
end
|
||||
|
||||
it "does not raise an error if the file does not exist" do
|
||||
create_file("doc/config.rb")
|
||||
revoke!
|
||||
expect(File.exists?(@action.destination)).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#exists?" do
|
||||
it "returns true if the destination file exists" do
|
||||
create_file("doc/config.rb")
|
||||
expect(@action.exists?).to be_false
|
||||
invoke!
|
||||
expect(@action.exists?).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#identical?" do
|
||||
it "returns true if the destination file and is identical" do
|
||||
create_file("doc/config.rb")
|
||||
expect(@action.identical?).to be_false
|
||||
invoke!
|
||||
expect(@action.identical?).to be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
95
vendor/gems/thor-0.18.1/spec/actions/create_link_spec.rb
vendored
Normal file
95
vendor/gems/thor-0.18.1/spec/actions/create_link_spec.rb
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
require 'helper'
|
||||
require 'thor/actions'
|
||||
require 'tempfile'
|
||||
|
||||
describe Thor::Actions::CreateLink do
|
||||
before do
|
||||
@hardlink_to = File.join(Dir.tmpdir, 'linkdest.rb')
|
||||
::FileUtils.rm_rf(destination_root)
|
||||
::FileUtils.rm_rf(@hardlink_to)
|
||||
end
|
||||
|
||||
def create_link(destination=nil, config={}, options={})
|
||||
@base = MyCounter.new([1,2], options, { :destination_root => destination_root })
|
||||
@base.stub!(:file_name).and_return('rdoc')
|
||||
|
||||
@tempfile = Tempfile.new("config.rb")
|
||||
|
||||
@action = Thor::Actions::CreateLink.new(@base, destination, @tempfile.path,
|
||||
{ :verbose => !@silence }.merge(config))
|
||||
end
|
||||
|
||||
def invoke!
|
||||
capture(:stdout) { @action.invoke! }
|
||||
end
|
||||
|
||||
def revoke!
|
||||
capture(:stdout) { @action.revoke! }
|
||||
end
|
||||
|
||||
def silence!
|
||||
@silence = true
|
||||
end
|
||||
|
||||
describe "#invoke!" do
|
||||
it "creates a symbolic link for :symbolic => true" do
|
||||
create_link("doc/config.rb", :symbolic => true)
|
||||
invoke!
|
||||
destination_path = File.join(destination_root, "doc/config.rb")
|
||||
expect(File.exists?(destination_path)).to be_true
|
||||
expect(File.symlink?(destination_path)).to be_true
|
||||
end
|
||||
|
||||
it "creates a hard link for :symbolic => false" do
|
||||
create_link(@hardlink_to, :symbolic => false)
|
||||
invoke!
|
||||
destination_path = @hardlink_to
|
||||
expect(File.exists?(destination_path)).to be_true
|
||||
expect(File.symlink?(destination_path)).to be_false
|
||||
end
|
||||
|
||||
it "creates a symbolic link by default" do
|
||||
create_link("doc/config.rb")
|
||||
invoke!
|
||||
destination_path = File.join(destination_root, "doc/config.rb")
|
||||
expect(File.exists?(destination_path)).to be_true
|
||||
expect(File.symlink?(destination_path)).to be_true
|
||||
end
|
||||
|
||||
it "does not create a link if pretending" do
|
||||
create_link("doc/config.rb", {}, :pretend => true)
|
||||
invoke!
|
||||
expect(File.exists?(File.join(destination_root, "doc/config.rb"))).to be_false
|
||||
end
|
||||
|
||||
it "shows created status to the user" do
|
||||
create_link("doc/config.rb")
|
||||
expect(invoke!).to eq(" create doc/config.rb\n")
|
||||
end
|
||||
|
||||
it "does not show any information if log status is false" do
|
||||
silence!
|
||||
create_link("doc/config.rb")
|
||||
expect(invoke!).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#identical?" do
|
||||
it "returns true if the destination link exists and is identical" do
|
||||
create_link("doc/config.rb")
|
||||
expect(@action.identical?).to be_false
|
||||
invoke!
|
||||
expect(@action.identical?).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#revoke!" do
|
||||
it "removes the symbolic link of non-existent destination" do
|
||||
create_link("doc/config.rb")
|
||||
invoke!
|
||||
File.delete(@tempfile.path)
|
||||
revoke!
|
||||
expect(File.symlink?(@action.destination)).to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
169
vendor/gems/thor-0.18.1/spec/actions/directory_spec.rb
vendored
Normal file
169
vendor/gems/thor-0.18.1/spec/actions/directory_spec.rb
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
require 'helper'
|
||||
require 'thor/actions'
|
||||
|
||||
describe Thor::Actions::Directory do
|
||||
before do
|
||||
::FileUtils.rm_rf(destination_root)
|
||||
invoker.stub!(:file_name).and_return("rdoc")
|
||||
end
|
||||
|
||||
def invoker
|
||||
@invoker ||= WhinyGenerator.new([1,2], {}, { :destination_root => destination_root })
|
||||
end
|
||||
|
||||
def revoker
|
||||
@revoker ||= WhinyGenerator.new([1,2], {}, { :destination_root => destination_root, :behavior => :revoke })
|
||||
end
|
||||
|
||||
def invoke!(*args, &block)
|
||||
capture(:stdout){ invoker.directory(*args, &block) }
|
||||
end
|
||||
|
||||
def revoke!(*args, &block)
|
||||
capture(:stdout){ revoker.directory(*args, &block) }
|
||||
end
|
||||
|
||||
def exists_and_identical?(source_path, destination_path)
|
||||
%w(config.rb README).each do |file|
|
||||
source = File.join(source_root, source_path, file)
|
||||
destination = File.join(destination_root, destination_path, file)
|
||||
|
||||
expect(File.exists?(destination)).to be_true
|
||||
expect(FileUtils.identical?(source, destination)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#invoke!" do
|
||||
it "raises an error if the source does not exist" do
|
||||
expect {
|
||||
invoke! "unknown"
|
||||
}.to raise_error(Thor::Error, /Could not find "unknown" in any of your source paths/)
|
||||
end
|
||||
|
||||
it "does not create a directory in pretend mode" do
|
||||
invoke! "doc", "ghost", :pretend => true
|
||||
expect(File.exists?("ghost")).to be_false
|
||||
end
|
||||
|
||||
it "copies the whole directory recursively to the default destination" do
|
||||
invoke! "doc"
|
||||
exists_and_identical?("doc", "doc")
|
||||
end
|
||||
|
||||
it "copies the whole directory recursively to the specified destination" do
|
||||
invoke! "doc", "docs"
|
||||
exists_and_identical?("doc", "docs")
|
||||
end
|
||||
|
||||
it "copies only the first level files if recursive" do
|
||||
invoke! ".", "commands", :recursive => false
|
||||
|
||||
file = File.join(destination_root, "commands", "group.thor")
|
||||
expect(File.exists?(file)).to be_true
|
||||
|
||||
file = File.join(destination_root, "commands", "doc")
|
||||
expect(File.exists?(file)).to be_false
|
||||
|
||||
file = File.join(destination_root, "commands", "doc", "README")
|
||||
expect(File.exists?(file)).to be_false
|
||||
end
|
||||
|
||||
it "ignores files within excluding/ directories when exclude_pattern is provided" do
|
||||
invoke! "doc", "docs", :exclude_pattern => /excluding\//
|
||||
file = File.join(destination_root, "docs", "excluding", "rdoc.rb")
|
||||
expect(File.exists?(file)).to be_false
|
||||
end
|
||||
|
||||
it "copies and evalutes files within excluding/ directory when no exclude_pattern is present" do
|
||||
invoke! "doc", "docs"
|
||||
file = File.join(destination_root, "docs", "excluding", "rdoc.rb")
|
||||
expect(File.exists?(file)).to be_true
|
||||
expect(File.read(file)).to eq("BAR = BAR\n")
|
||||
end
|
||||
|
||||
it "copies files from the source relative to the current path" do
|
||||
invoker.inside "doc" do
|
||||
invoke! "."
|
||||
end
|
||||
exists_and_identical?("doc", "doc")
|
||||
end
|
||||
|
||||
it "copies and evaluates templates" do
|
||||
invoke! "doc", "docs"
|
||||
file = File.join(destination_root, "docs", "rdoc.rb")
|
||||
expect(File.exists?(file)).to be_true
|
||||
expect(File.read(file)).to eq("FOO = FOO\n")
|
||||
end
|
||||
|
||||
it "copies directories and preserved file mode" do
|
||||
invoke! "preserve", "preserved", :mode => :preserve
|
||||
original = File.join(source_root, "preserve", "script.sh")
|
||||
copy = File.join(destination_root, "preserved", "script.sh")
|
||||
expect(File.stat(original).mode).to eq(File.stat(copy).mode)
|
||||
end
|
||||
|
||||
it "copies directories" do
|
||||
invoke! "doc", "docs"
|
||||
file = File.join(destination_root, "docs", "components")
|
||||
expect(File.exists?(file)).to be_true
|
||||
expect(File.directory?(file)).to be_true
|
||||
end
|
||||
|
||||
it "does not copy .empty_directory files" do
|
||||
invoke! "doc", "docs"
|
||||
file = File.join(destination_root, "docs", "components", ".empty_directory")
|
||||
expect(File.exists?(file)).to be_false
|
||||
end
|
||||
|
||||
it "copies directories even if they are empty" do
|
||||
invoke! "doc/components", "docs/components"
|
||||
file = File.join(destination_root, "docs", "components")
|
||||
expect(File.exists?(file)).to be_true
|
||||
end
|
||||
|
||||
it "does not copy empty directories twice" do
|
||||
content = invoke!("doc/components", "docs/components")
|
||||
expect(content).not_to match(/exist/)
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
content = invoke!("doc")
|
||||
expect(content).to match(/create doc\/README/)
|
||||
expect(content).to match(/create doc\/config\.rb/)
|
||||
expect(content).to match(/create doc\/rdoc\.rb/)
|
||||
expect(content).to match(/create doc\/components/)
|
||||
end
|
||||
|
||||
it "yields a block" do
|
||||
checked = false
|
||||
invoke!("doc") do |content|
|
||||
checked ||= !!(content =~ /FOO/)
|
||||
end
|
||||
expect(checked).to be_true
|
||||
end
|
||||
|
||||
it "works with glob characters in the path" do
|
||||
content = invoke!("app{1}")
|
||||
expect(content).to match(/create app\{1\}\/README/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#revoke!" do
|
||||
it "removes the destination file" do
|
||||
invoke! "doc"
|
||||
revoke! "doc"
|
||||
|
||||
expect(File.exists?(File.join(destination_root, "doc", "README"))).to be_false
|
||||
expect(File.exists?(File.join(destination_root, "doc", "config.rb"))).to be_false
|
||||
expect(File.exists?(File.join(destination_root, "doc", "components"))).to be_false
|
||||
end
|
||||
|
||||
it "works with glob characters in the path" do
|
||||
invoke! "app{1}"
|
||||
expect(File.exists?(File.join(destination_root, "app{1}", "README"))).to be_true
|
||||
|
||||
revoke! "app{1}"
|
||||
expect(File.exists?(File.join(destination_root, "app{1}", "README"))).to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
129
vendor/gems/thor-0.18.1/spec/actions/empty_directory_spec.rb
vendored
Normal file
129
vendor/gems/thor-0.18.1/spec/actions/empty_directory_spec.rb
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
require 'helper'
|
||||
require 'thor/actions'
|
||||
|
||||
describe Thor::Actions::EmptyDirectory do
|
||||
before do
|
||||
::FileUtils.rm_rf(destination_root)
|
||||
end
|
||||
|
||||
def empty_directory(destination, options={})
|
||||
@action = Thor::Actions::EmptyDirectory.new(base, destination)
|
||||
end
|
||||
|
||||
def invoke!
|
||||
capture(:stdout) { @action.invoke! }
|
||||
end
|
||||
|
||||
def revoke!
|
||||
capture(:stdout) { @action.revoke! }
|
||||
end
|
||||
|
||||
def base
|
||||
@base ||= MyCounter.new([1,2], {}, { :destination_root => destination_root })
|
||||
end
|
||||
|
||||
describe "#destination" do
|
||||
it "returns the full destination with the destination_root" do
|
||||
expect(empty_directory('doc').destination).to eq(File.join(destination_root, 'doc'))
|
||||
end
|
||||
|
||||
it "takes relative root into account" do
|
||||
base.inside('doc') do
|
||||
expect(empty_directory('contents').destination).to eq(File.join(destination_root, 'doc', 'contents'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#relative_destination" do
|
||||
it "returns the relative destination to the original destination root" do
|
||||
base.inside('doc') do
|
||||
expect(empty_directory('contents').relative_destination).to eq('doc/contents')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#given_destination" do
|
||||
it "returns the destination supplied by the user" do
|
||||
base.inside('doc') do
|
||||
expect(empty_directory('contents').given_destination).to eq('contents')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#invoke!" do
|
||||
it "copies the file to the specified destination" do
|
||||
empty_directory("doc")
|
||||
invoke!
|
||||
expect(File.exists?(File.join(destination_root, "doc"))).to be_true
|
||||
end
|
||||
|
||||
it "shows created status to the user" do
|
||||
empty_directory("doc")
|
||||
expect(invoke!).to eq(" create doc\n")
|
||||
end
|
||||
|
||||
it "does not create a directory if pretending" do
|
||||
base.inside("foo", :pretend => true) do
|
||||
empty_directory("ghost")
|
||||
end
|
||||
expect(File.exists?(File.join(base.destination_root, "ghost"))).to be_false
|
||||
end
|
||||
|
||||
describe "when directory exists" do
|
||||
it "shows exist status" do
|
||||
empty_directory("doc")
|
||||
invoke!
|
||||
expect(invoke!).to eq(" exist doc\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#revoke!" do
|
||||
it "removes the destination file" do
|
||||
empty_directory("doc")
|
||||
invoke!
|
||||
revoke!
|
||||
expect(File.exists?(@action.destination)).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#exists?" do
|
||||
it "returns true if the destination file exists" do
|
||||
empty_directory("doc")
|
||||
expect(@action.exists?).to be_false
|
||||
invoke!
|
||||
expect(@action.exists?).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "protected methods" do
|
||||
describe "#convert_encoded_instructions" do
|
||||
before do
|
||||
empty_directory("test_dir")
|
||||
@action.base.stub!(:file_name).and_return("expected")
|
||||
end
|
||||
|
||||
it "accepts and executes a 'legal' %\w+% encoded instruction" do
|
||||
expect(@action.send(:convert_encoded_instructions, "%file_name%.txt")).to eq("expected.txt")
|
||||
end
|
||||
|
||||
it "accepts and executes a private %\w+% encoded instruction" do
|
||||
@action.base.extend Module.new {
|
||||
private
|
||||
def private_file_name
|
||||
"expected"
|
||||
end
|
||||
}
|
||||
expect(@action.send(:convert_encoded_instructions, "%private_file_name%.txt")).to eq("expected.txt")
|
||||
end
|
||||
|
||||
it "ignores an 'illegal' %\w+% encoded instruction" do
|
||||
expect(@action.send(:convert_encoded_instructions, "%some_name%.txt")).to eq("%some_name%.txt")
|
||||
end
|
||||
|
||||
it "ignores incorrectly encoded instruction" do
|
||||
expect(@action.send(:convert_encoded_instructions, "%some.name%.txt")).to eq("%some.name%.txt")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
382
vendor/gems/thor-0.18.1/spec/actions/file_manipulation_spec.rb
vendored
Normal file
382
vendor/gems/thor-0.18.1/spec/actions/file_manipulation_spec.rb
vendored
Normal file
@@ -0,0 +1,382 @@
|
||||
require 'helper'
|
||||
|
||||
class Application; end
|
||||
|
||||
describe Thor::Actions do
|
||||
def runner(options={})
|
||||
@runner ||= MyCounter.new([1], options, { :destination_root => destination_root })
|
||||
end
|
||||
|
||||
def action(*args, &block)
|
||||
capture(:stdout) { runner.send(*args, &block) }
|
||||
end
|
||||
|
||||
def exists_and_identical?(source, destination)
|
||||
destination = File.join(destination_root, destination)
|
||||
expect(File.exists?(destination)).to be_true
|
||||
|
||||
source = File.join(source_root, source)
|
||||
expect(FileUtils).to be_identical(source, destination)
|
||||
end
|
||||
|
||||
def file
|
||||
File.join(destination_root, "foo")
|
||||
end
|
||||
|
||||
before do
|
||||
::FileUtils.rm_rf(destination_root)
|
||||
end
|
||||
|
||||
describe "#chmod" do
|
||||
it "executes the command given" do
|
||||
FileUtils.should_receive(:chmod_R).with(0755, file)
|
||||
action :chmod, "foo", 0755
|
||||
end
|
||||
|
||||
it "does not execute the command if pretending given" do
|
||||
FileUtils.should_not_receive(:chmod_R)
|
||||
runner(:pretend => true)
|
||||
action :chmod, "foo", 0755
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
FileUtils.should_receive(:chmod_R).with(0755, file)
|
||||
expect(action(:chmod, "foo", 0755)).to eq(" chmod foo\n")
|
||||
end
|
||||
|
||||
it "does not log status if required" do
|
||||
FileUtils.should_receive(:chmod_R).with(0755, file)
|
||||
expect(action(:chmod, "foo", 0755, :verbose => false)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#copy_file" do
|
||||
it "copies file from source to default destination" do
|
||||
action :copy_file, "command.thor"
|
||||
exists_and_identical?("command.thor", "command.thor")
|
||||
end
|
||||
|
||||
it "copies file from source to the specified destination" do
|
||||
action :copy_file, "command.thor", "foo.thor"
|
||||
exists_and_identical?("command.thor", "foo.thor")
|
||||
end
|
||||
|
||||
it "copies file from the source relative to the current path" do
|
||||
runner.inside("doc") do
|
||||
action :copy_file, "README"
|
||||
end
|
||||
exists_and_identical?("doc/README", "doc/README")
|
||||
end
|
||||
|
||||
it "copies file from source to default destination and preserves file mode" do
|
||||
action :copy_file, "preserve/script.sh", :mode => :preserve
|
||||
original = File.join(source_root, "preserve/script.sh")
|
||||
copy = File.join(destination_root, "preserve/script.sh")
|
||||
expect(File.stat(original).mode).to eq(File.stat(copy).mode)
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:copy_file, "command.thor")).to eq(" create command.thor\n")
|
||||
end
|
||||
|
||||
it "accepts a block to change output" do
|
||||
action :copy_file, "command.thor" do |content|
|
||||
"OMG" + content
|
||||
end
|
||||
expect(File.read(File.join(destination_root, "command.thor"))).to match(/^OMG/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#link_file" do
|
||||
it "links file from source to default destination" do
|
||||
action :link_file, "command.thor"
|
||||
exists_and_identical?("command.thor", "command.thor")
|
||||
end
|
||||
|
||||
it "links file from source to the specified destination" do
|
||||
action :link_file, "command.thor", "foo.thor"
|
||||
exists_and_identical?("command.thor", "foo.thor")
|
||||
end
|
||||
|
||||
it "links file from the source relative to the current path" do
|
||||
runner.inside("doc") do
|
||||
action :link_file, "README"
|
||||
end
|
||||
exists_and_identical?("doc/README", "doc/README")
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:link_file, "command.thor")).to eq(" create command.thor\n")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#get" do
|
||||
it "copies file from source to the specified destination" do
|
||||
action :get, "doc/README", "docs/README"
|
||||
exists_and_identical?("doc/README", "docs/README")
|
||||
end
|
||||
|
||||
it "uses just the source basename as destination if none is specified" do
|
||||
action :get, "doc/README"
|
||||
exists_and_identical?("doc/README", "README")
|
||||
end
|
||||
|
||||
it "allows the destination to be set as a block result" do
|
||||
action(:get, "doc/README"){ |c| "docs/README" }
|
||||
exists_and_identical?("doc/README", "docs/README")
|
||||
end
|
||||
|
||||
it "yields file content to a block" do
|
||||
action :get, "doc/README" do |content|
|
||||
expect(content).to eq("__start__\nREADME\n__end__\n")
|
||||
end
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:get, "doc/README", "docs/README")).to eq(" create docs/README\n")
|
||||
end
|
||||
|
||||
it "accepts http remote sources" do
|
||||
body = "__start__\nHTTPFILE\n__end__\n"
|
||||
FakeWeb.register_uri(:get, 'http://example.com/file.txt', :body => body)
|
||||
action :get, "http://example.com/file.txt" do |content|
|
||||
expect(content).to eq(body)
|
||||
end
|
||||
FakeWeb.clean_registry
|
||||
end
|
||||
|
||||
it "accepts https remote sources" do
|
||||
body = "__start__\nHTTPSFILE\n__end__\n"
|
||||
FakeWeb.register_uri(:get, 'https://example.com/file.txt', :body => body)
|
||||
action :get, "https://example.com/file.txt" do |content|
|
||||
expect(content).to eq(body)
|
||||
end
|
||||
FakeWeb.clean_registry
|
||||
end
|
||||
end
|
||||
|
||||
describe "#template" do
|
||||
it "allows using block helpers in the template" do
|
||||
action :template, "doc/block_helper.rb"
|
||||
|
||||
file = File.join(destination_root, "doc/block_helper.rb")
|
||||
expect(File.read(file)).to eq("Hello world!")
|
||||
end
|
||||
|
||||
it "evaluates the template given as source" do
|
||||
runner.instance_variable_set("@klass", "Config")
|
||||
action :template, "doc/config.rb"
|
||||
|
||||
file = File.join(destination_root, "doc/config.rb")
|
||||
expect(File.read(file)).to eq("class Config; end\n")
|
||||
end
|
||||
|
||||
it "copies the template to the specified destination" do
|
||||
action :template, "doc/config.rb", "doc/configuration.rb"
|
||||
file = File.join(destination_root, "doc/configuration.rb")
|
||||
expect(File.exists?(file)).to be_true
|
||||
end
|
||||
|
||||
it "converts enconded instructions" do
|
||||
runner.should_receive(:file_name).and_return("rdoc")
|
||||
action :template, "doc/%file_name%.rb.tt"
|
||||
file = File.join(destination_root, "doc/rdoc.rb")
|
||||
expect(File.exists?(file)).to be_true
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(capture(:stdout) { runner.template("doc/config.rb") }).to eq(" create doc/config.rb\n")
|
||||
end
|
||||
|
||||
it "accepts a block to change output" do
|
||||
action :template, "doc/config.rb" do |content|
|
||||
"OMG" + content
|
||||
end
|
||||
expect(File.read(File.join(destination_root, "doc/config.rb"))).to match(/^OMG/)
|
||||
end
|
||||
|
||||
it "guesses the destination name when given only a source" do
|
||||
action :template, "doc/config.yaml.tt"
|
||||
|
||||
file = File.join(destination_root, "doc/config.yaml")
|
||||
expect(File.exists?(file)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "when changing existent files" do
|
||||
before do
|
||||
::FileUtils.cp_r(source_root, destination_root)
|
||||
end
|
||||
|
||||
def file
|
||||
File.join(destination_root, "doc", "README")
|
||||
end
|
||||
|
||||
describe "#remove_file" do
|
||||
it "removes the file given" do
|
||||
action :remove_file, "doc/README"
|
||||
expect(File.exists?(file)).to be_false
|
||||
end
|
||||
|
||||
it "removes directories too" do
|
||||
action :remove_dir, "doc"
|
||||
expect(File.exists?(File.join(destination_root, "doc"))).to be_false
|
||||
end
|
||||
|
||||
it "does not remove if pretending" do
|
||||
runner(:pretend => true)
|
||||
action :remove_file, "doc/README"
|
||||
expect(File.exists?(file)).to be_true
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:remove_file, "doc/README")).to eq(" remove doc/README\n")
|
||||
end
|
||||
|
||||
it "does not log status if required" do
|
||||
expect(action(:remove_file, "doc/README", :verbose => false)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#gsub_file" do
|
||||
it "replaces the content in the file" do
|
||||
action :gsub_file, "doc/README", "__start__", "START"
|
||||
expect(File.binread(file)).to eq("START\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "does not replace if pretending" do
|
||||
runner(:pretend => true)
|
||||
action :gsub_file, "doc/README", "__start__", "START"
|
||||
expect(File.binread(file)).to eq("__start__\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "accepts a block" do
|
||||
action(:gsub_file, "doc/README", "__start__"){ |match| match.gsub('__', '').upcase }
|
||||
expect(File.binread(file)).to eq("START\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:gsub_file, "doc/README", "__start__", "START")).to eq(" gsub doc/README\n")
|
||||
end
|
||||
|
||||
it "does not log status if required" do
|
||||
expect(action(:gsub_file, file, "__", :verbose => false){ |match| match * 2 }).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#append_to_file" do
|
||||
it "appends content to the file" do
|
||||
action :append_to_file, "doc/README", "END\n"
|
||||
expect(File.binread(file)).to eq("__start__\nREADME\n__end__\nEND\n")
|
||||
end
|
||||
|
||||
it "accepts a block" do
|
||||
action(:append_to_file, "doc/README"){ "END\n" }
|
||||
expect(File.binread(file)).to eq("__start__\nREADME\n__end__\nEND\n")
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:append_to_file, "doc/README", "END")).to eq(" append doc/README\n")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#prepend_to_file" do
|
||||
it "prepends content to the file" do
|
||||
action :prepend_to_file, "doc/README", "START\n"
|
||||
expect(File.binread(file)).to eq("START\n__start__\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "accepts a block" do
|
||||
action(:prepend_to_file, "doc/README"){ "START\n" }
|
||||
expect(File.binread(file)).to eq("START\n__start__\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:prepend_to_file, "doc/README", "START")).to eq(" prepend doc/README\n")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#inject_into_class" do
|
||||
def file
|
||||
File.join(destination_root, "application.rb")
|
||||
end
|
||||
|
||||
it "appends content to a class" do
|
||||
action :inject_into_class, "application.rb", Application, " filter_parameters :password\n"
|
||||
expect(File.binread(file)).to eq("class Application < Base\n filter_parameters :password\nend\n")
|
||||
end
|
||||
|
||||
it "accepts a block" do
|
||||
action(:inject_into_class, "application.rb", Application){ " filter_parameters :password\n" }
|
||||
expect(File.binread(file)).to eq("class Application < Base\n filter_parameters :password\nend\n")
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:inject_into_class, "application.rb", Application, " filter_parameters :password\n")).to eq(" insert application.rb\n")
|
||||
end
|
||||
|
||||
it "does not append if class name does not match" do
|
||||
action :inject_into_class, "application.rb", "App", " filter_parameters :password\n"
|
||||
expect(File.binread(file)).to eq("class Application < Base\nend\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "when adjusting comments" do
|
||||
before do
|
||||
::FileUtils.cp_r(source_root, destination_root)
|
||||
end
|
||||
|
||||
def file
|
||||
File.join(destination_root, "doc", "COMMENTER")
|
||||
end
|
||||
|
||||
unmodified_comments_file = /__start__\n # greenblue\n#\n# yellowblue\n#yellowred\n #greenred\norange\n purple\n ind#igo\n # ind#igo\n__end__/
|
||||
|
||||
describe "#uncomment_lines" do
|
||||
it "uncomments all matching lines in the file" do
|
||||
action :uncomment_lines, "doc/COMMENTER", "green"
|
||||
expect(File.binread(file)).to match(/__start__\n greenblue\n#\n# yellowblue\n#yellowred\n greenred\norange\n purple\n ind#igo\n # ind#igo\n__end__/)
|
||||
|
||||
action :uncomment_lines, "doc/COMMENTER", "red"
|
||||
expect(File.binread(file)).to match(/__start__\n greenblue\n#\n# yellowblue\nyellowred\n greenred\norange\n purple\n ind#igo\n # ind#igo\n__end__/)
|
||||
end
|
||||
|
||||
it "correctly uncomments lines with hashes in them" do
|
||||
action :uncomment_lines, "doc/COMMENTER", "ind#igo"
|
||||
expect(File.binread(file)).to match(/__start__\n # greenblue\n#\n# yellowblue\n#yellowred\n #greenred\norange\n purple\n ind#igo\n ind#igo\n__end__/)
|
||||
end
|
||||
|
||||
it "does not modify already uncommented lines in the file" do
|
||||
action :uncomment_lines, "doc/COMMENTER", "orange"
|
||||
action :uncomment_lines, "doc/COMMENTER", "purple"
|
||||
expect(File.binread(file)).to match(unmodified_comments_file)
|
||||
end
|
||||
|
||||
it "does not uncomment the wrong line when uncommenting lines preceded by blank commented line" do
|
||||
action :uncomment_lines, "doc/COMMENTER", "yellow"
|
||||
expect(File.binread(file)).to match(/__start__\n # greenblue\n#\nyellowblue\nyellowred\n #greenred\norange\n purple\n ind#igo\n # ind#igo\n__end__/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#comment_lines" do
|
||||
it "comments lines which are not commented" do
|
||||
action :comment_lines, "doc/COMMENTER", "orange"
|
||||
expect(File.binread(file)).to match(/__start__\n # greenblue\n#\n# yellowblue\n#yellowred\n #greenred\n# orange\n purple\n ind#igo\n # ind#igo\n__end__/)
|
||||
|
||||
action :comment_lines, "doc/COMMENTER", "purple"
|
||||
expect(File.binread(file)).to match(/__start__\n # greenblue\n#\n# yellowblue\n#yellowred\n #greenred\n# orange\n # purple\n ind#igo\n # ind#igo\n__end__/)
|
||||
end
|
||||
|
||||
it "correctly comments lines with hashes in them" do
|
||||
action :comment_lines, "doc/COMMENTER", "ind#igo"
|
||||
expect(File.binread(file)).to match(/__start__\n # greenblue\n#\n# yellowblue\n#yellowred\n #greenred\norange\n purple\n # ind#igo\n # ind#igo\n__end__/)
|
||||
end
|
||||
|
||||
it "does not modify already commented lines" do
|
||||
action :comment_lines, "doc/COMMENTER", "green"
|
||||
expect(File.binread(file)).to match(unmodified_comments_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
135
vendor/gems/thor-0.18.1/spec/actions/inject_into_file_spec.rb
vendored
Normal file
135
vendor/gems/thor-0.18.1/spec/actions/inject_into_file_spec.rb
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
require 'helper'
|
||||
require 'thor/actions'
|
||||
|
||||
describe Thor::Actions::InjectIntoFile do
|
||||
before do
|
||||
::FileUtils.rm_rf(destination_root)
|
||||
::FileUtils.cp_r(source_root, destination_root)
|
||||
end
|
||||
|
||||
def invoker(options={})
|
||||
@invoker ||= MyCounter.new([1,2], options, { :destination_root => destination_root })
|
||||
end
|
||||
|
||||
def revoker
|
||||
@revoker ||= MyCounter.new([1,2], {}, { :destination_root => destination_root, :behavior => :revoke })
|
||||
end
|
||||
|
||||
def invoke!(*args, &block)
|
||||
capture(:stdout) { invoker.insert_into_file(*args, &block) }
|
||||
end
|
||||
|
||||
def revoke!(*args, &block)
|
||||
capture(:stdout) { revoker.insert_into_file(*args, &block) }
|
||||
end
|
||||
|
||||
def file
|
||||
File.join(destination_root, "doc/README")
|
||||
end
|
||||
|
||||
describe "#invoke!" do
|
||||
it "changes the file adding content after the flag" do
|
||||
invoke! "doc/README", "\nmore content", :after => "__start__"
|
||||
expect(File.read(file)).to eq("__start__\nmore content\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "changes the file adding content before the flag" do
|
||||
invoke! "doc/README", "more content\n", :before => "__end__"
|
||||
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
||||
end
|
||||
|
||||
it "accepts data as a block" do
|
||||
invoke! "doc/README", :before => "__end__" do
|
||||
"more content\n"
|
||||
end
|
||||
|
||||
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(invoke!("doc/README", "\nmore content", :after => "__start__")).to eq(" insert doc/README\n")
|
||||
end
|
||||
|
||||
it "does not change the file if pretending" do
|
||||
invoker :pretend => true
|
||||
invoke! "doc/README", "\nmore content", :after => "__start__"
|
||||
expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "does not change the file if already include content" do
|
||||
invoke! "doc/README", :before => "__end__" do
|
||||
"more content\n"
|
||||
end
|
||||
|
||||
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
||||
|
||||
invoke! "doc/README", :before => "__end__" do
|
||||
"more content\n"
|
||||
end
|
||||
|
||||
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
||||
end
|
||||
|
||||
it "does change the file if already include content and :force == true" do
|
||||
invoke! "doc/README", :before => "__end__" do
|
||||
"more content\n"
|
||||
end
|
||||
|
||||
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
||||
|
||||
invoke! "doc/README", :before => "__end__", :force => true do
|
||||
"more content\n"
|
||||
end
|
||||
|
||||
expect(File.read(file)).to eq("__start__\nREADME\nmore content\nmore content\n__end__\n")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "#revoke!" do
|
||||
it "substracts the destination file after injection" do
|
||||
invoke! "doc/README", "\nmore content", :after => "__start__"
|
||||
revoke! "doc/README", "\nmore content", :after => "__start__"
|
||||
expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "substracts the destination file before injection" do
|
||||
invoke! "doc/README", "more content\n", :before => "__start__"
|
||||
revoke! "doc/README", "more content\n", :before => "__start__"
|
||||
expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "substracts even with double after injection" do
|
||||
invoke! "doc/README", "\nmore content", :after => "__start__"
|
||||
invoke! "doc/README", "\nanother stuff", :after => "__start__"
|
||||
revoke! "doc/README", "\nmore content", :after => "__start__"
|
||||
expect(File.read(file)).to eq("__start__\nanother stuff\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "substracts even with double before injection" do
|
||||
invoke! "doc/README", "more content\n", :before => "__start__"
|
||||
invoke! "doc/README", "another stuff\n", :before => "__start__"
|
||||
revoke! "doc/README", "more content\n", :before => "__start__"
|
||||
expect(File.read(file)).to eq("another stuff\n__start__\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "substracts when prepending" do
|
||||
invoke! "doc/README", "more content\n", :after => /\A/
|
||||
invoke! "doc/README", "another stuff\n", :after => /\A/
|
||||
revoke! "doc/README", "more content\n", :after => /\A/
|
||||
expect(File.read(file)).to eq("another stuff\n__start__\nREADME\n__end__\n")
|
||||
end
|
||||
|
||||
it "substracts when appending" do
|
||||
invoke! "doc/README", "more content\n", :before => /\z/
|
||||
invoke! "doc/README", "another stuff\n", :before => /\z/
|
||||
revoke! "doc/README", "more content\n", :before => /\z/
|
||||
expect(File.read(file)).to eq("__start__\nREADME\n__end__\nanother stuff\n")
|
||||
end
|
||||
|
||||
it "shows progress information to the user" do
|
||||
invoke!("doc/README", "\nmore content", :after => "__start__")
|
||||
expect(revoke!("doc/README", "\nmore content", :after => "__start__")).to eq(" subtract doc/README\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
331
vendor/gems/thor-0.18.1/spec/actions_spec.rb
vendored
Normal file
331
vendor/gems/thor-0.18.1/spec/actions_spec.rb
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
require 'helper'
|
||||
|
||||
describe Thor::Actions do
|
||||
def runner(options={})
|
||||
@runner ||= MyCounter.new([1], options, { :destination_root => destination_root })
|
||||
end
|
||||
|
||||
def action(*args, &block)
|
||||
capture(:stdout) { runner.send(*args, &block) }
|
||||
end
|
||||
|
||||
def file
|
||||
File.join(destination_root, "foo")
|
||||
end
|
||||
|
||||
describe "on include" do
|
||||
it "adds runtime options to the base class" do
|
||||
expect(MyCounter.class_options.keys).to include(:pretend)
|
||||
expect(MyCounter.class_options.keys).to include(:force)
|
||||
expect(MyCounter.class_options.keys).to include(:quiet)
|
||||
expect(MyCounter.class_options.keys).to include(:skip)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#initialize" do
|
||||
it "has default behavior invoke" do
|
||||
expect(runner.behavior).to eq(:invoke)
|
||||
end
|
||||
|
||||
it "can have behavior revoke" do
|
||||
expect(MyCounter.new([1], {}, :behavior => :revoke).behavior).to eq(:revoke)
|
||||
end
|
||||
|
||||
it "when behavior is set to force, overwrite options" do
|
||||
runner = MyCounter.new([1], { :force => false, :skip => true }, :behavior => :force)
|
||||
expect(runner.behavior).to eq(:invoke)
|
||||
expect(runner.options.force).to be_true
|
||||
expect(runner.options.skip).not_to be_true
|
||||
end
|
||||
|
||||
it "when behavior is set to skip, overwrite options" do
|
||||
runner = MyCounter.new([1], ["--force"], :behavior => :skip)
|
||||
expect(runner.behavior).to eq(:invoke)
|
||||
expect(runner.options.force).not_to be_true
|
||||
expect(runner.options.skip).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "accessors" do
|
||||
describe "#destination_root=" do
|
||||
it "gets the current directory and expands the path to set the root" do
|
||||
base = MyCounter.new([1])
|
||||
base.destination_root = "here"
|
||||
expect(base.destination_root).to eq(File.expand_path(File.join(File.dirname(__FILE__), "..", "here")))
|
||||
end
|
||||
|
||||
it "does not use the current directory if one is given" do
|
||||
root = File.expand_path("/")
|
||||
base = MyCounter.new([1])
|
||||
base.destination_root = root
|
||||
expect(base.destination_root).to eq(root)
|
||||
end
|
||||
|
||||
it "uses the current directory if none is given" do
|
||||
base = MyCounter.new([1])
|
||||
expect(base.destination_root).to eq(File.expand_path(File.join(File.dirname(__FILE__), "..")))
|
||||
end
|
||||
end
|
||||
|
||||
describe "#relative_to_original_destination_root" do
|
||||
it "returns the path relative to the absolute root" do
|
||||
expect(runner.relative_to_original_destination_root(file)).to eq("foo")
|
||||
end
|
||||
|
||||
it "does not remove dot if required" do
|
||||
expect(runner.relative_to_original_destination_root(file, false)).to eq("./foo")
|
||||
end
|
||||
|
||||
it "always use the absolute root" do
|
||||
runner.inside("foo") do
|
||||
expect(runner.relative_to_original_destination_root(file)).to eq("foo")
|
||||
end
|
||||
end
|
||||
|
||||
it "creates proper relative paths for absolute file location" do
|
||||
expect(runner.relative_to_original_destination_root('/test/file')).to eq("/test/file")
|
||||
end
|
||||
|
||||
it "does not fail with files constaining regexp characters" do
|
||||
runner = MyCounter.new([1], {}, { :destination_root => File.join(destination_root, "fo[o-b]ar") })
|
||||
expect(runner.relative_to_original_destination_root("bar")).to eq("bar")
|
||||
end
|
||||
|
||||
describe "#source_paths_for_search" do
|
||||
it "add source_root to source_paths_for_search" do
|
||||
expect(MyCounter.source_paths_for_search).to include(File.expand_path("fixtures", File.dirname(__FILE__)))
|
||||
end
|
||||
|
||||
it "keeps only current source root in source paths" do
|
||||
expect(ClearCounter.source_paths_for_search).to include(File.expand_path("fixtures/bundle", File.dirname(__FILE__)))
|
||||
expect(ClearCounter.source_paths_for_search).not_to include(File.expand_path("fixtures", File.dirname(__FILE__)))
|
||||
end
|
||||
|
||||
it "customized source paths should be before source roots" do
|
||||
expect(ClearCounter.source_paths_for_search[0]).to eq(File.expand_path("fixtures/doc", File.dirname(__FILE__)))
|
||||
expect(ClearCounter.source_paths_for_search[1]).to eq(File.expand_path("fixtures/bundle", File.dirname(__FILE__)))
|
||||
end
|
||||
|
||||
it "keeps inherited source paths at the end" do
|
||||
expect(ClearCounter.source_paths_for_search.last).to eq(File.expand_path("fixtures/broken", File.dirname(__FILE__)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_in_source_paths" do
|
||||
it "raises an error if source path is empty" do
|
||||
expect {
|
||||
A.new.find_in_source_paths("foo")
|
||||
}.to raise_error(Thor::Error, /Currently you have no source paths/)
|
||||
end
|
||||
|
||||
it "finds a template inside the source path" do
|
||||
expect(runner.find_in_source_paths("doc")).to eq(File.expand_path("doc", source_root))
|
||||
expect{ runner.find_in_source_paths("README") }.to raise_error
|
||||
|
||||
new_path = File.join(source_root, "doc")
|
||||
runner.instance_variable_set(:@source_paths, nil)
|
||||
runner.source_paths.unshift(new_path)
|
||||
expect(runner.find_in_source_paths("README")).to eq(File.expand_path("README", new_path))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#inside" do
|
||||
it "executes the block inside the given folder" do
|
||||
runner.inside("foo") do
|
||||
expect(Dir.pwd).to eq(file)
|
||||
end
|
||||
end
|
||||
|
||||
it "changes the base root" do
|
||||
runner.inside("foo") do
|
||||
expect(runner.destination_root).to eq(file)
|
||||
end
|
||||
end
|
||||
|
||||
it "creates the directory if it does not exist" do
|
||||
runner.inside("foo") do
|
||||
expect(File.exists?(file)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "when pretending" do
|
||||
it "no directories should be created" do
|
||||
runner.inside("bar", :pretend => true) {}
|
||||
expect(File.exists?("bar")).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "when verbose" do
|
||||
it "logs status" do
|
||||
expect(capture(:stdout) {
|
||||
runner.inside("foo", :verbose => true) {}
|
||||
}).to match(/inside foo/)
|
||||
end
|
||||
|
||||
it "uses padding in next status" do
|
||||
expect(capture(:stdout) {
|
||||
runner.inside("foo", :verbose => true) do
|
||||
runner.say_status :cool, :padding
|
||||
end
|
||||
}).to match(/cool padding/)
|
||||
end
|
||||
|
||||
it "removes padding after block" do
|
||||
expect(capture(:stdout) {
|
||||
runner.inside("foo", :verbose => true) {}
|
||||
runner.say_status :no, :padding
|
||||
}).to match(/no padding/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#in_root" do
|
||||
it "executes the block in the root folder" do
|
||||
runner.inside("foo") do
|
||||
runner.in_root { expect(Dir.pwd).to eq(destination_root) }
|
||||
end
|
||||
end
|
||||
|
||||
it "changes the base root" do
|
||||
runner.inside("foo") do
|
||||
runner.in_root { expect(runner.destination_root).to eq(destination_root) }
|
||||
end
|
||||
end
|
||||
|
||||
it "returns to the previous state" do
|
||||
runner.inside("foo") do
|
||||
runner.in_root { }
|
||||
expect(runner.destination_root).to eq(file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#apply" do
|
||||
before do
|
||||
@template = <<-TEMPLATE
|
||||
@foo = "FOO"
|
||||
say_status :cool, :padding
|
||||
TEMPLATE
|
||||
@template.stub(:read).and_return(@template)
|
||||
|
||||
@file = '/'
|
||||
runner.stub(:open).and_return(@template)
|
||||
end
|
||||
|
||||
it "accepts a URL as the path" do
|
||||
@file = "http://gist.github.com/103208.txt"
|
||||
runner.should_receive(:open).with(@file, "Accept" => "application/x-thor-template").and_return(@template)
|
||||
action(:apply, @file)
|
||||
end
|
||||
|
||||
it "accepts a secure URL as the path" do
|
||||
@file = "https://gist.github.com/103208.txt"
|
||||
runner.should_receive(:open).with(@file, "Accept" => "application/x-thor-template").and_return(@template)
|
||||
action(:apply, @file)
|
||||
end
|
||||
|
||||
it "accepts a local file path with spaces" do
|
||||
@file = File.expand_path("fixtures/path with spaces", File.dirname(__FILE__))
|
||||
runner.should_receive(:open).with(@file).and_return(@template)
|
||||
action(:apply, @file)
|
||||
end
|
||||
|
||||
it "opens a file and executes its content in the instance binding" do
|
||||
action :apply, @file
|
||||
expect(runner.instance_variable_get("@foo")).to eq("FOO")
|
||||
end
|
||||
|
||||
it "applies padding to the content inside the file" do
|
||||
expect(action(:apply, @file)).to match(/cool padding/)
|
||||
end
|
||||
|
||||
it "logs its status" do
|
||||
expect(action(:apply, @file)).to match(/ apply #{@file}\n/)
|
||||
end
|
||||
|
||||
it "does not log status" do
|
||||
content = action(:apply, @file, :verbose => false)
|
||||
expect(content).to match(/cool padding/)
|
||||
expect(content).not_to match(/apply http/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#run" do
|
||||
before do
|
||||
runner.should_receive(:system).with("ls")
|
||||
end
|
||||
|
||||
it "executes the command given" do
|
||||
action :run, "ls"
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:run, "ls")).to eq(" run ls from \".\"\n")
|
||||
end
|
||||
|
||||
it "does not log status if required" do
|
||||
expect(action(:run, "ls", :verbose => false)).to be_empty
|
||||
end
|
||||
|
||||
it "accepts a color as status" do
|
||||
runner.shell.should_receive(:say_status).with(:run, 'ls from "."', :yellow)
|
||||
action :run, "ls", :verbose => :yellow
|
||||
end
|
||||
end
|
||||
|
||||
describe "#run_ruby_script" do
|
||||
before do
|
||||
Thor::Util.stub!(:ruby_command).and_return("/opt/jruby")
|
||||
runner.should_receive(:system).with("/opt/jruby script.rb")
|
||||
end
|
||||
|
||||
it "executes the ruby script" do
|
||||
action :run_ruby_script, "script.rb"
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
expect(action(:run_ruby_script, "script.rb")).to eq(" run jruby script.rb from \".\"\n")
|
||||
end
|
||||
|
||||
it "does not log status if required" do
|
||||
expect(action(:run_ruby_script, "script.rb", :verbose => false)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#thor" do
|
||||
it "executes the thor command" do
|
||||
runner.should_receive(:system).with("thor list")
|
||||
action :thor, :list, :verbose => true
|
||||
end
|
||||
|
||||
it "converts extra arguments to command arguments" do
|
||||
runner.should_receive(:system).with("thor list foo bar")
|
||||
action :thor, :list, "foo", "bar"
|
||||
end
|
||||
|
||||
it "converts options hash to switches" do
|
||||
runner.should_receive(:system).with("thor list foo bar --foo")
|
||||
action :thor, :list, "foo", "bar", :foo => true
|
||||
|
||||
runner.should_receive(:system).with("thor list --foo 1 2 3")
|
||||
action :thor, :list, :foo => [1,2,3]
|
||||
end
|
||||
|
||||
it "logs status" do
|
||||
runner.should_receive(:system).with("thor list")
|
||||
expect(action(:thor, :list)).to eq(" run thor list from \".\"\n")
|
||||
end
|
||||
|
||||
it "does not log status if required" do
|
||||
runner.should_receive(:system).with("thor list --foo 1 2 3")
|
||||
expect(action(:thor, :list, :foo => [1,2,3], :verbose => false)).to be_empty
|
||||
end
|
||||
|
||||
it "captures the output when :capture is given" do
|
||||
runner.should_receive(:`).with("thor foo bar")
|
||||
action(:thor, "foo", "bar", :capture => true)
|
||||
end
|
||||
end
|
||||
end
|
||||
291
vendor/gems/thor-0.18.1/spec/base_spec.rb
vendored
Normal file
291
vendor/gems/thor-0.18.1/spec/base_spec.rb
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
require 'helper'
|
||||
require 'thor/base'
|
||||
|
||||
class Amazing
|
||||
desc "hello", "say hello"
|
||||
def hello
|
||||
puts "Hello"
|
||||
end
|
||||
end
|
||||
|
||||
describe Thor::Base do
|
||||
describe "#initialize" do
|
||||
it "sets arguments array" do
|
||||
base = MyCounter.new [1, 2]
|
||||
expect(base.first).to eq(1)
|
||||
expect(base.second).to eq(2)
|
||||
end
|
||||
|
||||
it "sets arguments default values" do
|
||||
base = MyCounter.new [1]
|
||||
expect(base.second).to eq(2)
|
||||
end
|
||||
|
||||
it "sets options default values" do
|
||||
base = MyCounter.new [1, 2]
|
||||
expect(base.options[:third]).to eq(3)
|
||||
end
|
||||
|
||||
it "allows options to be given as symbols or strings" do
|
||||
base = MyCounter.new [1, 2], :third => 4
|
||||
expect(base.options[:third]).to eq(4)
|
||||
|
||||
base = MyCounter.new [1, 2], "third" => 4
|
||||
expect(base.options[:third]).to eq(4)
|
||||
end
|
||||
|
||||
it "creates options with indifferent access" do
|
||||
base = MyCounter.new [1, 2], :third => 3
|
||||
expect(base.options['third']).to eq(3)
|
||||
end
|
||||
|
||||
it "creates options with magic predicates" do
|
||||
base = MyCounter.new [1, 2], :third => 3
|
||||
expect(base.options.third).to eq(3)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#no_commands" do
|
||||
it "avoids methods being added as commands" do
|
||||
expect(MyScript.commands.keys).to include("animal")
|
||||
expect(MyScript.commands.keys).not_to include("this_is_not_a_command")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#argument" do
|
||||
it "sets a value as required and creates an accessor for it" do
|
||||
expect(MyCounter.start(["1", "2", "--third", "3"])[0]).to eq(1)
|
||||
expect(Scripts::MyScript.start(["zoo", "my_special_param", "--param=normal_param"])).to eq("my_special_param")
|
||||
end
|
||||
|
||||
it "does not set a value in the options hash" do
|
||||
expect(BrokenCounter.start(["1", "2", "--third", "3"])[0]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#arguments" do
|
||||
it "returns the arguments for the class" do
|
||||
expect(MyCounter.arguments).to have(2).items
|
||||
end
|
||||
end
|
||||
|
||||
describe ":aliases" do
|
||||
it "supports string aliases without a dash prefix" do
|
||||
expect(MyCounter.start(["1", "2", "-z", "3"])[4]).to eq(3)
|
||||
end
|
||||
|
||||
it "supports symbol aliases" do
|
||||
expect(MyCounter.start(["1", "2", "-y", "3"])[5]).to eq(3)
|
||||
expect(MyCounter.start(["1", "2", "-r", "3"])[5]).to eq(3)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#class_option" do
|
||||
it "sets options class wise" do
|
||||
expect(MyCounter.start(["1", "2", "--third", "3"])[2]).to eq(3)
|
||||
end
|
||||
|
||||
it "does not create an accessor for it" do
|
||||
expect(BrokenCounter.start(["1", "2", "--third", "3"])[3]).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#class_options" do
|
||||
it "sets default options overwriting superclass definitions" do
|
||||
options = Scripts::MyScript.class_options
|
||||
expect(options[:force]).not_to be_required
|
||||
end
|
||||
end
|
||||
|
||||
describe "#remove_argument" do
|
||||
it "removes previous defined arguments from class" do
|
||||
expect(ClearCounter.arguments).to be_empty
|
||||
end
|
||||
|
||||
it "undefine accessors if required" do
|
||||
expect(ClearCounter.new).not_to respond_to(:first)
|
||||
expect(ClearCounter.new).not_to respond_to(:second)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#remove_class_option" do
|
||||
it "removes previous defined class option" do
|
||||
expect(ClearCounter.class_options[:third]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#class_options_help" do
|
||||
before do
|
||||
@content = capture(:stdout) { MyCounter.help(Thor::Base.shell.new) }
|
||||
end
|
||||
|
||||
it "shows options description" do
|
||||
expect(@content).to match(/# The third argument/)
|
||||
end
|
||||
|
||||
it "shows usage with banner content" do
|
||||
expect(@content).to match(/\[\-\-third=THREE\]/)
|
||||
end
|
||||
|
||||
it "shows default values below description" do
|
||||
expect(@content).to match(/# Default: 3/)
|
||||
end
|
||||
|
||||
it "shows options in different groups" do
|
||||
expect(@content).to match(/Options\:/)
|
||||
expect(@content).to match(/Runtime options\:/)
|
||||
expect(@content).to match(/\-p, \[\-\-pretend\]/)
|
||||
end
|
||||
|
||||
it "use padding in options that does not have aliases" do
|
||||
expect(@content).to match(/^ -t, \[--third/)
|
||||
expect(@content).to match(/^ \[--fourth/)
|
||||
end
|
||||
|
||||
it "allows extra options to be given" do
|
||||
hash = { "Foo" => B.class_options.values }
|
||||
|
||||
content = capture(:stdout) { MyCounter.send(:class_options_help, Thor::Base.shell.new, hash) }
|
||||
expect(content).to match(/Foo options\:/)
|
||||
expect(content).to match(/--last-name=LAST_NAME/)
|
||||
end
|
||||
|
||||
it "displays choices for enums" do
|
||||
content = capture(:stdout) { Enum.help(Thor::Base.shell.new) }
|
||||
expect(content).to match(/Possible values\: apple, banana/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#namespace" do
|
||||
it "returns the default class namespace" do
|
||||
expect(Scripts::MyScript.namespace).to eq("scripts:my_script")
|
||||
end
|
||||
|
||||
it "sets a namespace to the class" do
|
||||
expect(Scripts::MyDefaults.namespace).to eq("default")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#group" do
|
||||
it "sets a group" do
|
||||
expect(MyScript.group).to eq("script")
|
||||
end
|
||||
|
||||
it "inherits the group from parent" do
|
||||
expect(MyChildScript.group).to eq("script")
|
||||
end
|
||||
|
||||
it "defaults to standard if no group is given" do
|
||||
expect(Amazing.group).to eq("standard")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#subclasses" do
|
||||
it "tracks its subclasses in an Array" do
|
||||
expect(Thor::Base.subclasses).to include(MyScript)
|
||||
expect(Thor::Base.subclasses).to include(MyChildScript)
|
||||
expect(Thor::Base.subclasses).to include(Scripts::MyScript)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#subclass_files" do
|
||||
it "returns tracked subclasses, grouped by the files they come from" do
|
||||
thorfile = File.join(File.dirname(__FILE__), "fixtures", "script.thor")
|
||||
expect(Thor::Base.subclass_files[File.expand_path(thorfile)]).to eq([
|
||||
MyScript, MyScript::AnotherScript, MyChildScript, Barn,
|
||||
PackageNameScript, Scripts::MyScript, Scripts::MyDefaults,
|
||||
Scripts::ChildDefault, Scripts::Arities
|
||||
])
|
||||
end
|
||||
|
||||
it "tracks a single subclass across multiple files" do
|
||||
thorfile = File.join(File.dirname(__FILE__), "fixtures", "command.thor")
|
||||
expect(Thor::Base.subclass_files[File.expand_path(thorfile)]).to include(Amazing)
|
||||
expect(Thor::Base.subclass_files[File.expand_path(__FILE__)]).to include(Amazing)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#commands" do
|
||||
it "returns a list with all commands defined in this class" do
|
||||
expect(MyChildScript.new).to respond_to("animal")
|
||||
expect(MyChildScript.commands.keys).to include("animal")
|
||||
end
|
||||
|
||||
it "raises an error if a command with reserved word is defined" do
|
||||
expect {
|
||||
klass = Class.new(Thor::Group)
|
||||
klass.class_eval "def shell; end"
|
||||
}.to raise_error(RuntimeError, /"shell" is a Thor reserved word and cannot be defined as command/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#all_commands" do
|
||||
it "returns a list with all commands defined in this class plus superclasses" do
|
||||
expect(MyChildScript.new).to respond_to("foo")
|
||||
expect(MyChildScript.all_commands.keys).to include("foo")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#remove_command" do
|
||||
it "removes the command from its commands hash" do
|
||||
expect(MyChildScript.commands.keys).not_to include("bar")
|
||||
expect(MyChildScript.commands.keys).not_to include("boom")
|
||||
end
|
||||
|
||||
it "undefines the method if desired" do
|
||||
expect(MyChildScript.new).not_to respond_to("boom")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#from_superclass" do
|
||||
it "does not send a method to the superclass if the superclass does not respond to it" do
|
||||
expect(MyCounter.get_from_super).to eq(13)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#start" do
|
||||
it "raises an error instead of rescueing if THOR_DEBUG=1 is given" do
|
||||
begin
|
||||
ENV["THOR_DEBUG"] = 1
|
||||
expect {
|
||||
MyScript.start ["what", "--debug"]
|
||||
}.to raise_error(Thor::UndefinedcommandError, 'Could not find command "what" in "my_script" namespace.')
|
||||
rescue
|
||||
ENV["THOR_DEBUG"] = nil
|
||||
end
|
||||
end
|
||||
|
||||
it "does not steal args" do
|
||||
args = ["foo", "bar", "--force", "true"]
|
||||
MyScript.start(args)
|
||||
expect(args).to eq(["foo", "bar", "--force", "true"])
|
||||
end
|
||||
|
||||
it "checks unknown options" do
|
||||
expect(capture(:stderr) {
|
||||
MyScript.start(["foo", "bar", "--force", "true", "--unknown", "baz"])
|
||||
}.strip).to eq("Unknown switches '--unknown'")
|
||||
end
|
||||
|
||||
it "checks unknown options except specified" do
|
||||
expect(capture(:stderr) {
|
||||
expect(MyScript.start(["with_optional", "NAME", "--omg", "--invalid"])).to eq(["NAME", {}, ["--omg", "--invalid"]])
|
||||
}.strip).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "attr_*" do
|
||||
it "does not add attr_reader as a command" do
|
||||
expect(capture(:stderr){ MyScript.start(["another_attribute"]) }).to match(/Could not find/)
|
||||
end
|
||||
|
||||
it "does not add attr_writer as a command" do
|
||||
expect(capture(:stderr){ MyScript.start(["another_attribute=", "foo"]) }).to match(/Could not find/)
|
||||
end
|
||||
|
||||
it "does not add attr_accessor as a command" do
|
||||
expect(capture(:stderr){ MyScript.start(["some_attribute"]) }).to match(/Could not find/)
|
||||
expect(capture(:stderr){ MyScript.start(["some_attribute=", "foo"]) }).to match(/Could not find/)
|
||||
end
|
||||
end
|
||||
end
|
||||
80
vendor/gems/thor-0.18.1/spec/command_spec.rb
vendored
Normal file
80
vendor/gems/thor-0.18.1/spec/command_spec.rb
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
require 'helper'
|
||||
|
||||
describe Thor::Command do
|
||||
def command(options={})
|
||||
options.each do |key, value|
|
||||
options[key] = Thor::Option.parse(key, value)
|
||||
end
|
||||
|
||||
@command ||= Thor::Command.new(:can_has, "I can has cheezburger", "I can has cheezburger\nLots and lots of it", "can_has", options)
|
||||
end
|
||||
|
||||
describe "#formatted_usage" do
|
||||
it "includes namespace within usage" do
|
||||
object = Struct.new(:namespace, :arguments).new("foo", [])
|
||||
expect(command(:bar => :required).formatted_usage(object)).to eq("foo:can_has --bar=BAR")
|
||||
end
|
||||
|
||||
it "includes subcommand name within subcommand usage" do
|
||||
object = Struct.new(:namespace, :arguments).new("main:foo", [])
|
||||
expect(command(:bar => :required).formatted_usage(object, false, true)).to eq("foo can_has --bar=BAR")
|
||||
end
|
||||
|
||||
it "removes default from namespace" do
|
||||
object = Struct.new(:namespace, :arguments).new("default:foo", [])
|
||||
expect(command(:bar => :required).formatted_usage(object)).to eq(":foo:can_has --bar=BAR")
|
||||
end
|
||||
|
||||
it "injects arguments into usage" do
|
||||
options = {:required => true, :type => :string}
|
||||
object = Struct.new(:namespace, :arguments).new("foo", [Thor::Argument.new(:bar, options)])
|
||||
expect(command(:foo => :required).formatted_usage(object)).to eq("foo:can_has BAR --foo=FOO")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#dynamic" do
|
||||
it "creates a dynamic command with the given name" do
|
||||
expect(Thor::DynamicCommand.new('command').name).to eq('command')
|
||||
expect(Thor::DynamicCommand.new('command').description).to eq('A dynamically-generated command')
|
||||
expect(Thor::DynamicCommand.new('command').usage).to eq('command')
|
||||
expect(Thor::DynamicCommand.new('command').options).to eq({})
|
||||
end
|
||||
|
||||
it "does not invoke an existing method" do
|
||||
mock = mock()
|
||||
mock.class.should_receive(:handle_no_command_error).with("to_s")
|
||||
Thor::DynamicCommand.new('to_s').run(mock)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#dup" do
|
||||
it "dup options hash" do
|
||||
command = Thor::Command.new("can_has", nil, nil, nil, :foo => true, :bar => :required)
|
||||
command.dup.options.delete(:foo)
|
||||
expect(command.options[:foo]).to be
|
||||
end
|
||||
end
|
||||
|
||||
describe "#run" do
|
||||
it "runs a command by calling a method in the given instance" do
|
||||
mock = mock()
|
||||
mock.should_receive(:can_has).and_return {|*args| args }
|
||||
expect(command.run(mock, [1, 2, 3])).to eq([1, 2, 3])
|
||||
end
|
||||
|
||||
it "raises an error if the method to be invoked is private" do
|
||||
klass = Class.new do
|
||||
def self.handle_no_command_error(name)
|
||||
name
|
||||
end
|
||||
|
||||
private
|
||||
def can_has
|
||||
"fail"
|
||||
end
|
||||
end
|
||||
|
||||
expect(command.run(klass.new)).to eq("can_has")
|
||||
end
|
||||
end
|
||||
end
|
||||
48
vendor/gems/thor-0.18.1/spec/core_ext/hash_with_indifferent_access_spec.rb
vendored
Normal file
48
vendor/gems/thor-0.18.1/spec/core_ext/hash_with_indifferent_access_spec.rb
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
require 'helper'
|
||||
require 'thor/core_ext/hash_with_indifferent_access'
|
||||
|
||||
describe Thor::CoreExt::HashWithIndifferentAccess do
|
||||
before do
|
||||
@hash = Thor::CoreExt::HashWithIndifferentAccess.new :foo => 'bar', 'baz' => 'bee', :force => true
|
||||
end
|
||||
|
||||
it "has values accessible by either strings or symbols" do
|
||||
expect(@hash['foo']).to eq('bar')
|
||||
expect(@hash[:foo]).to eq('bar')
|
||||
|
||||
expect(@hash.values_at(:foo, :baz)).to eq(['bar', 'bee'])
|
||||
expect(@hash.delete(:foo)).to eq('bar')
|
||||
end
|
||||
|
||||
it "handles magic boolean predicates" do
|
||||
expect(@hash.force?).to be_true
|
||||
expect(@hash.foo?).to be_true
|
||||
expect(@hash.nothing?).to be_false
|
||||
end
|
||||
|
||||
it "handles magic comparisions" do
|
||||
expect(@hash.foo?('bar')).to be_true
|
||||
expect(@hash.foo?('bee')).to be_false
|
||||
end
|
||||
|
||||
it "maps methods to keys" do
|
||||
expect(@hash.foo).to eq(@hash['foo'])
|
||||
end
|
||||
|
||||
it "merges keys independent if they are symbols or strings" do
|
||||
@hash.merge!('force' => false, :baz => "boom")
|
||||
expect(@hash[:force]).to eq(false)
|
||||
expect(@hash[:baz]).to eq("boom")
|
||||
end
|
||||
|
||||
it "creates a new hash by merging keys independent if they are symbols or strings" do
|
||||
other = @hash.merge('force' => false, :baz => "boom")
|
||||
expect(other[:force]).to eq(false)
|
||||
expect(other[:baz]).to eq("boom")
|
||||
end
|
||||
|
||||
it "converts to a traditional hash" do
|
||||
expect(@hash.to_hash.class).to eq(Hash)
|
||||
expect(@hash).to eq({ 'foo' => 'bar', 'baz' => 'bee', 'force' => true })
|
||||
end
|
||||
end
|
||||
115
vendor/gems/thor-0.18.1/spec/core_ext/ordered_hash_spec.rb
vendored
Normal file
115
vendor/gems/thor-0.18.1/spec/core_ext/ordered_hash_spec.rb
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
require 'helper'
|
||||
require 'thor/core_ext/ordered_hash'
|
||||
|
||||
describe Thor::CoreExt::OrderedHash do
|
||||
before do
|
||||
@hash = Thor::CoreExt::OrderedHash.new
|
||||
end
|
||||
|
||||
describe "without any items" do
|
||||
it "returns nil for an undefined key" do
|
||||
expect(@hash["foo"]).to be_nil
|
||||
end
|
||||
|
||||
it "doesn't iterate through any items" do
|
||||
@hash.each { fail }
|
||||
end
|
||||
|
||||
it "has an empty key and values list" do
|
||||
expect(@hash.keys).to be_empty
|
||||
expect(@hash.values).to be_empty
|
||||
end
|
||||
|
||||
it "must be empty" do
|
||||
expect(@hash).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "with several items" do
|
||||
before do
|
||||
@hash[:foo] = "Foo!"
|
||||
@hash[:bar] = "Bar!"
|
||||
@hash[:baz] = "Baz!"
|
||||
@hash[:bop] = "Bop!"
|
||||
@hash[:bat] = "Bat!"
|
||||
end
|
||||
|
||||
it "returns nil for an undefined key" do
|
||||
expect(@hash[:boom]).to be_nil
|
||||
end
|
||||
|
||||
it "returns the value for each key" do
|
||||
expect(@hash[:foo]).to eq("Foo!")
|
||||
expect(@hash[:bar]).to eq("Bar!")
|
||||
expect(@hash[:baz]).to eq("Baz!")
|
||||
expect(@hash[:bop]).to eq("Bop!")
|
||||
expect(@hash[:bat]).to eq("Bat!")
|
||||
end
|
||||
|
||||
it "iterates through the keys and values in order of assignment" do
|
||||
arr = []
|
||||
@hash.each do |key, value|
|
||||
arr << [key, value]
|
||||
end
|
||||
expect(arr).to eq([[:foo, "Foo!"], [:bar, "Bar!"], [:baz, "Baz!"],
|
||||
[:bop, "Bop!"], [:bat, "Bat!"]])
|
||||
end
|
||||
|
||||
it "returns the keys in order of insertion" do
|
||||
expect(@hash.keys).to eq([:foo, :bar, :baz, :bop, :bat])
|
||||
end
|
||||
|
||||
it "returns the values in order of insertion" do
|
||||
expect(@hash.values).to eq(["Foo!", "Bar!", "Baz!", "Bop!", "Bat!"])
|
||||
end
|
||||
|
||||
it "does not move an overwritten node to the end of the ordering" do
|
||||
@hash[:baz] = "Bip!"
|
||||
expect(@hash.values).to eq(["Foo!", "Bar!", "Bip!", "Bop!", "Bat!"])
|
||||
|
||||
@hash[:foo] = "Bip!"
|
||||
expect(@hash.values).to eq(["Bip!", "Bar!", "Bip!", "Bop!", "Bat!"])
|
||||
|
||||
@hash[:bat] = "Bip!"
|
||||
expect(@hash.values).to eq(["Bip!", "Bar!", "Bip!", "Bop!", "Bip!"])
|
||||
end
|
||||
|
||||
it "appends another ordered hash while preserving ordering" do
|
||||
other_hash = Thor::CoreExt::OrderedHash.new
|
||||
other_hash[1] = "one"
|
||||
other_hash[2] = "two"
|
||||
other_hash[3] = "three"
|
||||
expect(@hash.merge(other_hash).values).to eq(["Foo!", "Bar!", "Baz!", "Bop!", "Bat!", "one", "two", "three"])
|
||||
end
|
||||
|
||||
it "overwrites hash keys with matching appended keys" do
|
||||
other_hash = Thor::CoreExt::OrderedHash.new
|
||||
other_hash[:bar] = "bar"
|
||||
expect(@hash.merge(other_hash)[:bar]).to eq("bar")
|
||||
expect(@hash[:bar]).to eq("Bar!")
|
||||
end
|
||||
|
||||
it "converts to an array" do
|
||||
expect(@hash.to_a).to eq([[:foo, "Foo!"], [:bar, "Bar!"], [:baz, "Baz!"], [:bop, "Bop!"], [:bat, "Bat!"]])
|
||||
end
|
||||
|
||||
it "must not be empty" do
|
||||
expect(@hash).not_to be_empty
|
||||
end
|
||||
|
||||
it "deletes values from hash" do
|
||||
expect(@hash.delete(:baz)).to eq("Baz!")
|
||||
expect(@hash.values).to eq(["Foo!", "Bar!", "Bop!", "Bat!"])
|
||||
|
||||
expect(@hash.delete(:foo)).to eq("Foo!")
|
||||
expect(@hash.values).to eq(["Bar!", "Bop!", "Bat!"])
|
||||
|
||||
expect(@hash.delete(:bat)).to eq("Bat!")
|
||||
expect(@hash.values).to eq(["Bar!", "Bop!"])
|
||||
end
|
||||
|
||||
it "returns nil if the value to be deleted can't be found" do
|
||||
expect(@hash.delete(:nothing)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
19
vendor/gems/thor-0.18.1/spec/exit_condition_spec.rb
vendored
Normal file
19
vendor/gems/thor-0.18.1/spec/exit_condition_spec.rb
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
require 'helper'
|
||||
require 'thor/base'
|
||||
|
||||
describe "Exit conditions" do
|
||||
it "exits 0, not bubble up EPIPE, if EPIPE is raised" do
|
||||
epiped = false
|
||||
|
||||
command = Class.new(Thor) do
|
||||
desc "my_action", "testing EPIPE"
|
||||
define_method :my_action do
|
||||
epiped = true
|
||||
raise Errno::EPIPE
|
||||
end
|
||||
end
|
||||
|
||||
expect{ command.start(["my_action"]) }.to raise_error(SystemExit)
|
||||
expect(epiped).to eq(true)
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user