+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-
-# Copyright (C) 2016-2022 OPEN CASCADE
-#
-# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-#
-
-###
-# Command line tool to manage SALOME configuration.
-# Usage: type "scfg help" to learn how to use tool.
-###
-
-import sys
-import os
-from sconfig.salome_config import CfgTool, defaultConfFile
-
-###
-# TODO
-# 1. Improve parsing of command line: each command should be defined as:
-# - command: name of the command
-# - help: help string as appears in the short description of a command in a list
-# of commands and as a first line of command's help
-# - options: (dict) see below
-# - parameters: (list or dict) see below
-# Each option should be defined with:
-# - title: one letter signature
-# - help: help string
-# - parameter: name of parameter if option requires a parameter
-# Each parameter should be defined with:
-# - title: as appears in help information
-# - optional: flag (boolean) showing if this parameter is optional
-# - help: help description
-#
-# Parser of command line should then automatically check validity of the command,
-# its parameters and options.
-#
-# 2. Usage and help information should be automaticall generated and formatted
-# from command description as described above.
-#
-# 3. Protect from adding same named option to a command.
-#
-# 4. Improve formatting help for command's parameters (see 1) - namely, wrapping
-# into a block.
-###
-
-##
-# function: get_tool_name
-#
-# gets a name of this command line tool (string)
-##
-
-def get_tool_name():
- return os.path.basename(sys.argv[0])
-
-##
-# function: verbose
-#
-# returns True when in debug mode (env var VERBOSE is set to 1)
-##
-
-def verbose():
- return bool(os.getenv("VERBOSE", False))
-
-##
-# function: debug
-#
-# prints debug information (for debug purposes)
-#
-# Parameters:
-# args: output data to be printed to the screen (any printable objects)
-##
-
-def debug(*args):
- if verbose():
- print("[DEBUG]", end=' ')
- for a in args: print(a, end=' ')
- print()
- pass
-
-##
-# function: error_exit
-#
-# prints error information and exits with non-zero status
-#
-# Parameters:
-# msg: error message (string)
-##
-
-def error_exit(msg):
- print("%s: %s" % (get_tool_name(), msg))
- sys.exit(1)
- pass
-
-##
-# function: get_commands
-#
-# get supported commands
-#
-# return value is a dictionary:
-# { cmd : ( help, opt_map ) }
-# here:
-# - cmd is a command (string)
-# - help is a command's general help information on a command (string)
-# - opt_map is a disctionary of allowed command's options:
-# { opt: opt_help }, where
-# - opt is option ("a:" if option requires a parameter or just "a" elsewhere, where
-# "a" is any letter)
-# - opt_help is a help information on the option (string).
-#
-# See also: add_command
-##
-
-def get_commands():
- if not globals().get("__commands__"): globals()["__commands__"] = {}
- return globals().get("__commands__")
-
-##
-# function: add_command
-#
-# adds command to the tool
-#
-# Parameters:
-# cmd: command (string)
-# help_string: help information on the command (string)
-# options: options supported by the command (map {opt: opt_help}, see get_commands)
-##
-
-def add_command(cmd, help_string, options):
- if cmd in get_commands():
- debug("command %s already exists" % cmd)
- else:
- get_commands()[ cmd ] = ( help_string, options )
- pass
-
-##
-# function: get_opts
-#
-# gets supported options for the command
-#
-# Parameters:
-# cmd: command (string)
-#
-# return value is map {opt: opt_help} (see get_commands)
-##
-
-def get_opts(cmd):
- if cmd is None: cmd = ""
- opts = {}
- try:
- opts = get_commands()[cmd][1]
- except:
- pass
- return opts
-
-##
-# function: get_help
-#
-# gets help string for the command
-#
-# Parameters:
-# cmd: command (string)
-#
-# return value is unformatted string
-##
-
-def get_help(cmd):
- if cmd is None: cmd = ""
- help_string = ""
- try:
- help_string = get_commands()[cmd][0]
- except:
- pass
- return help_string
-
-##
-# function: format_string
-#
-# formats string into block according to the given block width
-#
-# Parameters:
-# s: string data
-# width: requested width of resulting string block
-#
-# return formatted string block
-##
-
-def format_string(s, width):
- blocks = s.split("\n")
- result = []
- for block in blocks:
- block = block.replace("\t", " [[TAB]] ")
- words = block.split()
- current_string = ""
- for word in words:
- word = word if word != "[[TAB]]" else " "*2
- if not current_string:
- current_string = word
- else:
- if len(current_string + " " + word) <= width:
- current_string += " " + word
- else:
- result.append(current_string)
- current_string = word
- pass
- pass
- pass
- result.append(current_string)
- pass
- return "\n".join(result)
-
-##
-# function: format_commands
-#
-# formats short help on all supported commands
-#
-# return string that contains formatted help on commands
-##
-
-def format_commands():
- commands = get_commands()
- # filter out tool itself
- commands = sorted([a for a in commands if a != ""])
- # sort commands alphabetically
- # get max command's length
- max_length = max([ len(i) for i in commands])
- # generate formatting string
- prefix = " "
- separator = " "
- fmt_string = prefix + "%" + "-%ds" % max_length + separator
- def _format(_c):
- _h = get_help(_c).split("\n")[0]
- _h = format_string(_h, 80-(max_length+len(prefix)+len(separator)))
- _h = _h.split("\n")
- _t = prefix + " " * max_length + separator
- _r = []
- _r.append(_h[0])
- for _i in _h[1:]: _r.append(_t + _i)
- return "\n".join(_r)
- return "\n".join([ fmt_string % i + _format(i) for i in commands])
-
-##
-# function: format_list_options
-#
-# formats short help on commands's options to be inserted into short help info on a command
-#
-# Parameters:
-# cmd: command (string)
-#
-# return string that contains formatted help
-##
-
-def format_list_options(cmd):
- opts = get_opts(cmd)
- return "".join([" [%s]" % i for i in opts])
-
-##
-# function: format_options
-#
-# formats help on commands's options to be inserted after short help info on a command
-#
-# Parameters:
-# cmd: command (string)
-#
-# return string that contains formatted help
-##
-
-def format_options(cmd):
- opts = get_opts(cmd)
- opts_names = list(opts.keys())
- if not opts: return ""
- # get max command's length
- max_length = max([ len(i) for i in opts_names])
- # generate formatting string
- prefix = " "
- separator = " "
- fmt_string = prefix + "%" + "-%ds" % max_length + separator
- def _format(_o):
- _h = opts[_o]
- _h = format_string(_h, 80-(max_length+len(prefix)+len(separator)))
- _h = _h.split("\n")
- _t = prefix + " " * max_length + separator
- _r = []
- _r.append(_h[0])
- for _i in _h[1:]: _r.append(_t + _i)
- return "\n".join(_r)
- return "\n" + "\n".join([ fmt_string % i + _format(i) for i in opts_names]) + "\n"
-
-##
-# function: usage
-#
-# prints help and exits with zero status
-#
-# Parameters:
-# cmd: command (string)
-##
-
-def usage(cmd=None):
- if cmd is None: cmd = ""
- if cmd not in get_commands(): error_exit("unknown command: %s" % cmd)
- fmt = {}
- fmt[ "prg" ] = get_tool_name()
- fmt[ "cmd" ] = get_tool_name() if not cmd else cmd
- fmt[ "cmd_list" ] = format_commands()
- fmt[ "opts" ] = format_list_options(cmd)
- fmt[ "opt_list" ] = format_options(cmd)
- help_string = get_help(cmd)
- help_string = help_string.replace("\t", " ")
- print(help_string.format(**fmt))
- sys.exit(0)
- pass
-
-##
-# function: parse_cmd_line
-#
-# parses command line; prints error and exits if unsupported command
-# or option is specified
-#
-# Parameters:
-# args: arguments being parsed (list of strings)
-##
-
-def parse_cmd_line(args):
- tool_opts, cmd, cmd_opts, tgt, params = {}, None, {}, None, []
- args.reverse()
- commands = get_commands()
- while args:
- a = args.pop()
- if a == "-":
- # empty option
- error_exit("empty option is not allowed")
- if a.startswith("-"):
- allowed_opts = list(get_opts(cmd).keys())
- allowed_opts = dict([(i[1], len(i)>2) for i in allowed_opts])
- processed_opts = tool_opts if cmd is None else cmd_opts
- cmd_descr = "" if cmd is None else " for command '%s'" % cmd
- opts = a[1:]
- while opts:
- o = opts[0]
- opts = opts[1:]
- if o == "-":
- # "--" format is not supported
- error_exit("invalid format of option")
- elif o in allowed_opts:
- if allowed_opts[o]:
- # supported option; requires parameter
- if opts:
- processed_opts[ o ] = opts
- opts = []
- elif args and not args[-1].startswith("-") and not args[-1] in commands:
- processed_opts[ o ] = args.pop()
- else:
- error_exit("option %s%s requires argument" % (o, cmd_descr))
- else:
- # supported option; does not require parameter
- processed_opts[ o ] = None
- pass
- pass
- else:
- # unsupported option
- error_exit("unknown option: -%s%s" % (o, cmd_descr))
- pass # while opts
- pass
- elif not cmd:
- cmd = a
- if cmd not in commands:
- # unsupported command
- error_exit("unknown command: %s" % cmd)
- pass
- elif not tgt:
- tgt = a
- pass
- else:
- params += [ a ]
- return tool_opts, cmd, cmd_opts, tgt, params
-
-##
-# function: main
-#
-# main entry point of the tool
-##
-
-def main():
- # set-up commands
-
- # - tool itself
- help_string = "Command line tool to manage SALOME configuration.\n\n"
- help_string += "Usage: {prg}{opts} COMMAND [ARGS]\n"
- help_string += "{opt_list}\n"
- help_string += "Supported commands:\n"
- help_string += "{cmd_list}\n\n"
- help_string += "See '{prg} help COMMAND' for more information on a specific command."
- options = {}
- options [ "-s FILE" ] = "Path to the configuration file; default: %s." % defaultConfFile()
- add_command("",
- help_string,
- options)
-
- # - help command
- help_string = "Display help information about this tool.\n\n"
- help_string += "Usage: {prg} {cmd}{opts}\n"
- help_string += "{opt_list}"
- add_command("help",
- help_string,
- {})
-
- # - set command
- help_string = "Create or modify configuration object.\n\n"
- help_string += "Usage: {prg} {cmd}{opts} TARGET [PARAM VALUE ...]\n\n"
- help_string += "\tTARGET: configuration object being created / modified\n"
- help_string += "\tPARAM: parameter of the target object\n"
- help_string += "\tVALUE: value to be assigned to the attribute of the target object\n"
- help_string += "{opt_list}"
- add_command("set",
- help_string,
- {})
-
- # - get command
- help_string = "Get parameter of configuration object.\n\n"
- help_string += "Usage: {prg} {cmd}{opts} TARGET PARAM\n\n"
- help_string += "\tTARGET: configuration object being inspected\n"
- help_string += "\tPARAM: parameter of the target object\n"
- help_string += "{opt_list}"
- add_command("get",
- help_string,
- {})
-
- # - remove command
- help_string = "Remove configuration object or its attribute(s).\n\n"
- help_string += "Usage: {prg} {cmd}{opts} TARGET [PARAM ...]\n\n"
- help_string += "\tTARGET: configuration object\n"
- help_string += "\tPARAM: attribute of the target object\n"
- help_string += "{opt_list}"
- add_command("remove",
- help_string,
- {})
-
- # - dump command
- help_string = "Dump configuration.\n\n"
- help_string += "Usage: {prg} {cmd}{opts} [TARGET]\n\n"
- help_string += "\tTARGET: optional configuration object (if not specified,\n"
- help_string += "\t all configuration is dumped).\n"
- help_string += "{opt_list}"
- add_command("dump",
- help_string,
- {})
-
- # - verify command
- help_string = "Verify configuration.\n\n"
- help_string += "Usage: {prg} {cmd}{opts} [TARGET]\n\n"
- help_string += "\tTARGET: optional configuration object (if not specified,\n"
- help_string += "\t all configuration is verified).\n"
- help_string += "{opt_list}"
- add_command("verify",
- help_string,
- {})
-
- # - clean command
- help_string = "Clean configuration.\n\n"
- help_string += "Usage: {prg} {cmd}{opts}\n"
- help_string += "{opt_list}"
- add_command("clean",
- help_string,
- {})
-
- # parse command line
-
- opts, cmd, cmd_opts, tgt, params = parse_cmd_line(sys.argv[1:])
- debug("parse command line: options =", opts, "; command =", cmd, "; command options =", cmd_opts, "; target =", tgt, "; arguments =", params)
-
- # process command
-
- if not cmd or cmd == "help":
- # show help and exit
- usage(tgt)
- pass
-
- try:
- # check if custom source file is specified
-
- src_file = opts["s"] if "s" in opts else None
- debug("source file:", src_file)
-
- # create config tool
-
- cfg_tool = CfgTool(src_file)
- debug("cfg tool:", cfg_tool)
-
- # TODO: we should not check commands in a switch-like block below;
- # instead processing should be done automatically basing on the
- # predefined set of commands (TODO)
-
- if cmd == "get":
- if not tgt:
- error_exit("%s: target is not specified!" % cmd)
- if len(params) < 1:
- error_exit("%s: parameter of target %s is not specified!" % (cmd, tgt))
- # only one parameter can be read!
- if len(params) > 1:
- error_exit("%s: can't read more than one parameter at once!" % cmd)
- def _toString(v):
- if v is None: return ""
- elif isinstance(v, list): return " ".join(v)
- else: return v
- print(_toString(cfg_tool.get(tgt, params[0])))
- pass
- elif cmd == "set":
- if not tgt:
- error_exit("%s: target is not specified!" % cmd)
- # empty parameters list is allowed!
- cfg_tool.set(tgt, *params)
- pass
- elif cmd == "remove":
- if not tgt:
- error_exit("%s: target is not specified!" % cmd)
- # empty parameters list is allowed!
- cfg_tool.remove(tgt, *params)
- pass
- elif cmd == "dump":
- if len(params) > 0:
- error_exit("%s: command does not support parameters!" % cmd)
- # empty target is allowed!
- cfg_tool.dump(tgt)
- pass
- elif cmd == "verify":
- if len(params) > 0:
- error_exit("%s: command does not support parameters!" % cmd)
- # empty target is allowed!
- errors = []
- if cfg_tool.verify(tgt, errors):
- msg = " (no products found)" if not cfg_tool.get("cfg", "products") else ""
- print("Configuration is valid%s." % msg)
- else:
- raise Exception("Configuration is invalid:\n"+ "\n".join(errors))
- pass
- elif cmd == "clean":
- if tgt:
- error_exit("%s: command does not support target!" % cmd)
- if len(params) > 0:
- error_exit("%s: command does not support parameters!" % cmd)
- # empty target is allowed!
- cfg_tool.clean()
- pass
- else:
- # unknown command: normally we should not go here
- error_exit("unknown command: %s" % cmd)
- pass
- pass
- except Exception as e:
- error_exit(e)
- pass
-
-if __name__ == "__main__":
- main()