13. Pypsi Demo ShellΒΆ
The source code for this file is located in /demo.py
. The code is provided
as an example of the overarching Pypsi design and API. The demo shell can be
used as a skeleton for new shells and can be easily modified.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | #
# Copyright (c) 2015, Adam Meily <meily.adam@gmail.com>
# Pypsi - https://github.com/ameily/pypsi
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
'''
This is an example Pypsi shell using several key features of the Pypsi API and
architecture. The code is provided as an example of the overarching Pypsi design
and API. The demo shell can be used as a skeleton for new shells and can be
easily modified.
'''
from pypsi.shell import Shell
from pypsi.core import Command
from pypsi.plugins.cmd import CmdPlugin
from pypsi.plugins.block import BlockPlugin
from pypsi.plugins.hexcode import HexCodePlugin
from pypsi.commands.macro import MacroCommand
from pypsi.commands.system import SystemCommand
from pypsi.plugins.multiline import MultilinePlugin
from pypsi.commands.xargs import XArgsCommand
from pypsi.commands.exit import ExitCommand
from pypsi.plugins.variable import VariablePlugin
from pypsi.plugins.history import HistoryPlugin
from pypsi.plugins.alias import AliasPlugin
from pypsi.commands.echo import EchoCommand
from pypsi.commands.include import IncludeCommand
from pypsi.commands.help import HelpCommand, Topic
from pypsi.commands.tip import TipCommand
from pypsi.commands.tail import TailCommand
from pypsi.commands.chdir import ChdirCommand
from pypsi.commands.pwd import PwdCommand
from pypsi.plugins.comment import CommentPlugin
from pypsi import wizard as wiz
from pypsi.format import Table, Column, title_str
from pypsi.completers import path_completer
from pypsi.ansi import AnsiCodes
from pypsi import topics
from pypsi.os import find_bins_in_path
import sys
ShellTopic = """These commands are built into the Pypsi shell (all glory and honor to the pypsi shell).
This is a single newline
and This is a double"""
class WizardCommand(Command):
'''
Simple command to launch an example configuration wizard.
'''
def __init__(self, name='wizard', **kwargs):
super(WizardCommand, self).__init__(name=name, **kwargs)
def run(self, shell, args):
ns = ConfigWizard.run(shell)
if ns:
print()
# Create a table with optimally sized columns.
Table(
columns=(
# FIrst column is the configuration ID. This column will be
# the minimum width possible without wrapping
Column('Config ID', Column.Shrink),
# Second column is the configuration value. This column will
# grow to a maximum width possible.
Column('Config Value', Column.Grow)
),
# Number of spaces between each column.
spacing=4
).extend(
# Each tuple is a row
('ip_addr', ns.ip_addr),
('port', ns.port),
('path', ns.path),
('mode', ns.mode)
).write(sys.stdout) # Write the table to stdout
else:
pass
return 0
ConfigWizard = wiz.PromptWizard(
name="Example Configuration",
description="Shows various examples of wizard steps",
steps=(
# The list of input prompts to ask the user.
wiz.WizardStep(
# ID where the value will be stored
id="ip_addr",
# Display name
name="IP Address",
# Help message
help="Local IP Address or Host name",
# List of validators to run on the input
validators=(wiz.required_validator, wiz.hostname_or_ip_validator)
),
wiz.WizardStep(
id='port',
name="TCP Port",
help="TCP port to listen on",
validators=(wiz.required_validator, wiz.int_validator(1024, 65535)),
default=1337
),
wiz.WizardStep(
id='path',
name='File path',
help='File path to log file',
validators=wiz.file_validator,
# Tab complete based on path
completer=path_completer
),
wiz.WizardStep(
id='mode',
name='Shell mode',
help='Mode of the shell',
default='local',
validators=(wiz.required_validator, wiz.choice_validator(['local', 'remote']))
)
)
)
class DemoShell(Shell):
'''
Example demonstration shell.
'''
# First, add commands and plugins to the shell
wizard_cmd = WizardCommand()
echo_cmd = EchoCommand()
block_plugin = BlockPlugin()
hexcode_plugin = HexCodePlugin()
macro_cmd = MacroCommand()
# Drop commands to cmd.exe if the platform is Windows
system_cmd = SystemCommand(use_shell=(sys.platform == 'win32'))
ml_plugin = MultilinePlugin()
xargs_cmd = XArgsCommand()
exit_cmd = ExitCommand()
history_plugin = HistoryPlugin()
include_cmd = IncludeCommand()
cmd_plugin = CmdPlugin(cmd_args=1)
tip_cmd = TipCommand()
tail_cmd = TailCommand()
help_cmd = HelpCommand()
var_plugin = VariablePlugin(case_sensitive=False, env=False)
comment_plugin = CommentPlugin()
chdir_cmd = ChdirCommand()
pwd_cmd = PwdCommand()
alias_plugin = AliasPlugin()
def __init__(self):
# You must call the Shell.__init__() method.
super(DemoShell, self).__init__()
try:
# Attempt to load tips
self.tip_cmd.load_tips("./demo-tips.txt")
except:
self.error("failed to load tips file: demo-tips.txt")
try:
# Attempt to load the message of the day (MOTD)
self.tip_cmd.load_motd("./demo-motd.txt")
except:
self.error("failed to load message of the day file: demo-motd.txt")
self.prompt = "{gray}[$time]{r} {cyan}pypsi{r} {green})>{r} ".format(
gray=AnsiCodes.gray.prompt(), r=AnsiCodes.reset.prompt(),
cyan=AnsiCodes.cyan.prompt(), green=AnsiCodes.green.prompt()
)
self.fallback_cmd = self.system_cmd
# Register the shell topic for the help command
self.help_cmd.add_topic(self, Topic("shell", "Builtin Shell Commands"))
# Add the I/O redirection topic
self.help_cmd.add_topic(self, topics.IoRedirection)
self._sys_bins = None
def on_cmdloop_begin(self):
print(AnsiCodes.clear_screen)
if self.tip_cmd.motd:
self.tip_cmd.print_motd(self)
print()
else:
print("No tips registered. Create the demo-tips.txt file for the tip of the day.")
if self.tip_cmd.tips:
print(AnsiCodes.green, "Tip of the Day".center(self.width), sep='')
print('>' * self.width, AnsiCodes.reset, sep='')
self.tip_cmd.print_random_tip(self, False)
print(AnsiCodes.green, '<' * self.width, AnsiCodes.reset, sep='')
print()
else:
print("To see the message of the day. Create the demo-motd.txt file for the MOTD.")
############################################################################
# This functions demonstrate that existing Python :mod:`cmd` shell commands
# work without modification in Pypsi.
############################################################################
def do_cmddoc(self, args):
'''
This is some long description for the cmdargs command.
'''
print("do_cmdargs(", args, ")")
return 0
def help_cmdout(self):
print("this is the help message for the cmdout command")
def do_cmdout(self, args):
print("do_cmdout(", args, ")")
return 0
def get_command_name_completions(self, prefix):
if not self._sys_bins:
self._sys_bins = find_bins_in_path()
return sorted(
[name for name in self.commands if name.startswith(prefix)] +
[name for name in self._sys_bins if name.startswith(prefix)]
)
if __name__ == '__main__':
shell = DemoShell()
rc = shell.cmdloop()
sys.exit(rc)
|