* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/console/
2013-07-23 7:51 André Erdmann
@ 2013-07-18 19:25 ` André Erdmann
0 siblings, 0 replies; 5+ messages in thread
From: André Erdmann @ 2013-07-18 19:25 UTC (permalink / raw
To: gentoo-commits
commit: f59d23792974b73d890cac678033fabe70ae0bf1
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jul 18 19:22:32 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jul 18 19:25:35 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f59d2379
roverlay/console: console reimplementation
roverlay.console features tab-completion, command history, a strict control flow
and a clean(er) split between interpreter (command parser) code and actual
functionality (mostly kept in roverlay.interface).
roverlay.console.depres offers a dependency resolution console, which will
replace the old one (roverlay.depres.simpledeprule.console) soon.
---
roverlay/console/__init__.py | 5 +
roverlay/console/base.py | 75 ++++++++
roverlay/console/depres.py | 143 +++++++++++++++
roverlay/console/interpreter.py | 384 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 607 insertions(+)
diff --git a/roverlay/console/__init__.py b/roverlay/console/__init__.py
new file mode 100644
index 0000000..d71d876
--- /dev/null
+++ b/roverlay/console/__init__.py
@@ -0,0 +1,5 @@
+# R overlay --
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
diff --git a/roverlay/console/base.py b/roverlay/console/base.py
new file mode 100644
index 0000000..ca3c7a0
--- /dev/null
+++ b/roverlay/console/base.py
@@ -0,0 +1,75 @@
+# R overlay --
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import sys
+
+import roverlay.interface.main
+import roverlay.console.interpreter
+
+class RoverlayConsole ( object ):
+ pass
+
+class MainConsole ( RoverlayConsole ):
+
+ INTERPRETER_CLS = roverlay.console.interpreter.ConsoleInterpreter
+
+ def __init__ ( self, config_file=None ):
+ super ( MainConsole, self ).__init__()
+ self.config = None
+ self.root_interface = roverlay.interface.main.MainInterface()
+ self.interpreter = self.INTERPRETER_CLS()
+ self.interface = None
+
+ if config_file is not None:
+ self.setup ( config_file )
+ # --- end of __init__ (...) ---
+
+ def get_interface ( self ):
+ return self.root_interface
+
+ def has_config ( self ):
+ return self.config is not None
+ # --- end of has_config (...) ---
+
+ def setup ( self, config_file ):
+ self.root_interface.setup ( config_file )
+
+ self.config = self.root_interface.config
+ self.interface = self.get_interface()
+
+ self.interpreter.setup ( self.interface )
+ # --- end of setup (...) ---
+
+ def run ( self ):
+ self.interpreter.cmdloop()
+ # --- end of run (...) ---
+
+ def _want_resume ( self ):
+ if self.interpreter.state.is_paused():
+ return False
+ elif self.interpreter.state == self.interpreter.state.STATE_QUIT:
+ return False
+ else:
+ return True
+ # --- end of _want_resume (...) ---
+
+ def run_forever ( self ):
+ retry = True
+ while retry:
+ retry = False
+ try:
+ self.run()
+ except roverlay.console.interpreter.ConsoleException as ce:
+ sys.stderr.write (
+ "{}: {}\n".format ( ce.__class__.__name__, str ( ce ) )
+ )
+ retry = self._want_resume()
+ except KeyboardInterrupt:
+ sys.stdout.write ( '\n^C\n' )
+ retry = self._want_resume()
+ # --- end of run_forever (...) ---
+
+# --- end of MainConsole ---
diff --git a/roverlay/console/depres.py b/roverlay/console/depres.py
new file mode 100644
index 0000000..ce6a11b
--- /dev/null
+++ b/roverlay/console/depres.py
@@ -0,0 +1,143 @@
+# R overlay --
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import sys
+
+import roverlay.console.base
+import roverlay.console.interpreter
+
+# hidden import
+#import roverlay.interface.depres
+
+# TODO/FIXME: turn off dep resolver logging: "RESOLVED: this as that"
+
+class DepresConsoleInterpreter (
+ roverlay.console.interpreter.ConsoleInterpreter
+):
+ def __init__ ( self, *args, **kwargs ):
+ super ( DepresConsoleInterpreter, self ).__init__ ( *args, **kwargs )
+ self.intro = "depres console (r2)"
+
+ def setup_aliases ( self ):
+ self.add_alias ( "help", "h" )
+
+ # rule pool management
+ self.add_alias ( "add_pool", "<<" )
+ self.add_alias ( "unwind_pool", ">>" )
+ self.add_alias ( "print_pool", "p" )
+
+ # rule creation
+ self.add_alias ( "add_rule", "+" )
+ self.add_alias ( "load_conf", "lc" )
+
+ # dep res
+ self.add_alias ( "resolve", "??" )
+ # --- end of setup_aliases (...) ---
+
+
+ def reset ( self, soft=True ):
+ super ( DepresConsoleInterpreter, self ).reset ( soft=soft )
+ if not soft:
+ self.interface.discard_pools()
+
+ def do_resolve ( self, line ):
+ """Resolve a dependency string.
+
+ Usage:
+ * resolve <dependency string>
+ * ?? <dependency string>
+
+ Examples:
+ * resolve R
+ * resolve fftw 3.2
+ """
+ if line:
+ ret = self.interface.resolve ( line )
+ if ret is None:
+ sys.stdout.write ( "{!r} could not be resolved.\n".format ( line ) )
+ elif not ret:
+ sys.stdout.write (
+ "{!r} has been resolved as nothing(?)\n".format ( line )
+ )
+ elif len ( ret ) == 1:
+ sys.stdout.write (
+ "{!r} has been resolved as {}.\n".format (
+ line, (
+ ret[0].dep if ( ret[0] and ret[0].dep is not None )
+ else "<ignored>"
+ )
+ )
+ )
+ else:
+ sys.stdout.write (
+ "{!r} has been resolved as {}.\n".format (
+ line, ( ', '.join ( str ( dep ) for dep in ret ) )
+ )
+ )
+ else:
+ sys.stderr.write ( "Usage: resolve <dependency string>\n" )
+ # --- end of do_resolve (...) ---
+
+ def do_add_pool ( self, line ):
+ """Creates a new rule pool on top of the existing ones."""
+ self.interface.get_new_pool()
+ # --- end of do_add_pool (...) ---
+
+ def do_unwind_pool ( self, line ):
+ """Removes the topmost rule pool."""
+ if self.interface.discard_pool():
+ sys.stdout.write ( "pool has been removed.\n" )
+ else:
+ sys.stdout.write ( "resolver has no pools.\n" )
+ # --- end of do_unwind_pool (...) ---
+
+ def do_add_rule ( self, line ):
+ """Adds a rule. Rules have to be given in rule file syntax.
+
+ Usage:
+ * add_rule <str>
+ * + <str>
+
+ Examples:
+ * add_rule dev-lang/R :: R
+ """
+ if self._cmdbuffer:
+ self.interface.add_rule_list ( self.get_argbuffer() )
+ elif line:
+ self.interface.add_rule ( line )
+ else:
+ self.warn_usage()
+
+ # compile rules if not inside of a rule
+ self.interface.try_compile_rules()
+ # --- end of do_add_rule (...) ---
+
+ def do_print_pool ( self, line ):
+ """Prints the topmost pool (TODO:: or all)."""
+ sys.stdout.write ( self.interface.visualize_pool() )
+ sys.stdout.write ( "\n" )
+ # --- end of do_print_pool (...) ---
+
+ def do_print ( self, line ):
+ """Prints the topmost pool (TODO:: or all)."""
+ return self.do_print_pool ( line )
+ # --- end of do_print (...) ---
+
+ def do_load_conf ( self, line ):
+ """Load configured dependency rule files."""
+ self.interface.discard_empty_pools()
+ if not self.interface.load_rules_from_config ( ignore_missing=True ):
+ sys.stderr.write ( "failed to load rule files!\n" )
+
+ # --- end of do_load_conf (...) ---
+
+
+
+class DepresConsole ( roverlay.console.base.MainConsole ):
+ INTERPRETER_CLS = DepresConsoleInterpreter
+
+ def get_interface ( self ):
+ return self.root_interface.spawn_interface ( "depres" )
diff --git a/roverlay/console/interpreter.py b/roverlay/console/interpreter.py
new file mode 100644
index 0000000..cf1d106
--- /dev/null
+++ b/roverlay/console/interpreter.py
@@ -0,0 +1,384 @@
+# R overlay --
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import collections
+import sys
+import cmd
+
+def fcopy ( func, name=None, mark_as_alias=True ):
+ """Creates an alias to func."""
+ def wrapped ( *args, **kwargs ):
+ return func ( *args, **kwargs )
+
+ wrapped.__name__ = name if name is not None else func.__name__
+ wrapped.__doc__ = func.__doc__
+ wrapped.__dict__.update ( func.__dict__ )
+ if mark_as_alias:
+ wrapped.is_alias = True
+
+ return wrapped
+# --- end of fcopy (...) ---
+
+class RingBuffer ( collections.deque ):
+ def __init__ ( self, max_size ):
+ super ( RingBuffer, self ).__init__()
+ self.max_size = int ( max_size )
+
+ def reset ( self, max_size=None ):
+ if max_size is not None:
+ self.max_size = int ( max_size )
+ self.clear()
+
+ def is_full ( self ):
+ return len ( self ) >= self.max_size
+
+ def append ( self, value ):
+ if self.is_full():
+ self.popleft()
+ super ( RingBuffer, self ).append ( value )
+
+
+class CommandHistory ( RingBuffer ):
+
+ def __init__ ( self, max_size=100 ):
+ super ( CommandHistory, self ).__init__ ( max_size=max_size )
+
+
+
+
+class ConsoleException ( Exception ):
+ pass
+
+class ConsoleStatusException ( ConsoleException ):
+ pass
+
+class ConsoleInterpreterStatus ( object ):
+ """Object that represents the status of a ConsoleInterpreter."""
+
+ # STATE := {0..N}
+ # overall, there are 4 (5) states
+ # * the undefined state
+ # * exiting
+ # * ready to parse
+ # * parsing a command
+ # * executing a command
+ #
+ STATE_UNDEF = 0
+ STATE_QUIT = 1
+ STATE_READY = 2
+ STATE_CMD_PARSE = 3
+ STATE_CMD_EXEC = 4
+
+ STATE_TRANSITION_TABLE = {
+ STATE_UNDEF : frozenset(),
+ STATE_QUIT : frozenset(),
+ STATE_READY : frozenset ({ STATE_CMD_PARSE, STATE_CMD_EXEC }),
+ STATE_CMD_PARSE : frozenset ({
+ STATE_READY, STATE_CMD_EXEC, STATE_CMD_PARSE
+ }),
+ STATE_CMD_EXEC : frozenset ({ STATE_READY, STATE_QUIT }),
+ }
+
+ # FLAGS := {0,} | {2^k for k in 0..N}
+ FLAGS_UNDEF = 0
+ FLAGS_CONFIGURED = 1
+ FLAGS_ONERROR = 2
+
+ @classmethod
+ def get_state ( cls, name ):
+ return getattr ( cls, "STATE_" + name.upper() )
+ # --- end of get_state (...) ---
+
+ def __init__ ( self ):
+ super ( ConsoleInterpreterStatus, self ).__init__()
+ self.state = self.STATE_UNDEF
+ self.flags = self.FLAGS_UNDEF
+ # --- end of __init__ (...) ---
+
+ def set_flag ( self, flag ):
+ self.flags |= flag
+
+ def clear_flag ( self, flag ):
+ self.flags &= ~flag
+
+ def has_flag ( self, flag ):
+ return bool ( self.flags & flag )
+
+ def set_configured ( self ):
+ self.flags |= self.FLAGS_CONFIGURED
+ # --- end of set_configured (...) ---
+
+ def reset ( self ):
+ self.state = self.STATE_READY
+ self.clear_flag ( self.FLAGS_ONERROR )
+ # --- end of reset (...) ---
+
+ def __eq__ ( self, other ):
+ if isinstance ( other, int ):
+ return self.state == other
+ else:
+ raise NotImplementedError()
+
+ def __ne__ ( self, other ):
+ if isinstance ( other, int ):
+ return self.state != other
+ else:
+ raise NotImplementedError()
+
+
+ def goto ( self, next_state ):
+ """state transition"""
+ #if "self.state => next_state" allowed
+ #returns ??
+
+ i_next_state = self.get_state ( next_state )
+
+ if i_next_state in self.STATE_TRANSITION_TABLE [self.state]:
+ self.state = i_next_state
+ return True
+ else:
+ raise ConsoleStatusException (
+ "invalid state transition {src}->{dest} ({name!r}).".format (
+ src=self.state, dest=self.get_state ( next_state ),
+ name=next_state
+ )
+ )
+ # --- end of goto (...) ---
+
+ def force ( self, next_state="READY" ):
+ """forced state transitition"""
+ self.state = self.get_state ( next_state )
+ return True
+ # --- end of force (...) ---
+
+ def is_paused ( self ):
+ return False
+
+ #def __str__ ...
+
+
+# --- end of ConsoleInterpreterStatus ---
+
+class ConsoleInterpreter ( cmd.Cmd ):
+ # TODO: line continuation when "\" at the end of a line
+
+ def __init__ ( self, *args, **kwargs ):
+ super ( ConsoleInterpreter, self ).__init__ ( *args, **kwargs )
+ self.state = ConsoleInterpreterStatus()
+ self.interface = None
+
+ self._locals = {}
+ # for printing the history
+ self._history = CommandHistory()
+ # name => real command name
+ self._alias = {}
+ self._cmdbuffer = None
+
+ self.MULTILINE_JOIN = ' '
+
+ self.DEFAULT_PS1 = 'cmd %'
+ self.DEFAULT_PS2 = '>'
+ #self.PS3 = ''
+ #self.PS4 = '+ '
+
+ self.intro = "roverlay console"
+
+ self.setup_aliases()
+ # --- end of __init__ (...) ---
+
+ def setup_aliases ( self ):
+ pass
+ # --- end of setup_aliases (...) ---
+
+ def is_onerror ( self ):
+ return self.state.has_flag ( ConsoleInterpreterStatus.FLAGS_ONERROR )
+ # --- end of is_onerror (...) ---
+
+ def set_onerror ( self ):
+ return self.state.set_flag ( ConsoleInterpreterStatus.FLAGS_ONERROR )
+ # --- end of set_onerror (...) ---
+
+ def clear_onerror ( self ):
+ return self.state.clear_flag ( ConsoleInterpreterStatus.FLAGS_ONERROR )
+ # --- end of clear_onerror (...) ---
+
+ def add_alias ( self, dest, *aliases ):
+ if hasattr ( self, 'do_' + dest ):
+ for alias in aliases:
+ self._alias [alias] = dest
+ return True
+ elif self.state == ConsoleInterpreterStatus.STATE_UNDEF:
+ raise AssertionError ( "no such function: do_{}".format ( dest ) )
+ else:
+ sys.stderr.write ( "alias: do_{} does not exist\n".format ( dest ) )
+ return False
+
+ def reset ( self, soft=True ):
+ self.state.reset()
+ self._cmdbuffer = None
+ self.prompt = self._locals.get ( "PS1", self.DEFAULT_PS1 ) + ' '
+
+ def unalias_cmdline ( self, line ):
+ if line:
+ lc = line.split ( None, 1 )
+ unaliased = self._alias.get ( lc[0] ) if lc[0] else None
+
+ if unaliased:
+ if len ( lc ) > 1:
+ return unaliased + ' ' + lc[1]
+ else:
+ return unaliased
+ else:
+ return line
+ else:
+ return line
+ # --- end of unalias_cmdline (...) ---
+
+ def warn_usage ( self ):
+ sys.stderr.write ( "{}: bad usage.\n".format ( self.lastcmd ) )
+
+ def get_argbuffer ( self ):
+ return self._cmdbuffer[1:]
+ # --- end of get_linebuffer (...) ---
+
+ def precmd ( self, line ):
+ sline = line.strip()
+
+ if sline and sline[-1] == chr ( 92 ):
+ # "\" at end of line => line continuation
+ self.state.goto ( "CMD_PARSE" )
+ self.prompt = self._locals.get ( "PS2", self.DEFAULT_PS2 ) + ' '
+
+ if self._cmdbuffer is None:
+ # unalias
+ self._cmdbuffer = sline[:-1].rstrip().split ( None, 1 )
+ if self._cmdbuffer[0] in self._alias:
+ self._cmdbuffer[0] = self._alias [self._cmdbuffer[0]]
+ else:
+ self._cmdbuffer.append ( sline[:-1].rstrip() )
+
+ return ""
+ elif self._cmdbuffer:
+ self._cmdbuffer.append ( sline )
+
+ self.state.goto ( "CMD_EXEC" )
+ return self.MULTILINE_JOIN.join ( self._cmdbuffer )
+ else:
+ # unalias
+ self.state.goto ( "CMD_EXEC" )
+ return self.unalias_cmdline ( line )
+ # --- end of precmd (...) ---
+
+ def postcmd ( self, stop, line ):
+ if self.state == ConsoleInterpreterStatus.STATE_CMD_EXEC:
+ if self.is_onerror():
+ self.clear_onerror()
+ elif self.lastcmd != "history":
+ self._history.append ( line )
+
+ self.state.goto ( "READY" )
+ self._cmdbuffer = None
+ self.prompt = self._locals.get ( "PS1", self.DEFAULT_PS1 ) + ' '
+
+ return stop
+ # --- end of postcmd (...) ---
+
+ def onecmd ( self, *a, **b ):
+ if self.state == ConsoleInterpreterStatus.STATE_CMD_EXEC:
+ return super ( ConsoleInterpreter, self ).onecmd ( *a, **b )
+ else:
+ # suppress command
+ return None
+ # --- end of onecmd (...) ---
+
+ def emptyline ( self ):
+ pass
+ # -- end of emptyline (...) ---
+
+ def preloop ( self ):
+ if not self.state.is_paused():
+ self.reset ( soft=True )
+ # --- end of preloop (...) ---
+
+ def setup ( self, interface ):
+ self.interface = interface
+ self.state.set_configured()
+ return True
+ # --- end of setup (...) ---
+
+ def do_alias ( self, line ):
+ """Show/set aliases (currently only shows all aliases)."""
+ alen = 1 + len ( max ( self._alias, key=lambda k: len ( k ) ) )
+
+ sys.stdout.write ( '\n'.join (
+ "{:<{l}} is {!r}".format ( alias, name, l=alen )
+ for alias, name in self._alias.items()
+ ) )
+ sys.stdout.write ( '\n' )
+ # --- end of do_alias (...) ---
+
+ def do_unalias ( self, line ):
+ """Unsets an alias."""
+ sys.stderr.write ( "unalias: method stub\n" )
+ # --- end of do_unalias (...) ---
+
+ def do_history ( self, line ):
+ """Shows the command history."""
+ sys.stdout.write ( '\n'.join ( l for l in self._history ) )
+ sys.stdout.write ( '\n' )
+ # --- end of history (...) ---
+
+ def do_set ( self, line ):
+ """Sets a variable.
+
+ Usage: set VAR=VALUE
+
+ Examples:
+ * set PS1=cmd %
+ * set dep=fftw 3
+ """
+ name, sepa, value = line.partition ( '=' )
+ if not sepa:
+ sys.stderr.write ( "set, bad syntax: {}\n".format ( line ) )
+ else:
+ self._locals [name.strip()] = value
+ # --- end of do_set (...) ---
+
+ def do_unset ( self, line ):
+ """Unsets zero or more variables.
+
+ Usage: unset VAR0 [VAR1...]
+
+ Examples:
+ * unset PS1
+ """
+ for varname in line.split ( None ):
+ try:
+ del self._locals [varname]
+ except KeyError:
+ pass
+ # --- end of do_unset (...) ---
+
+ def do_quit ( self, *a ):
+ """Exit"""
+ sys.stdout.flush()
+ sys.stderr.flush()
+ self.state.goto ( "QUIT" )
+ return True
+
+ def do_exit ( self, *a ):
+ """Exit"""
+ return self.do_quit()
+
+ def do_q ( self, *a ):
+ """Exit"""
+ return self.do_quit()
+
+ def do_EOF ( self, *a ):
+ """Exit"""
+ sys.stdout.write ( '\n' )
+ return self.do_quit()
+# --- end of ConsoleInterpreter ---
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/console/
@ 2013-07-19 18:00 André Erdmann
2013-07-23 7:51 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
0 siblings, 1 reply; 5+ messages in thread
From: André Erdmann @ 2013-07-19 18:00 UTC (permalink / raw
To: gentoo-commits
commit: 3437297b76c1c711207e45e73534c98493a65c80
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 19 17:46:35 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 19 17:46:35 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=3437297b
roverlay/console/base: close(), accept config
---
roverlay/console/base.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/roverlay/console/base.py b/roverlay/console/base.py
index ca3c7a0..acd4ca0 100644
--- a/roverlay/console/base.py
+++ b/roverlay/console/base.py
@@ -34,8 +34,12 @@ class MainConsole ( RoverlayConsole ):
return self.config is not None
# --- end of has_config (...) ---
- def setup ( self, config_file ):
- self.root_interface.setup ( config_file )
+ def close ( self ):
+ self.root_interface.close()
+ # --- end of close (...) ---
+
+ def setup ( self, config_file=None, config=None ):
+ self.root_interface.setup ( config_file=config_file, config=config )
self.config = self.root_interface.config
self.interface = self.get_interface()
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/console/
2013-07-23 7:51 [gentoo-commits] proj/R_overlay:master " André Erdmann
@ 2013-07-19 18:00 ` André Erdmann
0 siblings, 0 replies; 5+ messages in thread
From: André Erdmann @ 2013-07-19 18:00 UTC (permalink / raw
To: gentoo-commits
commit: b5013fb1b3d8f5e108f46abb045b798b3337ed4b
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 19 17:48:40 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 19 17:48:40 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b5013fb1
console, interpreter: add commands, parsing, compl
new commands:
* some standard commands: pwd, cd, ls, cat, echo, declare
* "command chroot": prefix all user input with a specific command while in
chroot
misc features:
* argparser for commands ("--opt pos_arg ... --another-opt ...")
* arg completion for some commands (e.g. for filepaths)
* (partial) support for !$, which is replaced by "last arg"
* commands with an argparser support variables (by means of string formatting)
---
roverlay/console/interpreter.py | 430 +++++++++++++++++++++++++++++++++++++---
1 file changed, 401 insertions(+), 29 deletions(-)
diff --git a/roverlay/console/interpreter.py b/roverlay/console/interpreter.py
index cf1d106..babdba5 100644
--- a/roverlay/console/interpreter.py
+++ b/roverlay/console/interpreter.py
@@ -4,33 +4,39 @@
# Distributed under the terms of the GNU General Public License;
# either version 2 of the License, or (at your option) any later version.
+import argparse
+import errno
import collections
+import os
import sys
import cmd
+import string
+import shlex
+##import glob
-def fcopy ( func, name=None, mark_as_alias=True ):
- """Creates an alias to func."""
- def wrapped ( *args, **kwargs ):
- return func ( *args, **kwargs )
-
- wrapped.__name__ = name if name is not None else func.__name__
- wrapped.__doc__ = func.__doc__
- wrapped.__dict__.update ( func.__dict__ )
- if mark_as_alias:
- wrapped.is_alias = True
-
- return wrapped
-# --- end of fcopy (...) ---
+import roverlay.util.fileio
+import roverlay.strutil
+from roverlay.strutil import unquote, unquote_all
class RingBuffer ( collections.deque ):
def __init__ ( self, max_size ):
super ( RingBuffer, self ).__init__()
self.max_size = int ( max_size )
- def reset ( self, max_size=None ):
+ def reset ( self, max_size=None, clear=True ):
if max_size is not None:
self.max_size = int ( max_size )
- self.clear()
+
+ if clear or self.max_size <= 0:
+ self.clear()
+ else:
+ while len ( self ) > self.max_size:
+ self.popleft()
+ # --- end of reset (...) ---
+
+ def resize ( self, max_size=None ):
+ self.reset ( max_size=max_size, clear=False )
+ # --- end of resize (...) ---
def is_full ( self ):
return len ( self ) >= self.max_size
@@ -40,12 +46,14 @@ class RingBuffer ( collections.deque ):
self.popleft()
super ( RingBuffer, self ).append ( value )
+# --- end of RingBuffer ---
class CommandHistory ( RingBuffer ):
def __init__ ( self, max_size=100 ):
super ( CommandHistory, self ).__init__ ( max_size=max_size )
+# --- end of CommandHistory ---
@@ -55,6 +63,33 @@ class ConsoleException ( Exception ):
class ConsoleStatusException ( ConsoleException ):
pass
+class ConsoleUsageException ( ConsoleException ):
+ pass
+
+class ConsoleArgumentParser ( argparse.ArgumentParser ):
+
+ def exit ( self, status=0, message=None ):
+ if message:
+ raise ConsoleUsageException ( message )
+ else:
+ raise ConsoleUsageException()
+
+ def error ( self, message ):
+ raise ConsoleUsageException ( message )
+
+ def add_opt_in ( self, *args, **kwargs ):
+ self.add_argument (
+ *args, default=False, action='store_true', **kwargs
+ )
+
+ def add_opt_out ( self, *args, **kwargs ):
+ self.add_argument (
+ *args, default=True, action='store_false', **kwargs
+ )
+
+# --- end of ConsoleArgumentParser ---
+
+
class ConsoleInterpreterStatus ( object ):
"""Object that represents the status of a ConsoleInterpreter."""
@@ -128,7 +163,6 @@ class ConsoleInterpreterStatus ( object ):
else:
raise NotImplementedError()
-
def goto ( self, next_state ):
"""state transition"""
#if "self.state => next_state" allowed
@@ -162,14 +196,22 @@ class ConsoleInterpreterStatus ( object ):
# --- end of ConsoleInterpreterStatus ---
+
+
class ConsoleInterpreter ( cmd.Cmd ):
- # TODO: line continuation when "\" at the end of a line
+ # !!! cmd.Cmd is an old-style class
def __init__ ( self, *args, **kwargs ):
- super ( ConsoleInterpreter, self ).__init__ ( *args, **kwargs )
+ #super ( ConsoleInterpreter, self ).__init__ ( *args, **kwargs )
+ cmd.Cmd.__init__ ( self, *args, **kwargs )
+
+
+ self.identchars += os.sep
self.state = ConsoleInterpreterStatus()
self.interface = None
+ self._str_formatter = string.Formatter()
+
self._locals = {}
# for printing the history
self._history = CommandHistory()
@@ -177,6 +219,12 @@ class ConsoleInterpreter ( cmd.Cmd ):
self._alias = {}
self._cmdbuffer = None
+ self._initial_pwd = os.getcwd()
+ self._pwd = None
+ self._oldpwd = None
+
+ self._chroot = None
+
self.MULTILINE_JOIN = ' '
self.DEFAULT_PS1 = 'cmd %'
@@ -186,13 +234,109 @@ class ConsoleInterpreter ( cmd.Cmd ):
self.intro = "roverlay console"
+ self._argparser = dict()
+
self.setup_aliases()
+ self.setup_argparser()
+ self.setup_interpreter()
# --- end of __init__ (...) ---
+ def set_var ( self, name, value ):
+ self._locals [name] = value
+ # --- end of set_var (...) ---
+
+ def set_lastarg ( self, value ):
+ return self.set_var ( "_lastarg", value )
+ # --- end of set_lastarg (...) ---
+
+ def get_argparser ( self, cmd, create=False ):
+ if create:
+ parser = self._argparser.get ( cmd, None )
+ if parser is None:
+ parser = ConsoleArgumentParser ( prog=cmd, add_help=True )
+ self._argparser [cmd] = parser
+ return parser
+ else:
+ return self._argparser [cmd]
+ # --- end of get_argparser (...) ---
+
+ def parse_cmdline ( self, cmd, line ):
+ try:
+ ret = self.get_argparser ( cmd, create=False ).parse_args (
+ shlex.split ( self.format_locals ( line ) )
+ )
+ except ConsoleUsageException as cue:
+ sys.stderr.write ( str ( cue ) + '\n' )
+ ret = None
+
+ return ret
+ # --- end of parse_cmdline (...) ---
+
+ def format_locals ( self, line, replace_lastarg=True ):
+ if '_lastarg' not in self._locals:
+ self.set_lastarg ( "" )
+
+ if replace_lastarg:
+ l = line.replace ( '!$', '{_lastarg}' )
+ else:
+ l = line
+
+ return self._str_formatter.vformat ( l, (), self._locals )
+ # --- end of format_locals (...) ---
+
+ def get_fspath ( self, line ):
+ pline = unquote_all ( line )
+ if pline:
+ return os.path.normpath ( os.path.join ( self._pwd, pline ) )
+ else:
+ return self._pwd
+ # --- end of get_fspath (...) ---
+
+ def argparse_filepath ( self, value ):
+ f = self.get_fspath ( value ) if value else None
+ if f and os.path.isfile ( f ):
+ return f
+ else:
+ raise argparse.ArgumentTypeError (
+ "{!r} is not a file!".format ( value )
+ )
+ # --- end of argparse_filepath (...) ---
+
+ def argparse_fspath ( self, value ):
+ f = self.get_fspath ( value ) if value else None
+ if f and os.path.exists ( f ):
+ return f
+ else:
+ raise argparse.ArgumentTypeError (
+ "{!r} does not exist!".format ( value )
+ )
+ # --- end of argparse_fspath (...) ---
+
+ def set_pwd ( self, newpwd ):
+ pwd = os.path.normpath ( newpwd )
+ if pwd is not None and pwd != self._pwd:
+ self._oldpwd = self._pwd
+ self._pwd = pwd
+
+ self._locals ['PWD'] = self._pwd
+ self._locals ['OLDPWD'] = self._oldpwd
+ # --- end of set_pwd (...) ---
+
def setup_aliases ( self ):
pass
# --- end of setup_aliases (...) ---
+ def setup_argparser ( self ):
+ parser = self.get_argparser ( "cat", create=True )
+ parser.add_argument ( "files", metavar='<file>', nargs='*',
+ help='files to read', type=self.argparse_filepath,
+ )
+ # --- end of setup_argparser (...) ---
+
+ def setup_interpreter ( self ):
+ pass
+ # --- end of setup_interpreter (...) ---
+
def is_onerror ( self ):
return self.state.has_flag ( ConsoleInterpreterStatus.FLAGS_ONERROR )
# --- end of is_onerror (...) ---
@@ -206,9 +350,18 @@ class ConsoleInterpreter ( cmd.Cmd ):
# --- end of clear_onerror (...) ---
def add_alias ( self, dest, *aliases ):
- if hasattr ( self, 'do_' + dest ):
+ COMP = lambda a: 'complete_' + a
+
+ lc = dest.split ( None, 1 )
+
+ if lc and lc[0] and hasattr ( self, 'do_' + lc[0] ):
for alias in aliases:
self._alias [alias] = dest
+
+ # add ref to complete function (if available)
+ comp_func = getattr ( self, COMP ( lc[0] ), None )
+ if comp_func is not None:
+ setattr ( self, COMP ( alias ), comp_func )
return True
elif self.state == ConsoleInterpreterStatus.STATE_UNDEF:
raise AssertionError ( "no such function: do_{}".format ( dest ) )
@@ -219,7 +372,15 @@ class ConsoleInterpreter ( cmd.Cmd ):
def reset ( self, soft=True ):
self.state.reset()
self._cmdbuffer = None
- self.prompt = self._locals.get ( "PS1", self.DEFAULT_PS1 ) + ' '
+ self._chroot = None
+ self.prompt = self._locals.get ( "PS1", self.DEFAULT_PS1 ) + ' '
+
+ self._pwd = self._initial_pwd
+ self._oldpwd = self._initial_pwd
+ self._locals ['PWD'] = self._initial_pwd
+ self._locals ['OLDPWD'] = self._initial_pwd
+ self.set_lastarg ( "" )
+ # --- end of reset (...) ---
def unalias_cmdline ( self, line ):
if line:
@@ -244,6 +405,28 @@ class ConsoleInterpreter ( cmd.Cmd ):
return self._cmdbuffer[1:]
# --- end of get_linebuffer (...) ---
+ def chroot_cmd ( self, line ):
+ if not line:
+ return self._chroot if self._chroot else line
+ elif line[0] == '/':
+ return 'chroot ' + line
+ elif self._chroot:
+ lc = line.split ( None, 1 )
+ if lc[0] == 'chroot':
+ return line
+ else:
+ return self._chroot + ' ' + line
+ else:
+ return line
+ # --- end of chroot_cmd (...) ---
+
+ def chroot_allowed ( self, cmd ):
+ if hasattr ( self, 'CHROOT_ALLOWED' ):
+ return cmd in self.CHROOT_ALLOWED
+ else:
+ return True
+ # --- end of chroot_allowed (...) ---
+
def precmd ( self, line ):
sline = line.strip()
@@ -255,7 +438,7 @@ class ConsoleInterpreter ( cmd.Cmd ):
if self._cmdbuffer is None:
# unalias
self._cmdbuffer = sline[:-1].rstrip().split ( None, 1 )
- if self._cmdbuffer[0] in self._alias:
+ if self._cmdbuffer and self._cmdbuffer[0] in self._alias:
self._cmdbuffer[0] = self._alias [self._cmdbuffer[0]]
else:
self._cmdbuffer.append ( sline[:-1].rstrip() )
@@ -265,30 +448,42 @@ class ConsoleInterpreter ( cmd.Cmd ):
self._cmdbuffer.append ( sline )
self.state.goto ( "CMD_EXEC" )
- return self.MULTILINE_JOIN.join ( self._cmdbuffer )
+ return self.chroot_cmd (
+ self.MULTILINE_JOIN.join ( self._cmdbuffer )
+ )
else:
# unalias
self.state.goto ( "CMD_EXEC" )
- return self.unalias_cmdline ( line )
+ return self.chroot_cmd (
+ self.unalias_cmdline ( line )
+ )
# --- end of precmd (...) ---
def postcmd ( self, stop, line ):
if self.state == ConsoleInterpreterStatus.STATE_CMD_EXEC:
if self.is_onerror():
self.clear_onerror()
- elif self.lastcmd != "history":
+ elif self.lastcmd and self.lastcmd != "history":
self._history.append ( line )
self.state.goto ( "READY" )
self._cmdbuffer = None
- self.prompt = self._locals.get ( "PS1", self.DEFAULT_PS1 ) + ' '
+
+ if self._chroot:
+ self.prompt = self._locals.get (
+ "CHROOT_PS1", "({}) %".format ( self._chroot )
+ ) + ' '
+ else:
+ self.prompt = self._locals.get ( "PS1", self.DEFAULT_PS1 ) + ' '
+
return stop
# --- end of postcmd (...) ---
def onecmd ( self, *a, **b ):
if self.state == ConsoleInterpreterStatus.STATE_CMD_EXEC:
- return super ( ConsoleInterpreter, self ).onecmd ( *a, **b )
+ return cmd.Cmd.onecmd ( self, *a, **b )
+ #return super ( ConsoleInterpreter, self ).onecmd ( *a, **b )
else:
# suppress command
return None
@@ -309,13 +504,32 @@ class ConsoleInterpreter ( cmd.Cmd ):
return True
# --- end of setup (...) ---
+ def complete_fspath ( self, text, line, begidx, endidx ):
+ # FIXME: why gets an "/" at the beginning of text ignored?
+ # (doesn't seem to be related to chrooted commands here)
+
+ dcomponents = line.rsplit ( None, 1 )
+ if len ( dcomponents ) > 1:
+ dpath = self.get_fspath ( os.path.dirname ( dcomponents[1] ) )
+ else:
+ dpath = self._pwd
+
+ if os.path.isdir ( dpath ):
+ return list (
+ ( f + os.sep if os.path.isdir ( dpath + os.sep + f ) else f )
+ for f in os.listdir ( dpath ) if f.startswith ( text )
+ )
+ else:
+ return []
+ # --- end of complete_fspath (...) ---
+
def do_alias ( self, line ):
"""Show/set aliases (currently only shows all aliases)."""
alen = 1 + len ( max ( self._alias, key=lambda k: len ( k ) ) )
sys.stdout.write ( '\n'.join (
- "{:<{l}} is {!r}".format ( alias, name, l=alen )
- for alias, name in self._alias.items()
+ "{:<{l}} is {}".format ( kv[0], kv[1], l=alen )
+ for kv in sorted ( self._alias.items(), key=lambda kv: kv[1] )
) )
sys.stdout.write ( '\n' )
# --- end of do_alias (...) ---
@@ -331,6 +545,109 @@ class ConsoleInterpreter ( cmd.Cmd ):
sys.stdout.write ( '\n' )
# --- end of history (...) ---
+ def do_pwd ( self, line ):
+ """Prints the current working directory."""
+ if not self._pwd:
+ self._pwd = self._initial_pwd
+ self._oldpwd = self._initial_pwd
+ sys.stdout.write ( self._initial_pwd + '\n' )
+ elif os.path.isdir ( self._pwd ):
+ sys.stdout.write ( self._pwd + '\n' )
+ else:
+ sys.stdout.write ( "[virtual] {}\n".format ( self._pwd ) )
+ # --- end of do_pwd (...) ---
+
+ def complete_cd ( self, *args, **kw ):
+ return self.complete_fspath ( *args, **kw )
+ # --- end of complete_cd (...) ---
+
+ def do_cd ( self, line ):
+ """Changes the working directory.
+
+ Usage: cd [-|<dir>]
+
+ Examples:
+ * cd -- change working directory to the initial dir
+ * cd - -- change working directory to OLDPWD
+ * cd /var -- change working to /var
+ """
+ pline = unquote_all ( line )
+ if not pline:
+ self.set_pwd ( self._initial_pwd )
+ elif pline == '-':
+ self.set_pwd ( self._oldpwd )
+ elif self._pwd:
+ self.set_pwd ( os.path.join ( self._pwd, pline ) )
+ else:
+ self.set_pwd ( pline )
+
+ if not self._pwd or not os.path.isdir ( self._pwd ):
+ sys.stderr.write (
+ "warn: {!r} does not exist.\n".format ( self._pwd )
+ )
+ # --- end of do_cd (...) ---
+
+ def complete_ls ( self, *args, **kw ):
+ return self.complete_fspath ( *args, **kw )
+ # --- end of complete_ls (...) ---
+
+ def do_ls ( self, line ):
+ """Shows the directory content of the given dir (or the current working
+ directory).
+ """
+ p = self.get_fspath ( line )
+
+ try:
+ items = '\n'.join (
+ sorted ( os.listdir ( p ), key=lambda k: k.lower() )
+ )
+ except OSError as oserr:
+ if oserr.errno == errno.ENOENT:
+ sys.stderr.write ( "ls: {!r} does not exist.\n".format ( p ) )
+ else:
+ sys.stdout.write ( "{}:\n{}\n".format ( p, items ) )
+ # --- end of do_ls (...) ---
+
+ def complete_cat ( self, *args, **kw ):
+ return self.complete_fspath ( *args, **kw )
+ # --- end of complete_cat (...) ---
+
+ def do_cat ( self, line ):
+ """Read files and print them.
+ Supports uncompressed and bzip2,gzip-compressed files.
+ """
+ args = self.parse_cmdline ( "cat", line )
+ if args:
+ try:
+ for fpath in args.files:
+ for fline in roverlay.util.fileio.read_text_file ( fpath ):
+ sys.stdout.write ( fline )
+ else:
+ self.set_lastarg ( fpath )
+ except Exception as err:
+ sys.stderr.write ( "cat failed ({}, {})!\n".format (
+ err.__class__.__name__, str ( err )
+ ) )
+ # --- end of do_cat (...) ---
+
+ def do_echo ( self, line ):
+ """Prints a message. String formatting '{VARNAME}' is supported."""
+ try:
+ s = self.format_locals ( line )
+ except ( IndexError, KeyError ):
+ sys.stderr.write ( "cannot print {!r}!\n".format ( line ) )
+ else:
+ sys.stdout.write ( s + '\n' )
+ # --- end of do_echo (...) ---
+
+ def do_declare ( self, line ):
+ """Prints all variables."""
+ for kv in sorted (
+ self._locals.items(), key=lambda kv: kv[0].lower()
+ ):
+ sys.stdout.write ( "{k}=\"{v}\"\n".format ( k=kv[0], v=kv[1] ) )
+ # --- end of do_declare (...) ---
+
def do_set ( self, line ):
"""Sets a variable.
@@ -344,7 +661,7 @@ class ConsoleInterpreter ( cmd.Cmd ):
if not sepa:
sys.stderr.write ( "set, bad syntax: {}\n".format ( line ) )
else:
- self._locals [name.strip()] = value
+ self.set_var ( name.strip(), value )
# --- end of do_set (...) ---
def do_unset ( self, line ):
@@ -362,6 +679,57 @@ class ConsoleInterpreter ( cmd.Cmd ):
pass
# --- end of do_unset (...) ---
+ def complete_chroot ( self, text, line, begidx, endidx ):
+ if hasattr ( self, 'COMP_CHROOT_ALLOWED' ):
+ if text:
+ c = text.lstrip ( "/" )
+ return list (
+ k for k in self.COMP_CHROOT_ALLOWED if k.startswith ( c )
+ )
+ else:
+ return list ( self.COMP_CHROOT_ALLOWED )
+ else:
+ return []
+ # --- end of complete_chroot (...) ---
+
+ def do_chroot ( self, line ):
+ """Enters or leaves a command chroot.
+ A command chroot prefixes all input lines with a command (except for
+ chroot commands).
+
+ Usage:
+ * chroot -- query chroot status
+ * chroot / -- leave chroot
+ * chroot /<cmd> -- enter chroot for <cmd>
+ * / -- alias to chroot /
+ * /<cmd> -- alias to chroot /<cmd>
+ """
+ pline = unquote_all ( line )
+ sline = pline.lstrip ( "/" ).lstrip()
+
+ if pline == "/":
+ self._chroot = None
+ self.do_unset ( "CHROOT_PS1" )
+ elif not sline:
+ if self._chroot:
+ sys.stdout.write (
+ "current command chroot is {!r}\n".format ( self._chroot )
+ )
+ else:
+ sys.stdout.write ( "no command chroot in use.\n" )
+ else:
+ cmd = self._alias.get ( sline, sline )
+ if not hasattr ( self, 'do_' + cmd ):
+ sys.stderr.write ( "no such command: {!r}\n".format ( cmd ) )
+ elif cmd != 'chroot' and self.chroot_allowed ( cmd ):
+ self._chroot = cmd
+ else:
+ sys.stderr.write (
+ "{!r} cmd chroot is not allowed!\n".format ( cmd )
+ )
+
+ # --- end of do_chroot (...) ---
+
def do_quit ( self, *a ):
"""Exit"""
sys.stdout.flush()
@@ -377,6 +745,10 @@ class ConsoleInterpreter ( cmd.Cmd ):
"""Exit"""
return self.do_quit()
+ def do_qq ( self, *a ):
+ """Exit"""
+ return self.do_quit()
+
def do_EOF ( self, *a ):
"""Exit"""
sys.stdout.write ( '\n' )
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/console/
2013-07-23 7:51 [gentoo-commits] proj/R_overlay:master " André Erdmann
@ 2013-07-19 18:00 ` André Erdmann
0 siblings, 0 replies; 5+ messages in thread
From: André Erdmann @ 2013-07-19 18:00 UTC (permalink / raw
To: gentoo-commits
commit: 88095f8d7f7c2c57edbc6319094fb272f3977444
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 19 17:55:54 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 19 17:55:54 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=88095f8d
extend new depres console
* added extended versions of load, load_conf, write known from the old console
* print_pool can now be used to print all or a specific set of pools
* unwind_pool accepts '--all','-a' as opt, which removes all pools
* '/resolve', '!' can be used to enter a resolve command chroot where
dependency strings don't have to be prefixed with "resolve"
* '!!' for exiting the command chroot
---
roverlay/console/depres.py | 179 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 158 insertions(+), 21 deletions(-)
diff --git a/roverlay/console/depres.py b/roverlay/console/depres.py
index ce6a11b..457b577 100644
--- a/roverlay/console/depres.py
+++ b/roverlay/console/depres.py
@@ -4,24 +4,36 @@
# Distributed under the terms of the GNU General Public License;
# either version 2 of the License, or (at your option) any later version.
+import os
import sys
import roverlay.console.base
import roverlay.console.interpreter
+from roverlay.console.interpreter import ConsoleInterpreter
+
+import roverlay.strutil
+from roverlay.strutil import unquote, unquote_all
+
+#wrap_lastarg = roverlay.console.interpreter.wrap_lastarg
# hidden import
#import roverlay.interface.depres
# TODO/FIXME: turn off dep resolver logging: "RESOLVED: this as that"
-class DepresConsoleInterpreter (
- roverlay.console.interpreter.ConsoleInterpreter
-):
+class DepresConsoleInterpreter ( ConsoleInterpreter ):
+ # Note: this is an old-style class (inherited from cmd.Cmd)
+
+ CHROOT_ALLOWED = frozenset ({ 'resolve', })
+ COMP_CHROOT_ALLOWED = list ( CHROOT_ALLOWED | { '/', } )
+
def __init__ ( self, *args, **kwargs ):
- super ( DepresConsoleInterpreter, self ).__init__ ( *args, **kwargs )
- self.intro = "depres console (r2)"
+ ConsoleInterpreter.__init__ ( self, *args, **kwargs )
+ self.intro = "dependency resolution console (r2)"
def setup_aliases ( self ):
+ ConsoleInterpreter.setup_aliases ( self )
+
self.add_alias ( "help", "h" )
# rule pool management
@@ -31,15 +43,61 @@ class DepresConsoleInterpreter (
# rule creation
self.add_alias ( "add_rule", "+" )
+
+ # load rules
self.add_alias ( "load_conf", "lc" )
+ self.add_alias ( "load", "l" )
- # dep res
+ # rule export
+ self.add_alias ( "write", "w" )
+
+ # depres
self.add_alias ( "resolve", "??" )
+
+ # enter/leave depres chroot
+ self.add_alias ( "chroot /resolve", "!" )
+ self.add_alias ( "chroot /", "!!" )
# --- end of setup_aliases (...) ---
+ def setup_argparser ( self ):
+ ConsoleInterpreter.setup_argparser ( self )
+
+ # write
+ parser = self.get_argparser ( "write", create=True )
+
+ parser.add_argument ( 'outfile', nargs=1, metavar="<file>", type=str,
+ help="file to write"
+ )
+ parser.add_opt_in ( '--force', '-f', help='overwrite existing files' )
+ parser.add_opt_in ( '--all', '-a',
+ help="write all pools into a single file"
+ )
+
+ # load
+ parser = self.get_argparser ( "load", create=True )
+
+ parser.add_argument ( 'files', nargs='*', metavar="<file|dir>",
+ type=self.argparse_fspath, help="files/dirs to load",
+ )
+
+ # print_pool
+ parser = self.get_argparser ( "print_pool", create=True )
+
+ parser.add_opt_in ( '--all', '-a', help="print all pools" )
+ parser.add_argument ( 'pools', metavar='<id>', nargs='*',
+ help="print specific pools (by id)", type=int,
+ )
+
+
+ # unwind_pool
+ parser = self.get_argparser ( "unwind_pool", create=True )
+
+ parser.add_opt_in ( '--all', '-a', help='discard all rule pools' )
+
+ # --- end of setup_argparser (...) ---
def reset ( self, soft=True ):
- super ( DepresConsoleInterpreter, self ).reset ( soft=soft )
+ ConsoleInterpreter.reset ( self, soft=soft )
if not soft:
self.interface.discard_pools()
@@ -54,18 +112,21 @@ class DepresConsoleInterpreter (
* resolve R
* resolve fftw 3.2
"""
- if line:
- ret = self.interface.resolve ( line )
+ depstr = unquote ( line )
+ if depstr:
+ ret = self.interface.resolve ( depstr )
if ret is None:
- sys.stdout.write ( "{!r} could not be resolved.\n".format ( line ) )
+ sys.stdout.write (
+ "{!r} could not be resolved.\n".format ( depstr )
+ )
elif not ret:
sys.stdout.write (
- "{!r} has been resolved as nothing(?)\n".format ( line )
+ "{!r} has been resolved as nothing(?)\n".format ( depstr )
)
elif len ( ret ) == 1:
sys.stdout.write (
"{!r} has been resolved as {}.\n".format (
- line, (
+ depstr, (
ret[0].dep if ( ret[0] and ret[0].dep is not None )
else "<ignored>"
)
@@ -74,7 +135,7 @@ class DepresConsoleInterpreter (
else:
sys.stdout.write (
"{!r} has been resolved as {}.\n".format (
- line, ( ', '.join ( str ( dep ) for dep in ret ) )
+ depstr, ( ', '.join ( str ( dep ) for dep in ret ) )
)
)
else:
@@ -87,8 +148,20 @@ class DepresConsoleInterpreter (
# --- end of do_add_pool (...) ---
def do_unwind_pool ( self, line ):
- """Removes the topmost rule pool."""
- if self.interface.discard_pool():
+ """Removes the topmost rule pool. See --help for usage."""
+ args = self.parse_cmdline ( "unwind_pool", line )
+
+ if args is None:
+ pass
+ elif args.all:
+ count = self.interface.discard_all_pools()
+ if count == 0:
+ sys.stdout.write ( "resolver has no pools.\n" )
+ else:
+ sys.stdout.write (
+ "{:d} pools have been removed.\n".format ( count )
+ )
+ elif self.interface.discard_pool():
sys.stdout.write ( "pool has been removed.\n" )
else:
sys.stdout.write ( "resolver has no pools.\n" )
@@ -116,28 +189,92 @@ class DepresConsoleInterpreter (
# --- end of do_add_rule (...) ---
def do_print_pool ( self, line ):
- """Prints the topmost pool (TODO:: or all)."""
- sys.stdout.write ( self.interface.visualize_pool() )
- sys.stdout.write ( "\n" )
+ """Prints the topmost pool. See --help for usage."""
+ args = self.parse_cmdline ( "print_pool", line )
+ if args is not None:
+ if args.all:
+ sys.stdout.write ( self.interface.visualize_pools() )
+ elif args.pools:
+ sys.stdout.write ( self.interface.visualize_pools ( args.pools ) )
+ else:
+ sys.stdout.write ( self.interface.visualize_pool() )
+
+ sys.stdout.write ( "\n" )
# --- end of do_print_pool (...) ---
def do_print ( self, line ):
- """Prints the topmost pool (TODO:: or all)."""
+ """Prints the topmost pool. See --help for usage."""
return self.do_print_pool ( line )
# --- end of do_print (...) ---
def do_load_conf ( self, line ):
- """Load configured dependency rule files."""
+ """Load configured dependency rule files. See --help for usage."""
self.interface.discard_empty_pools()
if not self.interface.load_rules_from_config ( ignore_missing=True ):
sys.stderr.write ( "failed to load rule files!\n" )
-
# --- end of do_load_conf (...) ---
+ def complete_load ( self, *args, **kw ):
+ return self.complete_fspath ( *args, **kw )
+ # --- end of complete_load (...) ---
+
+ def do_load ( self, line ):
+ """Loads a dependency rule file.
+
+ Usage: load <file|dir>
+
+ See --help for detailed usage.
+ """
+ self.interface.discard_empty_pools()
+
+ args = self.parse_cmdline ( "load", line )
+ if args and args.files:
+ if not self.interface.load_rule_files (
+ args.files, ignore_missing=True
+ ):
+ sys.stderr.write (
+ "failed to load rule file {!r}\n".format ( line )
+ )
+ # --- end of do_load (...) ---
+
+ def complete_write ( self, text, *args, **kw ):
+ return self.complete_fspath ( text, *args, **kw )
+ # --- end of complete_write (...) ---
+
+ def do_write ( self, line ):
+ """Exports the rules of the topmost rule pool into a file.
+ See --help for usage."""
+ args = self.parse_cmdline ( "write", line )
+ if args and args.outfile and args.outfile[0]:
+ outfile = self.get_fspath ( args.outfile[0] )
+ if args.force or not os.path.exists ( outfile ):
+ try:
+ output = (
+ self.interface.visualize_pools() if args.all
+ else self.interface.visualize_pool()
+ )
+ with open ( outfile, 'wt' ) as FH:
+ FH.write ( output )
+ FH.write ( '\n' )
+ except Exception as err:
+ sys.stderr.write ( "write failed: {}\n".format ( err ) )
+ else:
+ self.set_lastarg ( outfile )
+ sys.stdout.write ( "wrote {!r}\n".format ( outfile ) )
+ else:
+ sys.stderr.write ( "cannot write {!r}: exists\n".format ( outfile ) )
+ else:
+ sys.stderr.write ( "nothing written!\n" )
+ # --- end of do_write (...) ---
+
+# --- end of DepresConsoleInterpreter ---
class DepresConsole ( roverlay.console.base.MainConsole ):
INTERPRETER_CLS = DepresConsoleInterpreter
def get_interface ( self ):
return self.root_interface.spawn_interface ( "depres" )
+ # --- end of get_interface (...) ---
+
+# --- end of DepresConsole ---
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/console/
2013-07-19 18:00 [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/console/ André Erdmann
@ 2013-07-23 7:51 ` André Erdmann
0 siblings, 0 replies; 5+ messages in thread
From: André Erdmann @ 2013-07-23 7:51 UTC (permalink / raw
To: gentoo-commits
commit: 3437297b76c1c711207e45e73534c98493a65c80
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 19 17:46:35 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 19 17:46:35 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=3437297b
roverlay/console/base: close(), accept config
---
roverlay/console/base.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/roverlay/console/base.py b/roverlay/console/base.py
index ca3c7a0..acd4ca0 100644
--- a/roverlay/console/base.py
+++ b/roverlay/console/base.py
@@ -34,8 +34,12 @@ class MainConsole ( RoverlayConsole ):
return self.config is not None
# --- end of has_config (...) ---
- def setup ( self, config_file ):
- self.root_interface.setup ( config_file )
+ def close ( self ):
+ self.root_interface.close()
+ # --- end of close (...) ---
+
+ def setup ( self, config_file=None, config=None ):
+ self.root_interface.setup ( config_file=config_file, config=config )
self.config = self.root_interface.config
self.interface = self.get_interface()
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2013-07-23 7:51 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-19 18:00 [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/console/ André Erdmann
2013-07-23 7:51 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
-- strict thread matches above, loose matches on Subject: below --
2013-07-23 7:51 André Erdmann
2013-07-18 19:25 ` [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-23 7:51 [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-19 18:00 ` [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-23 7:51 [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-19 18:00 ` [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox