Skip to content

Commit

Permalink
Improve subcommands and enable to generate completion scripts for bash
Browse files Browse the repository at this point in the history
and zsh.
  • Loading branch information
keita committed Dec 10, 2013
1 parent 2aa293c commit f95b60f
Show file tree
Hide file tree
Showing 40 changed files with 1,175 additions and 437 deletions.
22 changes: 22 additions & 0 deletions Rakefile
Expand Up @@ -87,3 +87,25 @@ task "man" do
generate_man("doc/man/pione-action-list.md", "man/pione-action-list.1")
generate_man("doc/man/pione-list-param.md", "man/pione-list-param.1")
end

#
# Completion
#

desc "generate bash completion file"
task "completion:bash" do
require 'pione/util/completion'
misc = Pione::Location[File.dirname(__FILE__)] + "misc"
source = misc + "pione-completion.erb"
target = misc + "pione-completion.bash"
Pione::Util::BashCompletion.compile(source, target)
end

desc "generate zsh completion file"
task "completion:zsh" do
require 'pione/util/completion'
misc = Pione::Location[File.dirname(__FILE__)] + "misc"
source = misc + "pione-completion.erb"
target = misc + "pione-completion.zsh"
Pione::Util::ZshCompletion.compile(source, target)
end
9 changes: 0 additions & 9 deletions lib/pione/command.rb
Expand Up @@ -17,14 +17,5 @@ module Command; end
require 'pione/command/pione-relay'
require 'pione/command/pione-relay-client-db'
require 'pione/command/pione-relay-account-db'
require 'pione/command/pione-clean' # pione clean
require 'pione/command/pione-syntax-checker'
require 'pione/command/pione-log' # pione log
require 'pione/command/pione-val' # pione-val
require 'pione/command/pione-package'
require 'pione/command/pione-compiler'
require 'pione/command/pione-update-package-info' # pione update-package-info
require 'pione/command/pione-action' # pione action
require 'pione/command/pione-action-list' # pione action:list
require 'pione/command/pione-list-param' # pione list-param
require 'pione/command/pione-config'
34 changes: 33 additions & 1 deletion lib/pione/command/basic-command.rb
Expand Up @@ -14,9 +14,11 @@ class << self
attr_reader :execution_actions
attr_reader :termination_actions
attr_reader :exception_handler
attr_reader :subcommand

def inherited(subclass)
subclass.instance_eval do
@subcommand = {}
@phase_option = {:init => {}, :setup => {}, :execution => {}, :termination => {}}
@option_definition = OptionDefinition.new
@command_name = nil
Expand All @@ -29,6 +31,7 @@ def inherited(subclass)
@execution_actions = Array.new
@termination_actions = Array.new
@exception_handler = {:init => {}, :setup => {}, :execution => {}, :termination => {}}
@toplevel = false

# define init phase actions
init :process_name
Expand All @@ -43,6 +46,15 @@ def option_parser_mode(mode)
@option_definition.parser_mode = mode
end

# Set toplvel command.
def toplevel(b)
@toplevel = b
end

def toplevel?
@toplevel
end

# Set progaram name or return the name.
def command_name(name=nil, &b)
if name
Expand Down Expand Up @@ -72,6 +84,10 @@ def command_front(front_class=nil, &b)
end
end

def define_subcommand(name, subclass)
@subcommand[name] = subclass
end

forward :@option_definition, :use, :use_option
forward :@option_definition, :define, :define_option
forward :@option_definition, :item, :option_item
Expand Down Expand Up @@ -160,7 +176,7 @@ def register_action(phase_actions, action, option={})
attr_accessor :action_type

forward! :class, :option_definition, :command_name, :command_name_block
forward! :class, :command_banner, :command_front, :command_front_block
forward! :class, :command_banner, :command_front, :command_front_block, :subcommand

def initialize(argv)
@argv = argv
Expand All @@ -184,6 +200,22 @@ def current_phase

# Run 4 phase lifecycle of the command. This fires actions in each phase.
def run
# check subcommand
if subcommand.size > 0
if name = @argv.first
if subcommand.has_key?(name)
return subcommand[name].run(@argv.drop(1))
else
unless name[0] == "-"
abort("no such subcommand: %s" % name)
end
end
else
abort("require a subcommand name")
end
end

# run this command
@running_thread = Thread.current
enter_phase(:init)
enter_phase(:setup)
Expand Down
24 changes: 23 additions & 1 deletion lib/pione/command/option.rb
Expand Up @@ -41,6 +41,7 @@ def use(item_name, option={})

# OptionDefinition is a class for holding option definitions.
class OptionDefinition
attr_reader :items
attr_accessor :parser_mode

# Creata a command option context.
Expand All @@ -64,18 +65,39 @@ def parse(argv, cmd)
OptionParser.new do |opt|
# set banner
opt.banner = "Usage: %s [options]" % cmd.command_name
opt.banner << "\n\n" + cmd.command_banner + "\n" if cmd.command_banner
opt.banner << "\n" + cmd.command_banner + "\n" if cmd.command_banner

