Update CLI

This commit is contained in:
Thomas Reynolds 2015-01-04 14:23:35 -06:00
parent 302a891bbb
commit f16510d034
13 changed files with 193 additions and 269 deletions

View file

@ -1,6 +1,7 @@
master master
=== ===
* Remove side-loading of CLI tasks from `tasks/`
* Add the option of naming `config.rb` as `middleman.rb`. * Add the option of naming `config.rb` as `middleman.rb`.
* Builder extracted from Thor. `after_build` hook now passes an instance of a Builder instead of the Thor CLI. * Builder extracted from Thor. `after_build` hook now passes an instance of a Builder instead of the Thor CLI.
* New FileWatcher API. * New FileWatcher API.

View file

@ -14,5 +14,10 @@ require "middleman-cli"
# Change directory to the root # Change directory to the root
Dir.chdir(ENV["MM_ROOT"]) if ENV["MM_ROOT"] Dir.chdir(ENV["MM_ROOT"]) if ENV["MM_ROOT"]
# Default command is server
if ARGV[0] != 'help' && (ARGV.length < 1 || ARGV.first.include?('-'))
ARGV.unshift('server')
end
# Start the CLI # Start the CLI
Middleman::Cli::Base.start Middleman::Cli::Base.start(ARGV)

View file

@ -6,81 +6,18 @@ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
# Require Thor since that's what the whole CLI is built around # Require Thor since that's what the whole CLI is built around
require 'thor' require 'thor'
require 'thor/group'
# CLI Module # CLI Module
module Middleman module Middleman::Cli
module Cli
# The base task from which everything else extends # The base task from which everything else extends
class Base < Thor class Base < ::Thor
class << self
def start(*args)
# Change flag to a module
ARGV.unshift('help') if ARGV.delete('--help')
# Default command is server
if ARGV[0] != 'help' && (ARGV.length < 1 || ARGV.first.include?('-'))
ARGV.unshift('server')
end
super
end
end
desc 'version', 'Show version' desc 'version', 'Show version'
def version def version
say "Middleman #{Middleman::VERSION}" say "Middleman #{Middleman::VERSION}"
end end
desc 'help', 'Show help' def self.exit_on_failure?
true
# Override the Thor help method to find help for subtasks
# @param [Symbol, String, nil] meth
# @param [Boolean] subcommand
# @return [void]
# rubocop:disable UnusedMethodArgument
def help(meth=nil, subcommand=false)
if meth && !self.respond_to?(meth)
klass, task = Thor::Util.find_class_and_task_by_namespace("#{meth}:#{meth}")
klass.start(['-h', task].compact, shell: shell)
else
list = []
Thor::Util.thor_classes_in(Middleman::Cli).each do |thor_class|
list += thor_class.printable_tasks(false)
end
list.sort! { |a, b| a[0] <=> b[0] }
shell.say 'Tasks:'
shell.print_table(list, ident: 2, truncate: true)
shell.say %(\nSee 'middleman help <command>' for more information on specific command.)
shell.say
end
end
# Intercept missing methods and search subtasks for them
# @param [Symbol] meth
def method_missing(meth, *args)
meth = meth.to_s
meth = self.class.map[meth] if self.class.map.key?(meth)
klass, task = Thor::Util.find_class_and_task_by_namespace("#{meth}:#{meth}")
if klass.nil?
tasks_dir = File.join(Dir.pwd, 'tasks')
if File.exist?(tasks_dir)
Dir[File.join(tasks_dir, '**/*_task.rb')].each { |f| require f }
klass, task = Thor::Util.find_class_and_task_by_namespace("#{meth}:#{meth}")
end
end
if klass.nil?
raise Thor::Error, "There's no '#{meth}' command for Middleman. Try 'middleman help' for a list of commands."
else
args.unshift(task) if task
klass.start(args, shell: shell)
end
end
end end
end end
end end

View file

@ -1,36 +1,33 @@
# CLI Module # CLI Module
module Middleman::Cli module Middleman::Cli
# The CLI Build class # The CLI Build class
class Build < Thor class Build < Thor::Group
include Thor::Actions include Thor::Actions
check_unknown_options! check_unknown_options!
namespace :build class_option :environment,
desc 'build [options]', 'Builds the static site for deployment'
method_option :environment,
aliases: '-e', aliases: '-e',
default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'production', default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'production',
desc: 'The environment Middleman will run under' desc: 'The environment Middleman will run under'
method_option :clean, class_option :clean,
type: :boolean, type: :boolean,
default: true, default: true,
desc: 'Remove orphaned files from build (--no-clean to disable)' desc: 'Remove orphaned files from build (--no-clean to disable)'
method_option :glob, class_option :glob,
type: :string, type: :string,
aliases: '-g', aliases: '-g',
default: nil, default: nil,
desc: 'Build a subset of the project' desc: 'Build a subset of the project'
method_option :verbose, class_option :verbose,
type: :boolean, type: :boolean,
default: false, default: false,
desc: 'Print debug messages' desc: 'Print debug messages'
method_option :instrument, class_option :instrument,
type: :string, type: :string,
default: false, default: false,
desc: 'Print instrument messages' desc: 'Print instrument messages'
method_option :profile, class_option :profile,
type: :boolean, type: :boolean,
default: false, default: false,
desc: 'Generate profiling report for the build' desc: 'Generate profiling report for the build'
@ -78,12 +75,8 @@ module Middleman::Cli
end end
end end
# Tell Thor to send an exit status on a failure. protected
def self.exit_on_failure?
true
end
no_tasks do
# Handles incoming events from the builder. # Handles incoming events from the builder.
# @param [Symbol] event_type The type of event. # @param [Symbol] event_type The type of event.
# @param [String] contents The event contents. # @param [String] contents The event contents.
@ -120,9 +113,11 @@ module Middleman::Cli
remove_file d, force: true if Pathname(d).children.empty? remove_file d, force: true if Pathname(d).children.empty?
end end
end end
end
end
# Alias "b" to "build" # Add to CLI
Base.register(self, 'build', 'build [options]', 'Builds the static site for deployment')
# Map "b" to "build"
Base.map('b' => 'build') Base.map('b' => 'build')
end end
end

