GetoptLong: ARGV must be used, no @argv possible. :/

master
Denis Knauf 2013-02-16 15:39:57 +01:00
parent 4452a3cf61
commit a479b980e0
4 changed files with 247 additions and 76 deletions

View File

@ -14,3 +14,9 @@ install: truckle
install -m 0755 truckle $(D)$(BIN_PREFIX)/truckle install -m 0755 truckle $(D)$(BIN_PREFIX)/truckle
for c in `./truckle --list-commands`; do ln -fs truckle $(D)$(BIN_PREFIX)/truckle-$${c} ; done for c in `./truckle --list-commands`; do ln -fs truckle $(D)$(BIN_PREFIX)/truckle-$${c} ; done
for c in trdo tresume; do ln -fs truckle $(D)$(BIN_PREFIX)/$${c} ; done for c in trdo tresume; do ln -fs truckle $(D)$(BIN_PREFIX)/$${c} ; done
README.md: truckle README.pre.md
( cat README.pre.md ; ./truckle --help ) > README.md.tmp
mv README.md.tmp README.md
release: README.md

79
README.md Normal file
View File

@ -0,0 +1,79 @@
truckle and cave
================
`cave` is very powerful package mangler. If you do not know it, you will not know exherbo, too. So you should try exherbo or you never will need `truckle`.
`truckle` will do thing, which `cave` will never do, for example uses a pager automaticaly for longer output. Useful if you want to install many packages. And will use `sudo` if needed.
Why did not `cave` provide these things? It's unclean and it should be clean. While `cave` is a very powerful package mangler, `truckle` is a smart tool for often used functions of `cave`
Usage
=====
truckle *PREARGS Command *ARGS
Arguments
=========
Precede the command, it's possible to set some arguments.
These Arguments really must precede the command.
- `-C|--list-commands` will list all possible commands and exit.
- `-h|--help` will print this help and exit.
- `-n|--dummy` will print the shellcode, which will be executed, if not --dummy.
- `-s|--sudo on|off|auto` will use (or not) sudo if you are not root.
- `-c|--color|--colour on|off|auto` will control the colorfull output of `cave`.
- `-L|--log-level LOGLEVEL` will control the log-level of `cave`.
- `-p|--pager PAGER` will change the pager to display.
Instead of on|off you can use 0|true or 1|false too. Default is everytime auto.
Environment
===========
- `DUMMY=1` will print the shellcode, which will be executed, like `--dummy`.
- `NOSUDO=1` will prevent of using sudo, if you are not root, like `--sudo off`.
- `PAGER=more` will change the pager to more, instead of less, like `--pager more`.
Commands
========
Most commands are like by cave.
- `search` is pagered.
- `show` is pagered.
- `resolve` is pagered and resumable. Do *not* use `-x`! Use `resume`.
- `install` is resumable and like `cave resolve -x`.
- `upgrade` is pagered and resumable and like `cave resolve -c world`. Do *not* use `-x`! Use `resume`.
- `remove` is pagered, resumable and like `cave uninstall`. Do *not* use `-x`! Use `resume`.
- `uninstall` is resumable and like `cave uninstall -x`.
- `fix-linkage` is pagered and resumable.
- `do` and `resume` are resumable and will resume or execute the last command.
Resumable
=========
You do not need to set a resume-file. truckle will determine it automaticaly. First, you can give a first argument for tagging. Tag must be numerical!
truckle 321 resolve netcat6
truckle 321 do
If you do not give a tag, truckle will use the actual terminal-device-number. If it isn't possible to determine terminal, the parent-pid will be used.
Like cave but different
=======================
Some commands will be displayed by a pager, so you can scroll up and down like
truckle resolve WHAT # cave -cy resolve WHAT | less -R
truckle remove WHAT # cave -cy uninstall WHAT | less -R
Some commands are not displayed by a pager, but will execute:
truckle install WHAT # cave -cy resolve -x WHAT
truckle uninstall WHAT # cave -cy uninstall -x WHAT
«do» and «resume» are special, to execute the last command:
truckle resume # | do # cave resume
trdo # | tresume # shortcuts

9
README.pre.md Normal file
View File

@ -0,0 +1,9 @@
truckle and cave
================
`cave` is very powerful package mangler. If you do not know it, you will not know exherbo, too. So you should try exherbo or you never will need `truckle`.
`truckle` will do thing, which `cave` will never do, for example uses a pager automaticaly for longer output. Useful if you want to install many packages. And will use `sudo` if needed.
Why did not `cave` provide these things? It's unclean and it should be clean. While `cave` is a very powerful package mangler, `truckle` is a smart tool for often used functions of `cave`

229
truckle
View File