# set version
opt.program_name = cmd.command_name
opt.version = Pione::VERSION

if cmd.subcommand.size > 0
size = cmd.subcommand.keys.max_by{|key| key.size}.size

# show subcommand banner
opt.separator("")
opt.separator("Subcommands:")

# show subcommand list
cmd.subcommand.each do |key, val|
opt.separator(opt.summary_indent + ("%-#{size}s" % key) + opt.summary_indent + val.command_banner)
end
end

# show options banner
opt.separator("")
opt.separator("Options:")

# default values
@items.each {|item| data[item.name] = item.default if item.default}
data.merge!(@default)

# setup option parser
@items.sort{|a,b| a.long <=> b.long}.each {|item| setup_item(cmd, opt, data, item)}

# show default options
opt.on("--help", "show this help") { puts opt.help; cmd.terminate }
opt.on("--version", "show PIONE version") { puts opt.version; cmd.terminate }
end.send(@parser_mode, argv)

# check option's validness
Expand Down
79 changes: 79 additions & 0 deletions lib/pione/command/pione-action-exec.rb
@@ -0,0 +1,79 @@
module Pione
module Command
# PioneActionExec is a command that executes action from outside of rule
# engine.
class PioneActionExec < BasicCommand
#
# basic informations
#

command_name "pione action exec"
command_banner "execute an action in literate action document"

#
# options
#

use_option :color
use_option :debug

define_option(:domain) do |item|
item.long = "--domain"
item.desc = "use the domain information file"
item.default = Location["./domain.dump"]
item.value = lambda {|b| b}
end

define_option(:directory) do |item|
item.short = "-d"
item.long = "--directory PATH"
item.desc = "execute in the PATH"
item.value = lambda {|b| Location[b]}
end

#
# command lifecycle: setup phase
#

setup :source
setup :action_name
setup :domain

# Setup location of literate action document and action name.
def setup_source
abort("There are no literate action documents or packages.") if @argv[0].nil?
@location = Location[@argv[0]]
end

# Setup action name.
def setup_action_name
abort("There is no action name.") if @argv[1].nil?
@name = @argv[1]
end

# Load a domain information file.
def setup_domain
if option[:domain].exist?
@domain_info = System::DomainInfo.read(option[:domain])
end
end

#
# command lifecycle: execution phase
#

execute :exec

# Update pacakge info files.
def execute_exec
if action = LiterateAction::Document.load(@location).find(@name)
action.execute(@domain_info, option[:directory])
else
abort("The action not found.")
end
rescue Location::NotFound => e
abot(e.message)
end
end
end
end
18 changes: 14 additions & 4 deletions lib/pione/command/pione-action-list.rb
Expand Up @@ -7,16 +7,22 @@ class PioneActionList < BasicCommand
# basic informations
#

command_name "pione action:list"
command_banner "show list of action names in document"
PioneCommand.add_subcommand("action:list", self)
command_name "pione action list"
command_banner "list action names in document"

#
# options
#

use_option :color

define_option(:compact) do |item|
item.long = "--compact"
item.desc = "one line list"
item.default = false
item.value = lambda {|b| b}
end

#
# command lifecycle: setup phase
#
Expand All @@ -41,7 +47,11 @@ def execute_show_list
if names.empty?
abort("no action names in %s" % @location.address)
else
names.each {|name| puts name}
if option[:compact]
puts names.join(" ")
else
names.each {|name| puts name}
end
end
end
end
Expand Down
70 changes: 70 additions & 0 deletions lib/pione/command/pione-action-print.rb
@@ -0,0 +1,70 @@
module Pione
module Command
# `PioneActionPrint` is a command that prints action contents.
class PioneActionPrint < BasicCommand
#
# basic informations
#

command_name "pione action print"
command_banner "print action contents"

#
# options
#

use_option :color

define_option(:domain) do |item|
item.long = "--domain"
item.desc = "use the domain information file"
item.default = Location["./domain.dump"]
item.value = lambda {|b| b}
end

#
# command lifecycle: setup phase
#

setup :source
setup :action_name
setup :domain

# Setup source location.
def setup_source
abort("There are no literate action documents or packages.") if @argv[0].nil?
@location = Location[@argv[0]]
end

# Setup action name.
def setup_action_name
abort("There is no action name.") if @argv[1].nil?
@name = @argv[1]
end

# Load a domain information file.
def setup_domain
if option[:domain].exist?
@domain_info = System::DomainInfo.read(option[:domain])
end
end

#
# command lifecycle: execution phase
#

execute :print

# Print the action contents.
def execute_print
if action = LiterateAction::Document.load(@location).find(@name)
puts action.textize(@domain_info)
else
abort("The action not found.")
end
rescue Location::NotFound => e
abot(e.message)
end
end
end
end

0 comments on commit f95b60f

Please sign in to comment.