View file

@ -1,22 +1,16 @@
# CLI Module # CLI Module
module Middleman::Cli module Middleman::Cli
# Alias "c" to "console"
Base.map(c: 'console')
# The CLI Console class # The CLI Console class
class Console < Thor class Console < Thor::Group
include Thor::Actions include Thor::Actions
check_unknown_options! check_unknown_options!
namespace :console class_option :environment,
desc 'console [options]', 'Start an interactive console in the context of your Middleman application'
method_option :environment,
aliases: '-e', aliases: '-e',
default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development', default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development',
desc: 'The environment Middleman will run under' desc: 'The environment Middleman will run under'
method_option :verbose, class_option :verbose,
type: :boolean, type: :boolean,
default: false, default: false,
desc: 'Print debug messages' desc: 'Print debug messages'
@ -42,5 +36,11 @@ module Middleman::Cli
require 'irb/ext/multi-irb' require 'irb/ext/multi-irb'
IRB.irb nil, @app IRB.irb nil, @app
end end
# Add to CLI
Base.register(self, 'console', 'console [options]', 'Start an interactive console in the context of your Middleman application')
# Map "c" to "console"
Base.map('c' => 'console')
end end
end end

View file

@ -1,13 +1,11 @@
# CLI Module # CLI Module
module Middleman::Cli module Middleman::Cli
# A thor task for creating new projects # A thor task for creating new projects
class Extension < Thor class Extension < Thor::Group
include Thor::Actions include Thor::Actions
check_unknown_options! check_unknown_options!
namespace :extension
# Required path for the new project to be generated # Required path for the new project to be generated
argument :name, type: :string argument :name, type: :string
@ -17,12 +15,14 @@ module Middleman::Cli
File.join(File.dirname(__FILE__), 'templates') File.join(File.dirname(__FILE__), 'templates')
end end
desc 'extension [options]', 'Create Middleman extension scaffold NAME' class_option 'skip-git',
method_option 'skip-git',
type: :boolean, type: :boolean,
default: false, default: false,
desc: 'Skip Git ignores and keeps' desc: 'Skip Git ignores and keeps'
# Output a .gitignore file
class_option :git, type: :boolean, default: true
# The extension task # The extension task
# @param [String] name # @param [String] name
def extension def extension
@ -36,7 +36,7 @@ module Middleman::Cli
empty_directory File.join(name, 'fixtures') empty_directory File.join(name, 'fixtures')
end end
# Output a .gitignore file # Add to CLI
class_option :git, type: :boolean, default: true Base.register(self, 'extension', 'extension [options]', 'Create a new Middleman extension')
end end
end end

View file

