Refactor CLI to allow 3rd party commands

This commit is contained in:
Thomas Reynolds 2011-12-21 11:03:45 -08:00
parent 7e20616fe6
commit 20ae42dcc0
7 changed files with 173 additions and 181 deletions

View file

@ -9,7 +9,7 @@ require 'rubygems'
module Middleman module Middleman
module ProjectLocator module ProjectLocator
class << self class << self
def locate_middleman_root!(args) def locate_middleman_root!
cwd = Dir.pwd cwd = Dir.pwd
if !in_middleman_project? && !in_middleman_project_subdirectory? if !in_middleman_project? && !in_middleman_project_subdirectory?
@ -18,14 +18,14 @@ module Middleman
end end
if in_middleman_project? if in_middleman_project?
did_locate_middleman_project(cwd, args) did_locate_middleman_project(cwd)
return return
end end
Dir.chdir("..") do Dir.chdir("..") do
# Recurse in a chdir block: if the search fails we want to be sure # Recurse in a chdir block: if the search fails we want to be sure
# the application is generated in the original working directory. # the application is generated in the original working directory.
locate_middleman_root!(args) unless cwd == Dir.pwd locate_middleman_root! unless cwd == Dir.pwd
end end
rescue SystemCallError rescue SystemCallError
# could not chdir, no problem just return # could not chdir, no problem just return
@ -39,39 +39,25 @@ module Middleman
File.exists?(File.join(path, 'config.rb')) || !path.root? && in_middleman_project_subdirectory?(path.parent) File.exists?(File.join(path, 'config.rb')) || !path.root? && in_middleman_project_subdirectory?(path.parent)
end end
def did_locate_middleman_project(path, args) def did_locate_middleman_project(path)
# Set up gems listed in the Gemfile. # Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('Gemfile', path) ENV['BUNDLE_GEMFILE'] ||= File.expand_path('Gemfile', path)
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
start_cli!(args) start_cli!
end end
def start_cli!(args) def start_cli!
require 'middleman' require 'middleman'
Middleman::CLI.start(args) Middleman::CLI::Base.start
end end
end end
end end
end end
args = ARGV.dup if ARGV.length < 1 || %w(server build migrate).include?(ARGV.first)
Middleman::ProjectLocator.locate_middleman_root!
ARG_ALIASES = {
"s" => "server",
"b" => "build",
"i" => "init",
"new" => "init",
"n" => "init"
}
if ARG_ALIASES.has_key?(args[0])
args[0] = ARG_ALIASES[args[0]]
end
if args.length < 1 || %w(server build migrate).include?(args.first)
Middleman::ProjectLocator.locate_middleman_root!(args)
else else
Middleman::ProjectLocator.start_cli!(args) Middleman::ProjectLocator.start_cli!
end end

View file

@ -12,11 +12,16 @@ module Middleman
# Auto-load modules on-demand # Auto-load modules on-demand
autoload :Base, "middleman/base" autoload :Base, "middleman/base"
autoload :Cache, "middleman/cache" autoload :Cache, "middleman/cache"
autoload :Builder, "middleman/builder"
autoload :CLI, "middleman/cli"
autoload :Templates, "middleman/templates" autoload :Templates, "middleman/templates"
autoload :Guard, "middleman/guard" autoload :Guard, "middleman/guard"
module CLI
autoload :Base, "middleman/cli"
autoload :Build, "middleman/cli/build"
autoload :Templates, "middleman/cli/templates"
autoload :Server, "middleman/cli/server"
end
# Custom Renderers # Custom Renderers
module Renderers module Renderers
autoload :Haml, "middleman/renderers/haml" autoload :Haml, "middleman/renderers/haml"
@ -161,12 +166,6 @@ module Middleman
class << self class << self
# Where to look for custom templates
# @return [String]
def templates_path
File.join(File.expand_path("~/"), ".middleman")
end
# Automatically load extensions from available RubyGems # Automatically load extensions from available RubyGems
# which contain the EXTENSION_FILE # which contain the EXTENSION_FILE
# #

View file

@ -1,10 +1,11 @@
require 'thor' require 'thor'
require "thor/group"
module Middleman # CLI Module
class CLI < Thor module Middleman::CLI
class Base < Thor
include Thor::Actions include Thor::Actions
check_unknown_options!
default_task :server
class_option "help", class_option "help",
:type => :boolean, :type => :boolean,
@ -15,98 +16,6 @@ module Middleman
help_check if options[:help] help_check if options[:help]
end end
desc "init NAME [options]", "Create new project NAME"
available_templates = Middleman::Templates.registered.keys.join(", ")
method_option "template",
:aliases => "-T",
:default => "default",
:desc => "Use a project template: #{available_templates}"
method_option "css_dir",
:default => "stylesheets",
:desc => 'The path to the css files'
method_option "js_dir",
:default => "javascripts",
:desc => 'The path to the javascript files'
method_option "images_dir",
:default => "images",
:desc => 'The path to the image files'
method_option "rack",
:type => :boolean,
:default => false,
:desc => 'Include a config.ru file'
method_option "bundler",
:type => :boolean,
:default => false,
:desc => 'Create a Gemfile and use Bundler to manage gems'
def init(name)
key = options[:template].to_sym
unless Middleman::Templates.registered.has_key?(key)
raise Thor::Error.new "Unknown project template '#{key}'"
end
thor_group = Middleman::Templates.registered[key]
thor_group.new([name], options).invoke_all
end
desc "server [options]", "Start the preview server"
method_option "environment",
:aliases => "-e",
:default => ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development',
:desc => "The environment Middleman will run under"
method_option :host,
:type => :string,
:aliases => "-h",
# :required => true,
:default => "0.0.0.0",
:desc => "Bind to HOST address"
method_option "port",
:aliases => "-p",
:default => "4567",
:desc => "The port Middleman will listen on"
method_option "debug",
:type => :boolean,
:default => false,
:desc => 'Print debug messages'
def server
params = {
:port => options["port"],
:host => options["host"],
:environment => options["environment"],
:debug => options["debug"]
}
puts "== The Middleman is loading"
Middleman::Guard.start(params)
end
desc "build", "Builds the static site for deployment"
method_option :relative,
:type => :boolean,
:aliases => "-r",
:default => false,
:desc => 'Force relative urls'
method_option :clean,
:type => :boolean,
:aliases => "-c",
:default => false,
:desc => 'Removes orpahand files or directories from build'
method_option :glob,
:type => :string,
:aliases => "-g",
:default => nil,
:desc => 'Build a subset of the project'
def build
thor_group = Middleman::Builder.new([], options).invoke_all
end
desc "migrate", "Migrates an older project to the 2.0 structure"
def migrate
return if File.exists?("source")
`mv public source`
`cp -R views/* source/`
`rm -rf views`
end
desc "version", "Show version" desc "version", "Show version"
def version def version
require 'middleman/version' require 'middleman/version'
@ -121,3 +30,7 @@ module Middleman
end end
end end
end end
require "middleman/cli/templates"
require "middleman/cli/server"
require "middleman/cli/build"

View file

@ -1,11 +1,42 @@
require "thor" require "rack"
require "thor/group"
require "rack/test" require "rack/test"
require "find"
module Middleman module Middleman::CLI
class Builder < Thor::Group class Build < Thor::Group
include Thor::Actions include Thor::Actions
check_unknown_options!
desc "build [options]"
class_option :relative,
:type => :boolean,
:aliases => "-r",
:default => false,
:desc => 'Force relative urls'
class_option :clean,
:type => :boolean,
:aliases => "-c",
:default => false,
:desc => 'Removes orpahand files or directories from build'
class_option :glob,
:type => :string,
:aliases => "-g",
:default => nil,
:desc => 'Build a subset of the project'
def build
if options.has_key?("relative") && options["relative"]
self.class.shared_instance.activate :relative_assets
end
self.class.shared_rack
opts = {}
opts[:glob] = options["glob"] if options.has_key?("glob")
opts[:clean] = options["clean"] if options.has_key?("clean")
action GlobAction.new(self, self.class.shared_instance, opts)
self.class.shared_instance.run_hook :after_build, self
end
class << self class << self
def shared_instance def shared_instance
@ -28,6 +59,8 @@ module Middleman
end end
end end
source_root(shared_instance.root)
# @private # @private
module ThorActions module ThorActions
# Render a template to a file. # Render a template to a file.
@ -36,12 +69,12 @@ module Middleman
config = args.last.is_a?(Hash) ? args.pop : {} config = args.last.is_a?(Hash) ? args.pop : {}
destination = args.first || source destination = args.first || source
request_path = destination.sub(/^#{::Middleman::Builder.shared_instance.build_dir}/, "") request_path = destination.sub(/^#{self.class.shared_instance.build_dir}/, "")
begin begin
destination, request_path = ::Middleman::Builder.shared_instance.reroute_builder(destination, request_path) destination, request_path = self.class.shared_instance.reroute_builder(destination, request_path)
response = ::Middleman::Builder.shared_rack.get(request_path.gsub(/\s/, "%20")) response = self.class.shared_rack.get(request_path.gsub(/\s/, "%20"))
create_file(destination, response.body, config) create_file(destination, response.body, config)
@ -52,36 +85,8 @@ module Middleman
end end
end end
end end
include ThorActions include ThorActions
class_option :relative, :type => :boolean, :aliases => "-r", :default => false, :desc => 'Override the config.rb file and force relative urls'
class_option :glob, :type => :string, :aliases => "-g", :default => nil, :desc => 'Build a subset of the project'
def initialize(*args)
super
if options.has_key?("relative") && options["relative"]
self.class.shared_instance.activate :relative_assets
end
end
def source_paths
@source_paths ||= [
self.class.shared_instance.root
]
end
def build_all_files
self.class.shared_rack
opts = { }
opts[:glob] = options["glob"] if options.has_key?("glob")
opts[:clean] = options["clean"] if options.has_key?("clean")
action GlobAction.new(self, self.class.shared_instance, opts)
self.class.shared_instance.run_hook :after_build, self
end
end end
# @private # @private
@ -179,4 +184,7 @@ module Middleman
end end
end end
end end
Base.register(Build, :build, "build [options]", "Builds the static site for deployment")
Base.map({ "b" => "build" })
end end

View file

@ -0,0 +1,40 @@
module Middleman::CLI
class Server < Thor::Group
check_unknown_options!
desc "server [options]"
class_option "environment",
:aliases => "-e",
:default => ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development',
:desc => "The environment Middleman will run under"
class_option :host,
:type => :string,
:aliases => "-h",
# :required => true,
:default => "0.0.0.0",
:desc => "Bind to HOST address"
class_option "port",
:aliases => "-p",
:default => "4567",
:desc => "The port Middleman will listen on"
class_option "debug",
:type => :boolean,
:default => false,
:desc => 'Print debug messages'
def server
params = {
:port => options["port"],
:host => options["host"],
:environment => options["environment"],
:debug => options["debug"]
}
puts "== The Middleman is loading"
Middleman::Guard.start(params)
end
end
Base.register(Server, :server, "server [options]", "Start the preview server")
Base.map({ "s" => "server" })
Base.default_task :server
end

View file

@ -0,0 +1,46 @@
module Middleman::CLI
class Templates < Thor::Group
check_unknown_options!
desc "init NAME [options]"
available_templates = ::Middleman::Templates.registered.keys.join(", ")
argument :name
class_option "template",
:aliases => "-T",
:default => "default",
:desc => "Use a project template: #{available_templates}"
class_option "css_dir",
:default => "stylesheets",
:desc => 'The path to the css files'
class_option "js_dir",
:default => "javascripts",
:desc => 'The path to the javascript files'
class_option "images_dir",
:default => "images",
:desc => 'The path to the image files'
class_option "rack",
:type => :boolean,
:default => false,
:desc => 'Include a config.ru file'
class_option "bundler",
:type => :boolean,
:default => false,
:desc => 'Create a Gemfile and use Bundler to manage gems'
def init
key = options[:template].to_sym
unless ::Middleman::Templates.registered.has_key?(key)
raise Thor::Error.new "Unknown project template '#{key}'"
end
thor_group = ::Middleman::Templates.registered[key]
thor_group.new([name], options).invoke_all
end
end
Base.register(Templates, :init, "init NAME [options]", "Create new project NAME")
Base.map({
"i" => "init",
"new" => "init",
"n" => "init"
})
end

View file

@ -4,7 +4,7 @@ class Middleman::Templates::Local < Middleman::Templates::Base
# Look for templates in ~/.middleman # Look for templates in ~/.middleman
# @return [String] # @return [String]
def self.source_root def self.source_root
Middleman.templates_path File.join(File.expand_path("~/"), ".middleman")
end end
# Just copy from the template path # Just copy from the template path
@ -15,7 +15,7 @@ class Middleman::Templates::Local < Middleman::Templates::Base
end end
# Iterate over the directories in the templates path and register each one. # Iterate over the directories in the templates path and register each one.
Dir[File.join(Middleman.templates_path, "*")].each do |dir| Dir[File.join(Middleman::Templates::Local.source_root, "*")].each do |dir|
next unless File.directory?(dir) next unless File.directory?(dir)
Middleman::Templates.register(File.basename(dir).to_sym, Middleman::Templates::Local) Middleman::Templates.register(File.basename(dir).to_sym, Middleman::Templates::Local)
end end