crafterm-sprinkle 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/CREDITS +11 -0
  2. data/History.txt +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +55 -0
  5. data/README.txt +218 -0
  6. data/Rakefile +4 -0
  7. data/bin/sprinkle +79 -0
  8. data/config/hoe.rb +70 -0
  9. data/config/requirements.rb +17 -0
  10. data/examples/merb/deploy.rb +5 -0
  11. data/examples/rails/README +15 -0
  12. data/examples/rails/deploy.rb +2 -0
  13. data/examples/rails/packages/database.rb +9 -0
  14. data/examples/rails/packages/essential.rb +6 -0
  15. data/examples/rails/packages/rails.rb +28 -0
  16. data/examples/rails/packages/search.rb +11 -0
  17. data/examples/rails/packages/server.rb +28 -0
  18. data/examples/rails/rails.rb +71 -0
  19. data/lib/sprinkle/actors/capistrano.rb +80 -0
  20. data/lib/sprinkle/deployment.rb +33 -0
  21. data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
  22. data/lib/sprinkle/extensions/array.rb +7 -0
  23. data/lib/sprinkle/extensions/blank_slate.rb +5 -0
  24. data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
  25. data/lib/sprinkle/extensions/string.rb +10 -0
  26. data/lib/sprinkle/extensions/symbol.rb +7 -0
  27. data/lib/sprinkle/installers/apt.rb +20 -0
  28. data/lib/sprinkle/installers/gem.rb +31 -0
  29. data/lib/sprinkle/installers/installer.rb +47 -0
  30. data/lib/sprinkle/installers/rake.rb +16 -0
  31. data/lib/sprinkle/installers/source.rb +137 -0
  32. data/lib/sprinkle/package.rb +76 -0
  33. data/lib/sprinkle/policy.rb +84 -0
  34. data/lib/sprinkle/script.rb +13 -0
  35. data/lib/sprinkle/version.rb +9 -0
  36. data/lib/sprinkle.rb +29 -0
  37. data/script/destroy +14 -0
  38. data/script/generate +14 -0
  39. data/spec/spec.opts +1 -0
  40. data/spec/spec_helper.rb +17 -0
  41. data/spec/sprinkle/actors/capistrano_spec.rb +150 -0
  42. data/spec/sprinkle/deployment_spec.rb +80 -0
  43. data/spec/sprinkle/extensions/array_spec.rb +19 -0
  44. data/spec/sprinkle/extensions/string_spec.rb +21 -0
  45. data/spec/sprinkle/installers/apt_spec.rb +46 -0
  46. data/spec/sprinkle/installers/gem_spec.rb +64 -0
  47. data/spec/sprinkle/installers/installer_spec.rb +125 -0
  48. data/spec/sprinkle/installers/source_spec.rb +315 -0
  49. data/spec/sprinkle/package_spec.rb +203 -0
  50. data/spec/sprinkle/policy_spec.rb +110 -0
  51. data/spec/sprinkle/script_spec.rb +51 -0
  52. data/spec/sprinkle/sprinkle_spec.rb +25 -0
  53. data/tasks/deployment.rake +34 -0
  54. data/tasks/environment.rake +7 -0
  55. data/tasks/rspec.rake +21 -0
  56. metadata +137 -0
@@ -0,0 +1,80 @@
1
+ require 'capistrano/cli'
2
+
3
+ module Sprinkle
4
+ module Actors
5
+ class Capistrano
6
+ attr_accessor :config, :loaded_recipes
7
+
8
+ def initialize(&block)
9
+ @config = ::Capistrano::Configuration.new
10
+ @config.logger.level = Sprinkle::OPTIONS[:verbose] ? ::Capistrano::Logger::INFO : ::Capistrano::Logger::IMPORTANT
11
+ @config.set(:password) { ::Capistrano::CLI.password_prompt }
12
+ if block
13
+ self.instance_eval &block
14
+ else
15
+ @config.load 'deploy' # normally in the config directory for rails
16
+ end
17
+ end
18
+
19
+ def recipes(script)
20
+ @loaded_recipes ||= []
21
+ @config.load script
22
+ @loaded_recipes << script
23
+ end
24
+
25
+ def process(name, commands, roles)
26
+ define_task(name, roles) do
27
+ via = fetch(:run_method, :sudo)
28
+ commands.each do |command|
29
+ invoke_command command, :via => via
30
+ end
31
+ end
32
+ run(name)
33
+ end
34
+
35
+ private
36
+
37
+ # REVISIT: can we set the description somehow?
38
+ def define_task(name, roles, &block)
39
+ @config.task task_sym(name), :roles => roles, &block
40
+ end
41
+
42
+ def run(task)
43
+ @config.send task_sym(task)
44
+ end
45
+
46
+ def task_sym(name)
47
+ "install_#{name.to_task_name}".to_sym
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+
54
+ =begin
55
+
56
+ # channel: the SSH channel object used for this response
57
+ # stream: either :err or :out, for stderr or stdout responses
58
+ # output: the text that the server is sending, might be in chunks
59
+ run "apt-get update" do |channel, stream, output|
60
+ if output =~ /Are you sure?/
61
+ answer = Capistrano::CLI.ui.ask("Are you sure: ")
62
+ channel.send_data(answer + "\n")
63
+ else
64
+ # allow the default callback to be processed
65
+ Capistrano::Configuration.default_io_proc.call[channel, stream, output]
66
+ end
67
+ end
68
+
69
+
70
+
71
+ You can tell subversion to use a different username+password by
72
+ setting a couple variables:
73
+ set :svn_username, "my svn username"
74
+ set :svn_password, "my svn password"
75
+ If you don't want to set the password explicitly in your recipe like
76
+ that, you can make capistrano prompt you for it like this:
77
+ set(:svn_password) { Capistrano::CLI.password_prompt("Subversion
78
+ password: ") }
79
+ - Jamis
80
+ =end
@@ -0,0 +1,33 @@
1
+ module Sprinkle
2
+ module Deployment
3
+ def deployment(&block)
4
+ @deployment = Deployment.new(&block)
5
+ end
6
+
7
+ class Deployment
8
+ attr_accessor :style, :defaults
9
+
10
+ def initialize(&block)
11
+ @defaults = {}
12
+ self.instance_eval(&block)
13
+ raise 'No delivery mechanism defined' unless @style
14
+ end
15
+
16
+ def delivery(type, &block)
17
+ @style = Actors.const_get(type.to_s.titleize).new &block
18
+ end
19
+
20
+ def method_missing(sym, *args, &block)
21
+ @defaults[sym] = block
22
+ end
23
+
24
+ def respond_to?(sym); !!@defaults[sym]; end
25
+
26
+ def process
27
+ POLICIES.each do |policy|
28
+ policy.process(self)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,10 @@
1
+ module ArbitraryOptions
2
+ def self.included(base)
3
+ base.alias_method_chain :method_missing, :arbitrary_options
4
+ end
5
+
6
+ def method_missing_with_arbitrary_options(sym, *args, &block)
7
+ self.class.dsl_accessor sym
8
+ send(sym, *args, &block)
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ class Array
2
+
3
+ def to_task_name
4
+ collect(&:to_task_name).join('_')
5
+ end
6
+
7
+ end
@@ -0,0 +1,5 @@
1
+ class BlankSlate
2
+ instance_methods.each do |m|
3
+ undef_method(m) unless %w( __send__ __id__ send class inspect instance_eval instance_variables ).include?(m)
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ class Module
2
+ def dsl_accessor(*symbols)
3
+ symbols.each do |sym|
4
+ class_eval %{
5
+ def #{sym}(*val)
6
+ if val.empty?
7
+ @#{sym}
8
+ else
9
+ @#{sym} = val.size == 1 ? val[0] : val
10
+ end
11
+ end
12
+ }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ class String
2
+
3
+ # REVISIT: what chars shall we allow in task names?
4
+ def to_task_name
5
+ s = downcase
6
+ s.gsub!(/-/, '_') # all - to _ chars
7
+ s
8
+ end
9
+
10
+ end
@@ -0,0 +1,7 @@
1
+ class Symbol
2
+
3
+ def to_task_name
4
+ to_s.to_task_name
5
+ end
6
+
7
+ end
@@ -0,0 +1,20 @@
1
+ module Sprinkle
2
+ module Installers
3
+ class Apt < Installer
4
+ attr_accessor :packages
5
+
6
+ def initialize(parent, packages, &block)
7
+ super parent, &block
8
+ packages = [packages] unless packages.is_a? Array
9
+ @packages = packages
10
+ end
11
+
12
+ protected
13
+
14
+ def install_sequence
15
+ "DEBCONF_TERSE='yes' DEBIAN_PRIORITY='critical' DEBIAN_FRONTEND=noninteractive apt-get -qyu install #{@packages.join(' ')}"
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module Sprinkle
2
+ module Installers
3
+ class Gem < Installer
4
+ attr_accessor :gem
5
+
6
+ def initialize(parent, gem, options = {}, &block)
7
+ super parent, options, &block
8
+ @gem = gem
9
+ end
10
+
11
+ def source(location = nil)
12
+ # package defines an installer called source so here we specify a method directly
13
+ # rather than rely on the automatic options processing since packages' method missing
14
+ # won't be run
15
+ return @options[:source] unless location
16
+ @options[:source] = location
17
+ end
18
+
19
+ protected
20
+
21
+ # rubygems 0.9.5+ installs dependencies by default, and does platform selection
22
+
23
+ def install_sequence
24
+ cmd = "gem install #{gem}"
25
+ cmd << " --version '#{version}'" if version
26
+ cmd << " --source #{source}" if source
27
+ cmd
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,47 @@
1
+ module Sprinkle
2
+ module Installers
3
+ class Installer
4
+ attr_accessor :delivery, :package, :options
5
+
6
+ def initialize(package, options = {}, &block)
7
+ @package = package
8
+ @options = options
9
+ self.instance_eval(&block) if block
10
+ end
11
+
12
+ def defaults(deployment)
13
+ defaults = deployment.defaults[self.class.name.split(/::/).last.downcase.to_sym]
14
+ self.instance_eval(&defaults) if defaults
15
+ @delivery = deployment.style
16
+ end
17
+
18
+ def process(roles)
19
+ raise 'Unknown command delivery target' unless @delivery
20
+
21
+ if logger.debug?
22
+ sequence = install_sequence; sequence = sequence.join('; ') if sequence.is_a? Array
23
+ logger.debug "#{@package.name} install sequence: #{sequence} for roles: #{roles}\n"
24
+ end
25
+
26
+ unless Sprinkle::OPTIONS[:testing]
27
+ logger.info "--> Installing #{package.name} for roles: #{roles}"
28
+ @delivery.process(@package.name, install_sequence, roles)
29
+ end
30
+ end
31
+
32
+ def method_missing(sym, *args, &block)
33
+ unless args.empty? # mutate if not set
34
+ @options[sym] = *args unless @options[sym]
35
+ end
36
+
37
+ @options[sym] || @package.send(sym, *args, &block) # try the parents options if unknown
38
+ end
39
+
40
+ protected
41
+
42
+ def install_sequence
43
+ raise 'Concrete installers implement this to specify commands to run to install their respective packages'
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ module Sprinkle
2
+ module Installers
3
+ class Rake < Installer
4
+ def initialize(parent, commands = [], &block)
5
+ super parent, &block
6
+ @commands = commands
7
+ end
8
+
9
+ protected
10
+
11
+ def install_sequence
12
+ "rake #{@commands.join(' ')}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,137 @@
1
+ module Sprinkle
2
+ module Installers
3
+ class Source < Installer
4
+ attr_accessor :source, :pre, :post
5
+
6
+ def initialize(parent, source, options = {}, &block)
7
+ @pre = {}; @post = {}
8
+ @source = source
9
+ super parent, options, &block
10
+ end
11
+
12
+ def pre(stage, *commands)
13
+ @pre[stage] ||= []
14
+ @pre[stage] += commands
15
+ end
16
+
17
+ def post(stage, *commands)
18
+ @post[stage] ||= []
19
+ @post[stage] += commands
20
+ end
21
+
22
+ protected
23
+
24
+ def install_sequence
25
+ prepare + download + extract + configure + build + install
26
+ end
27
+
28
+ %w( prepare download extract configure build install ).each do |stage|
29
+ define_method stage do
30
+ pre_commands(stage.to_sym) + self.send("#{stage}_commands") + post_commands(stage.to_sym)
31
+ end
32
+ end
33
+
34
+ def prepare_commands
35
+ raise 'No installation area defined' unless @options[:prefix]
36
+ raise 'No build area defined' unless @options[:builds]
37
+ raise 'No source download area defined' unless @options[:archives]
38
+
39
+ [ "mkdir -p #{@options[:prefix]}",
40
+ "mkdir -p #{@options[:builds]}",
41
+ "mkdir -p #{@options[:archives]}" ]
42
+ end
43
+
44
+ def download_commands
45
+ [ "wget -cq --directory-prefix='#{@options[:archives]}' #{@source}" ]
46
+ end
47
+
48
+ def extract_commands
49
+ [ "bash -c 'cd #{@options[:builds]} && #{extract_command} #{@options[:archives]}/#{archive_name}'" ]
50
+ end
51
+
52
+ def configure_commands
53
+ return [] if custom_install?
54
+
55
+ command = "bash -c 'cd #{build_dir} && ./configure --silent --prefix #{@options[:prefix]} "
56
+
57
+ extras = {
58
+ :enable => '--enable', :disable => '--disable',
59
+ :with => '--with', :without => '--without'
60
+ }
61
+
62
+ extras.inject(command) { |m, (k, v)| m << create_options(k, v) if options[k]; m }
63
+
64
+ [ command << " > #{@package.name}-configure.log 2>&1'" ]
65
+ end
66
+
67
+ def build_commands
68
+ return [] if custom_install?
69
+ [ "bash -c 'cd #{build_dir} && make > #{@package.name}-build.log 2>&1'" ]
70
+ end
71
+
72
+ def install_commands
73
+ return custom_install_commands if custom_install?
74
+ [ "bash -c 'cd #{build_dir} && make install > #{@package.name}-install.log 2>&1'" ]
75
+ end
76
+
77
+ def custom_install?
78
+ !! @options[:custom_install]
79
+ end
80
+
81
+ # REVISIT: must be better processing of custom install commands somehow? use splat operator?
82
+ def custom_install_commands
83
+ dress @options[:custom_install], :install
84
+ end
85
+
86
+ private
87
+
88
+ def pre_commands(stage)
89
+ dress @pre[stage] || [], :pre
90
+ end
91
+
92
+ def post_commands(stage)
93
+ dress @post[stage] || [], :post
94
+ end
95
+
96
+ def dress(commands, stage)
97
+ commands.collect { |command| "bash -c 'cd #{build_dir} && #{command} >> #{@package.name}-#{stage}.log 2>&1'" }
98
+ end
99
+
100
+ def create_options(key, prefix)
101
+ @options[key].inject(' ') { |m, option| m << "#{prefix}-#{option} "; m }
102
+ end
103
+
104
+ def extract_command
105
+ case @source
106
+ when /(tar.gz)|(tgz)$/
107
+ 'tar xzf'
108
+ when /(tar.bz2)|(tb2)$/
109
+ 'tar xjf'
110
+ when /tar$/
111
+ 'tar xf'
112
+ when /zip$/
113
+ 'unzip'
114
+ else
115
+ raise "Unknown source archive format: #{archive_name}"
116
+ end
117
+ end
118
+
119
+ def archive_name
120
+ name = @source.split('/').last
121
+ raise "Unable to determine archive name for source: #{source}, please update code knowledge" unless name
122
+ name
123
+ end
124
+
125
+ def build_dir
126
+ "#{@options[:builds]}/#{base_dir}"
127
+ end
128
+
129
+ def base_dir
130
+ if @source.split('/').last =~ /(.*)\.(tar\.gz|tgz|tar\.bz2|tb2)/
131
+ return $1
132
+ end
133
+ raise "Unknown base path for source archive: #{@source}, please update code knowledge"
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,76 @@
1
+ module Sprinkle
2
+ module Package
3
+ PACKAGES = {}
4
+
5
+ def package(name, metadata = {}, &block)
6
+ package = Package.new(name, metadata, &block)
7
+ PACKAGES[name] = package
8
+
9
+ if package.provides
10
+ (PACKAGES[package.provides] ||= []) << package
11
+ end
12
+
13
+ package
14
+ end
15
+
16
+ class Package
17
+ include ArbitraryOptions
18
+ attr_accessor :name, :provides, :installer, :dependencies
19
+
20
+ def initialize(name, metadata = {}, &block)
21
+ raise 'No package name supplied' unless name
22
+
23
+ @name = name
24
+ @provides = metadata[:provides]
25
+ @dependencies = []
26
+ self.instance_eval &block
27
+ end
28
+
29
+ def apt(*names)
30
+ @installer = Sprinkle::Installers::Apt.new(self, *names)
31
+ end
32
+
33
+ def gem(name)
34
+ @dependencies << :rubygems
35
+ @installer = Sprinkle::Installers::Gem.new(self, name)
36
+ end
37
+
38
+ def source(source, &block)
39
+ @dependencies << :build_essential # REVISIT: should only be for Ubuntu/Debian, need platform specific bits here
40
+ @installer = Sprinkle::Installers::Source.new(self, source, &block)
41
+ end
42
+
43
+ def process(deployment, roles)
44
+ return if meta_package?
45
+
46
+ @installer.defaults(deployment)
47
+ @installer.process(roles)
48
+ end
49
+
50
+ def requires(*packages)
51
+ @dependencies << packages
52
+ @dependencies.flatten!
53
+ end
54
+
55
+ def tree(depth = 1, &block)
56
+ packages = []
57
+
58
+ @dependencies.each do |dep|
59
+ package = PACKAGES[dep]
60
+ block.call(self, package, depth) if block
61
+ packages << package.tree(depth + 1, &block)
62
+ end
63
+
64
+ packages << self
65
+ end
66
+
67
+ def to_s; @name; end
68
+
69
+ private
70
+
71
+ def meta_package?
72
+ @installer == nil
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,84 @@
1
+ require 'highline/import'
2
+
3
+ module Sprinkle
4
+ module Policy
5
+ POLICIES = []
6
+
7
+ def policy(name, options = {}, &block)
8
+ p = Policy.new(name, options, &block)
9
+ POLICIES << p
10
+ p
11
+ end
12
+
13
+ class Policy
14
+ attr_reader :name, :packages
15
+
16
+ def initialize(name, metadata = {}, &block)
17
+ raise 'No name provided' unless name
18
+ raise 'No roles provided' unless metadata[:roles]
19
+
20
+ @name = name
21
+ @roles = metadata[:roles]
22
+ @packages = []
23
+ self.instance_eval(&block)
24
+ end
25
+
26
+ def requires(package, options = {})
27
+ @packages << package
28
+ end
29
+
30
+ def to_s; name; end
31
+
32
+ def process(deployment)
33
+ all = []
34
+
35
+ cloud_info "--> Cloud hierarchy for policy #{@name}"
36
+
37
+ @packages.each do |p|
38
+ cloud_info "\nPolicy #{@name} requires package #{p}"
39
+
40
+ package = Sprinkle::Package::PACKAGES[p]
41
+ package = select_package(p, package) if package.is_a? Array # handle virtual package selection
42
+
43
+ tree = package.tree do |parent, child, depth|
44
+ indent = "\t" * depth; cloud_info "#{indent}Package #{parent.name} requires #{child.name}"
45
+ end
46
+
47
+ all << tree
48
+ end
49
+
50
+ normalize(all) do |package|
51
+ package.process(deployment, @roles)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def cloud_info(message)
58
+ logger.info(message) if Sprinkle::OPTIONS[:cloud] or logger.debug?
59
+ end
60
+
61
+ def select_package(name, packages)
62
+ if packages.size <= 1
63
+ package = packages.first
64
+ else
65
+ package = choose do |menu|
66
+ menu.prompt = "Multiple choices exist for virtual package #{name}"
67
+ menu.choices *packages.collect(&:to_s)
68
+ end
69
+ package = Sprinkle::Package::PACKAGES[package]
70
+ end
71
+
72
+ cloud_info "Selecting #{package.to_s} for virtual package #{name}"
73
+
74
+ package
75
+ end
76
+
77
+ def normalize(all, &block)
78
+ all = all.flatten.uniq
79
+ cloud_info "\n--> Normalized installation order for all packages: #{all.collect(&:name).join(', ')}"
80
+ all.each &block
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,13 @@
1
+ module Sprinkle
2
+ class Script
3
+ def self.sprinkle(script, filename = '__SCRIPT__')
4
+ powder = new
5
+ powder.instance_eval script, filename
6
+ powder.sprinkle
7
+ end
8
+
9
+ def sprinkle
10
+ @deployment.process if @deployment
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Sprinkle #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/sprinkle.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+
4
+ # Use active supports auto load mechanism
5
+ Dependencies.load_paths << File.dirname(__FILE__)
6
+
7
+ # Configure active support to log auto-loading of dependencies
8
+ #Dependencies::RAILS_DEFAULT_LOGGER = Logger.new($stdout)
9
+ #Dependencies.log_activity = true
10
+
11
+ # Load up extensions to existing classes
12
+ Dir[File.dirname(__FILE__) + '/sprinkle/extensions/*.rb'].each { |e| require e }
13
+
14
+ # Configuration options
15
+ module Sprinkle
16
+ OPTIONS = { :testing => false, :verbose => false }
17
+ end
18
+
19
+ # Understand packages, policies and deployment DSL
20
+ class Object
21
+ include Sprinkle::Package, Sprinkle::Policy, Sprinkle::Deployment
22
+ end
23
+
24
+ # Define a logging target
25
+ class Object
26
+ def logger
27
+ @@__log__ ||= ActiveSupport::BufferedLogger.new($stdout, ActiveSupport::BufferedLogger::Severity::INFO)
28
+ end
29
+ end
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour