Source code for mylinux.model.config.Installed

from __future__ import absolute_import

import json
from datetime import datetime

from decisionTable import DecisionTable

from mylinux import view
from mylinux.constants import error as ERR
from mylinux.libs import AppErr

[docs]class Installed: '''Class for handeling installed file. Args: path (str): Absolute path to installed file. Attributes: __inited (boo): Was class allready inited? __selectTableRule (str): Define CSV like decision table rule for selecting packages. __executeTableRule (str): Define CSV like decision table rule for executing packages. __selectTable (cla): ``DecisionTable`` class activated with select table rule. __executeTable (cla): ``DecisionTable`` class activated with execute table rule. __requirdPackageKeys (arr-str): Required packages keys in every package which is installed. __path (str): See args info. __data (dic): All installed data. Raises: AppErr.developer: If class was already inited. Other Parameters: Set data to __data. Note: Installed class for every package executing/selecting action is using ``decisionTable`` package which makes logic visual more nice than raw if/else/elif code... For more info visit: https://decisiontable.readthedocs.org ''' __inited = False __selectTableRule = """ packageState configState config action new_packageState new_configState ================================================================================================ None None False install install install ok ok False purge purge purge . . True purge ok purge . . True update ok update ok error False purge purge purge . . True update ok update . . True install ok install . . True purge ok purge error install False purge purge purge . . False install install install None error True purge None purge error purge False purge purge purge ok None True install ok install . . False purge purge purge * * * * ERROR ERROR""" __executeTableRule = """ packageState configState execute err_package err_config new_packageState new_configState =============================================================================================================== install install installAll False False ok ok . . . . True ok error . . . True None error install purge purge purgeAll False False None None . . . False True None error . . . True None error purge ok purge purgeConfig None True ok error . . . None False ok None ok update updateConfig None False ok ok . . . None True ok error ok install installConfig None False ok ok . . . None True ok error None purge purgeConfig None False None None . . . None True None error""" __selectTable = DecisionTable(__selectTableRule) __executeTable = DecisionTable(__executeTableRule) __requiredPackageKeys = ['created', 'configState', 'stdout', 'lastChange', 'stderr', 'packageState'] def __init__(self, path): if not Installed.__inited: Installed.__inited = True self.__path = path self.__data = None self.__setData() else: raise AppErr.developer(ERR.singletone)
[docs] def __call__(self): """ Return: __data """ return self.__data
[docs] def __getitem__(self, item): """ Args: item (str) Return: __data[item] """ return self.__data[item]
@property def path(self): """ Return: __path """ return self.__path @property def selectTableRule(self): """ Return: __selectTableRule """ return self.__selectTableRule @property def executeTableRule(self): """ Return: __executeTableRule """ return self.__executeTableRule @property def requiredPackageKeys(self): """ Return: __requiredPackageKeys """ return self.__requiredPackageKeys def __setData(self): """Seting installed data. Other Parameters: Check if file on __path exist. Check if json format is correct. If pre checks fails show error report. Set __data with data from __path. """ error = [] try: with open(self.__path) as f: try: self.__data = json.load(f) except Exception as err: error.append(['ERROR', 'Json load', ' '.join(list(err.args)) ]) except Exception: error.append(['FAIL', 'File open', 'No such file or directory']) if not error: for package in self.__data: for reqKey in self.__requiredPackageKeys: if not reqKey in self.__data[package]: error.append(['ERROR', 'Json key', ERR.Format.keyMissingIn(reqKey, package)]) if error: view.Tli.raiseError(AppErr.model,self.__path,error) def __createPackage(self, packageName): """Create new installed package. Args: packageName (str): Name for new package. Other Parameters: Check if packageName don't exist in installed. If pre check fails show error report. Create new package in installed. """ if not packageName in self.__data: self.__data[packageName] = { 'lastChange': str(datetime.now()), 'created': str(datetime.now()), 'stdout': None, 'stderr': None, 'packageState': None, 'configState': None } else: view.Tli.raiseError(AppErr.user,'Create package', ['FAIL', packageName, ERR.Format.alreadyExistIn('installed')], headers=['Status', 'Package', 'Message'] ) def __changePackageValues(self, packageName, **args): """Handler for updating packages data. Args: packageName (str): Package name whose values are going to change. **args : Keys and values for package data. Other Parameters: Check if key in args is permited to be changed. If check fails show error report. Set key data to new value from args. Update last change value in package. """ change = False error = [] for key in args: if not key in ['stdout', 'stderr', 'packageState', 'configState']: error.append(['ERROR', 'Json key', ERR.Format.keyNotValidFor(key, 'installed package')]) else: self.__data[packageName][key] = args[key] change = True if error: view.Tli.raiseError( AppErr.developer, '{0} in {1}'.format(self.__changePackageValues.__name__,__name__), error ) elif change: self.__data[packageName]['lastChange'] = str(datetime.now())
[docs] def getNames(self): """Get packages names from installed Return: Array of str. of installed packages. """ return [key for key in self.__data]
[docs] def packageAfterExecution(self, packageName, err_package, err_config, stdout='', stderr=''): """Set package in installed new set of data Args: packageName (str): Package which states will be updated. err_package (str): Does have package after execution error? err_config (str): Does config have execution error? stdout (str): Stout from execution. stderr (str): Possible error message from terminal. Other Parameters: Get package and config state base on execution information. Update package in installed with new set of data. """ new_packageState, new_configState = self.__executeTable.decision( ['new_packageState', 'new_configState'], packageState=self.__data[packageName]['packageState'], configState=self.__data[packageName]['configState'], err_package=err_package, err_config=err_config ) self.__changePackageValues( packageName, packageState=new_packageState, configState=new_configState, stdout=stdout, stderr=stderr )
[docs] def decidePackageExecution(self, packageName): """Decide what action should be executed on package. Args: packageName (str): Package name Returns: [package state executing decision, config -//- decision] """ return self.__executeTable.decision( ['execute'], packageState=self.__data[packageName]['packageState'], configState=self.__data[packageName]['configState'] )
[docs] def getStates(self, key, packageNames, filler): """Hellper method for TUI select class. Get infos data value from all installed package key. If package is not installed replace states with filler. Args: key (str): Package key from installed package data. packageNames (arr-str): All package names so that key value is extracted. filler (str): If package is not in installed replace value with this. Return: If not packageNames return arr-str of all key values from installed packages data. If packageNames return arr-str of all selected package key values from installed packages data. """ if packageNames: return [self.__data[package][key] if package in self.__data else filler for package in packageNames] else: return [package[key] for package in self.__data]
[docs] def createOrUpdateSelected(self, config, action, packageNames): """Method for creation or updating installed packages data. If package in installed exist it will update its data. Else the package will be created. Args: config (boo): Is action want to be executed on configs too? action (str): What action will be made on packageNames? packageNames (arr-str): What packages names should be executed with an action? Other Parameters: If package do not exist in installed create one with None package state and None config state. If package do not exist but don't have right action show error report. Make select decision for package base on action and config boolean value. If right decision was not finded show hinting report. If decision was finded change package values. """ error = [] for packageName in packageNames: # If not exist create package with states: None,None if not packageName in self.__data: if action == 'install' and not config: self.__createPackage(packageName) else: view.Tli.raiseError( AppErr.user, self.__path, ['FAIL', packageName, ERR.Format.notInstalled()], headers=view.Tli.reportHeaders ) # Get decisions return from decision table new_packageState, new_configState = self.__selectTable.decision( ['new_packageState', 'new_configState'], packageState=self.__data[packageName]['packageState'], configState=self.__data[packageName]['configState'], config=config, action=action, ) # Check if new states have error response from decision table if new_configState == 'ERROR' or new_packageState == 'ERROR': # Find hinting for the current state... allConfigs, allActions = self.__selectTable.allDecisions( ['config', 'action'], packageState=self.__data[packageName]['packageState'], configState=self.__data[packageName]['configState'], ) hinting = [] for i in range(len(allConfigs)): if str(allConfigs[i]) != '*' and str(allActions[i]) != '*': if allConfigs[i] == 'True': hinting.append('config ' + allActions[i]) else: hinting.append(allActions[i]) error.append([ 'FAIL', packageName, self.__data[packageName]['packageState'], self.__data[packageName]['configState'], '||'.join(hinting) ]) continue else: # If every thing went ok update installed package values self.__changePackageValues(packageName, packageState=new_packageState, configState=new_configState, ) if error: view.Tli.raiseError( AppErr.user, 'Select table rule conflict', error, headers=['Status', 'Package', 'packageState', 'configState', 'Possible select actions'] )
[docs] def override(self): """Update or override __data variable Other Parameters: Check if file on __path exist. Check if json format is ok. If pre checks fail show error report. """ try: with open(self.__path, 'w') as f: try: json.dump(self.__data, f, indent=4) except Exception as err: view.Tli.raiseError( AppErr.model, self.__path, ['ERROR', 'Json dump', ' '.join(list(err.args))] ) except Exception: view.Tli.raiseError( AppErr.model, self.__path, ['ERROR', 'File write', "Can't write to file"] )