@ -3,6 +3,14 @@
require 'irb-pager' require 'irb-pager'
require 'shellwords' require 'shellwords'
require 'getoptlong'
class GetoptLong
def argv=( v) @argv = v end
def argv() @argv end
def ARGV=( v) @argv = v end
def ARGV() @argv end
end
class Commands < Hash class Commands < Hash
class CommandError < Exception class CommandError < Exception
@ -94,7 +102,7 @@ class RunCave
class ResumeFileExpected <Exception class ResumeFileExpected <Exception
end end
attr_accessor :preargs, :cmd, :args attr_accessor :preargs, :cmd, :args, :log_level
attr_reader :dummy, :resumable attr_reader :dummy, :resumable
attr_writer :resume_file attr_writer :resume_file
def initialize preargs = nil, cmd = nil, args = nil def initialize preargs = nil, cmd = nil, args = nil
@ -134,10 +142,15 @@ class RunCave
colored? ? ['--colour', 'yes'] : [] colored? ? ['--colour', 'yes'] : []
end end
def prepare_log_level
@log_level ? ['--log-level', @log_level] : []
end
def prepare def prepare
raise CommandExpected, "Set #{self}.cmd = yourcommand." if @cmd.nil? or @cmd.empty? raise CommandExpected, "Set #{self}.cmd = yourcommand." if @cmd.nil? or @cmd.empty?
[ [
:cave, prepare_colored, @preargs, @cmd, prepare_resume_file, *@args :cave, prepare_colored, prepare_log_level, @preargs,
@cmd, prepare_resume_file, *@args
].flatten.select{|x|x}.map {|x| x.to_s } ].flatten.select{|x|x}.map {|x| x.to_s }
end end
@ -173,6 +186,50 @@ class RunCave
alias call run_exit alias call run_exit
end end
class Opts < Hash
class UnknownArgument < Exception
def initialize arg
super "Unknown argument: #{arg}"
end
end
class ArgumentExpected < Exception
def initialize arg
super "Argument expected for: #{arg}"
end
end
def opt *names, &exe
names.each do |name|
self[name.to_s.to_sym] = [exe, false]
end
end
def opt_arg *names, &exe
names.each do |name|
self[name.to_s.to_sym] = [exe, true]
end
end
def parse *argv
get_arg = lambda {|e| argv.shift; e.call argv[0] }
argv = argv.dup
until argv.empty?
opt = argv[0]
case opt
when /^(?:(-[^-])=?|(--[^=]+)=)(.*)$/
opt, arg = $1||$2, $3
exe, need_arg = (self[opt] or return( argv))
need_arg ? exe( opt, arg) : raise( ArgumentExpected, opt)
when /^(?:-[^-]|--[^=]+)$/
exe, need_arg = (self[opt] or return( argv))
need_arg ? exe( opt, get_arg.()) : exe
else
return argv
end
end
end
end
# Truckle # Truckle
# ======= # =======
# #
@ -232,7 +289,9 @@ class Truckle
if colored if colored
t.gsub! /^([^\n]+)\n===+/m, "\n«««««« \033[1;4;33m\\1\033[0m »»»»»»" t.gsub! /^([^\n]+)\n===+/m, "\n«««««« \033[1;4;33m\\1\033[0m »»»»»»"
t.gsub! /^([^\n]+)\n---+/m, "\n««« \033[1;33m\\1\033[0m »»»" t.gsub! /^([^\n]+)\n---+/m, "\n««« \033[1;33m\\1\033[0m »»»"
t.gsub! /^ (.*?)( *#.*)$/, " \033[1;44m\\1\033[0m\\2"
t.gsub! /`([^`]+)`/, "\033[1;44m \\1 \033[0m" t.gsub! /`([^`]+)`/, "\033[1;44m \\1 \033[0m"
t.gsub! /\*([^*]+)\*/, "\033[1m\\1\033[0m"
end end
t = t[1..-1] while t.start_with? "\n" t = t[1..-1] while t.start_with? "\n"
t t
@ -257,7 +316,45 @@ class Truckle
Usage Usage
===== =====
#{cmd} Command *ARGS #{cmd} *PREARGS Command *ARGS
Arguments
=========
Precede the command, it's possible to set some arguments.
These Arguments really must precede the command.
- `-C|--list-commands` will list all possible commands and exit.
- `-h|--help` will print this help and exit.
- `-n|--dummy` will print the shellcode, which will be executed, if not --dummy.
- `-s|--sudo on|off|auto` will use (or not) sudo if you are not root.
- `-c|--color|--colour on|off|auto` will control the colorfull output of `cave`.
- `-L|--log-level LOGLEVEL` will control the log-level of `cave`.
- `-p|--pager PAGER` will change the pager to display.
Instead of on|off you can use 0|true or 1|false too. Default is everytime auto.
Environment
===========
- `DUMMY=1` will print the shellcode, which will be executed, like `--dummy`.
- `NOSUDO=1` will prevent of using sudo, if you are not root, like `--sudo off`.
- `PAGER=more` will change the pager to more, instead of less, like `--pager more`.
Commands
========
Most commands are like by cave.
- `search` is pagered.
- `show` is pagered.
- `resolve` is pagered and resumable. Do *not* use `-x`! Use `resume`.
- `install` is resumable and like `cave resolve -x`.
- `upgrade` is pagered and resumable and like `cave resolve -c world`. Do *not* use `-x`! Use `resume`.
- `remove` is pagered, resumable and like `cave uninstall`. Do *not* use `-x`! Use `resume`.
- `uninstall` is resumable and like `cave uninstall -x`.
- `fix-linkage` is pagered and resumable.
- `do` and `resume` are resumable and will resume or execute the last command.
Resumable Resumable
========= =========
@ -286,31 +383,6 @@ Some commands are not displayed by a pager, but will execute:
truckle resume # | do # cave resume truckle resume # | do # cave resume
trdo # | tresume # shortcuts trdo # | tresume # shortcuts
Environment
===========
- `DUMMY=1` will prevent any doing. But it will print, which command would be executed, if not DUMMY=1.
- `NOSUDO=1` will prevent of using sudo, if you are not root.
- `PAGER=more` will change the pager to more, instead of less.
Commands
========
Most commands are like by cave.
- `search` is pagered.
- `show` is pagered.
- `resolve` is pagered and resumable. Do _not_ use `-x`! Use `resume`.
- `install` is resumable and like `cave resolve -x`.
- `upgrade` is pagered and resumable and like `cave resolve -c world`. Do _not_ use `-x`! Use `resume`.
- `remove` is pagered, resumable and like `cave uninstall`. Do _not_ use `-x`! Use `resume`.
- `uninstall` is resumable and like `cave uninstall -x`.
- `fix-linkage` is pagered and resumable.
- `do` and `resume` are resumable and will resume or execute the last command.
- `--list-commands` will list all possible commands.
- `--install-commands` will install all commands as truckle-COMMAND.
EOF EOF
end end
@ -337,54 +409,58 @@ EOF
cmds.on :do, :resume, &sudod {|cmd, *args| cave.resumable!.resume( *args).() } cmds.on :do, :resume, &sudod {|cmd, *args| cave.resumable!.resume( *args).() }
cmds.on '--list-commands', &pagered { puts cmds.map{|k,v|k} } cmds.on '--list-commands', &pagered { puts cmds.map {|k,v| k } }
cmds.on '--install-commands', &sudod {
dir, exe = File.split( argv0)
cmds.each do |k,v|
k = k.to_s
k = File.join dir, "#{cmds.prefix}-#{k}"
File.symlink exe, k unless File.exist? k
end
}
end end
def setup_params options, argv def setup_params options
on_off_auto = lambda do on_off_auto = lambda do |arg|
argv.shift case arg
case argv[0]
when 'on', '1', 'true', 't' then true when 'on', '1', 'true', 't' then true
when 'off', '0', 'false', 'f' then false when 'off', '0', 'false', 'f' then false
end end
end end
param = lambda { argv.shift; argv[0] } opts = GetoptLong.new(
[ '-r', '--resume-file', GetoptLong::REQUIRED_ARGUMENT ],
[ '-h', '--help', GetoptLong::NO_ARGUMENT ],
[ '-C', '--list-commands', GetoptLong::NO_ARGUMENT ],
[ '-n', '--dummy', GetoptLong::NO_ARGUMENT ],
[ '-t', '--tag', GetoptLong::REQUIRED_ARGUMENT ],
[ '-p', '--pager', GetoptLong::REQUIRED_ARGUMENT ],
[ '-c', '--color', '--colour', GetoptLong::REQUIRED_ARGUMENT ],
[ '-L', '--log-level', GetoptLong::REQUIRED_ARGUMENT ],
[ '-s', '--sudo', GetoptLong::REQUIRED_ARGUMENT ]
)
opts.ordering = GetoptLong::REQUIRE_ORDER
until argv.empty? opts.each do |opt, arg|
case opt = argv[0] case opt
when '--list-commands', '--install-commands' when '-C' then options[:cmd] = '--list-commands'
options[:cmd] = opt when '-r' then options[:resume_file] = arg
when '--dummy' then options[:dummy] = true when '-h' then options[:cmd] = 'help'
when '--resume-file' then options[:resume_file] = param.call when '-n' then options[:dummy] = true
when '--tag' then options[:tag] = param.call when '-t' then options[:tag] = arg
when /^\d+$/ then options[:tag] = opt when '-p' then options[:pager] = on_off_auto[arg]
when '--pager' then options[:pager] = on_off_auto.call when '-c' then options[:color] = on_off_auto[arg]
when '--color' then options[:color] = on_off_auto.call when '-L' then options[:log_level] = arg
when '--sudo' then options[:sudo] = on_off_auto.call when '-s' then options[:sudo] = on_off_auto[arg]
else return else opts.terminate
end end
argv.shift ''
end end
options
end end
def setup_env options, argv def setup_env options
options[:dummy] = true if %w[1 true yes].include?( ENV['DUMMY'].to_s.downcase) options[:dummy] = true if %w[1 true yes].include?( ENV['DUMMY'].to_s.downcase)
options[:sudo] = false if %w[1 true yes].include?( ENV['NOSUDO'].to_s.downcase) options[:sudo] = false if %w[1 true yes].include?( ENV['NOSUDO'].to_s.downcase)
options[:tty] = true if STDOUT.tty? options[:tty] = true if STDOUT.tty?
end end
def setup_run options, argv def setup_run options
on_off_auto = lambda {|x| nil == x ? true : x } on_off_auto = lambda {|x| nil == x ? true : x }
argv.unshift options[:cmd] if options[:cmd] ARGV.unshift options[:cmd] if options[:cmd]
@cave.dummy! if options[:dummy] @cave.dummy! if options[:dummy]
@cave.log_level if options[:log_level]
@cave.can_be_colored if on_off_auto.( options[:color]) and options[:tty] @cave.can_be_colored if on_off_auto.( options[:color]) and options[:tty]
@nopager = true unless on_off_auto.( options[:pager]) or options[:tty] @nopager = true unless on_off_auto.( options[:pager]) or options[:tty]
@nosudo = true unless on_off_auto.( options[:sudo]) @nosudo = true unless on_off_auto.( options[:sudo])
@ -401,7 +477,7 @@ EOF
@cave.resume_file = options[:resume_file] || "/tmp/truckle-resume-#{resumefilesuffix}" @cave.resume_file = options[:resume_file] || "/tmp/truckle-resume-#{resumefilesuffix}"
end end
def setup_recall options, argv def setup_recall options
on_off_auto = lambda {|n,x| case x when true then [n, 'on'] when false then [n, 'off'] end } on_off_auto = lambda {|n,x| case x when true then [n, 'on'] when false then [n, 'off'] end }
param = lambda {|n,x| n if x } param = lambda {|n,x| n if x }
@ -409,31 +485,32 @@ EOF
param.( '--dummy', options[:dummy]), param.( '--dummy', options[:dummy]),
param.( ['--resume-file', options[:resume_file]], options[:resume_file]), param.( ['--resume-file', options[:resume_file]], options[:resume_file]),
param.( ['--tag', options[:tag]], options[:tag]), param.( ['--tag', options[:tag]], options[:tag]),
param.( ['--log-level', options[:log_level]], options[:log_level]),
on_off_auto.( '--sudo', options[:sudo]), on_off_auto.( '--sudo', options[:sudo]),
on_off_auto.( '--color', options[:color]), on_off_auto.( '--color', options[:color]),
on_off_auto.( '--pager', options[:pager]) on_off_auto.( '--pager', options[:pager])
].flatten.select{|x|x}.map(&:to_s) ].flatten.select{|x|x}.map(&:to_s)
end end
def run *argv def run
options = {} options = {}
setup_env options, argv setup_env options
setup_params options, argv setup_params options
setup_recall options, argv setup_recall options
setup_run options, argv setup_run options
@cmds.run *argv @cmds.run *ARGV
end end
def self.run argv0, *argv def self.run argv0
self.new( argv0).run *argv self.new( argv0).run
end end
end end
class Shortcut class Shortcut
attr_reader :argv0, :argv attr_reader :argv0
def initialize argv0, *argv def initialize argv0
@argv0, @argv = argv0, argv @argv0 = argv0
end end
def exec exe, *args def exec exe, *args
@ -444,16 +521,16 @@ class Shortcut
def run def run
exe = File.basename @argv0 exe = File.basename @argv0
case exe.to_sym case exe.to_sym
when :trdo then exec :truckle, :do, *@argv when :trdo then exec :truckle, :do, *ARGV
when :tresume then exec :truckle, :resume, *@argv when :tresume then exec :truckle, :resume, *ARGV
end end
end end
alias call run alias call run
def self.run argv0, *argv def self.run argv0
self.new( argv0, *argv).run self.new( argv0).run
end end
end end
Shortcut.run $0, *ARGV Shortcut.run $0
Truckle.run $0, *ARGV Truckle.run $0