@ -1,28 +1,27 @@
# CLI Module # CLI Module
module Middleman::Cli module Middleman::Cli
# A thor task for creating new projects # A thor task for creating new projects
class Init < Thor class Init < Thor::Group
include Thor::Actions include Thor::Actions
check_unknown_options! check_unknown_options!
namespace :init argument :target, type: :string, default: '.'
desc 'init TARGET [options]', 'Create new project at TARGET' class_option 'template',
method_option 'template',
aliases: '-T', aliases: '-T',
default: 'middleman/middleman-templates-default', default: 'middleman/middleman-templates-default',
desc: 'Use a project template' desc: 'Use a project template'
# Do not run bundle install # Do not run bundle install
method_option 'skip-bundle', class_option 'skip-bundle',
type: :boolean, type: :boolean,
aliases: '-B', aliases: '-B',
default: false, default: false,
desc: 'Skip bundle install' desc: 'Skip bundle install'
# The init task # The init task
# @param [String] name def init
def init(target='.')
require 'tmpdir' require 'tmpdir'
repo_path, repo_branch = if shortname?(options[:template]) repo_path, repo_branch = if shortname?(options[:template])
@ -37,8 +36,8 @@ module Middleman::Cli
data['links']['github'] data['links']['github']
data['links']['github'].split('#') data['links']['github'].split('#')
rescue ::OpenURI::HTTPError rescue ::OpenURI::HTTPError
puts "Template `#{options[:template]}` not found in Middleman Directory." say "Template `#{options[:template]}` not found in Middleman Directory."
puts 'Did you mean to use a full `user/repo` path?' say 'Did you mean to use a full `user/repo` path?'
exit exit
end end
else else
@ -51,13 +50,20 @@ module Middleman::Cli
run("git #{cmd} #{repo_path} #{dir}") run("git #{cmd} #{repo_path} #{dir}")
source_paths << dir
directory dir, target, exclude_pattern: /\.git\/|\.gitignore$/
inside(target) do inside(target) do
run('bundle install') thorfile = File.join(dir, 'Thorfile')
end unless ENV['TEST'] || options[:'skip-bundle']
if File.exist?(thorfile)
::Thor::Util.load_thorfile(thorfile)
invoke 'middleman:generator'
else
source_paths << dir
directory dir, '.', exclude_pattern: /\.git\/|\.gitignore$/
end
run('bundle install') unless ENV['TEST'] || options[:'skip-bundle']
end
end end
end end
@ -70,11 +76,9 @@ module Middleman::Cli
def repository_path(repo) def repository_path(repo)
"git://github.com/#{repo}.git" "git://github.com/#{repo}.git"
end end
end
def self.exit_on_failure? # Add to CLI
true Base.register(self, 'init', 'init TARGET [options]', 'Create new project at TARGET')
end
# Map "i", "new" and "n" to "init" # Map "i", "new" and "n" to "init"
Base.map( Base.map(
@ -83,3 +87,4 @@ module Middleman::Cli
'n' => 'init' 'n' => 'init'
) )
end end
end

View file

@ -1,46 +1,43 @@
# CLI Module # CLI Module
module Middleman::Cli module Middleman::Cli
# Server thor task # Server thor task
class Server < Thor class Server < Thor::Group
check_unknown_options! check_unknown_options!
namespace :server class_option :environment,
desc 'server [options]', 'Start the preview server'
method_option :environment,
aliases: '-e', aliases: '-e',
default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development', default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development',
desc: 'The environment Middleman will run under' desc: 'The environment Middleman will run under'
method_option :host, class_option :host,
type: :string, type: :string,
aliases: '-h', aliases: '-h',
default: '0.0.0.0', default: '0.0.0.0',
desc: 'Bind to HOST address' desc: 'Bind to HOST address'
method_option :port, class_option :port,
aliases: '-p', aliases: '-p',
default: '4567', default: '4567',
desc: 'The port Middleman will listen on' desc: 'The port Middleman will listen on'
method_option :verbose, class_option :verbose,
type: :boolean, type: :boolean,
default: false, default: false,
desc: 'Print debug messages' desc: 'Print debug messages'
method_option :instrument, class_option :instrument,
type: :string, type: :string,
default: false, default: false,
desc: 'Print instrument messages' desc: 'Print instrument messages'
method_option :disable_watcher, class_option :disable_watcher,
type: :boolean, type: :boolean,
default: false, default: false,
desc: 'Disable the file change and delete watcher process' desc: 'Disable the file change and delete watcher process'
method_option :profile, class_option :profile,
type: :boolean, type: :boolean,
default: false, default: false,
desc: 'Generate profiling report for server startup' desc: 'Generate profiling report for server startup'
method_option :force_polling, class_option :force_polling,
type: :boolean, type: :boolean,
default: false, default: false,
desc: 'Force file watcher into polling mode' desc: 'Force file watcher into polling mode'
method_option :latency, class_option :latency,
type: :numeric, type: :numeric,
aliases: '-l', aliases: '-l',
default: 0.25, default: 0.25,
@ -71,12 +68,11 @@ module Middleman::Cli
puts '== The Middleman is loading' puts '== The Middleman is loading'
::Middleman::PreviewServer.start(params) ::Middleman::PreviewServer.start(params)
end end
end
def self.exit_on_failure? # Add to CLI
true Base.register(self, 'server', 'server [options]', 'Start the preview server')
end
# Map "s" to "server" # Map "s" to "server"
Base.map('s' => 'server') Base.map('s' => 'server')
end end
end

View file

@ -24,7 +24,7 @@ class MyExtension < ::Middleman::Extension
# def manipulate_resource_list(resources) # def manipulate_resource_list(resources)
# end # end
# module do # helpers do
# def a_helper # def a_helper
# end # end
# end # end

View file

@ -1,15 +0,0 @@
Feature: Allow config.rb and extensions to add CLI commands
Scenario: Command autoloaded from tasks/ directory
Given an empty app
And a file named "tasks/hello_task.rb" with:
"""
class Hello < Thor
desc "hello", "Say hello"
def hello
puts "Hello World"
end
end
"""
When I run `middleman hello`
Then the output should contain "Hello World"

View file

@ -17,5 +17,5 @@ end
World(ArubaMonkeypatch) World(ArubaMonkeypatch)
Before do Before do
@aruba_timeout_seconds = RUBY_PLATFORM == 'java' ? 120 : 60 @aruba_timeout_seconds = RUBY_PLATFORM == 'java' ? 240 : 120
end end