summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Minar <miminar@redhat.com>2014-04-22 15:19:56 +0200
committerMichal Minar <miminar@redhat.com>2014-04-24 09:58:44 +0200
commit2a78da4f98a583a382c553f2e1fc68299210e7d5 (patch)
tree53029ae0a8474a9ddc464419da7337d0d88dea13
parent9138628a62461fd8914d5b82ec6a4ace964a4b2b (diff)
downloadopenlmi-scripts-2a78da4f98a583a382c553f2e1fc68299210e7d5.tar.gz
openlmi-scripts-2a78da4f98a583a382c553f2e1fc68299210e7d5.tar.xz
openlmi-scripts-2a78da4f98a583a382c553f2e1fc68299210e7d5.zip
moved lmi meta-command to openlmi-tools repository
-rw-r--r--Changelog67
-rw-r--r--Makefile8
-rwxr-xr-xcompletion/lmi-bash-completion/commands/_help9
-rwxr-xr-xcompletion/lmi-bash-completion/print_possible_commands.sh11
-rw-r--r--completion/lmi.bash65
-rw-r--r--config/lmi.conf66
-rw-r--r--doc/Makefile236
-rw-r--r--doc/README.md39
-rw-r--r--doc/_static/imode-tree.svg605
-rw-r--r--doc/_static/logicalfile.class.violet556
-rw-r--r--doc/_static/logicalfile.pngbin32696 -> 0 bytes
-rwxr-xr-xdoc/build-with-sphinx.sh34
-rw-r--r--doc/command-classes.rst163
-rw-r--r--doc/command-properties.rst574
-rw-r--r--doc/conf.py.skel290
-rw-r--r--doc/configuration.rst175
-rwxr-xr-xdoc/gendoc.sh70
-rw-r--r--doc/index.rst25
-rw-r--r--doc/make.bat190
-rw-r--r--doc/mylf/README.md7
-rw-r--r--doc/mylf/doc/Makefile177
-rw-r--r--doc/mylf/doc/cmdline.rst6
-rw-r--r--doc/mylf/doc/conf.py285
-rw-r--r--doc/mylf/doc/index.rst24
-rw-r--r--doc/mylf/doc/make.bat190
-rw-r--r--doc/mylf/lmi/__init__.py27
-rw-r--r--doc/mylf/lmi/scripts/__init__.py27
-rw-r--r--doc/mylf/lmi/scripts/mylf/__init__.py191
-rw-r--r--doc/mylf/lmi/scripts/mylf/cmd.py100
-rw-r--r--doc/mylf/setup.py44
-rw-r--r--doc/script-development.rst668
-rw-r--r--doc/script-tutorial.rst447
-rw-r--r--doc/usage.rst133
-rw-r--r--lmi/__init__.py30
-rw-r--r--lmi/scripts/__init__.py30
-rw-r--r--lmi/scripts/_metacommand/__init__.py239
-rw-r--r--lmi/scripts/_metacommand/cmdutil.py68
-rw-r--r--lmi/scripts/_metacommand/exit.py74
-rw-r--r--lmi/scripts/_metacommand/help.py101
-rw-r--r--lmi/scripts/_metacommand/interactive.py475
-rw-r--r--lmi/scripts/_metacommand/manager.py182
-rw-r--r--lmi/scripts/_metacommand/toplevel.py184
-rw-r--r--lmi/scripts/_metacommand/util.py264
-rw-r--r--lmi/scripts/common/__init__.py73
-rw-r--r--lmi/scripts/common/command/__init__.py50
-rw-r--r--lmi/scripts/common/command/base.py341
-rw-r--r--lmi/scripts/common/command/checkresult.py140
-rw-r--r--lmi/scripts/common/command/endpoint.py367
-rw-r--r--lmi/scripts/common/command/helper.py137
-rw-r--r--lmi/scripts/common/command/lister.py176
-rw-r--r--lmi/scripts/common/command/meta.py839
-rw-r--r--lmi/scripts/common/command/multiplexer.py155
-rw-r--r--lmi/scripts/common/command/select.py195
-rw-r--r--lmi/scripts/common/command/session.py206
-rw-r--r--lmi/scripts/common/command/show.py112
-rw-r--r--lmi/scripts/common/command/util.py109
-rw-r--r--lmi/scripts/common/configuration.py311
-rw-r--r--lmi/scripts/common/errors.py140
-rw-r--r--lmi/scripts/common/formatter/__init__.py484
-rw-r--r--lmi/scripts/common/formatter/command.py71
-rw-r--r--lmi/scripts/common/lmi_logging.py256
-rw-r--r--lmi/scripts/common/session.py190
-rw-r--r--lmi/scripts/common/util.py146
-rw-r--r--lmi/scripts/common/versioncheck/__init__.py146
-rw-r--r--lmi/scripts/common/versioncheck/parser.py521
-rw-r--r--man/Makefile14
-rwxr-xr-xman/generate.sh199
-rw-r--r--man/lmi.1201
-rw-r--r--setup.cfg2
-rw-r--r--setup.py.skel71
-rw-r--r--test/README.md32
-rw-r--r--test/base.sh51
-rw-r--r--test/cmd/help_foo.out6
-rw-r--r--test/cmd/help_help.out4
-rw-r--r--test/cmd/help_test.out7
-rw-r--r--test/cmd/help_test_list.out5
-rw-r--r--test/cmd/help_with_test.out6
-rw-r--r--test/cmd/help_without_test.out5
-rw-r--r--test/cmdver/README.md1
-rw-r--r--test/cmdver/lmi/__init__.py27
-rw-r--r--test/cmdver/lmi/scripts/__init__.py27
-rw-r--r--test/cmdver/lmi/scripts/cmdver/__init__.py135
-rw-r--r--test/cmdver/lmi/scripts/cmdver/devel.py32
-rw-r--r--test/cmdver/lmi/scripts/cmdver/pre042.py32
-rw-r--r--test/cmdver/lmi/scripts/cmdver/swbase.py51
-rw-r--r--test/cmdver/lmi/scripts/cmdver/ver042.py32
-rw-r--r--test/cmdver/setup.py48
-rw-r--r--test/imode/builtin_help.out15
-rw-r--r--test/imode/cd_test.exp69
-rw-r--r--test/imode/complete_builtin.exp37
-rw-r--r--test/imode/completion.exp54
-rw-r--r--test/imode/empty_lines.exp26
-rw-r--r--test/imode/empty_lines.out1
-rw-r--r--test/imode/empty_lines.txt6
-rw-r--r--test/imode/eof.exp21
-rw-r--r--test/imode/exit.exp20
-rw-r--r--test/imode/help.out13
-rw-r--r--test/imode/help_exit.out3
-rw-r--r--test/imode/help_foo.out14
-rw-r--r--test/imode/help_help.out4
-rw-r--r--test/imode/help_test.out7
-rw-r--r--test/imode/lmi_test_help.out6
-rw-r--r--test/imode/run_test_cmd.exp39
-rw-r--r--test/imode/test_builtin_help.txt2
-rw-r--r--test/imode/test_help.out10
-rw-r--r--test/imode/test_help.txt2
-rw-r--r--test/imode/test_help_exit.txt2
-rw-r--r--test/imode/test_help_list.out5
-rw-r--r--test/imode/test_help_list.txt2
-rw-r--r--test/imode/test_help_show.out7
-rw-r--r--test/imode/test_help_show.txt2
-rw-r--r--test/imode/test_list_opt_help.out5
-rw-r--r--test/imode/test_opt_help.out7
-rw-r--r--test/logging/defaults.conf1
-rw-r--r--test/logging/log_all_debug.file9
-rw-r--r--test/logging/log_all_debug.stderr9
-rw-r--r--test/logging/log_all_debug.stdout3
-rw-r--r--test/logging/log_all_debug_notrace.stdout2
-rw-r--r--test/logging/log_all_default.stdout0
-rw-r--r--test/logging/log_all_error.stderr2
-rw-r--r--test/logging/log_all_info.stderr5
-rw-r--r--test/logging/log_all_info.stdout2
-rw-r--r--test/logging/log_all_silent.stdout2
-rw-r--r--test/logging/log_all_warn.file4
-rw-r--r--test/logging/log_all_warn.stderr4
-rwxr-xr-xtest/run.sh38
-rw-r--r--test/subcmd/lmi/__init__.py30
-rw-r--r--test/subcmd/lmi/scripts/__init__.py30
-rw-r--r--test/subcmd/lmi/scripts/cmdtest/__init__.py210
-rw-r--r--test/subcmd/setup.py36
-rw-r--r--test/test_cmd.sh172
-rw-r--r--test/test_imode.sh270
-rw-r--r--test/test_logging.sh249
-rw-r--r--test/test_unit.sh69
-rw-r--r--test/test_versioning.sh236
-rw-r--r--test/unit/test_common.py79
136 files changed, 3 insertions, 15147 deletions
diff --git a/Changelog b/Changelog
deleted file mode 100644
index 25c39d6..0000000
--- a/Changelog
+++ /dev/null
@@ -1,67 +0,0 @@
-0.2.7
-* errors handled more gracefully, they are more helpful
-* colorized error log messages
-* interactive mode won't be ended by error so easily
-* redone help command
-* help command accepts command path
-* added built-in commands - starting with ':'
-* allowed for nesting into subcommands in interactive mode
-* better tab completion
-* added formatting properties to commands
-* fixed --log-file option
-
-0.2.6
-* allow digits in command names and options
-
-0.2.5
-* terminate with exit code of the last executed command
-* exit interactive mode only on user request
-
-0.2.4
-* add get_computer_system() utility function
-* require at least lmi shell v0.8
-* correct support for lmi shell v0.8 and above
-
-0.2.3
-* made localhost a default host
-* allow to have a fallback command for command multiplexers
-* fixed rendering of instances when PROPERTIES are omitted
-
-0.2.2
-* double and single dash can now be used in usage strings
-* fixed error handling
-* improved logging of errors - handled the same way for all commands
-* added [Log] LogToConsole configuration option
-* added --notrace and --log-file options
-* logging configuration fixes
-* support for openlmi-python-base 0.2.1+
-
-0.2.1
-* compability fix for newer openlmi-tools
-* enhanced check_result() method invocation
-* fixed handling of verbosity parameter
-* fixed handling of ARG_ARRAY_SUFFIX
-
-0.2.0
-* allow embedded credentials in urls of hosts
-* allow to override default namespace from config and command line
-* added OPT_NO_UNDERSCORES property
-* commands api change: replace any sequence of characters matching [^a-z_]
-with a single underscore, when renaming options to function arguments
-* added LmiInstanceLister base command class
-* fixed exit command
-* added ARG_ARRAY_SUFFIX
-* added --same-credentials flag
-* fixed parsing of hosts file
-
-0.1.1
-* support for (non)verification of server-side certificates
-* allowed *connection* to be an argument in command usage strings
-* fixed command declaration checking
-* relicensed to BSD
-* added namespace property to end-point commands
-* associated functions invoked with namespace rather then just connection
-object
-
-0.1.0
-* initial version with dependency only on docopt
diff --git a/Makefile b/Makefile
index fbfc67e..4aadbe7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,12 @@
-include Makefile.inc
-
-COMMANDS ?= $(shell find commands -mindepth 1 -maxdepth 1 -type d)
+COMMANDS ?= $(notdir $(shell find commands -mindepth 1 -maxdepth 1 -type d))
# all rules executable on meta-command and commands
RULES := setup upload upload_docs clean develop
MASSRULES := $(foreach rule,$(RULES),$(rule)-all)
.PHONY: $(MASSRULES)
-$(MASSRULES): %-all: %
+$(MASSRULES): %-all:
# executes rule for metacommand and for all commands found
for cmd in $(COMMANDS); do \
- make -C $$cmd $*; \
+ make -C commands/$$cmd $*; \
done
diff --git a/completion/lmi-bash-completion/commands/_help b/completion/lmi-bash-completion/commands/_help
deleted file mode 100755
index ae3ed8b..0000000
--- a/completion/lmi-bash-completion/commands/_help
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-if (( $# > 1 )); then
- exit
-fi
-helpers_path=lmi-bash-completion
-if ! [[ -e $helpers_path ]]; then
- helpers_path="/usr/libexec/$helpers_path"
-fi
-compgen "-W $($helpers_path/print_possible_commands.sh)" -- "$1"
diff --git a/completion/lmi-bash-completion/print_possible_commands.sh b/completion/lmi-bash-completion/print_possible_commands.sh
deleted file mode 100755
index ba29a4a..0000000
--- a/completion/lmi-bash-completion/print_possible_commands.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-# prints possible commands
-# one per line
-# parse lmi help
-re_command="^[[:blank:]]*([[:alnum:]]+)[[:blank:]]*-"
-while IFS= read line; do
- if [[ $line =~ $re_command ]]; then
- printf '%s\n' "${BASH_REMATCH[1]}"
- fi
-done < <(lmi help 2>/dev/null)
diff --git a/completion/lmi.bash b/completion/lmi.bash
deleted file mode 100644
index c60ab9b..0000000
--- a/completion/lmi.bash
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#
-# Authors: Roman Rakus <rrakus@redhat.com>
-#
-# Bash completion for LMI commands
-
-_lmi() {
- local helpers_path="lmi-bash-completion"
- if ! [[ -e "$helpers_path" ]]; then
- helpers_path="/usr/libexec/$helpers_path"
- fi
- local options=(-c --config-file -h --host --hosts-file --user -v --trace -q --quiet -n --noverify --same-credentials --help --version)
- local current="${COMP_WORDS[$COMP_CWORD]}"
- local previous="${COMP_WORDS[COMP_CWORD-1]}"
- local commands=( $($helpers_path/print_possible_commands.sh) )
- local used_command=
-
- for (( i=1; i < ${#COMP_WORDS[@]} - 1 && i < $COMP_CWORD; i++ )); do
- for (( ci=0; ci < ${#commands[@]}; ci++ )); do
- if [[ ${COMP_WORDS[$i]} == ${commands[$ci]} ]]; then
- used_command=${commands[$ci]}
- break 2;
- fi
- done
- done
-
- if [[ $used_command ]]; then
- # Check if we have completion executable for command
- if [[ -x $helpers_path/commands/"_$used_command" ]] ; then
- # pass the rest of words typed as parameters
- COMPREPLY=( $($helpers_path/commands/_$used_command "${COMP_WORDS[@]:$((i+1))}") )
- else
- # commands without completion - filename completion
- COMPREPLY=( $(compgen -f -- "$current") )
- fi
- else
- case $current in
- -*) COMPREPLY=( $(compgen "-W ${options[*]}" -- "$current" ) );;
- *) case $previous in
- -c|--config-file|--hosts-file) COMPREPLY=( $(compgen -f -- "$current" ) );;
- -h|--host) COMPREPLY=( $(compgen -A hostname -- "$current" ) );;
- --user) COMPREPLY=( $(compgen -u -- "$current" ) );;
- --help|--version) ;;
- *) COMPREPLY=( $(compgen "-W ${commands[*]}" -- "$current" ) );;
- esac
- esac
- fi
-}
-
-complete -F _lmi lmi
diff --git a/config/lmi.conf b/config/lmi.conf
deleted file mode 100644
index 6b35fc8..0000000
--- a/config/lmi.conf
+++ /dev/null
@@ -1,66 +0,0 @@
-# Sample configuration file for OpenLMI script meta-command.
-
-[Main]
-# Python namespace, where command entry points will be searched for.
-#CommandNamespace = lmi.scripts.cmd
-
-# Whether the exceptions should be logged with tracebacks.
-#Trace = False
-
-# A number within 0-2 range saying, how verbose the output to console shall
-# be. This differs from [Log] Level, which controls the logging messages being
-# logged to file. If logging to console is enabled it sets the minimum
-# severity level. -1 Suppresses all messages except for errors. 0 shows
-# warnings, 1 info messages and 2 enables debug messages. This option also
-# affects the verbosity of commands, making them print more information to
-# stdout.
-#Verbosity = 0
-
-# Maximum number of lines stored in history file.
-#HistoryMaxLength = 4000
-
-[CIM]
-# To override default CIM namespace, uncomment the line below.
-#namespace = root/cimv2
-
-[SSL]
-# Whether to verify server-side certificate, when making secured connection
-# over ssl.
-#VerifyServerCertificate = True
-
-[Format]
-# Whether to print values in human readable forms (e.g. with units).
-#HumanFriendly = False
-
-# What format to use, when listing tabular data. Possible values are:
-# {csv, table}. The former allows for easy machine parsing, the latter
-# is more human friendly.
-#ListerFormat = table
-
-# Whether to suppress headings (column names) when printing tables.
-#NoHeadings = False
-
-[Log]
-# Level can be set to following values:
-# DEBUG, INFO, WARNING, ERROR, CRITICAL
-# Affects only logging to a file.
-#Level = ERROR
-
-# Format string used, when logging to a console. For details visit:
-# http://docs.python.org/2/library/logging.html#logrecord-attributes
-# This applies to levels more severe than INFO.
-#ConsoleFormat = %(cseq)s%(levelname)-8s:%(creset)s %(message)s
-
-# Format string used, when logging to a console. This applies to all messages
-# with severity level up to INFO.
-#ConsoleInfoFormat = %(message)s
-
-# Whether the logging to console is enabled.
-#LogToConsole = True
-
-# Format string used, when logging to a file.
-#FileFormat = %(asctime)s:%(levelname)-8s:%(name)s:%(lineno)d - %(message)s
-
-# Allows to set a path to file, where messages will be logged. No log
-# file is written at default.
-#OutputFile =
diff --git a/doc/Makefile b/doc/Makefile
deleted file mode 100644
index 0900330..0000000
--- a/doc/Makefile
+++ /dev/null
@@ -1,236 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR ?= _build
-PROJECTNAME = OpenLMIScripts
-COMMANDS_PATH ?= ../commands
-INCLUDE_COMMANDS ?= 0
-COMMANDS ?= logicalfile service software storage
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -n -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-TUTORIAL_SOURCES := mylf/*.md mylf/*.py mylf/lmi/*.py mylf/*/*.py mylf/*/*/*.py \
- mylf/doc/*.py mylf/doc/*.rst mylf/doc/Makefile mylf/doc/_static
-TUTORIAL_TARBALL := _static/mylf.tar.gz
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp \
- devhelp epub latex latexpdf text man changes linkcheck doctest gettext \
- commands.rst
-
-export COMMANDS
-export INCLUDE_COMMANDS
-
-all: html
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " singlehtml to make a single large HTML file"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " devhelp to make HTML files and a Devhelp project"
- @echo " epub to make an epub"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " texinfo to make Texinfo files"
- @echo " info to make Texinfo files and run them through makeinfo"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
-
-api.rst: gendoc.sh $(wildcard ../lmi/scripts/*.py \
- ../lmi/scripts/common/*.py \
- ../lmi/scripts/_metacommand/*.py \
- ../lmi/scripts/formatter/*.py)
- ./gendoc.sh
-
-commands.rst:
- echo "Command libraries documentation" > $@
- echo "===============================" >> $@
-ifneq ($(INCLUDE_COMMANDS), 0)
- -[ -e commands ] && rm -rf commands
- mkdir commands
- echo "Usage and developer documentations of provider libraries" >> $@
- echo "(also called *commands*.)" >> $@
- printf "\n.. toctree::\n" >> $@
- printf " :maxdepth: 2\n\n" >> $@
- for cmd in $(COMMANDS); do \
- printf " commands/$$cmd\n" >> $@; \
- ln -s ../$(COMMANDS_PATH)/$${cmd}/doc commands/$${cmd}_docdir; \
- title="$${cmd^} library"; \
- length=`echo "$$title" | wc -c`; \
- ( \
- printf "$${title}\n"; \
- printf -- "!%.0s" `seq 2 $$length`; \
- printf "\n\n"; \
- if [ -e commands/$${cmd}_docdir/cmdline.rst ]; then \
- sed "s,\(\.\.\s\+include::\s*\)\(.*\),\1$${cmd}_docdir/\2," \
- commands/$${cmd}_docdir/cmdline.rst \
- >commands/$${cmd}_cmdline.txt; \
- printf ".. include:: $${cmd}_cmdline.txt\n\n"; \
- fi; \
- printf "$${cmd^} library reference\n"; \
- printf -- "==========================\n"; \
- if [ -e commands/$${cmd}_docdir/python.rst ]; then \
- printf ".. toctree::\n :maxdepth: 2\n\n"; \
- printf " $${cmd}_docdir/python\n\n"; \
- else \
- printf ".. automodule:: lmi.scripts.$${cmd}\n"; \
- printf " :members:\n"; \
- fi; \
- ) > commands/$${cmd}.rst; \
- done
-else
- ( \
- printf "You may visit command usage and developer documentations\n"; \
- printf "on pythonhosted site:\n\n"; \
- for cmd in $(COMMANDS); do \
- printf " * \`openlmi-scripts-$${cmd}"; \
- printf " <http://pythonhosted.org/openlmi-scripts-$${cmd}>\`_\n"; \
- done \
- ) >> $@
-endif
-
-
-clean:
- -rm -rf $(BUILDDIR)/* modules/ api.rst commands.rst commands/
-ifneq ($(INCLUDE_COMMANDS), 0)
- for cmd in $(COMMANDS); do \
- make -C $(COMMANDS_PATH)/$${cmd}/doc clean; \
- done
-endif
-
-%.png: %.dia
- dia -e $@ $<
-
-%.svg: %.uml plantuml.cfg
- plantuml -config plantuml.cfg -Tsvg $<
-
-figures:
-
-$(TUTORIAL_TARBALL):
- tar -czf $@ mylf
-
-html: figures api.rst commands.rst $(TUTORIAL_TARBALL)
- ./build-with-sphinx.sh "$(COMMANDS)" -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/AnacondaStorageProvider.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/AnacondaStorageProvider.qhc"
-
-devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
- @echo
- @echo "Build finished."
- @echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/AnacondaStorageProvider"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/AnacondaStorageProvider"
- @echo "# devhelp"
-
-epub: figures api.rst commands.rst
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex: figures api.rst commands.rst
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- sed -i 's/^\\makeindex$$/\0[columns=1]/' $(BUILDDIR)/latex/$(PROJECTNAME).tex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make' in that directory to run these through (pdf)latex" \
- "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf: latex
- $(MAKE) -C $(BUILDDIR)/latex all-pdf
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo
- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
- @echo "Run \`make' in that directory to run these through makeinfo" \
- "(use \`make info' here to do that automatically)."
-
-info:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo "Running Texinfo files through makeinfo..."
- make -C $(BUILDDIR)/texinfo info
- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
- @echo
- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/README.md b/doc/README.md
deleted file mode 100644
index 12b6e95..0000000
--- a/doc/README.md
+++ /dev/null
@@ -1,39 +0,0 @@
-Documentation
-=============
-This directory contains usage and developer documentation.
-It's available online on [pythonhosted][].
-
-How to build
-------------
-Supported builds are *html*, *pdflatex* and *epub*.
-
-### Requirements
-
- * `bash`
- * `GNU make`
- * `setuptools` - provided by package `python-setuptools`
- * `sphinx-build` - provided by package `python-sphinx`
-
-### Steps
-There are two kinds of builds available. One containing documentation of `lmi`
-command libraries and one with just references to them to external sources.
-Following examples will generate only *html* documentation, to make any other
-just replace the `html` argument with prefered one.
-
-#### Including commands documentation
-
- INCLUDE_COMMANDS=1 make -C doc html
-
-#### Without commands documentation
-This build is the preferred one for Python Hosted site.
-
- make -C doc html
-
-How to upload
--------------
-First build it (see the section above).
-Then run:
-
- python setup.py upload_docs
-
-[pythonhosted]: http://pythonhosted.org/openlmi-scripts/index.html
diff --git a/doc/_static/imode-tree.svg b/doc/_static/imode-tree.svg
deleted file mode 100644
index 91c1614..0000000
--- a/doc/_static/imode-tree.svg
+++ /dev/null
@@ -1,605 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="678.85718"
- height="399.14285"
- id="svg2"
- version="1.1"
- inkscape:version="0.48.4 r9939"
- sodipodi:docname="imode-tree.svg">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="0.98994949"
- inkscape:cx="524.19771"
- inkscape:cy="224.52211"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:window-width="1920"
- inkscape:window-height="1058"
- inkscape:window-x="0"
- inkscape:window-y="0"
- inkscape:window-maximized="0"
- fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
- fit-margin-bottom="0" />
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-14.499999,-184.21933)">
- <path
- style="fill:none;stroke:#b3b3b3;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 4;stroke-dashoffset:0"
- d="m 162.85714,185.21933 0,397.14285"
- id="path4052"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- <path
- sodipodi:type="arc"
- style="fill:#ffffff;fill-opacity:1;stroke:#800000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0"
- id="path4042"
- sodipodi:cx="122.5"
- sodipodi:cy="410.57648"
- sodipodi:rx="69.64286"
- sodipodi:ry="35.357143"
- d="m 192.14286,410.57648 c 0,19.52721 -31.18017,35.35714 -69.64286,35.35714 -38.46269,0 -69.64286,-15.82993 -69.64286,-35.35714 0,-19.52721 31.18017,-35.35715 69.64286,-35.35715 38.46269,0 69.64286,15.82994 69.64286,35.35715 z"
- transform="translate(35.714286,-14.285714)" />
- <g
- id="g3003"
- transform="translate(0,0.71427917)">
- <rect
- ry="17.857143"
- y="230.21933"
- x="14.999999"
- height="35.714287"
- width="137.85715"
- id="rect2985"
- style="fill:#ffe680;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <text
- sodipodi:linespacing="125%"
- id="text2999"
- y="253.59406"
- x="41.628769"
- style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- xml:space="preserve"><tspan
- y="253.59406"
- x="41.628769"
- id="tspan3001"
- sodipodi:role="line">TopLevel</tspan></text>
- </g>
- <g
- id="g3033"
- transform="translate(-41.20703,-4.2857208)">
- <rect
- style="fill:#ffaaaa;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="rect3024"
- width="137.85715"
- height="35.714287"
- x="215"
- y="235.21933"
- ry="17.857143" />
- <text
- xml:space="preserve"
- style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="244.661"
- y="258.41827"
- id="text3026"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3028"
- x="244.661"
- y="258.41827">Storage</tspan></text>
- </g>
- <g
- id="g4032"
- transform="translate(0.22154353,20)">
- <rect
- ry="17.857143"
- y="463.07648"
- x="173.57143"
- height="35.714287"
- width="137.85715"
- id="rect3040"
- style="fill:#ffaaaa;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <text
- sodipodi:linespacing="125%"
- id="text3042"
- y="488.38968"
- x="198.27148"
- style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- xml:space="preserve"><tspan
- y="488.38968"
- x="198.27148"
- id="tspan3044"
- sodipodi:role="line">Software</tspan></text>
- </g>
- <text
- xml:space="preserve"
- style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono"
- x="46.047226"
- y="290.93359"
- id="text3049"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3051"
- x="46.047226"
- y="290.93359">lmi&gt; :pwd</tspan><tspan
- sodipodi:role="line"
- x="46.047226"
- y="308.43359"
- id="tspan3053">/lmi</tspan></text>
- <text
- sodipodi:linespacing="125%"
- id="text3055"
- y="290.93359"
- x="183.97691"
- style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono"
- xml:space="preserve"><tspan
- y="290.93359"
- x="183.97691"
- id="tspan3057"
- sodipodi:role="line"
- style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono">&gt;storage&gt; :pwd</tspan><tspan
- id="tspan3059"
- y="308.43359"
- x="183.97691"
- sodipodi:role="line"
- style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono">/lmi/storage</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono"
- x="183.97691"
- y="542.18982"
- id="text3061"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3063"
- x="183.97691"
- y="542.18982">&gt;sw&gt; :pwd</tspan><tspan
- sodipodi:role="line"
- x="183.97691"
- y="559.68982"
- id="tspan3065">/lmi/sw</tspan></text>
- <g
- id="g3078"
- transform="translate(-71.821487,-5)">
- <rect
- ry="17.857143"
- y="235.93361"
- x="415.71426"
- height="35.714287"
- width="137.85715"
- id="rect3069"
- style="fill:#ffaaaa;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <text
- sodipodi:linespacing="125%"
- id="text3071"
- y="261.2468"
- x="450.17505"
- style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- xml:space="preserve"><tspan
- y="261.2468"
- x="450.17505"
- id="tspan3073"
- sodipodi:role="line">LVCmd</tspan></text>
- </g>
- <g
- id="g4037"
- transform="translate(-8.9643402,2.1428265)">
- <rect
- style="fill:#ffaaaa;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="rect3085"
- width="137.85715"
- height="35.714287"
- x="352.85712"
- y="320.93362"
- ry="17.857143" />
- <text
- xml:space="preserve"
- style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="374.60309"
- y="346.24683"
- id="text3087"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3089"
- x="374.60309"
- y="346.24683">RAIDCmd</tspan></text>
- </g>
- <g
- id="g4027"
- transform="translate(-7.5357819,0)">
- <rect
- ry="17.857143"
- y="422.36218"
- x="351.42856"
- height="35.714287"
- width="137.85715"
- id="rect3101"
- style="fill:#a8dbff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <text
- sodipodi:linespacing="125%"
- id="text3103"
- y="447.67538"
- x="377.3493"
- style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- xml:space="preserve"><tspan
- y="447.67538"
- x="377.3493"
- id="tspan3105"
- sodipodi:role="line">TreeCmd</tspan></text>
- </g>
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- x="65.21373"
- y="198.29857"
- id="text3886"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3888"
- x="65.21373"
- y="198.29857">Root</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- x="198.54967"
- y="198.79076"
- id="text3890"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3892"
- x="198.54967"
- y="198.79076">Registered</tspan><tspan
- sodipodi:role="line"
- x="198.54967"
- y="218.79076"
- id="tspan3894">commands</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- x="350.43854"
- y="198.79076"
- id="text3896"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3898"
- x="350.43854"
- y="198.79076">Sub-commands</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono"
- x="337.14752"
- y="290.93359"
- id="text3900"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3902"
- x="337.14752"
- y="290.93359">&gt;&gt;lv&gt; :pwd</tspan><tspan
- sodipodi:role="line"
- x="337.14752"
- y="308.43359"
- id="tspan3904">/lmi/storage/lv</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono"
- x="337.14752"
- y="385.93359"
- id="text3906"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3908"
- x="337.14752"
- y="385.93359">&gt;&gt;raid&gt; :pwd</tspan><tspan
- sodipodi:role="line"
- x="337.14752"
- y="403.43359"
- id="tspan3910">/lmi/storage/raid</tspan></text>
- <path
- style="fill:none;stroke:#808080;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0"
- d="M 245.57868,275.21932 194.8644,359.50503"
- id="path3916"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- <path
- style="fill:none;stroke:#808080;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0"
- d="M 362.85714,273.79075 C 360,275.93361 221.42858,372.36218 221.42858,372.36218"
- id="path3918"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- <path
- style="fill:none;stroke:#808080;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0"
- d="m 349.28571,350.21932 c -1.42857,2.85715 -117.85714,33.57144 -117.85714,33.57144"
- id="path3920"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- <path
- style="fill:none;stroke:#808080;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0"
- d="M 225.57868,478.79076 194.8644,432.36217"
- id="path3924"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- <g
- id="g3992"
- transform="translate(-41.428572,0)">
- <rect
- style="fill:#a8dbff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="rect3878"
- width="137.85715"
- height="35.714287"
- x="546.42859"
- y="230.93361"
- ry="17.857143" />
- <text
- sodipodi:linespacing="125%"
- id="text3929"
- y="256.2468"
- x="597.1394"
- style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- xml:space="preserve"><tspan
- y="256.2468"
- x="597.1394"
- id="tspan3931"
- sodipodi:role="line">List</tspan></text>
- </g>
- <g
- id="g3997"
- transform="translate(-40.000044,1.4285889)">
- <rect
- ry="17.857143"
- y="275.21933"
- x="545.00006"
- height="35.714287"
- width="137.85715"
- id="rect3880"
- style="fill:#a8dbff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <text
- sodipodi:linespacing="125%"
- id="text3933"
- y="300.35675"
- x="580.63763"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- xml:space="preserve"><tspan
- style="font-size:20px"
- y="300.35675"
- x="580.63763"
- id="tspan3935"
- sodipodi:role="line">Create</tspan></text>
- </g>
- <g
- id="g4002"
- transform="translate(-38.571455,2.1428265)">
- <rect
- style="fill:#a8dbff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="rect3882"
- width="137.85715"
- height="35.714287"
- x="543.57147"
- y="320.93362"
- ry="17.857143" />
- <text
- sodipodi:linespacing="125%"
- id="text3937"
- y="346.24683"
- x="594.28229"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- xml:space="preserve"><tspan
- style="font-size:20px"
- y="346.24683"
- x="594.28229"
- id="tspan3939"
- sodipodi:role="line">List</tspan></text>
- </g>
- <g
- id="g4007"
- transform="translate(-38.571455,0)">
- <rect
- ry="17.857143"
- y="368.07648"
- x="543.57147"
- height="35.714287"
- width="137.85715"
- id="rect3884"
- style="fill:#a8dbff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <text
- sodipodi:linespacing="125%"
- id="text3941"
- y="393.38968"
- x="579.19928"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- xml:space="preserve"><tspan
- style="font-size:20px"
- y="393.38968"
- x="579.19928"
- id="tspan3943"
- sodipodi:role="line">Delete</tspan></text>
- </g>
- <path
- style="fill:none;stroke:#808080;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0"
- d="m 491.42857,441.64789 56.42857,0"
- id="path3968"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- <g
- id="g4022"
- transform="translate(-14.100082,20)">
- <rect
- style="fill:#ffaaaa;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="rect3972"
- width="137.85715"
- height="35.714287"
- x="357.99286"
- y="463.07648"
- ry="17.857143" />
- <text
- sodipodi:linespacing="125%"
- id="text3974"
- y="486.4512"
- x="373.05426"
- style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- xml:space="preserve"><tspan
- y="486.4512"
- x="373.05426"
- id="tspan3976"
- sodipodi:role="line">Repository</tspan></text>
- </g>
- <g
- id="g4012"
- transform="translate(-36.428572,1.4285579)">
- <rect
- style="fill:#a8dbff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="rect3980"
- width="137.85715"
- height="35.714287"
- x="541.42859"
- y="481.64792"
- ry="17.857143" />
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- x="575.82593"
- y="506.96112"
- id="text3982"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3984"
- x="575.82593"
- y="506.96112"
- style="font-size:20px">Enable</tspan></text>
- </g>
- <g
- id="g4017"
- transform="translate(-36.428572,2.1428571)">
- <rect
- ry="17.857143"
- y="528.79077"
- x="541.42859"
- height="35.714287"
- width="137.85715"
- id="rect3986"
- style="fill:#a8dbff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <text
- sodipodi:linespacing="125%"
- id="text3988"
- y="554.10394"
- x="572.81812"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- xml:space="preserve"><tspan
- style="font-size:20px"
- y="554.10394"
- x="572.81812"
- id="tspan3990"
- sodipodi:role="line">Disable</tspan></text>
- </g>
- <text
- xml:space="preserve"
- style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- x="101.7055"
- y="401.48608"
- id="text3912"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3914"
- x="101.7055"
- y="401.48608"
- style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">multiplexers</tspan></text>
- <path
- inkscape:connector-curvature="0"
- id="path4054"
- d="m 327.85714,185.21933 0,397.14285"
- style="fill:none;stroke:#b3b3b3;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 4;stroke-dashoffset:0"
- sodipodi:nodetypes="cc" />
- <g
- id="g4058">
- <path
- sodipodi:type="arc"
- style="fill:#ffffff;fill-opacity:1;stroke:#800000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0"
- id="path4056"
- sodipodi:cx="122.5"
- sodipodi:cy="410.57648"
- sodipodi:rx="69.64286"
- sodipodi:ry="35.357143"
- d="m 192.14286,410.57648 c 0,19.52721 -31.18017,35.35714 -69.64286,35.35714 -38.46269,0 -69.64286,-15.82993 -69.64286,-35.35714 0,-19.52721 31.18017,-35.35715 69.64286,-35.35715 38.46269,0 69.64286,15.82994 69.64286,35.35715 z"
- transform="translate(500.71429,32.857143)" />
- <text
- sodipodi:linespacing="125%"
- id="text3912-0"
- y="438.43362"
- x="573.19476"
- style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Terminus"
- xml:space="preserve"><tspan
- style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
- y="438.43362"
- x="573.19476"
- id="tspan3914-9"
- sodipodi:role="line">end point</tspan><tspan
- id="tspan3966"
- style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
- y="463.43362"
- x="573.19476"
- sodipodi:role="line">commands</tspan></text>
- </g>
- <path
- sodipodi:nodetypes="cc"
- inkscape:connector-curvature="0"
- id="path4064"
- d="M 542.14286,407.36217 555,423.07646"
- style="fill:none;stroke:#808080;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0" />
- <path
- style="fill:none;stroke:#808080;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0"
- d="m 545.00001,478.79074 13.57142,-13.57143"
- id="path4066"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- <text
- sodipodi:linespacing="125%"
- id="text4068"
- y="540.57654"
- x="337.14752"
- style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono"
- xml:space="preserve"><tspan
- y="540.57654"
- x="337.14752"
- id="tspan4070"
- sodipodi:role="line">&gt;&gt;repo&gt; :pwd</tspan><tspan
- id="tspan4072"
- y="558.07654"
- x="337.14752"
- sodipodi:role="line">/lmi/software/repo</tspan></text>
- <path
- sodipodi:nodetypes="cc"
- inkscape:connector-curvature="0"
- id="path4074"
- d="M 337.00725,484.50505 228.43583,416.64789"
- style="fill:none;stroke:#808080;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0" />
- </g>
-</svg>
diff --git a/doc/_static/logicalfile.class.violet b/doc/_static/logicalfile.class.violet
deleted file mode 100644
index 4df1546..0000000
--- a/doc/_static/logicalfile.class.violet
+++ /dev/null
@@ -1,556 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<java version="1.7.0_60" class="java.beans.XMLDecoder">
- <object class="com.horstmann.violet.ClassDiagramGraph">
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode0">
- <void property="name">
- <void property="text">
- <string>LMI_DataFile</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double0">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double0"/>
- <double>1016.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double0"/>
- <double>330.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>1016.0</double>
- <double>330.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode1">
- <void property="attributes">
- <void property="text">
- <string>CIM_Directory REF GroupComponent
-CIM_LogicalFile REF PartComponent</string>
- </void>
- </void>
- <void property="name">
- <void property="text">
- <string>LMI_DirectoryContainsFile</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double1">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double1"/>
- <double>407.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double1"/>
- <double>239.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>407.0</double>
- <double>239.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode2">
- <void property="name">
- <void property="text">
- <string>LMI_FIFOPipeFile</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double2">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double2"/>
- <double>742.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double2"/>
- <double>430.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>742.0</double>
- <double>430.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode3">
- <void property="attributes">
- <void property="text">
- <string>CIM_ManagedElement REF SameElement
-CIM_ManagedElement REF SystemElement</string>
- </void>
- </void>
- <void property="name">
- <void property="text">
- <string>LMI_FileIdentity</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double3">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double3"/>
- <double>676.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double3"/>
- <double>56.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>676.0</double>
- <double>56.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode4">
- <void property="attributes">
- <void property="text">
- <string>CIM_ManagedElement REF GroupComponent
-LMI_UnixDirectory REF PartComponent</string>
- </void>
- </void>
- <void property="name">
- <void property="text">
- <string>LMI_RootDirectory</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double4">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double4"/>
- <double>128.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double4"/>
- <double>418.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>128.0</double>
- <double>418.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode5">
- <void property="name">
- <void property="text">
- <string>LMI_SymbolicLink</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double5">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double5"/>
- <double>923.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double5"/>
- <double>431.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>923.0</double>
- <double>431.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode6">
- <void property="name">
- <void property="text">
- <string>LMI_UnixDeviceFile</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double6">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double6"/>
- <double>1020.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double6"/>
- <double>168.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>1020.0</double>
- <double>168.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode7">
- <void property="name">
- <void property="text">
- <string>LMI_UnixDirectory</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double7">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double7"/>
- <double>462.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double7"/>
- <double>425.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>462.0</double>
- <double>425.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode8">
- <void property="attributes">
- <void property="text">
- <string>string FSCreationClassName
-string CSName
-string CSCreationClassName
-string CreationClassName
-string FSName
-string LFName</string>
- </void>
- </void>
- <void property="name">
- <void property="text">
- <string>LMI_UnixFile</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double8">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double8"/>
- <double>334.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double8"/>
- <double>36.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>334.0</double>
- <double>36.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode9">
- <void property="name">
- <void property="text">
- <string>LMI_UnixSocket</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double9">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double9"/>
- <double>1015.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double9"/>
- <double>254.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>1015.0</double>
- <double>254.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode10">
- <void property="attributes">
- <void property="text">
- <string>string CreationClassName
-string Name</string>
- </void>
- </void>
- <void property="name">
- <void property="text">
- <string>CIM_ComputerSystem</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double10">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double10"/>
- <double>180.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double10"/>
- <double>245.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>180.0</double>
- <double>245.0</double>
- </void>
- </object>
- </void>
- <void method="addNode">
- <object class="com.horstmann.violet.ClassNode" id="ClassNode11">
- <void property="attributes">
- <void property="text">
- <string>string FSCreationClassName
-string Name
-string CSName
-string CSCreationClassName
-string CreationClassName
-string FSName</string>
- </void>
- </void>
- <void property="name">
- <void property="text">
- <string>CIM_LogicalFile</string>
- </void>
- </void>
- </object>
- <object class="java.awt.geom.Point2D$Double" id="Point2D$Double11">
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>x</string>
- <void method="set">
- <object idref="Point2D$Double11"/>
- <double>707.0</double>
- </void>
- </void>
- <void class="java.awt.geom.Point2D$Double" method="getField">
- <string>y</string>
- <void method="set">
- <object idref="Point2D$Double11"/>
- <double>209.0</double>
- </void>
- </void>
- <void method="setLocation">
- <double>707.0</double>
- <double>209.0</double>
- </void>
- </object>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="HVH"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="V"/>
- </void>
- <void property="endLabel">
- <string>1</string>
- </void>
- </object>
- <object idref="ClassNode4"/>
- <object idref="ClassNode10"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="HVH"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="V"/>
- </void>
- <void property="endLabel">
- <string>1</string>
- </void>
- </object>
- <object idref="ClassNode4"/>
- <object idref="ClassNode7"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="VHV"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
- </void>
- </object>
- <object idref="ClassNode5"/>
- <object idref="ClassNode11"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="VHV"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
- </void>
- </object>
- <object idref="ClassNode6"/>
- <object idref="ClassNode11"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="VHV"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
- </void>
- </object>
- <object idref="ClassNode2"/>
- <object idref="ClassNode11"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="VHV"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
- </void>
- </object>
- <object idref="ClassNode9"/>
- <object idref="ClassNode11"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="VHV"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
- </void>
- </object>
- <object idref="ClassNode0"/>
- <object idref="ClassNode11"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="HVH"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="V"/>
- </void>
- <void property="endLabel">
- <string>1</string>
- </void>
- </object>
- <object idref="ClassNode3"/>
- <object idref="ClassNode8"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="HVH"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="V"/>
- </void>
- <void property="endLabel">
- <string>1</string>
- </void>
- </object>
- <object idref="ClassNode3"/>
- <object idref="ClassNode11"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
- </void>
- </object>
- <object idref="ClassNode7"/>
- <object idref="ClassNode11"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="HVH"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="V"/>
- </void>
- <void property="endLabel">
- <string>1</string>
- </void>
- </object>
- <object idref="ClassNode1"/>
- <object idref="ClassNode7"/>
- </void>
- <void method="connect">
- <object class="com.horstmann.violet.ClassRelationshipEdge">
- <void property="bentStyle">
- <object class="com.horstmann.violet.BentStyle" field="HVH"/>
- </void>
- <void property="endArrowHead">
- <object class="com.horstmann.violet.ArrowHead" field="V"/>
- </void>
- <void property="endLabel">
- <string>*</string>
- </void>
- </object>
- <object idref="ClassNode1"/>
- <object idref="ClassNode11"/>
- </void>
- </object>
-</java>
diff --git a/doc/_static/logicalfile.png b/doc/_static/logicalfile.png
deleted file mode 100644
index 04633d1..0000000
--- a/doc/_static/logicalfile.png
+++ /dev/null
Binary files differ
diff --git a/doc/build-with-sphinx.sh b/doc/build-with-sphinx.sh
deleted file mode 100755
index e1a08d2..0000000
--- a/doc/build-with-sphinx.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-# This script creates a temporary python workspace directory, where the
-# openlmi-scripts and all specified commands are installed in order for
-# sphinx-build to successfuly find them and generate devel documentation out of
-# them.
-#
-# There are several environment variables affecting the execution:
-# * SPHINXBUILD
-# sphinx binary generating the documentation
-# * INCLUDE_COMMANDS
-# whether the command should be included in generated documentation
-# * COMMANDS
-# list of subcommands to include
-
-SPHINXBUILD=${SPHINXBUILD:-sphinx-build}
-INCLUDE_COMMANDS=${INCLUDE_COMMANDS:-1}
-tmp=`mktemp -d`
-pushd ..
-export PYTHONPATH=$tmp
-python setup.py develop --install-dir=$tmp || exit 1
-if [ "$INCLUDE_COMMANDS" == 1 ]; then
- pushd commands
- COMMANDS="$1"
- for cmd in ${COMMANDS}; do
- pushd $cmd
- python setup.py develop --install-dir=$tmp || exit 1
- popd
- done
- popd
-fi
-popd # ..
-shift
-${SPHINXBUILD} $@ || exit 1
-rm -rf $tmp
diff --git a/doc/command-classes.rst b/doc/command-classes.rst
deleted file mode 100644
index bdee7c7..0000000
--- a/doc/command-classes.rst
+++ /dev/null
@@ -1,163 +0,0 @@
-.. _command_classes:
-
-Command classes
-===============
-Before reading this, please make sure you're familiar with
-:ref:`command_wrappers_overview`.
-
-We focus here on commands intended for subclassing in command wrapper modules.
-*OpenLMI Scripts* defines and uses other kinds of commands internally. But
-the script developer does not need to know about them.
-
-.. seealso::
- General and class specific properties in :ref:`command_properties`.
-
-.. _end-point_commands:
-
-End-point commands
-------------------
-Were already introduced before (see :ref:`end-point_commands_introduction`).
-We'll dive into details here.
-
-Every end-point command allows to verify and transform options parsed by
-docopt_ before they are passed to associated function. This can happen in
-methods:
-
-``verify_options(self, options)``
- Taking pre-processed options dictionary as a first argument.
- Properties affecting this pre-processing can be found in
- :ref:`pre_processing_properties`. This method shall check option values or
- their combination and raise ``lmi.scripts.common.errors.LmiInvalidOptions``
- if any inconsistency is discovered.
-
- Example usage: ::
-
- class FileLister(command.LmiInstanceLister):
- DYNAMIC_PROPERTIES = True
-
- def verify_options(self, options):
- file_types = { 'all', 'file', 'directory', 'symlink'
- , 'fifo', 'device'}
- if ( options['--type'] is not None
- and options['--type'] not in file_types):
- raise errors.LmiInvalidOptions(
- 'Invalid file type given, must be one of %s' %
- file_types)
-
- .. seealso::
- API doccumentation on
- :py:meth:`~lmi.scripts.common.command.endpoint.LmiEndPointCommand.verify_options`
-
-``transform_options(self, options)``
- Takes verified options dictionary. It modifies this dictionary in
- arbitrary way in place. Its return value is ignored.
-
- Example usage: ::
-
- class Lister(command.LmiLister):
- COLUMNS = ('Device', 'Name', "ElementName", "Type")
-
- def transform_options(self, options):
- """
- Rename 'device' option to 'devices' parameter name for better
- readability.
- """
- options['<devices>'] = options.pop('<device>')
-
- .. seealso::
- API documentation on
- :py:meth:`~lmi.scripts.common.command.endpoint.LmiEndPointCommand.transform_options`
-
-Above methods can be used to process options in a way that any script library
-function can be called. In case we need more control over what is called or
-when we want to decide at runtime which function shall be called, we may override
-:py:meth:`~lmi.scripts.common.command.endpoint.LmiEndPointCommand.execute` method
-instead. Example of this may be found at :ref:`associating_a_function`.
-
-.. _lmi_check_result:
-
-``LmiCheckResult``
-~~~~~~~~~~~~~~~~~~
-This command invokes associated function on hosts in session, collects results
-from them and compares them to an expected value. It does not produce any
-output, when all returned values are expected.
-
-This command class is very useful when wrapping up some CIM class's method
-such as ``LMI_Service::StartService()``. Example can be seen in
-:ref:`property_descriptions`.
-
-Its specific properties are listed in :ref:`lmi_check_result_properties`.
-
-.. seealso::
- API documentation on
- :py:class:`~lmi.scripts.common.command.checkresult.LmiCheckResult`
-
-.. _lmi_lister:
-
-``LmiLister``
-~~~~~~~~~~~~~
-Prints tablelike data. It expects associated function to return its result
-in form: ::
-
- [row1, row2, ...]
-
-Where ``rowX`` is a tuple containing row values. Each such row is ``list`` or
-``tuple`` of the same length. There is a property ``COLUMNS`` defining column
-names [#]_ (see :ref:`lmi_lister_properties`). Generator is prefered over
-a ``list`` of rows. If ``COLUMNS`` property is omitted, returned value shall
-take the following form instead: ::
-
- (columns, data)
-
-Where ``columns`` has the same meaning as ``COLUMNS`` as a class property and
-``data`` is the result of previous case [#]_.
-
-.. seealso::
- API documentation on
- :py:class:`~lmi.scripts.common.command.lister.LmiLister`
-
-.. _lmi_instance_lister:
-
-``LmiInstanceLister``
-~~~~~~~~~~~~~~~~~~~~~
-Is a variant of ``LmiLister``. Instead of rows being tuples, here they are
-instances of some CIM class. Instead of using ``COLUMNS`` property for
-specifying columns labels, ``PROPERTIES`` is used for the same purpose here.
-Its primary use is in specifying which properties of instances shall be
-rendered in which column. This is described in detail in
-:ref:`lmi_instance_lister_properties`.
-
-The expected output of associated function is therefore: ::
-
- [instance1, instance2, ...]
-
-Again, usage of generators is preferred.
-
-.. seealso::
- API documentation on
- :py:class:`~lmi.scripts.common.command.lister.LmiInstanceLister`
-
-.. _lmi_show_instance:
-
-``LmiShowInstance``
-~~~~~~~~~~~~~~~~~~~
-Renders a single instance of some CIM class. It's rendered in a form of
-two-column table, where the first column contains property names and
-the second their corresponding values. Rendering is controlled in the same
-way as for ``LmiInstanceLister`` (see :ref:`lmi_show_instance_properties`).
-
-.. seealso::
- API documentation on
- :py:class:`~lmi.scripts.common.command.show.LmiShowInstance`
-
-.. ****************************************************************************
-
-.. _CIM: http://dmtf.org/standards/cim
-.. _OpenLMI: http://fedorahosted.org/openlmi/
-.. _openlmi-tools: http://fedorahosted.org/openlmi/wiki/shell
-.. _docopt: http://docopt.org/
-
--------------------------------------------------------------------------------
-
-.. [#] Having the same length as each row in returned data.
-.. [#] Generator or a ``list`` of rows.
diff --git a/doc/command-properties.rst b/doc/command-properties.rst
deleted file mode 100644
index d45f8d9..0000000
--- a/doc/command-properties.rst
+++ /dev/null
@@ -1,574 +0,0 @@
-.. _command_properties:
-
-Command properties
-==================
-
-As noted before in :ref:`end-point_commands`, command at first tries to
-process input arguments, calls an associated function and then renders its
-result. We'll now introduce properties affecting this process.
-
-Command class properties are written in their bodies and handled by their
-metaclasses. After being processed, they are removed from class. So they are
-not accessible as class attributes or from their instances.
-
-.. _pre_processing_properties:
-
-Options pre-processing
-----------------------
-Influencing properties:
-
- * ``OPT_NO_UNDERSCORES`` (opt_no_underscores_)
- * ``ARG_ARRAY_SUFFIX`` (arg_array_suffix_)
- * ``OWN_USAGE`` (own_usage_)
-
-docopt_ will make a dictionary of options based on usage string such
-as the one above (:ref:`usage_string`). Options dictionary matching this
-example looks like this: ::
-
- { 'list' : bool
- , '--all' : bool
- , '--disabled' : bool
- , 'start' : bool
- , '<service>' : str
- }
-
-Values of this dictionary are passed to an associated function as arguments
-with names created out of matching keys. Since argument names can not contain
-characters such as `'<'`, `'>'`, `'-'`, etc., these need to be replaced.
-Process of renaming of these options can be described by the following pseudo
-algorithm:
-
-.. _options_transform_algorithm:
-
- 1. arguments enclosed in brackets are un-surrounded -- brackets get
- removed ::
-
- "<service>" -> "service"
-
- 2. arguments written in upper case are made lower cased ::
-
- "FILE" -> "file"
-
- 3. prefix of short and long options made of dashes shall be replaced with
- single underscore ::
-
- "-a" -> "_a"
- "--all" -> "_all"
-
- 4. any non-empty sequence of characters not allowed in python's identitier
- shall be replaced with a single underscore ::
-
- "_long-option" -> "_long_option"
- "special--cmd-#2" -> "special_cmd_2"
-
-Points 3 and 4 could be merged into one. But we separate them due to effects
-of ``OPT_NO_UNDERSCORES`` property described below.
-
-.. seealso::
- Notes in :ref:`end-point_commands` for method
- :py:meth`lmi.scripts.common.command.endpoint.LmiEndPointCommand.transform_options`
- which is issued before the above algorithm is run.
-
-Treating dashes
-~~~~~~~~~~~~~~~
-Single dash and double dash are special cases of commands.
-
-Double dash in usage string allows to pass option-like argument to a script
-e.g.: ::
-
- lmi file show -- --file-prefix-with-double-dash
-
-Without the ``'--'`` argument prefixing the file, docopt_ would throw an error
-beacause of ``--file-prefix-with-double-dash`` being treated as an unknown
-option. This way it's correctly treated as an argument ``<file>`` given the
-usage string: ::
-
- Usage: %(cmd)s file show [--] <file>
-
-Double dash isn't be passed to an associated function.
-
-Single dash on a command line is commonly used to specify stdout or stding. For
-example in the following snippet: ::
-
- Usage: %(cmd)s file copy (- | <file>) <dest>
-
-``'-'`` stands for standard input which will be read instead of a file if the
-user wishes to.
-
-Property descriptions
-~~~~~~~~~~~~~~~~~~~~~
-.. _opt_no_underscores:
-
-``OPT_NO_UNDERSCORES`` : ``bool`` (defaults to ``False``)
- Modifies point 3 of options pre-processing. It causes the prefix of dashes
- to be completely removed with no replacement: ::
-
- "--long-options" -> "long-option"
-
- This may not be save if there is a command with the same name as the
- option being removed. Setting this property to ``True`` will cause
- overwriting the command with the value of option. A warning shall be
- echoed if such a case occurs.
-
-.. _arg_array_suffix:
-
-``ARG_ARRAY_SUFFIX`` : ``str`` (defaults to ``""``)
- Adds additional point (5) to `options_transform_algorithm`_. All
- repeatable arguments, resulting in a ``list`` of items, are renamed to
- ``<original_name><suffix>`` [#]_. Repeatable argument in usage string
- looks like this: ::
-
- """
- Usage: %(cmd)s start <service> ...
- """
-
- Causing all of the ``<service>`` arguments being loaded into a ``list``
- object.
-
-.. _own_usage:
-
-``OWN_USAGE`` : ``bool`` (defaults to ``False``)
- Says whether the documentation string of this class is a usage string.
- Each command in hierarchy can have its own usage string.
-
- This can also be assigned a usage string directly: ::
-
- class MySubcommand(LmiCheckResult):
- """
- Class doc string.
- """
- OWN_USAGE = "Usage: %(cmd)s --opt1 --opt1 <file> <args> ..."
- EXPECT = 0
-
- But using a boolean value is more readable: ::
-
- class MySubcommand(LmiCheckResult):
- """
- Usage: %(cmd)s --opt1 --opt1 <file> <args> ...
- """
- OWN_USAGE = True
- EXPECT = 0
-
- .. note::
-
- Using own usage strings in subcommands of top-level commands is not
- recommended. It brings a lot of redundancy and may prove problematic
- to modify while keeping consistency among hierarchically nested
- usages.
-
- Therefore try to have just one usage string in a top-level command.
- And one top-level command in a single module. Resulting in one usage
- string per one command wrappers module. This makes it easier to read
- and modify.
-
-.. _associating_a_function:
-
-Associating a function
-----------------------
-Influencing properties:
-
- * ``CALLABLE`` (callable_)
-
-When command is invoked, its method
-:py:meth:`~lmi.scripts.common.command.endpoint.LmiEndPointCommand.execute` will
-get verified and transformed options as positional and keyword arguments.
-This method shall pass them to an associated function residing in script
-library and return its result on completition.
-
-One way to associate a function is to use ``CALLABLE`` property. The other
-is to define very own ``execute()`` method like this: ::
-
- class Lister(command.LmiInstanceLister):
- PROPERTIES = ('Name', "Started", 'Status')
-
- def execute(self, ns, _all, _disabled, _oneshot):
- kind = 'enabled'
- if _all:
- kind = 'all'
- elif _disabled:
- kind = 'disabled'
- elif _oneshot:
- kind = 'oneshot'
- for service_inst in service.list_services(ns, kind):
- yield service_inst
-
-This may come handy if the application object [#]_ needs to be accessed or
-if we need to decide which function to call based on command line options.
-
-.. _property_descriptions:
-
-Property descriptions
-~~~~~~~~~~~~~~~~~~~~~
-.. _callable:
-
-``CALLABLE`` : ``str`` (defaults to ``None``)
- This is a mandatory option if
- :py:meth:`~lmi.scripts.common.command.endpoint.LmiEndPointCommand.execute`
- method is not overriden. It may be a string composed of a full path of
- module and its callable delimited with ``':'``: ::
-
- CALLABLE = 'lmi.scripts.service:start'
-
- Causes function ``start()`` of ``'lmi.scripts.service'`` module to be
- associated with command.
-
- Callable may also be assigned directly like this: ::
-
- from lmi.scripts import service
- class Start(command.LmiCheckResult):
- CALLABLE = service.start
- EXPECT = 0
-
- The first variant (by assigning string) comes handy if the particular
- module of associated function is not yet imported. Thus delaying the
- import until the point of function's invocation - if the execution comes
- to this point at all. In short it speeds up execution of ``lmi``
- meta-command by reducing number of module imports that are not needed.
-
-.. _function_invocation:
-
-Function invocation
--------------------
-Influencing properties:
-
- * ``NAMESPACE`` (namespace_)
-
-Property descriptions
-~~~~~~~~~~~~~~~~~~~~~
-
-.. _namespace:
-
-``NAMESPACE`` : ``str`` (defaults to ``None``)
- This property affects the first argument passed to an associated function.
- Various values have different impact:
-
- +-----------+---------------------------------------+-------------------------------------+
- | Value | Value of first argument. | Its type |
- +===========+=======================================+=====================================+
- | ``None`` | Same impact as value ``"root/cimv2"`` | :py:class:`lmi.shell.LMINamespace` |
- +-----------+---------------------------------------+-------------------------------------+
- | ``False`` | Raw connection object | :py:class:`lmi.shell.LMIConnection` |
- +-----------+---------------------------------------+-------------------------------------+
- | any path | Namespace object with given path | :py:class:`lmi.shell.LMINamespace` |
- +-----------+---------------------------------------+-------------------------------------+
-
- This usually won't need any modification. Sometimes perhaps associated
- function might want to access more than one namespace, in that case an
- instance of :py:class:`lmi.shell.LMIConnection` might provide more useful.
-
- Namespace can also be overriden globally in a configuration file or with
- an option on command line.
-
-
-Output rendering
-----------------
-All these options begin with ``FMT_`` which is a shortcut for *formatter* as
-they become options to formatter objects. These can be defined not only in
-end-point commands but also in multiplexers. In the latter case they set the
-defaults for all their direct and indirect child commands.
-
-.. note::
- These options override configuration settings and command line options.
- Therefor use them with care.
-
-They are:
-
-.. _fmt_no_headings:
-
-``FMT_NO_HEADINGS`` : ``bool`` (defaults to ``False``)
- Allows to suppress headings (column or row names) in the output.
-
- .. note::
- With :ref:`lmi_lister` command it's preferable to set the *COLUMNS*
- property to empty list instead. Otherwise associated function is
- expected to return column headers as a first row in its result.
-
-.. _fmt_human_friendly:
-
-``FMT_HUMAN_FRIENDLY`` : ``bool`` (defaults to ``False``)
- Forces the output to be more pleasant to read by human beings.
-
-.. _specifying_requirements:
-
-Command specific properties
----------------------------
-Each command class can have its own specific properties. Let's take a look on
-them.
-
-``LmiCommandMultiplexer``
-~~~~~~~~~~~~~~~~~~~~~~~~~
-.. _commands:
-
-``COMMANDS`` : ``dict`` (mandatory)
- Dictionary assigning subcommands to their names listed in usage string.
- Example follows: ::
-
- class MyCommand(LmiCommandMultiplexer):
- '''
- My command description.
-
- Usage: %(cmd)s mycommand (subcmd1 | subcmd2)
- '''
- COMMANDS = {'subcmd1' : Subcmd1, 'subcmd2' : Subcmd2}
- OWN_USAGE = True
-
- Where ``Subcmd1`` and ``Subcmd2`` are some other ``LmiBaseCommand``
- subclasses. Documentation string must be parseable with docopt_.
-
- ``COMMANDS`` property will be translated to
- :py:meth:`~lmi.scripts.common.command.multiplexer.LmiCommandMultiplexer.child_commands`
- class method by
- :py:class:`~lmi.scripts.common.command.meta.MultiplexerMetaClass`.
-
-``FALLBACK_COMMAND`` : :py:class:`lmi.scripts.common.command.endpoint.LmiEndPointCommand`
- Command class used when no command defined in ``COMMANDS`` dictionary is
- passed on command line.
-
- Take for example this usage string: ::
-
- """
- Display hardware information.
-
- Usage:
- %(cmd)s [all]
- %(cmd)s system
- %(cmd)s chassis
- """
-
- This suggests there are tree commands defined taking care of listing
- hardware informations. Entry point definition could look like this: ::
-
- class Hardware(command.LmiCommandMultiplexer):
- OWN_USAGE = __doc__ # usage string from above
- COMMANDS = { 'all' : All
- , 'system' : System
- , 'chassis' : Chassis
- }
- FALLBACK_COMMAND = All
-
- Without the ``FALLBACK_COMMAND`` property, the multiplexer would not
- handle the case when ``'all'`` argument is omitted as is suggested in
- the usage string. Adding it to command properties causes this multiplexer
- to behave exactly as ``All`` subcommand in case that no command
- is given on command line.
-
-.. _lmi_select_command_properties:
-
-``LmiSelectCommand`` properties
--------------------------------
-Following properties allow to define profile and class requirements for
-commands.
-
-.. _select:
-
-``SELECT`` : ``list`` (mandatory)
- Is a list of pairs ``(condition, command)`` where ``condition`` is an
- expression in *LMIReSpL* language. And ``command`` is either a string with
- absolute path to command that shall be loaded or the command class itself.
-
- Small example: ::
-
- SELECT = [
- ( 'OpenLMI-Hardware < 0.4.2'
- , 'lmi.scripts.hardware.pre042.PreCmd'
- )
- , ('OpenLMI-Hardware >= 0.4.2 & class LMI_Chassis == 0.3.0'
- , HwCmd
- )
- ]
-
- It says: Let the ``PreHwCmd`` command do the job on brokers having
- ``openlmi-hardware`` package older than ``0.4.2``. Use the ``HwCmd``
- anywhere else where also the ``LMI_Chassis`` CIM class in version ``0.3.0``
- is available.
-
- First matching condition wins and assigned command will be passed all the
- arguments. If no condition can be satisfied and no default command is set,
- an exception will be raised.
-
- .. seealso::
- Definition of *LMIReSpL* mini-language:
- :py:mod:`~lmi.scripts.common.versioncheck.parser`
-
-.. _default:
-
-``DEFAULT`` : ``string`` or reference to command class
- Defines fallback command used in case no condition in ``SELECT`` can be
- satisfied.
-
-.. _lmi_lister_properties:
-
-``LmiLister`` properties
-~~~~~~~~~~~~~~~~~~~~~~~~
-.. _columns:
-
-``COLUMNS`` : ``tuple``
- Column names. It's a tuple with name for each column. Each row of data
- shall then contain the same number of items as this tuple. If omitted,
- associated function is expected to provide them in the first row of
- returned list. It's translated to
- :py:meth:`~lmi.scripts.common.command.lister.LmiBaseListerCommand.get_columns`
- class method.
-
- If set to empty list, no column headers will be printed. Every item of
- returned list of associated function will be treated as data. Note that
- setting this to empty list makes the *FMT_NO_HEADINGS* property
- redundant.
-
-.. _lmi_instance_commands_properties:
-.. _lmi_show_instance_properties:
-.. _lmi_instance_lister_properties:
-
-``LmiShowInstance`` and ``LmiInstanceLister`` properties
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-These two classes expect, as a result of their associated function, an instance
-or a list of instances of some CIM class. They take care of rendering them to
-standard output. Thus their properties affect the way how their properties
-are rendered.
-
-.. _properties:
-
-``PROPERTIES`` : ``tuple``
- Property names in the same order as the properties shall be listed. Items
- of this tuple can take multiple forms:
-
- Property Name : ``str``
- Will be used for the name of column/property in output table and the
- same name will be used when obtaining the value from instance. Thus
- this form may be used only if the property name of instance can appear
- as a name of column.
-
- (Column Name, Property Name) : ``(str, str)``
- This pair allows to render value of property under different name
- (*Column Name*).
-
- (Column Name, getter) : ``(str, callable)``
- This way allows the value to be arbitrarily computed. The second
- item is a callable taking one and only argument -- the instance of
- class to be rendered.
-
- Example below shows different ways of rendering attributes for instances
- of ``LMI_Service`` CIM class: ::
-
- class Show(command.LmiShowInstance):
- CALLABLE = 'lmi.scripts.service:get_instance'
- PROPERTIES = (
- 'Name',
- ('Enabled', lambda i: i.EnabledDefault == 2),
- ('Active', 'Started'))
-
- First property will be shown with the same label as the name of property.
- Second one modifies the value of ``EnabledDefault`` from ``int`` to
- ``bool`` representing enabled state. The last one uses different label for
- property name ``Started``.
-
-.. _dynamic_properties:
-
-``DYNAMIC_PROPERTIES`` : ``bool`` (defaults to ``False``)
- Whether the associated function is expected to return the properties tuple
- itself. If ``True``, the result of associated function must be in form: ::
-
- (properties, data)
-
- Where ``properties`` have the same inscription and meaning as a
- ``PROPERTIES`` property of class.
-
- Otherwise, only the ``data`` is expected.
-
- .. note::
- Both :py:class:`~lmi.scripts.common.command.show.LmiShowInstance`
- and :py:class:`~lmi.scripts.common.command.lister.LmiInstanceLister`
- expect different ``data`` to be returned. See :ref:`lmi_show_instance`
- and :ref:`lmi_instance_lister` for more information.
-
-.. note::
-
- Omitting both ``PROPERTIES`` and ``DYNAMIC_PROPERTIES`` makes the
- ``LmiShowInstance`` render all attributes of instance. For
- ``LmiInstanceLister`` this is not allowed, either ``DYNAMIC_PROPERTIES``
- must be ``True`` or ``PROPERTIES`` must be filled.
-
-
-.. _lmi_check_result_properties:
-
-``LmiCheckResult`` properties
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-This command typically does not produce any output if operation succeeds. The
-operation succeeds if the result of associated function is expected. There are
-more ways how to say what is an expected result. One way is to use ``EXPECT``
-property. The other is to provide very own implementation of
-:py:class:`~lmi.scripts.common.command.checkresult.LmiCheckResult.check_result`
-method.
-
-.. _expect:
-
-``EXPECT``: (mandatory)
- Any value can be assigned to this property. This value is then expected
- to be returned by associated function. Unexpected result is treated
- as an error.
-
- A callable object assigned here has special meaning. This object must
- accept exactly two parameters:
-
- 1. options - Dictionary with parsed command line options returned by
- docopt_ after being processed by
- :py:meth:`~lmi.scripts.common.command.endpoint.LmiEndPointCommand.transform_options`.
- 2. result - Return value of associated function.
-
- If the associated function does not return an expected result, an error
- such as: ::
-
- There was 1 error:
- host kvm-fedora-20
- 0 != 1
-
- will be presented to user which is not much helpful. To improve user
- experience, the
- :py:class:`~lmi.scripts.common.command.checkresult.LmiCheckResult.check_result`
- method could be implemented instead. Note the example: ::
-
- class Update(command.LmiCheckResult):
- ARG_ARRAY_SUFFIX = '_array'
-
- def check_result(self, options, result):
- """
- :param list result: List of packages successfuly installed
- that were passed as an ``<package_array>`` arguments.
- """
- if options['<package_array>'] != result:
- return (False, ('failed to update packages: %s' %
- ", ".join( set(options['<package_array>'])
- - set(result))))
- return True
-
- The ``execute()`` method is not listed to make the listing shorter. This
- command could be used with usage string such as: ::
-
- %(cmd)s update [--force] [--repoid <repository>] <package> ...
-
- In case of a failure, this would produce output like this one: ::
-
- $ lmi sw update wt wt-doc unknownpackage
- There was 1 error:
- host kvm-fedora-20
- failed to update packages: unknownpackage
-
-.. seealso::
-
- Docopt_ home page and its git: http://github.org/docopt/docopt.
-
--------------------------------------------------------------------------------
-
-.. [#] Angle brackets here just mark the boundaries of name components. They
- have nothing to do with arguments.
-.. [#] Application object is accessible through ``app`` property of each
- command instance.
-
-.. ****************************************************************************
-
-.. _CIM: http://dmtf.org/standards/cim
-.. _OpenLMI: http://fedorahosted.org/openlmi/
-.. _openlmi-tools: http://fedorahosted.org/openlmi/wiki/shell
-.. _docopt: http://docopt.org/
-.. _docopt-git: http://github.org/docopt
-
diff --git a/doc/conf.py.skel b/doc/conf.py.skel
deleted file mode 100644
index af4caa9..0000000
--- a/doc/conf.py.skel
+++ /dev/null
@@ -1,290 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# OpenLMI Scripts documentation build configuration file, created by
-# sphinx-quickstart on Thu Sep 5 12:50:18 2013.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath('..'))
-
-if os.environ.get('INCLUDE_COMMANDS', '0').lower() in {'1', 'true', 'yes'}:
- commands_path = os.environ.get('COMMANDS_PATH', '../commands')
- commands = os.environ.get('COMMANDS', '')
- if commands:
- for i, cmd in enumerate(commands.split(',')):
- sys.path.insert(1 + i, os.path.join(os.path.abspath(commands_path), cmd))
-
- include_commands_docs = True
- include_commands = commands.split(',')
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'OpenLMI Scripts'
-copyright = u'2013-2014, Red Hat, Inc.'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '@@VERSION@@'
-# The full version, including alpha/beta/rc tags.
-release = '@@VERSION@@'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ['mylf/*']
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'OpenLMIScriptsdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-'preamble': u"""
-\\usepackage{imakeidx}
-\\usepackage{tikz}
-
-\\makeatletter
-\\newcount\\dirtree@lvl
-\\newcount\\dirtree@plvl
-\\newcount\\dirtree@clvl
-\\def\\dirtree@growth{%
- \\ifnum\\tikznumberofcurrentchild=1\\relax
- \\global\\advance\\dirtree@plvl by 1
- \\expandafter\\xdef\\csname dirtree@p@\\the\\dirtree@plvl\\endcsname{\\the\\dirtree@lvl}
- \\fi
- \\global\\advance\\dirtree@lvl by 1\\relax
- \\dirtree@clvl=\\dirtree@lvl
- \\advance\\dirtree@clvl by -\\csname dirtree@p@\\the\\dirtree@plvl\\endcsname
- \\pgf@xa=0.5cm\\relax
- \\pgf@ya=-0.5cm\\relax
- \\pgf@ya=\\dirtree@clvl\\pgf@ya
- \\pgftransformshift{\\pgfqpoint{\\the\\pgf@xa}{\\the\\pgf@ya}}%
- \\ifnum\\tikznumberofcurrentchild=\\tikznumberofchildren
- \\global\\advance\\dirtree@plvl by -1
- \\fi
-}
-
-\\tikzset{
- dirtree/.style={
- growth function=\\dirtree@growth,
- every node/.style={anchor=north},
- every child node/.style={anchor=west},
- edge from parent path={(\\tikzparentnode\\tikzparentanchor) |- (\\tikzchildnode\\tikzchildanchor)}
- }
-}
-\\makeatother
-""",
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'OpenLMIScripts.tex', u'OpenLMI Scripts Documentation',
- u'Michal Minář', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'openlmiscripts', u'OpenLMI Scripts Documentation',
- [u'Michal Minář'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'OpenLMIScripts', u'OpenLMI Scripts Documentation',
- u'Michal Minář', 'OpenLMIScripts', 'One line description of project.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-def setup(app):
- app.add_config_value('include_commands', False, 'env')
- app.add_config_value('commands', '', 'env')
diff --git a/doc/configuration.rst b/doc/configuration.rst
deleted file mode 100644
index 3c56ee9..0000000
--- a/doc/configuration.rst
+++ /dev/null
@@ -1,175 +0,0 @@
-.. _configuration:
-
-Configuration
-=============
-``lmi`` meta-command has the main configuration file located in: ::
-
- /etc/openlmi/scripts/lmi.conf
-
-User can have his own configuration file taking precedence over anything in
-global one above: ::
-
- $HOME/.lmirc
-
-Configuration is written in MS Windows INI files fashion. Please refer to
-corresponding `RFC 822`_ and to `ConfigParser`_ for python specific
-interpretation language.
-
-Follows a list of sections with their list of options. Most of the options
-listed here can be overridden with command line parameters.
-
-.. seealso::
- :py:mod:`~lmi.scripts.common.configuration`
-
-.. _sect_main:
-
-Section [Main]
---------------
-.. _main_command_namespace:
-
-CommandNamespace : ``string``
- Python namespace, where command entry points will be searched for.
-
- Defaults to ``lmi.scripts.cmd``.
-
-.. _main_trace:
-
-Trace : ``boolean``
- Whether the exceptions should be logged with tracebacks.
-
- Defaults to ``False``.
-
- Can be overridden with ``--trace`` and ``--notrace`` options on
- command-line.
-
- .. note::
- For most exceptions generated by scripts a *Verbosity* option
- needs to be highest as well for tracebacks to be printed.
-
-.. _main_verbosity:
-
-Verbosity: ``integer``
- A number within 0-2 range saying, how verbose the output shall be. This
- differs from `log_level`_, which controls the logging messages written to
- file. If logging to console is enabled it sets the minimum severity level.
- -1 Suppresses all messages except for errors. 0 shows warnings, 1 info
- messages and 2 enables debug messages. This option also affects the
- verbosity of commands, making them print more information to stdout.
-
- Defaults to 0.
-
- Can be overridden with ``-v`` and ``-q`` flags on command-line.
-
-Section [CIM]
--------------
-.. _cim_namespace:
-
-Namespace : ``string``
- Allows to override default CIM namespace, which will be passed to
- script library functions.
-
- Defaults to ``root/cimv2``.
-
-Section [SSL]
--------------
-.. _ssl_verify_server_certificate:
-
-VerifyServerCertificate : ``boolean``
- Whether to verify server-side certificate, when making secured
- connection over https.
-
- Defaults to ``True``.
-
- Can be overridden with ``-n | --noverify`` flag on command-line.
-
-Section [Format]
-----------------
-.. _format_human_friendly:
-
-HumanFriendly : ``boolean``
- Whether to print values in human readable forms (e.g. with units).
-
- Defaults to ``False``.
-
- Can be overridden with ``-H | --human-frienly`` flag on command-line.
-
-.. _format_lister_format:
-
-ListerFormat : one of {``csv``, ``table``}
- What format to use, when listing tabular data. ``csv`` format allows for
- easy machine parsing, the second one is more human friendly.
-
- Defaults to ``table``.
-
- Can be overridden with ``-L | --lister-format`` option on command line.
-
-.. _format_no_headings:
-
-NoHeadings : ``boolean``
- Whether to suppress headings (column names) when printing tables.
-
- Defaults to ``False``.
-
- Can be overridden with ``-N | --no-headings`` option on command line.
-
-Section [Log]
--------------
-.. _log_level:
-
-Level : one of {``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``, ``CRITICAL``}
- Minimal severity level of messages to log. Affects only logging to a
- file. See the `main_verbosity`_ option controlling console logging level.
-
- Defaults to ``ERROR``.
-
-LogToConsole : ``boolean``
- Whether the logging to console is enabled.
-
- Defaults to ``True``
-
- On command-line the same could be achieved by redirecting *stderr* to
- ``/dev/null``.
-
-.. _log_console_format:
-
-ConsoleFormat : ``string``
- Format string used when logging to a console. This applies to warnings and
- more severe messages. Refer to `Format String` in python's documentation for
- details.
-
- Defaults to ``%(levelname)s: %(message)s``.
-
-.. _log_console_info_format:
-
-ConsoleInfoFormat : ``string``
- Format string used when logging to a console. Applies to info and debug
- messages. Refer to `Format String` in python's documentation for details.
-
-
- Defaults to ``%(message)s``.
-
-.. _log_file_format:
-
-FileFormat : ``string``
- Format string used, when logging to a console. This applies only when
- *OutputFile* is set (see below). Refer to `Format String` in python's
- documentation for details.
-
- Defaults to
- ``%(asctime)s:%(levelname)-8s:%(name)s:%(lineno)d - %(message)s``
-
-.. _log_output_file:
-
-OutputFile : ``string``
- Allows to set a path to file, where messages will be logged. No log
- file is written at default.
-
- Defaults to empty string.
-
- Can be overridden on command line with ``--log-file`` option.
-
-.. ****************************************************************************
-
-.. _`RFC 822`: http://tools.ietf.org/html/rfc822.html
-.. _`ConfigParser`: http://docs.python.org/2/library/configparser.html
-.. _`Format String`: http://docs.python.org/2/library/logging.html#logrecord-attributes
diff --git a/doc/gendoc.sh b/doc/gendoc.sh
deleted file mode 100755
index 4ce3244..0000000
--- a/doc/gendoc.sh
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/bin/bash
-
-#
-# Helper script to generate developer documentation in
-# doc/modules and api.rst
-#
-
-TOPDIR=..
-
-[ -e $TOPDIR/doc/modules ] || mkdir $TOPDIR/doc/modules
-
-function get_modules() {
- find $TOPDIR/lmi/scripts/ -type f -a -name '*.py' | \
- sed 's:/__init__\.py$::' | \
- grep -v "^${TOPDIR}/lmi/scripts/\?$" | \
- grep -v '/_' | \
- sort -u
-}
-
-function get_module_name() {
- path=`sed -e "s:^.*${TOPDIR}/lmi/scripts/\(.*\)$:\1:" -e "s:/:.:g"`
- basename -s .py "$path"
-}
-
-function get_version_string() {
- out=`python $TOPDIR/setup.py --version`
- git_version=`git describe HEAD 2>/dev/null`
- echo -n "\`\`$out\`\`"
- if [ -n "$git_version" ]; then
- echo ", git: \`\`$git_version\`\`"
- fi
-}
-
-# api.rst header
-cat >$TOPDIR/doc/api.rst <<_EOF_
-OpenLMI Scripts API
-===================
-
-This is a generated documentation form *OpenLMI Scripts* sources.
-
-Developer of script library will be interested in
-:py:mod:\`lmi.scripts.common\` package providing useful functionality to
-script development.
-
-Generated from version: $(get_version_string)
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
-_EOF_
-
-# Generate modules/*.rst
-for module_path in `get_modules`; do
- module=`echo "$module_path" | get_module_name`
- out=$module.rst
- len=`echo $module| wc -c`
- len=$(($len-1))
- underline=""
- for i in `seq $len`; do underline="=$underline"; done
-
- cat >$TOPDIR/doc/modules/$out <<_EOF_
-$module
-$underline
-.. automodule:: lmi.scripts.$module
- :members:
-_EOF_
- echo >>$TOPDIR/doc/api.rst " modules/$module"
-done
diff --git a/doc/index.rst b/doc/index.rst
deleted file mode 100644
index c95879e..0000000
--- a/doc/index.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-OpenLMI Scripts documentation
-=============================
-
-Client-side python modules and command line utilities. Contains python
-libraries for interfacing with OpenLMI providers through local or remote CIMOM
-with WBEM as a protocol in between. It also contains `lmi` meta-command
-allowing to instrument these libraries from command line.
-
-Content:
-
-.. toctree::
- :maxdepth: 2
-
- usage
- configuration
- script-development
- api
- commands
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/doc/make.bat b/doc/make.bat
deleted file mode 100644
index c9db9bc..0000000
--- a/doc/make.bat
+++ /dev/null
@@ -1,190 +0,0 @@
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
-set I18NSPHINXOPTS=%SPHINXOPTS% source
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenLMIScripts.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenLMIScripts.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-:end
diff --git a/doc/mylf/README.md b/doc/mylf/README.md
deleted file mode 100644
index b3e7107..0000000
--- a/doc/mylf/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-MyLF
-====
-A complete source for step-by-step tutorial hosted on
-https://fedorahosted.org/openlmi/wiki/scripts/tutorial.
-
-It provides similar functionality as `logicalfile` script and operates upon the
-same set of providers.
diff --git a/doc/mylf/doc/Makefile b/doc/mylf/doc/Makefile
deleted file mode 100644
index 5efe803..0000000
--- a/doc/mylf/doc/Makefile
+++ /dev/null
@@ -1,177 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = _build
-COMMAND_NAME := mylf
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext cmdregen cmdline.generated
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " singlehtml to make a single large HTML file"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " devhelp to make HTML files and a Devhelp project"
- @echo " epub to make an epub"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " texinfo to make Texinfo files"
- @echo " info to make Texinfo files and run them through makeinfo"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
- @echo " "
- @echo " cmdregen to regenerate cmdline.generated with actual content from installed lmi help"
-
-cmdregen: cmdline.generated
-
-cmdline.generated:
- if ! python -c 'import lmi.scripts.$(COMMAND_NAME)' >/dev/null; then \
- echo "Please install install the command library first." >&2; \
- exit 1; \
- fi
- ( \
- echo ".."; \
- echo " !!!!!!!!!"; \
- echo -n " This is generated file. Use 'make cmdregen' to regenerate it"; \
- echo " from installed 'lmi help <CMD_NAME>'"; \
- echo " !!!!!!!!!"; \
- echo ; \
- for i in `sed -n '/entry_points/,/)/p' ../setup.py | \
- sed -n "s/\s*,\?['\"]\s*\([a-z-]\+\)\s*=.*/\1/p"`; do \
- lmi help $$i | python ../../../tools/help2rst $$i | \
- tr -d '\033' |sed 's/..1034h//'; \
- done \
- ) > $@
-
-clean:
- -rm -rf $(BUILDDIR)/*
-
-html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenLMIMyLFscripts.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenLMIMyLFscripts.qhc"
-
-devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
- @echo
- @echo "Build finished."
- @echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/OpenLMIMyLFscripts"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenLMIMyLFscripts"
- @echo "# devhelp"
-
-epub:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make' in that directory to run these through (pdf)latex" \
- "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through pdflatex..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo
- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
- @echo "Run \`make' in that directory to run these through makeinfo" \
- "(use \`make info' here to do that automatically)."
-
-info:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo "Running Texinfo files through makeinfo..."
- make -C $(BUILDDIR)/texinfo info
- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
- @echo
- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/mylf/doc/cmdline.rst b/doc/mylf/doc/cmdline.rst
deleted file mode 100644
index ae96494..0000000
--- a/doc/mylf/doc/cmdline.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-LMI command line reference
-==========================
-..
- Write some description here.
-
-.. include:: cmdline.generated
diff --git a/doc/mylf/doc/conf.py b/doc/mylf/doc/conf.py
deleted file mode 100644
index 91e943c..0000000
--- a/doc/mylf/doc/conf.py
+++ /dev/null
@@ -1,285 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# OpenLMI MyLF scripts documentation build configuration file, created by
-# sphinx-quickstart on Wed Oct 2 08:58:25 2013.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'OpenLMI MyLF scripts'
-copyright = u'2013-2014, Red Hat, Inc.'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '0.0.1'
-# The full version, including alpha/beta/rc tags.
-release = '0.0.1'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'OpenLMIMyLFscriptsdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'OpenLMIMyLFscripts.tex', u'OpenLMI MyLF scripts Documentation',
- u'Michal', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'openlmimylfscripts', u'OpenLMI MyLF scripts Documentation',
- [u'Michal'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'OpenLMIMyLFscripts', u'OpenLMI MyLF scripts Documentation',
- u'Michal', 'OpenLMIMyLFscripts', 'One line description of project.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-
-# -- Options for Epub output ---------------------------------------------------
-
-# Bibliographic Dublin Core info.
-epub_title = u'OpenLMI MyLF scripts'
-epub_author = u'Michal'
-epub_publisher = u'Michal'
-epub_copyright = u'2013-2014, Red Hat, Inc.'
-
-# The language of the text. It defaults to the language option
-# or en if the language is not set.
-#epub_language = ''
-
-# The scheme of the identifier. Typical schemes are ISBN or URL.
-#epub_scheme = ''
-
-# The unique identifier of the text. This can be a ISBN number
-# or the project homepage.
-#epub_identifier = ''
-
-# A unique identification for the text.
-#epub_uid = ''
-
-# A tuple containing the cover image and cover page html template filenames.
-#epub_cover = ()
-
-# HTML files that should be inserted before the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_pre_files = []
-
-# HTML files shat should be inserted after the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_post_files = []
-
-# A list of files that should not be packed into the epub file.
-#epub_exclude_files = []
-
-# The depth of the table of contents in toc.ncx.
-#epub_tocdepth = 3
-
-# Allow duplicate toc entries.
-#epub_tocdup = True
diff --git a/doc/mylf/doc/index.rst b/doc/mylf/doc/index.rst
deleted file mode 100644
index dc7a55f..0000000
--- a/doc/mylf/doc/index.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-.. OpenLMI MyLF scripts documentation master file, created by
- sphinx-quickstart on Wed Oct 2 08:58:25 2013.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-Welcome to OpenLMI MyLF scripts's documentation!
-================================================
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- cmdline
- python
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
diff --git a/doc/mylf/doc/make.bat b/doc/mylf/doc/make.bat
deleted file mode 100644
index 4fc6844..0000000
--- a/doc/mylf/doc/make.bat
+++ /dev/null
@@ -1,190 +0,0 @@
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=_build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
-set I18NSPHINXOPTS=%SPHINXOPTS% .
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenLMIMyLFscripts.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenLMIMyLFscripts.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-:end
diff --git a/doc/mylf/lmi/__init__.py b/doc/mylf/lmi/__init__.py
deleted file mode 100644
index b1a2ff0..0000000
--- a/doc/mylf/lmi/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/doc/mylf/lmi/scripts/__init__.py b/doc/mylf/lmi/scripts/__init__.py
deleted file mode 100644
index b1a2ff0..0000000
--- a/doc/mylf/lmi/scripts/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/doc/mylf/lmi/scripts/mylf/__init__.py b/doc/mylf/lmi/scripts/mylf/__init__.py
deleted file mode 100644
index 18bebbb..0000000
--- a/doc/mylf/lmi/scripts/mylf/__init__.py
+++ /dev/null
@@ -1,191 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-import os
-
-from lmi.shell import LMIInstance, LMIInstanceName
-from lmi.scripts.common import errors
-from lmi.scripts.common import get_logger
-
-LOG = get_logger(__name__)
-
-def logical_file_type_name(file_identity):
- """
- Get a name of file type for supplied instance of ``CIM_LogicalFile``.
- """
- namemap = {
- 'lmi_datafile' : 'file',
- 'lmi_unixdevicefile' : 'device',
- 'lmi_unixdirectory' : 'directory',
- 'lmi_fifopipefile' : 'fifo',
- 'lmi_symboliclink' : 'symlink',
- 'lmi_unixsocket' : 'socket'
- }
- try:
- return namemap[file_identity.classname.lower()]
- except KeyError:
- LOG().warn('Unhandled logical file class "%s".',
- file_identity.classname)
- return 'unknown'
-
-def permission_string(file_identity):
- """
- Make a ls-like permission string for supplied instance of
- ``CIM_LogicalFile``.
- """
- return ''.join(l if getattr(file_identity, a) else '-'
- for l, a in zip('rwx', ('Readable', 'Writeable', 'Executable')))
-
-def get_computer_system(ns):
- """
- :returns: Instance of ``Linux_ComputerSystem``.
- """
- if not hasattr(get_computer_system, 'instance'):
- get_computer_system.instance = ns.Linux_ComputerSystem.first_instance()
- return get_computer_system.instance
-
-def get_unix_file_instance(ns, path, dereference=False):
- """
- :param boolean dereference: Whether to follow symbolic links
- :returns: Instance of ``LMI_UnixFile`` corresponding to given *path*.
- """
- cs = get_computer_system(ns)
- uf_name = ns.LMI_UnixFile.new_instance_name({
- 'CSCreationClassName' : cs.classname,
- 'CSName' : cs.name,
- 'LFName' : path,
- 'LFCreationClassName' : 'ignored',
- 'FSCreationClassName' : 'ignored',
- 'FSName' : 'ignored',
- })
- try:
- uf = uf_name.to_instance()
- if dereference:
- lf = get_logical_file_instance(ns, uf, False)
- if logical_file_type_name(lf) == 'symlink':
- try:
- target = lf.TargetFile
- if not os.path.isabs(target):
- target = os.path.abspath(
- os.path.join(os.path.dirname(lf.Name), target))
- # recursively try to dereference
- uf = get_unix_file_instance(ns, target, dereference)
- except Exception as err:
- LOG.warn('failed to get link target "%s": %s',
- lf.TargetLink, err)
- return uf
- except:
- raise errors.LmiFailed('No such file or directory: "%s".' % path)
-
-def get_logical_file_instance(ns, file_ident, dereference=False):
- """
- Get an instance of ``CIM_LogicalFile`` corresponding to given file
- identity.
-
- :param file_ident: Either a file path or an instance of ``LMI_UnixFile``.
- :param boolean dereference: Whether to follow symbolic links
- """
- if isinstance(file_ident, basestring):
- uf = get_unix_file_instance(ns, file_ident, dereference)
- elif isinstance(file_ident, LMIInstanceName):
- uf = file_ident.to_instance()
- else:
- uf = file_ident
- return uf.first_associator(AssocClass='LMI_FileIdentity')
-
-def make_directory_instance_name(ns, directory):
- """
- Retrieve object path of a directory.
-
- :type directory: string
- :param directory: Full path to the directory.
- :rtype: :py:class:`lmi.shell.LMIInstanceName`
- """
- if directory != '/':
- directory = directory.rstrip('/')
- cs = get_computer_system(ns)
- return ns.LMI_UnixDirectory.new_instance_name(
- { 'CSCreationClassName' : cs.classname
- , 'CSName' : cs.name
- , 'CreationClassName' : 'LMI_UnixDirectory'
- , 'FSCreationClassName' : 'LMI_LocalFileSystem'
- , 'FSName' : ''
- , 'Name' : directory})
-
-def get_directory_instance(ns, directory):
- """
- Retrieve instance of `LMI_UnixDirectory`.
-
- :type directory: string of :py:class:`lmi.shell.LMIInstanceName`
- :param directory: Full path to the directory or its instance name.
- :rtype: :py:class:`lmi.shell.LMIInstance`
- """
- if isinstance(directory, basestring):
- directory = make_directory_instance_name(ns, directory)
- if isinstance(directory, LMIInstanceName):
- directory = directory.to_instance()
- return directory
-
-def list_directory(ns, directory, file_type='any'):
- """
- Yields instances of ``CIM_LogicalFile`` representing direct children of the
- given directory.
-
- :param directory: Either a file path or an instance of
- ``LMI_UnixDirectory``.
- :param file_type: Filter of files made by checking their type. One of: ::
-
- {'any', 'file', 'device', 'directory', 'fifo', 'symlink', 'socket'}
- """
- def _generate_children():
- for child in get_directory_instance(ns, directory).associators(
- AssocClass='LMI_DirectoryContainsFile',
- Role='GroupComponent',
- ResultRole='PartComponent'):
- if ( file_type and file_type != 'any'
- and logical_file_type_name(child) != file_type):
- continue
- yield child
- return sorted(_generate_children(), key=lambda i: i.Name)
-
-def create_directory(ns, directory):
- """
- Create a directory.
-
- :type directory: string
- :param directory: Full path to the directory.
- """
- ns.LMI_UnixDirectory.create_instance(
- make_directory_instance_name(ns, directory).path.keybindings)
-
-def delete_directory(ns, directory):
- """
- Delete an empty directory.
-
- :param directory: Either a file path or an instance of
- ``LMI_UnixDirectory``.
- """
- get_directory_instance(ns, directory).delete()
diff --git a/doc/mylf/lmi/scripts/mylf/cmd.py b/doc/mylf/lmi/scripts/mylf/cmd.py
deleted file mode 100644
index 59b0f32..0000000
--- a/doc/mylf/lmi/scripts/mylf/cmd.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-
-"""
-Read informations about file system structure.
-
-Usage:
- %(cmd)s list [options] <directory>
- %(cmd)s show [-L] <file>
- %(cmd)s create <directory>
- %(cmd)s delete <directory>
-
-Options:
- -t --type <type> Filter listed files by their type. One of:
- any, file, device, directory, fifo, symlink, socket.
- Defaults to any.
- -L --dereference Causes symlink to be followed.
-"""
-
-from lmi.scripts import mylf
-from lmi.scripts.common import command
-from lmi.scripts.common import errors
-
-class Show(command.LmiLister):
- COLUMNS = ('Attribute', 'Value')
-
- def transform_options(self, options):
- options['<path>'] = options.pop('<file>')
-
- def execute(self, ns, path, _dereference):
- uf = mylf.get_unix_file_instance(ns, path, _dereference)
- lf = mylf.get_logical_file_instance(ns, uf, _dereference)
- return [
- ('Path' , lf.Name),
- ('Type' , mylf.logical_file_type_name(lf)),
- ('User ID' , uf.UserID),
- ('Group ID' , uf.GroupID),
- ('Size' , lf.FileSize),
- ('Permissions' , mylf.permission_string(lf))
- ]
-
-class List(command.LmiInstanceLister):
- CALLABLE = mylf.list_directory
- PROPERTIES = (
- 'Name',
- ('Type', mylf.logical_file_type_name),
- ('Permissions', mylf.permission_string),
- ('Size', 'FileSize'))
-
- def verify_options(self, options):
- if ( options['--type'] is not None
- and not options['--type'].lower() in {
- 'any', 'file', 'directory', 'symlink', 'dev', 'socket', 'fifo'}):
- raise errors.LmiInvalidOptions(
- 'Unsupported type: %s' % options['--type'])
-
- def transform_options(self, options):
- file_type = options.pop('--type')
- if file_type is None:
- file_type = 'any'
- options['file-type'] = file_type
-
-class Create(command.LmiCheckResult):
- EXPECT = None
- CALLABLE = mylf.create_directory
-
-class Delete(command.LmiCheckResult):
- EXPECT = None
- CALLABLE = mylf.delete_directory
-
-MyLF = command.register_subcommands('MyLF', __doc__,
- { 'show' : Show
- , 'list' : List
- , 'create' : Create
- , 'delete' : Delete
- })
diff --git a/doc/mylf/setup.py b/doc/mylf/setup.py
deleted file mode 100644
index 9281962..0000000
--- a/doc/mylf/setup.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env python
-# -*- encoding: utf-8 -*-
-
-from setuptools import setup
-
-try:
- long_description = open('README.md', 'rt').read()
-except IOError:
- long_description = ''
-
-setup(
- name='openlmi-scripts-mylf',
- version='0.0.1',
- description='OpenLMI scripts for LogicalFile profile',
- long_description=long_description,
- author=u'Michal',
- author_email='Minar',
- url='https://github.com/openlmi/openlmi-mylf',
- download_url='https://github.com/openlmi/openlmi-mylf/tarball/master',
- platforms=['Any'],
- license="BSD",
- classifiers=[
- 'License :: OSI Approved :: BSD License',
- 'Operating System :: POSIX :: Linux',
- 'Topic :: System :: Systems Administration',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Intended Audience :: Developers',
- 'Environment :: Console',
- ],
-
- install_requires=['openlmi-scripts'],
-
- namespace_packages=['lmi', 'lmi.scripts'],
- packages=['lmi', 'lmi.scripts', 'lmi.scripts.mylf'],
- include_package_data=True,
-
- entry_points={
- 'lmi.scripts.cmd': [
- 'mylf = lmi.scripts.mylf.cmd:MyLF',
- ],
- },
- )
diff --git a/doc/script-development.rst b/doc/script-development.rst
deleted file mode 100644
index a4ec801..0000000
--- a/doc/script-development.rst
+++ /dev/null
@@ -1,668 +0,0 @@
-Script Development
-==================
-This provides a general overview on what script is, how is it written
-and is interfaced with.
-
-Prerequisities
---------------
-Reader should be familiar about a CIM_ (Common Information Model). He should
-have a general idea about, what OpenLMI_ is and what it does. He should get
-familiar with ``lmishell``, which is a python binary shipped with
-openlmi-tools_.
-
-Also user should be acquinted with writing help strings for unix command line
-utilities [#]_.
-
-Introduction
-------------
-By a *script* in this document we mean:
-
- * Python library utilizing ``lmishell`` for instrumenting CIM providers
- through a CIMOM broker. It resides in ``lmi.scripts.<profile_name>``
- package, where ``<profile_name>`` corresponds to a DMTF profile or an
- arbitrary set of ``OpenLMI`` providers.
- * Command wrappers for this library as a set of classes inheriting from
- :py:class:`~lmi.scripts.common.command.base.LmiBaseCommand`. These may
- create a hierarchy of nested subcommands. They are the entry points of
- ``lmi`` meta-command to the wrapped functionality of library.
-
-Command wrappers are part of the library usually grouped in a single
-module named after the ``lmi`` subcommand or ``cmd``: ::
-
- lmi.scripts.<profile_name>.cmd
-
-Writing a library
------------------
-Library shall consist of a set of functions taking a namespace or
-connection object as a first argument. There are no special requirements
-on how to divide these functions into submodules. Use common sense. Smaller
-scripts can have all functionality in
-``lmi/scripts/<profile_name>/__init__.py`` module. With wrappers usually
-contained in ``lmi/scripts/<profile_name>/cmd.py``.
-
-Library should be written with an ease of use in mind. Functions should
-represent possible use cases of what can be done with particular
-providers instead of wrapping 1-to-1 a CIM class's methods in python
-functions.
-
-Any function that shall be called by a command wrapper must accect a
-``namespace`` argument, which by a convention is called ``ns``. It's an
-instance of :py:class:`lmi.shell.LMINamespace` providing quick access to
-represented CIM namespace [#]_ and its classes. It's also possible to specify
-that function shall be passed a raw :py:class:`lmi.shell.LMIConnection` object.
-For details see :ref:`function_invocation`.
-
-Service example
-~~~~~~~~~~~~~~~
-Suppose we have a service profile and we want to write a python interface
-for. Real provider implementation can be found at ``src/service`` directory
-in upstream git [#]_. For more information please refer to `service description`_.
-
-As you may see, this implements single CIM class ``LMI_Service`` with a few
-useful methods such as:
-
- * ``StartService()``
- * ``StopService()``
-
-We'd like our users to provide a way how to list system services, get a
-details for one of them and allow to start, stop and restart them.
-
-Simplified [#]_ version of some of these functions may look like this: ::
-
- def list_services(ns, kind='enabled'):
- for service in sorted(ns.LMI_Service.instances(),
- key=lambda i: i.Name):
- if kind == 'disabled' and service.EnabledDefault != \
- ns.LMI_Service.EnabledDefaultValues.Disabled:
- continue
- if kind == 'oneshot' and service.EnabledDefault != \
- ns.LMI_Service.EnabledDefaultValues.NotApplicable:
- continue
- if kind == 'enabled' and service.EnabledDefault != \
- ns.LMI_Service.EnabledDefaultValues.Enabled:
- # list only enabled
- continue
- yield service
-
-It yields instances of ``LMI_Service`` class. There is no need to use
-exclusively ``yield`` statement instead of ``return``. We prefer to use it in
-enumerating functions because of memory usage reduction (which is possible to
-occur in the future, when underlying components will also allow for lazy
-evaluation). Moreover user may limit the number of instances listed, reducing
-the number of instances evaluated.
-
-::
-
- from lmi.shell import LMIInstanceName
- from lmi.scripts.common import get_logger
- from lmi.scripts.common.errors import LmiFailed
-
- LOG = get_logger(__name__)
-
- def start_service(ns, service):
- if isinstance(service, basestring):
- # let's accept service as a string
- inst = ns.LMI_Service.first_instance(key="Name", value=service)
- name = service
- else: # or as LMIInstance or LMIInstanceName
- inst = service
- name = inst.path['Name']
- if inst is None:
- raise LmiFailed('No such service "%s".' % name)
- if isinstance(inst, LMIInstanceName):
- # we need LMIInstance
- inst = inst.to_instance()
- res = inst.StartService()
- if res == 0:
- LOG().debug('Started service "%s" on hostname "%s".',
- name, ns.hostname)
- return res
-
-In similar fashion, ``stop_service``, ``restart_service`` and others could be
-written.
-
-``ns`` argument typically points to ``root/cimv2`` namespace, which is the
-main implementation namespace for ``OpenLMI`` providers. One could also write
-these functions operating upon a connection object like this: ::
-
- def get_instance(c, service):
- inst = c.root.cimv2.LMI_Service.first_instance(
- key="Name", value=service)
- if inst is None:
- raise LmiFailed('No such service "%s".' % service)
- return inst
-
-User can then easily access any other namespace he may need. Command classes
-need to be informed about what wrapped function expects. This will be
-explained later in more detail (see :ref:`function_invocation`).
-
-The ``LOG`` variable provides acces to the logger of this module. Messages
-logged in this way end up in a log file [#]_ and console. Implicitly only
-warnings and higher priority messages are logged into a console. This is
-controllable with ``lmi`` parameters.
-
-Useful information should not be rendered or printed by these functions
-directly. Wrapper commands shall post-process instances or data returned,
-render useful information and print it on standard output stream.
-
-If operation fails due to some not-so-unexpected error, please use
-:py:class:`~lmi.scripts.common.errors.LmiFailed` exception with human readable
-description.
-
-For more *real world* examples, take a look on scripts already present in our
-`upstream git`_.
-
-.. _command_wrappers_overview:
-
-Command wrappers overview
--------------------------
-They are a set of commands wrapping up library's functionality in a set of
-commands creating a tree invocable by ``lmi`` meta-command. All commands are
-subclasses of :py:class:`~lmi.scripts.common.command.base.LmiBaseCommand`.
-
-Behaviour of commands is controlled by class properties such as these: ::
-
- class Show(command.LmiShowInstance):
- CALLABLE = 'lmi.scripts.service:get_instance'
- PROPERTIES = (
- 'Name',
- 'Caption',
- ('Enabled', lambda i: i.EnabledDefault == 2),
- ('Active', 'Started'),
- 'Status')
-
-Example above contains definition of **show** command for instances of
-``LMI_Service``. Its associated function is ``get_instance()`` located in
-``lmi.scripts.service`` module [#]_. Properties used will be described
-in detail later (see :ref:`lmi_instance_commands_properties`). Let's just say,
-that ``PROPERTIES`` specify a way how the instance is rendered.
-
-Top-level commands
-~~~~~~~~~~~~~~~~~~
-Are entry points of a script library. They are direct subcommands of ``lmi``.
-For example: ::
-
- $ lmi help
- $ lmi service list
- $ lmi sw show openlmi-providers
-
-``help``, ``service`` and ``sw`` are top-level commands. One script library
-(such as ``service`` above) can provide one or more of them. They need to be
-listed in a ``setup.py`` script in ``entry_points`` argument of ``setup()``
-function. More details will be noted later in `Writing setup.py`_.
-
-They contain usage string which is a documentation and prescription of
-command-line arguments in one string. This string is printed when user
-requests command's help: ::
-
- $ lmi help
-
-.. _usage_string:
-
-Usage string
-^^^^^^^^^^^^
-looks like this: ::
-
- """
- System service management.
-
- Usage:
- %(cmd)s list [--all | --disabled]
- %(cmd)s start <service>
-
- Options:
- --all List all services available.
- --disabled List only disabled services.
- """
-
-Format of this string is very important, it's parsed by a docopt_ command line
-parser, generating options dictionary for commands. Please refer to its
-documentation for details.
-
-.. note::
-
- There is one deviation to *classical* usage string. It's the use of
- ``%(cmd)s`` formatting mark. This is replaced with full command's name.
- Full name means that all subcommands and binary name prefixing current
- command on command line are part of it. So for example full name of
- command **list** in a following string passed to command line: ::
-
- lmi sw list pkgs
-
- is ``lmi sw list``.
-
- If parsing **sw** usage, it is just ``lmi sw``.
-
- Please use this notation instead of writing your own usages completely.
- Although it may work from command line, it won't work in interactive
- mode without ``%(cmd)s`` being used.
-
-.. _end-point_commands_introduction:
-
-End-point commands
-~~~~~~~~~~~~~~~~~~
-Are associated with one or more function of script library. They handle the
-following:
-
- 1. call docopt_ parser on command line arguments
- 2. make some name pre-processing on them (see
- :ref:`pre_processing_properties`)
- 3. verify them (see :ref:`end-point_commands`)
- 4. transform them (see :ref:`end-point_commands`)
- 5. pass them to associated function
- 6. collect results
- 7. render them and print them
-
-Developper of command wrappers needs to be familiar about each step. We will
-describe them later in details.
-
-There are following end-point commands available for subclassing:
-
- * ``LmiCheckResult`` (see :ref:`lmi_check_result`)
- * ``LmiLister`` (see :ref:`lmi_lister`)
- * ``LmiInstanceLister`` (see :ref:`lmi_instance_lister`)
- * ``LmiShowInstance`` (see :ref:`lmi_show_instance`)
-
-They differ in how they render the result obtained from associated function.
-
-These are listed in depth in :ref:`end-point_commands`.
-
-.. _command_multiplexers_introduction:
-
-Command multiplexers
-~~~~~~~~~~~~~~~~~~~~
-Provide a way how to group multiple commands under one. Suppose you want to
-list packages, repositories and files. All of these use cases need different
-arguments, and render different information so logically they should be
-represented by independent end-point commands. What binds them together is the
-user's wish to *list* something. He may wish for other things like *show*,
-*add*, *remove* etc. Having all combination of these wishes and things would
-generate a lot of commands under the top-level one. Let's instead group them
-under particular *wish* like this:
-
- * ``sw list packages``
- * ``sw list repositories``
- * ``sw list files``
- * ``sw show package``
-
-To reflect it in our commands definition hierarchy, we need to use
-:py:class:`~lmi.scripts.common.command.multiplexer.LmiCommandMultiplexer`
-command.
-
-::
-
- class Lister(command.LmiCommandMultiplexer):
- """ List information about packages, repositories or files. """
- COMMANDS = {
- 'packages' : PkgLister,
- 'repositories' : RepoLister,
- 'files' : FileLister
- }
-
-Where ``COMMANDS`` property maps subcommand classes to their names as will
-be passed on command line. Each command multiplexer consumes one command
-argument from command line, representing the subcommand and passes the rest
-of options to it. In this way we can create arbitrarily tall command trees.
-
-Top-level command is nothing else than a subclass of ``LmiCommandMultiplexer``.
-
-Specifying profile and class requirements
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Most commands require some provider installed on managed machine to work
-properly. Each such provider should be represented by an instance of
-``CIM_RegisteredProfile`` on remote broker. This instance looks like
-this (in MOF syntax): ::
-
- instance of CIM_RegisteredProfile {
- InstanceID = "OpenLMI+OpenLMI-Software+0.4.2";
- RegisteredOrganization = 1;
- OtherRegisteredOrganization = "OpenLMI";
- RegisteredVersion = "0.4.2";
- AdvertiseTypes = [2];
- RegisteredName = "OpenLMI-Software";
- };
-
-We are interested just in ``RegisteredName`` and ``RegisteredVersion``
-properties that we'll use for requirement specification.
-
-Requirement is written in *LMIReSpL* language. For its formal definition
-refer to documentation of :py:mod:`~lmi.scripts.common.versioncheck.parser`.
-Since the language is quite simple, few examples should suffice:
-
- ``'OpenLMI-Software < 0.4.2'``
- Requires OpenLMI Software provider to be installed in version lower
- than ``0.4.2``.
- ``'OpenLMI-Hardware == 0.4.2 & Openlmi-Software >= 0.4.2'``
- Requires both hardware and software providers to be installed in
- particular version. Short-circuit evaluation is utilized here. It
- means that in this example OpenLMI Software won't be queried unless
- OpenLMI Hardware is installed and having desired version.
- ``'profile "OpenLMI-Logical File" > 0.4.2'``
- If you have spaces in the name of profile, surround it in double
- quotes. ``profile`` keyword is optional. It could be also present in
- previous examples.
-
-Version requirements are not limited to profiles only. CIM classes may be
-specified as well:
-
- ``'class LMI_SoftwareIdentity >= 0.3.0 & OpenLMI-LogicalFile'``
- In case of class requirements the ``class`` keyword is mandatory. As
- you can see, version requirement is optional.
- ``'! (class LMI_SoftwareIdentity | class LMI_UnixFile)'``
- Complex expressions can be created with the use of brackets and other
- operators.
-
-One requirement is evaluated in these steps:
-
- Profile requirement
- 1. Query ``CIM_RegisteredProfile`` for instances with
- ``RegisteredName`` matching given name. If found, go to 2. Otherwise
- query ``CIM_RegisteredSubProfile`` [#subprof]_ for instances with
- ``RegisteredName`` matching given name. If not found return
- ``False``.
- 2. Select the (sub)profile with highest version and go to 3.
- 3. If the requirement has version specification then compare it to the
- value of ``RegisteredVersion`` using given operator. If the relation
- does not apply, return ``False``.
- 4. Return ``True``.
-
- Class requirement
- 1. Get specified class. If not found, return ``False``.
- 2. If the requirement has version specification then compare it to the
- value of ``Version`` [#missing_version]_ qualifier of
- obtained class using given operator. And if the relation
- does not apply, return ``False``.
- 3. Return ``True``.
-
-Now let's take a look, where these requirements can be specified.
-There is a special select command used to specify which command to load
-for particular version on remote broker. It can be written like this: ::
-
- from lmi.scripts.common.command import LmiSelectCommand
-
- class SoftwareCMD(LmiSelectCommand):
-
- SELECT = [
- ( 'OpenLMI-Software >= 0.4.2 & OpenLMI-LogicalFile'
- , 'lmi.scripts.software.current.SwLFCmd')
- , ( 'OpenLMI-Software >= 0.4.2'
- , 'lmi.scripts.software.current.SwCmd')
- , ('OpenLMI-Software', 'lmi.scripts.software.pre042.SwCmd')
- ]
-
-It says to load ``SwLFCmd`` command in case both OpenLMI Software and
-OpenLMI LogicalFile providers are installed. If not, load the ``SwCMD`` from
-``current`` module for OpenLMI Software with recent version and fallback to
-``SwCmd`` for anything else. If the OpenLMI Software provider is not available
-at all, no command will be loaded and exception will be raised.
-
-Previous command could be used as an entry point in your ``setup.py`` script
-(see the :ref:`entry_points`). There is also a utility that makes it look
-better: ::
-
- from lmi.scripts.common.command import select_command
-
- SoftwareCMD = select_command('SoftwareCMD',
- ( 'OpenLMI-Software >= 0.4.2 & OpenLMI-LogicalFile'
- , 'lmi.scripts.software.current.SwLFCmd'),
- ( 'OpenLMI-Software >= 0.4.2', 'lmi.scripts.software.current.SwCmd'),
- ('OpenLMI-Software', 'lmi.scripts.software.pre042.SwCmd')
- )
-
-.. seealso::
- Documentation of
- :py:class:`~lmi.scripts.common.command.select.LmiSelectCommand` and
- :py:class:`~lmi.scripts.common.command.helper.select_command`.
-
- And also notes on related :ref:`lmi_select_command_properties`.
-
-Command wrappers module
-~~~~~~~~~~~~~~~~~~~~~~~
-Usually consists of:
-
- 1. license header
- 2. usage dostring - parseable by docopt_
- 3. end-point command wrappers
- 4. single top-level command
-
-The top-level command is usally defined like this: ::
-
- Service = command.register_subcommands(
- 'Service', __doc__,
- { 'list' : Lister
- , 'show' : Show
- , 'start' : Start
- , 'stop' : Stop
- , 'restart' : Restart
- },
- )
-
-Where the ``__doc__`` is a usage string (see usage_string_) and module's doc
-string at the same time. It's mentioned in point 2. ``Service`` is a name,
-which will be listed in ``entry_points`` dictionary described in section below
-(entry_points_). The global variable's name we assign to should be the same as
-the value of the first argument to
-:py:func:`~lmi.scripts.common.command.helper.register_subcommands`. The last
-argument here is the dictionary mapping all subcommands of **service** to their
-names [#]_.
-
-Egg structure
-~~~~~~~~~~~~~
-Script library is distributed as an python egg, making it easy to distribute
-and install either to system or user directory.
-
-Following tree shows directory structure of *service* egg residing in
-`upstream git`_:
-
-.. only:: not latex
-
- ::
-
- commands/service
- ├── lmi
- │ ├── __init__.py
- │ └── scripts
- │ ├── __init__.py
- │ └── service
- │ ├── cmd.py
- │ └── __init__.py
- ├── README.md
- └── setup.py
-
-.. raw:: latex
-
- \begin{center}
- \begin{tikzpicture}[dirtree]
- \node {commands/service}
- child { node {lmi}
- child { node {\_\_init\_\_.py} }
- child { node {scripts}
- child { node {\_\_init\_\_.py} }
- child { node {service}
- child { node {cmd.py} }
- child { node {\_\_init\_\_.py} }
- }
- }
- }
- child { node {README.md} }
- child { node {setup.py} };
- \end{tikzpicture} \\
- \end{center}
-
-This library then can be imported with: ::
-
- from lmi.scripts import service
-
-``commands/service/scripts/service`` must be a package (directory with
-``__init__.py``) because ``lmi.scripts`` is a namespace package. It
-can have arbitrary number of modules and subpackages. The care should be taken
-to make the API easy to use and learn though.
-
-Writing ``setup.py``
---------------------
-Follows a minimal example of ``setup.py`` script for service library. ::
-
- from setuptools import setup, find_packages
- setup(
- name="openlmi-scripts-service",
- version="0.1.0",
- description='LMI command for system service administration.',
- url='https://github.com/openlmi/openlmi-scripts',
- platforms=['Any'],
- license="BSD",
- install_requires=['openlmi-scripts'],
- namespace_packages=['lmi', 'lmi.scripts'],
- packages=['lmi', 'lmi.scripts', 'lmi.scripts.service'],
-
- entry_points={
- 'lmi.scripts.cmd': [
- 'service = lmi.scripts.service.cmd:Service',
- ],
- },
- )
-
-.. _entry_points:
-
-Entry points
-~~~~~~~~~~~~
-The most notable argument here is ``entry_points`` which is a dictionary
-containing python namespaces where plugins are registered. In this case, we
-register single top-level command (see `Top-level commands`_) called
-``service`` in ``lmi.scripts.cmd`` namespace. This particular namespace is used
-by ``lmi`` meta-command when searching of registered user commands. ``Service``
-is a command multiplexer, created with a call to
-:py:func:`~lmi.scripts.common.command.helper.register_subcommands` grouping
-end-point commands together.
-
-Next example shows setup with more top-level commands
-(of storage scripts library): ::
-
- entry_points={
- 'lmi.scripts.cmd': [
- 'fs = lmi.scripts.storage.fs_cmd:Fs',
- 'partition = lmi.scripts.storage.partition_cmd:Partition',
- 'raid = lmi.scripts.storage.raid_cmd:Raid',
- 'lv = lmi.scripts.storage.lv_cmd:Lv',
- 'vg = lmi.scripts.storage.vg_cmd:Vg',
- 'storage = lmi.scripts.storage.storage_cmd:Storage',
- 'mount = lmi.scripts.storage.mount_cmd:Mount',
- ],
- },
-
-Conventions
------------
-There are several conventions you should try to follow in your shiny scripts.
-
-Logging messages
-~~~~~~~~~~~~~~~~
-In each module where logging facilities are going to be used, define global
-varibale ``LOG`` like this: ::
-
- from lmi.scripts.common import get_logger
-
- LOG = get_logger(__name__)
-
-It's a callable used throughout particular module in this way: ::
-
- LOG().warn('All the data of "%s" will be lost!', partition)
-
-Each message should be a whole sentence. It shall begin with an upper case
-letter and end with a dot or other sentence terminator.
-
-Bad example: ::
-
- LOG().info('processing %s', card)
-
-Exceptions
-~~~~~~~~~~
-Again all the exceptions should be initialized with messages forming
-a whole sentence.
-
-They will be catched and printed on *stderr* by lmi meta-command. If the
-*Trace* option in :ref:`sect_main` is on, traceback will be printed. There is
-just one exception. If the exception inherits from
-:py:class:`~lmi.scripts.common.errors.LmiError`, traceback won't be printed
-unless verbosity level is highest: ::
-
- # self refers to some command
- self.app.config.verbosity == self.app.config.OUTPUT_DEBUG
-
-This is a feature allowing for common error use-cases to be gracefully
-handled. In your scripts you should stick to using
-:py:class:`~lmi.scripts.common.errors.LmiFailed` for such exceptions.
-
-Following is an example of such a common error-case, where printing traceback
-does not add any interesting information: ::
-
- iname = ns.LMI_Service.new_instance_name({
- "Name": service,
- "CreationClassName" : "LMI_Service",
- "SystemName" : cs.Name,
- "SystemCreationClassName" : cs.CreationClassName
- })
- inst = iname.to_instance()
- if inst is None:
- raise errors.LmiFailed('No such service "%s".' % service)
- # process the service instance
-
-``service`` is a name provided by user. If such a service is not found,
-``inst`` will be assigned ``None``. In this case we don't want to continue in
-script's execution thus we raise an exception. We provide very clear message
-that needs no other comment. We don't want any traceback to be printed, thus
-the use of :py:class:`~lmi.scripts.common.errors.LmiFailed`.
-
-Detailed description
---------------------
-These pages provide more details of some aspects:
-
-.. toctree::
- :maxdepth: 2
-
- command-classes
- command-properties
-
-Tutorial
---------
-
-.. toctree::
- :maxdepth: 2
-
- script-tutorial
-
--------------------------------------------------------------------------------
-
-.. seealso::
-
- Docopt_ documentation.
-
- :ref:`command_classes`
-
- :ref:`command_properties`
-
- :ref:`script_tutorial`
-
--------------------------------------------------------------------------------
-
-.. [#] Described by a POSIX.
-.. [#] Default namespace is ``"root/cimv2"``.
-.. [#] view: https://fedorahosted.org/openlmi/browser/openlmi-providers
- git: ``ssh://git.fedorahosted.org/git/openlmi-providers.git/``
-.. [#] Simplified here means that there are no documentation strings
- and no type checking.
-.. [#] If logging to a file is enabled in configuration.
-.. [#] Precisely in an ``__init__.py`` module of this package.
-.. [#] These names must exactly match the names in usage strings.
-
-.. [#subprof] This is a subclass of ``CIM_RegisteredProfile`` thus it has the
- same properties.
-.. [#missing_version] If the Version qualifier is missing, -1 will be used
- for comparison instead of empty string.
-
-.. ****************************************************************************
-
-.. _CIM: http://dmtf.org/standards/cim
-.. _OpenLMI: http://fedorahosted.org/openlmi/
-.. _openlmi-tools: http://fedorahosted.org/openlmi/wiki/shell
-.. _docopt: http://docopt.org/
-.. _`service description`: https://fedorahosted.org/openlmi/wiki/service
-.. _`upstream git`: https://github.com/openlmi/openlmi-scripts
diff --git a/doc/script-tutorial.rst b/doc/script-tutorial.rst
deleted file mode 100644
index 517a9dd..0000000
--- a/doc/script-tutorial.rst
+++ /dev/null
@@ -1,447 +0,0 @@
-.. _script_tutorial:
-
-Script Tutorial
-===============
-
-This is a step-by-step tutorial on developing script library for
-*OpenLMI* providers.
-
-Required knowledge
-------------------
-
-You should be familiar with terms like *CIM*, *cimom*, *schema*,
-*provider*, *DMTF* profile.
-`This <http://fedorahosted.org/openlmi/wiki/ProviderTutorialIntroduction>`_
-short tutorial should be enough to get you started.
-
-You should also be familiar with scripting in *python* and
-`lmishell <http://www.openlmi.org/using_lmishell>`_ which we use heavily
-in snippets below.
-
-Preparation
------------
-
-This tutorial assumes you have ``tog-pegasus`` *cimom* up and running
-with ``openlmi-logicalfile`` providers installed and registered on
-remote host. We will connect to it from client machine which needs the
-following installed:
-
-* ``openlmi-python-base``
-* ``openlmi-tools``
-* ``openlmi-scripts``
-
-Installing python dependencies
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-For the first two items you may use standard rpms build for Fedora. The
-first one is available from ''OpenLMI Nightly'' repository having the
-newest builds:
-
-.. code-block:: sh
-
- cat > /etc/yum.repos.d/openlmi-nightly.repo
- [openlmi-nightly]
- name=openlmi-nightly
- baseurl=http://openlmi-rnovacek.rhcloud.com/rpm/rawhide/
- gpgcheck=0
- enabled = 1
- ^D
-
-And then run:
-
-.. code-block:: sh
-
- yum install openlmi-python-base openlmi-tools
-
-Or you may install them to your user directory as python eggs with
-``pip``:
-
-.. code-block:: sh
-
- pip install openlmi-python openlmi-tools
-
-The last one can only be installed with ``pip``:
-
-.. code-block:: sh
-
- pip install openlmi-scripts
-
-Or directly from git repository (viz `below <#install_from_git>`_).
-
-Setting up environment
-~~~~~~~~~~~~~~~~~~~~~~
-
-We'll stick to the process described
-`here <https://github.com/openlmi/openlmi-scripts#developing-lmi-scripts>`_
-that let us develop quickly without the need to reinstall anything while
-making changes.
-
-First let's check out our ``openlmi-scripts`` repository:
-
-::
-
- git clone https://github.com/openlmi/openlmi-scripts.git
- cd openlmi-scripts
-
-Optionally we may install ``openlmi-scripts`` to user directory if not
-having done yet:
-
-.. code-block:: sh
-
- python setup.py install --user
-
-Then let's set up the workspace directory:
-
-.. code-block:: sh
-
- WSP=~/.python_workspace
- mkdir $WSP
- # may be added to `$HOME/.profile` or `$HOME/.bashrc`
- export PYTHONPATH=$WSP:$PYTHONPATH
- export PATH="$PATH:$WSP"
-
-Making our command structure
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We'll use provided ``commands/make_new.py`` script to create the basic
-structure and ``setup.py`` file:
-
-.. code-block:: sh
-
- cd commands
- # this will ask us additional questions used to create setup.py file
- ./make_new.py mylf
-
-Because a script implementation for ``OpenLMI LogicalFile`` profile is
-already present in upstream repository (in ``commands/logicalfile``), we
-need to name our library distinctly (e.g. ``mylf``).
-
-Following structure should be created:
-
-::
-
- mylf
- ├── doc
- │   ├── _build
- │   ├── cmdline.rst
- │   ├── conf.py
- │   ├── err.log
- │   ├── index.rst
- │   ├── make.bat
- │   ├── _static
- │   └── _templates
- ├── lmi
- │   ├── __init__.py
- │   └── scripts
- │   ├── __init__.py
- │   └── mylf
- │   ├── cmd.py
- │   └── __init__.py
- ├── README.md
- └── setup.py
-
-We should check that everything matches in ``mylf/setup.py`` and correct
-any shortcomings.
-
-OpenLMI LogicalFile introduction
---------------------------------
-
-*OpenLMI LogicalFile* is a CIM provider which provides a way to read
-information about files and directories. The provider also allows to
-traverse the file hierarchy, create and remove empty directories.
-
-.. figure:: _static/logicalfile.png
- :align: center
- :alt: LogicalFile model
-
- LogicalFile model
-
-It consists mainly of few specializations of ``CIM_LogicalFile``
-representing any type of file on filesystem, ``LMI_UnixFile`` holding
-unix specific information for each such file and association classes
-between them. ``CIM_LogicalFile`` has following key properties inherited
-by ``LMI_*`` subclasses above:
-
-* **Name**
-* **CSName**
-* **CSCreationClassName**
-* ``FSCreationClassName``
-* ``CreationClassName``
-* ``FSName``
-
-Only those shown in **bold** are mandatory. Others are ignored when
-requesting an instance of ``CIM_LogicalFile``. This applies also to
-``LMI_UnixFile`` with **Name** being replaced with **LFName**. None of
-the presented classes supports enumeration of instances. Only references
-can be obtained.
-
-With ``CreateInstance()`` and ``DeleteInstance()`` calls issued on
-class/object of ``LMI_UnixDirectory`` we are able to create and delete
-directories.
-
-Writing usage string
-~~~~~~~~~~~~~~~~~~~~
-
-Usage string is a module's documentation, help message and a
-prescription for command line parser all-in-one. Writing it is pretty
-straightforward. Let's put it to ``mylf/lmi/scripts/mylf/cmd.py``:
-
-::
-
- """
- Read informations about file system structure.
-
- Usage:
- %(cmd)s list [options] <directory>
- %(cmd)s show [-L] <file>
- %(cmd)s create <directory>
- %(cmd)s delete <directory>
-
- Options:
- -t --type <type> Filter listed files by their type. One of:
- any, file, device, directory, fifo, symlink, socket.
- Defaults to any.
- -L --dereference Causes symlink to be followed.
- """
-
-The first line provides a short description shown in help of ``lmi``
-meta-command for its registered subcommand. Text under ``Usage:`` and
-``Options:`` are parsed by ``doctopt``. Please refer to its
-documentation at http://docopt.org for more information.
-
-**Note** the ``%(cmd)s`` string which needs to be present instead of
-``lmi mylf`` or similar command names.
-
-Let's add one more snippet so we can test it:
-
-::
-
- from lmi.scripts.common import command
-
- MyLF = command.register_subcommands('MyLF', __doc__, {})
-
-This creates a command multiplexer without any children (we'll add them
-later).
-
-And finally let's modify our ``mylf/setup.py`` by adding entry point:
-
-::
-
- entry_points={
- 'lmi.scripts.cmd': [
- 'mylf = lmi.scripts.mylf.cmd:MyLF',
- ],
- }
-
-Now we can install it and test it:
-
-.. code-block:: sh
-
- # make sure the $WSP is in $PYTHONPATH
- python mylf/stup.py develop --install-dir=$WSP
- lmi help
- lmi help mylf
-
-We should be able to see the usage string we've written.
-
-Implementing ``list``
-~~~~~~~~~~~~~~~~~~~~~
-
-Most of neccessary functionality has been implemented in previous
-snippet for the ``show`` command. Following snippet is enough to
-generate all the files in directory. Put it again to
-``mylf/lmi/scripts/mylf/__init__.py``.
-
-::
-
- def make_directory_instance_name(ns, directory):
- """
- Retrieve object path of a directory.
-
- :type directory: string
- :param directory: Full path to the directory.
- :rtype: :py:class:`lmi.shell.LMIInstanceName`
- """
- if directory != '/':
- directory = directory.rstrip('/')
- cs = get_computer_system(ns)
- return ns.LMI_UnixDirectory.new_instance_name(
- { 'CSCreationClassName' : cs.classname
- , 'CSName' : cs.name
- , 'CreationClassName' : 'LMI_UnixDirectory'
- , 'FSCreationClassName' : 'LMI_LocalFileSystem'
- , 'FSName' : ''
- , 'Name' : directory})
-
- def get_directory_instance(ns, directory):
- """
- Retrieve instance of `LMI_UnixDirectory`.
-
- :type directory: string of :py:class:`lmi.shell.LMIInstanceName`
- :param directory: Full path to the directory or its instance name.
- :rtype: :py:class:`lmi.shell.LMIInstance`
- """
- if isinstance(directory, basestring):
- directory = make_directory_instance_name(ns, directory)
- if isinstance(directory, LMIInstanceName):
- directory = directory.to_instance()
- return directory
-
- def list_directory(ns, directory, file_type='any'):
- """
- Yields instances of ``CIM_LogicalFile`` representing direct children of the
- given directory.
-
- :param directory: Either a file path or an instance of
- ``LMI_UnixDirectory``.
- :param file_type: Filter of files made by checking their type. One of: ::
-
- {'any', 'file', 'device', 'directory', 'fifo', 'symlink', 'socket'}
- """
- def _generate_children():
- for child in get_directory_instance(ns, directory).associators(
- AssocClass='LMI_DirectoryContainsFile',
- Role='GroupComponent',
- ResultRole='PartComponent'):
- if ( file_type and file_type != 'any'
- and logical_file_type_name(child) != file_type):
- continue
- yield child
- return sorted(_generate_children(), key=lambda i: i.Name)
-
-Note the ``associators()`` call on ``LMI_UnixDirectory`` instance. It
-enumerates all ``CIM_LogicalFile`` instances that are referenced by
-``LMI_DirectoryContainsFile`` associations. These represent a relation
-of parent directory and its direct children. Parent directory is
-referenced with ``GroupComponent`` role while the children with
-``PartComponent``. It's advisable to always provide as much information
-to calls like:
-
-- ``associators()``
-- ``associator_names()``
-- ``references()``
-- ``reference_names()``
-
-as possible. Without the ``AssocClass`` parameter given, broker would
-try to enumerate all instrumented association classes possible,
-resulting in very poor performance. Both ``Role`` and ``ResultRole``
-parameters need to be given here, otherwise a parent directory of the
-one being enumerated would also appear in output.
-
-Following subclass of ``LmiInstanceLister`` needs to be added to
-``mylf/lmi/scripts/mylf/cmd.py`` and added to ``MyLF`` subcommands
-dictionary (omitted for now).
-
-::
-
- class List(command.LmiInstanceLister):
- CALLABLE = mylf.list_directory
- PROPERTIES = (
- 'Name',
- ('Type', mylf.logical_file_type_name),
- ('Permissions', mylf.permission_string),
- ('Size', 'FileSize'))
-
- def verify_options(self, options):
- if ( options['--type'] is not None
- and not options['--type'].lower() in {
- 'any', 'file', 'directory', 'symlink', 'dev', 'socket', 'fifo'}):
- raise errors.LmiInvalidOptions(
- 'Unsupported type: %s' % options['--type'])
-
- def transform_options(self, options):
- file_type = options.pop('--type')
- if file_type is None:
- file_type = 'any'
- options['file-type'] = file_type
-
-Instead of defining our own ``execute()`` method, we just associate
-wrapped function defined previously using ``CALLABLE`` property. Thanks
-to the ability to transform option names in any way, we are not limited
-to the use of arguments as listed in usage string. Apart from renaming
-options, we also check for the value of ``--type``. Overriding
-``verify_options()`` to check for validity of options is the more
-preferred approach compared to delayed checking in associated function.
-
-Implementing ``create`` and ``delete``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Let's again start with content of ``mylf/lmi/scripts/mylf/__init__.py``
-module.
-
-::
-
- def create_directory(ns, directory):
- """
- Create a directory.
-
- :type directory: string
- :param directory: Full path to the directory.
- """
- ns.LMI_UnixDirectory.create_instance(
- make_directory_instance_name(ns, directory).path.keybindings)
-
- def delete_directory(ns, directory):
- """
- Delete an empty directory.
-
- :param directory: Either a file path or an instance of
- ``LMI_UnixDirectory``.
- """
- get_directory_instance(ns, directory).delete()
-
-``create_instance()`` call of any ``LMIClass`` creates a new instance,
-in this case we create an instance of ``LMI_UnixDirectory``. If it
-exists already, an exception will be raised. On the other hand,
-``delete_directory()`` operates on an ``LMIInstance`` which must exists.
-If directory does not exist or it's not empty, an exception will be
-raised.
-
-Now let's move on to ``mylf/lmi/scripts/mylf/cmd.py``:
-
-::
-
- class Create(command.LmiCheckResult):
- EXPECT = None
- CALLABLE = mylf.create_directory
-
- class Delete(command.LmiCheckResult):
- EXPECT = None
- CALLABLE = mylf.delete_directory
-
-``LmiCheckResult`` is a special command that prints no useful
-information. It allows us to check, whether the associated function
-returns expected result and prints an error if not. Here we expect
-``None``. Associated functions in this case throw an exception upon any
-error which have the same effect. For more information please refer to
-its
-`documentation <http://pythonhosted.org/openlmi-scripts/command-classes.html#lmicheckresult>`_.
-
-Test it
-~~~~~~~
-
-::
-
- lmi -h $HOST mylf create /root/some_directory
- # try it for the second time (it will fail)
- lmi -h $HOST mylf create /root/some_directory
- # now let's delete it
- lmi -h $HOST mylf delete /root/some_directory
- # try it for the second time (it will fail)
- lmi -h $HOST mylf delete /root/some_directory
-
-Summary
--------
-
-Now that the script is ready and tested, we may commit it, push it, do a
-pull request (on
-`github <https://help.github.com/articles/using-pull-requests>`_) and
-host it on `PyPI <https://pypi.python.org/pypi>`_:
-
-::
-
- python setup.py register
- python setup.py sdist upload
-
-You can also download source tarball :download:`tarball <_static/mylf.tar.gz>`.
-
diff --git a/doc/usage.rst b/doc/usage.rst
deleted file mode 100644
index 70e19ca..0000000
--- a/doc/usage.rst
+++ /dev/null
@@ -1,133 +0,0 @@
-`lmi` meta-command usage
-========================
-``lmi`` meta-command is a command line utility build on top of client-side
-libraries. Each library for particular set of providers can declare one or
-more commands that will be registered with ``lmi`` meta-command and will be
-available to user at command line.
-
-Running from command line
--------------------------
-It can run single command given on command line like this: ::
-
- lmi -h ${hostname} service list --all
-
-Getting help
-------------
-For detailed help run: ::
-
- lmi --help
-
-To get a list of available commands with short descriptions: ::
-
- lmi help
-
-For help on a particular registered command: ::
-
- lmi help service
-
-Running in interactive mode
----------------------------
-Or it can be run in interactive mode when command is omitted: ::
-
- lmi -h ${hostname}
- lmi> help
- ...
- lmi> sw search django
- ...
- lmi> sw install python-django
- ...
- lmi> exit
-
-The most important command is ``help`` which shows you possible commands.
-It also accepts arguments: ::
-
- lmi> help storage raid
-
-prints help for raid subcommand of storage command. The same behaviour is achieved
-with: ::
-
- lmi> storage raid --help
-
-Built-in commands
-~~~~~~~~~~~~~~~~~
-Interactive mode comes with few special commands. To get their list together
-with help, type: ::
-
- lmi> : help
-
-They are prefixed with ``:`` and optional space. Currently only namespace nesting
-commands are supported. Those are ``:cd``, ``:..`` and ``:pwd``.
-
-Command namespaces
-~~~~~~~~~~~~~~~~~~
-Most end-point commands (also known as multiplexers) have one or more subcommands
-assigned. Namespace of such multiplexer is comprised of these subcommand's names.
-The root multiplexer (also known as top-level command) has namespace comprised of
-registered commands.
-
-.. figure:: _static/imode-tree.svg
- :align: center
- :alt: Command namespaces.
- :width: 600px
-
-Above figure depicts command tree. On the left side is a top-level command. It
-has two registered commands (``Storage`` and ``Software``) that creates its
-namespace. Each of them has their own sub-commands -- either another
-multiplexer (``LVCmd``, ``Repository``, etc.) or an end-point command.
-
-Under each multiplexer or top-level command is corresponding prompt with path.
-This prompt becomes active when ``:cd`` command is used to nest into particular
-command's namespace. Such a namespace begins an active one. Just one namespace
-can be active at a moment. Commands from non-active namespaces are not
-available. For example if ``RAIDCmd`` is currently active -- current command
-path is ``/lmi/storage/raid``, just ``list`` and ``delete`` commands are
-available ( note that in reality ``RAIDCMD`` has a lot more subcommands). Thus
-one can not write ``enable`` or ``disable`` which belongs to ``Repository``
-command's namespace.
-
-There is also something like global namespace containing static commands and
-built-ins. Commands from global namespace are accessible from any active
-namespace.
-
-Static commands
-+++++++++++++++
-
- +------+------------------------------------------------------------------+
- | EOF | Same as hitting ``^D``. If some nested into some subcommand's |
- | | namespace, it will map to ``:cd ..`` and parent namespace will |
- | | become active. If the top-level namespace is active, program |
- | | will exit. |
- +------+------------------------------------------------------------------+
- | exit | Exits immediately. It accepts optional exit code as an argument. |
- +------+------------------------------------------------------------------+
- | help | Lists available commands. Accepts command path as an optional |
- | | argument. |
- +------+------------------------------------------------------------------+
-
-Changing command namespaces
----------------------------
-Changing or nesting to some command namespace can be achieved with built-in
-commands ``:cd`` and ``:..``. The latter is just a shortcut for ``:cd ..`` that
-changes to parent namespace. ``:cd`` accepts a path to command. Whole command
-path begins with ``/lmi`` prefix which denotes top-level command. Path
-beginning with a ``'/'`` is an absolute path, which means it contains all
-command names on a path from top-level command to target one. Other paths are
-relative to current command.
-
-Here is a an example of changing command namespaces: ::
-
- lmi> :pwd
- /lmi
- lmi> :cd storage
- >storage> :pwd
- /lmi/storage
- >storage> :cd lv
- >>lv> :pwd
- /lmi/storage/lv
- >>lv> :cd ../raid
- >>raid> :cd ../../sw/repo
- >>repo> :..
- >sw> :cd /storage # /lmi prefix is optional for absolute paths
- >storage :cd /
- lmi>
-
diff --git a/lmi/__init__.py b/lmi/__init__.py
deleted file mode 100644
index ca65877..0000000
--- a/lmi/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/lmi/scripts/__init__.py b/lmi/scripts/__init__.py
deleted file mode 100644
index ca65877..0000000
--- a/lmi/scripts/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/lmi/scripts/_metacommand/__init__.py b/lmi/scripts/_metacommand/__init__.py
deleted file mode 100644
index affea7b..0000000
--- a/lmi/scripts/_metacommand/__init__.py
+++ /dev/null
@@ -1,239 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Subpackage containing functionality of lmi meta-command.
-"""
-
-import argparse
-import logging
-import sys
-
-from lmi.scripts import common
-from lmi.scripts.common import errors
-from lmi.scripts._metacommand import util
-from lmi.scripts._metacommand import exit
-from lmi.scripts._metacommand.help import Help
-from lmi.scripts._metacommand.manager import CommandManager
-from lmi.scripts._metacommand.interactive import Interactive
-from lmi.scripts._metacommand.toplevel import TopLevelCommand
-from lmi.scripts.common.command import LmiCommandMultiplexer, LmiBaseCommand
-from lmi.scripts.common.configuration import Configuration
-from lmi.scripts.common.session import Session
-from lmi.shell import LMIUtil
-
-LOG = common.get_logger(__name__)
-
-# write errors to stderr until logging is configured
-logging.getLogger('').addHandler(logging.StreamHandler())
-
-class MetaCommand(object):
- """
- Main application class. It instantiates configuration object, logging and
- then it passes control to commands.
-
- Example usage:
-
- MetaCommand().run()
- """
-
- def __init__(self):
- # allow exceptions in lmi shell
- LMIUtil.lmi_set_use_exceptions(True)
- # instance of CommandManager, created when first needed
- self._command_manager = None
- self.stdout = sys.stdout
- self.stderr = sys.stderr
- self.stdin = sys.stdin
- # instance of Session, created when needed
- self._session = None
- # instance of Configuration, created in setup()
- self.config = None
- # dictionary of not yet processed options, it's created in setup()
- self._options = None
- self._active_command = None
-
- def _configure_logging(self):
- """
- Setup logging. It expects Configuration object to be already
- initialized.
-
- Logging can be tuned in various ways:
-
- * In configuration file with options:
- * [Main] Verbosity
- * [Log] OutputFile
- * [Log] FileFormat
- * [Log] ConsoleFormat
- * [Log] ConsoleInfoFormat
- * [Log] LogToConsole
- * With command line options:
- ``-v`` flags :
- Each such flag increases logging level of what is logged
- into console. This overrides `[Main] Verbosity` option.
- ``-q`` :
- Causes supression of any output made to stdout except for
- error messages. This overrides ``[Main] Verbosity``.
- option and ``-v`` flags.
- ``--log-file`` :
- Output file for logging messages. This overrides ``[Log]
- OutputFile`` option.
-
- Implicitly only warnings and errors are logged to the standard error
- stream without any tracebacks.
- """
- util.setup_logging(self.config, self.stderr)
-
- @property
- def command_manager(self):
- """
- Return instance of ``CommandManager``. It's initialized when first
- needed.
-
- :rtype: (``CommandManager``)
- """
- if self._command_manager is None:
- self._command_manager = CommandManager()
- self._command_manager.add_command('help', Help)
- return self._command_manager
-
- @property
- def session(self):
- """
- Return instance of Session. Instantiated when first needed.
-
- :rtype: (``Session``)
- """
- if self._session is None:
- if ( not self._options['--host']
- and not self._options['--hosts-file']):
- self._options['--host'] = [util.get_default_hostname()]
- LOG().info('No hosts given, using "%s".',
- self._options['--host'][0])
- hostnames = []
- # credentials loaded from file
- credentials = {}
- def add_hosts(hosts, creds):
- """ Update hostnames and credentials for new data. """
- hostnames.extend(hosts)
- credentials.update(creds)
- if self._options['--hosts-file']:
- hosts_path = self._options['--hosts-file']
- try:
- with open(hosts_path, 'r') as hosts_file:
- add_hosts(*util.parse_hosts_file(hosts_file))
- except (OSError, IOError) as err:
- LOG().critical('Could not read hosts file "%s": %s',
- hosts_path, err)
- sys.exit(1)
- add_hosts(*util.get_hosts_credentials(self._options['--host']))
- if self._options['--user']:
- credentials.update({
- # credentials in file has precedence over --user option
- h : credentials.get(h, (self._options['--user'], ''))
- for h in hostnames if h not in credentials
- })
- self._session = Session(self, hostnames, credentials,
- same_credentials=self._options['--same-credentials'])
- return self._session
-
- @property
- def active_command(self):
- return self._active_command
- @active_command.setter
- def active_command(self, cmd):
- if not isinstance(cmd, LmiBaseCommand):
- raise TypeError("cmd must be an instance of LmiBaseCommand")
- self._active_command = cmd
-
- def print_version(self):
- """ Print version of this egg to stdout. """
- self.stdout.write("%s\n" % util.get_version())
-
- def setup(self, options):
- """
- Initialise global Configuration object and set up logging.
-
- :param options: (``dict``) Dictionary of options parsed from command
- line by docopt.
- """
- conf_kwargs = {}
- if options['--config-file']:
- conf_kwargs['user_config_file_path'] = options.pop('--config-file')
- self.config = Configuration.get_instance(**conf_kwargs)
- # two mutually exclusive options
- if options['--trace'] or options['--notrace']:
- self.config.trace = bool(options['--trace'])
- if options.pop('--quiet', False):
- self.config.verbosity = Configuration.OUTPUT_SILENT
- elif options['-v'] and options['-v'] > 0:
- self.config.verbosity = options['-v']
- if options.pop('--noverify', False):
- self.config.verify_server_cert = False
- self.config.log_file = options.pop('--log-file', None)
- self._configure_logging()
- del options['--trace']
- del options['--notrace']
- del options['-v']
- self.config.namespace = options.pop('--namespace', None)
- self.config.human_friendly = options.pop('--human-friendly', None)
- self.config.no_headings = options.pop('--no-headings', None)
- self.config.lister_format = options.pop('--lister-format', None)
- # unhandled options may be used later (for session creation),
- # so let's save them
- self._options = options
-
- def run(self, argv):
- """
- Equivalent to the main program for the application.
-
- :param argv: (``list``) Input arguments and options.
- Contains all arguments but the application name.
- """
- retval = exit.EXIT_CODE_FAILURE
- cmd = TopLevelCommand(self)
- try:
- retval = cmd.run(argv)
- except Exception as exc:
- if isinstance(exc, errors.LmiUnsatisfiedDependencies):
- retval = exit.EXIT_CODE_UNSATISFIED_DEPENDENCIES
- LOG().exception(str(exc))
- if isinstance(retval, bool) or not isinstance(retval, (int, long)):
- return ( exit.EXIT_CODE_SUCCESS if bool(retval) or retval is None
- else exit.EXIT_CODE_FAILURE)
-
- return retval
-
-def main(argv=sys.argv[1:]):
- """
- Main entry point function. It just passes arguments to instantiated
- ``MetaCommand``.
- """
- return MetaCommand().run(argv)
-
diff --git a/lmi/scripts/_metacommand/cmdutil.py b/lmi/scripts/_metacommand/cmdutil.py
deleted file mode 100644
index 986e835..0000000
--- a/lmi/scripts/_metacommand/cmdutil.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (c) 2013, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Utility functions for command inspection.
-"""
-from lmi.scripts.common import errors
-from lmi.scripts.common.command import LmiBaseCommand
-from lmi.scripts.common.command import LmiCommandMultiplexer
-
-def get_subcommand_names(command):
- """
- :param command: Either a multiplexer command or top-level one.
- :returns: Names of children commands.
- :rtype: list
- """
- if not isinstance(command, LmiBaseCommand):
- raise TypeError("command must be an instance of LmiBaseCommand")
- if isinstance(command, LmiCommandMultiplexer):
- return command.child_commands().keys()
- if command.parent is None: # top level command
- return command.app.command_manager.command_names
- raise ValueError("command must be either multiplexer or top-level command")
-
-def get_subcommand_factory(command, name):
- """
- :param command: Either a multiplexer command or top-level one.
- :returns: Callable returning an instance of
- :py:class:`~lmi.scripts.common.command.multiplexer.LmiCommandMultiplexer`
- :rtype: callable
- """
- if isinstance(command, LmiCommandMultiplexer):
- try:
- return command.child_commands()[name]
- except KeyError:
- cmd_path = command.cmd_name_parts
- cmd_path.append(name)
- raise errors.LmiCommandNotFound(" ".join(cmd_path))
- if command.parent is None: # top level command
- return command.app.command_manager.find_command(name)
- raise ValueError("command must be either multiplexer or top-level command")
-
diff --git a/lmi/scripts/_metacommand/exit.py b/lmi/scripts/_metacommand/exit.py
deleted file mode 100644
index e876073..0000000
--- a/lmi/scripts/_metacommand/exit.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Module containing help command.
-"""
-
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.command import LmiEndPointCommand
-from lmi.scripts.common import errors
-
-LOG = get_logger(__name__)
-
-EXIT_CODE_SUCCESS = 0
-EXIT_CODE_FAILURE = 1
-EXIT_CODE_KEYBOARD_INTERRUPT = 2
-EXIT_CODE_COMMAND_NOT_FOUND = 3
-EXIT_CODE_INVALID_SYNTAX = 4
-EXIT_CODE_UNSATISFIED_DEPENDENCIES = 5
-
-def _execute_exit(exit_code):
- """ Associated function with ``Exit`` command. """
- raise errors.LmiTerminate(exit_code)
-
-class Exit(LmiEndPointCommand):
- """
- Terminate the shell.
-
- Usage: %(cmd)s [<exit_code>]
- """
- CALLABLE = _execute_exit
- OWN_USAGE = True
-
- def verify_options(self, options):
- code = options['<exit_code>']
- if code is not None:
- try:
- int(code)
- except ValueError:
- raise errors.LmiInvalidOptions(
- "<exit_code> must be an integer not \"%s\"" % code)
-
- def transform_options(self, options):
- code = options.get('<exit_code>', None)
- if code is None:
- code = EXIT_CODE_SUCCESS
- options['<exit_code>'] = int(code)
-
diff --git a/lmi/scripts/_metacommand/help.py b/lmi/scripts/_metacommand/help.py
deleted file mode 100644
index b88f6b5..0000000
--- a/lmi/scripts/_metacommand/help.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-
-"""
-Module containing help command.
-"""
-
-from lmi.scripts.common import errors
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.command import LmiEndPointCommand
-from lmi.scripts._metacommand import cmdutil
-from lmi.scripts._metacommand import exit
-
-LOG = get_logger(__name__)
-
-class Help(LmiEndPointCommand):
- """
- Print the list of supported commands with short description.
- If a subcommand is given, its detailed help will be printed.
-
- Usage: %(cmd)s [<subcommand>...]
- """
- OWN_USAGE = True
-
- def execute(self, subcommand):
- mgr = self.app.command_manager
- node = self.app.active_command
- toplevel = self
- while toplevel.parent is not None:
- toplevel = toplevel.parent
-
- if node or subcommand:
- # Help for some subcommand will be printed.
- if node is None:
- node = toplevel
- if subcommand:
- index = 0
- try:
- while index < len(subcommand) and not node.is_end_point():
- while node.is_selector():
- cmd_factory, _ = node.select_cmds().next()
- node = cmd_factory(self.app, node.cmd_name,
- node.parent)
- # selector may return either multiplexer or end-point
- if node.is_end_point():
- break
- cmd_factory = cmdutil.get_subcommand_factory(node,
- subcommand[index])
- node = cmd_factory(self.app, subcommand[index], node)
- index += 1
- except errors.LmiCommandNotFound as err:
- LOG().error(str(err))
- if node is not toplevel:
- self.app.stdout.write(node.get_usage(True))
- if node is self.app.active_command:
- # show additional information only when no command given
- self.app.stdout.write('\nTo get help for built-in commands,'
- ' type:\n :help\n')
- return exit.EXIT_CODE_SUCCESS
-
- # let's print the summary of available commands
- self.app.stdout.write("Commands:\n")
- max_cmd_len = max(len(n) for n in mgr)
- cmd_line = " %%-%ds - %%s\n" % max_cmd_len
- for cmd in sorted(mgr):
- self.app.stdout.write(cmd_line
- % (cmd, mgr[cmd].get_description()
- .strip().split("\n", 1)[0]))
- self.app.stdout.write(
- "\nFor more informations about particular command type:\n"
- " help <command>\n")
-
- return exit.EXIT_CODE_SUCCESS
-
diff --git a/lmi/scripts/_metacommand/interactive.py b/lmi/scripts/_metacommand/interactive.py
deleted file mode 100644
index 349d622..0000000
--- a/lmi/scripts/_metacommand/interactive.py
+++ /dev/null
@@ -1,475 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Module with interactive application.
-"""
-
-import cmd
-import docopt
-import itertools
-import os
-import readline
-import shlex
-
-from lmi.scripts.common import errors
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.command import LmiBaseCommand, LmiCommandMultiplexer
-from lmi.scripts._metacommand import cmdutil
-from lmi.scripts._metacommand import exit
-
-LOG = get_logger(__name__)
-
-BUILT_INS_USAGE = """
-Built-ins.
-
-Usage:
- : cd [<path>]
- : ..
- : pwd
- : (help | -h | --help)
-
-Description:
- cd Nest to a subcommand. Accepts a sequence of subcommands separated
- with "/". If "/" is given, top-level command becomes the active one.
- Other supported special symbols are ".." and ".".
- .. Make parent command the active one. Same as issuing ":cd ..".
- pwd Print current command path.
- help Show this help.
-"""
-
-BUILT_INS = ('..', 'cd', 'pwd', 'help')
-
-class LmiBuiltInError(errors.LmiError):
- """ General exception concerning the use of built-in commands. """
- pass
-
-class LmiCanNotNest(LmiBuiltInError):
- """ Raised upon invalid use of *cd* built-in command. """
- pass
-
-class Interactive(cmd.Cmd):
- """
- Launched by the main application. It enters *shell* mode. Allows to launch
- set of commands interactively on all given hosts. Session object stays the
- same for the whole life of interactive mode.
-
- :param top_level_cmd: Top-level command.
- :type top_level_cmd: :py:class:`.toplevel.TopLevelCommand`
- """
-
- def __init__(self, top_level_cmd):
- self._top_level_cmd = top_level_cmd
- cmd.Cmd.__init__(self,
- stdin=top_level_cmd.app.stdin, stdout=top_level_cmd.app.stdout)
- self._last_exit_code = exit.EXIT_CODE_SUCCESS
- self.doc_header = 'Static commands'
- self.app.active_command = top_level_cmd
- self.load_history()
-
- # *************************************************************************
- # Properties
- # *************************************************************************
- @property
- def app(self):
- """ :returns: Application object. """
- return self._top_level_cmd.app
-
- @property
- def command_manager(self):
- """ :returns: An instance of :py:class:`~.manager.CommandManager`. """
- return self.app.command_manager
-
- @property
- def on_top_level_node(self):
- """
- :returns: Whether the current node is a top-level one. In other words
- we're not nested in any subcommand namespace.
- :rtype: boolean
- """
- return self._top_level_cmd is self.app.active_command
-
- @property
- def prompt(self):
- """
- :returns: Dynamically computed shell prompt.
- :rtype: string
- """
- if self.app.stdin.isatty():
- parents_num = 0
- node = self.app.active_command
- while node.parent is not None:
- parents_num += 1
- node = node.parent
- return '>'*parents_num + self.app.active_command.cmd_name + '> '
- return ''
-
- # *************************************************************************
- # Private methods
- # *************************************************************************
- def _change_to_node(self, path):
- """
- Handles any command path. It constructs an object of command
- corresponding to given path. Path can be absolute or relative.
-
- :param str path: Path to command. Looks similar to unix file path.
- Command names are separated with ``'/'``.
- :returns: Multiplexer command corresponding to path.
- :rtype: :py:class:`~lmi.scripts.common.command.multiplexer.LmiCommandMultiplexer`
- """
- cur_node = self.app.active_command
- if path.startswith('/'):
- if path.startswith('/lmi'):
- path = path[4:]
- else:
- path = path[1:]
- cur_node = self._top_level_cmd
-
- cmd_chain = os.path.normpath(path).split('/')
- for subcmd in cmd_chain:
- if subcmd == '..':
- cur_node = ( cur_node.parent
- if cur_node.parent is not None else cur_node)
- elif subcmd and subcmd != '.':
- if not subcmd in cmdutil.get_subcommand_names(cur_node):
- raise LmiCanNotNest('No such subcommand "%s".' %
- "/".join(cmd_chain))
- cmd_cls = cmdutil.get_subcommand_factory(cur_node, subcmd)
- if not issubclass(cmd_cls, LmiCommandMultiplexer):
- raise LmiCanNotNest('Can not nest to subcommand "%s" which'
- " is not a multiplexer." % "/".join(cmd_chain))
- if not cmd_cls.has_own_usage():
- raise LmiCanNotNest('Can not nest to subcommand "%s" which'
- ' lacks any help message.' % "/".join(cmd_chain))
- cur_node = cmd_cls(self.app, subcmd, cur_node)
- self.app.active_command = cur_node
- return exit.EXIT_CODE_SUCCESS
-
- def _do_built_in_cmd(self, args):
- """
- Execute built-in command.
-
- :param list args: Command arguments including command name.
- """
- options = docopt.docopt(BUILT_INS_USAGE, args, help=False)
- if options['cd']:
- path = '.' if not options.get('<path>', None) else options['<path>']
- return self._change_to_node(path)
- elif options['..']:
- return self._change_to_node('..')
- elif options['pwd']:
- self.app.stdout.write("/"
- + "/".join(self.app.active_command.get_cmd_name_parts(
- all_parts=True)) + "\n")
- elif options['help'] or options['-h'] or options['--help']:
- self.app.stdout.write(BUILT_INS_USAGE[1:])
- return exit.EXIT_CODE_SUCCESS
-
- def _execute_line_parts(self, line_parts):
- """
- Try to execute given line. This method can throw various exceptions
- that needs to be handled by a caller, otherwise interactive mode will
- be terminated.
-
- :param list line_parts: Parsed command line arguments.
- :returns: Command's exit code.
- """
- if line_parts[0][0] == ':':
- if len(line_parts[0]) > 1:
- line_parts[0] = line_parts[0][1:]
- else:
- line_parts = line_parts[1:]
- return self._do_built_in_cmd(line_parts)
-
- else:
- # let's try to run registered subcommand
- retval = self.run_subcommand(line_parts)
- if isinstance(retval, bool) or not isinstance(retval, (int, long)):
- retval = ( exit.EXIT_CODE_SUCCESS
- if bool(retval) or retval is None
- else exit.EXIT_CODE_FAILURE)
- return retval
-
- # *************************************************************************
- # Public methods
- # *************************************************************************
- def complete(self, text, state):
- """
- Overrides parent's method so that registered commands can be also
- completed.
- """
- if state == 0:
- import readline
- origline = readline.get_line_buffer()
- line = origline.lstrip()
- stripped = len(origline) - len(line)
- begidx = readline.get_begidx() - stripped
- endidx = readline.get_endidx() - stripped
- command, _, _ = self.parseline(line)
- compfunc = self.completedefault
- if command and hasattr(self, 'complete_' + command):
- compfunc = getattr(self, 'complete_' + command)
- self.completion_matches = compfunc(text, line, begidx, endidx)
- try:
- return self.completion_matches[state]
- except IndexError:
- return None
-
- def completedefault(self, text, line, *_args, **_kwargs):
- """
- Tab-completion for commands known to the command manager and subcommands
- in current command namespace. Does not handle command options.
- """
- if line.startswith(':'):
- commands = BUILT_INS
- else:
- commands = set(self.completenames(text))
- commands.update(set(cmdutil.get_subcommand_names(self.app.active_command)))
- completions = sorted(n for n in commands
- if not text or n.startswith(text))
- return completions
-
- def clear_history(self):
- """ Clear readline history. """
- readline.clear_history()
-
- def default(self, line):
- """
- This is run, when line contains unknown command to ``cmd.Cmd``. It
- expects us to handle it if we know it, or print an error.
-
- :param str line: Line given to our shell.
- """
- try:
- line_parts = shlex.split(line)
- except ValueError as err:
- LOG().error(str(err))
- return exit.EXIT_CODE_INVALID_SYNTAX
-
- try:
- self._execute_line_parts(line_parts)
-
- except docopt.DocoptExit as err:
- # command found, but options given to it do not comply with its
- # usage string
- if '--help' in line_parts:
- return self.do_help(" ".join(
- line_parts[:line_parts.index('--help')]))
- LOG().warn("Wrong options given: %s", line.strip())
- self.stdout.write(str(err))
- if ( line_parts[0] in cmdutil.get_subcommand_names(
- self.app.active_command)
- and cmdutil.get_subcommand_factory(self.app.active_command,
- line_parts[0]).is_end_point()):
- self.stdout.write("\n\nTo see a full usage string, type:\n"
- " help %s\n" % line_parts[0])
- else:
- self.stdout.write("\n\nTo see a list of available commands,"
- " type:\n help\n")
- self._last_exit_code = exit.EXIT_CODE_FAILURE
-
- except errors.LmiCommandNotFound as err:
- LOG().error(str(err))
- self._last_exit_code = exit.EXIT_CODE_COMMAND_NOT_FOUND
-
- except errors.LmiUnsatisfiedDependencies as err:
- LOG().error(str(err))
- self._last_exit_code = exit.EXIT_CODE_UNSATISFIED_DEPENDENCIES
-
- except errors.LmiError as err:
- LOG().error(str(err))
- self._last_exit_code = exit.EXIT_CODE_FAILURE
-
- except KeyboardInterrupt as err:
- LOG().debug('%s: %s', err.__class__.__name__, str(err))
- self._last_exit_code = exit.EXIT_CODE_KEYBOARD_INTERRUPT
-
- return self._last_exit_code
-
- def do_EOF(self, _arg): #pylint: disable=C0103,R0201
- """
- Exit on End-Of-File if we are on top-level command. Otherwise change
- to parent command.
- """
- if self.app.stdin.isatty():
- self.app.stdout.write('\n')
- if self.app.stdin.isatty() and not self.on_top_level_node:
- self._change_to_node('..')
- else:
- raise errors.LmiTerminate(self._last_exit_code)
-
- def do_exit(self, arg):
- """
- This makes the exit command work in both (non-)interactive modes.
- """
- command = ["exit"]
- if arg:
- command.append(arg)
- return self.run_subcommand(command)
-
- def do_help(self, arg):
- """ Handle help subcommand. """
- if arg:
- try:
- arg_parts = shlex.split(arg)
- except ValueError as err:
- LOG().error(str(err))
- return exit.EXIT_CODE_INVALID_SYNTAX
-
- method_name = '_'.join(
- itertools.chain(['do'],
- itertools.takewhile(lambda x: not x.startswith('-'),
- arg_parts)))
- if hasattr(self, method_name):
- return cmd.Cmd.do_help(self, arg)
- else:
- arg_parts = []
-
- if ( self.on_top_level_node
- and ( not arg
- or ( len(arg_parts) == 1
- and arg not in self.app.command_manager.command_names))):
- if not self.completenames(arg):
- LOG().error(str(errors.LmiCommandNotFound(arg)))
- cmd.Cmd.do_help(self, '')
- else:
- cmd.Cmd.do_help(self, arg)
- cmd_names = set(self.command_manager)
- cmd_names.difference_update(set(self.completenames('')))
- self.print_topics(
- "Application commands (type help <topic>):",
- sorted(cmd_names), 15, 80)
- self.print_topics(
- "Built-in commands (type :help):",
- [':'+bi for bi in BUILT_INS], 15, 80)
- return exit.EXIT_CODE_SUCCESS
-
- return self.run_subcommand(['help'] + arg_parts)
-
- def emptyline(self): #pylint: disable=R0201
- """ Do nothing for empty line. """
- pass
-
- def help_exit(self):
- """ Provide help for exit command. """
- cur_node = self.app.active_command
- # temporarily change to top level command where help cmd is registered
- self.app.active_command = self._top_level_cmd
- try:
- return self.run_subcommand(["help", "exit"])
- finally:
- self.app.active_command = cur_node
-
- def help_help(self):
- """
- Use the command manager to get instructions for "help".
- """
- cur_node = self.app.active_command
- # temporarily change to top level command where help cmd is registered
- self.app.active_command = self._top_level_cmd
- try:
- return self.run_subcommand(["help", "help"])
- finally:
- self.app.active_command = cur_node
-
- def load_history(self):
- """
- Load a readline history file.
- """
- if ( self.app.config.history_max_length == 0
- or not os.path.exists(self.app.config.history_file)):
- return
- LOG().debug('Reading history file "%s"', self.app.config.history_file)
- try:
- readline.read_history_file(self.app.config.history_file)
- if ( self.app.config.history_max_length > 0
- and readline.get_current_history_length()
- > self.app.config.history_max_length):
- readline.set_history_length(self.app.config.history_max_length)
- readline.write_history_file(self.app.config.history_file)
- readline.read_history_file(self.app.config.history_file)
- except (IOError, OSError) as err:
- LOG().warn('Failed to read history file "%s".',
- self.app.config.history_file, exc_info=err)
-
- def postcmd(self, stop, _line):
- """
- This is called after the ``do_*`` command to postprocess its result and
- decide whether to stop the shell. We want to stop only when
- :py:class:`lmi.scripts.common.errors.LmiError` is raised. This
- exception is catched upwards in call chain.
-
- :returns: Whether to stop the shell.
- :rtype: bool
- """
- return False
-
- def run_subcommand(self, args):
- """
- Run a subcommand given as a first item of ``args``. It must be one of
- commands registered in manager. Returns the return value of invoked
- command.
-
- :param list args: List of commands.
- """
- if not isinstance(args, (list, tuple)):
- raise TypeError("args must be a list")
- if len(args) < 1:
- raise ValueError("args must not be empty")
- try:
- cmd_factory = cmdutil.get_subcommand_factory(
- self.app.active_command, args[0])
- parent = self.app.active_command
- except errors.LmiCommandNotFound:
- # When nested into a subcommand, let it handle the args if known.
- # If not known, try one of static commands.
- if not self.on_top_level_node and hasattr(self, 'do_' + args[0]):
- cmd_factory = self.app.command_manager.find_command(args[0])
- parent = self._top_level_cmd
- else:
- raise
- cmd_inst = cmd_factory(self.app, args[0], parent)
- return cmd_inst.run(args[1:])
-
- def save_history(self):
- """
- Saves current history of commands into the history file. If the length
- of history exceeds a maximum history file length, the history will be
- truncated.
- """
- if self.app.config.history_max_length != 0:
- LOG().debug('Writing history file "%s"',
- self.app.config.history_file)
- if self.app.config.history_max_length > 0:
- readline.set_history_length(self.app.config.history_max_length)
- try:
- readline.write_history_file(self.app.config.history_file)
- except (IOError, OSError), err:
- LOG().warn('Failed to write history file "%s".',
- self.app.config.history_file, exc_info=err)
diff --git a/lmi/scripts/_metacommand/manager.py b/lmi/scripts/_metacommand/manager.py
deleted file mode 100644
index 773979b..0000000
--- a/lmi/scripts/_metacommand/manager.py
+++ /dev/null
@@ -1,182 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Manager module for direct subcommands of lmi metacommand. Most of them are
-loaded from entry_points of installed python eggs.
-"""
-
-import pkg_resources
-
-from lmi.scripts.common import Configuration
-from lmi.scripts.common import errors
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.command import base
-from lmi.scripts.common.command import util
-
-LOG = get_logger(__name__)
-
-class _CustomCommandWrapper(object):
- """
- Provide an interface mocking an entry_point object for custom commands
- added by lmi metacommand application.
-
- :param name: (``str``) Name of command.
- :param cmd_class: (``LmiBaseCommand``) Factory for custom commands.
- """
-
- def __init__(self, name, cmd_class):
- if not isinstance(name, basestring):
- raise TypeError("name must be a string")
- if not issubclass(cmd_class, base.LmiBaseCommand):
- raise TypeError("cmd_class must be a LmiBaseCommand")
- self._name = name
- self._cmd_class = cmd_class
-
- @property
- def name(self):
- """ Return command name. """
- return self._name
-
- def load(self):
- """ Return command class. """
- return self._cmd_class
-
-class CommandManager(object):
- """
- Manager of direct subcommands of lmi metacommand. It manages commands
- registered with entry_points under particular namespace installed by
- python eggs. Custom commands may also be added.
-
- :param namespace: (``str``) Namespace, where commands are registered.
- For example ``lmi.scripts.cmd``.
- """
-
- def __init__(self, namespace=None):
- if namespace is not None and not isinstance(namespace, basestring):
- raise TypeError("namespace must be a string")
- if namespace is None:
- namespace = Configuration.get_instance().get_safe(
- "Main", "CommandNamespace")
- self._namespace = namespace
- self._commands = {}
- self._load_commands()
-
- @property
- def command_names(self):
- """ Returns list of command names. """
- return self._commands.keys()
-
- def __len__(self):
- return len(self._commands)
-
- def __iter__(self):
- """ Yields command names. """
- return iter(self._commands)
-
- def __getitem__(self, cmd_name):
- """ Gets command factory for name. """
- return self.find_command(cmd_name)
-
- def _load_commands(self):
- """ Loads commands from entry points under provided namespace. """
- def _add_entry_point(epoint):
- """
- Convenience function taking an entry point, making some name
- checks and adding it to registered commands.
- """
- if not util.RE_COMMAND_NAME.match(epoint.name):
- LOG().error('Invalid command name: %s, ignoring.', epoint.name)
- return
- if epoint.name in self._commands:
- LOG().warn('Command "%s" already registered, ignoring.',
- epoint.name)
- else:
- LOG().debug('Found registered command "%s".', epoint.name)
- self._commands[epoint.name] = epoint
-
- for entry_point in pkg_resources.iter_entry_points(self._namespace):
- if isinstance(entry_point, dict):
- for epoint in entry_point.values():
- _add_entry_point(epoint)
- else:
- _add_entry_point(entry_point)
-
-
- def add_command(self, name, cmd_class):
- """
- Registers custom command. May be used for example for *help* command.
-
- :param name: (``str``) Name of command.
- :param cmd_class: (``LmiBaseCommand``) Factory for commands.
- """
- if not isinstance(name, basestring):
- raise TypeError("name must be a string")
- if not issubclass(cmd_class, base.LmiBaseCommand):
- raise TypeError("cmd_class must be a LmiBaseCommand")
- if not util.RE_COMMAND_NAME.match(name):
- raise errors.LmiCommandInvalidName(
- cmd_class.__module__, cmd_class.__class__.__name__, name)
- if name in self._commands:
- LOG().warn('Command "%s" already managed, overwriting with "%s:%s".',
- name, cmd_class.__module__, cmd_class.__name__)
- self._commands[name] = _CustomCommandWrapper(name, cmd_class)
-
- def find_command(self, cmd_name):
- """
- Loads a command associated with given name and returns it.
-
- :param cmd_name: (``str``) Name of command to load.
- :rtype: (``LmiBaseCommand``) Factory for commands.
- """
- try:
- return self._commands[cmd_name].load()
- except KeyError:
- raise errors.LmiCommandNotFound(cmd_name)
- except ImportError as err:
- LOG().debug('Failed to import command "%s".', cmd_name, exc_info=err)
- raise errors.LmiCommandImportError(
- cmd_name, self._commands[cmd_name].module_name, err)
-
- def reload_commands(self, keep_custom=True):
- """
- Flushes all commands and reloads entry points.
-
- :param keep_custom: (``bool``) Custom commands -- not loaded from
- entry points -- are preserved.
- """
- if keep_custom:
- keep = { n: c for n, c in self._commands.items()
- if isinstance(c, _CustomCommandWrapper)}
- else:
- keep = {}
- self._commands = {}
- self._load_commands()
- self._commands.update(keep)
-
diff --git a/lmi/scripts/_metacommand/toplevel.py b/lmi/scripts/_metacommand/toplevel.py
deleted file mode 100644
index 1e654a3..0000000
--- a/lmi/scripts/_metacommand/toplevel.py
+++ /dev/null
@@ -1,184 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Module defining the root command (``lmi`` binary).
-"""
-
-USAGE_STRING = \
-"""
-OpenLMI command line interface for CIM providers. It's functionality is
-composed of registered subcommands, operating on top of simple libraries,
-interfacing with particular OpenLMI profile providers.
-Works also in interactive mode which is entered, when <command> argument is
-omitted.
-
-Usage:
- %(cmd)s [options] [(--trace | --notrace)] [-v]... [-h <host>]...
- <command> [<args> ...]
- %(cmd)s [options] [(--trace | --notrace)] [-v]... [-h <host>]...
- %(cmd)s (--help | --version)
-
-Options:
- -c --config-file <config> Path to a user configuration file. Options
- specified here override any settings of global
- configuration file.
- -h --host <host> Hostname of target system.
- --hosts-file <hosts> Path to a file containing target hostnames.
- Each hostname must be listed on a single line.
- --user <user> Username used in connection to any target host.
- --same-credentials Use the first credentials given for all hosts.
- -n --noverify Do not verify cimom's ssl certificate.
- -v Increase verbosity of output.
- --trace Show tracebacks on errors.
- --notrace Suppress tracebacks for exceptions.
- -q --quiet Supress output except for errors.
- --log-file <log_file> Output file for logging messages.
- --namespace <namespace> Default CIM namespace to use.
- -N --no-headings Don't print table headings.
- -H --human-friendly Print large values in human friendly units (i.e.
- MB, GB, TB etc.)
- -L --lister-format (table | csv)
- Print output of lister commands in CSV or table
- format. CSV format is more suitable for machine
- processing. Defaults to table.
- --help Show this text and quit.
- --version Print version of '%(cmd)s' in use and quit.
-
-Handling hosts:
- If no --host or --hosts-file given the "localhost" is tried. When running
- under root with Pegasus CIMOM, this results in a connection over unix
- socket (without the need for credentials).
-
- Hosts may contain embedded credentials e.g.:
- http://user:passwd@hostname:5988
- Avoid supplying them on command line though since arguments are visible in
- process table. Use --hosts-file option instead.
-"""
-
-import docopt
-
-from lmi.scripts._metacommand import exit
-from lmi.scripts._metacommand import util
-from lmi.scripts._metacommand import Interactive
-from lmi.scripts.common import get_logger
-from lmi.scripts.common import errors
-from lmi.scripts.common.command import base
-
-LOG = get_logger(__name__)
-
-class TopLevelCommand(base.LmiBaseCommand):
- """
- Top level (instance, without any parent) command handling application
- parameters and passing work to registered subcommands.
- """
-
- @classmethod
- def has_own_usage(cls):
- return True
-
- @classmethod
- def child_commands(cls):
- return []
-
- @classmethod
- def is_end_point(cls):
- return False
-
- def __init__(self, app, cmd_name='lmi'):
- base.LmiBaseCommand.__init__(self, app, cmd_name)
-
- def get_usage(self, proper=False):
- return USAGE_STRING[1:] % { 'cmd' : " ".join(self.cmd_name_parts) }
-
- def run_subcommand(self, cmd_name, args):
- """
- Finds a command factory, instantiates it and passes the control.
- """
- cmd_factory = self.app.command_manager[cmd_name]
- cmd = cmd_factory(self.app, cmd_name, parent=self)
- return cmd.run(args)
-
- def start_interactive_mode(self):
- """ Run the command line loop of interactive application. """
- self.app.command_manager.add_command("exit", exit.Exit)
- iapp = Interactive(self)
- while True:
- try:
- ret = iapp.cmdloop()
- break
- except errors.LmiTerminate as err:
- ret = err.args[0]
- break
- except KeyboardInterrupt as err:
- LOG().debug('%s: %s', err.__class__.__name__, str(err))
- self.app.stdout.write('\n')
- iapp.save_history()
- return ret
-
- def run(self, args):
- """
- Handle program arguments, set up the application and call
- a subcommand or enter interactive mode. Return exit code.
-
- :param args: (``list``) Arguments without the binary name.
- """
- if not isinstance(args, (tuple, list)):
- raise TypeError("args must be a list")
- try:
- options = docopt.docopt(self.get_usage(), args,
- version=util.get_version(), help=False, options_first=True)
- except docopt.DocoptLanguageError as exc:
- self.app.stderr.write("%s\n" % str(exc))
- return exit.EXIT_CODE_FAILURE
- if options.pop('--help', False):
- self.app.stdout.write(self.get_usage())
- self.app.stdout.write("\nCommands:\n")
- self.app.stdout.write(" %s\n" % " ".join(
- n for n in sorted(self.app.command_manager)))
- return exit.EXIT_CODE_SUCCESS
- if options.pop('--version', False):
- self.app.print_version()
- return exit.EXIT_CODE_SUCCESS
- self.app.setup(options)
- if options['<command>'] is None:
- return self.start_interactive_mode()
-
- try:
- LOG().debug('Running command "%s".', options['<command>'])
- return self.run_subcommand(options['<command>'], options['<args>'])
- except docopt.DocoptExit as err:
- if '--help' in args:
- cmd_args = options['<args>']
- cmd_args = cmd_args[:cmd_args.index('--help')]
- return self.run_subcommand(
- 'help', [options['<command>']] + cmd_args)
- raise
-
-
diff --git a/lmi/scripts/_metacommand/util.py b/lmi/scripts/_metacommand/util.py
deleted file mode 100644
index 15686a3..0000000
--- a/lmi/scripts/_metacommand/util.py
+++ /dev/null
@@ -1,264 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Meta-command utility module.
-"""
-
-import logging
-import logging.config
-import os
-import pkg_resources
-import platform
-import re
-import socket
-import sys
-import urlparse
-
-from lmi.scripts.common import Configuration
-from lmi.scripts.common import get_logger
-from lmi.scripts.common import lmi_logging
-
-PYTHON_EGG_NAME = "openlmi-scripts"
-#: Service name identifying tcp port used to connect to CIMOM.
-DEFAULT_BROKER_SERVICE_NAME = 'wbem-https'
-
-RE_NETLOC = re.compile(r'^((?P<username>[^:@]+)(:(?P<password>[^@]+))?@)?'
- r'(?P<hostname>[^:]+)(:(?P<port>\d+))?$')
-
-VERBOSITY_2_LOG_LEVEL = {
- Configuration.OUTPUT_SILENT : logging.ERROR,
- Configuration.OUTPUT_WARNING : logging.WARNING,
- Configuration.OUTPUT_INFO : logging.INFO,
- Configuration.OUTPUT_DEBUG : logging.DEBUG,
-}
-
-DEFAULT_LOGGING_CONFIG = {
- 'version' : 1,
- 'disable_existing_loggers': True,
- 'formatters' : {
- 'console' : {
- "()" : "lmi.scripts.common.lmi_logging.LevelDispatchingFormatter",
- "formatters" : {
- logging.INFO :
- Configuration.default_options()['ConsoleInfoFormat']
- },
- 'default': Configuration.default_options()['ConsoleFormat'],
- 'datefmt' : '%Y-%m-%d %H:%M:%S'
- },
- 'file' : {
- 'format' : Configuration.default_options()['FileFormat'],
- 'datefmt' : '%Y-%m-%d %H:%M:%S'
- }
- },
- 'handlers' : {
- 'console': {
- 'class' : "logging.StreamHandler",
- 'level' : logging.ERROR,
- 'formatter': 'console',
- },
- 'console_shell': {
- 'class' : "logging.StreamHandler",
- 'level' : logging.CRITICAL,
- 'formatter': 'console',
- },
- 'file' : {
- 'class' : "logging.FileHandler",
- 'level' : Configuration.default_options()['Level'].upper(),
- 'formatter': 'file',
- }
- },
- 'loggers' : {
- 'lmi.shell' : {
- 'handlers' : ['console_shell'],
- 'level' : logging.DEBUG,
- 'propagate' : False
- }
- },
- 'root' : {
- 'level' : logging.DEBUG,
- 'handlers' : ['console']
- }
-}
-
-LOG = get_logger(__name__)
-
-def setup_logging(app_config, stderr=sys.stderr):
- """
- Setup logging to console and optionally to the file.
-
- :param app_config: (``lmi.scripts.common.Configuration``)
- Configuration object.
- :param stderr: (``file``) Output stream, where console handler should
- dispatch logging messages.
- """
- cfg = DEFAULT_LOGGING_CONFIG.copy()
-
- # Set up logging to a file
- if app_config.log_file:
- cfg['handlers']['file']['filename'] = app_config.log_file
- cfg['formatters']['file']['format'] = app_config.get_safe(
- 'Log', 'FileFormat', raw=True)
- try:
- cfg['handlers']['file']['level'] = \
- getattr(logging, app_config.logging_level.upper())
- except KeyError:
- LOG().error('Unsupported logging level: "%s".',
- app_config.logging_level)
- cfg['root']['handlers'].append('file')
- cfg['loggers']['lmi.shell']['handlers'].append('file')
- else:
- del cfg['formatters']['file']
- del cfg['handlers']['file']
-
- if app_config.get_safe('Log', "LogToConsole", bool):
- # Set up logging to console
- if stderr is not sys.stderr:
- cfg['handlers']['console']['stream'] = stderr
- cfg['handlers']['console']['level'] = \
- VERBOSITY_2_LOG_LEVEL[app_config.verbosity]
-
- # make the verbosity of lmi shell one level less
- lmi_shell_verbosity = app_config.verbosity
- if ( app_config.verbosity < app_config.OUTPUT_DEBUG
- and app_config.verbosity > app_config.OUTPUT_SILENT):
- lmi_shell_verbosity -= 1
- cfg['handlers']['console_shell']['level'] = \
- VERBOSITY_2_LOG_LEVEL[lmi_shell_verbosity]
-
- # use ConsoleInfoFormat for INFO and less severe levels
- cfg['formatters']['console']['formatters'] = {
- logging.INFO :
- app_config.get_safe('Log', 'ConsoleInfoFormat', raw=True)
- }
- # use ConsoleFormat for any other level
- cfg['formatters']['console']['default'] = app_config.get_safe(
- 'Log', 'ConsoleFormat', raw=True)
- else:
- cfg['root']['handlers'].remove('console')
- cfg['loggers']['lmi.shell']['handlers'].remove('console_shell')
- del cfg['handlers']['console']
- del cfg['handlers']['console_shell']
-
- use_colors = platform.system() != 'Windows' and stderr.isatty()
- lmi_logging.setup_logger(use_colors = use_colors)
- logging.config.dictConfig(cfg)
-
-def get_version(egg_name=PYTHON_EGG_NAME):
- """
- Gets version string of any python egg. Defaults to the egg of current
- application.
- """
- return pkg_resources.get_distribution(egg_name).version
-
-def get_hosts_credentials(hostnames):
- """
- Parse list of hostnames, get credentials out of them and return
- ``(hostnames, creds)``, where ``hostnames`` is a list of ``hostnames``
- with credentials removed and ``creds`` is a dictionary with a pair
- ``(username, password)`` for every hostname, that supplied it.
-
- :param hostnames: (``list``) List of hostnames with optional credentials.
- For example: ``http://root:password@hostname:5988``.
- """
- if not hasattr(hostnames, '__iter__'):
- raise TypeError("hostnames must be a list of hosts")
- new_hostnames = []
- credentials = {}
- for hostname in hostnames:
- parsed = urlparse.urlparse(hostname)
- if not parsed.netloc and parsed.path:
- # got something like [user[:pass]@]hostname[:port] (no scheme)
- match = RE_NETLOC.match(hostname)
- if match:
- hostname = match.group('hostname')
- if match.group('port'):
- hostname += ':' + match.group('port')
- if match.group('username') or match.group('password'):
- credentials[hostname] = (
- match.group('username'), match.group('password'))
- elif parsed.username or parsed.password:
- hostname = parsed.scheme
- if parsed.scheme:
- hostname += "://"
- hostname += parsed.hostname
- if parsed.port:
- hostname += ":" + str(parsed.port)
- hostname += parsed.path
- credentials[hostname] = (parsed.username, parsed.password)
- new_hostnames.append(hostname)
- return (new_hostnames, credentials)
-
-def parse_hosts_file(hosts_file):
- """
- Parse file with hostnames to connect to. Return list of parsed hostnames.
-
- :param hosts_file: (``file``) File object openned for read.
- It containes hostnames. Each hostname occupies single line.
- :rtype: (``tuple``) A pair of ``(hosts, creds)``, where ``hosts`` is a list
- of string with hostnames and ``creds`` is a dictionary mapping
- ``(username, password)`` to each hostname if supplied.
- """
- hostnames = []
- for line in hosts_file.readlines():
- hostnames.append(line.strip())
- return get_hosts_credentials(hostnames)
-
-def get_default_hostname(port=None):
- """
- Choose default hostname to connect to. If logged as root, this will default
- to localhost, which results in unix socket being used for connection.
- Otherwise use full qualified domain name and hostname will be tried in this
- order. If they are not address-resolvable, '127.0.0.1' is returned.
-
- This function shall be used only if no uri is specified on command line.
-
- :param port: Port of desired service running on host (CIMOM broker).
- This defaults to :py:attr:`DEFAULT_BROKER_SERVICE_NAME`
- :type port: string or int
- """
- if port is None:
- port = DEFAULT_BROKER_SERVICE_NAME
- # Functions used to get hostname. first resolvable result will be used.
- name_getters = []
- if os.getuid() != 0:
- # Use non-'localhost' name only if we'are not logged in as root
- # for it prevents the use of unix socket.
- name_getters.extend([socket.getfqdn, socket.gethostname])
- name_getters.append(lambda: 'localhost')
- for name_func in name_getters:
- try:
- hostname = name_func()
- socket.getaddrinfo(hostname, port)
- break
- except socket.gaierror:
- pass
- else:
- hostname = '127.0.0.1'
- return hostname
diff --git a/lmi/scripts/common/__init__.py b/lmi/scripts/common/__init__.py
deleted file mode 100644
index cda4266..0000000
--- a/lmi/scripts/common/__init__.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Package with client-side python modules and command line utilities.
-"""
-
-import logging
-
-from lmi.shell import LMINamespace
-from lmi.shell import LMIExceptions
-from lmi.scripts.common.configuration import Configuration
-from lmi.scripts.common.lmi_logging import get_logger
-
-LOG = get_logger(__name__)
-
-def get_computer_system(ns):
- """
- Obtain an instance of ``CIM_ComputerSystem`` or its subclass. Preferred
- class name can be configured in configuration file. If such class does
- not exist, a base class (``CIM_ComputerSystem``) is enumerated instead.
- First feasible instance is cached and returned.
-
- :param ns: Namespace object where to look for computer system class.
- :type ns: :py:class:`lmi.shell.LMINamespace`
- :returns: Instance of ``CIM_ComputerSystem``.
- :rtype: :py:class:`lmi.shell.LMIInstance`.
- """
- if not isinstance(ns, LMINamespace):
- raise TypeError("ns must be an instance of LMINamespace")
- if not hasattr(get_computer_system, '_cs_cache'):
- get_computer_system._cs_cache = {}
- ns_path = ns.connection.uri + '/' + ns.name
- if not ns_path in get_computer_system._cs_cache:
- config = Configuration.get_instance()
- try:
- get_computer_system._cs_cache[ns_path] = cs = \
- getattr(ns, config.system_class_name).first_instance()
- except LMIExceptions.LMIClassNotFound:
- LOG().warn('Failed to get instance of %s on host "%s"'
- ' - falling back to CIM_ComputerSystem.',
- config.system_class_name, ns.connection.uri)
- get_computer_system._cs_cache[ns_path] = cs = \
- ns.CIM_ComputerSystem.first_instance_name()
- LOG().debug('Loaded instance of %s:%s for host "%s".',
- ns.name, cs.classname, ns.connection.uri)
- return get_computer_system._cs_cache[ns_path]
diff --git a/lmi/scripts/common/command/__init__.py b/lmi/scripts/common/command/__init__.py
deleted file mode 100644
index a7c2df4..0000000
--- a/lmi/scripts/common/command/__init__.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-This subpackage defines base classes and utility functions for declaring
-commands. These serve as wrappers for functions in libraries specific to
-particular provider.
-
-Tree of these commands build a command line interface for this library.
-"""
-
-from lmi.scripts.common.command.base import LmiBaseCommand
-from lmi.scripts.common.command.checkresult import LmiCheckResult
-from lmi.scripts.common.command.endpoint import LmiEndPointCommand
-from lmi.scripts.common.command.lister import LmiInstanceLister
-from lmi.scripts.common.command.lister import LmiLister
-from lmi.scripts.common.command.multiplexer import LmiCommandMultiplexer
-from lmi.scripts.common.command.session import LmiSessionCommand
-from lmi.scripts.common.command.select import LmiSelectCommand
-from lmi.scripts.common.command.show import LmiShowInstance
-
-from lmi.scripts.common.command.helper import make_list_command
-from lmi.scripts.common.command.helper import register_subcommands
-from lmi.scripts.common.command.helper import select_command
diff --git a/lmi/scripts/common/command/base.py b/lmi/scripts/common/command/base.py
deleted file mode 100644
index cebf422..0000000
--- a/lmi/scripts/common/command/base.py
+++ /dev/null
@@ -1,341 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Module defining base command class for all possible commands of ``lmi``
-meta-command.
-"""
-
-import abc
-import re
-
-# regular expression matching leading whitespaces not until the first line
-# containing non-white-spaces
-RE_LSPACES = re.compile(r'\A(\s*$.)*', re.DOTALL | re.MULTILINE)
-
-#: Default formatting options overriden by options passed onc ommand-line and
-#: set in configuration file.
-DEFAULT_FORMATTER_OPTIONS = {
- 'no_headings' : False,
- 'padding' : 0,
- 'human_friendly' : False,
-}
-
-class LmiBaseCommand(object):
- """
- Abstract base class for all commands handling command line arguments.
- Instances of this class are organized in a tree with root element being the
- ``lmi`` meta-command (if not running in interactive mode). Each such
- instance can have more child commands if its
- :py:meth:`LmiBaseCommand.is_multiplexer` method return ``True``. Each has
- one parent command except for the top level one, whose :py:attr:`parent`
- property returns ``None``.
-
- Set of commands is organized in a tree, where each command (except for the
- root) has its own parent. :py:meth:`is_end_point` method distinguishes
- leaves from nodes. The path from root command to the leaf is a sequence of
- commands passed to command line.
-
- There is also a special command called selector. Its :py:meth:`is_selector`
- method returns ``True``. It selects proper command that shall be passed all
- the arguments based on expression with profile requirements. It shares its
- name and parent with selected child.
-
- If the :py:meth:`LmiBaseCommand.has_own_usage` returns ``True``, the parent
- command won't process the whole command line and the remainder will be
- passed as a second argument to the :py:meth:`LmiBaseCommand.run` method.
-
- :param app: Main application object.
- :param string cmd_name: Name of command.
- :param parent: Parent command.
- :type parent: :py:class:`LmiBaseCommand`
- """
-
- __metaclass__ = abc.ABCMeta
-
- @classmethod
- def get_description(cls):
- """
- Return description for this command. This is usually a first line
- of documentation string of a class.
-
- :rtype: string
- """
- if cls.__doc__ is None:
- return ""
- return cls.__doc__.strip().split("\n", 1)[0]
-
- @classmethod
- def is_end_point(cls):
- """
- :returns: ``True``, if this command parses the rest of command line and
- can not have any child subcommands.
- :rtype: boolean
- """
- return True
-
- @classmethod
- def is_multiplexer(cls):
- """
- Is this command a multiplexer? Note that only one of
- :py:meth:`is_end_point`, :py:meth:`is_selector` and this method can
- evaluate to``True``.
-
- :returns: ``True`` if this command is not an end-point command and it's
- a multiplexer. It contains one or more subcommands. It consumes the
- first argument from command-line arguments and passes the rest to
- one of its subcommands.
- :rtype: boolean
- """
- return not cls.is_end_point()
-
- @classmethod
- def is_selector(cls):
- """
- Is this command a selector?
-
- :returns: ``True`` if this command is a subclass of
- :py:class:`lmi.scripts.common.command.select.LmiSelectCommand`.
- :rtype: boolean
- """
- return not cls.is_end_point() and not cls.is_multiplexer()
-
- @classmethod
- def has_own_usage(cls):
- """
- :returns: ``True``, if this command has its own usage string, which is
- returned by :py:meth:`LmiBaseCommand.get_description`. Otherwise
- the parent command must be queried.
- :rtype: boolean
- """
- return False
-
- @classmethod
- def child_commands(cls):
- """
- Abstract class method returning dictionary of child commands with
- structure: ::
-
- { "command-name" : cmd_factory, ... }
-
- Dictionary contains just a direct children (commands, which
- may immediately follow this particular command on command line).
- """
- raise NotImplementedError("child_commands() method must be overriden"
- " in a subclass")
-
- def __init__(self, app, cmd_name, parent=None):
- if not isinstance(cmd_name, basestring):
- raise TypeError('cmd_name must be a string')
- if parent is not None and not isinstance(parent, LmiBaseCommand):
- raise TypeError('parent must be an LmiBaseCommand instance')
- self._app = app
- self._cmd_name = cmd_name.strip()
- self._parent = parent
-
- @property
- def app(self):
- """ Return application object. """
- return self._app
-
- @property
- def parent(self):
- """ Return parent command. """
- return self._parent
-
- @property
- def cmd_name(self):
- """ Name of this subcommand as a single word. """
- return self._cmd_name
-
- @property
- def cmd_name_parts(self):
- """
- Convenience property calling :py:meth:`get_cmd_name_parts` to obtain
- command path as a list of all preceding command names.
-
- :rtype: list
- """
- return self.get_cmd_name_parts()
-
- @property
- def format_options(self):
- """
- Compose formatting options. Parent commands are queried for defaults. If
- command has no parent, default options will be taken from
- :py:attr:`DEFAULT_FORMATTER_OPTIONS` which are overriden by config
- settings.
-
- :returns: Arguments passed to formatter factory when formatter is
- for current command is constructed.
- :rtype: dictionary
- """
- if self.parent is None:
- options = DEFAULT_FORMATTER_OPTIONS.copy()
- options['no_headings'] = self.app.config.no_headings
- options['human_friendly'] = self.app.config.human_friendly
- else:
- options = self.parent.format_options
- return options
-
- @property
- def session(self):
- """
- :returns: Session object. Session for command and all of its children
- may be overriden with a call to :py:meth:`set_session_proxy`.
- :rtype: :py:class:`lmi.scripts.common.session.Session`
- """
- proxy = getattr(self, '_session_proxy', None)
- if proxy:
- return proxy
- if self.parent is not None:
- return self.parent.session
- return self.app.session
-
- def get_cmd_name_parts(self, all_parts=False, demand_own_usage=True,
- for_docopt=False):
- """
- Get name of this command as a list composed of names of all preceding
- commands since the top level one. When in interactive mode, only
- commands following the active one will be present.
-
- :param boolean full: Take no heed to the active command or interactive
- mode. Return all command names since top level node inclusive. This
- is overriden with *for_docopt* flag.
- :param boolean demand_own_usage: Wether to continue the upward
- traversal through command hieararchy past the active command until
- the command with its own usage is found. This is the default behaviour.
- :param boolean for_docopt: Docopt parser needs to be given arguments list
- without the first item compared to command names in usage string
- it receives. Thus this option causes skipping the first item that would
- be otherwise included.
- :returns: Command path. Returned list will always contain at least the
- name of this command.
- :rtype: list
- """
- parts = [self.cmd_name]
- cmd = self
- own_usage = cmd.has_own_usage()
- while ( cmd.parent is not None
- and (all_parts or self.app.active_command not in (cmd, cmd.parent))
- or (demand_own_usage and not own_usage)):
- cmd = cmd.parent
- parts.append(cmd.cmd_name)
- own_usage = own_usage or cmd.has_own_usage()
- if for_docopt and parts:
- parts.pop()
- return list(reversed(parts))
-
- def get_usage(self, proper=False):
- """
- Get command usage. Return value of this function is used by docopt
- parser as usage string. Command tree is traversed upwards until command
- with defined usage string is found. End point commands (leaves) require
- manually written usage, so the first command in the sequence of parents
- with own usage string is obtained and its usage returned. For nodes
- missing own usage string this can be generated based on its
- subcommands.
-
- :param boolean proper: Says, whether the usage string written
- manually is required or not. It applies only to node (not a leaf)
- commands without its own usage string.
- """
- if self.is_end_point() or self.has_own_usage() or proper:
- # get proper (manually written) usage, also referred as *own*
- cmd = self
- while not cmd.has_own_usage() and cmd.parent is not None:
- cmd = cmd.parent
- if cmd.__doc__ is None:
- docstr = "Usage: %s\n" % " ".join(self.cmd_name_parts)
- else:
- docstr = ( ( cmd.__doc__.rstrip()
- % {'cmd' : " ".join(cmd.cmd_name_parts)}
- ))
-
- match = RE_LSPACES.match(docstr)
- if match: # strip leading newlines
- docstr = docstr[match.end(0):]
-
- match = re.match(r'^ +', docstr)
- if match: # unindent help message
- re_lspaces = re.compile(r'^ {%s}' % match.end(0))
- docstr = "\n".join(re_lspaces.sub('', l)
- for l in docstr.splitlines())
- docstr += "\n"
-
- else:
- # generate usage string from what is known, applies to nodes
- # without own usage
- hlp = []
- if self.get_description():
- hlp.append(self.get_description())
- hlp.append("")
- hlp.append("Usage:")
- hlp.append(" %s <command> [<args> ...]"
- % " ".join(self.cmd_name_parts))
- hlp.append("")
- hlp.append("Commands:")
- cmd_max_len = max(len(c) for c in self.child_commands())
- for name, cmd in sorted(self.child_commands().items()):
- hlp.append((" %%-%ds %%s" % cmd_max_len)
- % (name, cmd.get_description()))
- docstr = "\n".join(hlp) + "\n"
-
- return docstr
-
- @abc.abstractmethod
- def run(self, args):
- """
- Handle the command line arguments. If this is not an end point
- command, it will pass the unhandled arguments to one of it's child
- commands. So the arguments are processed recursively by the instances
- of this class.
-
- :param list args: Arguments passed to the command line that were
- not yet parsed. It's the contents of ``sys.argv`` (if in
- non-interactive mode) from the current command on.
- :returns: Exit code of application. This maybe also be a boolean value
- or ``None``. ``None`` and ``True`` are treated as a success causing
- exit code to be 0.
- :rtype: integer
- """
- raise NotImplementedError("run method must be overriden in subclass")
-
- def set_session_proxy(self, session):
- """
- Allows to override session object. This is useful for especially for
- conditional commands (subclasses of
- :py:class:`~lmi.scripts.common.command.select.LmiSelectCommand`) that devide
- connections to groups satisfying particular expression. These groups
- are turned into session proxies containing just a subset of connections
- in global session object.
-
- :param session: Session object.
- """
- self._session_proxy = session
diff --git a/lmi/scripts/common/command/checkresult.py b/lmi/scripts/common/command/checkresult.py
deleted file mode 100644
index 27e9549..0000000
--- a/lmi/scripts/common/command/checkresult.py
+++ /dev/null
@@ -1,140 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-This module defines LmiCheckResult command class and related utilities.
-"""
-
-import abc
-
-from lmi.scripts.common import Configuration
-from lmi.scripts.common import get_logger
-from lmi.scripts.common import formatter
-from lmi.scripts.common import errors
-from lmi.scripts.common.command import meta
-from lmi.scripts.common.command.session import LmiSessionCommand
-
-LOG = get_logger(__name__)
-
-class LmiResultFailed(errors.LmiFailed):
- """
- Exception raised when associated function returns unexpected result. This
- is evaluated by :py:meth:`LmiCheckResult.check_result` method.
- """
- pass
-
-def _make_result_failed(expected, result):
- """
- Instantiate :py:exc:`LmiResultFailed` exception with descriptive message
- composed of what was expected and what was returned instead.
-
- :rtype: :py:class:`LmiResultFailed`
- """
- return LmiResultFailed('failed (%s != %s)' % (repr(expected), repr(result)))
-
-class LmiCheckResult(LmiSessionCommand):
- """
- Run an associated action and check its result. It implicitly makes no
- output if the invocation is successful and expected result matches.
-
- List of additional recognized properties:
-
- ``EXPECT`` :
- Value, that is expected to be returned by invoked associated
- function. This can also be a callable taking two arguments:
-
- 1. options - Dictionary with parsed command line options
- returned by ``docopt``.
- 2. result - Return value of associated function.
-
- Using metaclass: :py:class:`~.meta.CheckResultMetaClass`.
- """
- __metaclass__ = meta.CheckResultMetaClass
-
- def __init__(self, *args, **kwargs):
- LmiSessionCommand.__init__(self, *args, **kwargs)
-
- def formatter_factory(self):
- return formatter.TableFormatter
-
- @abc.abstractmethod
- def check_result(self, options, result):
- """
- Check the returned value of associated function.
-
- :param dictionary options: Dictionary as returned by ``docopt`` parser
- after running
- :py:meth:`~.endpoint.LmiEndPointCommand.transform_options`.
- :param result: Any return value that will be compared against what is
- expected.
- :returns: Whether the result is expected value or not. If ``tuple``
- is returned, it contains ``(passed_flag, error_description)``.
- :rtype: boolean or tuple.
- """
- raise NotImplementedError("check_result must be overriden in subclass")
-
- def take_action(self, connection, args, kwargs):
- """
- Invoke associated method and check its return value for single host.
-
- :param list args: List of arguments to pass to the associated
- function.
- :param dictionary kwargs: Keyword arguments to pass to the associated
- function.
- :returns: Exit code (0 on success).
- :rtype: integer
- """
- try:
- result = self.execute_on_connection(connection, *args, **kwargs)
- passed = self.check_result(self._options, result)
- if isinstance(passed, tuple):
- if len(passed) != 2:
- raise errors.LmiUnexpectedResult('check_result() must'
- ' return either boolean or (passed_flag,'
- ' error_description), not "%s"' % repr(passed))
- if not passed[0]:
- raise LmiResultFailed(passed[1])
- elif not passed and hasattr(self.check_result, 'expected'):
- err = _make_result_failed(self.check_result.expected, result)
- raise err
- except LmiResultFailed:
- raise
- except Exception as err:
- LOG().debug("Failed to execute wrapped function.", exc_info=err)
- raise
- return 0
-
- def process_host_result(self, hostname, success, result):
- pass
-
- def process_session_results(self, session, results):
- if len(self.session) > 1:
- LOG().debug('Successful runs: %d\n',
- len([r for r in results.values() if r[0]]))
- LmiSessionCommand.process_session_results(self, session, results)
diff --git a/lmi/scripts/common/command/endpoint.py b/lmi/scripts/common/command/endpoint.py
deleted file mode 100644
index c744e34..0000000
--- a/lmi/scripts/common/command/endpoint.py
+++ /dev/null
@@ -1,367 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Defines base command class for all endpoint commands. Those having no children.
-"""
-import abc
-import inspect
-import re
-from docopt import docopt
-
-from lmi.scripts.common import errors
-from lmi.scripts.common import formatter
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.formatter import command as fcmd
-from lmi.scripts.common.command import base
-from lmi.scripts.common.command import meta
-from lmi.scripts.common.command import util
-
-LOG = get_logger(__name__)
-
-def opt_name_sanitize(opt_name):
- """
- Make a function parameter name out of option name. This replaces any
- character not suitable for python identificator with ``'_'`` and
- make the whole string lowercase.
-
- :param string opt_name: Option name.
- :returns: Modified option name.
- :rtype: string
- """
- return re.sub(r'[^a-zA-Z0-9]+', '_', opt_name).lower()
-
-def options_dict2kwargs(options):
- """
- Convert option name from resulting ``docopt`` dictionary to a valid python
- identificator token used as function argument name.
-
- :param dictionary options: Dictionary returned by docopt call.
- :returns: New dictionary with keys passable to function as argument
- names.
- :rtype: dictionary
- """
- # (new_name, value) for each pair in options dictionary
- kwargs = {}
- # (new_name, name)
- orig_names = {}
- for name, value in options.items():
- for (reg, func) in (
- (util.RE_OPT_BRACKET_ARGUMENT, lambda m: m.group('name')),
- (util.RE_OPT_UPPER_ARGUMENT, lambda m: m.group('name')),
- (util.RE_OPT_SHORT_OPTION, lambda m: m.group(0)),
- (util.RE_OPT_LONG_OPTION, lambda m: m.group(0)),
- (util.RE_COMMAND_NAME, lambda m: m.group(0))):
- match = reg.match(name)
- if match:
- new_name = func(match)
- break
- else:
- raise errors.LmiError(
- 'Failed to convert argument "%s" to function option.' %
- name)
- if new_name == '--':
- continue # ignore double dash
- new_name = opt_name_sanitize(new_name)
- if new_name in kwargs:
- raise errors.LmiError('Option clash for "%s" and "%s", which both'
- ' translate to "%s".' % (name, orig_names[new_name], new_name))
- kwargs[new_name] = value
- orig_names[new_name] = name
- return kwargs
-
-class LmiEndPointCommand(base.LmiBaseCommand):
- """
- Base class for any leaf command.
-
- List of additional recognized properties:
-
- ``CALLABLE`` : ``tuple``
- Associated function. Will be wrapped in
- :py:meth:`LmiEndPointCommand.execute` method and will be accessible
- directly as a ``cmd.execute.dest`` property. It may be specified
- either as a string in form ``"<module_name>:<callable>"`` or as a
- reference to callable itself.
- ``ARG_ARRAY_SUFFIX`` : ``str``
- String appended to every option parsed by ``docopt`` having list as
- an associated value. It defaults to empty string. This modification
- is applied before calling
- :py:meth:`LmiEndPointCommand.verify_options` and
- :py:meth:`LmiEndPointCommand.transform_options`.
- ``FORMATTER`` : callable
- Default formatter factory for instances of given command. This
- factory accepts an output stream as the only parameter and returns
- an instance of :py:class:`~lmi.scripts.common.formatter.Formatter`.
-
- Using metaclass:
- :py:class:`.meta.EndPointCommandMetaClass`.
- """
- __metaclass__ = meta.EndPointCommandMetaClass
-
- def __init__(self, *args, **kwargs):
- super(LmiEndPointCommand, self).__init__(*args, **kwargs)
- self._formatter = None
- # saved options dictionary after call to transform_options()
- self._options = None
-
- @abc.abstractmethod
- def execute(self, *args, **kwargs):
- """
- Subclasses must override this method to pass given arguments to
- command library function. This function shall be specified in
- ``CALLABLE`` property.
- """
- raise NotImplementedError("execute method must be overriden"
- " in subclass")
-
- def formatter_factory(self):
- """
- Subclasses shall override this method to provide default formatter
- factory for printing output.
-
- :returns: Subclass of basic formatter.
- """
- return formatter.Formatter
-
- @classmethod
- def dest_pos_args_count(cls):
- """
- Number of positional arguments the associated function takes from
- command. These arguments are created by the command alone -- they do
- not belong to options in usage string. Function can take additional
- positional arguments that need to be covered by usage string.
-
- :rtype: integer
- """
- dest = getattr(cls.execute, "dest", cls.execute)
- abstract = dest == cls.execute and util.is_abstract_method(
- cls, 'execute', True)
- # if the destination function is not yet defined (abstract is True)
- # let's assume it's not a method => 0 positional arguments needed
- return 1 if not abstract and inspect.ismethod(dest) else 0
-
- def run_with_args(self, args, kwargs):
- """
- Process end-point arguments and exit.
-
- :param list args: Positional arguments to pass to associated
- function in command library.
- :param dictionary kwargs: Keyword arguments as a dictionary.
- :returns: Exit code of application.
- :rtype: integer
- """
- return self.execute(*args, **kwargs)
-
- @property
- def formatter(self):
- """
- Return instance of default formatter.
-
- :rtype: :py:class:`~lmi.scripts.common.formatter.Formatter`
- """
- if self._formatter is None:
- opts = self.format_options
- factory = self.formatter_factory()
- argspec = inspect.getargspec(
- factory.__init__ if type(factory) is type else factory)
- if not argspec.keywords:
- kwargs = {k: v for k, v in opts.items() if k in argspec.args}
- self._formatter = factory(self.app.stdout, **kwargs)
- return self._formatter
-
- def _make_end_point_args(self, options):
- """
- Creates a pair of positional and keyword arguments for a call to
- associated function from command line options. All keyword
- options not expected by target function are removed.
-
- :param dictionary options: Output of ``docopt`` parser.
- :returns: Positional and keyword arguments as a pair.
- :rtype: tuple
- """
- # if execute method does not have a *dest* attribute, then it's
- # itself a destination
- dest = getattr(self.execute, "dest", self.execute)
- argspec = inspect.getargspec(dest)
- kwargs = options_dict2kwargs(options)
- # number of positional arguments not covered by usage string
- pos_args_count = self.dest_pos_args_count()
- to_remove = []
- # if associated function takes keyword arguments in a single
- # dictionary (kwargs), we can pass all options
- if argspec.keywords is None:
- # otherwise we need to remove any unhandled
- for opt_name in kwargs:
- if opt_name not in argspec.args[pos_args_count:]:
- if opt_name not in self.cmd_name_parts:
- LOG().debug('Option "%s" not handled in function "%s",'
- ' ignoring.', opt_name, self.cmd_name)
- to_remove.append(opt_name)
- for opt_name in to_remove:
- # remove options unhandled by function
- del kwargs[opt_name]
- args = []
- for arg_name in argspec.args[pos_args_count:]:
- if arg_name not in kwargs:
- raise errors.LmiCommandError(
- self.__module__, self.__class__.__name__,
- 'registered command "%s" expects option "%s", which'
- ' is not covered in usage string'
- % (self.cmd_name, arg_name))
- args.append(kwargs.pop(arg_name))
- return args, kwargs
-
- def _preprocess_options(self, options):
- """
- This method may be overriden by
- :py:class:`~.meta.EndPointCommandMetaClass`
- as a result of processing ``ARG_ARRAY_SUFFIX`` and other properties
- modifying names of parsed options.
-
- This should not be overriden in command class's body.
-
- :param dictionary options: The result of ``docopt`` parser invocation
- which can be modified by this method.
- """
- pass
-
- def _parse_args(self, args):
- """
- Run ``docopt`` command line parser on given list of arguments.
- Removes all unrelated commands from created dictionary of options.
-
- :param list args: List of command line arguments just after the
- current command.
- :returns: Dictionary with parsed options. Please refer to
- docopt_ documentation for more informations.
- :rtype: dictionary
-
- .. _docopt: http://docopt.org/
- """
- full_args = self.get_cmd_name_parts(for_docopt=True) + args
- options = docopt(self.get_usage(), full_args, help=False)
- self._preprocess_options(options)
-
- # remove all command names from options
- cmd = self.parent
- while cmd is not None and not cmd.has_own_usage():
- cmd = cmd.parent
- if cmd is not None:
- for scn in cmd.child_commands():
- try:
- del options[scn]
- except KeyError:
- LOG().warn('Usage string of "%s.%s" command does not'
- ' contain registered command "%s" command.',
- cmd.__module__, cmd.__class__.__name__, scn)
- # remove also the root command name from options
- if cmd is not None and cmd.cmd_name in options:
- del options[cmd.cmd_name]
- return options
-
- def verify_options(self, options):
- """
- This method can be overriden in subclasses to check, whether the
- options given on command line are valid. If any flaw is discovered, an
- :py:exc:`~lmi.scripts.common.errors.LmiInvalidOptions` exception shall
- be raised. Any returned value is ignored.
-
- .. note::
- This is run before :py:meth:`transform_options()` method.
-
- :param dictionary options: Dictionary as returned by ``docopt`` parser.
- """
- pass
-
- def transform_options(self, options):
- """
- This method can be overriden in subclasses if options shall be somehow
- modified before passing them associated function.
-
- .. note::
- Run after :py:meth:`verify_options()` method.
-
- :param dictionary options: Dictionary as returned by ``docopt`` parser.
- """
- pass
-
- def produce_output(self, data):
- """
- This method can be use to render and print results with default
- formatter.
-
- :param data: Is an object expected by the
- :py:meth:`~lmi.scripts.common.formatter.Formatter.produce_output`
- method of formatter.
- """
- self.formatter.produce_output(data)
-
- def run(self, args):
- """
- Create options dictionary from input arguments, verify them,
- transform them, make positional and keyword arguments out of them and
- pass them to ``process_session()``.
-
- :param list args: List of command arguments.
- :returns: Exit code of application.
- :rtype: integer
- """
- options = self._parse_args(args)
- self.verify_options(options)
- self.transform_options(options)
- self._options = options.copy()
- args, kwargs = self._make_end_point_args(options)
- return self.run_with_args(args, kwargs)
-
- def _print_errors(self, error_list, new_line=True):
- """
- Print list of errors.
-
- :param list errors: Errors to print. Each error is a ``tuple``: ::
-
- (hostname, [error, error])
-
- Where ``error`` may be a test description or an instance of
- exception.
- :param new_line: Whether to print the new line before new error
- table is printed.
- """
- fmt = formatter.ErrorFormatter(self.app.stderr)
- if new_line:
- fmt.out.write('\n')
- if error_list:
- new_table_cmd = fcmd.NewTableCommand("There %s %d error%s" %
- ( 'were' if len(error_list) > 1 else 'was'
- , len(error_list)
- , 's' if len(error_list) > 1 else ''))
- fmt.produce_output((new_table_cmd, ))
- for hostname, host_errors in error_list:
- fmt.produce_output((fcmd.NewHostCommand(hostname), ))
- fmt.produce_output(host_errors)
-
diff --git a/lmi/scripts/common/command/helper.py b/lmi/scripts/common/command/helper.py
deleted file mode 100644
index 578fa8b..0000000
--- a/lmi/scripts/common/command/helper.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Module with convenient function for defining user commands.
-"""
-
-from lmi.scripts.common.command import LmiLister
-from lmi.scripts.common.command import LmiCommandMultiplexer
-from lmi.scripts.common.command import LmiSelectCommand
-from lmi.scripts.common.command import util
-
-def make_list_command(func,
- name=None,
- columns=None,
- verify_func=None,
- transform_func=None):
- """
- Create a command subclassed from :py:class:`~.lister.LmiLister`. Please
- refer to this class for detailed usage.
-
- :param func: Contents of ``CALLABLE`` property.
- :type func: string or callable
- :param string name: Optional name of resulting class. If not given,
- it will be made from the name of associated function.
- :param tuple columns: Contents of ``COLUMNS`` property.
- :param callable verify_func: Callable overriding
- py:meth:`~.endpoint.LmiEndPointCommand.verify_options` method.
- :param callable transform_func: Callable overriding
- :py:meth:`~.endpoint.LmiEndPointCommand.transform_options` method.
- :returns: Subclass of :py:class:`~.lister.LmiLister`.
- :rtype: type
- """
- if name is None:
- if isinstance(func, basestring):
- name = func.split('.')[-1]
- else:
- name = func.__name__
- if not name.startswith('_'):
- name = '_' + name.capitalize()
- props = { 'COLUMNS' : columns
- , 'CALLABLE' : func
- , '__module__' : util.get_module_name() }
- if verify_func:
- props['verify_options'] = verify_func
- if transform_func:
- props['transform_options'] = transform_func
- return LmiLister.__metaclass__(name, (LmiLister, ), props)
-
-def register_subcommands(command_name, usage, command_map,
- fallback_command=None):
- """
- Create a multiplexer command (a node in a tree of commands).
-
- :param string command_name: Name of created command. The same as will
- be given on a command line.
- :param string usage: Usage string parseable by ``docopt``.
- :param dictionary command_map: Dictionary of subcommands. Associates
- command names to their factories. It's assigned to ``COMMANDS``
- property.
- :param fallback_command: Command factory used when no command is given
- on command line.
- :type fallback_command: :py:class:`~.endpoint.LmiEndPointCommand`
- :returns: Subclass of :py:class:`~.multiplexer.LmiCommandMultiplexer`.
- :rtype: type
- """
- props = { 'COMMANDS' : command_map
- , 'OWN_USAGE' : True
- , '__doc__' : usage
- , '__module__' : util.get_module_name()
- , 'FALLBACK_COMMAND' : fallback_command }
- return LmiCommandMultiplexer.__metaclass__(command_name,
- (LmiCommandMultiplexer, ), props)
-
-def select_command(command_name, *args, **kwargs):
- """
- Create command selector that loads command whose requirements are met.
-
- Example of invocation: ::
-
- Hardware = select_command('Hardware',
- ("Openlmi-Hardware >= 0.4.2", "lmi.scripts.hardware.current.Cmd"),
- ("Openlmi-Hardware < 0.4.2" , "lmi.scripts.hardware.pre042.Cmd"),
- default=HwMissing
- )
-
- Above example checks remote broker for OpenLMI-Hardware provider. If it is
- installed and its version is equal or higher than 0.4.2, command from
- ``current`` module will be used. For older registered versions command
- contained in ``pre042`` module will be loaded. If hardware provider is not
- available, HwMissing command will be loaded instead.
-
- .. seealso::
- Check out the grammer describing language used in these conditions at
- :py:mod:`lmi.scripts.common.versioncheck.parser`.
-
- :param args: List of pairs ``(condition, command)`` that are inspected in
- given order until single condition is satisfied. Associated command is
- then loaded. Command is either a reference to command class or path to
- it given as string. In latter case last dot divides module's import
- path and command name.
- :param default: This command will be loaded when no condition from *args*
- is satisfied.
- """
- props = { 'SELECT' : args
- , 'DEFAULT' : kwargs.get('default', None)
- , '__module__' : util.get_module_name()
- }
- return LmiSelectCommand.__metaclass__(command_name,
- (LmiSelectCommand, ), props)
-
diff --git a/lmi/scripts/common/command/lister.py b/lmi/scripts/common/command/lister.py
deleted file mode 100644
index 6b36168..0000000
--- a/lmi/scripts/common/command/lister.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Defines command classes producing tablelike output.
-"""
-
-import abc
-from itertools import chain
-
-from lmi.scripts.common import errors
-from lmi.scripts.common import formatter
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.command import meta
-from lmi.scripts.common.command.session import LmiSessionCommand
-from lmi.scripts.common.configuration import Configuration
-from lmi.scripts.common.formatter import command as fcmd
-
-LOG = get_logger(__name__)
-
-class LmiBaseListerCommand(LmiSessionCommand):
- """
- Base class for all lister commands.
- """
-
- @classmethod
- def get_columns(cls):
- """
- :returns: Column names for resulting table. ``COLUMNS`` property
- will be converted to this class method. If ``None``, the associated
- function shall return column names as the first tuple of returned
- list. If empty tuple or list, no header shall be printed and associated
- function returns just data rows.
- :rtype: list or tuple or None
- """
- return None
-
- def formatter_factory(self):
- if self.app.config.lister_format == Configuration.LISTER_FORMAT_CSV:
- return formatter.CsvFormatter
- else:
- return formatter.TableFormatter
-
-class LmiLister(LmiBaseListerCommand):
- """
- End point command outputting a table for each host. Associated function
- shall return a list of rows. Each row is represented as a tuple holding
- column values.
-
- List of additional recognized properties:
-
- ``COLUMNS`` : ``tuple``
- Column names. It's a tuple with name for each column. Each row
- shall then contain the same number of items as this tuple. If
- omitted, associated function is expected to provide them in the
- first row of returned list. It's translated to ``get_columns()``
- class method.
-
- Using metaclass: :py:class:`~.meta.ListerMetaClass`.
- """
- __metaclass__ = meta.ListerMetaClass
-
- def take_action(self, connection, args, kwargs):
- """
- Collects results of single host.
-
- :param connection: Connection to a single host.
- :type connection: :py:class:`lmi.shell.LMIConnection`
- :param list args: Positional arguments for associated function.
- :param dictionary kwargs: Keyword arguments for associated function.
- :returns: Column names and item list as a pair.
- :rtype: tuple
- """
- res = self.execute_on_connection(connection, *args, **kwargs)
- columns = self.get_columns()
- if isinstance(columns, (tuple, list)) and columns:
- command = fcmd.NewTableHeaderCommand(columns)
- res = chain((command, ), res)
- elif columns is None:
- resi = iter(res)
- command = fcmd.NewTableHeaderCommand(resi.next())
- res = chain((command, ), resi)
- return res
-
-class LmiInstanceLister(LmiBaseListerCommand):
- """
- End point command outputting a table of instances for each host.
- Associated function shall return a list of instances. They may be
- prepended with column names depending on value of ``DYNAMIC_PROPERTIES``.
- Each instance will occupy single row of table with property values being a
- content of cells.
-
- List of additional recognized properties is the same as for
- :py:class:`~.show.LmiShowInstance`. There is just one difference. Either
- ``DYNAMIC_PROPERTIES`` must be ``True`` or ``PROPERTIES`` must be filled.
-
- Using metaclass: :py:class:`~.meta.InstanceListerMetaClass`.
- """
- __metaclass__ = meta.InstanceListerMetaClass
-
- @abc.abstractmethod
- def render(self, result):
- """
- This method can either be overriden in a subclass or left alone. In the
- latter case it will be generated by
- :py:class:`~.meta.InstanceListerMetaClass` metaclass with regard to
- ``PROPERTIES`` and ``DYNAMIC_PROPERTIES``.
-
- :param result: Either an instance to render or pair of properties and
- instance.
- :type result: :py:class:`lmi.shell.LMIInstance` or tuple
- :returns: List of pairs, where the first item is a label and second a
- value to render.
- :rtype: list
- """
- raise NotImplementedError(
- "render method must be overriden in subclass")
-
- def take_action(self, connection, args, kwargs):
- """
- Collects results of single host.
-
- :param connection: Connection to a single host.
- :type connection: :py:class:`lmi.shell.LMIConnection`
- :param list args: Positional arguments for associated function.
- :param dictionary kwargs: Keyword arguments for associated function.
- :returns: Column names and item list as a pair.
- :rtype: tuple
- """
- cols = self.get_columns()
- if cols is None:
- result = self.execute_on_connection(
- connection, *args, **kwargs)
- if not isinstance(result, tuple) or len(result) != 2:
- raise errors.LmiUnexpectedResult(
- self.__class__, "(properties, instances)", result)
- cols, data = result
- if not isinstance(cols, (tuple, list)):
- raise errors.LmiUnexpectedResult(
- self.__class__, "(tuple, ...)", (cols, '...'))
- header = [c if isinstance(c, basestring) else c[0] for c in cols]
- cmd = fcmd.NewTableHeaderCommand(columns=header)
- return chain((cmd, ), (self.render((cols, inst)) for inst in data))
- else:
- data = self.execute_on_connection(connection, *args, **kwargs)
- if not hasattr(data, '__iter__'):
- raise errors.LmiUnexpectedResult(
- self.__class__, 'list or generator', data)
- cmd = fcmd.NewTableHeaderCommand(columns=cols)
- return chain((cmd, ), (self.render(inst) for inst in data))
diff --git a/lmi/scripts/common/command/meta.py b/lmi/scripts/common/command/meta.py
deleted file mode 100644
index 7d8213e..0000000
--- a/lmi/scripts/common/command/meta.py
+++ /dev/null
@@ -1,839 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Meta classes simplifying declaration of user commands.
-
-Each command is defined as a class with a set of properties. Some are
-mandatory, the others have some default values. Each of them is transformed by
-metaclasse to some function, class method or other property depending on
-command type and semantic of property. Property itself is removed from
-resulting class after being processed by meta class.
-"""
-
-import abc
-import inspect
-import re
-
-from lmi.scripts.common import Configuration
-from lmi.scripts.common import get_logger
-from lmi.scripts.common import errors
-from lmi.scripts.common.command import base
-from lmi.scripts.common.command import util
-from lmi.shell import LMIInstance
-from lmi.shell.LMIReturnValue import LMIReturnValue
-
-RE_CALLABLE = re.compile(
- r'^(?P<module>[a-z_]+(?:\.[a-z_]+)*):(?P<func>[a-z_]+)$',
- re.IGNORECASE)
-RE_ARRAY_SUFFIX = re.compile(r'^(?:[a-z_]+[a-z0-9_]*)?$', re.IGNORECASE)
-RE_OPTION = re.compile(r'^-+(?P<name>[^-+].*)$')
-RE_MODULE_PATH = re.compile(r'([a-zA-z_]\w+\.)+[a-zA-z_]\w+')
-
-FORMAT_OPTIONS = ('no_headings', 'human_friendly')
-
-LOG = get_logger(__name__)
-
-def _handle_usage(name, bases, dcl):
- """
- Take care of ``OWN_USAGE`` property. Supported values:
-
- `True`` :
- Means that documentation string of class is a usage string.
- ``False`` :
- No usage string for this command is defined.
- ``"usage string"`` :
- This property is a usage string.
-
- Defaults to ``False``.
-
- Usage string is an input parameter to ``docopt`` command-line options
- parser.
-
- :param string name: Name o command class.
- :param dictionary dcl: Class dictionary, which is modified by this
- function.
- """
- has_own_usage = False
- hlp = dcl.pop('OWN_USAGE', False)
- if hlp is True:
- if dcl['__doc__'] is None:
- raise errors.LmiCommandInvalidProperty(dcl['__module__'], name,
- "OWN_USAGE set to True, but no __doc__ string present!")
- has_own_usage = True
- elif isinstance(hlp, basestring):
- if not '__doc__' in dcl:
- dcl['__doc__'] = hlp
- else:
- if not 'get_usage' in dcl:
- def _new_get_usage(_self, proper=False):
- """ Get the usage string for ``doctopt`` parser. """
- return hlp
- dcl['get_usage'] = _new_get_usage
- has_own_usage = True
- elif ( dcl.get('__node__', None) is None
- and any(getattr(b, 'has_own_usage', lambda: False)() for b in bases)):
- # inherit doc string of base class
- dcl['__doc__'] = ( b.__doc__ for b in bases
- if getattr(b, 'has_own_usage', lambda: False)()).next()
- has_own_usage = True
- if has_own_usage:
- if not 'has_own_usage' in dcl:
- dcl['has_own_usage'] = classmethod(lambda _cls: True)
-
-def _make_execute_method(bases, dcl, func):
- """
- Creates ``execute()`` method of a new end point command.
-
- :param tuple bases: Base classes of new command.
- :param dictionary dcl: Class dictionary being modified by this method.
- :param callable func: A callable wrapped by this new command. It's usually
- being referred to as *associated function*. If ``None``, no function
- will be created -- ``dcl`` won't be modified.
- """
- if func is not None and util.is_abstract_method(
- bases, 'execute', missing_is_abstract=True):
- del dcl['CALLABLE']
- def _execute(__self__, __connection__, *args, **kwargs):
- """ Invokes associated function with given arguments. """
- return func(__connection__, *args, **kwargs)
- _execute.dest = func
- dcl['execute'] = _execute
-
-def _handle_namespace(dcl):
- """
- Overrides ``cim_namespace()`` class method if ``NAMESPACE`` property
- is given.
-
- :param dictionary dcl: Class dictionary being modified by this method.
- """
- if 'NAMESPACE' in dcl:
- namespace = dcl.pop('NAMESPACE')
- def _new_cim_namespace(_cls):
- """ Returns cim namespace used to modify connection object. """
- return namespace
- dcl['cim_namespace'] = classmethod(_new_cim_namespace)
-
-def _handle_callable(name, bases, dcl):
- """
- Process the ``CALLABLE`` property of end-point command. Create the
- ``execute()`` method based on it.
-
- :param string name: Name of command class to create.
- :param tuple bases: Base classes of new command.
- :param dictionary dcl: Class dictionary being modified by this method.
- """
- try:
- func = dcl.get('CALLABLE')
- if isinstance(func, basestring):
- match = RE_CALLABLE.match(func)
- if not match:
- raise errors.LmiCommandInvalidCallable(
- dcl['__module__'], name,
- 'Callable "%s" has invalid format (\':\' expected)'
- % func)
- mod_name = match.group('module')
- try:
- func = getattr(__import__(mod_name, globals(), locals(),
- [match.group('func')], 0),
- match.group('func'))
- except (ImportError, AttributeError):
- raise errors.LmiImportCallableFailed(
- dcl['__module__'], name, func)
- except KeyError:
- raise errors.LmiCommandMissingCallable(dcl['__module__'], name)
- if func is not None and not callable(func):
- raise errors.LmiCommandInvalidCallable(
- '"%s" is not a callable object or function.' % (
- func.__module__ + '.' + func.__name__))
-
- _make_execute_method(bases, dcl, func)
-
-def _make_render_all_properties(bases):
- """
- Creates ``render()`` method, rendering all properties of instance.
-
- :param tuple bases: Base classes of new command class.
- :returns: Rendering method taking CIM instance as an
- argument.
- :rtype: function
- """
- if util.is_abstract_method(bases, 'render', missing_is_abstract=True):
- def _render(_self, inst):
- """
- Return tuple of ``(column_names, values)`` ready for output by
- formatter.
- """
- column_names, values = [], []
- for prop_name, value in sorted(inst.properties_dict().iteritems()):
- column_names.append(prop_name)
- if value is None:
- value = ''
- values.append(value)
- return (column_names, values)
-
- return _render
-
-def _make_render_with_properties(properties, target_formatter_lister=False):
- """
- Creates ``render()`` method, rendering given instance properties.
-
- :param properties: (``list``) List of properties to render.
- :param target_formatter_lister: (``bool``) Whether the output is targeted
- for Show command or Lister. The former expects a pair of column_names
- and values. The latter expects just values.
- :rtype: (``function``) Rendering method taking CIM instance as an
- argument.
- """
- def _process_property(prop, inst):
- """
- Takes a single property and instance. Returns computed value.
-
- :rtype: ``(str, any)`` A pair of property name and value.
- """
- if isinstance(prop, basestring):
- prop_name = prop
- if not prop in inst.properties():
- LOG().warn('Property "%s" not present in instance of "%s".',
- prop, inst.path)
- value = "UNKNOWN"
- else:
- value = getattr(inst, prop)
- else:
- if not isinstance(prop, (tuple, list)):
- raise TypeError("prop must be a string or tuple, not %s" %
- repr(prop))
- prop_name = prop[0]
- try:
- if callable(prop[1]):
- value = prop[1](inst)
- else:
- value = getattr(inst, prop[1])
- except Exception as exc:
- LOG().exception('Failed to render property "%s": %s',
- prop[0], exc)
- value = "ERROR"
- if value is None:
- value = ''
- return prop_name, value
-
- if target_formatter_lister:
- def _render(self, inst):
- """
- Renders a limited set of properties and returns a row for instance
- table composed of property values.
- """
- if not isinstance(inst, LMIInstance):
- raise errors.LmiUnexpectedResult(
- self.__class__, 'LMIInstance object', inst)
- return tuple(_process_property(p, inst)[1] for p in properties)
-
- else:
- def _render(self, inst):
- """
- Renders a limited set of properties and returns a pair of
- column names and values.
- """
- if not isinstance(inst, LMIInstance):
- raise errors.LmiUnexpectedResult(
- self.__class__, 'LMIInstance object', inst)
- column_names, values = [], []
- for prop in properties:
- prop_name, value = _process_property(prop, inst)
- column_names.append(prop_name)
- values.append(value)
- return (column_names, values)
-
- return _render
-
-def _check_render_properties(name, dcl, props):
- """
- Make sanity check for ``PROPERTIES`` class property. Exception will be
- raised when any flaw discovered.
-
- :param string name: Name of class to be created.
- :param dictionary dcl: Class dictionary.
- :param list props: List of properties or ``None``.
- """
- if props is not None:
- for prop in props:
- if not isinstance(prop, (basestring, tuple, list)):
- raise errors.LmiCommandInvalidProperty(
- dcl['__module__'], name,
- 'PROPERTIES must be a list of strings or tuples')
- if isinstance(prop, (tuple, list)):
- if ( len(prop) != 2
- or not isinstance(prop[0], basestring)
- or ( not callable(prop[1])
- and not isinstance(prop[1], basestring))):
- raise errors.LmiCommandInvalidProperty(
- dcl['__module__'], name,
- 'tuples in PROPERTIES must be: ("name",'
- ' callable or property_name)')
-
-def _handle_render_properties(name, bases, dcl, target_formatter_lister=False):
- """
- Process properties related to rendering function for commands operating
- on CIM instances. Result of this function a ``render()`` and
- ``get_columns()`` functions being added to class's dictionary with
- regard to handled properties.
-
- Currently handled properties are:
-
- ``DYNAMIC_PROPERTIES`` : ``bool``
- Whether the associated function itself provides list of
- properties. Optional property.
- ``PROPERTIES`` : ``bool``
- List of instance properties to print. Optional property.
-
- :param string name: Name of class to be created.
- :param tuple bases: Base classes of new command.
- :param dictionary dcl: Class dictionary being modified by this method.
- :param boolean target_formatter_lister: Whether the output is targeted
- for *Show* command or *Lister*. The former expects a pair of
- column_names and values. The latter expects just values.
- """
- dynamic_properties = dcl.pop('DYNAMIC_PROPERTIES', False)
- if dynamic_properties and 'PROPERTIES' in dcl:
- raise errors.LmiCommandError(
- dcl['__module__'], name,
- 'DYNAMIC_PROPERTIES and PROPERTIES are mutually exclusive')
-
- properties = dcl.pop('PROPERTIES', None)
- _check_render_properties(name, dcl, properties)
-
- renderer = None
- get_columns = lambda cls: None
- if properties is None and not dynamic_properties:
- if ( target_formatter_lister
- and dcl.get('__metaclass__', None) is not InstanceListerMetaClass):
- raise errors.LmiCommandError(dcl['__module__'], name,
- "either PROPERTIES must be declared or"
- " DYNAMIC_PROPERTIES == True for InstanceLister"
- " commands")
- renderer = _make_render_all_properties(bases)
- elif properties is None and dynamic_properties:
- def _render_dynamic(self, return_value):
- """ Renderer of dynamic properties. """
- properties, inst = return_value
- return _make_render_with_properties(properties,
- target_formatter_lister)(self, inst)
- renderer = _render_dynamic
- elif properties is not None:
- renderer = _make_render_with_properties(properties,
- target_formatter_lister)
- get_columns = (lambda cls:
- tuple((p[0] if isinstance(p, tuple) else p)
- for p in properties))
- if renderer is not None:
- dcl['render'] = classmethod(renderer)
- if target_formatter_lister:
- dcl['get_columns'] = get_columns
-
-def _handle_opt_preprocess(name, dcl):
- """
- Process properties, that cause modification of parsed argument names before
- passing them to ``verify_options()`` or ``transform_options()``. If any of
- handled properties is supplied, it causes ``_preprocess_options()`` to be
- overriden, where all of desired name modifications will be made.
- Currently handled properties are:
-
- ``OPT_NO_UNDERSCORES`` : ``bool``
- When making a function's parameter name out of option, the leading
- dashes are replaced with underscore. If this property is True,
- dashes will be removed completely with no replacement.
- ``ARG_ARRAY_SUFFIX`` : ``bool``
- Add given suffix to all arguments resulting in list objects.
-
- :param string name: Command class name.
- :param dictionary dcl: Class dictionary being modified by this method.
- """
- if ( dcl.get('__metaclass__', None) is not EndPointCommandMetaClass
- and '_preprocess_options' in dcl):
- raise errors.LmiCommandError(dcl['__module__'], name,
- '_preprocess_options() method must not be overriden in the'
- 'body of command class; use transform_options() instead')
- arr_suffix = dcl.pop('ARG_ARRAY_SUFFIX', '')
- if ( not isinstance(arr_suffix, str)
- or not RE_ARRAY_SUFFIX.match(arr_suffix)):
- raise errors.LmiCommandInvalidProperty(dcl['__module__'], name,
- 'ARG_ARRAY_SUFFIX must be a string matching regular'
- ' expression "%s"' % RE_ARRAY_SUFFIX.pattern)
- opt_no_underscores = dcl.pop('OPT_NO_UNDERSCORES', False)
- if arr_suffix or opt_no_underscores:
- def _new_preprocess_options(_self, options):
- """ Modify (in-place) given options dictionary by renaming keys. """
- for do_it, cond, transform in (
- ( arr_suffix
- , lambda _, v: isinstance(v, list)
- , lambda n :
- ('<' + util.RE_OPT_BRACKET_ARGUMENT.match(n)
- .group(1) + arr_suffix + '>')
- if util.RE_OPT_BRACKET_ARGUMENT.match(n)
- else (n + arr_suffix))
- , ( opt_no_underscores
- , lambda n, _: RE_OPTION.match(n)
- , lambda n : RE_OPTION.match(n).group('name'))
- ):
- if not do_it:
- continue
- to_rename = ( name for name, value in options.items()
- if cond(name, value))
- for name in to_rename:
- new_name = transform(name)
- LOG().debug('Renaming option "%s" to "%s".', name, new_name)
- if new_name in options:
- LOG().warn(
- 'Existing option named "%s" replaced with "%s".',
- new_name, name)
- options[new_name] = options.pop(name)
-
- dcl['_preprocess_options'] = _new_preprocess_options
-
-def _handle_fallback_command(name, bases, dcl):
- """
- Process ``FALLBACK_COMMAND`` property of multiplexer command. It's turned
- into a :py:meth:`~.multiplexer.LmiCommandMultiplexer.fallback_command`
- class method. It needs to be called after the usage string is handled.
-
- .. seealso::
- :py:func:`_handle_usage`
- """
- fallback = dcl.pop('FALLBACK_COMMAND', None)
- if fallback is not None:
- if not issubclass(type(fallback), EndPointCommandMetaClass):
- raise errors.LmiCommandInvalidProperty(dcl['__module__'], name,
- "FALLBACK_COMMAND must be a command class"
- " (subclass of LmiEndPointCommand) not %s" % repr(fallback))
- if not fallback.has_own_usage():
- usage_string = dcl.get('__doc__', None)
- if not usage_string:
- for base_cls in bases:
- if not issubclass(base_cls, base.LmiBaseCommand):
- continue
- cmd = base_cls
- while not cmd.has_own_usage() and cmd.parent is not None:
- cmd = cmd.parent
- usage_string = cmd.__doc__
- if not usage_string:
- errors.LmiCommandError(dcl['__module__'], name,
- "Missing usage string.")
- fallback.__doc__ = usage_string
- fallback.has_own_usage = lambda cls: True
- dcl['fallback_command'] = staticmethod(lambda: fallback)
-
-def _handle_format_options(name, bases, dcl):
- """
- Process any ``FMT_*`` properties. This overrides ``format_options``
- property which returns dictionary of arguments passed to formatter factory.
-
- These properties are removed from class' dictionary.
- """
- format_options = {}
- for key, value in dcl.items():
- if key.startswith("FMT_"):
- opt_name = key[4:].lower()
- if opt_name not in FORMAT_OPTIONS:
- raise errors.LmiCommandInvalidProperty(
- dcl['__module__'], name,
- 'Formatting option "%s" is not supported.' %
- opt_name)
- if ( opt_name in ('no_headings', 'human_friendly')
- and not isinstance(value, bool)):
- raise errors.LmiCommandInvalidProperty(
- dcl['__module__'], name,
- '"%s" property must be a boolean')
- format_options[opt_name] = value
-
- if format_options:
- def _new_format_options(self):
- """ :returns: Dictionary of options for formatter object. """
- basecls = [b for b in bases if issubclass(b, base.LmiBaseCommand)][0]
- opts = basecls.format_options.fget(self)
- opts.update(format_options)
- return opts
- if 'format_options' in dcl:
- raise errors.LmiCommandError(dcl['__module__'], name,
- 'can not define both FMT_ options and "format_options" in'
- ' the same class, choose just one of them')
- dcl['format_options'] = property(_new_format_options)
-
- for key in format_options:
- dcl.pop('FMT_' + key.upper())
-
-def _handle_select(name, dcl):
- """
- Process properties of :py:class:`.select.LmiSelectCommand`.
- Currently handled properties are:
-
- ``SELECT`` : ``list``
- Is a list of pairs ``(condition, command)`` where ``condition`` is
- an expression in *LMIReSpL* language. And ``command`` is either a
- string with absolute path to command that shall be loaded or the
- command class itself.
-
- Small example: ::
-
- SELECT = [
- ( 'OpenLMI-Hardware < 0.4.2'
- , 'lmi.scripts.hardware.pre042.PreCmd'
- )
- , ('OpenLMI-Hardware >= 0.4.2 & class LMI_Chassis == 0.3.0'
- , HwCmd
- )
- ]
-
- It says: Let the ``PreHwCmd`` command do the job on brokers having
- ``openlmi-hardware`` package older than ``0.4.2``. Use the
- ``HwCmd`` anywhere else where also the ``LMI_Chassis`` CIM class in
- version ``0.3.0`` is available.
-
- First matching condition wins and assigned command will be passed
- all the arguments.
-
- ``DEFAULT`` : ``str`` or :py:class:`~.base.LmiBaseCommand`
- Defines fallback command used in case no condition can be
- satisfied.
-
- They will be turned into ``get_conditionals()`` method.
- """
- module_name = dcl.get('__module__', name)
- if not 'SELECT' in dcl:
- raise errors.LmiCommandError(module_name, name,
- "Missing SELECT property.")
- def inv_prop(msg, *args):
- return errors.LmiCommandInvalidProperty(module_name, name, msg % args)
- expressions = dcl.pop('SELECT')
- if not isinstance(expressions, (list, tuple)):
- raise inv_prop('SELECT must be list or tuple.')
- if len(expressions) < 1:
- raise inv_prop('SELECT must contain at least one condition!')
- for index, item in enumerate(expressions):
- if not isinstance(item, tuple):
- raise inv_prop('Items of SELECT must be tuples, not %s!' %
- getattr(type(item), '__name__', 'UNKNOWN'))
- if len(item) != 2:
- raise inv_prop('Expected pair in SELECT on index %d!' % index)
- expr, cmd = item
- if not isinstance(expr, basestring):
- raise inv_prop('Expected expression string on index %d'
- ' in SELECT!' % index)
- if isinstance(cmd, basestring) and not RE_MODULE_PATH.match(cmd):
- raise inv_prop('Second item of conditional pair on index %d'
- ' in SELECT does not look as an importable path!' % cmd)
- if ( not isinstance(cmd, basestring)
- and not issubclass(cmd, (basestring, base.LmiBaseCommand))):
- raise inv_prop('Expected subclass of LmiBaseCommand (or its import'
- ' path) as a second item of a pair on index %d in SELECT!'
- % index)
-
- default = dcl.pop('DEFAULT', None)
- if isinstance(default, basestring) and not RE_MODULE_PATH.match(default):
- raise inv_prop('DEFAULT "%s" does not look as an importable path!'
- % default)
- if ( default is not None and not isinstance(default, basestring)
- and not issubclass(default, (basestring, base.LmiBaseCommand))):
- raise inv_prop('Expected subclass of LmiBaseCommand'
- ' (or its import path) as a value of DEFAULT!')
- def _new_get_conditionals(self):
- return expressions, default
-
- dcl['get_conditionals'] = _new_get_conditionals
-
-class EndPointCommandMetaClass(abc.ABCMeta):
- """
- End point command does not have any subcommands. It's a leaf of
- command tree. It wraps some function in command library being
- referred to as an *associated function*. It handles following class
- properties:
-
- ``CALLABLE`` : ``str`` or callable
- An associated function. Mandatory property.
- ``OWN_USAGE`` : ``bool`` or ``str``
- Usage string. Optional property.
- ``ARG_ARRAY_SUFFIX`` : ``str``
- Suffix added to argument names containing array of values.
- Optional property.
- ``FMT_NO_HEADINGS`` : ``bool``
- Allows to force printing of table headers on and off for
- this command. Default is to print them.
- ``FMT_HUMAN_FRIENDLY`` : ``bool``
- Tells formatter to make the output more human friendly. The result
- is dependent on the type of formatter used.
- """
-
- def __new__(mcs, name, bases, dcl):
- _handle_usage(name, bases, dcl)
- _handle_callable(name, bases, dcl)
- _handle_opt_preprocess(name, dcl)
- _handle_format_options(name, bases, dcl)
-
- cls = super(EndPointCommandMetaClass, mcs).__new__(
- mcs, name, bases, dcl)
-
- # make additional check for arguments count
- dest = getattr(cls.execute, "dest", cls.execute)
- argspec = inspect.getargspec(dest)
- if ( not argspec.varargs
- and len(argspec.args) < cls.dest_pos_args_count()):
- raise errors.LmiCommandInvalidCallable(
- dcl['__module__'], name,
- 'Callable must accept at least %d positional arguments' %
- cls.dest_pos_args_count())
-
- return cls
-
-class SessionCommandMetaClass(EndPointCommandMetaClass):
- """
- Meta class for commands operating upon a session object.
- All associated functions take as first argument an namespace abstraction
- of type ``lmi.shell``.
-
- Handles following class properties:
-
- ``NAMESPACE`` : ``str``
- CIM namespace abstraction that will be passed to associated
- function. Defaults to ``"root/cimv2"``. If ``False``, raw
- :py:class:`lmi.shell.LMIConnection` object will be passed to
- associated function.
- """
- def __new__(mcs, name, bases, dcl):
- _handle_usage(name, bases, dcl)
- _handle_namespace(dcl)
- _handle_callable(name, bases, dcl)
-
- return EndPointCommandMetaClass.__new__(mcs, name, bases, dcl)
-
-class ListerMetaClass(SessionCommandMetaClass):
- """
- Meta class for end-point lister commands. Handles following class
- properties:
-
- ``COLUMNS`` : ``tuple``
- List of column names. Optional property. There are special values
- such as:
-
- ``None`` or omitted
- Associated function provides column names in a first row of
- returned list or generator.
-
- empty list, empty tuple or ``False``
- They mean that no headers shall be printed. It is simalar
- to using ``FMT_NO_HEADINGS = True``. But in this case all
- the rows returned from associated functions are treated as
- data.
- """
-
- def __new__(mcs, name, bases, dcl):
- cols = dcl.pop('COLUMNS', None)
- if cols is not None:
- if not isinstance(cols, (list, tuple)):
- raise errors.LmiCommandInvalidProperty(dcl['__module__'], name,
- 'COLUMNS class property must be either list or tuple')
- if len(cols) < 1 or cols is False:
- dcl['FMT_NO_HEADINGS'] = True
- cols = tuple()
- elif not all(isinstance(c, basestring) for c in cols):
- raise errors.LmiCommandInvalidProperty(dcl['__module__'], name,
- 'COLUMNS must contain just column names as strings')
- def _new_get_columns(_cls):
- """ Return column names. """
- return cols
- dcl['get_columns'] = classmethod(_new_get_columns)
-
- return super(ListerMetaClass, mcs).__new__(mcs, name, bases, dcl)
-
-class ShowInstanceMetaClass(SessionCommandMetaClass):
- """
- Meta class for end-point show instance commands. Additional handled
- properties:
-
- ``DYNAMIC_PROPERTIES`` : ``bool``
- Whether the associated function itself provides list of
- properties. Optional property.
- ``PROPERTIES`` : ``tuple``
- List of instance properties to print. Optional property.
-
- These are translated in a :py:meth:`~.show.LmiShowInstance.render`, which
- should be marked as abstract in base lister class.
- """
-
- def __new__(mcs, name, bases, dcl):
- _handle_render_properties(name, bases, dcl)
-
- return super(ShowInstanceMetaClass, mcs).__new__(
- mcs, name, bases, dcl)
-
-class InstanceListerMetaClass(SessionCommandMetaClass):
- """
- Meta class for instance lister command handling the same properties
- as :py:class:`ShowInstanceMetaClass`.
- """
-
- def __new__(mcs, name, bases, dcl):
- _handle_render_properties(name, bases, dcl, True)
-
- return super(InstanceListerMetaClass, mcs).__new__(
- mcs, name, bases, dcl)
-
-class CheckResultMetaClass(SessionCommandMetaClass):
- """
- Meta class for end-point command "check result". Additional handled
- properties:
-
- ``EXPECT`` :
- Value to compare against the return value. Mandatory property.
-
- ``EXPECT`` property is transformed into a
- :py:meth:`.checkresult.LmiCheckResult.check_result` method taking two
- arguments ``(options, result)`` and returning a boolean.
- """
-
- def __new__(mcs, name, bases, dcl):
- try:
- expect = dcl['EXPECT']
- if callable(expect):
- def _new_expect(_self, options, result):
- """
- Comparison function testing return value with *expect*
- function.
- """
- if isinstance(result, LMIReturnValue):
- result = result.rval
- passed = expect(options, result)
- if not passed:
- LOG().info('Got unexpected result "%s".')
- return passed
- else:
- def _new_expect(_self, _options, result):
- """ Comparison function testing by equivalence. """
- if isinstance(result, LMIReturnValue):
- result = result.rval
- passed = expect == result
- if not passed:
- LOG().info('Expected "%s", got "%s".', expect, result)
- return (False, '%s != %s' % (expect, result))
- return passed
- _new_expect.expected = expect
- del dcl['EXPECT']
- dcl['check_result'] = _new_expect
- except KeyError:
- # EXPECT might be defined in some subclass
- pass
-
- return super(CheckResultMetaClass, mcs).__new__(mcs, name, bases, dcl)
-
-class MultiplexerMetaClass(abc.ABCMeta):
- """
- Meta class for node command (not an end-point command). It handles
- following class properties:
-
- ``COMMANDS`` : ``dict``
- Command names with assigned command classes. Each of them is a
- direct subcommands of command with this property. Mandatory
- property.
-
- ``FALLBACK_COMMAND`` : :py:class:`~.endpoint.LmiEndPointCommand`
- Command factory to use in case that no command is passed on command
- line.
-
- Formatting options (starting with ``FMT_`` are also accepted, and may used
- to set defaults for all subcommands.
- """
-
- def __new__(mcs, name, bases, dcl):
- if dcl.get('__metaclass__', None) is not MultiplexerMetaClass:
- module_name = dcl.get('__module__', name)
- # check COMMANDS property and make it a classmethod
- if not 'COMMANDS' in dcl:
- raise errors.LmiCommandError(module_name, name,
- 'Missing COMMANDS property.')
- cmds = dcl.pop('COMMANDS')
- if not isinstance(cmds, dict):
- raise errors.LmiCommandInvalidProperty(module_name, name,
- 'COMMANDS must be a dictionary')
- if not all(isinstance(c, basestring) for c in cmds.keys()):
- raise errors.LmiCommandInvalidProperty(module_name, name,
- 'Keys of COMMANDS dictionary must contain command'
- ' names as strings.')
- for cmd_name, cmd in cmds.items():
- if not util.RE_COMMAND_NAME.match(cmd_name):
- raise errors.LmiCommandInvalidName(
- module_name, name, cmd_name)
- if not issubclass(cmd, base.LmiBaseCommand):
- raise errors.LmiCommandError(module_name, name,
- 'COMMANDS dictionary must be composed of'
- ' LmiBaseCommand subclasses, failed class: "%s"'
- % cmd.__name__)
- if cmd.is_multiplexer() and not cmd.has_own_usage():
- LOG().warn('Command "%s.%s" is missing usage string.'
- ' It will be inherited from parent command.',
- cmd.__module__, cmd.__name__)
- cmd.__doc__ = dcl['__doc__']
- def _new_child_commands(_cls):
- """ Returns list of subcommands. """
- return cmds
- dcl['child_commands'] = classmethod(_new_child_commands)
-
- _handle_usage(name, bases, dcl)
- _handle_fallback_command(name, bases, dcl)
- _handle_format_options(name, bases, dcl)
-
- return super(MultiplexerMetaClass, mcs).__new__(mcs, name, bases, dcl)
-
-class SelectMetaClass(abc.ABCMeta):
- """
- Meta class for select commands with guarded commands. Additional handled
- properties:
-
- ``SELECT`` : ``list``
- List of commands guarded with expressions representing requirements
- on server's side that need to be met.
- ``DEFAULT`` : ``str`` or :py:class:`~.base.LmiBaseCommand`
- Defines fallback command used in case no condition can is
- satisfied.
- """
-
- def __new__(mcs, name, bases, dcl):
- if dcl.get('__metaclass__', None) is not SelectMetaClass:
- module_name = dcl.get('__module__', name)
- if not '__doc__' in dcl:
- LOG().warn('Command selector "%s.%s" is missing short'
- ' description string (__doc__).',
- module_name, name)
- default = dcl.get('DEFAULT', None)
- if ( default is not None
- and issubclass(default, base.LmiBaseCommand)
- and getattr(dcl['DEFAULT'], '__doc__', None)):
- LOG().warn('Using __doc__ string from default command for'
- ' selector "%s.%s".', module_name, name)
- dcl['__doc__'] = dcl['DEFAULT'].__doc__
- _handle_select(name, dcl)
- return super(SelectMetaClass, mcs).__new__(mcs, name, bases, dcl)
-
diff --git a/lmi/scripts/common/command/multiplexer.py b/lmi/scripts/common/command/multiplexer.py
deleted file mode 100644
index 61ebcd7..0000000
--- a/lmi/scripts/common/command/multiplexer.py
+++ /dev/null
@@ -1,155 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Defines command class used to nest multiple commands under one.
-"""
-
-from docopt import docopt
-
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.command import base
-from lmi.scripts.common.command import meta
-
-LOG = get_logger(__name__)
-
-class LmiCommandMultiplexer(base.LmiBaseCommand):
- """
- Base class for node commands. It consumes just part of command line
- arguments and passes the remainder to one of its subcommands.
-
- Example usage: ::
-
- class MyCommand(LmiCommandMultiplexer):
- '''
- My command description.
-
- Usage: %(cmd)s mycommand (subcmd1 | subcmd2)
- '''
- COMMANDS = {'subcmd1' : Subcmd1, 'subcmd2' : Subcmd2}
-
- Where ``Subcmd1`` and ``Subcmd2`` are some other ``LmiBaseCommand``
- subclasses. Documentation string must be parseable with ``docopt``.
-
- Recognized properties:
-
- ``COMMANDS`` : ``dictionary``
- property will be translated to
- :py:meth:`LmiCommandMultiplexer.child_commands` class method by
- :py:class:`~.meta.MultiplexerMetaClass`.
-
- Using metaclass: :py:class:`.meta.MultiplexerMetaClass`.
- """
- __metaclass__ = meta.MultiplexerMetaClass
-
- @classmethod
- def child_commands(cls):
- """
- Abstract class method, that needs to be implemented in subclass.
- This is done by associated meta-class, when defining a command with
- assigned ``COMMANDS`` property.
-
- :returns: Dictionary of subcommand names with assigned command
- factories.
- :rtype: dictionary
- """
- raise NotImplementedError("child_commands must be implemented in"
- " a subclass")
-
- @classmethod
- def fallback_command(cls):
- """
- This is overriden by :py:class:`~.meta.MultiplexerMetaClass` when
- the ``FALLBACK_COMMAND`` gets processed.
-
- :returns: Command factory invoked for missing command on command line.
- :rtype: :py:class:`~.endpoint.LmiEndPointCommand`
- """
- return None
-
- @classmethod
- def is_end_point(cls):
- return False
-
- def run_subcommand(self, cmd_name, args):
- """
- Pass control to a subcommand identified by given name.
-
- :param string cmd_name: Name of direct subcommand, whose
- :py:meth:`~.base.LmiBaseCommand.run` method shall be invoked.
- :param list args: List of arguments for particular subcommand.
- :returns: Application exit code.
- :rtype: integer
- """
- if not isinstance(cmd_name, basestring):
- raise TypeError("cmd_name must be a string, not %s" %
- repr(cmd_name))
- if not isinstance(args, (list, tuple)):
- raise TypeError("args must be a list, not %s" % repr(args))
- try:
- cmd_cls = self.child_commands()[cmd_name]
- cmd = cmd_cls(self.app, cmd_name, self)
- except KeyError:
- self.app.stderr.write(self.get_usage())
- LOG().critical('Unexpected command "%s".', cmd_name)
- return 1
- return cmd.run(args)
-
- def run(self, args):
- """
- Handle optional parameters, retrieve desired subcommand name and
- pass the remainder of arguments to it.
-
- :param list args: List of arguments with at least subcommand name.
- """
- if not isinstance(args, (list, tuple)):
- raise TypeError("args must be a list")
- full_args = self.get_cmd_name_parts(for_docopt=True) + args
- docopt_kwargs = {
- # check the --help ourselves (the default docopt behaviour checks
- # also for --version)
- 'help' : False,
- # let's ignore options following first command for generated
- # usage string and when a height of this branch is > 2
- 'options_first' : not self.has_own_usage()
- or any( not cmd.is_end_point()
- for cmd in self.child_commands().values()
- if not args or args[0] not in self.child_commands()
- or self.child_commands()[args[0]] is cmd)
- }
- options = docopt(self.get_usage(), full_args, **docopt_kwargs)
- if options.pop('--help', False) or (args and args[0] == '--help'):
- self.app.stdout.write(self.get_usage(proper=True))
- return 0
- if ( self.fallback_command() is not None
- and (not args or args[0] not in self.child_commands())):
- cmd_cls = self.fallback_command()
- cmd = cmd_cls(self.app, self.cmd_name, self.parent)
- return cmd.run(args)
- return self.run_subcommand(args[0], args[1:])
diff --git a/lmi/scripts/common/command/select.py b/lmi/scripts/common/command/select.py
deleted file mode 100644
index 5f89994..0000000
--- a/lmi/scripts/common/command/select.py
+++ /dev/null
@@ -1,195 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Defines command class used to choose other commands depending on
-profile and class requirements.
-"""
-
-from docopt import docopt
-from pyparsing import ParseException
-
-from lmi.scripts.common import get_logger
-from lmi.scripts.common import errors
-from lmi.scripts.common.command import base
-from lmi.scripts.common.command import meta
-from lmi.scripts.common.session import SessionProxy
-from lmi.scripts.common.versioncheck import eval_respl
-
-class LmiSelectCommand(base.LmiBaseCommand):
- """
- Base class for command selectors. It does not process command line
- arguments. Thery are passed unchanged to selected command whose
- requirements are met. Its doc string is not interpreted in any way.
-
- If there are more hosts, conditions are evaluated per each. They are then
- split into groups, each fulfilling particular condition. Associated
- commands are then invoked on these groups separately.
-
- Example usage: ::
-
- class MySelect(LmiSelectCommand):
- SELECT = [
- ( 'OpenLMI-Hardware >= 0.4.2'
- , 'lmi.scripts.hardware.current.Cmd'),
- ('OpenLMI-Hardware', 'lmi.scripts.hardware.pre042.Cmd')
- ]
- DEFAULT = MissingHwProviderCmd
-
- Using metaclass: :py:class:`.meta.SelectMetaClass`.
- """
- __metaclass__ = meta.SelectMetaClass
-
- @classmethod
- def is_end_point(cls):
- return False
-
- @classmethod
- def is_multiplexer(cls):
- return False
-
- @classmethod
- def get_conditionals(cls):
- """
- Get the expressions with associated commands. This shall be overriden
- by a subclass.
-
- :returns: Pair of ``(expressions, default)``.
- Where ``expressions`` is a list of pairs ``(condition, command)``.
- And ``default`` is the same as ``command`` used in case no
- ``condition`` is satisfied.
- :rtype: list
- """
- raise NotImplementedError(
- "get_conditionals needs to be defined in subclass")
-
- def eval_expr(self, expr, hosts, cache=None):
- """
- Evaluate expression on group of hosts.
-
- :param string expr: Expression to evaluate.
- :param list hosts: Group of hosts that shall be checked.
- :param dictionary cache: Optional cache object speeding up evaluation
- by reducing number of queries to broker.
- :returns: Subset of hosts satisfying *expr*.
- :rtype: list
- """
- if cache is None:
- cache = dict()
- session = self.session
- satisfied = []
- try:
- for host in hosts: # TODO: could be done concurrently
- conn = session[host]
- if not conn:
- continue
- if eval_respl(expr, conn, cache=cache):
- satisfied.append(host)
- except ParseException:
- raise errors.LmiBadSelectExpression(self.__class__.__module__,
- self.__class__.__name__, "Bad select expression: %s" % expr)
- return satisfied
-
- def select_cmds(self, cache=None):
- """
- Generator of command factories with associated groups of hosts. It
- evaluates given expressions on session. In this process all expressions
- from :py:meth:`get_conditionals` are checked in a row. Host satisfying
- some expression is added to group associated with it and is excluded
- from processing following expressions.
-
- :param dictionary cache: Optional cache object speeding up the evaluation
- by reducing number of queries to broker.
- :returns: Pairs in form ``(command_factory, session_proxy)``.
- :rtype: generator
- :raises:
- * :py:class:`~lmi.scripts.common.errors.LmiUnsatisfiedDependencies`
- if no condition is satisfied for at least one host. Note that
- this exception is raised at the end of evaluation. This lets
- you choose whether you want to process satisfied hosts - by
- processing the generator at once. Or whether you want to be
- sure it is satisfied by all of them - you turn the generator
- into a list.
- * :py:class:`~lmi.scripts.common.errors.LmiNoConnections`
- if no successful connection was done.
- """
- if cache is None:
- cache = dict()
- conds, default = self.get_conditionals()
- def get_cmd_factory(cmd):
- if isinstance(cmd, basestring):
- i = cmd.rindex('.')
- module = __import__(cmd[:i], fromlist=cmd[i+1:])
- return getattr(module, cmd[i+1:])
- else:
- return cmd
-
- session = self.session
- unsatisfied = set(session.hostnames)
-
- for expr, cmd in conds:
- hosts = self.eval_expr(expr, unsatisfied, cache)
- if hosts:
- yield get_cmd_factory(cmd), SessionProxy(session, hosts)
- hosts = set(hosts).union(set(session.get_unconnected()))
- unsatisfied.difference_update(hosts)
- if not unsatisfied:
- break
- if default is not None and unsatisfied:
- yield get_cmd_factory(default), SessionProxy(session, unsatisfied)
- unsatisfied.clear()
- if len(unsatisfied):
- raise errors.LmiUnsatisfiedDependencies(unsatisfied)
- if len(session) == len(session.get_unconnected()):
- raise errors.LmiNoConnections("No successful connection!")
-
- def get_usage(self, proper=False):
- """
- Try to get usage of any command satisfying some expression.
-
- :raises: Same exceptions as :py:meth:`select_cmds`.
- """
- for cmd_cls, _ in self.select_cmds():
- cmd = cmd_cls(self.app, self.cmd_name, self.parent)
- return cmd.get_usage(proper)
-
- def run(self, args):
- """
- Iterate over command factories with associated sessions and
- execute them with unchanged *args*.
- """
- result = 0
- for cmd_cls, session in self.select_cmds():
- cmd = cmd_cls(self.app, self.cmd_name, self.parent)
- cmd.set_session_proxy(session)
- ret = cmd.run(args)
- if result == 0:
- result = ret
- return result
-
diff --git a/lmi/scripts/common/command/session.py b/lmi/scripts/common/command/session.py
deleted file mode 100644
index 9d88bbe..0000000
--- a/lmi/scripts/common/command/session.py
+++ /dev/null
@@ -1,206 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Defines a base class for all command classes operating upon a
-:py:class:`~lmi.scripts.common.session.Session` object.
-"""
-import abc
-from collections import OrderedDict
-
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.command import meta
-from lmi.scripts.common.command.endpoint import LmiEndPointCommand
-from lmi.scripts.common.configuration import Configuration
-from lmi.scripts.common.session import Session
-from lmi.shell import LMIConnection
-from lmi.shell import LMIUtil
-
-LOG = get_logger(__name__)
-
-class LmiSessionCommand(LmiEndPointCommand):
- """
- Base class for end-point commands operating upon a session object.
-
- Using metaclass: :py:class:`~.meta.SessionCommandMetaClass`.
- """
- __metaclass__ = meta.SessionCommandMetaClass
-
- @classmethod
- def cim_namespace(cls):
- """
- This returns default cim namespace, the connection object will be
- nested into before being passed to associated function.
- It can be overriden in few ways:
-
- 1. by setting ``[CIM] Namespace`` option in configuration
- 2. by giving ``--namespace`` argument on command line to the
- ``lmi`` meta-command
- 3. by setting ``NAMESPACE`` property in declaration of command
-
- Higher number means higher priority.
- """
- return Configuration.get_instance().namespace
-
- @classmethod
- def dest_pos_args_count(cls):
- """
- There is a namespace/connection object passed as the first positional
- argument.
- """
- return LmiEndPointCommand.dest_pos_args_count.im_func(cls) + 1
-
- def process_session(self, session, args, kwargs):
- """
- Process each host of given session, call the associated command
- function, collect results and print it to standard output.
-
- :param session: Session object with set of hosts.
- :type session: :py:class:`~lmi.scripts.common.session.Session`
- :param list args: Positional arguments to pass to associated function
- in command library.
- :param dictionary kwargs: Keyword arguments as a dictionary.
- :returns: Exit code of application.
- :rtype: integer
- """
- if not isinstance(session, Session):
- raise TypeError("session must be an object of Session, not %s"
- % repr(session))
- # { ( hostname : (passed, result) ), ... }
- # where passed is a boolean and result is returned value if passed is
- # True and exception otherwise
- results = OrderedDict()
- for connection in session:
- try:
- result = self.take_action(connection, args, kwargs)
- # result may be a generator which may throw in the following
- # function
- results[connection.uri] = (True, result)
- self.process_host_result(connection.uri, True, result)
- except Exception as exc:
- if len(session) > 1:
- LOG().exception('Invocation failed for host "%s": %s',
- connection.uri, exc)
- else:
- LOG().exception(exc)
- results[connection.uri] = (False, exc)
- self.process_host_result(connection.uri, False, exc)
- self.process_session_results(session, results)
- return all(r[0] for r in results.values())
-
- def process_host_result(self, hostname, success, result):
- """
- Called from :py:meth:`process_session` after single host gets
- processed. By default this prints obtained *result* with default
- formatter if the execution was successful. Children of this class may
- want to override this.
-
- :param string hostname: Name of host involved.
- :param boolean success: Whether the action on host succeeded.
- :param result: Either the value returned by associated function upon a
- successful invocation or an exception.
- """
- if success:
- if len(self.session) > 1:
- self.formatter.print_host(hostname)
- self.produce_output(result)
-
- def process_session_results(self, session, results):
- """
- Called at the end of :py:meth:`process_session`'s execution. It's
- supposed to do any summary work upon results from all hosts. By default
- it just prints errors in a form of list.
-
- :param session: Session object.
- :type session: :py:class:`lmi.scripts.common.session.Session`
- :param dictionary results: Dictionary of form: ::
-
- { 'hostname' : (success_flag, result), ... }
-
- where *result* is either an exception or returned value of
- associated function, depending on *success_flag*. See the
- :py:meth:`process_host_result`.
- """
- if not isinstance(session, Session):
- raise TypeError("session must be a Session object")
- if not isinstance(results, dict):
- raise TypeError("results must be a dictionary")
- # check whether any output has been produced
- if ( len(session.get_unconnected())
- or any(not r[0] for r in results.values())):
- data = []
- for hostname in session.get_unconnected():
- data.append((hostname, ['failed to connect']))
- for hostname, (success, error) in results.items():
- if not success:
- data.append((hostname, [error]))
- if len(session) > 1:
- self._print_errors(data,
- new_line=any(r[0] for r in results.values()))
-
- @abc.abstractmethod
- def take_action(self, connection, args, kwargs):
- """
- Executes an action on single host and collects results.
-
- :param connection: Connection to a single host.
- :type connection: :py:class:`lmi.shell.LMIConnection`
- :param list args: Positional arguments for associated function.
- :param dictionary kwargs: Keyword arguments for associated function.
- :returns: Column names and item list as a pair.
- :rtype: tuple
- """
- raise NotImplementedError("take_action must be implemented in subclass")
-
- def execute_on_connection(self, connection, *args, **kwargs):
- """
- Wraps the :py:meth:`~.endpoint.LmiEndPointCommand.execute` method with
- connection adjustments. Connection object is not usually passed
- directly to associated function. Mostly it's the namespace object that
- is expected. This method checks, whether the namespace object is
- desired and modifies connection accordingly.
-
- :param connection: Connection to single host.
- :type connection: :py:class:`lmi.shell.LMIConnection`
- :param list args: Arguments handed over to associated function.
- :param dictionary kwargs: Keyword arguments handed over to associated
- function.
- """
- if not isinstance(connection, LMIConnection):
- raise TypeError("expected an instance of LMIConnection for"
- " connection argument, not %s" % repr(connection))
- namespace = self.cim_namespace()
- if namespace is not None:
- connection = LMIUtil.lmi_wrap_cim_namespace(
- connection, namespace)
- return self.execute(connection, *args, **kwargs)
-
- def run_with_args(self, args, kwargs):
- return self.process_session(self.session, args, kwargs)
-
diff --git a/lmi/scripts/common/command/show.py b/lmi/scripts/common/command/show.py
deleted file mode 100644
index 1698fec..0000000
--- a/lmi/scripts/common/command/show.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Contains command classes producing key-value pairs to output.
-"""
-import abc
-
-from lmi.scripts.common import formatter
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.command import meta
-from lmi.scripts.common.command.session import LmiSessionCommand
-
-LOG = get_logger(__name__)
-
-class LmiShowInstance(LmiSessionCommand):
- """
- End point command producing a list of properties of particular CIM
- instance. Either reduced list of properties to print can be specified, or
- the associated function alone can decide, which properties shall be
- printed. Associated function is expected to return CIM instance as a
- result.
-
- List of additional recognized properties:
-
- ``DYNAMIC_PROPERTIES`` : ``bool``
- A boolean saying, whether the associated function alone shall
- specify the list of properties of rendered instance. If ``True``,
- the result of function must be a pair: ::
-
- (props, inst)
-
- Where props is the same value as can be passed to ``PROPERTIES``
- property. Defaults to ``False``.
- ``PROPERTIES`` : ``tuple``
- May contain list of instance properties, that will be produced in
- the same order as output. Each item of list can be either:
-
- name : ``str``
- Name of property to render.
- pair : ``tuple``
- A tuple ``(Name, render_func)``, where former item an
- arbitraty name for rendered value and the latter is a
- function taking as the only argument particular instance
- and returning value to render.
-
- ``DYNAMIC_PROPERTIES`` and ``PROPERTIES`` are mutually exclusive. If none
- is given, all instance properties will be printed.
-
- Using metaclass: :py:class:`~.meta.ShowInstanceMetaClass`.
- """
- __metaclass__ = meta.ShowInstanceMetaClass
-
- def formatter_factory(self):
- return formatter.SingleFormatter
-
- @abc.abstractmethod
- def render(self, result):
- """
- This method can either be overriden in a subclass or left alone. In the
- latter case it will be generated by
- :py:class:`~.meta.ShowInstanceMetaClass` metaclass with regard to
- ``PROPERTIES`` and ``DYNAMIC_PROPERTIES``.
-
- :param result: Either an instance to
- render or pair of properties and instance.
- :type: :py:class:`lmi.shell.LMIInstance` or ``tuple``
- :returns: List of pairs, where the first item is a label and second a
- value to render.
- :rtype: list
- """
- raise NotImplementedError(
- "render method must be overriden in subclass")
-
- def take_action(self, connection, args, kwargs):
- """
- Process single connection to a host, render result and return a value
- to render.
-
- :returns: List of pairs, where the first item is a label and
- second a value to render.
- :rtype: list
- """
- res = self.execute_on_connection(connection, *args, **kwargs)
- return self.render(res)
-
diff --git a/lmi/scripts/common/command/util.py b/lmi/scripts/common/command/util.py
deleted file mode 100644
index 914850a..0000000
--- a/lmi/scripts/common/command/util.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Utility functions used in command sub-package.
-"""
-
-import inspect
-import os
-import re
-
-#: Regular expression matching bracket argument such as ``<arg_name>``.
-RE_OPT_BRACKET_ARGUMENT = re.compile('^<(?P<name>[^>]+)>$')
-#: Regular expression matching argument written in upper case such as
-#:``ARG_NAME``.
-RE_OPT_UPPER_ARGUMENT = re.compile('^(?P<name>[A-Z0-9]+(?:[_-][A-Z0-9]+)*)$')
-#: Regular expression matching showt options. They are one character
-#: long, prefixed with single dash.
-RE_OPT_SHORT_OPTION = re.compile('^-(?P<name>[a-z])$', re.IGNORECASE)
-#: Regular expression matching long options (prefixed with double dash).
-RE_OPT_LONG_OPTION = re.compile('^--(?P<name>[a-z0-9_-]+)$', re.IGNORECASE)
-#: Command name can also be a single or double dash.
-RE_COMMAND_NAME = re.compile(r'^([a-z]+(-[a-z0-9]+)*|--?)$')
-
-def is_abstract_method(clss, method, missing_is_abstract=False):
- """
- Check, whether the given method is abstract in given class or list of
- classes. May be used to check, whether we should override particular
- abstract method in a meta-class in case that no non-abstract
- implementation is defined.
-
- :param clss: Class or list of classes that is
- searched for non-abstract implementation of particular method.
- If the first class having particular method in this list contain
- non-abstract implementation, ``False`` is returned.
- :type clss: type or tuple
- :param string method: Name of method to look for.
- :param boolean missing_is_abstract: This is a value returned, when
- not such method is defined in a set of given classes.
- :returns: Are all occurences of given method abstract?
- :rtype: boolean
- """
- if ( not isinstance(clss, (list, tuple, set))
- and not isinstance(clss, type)):
- raise TypeError("clss must be either a class or a tuple of classes")
- if not isinstance(method, basestring):
- raise TypeError("method must be a string")
- if isinstance(clss, type):
- clss = [clss]
- for cls in clss:
- if hasattr(cls, method):
- if getattr(getattr(cls, method), "__isabstractmethod__", False):
- return True
- else:
- return False
- return missing_is_abstract
-
-def get_module_name(frame_level=2):
- """
- Get a module name of caller from particular outer frame.
-
- :param integer frame_level: Number of nested frames to skip when searching
- for called function scope by inspecting stack upwards. When the result
- of this function is applied directly on the definition of function,
- it's value should be 1. When used from inside of some other factory, it
- must be increased by 1.
-
- Level 0 returns name of this module. Level 1 returns module name of
- caller. Level 2 returns module name of caller's caller.
- :returns: Module name.
- :rtype: string
- """
- frame = inspect.currentframe()
- while frame_level > 0 and frame.f_back:
- frame = frame.f_back
- frame_level -= 1
- module = getattr(frame, 'f_globals', {}).get('__name__', None)
- if module is None:
- if hasattr(frame, 'f_code'):
- module = os.path.basename(frame.f_code.co_filename.splitext())[0]
- else:
- module = '_unknown_'
- return module
diff --git a/lmi/scripts/common/configuration.py b/lmi/scripts/common/configuration.py
deleted file mode 100644
index 97ebebe..0000000
--- a/lmi/scripts/common/configuration.py
+++ /dev/null
@@ -1,311 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Module for Configuration class.
-
-Configuration
----------------------
-
-.. autoclass:: Configuration
- :members:
-
-"""
-
-import os
-from lmi.base.BaseConfiguration import BaseConfiguration
-
-LISTER_FORMATS = ['csv', 'table']
-
-#: Default format string to use in stderr handlers.
-DEFAULT_FORMAT_STRING = "%(cseq)s%(levelname_)-8s:%(creset)s %(message)s"
-
-class Configuration(BaseConfiguration):
- """
- Configuration class specific to software providers.
- *OpenLMI* configuration file should reside in: ::
-
- /etc/openlmi/scripts/lmi.conf
-
- :param string user_config_file_path: Path to the user configuration
- options.
- """
-
- USER_CONFIG_FILE_PATH = "~/.lmirc"
- HISTORY_FILE = "~/.lmi_history"
-
- OUTPUT_SILENT = -1
- OUTPUT_WARNING = 0
- OUTPUT_INFO = 1
- OUTPUT_DEBUG = 2
-
- # indexes to LISTER_FORMATS
- LISTER_FORMAT_CSV = 0
- LISTER_FORMAT_TABLE = 1
-
- def __init__(self, user_config_file_path=USER_CONFIG_FILE_PATH, **kwargs):
- self._user_config_file_path = os.path.expanduser(user_config_file_path)
- BaseConfiguration.__init__(self, **kwargs)
- self._verbosity = None
- self._trace = None
- self._verify_server_cert = None
- self._cim_namespace = None
- self._human_friendly = None
- self._lister_format = None
- self._no_headings = None
- self._log_file = None
- self._history_max_length = None
-
- @classmethod
- def provider_prefix(cls):
- return "scripts"
-
- @classmethod
- def default_options(cls):
- """
- :returns: Dictionary of default values.
- :rtype: dictionary
- """
- defaults = BaseConfiguration.default_options().copy()
- # [Main] options
- defaults["CommandNamespace"] = 'lmi.scripts.cmd'
- defaults["Trace"] = "False"
- defaults["Verbosity"] = "0"
- defaults["HistoryMaxLength"] = "4000"
- # [Log] options
- defaults['ConsoleFormat'] = DEFAULT_FORMAT_STRING
- defaults['ConsoleInfoFormat'] = '%(message)s'
- defaults['FileFormat'] = \
- "%(asctime)s:%(levelname)-8s:%(name)s:%(lineno)d - %(message)s"
- defaults['LogToConsole'] = 'True'
- defaults['OutputFile'] = ''
- # [SSL] options
- defaults['VerifyServerCertificate'] = 'True'
- # [Format] options
- defaults['HumanFriendly'] = 'False' # be ugly by default
- defaults['ListerFormat'] = 'table'
- defaults['NoHeadings'] = 'False'
- return defaults
-
- @classmethod
- def mandatory_sections(cls):
- sects = set(BaseConfiguration.mandatory_sections())
- sects.add('Main')
- sects.add('SSL')
- sects.add('Format')
- return list(sects)
-
- def load(self):
- """ Read additional user configuration file if it exists. """
- BaseConfiguration.load(self)
- self.config.read(self._user_config_file_path)
-
- # *************************************************************************
- # [CIM] options
- # *************************************************************************
- @property
- def namespace(self):
- if self._cim_namespace is None:
- return BaseConfiguration.namespace.fget(self)
- return self._cim_namespace
- @namespace.setter
- def namespace(self, namespace):
- if not isinstance(namespace, basestring) and namespace is not None:
- raise TypeError("namespace must be a string")
- self._cim_namespace = namespace
-
- # *************************************************************************
- # [Main] options
- # *************************************************************************
- @property
- def history_file(self):
- """ Path to a file with history of interactive mode. """
- return os.path.expanduser(self.HISTORY_FILE)
-
- @property
- def history_max_length(self):
- """ Maximum number of lines kept in history file. """
- return self.get_safe('Main', 'HistoryMaxLength', int)
-
- @property
- def silent(self):
- """ Whether to suppress all output messages except for errors. """
- return self.verbosity <= self.OUTPUT_SILENT
-
- @property
- def trace(self):
- """ Whether the tracebacks shall be printed upon errors. """
- if self._trace is not None:
- return self._trace
- return self.get_safe('Main', 'Trace', bool)
-
- @trace.setter
- def trace(self, trace):
- """ Allow to override configuration option Trace. """
- if trace is not None:
- trace = bool(trace)
- self._trace = trace
-
- @property
- def verbose(self):
- """ Whether to output more details. """
- return self.verbosity >= self.OUTPUT_INFO
-
- @property
- def verbosity(self):
- """ Return integer indicating verbosity level of output to console. """
- if self._verbosity is None:
- return self.get_safe('Main', 'Verbosity', int)
- return self._verbosity
-
- @verbosity.setter
- def verbosity(self, level):
- """ Allow to set verbosity without modifying configuration values. """
- if not isinstance(level, (long, int)) and level is not None:
- raise TypeError("level must be integer")
- if level is not None:
- if level < self.OUTPUT_SILENT:
- level = self.OUTPUT_SILENT
- elif level > self.OUTPUT_DEBUG:
- level = self.OUTPUT_DEBUG
- self._verbosity = level
-
- # *************************************************************************
- # [Log] options
- # *************************************************************************
- @property
- def log_file(self):
- """ Path to a file, where logging messages shall be written. """
- if self._log_file is None:
- return self.get_safe('Log', 'OutputFile')
- return self._log_file
- @log_file.setter
- def log_file(self, log_file):
- """ Override logging file path. """
- if log_file is not None and not isinstance(log_file, basestring):
- raise TypeError("log_file must be a string")
- self._log_file = log_file
-
- # *************************************************************************
- # [SSL] options
- # *************************************************************************
- @property
- def verify_server_cert(self):
- """
- Return boolean saying, whether the server-side certificate should be
- checked.
- """
- if self._verify_server_cert is None:
- return self.get_safe('SSL', 'VerifyServerCertificate', bool)
- return self._verify_server_cert
- @verify_server_cert.setter
- def verify_server_cert(self, value):
- """ Allows to override configuration option value. """
- if value is not None:
- value = bool(value)
- self._verify_server_cert = value
-
- # *************************************************************************
- # [Format] options
- # *************************************************************************
- @property
- def human_friendly(self):
- """ Whether to print human-friendly values. """
- if self._human_friendly is None:
- return self.get_safe('Format', 'HumanFriendly', bool)
- return self._human_friendly
- @human_friendly.setter
- def human_friendly(self, value):
- """ Allows to override configuration option value. """
- if value is not None:
- value = bool(value)
- self._human_friendly = value
-
- @property
- def lister_format(self):
- """
- Output format used for lister commands. Returns one of
- * LISTER_FORMAT_CSV
- * LISTER_FORMAT_TABLE
-
- :rtype: integer
- """
- if self._lister_format is None:
- value = self.get_safe('Format', 'ListerFormat')
- try:
- return LISTER_FORMATS.index(value.lower())
- except ValueError:
- value = self.default_options()['ListerFormat']
- return LISTER_FORMATS.index(value.lower())
- return self._lister_format
- @lister_format.setter
- def lister_format(self, value):
- """
- Allows to override configuration option.
-
- :param value: One of items from ``LISTER_FORMATS`` array or an index
- to it.
- :type value: integer or string
- """
- if ( value is not None
- and ( not isinstance(value, int)
- or (value < 0 or value >= len(LISTER_FORMATS)))
- and ( not isinstance(value, basestring)
- or value.lower() not in LISTER_FORMATS)) :
- raise TypeError("value must be an integer or one of: %s" %
- LISTER_FORMATS)
- if isinstance(value, basestring):
- value = LISTER_FORMATS.index(value.lower())
- self._lister_format = value
-
- @property
- def no_headings(self):
- """ Whether to print headings of tables. """
- if self._no_headings is None:
- return self.get_safe('Format', 'NoHeadings', bool)
- return self._no_headings
- @no_headings.setter
- def no_headings(self, value):
- """ Allows to override configuration option. """
- if value is not None:
- value = bool(value)
- self._no_headings = value
-
-# There were some path changes in BaseConfiguration after 0.2.0 release.
-# Let's fallback to older variable name when the new one is not present.
-if hasattr(BaseConfiguration, 'CONFIG_DIRECTORY_TEMPLATE_PROVIDER'):
- setattr( Configuration
- , 'CONFIG_FILE_PATH_TEMPLATE_PROVIDER'
- , getattr(BaseConfiguration, 'CONFIG_DIRECTORY_TEMPLATE_PROVIDER')
- + 'lmi.conf')
-else: # fallback
- setattr( Configuration
- , 'CONFIG_FILE_PATH_TEMPLATE'
- , getattr(BaseConfiguration, 'CONFIG_DIRECTORY_TEMPLATE')
- + 'lmi.conf')
diff --git a/lmi/scripts/common/errors.py b/lmi/scripts/common/errors.py
deleted file mode 100644
index 5162cf8..0000000
--- a/lmi/scripts/common/errors.py
+++ /dev/null
@@ -1,140 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Module with predefined exceptions for use in scripts.
-"""
-
-class LmiError(Exception):
- """
- The base Lmi scripts error.
- All the other exceptions inherit from it.
- """
- pass
-
-class LmiFailed(LmiError):
- """
- Raised, when operation on remote host failes.
- It's supposed to be used especially in command libraries.
- """
- pass
-
-class LmiUnsatisfiedDependencies(LmiFailed):
- """
- Raised when no guarded command in
- :py:class:`~.command.select.LmiSelectCommand` can be loaded due to
- unsatisfied requirements.
- """
- def __init__(self, uris):
- LmiFailed.__init__(self, "Profile and class dependencies were not"
- " satisfied for this session (%s)." % ', '.join(uris))
-
-class LmiUnexpectedResult(LmiError):
- """
- Raised, when command's associated function returns something unexpected.
- """
- def __init__(self, command_class, expected, result):
- LmiError.__init__(self,
- 'Got unexpected result from associated function of'
- ' "%s.%s", expected "%s", got: "%s".' %
- (command_class.__module__, command_class.__name__,
- expected, repr(result)))
-
-class LmiInvalidOptions(LmiError):
- """
- Raised in :py:meth:`~.command.endpoint.LmiEndPointCommand.verify_options`
- method if the options given are not valid.
- """
- pass
-
-class LmiCommandNotFound(LmiError):
- """ Raised, when user requests not registered command. """
- def __init__(self, cmd_name):
- LmiError.__init__(self, 'No such command "%s".' % cmd_name)
-
-class LmiNoConnections(LmiError):
- """ Raised, when no connection to remote hosts could be made. """
- pass
-
-class LmiCommandImportError(LmiError):
- """ Exception raised when command can not be imported. """
- def __init__(self, cmd_name, cmd_path, reason):
- LmiError.__init__(self, 'Failed to import command "%s" (%s): %s' % (
- cmd_name, cmd_path, reason))
-
-class LmiCommandError(LmiError):
- """ Generic exception related to command declaration. """
- def __init__(self, module_name, class_name, msg):
- LmiError.__init__(self, 'Wrong declaration of command "%s": %s'
- % ( ".".join([module_name, class_name])
- if module_name else class_name
- , msg))
-
-class LmiCommandInvalidName(LmiCommandError):
- """ Raised, when command gets invalid name. """
- def __init__(self, module_name, class_name, cmd_name):
- LmiCommandError.__init__(self, module_name, class_name,
- 'Invalid command name "%s".' % cmd_name)
-
-class LmiCommandMissingCallable(LmiCommandError):
- """ Raised, when command declaration is missing callable object. """
- def __init__(self, module_name, class_name):
- LmiCommandError.__init__(self, module_name, class_name,
- 'Missing CALLABLE property.')
-
-class LmiCommandInvalidProperty(LmiCommandError):
- """ Raised, when any command property contains unexpected value. """
- pass
-
-class LmiImportCallableFailed(LmiCommandInvalidProperty):
- """ Raised, when callable object of command could not be imported. """
- def __init__(self, module_name, class_name, callable_prop):
- LmiCommandInvalidProperty.__init__(self, module_name, class_name,
- 'Failed to import callable "%s".' % callable_prop)
-
-class LmiCommandInvalidCallable(LmiCommandInvalidProperty):
- """ Raised, when given callback is not callable. """
- def __init__(self, module_name, class_name, msg):
- LmiCommandInvalidProperty.__init__(self, module_name, class_name, msg)
-
-class LmiBadSelectExpression(LmiCommandError):
- """
- Raised, when expression of :py:class:`~.command.select.LmiSelectCommand`
- could not be evaluated.
- """
- def __init__(self, module_name, class_name, expr):
- LmiCommandError.__init__(self, module_name, class_name,
- "Bad select expression: %s" % expr)
-
-class LmiTerminate(Exception):
- """
- Raised to cleanly terminate interavtive shell.
- """
- def __init__(self, exit_code=0):
- Exception.__init__(self, exit_code)
diff --git a/lmi/scripts/common/formatter/__init__.py b/lmi/scripts/common/formatter/__init__.py
deleted file mode 100644
index db7b7e3..0000000
--- a/lmi/scripts/common/formatter/__init__.py
+++ /dev/null
@@ -1,484 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Subpackage with formatter classes used to render and output results.
-
-Each formatter has a :py:meth:`Formatter.produce_output` method taking one
-argument which gets rendered and printed to output stream. Each formatter
-expects different argument, please refer to doc string of particular class.
-"""
-
-import itertools
-import locale
-import os
-import pywbem
-
-from lmi.scripts.common import errors
-from lmi.scripts.common.formatter import command as fcmd
-
-def get_terminal_width():
- """
- Get the number of columns of current terminal if attached to it. It
- defaults to 79 characters.
-
- :returns: Number of columns of attached terminal.
- :rtype: integer
- """
- try:
- term_cols = int(os.popen('stty size', 'r').read().split()[1])
- except (IOError, OSError, ValueError):
- term_cols = 79 # fallback
- return term_cols
-
-class Formatter(object):
- """
- Base formatter class.
-
- It produces string representation of given argument and prints it.
-
- This formatter supports following commands:
-
- * :py:class:`~.command.NewHostCommand`.
-
- :param file stream: Output stream.
- :param integer padding: Number of leading spaces to print at each line.
- :param boolean no_headings: If table headings should be omitted.
- """
-
- def __init__(self, stream, padding=0, no_headings=False):
- if not isinstance(padding, (int, long)):
- raise TypeError("padding must be an integer")
- if padding < 0:
- padding = 0
- self.out = stream
- self.padding = padding
- self.no_headings = no_headings
- #: counter of hosts printed
- self.host_counter = 0
- #: counter of tables produced for current host
- self.table_counter = 0
- #: counter of lines producted for current table
- self.line_counter = 0
-
- @property
- def encoding(self):
- """
- Try to determine encoding for output terminal.
-
- :returns: Encoding used to encode unicode strings.
- :rtype: string
- """
- enc = getattr(self.out, 'encoding')
- if not enc:
- enc = locale.getpreferredencoding()
- return enc
-
- def render_value(self, val):
- """
- Rendering function for single value.
-
- :param val: Any value to render.
- :returns: Value converted to its string representation.
- :rtype: str
- """
- if isinstance(val, unicode):
- return val.encode(self.encoding)
- if not isinstance(val, str):
- val = str(val)
- return val
-
- def print_line(self, line, *args, **kwargs):
- """
- Prints single line. Output message is prefixed with ``padding`` spaces,
- formated and printed to output stream.
-
- :param string line: Message to print, it can contain markers for
- other arguments to include according to ``format_spec`` language.
- Please refer to ``Format Specification Mini-Language`` in python
- documentation.
- :param list args: Positional arguments to ``format()`` function of
- ``line`` argument.
- :param dictionary kwargs: Keyword arguments to ``format()`` function.
- """
- line = ' ' * self.padding + line.format(*args, **kwargs)
- self.out.write(line.encode(self.encoding))
- self.out.write("\n")
- self.line_counter += 1
-
- def print_host(self, hostname):
- """
- Prints header for new host.
-
- :param string hostname: Hostname to print.
- """
- if ( self.host_counter > 0
- or self.table_counter > 0
- or self.line_counter > 0):
- self.out.write("\n")
- term_width = get_terminal_width()
- self.out.write("="*term_width + "\n")
- self.out.write("Host: %s\n" % hostname)
- self.out.write("="*term_width + "\n")
- self.host_counter += 1
- self.table_counter = 0
- self.line_counter = 0
-
- def produce_output(self, data):
- """
- Render and print given data.
-
- Data can be also instance of
- :py:class:`~.command.FormatterCommand`, see
- documentation of this class for list of
- allowed commands.
-
- This shall be overridden by subclasses.
-
- :param data: Any value to print. Subclasses may specify their
- requirements for this argument. It can be also am instance of
- :py:class:`~.command.FormatterCommand`.
- """
- self.print_line(str(data))
- self.line_counter += 1
-
-class ListFormatter(Formatter):
- """
- Base formatter taking care of list of items. It renders input data in a
- form of table with mandatory column names at the beginning followed by
- items, one occupying single line (row).
-
- This formatter supports following commands:
- * :py:class:`~.command.NewHostCommand`
- * :py:class:`~.command.NewTableCommand`
- * :py:class:`~.command.NewTableHeaderCommand`
-
- The command must be provided as content of one row. This row is then not
- printed and the command is executed.
-
- This class should be subclassed to provide nice output.
- """
- def __init__(self, stream, padding=0, no_headings=False):
- super(ListFormatter, self).__init__(stream, padding, no_headings)
- self.column_names = None
-
- def print_text_row(self, row):
- """
- Print data row without any header.
-
- :param tuple row: Data to print.
- """
- self.out.write(" "*self.padding + self.render_value(row) + "\n")
- self.line_counter += 1
-
- def print_row(self, data):
- """
- Print data row. Optionaly print header, if requested.
-
- :param tuple data: Data to print.
- """
- if self.line_counter == 0 and not self.no_headings:
- self.print_header()
- self.print_text_row(data)
-
- def print_table_title(self, title):
- """
- Prints title of next tale.
-
- :param string title: Title to print.
- """
- if self.table_counter > 0 or self.line_counter > 0:
- self.out.write('\n')
- self.out.write("%s:\n" % title)
- self.table_counter += 1
- self.line_counter = 0
-
- def print_header(self):
- """ Print table header. """
- if self.no_headings:
- return
- if self.column_names:
- self.print_text_row(self.column_names)
-
- def produce_output(self, rows):
- """
- Prints list of rows.
-
- There can be a :py:class:`~.command.FormatterCommand` instance instead
- of a row. See documentation of this class for list of allowed commands.
-
- :param rows: List of rows to print.
- :type rows: list, generator or :py:class:`.command.FormatterCommand`
- """
- for row in rows:
- if isinstance(row, fcmd.NewHostCommand):
- self.print_host(row.hostname)
- elif isinstance(row, fcmd.NewTableCommand):
- self.print_table_title(row.title)
- elif isinstance(row, fcmd.NewTableHeaderCommand):
- self.column_names = row.columns
- else:
- self.print_row(row)
-
-class TableFormatter(ListFormatter):
- """
- Print nice human-readable table to terminal.
-
- To print the table nicely aligned, the whole table must be populated first.
- Therefore this formatter stores all rows locally and does not print
- them until the table is complete. Column sizes are computed afterwards
- and the table is printed at once.
-
- This formatter supports following commands:
- * :py:class:`~.command.NewHostCommand`
- * :py:class:`~.command.NewTableCommand`
- * :py:class:`~.command.NewTableHeaderCommand`
-
- The command must be provided as content of one row. This row is then not
- printed and the command is executed.
- """
- def __init__(self, stream, padding=0, no_headings=False):
- super(TableFormatter, self).__init__(stream, padding, no_headings)
- self.stash = []
-
- def print_text_row(self, row, column_sizes):
- for i in xrange(len(row)):
- size = column_sizes[i]
- # Convert to unicode to compute correct length of utf-8 strings
- # (e.g. with fancy trees with utf-8 graphics).
- item = ( unicode(row[i]) if not isinstance(row[i], str)
- else row[i].decode(self.encoding))
- if i < len(row) - 1:
- item = item.ljust(size)
- self.out.write(self.render_value(item))
- if i < len(row) - 1:
- self.out.write(" ")
- self.out.write("\n")
- self.line_counter += 1
-
- def print_stash(self):
- # Compute column sizes
- column_sizes = []
- rows = iter(self.stash)
- try:
- if self.column_names is None:
- row = rows.next()
- else:
- row = self.column_names
- for i in xrange(len(row)):
- column_sizes.append(len(row[i]))
- except StopIteration:
- pass # empty stash
-
- for row in rows:
- for i in xrange(len(row)):
- row_length = len(
- unicode(row[i]) if not isinstance(row[i], str)
- else row[i].decode(self.encoding))
- if column_sizes[i] < row_length:
- column_sizes[i] = row_length
-
- # print headers
- if not self.no_headings and self.column_names:
- self.print_text_row(self.column_names, column_sizes)
- # print stashed rows
- for row in self.stash:
- self.print_text_row(row, column_sizes)
- self.stash = []
-
- def print_row(self, data):
- """
- Print data row.
-
- :param tuple data: Data to print.
- """
- self.stash.append(data)
-
- def print_host(self, hostname):
- """
- Prints header for new host.
-
- :param string hostname: Hostname to print.
- """
- if len(self.stash):
- # without a check, this would print headers for empty stash
- self.print_stash()
- super(TableFormatter, self).print_host(hostname)
-
- def print_table_title(self, title):
- """
- Prints title of next tale.
-
- :param string title: Title to print.
- """
- if len(self.stash):
- # without a check, this would print headers for empty stash
- self.print_stash()
- if self.table_counter > 0 or self.line_counter > 0:
- self.out.write('\n')
- self.out.write("%s:\n" % title)
- self.table_counter += 1
- self.line_counter = 0
-
- def produce_output(self, rows):
- """
- Prints list of rows.
-
- There can be :py:class:`~.command.FormatterCommand` instance instead of
- a row. See documentation of this class for list of allowed commands.
-
- :param rows: List of rows to print.
- :type rows: list or generator
- """
- super(TableFormatter, self).produce_output(rows)
- self.print_stash()
-
-class CsvFormatter(ListFormatter):
- """
- Renders data in a csv (Comma-separated values) format.
-
- This formatter supports following commands:
- * :py:class:`~.command.NewHostCommand`
- * :py:class:`~.command.NewTableCommand`
- * :py:class:`~.command.NewTableHeaderCommand`
- """
-
- def render_value(self, val):
- if isinstance(val, basestring):
- if isinstance(val, unicode):
- val.encode(self.encoding)
- val = '"%s"' % val.replace('"', '""')
- elif val is None:
- val = ''
- else:
- val = str(val)
- return val
-
- def print_text_row(self, row):
- self.print_line(",".join(self.render_value(v) for v in row))
- self.line_counter += 1
-
-class SingleFormatter(Formatter):
- """
- Meant to render and print attributes of single object. Attributes are
- rendered as a list of assignments of values to variables (attribute names).
-
- This formatter supports following commands:
- * :py:class:`~.command.NewHostCommand`
- """
-
- def produce_output(self, data):
- """
- Render and print attributes of single item.
-
- There can be a :py:class:`~.command.FormatterCommand` instance instead
- of a data. See documentation of this class for list of allowed
- commands.
-
- :param data: Is either a pair of property names with list of values or
- a dictionary with property names as keys. Using the pair allows to
- order the data the way it should be printing. In the latter case
- the properties will be sorted by the property names.
- :type data: tuple or dict
- """
- if isinstance(data, fcmd.NewHostCommand):
- self.print_host(data.hostname)
- return
-
- if not isinstance(data, (tuple, dict)):
- raise ValueError("data must be tuple or dict")
-
- if isinstance(data, tuple):
- if not len(data) == 2:
- raise ValueError(
- "data must contain: (list of columns, list of rows)")
- dataiter = itertools.izip(data[0], data[1])
- else:
- dataiter = itertools.imap(
- lambda k: (k, self.render_value(data[k])),
- sorted(data.keys()))
- for name, value in dataiter:
- self.print_line("{0}={1}", name, value)
- self.line_counter += 1
-
-class ShellFormatter(SingleFormatter):
- """
- Specialization of :py:class:`SingleFormatter` having its output executable
- as a shell script.
-
- This formatter supports following commands:
- * :py:class:`~.command.NewHostCommand`
- """
-
- def render_value(self, val):
- if isinstance(val, basestring):
- if isinstance(val, unicode):
- val.encode(self.encoding)
- val = "'%s'" % val.replace("'", "\\'")
- elif val is None:
- val = ''
- else:
- val = str(val)
- return val
-
-class ErrorFormatter(ListFormatter):
- """
- Render error strings for particular host. Supported commands:
- * :py:class:`~.command.NewHostCommand`
- """
- def __init__(self, stream, padding=4):
- super(ErrorFormatter, self).__init__(stream, padding)
-
- def print_row(self, data):
- if isinstance(data, Exception):
- if isinstance(data, pywbem.CIMError):
- self.print_text_row("%s: %s" % (data.args[1], data.message))
- elif not isinstance(data, errors.LmiFailed):
- self.print_text_row("(%s) %s" % (data.__class__.__name__,
- str(data)))
- else:
- self.print_text_row(data)
- else:
- self.print_text_row(data)
-
- def print_host(self, hostname):
- self.out.write("host %s\n" % hostname)
- self.host_counter += 1
- self.table_counter = 0
- self.line_counter = 0
-
- def produce_output(self, rows):
- for row in rows:
- if isinstance(row, fcmd.NewHostCommand):
- self.print_host(row.hostname)
- elif isinstance(row, fcmd.NewTableCommand):
- self.print_table_title(row.title)
- else:
- self.print_row(row)
-
diff --git a/lmi/scripts/common/formatter/command.py b/lmi/scripts/common/formatter/command.py
deleted file mode 100644
index 78830c6..0000000
--- a/lmi/scripts/common/formatter/command.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Contains command classes used to control formatters from inside of command
-execution functions.
-"""
-
-class FormatterCommand(object):
- """
- Base class for formatter commands.
- """
- pass
-
-class NewHostCommand(FormatterCommand):
- """
- Command for formatter to finish current table (if any), print header for
- new host and (if there are any data) print table header.
-
- :param string hostname: Name of host appearing at the front of new table.
- """
- def __init__(self, hostname):
- self.hostname = hostname
-
-class NewTableCommand(FormatterCommand):
- """
- Command for formatter to finish current table (if any), print the **title**
- and (if there are any data) print table header.
-
- :param string title: Optional title for new table.
- """
- def __init__(self, title=None):
- self.title = title
-
-class NewTableHeaderCommand(FormatterCommand):
- """
- Command for formatter to finish current table (if any), store new table
- header and (if there are any data) print the table header.
- The table header will be printed in all subsequent tables, until
- new instance of this class arrives.
-
- :param tuple columns: Array of column names.
- """
- def __init__(self, columns=None):
- self.columns = columns
diff --git a/lmi/scripts/common/lmi_logging.py b/lmi/scripts/common/lmi_logging.py
deleted file mode 100644
index a6ff0e1..0000000
--- a/lmi/scripts/common/lmi_logging.py
+++ /dev/null
@@ -1,256 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Utilities for logging framework.
-"""
-import logging
-import sys
-
-from lmi.scripts.common import configuration
-from lmi.scripts.common import errors
-
-TERM_COLOR_NAMES = (
- 'black',
- 'red',
- 'green',
- 'yellow',
- 'blue',
- 'magenta',
- 'cyan',
- 'white',
- )
-
-# Following are terminal color codes of normal mode.
-CN_BLACK = 0
-CN_RED = 1
-CN_GREEN = 2
-CN_YELLOW = 3
-CN_BLUE = 4
-CN_MAGENTA = 5
-CN_CYAN = 6
-CN_WHITE = 7
-# Following are terminal color codes of bright mode.
-CB_BLACK = 8
-CB_RED = 9
-CB_GREEN = 10
-CB_YELLOW = 11
-CB_BLUE = 12
-CB_MAGENTA = 13
-CB_CYAN = 14
-CB_WHITE = 15
-
-WARNING_COLOR = CB_YELLOW
-ERROR_COLOR = CB_RED
-CRITICAL_COLOR = CB_MAGENTA
-
-#: Dictionary assigning color code to logging level.
-LOG_LEVEL_2_COLOR = {
- logging.WARNING : WARNING_COLOR,
- logging.ERROR : ERROR_COLOR,
- logging.CRITICAL: CRITICAL_COLOR
-}
-
-class LogRecord(logging.LogRecord):
- """
- Overrides :py:class:`logging.LogRecord`. It adds new attributes:
-
- * `levelname_` - Name of level in lowercase.
- * `cseq` - Escape sequence for terminal used to set color
- assigned to particular log level.
- * `creset` - Escape sequence for terminal used to reset foreground
- color.
-
- These can be used in format strings initializing logging formatters.
-
- Accepts the same arguments as base class.
- """
-
- def __init__(self, name, level, *args, **kwargs):
- use_colors = kwargs.pop('use_colors', True)
- logging.LogRecord.__init__(self, name, level, *args, **kwargs)
- self.levelname_ = self.levelname.lower()
- if use_colors and level >= logging.WARNING:
- if level >= logging.CRITICAL:
- color = LOG_LEVEL_2_COLOR[logging.CRITICAL]
- elif level >= logging.ERROR:
- color = LOG_LEVEL_2_COLOR[logging.ERROR]
- else:
- color = LOG_LEVEL_2_COLOR[logging.WARNING]
- self.cseq = get_color_sequence(color)
- self.creset = "\x1b[39m"
- else:
- self.cseq = self.creset = ''
-
-class ScriptsLogger(logging.getLoggerClass()):
-
- #: Boolean saying whether the color sequences for log messages shall be
- #: generated.
- USE_COLORS = True
-
- def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None,
- extra=None):
- """
- Overriden method that just changes the *LogRecord* class to our
- predefined and ensures that exception's traceback is printed once at
- most.
- """
- if exc_info:
- err = exc_info[1]
- if getattr(err, '_traceback_logged', False):
- # do not print traceback second time
- exc_info = None
- elif self.isEnabledFor(level):
- try:
- err._traceback_logged = True
- except AttributeError:
- pass
- rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func,
- use_colors=self.USE_COLORS)
- if extra is not None:
- for key in extra:
- if (key in ["message", "asctime"]) or (key in rv.__dict__):
- raise KeyError("Attempt to overwrite %r in LogRecord" % key)
- rv.__dict__[key] = extra[key]
- return rv
-
- def exception(self, msg, *args, **kwargs):
- lmi_config = configuration.Configuration.get_instance()
- exc_info = sys.exc_info()
- err = exc_info[1]
- if ( lmi_config.trace
- and ( not isinstance(err, errors.LmiError)
- or ( not getattr(err, '_traceback_logged', False)
- and lmi_config.verbosity >= lmi_config.OUTPUT_DEBUG))):
- kwargs['exc_info'] = exc_info
- else:
- kwargs.pop('exc_info', None)
- self.error(msg, *args, **kwargs)
-
-class LevelDispatchingFormatter(object):
- """
- Formatter class for logging module. It allows to predefine different format
- string used for some level ranges.
-
- :param dict formatters: Mapping of module names to *format*.
- It is a dictionary of following format: ::
-
- { max_level1 : format1
- , max_level2 : format2
- , ... }
-
- *format* in parameters description can be either ``string`` or another
- formatter object.
-
- For example if you want to have format3 used for *ERROR* and *CRITICAL*
- levels, *format2* for *INFO* and *format1* for anything else, your
- dictionary will look like this: ::
-
- { logging.INFO - 1 : format1
- , logging.INFO : format2 }
-
- And the *default* value should have *format3* assigned.
-
- :param default: Default *format* to use. This format is used for all levels
- higher than the maximum of *formatters*' keys.
- """
- def __init__(self, formatters, default=configuration.DEFAULT_FORMAT_STRING,
- datefmt=None):
- for k, formatter in formatters.items():
- if isinstance(formatter, basestring):
- formatters[k] = logging.Formatter(formatter, datefmt=datefmt)
- #: This a a tuple of pairs sorted by the first item in descending
- #: order (highest priority ordered first).
- self._formatters = tuple(sorted(formatters.items(),
- key=lambda t: -t[0]))
- if isinstance(default, basestring):
- default = logging.Formatter(default, datefmt=datefmt)
- self._default_formatter = default
-
- def format(self, record):
- """
- Interface for logging module.
- """
- record.levelname_ = record.levelname.lower()
- formatter = self._default_formatter
- for level, fmt in self._formatters:
- if level < record.levelno:
- break
- formatter = fmt
- try:
- return formatter.format(record)
- except KeyError:
- # in some modules or libraries it may happen that logger is
- # initialized before our logger class is set as default
- record.cseq = record.creset = ''
- return formatter.format(record)
-
-def get_logger(module_name):
- """
- Convenience function for getting callable returning logger for particular
- module name. It's supposed to be used at module's level to assign its
- result to global variable like this: ::
-
- from lmi.scripts import common
-
- LOG = common.get_logger(__name__)
-
- This can be used in module's functions and classes like this: ::
-
- def module_function(param):
- LOG().debug("This is debug statement logging param: %s", param)
-
- Thanks to ``LOG`` being a callable, it always returns valid logger object
- with current configuration, which may change overtime.
-
- :param string module_name: Absolute dotted module path.
- :rtype: :py:class:`logging.Logger`
- """
- def _logger():
- """ Callable used to obtain current logger object. """
- return logging.getLogger(module_name)
- return _logger
-
-def get_color_sequence(color_code):
- """
- Computer color sequence for particular color code.
-
- :returns: Escape sequence for terminal used to set foreground color.
- :rtype: str
- """
- if color_code <= 7:
- return "\x1b[%dm" % (30 + color_code)
- return "\x1b[38;5;%dm" % color_code
-
-def setup_logger(use_colors=True):
- """
- This needs to be called before any logging takes place.
- """
- ScriptsLogger.USE_COLORS = use_colors
- logging.setLoggerClass(ScriptsLogger)
diff --git a/lmi/scripts/common/session.py b/lmi/scripts/common/session.py
deleted file mode 100644
index b063d0a..0000000
--- a/lmi/scripts/common/session.py
+++ /dev/null
@@ -1,190 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Module for session object representing all connection to remote hosts.
-"""
-
-from collections import defaultdict
-
-from lmi.scripts.common import errors
-from lmi.scripts.common import get_logger
-from lmi.scripts.common.util import FilteredDict
-from lmi.shell.LMIConnection import connect
-
-LOG = get_logger(__name__)
-
-class Session(object):
- """
- Session object keeps connection objects to remote hosts. Their are
- associated with particular hostnames. It also caches credentials for them.
- Connections are made as they are needed. When credentials are missing
- for connection to be made, the user is asked to supply them from
- standard input.
-
- :param app: Instance of main application.
- :param list hosts: List of hostname strings.
- :param dictionary credentials: Mapping assigning a pair
- ``(user, password)`` to each hostname.
- :param boolean same_credentials: Use the same credentials for all
- hosts in session. The first credentials given will be used.
- """
-
- def __init__(self, app, hosts, credentials=None, same_credentials=False):
- self._app = app
- self._connections = {h: None for h in hosts}
- # { hostname : (username, password, verified), ... }
- # where verified is a flag saying, whether these credentials
- # were successfuly used for logging in
- self._credentials = defaultdict(lambda: ('', '', False))
- self._same_credentials = same_credentials
- if credentials is not None:
- if not isinstance(credentials, dict):
- raise TypeError("credentials must be a dictionary")
- for hostname, creds in credentials.items():
- credentials[hostname] = (creds[0], creds[1], False)
- self._credentials.update(credentials)
-
- def __getitem__(self, hostname):
- """
- :rtype: (``LMIConnection``) Connection object to remote host.
- ``None`` if connection can not be made.
- """
- if self._connections[hostname] is None:
- try:
- self._connections[hostname] = self._connect(
- hostname, interactive=True)
- except Exception as exc:
- LOG().error('Failed to make a connection to "%s": %s',
- hostname, exc)
- return self._connections[hostname]
-
- def __len__(self):
- """ Get the number of hostnames in session. """
- return len(self._connections)
-
- def __contains__(self, uri):
- return uri in self._connections
-
- def __iter__(self):
- """ Yields connection objects. """
- successful_connections = 0
- for hostname in self._connections:
- connection = self[hostname]
- if connection is not None:
- yield connection
- successful_connections += 1
- if successful_connections == 0:
- raise errors.LmiNoConnections('No successful connection made.')
-
- def _connect(self, hostname, interactive=False):
- """
- Makes the connection to host.
-
- :param string hostname: Name of host.
- :param boolean interactive: Whether we can interact with user
- and expect a reply from him.
- :returns: Connection to remote host or ``None``.
- :rtype: :py:class:`lmi.shell.LMIConnection` or ``None``
- """
- username, password = self.get_credentials(hostname)
- kwargs = {
- 'verify_server_cert' : self._app.config.verify_server_cert,
- 'interactive' : interactive
- }
- if len(self._connections) > 1:
- kwargs['prompt_prefix'] = '[%s] ' % hostname
- connection = connect(hostname, username, password, **kwargs)
- if connection is not None:
- tp = connection._client._cliconn.creds
- if tp is None:
- tp = ('', '')
- self._credentials[hostname] = (tp[0], tp[1], True)
- else:
- LOG().error('Failed to connect to host "%s".', hostname)
- return connection
-
- @property
- def hostnames(self):
- """
- List of hostnames in session.
-
- :rtype: list
- """
- return self._connections.keys()
-
- def get_credentials(self, hostname):
- """
- :param string hostname: Name of host to get credentials for.
- :returns: Pair of ``(username, password)`` for given hostname. If no
- credentials were given for this host, ``('', '')`` is returned.
- :rtype: tuple
- """
- username, password, verified = self._credentials[hostname]
- if ( not verified
- and (not username or not password)
- and self._same_credentials):
- for tp in self._credentials.values():
- if tp[2]:
- username, password = tp[0], tp[1]
- break
- return username, password
-
- def get_unconnected(self):
- """
- :returns: List of hostnames, which do not have associated connection
- yet.
- :rtype: list
- """
- return [h for h, c in self._connections.items() if c is None]
-
-class SessionProxy(Session):
- """
- Behaves like a session. But it just encapsulates other session object and
- provides access to a subset of its items.
-
- :param session: Session object or even another session proxy.
- :param list uris: Subset of uris in encapsulated session object.
- """
-
- def __init__(self, session, uris):
- uris = set(uris)
- if not all(isinstance(uri, basestring) for uri in uris):
- raise ValueError("uris must be iterable of uris")
- for uri in uris:
- if not uri in session:
- raise ValueError('uri "%s" needs to belong to given session'
- % uri)
- Session.__init__(self, session._app, uris, session._credentials,
- session._same_credentials)
- self._origin = session
- self._connections = FilteredDict(uris, session._connections)
- # let the credentials propagage to original session
- self._credentials = session._credentials
-
diff --git a/lmi/scripts/common/util.py b/lmi/scripts/common/util.py
deleted file mode 100644
index 4ee2161..0000000
--- a/lmi/scripts/common/util.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Various utilities for LMI Scripts.
-"""
-
-class FilteredDict(dict):
- """
- Dictionary-like collection that wraps some other dictionary and provides
- limited access to its keys and values. It permits to get, delete and set
- items specified in advance.
-
- .. note::
- Please use only the methods overriden. This class does not guarantee
- 100% API compliance. Not overriden methods won't work properly.
-
- :param list key_filter: Set of keys that can be get, set or deleted.
- For other keys, :py:class:`KeyError` will be raised.
- :param dictionary original: Original dictionary containing not only
- keys in *key_filter* but others as well. All modifying operations
- operate also on this dictionary. But only those keys in *key_filter*
- can be affected by them.
- """
-
- def __init__(self, key_filter, original=None):
- dict.__init__(self)
- if original is not None and not isinstance(original, dict):
- raise TypeError("original needs to be a dictionary")
- if original is None:
- original = dict()
- self._original = original
- self._keys = frozenset(key_filter)
-
- def __contains__(self, key):
- return key in self._keys and key in self._original
-
- def __delitem__(self, key):
- if not key in self._keys:
- raise KeyError(repr(key))
- del self._original[key]
-
- def clear(self):
- for key in self._keys:
- self._original.pop(key, None)
-
- def copy(self):
- return FilteredDict(self._keys, self._original)
-
- def iterkeys(self):
- for key in self._keys:
- yield key
-
- def __getitem__(self, key):
- if not key in self._keys:
- raise KeyError(repr(key))
- return self._original[key]
-
- def __iter__(self):
- for key in self._keys:
- if key in self._original:
- yield key
-
- def __eq__(self, other):
- return ( isinstance(other, FilteredDict)
- and self._original == other._original
- and self._keys == other._keys)
-
- def __lt__(self, other):
- if isinstance(other, dict):
- return { k: v for k, v in self._original.items()
- if k in self._keys} < other
- if not isinstance(other, FilteredDict):
- raise TypeError("Can not compare FilteredDict to objects"
- " of other types!")
- return self._original <= other._original and self._keys <= other._keys
-
- def __len__(self):
- return len(self.keys())
-
- def __setitem__(self, key, value):
- if not key in self._keys:
- raise KeyError(repr(key))
- self._original[key] = value
-
- def keys(self):
- return [k for k in self._keys if k in self._original]
-
- def values(self):
- return [self._original[k] for k in self.keys() if k in self._original]
-
- def items(self):
- return [(k, self._original[k]) for k in self.keys()]
-
- def iteritems(self):
- return iter(self.items())
-
- def pop(self, key, *args):
- ret = self[key]
- del self[key]
- return ret
-
- def popitem(self):
- for key in self._keys:
- if key in self._original:
- return self.pop(key)
- raise KeyError("FilterDict is empty!")
-
- def update(self, *args, **kwargs):
- if len(args) > 1:
- raise TypeError('Expected just one positional argument!')
- if args and callable(getattr(args[0], 'keys', None)):
- for key in args[0].keys():
- self[key] = args[0][key]
- elif args:
- for key, value in args[0]:
- self[key] = value
- for key, value in kwargs.items():
- self[key] = value
-
diff --git a/lmi/scripts/common/versioncheck/__init__.py b/lmi/scripts/common/versioncheck/__init__.py
deleted file mode 100644
index c7e595f..0000000
--- a/lmi/scripts/common/versioncheck/__init__.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Package with utilities for checking availability of profiles or CIM classes.
-Version requirements can also be specified.
-"""
-
-import functools
-from pyparsing import ParseException
-
-from lmi.scripts.common import Configuration
-from lmi.scripts.common import errors
-from lmi.scripts.common.versioncheck import parser
-
-def cmp_profiles(fst, snd):
- """
- Compare two profiles by their version.
-
- :returns:
- * -1 if the *fst* profile has lower version than *snd*
- * 0 if their versions are equal
- * 1 otherwise
- :rtype: int
- """
- fstver = fst.RegisteredVersion
- sndver = snd.RegisteredVersion
- if fstver == sndver:
- return 0
- return -1 if parser.cmp_version(fstver, sndver) else 1
-
-def get_profile_version(conn, name, cache=None):
- """
- Get version of registered profile on particular broker. Queries
- ``CIM_RegisteredProfile`` and ``CIM_RegisteredSubProfile``. The latter
- comes in question only when ``CIM_RegisteredProfile`` does not yield any
- matching result.
-
- :param conn: Connection object.
- :param string name: Name of the profile which must match value of *RegisteredName*
- property.
- :param dictionary cache: Optional cache where the result will be stored for
- later use. This greatly speeds up evaluation of several expressions refering
- to same profiles or classes.
- :returns: Version of matching profile found. If there were more of them,
- the highest version will be returned. ``None`` will be returned when no matching
- profile or subprofile is found.
- :rtype: string
- """
- if cache and name in cache:
- return cache[(conn.uri, name)]
- insts = conn.root.interop.wql('SELECT * FROM CIM_RegisteredProfile'
- ' WHERE RegisteredName=\"%s\"' % name)
- regular = set(i for i in insts if i.classname.endswith('RegisteredProfile'))
- if regular: # select instances of PG_RegisteredProfile if available
- insts = regular
- else: # otherwise fallback to PG_RegisteredSubProfile instances
- insts = set(i for i in insts if i not in regular)
- if not insts:
- ret = None
- else:
- ret = sorted(insts, cmp=cmp_profiles)[-1].RegisteredVersion
- if cache is not None:
- cache[(conn.uri, name)] = ret
- return ret
-
-def get_class_version(conn, name, namespace=None, cache=None):
- """
- Query broker for version of particular CIM class. Version is stored in
- ``Version`` qualifier of particular CIM class.
-
- :param conn: Connection object.
- :param string name: Name of class to query.
- :param string namespace: Optional CIM namespace. Defaults to configured namespace.
- :param dictionary cache: Optional cache used to speed up expression prrocessing.
- :returns: Version of CIM matching class. Empty string if class is registered but
- is missing ``Version`` qualifier and ``None`` if it is not registered.
- :rtype: string
- """
- if namespace is None:
- namespace = Configuration.get_instance().namespace
- if cache and (namespace, name) in cache:
- return cache[(conn.uri, namespace, name)]
- ns = conn.get_namespace(namespace)
- cls = getattr(ns, name, None)
- if not cls:
- ret = None
- else:
- quals = cls.wrapped_object.qualifiers
- if 'Version' not in quals:
- ret = ''
- else:
- ret = quals['Version'].value
- if cache is not None:
- cache[(conn.uri, namespace, name)] = ret
- return ret
-
-def eval_respl(expr, conn, namespace=None, cache=None):
- """
- Evaluate LMIReSpL expression on particular broker.
-
- :param string expr: Expression to evaluate.
- :param conn: Connection object.
- :param string namespace: Optional CIM namespace where CIM classes will be
- searched.
- :param dictionary cache: Optional cache speeding up evaluation.
- :returns: ``True`` if requirements in expression are satisfied.
- :rtype: boolean
- """
- if namespace is None:
- namespace = Configuration.get_instance().namespace
- stack = []
- pvget = functools.partial(get_profile_version, conn, cache=cache)
- cvget = functools.partial(get_class_version, conn,
- namespace=namespace, cache=cache)
- pr = parser.bnf_parser(stack, pvget, cvget)
- pr.parseString(expr, parseAll=True)
- # Now evaluate starting non-terminal created on stack.
- return stack[0]()
-
diff --git a/lmi/scripts/common/versioncheck/parser.py b/lmi/scripts/common/versioncheck/parser.py
deleted file mode 100644
index b5f9116..0000000
--- a/lmi/scripts/common/versioncheck/parser.py
+++ /dev/null
@@ -1,521 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Parser for mini-language specifying profile and class requirements. We call
-the language LMIReSpL (openLMI Requirement Specification Language).
-
-The only thing designed for use outside this module is :py:func:`bnf_parser`.
-
-Language is generated by BNF grammer which served as a model for parser.
-
-Formal representation of BNF grammer is following: ::
-
- expr ::= term [ op expr ]*
- term ::= '!'? req
- req ::= profile_cond | clsreq_cond | '(' expr ')'
- profile_cond ::= 'profile'? [ profile | profile_quot ] cond?
- clsreq_cond ::= 'class' [ clsname | clsname_quot] cond?
- profile_quot ::= '"' /\w+[ +.a-zA-Z0-9_-]*/ '"'
- profile ::= /\w+[+.a-zA-Z_-]*/
- clsname_quot ::= '"' clsname '"'
- clsname ::= /[a-zA-Z]+_[a-zA-Z][a-zA-Z0-9_]*/
- cond ::= cmpop version
- cmpop ::= /(<|=|>|!)=|<|>/
- version ::= /[0-9]+(\.[0-9]+)*/
- op ::= '&' | '|'
-
-String surrounded by quotes is a literal. String enclosed with slashes is a
-regular expression. Square brackets encloses a group of words and limit
-the scope of some operation (like iteration).
-"""
-import abc
-import operator
-from pyparsing import Literal, Combine, Optional, ZeroOrMore, \
- Forward, Regex, Keyword, FollowedBy, LineEnd, ParseException
-
-#: Dictionary mapping supported comparison operators to a pair. First item is a
-#: function making the comparison and the second can be of two values (``all``
-#: or ``any``). Former sayes that each part of first version string must be in
-#: relation to corresponding part of second version string in order to satisfy
-#: the condition. The latter causes the comparison to end on first satisfied
-#: part.
-OP_MAP = {
- '==' : (operator.eq, all),
- '<=' : (operator.le, all),
- '>=' : (operator.ge, all),
- '!=' : (operator.ne, any),
- '>' : (operator.gt, any),
- '<' : (operator.lt, any)
-}
-
-def cmp_version(fst, snd, opsign='<'):
- """
- Compare two version specifications. Each version string shall contain
- digits delimited with dots. Empty string is also valid version. It will be
- replaced with -1.
-
- :param str fst: First version string.
- :param str snd: Second version string.
- :param str opsign: Sign denoting operation to be used. Supported signs
- are present in :py:attr:`OP_MAP`.
- :returns: ``True`` if the relation denoted by particular operation exists
- between two operands.
- :rtype: boolean
- """
- def splitver(ver):
- """ Converts version string to a tuple of integers. """
- return tuple(int(p) if p else -1 for p in ver.split('.'))
- aparts = splitver(fst)
- bparts = splitver(snd)
- op, which = OP_MAP[opsign]
- if which is all:
- for ap, bp in zip(aparts, bparts):
- if not op(ap, bp):
- return False
- else:
- for ap, bp in zip(aparts, bparts):
- if op(ap, bp):
- return True
- if ap != bp:
- return False
- return op(len(aparts), len(bparts))
-
-class SemanticGroup(object):
- """
- Base class for non-terminals. Just a minimal set of non-terminals is
- represented by objects the rest is represented by strings.
-
- All subclasses need to define their own :py:meth:`evaluate` method. The
- parser builds a tree of these non-terminals with single non-terminal being
- a root node. This node's *evaluate* method returns a boolean saying whether
- the condition is satisfied. Root node is always an object of
- :py:class:`Expr`.
- """
-
- __metaclass__ = abc.ABCMeta
-
- def __call__(self):
- return self.evaluate()
-
- @abc.abstractmethod
- def evaluate(self):
- """
- :returns: ``True`` if the sub-condition represented by this non-terminal
- is satisfied.
- :rtype: boolean
- """
- pass
-
-class Expr(SemanticGroup):
- """
- Initial non-terminal. Object of this class (or one of its subclasses) is a
- result of parsing.
-
- :param term: An object of :py:class:`Term` non-terminal.
- """
-
- def __init__(self, term):
- assert isinstance(term, Term)
- self.fst = term
-
- def evaluate(self):
- return self.fst()
-
- def __str__(self):
- return str(self.fst)
-
-class And(Expr):
- """
- Represents logical *AND* of two expressions. Short-circuit evaluation is
- being exploited here.
-
- :param fst: An object of :py:class:`Term` non-terminal.
- :param snd: An object of :py:class:`Term` non-terminal.
- """
-
- def __init__(self, fst, snd):
- assert isinstance(snd, (Term, Expr))
- Expr.__init__(self, fst)
- self.snd = snd
-
- def evaluate(self):
- if self.fst():
- return self.snd()
- return False
-
- def __str__(self):
- return "%s & %s" % (self.fst, self.snd)
-
-class Or(Expr):
- """
- Represents logical *OR* of two expressions. Short-circuit evaluation is being
- exploited here.
-
- :param fst: An object of :py:class:`Term` non-terminal.
- :param snd: An object of :py:class:`Term` non-terminal.
- """
-
- def __init__(self, fst, snd):
- assert isinstance(snd, (Term, Expr))
- Expr.__init__(self, fst)
- self.snd = snd
-
- def evaluate(self):
- if self.fst():
- return True
- return self.snd()
-
- def __str__(self):
- return "%s | %s" % (self.fst, self.snd)
-
-class Term(SemanticGroup):
- """
- Represents possible negation of expression.
-
- :param req: An object of :py:class:`Req`.
- :param boolean negate: Whether the result of children shall be negated.
- """
-
- def __init__(self, req, negate):
- assert isinstance(req, Req)
- self.req = req
- self.negate = negate
-
- def evaluate(self):
- res = self.req()
- return not res if self.negate else res
-
- def __str__(self):
- if self.negate:
- return '!' + str(self.req)
- return str(self.req)
-
-class Req(SemanticGroup):
- """
- Represents one of following subexpressions:
-
- * single requirement on particular profile
- * single requirement on particular class
- * a subexpression
- """
- pass
-
-class ReqCond(Req):
- """
- Represents single requirement on particular class or profile.
-
- :param str kind: Name identifying kind of thing this belongs. For example
- ``'class'`` or ``'profile'``.
- :param callable version_getter: Is a function called to get version of
- either profile or CIM class. It must return corresponding version string
- if the profile or class is registered and ``None`` otherwise.
- Version string is read from ``RegisteredVersion`` property of
- ``CIM_RegisteredProfile``. If a class is being queried, version
- shall be taken from ``Version`` qualifier of given class.
- :param str name: Name of profile or CIM class to check for. In case
- of a profile, it is compared to ``RegisteredName`` property of
- ``CIM_RegisteredProfile``. If any instance of this class has matching
- name, it's version will be checked. If no matching instance is found,
- instances of ``CIM_RegisteredSubProfile`` are queried the same way.
- Failing to find it results in ``False``.
- :param str cond: Is a version requirement. Check the grammer above for
- ``cond`` non-terminal.
- """
-
- def __init__(self, kind, version_getter, name, cond=None):
- assert isinstance(kind, basestring)
- assert callable(version_getter)
- assert isinstance(name, basestring)
- assert cond is None or (isinstance(cond, tuple) and len(cond) == 2)
- self.kind = kind
- self.version_getter = version_getter
- self.name = name
- self.cond = cond
-
- def evaluate(self):
- version = self.version_getter(self.name)
- return version and (not self.cond or self._check_version(version))
-
- def _check_version(self, version):
- """
- Checks whether the version of profile or class satisfies the
- requirement. Version strings are first split into a list of integers
- (that were delimited with a dot) and then they are compared in
- descending order from the most signigicant down.
-
- :param str version: Version of profile or class to check.
- """
- opsign, cmpver = self.cond
- return cmp_version(version, cmpver, opsign)
-
- def __str__(self):
- return '{%s "%s"%s}' % (
- self.kind, self.name, ' %s %s' % self.cond if self.cond else '')
-
-class Subexpr(Req):
- """
- Represents a subexpression originally enclosed in brackets.
- """
-
- def __init__(self, expr):
- assert isinstance(expr, Expr)
- self.expr = expr
-
- def evaluate(self):
- return self.expr()
-
- def __str__(self):
- return "(%s)" % self.expr
-
-class TreeBuilder(object):
- """
- A stack interface for parser. It defines methods modifying the stack with
- additional checks.
- """
-
- def __init__(self, stack, profile_version_getter, class_version_getter):
- if not isinstance(stack, list):
- raise TypeError("stack needs to be empty!")
- if stack:
- stack[:] = []
- self.stack = stack
- self.profile_version_getter = profile_version_getter
- self.class_version_getter = class_version_getter
-
- def expr(self, strg, loc, toks):
- """
- Operates upon a stack. It takes either one or two *terms* there
- and makes an expression object out of them. Terms need to be delimited
- with logical operator.
- """
- assert len(self.stack) > 0
- if not isinstance(self.stack[-1], (Term, Expr)):
- raise ParseException("Invalid expression (stopped at char %d)."
- % loc)
- if len(self.stack) >= 3 and self.stack[-2] in ('&', '|'):
- assert isinstance(self.stack[-3], Term)
- if self.stack[-2] == '&':
- expr = And(self.stack[-3], self.stack[-1])
- else:
- expr = Or(self.stack[-3], self.stack[-1])
- self.stack.pop()
- self.stack.pop()
- elif not isinstance(self.stack[-1], Expr):
- expr = Expr(self.stack[-1])
- else:
- expr = self.stack[-1]
- self.stack[-1] = expr
-
- def term(self, strg, loc, toks):
- """
- Creates a ``term`` out of requirement (``req`` non-terminal).
- """
- assert len(self.stack) > 0
- assert isinstance(self.stack[-1], Req)
- self.stack[-1] = Term(self.stack[-1], toks[0] == '!')
-
- def subexpr(self, strg, loc, toks):
- """
- Operates upon a stack. It creates an instance of :py:class:`Subexpr`
- out of :py:class:`Expr` which is enclosed in brackets.
- """
- assert len(self.stack) > 1
- assert self.stack[-2] == '('
- assert isinstance(self.stack[-1], Expr)
- assert len(toks) > 0 and toks[-1] == ')'
- self.stack[-2] = Subexpr(self.stack[-1])
- self.stack.pop()
-
- def push_class(self, strg, loc, toks):
- """
- Handles ``clsreq_cond`` non-terminal in one go. It extracts
- corresponding tokens and pushes an object of :py:class:`ReqCond` to a
- stack.
- """
- assert toks[0] == 'class'
- assert len(toks) >= 2
- name = toks[1]
- condition = None
- if len(toks) > 2 and toks[2] in OP_MAP:
- assert len(toks) >= 4
- condition = toks[2], toks[3]
- self.stack.append(ReqCond('class', self.class_version_getter,
- name, condition))
-
- def push_profile(self, strg, loc, toks):
- """
- Handles ``profile_cond`` non-terminal in one go. It behaves in the same
- way as :py:meth:`push_profile`.
- """
- index = 0
- if toks[0] == 'profile':
- index = 1
- assert len(toks) > index
- name = toks[index]
- index += 1
- condition = None
- if len(toks) > index and toks[index] in OP_MAP:
- assert len(toks) >= index + 2
- condition = toks[index], toks[index + 1]
- self.stack.append(ReqCond('profile', self.profile_version_getter,
- name, condition))
-
- def push_literal(self, strg, loc, toks):
- """
- Pushes operators to a stack.
- """
- assert toks[0] in ('&', '|', '(')
- if toks[0] == '(':
- assert not self.stack or self.stack[-1] in ('&', '|')
- else:
- assert len(self.stack) > 0
- assert isinstance(self.stack[-1], Term)
- self.stack.append(toks[0])
-
-def bnf_parser(stack, profile_version_getter, class_version_getter):
- """
- Builds a parser operating on provided stack.
-
- :param list stack: Stack to operate on. It will contain the resulting
- :py:class:`Expr` object when the parsing is successfully over -
- it will be the only item in the list. It needs to be initially empty.
- :param callable profile_version_getter: Function returning version
- of registered profile or ``None`` if not present.
- :param callable class_version_getter: Fucntion returning version
- of registered class or ``None`` if not present.
- :returns: Parser object.
- :rtype: :py:class:`pyparsing,ParserElement`
- """
- if not isinstance(stack, list):
- raise TypeError("stack must be a list!")
- builder = TreeBuilder(stack, profile_version_getter, class_version_getter)
-
- ntop = ((Literal('&') | Literal('|')) + FollowedBy(Regex('["a-zA-Z\(!]'))) \
- .setName('op').setParseAction(builder.push_literal)
- ntversion = Regex(r'[0-9]+(\.[0-9]+)*').setName('version')
- ntcmpop = Regex(r'(<|=|>|!)=|<|>(?=\s*\d)').setName('cmpop')
- ntcond = (ntcmpop + ntversion).setName('cond')
- ntclsname = Regex(r'[a-zA-Z]+_[a-zA-Z][a-zA-Z0-9_]*').setName('clsname')
- ntclsname_quot = Combine(
- Literal('"').suppress()
- + ntclsname
- + Literal('"').suppress()).setName('clsname_quot')
- ntprofile_quot = Combine(
- Literal('"').suppress()
- + Regex(r'\w+[ +.a-zA-Z0-9_-]*')
- + Literal('"').suppress()).setName('profile_quot')
- ntprofile = Regex(r'\w+[+.a-zA-Z0-9_-]*').setName('profile')
- ntclsreq_cond = (
- Keyword('class')
- + (ntclsname_quot | ntclsname)
- + Optional(ntcond)).setName('clsreq_cond').setParseAction(
- builder.push_class)
- ntprofile_cond = (
- Optional(Keyword('profile'))
- + (ntprofile_quot | ntprofile)
- + Optional(ntcond)).setName('profile_cond').setParseAction(
- builder.push_profile)
- ntexpr = Forward().setName('expr')
- bracedexpr = (
- Literal('(').setParseAction(builder.push_literal)
- + ntexpr
- + Literal(')')).setParseAction(builder.subexpr)
- ntreq = (bracedexpr | ntclsreq_cond | ntprofile_cond).setName('req')
- ntterm = (Optional(Literal("!")) + ntreq + FollowedBy(Regex('[\)&\|]') | LineEnd()))\
- .setParseAction(builder.term)
- ntexpr << ntterm + ZeroOrMore(ntop + ntexpr).setParseAction(builder.expr)
-
- return ntexpr
-
-if __name__ == '__main__':
- def get_class_version(class_name):
- try:
- version = { 'lmi_logicalfile' : '0.1.2'
- , 'lmi_softwareidentity' : '3.2.1'
- , 'pg_computersystem' : '1.1.1'
- }[class_name.lower()]
- except KeyError:
- version = None
- return version
-
- def get_profile_version(profile_name):
- try:
- version = { 'openlmi software' : '0.1.2'
- , 'openlmi-software' : '1.3.4'
- , 'openlmi hardware' : '1.1.1'
- , 'openlmi-hardware' : '0.2.3'
- }[profile_name.lower()]
- except KeyError:
- version = None
- return version
-
- def test(s, expected):
- stack = []
- parser = bnf_parser(stack, get_profile_version, get_class_version)
- results = parser.parseString(s, parseAll=True)
- if len(stack) == 1:
- evalresult = stack[0]()
- if expected == evalresult:
- print "%s\t=>\tOK" % s
- else:
- print "%s\t=>\tFAILED" % s
- else:
- print "%s\t=>\tFAILED" % s
- print " stack: [%s]" % ', '.join(str(i) for i in stack)
-
- test( 'class LMI_SoftwareIdentity == 0.2.0', False)
- test( '"OpenLMI-Software" == 0.1.2 & "OpenLMI-Hardware" < 0.1.3', False)
- test( 'OpenLMI-Software<1|OpenLMI-Hardware!=1.2.4', True)
- test( '"OpenLMI Software" & profile "OpenLMI Hardware"'
- ' | ! class LMI_LogicalFile', True)
- test( 'profile OpenLMI-Software > 0.1.2 & !(class "PG_ComputerSystem"'
- ' == 2.3.4 | "OpenLMI Hardware")', False)
- test( 'OpenLMI-Software > 1.3 & OpenLMI-Software >= 1.3.4'
- ' & OpenLMI-Software < 1.3.4.1 & OpenLMI-Software <= 1.3.4'
- ' & OpenLMI-Software == 1.3.4', True)
- test( 'OpenLMI-Software < 1.3.4 | OpenLMI-Software > 1.3.4'
- ' | OpenLMI-Software != 1.3.4', False)
- test( '(! OpenLMI-Software == 1.3.4 | OpenLMI-Software <= 1.3.4.1)'
- ' & !(openlmi-software > 1.3.4 | Openlmi-software != 1.3.4)', True)
- for badexpr in (
- 'OpenLMI-Software > & OpenLMI-Hardware',
- 'classs LMI_SoftwareIdentity',
- 'OpenLMI-Software > 1.2.3 | == 5.4.3',
- '',
- '"OpenLMI-Software',
- 'OpenLMI-Software < > OpenLMI-Hardware',
- 'OpenlmiSoftware & (openLMI-Hardware ',
- 'OpenLMISoftware & ) OpenLMI-Hardare (',
- 'OpenLMISoftware | OpenlmiSoftware > "1.2.3"'
- ):
- try:
- test(badexpr, None)
- except ParseException:
- print "%s\t=>\tOK" % badexpr
diff --git a/man/Makefile b/man/Makefile
deleted file mode 100644
index 47a3f18..0000000
--- a/man/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-BUILDDIR ?= .
-MANPAGE := lmi.1
-TARGET := $(BUILDDIR)/$(notdir $(MANPAGE)).gz
-
-.PHONY: clean
-
-$(TARGET): $(MANPAGE)
- cat $? | gzip > $@
-
-$(MANPAGE): generate.sh ../config/lmi.conf ../lmi/scripts/_metacommand/toplevel.py
- ./generate.sh $@
-
-clean:
- rm -f $(TARGET)
diff --git a/man/generate.sh b/man/generate.sh
deleted file mode 100755
index a8a8e8d..0000000
--- a/man/generate.sh
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/bin/bash
-# This script needs to be run from openlmi-scripts/man directory. It creates a
-# man page in current directory for lmi meta-command. It's generated from lmi's
-# help message and from the configuration file.
-# Requirements:
-# * lmi meta-command needs to be installed and on PATH.
-
-dest=${1:-lmi.1}
-usage_file=`mktemp`
-options_file=`mktemp`
-configuration_file=`mktemp`
-
-# states:
-# desc - parse description
-# wusg - wait for usage
-# pusg - parse usage
-# wopt - wait for options
-# popt - parse options
-state="desc"
-re_option="^([[:blank:]]+)((-[-[:alpha:]_]+)"
-re_option+="(\ [][:alpha:]<>_()[|-]+)*)(\ \ +(.*))?"
-DESCRIPTION=
-
-if ! which "lmi" >/dev/null 2>&1; then
- echo "Please install lmi meta-command first!" >&2
- exit 1
-fi
-
-while IFS= read line; do
- case "$state" in
- "desc")
- if [[ "$line" =~ ^[[:blank:]]*$ ]] && [ -n "$DESCRIPTION" ]; then
- state="wusg"
- else
- [ -n "$DESCRIPTION" ] && DESCRIPTION+=" "
- DESCRIPTION+="$line"
- fi
- ;;
-
- "wusg")
- if [[ "$line" =~ ^[Uu]sage: ]]; then
- state="pusg0"
- printf ".nf\n" >$usage_file
- fi
- ;;
-
- pusg*)
- if [[ "$line" =~ ^[[:blank:]]*$ ]]; then
- state="wopt"
- printf ".fi\n" >>$usage_file
- else
- usg_count=`echo $state | sed 's/^pusg\([[:digit:]]\+\)/\1/'`
- if [ "$usg_count" = 0 ]; then
- spaces=`echo "$line" | sed 's/^\(\s\+\).*/\1/' | wc -c`
- elif [ $spaces -lt `echo "$line" | sed 's/^\(\s\+\).*/\1/' | wc -c` ];
- then
- indented=true
- printf ".RS\n" >>$usage_file
- elif $indented; then
- indented=false
- printf ".RE\n" >>$usage_file
- fi
- printf ".B " >>$usage_file
- echo "$line" >>$usage_file
- #echo "$line" | sed -e 's/^\s\+//' -e 's/\s\+$//' >>$usage_file
- state="pusg$((usg_count+1))"
- fi
- ;;
-
- "wopt")
- if [[ "$line" =~ ^[Oo]ption ]]; then
- state="popt0"
- fi
- ;;
-
- popt*)
- if [[ "$line" =~ ^[[:blank:]]*$ ]]; then
- printf "\n"
- break
- elif [[ "$line" =~ $re_option ]]; then
- opt_count=`echo $state | sed 's/^popt\([[:digit:]]\+\)/\1/'`
- [ "$opt_count" -gt 0 ] && printf '\n'
- printf ".TP\n.I ${BASH_REMATCH[2]}\n"
- printf -- "${BASH_REMATCH[5]}" | sed -e 's/^\s\+//' -e 's/\s\+$//'
- state="popt$((opt_count+1))"
- else
- printf " "
- printf "$line" | sed -e 's/^\s\+//' -e 's/\s\+$//'
- fi
- ;;
-
- *) break
- ;;
-
- esac
-done < <( lmi --help ) >$options_file;
-
-# states:
-# wsct - wait for the first section
-# psct - parsing the section
-# pdsc - parsing description of section
-state="wsct"
-re_sct_start="^\[([[:alpha:]]+)\]"
-re_opt_desc="^#(\s+(.*)|$)"
-re_opt_value="^#?([[:alpha:]]+)\s*=\s*(.*)"
-while IFS= read line; do
- case $state in
- "wsct")
- if [[ "$line" =~ $re_sct_start ]]; then
- state="psct"
- printf ".TP\n.B ${BASH_REMATCH[1]} Section\n"
- fi
- ;;
-
- "psct")
- if [[ "$line" =~ $re_opt_desc ]]; then
- state="pdsc"
- DESCRIPTION="${BASH_REMATCH[2]}"
- elif [[ "$line" =~ $re_sct_start ]]; then
- printf ".TP\n.B ${BASH_REMATCH[1]} Section\n"
- fi
- ;;
-
- "pdsc")
- if [[ "$line" =~ $re_opt_value ]]; then
- state="psct"
- #DESCRIPTION="${DESCRIPTION} ${BASH_REMATCH[2]}"
- printf ".RS 4\n.TP 4\n.B ${BASH_REMATCH[1]}\n"
- if [ -n "${BASH_REMATCH[2]}" ]; then
- echo "Default:"
- echo ".B ${BASH_REMATCH[2]}"
- printf ".IP\n"
- fi
- echo "${DESCRIPTION}"
- printf ".RE\n"
- elif [[ "$line" =~ $re_opt_desc ]]; then
- DESCRIPTION="${DESCRIPTION} ${BASH_REMATCH[2]}"
- elif [[ $line =~ ^$ ]]; then
- state="psct"
- fi
- ;;
-
- esac
-done < ../config/lmi.conf >$configuration_file
-
-DATE=`LC_ALL="en_US.utf8" date '+%B %Y'`
-VERSION=`lmi --version`
-
-cat >$dest <<EOF
-.TH lmi 1 "${DATE}" "openlmi-scripts ${VERSION}" "User Commands"
-
-.SH NAME
-lmi \- meta-command for managing systems with OpenLMI providers
-.SH SYNOPSIS
-EOF
-
-cat $usage_file >>$dest
-rm $usage_file
-
-cat >>$dest << EOF
-.SH DESCRIPTION
-${DESCRIPTION}
-.SH OPTIONS
-EOF
-
-cat $options_file >>$dest
-rm $options_file
-
-cat >>$dest <<EOF
-.SH CONFIGURATION
-There is a system-wide configuration file located at
-\`/etc/openlmi/lmi.conf\` and user configuration file searched at \`~/.lmirc\`.
-File path of the later can also be specified with
-.B --config-file
-option. Options in user configuration overrides system-wide.
-
-The configuration consists of sections, led by a
-.B [section]
-header and followed by
-.B name: value
-entries. Comments are prefixed with
-.B #
-or
-.B ;
-.PP
-Please refer to
-.B RFC 822
-for more details on this format. Follows a list of possible configuration
-options with leading section names.
-EOF
-
-cat $configuration_file >>$dest
-rm $configuration_file
-
-cat >>$dest <<EOF
-.SH AUTHORS
-.LP
-Michal Minar <miminar@redhat.com>
-EOF
diff --git a/man/lmi.1 b/man/lmi.1
deleted file mode 100644
index d402bf5..0000000
--- a/man/lmi.1
+++ /dev/null
@@ -1,201 +0,0 @@
-.TH lmi 1 "October 2013" "openlmi-scripts 0.2.2" "User Commands"
-
-.SH NAME
-lmi \- meta-command for managing systems with OpenLMI providers
-.SH SYNOPSIS
-.nf
-.B lmi [options] [(--trace | --notrace)] [-v]... [-h <host>]...
-.RS
-.B <command> [<args> ...]
-.RE
-.B lmi [options] [(--trace | --notrace)] [-v]... [-h <host>]...
-.B lmi (--help | --version)
-.fi
-.SH DESCRIPTION
-Allows to set a path to file, where messages will be logged. No log file is written at default.
-.SH OPTIONS
-.TP
-.I -c --config-file <config>
-Path to a user configuration file. Options specified here override any settings of global configuration file.
-.TP
-.I -h --host <host>
-Hostname of target system.
-.TP
-.I --hosts-file <hosts>
-Path to a file containing target hostnames. Each hostname must be listed on a single line.
-.TP
-.I --user <user>
-Username used in connection to any target host.
-.TP
-.I --same-credentials
-Use the first credentials given for all hosts.
-.TP
-.I -n --noverify
-Do not verify cimom's ssl certificate.
-.TP
-.I -v
-Increase verbosity of output.
-.TP
-.I --trace
-Show tracebacks on errors.
-.TP
-.I --notrace
-Suppress tracebacks for exceptions.
-.TP
-.I -q --quiet
-Supress output except for errors.
-.TP
-.I --log-file <log_file>
-Output file for logging messages.
-.TP
-.I --namespace <namespace>
-Default CIM namespace to use.
-.TP
-.I -N --no-headings
-Don't print table headings.
-.TP
-.I -H --human-friendly
-Print large values in human friendly units (i.e. MB, GB, TB etc.)
-.TP
-.I -L --lister-format (table | csv)
- Print output of lister commands in CSV or table format. CSV format is more suitable for machine processing. Defaults to table.
-.TP
-.I --help
-Show this text and quit.
-.TP
-.I --version
-Print version of 'lmi' in use and quit.
-.SH CONFIGURATION
-There is a system-wide configuration file located at
-`/etc/openlmi/lmi.conf` and user configuration file searched at `~/.lmirc`.
-File path of the later can also be specified with
-.B --config-file
-option. Options in user configuration overrides system-wide.
-
-The configuration consists of sections, led by a
-.B [section]
-header and followed by
-.B name: value
-entries. Comments are prefixed with
-.B #
-or
-.B ;
-.PP
-Please refer to
-.B RFC 822
-for more details on this format. Follows a list of possible configuration
-options with leading section names.
-.TP
-.B Main Section
-.RS 4
-.TP 4
-.B CommandNamespace
-Default:
-.B lmi.scripts.cmd
-.IP
-Python namespace, where command entry points will be searched for.
-.RE
-.RS 4
-.TP 4
-.B Trace
-Default:
-.B False
-.IP
-Whether the exceptions should be logged with tracebacks.
-.RE
-.RS 4
-.TP 4
-.B Verbosity
-Default:
-.B 0
-.IP
-An integer from -1 to 2 saying, how verbosive the output to console shall be. This differs from [Log] Level, which controls the logging messages being logged to file. If logging to console is enabled it sets the minimum severity level. -1 Supresses all messages except for critical ones. 0 shows warnings, 1 info messages and 2 enables debug messages. This option also affects the verbosity of commands, making them print more information to stdout.
-.RE
-.TP
-.B CIM Section
-.RS 4
-.TP 4
-.B namespace
-Default:
-.B root/cimv2
-.IP
-To override default CIM namespace, uncomment the line below.
-.RE
-.TP
-.B SSL Section
-.RS 4
-.TP 4
-.B VerifyServerCertificate
-Default:
-.B True
-.IP
-Whether to verify server-side certificate, when making secured connection over ssl.
-.RE
-.TP
-.B Format Section
-.RS 4
-.TP 4
-.B HumanFriendly
-Default:
-.B False
-.IP
-Whether to print values in human readable forms (e.g. with units).
-.RE
-.RS 4
-.TP 4
-.B ListerFormat
-Default:
-.B table
-.IP
-What format to use, when listing tabular data. Possible values are: {csv, table}. The former allows for easy machine parsing, the latter is more human friendly.
-.RE
-.RS 4
-.TP 4
-.B NoHeadings
-Default:
-.B False
-.IP
-Whether to suppress headings (column names) when printing tables.
-.RE
-.TP
-.B Log Section
-.RS 4
-.TP 4
-.B Level
-Default:
-.B ERROR
-.IP
-Level can be set to following values: DEBUG, INFO, WARNING, ERROR, CRITICAL Affects only logging to a file.
-.RE
-.RS 4
-.TP 4
-.B ConsoleFormat
-Default:
-.B %(levelname)s: %(message)s
-.IP
-Format string used, when logging to a console. For details visit: http://docs.python.org/2/library/logging.html#logrecord-attributes
-.RE
-.RS 4
-.TP 4
-.B LogToConsole
-Default:
-.B True
-.IP
-Whether the logging to console is enabled.
-.RE
-.RS 4
-.TP 4
-.B FileFormat
-Default:
-.B %(asctime)s:%(levelname)-8s:%(name)s:%(lineno)d - %(message)s
-.IP
-Format string used, when logging to a file.
-.RE
-.RS 4
-.TP 4
-.B OutputFile
-Allows to set a path to file, where messages will be logged. No log file is written at default.
-.RE
-.SH AUTHORS
-.LP
-Michal Minar <miminar@redhat.com>
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 2ddce25..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[upload_docs]
-upload-dir = doc/_build/html
diff --git a/setup.py.skel b/setup.py.skel
deleted file mode 100644
index ff31f29..0000000
--- a/setup.py.skel
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python
-
-import os
-import subprocess
-import sys
-from setuptools import setup, find_packages
-
-long_description = ''
-try:
- try:
- script_dir = os.path.dirname(sys.argv[0])
- cmd = ['/usr/bin/make', 'readme']
- readme_file = 'README.txt'
- if script_dir not in (',', ''):
- cmd[1:1] = ['-C', script_dir]
- readme_file = os.path.join(script_dir, readme_file)
- with open('/dev/null', 'w') as null:
- ret = subprocess.call(cmd, stdout=null, stderr=null)
- if not ret:
- long_description = open(readme_file, 'rt').read()
- except Exception as err:
- sys.stderr.write('ERROR while reading README.txt: %s\n' % str(err))
- if not long_description:
- long_description = open('README.md', 'rt').read()
-except IOError:
- pass
-
-setup(
- name='openlmi-scripts',
- version='@@VERSION@@',
- description='Client-side library and command-line client',
- long_description=long_description,
- author='Michal Minar',
- author_email='miminar@redhat.com',
- url='https://github.com/openlmi/openlmi-scripts',
- download_url='https://github.com/openlmi/openlmi-scripts/tarball/master',
- platforms=['Any'],
- license="BSD",
- classifiers=[
- 'License :: OSI Approved :: BSD License',
- 'Operating System :: POSIX :: Linux',
- 'Topic :: System :: Systems Administration',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.2',
- 'Intended Audience :: Developers',
- 'Environment :: Console',
- ],
-
- namespace_packages=['lmi', 'lmi.scripts'],
- packages=[
- 'lmi',
- 'lmi.scripts',
- 'lmi.scripts.common',
- 'lmi.scripts.common.command',
- 'lmi.scripts.common.formatter',
- 'lmi.scripts.common.versioncheck',
- 'lmi.scripts._metacommand'],
- install_requires=['openlmi-tools >= 0.8', 'docopt >= 0.6', 'pyparsing'],
- include_package_data=True,
- #data_files=[('/etc/openlmi/scripts', ['config/lmi.conf'])],
- zip_safe=False,
- entry_points={
- 'console_scripts': [
- 'lmi = lmi.scripts._metacommand:main'
- ],
- 'lmi.scripts.cmd': [],
- },
- )
diff --git a/test/README.md b/test/README.md
deleted file mode 100644
index cfcbbf7..0000000
--- a/test/README.md
+++ /dev/null
@@ -1,32 +0,0 @@
-Tests Description
-=================
-Here are tests for lmi meta-command.
-Interactive and non-interactive modes are tested.
-
-Dependencies
-------------
- * bash
- * beakerlib
- * expect
- * openlmi-tools
-
-Openlmi scripts need not be installed.
-
-Remote host shall have `openlmi-software` and `openlmi-hardware` installed. If
-not, `LMI_SOFTWARE_PROVIDER_VERSION` and `LMI_HARDWARE_PROVIDER_VERSION` needs
-to be set to `none`.
-
-Run
----
-Install and run any CIM broker on this or any remote host. Ensure that lmishell
-can connect to it. Export these variables:
-
- * LMI_CIMOM_URL
- * LMI_CIMOM_USERNAME
- * LMI_CIMOM_PASSWORD
- * LMI_SOFTWARE_PROVIDER_VERSION - version of software provider registered
- with CIMOM
- * LMI_HARDWARE_PROVIDER_VERSION
-
-Execute:
- $ ./run.sh
diff --git a/test/base.sh b/test/base.sh
deleted file mode 100644
index acec1be..0000000
--- a/test/base.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Jan Safranek <jsafrane@redhat.com>
-# Authors: Michal Minar <miminar@redhat.com>
-
-# Basic framework for all 'lmi' tests.
-# It is based on Beakerlib, https://fedorahosted.org/beakerlib/
-
-. /usr/share/beakerlib/beakerlib.sh
-
-LMI_CIMOM_URL=${LMI_CIMOM_URL:-kvm-rhel7}
-LMI_CIMOM_USERNAME=${LMI_CIMOM_USERNAME:-root}
-LMI_CIMOM_PASSWORD=${LMI_CIMOM_PASSWORD:-redhat}
-
-SCHEMA=$(echo $LMI_CIMOM_URL | sed -n 's!^\([[:alpha:]]\+://\).*!\1!p')
-HOSTNAME=$(echo $LMI_CIMOM_URL | sed -e 's!^.*//!!' -e 's!/.*!!')
-LMI="lmi"
-[ -n "$HOSTNAME" ] && \
- LMI+=" -n -h $SCHEMA$LMI_CIMOM_USERNAME:$LMI_CIMOM_PASSWORD@$HOSTNAME"
-export LMI
-
-# for some tests no other options are welcomed
-export LMI_=`echo $LMI | cut -d \ -f 1`
-
diff --git a/test/cmd/help_foo.out b/test/cmd/help_foo.out
deleted file mode 100644
index 1584a91..0000000
--- a/test/cmd/help_foo.out
+++ /dev/null
@@ -1,6 +0,0 @@
-error : No such command "foo".
-Commands:
- help - Print the list of supported commands with short description.
-
-For more informations about particular command type:
- help <command>
diff --git a/test/cmd/help_help.out b/test/cmd/help_help.out
deleted file mode 100644
index fd6fecb..0000000
--- a/test/cmd/help_help.out
+++ /dev/null
@@ -1,4 +0,0 @@
-Print the list of supported commands with short description.
-If a subcommand is given, its detailed help will be printed.
-
-Usage: lmi help [<subcommand>...]
diff --git a/test/cmd/help_test.out b/test/cmd/help_test.out
deleted file mode 100644
index 8ebe3a4..0000000
--- a/test/cmd/help_test.out
+++ /dev/null
@@ -1,7 +0,0 @@
-Test command for lmi-metacommand.
-
-Usage:
- lmi test list <cmd> [<args> ...]
- lmi test show pkg <name>
- lmi test show repo <name>
- lmi test log <cmd> [<args> ...]
diff --git a/test/cmd/help_test_list.out b/test/cmd/help_test_list.out
deleted file mode 100644
index 3063607..0000000
--- a/test/cmd/help_test_list.out
+++ /dev/null
@@ -1,5 +0,0 @@
-List various types of software data.
-
-Usage:
- lmi test list pkgs [(--installed | --available)]
- lmi test list repos [(--enabled | --disabled)]
diff --git a/test/cmd/help_with_test.out b/test/cmd/help_with_test.out
deleted file mode 100644
index 8b93267..0000000
--- a/test/cmd/help_with_test.out
+++ /dev/null
@@ -1,6 +0,0 @@
-Commands:
- help - Print the list of supported commands with short description.
- test - Test command for lmi-metacommand.
-
-For more informations about particular command type:
- help <command>
diff --git a/test/cmd/help_without_test.out b/test/cmd/help_without_test.out
deleted file mode 100644
index 6640727..0000000
--- a/test/cmd/help_without_test.out
+++ /dev/null
@@ -1,5 +0,0 @@
-Commands:
- help - Print the list of supported commands with short description.
-
-For more informations about particular command type:
- help <command>
diff --git a/test/cmdver/README.md b/test/cmdver/README.md
deleted file mode 100644
index 14c401e..0000000
--- a/test/cmdver/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Subcommand just for testing purposes.
diff --git a/test/cmdver/lmi/__init__.py b/test/cmdver/lmi/__init__.py
deleted file mode 100644
index b1a2ff0..0000000
--- a/test/cmdver/lmi/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/test/cmdver/lmi/scripts/__init__.py b/test/cmdver/lmi/scripts/__init__.py
deleted file mode 100644
index b1a2ff0..0000000
--- a/test/cmdver/lmi/scripts/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/test/cmdver/lmi/scripts/cmdver/__init__.py b/test/cmdver/lmi/scripts/cmdver/__init__.py
deleted file mode 100644
index f9e0c8b..0000000
--- a/test/cmdver/lmi/scripts/cmdver/__init__.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-
-import pywbem
-from lmi.scripts.common import command
-from lmi.scripts.common import get_computer_system
-
-# 1st entry point
-class CmdverSw(command.LmiSelectCommand):
- """
- This is a short description for CmdverSw.
- """
- SELECT = (
- ('OpenLMI-Software < 0.4.2', 'lmi.scripts.cmdver.pre042.Cmd'),
- ('OpenLMI-Software == 0.4.2', 'lmi.scripts.cmdver.ver042.Cmd'),
- ('OpenLMI-Software > 0.4.2', 'lmi.scripts.cmdver.devel.Cmd'),
- )
-
-def get_hw_profile_version(ns):
- try:
- return ns.connection.root.interop.wql('SELECT * FROM PG_RegisteredProfile'
- ' WHERE RegisteredName="OpenLMI-Hardware"')[0].RegisteredVersion
- except pywbem.CIMError, IndexError:
- return None
-
-class SystemInfo(command.LmiLister):
- COLUMNS = []
- PRE042 = False
-
- def execute(self, ns):
- cls = ns.LMI_Chassis
- inst = cls.first_instance()
- verstr = get_hw_profile_version(ns)
- if self.PRE042:
- verstr += ' (PRE 0.4.2)'
- return [('Prov version', verstr),
- ('Chassis Type', cls.ChassisPackageTypeValues.value_name(
- inst.ChassisPackageType))]
-
-class HostnameInfo(command.LmiLister):
- COLUMNS = []
- PRE042 = False
-
- def execute(self, ns):
- verstr = get_hw_profile_version(ns)
- if self.PRE042:
- verstr += ' (PRE 0.4.2)'
- return [('Prov version', verstr),
- ('Hostname', get_computer_system(ns).Name)]
-
-class PreSystemInfo(SystemInfo):
- PRE042 = True
-
-class PreHostnameInfo(HostnameInfo):
- PRE042 = True
-
-class HwCmd(command.LmiCommandMultiplexer):
- """
- Hardware testing command.
-
- Usage:
- %(cmd)s system
- %(cmd)s hostname
- """
- COMMANDS = {
- 'system' : SystemInfo,
- 'hostname' : HostnameInfo
- }
- OWN_USAGE = True
-
-class PreHwCmd(HwCmd):
- COMMANDS = {
- 'system' : PreSystemInfo,
- 'hostname' : PreHostnameInfo
- }
-
-class NoHwRegistered(command.LmiLister):
- """
- Hardware testing command.
-
- Usage: %(cmd)s <cmd>
- """
- COLUMNS = []
- OWN_USAGE = True
- def execute(self, ns, cmd):
- return [('Given command', cmd), ('Prov version', 'N/A')]
-
-# 2nd entry point
-class CmdverHw(command.LmiSelectCommand):
- """
- This is a short description for CmdverHw.
- """
- SELECT = (
- ('OpenLMI-Hardware < 0.4.2', PreHwCmd),
- ('OpenLMI-Hardware >= 0.4.2 & class LMI_Chassis == 0.3.0', HwCmd)
- )
- DEFAULT = NoHwRegistered
-
-# 3rd entry point
-class Cmdver(command.LmiCommandMultiplexer):
- """
- Command for testing version dependencies.
-
- Usage:
- %(cmd)s (sw|hw) [<args>...]
- """
- COMMANDS = {
- 'sw' : CmdverSw,
- 'hw' : CmdverHw
- }
- OWN_USAGE = True
diff --git a/test/cmdver/lmi/scripts/cmdver/devel.py b/test/cmdver/lmi/scripts/cmdver/devel.py
deleted file mode 100644
index 624428e..0000000
--- a/test/cmdver/lmi/scripts/cmdver/devel.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-
-from lmi.scripts.common import command
-from lmi.scripts.cmdver import swbase
-
-class Cmd(swbase.SwCmdBase):
- ADDITIONAL_VERSION_INFO = ' (DEVEL)'
diff --git a/test/cmdver/lmi/scripts/cmdver/pre042.py b/test/cmdver/lmi/scripts/cmdver/pre042.py
deleted file mode 100644
index e7565ae..0000000
--- a/test/cmdver/lmi/scripts/cmdver/pre042.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-
-from lmi.scripts.common import command
-from lmi.scripts.cmdver import swbase
-
-class Cmd(swbase.SwCmdBase):
- ADDITIONAL_VERSION_INFO = ' (PRE 0.4.2)'
diff --git a/test/cmdver/lmi/scripts/cmdver/swbase.py b/test/cmdver/lmi/scripts/cmdver/swbase.py
deleted file mode 100644
index eed9dc2..0000000
--- a/test/cmdver/lmi/scripts/cmdver/swbase.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-"""
-Software testing command.
-
-Usage: %(cmd)s
-"""
-
-import pywbem
-from lmi.scripts.common import command
-
-def get_sw_profile_version(ns):
- try:
- return ns.connection.root.interop.wql('SELECT * FROM PG_RegisteredProfile'
- ' WHERE RegisteredName="OpenLMI-Software"')[0].RegisteredVersion
- except pywbem.CIMError, IndexError:
- return None
-
-class SwCmdBase(command.LmiLister):
- OWN_USAGE = __doc__
- COLUMNS = []
- ADDITIONAL_VERSION_INFO = ''
-
- def execute(self, ns):
- return [('Prov version',
- get_sw_profile_version(ns) + self.ADDITIONAL_VERSION_INFO)]
-
diff --git a/test/cmdver/lmi/scripts/cmdver/ver042.py b/test/cmdver/lmi/scripts/cmdver/ver042.py
deleted file mode 100644
index 433b539..0000000
--- a/test/cmdver/lmi/scripts/cmdver/ver042.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-
-from lmi.scripts.common import command
-from lmi.scripts.cmdver import swbase
-
-class Cmd(swbase.SwCmdBase):
- ADDITIONAL_VERSION_INFO = ' (VER 0.4.2)'
diff --git a/test/cmdver/setup.py b/test/cmdver/setup.py
deleted file mode 100644
index 58ea463..0000000
--- a/test/cmdver/setup.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-# -*- encoding: utf-8 -*-
-
-from setuptools import setup
-
-try:
- long_description = open('README.md', 'rt').read()
-except IOError:
- long_description = ''
-
-setup(
- name='openlmi-scripts-cmdver',
- version='0.1.2',
- description='Test command for versioning.',
- long_description=long_description,
- author=u'Michal Minar',
- author_email='miminar@redhat.com',
- url='https://github.com/openlmi/openlmi-cmdver',
- download_url='https://github.com/openlmi/openlmi-cmdver/tarball/master',
- platforms=['Any'],
- license="BSD",
- classifiers=[
- 'License :: OSI Approved :: BSD License',
- 'Operating System :: POSIX :: Linux',
- 'Topic :: System :: Systems Administration',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Intended Audience :: Developers',
- 'Environment :: Console',
- ],
-
- install_requires=['openlmi-scripts'],
-
- namespace_packages=['lmi', 'lmi.scripts'],
- packages=['lmi', 'lmi.scripts', 'lmi.scripts.cmdver'],
- include_package_data=True,
-
- entry_points={
- 'lmi.scripts.cmd': [
- # All subcommands of lmi command should go here.
- # See http://pythonhosted.org/openlmi-scripts/script-development.html#writing-setup-py
- 'ver-sw = lmi.scripts.cmdver:CmdverSw',
- 'ver-hw = lmi.scripts.cmdver:CmdverHw',
- 'ver = lmi.scripts.cmdver:Cmdver',
- ],
- },
- )
diff --git a/test/imode/builtin_help.out b/test/imode/builtin_help.out
deleted file mode 100644
index 016468d..0000000
--- a/test/imode/builtin_help.out
+++ /dev/null
@@ -1,15 +0,0 @@
-Built-ins.
-
-Usage:
- : cd [<path>]
- : ..
- : pwd
- : (help | -h | --help)
-
-Description:
- cd Nest to a subcommand. Accepts a sequence of subcommands separated
- with "/". If "/" is given, top-level command becomes the active one.
- Other supported special symbols are ".." and ".".
- .. Make parent command the active one. Same as issuing ":cd ..".
- pwd Print current command path.
- help Show this help.
diff --git a/test/imode/cd_test.exp b/test/imode/cd_test.exp
deleted file mode 100644
index c241c89..0000000
--- a/test/imode/cd_test.exp
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/expect -f
-# Test :cd and :pwd built-in commands.
-#
-# Environment variables:
-# LMI - path to lmi meta-command executable with optional argumenta.
-#
-# Last change dir is unsuccessful.
-# Exits with the exit code os spawned lmi shell.
-
-set timeout 1
-
-expect_after {
- timeout { exit -1 }
-}
-
-proc send1l {in out} {
- send "$in\r"
- expect "$out"
-}
-
-proc send2l {in out1 out2} {
- send "$in\r"
- expect "$out1"
- expect "$out2"
-}
-
-set LMI lmi
-if {[info exists env(LMI)]} {
- set LMI $env(LMI)
-}
-spawn {*}$LMI
-expect "lmi> "
-send2l ": pwd" "/lmi" "lmi> "
-send1l ": cd ." "lmi> "
-send2l " : pwd " "/lmi" "lmi> "
-send1l ":cd .." "lmi> "
-send1l ":cd /" "lmi> "
-send1l " : cd // " "lmi> "
-send1l ": cd test" ">test> "
-send2l ": pwd" "/lmi/test" ">test> "
-send1l ":cd ." ">test> "
-send1l ": .." "lmi> "
-send2l ":pwd" "/lmi" "lmi> "
-send1l ":cd test" ">test> "
-send1l ":cd / " "lmi> "
-send1l ":cd test/" ">test> "
-send1l ":cd ../test" ">test> "
-send1l ":cd .././test/.././test/../" "lmi> "
-send1l ":cd test/./" ">test> "
-send1l ":cd list" ">>list> "
-send2l ":pwd" "/lmi/test/list" ">>list> "
-send1l ":cd .." ">test> "
-send1l ":cd /lmi/test/list" "list> "
-send1l ":cd /lmi" "lmi> "
-send1l ":cd /test/list" "list> "
-send1l ":cd" "list> "
-send1l ":cd /./test/../test/./list" ">>list> "
-send2l ":cd /foo" "No such subcommand \"foo\"." ">>list> "
-send2l ":cd pkgs" "Can not nest to subcommand \"pkgs\" which is not a multiplexer." ">>list> "
-send2l ":cd ../show" "Can not nest to subcommand \"../show\" which lacks any help message." ">>list> "
-send2l ":cd foo" "No such subcommand \"foo\"." ">>list> "
-send ""
-expect ">test> "
-send ""
-expect "lmi> "
-send ""
-expect ""
-catch wait result
-exit [lindex $result 3]
diff --git a/test/imode/complete_builtin.exp b/test/imode/complete_builtin.exp
deleted file mode 100644
index 9f9ef88..0000000
--- a/test/imode/complete_builtin.exp
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/expect -f
-
-set timeout 1
-
-expect_after {
- timeout { exit -1 }
-}
-
-set LMI lmi
-if {[info exists env(LMI)]} {
- set LMI $env(LMI)
-}
-spawn {*}$LMI
-expect "lmi> "
-send ": "
-expect ".. cd help pwd"
-expect "lmi> :"
-send ". "
-expect "."
-send ""
-send "p "
-expect "wd"
-send "c "
-expect "d"
-send " test\r"
-expect ">test> "
-send " : "
-expect ".. cd help pwd"
-send "h "
-expect "elp"
-send ""
-expect ">test> "
-send "EOF\r"
-expect "lmi> "
-send "EOF\r"
-catch wait result
-exit [lindex $result 3]
diff --git a/test/imode/completion.exp b/test/imode/completion.exp
deleted file mode 100644
index d9ea477..0000000
--- a/test/imode/completion.exp
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/expect -f
-
-set timeout 1
-
-expect_after {
- timeout { exit -1 }
-}
-
-set LMI lmi
-if {[info exists env(LMI)]} {
- set LMI $env(LMI)
-}
-
-spawn {*}$LMI
-expect "lmi> "
-send " "
-expect "EOF exit help test"
-send "E "
-expect "EOF"
-send ""
-expect "lmi> "
-send "e "
-expect "xit"
-send " "
-expect "exit"
-expect "lmi> exit"
-send "\r"
-expect ""
-catch wait result
-if {[lindex $result 3] != 0} {
- exit [expr 10 + [lindex $result 3]]
-} else {
- puts "\n"
-}
-
-spawn {*}$LMI
-expect "lmi> "
-send ":cd test\r"
-expect ">test> "
-send " "
-expect "EOF exit help list log show"
-send "l "
-expect "list log"
-expect ">test> l"
-send "i "
-expect "st"
-send ""
-expect ">test> "
-send "ex "
-expect "it"
-send " 20\r"
-expect ""
-catch wait result
-exit [lindex $result 3]
diff --git a/test/imode/empty_lines.exp b/test/imode/empty_lines.exp
deleted file mode 100644
index c5fdb77..0000000
--- a/test/imode/empty_lines.exp
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/expect -f
-
-set timeout 1
-
-expect_after {
- timeout { exit -1 }
-}
-
-set LMI lmi
-if {[info exists env(LMI)]} {
- set LMI $env(LMI)
-}
-spawn {*}$LMI
-expect "lmi> "
-send "\r"
-expect "lmi> "
-send "\r"
-expect "lmi> "
-send " \r"
-expect "lmi> "
-send " : pwd\r"
-expect "/lmi"
-expect "lmi> "
-send "exit\r"
-catch wait result
-exit [lindex $result 3]
diff --git a/test/imode/empty_lines.out b/test/imode/empty_lines.out
deleted file mode 100644
index e03a6dc..0000000
--- a/test/imode/empty_lines.out
+++ /dev/null
@@ -1 +0,0 @@
-/lmi
diff --git a/test/imode/empty_lines.txt b/test/imode/empty_lines.txt
deleted file mode 100644
index 006be60..0000000
--- a/test/imode/empty_lines.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-:cd .
-:pwd
-
-
diff --git a/test/imode/eof.exp b/test/imode/eof.exp
deleted file mode 100644
index 56187ec..0000000
--- a/test/imode/eof.exp
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/expect -f
-
-set timeout 1
-
-expect_after {
- timeout { exit -1 }
-}
-
-spawn lmi
-expect "lmi> "
-if {[llength $argv] > 0} {
- send "[lindex $argv 0]\r"
- expect {
- timeout { exit -2 }
- "[lindex $argv 1]"
- }
- expect "lmi> "
-}
-close
-catch wait result
-exit [lindex $result 3]
diff --git a/test/imode/exit.exp b/test/imode/exit.exp
deleted file mode 100644
index 55cf207..0000000
--- a/test/imode/exit.exp
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/expect -f
-
-set timeout 1
-
-expect_after {
- timeout { exit -1 }
-}
-
-if {[llength $argv] > 0} {
- set exit_arg " [lindex $argv 0]"
-} else {
- set exit_arg ""
-}
-
-spawn lmi
-expect "lmi> "
-send "exit$exit_arg\r"
-expect eof
-catch wait result
-exit [lindex $result 3]
diff --git a/test/imode/help.out b/test/imode/help.out
deleted file mode 100644
index 4a89747..0000000
--- a/test/imode/help.out
+++ /dev/null
@@ -1,13 +0,0 @@
-
-Static commands
-===============
-EOF exit help
-
-Application commands (type help <topic>):
-=========================================
-test
-
-Built-in commands (type :help):
-===============================
-:.. :cd :pwd :help
-
diff --git a/test/imode/help_exit.out b/test/imode/help_exit.out
deleted file mode 100644
index c6ab1d1..0000000
--- a/test/imode/help_exit.out
+++ /dev/null
@@ -1,3 +0,0 @@
-Terminate the shell.
-
-Usage: exit [<exit_code>]
diff --git a/test/imode/help_foo.out b/test/imode/help_foo.out
deleted file mode 100644
index 134c3f8..0000000
--- a/test/imode/help_foo.out
+++ /dev/null
@@ -1,14 +0,0 @@
-error : No such command "foo".
-
-Static commands
-===============
-EOF exit help
-
-Application commands (type help <topic>):
-=========================================
-test
-
-Built-in commands (type :help):
-===============================
-:.. :cd :pwd :help
-
diff --git a/test/imode/help_help.out b/test/imode/help_help.out
deleted file mode 100644
index bddf2cd..0000000
--- a/test/imode/help_help.out
+++ /dev/null
@@ -1,4 +0,0 @@
-Print the list of supported commands with short description.
-If a subcommand is given, its detailed help will be printed.
-
-Usage: help [<subcommand>...]
diff --git a/test/imode/help_test.out b/test/imode/help_test.out
deleted file mode 100644
index 4d69313..0000000
--- a/test/imode/help_test.out
+++ /dev/null
@@ -1,7 +0,0 @@
-Test command for lmi-metacommand.
-
-Usage:
- test list <cmd> [<args> ...]
- test show pkg <name>
- test show repo <name>
- test log <cmd> [<args> ...]
diff --git a/test/imode/lmi_test_help.out b/test/imode/lmi_test_help.out
deleted file mode 100644
index 8b93267..0000000
--- a/test/imode/lmi_test_help.out
+++ /dev/null
@@ -1,6 +0,0 @@
-Commands:
- help - Print the list of supported commands with short description.
- test - Test command for lmi-metacommand.
-
-For more informations about particular command type:
- help <command>
diff --git a/test/imode/run_test_cmd.exp b/test/imode/run_test_cmd.exp
deleted file mode 100644
index f61b7a0..0000000
--- a/test/imode/run_test_cmd.exp
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/expect -f
-# Environment variables:
-# LMI - path to lmi meta-command executable with optional argumenta.
-#
-# Arguments:
-# OUTFILE - Where to write the output of COMMAND.
-# PATH - Command path where we change before execution.
-# PROMPT - Prompt that is expected to appear after changing to PATH.
-# COMMAND - Command to execute on given PATH.
-#
-# Exits with the exit code of spawned lmi shell.
-
-set timeout 2
-
-expect_after {
- timeout { exit -1 }
-}
-
-set OUTFILE [open [lindex $argv 0] w]
-set PROMPT [lindex $argv 2]
-set LMI lmi
-if {[info exists env(LMI)]} {
- set LMI $env(LMI)
-}
-spawn -noecho sh -c "$LMI 2> /dev/null"
-expect "lmi> "
-send ":cd [lindex $argv 1]\r"
-expect $PROMPT
-send "[lindex $argv 3]\r"
-expect -re ".*" {}
-set REG {([^\n]+)\n(.*)}
-expect -re "$REG$PROMPT\s*" {
- puts -nonewline $OUTFILE [string map {"\r" ""} "$expect_out(2,string)"]
-}
-send "exit\r"
-expect eof
-
-catch wait result
-exit [lindex $result 3]
diff --git a/test/imode/test_builtin_help.txt b/test/imode/test_builtin_help.txt
deleted file mode 100644
index 99cdb2b..0000000
--- a/test/imode/test_builtin_help.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-: cd test
-: help
diff --git a/test/imode/test_help.out b/test/imode/test_help.out
deleted file mode 100644
index 39176aa..0000000
--- a/test/imode/test_help.out
+++ /dev/null
@@ -1,10 +0,0 @@
-Test command for lmi-metacommand.
-
-Usage:
- test list <cmd> [<args> ...]
- test show pkg <name>
- test show repo <name>
- test log <cmd> [<args> ...]
-
-To get help for built-in commands, type:
- :help
diff --git a/test/imode/test_help.txt b/test/imode/test_help.txt
deleted file mode 100644
index e17ac65..0000000
--- a/test/imode/test_help.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-:cd test
-help
diff --git a/test/imode/test_help_exit.txt b/test/imode/test_help_exit.txt
deleted file mode 100644
index 5470ee3..0000000
--- a/test/imode/test_help_exit.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-:cd test
-help exit
diff --git a/test/imode/test_help_list.out b/test/imode/test_help_list.out
deleted file mode 100644
index 3f81637..0000000
--- a/test/imode/test_help_list.out
+++ /dev/null
@@ -1,5 +0,0 @@
-List various types of software data.
-
-Usage:
- list pkgs [(--installed | --available)]
- list repos [(--enabled | --disabled)]
diff --git a/test/imode/test_help_list.txt b/test/imode/test_help_list.txt
deleted file mode 100644
index 6ccd253..0000000
--- a/test/imode/test_help_list.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-:cd test
-help list
diff --git a/test/imode/test_help_show.out b/test/imode/test_help_show.out
deleted file mode 100644
index 4d69313..0000000
--- a/test/imode/test_help_show.out
+++ /dev/null
@@ -1,7 +0,0 @@
-Test command for lmi-metacommand.
-
-Usage:
- test list <cmd> [<args> ...]
- test show pkg <name>
- test show repo <name>
- test log <cmd> [<args> ...]
diff --git a/test/imode/test_help_show.txt b/test/imode/test_help_show.txt
deleted file mode 100644
index bd8ae57..0000000
--- a/test/imode/test_help_show.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-:cd test
-help show
diff --git a/test/imode/test_list_opt_help.out b/test/imode/test_list_opt_help.out
deleted file mode 100644
index 92f76ee..0000000
--- a/test/imode/test_list_opt_help.out
+++ /dev/null
@@ -1,5 +0,0 @@
-List various types of software data.
-
-Usage:
- test list pkgs [(--installed | --available)]
- test list repos [(--enabled | --disabled)]
diff --git a/test/imode/test_opt_help.out b/test/imode/test_opt_help.out
deleted file mode 100644
index 4d69313..0000000
--- a/test/imode/test_opt_help.out
+++ /dev/null
@@ -1,7 +0,0 @@
-Test command for lmi-metacommand.
-
-Usage:
- test list <cmd> [<args> ...]
- test show pkg <name>
- test show repo <name>
- test log <cmd> [<args> ...]
diff --git a/test/logging/defaults.conf b/test/logging/defaults.conf
deleted file mode 100644
index 047572b..0000000
--- a/test/logging/defaults.conf
+++ /dev/null
@@ -1 +0,0 @@
-[Log]
diff --git a/test/logging/log_all_debug.file b/test/logging/log_all_debug.file
deleted file mode 100644
index 69326b5..0000000
--- a/test/logging/log_all_debug.file
+++ /dev/null
@@ -1,9 +0,0 @@
-DEBUG: Running command "test".
-DEBUG: Found registered command "test".
-WARNING: Command "lmi.scripts.cmdtest.Show" is missing usage string. It will be inherited from parent command.
-INFO: Connected to kvm-rhel7
-DEBUG: One Ring to rule them all.
-INFO: One Ring to find them.
-WARNING: One Ring to bring them all
-ERROR: and in the darkness bind them.
-CRITICAL: In the land of Mordor where the Shadows lie.
diff --git a/test/logging/log_all_debug.stderr b/test/logging/log_all_debug.stderr
deleted file mode 100644
index 31573aa..0000000
--- a/test/logging/log_all_debug.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-Running command "test".
-Found registered command "test".
-warning : Command "lmi.scripts.cmdtest.Show" is missing usage string. It will be inherited from parent command.
-Connected to kvm-rhel7
-One Ring to rule them all.
-One Ring to find them.
-warning : One Ring to bring them all
-error : and in the darkness bind them.
-critical: In the land of Mordor where the Shadows lie.
diff --git a/test/logging/log_all_debug.stdout b/test/logging/log_all_debug.stdout
deleted file mode 100644
index 98d7a80..0000000
--- a/test/logging/log_all_debug.stdout
+++ /dev/null
@@ -1,3 +0,0 @@
-Additional information.
-Enjoy tracebacks.
-I can not be more verbose than this!
diff --git a/test/logging/log_all_debug_notrace.stdout b/test/logging/log_all_debug_notrace.stdout
deleted file mode 100644
index dfd2b72..0000000
--- a/test/logging/log_all_debug_notrace.stdout
+++ /dev/null
@@ -1,2 +0,0 @@
-Additional information.
-I can not be more verbose than this!
diff --git a/test/logging/log_all_default.stdout b/test/logging/log_all_default.stdout
deleted file mode 100644
index e69de29..0000000
--- a/test/logging/log_all_default.stdout
+++ /dev/null
diff --git a/test/logging/log_all_error.stderr b/test/logging/log_all_error.stderr
deleted file mode 100644
index f8f1c07..0000000
--- a/test/logging/log_all_error.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error : and in the darkness bind them.
-critical: In the land of Mordor where the Shadows lie.
diff --git a/test/logging/log_all_info.stderr b/test/logging/log_all_info.stderr
deleted file mode 100644
index 2abec7e..0000000
--- a/test/logging/log_all_info.stderr
+++ /dev/null
@@ -1,5 +0,0 @@
-warning : Command "lmi.scripts.cmdtest.Show" is missing usage string. It will be inherited from parent command.
-One Ring to find them.
-warning : One Ring to bring them all
-error : and in the darkness bind them.
-critical: In the land of Mordor where the Shadows lie.
diff --git a/test/logging/log_all_info.stdout b/test/logging/log_all_info.stdout
deleted file mode 100644
index 17af42d..0000000
--- a/test/logging/log_all_info.stdout
+++ /dev/null
@@ -1,2 +0,0 @@
-Additional information.
-Enjoy tracebacks.
diff --git a/test/logging/log_all_silent.stdout b/test/logging/log_all_silent.stdout
deleted file mode 100644
index 73f7ea6..0000000
--- a/test/logging/log_all_silent.stdout
+++ /dev/null
@@ -1,2 +0,0 @@
-Let's be silent.
-Enjoy tracebacks.
diff --git a/test/logging/log_all_warn.file b/test/logging/log_all_warn.file
deleted file mode 100644
index 4eaadb9..0000000
--- a/test/logging/log_all_warn.file
+++ /dev/null
@@ -1,4 +0,0 @@
-WARNING: Command "lmi.scripts.cmdtest.Show" is missing usage string. It will be inherited from parent command.
-WARNING: One Ring to bring them all
-ERROR: and in the darkness bind them.
-CRITICAL: In the land of Mordor where the Shadows lie.
diff --git a/test/logging/log_all_warn.stderr b/test/logging/log_all_warn.stderr
deleted file mode 100644
index eab784d..0000000
--- a/test/logging/log_all_warn.stderr
+++ /dev/null
@@ -1,4 +0,0 @@
-warning : Command "lmi.scripts.cmdtest.Show" is missing usage string. It will be inherited from parent command.
-warning : One Ring to bring them all
-error : and in the darkness bind them.
-critical: In the land of Mordor where the Shadows lie.
diff --git a/test/run.sh b/test/run.sh
deleted file mode 100755
index 03c87ae..0000000
--- a/test/run.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com
-
-retval=0
-for test in test_*.sh; do
- bash ./$test
- [ "$retval" = 0 ] && retval=$?
-done
-
-exit $retval
diff --git a/test/subcmd/lmi/__init__.py b/test/subcmd/lmi/__init__.py
deleted file mode 100644
index f752629..0000000
--- a/test/subcmd/lmi/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/test/subcmd/lmi/scripts/__init__.py b/test/subcmd/lmi/scripts/__init__.py
deleted file mode 100644
index f752629..0000000
--- a/test/subcmd/lmi/scripts/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/test/subcmd/lmi/scripts/cmdtest/__init__.py b/test/subcmd/lmi/scripts/cmdtest/__init__.py
deleted file mode 100644
index e15fd97..0000000
--- a/test/subcmd/lmi/scripts/cmdtest/__init__.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-#
-"""
-Test command for lmi-metacommand.
-
-Usage:
- %(cmd)s list <cmd> [<args> ...]
- %(cmd)s show pkg <name>
- %(cmd)s show repo <name>
- %(cmd)s log <cmd> [<args> ...]
-"""
-
-from lmi.scripts.common import get_logger
-from lmi.scripts.common import errors
-from lmi.scripts.common import command
-from lmi.scripts.common import configuration
-
-LOG = get_logger(__name__)
-
-class ListPackages(command.LmiLister):
- OPT_NO_UNDERSCORES = True
- COLUMNS = ('Name', 'Arch')
-
- def execute(self, ns, installed, available):
- fltr = lambda a: True
- if installed:
- fltr = lambda a: a[2]
- elif available:
- fltr = lambda a: not a[2]
- for pkg in PACKAGES:
- if fltr(pkg):
- yield (pkg[0], pkg[1])
-
-class ListRepos(command.LmiLister):
- OPT_NO_UNDERSCORES = True
-
- def execute(self, ns, enabled, disabled):
- fltr = lambda a: True
- if enabled:
- fltr = lambda a: a[1]
- elif disabled:
- fltr = lambda a: not a[1]
- if self.app.config.verbose:
- props = ('Name', 'Enabled')
- else:
- props = ('Name', )
- yield props
- for repo in REPOSITORIES:
- if not fltr(repo):
- continue
- yield tuple(v for _, v in zip(props, repo))
-
-class Lister(command.LmiCommandMultiplexer):
- """
- List various types of software data.
-
- Usage:
- %(cmd)s pkgs [(--installed | --available)]
- %(cmd)s repos [(--enabled | --disabled)]
- """
- COMMANDS = {
- 'pkgs' : ListPackages,
- 'repos' : ListRepos
- }
- OWN_USAGE = True
-
-class ShowPackage(command.LmiLister):
- COLUMNS = ("Prop", "Value")
-
- def execute(self, ns, name):
- pkgd = { p[0] : p for p in PACKAGES }
- if not name in pkgd:
- raise errors.LmiFailed('No such package "%s".' % name)
- for n, v in zip(('Name', 'Architecture', 'Installed'), pkgd[name]):
- yield n, v
-
-class ShowRepository(command.LmiLister):
-
- def execute(self, ns, name):
- repod = { r[0] : r for r in REPOSITORIES }
- if not name in repod:
- raise errors.LmiFailed('No such repository "%s".' % name)
- if self.app.config.verbose:
- props = ('Name', 'Enabled', 'Packages')
- else:
- props = ('Name', 'Enabled')
- value_map = {n: v for n, v in zip(props, repod[name])}
-
- return (props, tuple(value_map[p] for p in props))
-
-class Show(command.LmiCommandMultiplexer):
- COMMANDS = {
- 'pkg' : ShowPackage,
- 'repo' : ShowRepository
- }
-
-class LogLevel(command.LmiCheckResult):
- EXPECT = None
-
- def execute(self, ns, _debug, _info, _warn, _error, _critical,
- message=None, args=None):
- for level in ('debug', 'info', 'warn', 'error', 'critical'):
- if locals()['_' + level]:
- break
- if not message:
- message = "This is %s message." % level
- if not args:
- args = []
- getattr(LOG(), level)(message, *args)
-
-class LogAll(command.LmiCheckResult):
- EXPECT = None
- POEM = (
- 'One Ring to rule them all.',
- 'One Ring to find them.',
- 'One Ring to bring them all',
- 'and in the darkness bind them.',
- 'In the land of Mordor where the Shadows lie.')
-
- def execute(self, ns, _with_traceback):
- for verse, level in zip(LogAll.POEM,
- ('debug', 'info', 'warn', 'error', 'critical')):
- if _with_traceback:
- try:
- raise RuntimeError('S**t happens!')
- except RuntimeError as err:
- getattr(LOG(), level)(verse, exc_info=err)
- else:
- getattr(LOG(), level)(verse)
- if self.app.config.verbose:
- self.app.stdout.write('Additional information.\n')
- if self.app.config.silent:
- self.app.stdout.write("Let's be silent.\n")
- if self.app.config.trace:
- self.app.stdout.write('Enjoy tracebacks.\n')
- if self.app.config.verbosity >= self.app.config.OUTPUT_DEBUG:
- self.app.stdout.write('I can not be more verbose than this!\n')
-
-class LogRaise(command.LmiCheckResult):
- EXPECT = None
-
- def execute(self, ns, _lmi_failed=False):
- if _lmi_failed:
- raise errors.LmiFailed("You asked for it!")
- raise RuntimeError("This shall make a nice traceback.")
-
-class Logger(command.LmiCommandMultiplexer):
- """
- Command for logging testing.
-
- Usage:
- %(cmd)s level (--debug | --info | --warn | --error | --critical)
- [<message> <args>...]
- %(cmd)s all [--with-traceback]
- %(cmd)s raise [--lmi-failed]
- """
- COMMANDS = {
- 'level' : LogLevel,
- 'all' : LogAll,
- 'raise' : LogRaise
- }
- OWN_USAGE = True
-
-Test = command.register_subcommands(
- 'Test', __doc__,
- { 'list' : Lister,
- 'show' : Show,
- 'log' : Logger,
- },
- )
-
-PACKAGES = (
- # Name, Arch, Installed
- ('pywbem', 'noarch', True),
- ('hwdata', 'noarch', True),
- ('tog-pegasus', 'x86_64', False),
- ('python-docopt', 'noarch', False))
-
-REPOSITORIES = (
- # Name, Enabled, Packages
- ('fedora', True, 1000),
- ('updates', False, 500))
-
diff --git a/test/subcmd/setup.py b/test/subcmd/setup.py
deleted file mode 100644
index 20a50a1..0000000
--- a/test/subcmd/setup.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python
-
-from setuptools import setup, find_packages
-
-setup(
- name="openlmi-scripts-cmdtest",
- version="0.0.1",
- description='Test command for lmi',
- author='Michal Minar',
- author_email='miminar@redhat.com',
- url='http://openlmi.org',
- platforms=['Any'],
- license="BSD",
- classifiers=[
- 'License :: OSI Approved :: BSD License',
- 'Operating System :: POSIX :: Linux',
- 'Topic :: System :: Systems Administration',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Intended Audience :: Developers',
- 'Environment :: Console',
- ],
-
- install_requires=['openlmi-scripts >= 0.2.6'],
-
- namespace_packages=['lmi', 'lmi.scripts'],
- packages=['lmi', 'lmi.scripts', 'lmi.scripts.cmdtest'],
- include_package_data=True,
-
- entry_points={
- 'lmi.scripts.cmd': [
- 'test = lmi.scripts.cmdtest:Test',
- ],
- },
- )
diff --git a/test/test_cmd.sh b/test/test_cmd.sh
deleted file mode 100644
index e846699..0000000
--- a/test/test_cmd.sh
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-
-. ./base.sh
-
-# Set the full test name
-TEST="openlmi-scripts/test/test_cmd.sh"
-
-# Package being tested
-PACKAGE="openlmi-scripts"
-
-rlJournalStart
-
-rlPhaseStartSetup
- rlLogInfo "Creating temporary python sandbox"
- sandbox=`mktemp -d`
- export PYTHONPATH="$sandbox"
- pushd ..
- rlLogInfo "Installing lmi meta-command"
- rlRun "python setup.py develop --install-dir=$sandbox"
- popd
- export "$sandbox:$PATH"
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test help messages without subommands"
-
- rlRun -s "$LMI_ --help"
- rlAssertGrep "^Usage:$" $rlRun_LOG
- rlAssertGrep "^Options:$" $rlRun_LOG
- rlAssertGrep "^Commands:$" $rlRun_LOG
- rlAssertGrep "^ help$" $rlRun_LOG
- rlRun "head -n 1 $rlRun_LOG | grep -q '[[:alpha:]]\+'" 0 \
- "Test whether first line is not blank"
- rm $rlRun_LOG
-
- rlRun -s "$LMI help"
- rlAssertNotDiffer "cmd/help_without_test.out" $rlRun_LOG
- rm $rlRun_LOG
-
- # suppress warning messages
- rlRun -s "$LMI -q help foo"
- rlAssertNotDiffer "cmd/help_foo.out" $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI help help"
- rlAssertNotDiffer "cmd/help_help.out" $rlRun_LOG
- rm $rlRun_LOG
-
-rlPhaseEnd
-
-rlPhaseStartSetup
- rlLogInfo "Installing testing command"
- pushd subcmd
- rlRun "python setup.py develop --install-dir=$sandbox"
- popd
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test help messages with test subcommand"
-
- rlRun -s "$LMI_ --help"
- rlAssertGrep "^Usage:$" $rlRun_LOG
- rlAssertGrep "^Options:$" $rlRun_LOG
- rlAssertGrep "^Commands:$" $rlRun_LOG
- rlAssertGrep "^ help test$" $rlRun_LOG
- rlRun "head -n 1 $rlRun_LOG | grep -q '[[:alpha:]]\+'" 0 \
- "Test whether first line is not blank"
- rm $rlRun_LOG
-
- rlRun -s "$LMI help 2>/dev/null"
- rlAssertNotDiffer "cmd/help_with_test.out" $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI help test 2>/dev/null"
- rlAssertNotDiffer "cmd/help_test.out" $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI test --help 2>/dev/null"
- rlAssertNotDiffer "cmd/help_test.out" $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI test list --help 2>/dev/null"
- rlAssertNotDiffer "cmd/help_test_list.out" $rlRun_LOG
- rm $rlRun_LOG
-
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test the *no headings* option"
- with_headings=`mktemp with_headingsXXXX`
- without_headings=`mktemp without_headingsXXXX`
- expected_colonized=`mktemp expectedXXXX`
-
- rlRun -s "$LMI test show pkg hwdata >$with_headings"
- whl=`cat $with_headings | wc -l`
- rlRun -s "$LMI -N test show pkg hwdata >$without_headings"
- nhl=`cat $without_headings | wc -l`
- rlAssertEquals "Output without headings needs to be one line shorter" \
- $((whl - 1)) $nhl
- rlAssertGrep "Prop\s\+Value" $with_headings
- rlAssertNotGrep "Prop\s\+Value" $without_headings
- cat >$expected_colonized <<EOF
-Name:hwdata
-Architecture:noarch
-Installed:True
-EOF
- rlRun "sed -n -e '/^warning :/ d' -e '1 !s/\s\+/:/gp' $with_headings | cmp $expected_colonized -" 0 \
- "Compare the output to expected with reduced spaces"
-
- rlRun -s "$LMI test show repo fedora >$with_headings"
- whl=`cat $with_headings | wc -l`
- rlRun -s "$LMI -N test show repo fedora >$without_headings"
- nhl=`cat $without_headings | wc -l`
- rlAssertEquals "Output without headings needs to be one line shorter" \
- $((whl - 1)) $nhl
- rlAssertGrep "^Name\s\+Enabled" $with_headings
- rlAssertNotGrep "^Name\s\+Enabled" $without_headings
- echo "fedora:True" >$expected_colonized
- rlRun "sed -n -e '/^warning :/ d' -e '1 !s/\s\+/:/gp' $with_headings | cmp $expected_colonized -" 0 \
- "Compare the output to expected with reduced spaces"
-
- rlRun -s "$LMI -v test show repo fedora >$with_headings"
- whl=`cat $with_headings | wc -l`
- rlRun -s "$LMI -v -N test show repo fedora >$without_headings"
- nhl=`cat $without_headings | wc -l`
- rlAssertEquals "Output without headings needs to be one line shorter" \
- $((whl - 1)) $nhl
- rlAssertGrep "^Name\s\+Enabled\s\+Packages" $with_headings
- rlAssertNotGrep "^Name\s\+Enabled\s\+Packages" $without_headings
- sed -i '1 s/$/:1000/' $expected_colonized
- rlRun "sed -n -e '/^warning :/ d' -e '1 !s/\s\+/:/gp' $with_headings | cmp $expected_colonized -" 0 \
- "Compare the output to expected with reduced spaces"
-
- rm $with_headings $without_headings $expected_colonized
-rlPhaseEnd
-
-rlPhaseStartCleanup
- rlLogInfo "Removing temporary python sandbox"
- rm -rf "$sandbox"
-rlPhaseEnd
-
-rlJournalPrintText
-rlJournalEnd
diff --git a/test/test_imode.sh b/test/test_imode.sh
deleted file mode 100644
index 6cd2ab2..0000000
--- a/test/test_imode.sh
+++ /dev/null
@@ -1,270 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-
-. ./base.sh
-
-# Set the full test name
-TEST="openlmi-scripts/test/test_imode.sh"
-
-# Package being tested
-PACKAGE="openlmi-scripts"
-
-function run_and_compare_output() {
- # Run lmi command and compare its output to a contents of given file.
- #
- # Args:
- # command - command to run which is executed in subshell
- # expected - file name with expected output stored in imode without
- # extension
- rlRun -s "$1" 0
- rlRun -l "cmp imode/$2.out $rlRun_LOG" 0
- rm $rlRun_LOG
-}
-
-function run_test_command() {
- # Run command in interactive mode with expect script
- # `imode/run_test_cmd.exp`. Command is run iteratively from different
- # command namespaces. stderr is redirected to /dev/null when running
- # the `command`.
- #
- # Args:
- # command - command path (without `lmi` prefix)
- # expected - path to a file with expected output
- # dir... - command namespaces to nest to before running command
- #
- # Common prefix of `command` and current namespace is removed from command
- # in each iteration before running it.
- cmd="$1"
- expected_output="$2"
- shift 2
- while [ $# -gt 0 ]; do
- dir="$1"
- cmd_="${cmd#$dir }"
- out_file=`mktemp out_fileXXXX`
- prompt='lmi> '
- path="$(echo $dir | tr ' ' '/')"
- [ "$dir" = '.' ] || prompt=">$(echo $dir | sed 's/\([^ ]\+ \)/>/g')> "
- rlRun "expect imode/run_test_cmd.exp $out_file \"$path\" \"$prompt\" \"$cmd_\"" 0
- rlAssertNotDiffer $expected_output $out_file
- rm $out_file
- shift
- done
-}
-
-function make_error_message() {
- # Args:
- # level - one of debug, info, warn, error, critical
- # message
- level=$1
- message="$2"
- [ "$level" = 'warn' ] && level=warning
- case "$level" in
- warning) color='\x1b[38;5;11m'; ;;
- error) color='\x1b[38;5;9m'; ;;
- critical) color='\x1b[38;5;13m'; ;;
- *) unset color; ;;
- esac
- if [[ -n "$color" ]]; then
- printf "$color%-8s:\x1b[39m %s\n" $level "$message"
- else
- echo "$message"
- fi
-}
-
-rlJournalStart
-
-rlPhaseStartSetup
- rlLogInfo "Creating temporary python sandbox"
- sandbox=`mktemp -d`
- export PYTHONPATH="$sandbox"
- pushd ..
- rlLogInfo "Installing lmi meta-command"
- rlRun "python setup.py develop --install-dir=$sandbox" 0
- popd
- export "$sandbox:$PATH"
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Try to import lmi meta-command"
- rlRun 'python -c "import lmi.scripts._metacommand"' 0
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test exit command"
- rlRun "expect imode/exit.exp" 0
- rlRun "expect imode/exit.exp 0" 0
- rlRun "expect imode/exit.exp 1" 1
- rlRun "expect imode/exit.exp 2" 2
- rlRun "expect imode/exit.exp 10" 10
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test end of file"
- rlRun "expect imode/eof.exp" 0
- rlRun "expect imode/eof.exp ':pwd' '/lmi'" 0
- errmsg=`make_error_message error 'No such subcommand \"foo\".'`
- rlRun "expect imode/eof.exp ':cd foo' \"$errmsg\"" 0
- rlRun "expect imode/empty_lines.exp" 0
- run_and_compare_output "$LMI < imode/empty_lines.txt" empty_lines
-rlPhaseEnd
-
-rlPhaseStartSetup
- rlLogInfo "Installing testing command"
- pushd subcmd
- rlRun "python setup.py develop --install-dir=$sandbox"
- popd
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Check whether test command is installed"
- run_and_compare_output "$LMI help 2>/dev/null" lmi_test_help
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test nesting to subcommands"
- rlRun "expect imode/cd_test.exp" 1
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test help messages in interactive mode"
- run_and_compare_output "echo help | $LMI" "help"
- run_and_compare_output "echo help help | $LMI" "help_help"
- run_and_compare_output "echo \": help\" | $LMI" "builtin_help"
- run_and_compare_output "echo help exit | $LMI 2>/dev/null" "help_exit"
- run_and_compare_output "echo help test | $LMI 2>/dev/null" "help_test"
- run_and_compare_output "$LMI 2>/dev/null < imode/test_help_exit.txt" \
- "help_exit"
- run_and_compare_output "$LMI 2>/dev/null < imode/test_help.txt" \
- "test_help"
- run_and_compare_output "$LMI 2>/dev/null < imode/test_builtin_help.txt" \
- "builtin_help"
- run_and_compare_output "$LMI 2>/dev/null < imode/test_help_list.txt" \
- "test_help_list"
- run_and_compare_output "$LMI 2>/dev/null < imode/test_help_show.txt" \
- "test_help_show"
- run_and_compare_output "echo help foo | $LMI" "help_foo"
-
- rlLogInfo "Test --help"
- outfile=`mktemp outfileXXXX`
- expected=`mktemp expectedXXXX`
- rlRun "expect imode/run_test_cmd.exp $outfile . 'lmi> ' 'test --help'" 0
- rlAssertNotDiffer imode/test_opt_help.out $outfile
-
- rlRun "expect imode/run_test_cmd.exp $outfile . 'lmi> ' 'test list --help'" 0
- rlAssertNotDiffer imode/test_list_opt_help.out $outfile
-
- cmd="test list pkgs --help"
- rlRun "expect imode/run_test_cmd.exp $outfile . 'lmi> ' '$cmd'" 0
- rlAssertNotDiffer imode/test_list_opt_help.out $outfile
-
- cmd="test show --help"
- rlRun "expect imode/run_test_cmd.exp $outfile . 'lmi> ' '$cmd'" 0
- rlAssertNotDiffer imode/test_opt_help.out $outfile
-
- cmd="test foo --help"
- rlRun "expect imode/run_test_cmd.exp $outfile . 'lmi> ' '$cmd'" 0
- rlAssertNotDiffer imode/test_opt_help.out $outfile
-
- cmd="list --help"
- sed 's/^ test / /' imode/test_list_opt_help.out >$expected
- rlRun "expect imode/run_test_cmd.exp $outfile test '>test> ' '$cmd'" 0
- rlAssertNotDiffer $expected $outfile
-
- cmd="list pkgs --help"
- rlRun "expect imode/run_test_cmd.exp $outfile test '>test> ' '$cmd'" 0
- rlAssertNotDiffer $expected $outfile
-
- cmd="show --help"
- rlRun "expect imode/run_test_cmd.exp $outfile test '>test> ' '$cmd'" 0
- rlAssertNotDiffer imode/test_opt_help.out $outfile
-
- rm $expected $outfile
-
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test completion in interactive mode"
- # this also tests exit command nested in subcommand (with 20 as argument)
- rlRun "expect imode/completion.exp" 20
- rlRun "expect imode/complete_builtin.exp" 0
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Check behaviour of test subcommand"
-
- rlLogInfo \
- "First create files in non-interactive mode we will then compare to"
- rlRun -s "$LMI test list pkgs 2>/dev/null" 0
- rlAssertEquals "List of all packages is sane" \
- `grep -E '^(tog-pegasus|pywbem|hwdata|python-docopt)' $rlRun_LOG | wc -l` 4
- all_packages=`mktemp all_packagesXXXX`
- mv $rlRun_LOG $all_packages
-
- rlRun -s "$LMI test list pkgs --installed 2>/dev/null" 0
- rlAssertEquals "List of installed packages is sane"\
- `grep -E '^(pywbem|hwdata)' $rlRun_LOG | wc -l` 2
- installed_packages=`mktemp installed_packagesXXXX`
- mv $rlRun_LOG $installed_packages
-
- rlRun -s "$LMI test list repos 2>/dev/null" 0
- rlAssertEquals "List of repositories is sane" \
- `grep -E '^(fedora|updates)' $rlRun_LOG | wc -l` 2
- all_repos=`mktemp all_reposXXXX`
- mv $rlRun_LOG $all_repos
-
- rlRun -s "$LMI test show pkg hwdata 2>/dev/null" 0
- rlAssertEquals "Package description is sane" \
- `grep -E '^(Name|Arch|Installed)' $rlRun_LOG | wc -l` 3
- one_package=`mktemp one_packageXXXX`
- mv $rlRun_LOG $one_package
-
- rlLogInfo "Now compare outputs to interactive mode"
-
- run_test_command 'test list pkgs' $all_packages \
- '.' 'test' 'test list'
- run_test_command 'test list pkgs --installed' $installed_packages \
- '.' 'test' 'test list'
- run_test_command 'test list repos' $all_repos \
- '.' 'test' 'test list'
- run_test_command 'test show pkg hwdata' $one_package \
- '.' 'test'
-
- rm $all_packages $installed_packages $all_repos $one_package
-
-rlPhaseEnd
-
-rlPhaseStartCleanup
- rlLogInfo "Removing temporary python sandbox"
- rm -rf "$sandbox"
-rlPhaseEnd
-
-rlJournalPrintText
-rlJournalEnd
diff --git a/test/test_logging.sh b/test/test_logging.sh
deleted file mode 100644
index ef6060f..0000000
--- a/test/test_logging.sh
+++ /dev/null
@@ -1,249 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-
-. ./base.sh
-
-# Set the full test name
-TEST="openlmi-scripts/test/test_logging.sh"
-
-# Package being tested
-PACKAGE="openlmi-scripts"
-
-# array of supported log levels
-LEVELS=( critical error warn info debug )
-
-DEBUG_CONFIG_TEMPLATE="
-[Main]
-Trace = True
-Verbosity = 2
-
-[Log]
-Level = DEBUG
-LogToConsole = True
-FileFormat = %%(levelname)s: %%(message)s
-OutputFile = %s
-"
-
-rlJournalStart
-
-rlPhaseStartSetup
- rlLogInfo "Creating temporary python sandbox"
- sandbox=`mktemp -d`
- export PYTHONPATH="$sandbox"
- pushd ..
- rlLogInfo "Installing lmi meta-command"
- rlRun "python setup.py develop --install-dir=$sandbox" 0
- popd
- pushd subcmd
- rlRun "python setup.py develop --install-dir=$sandbox" 0
- popd
- export PATH="$sandbox:$PATH"
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test logging with default settings"
-
- LMICMD="$LMI -c logging/defaults.conf"
-
- stdout=`mktemp stdoutXXXX`
- stderr=`mktemp stderrXXXX`
- rlRun "$LMICMD test log all >$stdout 2>$stderr" 0
- rlAssertNotDiffer logging/log_all_default.stdout $stdout
- rlAssertNotDiffer logging/log_all_warn.stderr $stderr
-
- rlRun "$LMICMD test log all --with-traceback >$stdout 2>$stderr" 0
- rlAssertNotDiffer logging/log_all_default.stdout $stdout
- tmpout=`mktemp tmpoutXXXX`
- grep '^\(warning\|error\|critical\)' $stderr > $tmpout
- rlAssertNotDiffer logging/log_all_warn.stderr $tmpout
- rlAssertEquals "Correct number of exceptions were raised" 3 \
- `grep '^RuntimeError: S\*\*t happens!' $stderr | wc -l`
- rm $tmpout
-
- expected_out=`mktemp expected_stdoutXXXX`
- expected_err=`mktemp expected_stderrXXXX`
- for verbosity in 0 1 2; do
- if [[ $verbosity -gt 0 ]]; then
- option=`printf -- "-v %.0s" $(seq $verbosity)`
- else
- option=''
- fi
- CMD="$LMICMD $option test log level"
- for level in `seq 0 $((${#LEVELS[@]} - 1))`; do
- rlRun "$CMD --${LEVELS[$level]} >$stdout 2>$stderr" 0
- level_name=${LEVELS[$level]}
- log_level_name=$level_name
- [ $level_name = warn ] && log_level_name=warning
- ( \
- if [ $verbosity = 2 ]; then \
- echo 'Running command "test".'; \
- echo 'Found registered command "test".'; \
- fi; \
- echo -n 'warning : Command "lmi.scripts.cmdtest.Show"'; \
- echo -n " is missing usage string. It will be"; \
- echo " inherited from parent command."; \
- if [ $verbosity = 2 ]; then \
- for opt_name in '_with_traceback' '_lmi_failed'; do \
- echo -n "Option \"$opt_name\" not handled in function"; \
- echo ' "level", ignoring.'; \
- done; \
- echo "Connected to $HOSTNAME"; \
- fi; \
- if [ $(($verbosity + 2)) -ge $level ]; then \
- if [ $level -lt 3 ]; then \
- printf "%-8s: " $log_level_name; \
- fi; \
- echo "This is $level_name message."; \
- fi \
- ) >$expected_err
- rlAssertNotDiffer $expected_err $stderr
- rlAssertEquals "Nothing is written to stdout" 0 `cat $stdout | wc -c`
- done
- done
-
- rm $stdout $stderr $expected_out $expected_err
-
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test logging with debug settings"
-
- config_file=`mktemp configXXXX`
- log_file=`mktemp log_fileXXXX`
- printf "$DEBUG_CONFIG_TEMPLATE" $log_file >$config_file
-
- LMICMD="$LMI -c $config_file"
-
- stdout=`mktemp stdoutXXXX`
- stderr=`mktemp stderrXXXX`
- filter_debug=" | grep -v '^Option' > $stderr"
- rlRun "$LMICMD test log all 2>&1 >$stdout $filter_debug" 0
- rlAssertNotDiffer logging/log_all_debug.stdout $stdout
- rlAssertNotDiffer logging/log_all_debug.stderr $stderr
- cat $log_file | grep -v '^DEBUG: Option' >${log_file}.tmp
- mv ${log_file}{.tmp,}
- rlAssertNotDiffer logging/log_all_debug.file $log_file
- rm $log_file
-
- rlRun "$LMICMD test log all --with-traceback 2>&1 >$stdout $filter_debug" 0
- rlAssertNotDiffer logging/log_all_debug.stdout $stdout
- tmpout=`mktemp tmpoutXXXX`
- grep '^\(warning\|error\|critical\)' $stderr > $tmpout
- rlAssertNotDiffer logging/log_all_warn.stderr $tmpout
- rlAssertEquals "Correct number of exceptions were raised" 5 \
- `grep '^RuntimeError: S\*\*t happens!' $stderr | wc -l`
- rlAssertEquals "Correct number of exceptions were raised" 5 \
- `grep '^RuntimeError: S\*\*t happens!' $log_file | wc -l`
- rm $tmpout $log_file
-
- rlLogInfo "Try override log-file"
- new_log_file=`mktemp new_log_fileXXXX`
- rlRun "$LMICMD --log-file $new_log_file test log all 2>&1 >$stdout $filter_debug" 0
- rlAssertNotDiffer logging/log_all_debug.stdout $stdout
- rlAssertNotDiffer logging/log_all_debug.stderr $stderr
- cat $new_log_file | grep -v '^DEBUG: Option' >${new_log_file}.tmp
- mv ${new_log_file}{.tmp,}
- rlAssertNotDiffer logging/log_all_debug.file $new_log_file
- rlRun "[ -e $log_file ]" 1 "Log file from config file shall not be written"
-
- [ -e $new_log_file ] && rm $new_log_file
- [ -e $log_file ] && rm $log_file
-
- rlLogInfo "Try to disable logging to a file"
- rlRun "$LMICMD --log-file '' test log all 2>&1 >$stdout $filter_debug" 0
- rlAssertNotDiffer logging/log_all_debug.stdout $stdout
- rlAssertNotDiffer logging/log_all_debug.stderr $stderr
- rlRun "[ -e $log_file ]" 1 "Log file from config file shall not be written"
- [ -e $log_file ] && rm $log_file
-
- rlLogInfo "Try override verbosity"
- rlRun "$LMICMD -q test log all 2>&1 >$stdout $filter_debug" 0
- rlAssertNotDiffer logging/log_all_silent.stdout $stdout
- rlAssertNotDiffer logging/log_all_error.stderr $stderr
- cat $log_file | grep -v '^DEBUG: Option' >${log_file}.tmp
- mv ${log_file}{.tmp,}
- rlAssertNotDiffer logging/log_all_debug.file $log_file
- rm $log_file
-
- rlRun "$LMICMD -v test log all >$stdout 2>$stderr" 0
- rlAssertNotDiffer logging/log_all_info.stdout $stdout
- rlAssertNotDiffer logging/log_all_info.stderr $stderr
- cat $log_file | grep -v '^DEBUG: Option' >${log_file}.tmp
- mv ${log_file}{.tmp,}
- rlAssertNotDiffer logging/log_all_debug.file $log_file
- rm $log_file
-
- rlLogInfo "Change file log level"
- sed -i 's/DEBUG/WARNING/' $config_file
- rlAssertGrep 'Level = WARNING' $config_file
- rlRun "$LMICMD test log all 2>&1 >$stdout $filter_debug" 0
- rlAssertNotDiffer logging/log_all_debug.stdout $stdout
- rlAssertNotDiffer logging/log_all_debug.stderr $stderr
- rlAssertNotDiffer logging/log_all_warn.file $log_file
- [ -e $log_file ] && rm $log_file
-
- rlLogInfo "Disable logging to console"
- sed -i 's/\(LogToConsole.*\)True/\1False/' $config_file
- rlAssertGrep 'LogToConsole = False' $config_file
- rlRun "$LMICMD test log all >$stdout 2>$stderr" 0
- rlAssertNotDiffer logging/log_all_debug.stdout $stdout
- rlAssertEquals "Nothing is written to stderr" `cat $stderr | wc -c` 0
- rlAssertNotDiffer logging/log_all_warn.file $log_file
- [ -e $log_file ] && rm $log_file
-
- rlLogInfo "Override tracing"
- rlRun "$LMICMD --notrace test log all >$stdout 2>$stderr" 0
- rlAssertNotDiffer logging/log_all_debug_notrace.stdout $stdout
- rlAssertEquals "Nothing is written to stderr" `cat $stderr | wc -c` 0
- rlAssertNotDiffer logging/log_all_warn.file $log_file
-
- for f in $log_file $new_log_file $config_file $stdout $stderr; do
- [ -e $f ] && rm $f
- done
-
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test logging with settings"
-
- stdout=`mktemp stdoutXXXX`
- stderr=`mktemp stderrXXXX`
- rlRun "$LMI -c logging/defaults.conf test log all >$stdout 2>$stderr" 0
- rlAssertNotDiffer $stdout logging/log_all_default.stdout
- rlAssertNotDiffer $stderr logging/log_all_warn.stderr
- rm $stdout $stderr
-rlPhaseEnd
-
-
-rlPhaseStartCleanup
- rlLogInfo "Removing temporary python sandbox"
- rm -rf "$sandbox"
-rlPhaseEnd
diff --git a/test/test_unit.sh b/test/test_unit.sh
deleted file mode 100644
index 04fe17b..0000000
--- a/test/test_unit.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-
-. ./base.sh
-
-# Set the full test name
-TEST="openlmi-scripts/test/test_cmd.sh"
-
-PACKAGE="openlmi-scripts"
-
-rlJournalStart
-
-rlPhaseStartSetup
- rlLogInfo "Creating temporary python sandbox"
- sandbox=`mktemp -d`
- export PYTHONPATH="$sandbox"
- pushd ..
- rlLogInfo "Installing lmi meta-command"
- rlRun "python setup.py develop --install-dir=$sandbox"
- popd
- export "$sandbox:$PATH"
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Running unittests"
-
- pushd unit
- for i in test_*.py; do
- rlRun "python $i"
- done
- popd # unit
-
-rlPhaseEnd
-
-rlPhaseStartCleanup
- rlLogInfo "Removing temporary python sandbox"
- rm -rf "$sandbox"
-rlPhaseEnd
-
-rlJournalPrintText
-rlJournalEnd
diff --git a/test/test_versioning.sh b/test/test_versioning.sh
deleted file mode 100644
index 0f7f5b6..0000000
--- a/test/test_versioning.sh
+++ /dev/null
@@ -1,236 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2014, Red Hat, Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and documentation are
-# those of the authors and should not be interpreted as representing official
-# policies, either expressed or implied, of the FreeBSD Project.
-#
-# Authors: Michal Minar <miminar@redhat.com>
-
-. ./base.sh
-
-EXIT_CODE_UNSATISFIED=5
-DEFAULT_VERSION='0.4.2'
-
-# Set the full test name
-TEST="openlmi-scripts/test/test_versioning"
-
-# Package being tested
-PACKAGE="openlmi-scripts"
-
-function cmp2int() {
- digits=( `echo $1 | tr '.' ' '` )
- result=0
- for i in `seq 0 $((${#digits[@]} - 1))`; do
- result=$((result*100))
- result=$((result + ${digits[$i]}))
- done
- echo $result
-}
-
-rlJournalStart
-
-if [[ -z "${LMI_SOFTWARE_PROVIDER_VERSION}" ]]; then
- msg="No version specified for OpenLMI-Software. Defaulting to "
- msg+="{$DEFAULT_VERSION}."
- rlLogInfo "$msg"
- LMI_SOFTWARE_PROVIDER_VERSION="${DEFAULT_VERSION}"
-elif [[ "$LMI_SOFTWARE_PROVIDER_VERSION" == none ]]; then
- LMI_SOFTWARE_PROVIDER_VERSION=''
-fi
-if [[ -z "${LMI_HARDWARE_PROVIDER_VERSION}" ]]; then
- msg="No version specified for OpenLMI-Hardware Defaulting to "
- msg+="{$DEFAULT_VERSION}."
- rlLogInfo "$msg"
- LMI_HARDWARE_PROVIDER_VERSION="${DEFAULT_VERSION}"
-elif [[ "$LMI_SOFTWARE_PROVIDER_VERSION" == none ]]; then
- LMI_HARDWARE_PROVIDER_VERSION=''
-fi
-
-rlPhaseStartSetup
- rlLogInfo "Creating temporary python sandbox"
- sandbox=`mktemp -d`
- export PYTHONPATH="$sandbox"
- pushd ..
- rlLogInfo "Installing lmi meta-command"
- rlRun "python setup.py develop --install-dir=$sandbox"
- popd
- rlLogInfo "Installing testing command"
- pushd cmdver
- rlRun "python setup.py develop --install-dir=$sandbox"
- popd
- export "$sandbox:$PATH"
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test help on select command"
-
- rlRun -s "$LMI_ help"
- rlAssertEquals "Check the number of subcommands available." \
- `grep '^\s\+[[:alnum:]-]\+\s\+-\s\+' $rlRun_LOG | wc -l` 4
- rlAssertGrep '\<ver\>\s\+-\s\+Command for testing version dependencies\.$' \
- $rlRun_LOG
- rlAssertGrep '\<ver-hw\s\+-\s\+This is a short description for CmdverHw\.$' \
- $rlRun_LOG
- rlAssertGrep '\<ver-sw\s\+-\s\+This is a short description for CmdverSw\.$' \
- $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI help ver"
- rlAssertGrep "^Command for testing version dependencies.$" $rlRun_LOG
- rlAssertGrep "^Usage:$" $rlRun_LOG
- rlAssertGrep "^\s\+lmi ver (sw\\|hw) \[<args>\.\.\.\]$'" $rlRun_LOG
- rm $rlRun_LOG
-
- if [[ -z "$LMI_SOFTWARE_PROVIDER_VERSION" ]]; then
- rlRun -s "$LMI help ver-sw" $EXIT_CODE_UNSATISFIED
- rlAssertGrep "error\s*:\s\+Profile and class dependencies were not satisfied for" \
- $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI help ver sw" $EXIT_CODE_UNSATISFIED
- rlAssertGrep "error\s*:\s\+Profile and class dependencies were not satisfied for" \
- $rlRun_LOG
- rm $rlRun_LOG
-
- else
- rlRun -s "$LMI help ver-sw"
- rlAssertGrep "^Software testing command.$" $rlRun_LOG
- rlAssertGrep "Usage: lmi ver-sw" $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI help ver sw" 0
- rlAssertGrep "^Software testing command.$" $rlRun_LOG
- rlAssertGrep "Usage: lmi ver sw" $rlRun_LOG
- rm $rlRun_LOG
- fi
-
- if [[ -z "$LMI_HARDWARE_PROVIDER_VERSION" ]]; then
- rlRun -s "$LMI help ver-hw"
- rlAssertGrep "^Hardware testing command\.$" $rlRun_LOG
- rlAssertGrep "^Usage: lmi ver-hw <cmd>$" $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI help ver hw"
- rlAssertGrep "^Hardware testing command\.$" $rlRun_LOG
- rlAssertGrep "^Usage: lmi ver hw <cmd>$" $rlRun_LOG
- rm $rlRun_LOG
-
- else
- rlRun -s "$LMI help ver-hw"
- rlAssertGrep "^Hardware testing command\.$" $rlRun_LOG
- rlAssertGrep "^Usage:$" $rlRun_LOG
- rlAssertGrep "^\s\+lmi ver-hw system$" $rlRun_LOG
- rlAssertGrep "^\s\+lmi ver-hw hostname$" $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI help ver hw" 0
- rlAssertGrep "^Hardware testing command.$" $rlRun_LOG
- rlAssertGrep "^Usage:$" $rlRun_LOG
- rlAssertGrep "^\s\+lmi ver hw system$" $rlRun_LOG
- rlAssertGrep "^\s\+lmi ver hw hostname$" $rlRun_LOG
- rm $rlRun_LOG
-
- rlRun -s "$LMI help ver hw system" 0
- rlAssertGrep "^Hardware testing command.$" $rlRun_LOG
- rlAssertGrep "^Usage:$" $rlRun_LOG
- rlAssertGrep "^\s\+lmi ver hw system$" $rlRun_LOG
- rlAssertGrep "^\s\+lmi ver hw hostname$" $rlRun_LOG
- rm $rlRun_LOG
- fi
-
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test software testing command"
-
- if [[ -z "$LMI_SOFTWARE_PROVIDER_VERSION" ]]; then
- rlRun -s "$LMI ver-sw" $EXIT_CODE_UNSATISFIED
- rlAssertGrep "Profile and class dependencies were not satisfied" \
- $rlRun_LOG
- rm $rlRun_LOG
-
- elif [[ `cmp2int $LMI_SOFTWARE_PROVIDER_VERSION` -lt `cmp2int 0.4.2` ]]; then
-
- rlRun -s "$LMI ver-sw"
- rlAssertGrep "Prov version.*${LMI_SOFTWARE_PROVIDER_VERSION} (PRE 0.4.2)" $rlRun_LOG
- rm $rlRun_LOG
-
- elif [[ `cmp2int $LMI_SOFTWARE_PROVIDER_VERSION` == `cmp2int 0.4.2` ]]; then
- rlRun -s "$LMI ver-sw"
- rlAssertGrep "Prov version.*${LMI_SOFTWARE_PROVIDER_VERSION} (VER 0.4.2)" $rlRun_LOG
- rm $rlRun_LOG
-
- else
- rlRun -s "$LMI ver-sw"
- rlAssertGrep "Prov version.*${LMI_SOFTWARE_PROVIDER_VERSION} (DEVEL)" $rlRun_LOG
- rm $rlRun_LOG
- fi
-
-rlPhaseEnd
-
-rlPhaseStartTest
- rlLogInfo "Test hardware testing command"
-
- if [[ -z "$LMI_HARDWARE_PROVIDER_VERSION" ]]; then
- for cmd in "system" "hostname"; do
- rlRun -s "$LMI ver-hw $cmd"
- rlAssertEquals "Printed table has just 2 rows" \
- `cat $rlRun_LOG | wc -l` 2
- rlAssertGrep "^Given command\s\+$cmd$" $rlRun_LOG
- rlAssertGrep "^Prov version\s\+N/A" $rlRun_LOG
- rm $rlRun_LOG
- done
-
- else
- if [[ `cmp2int $LMI_HARDWARE_PROVIDER_VERSION` -lt `cmp2int 0.4.2` ]]; then
- ver_suffix=' (PRE 0.4.2)'
- else
- ver_suffix=''
- fi
- for cmd in "system" "hostname"; do
- rlRun -s "$LMI ver-hw $cmd"
- rlAssertEquals "Printed table has just 2 rows" \
- `cat $rlRun_LOG | wc -l` 2
- rlAssertGrep "^Prov version\s\+$LMI_SOFTWARE_PROVIDER_VERSION$ver_suffix\$" \
- $rlRun_LOG
- if [[ $cmd == system ]]; then
- reg="^Chassis Type\s\+.*"
- else
- reg="^Hostname\s\+$HOSTNAME" $rlRun_LOG
- fi
- rm $rlRun_LOG
- done
- fi
-
-rlPhaseEnd
-
-rlPhaseStartCleanup
- rlLogInfo "Removing temporary python sandbox"
- rm -rf "$sandbox"
-rlPhaseEnd
-
-rlJournalPrintText
-rlJournalEnd
diff --git a/test/unit/test_common.py b/test/unit/test_common.py
deleted file mode 100644
index 955d964..0000000
--- a/test/unit/test_common.py
+++ /dev/null
@@ -1,79 +0,0 @@
-import unittest
-
-from lmi.scripts.common.util import FilteredDict
-
-class FilteredDictTest(unittest.TestCase):
-
- def test_empty(self):
- d = FilteredDict(tuple(), {})
- self.assertEqual(0, len(d))
- self.assertNotIn('key', d)
- self.assertEqual(0, len(d.keys()))
- self.assertEqual(0, len(d.values()))
- self.assertEqual(0, len(d.items()))
- self.assertRaises(KeyError, d.__getitem__, 'key')
- self.assertRaises(KeyError, d.__setitem__, 'key', 'value')
-
- def test_empty_keys(self):
- d = FilteredDict(tuple(), {'a': 1})
- self.assertEqual(0, len(d))
- self.assertNotIn('a', d)
- self.assertEqual(0, len(d.keys()))
- self.assertEqual(0, len(d.values()))
- self.assertEqual(0, len(d.items()))
- self.assertRaises(KeyError, d.__getitem__, 'a')
- self.assertRaises(KeyError, d.__setitem__, 'a', 2)
-
- def test_empty_origin(self):
- d = FilteredDict(tuple('a'), {})
- self.assertEqual(0, len(d))
- self.assertNotIn('a', d)
- self.assertEqual(0, len(d.keys()))
- self.assertEqual(0, len(d.values()))
- self.assertEqual(0, len(d.items()))
- self.assertRaises(KeyError, d.__getitem__, 'a')
- d['a'] = 1
- self.assertEqual(1, len(d))
- self.assertEqual(1, d['a'])
- self.assertIn('a', d)
- self.assertEqual(['a',], d.keys())
- self.assertEqual([1], d.values())
- self.assertEqual([('a', 1)], d.items())
- di = d.iteritems()
- self.assertEqual(('a', 1), di.next())
- self.assertRaises(StopIteration, di.next)
- d['a'] = 2
- self.assertEqual(2, d['a'])
- del d['a']
- self.assertEqual(0, len(d))
-
- def test_filled(self):
- original = {'b': 2, 'c': 3}
- d = FilteredDict(('a', 'b'), original)
- self.assertEqual(1, len(d))
- self.assertNotIn('a', d)
- self.assertIn('b', d)
- self.assertNotIn('c', d)
- self.assertEqual(1, len(d.keys()))
- self.assertEqual(1, len(d.values()))
- self.assertEqual(1, len(d.items()))
- self.assertRaises(KeyError, d.__getitem__, 'a')
- self.assertEqual(2, d['b'])
- di = d.iteritems()
- self.assertEqual(('b', 2), di.next())
- self.assertRaises(StopIteration, di.next)
- self.assertEqual(2, d.pop('b'))
- self.assertEqual(0, len(d))
- self.assertEqual({'c': 3}, original)
- d.update({'a': 1, 'b': 4})
- self.assertEqual({'a': 1, 'b': 4, 'c': 3}, original)
- self.assertEqual(2, len(d))
- self.assertEqual(set((('a', 1), ('b', 4))), set(d.items()))
- d.clear()
- self.assertEqual(0, len(d))
- self.assertEqual({'c': 3}, original)
- self.assertRaises(KeyError, d.__setitem__, 'c', 5)
- self.assertRaises(KeyError, d.update, {'b': 2, 'c': 3})
-
-if __name__ == '__main__':
- unittest.main()