|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
|
|
|
#
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
# You may obtain a copy of the License at
|
|
|
#
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
#
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
# See the License for the specific language governing permissions and
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
|
|
|
|
import pickle
|
|
|
import random
|
|
|
import threading
|
|
|
import sys
|
|
|
import os
|
|
|
import re
|
|
|
from os import path
|
|
|
import glob
|
|
|
import traceback
|
|
|
from traceback import print_exc
|
|
|
from calculate.core.server.core_interfaces import (CoreServiceInterface,
|
|
|
MethodsInterface)
|
|
|
from calculate.install.distr import Distributive
|
|
|
from calculate.lib.cl_log import log
|
|
|
from calculate.lib.utils.colortext import convert_console_to_xml
|
|
|
from .api_types import ReturnProgress
|
|
|
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
|
|
|
|
|
|
_ = lambda x: x
|
|
|
setLocalTranslate('cl_core3', sys.modules[__name__])
|
|
|
__ = getLazyLocalTranslate(_)
|
|
|
|
|
|
from calculate.lib.utils.files import (process, readFile, processProgress,
|
|
|
readLinesFile,
|
|
|
makeDirectory, getProgPath)
|
|
|
from calculate.lib.datavars import DataVarsError, CriticalError, Variable
|
|
|
from calculate.lib.utils.content import getCfgFiles
|
|
|
from itertools import *
|
|
|
|
|
|
import calculate.contrib
|
|
|
from spyne import String, Integer, Boolean, Array
|
|
|
|
|
|
from calculate.core.server.api_types import ReturnedMessage, CommonInfo
|
|
|
from calculate.core.server.api_types import (Field,
|
|
|
GroupField, ViewInfo, ViewParams)
|
|
|
from calculate.lib.cl_template import Template
|
|
|
from calculate.lib.datavars import DataVars
|
|
|
from .loaded_methods import LoadedMethods
|
|
|
|
|
|
|
|
|
class CommonMethods(MethodsInterface):
|
|
|
def dispatchConf(self, filesApply=None, prefix="/"):
|
|
|
"""
|
|
|
Common dispatch conf. Using if ._cfg files created.
|
|
|
"""
|
|
|
|
|
|
def normalize_config(text):
|
|
|
"""
|
|
|
Нормализовать конфигурационный файл для сравнения:
|
|
|
* удалить calculate заголовок
|
|
|
* добавить перевод строки в конец если файл без перевода строки
|
|
|
"""
|
|
|
if text.endswith('\n'):
|
|
|
return Template.removeComment(text)
|
|
|
else:
|
|
|
return "%s\n" % Template.removeComment(text)
|
|
|
|
|
|
i_orig, i_data = 0, 1
|
|
|
i_mime, i_cfgname = 0, 1
|
|
|
cfg_files = getCfgFiles(prefix=prefix).items()
|
|
|
info = [x for x in cfg_files
|
|
|
if filesApply is None or x[i_data][0][i_cfgname] in filesApply]
|
|
|
max_info = len(info)
|
|
|
for ind, data in enumerate(info):
|
|
|
out = []
|
|
|
orig, data = data
|
|
|
data = data[0]
|
|
|
|
|
|
origdata = readFile(orig)
|
|
|
newdata = readFile(data[i_cfgname])
|
|
|
pattern = "%s/._cfg????_%s" % (os.path.dirname(orig),
|
|
|
os.path.basename(orig))
|
|
|
answ_map = {'usenew': 'use new', 'skip': 'next'}
|
|
|
dispatch_var = self.clVars.Get('cl_dispatch_conf')
|
|
|
for fn in glob.glob(pattern):
|
|
|
try:
|
|
|
if fn == data[i_cfgname]:
|
|
|
continue
|
|
|
os.unlink(fn)
|
|
|
except (OSError, IndexError):
|
|
|
pass
|
|
|
if (self.clVars.Get('cl_autoupdate_set') == 'on' or
|
|
|
origdata == newdata):
|
|
|
answ = "zap new" #was use new
|
|
|
elif dispatch_var in answ_map:
|
|
|
answ = answ_map.get(dispatch_var)
|
|
|
else:
|
|
|
orig_content = normalize_config(readFile(orig))
|
|
|
new_content = normalize_config(readFile(data[i_cfgname]))
|
|
|
if orig_content == new_content:
|
|
|
answ = "zap new" #was use new
|
|
|
else:
|
|
|
for i, s in enumerate(list(process("diff", "-Nu",
|
|
|
orig, data[i_cfgname]))):
|
|
|
s = convert_console_to_xml(s)
|
|
|
if s.startswith('+') and i > 1:
|
|
|
out.append('<font color="green">%s</font>' % s)
|
|
|
elif s.startswith('-') and i > 1:
|
|
|
out.append('<font color="red">%s</font>' % s)
|
|
|
else:
|
|
|
out.append(s)
|
|
|
self.printPre("<br/>".join(out))
|
|
|
self.printSUCCESS(_("({one} of {_all}) -- {fname}").format(
|
|
|
one=ind + 1, _all=max_info, fname=orig))
|
|
|
answ = self.askChoice(_("Choose a configuration action:"),
|
|
|
answers=(("zap new", _("Zap new")),
|
|
|
("use new", _("Use new")),
|
|
|
("next", _("Next"))))
|
|
|
if answ == "next":
|
|
|
continue
|
|
|
elif answ == "use new":
|
|
|
try:
|
|
|
with open(orig, 'w') as fd:
|
|
|
fd.write(readFile(data[i_cfgname]))
|
|
|
os.unlink(data[i_cfgname])
|
|
|
if filesApply:
|
|
|
try:
|
|
|
i = filesApply.index(data[i_cfgname])
|
|
|
filesApply[i] = orig
|
|
|
except Exception as e:
|
|
|
print(str(e))
|
|
|
except Exception as e:
|
|
|
print(str(e))
|
|
|
self.printERROR(
|
|
|
_("Failed to copy {ffrom} to {fto}").format(
|
|
|
ffrom=data[i_cfgname], fto=orig))
|
|
|
continue
|
|
|
elif answ == "zap new":
|
|
|
try:
|
|
|
os.unlink(data[i_cfgname])
|
|
|
if filesApply:
|
|
|
try:
|
|
|
filesApply.remove(data[i_cfgname])
|
|
|
except Exception as e:
|
|
|
print(str(e))
|
|
|
except OSError:
|
|
|
self.printERROR(
|
|
|
_("Failed to remove %s") % data[i_cfgname])
|
|
|
return True
|
|
|
|
|
|
def setVariable(self, varname, varvalue, force=False):
|
|
|
"""
|
|
|
Установить значение переменной
|
|
|
"""
|
|
|
self.clVars.Set(varname, varvalue, force=force)
|
|
|
return True
|
|
|
|
|
|
def invalidateVariables(self, *variables):
|
|
|
for varname in (x.rpartition('.')[2] for x in variables):
|
|
|
self.clVars.Invalidate(varname, force=True)
|
|
|
return True
|
|
|
|
|
|
def applyTemplates(self, target=None, useClt=None, cltFilter=False,
|
|
|
root=None, useDispatch=True, critical=False):
|
|
|
"""
|
|
|
Применить шаблоны.
|
|
|
|
|
|
Args:
|
|
|
target: дистрибутив, куда необходимо выполнить шаблоны (/ по умолчанию)
|
|
|
useClt: использовать clt шаблоны
|
|
|
cltFilter: применять фильтр на clt шаблоны
|
|
|
root: каталог, куда будут наложны шаблоны (cl_root_path)
|
|
|
"""
|
|
|
from calculate.lib.cl_template import (TemplatesError, ProgressTemplate)
|
|
|
|
|
|
if target is None:
|
|
|
chroot = '/'
|
|
|
elif isinstance(target, Distributive):
|
|
|
chroot = target.getDirectory()
|
|
|
else:
|
|
|
chroot = target
|
|
|
if root is None:
|
|
|
root = '/'
|
|
|
elif isinstance(root, Distributive):
|
|
|
root = root.getDirectory()
|
|
|
clt_filter = True if cltFilter in (True, "on") else False
|
|
|
self.clVars.Set("cl_chroot_path", chroot, True)
|
|
|
self.clVars.Set("cl_root_path", root, True)
|
|
|
# определение каталогов содержащих шаблоны
|
|
|
use_clt = useClt in ("on", True)
|
|
|
self.addProgress()
|
|
|
null_progress = lambda *args, **kw: None
|
|
|
dispatch = self.dispatchConf if useDispatch else None
|
|
|
cl_templ = ProgressTemplate(null_progress, self.clVars,
|
|
|
cltObj=use_clt,
|
|
|
cltFilter=clt_filter,
|
|
|
printSUCCESS=self.printSUCCESS,
|
|
|
printWARNING=self.printWARNING,
|
|
|
askConfirm=self.askConfirm,
|
|
|
dispatchConf=dispatch,
|
|
|
printERROR=self.printERROR,
|
|
|
critical=critical)
|
|
|
try:
|
|
|
cl_templ.applyTemplates()
|
|
|
if cl_templ.hasError():
|
|
|
if cl_templ.getError():
|
|
|
raise TemplatesError(cl_templ.getError())
|
|
|
finally:
|
|
|
if cl_templ:
|
|
|
if cl_templ.cltObj:
|
|
|
cl_templ.cltObj.closeFiles()
|
|
|
cl_templ.closeFiles()
|
|
|
return True
|
|
|
|
|
|
|
|
|
class CommonLink():
|
|
|
"""
|
|
|
Объект-связка объектов тип Install,Client,Action с Common объектом
|
|
|
"""
|
|
|
com = None
|
|
|
|
|
|
@staticmethod
|
|
|
def link_object(source, target):
|
|
|
for fn in (x for x in dir(CoreWsdl.Common) if not x.startswith("_")):
|
|
|
if hasattr(source, fn):
|
|
|
setattr(target, fn, getattr(source, fn))
|
|
|
|
|
|
def set_link(self, com):
|
|
|
"""
|
|
|
Установить связь с Common объектом
|
|
|
"""
|
|
|
self.com = com
|
|
|
self.link_object(com, self)
|
|
|
|
|
|
|
|
|
class ActionError(Exception):
|
|
|
pass
|
|
|
|
|
|
|
|
|
class Tasks():
|
|
|
"""
|
|
|
Класс для создания проверок необходимости запуска задачи в зависимости
|
|
|
от результатра работы предыдущих задач
|
|
|
"""
|
|
|
|
|
|
def __init__(self, check):
|
|
|
self.check = check
|
|
|
|
|
|
def __call__(self, result, all_result):
|
|
|
return self.check(result, all_result)
|
|
|
|
|
|
def __or__(self, y):
|
|
|
return Tasks(lambda result, all_result: self(result, all_result) or y(result, all_result))
|
|
|
|
|
|
def __ror__(self, y):
|
|
|
return Tasks(lambda result, all_result: y(result, all_result) or self(result, all_result))
|
|
|
|
|
|
def __and__(self, y):
|
|
|
return Tasks(lambda result, all_result: self(result, all_result) and y(result, all_result))
|
|
|
|
|
|
def __rand__(self, y):
|
|
|
return Tasks(lambda result, all_result: y(result, all_result) and self(result, all_result))
|
|
|
|
|
|
def __invert__(self):
|
|
|
return Tasks(lambda result, all_result: not self(result, all_result))
|
|
|
|
|
|
@classmethod
|
|
|
def _result(self, result, all_result):
|
|
|
return result
|
|
|
|
|
|
@classmethod
|
|
|
def success_all(cls, *tasks):
|
|
|
"""
|
|
|
Все указанные задачи выполнены и выполнены без ошибок
|
|
|
"""
|
|
|
return cls(
|
|
|
lambda *args: all(x in cls._result(*args) and cls._result(*args)[x] for x in tasks))
|
|
|
|
|
|
@classmethod
|
|
|
def success_one_of(cls, *tasks):
|
|
|
"""
|
|
|
Хотя бы одна из задач выполнена и хотя бы одна из выполненных без ошибок
|
|
|
"""
|
|
|
return cls(
|
|
|
lambda *args: any(cls._result(*args)[x] for x in tasks if x in cls._result(*args)))
|
|
|
|
|
|
@classmethod
|
|
|
def success(cls, inessential=()):
|
|
|
"""
|
|
|
Все ранее запущенные задачи успешно завершены, результат задач
|
|
|
inessential не важен
|
|
|
"""
|
|
|
return cls(lambda *args: all(cls._result(*args)[x] for x in cls._result(*args)
|
|
|
if x not in inessential))
|
|
|
|
|
|
@classmethod
|
|
|
def failed(cls, inessential=()):
|
|
|
"""
|
|
|
Хотя бы одна из задач завершилась неудачно, результат задач
|
|
|
inessential не важен
|
|
|
"""
|
|
|
return cls(lambda *args: any(not cls._result(*args)[x] for x in cls._result(*args)
|
|
|
if x not in inessential))
|
|
|
|
|
|
@classmethod
|
|
|
def failed_all(cls, *tasks):
|
|
|
"""
|
|
|
Выполнена хотя бы одна задача и все те, которые выполнены с ошибкой
|
|
|
"""
|
|
|
def not_empty_all(l):
|
|
|
l = list(l)
|
|
|
return bool(l and all(l))
|
|
|
return cls(
|
|
|
lambda *args: not_empty_all(not cls._result(*args)[x] for x in tasks if x in cls._result(*args)))
|
|
|
|
|
|
@classmethod
|
|
|
def failed_one_of(cls, *tasks):
|
|
|
"""
|
|
|
Хотя бы одна из указанных задач выполнена и выполнена с ошибкой
|
|
|
"""
|
|
|
return cls(
|
|
|
lambda *args: any(x in cls._result(*args) and not cls._result(*args)[x] for x in tasks))
|
|
|
|
|
|
@classmethod
|
|
|
def has(cls, *tasks):
|
|
|
"""
|
|
|
Был запуск всех перечисленных задач
|
|
|
"""
|
|
|
return cls(lambda *args: all(x in cls._result(*args) for x in tasks))
|
|
|
|
|
|
@classmethod
|
|
|
def hasnot(cls, *tasks):
|
|
|
"""
|
|
|
Не было запуска ни одной из перечисленных задач
|
|
|
"""
|
|
|
return cls(lambda *args: all(x not in cls._result(*args) for x in tasks))
|
|
|
|
|
|
@classmethod
|
|
|
def result(cls, task, eq=None, ne=None):
|
|
|
if eq:
|
|
|
wrapper = lambda *args: task in cls._result(*args) and cls._result(*args)[task] == eq
|
|
|
elif ne:
|
|
|
wrapper = lambda *args: task not in cls._result(*args) or cls._result(*args)[task] != ne
|
|
|
else:
|
|
|
wrapper = lambda *args: task in cls._result(*args) and cls._result(*args)[task]
|
|
|
return cls(wrapper)
|
|
|
|
|
|
@classmethod
|
|
|
def has_any(cls, *tasks):
|
|
|
"""
|
|
|
Был запуск любой из задач
|
|
|
"""
|
|
|
return cls(lambda *args: any(x in cls._result(*args) for x in tasks))
|
|
|
|
|
|
|
|
|
class AllTasks(Tasks):
|
|
|
@classmethod
|
|
|
def _result(cls, result, all_result):
|
|
|
return all_result
|
|
|
|
|
|
class Action(MethodsInterface):
|
|
|
"""
|
|
|
Класс для реализации выполнения действия
|
|
|
# default = {'depend':Tasks.success(),
|
|
|
# # прятать вывод
|
|
|
# 'hideout':False,
|
|
|
# # задача важна, в случае False результат
|
|
|
# # не сохраняется в self.result
|
|
|
# 'essential':True}
|
|
|
"""
|
|
|
eachvar = None
|
|
|
|
|
|
# список выполняемых задач
|
|
|
tasks = []
|
|
|
# список исключений, которые выводятся в сокращенном формате
|
|
|
# (ожидаемые ошибки)
|
|
|
# остальные выводятся с именем модуля и номером строки
|
|
|
native_error = ()
|
|
|
|
|
|
# сообщение об удачном завершении действия
|
|
|
successMessage = None
|
|
|
# сообщение при ошибке
|
|
|
failedMessage = None
|
|
|
# сообщение о прерывании
|
|
|
interruptMessage = None
|
|
|
|
|
|
# добавить стандартные сообщения в конце
|
|
|
finishMessage = True
|
|
|
|
|
|
def __init__(self):
|
|
|
if self.finishMessage:
|
|
|
tasks = []
|
|
|
if self.failedMessage:
|
|
|
tasks.append(
|
|
|
# вывести сообщение в случае ошибки
|
|
|
{'name': 'failed',
|
|
|
'error': self.failedMessage,
|
|
|
'depend': (Tasks.failed() & Tasks.hasnot("interrupt"))})
|
|
|
if self.successMessage:
|
|
|
tasks.append(
|
|
|
# вывести сообщение в случае успеха
|
|
|
{'name': 'success',
|
|
|
'message': self.successMessage,
|
|
|
'depend': (Tasks.success() & Tasks.hasnot("failed"))})
|
|
|
if self.interruptMessage:
|
|
|
tasks.append(
|
|
|
# вывести сообщение о том, что действие прервано
|
|
|
{'name': 'intmessage',
|
|
|
'error': self.interruptMessage,
|
|
|
'depend': (Tasks.has("interrupt"))})
|
|
|
self.tasks = self.tasks + tasks
|
|
|
self.group_name = ""
|
|
|
self.clVars = None
|
|
|
|
|
|
@classmethod
|
|
|
def program(cls, progName):
|
|
|
"""
|
|
|
Проверить наличие программы
|
|
|
"""
|
|
|
return lambda dv: bool(getProgPath(progName))
|
|
|
|
|
|
@classmethod
|
|
|
def packageInstalled(cls, pkg):
|
|
|
"""
|
|
|
Проверить было ли обновление пакета
|
|
|
"""
|
|
|
return lambda dv: False
|
|
|
|
|
|
@classmethod
|
|
|
def variables(cls, *varnames):
|
|
|
"""
|
|
|
Передать переменные как аргументы, поддерживается True,False
|
|
|
"""
|
|
|
return lambda dv: [dv.Get(x) if x not in (True, False) else x
|
|
|
for x in varnames]
|
|
|
|
|
|
reMethod = re.compile("^([A-Za-z]+)\.([A-Za-z0-9_]+)\(([^)]*)\)$")
|
|
|
reMessageVars = re.compile("\{([^}]+)\}")
|
|
|
|
|
|
def parseMethod(self, objs, dv, s, task):
|
|
|
"""
|
|
|
Разобрать строку метода, на объект, метод, аргументы
|
|
|
"""
|
|
|
result = self.reMethod.search(s)
|
|
|
if not result:
|
|
|
raise ActionError(_("Wrong method for task %s") % task)
|
|
|
objname, methodname, args = result.groups()
|
|
|
if objname not in objs:
|
|
|
raise ActionError(_("Object %s not found") % objname)
|
|
|
obj = objs[objname]
|
|
|
if not hasattr(obj, methodname):
|
|
|
raise ActionError(_("Method {method} for {obj} not found").
|
|
|
format(method=methodname, obj=objname))
|
|
|
|
|
|
def _convertMethodArg(param):
|
|
|
"""
|
|
|
Конвертировать аргумент для метода, взять по словарю,
|
|
|
либо строка - имя переменной
|
|
|
"""
|
|
|
param = param.strip()
|
|
|
mapstd = {'True': True,
|
|
|
'False': False,
|
|
|
'None': None,
|
|
|
'""': "",
|
|
|
"''": ""}
|
|
|
if param in mapstd:
|
|
|
return mapstd[param]
|
|
|
if param.isdigit():
|
|
|
return int(param)
|
|
|
if param.startswith('"') and param.endswith('"'):
|
|
|
return param.strip('"')
|
|
|
if param == 'eachvar':
|
|
|
return self.eachvar
|
|
|
_type = dv.getInfo(param).type
|
|
|
if _type == "int":
|
|
|
return dv.GetInteger(param)
|
|
|
if _type in ("bool", "boolauto"):
|
|
|
return dv.GetBool(param)
|
|
|
return dv.Get(param)
|
|
|
|
|
|
if args:
|
|
|
args = [_convertMethodArg(x) for x in args.split(',')]
|
|
|
else:
|
|
|
args = ()
|
|
|
return getattr(obj, methodname), args
|
|
|
|
|
|
def formatMessage(self, dv, message):
|
|
|
"""
|
|
|
Вставить значения переменных в текст сообщения
|
|
|
"""
|
|
|
|
|
|
class TextTrasformer():
|
|
|
|
|
|
@staticmethod
|
|
|
def first_letter_upper(s):
|
|
|
return "%s%s" % (s[0].upper(), s[1:])
|
|
|
|
|
|
tt = TextTrasformer()
|
|
|
|
|
|
def replace_value(match):
|
|
|
var = match.group(1)
|
|
|
if ":" in var:
|
|
|
var, func = var.split(':')
|
|
|
else:
|
|
|
func = None
|
|
|
if var == "eachvar":
|
|
|
val = self.eachvar
|
|
|
else:
|
|
|
val = dv.Get(var)
|
|
|
if type(val) in (list, tuple):
|
|
|
val = ", ".join(val)
|
|
|
if func:
|
|
|
if hasattr(tt, func):
|
|
|
val = getattr(tt, func)(val)
|
|
|
else:
|
|
|
val = getattr(val, func)()
|
|
|
return "{0}".format(val)
|
|
|
|
|
|
return self.reMessageVars.sub(replace_value, str(message))
|
|
|
|
|
|
def runCondition(self, func_condition):
|
|
|
"""
|
|
|
Запустить метод проверки условия (если аргумент называется Get,
|
|
|
то передавать в него не объект DataVars а метод Get,
|
|
|
если у нет аргументов, то не передавать туда аргументы
|
|
|
"""
|
|
|
args = []
|
|
|
arg_count = func_condition.__code__.co_argcount
|
|
|
for param_name in func_condition.__code__.co_varnames[:arg_count]:
|
|
|
if param_name in ('Get', 'GetBool', 'Select', 'ZipVars'):
|
|
|
args.append(getattr(self.clVars, param_name))
|
|
|
elif param_name == 'eachvar':
|
|
|
args.append(self.eachvar)
|
|
|
else:
|
|
|
args.append(self.clVars)
|
|
|
return func_condition(*args)
|
|
|
|
|
|
def getFormatMessage(self, action, *fields):
|
|
|
"""
|
|
|
Получить сообщение для вывода среди нескольких с приоритетом и
|
|
|
метод вывода
|
|
|
"""
|
|
|
for field in (x for x in fields if x in action):
|
|
|
if "error" in field:
|
|
|
print_func = self.printERROR
|
|
|
elif "warning" in field:
|
|
|
print_func = self.printWARNING
|
|
|
else:
|
|
|
print_func = self.printSUCCESS
|
|
|
return print_func, self.formatMessage(self.clVars, action[field])
|
|
|
return None, None
|
|
|
|
|
|
def get_tasks(self, tasks, result, all_result):
|
|
|
"""
|
|
|
Герератор задач (поддержка линейной обработки задач в группах)
|
|
|
"""
|
|
|
for task in tasks:
|
|
|
if "group" in task or "tasks" in task:
|
|
|
if all(self.get_condition_context(task, result,
|
|
|
all_result).values()):
|
|
|
self.group_name = task.get("group", "")
|
|
|
if "while" in task:
|
|
|
depend = task.get("while", [])
|
|
|
depend = (depend
|
|
|
if type(depend) in (list, tuple) else [depend])
|
|
|
depend.append(~Tasks.has_any("interrupt"))
|
|
|
while all([x(result, all_result) for x in depend]):
|
|
|
for action in self.get_tasks(task["tasks"],
|
|
|
result, all_result):
|
|
|
yield action
|
|
|
else:
|
|
|
for action in self.get_tasks(task["tasks"], result,
|
|
|
all_result):
|
|
|
yield action
|
|
|
if not self.group_name:
|
|
|
self.endGroup()
|
|
|
else:
|
|
|
self.group_name = ""
|
|
|
else:
|
|
|
yield task
|
|
|
|
|
|
def get_condition_context(self, action, result, all_result):
|
|
|
"""
|
|
|
Получить результаты проверки по зависимосятм и условиям
|
|
|
"""
|
|
|
group, op, name = action.get("name",
|
|
|
"<unknown>").rpartition(':')
|
|
|
# проверить по результатам
|
|
|
# если указанно группа к имени с '!', то проверяется
|
|
|
# только условие принадлежности задачи к группе
|
|
|
if group and group.endswith('!'):
|
|
|
group = group.strip('!')
|
|
|
depend = [Tasks.success_all(group)]
|
|
|
else:
|
|
|
depend = action.get("depend", Tasks.success())
|
|
|
depend = (depend
|
|
|
if type(depend) in (list, tuple) else [depend])
|
|
|
if group:
|
|
|
depend.append(Tasks.success_all(group))
|
|
|
depend_result = all([x(result, all_result) for x in depend])
|
|
|
# проверить по условиям
|
|
|
if depend_result:
|
|
|
condition_funcs = action.get("condition", lambda dv: True)
|
|
|
condition_funcs = (condition_funcs
|
|
|
if type(condition_funcs) in (list, tuple)
|
|
|
else [condition_funcs])
|
|
|
condition_result = all(
|
|
|
[self.runCondition(x) for x in condition_funcs])
|
|
|
else:
|
|
|
condition_result = True
|
|
|
return {'condition': condition_result, 'depend': depend_result}
|
|
|
|
|
|
def run(self, objs, dv):
|
|
|
"""Запустить список действий"""
|
|
|
|
|
|
class StubLogger():
|
|
|
def info(self, s):
|
|
|
pass
|
|
|
|
|
|
result = {}
|
|
|
all_result = {}
|
|
|
|
|
|
self.group_name = ""
|
|
|
self.clVars = dv
|
|
|
if dv.Get('cl_env_debug_set') == 'off' or \
|
|
|
dv.Get('cl_root_readonly') == 'on' or \
|
|
|
dv.Get('cl_ebuild_phase') or os.getuid():
|
|
|
logger = StubLogger()
|
|
|
else:
|
|
|
logger = log("core-action.log",
|
|
|
filename="/var/log/calculate/core-action.log",
|
|
|
formatter="%(asctime)s - %(levelname)s - %(message)s")
|
|
|
for obj in objs.values():
|
|
|
obj.set_link(self)
|
|
|
obj.clVars = dv
|
|
|
if hasattr(obj, "init"):
|
|
|
obj.init()
|
|
|
try:
|
|
|
self.beginFrame()
|
|
|
logger.info("Start {methodname}".format(
|
|
|
methodname=self.method_name))
|
|
|
for action in self.get_tasks(self.tasks, result, all_result):
|
|
|
foreach = action.get("foreach", "")
|
|
|
if foreach:
|
|
|
foreach = self.clVars.Get(foreach)
|
|
|
else:
|
|
|
foreach = [""]
|
|
|
self.eachvar = ""
|
|
|
for eachvar in foreach:
|
|
|
self.eachvar = eachvar
|
|
|
group, op, name = action.get("name",
|
|
|
"<unknown>").rpartition(':')
|
|
|
res = True
|
|
|
task = False
|
|
|
self.clVars.Set('cl_task_name', name, force=True)
|
|
|
try:
|
|
|
run_context = self.get_condition_context(action, result,
|
|
|
all_result)
|
|
|
actinfo = "Run" if all(run_context.values()) else "Skip"
|
|
|
logger.info(
|
|
|
"{action} {name}: condition: {condition}, "
|
|
|
"depend: {depend}".format(
|
|
|
action=actinfo,
|
|
|
name=name,
|
|
|
condition=run_context['condition'],
|
|
|
depend=run_context['depend']))
|
|
|
|
|
|
elsePrint, elseMessage = (
|
|
|
self.getFormatMessage(action, "else_error",
|
|
|
"else_warning",
|
|
|
"else_message"))
|
|
|
if (run_context['depend'] and
|
|
|
not run_context['condition'] and elseMessage):
|
|
|
if "else_error" in action:
|
|
|
all_result[name] = False
|
|
|
if action.get("essential", True):
|
|
|
result[name] = False
|
|
|
elsePrint(elseMessage)
|
|
|
if all(run_context.values()):
|
|
|
self.writeFile()
|
|
|
if self.group_name:
|
|
|
self.startGroup(str(self.group_name))
|
|
|
self.group_name = None
|
|
|
printFunc, message = self.getFormatMessage(
|
|
|
action, "error", "warning", "message")
|
|
|
if "confirm" in action and message:
|
|
|
all_result[name] = \
|
|
|
self.askConfirm(str(message),
|
|
|
action["confirm"])
|
|
|
result[name] = all_result[name]
|
|
|
continue
|
|
|
elif message:
|
|
|
# если действие с командой
|
|
|
if ("error" not in action and
|
|
|
"method" in action or
|
|
|
"command" in action):
|
|
|
self.startTask(str(message))
|
|
|
task = True
|
|
|
# действие содержит только сообщение
|
|
|
else:
|
|
|
if "error" in action:
|
|
|
res = False
|
|
|
printFunc(message)
|
|
|
# запустить метод объекта
|
|
|
if "method" in action:
|
|
|
try:
|
|
|
method, args = self.parseMethod(
|
|
|
objs, dv, action["method"], name)
|
|
|
if "decoration" in action:
|
|
|
decfunc, decargs = self.parseMethod(
|
|
|
objs, dv, action["decoration"],
|
|
|
name)
|
|
|
method = decfunc(*decargs)(method)
|
|
|
res = method(*args)
|
|
|
if res is None:
|
|
|
res = False
|
|
|
except CriticalError as e:
|
|
|
self.printERROR(str(e))
|
|
|
self.endFrame()
|
|
|
return False
|
|
|
except self.native_error as e:
|
|
|
if action.get('essential', True):
|
|
|
printerror = self.printERROR
|
|
|
else:
|
|
|
printerror = self.printWARNING
|
|
|
if hasattr(e, "addon") and e.addon:
|
|
|
printerror(str(e.addon))
|
|
|
printerror(str(e))
|
|
|
res = False
|
|
|
except Exception:
|
|
|
error = shortTraceback(*sys.exc_info())
|
|
|
self.printERROR(error)
|
|
|
res = False
|
|
|
# запустить системную команду
|
|
|
if "command" in action:
|
|
|
hideout = action.get("hideout", False)
|
|
|
cmdParam = [x.strip('"\'') for x
|
|
|
in re.findall('["\'][^"\']+["\']|\S+', action["command"])]
|
|
|
cmd = processProgress(*cmdParam)
|
|
|
for line in cmd.progress():
|
|
|
if not hideout:
|
|
|
self.printSUCCESS(line)
|
|
|
if cmd.failed():
|
|
|
lineCmd = cmd.pipe.stderr.read().split('\n')
|
|
|
for line in (x for x in lineCmd if x):
|
|
|
self.printERROR(line)
|
|
|
res = cmd.success()
|
|
|
all_result[name] = res
|
|
|
if action.get("essential", True):
|
|
|
result[name] = res
|
|
|
failedPrint, failedMessage = (
|
|
|
self.getFormatMessage(action, "failed_error",
|
|
|
"failed_warning",
|
|
|
"failed_message"))
|
|
|
if not res and failedPrint:
|
|
|
failedPrint(failedMessage)
|
|
|
if task and res in (True, False, "skip"):
|
|
|
self.endTask(res)
|
|
|
logger.info("{name}: Result is {result}".format(
|
|
|
name=name, result=res))
|
|
|
if res is True:
|
|
|
on_success = action.get('on_success', None)
|
|
|
if on_success:
|
|
|
on_success()
|
|
|
# else:
|
|
|
# print "[-] Skip ",name
|
|
|
except KeyboardInterrupt:
|
|
|
all_result[name] = False
|
|
|
if action.get("essential", True):
|
|
|
result[name] = False
|
|
|
self.endTask(False)
|
|
|
self.printWARNING(_("Task interrupted"))
|
|
|
all_result["interrupt"] = False
|
|
|
result["interrupt"] = False
|
|
|
logger.info("{name}: Interrupeted".format(name=name))
|
|
|
except self.native_error as e:
|
|
|
if action.get('essential', True):
|
|
|
printerror = self.printERROR
|
|
|
else:
|
|
|
printerror = self.printWARNING
|
|
|
if hasattr(e, "addon") and e.addon:
|
|
|
printerror(str(e.addon))
|
|
|
printerror(str(e))
|
|
|
result[name] = False
|
|
|
all_result[name] = False
|
|
|
logger.info("{name}: Native error".format(name=name))
|
|
|
except CriticalError as e:
|
|
|
self.printERROR(str(e))
|
|
|
self.endFrame()
|
|
|
return False
|
|
|
except BaseException as e:
|
|
|
result[name] = False
|
|
|
all_result[name] = False
|
|
|
error = shortTraceback(*sys.exc_info())
|
|
|
self.printERROR("%s:%s" % (name, error))
|
|
|
logger.info("{name}: Unknown exception {exp}".format(
|
|
|
name=name, exp=e.__class__.__name__))
|
|
|
finally:
|
|
|
dv.close()
|
|
|
self.endFrame()
|
|
|
if any(x in ("failed", "interrupt") for x in result):
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
# Never used. Why do we need it?
|
|
|
# def commonView(self, sid, params, arg):
|
|
|
# dv = self.get_cache(sid, arg, "vars")
|
|
|
# if not dv:
|
|
|
# dv = getattr(self, "%s_vars" % arg)()
|
|
|
# else:
|
|
|
# dv.processRefresh()
|
|
|
# view = ViewInfo(dv, viewparams=params)
|
|
|
# self.set_cache(sid, arg, "vars", dv, smart=False)
|
|
|
# return view
|
|
|
|
|
|
|
|
|
def catchExcept(*skipException):
|
|
|
class wrapper:
|
|
|
def __init__(self, f_static):
|
|
|
f = f_static.__func__
|
|
|
self.f = f
|
|
|
self.__name__ = f.__name__
|
|
|
self.__code__ = f.__code__
|
|
|
self.__doc__ = f.__doc__
|
|
|
self.__name__ = f.__name__
|
|
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
|
try:
|
|
|
return self.f(*args, **kwargs)
|
|
|
except BaseException as e:
|
|
|
from calculate.core.server.api_types import ViewInfo, \
|
|
|
GroupField, Field
|
|
|
|
|
|
if isinstance(e, KeyboardInterrupt):
|
|
|
error = _("Task interrupted")
|
|
|
else:
|
|
|
error = str(e)
|
|
|
view = ViewInfo(groups=[])
|
|
|
group = GroupField(name=_("Error"), last=True)
|
|
|
group.fields = []
|
|
|
group.fields.append(Field(
|
|
|
name="error",
|
|
|
label=error,
|
|
|
default='color:red;',
|
|
|
element="error"))
|
|
|
view.groups.append(group)
|
|
|
|
|
|
if not any(isinstance(e, x)
|
|
|
for x in chain(skipException, (KeyboardInterrupt,))):
|
|
|
print(shortTraceback(*sys.exc_info()))
|
|
|
|
|
|
return view
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
def shortTraceback(e1, e2, e3):
|
|
|
"""
|
|
|
Return short traceback
|
|
|
"""
|
|
|
frame = e3
|
|
|
for i in traceback.format_exception(*(e1, e2, e3)):
|
|
|
print(i, end=' ')
|
|
|
while frame.tb_next:
|
|
|
frame = frame.tb_next
|
|
|
module, part = os.path.split(frame.tb_frame.f_code.co_filename)
|
|
|
if part.endswith('.py'):
|
|
|
part = part[:-3]
|
|
|
fallbackmod = part
|
|
|
modname = [part]
|
|
|
while module != '/' and not module.endswith('site-packages'):
|
|
|
module, part = os.path.split(module)
|
|
|
modname.insert(0, part)
|
|
|
if module.endswith('site-packages'):
|
|
|
modname = ".".join(modname)
|
|
|
else:
|
|
|
modname = fallbackmod
|
|
|
return "%s:%s(%s:%s)" % (e1.__name__, str(e2), modname, frame.tb_lineno)
|
|
|
|
|
|
|
|
|
class ActiveClientStatus():
|
|
|
Success = 0
|
|
|
Failed = 1
|
|
|
WrongSID = 2
|
|
|
|
|
|
|
|
|
class CoreWsdl(CoreServiceInterface):
|
|
|
# client signals about presence
|
|
|
@staticmethod
|
|
|
def active_clients(cls, sid):
|
|
|
# curThread = threading.currentThread()
|
|
|
# REMOTE_ADDR = curThread.REMOTE_ADDR
|
|
|
|
|
|
#why is this here?
|
|
|
# cls.get_lang(cls, sid, "from active clients")
|
|
|
if 0 < sid < cls.max_sid:
|
|
|
try:
|
|
|
# open file its session
|
|
|
sid_file = cls.sids + "/%d.sid" % sid
|
|
|
if not os.path.isfile(sid_file):
|
|
|
return ActiveClientStatus.Failed
|
|
|
# check sid in sid.db
|
|
|
if not (os.path.isfile(cls.sids_file) and
|
|
|
cls.find_sid_in_file(cls, sid)):
|
|
|
try:
|
|
|
os.unlink(sid_file)
|
|
|
except (OSError, IOError):
|
|
|
pass
|
|
|
return ActiveClientStatus.Failed
|
|
|
with cls.sid_locker:
|
|
|
with open(sid_file, "rb") as fd:
|
|
|
# read information about session
|
|
|
sid_inf = pickle.load(fd)
|
|
|
# reset counters
|
|
|
sid_inf[1] = 0
|
|
|
sid_inf[2] = 0
|
|
|
fd.close()
|
|
|
if not os.path.isfile(sid_file):
|
|
|
return ActiveClientStatus.Failed
|
|
|
fd = open(sid_file, "wb")
|
|
|
pickle.dump(sid_inf, fd)
|
|
|
fd.close()
|
|
|
return ActiveClientStatus.Success
|
|
|
except Exception:
|
|
|
return ActiveClientStatus.Failed
|
|
|
else:
|
|
|
return ActiveClientStatus.WrongSID
|
|
|
|
|
|
@staticmethod
|
|
|
def serv_get_methods(cls, client_type):
|
|
|
curThread = threading.currentThread()
|
|
|
certificate = curThread.client_cert
|
|
|
from .cert_cmd import find_cert_id
|
|
|
|
|
|
cert_id = find_cert_id(certificate, cls.data_path, cls.certbase)
|
|
|
|
|
|
rights = cls.serv_view_cert_right(cert_id, cls.data_path, client_type)
|
|
|
return_list = []
|
|
|
if client_type == "console":
|
|
|
for meth in cls.return_conMethod():
|
|
|
right_flag = True
|
|
|
for right in LoadedMethods.rightsMethods[meth[1]]:
|
|
|
if right not in rights:
|
|
|
right_flag = False
|
|
|
if right_flag:
|
|
|
return_list.append(meth)
|
|
|
if not len(return_list):
|
|
|
return [['0', '0']]
|
|
|
return return_list
|
|
|
else:
|
|
|
for meth in cls.return_guiMethod():
|
|
|
right_flag = True
|
|
|
for right in LoadedMethods.rightsMethods[meth[1]]:
|
|
|
if right not in rights:
|
|
|
right_flag = False
|
|
|
if right_flag:
|
|
|
return_list.append(meth)
|
|
|
if not len(return_list):
|
|
|
return [['0', '0']]
|
|
|
return return_list
|
|
|
|
|
|
# return a list of methods for the console as list
|
|
|
@staticmethod
|
|
|
def return_conMethod():
|
|
|
from .loaded_methods import LoadedMethods
|
|
|
|
|
|
results = []
|
|
|
for item in LoadedMethods.conMethods:
|
|
|
temp = [item]
|
|
|
for i in LoadedMethods.conMethods[item]:
|
|
|
temp.append(i)
|
|
|
results.append(temp)
|
|
|
return results
|
|
|
|
|
|
# return a list of methods for the GUI as list
|
|
|
@staticmethod
|
|
|
def return_guiMethod():
|
|
|
from .loaded_methods import LoadedMethods
|
|
|
results = []
|
|
|
dv = DataVars()
|
|
|
dv.importVariables()
|
|
|
|
|
|
for item in LoadedMethods.guiMethods:
|
|
|
for i in range(0, len(LoadedMethods.guiMethods[item]), 4):
|
|
|
if LoadedMethods.guiMethods[item][i + 3]:
|
|
|
method_on = LoadedMethods.guiMethods[item][i + 3](dv.Get)
|
|
|
else:
|
|
|
method_on = True
|
|
|
if method_on:
|
|
|
temp = [item]
|
|
|
for j in range(3):
|
|
|
temp.append(LoadedMethods.guiMethods[item][i + j])
|
|
|
results.append(temp)
|
|
|
dv.close()
|
|
|
return results
|
|
|
|
|
|
# get available sessions
|
|
|
@staticmethod
|
|
|
def serv_get_sessions(cls):
|
|
|
result = []
|
|
|
fd = open(cls.sids_file, 'rb')
|
|
|
while 1:
|
|
|
try:
|
|
|
# read all on one record
|
|
|
list_sid = pickle.load(fd)
|
|
|
except (KeyError, IOError, EOFError):
|
|
|
break
|
|
|
# if session id found
|
|
|
result.append(str(list_sid[0]))
|
|
|
fd.close()
|
|
|
return result
|
|
|
|
|
|
# check client alive
|
|
|
@staticmethod
|
|
|
def client_alive(cls, sid, SIDS_DIR):
|
|
|
sid_path = SIDS_DIR + "/%d.sid" % sid
|
|
|
if not os.path.isfile(sid_path):
|
|
|
return 1
|
|
|
with cls.sid_locker:
|
|
|
with open(sid_path, "rb") as fd:
|
|
|
# read information about session
|
|
|
sid_inf = pickle.load(fd)
|
|
|
# flag absence client
|
|
|
fd.close()
|
|
|
if sid_inf[2] == 1:
|
|
|
return 0
|
|
|
else:
|
|
|
return 1
|
|
|
|
|
|
class Common(CommonMethods, MethodsInterface):
|
|
|
""" class to interact with the processes """
|
|
|
|
|
|
def __init__(self, process_dict, progress_dict, table_dict,
|
|
|
frame_list, pid):
|
|
|
self.process_dict = process_dict
|
|
|
self.progress_dict = progress_dict
|
|
|
self.progress_dict['id'] = 0
|
|
|
self.table_dict = table_dict
|
|
|
self.frame_list = frame_list
|
|
|
self.pid = pid
|
|
|
self.Num = 100000
|
|
|
|
|
|
def pauseProcess(self):
|
|
|
from calculate.core.server.gen_pid import ProcessStatus
|
|
|
|
|
|
self.method_status = ProcessStatus.Paused
|
|
|
self.writeFile()
|
|
|
|
|
|
def resumeProcess(self):
|
|
|
from calculate.core.server.gen_pid import ProcessStatus
|
|
|
|
|
|
self.method_status = ProcessStatus.Worked
|
|
|
self.writeFile()
|
|
|
|
|
|
def writeFile(self):
|
|
|
""" write data in file """
|
|
|
from .baseClass import Basic
|
|
|
from calculate.core.server.gen_pid import ProcessMode
|
|
|
|
|
|
if not os.path.exists(Basic.pids):
|
|
|
makeDirectory(Basic.pids)
|
|
|
build_id = ""
|
|
|
try:
|
|
|
from calculate.builder.variables.action import Actions
|
|
|
|
|
|
if self.clVars.Get('cl_action') in Actions.All:
|
|
|
build_id = self.clVars.Get('builder.cl_builder_id')
|
|
|
except Exception as e:
|
|
|
if isinstance(e, KeyboardInterrupt):
|
|
|
raise
|
|
|
|
|
|
pid_file = path.join(Basic.pids, '%d.pid' % self.pid)
|
|
|
try:
|
|
|
with open(pid_file, 'wb') as f:
|
|
|
d = {'name': self.process_dict['method_name'],
|
|
|
'mode': ProcessMode.CoreDaemon,
|
|
|
'os_pid': os.getpid(),
|
|
|
'status': self.process_dict['status'],
|
|
|
'id': build_id
|
|
|
}
|
|
|
pickle.dump(d, f)
|
|
|
except (IOError, OSError) as e:
|
|
|
print(str(e))
|
|
|
print(_("Failed to write the PID file %s!") % pid_file)
|
|
|
|
|
|
def setProgress(self, perc, short_message=None, long_message=None):
|
|
|
try:
|
|
|
id = self.progress_dict['id']
|
|
|
self.progress_dict[id] = ReturnProgress(perc, short_message,
|
|
|
long_message)
|
|
|
except IOError:
|
|
|
pass
|
|
|
|
|
|
def setStatus(self, stat):
|
|
|
self.process_dict['status'] = stat
|
|
|
|
|
|
def setData(self, dat):
|
|
|
self.data_list = dat
|
|
|
|
|
|
def getStatus(self):
|
|
|
try:
|
|
|
return self.process_dict['status']
|
|
|
except IOError:
|
|
|
return -1
|
|
|
|
|
|
def getProgress(self):
|
|
|
try:
|
|
|
id = self.progress_dict['id']
|
|
|
if id in self.progress_dict:
|
|
|
return self.progress_dict[id].percent
|
|
|
except IOError:
|
|
|
pass
|
|
|
return 0
|
|
|
|
|
|
def getAnswer(self):
|
|
|
import time
|
|
|
|
|
|
while self.process_dict['answer'] is None:
|
|
|
time.sleep(0.5)
|
|
|
res = self.process_dict['answer']
|
|
|
self.process_dict['answer'] = None
|
|
|
self.frame_list.pop(len(self.frame_list) - 1)
|
|
|
self.process_dict['counter'] -= 1
|
|
|
return res
|
|
|
|
|
|
def addProgress(self, message=""):
|
|
|
id = random.randint(1, self.Num)
|
|
|
while id in self.progress_dict:
|
|
|
id = random.randint(1, self.Num)
|
|
|
self.progress_dict['id'] = id
|
|
|
self.progress_dict[id] = ReturnProgress(0, '', '')
|
|
|
self.addMessage(message_type='progress', id=id)
|
|
|
|
|
|
def printTable(self, table_name, head, body, fields=None,
|
|
|
onClick=None, addAction=None, step=None,
|
|
|
records=None):
|
|
|
id = random.randint(1, self.Num)
|
|
|
while id in self.table_dict:
|
|
|
id = random.randint(1, self.Num)
|
|
|
|
|
|
from .api_types import Table
|
|
|
|
|
|
table = Table(head=head, body=[[str(y) for y in x] for x in body],
|
|
|
fields=fields,
|
|
|
onClick=onClick, addAction=addAction, step=step,
|
|
|
values=None, records=records)
|
|
|
self.table_dict[id] = table
|
|
|
self.addMessage(message_type='table', message=table_name, id=id)
|
|
|
|
|
|
def addMessage(self, message_type='normal', message=None, id=None,
|
|
|
onlyShow='', default=None):
|
|
|
from .api_types import Message
|
|
|
|
|
|
re_clean = re.compile('\[(?:\d+;)?\d+m')
|
|
|
messageObj = Message(
|
|
|
message_type=message_type,
|
|
|
message=(
|
|
|
None if message in (None, True, False)
|
|
|
# else re_clean.sub('', [x for x in message if x >= ' '])),
|
|
|
else re_clean.sub('', message)),
|
|
|
result=message if message in (True, False) else None,
|
|
|
id=id, onlyShow=onlyShow, default=default)
|
|
|
try:
|
|
|
self.frame_list.append(messageObj)
|
|
|
except BaseException as e:
|
|
|
if isinstance(e, KeyboardInterrupt):
|
|
|
raise
|
|
|
print(_(("%s:" % message_type) + str(message)))
|
|
|
|
|
|
def dropProgress(self):
|
|
|
perc = self.getProgress()
|
|
|
if perc == 0:
|
|
|
self.setProgress(100)
|
|
|
elif self.getProgress() > 0:
|
|
|
self.setProgress(0 - self.getProgress())
|
|
|
else:
|
|
|
# self.setProgress(-100)
|
|
|
self.setProgress(perc)
|
|
|
|
|
|
def printSUCCESS(self, message='', onlyShow=None):
|
|
|
self.dropProgress()
|
|
|
self.addMessage(message_type='normal', message=message,
|
|
|
onlyShow=onlyShow)
|
|
|
|
|
|
def printPre(self, message='', onlyShow=None):
|
|
|
self.dropProgress()
|
|
|
self.addMessage(message_type='pre', message=message,
|
|
|
onlyShow=onlyShow)
|
|
|
|
|
|
def printDefault(self, message='', onlyShow=None):
|
|
|
self.dropProgress()
|
|
|
self.addMessage(message_type='plain', message=message,
|
|
|
onlyShow=onlyShow)
|
|
|
|
|
|
def printWARNING(self, message, onlyShow=None):
|
|
|
self.dropProgress()
|
|
|
self.addMessage(message_type='warning', message=message,
|
|
|
onlyShow=onlyShow)
|
|
|
|
|
|
def printERROR(self, message='', onlyShow=None):
|
|
|
self.dropProgress()
|
|
|
self.addMessage(message_type='error', message=message,
|
|
|
onlyShow=onlyShow)
|
|
|
|
|
|
def startTask(self, message, progress=False, num=1):
|
|
|
if progress:
|
|
|
self.addMessage(message_type='startTask', message=message, id=num)
|
|
|
self.addProgress()
|
|
|
else:
|
|
|
self.addMessage(message_type='startTask', message=message, id=num)
|
|
|
|
|
|
def setTaskNumber(self, number=None):
|
|
|
self.addMessage(message_type='taskNumber', message=str(number))
|
|
|
|
|
|
def endTask(self, result=None, progress_message=None):
|
|
|
self.addMessage(message_type='endTask', message=result)
|
|
|
self.setProgress(100, progress_message)
|
|
|
|
|
|
def askConfirm(self, message, default="yes"):
|
|
|
self.addMessage(message_type='confirm', message=message, default=default)
|
|
|
ret = self.getAnswer()
|
|
|
if ret == "":
|
|
|
return default
|
|
|
return ret
|
|
|
|
|
|
def isInteractive(self):
|
|
|
return True
|
|
|
|
|
|
def askChoice(self, message, answers=(("yes", "Yes"), ("no", "No"))):
|
|
|
self.addMessage(message_type='choice', message="%s|%s" % (
|
|
|
message,
|
|
|
",".join(("%s(%s)" % (x[0], x[1]) for x in answers))))
|
|
|
return self.getAnswer()
|
|
|
|
|
|
def askQuestion(self, message):
|
|
|
self.addMessage(message_type='question', message=message)
|
|
|
return self.getAnswer()
|
|
|
|
|
|
def askPassword(self, message, twice=False):
|
|
|
pas_repeat = 2 if twice else 1
|
|
|
self.addMessage(message_type='password', message=message,
|
|
|
id=pas_repeat)
|
|
|
return self.getAnswer()
|
|
|
|
|
|
def beginFrame(self, message=None):
|
|
|
self.addMessage(message_type='beginFrame', message=message)
|
|
|
|
|
|
def endFrame(self):
|
|
|
self.addMessage(message_type='endFrame')
|
|
|
|
|
|
def startGroup(self, message):
|
|
|
self.addMessage(message_type='startGroup', message=message)
|
|
|
|
|
|
def endGroup(self):
|
|
|
self.addMessage(message_type='endGroup')
|
|
|
|
|
|
# def cache(self, param):
|
|
|
# sid = self.process_dict['sid']
|
|
|
# self.args[sid] = collections.OrderedDict()
|
|
|
|
|
|
@staticmethod
|
|
|
def startprocess(cls, sid, target=None, method=None, method_name=None,
|
|
|
auto_delete=False, args_proc=()):
|
|
|
""" start process """
|
|
|
pid = cls.gen_pid(cls)
|
|
|
cls.add_sid_pid(cls, sid, pid)
|
|
|
|
|
|
import multiprocessing
|
|
|
|
|
|
if cls.manager is None:
|
|
|
cls.manager = multiprocessing.Manager()
|
|
|
|
|
|
|
|
|
# Manager for sending glob_process_dict between watcher and process
|
|
|
# manager = multiprocessing.Manager()
|
|
|
cls.glob_process_dict[pid] = cls.manager.dict()
|
|
|
cls.glob_process_dict[pid]['sid'] = sid
|
|
|
cls.glob_process_dict[pid]['status'] = 0
|
|
|
cls.glob_process_dict[pid]['time'] = ""
|
|
|
cls.glob_process_dict[pid]['answer'] = None
|
|
|
cls.glob_process_dict[pid]['name'] = ""
|
|
|
cls.glob_process_dict[pid]['flag'] = 0
|
|
|
cls.glob_process_dict[pid]['counter'] = 0
|
|
|
|
|
|
cls.glob_frame_list[pid] = cls.manager.list()
|
|
|
cls.glob_progress_dict[pid] = cls.manager.dict()
|
|
|
cls.glob_table_dict[pid] = cls.manager.dict()
|
|
|
|
|
|
# create object Common and send parameters
|
|
|
com = target(cls.glob_process_dict[pid],
|
|
|
cls.glob_progress_dict[pid],
|
|
|
cls.glob_table_dict[pid],
|
|
|
cls.glob_frame_list[pid], pid)
|
|
|
|
|
|
|
|
|
if len(com.__class__.__bases__) > 1 and \
|
|
|
hasattr(com.__class__.__bases__[1], '__init__'):
|
|
|
com.__class__.__bases__[1].__init__(com)
|
|
|
# start helper
|
|
|
com.method_name = method_name
|
|
|
p = multiprocessing.Process(target=cls.target_helper,
|
|
|
args=(cls, com, getattr(com, method)) +
|
|
|
(method_name,) + args_proc)
|
|
|
|
|
|
cls.process_pid[pid] = p
|
|
|
p.start()
|
|
|
if auto_delete:
|
|
|
# start watcher (for kill process on signal)
|
|
|
watcher = threading.Thread(target=cls.watcher_pid_proc,
|
|
|
args=(cls, sid, pid))
|
|
|
|
|
|
watcher.start()
|
|
|
return str(pid)
|
|
|
|
|
|
# wrap all method
|
|
|
@staticmethod
|
|
|
def target_helper(cls, com, target_proc, method_name, *args_proc):
|
|
|
if not os.path.exists(cls.pids):
|
|
|
os.system('mkdir %s' % cls.pids)
|
|
|
# PID_FILE = cls.pids + '/%d.pid'%com.pid
|
|
|
import datetime
|
|
|
|
|
|
dat = datetime.datetime.now()
|
|
|
|
|
|
com.process_dict['status'] = 1
|
|
|
com.process_dict['time'] = dat
|
|
|
# if method_name:
|
|
|
com.process_dict['method_name'] = method_name
|
|
|
com.process_dict['name'] = target_proc.__func__.__name__
|
|
|
|
|
|
try:
|
|
|
result = target_proc(*args_proc)
|
|
|
except Exception:
|
|
|
result = False
|
|
|
print_exc()
|
|
|
fd = open(cls.log_filename, 'a')
|
|
|
print_exc(file=fd)
|
|
|
fd.close()
|
|
|
try:
|
|
|
if result is True:
|
|
|
com.setStatus(0)
|
|
|
com.writeFile()
|
|
|
elif result is False:
|
|
|
if com.getStatus() == 1:
|
|
|
com.setStatus(2)
|
|
|
com.writeFile()
|
|
|
else:
|
|
|
if com.getStatus() == 1:
|
|
|
com.setStatus(2)
|
|
|
else:
|
|
|
com.setStatus(0)
|
|
|
com.writeFile()
|
|
|
try:
|
|
|
if 0 < com.getProgress() < 100:
|
|
|
com.setProgress(0 - com.getProgress())
|
|
|
if len(com.frame_list):
|
|
|
last_message = com.frame_list[len(com.frame_list) - 1]
|
|
|
if last_message.type != 'endFrame':
|
|
|
com.endFrame()
|
|
|
else:
|
|
|
com.endFrame()
|
|
|
except IOError:
|
|
|
pass
|
|
|
|
|
|
except Exception:
|
|
|
print_exc()
|
|
|
fd = open(cls.log_filename, 'a')
|
|
|
print_exc(file=fd)
|
|
|
fd.close()
|
|
|
com.endFrame()
|
|
|
|
|
|
def serv_view_cert_right(cls, cert_id, data_path, client_type=None):
|
|
|
""" rights for the selected certificate """
|
|
|
try:
|
|
|
cert_id = int(cert_id)
|
|
|
except ValueError:
|
|
|
return ["-2"]
|
|
|
cert_file = data_path + '/client_certs/%s.crt' % str(cert_id)
|
|
|
if not os.path.exists(cert_file):
|
|
|
return ["-1"]
|
|
|
cert = readFile(cert_file)
|
|
|
|
|
|
# try:
|
|
|
import OpenSSL
|
|
|
|
|
|
certobj = OpenSSL.crypto.load_certificate(
|
|
|
OpenSSL.SSL.FILETYPE_PEM, cert)
|
|
|
com = certobj.get_extension(
|
|
|
certobj.get_extension_count() - 1).get_data()
|
|
|
groups = com.split(b':')[1].decode("UTF-8")
|
|
|
groups_list = groups.split(',')
|
|
|
# except:
|
|
|
# return ['-1']
|
|
|
results = []
|
|
|
find_flag = False
|
|
|
# if group = all and not redefined group all
|
|
|
if 'all' in groups_list:
|
|
|
fd = open(cls.group_rights, 'r')
|
|
|
t = fd.read()
|
|
|
# find all in group_rights file
|
|
|
for line in t.splitlines():
|
|
|
if not line:
|
|
|
continue
|
|
|
if line.split()[0] == 'all':
|
|
|
find_flag = True
|
|
|
break
|
|
|
if not find_flag:
|
|
|
result = []
|
|
|
if client_type == 'console':
|
|
|
for meth_list in cls.return_conMethod():
|
|
|
for right in LoadedMethods.rightsMethods[meth_list[1]]:
|
|
|
result.append(right)
|
|
|
else:
|
|
|
for meth_list in cls.return_guiMethod():
|
|
|
for right in LoadedMethods.rightsMethods[meth_list[1]]:
|
|
|
result.append(right)
|
|
|
result = uniq(result)
|
|
|
results = result
|
|
|
|
|
|
if 'all' not in groups_list or find_flag:
|
|
|
if not os.path.exists(cls.group_rights):
|
|
|
open(cls.group_rights, 'w').close()
|
|
|
with open(cls.group_rights) as fd:
|
|
|
t = fd.read()
|
|
|
for line in t.splitlines():
|
|
|
if not line:
|
|
|
continue
|
|
|
try:
|
|
|
words = line.split(' ', 1)
|
|
|
if len(words) < 2:
|
|
|
continue
|
|
|
# first word in line equal name input method
|
|
|
if words[0] in groups_list:
|
|
|
methods = words[1].split(',')
|
|
|
for i in methods:
|
|
|
results.append(i.strip())
|
|
|
except IndexError:
|
|
|
print('except IndexError in serv_view_cert_right')
|
|
|
continue
|
|
|
results = uniq(results)
|
|
|
|
|
|
add_list_rights = []
|
|
|
del_list_rights = []
|
|
|
|
|
|
with open(cls.rights) as fr:
|
|
|
t = fr.read()
|
|
|
for line in t.splitlines():
|
|
|
words = line.split()
|
|
|
meth = words[0]
|
|
|
for word in words:
|
|
|
try:
|
|
|
word = int(word)
|
|
|
except ValueError:
|
|
|
continue
|
|
|
# compare with certificat number
|
|
|
if cert_id == word:
|
|
|
# if has right
|
|
|
add_list_rights.append(meth)
|
|
|
if cert_id == -word:
|
|
|
del_list_rights.append(meth)
|
|
|
|
|
|
results += add_list_rights
|
|
|
results = uniq(results)
|
|
|
|
|
|
for method in results:
|
|
|
if method in del_list_rights:
|
|
|
results.remove(method)
|
|
|
|
|
|
if not results:
|
|
|
results.append("No Methods")
|
|
|
return results
|
|
|
|
|
|
@staticmethod
|
|
|
def get_lang(cls, sid, method_name=""):
|
|
|
""" get clients lang """
|
|
|
|
|
|
|
|
|
lang = None
|
|
|
SIDS_DIR = cls.sids
|
|
|
with cls.sid_locker:
|
|
|
|
|
|
sid_file = SIDS_DIR + "/%d.sid" % int(sid)
|
|
|
if os.path.exists(sid_file):
|
|
|
# fd = open(sid_file, 'r')
|
|
|
|
|
|
with open(sid_file, 'rb') as fd:
|
|
|
try:
|
|
|
list_sid = pickle.load(fd)
|
|
|
list_sid_sid = int(list_sid[0])
|
|
|
if sid == list_sid_sid:
|
|
|
# print("SID FOUND")
|
|
|
lang = list_sid[3]
|
|
|
except IOError:
|
|
|
print("some io error")
|
|
|
pass
|
|
|
except KeyError:
|
|
|
print("Key error")
|
|
|
pass
|
|
|
except EOFError:
|
|
|
print("EOF error")
|
|
|
pass
|
|
|
try:
|
|
|
# print(lang)
|
|
|
if lang.lower() not in ('uk', 'fr', 'ru', 'en'):
|
|
|
lang = "en"
|
|
|
except AttributeError:
|
|
|
# print("Attr error")
|
|
|
lang = "en"
|
|
|
import locale
|
|
|
|
|
|
try:
|
|
|
lang = locale.locale_alias[lang.lower()]
|
|
|
# print("lang got from locale: %s" % lang)
|
|
|
except (TypeError, AttributeError, IndexError, KeyError):
|
|
|
lang = locale.locale_alias['en']
|
|
|
# print("Setting lang: %s " % lang)
|
|
|
return lang
|
|
|
|
|
|
|
|
|
def create_symlink(data_path, old_data_path):
|
|
|
meths = LoadedMethods.conMethods
|
|
|
path_to_link = '/usr/bin'
|
|
|
core_wrapper = "/usr/libexec/calculate/cl-core-wrapper"
|
|
|
#path_to_user_link = '/usr/bin'
|
|
|
old_symlinks_file = os.path.join(old_data_path, 'conf/symlinks')
|
|
|
symlinks_file = os.path.join(data_path, 'conf/symlinks')
|
|
|
if not os.path.exists(os.path.join(data_path, 'conf')):
|
|
|
try:
|
|
|
os.makedirs(os.path.join(data_path, 'conf'))
|
|
|
except OSError:
|
|
|
print (_("cannot create directory %s")
|
|
|
% (os.path.join(data_path, 'conf')))
|
|
|
if os.path.exists(old_symlinks_file) and not os.path.exists(symlinks_file):
|
|
|
with open(symlinks_file, 'w') as fd:
|
|
|
fd.write(readFile(old_symlinks_file))
|
|
|
os.unlink(old_symlinks_file)
|
|
|
with open(symlinks_file, 'a') as fd:
|
|
|
for link in meths:
|
|
|
link_path = os.path.join(path_to_link, link)
|
|
|
if os.path.islink(link_path):
|
|
|
continue
|
|
|
if os.path.isfile(link_path):
|
|
|
red = '\033[31m * \033[0m'
|
|
|
print(red + link_path + _(' is a file, not a link!'))
|
|
|
continue
|
|
|
try:
|
|
|
if (os.path.islink(link_path) and
|
|
|
os.readlink(link_path) != core_wrapper):
|
|
|
os.unlink(link_path)
|
|
|
os.symlink(core_wrapper, link_path)
|
|
|
fd.write(link_path + '\n')
|
|
|
except OSError as e:
|
|
|
print(e)
|
|
|
print(_('Symlink %s created') % link_path)
|
|
|
|
|
|
temp_text_file = ''
|
|
|
for line in readLinesFile(symlinks_file):
|
|
|
cmdname = os.path.basename(line)
|
|
|
if cmdname not in meths.keys() or not line.startswith(path_to_link):
|
|
|
if os.path.islink(line):
|
|
|
os.unlink(line)
|
|
|
print(_('Symlink %s deleted') % line)
|
|
|
else:
|
|
|
temp_text_file += line + '\n'
|
|
|
fd = open(symlinks_file, 'w')
|
|
|
fd.write(temp_text_file)
|
|
|
fd.close()
|
|
|
|
|
|
|
|
|
def initialization(cl_wsdl):
|
|
|
""" find modules for further added in server class """
|
|
|
cl_apis = []
|
|
|
for pack in cl_wsdl:
|
|
|
if pack:
|
|
|
module_name = '%s.wsdl_%s' % (pack.replace("-", "."),
|
|
|
pack.rpartition("-")[2])
|
|
|
import importlib
|
|
|
|
|
|
cl_wsdl_core = importlib.import_module(module_name)
|
|
|
try:
|
|
|
cl_apis.append(cl_wsdl_core.Wsdl)
|
|
|
except ImportError:
|
|
|
sys.stderr.write(_("Unable to import %s") % module_name)
|
|
|
return cl_apis
|
|
|
|
|
|
|
|
|
# Creation of secret key of the client
|
|
|
def new_key_req(key, cert_path, serv_host_name, port):
|
|
|
from .create_cert import (generateRSAKey, makePKey, makeRequest,
|
|
|
passphrase_callback)
|
|
|
|
|
|
rsa = generateRSAKey()
|
|
|
rsa.save_key(key + '_pub', cipher=None, callback=passphrase_callback)
|
|
|
|
|
|
pkey = makePKey(rsa)
|
|
|
pkey.save_key(key, cipher=None, callback=passphrase_callback)
|
|
|
|
|
|
req = makeRequest(rsa, pkey, serv_host_name, port)
|
|
|
if not req:
|
|
|
sys.exit()
|
|
|
crtreq = req.as_pem()
|
|
|
crtfile = open(cert_path + '/server.csr', 'w')
|
|
|
crtfile.write(crtreq)
|
|
|
crtfile.close()
|
|
|
|
|
|
|
|
|
# delete dublicate from list
|
|
|
def uniq(seq):
|
|
|
seen = set()
|
|
|
seen_add = seen.add
|
|
|
return [x for x in seq if x not in seen and not seen_add(x)]
|
|
|
|
|
|
|
|
|
class WsdlMeta(type):
|
|
|
"""
|
|
|
Метакласс для создания методов по атрибуту methdos
|
|
|
"""
|
|
|
datavars = {}
|
|
|
|
|
|
def __new__(mcs, name, bases, attrs):
|
|
|
if "methods" in attrs:
|
|
|
for method in attrs["methods"]:
|
|
|
attrs[method['method_name']] = mcs.caller_constructor(**method)
|
|
|
attrs["%s_vars" % method[
|
|
|
'method_name']] = mcs.datavars_constructor(**method)
|
|
|
attrs["%s_view"
|
|
|
% method['method_name']] = mcs.view_constructor(**method)
|
|
|
return type.__new__(mcs, name, bases, attrs)
|
|
|
|
|
|
@classmethod
|
|
|
def close_datavars(mcs):
|
|
|
for dv in WsdlMeta.datavars.values():
|
|
|
dv.close()
|
|
|
|
|
|
@classmethod
|
|
|
def create_info_obj(mcs, **kwargs):
|
|
|
"""
|
|
|
Создание передаваемой структуры данных для WSDL
|
|
|
"""
|
|
|
def type_convert(s):
|
|
|
if "bool3" in s:
|
|
|
return String
|
|
|
if "bool" in s:
|
|
|
return Boolean
|
|
|
elif "table" in s:
|
|
|
return Array(Array(String))
|
|
|
elif "list" in s:
|
|
|
return Array(String)
|
|
|
else:
|
|
|
return String
|
|
|
|
|
|
d = {}
|
|
|
d["cl_console_args"] = Array(String)
|
|
|
if kwargs['datavars'] in WsdlMeta.datavars:
|
|
|
dv = WsdlMeta.datavars[kwargs['datavars']]
|
|
|
else:
|
|
|
dv = DataVars()
|
|
|
dv.importVariables()
|
|
|
dv.importVariables('calculate.%s.variables' % kwargs['datavars'])
|
|
|
dv.defaultModule = kwargs['datavars']
|
|
|
WsdlMeta.datavars[kwargs['datavars']] = dv
|
|
|
|
|
|
def group(*args, **kwargs):
|
|
|
for v in chain(kwargs.get('normal', ()), kwargs.get('expert', ())):
|
|
|
varname = v.rpartition(".")[2]
|
|
|
d[varname] = type_convert(dv.getInfo(v).type)
|
|
|
|
|
|
for gr in kwargs['groups']:
|
|
|
gr(group)
|
|
|
# if "brief" in kwargs:
|
|
|
#if "cl_page_count" not in d:
|
|
|
if True:
|
|
|
d["CheckOnly"] = Boolean
|
|
|
return d
|
|
|
|
|
|
@classmethod
|
|
|
def caller_constructor(mcs, **kwargs):
|
|
|
"""
|
|
|
Конструктор для создания метода-вызова для действия
|
|
|
"""
|
|
|
# @staticmethod
|
|
|
def wrapper(cls, sid, info):
|
|
|
# костыль для локализации install
|
|
|
callback_refresh = (
|
|
|
cls.fixInstallLocalization
|
|
|
if kwargs['method_name'] == 'install' else lambda cls, dv, sid: True)
|
|
|
return cls.callAction(cls, sid, info, logicClass=kwargs['logic'],
|
|
|
actionClass=kwargs['action'],
|
|
|
method_name=kwargs['method_name'],
|
|
|
callbackRefresh=callback_refresh,
|
|
|
invalidators=kwargs.get('invalidators', None)
|
|
|
)
|
|
|
|
|
|
wrapper.__name__ = kwargs['method_name']
|
|
|
wrapper = staticmethod(wrapper)
|
|
|
func = LoadedMethods.core_method(category=kwargs.get('category', None),
|
|
|
title=kwargs['title'],
|
|
|
image=kwargs.get('image', None),
|
|
|
gui=kwargs['gui'],
|
|
|
user=kwargs.get('user', False),
|
|
|
command=kwargs.get('command', None),
|
|
|
rights=kwargs['rights'],
|
|
|
depends=kwargs.get('depends', ()),
|
|
|
static_method=True)(
|
|
|
wrapper)
|
|
|
if "--start" in sys.argv:
|
|
|
info_obj = mcs.create_info_obj(**kwargs)
|
|
|
info_class = type("%sInfo" % kwargs["method_name"], (CommonInfo,),
|
|
|
info_obj)
|
|
|
|
|
|
#total hack: carry over info_class for later use
|
|
|
func.__func__.info_class = info_class
|
|
|
# return func
|
|
|
# else:
|
|
|
return func
|
|
|
|
|
|
@classmethod
|
|
|
def modify_datavars(mcs, dv, data):
|
|
|
"""
|
|
|
Поменять значения в datavars согласно data
|
|
|
"""
|
|
|
# установить заданные значения (!) принудительная установка
|
|
|
for k, v in data.items():
|
|
|
# если значение функция
|
|
|
if callable(v):
|
|
|
v = v(dv)
|
|
|
else:
|
|
|
if isinstance(v, (str)):
|
|
|
v = Variable._value_formatter.format(v, dv.Get)
|
|
|
dv.Set(k.strip('!'), v, force=k.endswith('!'))
|
|
|
|
|
|
@classmethod
|
|
|
def view_constructor(mcs, **kwargs):
|
|
|
"""
|
|
|
Конструктор для создания метода-представления
|
|
|
"""
|
|
|
# @staticmethod
|
|
|
def wrapper(cls, sid, params):
|
|
|
dv = cls.get_cache(sid, kwargs["method_name"], "vars")
|
|
|
lang_changed = False
|
|
|
if kwargs["groups"]:
|
|
|
def group(*args, **kwargs):
|
|
|
if isinstance(kwargs.get('normal', ()), (str)):
|
|
|
raise DataVarsError(_("Wrong normal varaiables list"))
|
|
|
if isinstance(kwargs.get('expert', ()), (str)):
|
|
|
raise DataVarsError(_("Wrong expert varaiables list"))
|
|
|
|
|
|
for gr in kwargs['groups']:
|
|
|
gr(group)
|
|
|
if not dv:
|
|
|
dv = getattr(cls, "%s_vars" % kwargs["method_name"])(cls,
|
|
|
params=params)
|
|
|
# print("got dv from cls: %s" % dv)
|
|
|
if hasattr(params, "clienttype"):
|
|
|
if params.clienttype == 'gui' and "guivars" in kwargs:
|
|
|
mcs.modify_datavars(dv, kwargs['guivars'])
|
|
|
if params.clienttype != 'gui' and "consolevars" in kwargs:
|
|
|
mcs.modify_datavars(dv, kwargs['consolevars'])
|
|
|
dv.Set('main.cl_client_type', params.clienttype, force=True)
|
|
|
else:
|
|
|
# костыль для метода install, который меняет локализацию
|
|
|
# интрефейса в зависимости от выбранного параметра lang
|
|
|
# print("dv groups: %s" % bool(dv.getGroups()))
|
|
|
if kwargs["method_name"] == 'install':
|
|
|
lang_changed = cls.fixInstallLocalization(cls, sid, dv)
|
|
|
lang = dv.Get('install.os_install_locale_lang')
|
|
|
cls.set_cache(sid, "install", "lang", lang, smart=False)
|
|
|
# print("dv before refresh groups: %s" % bool(dv.getGroups()))
|
|
|
dv.processRefresh()
|
|
|
# print("dv after refresh groups: %s" % bool(dv.getGroups()))
|
|
|
|
|
|
cls.set_cache(sid, kwargs["method_name"], "vars", dv, smart=False)
|
|
|
if "brief" in kwargs and "name" in kwargs['brief']:
|
|
|
brief_label = str(kwargs['brief']['name'])
|
|
|
else:
|
|
|
brief_label = None
|
|
|
|
|
|
if kwargs["groups"]:
|
|
|
# print("group view info creation")
|
|
|
# print(params)
|
|
|
# print(dv)
|
|
|
# print(brief_label)
|
|
|
# print(dv.getGroups())
|
|
|
# print("dv groups: %s" % bool(dv.getGroups()))
|
|
|
view = ViewInfo(dv, viewparams=params,
|
|
|
has_brief="brief" in kwargs,
|
|
|
allsteps=lang_changed,
|
|
|
brief_label=brief_label)
|
|
|
else:
|
|
|
# print("creating empty viewInfo")
|
|
|
view = ViewInfo()
|
|
|
return view
|
|
|
|
|
|
wrapper.__name__ = "%s_view" % kwargs['method_name']
|
|
|
wrapper = staticmethod(wrapper)
|
|
|
|
|
|
return catchExcept(kwargs.get("native_error", ()))(wrapper)
|
|
|
|
|
|
@classmethod
|
|
|
def datavars_constructor(mcs, **kwargs):
|
|
|
"""
|
|
|
Конструктор для создания метода описания параметров
|
|
|
"""
|
|
|
@staticmethod
|
|
|
def wrapper(cls, dv=None, params=None):
|
|
|
if not dv:
|
|
|
_dv = DataVars()
|
|
|
_dv.importVariables()
|
|
|
_dv.importVariables(
|
|
|
'calculate.%s.variables' % kwargs['datavars'])
|
|
|
_dv.defaultModule = kwargs['datavars']
|
|
|
_dv.flIniFile()
|
|
|
if params and params.help_set:
|
|
|
_dv.Set('cl_help_set', "on", force=True)
|
|
|
if params and params.dispatch_usenew:
|
|
|
_dv.Set('cl_dispatch_conf', "usenew", force=True)
|
|
|
if params:
|
|
|
if params.conargs:
|
|
|
conargs = list(params.conargs)
|
|
|
else:
|
|
|
conargs = []
|
|
|
if params.dispatch_usenew:
|
|
|
conargs.append("--force")
|
|
|
_dv.Set('cl_console_args', conargs, force=True)
|
|
|
else:
|
|
|
_dv = dv
|
|
|
# созданием группы переменных из datavars согласно параметрам groups
|
|
|
for groupfunc in kwargs['groups']:
|
|
|
groupfunc(_dv.addGroup)
|
|
|
if not dv:
|
|
|
mcs.modify_datavars(_dv, kwargs['setvars'])
|
|
|
# указание brief если нужно
|
|
|
if "brief" in kwargs:
|
|
|
_dv.addBrief(
|
|
|
next_label=str(kwargs['brief'].get('next', _('Next'))),
|
|
|
image=kwargs['brief'].get('image', None))
|
|
|
return _dv
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
class WsdlBase(metaclass=WsdlMeta):
|
|
|
"""
|
|
|
Базовый класс для автосоздания методов по описанию methods
|
|
|
"""
|
|
|
# __metaclass__ = WsdlMeta
|
|
|
|
|
|
|
|
|
def clearDataVars(func):
|
|
|
def wrapper(*args, **kwargs):
|
|
|
try:
|
|
|
return func(*args, **kwargs)
|
|
|
finally:
|
|
|
WsdlMeta.close_datavars()
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
class CustomButton():
|
|
|
@classmethod
|
|
|
def sort_argv(cls, args):
|
|
|
behavior = []
|
|
|
condition = None
|
|
|
for arg in args:
|
|
|
if callable(arg):
|
|
|
condition = arg
|
|
|
else:
|
|
|
behavior.append(arg)
|
|
|
return (behavior or None), condition
|
|
|
|
|
|
@classmethod
|
|
|
def run_method(cls, method_name, id, label, *args):
|
|
|
behavior, condition = cls.sort_argv(args)
|
|
|
return id, label, method_name, "button", behavior, condition
|
|
|
|
|
|
@classmethod
|
|
|
def open_method(cls, method_name, id, label, *args):
|
|
|
behavior, condition = cls.sort_argv(args)
|
|
|
return id, label, method_name, "button_view", behavior, condition
|
|
|
|
|
|
@classmethod
|
|
|
def next_button(cls, id=None, label=None):
|
|
|
return id, label, None, "button_next"
|
|
|
|
|
|
class Behavior():
|
|
|
@classmethod
|
|
|
def link(cls, source=None, target=None):
|
|
|
return "%s=%s" % (target, source)
|
|
|
|
|
|
@classmethod
|
|
|
def linkerror(cls, source=None, target=None):
|
|
|
return "%s->%s" % (source, target)
|
|
|
|
|
|
@classmethod
|
|
|
def setvalue(cls, variable=None, value=None):
|
|
|
return "%s!=%s" % (variable, value)
|
|
|
|