Source code for ffflash.main

from ffflash.inc.nodelist import handle_nodelist
from ffflash.inc.sidecars import handle_sidecars
from ffflash.info import info
from ffflash.lib.api import FFApi
from ffflash.lib.args import parsed_args
from ffflash.lib.clock import get_iso_timestamp
from ffflash.lib.files import check_file_location, dump_file, load_file


[docs]class FFFlash: ''' This is the main object, which stores all relevant information, and the :class:`ffflash.lib.api.FFApi` itself. :param args: ``Namespace`` object from :meth:`ffflash.lib.args.parsed_args` ''' def __init__(self, args): self.args = args self.location = check_file_location(self.args.APIfile, must_exist=True) self.api = None self.load_api()
[docs] def load_api(self): ''' Populate :attr:`api` with :class:`ffflash.lib.api.FFApi` with content loaded from :attr:`location`. :attr:`api` is populated only once, this prevents accidental reloads. ''' if (self.api is None) and self.location: c = load_file(self.location, as_yaml=False) if c: self.api = FFApi(c)
[docs] def set_timestamp(self): ''' Inject :meth:`ffflash.lib.clock.get_iso_timestamp` into ``state.lastchange``. ''' if self.access_for('api'): if self.api.pull('state', 'lastchange') is not None: self.api.push(get_iso_timestamp(), 'state', 'lastchange')
[docs] def save(self): ''' Save content from :attr:`api` (:class:`ffflash.lib.api.FFApi`) into :attr:`location`. A :meth:`ffflash.lib.api.FFApi.timestamp` is triggered before saving. ''' if self.access_for('api'): self.set_timestamp() return dump_file(self.location, self.api.c, as_yaml=False)
[docs] def access_for(self, name): ''' Check if it is save to access the api and/or depending files. :param name: String specifier of part to access. :return: ``True`` or ``False`` ''' return all([ (self.api is not None), { 'api': self.location, 'sidecars': self.args.sidecars, 'nodelist': self.args.nodelist, 'rankfile': all([ self.args.nodelist, self.args.rankfile ]), }.get(name, False) ])
[docs] def log(self, message, level=True): ''' Very advanced Logger. For professional use only. :param message: Some message string to display :param level: Severity of message. Can be anything as this is also the return value. There are three predefined rules: * ``True``: *info* (is dismissed unless ``--verbose`` was given) * ``None``: *warn* * ``False``: *error* :return: ``level`` ''' c = { True: 'info', None: 'warn', False: 'error' }.get(level, level) if ( level is None or isinstance(level, (bool, str)) ) else 'output' if self.args.verbose or level is not True: print('{}\t{}'.format(c.upper(), message)) return level
[docs]def run(argv=None): ''' Main function of |info_cname|. ''' ff = FFFlash(parsed_args(argv)) ff.log(info.ident) if not ff.access_for('api'): return (not ff.log('error loading API file', level=False)) modified = [] if ff.access_for('sidecars'): modified.append( handle_sidecars(ff) ) if ff.access_for('nodelist'): modified.append( handle_nodelist(ff) ) if ff.args.dry: ff.log('\n{}'.format(ff.api.pretty()), level='API file preview') else: if any(modified): ff.save() ff.log('saved api file') return (not any(modified))