Source code for gpi.cmd

#    Copyright (C) 2014  Dignity Health
#
#    This program 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 3 of the License, or
#    (at your option) any later version.
#
#    This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
#
#    NO CLINICAL USE.  THE SOFTWARE IS NOT INTENDED FOR COMMERCIAL PURPOSES
#    AND SHOULD BE USED ONLY FOR NON-COMMERCIAL RESEARCH PURPOSES.  THE
#    SOFTWARE MAY NOT IN ANY EVENT BE USED FOR ANY CLINICAL OR DIAGNOSTIC
#    PURPOSES.  YOU ACKNOWLEDGE AND AGREE THAT THE SOFTWARE IS NOT INTENDED FOR
#    USE IN ANY HIGH RISK OR STRICT LIABILITY ACTIVITY, INCLUDING BUT NOT
#    LIMITED TO LIFE SUPPORT OR EMERGENCY MEDICAL OPERATIONS OR USES.  LICENSOR
#    MAKES NO WARRANTY AND HAS NO LIABILITY ARISING FROM ANY USE OF THE
#    SOFTWARE IN ANY HIGH RISK OR STRICT LIABILITY ACTIVITIES.

# Brief: Commandline option parsing.
#           -can initiate some simple commands

import sys
import logging
import optparse

# gpi
from .associate import isGPIAssociatedFile
from .defines import isGPIModFile, isGPINetworkFile
from gpi import VERSION
from . import logger
from .logger import manager
from .sysspecs import Specs

# start logger for this module
log = manager.getLogger(__name__)


[docs]class CmdParser(object): '''An object to parse input commandline args after the QApplication has done its own parsing. ''' def __init__(self): '''Initialize all command-line parsed variables. ''' self._argv = None self._options = None self._args = None # a place for string args option self._sargs = {} # no gui option self._nogui = False self._scriptMode = False # splash is on by default self._nosplash = False self._loadable_mods = [] self._loadable_nets = [] self._loadable_files = [] # associated files # tell the USAGE text that this is always 'gpi' self._parser = optparse.OptionParser(prog='gpi') # take in any filename for extension checking, then loading. self._parser.add_option('--config', dest='dumpConfig', action='store_true', help='''GPI will read the User ENV and config file and dump the parsed info to stdout.''') self._parser.add_option('--log', dest='loglevel', action='store', choices=['debug', 'info', 'node', 'warn', 'error', 'critical'], help='''Change the output level of the logger: debug, info, node, warn, error, and critical''') self._parser.add_option('--nogui', dest='nogui', action='store_true', help='''causes GPI to run without a GUI for scripting. Requires a network file. The --script option is implied.''') self._parser.add_option('--script', dest='script', action='store_true', help='''causes GPI to terminate after the supplied network is finished executing. Requires a network file.''') self._parser.add_option('-s', '--string', dest='string', action='append', type='string', default=[], help='''passes a string arg to a String-node by label. Handles multiple args. Syntax: -s <label1>:<string/path> -s <label2>:<string/path>.''') self._parser.add_option('--specs', dest='dumpSpecs', action='store_true', help='''GPI will create a platform specs file and exit.''') self._parser.add_option('--defines', dest='dumpDefines', action='store_true', help='''Show some internally used defines, such as temp directory paths.''') self._parser.add_option('--nosplash', dest='nosplash', action='store_true', help='''Skip the splash screen.''') def parse(self, argv): # keep a copy of what was parsed self._argv = list(argv) # options: processed args that use switches # args: leftover positional args self._options, self._args = self._parser.parse_args(self._argv) # check for loadable files self.checkArgsForFiles() # check and process string args self.storeStringNodeArgs() # make sure the user passes a network if self._options.nogui: if self.netCount(): self._nogui = True else: log.error('the --nogui option was passed without a network, exiting.') sys.exit(1) # make sure the user passes a network if self._options.script: if self.netCount(): self._scriptMode = True else: log.error('the --script option was passed without a network, exiting.') sys.exit(1) # set log level asap, don't wait for mainWindow to be set if self.logLevel(): logger.manager.setLevel(self.logLevel()) # run simple commands if self._options.dumpSpecs: self.dumpSpecs() if self._options.dumpDefines: self.dumpDefines() if self._options.dumpConfig: from .config import Config log.dialog('Config:\n'+str(Config)) sys.exit(0) # splash self._nosplash = self._options.nosplash def dumpDefines(self): import gpi.defines msg = [] for d in dir(gpi.defines): o = getattr(gpi.defines,d) if type(o) is str: if d.startswith('GPI'): msg.append(d + ': ' + o + '\n') msg = sorted(msg) msg = '\n'+''.join(msg) log.dialog(msg) sys.exit(0) def dumpSpecs(self): with open('specs.txt', 'wb') as specsfile: specsfile.write('# GPI (v'+str(VERSION)+') system specifications file.\n') for k,v in list(Specs.table().items()): msg = k+': '+str(v) + '\n' specsfile.write(msg) log.dialog('Specs file written, exiting.') sys.exit(0) def logLevel(self): if self._options.loglevel == 'debug': return logging.DEBUG if self._options.loglevel == 'info': return logging.INFO if self._options.loglevel == 'node': return logger.GPINODE if self._options.loglevel == 'warn': return logging.WARNING if self._options.loglevel == 'error': return logging.ERROR if self._options.loglevel == 'critical': return logging.CRITICAL def noGUI(self): return self._nogui def scriptMode(self): return self._scriptMode def noSplash(self): return self._nosplash def mods(self): return self._loadable_mods def nets(self): return self._loadable_nets def files(self): return self._loadable_files def stringNodeArg(self, key): if key in self._sargs: return self._sargs[key] log.error('\''+str(key)+'\' not found in string args.') def stringNodeLabels(self): return list(self._sargs.keys()) def storeStringNodeArgs(self): # merge any redundant labels with warnings for arg in self._options.string: lab, path = arg.split(':') if lab in self._sargs: log.warn('input string label for arg: \''+ str(arg) + '\' already exists, skipping.') else: self._sargs[lab] = path def __str__(self): msg = '' msg += 'Unparsed: '+str(self._args) + '\n' msg += 'Parsed: '+str(self._options) + '\n' return msg def modCount(self): return len(self._loadable_mods) def netCount(self): return len(self._loadable_nets) def fileCount(self): return len(self._loadable_files) def stringNodeArgCount(self): return len(self._sargs) def pendingCount(self): return self.modCount() + self.netCount() + self.fileCount() + self.stringNodeArgCount() def checkArgsForFiles(self): for arg in self._args: if isGPIModFile(arg): self._loadable_mods.append(arg) elif isGPINetworkFile(arg): self._loadable_nets.append(arg) elif isGPIAssociatedFile(arg): self._loadable_files.append(arg)
Commands = CmdParser()