Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

5724 Zeilen
250 KiB

  1. #-*- coding: utf-8 -*-
  2. # Copyright 2008-2010 Calculate Ltd. http://www.calculate-linux.org
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import sys
  16. import os
  17. import stat
  18. import re
  19. import xml.dom.minidom
  20. import xml
  21. if hasattr(xml,"use_pyxml"):
  22. xml.use_pyxml()
  23. from xml import xpath
  24. import subprocess
  25. import types
  26. import random
  27. import string
  28. import time
  29. import glob
  30. import fcntl
  31. # < <= == != >= >
  32. from operator import lt, le, eq, ne, ge, gt
  33. # Переопределение exit
  34. import cl_overriding
  35. from cl_utils import _error, _warning, _toUNICODE, getModeFile, removeDir,\
  36. typeFile, scanDirectory, convertStrListDict, pathJoin
  37. import cl_lang
  38. tr = cl_lang.lang()
  39. tr.setLocalDomain('cl_lib')
  40. tr.setLanguage(sys.modules[__name__])
  41. class _shareTermsFunction:
  42. """Общие аттрибуты для классов _terms и templateFunctions"""
  43. # Символы допустимые в скобках функции шаблона
  44. _reFunctionArgvInSquareBrackets = "a-zA-Z0-9_:;\-\+\,\*\/\.\'\"~\\\\ "
  45. _reFunctionArgvText = "[%s]"%_reFunctionArgvInSquareBrackets
  46. # регулярное выражение для поиска функции в шаблоне
  47. _reFunctionText = "([a-zA-Z0-9\_\-]+)\((%s+|)\)" %_reFunctionArgvText
  48. class _terms(_error, _shareTermsFunction):
  49. """Вычисление условий применяемых в шаблонах
  50. """
  51. # регулярное выражение для поиска функции в шаблоне
  52. _reFunction = re.compile(_shareTermsFunction._reFunctionText)
  53. # регулярное выражение для не версии
  54. _re_not_Version = re.compile("[^0-9\.]")
  55. # регулярное выражение не номер
  56. _re_not_Number = re.compile("[^0-9]")
  57. _suffixDict = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
  58. _lenSuffixDict = len(_suffixDict)
  59. # Регулярное выражение для названия переменной
  60. _reDenyName = re.compile("[^a-zA-Z0-9\_\-]")
  61. # Регулярное выражение для сравниваемого значения
  62. _reDenyValue = re.compile("[^0-9a-zA-Z_/\.-]")
  63. # латинские буквы в нижнем регистре
  64. _letters = list(string.ascii_lowercase)
  65. def _splitVersion(self, strVersion):
  66. """
  67. Split version. Version, addition letter, list suffixes with version,
  68. revision.
  69. Examples:
  70. 2.2.30
  71. ("2.2.30","",[],"")
  72. 2.2.30-r1
  73. ("2.2.30","",[],"r1")
  74. 2.2.30a-r1
  75. ("2.2.30","a",[],"r1")
  76. 2.2.30a_rc1-r1
  77. ("2.2.30","a",[("rc","1")],"r1")
  78. 2.2.30a_rc1_p20111212-r1
  79. ("2.2.30","a",[("rc1","1"),("p","20111212")],"r1")
  80. """
  81. # get revision from version
  82. strWorkVersion, spl, rVersion = strVersion.rpartition("-")
  83. if rVersion == strVersion:
  84. strWorkVersion = rVersion
  85. rVersion = ""
  86. suffixes = []
  87. # get suffixes from version
  88. while "_" in strWorkVersion:
  89. # 2.3_p45 ('2.3','_','p43')
  90. # 2.3_rc4_p45 ('2.3_rc4','_','p43')
  91. strWorkVersion, spl, suffix = strWorkVersion.rpartition("_")
  92. suffSplList = filter(lambda x: suffix.startswith(x),
  93. self._suffixDict.keys())
  94. if suffSplList:
  95. suffSpl = suffSplList[0]
  96. lenSuffSpl = len(suffSpl)
  97. suffixVersion = suffix[lenSuffSpl:]
  98. suffixes.append((suffSpl,suffixVersion))
  99. letters = ""
  100. numberVersion = strWorkVersion
  101. if numberVersion and numberVersion[-1:] in self._letters:
  102. letters = numberVersion[-1:]
  103. numberVersion = numberVersion[:-1]
  104. return numberVersion, letters, suffixes, rVersion
  105. def _notVersion(self, strVersion):
  106. """strVersion is not version - True"""
  107. numberVersion, letters, suffixes, rVersion =\
  108. self._splitVersion(strVersion)
  109. if not numberVersion.strip():
  110. return True
  111. if self._re_not_Version.search(numberVersion):
  112. return True
  113. if letters and not letters in self._letters:
  114. return True
  115. for suffix,suffixVersion in suffixes:
  116. if suffixVersion and self._re_not_Number.search(suffixVersion):
  117. return True
  118. if rVersion:
  119. if rVersion[0] != "r" or len(rVersion) == 1:
  120. return True
  121. if self._re_not_Number.search(rVersion[1:]):
  122. return True
  123. return False
  124. def _convertVers(self, verA, verB):
  125. """Конвертирование номеров версий для корректного сравнения
  126. """
  127. def fillZero(elemA, elemB):
  128. #elemA, elemB = elemA[], elemB[]
  129. if len(elemA) > len(elemB):
  130. maxElemB = len(elemB)-1
  131. for i in range(len(elemA)):
  132. if i > maxElemB:
  133. elemB.append("0")
  134. else:
  135. maxElemA = len(elemA)-1
  136. for i in range(len(elemB)):
  137. if i > maxElemA:
  138. elemA.append("0")
  139. for i in range(len(elemB)):
  140. lenA = len(elemA[i])
  141. lenB = len(elemB[i])
  142. if lenA == lenB:
  143. pass
  144. elif lenA > lenB:
  145. res = lenA - lenB
  146. for z in range(res):
  147. elemB[i] = "0" + elemB[i]
  148. elif lenB > lenA:
  149. res = lenB - lenA
  150. for z in range(res):
  151. elemA[i] = "0" + elemA[i]
  152. def fillSuffix(elemA,elemB,sA,svA,sB,svB):
  153. if str(sA) or str(sB):
  154. svA, svB = map(lambda x: [x] if x else ['0'], (svA, svB))
  155. fillZero(svA, svB)
  156. sA, sB = map(lambda x: x if x else 0, (sA, sB))
  157. elemA.append(str(self._lenSuffixDict + sA))
  158. elemA.extend(svA)
  159. elemB.append(str(self._lenSuffixDict + sB))
  160. elemB.extend(svB)
  161. #Version, letters, suffix, suffixVersion, rVersion
  162. vA, lA, ssA, rvA = self._splitVersion(verA)
  163. vB, lB, ssB, rvB = self._splitVersion(verB)
  164. elemA = vA.split(".")
  165. elemB = vB.split(".")
  166. fillZero(elemA, elemB)
  167. if lA or lB:
  168. lA, lB = map(lambda x: x if x else '0', (lA, lB))
  169. elemA.append(lA)
  170. elemB.append(lB)
  171. # dereferencing suffix in suffixes list
  172. ssA = map(lambda x:(self._suffixDict.get(x[0],0),x[1]),ssA)
  173. ssB = map(lambda x:(self._suffixDict.get(x[0],0),x[1]),ssB)
  174. for suffix,sufVer in reversed(ssA):
  175. if ssB:
  176. sB,svB = ssB.pop()
  177. else:
  178. sB,svB = "",""
  179. fillSuffix(elemA,elemB,suffix,sufVer,sB,svB)
  180. while ssB:
  181. sB,svB = ssB.pop()
  182. fillSuffix(elemA,elemB,"","",sB,svB)
  183. if rvA or rvB:
  184. rvA, rvB = map(lambda x: [x[1:]], (rvA, rvB))
  185. fillZero(rvA, rvB)
  186. elemA += rvA
  187. elemB += rvB
  188. return (".".join(elemA), ".".join(elemB))
  189. def _equalTerm(self, term, textError, function=False):
  190. """Вычисление логических выражений для условий
  191. Для корректной работы в классе который наследует этот класс
  192. должен быть объявлен аттрибут self.objVar
  193. (объект для работы с переменными)
  194. function - функция для для обработки функций в заголовке блока
  195. """
  196. rpl = lambda x: x.replace("@@"," ")
  197. trm = {"&&":"@@and@@","||":"@@or@@"}
  198. dictRuleFunc = {"==":eq, "!=":ne, ">=":ge, "<=":le, ">":gt, "<":lt}
  199. rule = dictRuleFunc.keys()
  200. listEqual = []
  201. for k in trm.keys():
  202. if k in term:
  203. term = term.replace(k,trm[k])
  204. trs = term.split("@@")
  205. listSplitOr = []
  206. if "or" in trs:
  207. lst = []
  208. for t in trs:
  209. if t != "or":
  210. lst.append(t)
  211. else:
  212. listSplitOr.append(lst)
  213. lst = []
  214. if lst:
  215. listSplitOr.append(lst)
  216. else:
  217. listSplitOr = [trs]
  218. for trsAnd in listSplitOr:
  219. listEqual = []
  220. for t in trsAnd:
  221. flagRule = False
  222. for sepF in rule:
  223. if sepF in t:
  224. flagRule = True
  225. vals = t.split(sepF)
  226. break
  227. if flagRule:
  228. #проверка на допустимость названия переменной
  229. flagFunction = False
  230. if self._reDenyName.search(vals[0]):
  231. #проверка на допустимость функции
  232. flagError = True
  233. if function:
  234. searchFunct = self._reFunction.search(vals[0])
  235. if searchFunct:
  236. flagError = False
  237. flagFunction = True
  238. if flagError:
  239. self.setError("'%s'"%rpl(term)+" "+ _("incorrect"))
  240. self.setError(textError)
  241. return False
  242. #проверка на допустимость значения
  243. if self._reDenyValue.search(vals[1]):
  244. self.setError("'%s'"%rpl(term) + " " + _("incorrect"))
  245. self.setError(textError)
  246. return False
  247. flagIntTypeVar = None
  248. if flagFunction:
  249. valVars = function("#-%s-#"%vals[0])
  250. if valVars is False:
  251. self.setError("'%s'"%rpl(term)+" "+ _("incorrect"))
  252. self.setError(textError)
  253. return False
  254. if "load" == searchFunct.group(1) and\
  255. re.search("\(\s*num\s*,",vals[0]):
  256. if valVars:
  257. try:
  258. valVars = int(valVars)
  259. except:
  260. self.setError("'%s'"%rpl(term) + " " + \
  261. _("incorrect"))
  262. self.setError(textError)
  263. return False
  264. flagIntTypeVar = True
  265. else:
  266. flagIntTypeVar = False
  267. else:
  268. if valVars == "" and\
  269. not self._notVersion(vals[1]):
  270. valVars = "0"
  271. elif vals[1] == "" and\
  272. not self._notVersion(valVars):
  273. vals[1] = "0"
  274. else:
  275. try:
  276. valVars = self.objVar.Get(vals[0])
  277. except self.objVar.DataVarsError, e:
  278. cl_overriding.printERROR(textError)
  279. cl_overriding.printERROR(e)
  280. cl_overriding.exit(1)
  281. # Номера версий для ini
  282. flagNotIniFunct = True
  283. # Два значения не пусты
  284. flagNotEmptyVals = not (valVars == "" and vals[1] == "")
  285. if flagFunction and flagNotEmptyVals and\
  286. searchFunct.group(1) == "ini":
  287. # Проверка значения на версию
  288. if not self._notVersion(valVars) and\
  289. not self._notVersion(vals[1]):
  290. verFile, verVar = self._convertVers(vals[1],valVars)
  291. res = dictRuleFunc[sepF](verVar,verFile)
  292. if res:
  293. listEqual.append(True)
  294. else:
  295. listEqual.append(False)
  296. break
  297. flagNotIniFunct = False
  298. # Cравниваем номера версий
  299. if flagNotIniFunct:
  300. if flagNotEmptyVals and\
  301. ("_ver" in vals[0] or\
  302. (flagFunction and searchFunct.group(1)=="pkg") or\
  303. (flagFunction and searchFunct.group(1)=="load" and\
  304. re.search("\(\s*ver\s*,",vals[0]))):
  305. # Проверка значения на версию
  306. if self._notVersion(vals[1]):
  307. self.setError("'%s'"%rpl(term)+" "+\
  308. _("incorrect"))
  309. self.setError(_("Value is not version"))
  310. return False
  311. # Проверка значения функции на версию
  312. if self._notVersion(valVars):
  313. self.setError("'%s'"%rpl(term)+" "+\
  314. _("incorrect"))
  315. self.setError(\
  316. _("Function value is not version"))
  317. return False
  318. verFile, verVar = self._convertVers(vals[1],valVars)
  319. res = dictRuleFunc[sepF](verVar,verFile)
  320. if res:
  321. listEqual.append(True)
  322. else:
  323. listEqual.append(False)
  324. break
  325. flagNotIniFunct = False
  326. else:
  327. if flagIntTypeVar is None:
  328. flagIntTypeVar = True
  329. try:
  330. valVars = int(valVars)
  331. except:
  332. flagIntTypeVar = False
  333. if flagIntTypeVar:
  334. if not vals[1].strip():
  335. vals[1] = 0
  336. try:
  337. valFile = int(vals[1])
  338. except:
  339. self.setError("'%s'"%rpl(term) +" "+\
  340. _("incorrect"))
  341. self.setError(textError)
  342. return False
  343. valVar = valVars
  344. res = dictRuleFunc[sepF](valVar, valFile)
  345. if res:
  346. listEqual.append(True)
  347. else:
  348. listEqual.append(False)
  349. break
  350. else:
  351. if sepF == "!=" or sepF == "==":
  352. if not vals[1].strip():
  353. vals[1] = ""
  354. valFile = vals[1]
  355. valVar = valVars
  356. res = dictRuleFunc[sepF](valVar, valFile)
  357. if res:
  358. listEqual.append(True)
  359. else:
  360. listEqual.append(False)
  361. break
  362. else:
  363. if not flagNotEmptyVals:
  364. listEqual.append(False)
  365. break
  366. else:
  367. self.setError("'%s'"%rpl(term) + " "\
  368. + _("incorrect"))
  369. self.setError(textError)
  370. return False
  371. else:
  372. if t == "and":
  373. if listEqual == [] or False in listEqual:
  374. listEqual = [False]
  375. break
  376. else:
  377. listEqual = [True]
  378. else:
  379. self.setError("'%s'"%rpl(term) + " " + _("incorrect"))
  380. self.setError(textError)
  381. return False
  382. if not (listEqual == [] or False in listEqual):
  383. break
  384. if listEqual == [] or False in listEqual:
  385. return False
  386. return True
  387. def splitParLine(self, linePar):
  388. '''Split params line'''
  389. def splitQuote(listPar, quoteSymbol):
  390. listTerm = map(lambda x: x+quoteSymbol, ("=",">","<"))
  391. flagQ = False
  392. mass = []
  393. v = ""
  394. for i in listPar:
  395. if i.count(quoteSymbol)==1:
  396. if flagQ and i.endswith(quoteSymbol):
  397. v = v + " " + i
  398. mass.append(v)
  399. v = ""
  400. flagQ = False
  401. elif filter(lambda x: x in i, listTerm):
  402. flagQ = True
  403. v = i
  404. else:
  405. mass.append(i)
  406. elif flagQ:
  407. v = v + " " + i
  408. else:
  409. mass.append(i)
  410. foundPar = list(set(mass)-set(listPar))
  411. return not flagQ, filter(lambda x: not x in foundPar, mass),foundPar
  412. listPar = re.split("\s+",linePar)
  413. flagFoundQ = "'" in linePar
  414. flagFoundQQ = '"' in linePar
  415. if flagFoundQ and flagFoundQQ:
  416. flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
  417. if flagQ:
  418. flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listSplQPar,
  419. '"')
  420. if flagQQ:
  421. listPar = listSplQQPar + listFoundQPar + listFoundQQPar
  422. elif flagFoundQQ:
  423. flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listPar, '"')
  424. if flagQQ:
  425. listPar = listSplQQPar + listFoundQQPar
  426. elif flagFoundQ:
  427. flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
  428. if flagQ:
  429. listPar = listSplQPar + listFoundQPar
  430. if flagFoundQ:
  431. listQPar = []
  432. for par in listPar:
  433. if par.endswith("'"):
  434. listQPar.append(par.replace("'",""))
  435. else:
  436. listQPar.append(par)
  437. listPar = listQPar
  438. if flagFoundQQ:
  439. listQQPar = []
  440. for par in listPar:
  441. if par.endswith('"'):
  442. listQQPar.append(par.replace('"',''))
  443. else:
  444. listQQPar.append(par)
  445. listPar = listQQPar
  446. return listPar
  447. class fileHeader(_terms):
  448. """Обработка заголовков шаблонов и конфигурационных файлов
  449. """
  450. # Допустимые параметры заголовка
  451. allowParam = ["format", "format_conf", "comment", "append", "force",
  452. "link", "mirror", "symbolic", "chmod", "chown", "name",
  453. "path", "autoupdate", "exec"]
  454. # Тип шаблона
  455. fileType = ""
  456. # Тип вставки шаблона
  457. typeAppend = ""
  458. # Возможные типы вставки шаблонов
  459. _fileAppend = "join", "before", "after", "replace", "remove", "skip",\
  460. "patch", "clear"
  461. # Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
  462. execStr = ""
  463. # Символ комментария
  464. comment = False
  465. # Выражение для поиска строки интерпретатора
  466. reExecStr = re.compile("^#!.+\s*",re.M)
  467. # условные операторы
  468. terms = ('>', '<', '==', '!=', '>=', '<=')
  469. # параметры без значения
  470. listParNotVal = ("symbolic", "force", "mirror", "autoupdate")
  471. # Результат вычисления условия в заголовке
  472. headerTerm = True
  473. def __init__(self, templateName, text, comment=False, fileType=False,
  474. objVar=False, function=False):
  475. self.body = text
  476. # Объект с переменными
  477. self.objVar=objVar
  478. # Параметры описанные в заголовке файла шаблона
  479. self.params = {}
  480. # некорректные параметры
  481. incorrectParams = []
  482. # Поиск строки запустка (#!/bin/bash и.т. д)
  483. if comment or fileType!="bin":
  484. reExecRes = self.reExecStr.search(self.body)
  485. if reExecRes:
  486. self.execStr = self.body[reExecRes.start():reExecRes.end()]
  487. self.body = self.body[:reExecRes.start()] +\
  488. self.body[reExecRes.end():]
  489. # Удаление Заголовка Calculate
  490. if comment:
  491. titleFirst = "Modified"
  492. # В случае текста XML
  493. if type(comment) == types.TupleType and len(comment) == 2:
  494. reCalcHeader =\
  495. re.compile("\s*%s\s+%s.+\s+(.+\n)+%s\s?"\
  496. %(comment[0], titleFirst, comment[1]),re.M|re.I)
  497. reS = reCalcHeader.search(self.body)
  498. if reS:
  499. self.body = self.body[:reS.start()]+self.body[reS.end():]
  500. else:
  501. reCalcHeader = re.compile(\
  502. "\s*%s\-+\s+%s\s+%s.+\s+(%s.+\s+)+%s\-+\s?"\
  503. %(comment, comment, titleFirst ,comment,comment),
  504. re.M|re.I)
  505. reS = reCalcHeader.search(self.body)
  506. if reS:
  507. self.body = self.body[reS.end():]
  508. if fileType != False:
  509. if fileType=="bin":
  510. self.params["format"] = fileType
  511. self.fileType = self._getType()
  512. self.typeAppend = self._getAppend()
  513. else:
  514. textLines = self.body.splitlines()
  515. if textLines:
  516. textLine = textLines[0]
  517. rePar = re.compile(\
  518. "\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
  519. reP = rePar.search(textLine)
  520. if reP:
  521. reL = False
  522. reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
  523. reLs = reLns.search(self.body)
  524. if reLs:
  525. reL = reLs
  526. paramLine = self.body[reP.end():reLs.end()]
  527. paramLine = paramLine.replace("\\"," ")
  528. else:
  529. reLn = re.compile("\n")
  530. reL = reLn.search(self.body)
  531. paramLine = textLine[reP.end():]
  532. if reL:
  533. self.body = self.body[reL.end():]
  534. else:
  535. self.body = ""
  536. paramList = self.splitParLine(paramLine)
  537. if paramList:
  538. for i in paramList:
  539. foundTerm = False
  540. for term in self.terms:
  541. if term in i:
  542. foundTerm = True
  543. errorMsg = _("Incorrect template") +\
  544. ": "+ templateName +"\n"+\
  545. _("template header not valid")+\
  546. ": "+ i
  547. if function:
  548. rezTerm = self._equalTerm(i,
  549. errorMsg,
  550. function)
  551. else:
  552. rezTerm = self._equalTerm(i,
  553. errorMsg)
  554. if not rezTerm:
  555. self.headerTerm = False
  556. break
  557. if not foundTerm:
  558. par = i.split("=")
  559. if len(par) == 1:
  560. if i in self.listParNotVal:
  561. self.params[i] = "True"
  562. else:
  563. if i.strip():
  564. incorrectParams = set([i])
  565. elif len(par) == 2:
  566. self.params[par[0]] = par[1]
  567. self.comment = self._getComment()
  568. self.fileType = self._getType()
  569. typeAppend = self._getAppend()
  570. if typeAppend:
  571. self.typeAppend = typeAppend
  572. else:
  573. self.headerTerm = False
  574. self.setError(_("incorrect header parameters - '%s'")\
  575. %"append=%s"%self.params["append"])
  576. if 'exec' in self.params:
  577. self.execStr = "#!%s"%self.params['exec']
  578. if not incorrectParams and self.params:
  579. incorrectParams = set(self.params.keys()) - set(self.allowParam)
  580. if incorrectParams:
  581. self.headerTerm = False
  582. self.setError(_("incorrect header parameters - '%s'")\
  583. %" ".join(list(incorrectParams)))
  584. def _getType(self):
  585. """Выдать тип файла"""
  586. if "format" in self.params:
  587. return self.params["format"]
  588. else:
  589. return "raw"
  590. def _getAppend(self):
  591. """Выдать тип добавления файла"""
  592. if self.params.has_key("append"):
  593. if self.params["append"] in self._fileAppend:
  594. return self.params["append"]
  595. else:
  596. return False
  597. else:
  598. if self.fileType != "raw" and self.fileType != "bin" and\
  599. self.fileType != "":
  600. if "format" in self.params and self.params["format"] == "patch":
  601. self.params["append"] = "patch"
  602. return "patch"
  603. self.params["append"] = "join"
  604. return "join"
  605. self.params["append"] = "replace"
  606. return "replace"
  607. def _getComment(self):
  608. """Выдать символ комментария файла"""
  609. if self.params.has_key("comment"):
  610. if self.params["comment"] in ("xml", "XML"):
  611. return ("<!--","-->")
  612. else:
  613. return self.params["comment"]
  614. else:
  615. return False
  616. class dirHeader(_terms):
  617. """Обработка заголовков шаблонов директорий
  618. """
  619. # Допустимые параметры заголовка
  620. allowParam = ["append", "chmod", "chown", "name", "path", "autoupdate"]
  621. # Тип вставки шаблона
  622. typeAppend = ""
  623. # Возможные типы вставки шаблонов
  624. _fileAppend = "join", "remove", "skip", "clear"
  625. # условные операторы
  626. terms = ('>', '<', '==', '!=', '>=', '<=')
  627. # параметры без значения
  628. listParNotVal = ("symbolic", "force", "autoupdate")
  629. # Результат вычисления условия в заголовке
  630. headerTerm = True
  631. def __init__(self, templateName, text, objVar=False, function=False):
  632. self.body = text
  633. # Объект с переменными
  634. self.objVar=objVar
  635. # Параметры описанные в заголовке файла шаблона
  636. self.params = {}
  637. # некорректные параметры
  638. incorrectParams = set([])
  639. textLines = text.splitlines()
  640. flagErrorBody = False
  641. if textLines:
  642. textLine = textLines[0]
  643. rePar = re.compile(\
  644. "\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$",re.I)
  645. reP = rePar.search(textLine)
  646. if reP:
  647. reL = False
  648. reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
  649. reLs = reLns.search(text)
  650. if reLs:
  651. reL = reLs
  652. paramLine = text[reP.end():reLs.end()]
  653. paramLine = paramLine.replace("\\"," ")
  654. else:
  655. reLn = re.compile("\n")
  656. reL = reLn.search(text)
  657. paramLine = textLine[reP.end():]
  658. if reL:
  659. self.body = text[reL.end():]
  660. else:
  661. self.body = ""
  662. if self.body.strip():
  663. self.headerTerm = False
  664. self.setError(_("incorrect text in template: '%s'")\
  665. %self.body)
  666. flagErrorBody = True
  667. if not flagErrorBody:
  668. paramList = self.splitParLine(paramLine)
  669. if paramList:
  670. for i in paramList:
  671. foundTerm = False
  672. for term in self.terms:
  673. if term in i:
  674. foundTerm = True
  675. errorMsg = _("Incorrect template") +\
  676. ": "+ templateName +"\n"+\
  677. _("template header not valid")+ ": "+ i
  678. if function:
  679. rezTerm = self._equalTerm(i, errorMsg,
  680. function)
  681. else:
  682. rezTerm = self._equalTerm(i, errorMsg)
  683. if not rezTerm:
  684. self.headerTerm = False
  685. break
  686. if not foundTerm:
  687. par = i.split("=")
  688. if len(par) == 1:
  689. if i in self.listParNotVal:
  690. self.params[i] = "True"
  691. else:
  692. if i.strip():
  693. incorrectParams = set([i])
  694. elif len(par) == 2:
  695. self.params[par[0]] = par[1]
  696. typeAppend = self._getAppend()
  697. if typeAppend:
  698. self.typeAppend = typeAppend
  699. else:
  700. self.headerTerm = False
  701. self.setError(_("incorrect header parameters - '%s'")\
  702. %"append=%s"%self.params["append"])
  703. if not flagErrorBody:
  704. if not incorrectParams:
  705. incorrectParams = set(self.params.keys()) - set(self.allowParam)
  706. if incorrectParams:
  707. self.headerTerm = False
  708. self.setError(_("incorrect header parameters - '%s'")\
  709. %" ".join(list(incorrectParams)))
  710. def _getAppend(self):
  711. """Выдать тип добавления директории"""
  712. if self.params.has_key("append"):
  713. if self.params["append"] in self._fileAppend:
  714. return self.params["append"]
  715. else:
  716. return False
  717. else:
  718. return "join"
  719. class objShare:
  720. """Общий клас для объектов, наследуем
  721. """
  722. def createFieldTerm(self, name, value, quote, docObj):
  723. """Создание поля переменная - значение
  724. при создании поля проверяется первый символ названия переменной
  725. и добавляется тег action
  726. "!" - <action>drop</action> удаляет
  727. "+" - <action>join</action> добавляет
  728. "-" - <action>replace</action> заменяет
  729. """
  730. fieldAction = False
  731. if name:
  732. if name[0] == "!" or name[0] == "-" or name[0] == "+":
  733. qnt = self.removeSymbolTerm(quote)
  734. fieldXML = docObj.createField("var",[qnt],
  735. name[1:], [value],
  736. False, False)
  737. if name[0] == "!":
  738. fieldAction = "drop"
  739. elif name[0] == "+":
  740. fieldXML.setAttribute("type", "seplist")
  741. fieldAction = "join"
  742. else:
  743. fieldXML = docObj.createField("var",
  744. [quote.replace("\n","")],
  745. name, [value],
  746. False, False)
  747. else:
  748. fieldXML = docObj.createField("var",
  749. [quote.replace("\n","")],
  750. name, [value],
  751. False, False)
  752. if fieldAction:
  753. docObj.setActionField(fieldXML, fieldAction)
  754. return fieldXML
  755. def removeSymbolTerm(self, text):
  756. """Удаляет первый символ названия переменной в строке
  757. Если первый встречающийся символ с начала строки
  758. '+', '-', '!' то он из этой строки будет удален,
  759. если перед этим символом были пробельные символы,
  760. то они будут сохранены, так-же если в строке есть символ
  761. перевода строки он будет удален.
  762. """
  763. reTerm = re.compile("^[ \t]*(\!|\+|\-)")
  764. textNS = text.replace("\n","")
  765. res = reTerm.search(textNS)
  766. if res:
  767. textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
  768. return textNS
  769. def getConfig(self):
  770. """Выдает конфигурационный файл"""
  771. listConfigTxt = []
  772. childNodes = self.docObj.getNodeBody().childNodes
  773. for node in childNodes:
  774. if node.nodeType == node.ELEMENT_NODE:
  775. if node.tagName == "field":
  776. listConfigTxt.append(self.docObj.getQuoteField(node))
  777. elif node.tagName == "area":
  778. self.docObj.xmlToText([node], listConfigTxt)
  779. return "".join(listConfigTxt)
  780. def splitToFields(self, txtBloc):
  781. """Разбиваем текст на поля (объекты) которые имеют следующие аттрибуты
  782. self.name - если переменная то имя переменной
  783. self.value - если у переменной есть значение то значение переменной
  784. self.comment - если комментарий то текст комментария
  785. self.br - если перевод строки то текст перед переводом из пробелов
  786. Результат список объектов полей
  787. """
  788. finBloc = "\n"
  789. if txtBloc[-1] != "\n":
  790. finBloc = ""
  791. linesBlocTmp = txtBloc.splitlines()
  792. linesBloc = []
  793. brBloc = []
  794. z = 0
  795. lenLines = len(linesBlocTmp)
  796. for i in linesBlocTmp:
  797. if self.reComment.split(i)[0]:
  798. findCooment = self.reComment.search(i)
  799. comment = False
  800. par = i
  801. if findCooment:
  802. par = i[:findCooment.start()]
  803. comment = i[findCooment.start():]
  804. fields = self.reSepFields.split(par)
  805. lenFields = len(fields)
  806. if lenFields>1:
  807. for fi in range(lenFields-1):
  808. linesBloc.append(fields[fi]+ self.sepFields)
  809. if fi == lenFields-2:
  810. if comment:
  811. brBloc.append("")
  812. else:
  813. if (lenLines-1)== z:
  814. brBloc.append(finBloc)
  815. else:
  816. brBloc.append("\n")
  817. else:
  818. brBloc.append("")
  819. if comment:
  820. linesBloc.append(comment)
  821. if (lenLines-1)== z:
  822. brBloc.append(finBloc)
  823. else:
  824. brBloc.append("\n")
  825. else:
  826. linesBloc.append(i)
  827. if (lenLines-1)== z:
  828. brBloc.append(finBloc)
  829. else:
  830. brBloc.append("\n")
  831. else:
  832. linesBloc.append(i)
  833. if (lenLines-1)== z:
  834. brBloc.append(finBloc)
  835. else:
  836. brBloc.append("\n")
  837. z +=1
  838. fields = self.setDataField(linesBloc, brBloc)
  839. return fields
  840. class xmlShare:
  841. """Общий класс для объектов XML, наследуем
  842. """
  843. def _createElement(self, doc, tagName, text="", attributes={}):
  844. """Создание нового XML элемента"""
  845. element = doc.createElement(tagName)
  846. if text:
  847. txtNode = doc.createTextNode(_toUNICODE(text))
  848. element.appendChild(txtNode)
  849. for attr in attributes.keys():
  850. attribute = doc.createAttribute(attr)
  851. attribute.nodeValue = attributes[attr]
  852. element.setAttributeNode(attribute)
  853. return element
  854. class xmlNode(xmlShare):
  855. """Класс для создания нод без аттрибутов
  856. """
  857. def __init__(self):
  858. self.node = False
  859. def createNode(self, doc, tagName, text=""):
  860. """Создает XML элемент без аттрибутов"""
  861. self.node=self._createElement(doc, tagName, text)
  862. return self.node
  863. def getNode(self):
  864. return self.node
  865. class xmlCaption:
  866. """Класс XML заголовок
  867. """
  868. def __init__(self):
  869. #Заголовок области XML нода
  870. self.caption = False
  871. def createCaption(self, doc, name, quotes, action=False):
  872. """Создание заголовка области"""
  873. tmpNode = xmlNode()
  874. self.caption = tmpNode.createNode(doc, "caption")
  875. nameNode = tmpNode.createNode(doc, "name",name)
  876. self.caption.appendChild(nameNode)
  877. if action:
  878. actNode = tmpNode.createNode(doc, "action", action)
  879. self.caption.appendChild(actNode)
  880. for q in quotes:
  881. quoteNode = tmpNode.createNode(doc, "quote", q)
  882. self.caption.appendChild(quoteNode)
  883. return self.caption
  884. def getCaption(self):
  885. """Выдает XML ноду заголовка области"""
  886. return self.caption
  887. class xmlField(xmlShare):
  888. """Класс для работы с XML полем
  889. """
  890. def __init__(self):
  891. # XML нода поле
  892. self.field = False
  893. def createField(self, doc, typeField, quotes, name="",
  894. values=[],action=False):
  895. """Cоздание XML ноды поле"""
  896. self.field = self._createElement(doc, "field", "", {"type":typeField})
  897. if name:
  898. nameNode = self._createElement(doc, "name", name)
  899. self.field.appendChild(nameNode)
  900. for v in values:
  901. valueNode = self._createElement(doc, "value", v)
  902. self.field.appendChild(valueNode)
  903. if action:
  904. actNode = self._createElement(doc, "action", action)
  905. self.field.appendChild(actNode)
  906. for q in quotes:
  907. quoteNode = self._createElement(doc, "quote", q)
  908. self.field.appendChild(quoteNode)
  909. return self.field
  910. class xmlFields:
  911. """Класс, в котором находится список ХМL нод field
  912. """
  913. def __init__(self):
  914. self.fields = []
  915. def appendField(self, field):
  916. """Добавить XML ноду field"""
  917. self.fields.append(field)
  918. return self.fields
  919. def getFields(self):
  920. """Выдать список XML нод"""
  921. return self.fields
  922. class xmlArea:
  923. """Класс для работы с XML областью
  924. """
  925. def __init__(self):
  926. # Область
  927. self.area = False
  928. def createArea(self, doc, xmlCaption, xmlFields):
  929. """Создание XML области"""
  930. tmpNode = xmlNode()
  931. self.area = tmpNode.createNode(doc, "area")
  932. if xmlCaption and xmlCaption.getCaption():
  933. self.area.appendChild(xmlCaption.getCaption())
  934. if xmlFields:
  935. fields = xmlFields.getFields()
  936. for field in fields:
  937. self.area.appendChild(field)
  938. return self.area
  939. class xmlDoc:
  940. """Класс для работы с XML документом
  941. """
  942. def __init__(self):
  943. # документ
  944. self.doc = False
  945. # главная нода
  946. self.root = False
  947. # тело документа
  948. self.body = False
  949. # Заголовок области - временный (в реальности один объект заголовок)
  950. self.tmpCaption = False
  951. # Поля - временные (в реальности один объект поля)
  952. self.tmpFields = False
  953. # Разделитель областей - по умолчанию перевод строки "\n"
  954. self.sepAreas = False
  955. # Разделитель разделенных списков - по умолчанию перевод строки "\n"
  956. #self.sepSplitFields = False
  957. def createDoc(self, typeDoc, version):
  958. """Создание нового документа новый документ"""
  959. docTxt = '<?xml version="1.0" encoding="UTF-8"?><cxmlconf><head>'
  960. docTxt += '<ver>%s</ver>'% version
  961. docTxt += '<format>%s</format>' % typeDoc
  962. docTxt += '</head><body></body></cxmlconf>'
  963. self.doc = xml.dom.minidom.parseString(docTxt)
  964. self.root = self.doc.documentElement
  965. self.body = xpath.Evaluate('child::body',self.root)[0]
  966. # установка разделителя областей
  967. self.sepAreas = self.createField("br",[],"",[],False,False)
  968. # установка разделителя областей разделенных списков
  969. #self.sepSplitFields = self.createField("br",[],"",[],False,False)
  970. return self.doc
  971. def addField(self, field):
  972. """Добавляет поле во временный список
  973. Из этого списка в дальнейшем формируется XML область
  974. """
  975. if not self.tmpFields:
  976. self.tmpFields = xmlFields()
  977. self.tmpFields.appendField(field)
  978. def createCaption(self, name, quotes, action=False):
  979. """Cоздает заголовок области
  980. Помещает заголовок в временный артибут
  981. Используется при создании области
  982. """
  983. self.tmpCaption = xmlCaption()
  984. return self.tmpCaption.createCaption(self.doc, name, quotes, action)
  985. def createField(self, typeField, quotes=[], name="",
  986. values=[] ,action=False,addTmpField=True):
  987. """Cоздает поле
  988. Если установлена переменнная addTmpField
  989. добавляет поле во временный список
  990. """
  991. fieldObj = xmlField()
  992. field = fieldObj.createField(self.doc, typeField, quotes, name,
  993. values, action)
  994. if addTmpField:
  995. self.addField(field)
  996. return field
  997. def clearTmpFields(self):
  998. """Очищает временный список"""
  999. self.tmpFields = False
  1000. def createArea(self):
  1001. """Cоздает область
  1002. Область создается на основании временного атрибута и временного списка
  1003. """
  1004. areaObj = xmlArea()
  1005. area = areaObj.createArea(self.doc, self.tmpCaption, self.tmpFields)
  1006. self.clearTmpCaptionAndFields()
  1007. return area
  1008. def clearTmpCaptionAndFields(self):
  1009. """Очищает временный аттрибут и временный список"""
  1010. self.tmpCaption = False
  1011. self.tmpFields = False
  1012. def getNodeRoot(self):
  1013. """Выдает корневую ноду"""
  1014. return self.root
  1015. def getNodeBody(self):
  1016. """Выдает ноду body"""
  1017. return self.body
  1018. def setActionField(self, xmlField, actionTxt):
  1019. """Устанавливает свойство action для XML поля"""
  1020. xmlActions = xpath.Evaluate('child::action',xmlField)
  1021. if xmlActions and xmlActions[0].firstChild:
  1022. xmlActions[0].firstChild.nodeValue = actionTxt
  1023. else:
  1024. nodeObj = xmlNode()
  1025. newNode = nodeObj.createNode(self.doc, "action", actionTxt)
  1026. xmlField.appendChild(newNode)
  1027. def setActionArea(self, xmlArea, actionTxt):
  1028. """Устанавливает свойство action для XML области"""
  1029. xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
  1030. xmlCaptions = xpath.Evaluate('child::caption',xmlArea)
  1031. if xmlActions and xmlActions[0].firstChild:
  1032. xmlActions[0].firstChild.nodeValue = actionTxt
  1033. else:
  1034. if xmlCaptions:
  1035. nodeObj = xmlNode()
  1036. newNode = nodeObj.createNode(self.doc, "action", actionTxt)
  1037. xmlCaptions[0].appendChild(newNode)
  1038. def joinField(self, xmlArea, xmlNewField):
  1039. """Объединяет XML ноду область и XML ноду поле"""
  1040. newNameField = self.getNameField(xmlNewField)
  1041. if not newNameField or not newNameField.strip():
  1042. return False
  1043. fieldsOldComp = xpath.Evaluate("child::field[child::name='%s']"\
  1044. %(newNameField), xmlArea)
  1045. # Если поле не найдено добавляем его
  1046. typeNewField = self.getTypeField(xmlNewField)
  1047. if not fieldsOldComp and typeNewField != "seplist":
  1048. if self.getActionField(xmlNewField) != "drop":
  1049. self.setActionField(xmlNewField, "append")
  1050. xmlArea.appendChild(xmlNewField)
  1051. return True
  1052. newFieldsAction = self.getActionField(xmlNewField)
  1053. newValues = self.getFieldValues(xmlNewField)
  1054. flagCompare = True
  1055. for nodeFieldOld in fieldsOldComp:
  1056. if newFieldsAction == "drop":
  1057. if nodeFieldOld.nextSibling and\
  1058. self.getTypeField(nodeFieldOld.nextSibling) == "br":
  1059. xmlArea.removeChild(nodeFieldOld.nextSibling)
  1060. elif nodeFieldOld.previousSibling and\
  1061. self.getTypeField(nodeFieldOld.previousSibling) == "br":
  1062. xmlArea.removeChild(nodeFieldOld.previousSibling)
  1063. xmlArea.removeChild(nodeFieldOld)
  1064. continue
  1065. oldValues = self.getFieldValues(nodeFieldOld)
  1066. # Сравнение значений переменной шаблона и файла
  1067. if set(newValues) != set(oldValues):
  1068. flagCompare = False
  1069. if self.getActionField(xmlNewField) == "drop":
  1070. return True
  1071. appSplLst = []
  1072. insSplLst = []
  1073. if typeNewField == "seplist":
  1074. if fieldsOldComp:
  1075. xmlOldField = fieldsOldComp[-1]
  1076. else:
  1077. xmlOldField = False
  1078. seplistNewXML = self.getSepListToField(xmlNewField)
  1079. if seplistNewXML:
  1080. for nodeSeplist in seplistNewXML:
  1081. if self.getActionField(nodeSeplist) != "drop":
  1082. if newFieldsAction == "join":
  1083. flagCompareSeplist = False
  1084. newValues = self.getFieldValues(nodeSeplist)
  1085. for nodeFieldOld in fieldsOldComp:
  1086. oldValues = self.getFieldValues(nodeFieldOld)
  1087. for newValue in newValues:
  1088. if newValue in oldValues:
  1089. flagCompareSeplist = True
  1090. break
  1091. if not flagCompareSeplist:
  1092. nextNode = xmlOldField.nextSibling
  1093. newInsNode = nodeSeplist.cloneNode(True)
  1094. self.setActionField(newInsNode,"append")
  1095. if nextNode:
  1096. appSplLst.append((newInsNode,
  1097. nextNode,
  1098. "insert"))
  1099. else:
  1100. appSplLst.append((newInsNode,
  1101. False,
  1102. "append"))
  1103. else:
  1104. newInsNode = nodeSeplist.cloneNode(True)
  1105. if self.getActionField(newInsNode) == "join":
  1106. self.setActionField(newInsNode,"append")
  1107. if xmlOldField:
  1108. insSplLst.append((newInsNode,
  1109. xmlOldField,
  1110. "insert"))
  1111. else:
  1112. insSplLst.append((newInsNode,
  1113. False,
  1114. "append"))
  1115. #xmlArea.insertBefore(\
  1116. #nodeSeplist.cloneNode(True),
  1117. #xmlOldField)
  1118. parentNode = nodeSeplist.parentNode
  1119. parentNode.removeChild(nodeSeplist)
  1120. insNodesRepl = []
  1121. for newNode, nxtNode, app in insSplLst:
  1122. flagCompareSeplist = False
  1123. newValues = self.getFieldValues(newNode)
  1124. for nodeRepl, nxtNode, app in insNodesRepl:
  1125. oldValues = self.getFieldValues(nodeRepl)
  1126. for newValue in newValues:
  1127. if newValue in oldValues:
  1128. flagCompareSeplist = True
  1129. break
  1130. if not flagCompareSeplist:
  1131. if xmlOldField:
  1132. insNodesRepl.append((newNode, nxtNode, app))
  1133. for newNode, nxtNode, app in insNodesRepl:
  1134. if app == "insert":
  1135. xmlArea.insertBefore(newNode,nxtNode)
  1136. elif app == "append":
  1137. xmlArea.appendChild(newNode)
  1138. if xmlOldField:
  1139. parentNode = xmlOldField.parentNode
  1140. if parentNode and newFieldsAction != "join":
  1141. parentNode.removeChild(xmlOldField)
  1142. for newNode, nxtNode, app in appSplLst:
  1143. if app == "insert":
  1144. xmlArea.insertBefore(newNode,nxtNode)
  1145. elif app == "append":
  1146. xmlArea.appendChild(newNode)
  1147. if not flagCompare and typeNewField != "seplist":
  1148. # Устанавливаем action=replace
  1149. self.setActionField(xmlNewField, "replace")
  1150. # Если параметры поля не сходятся заменяем поле
  1151. xmlArea.replaceChild(xmlNewField.cloneNode(True),
  1152. fieldsOldComp[-1])
  1153. if newFieldsAction == "join":
  1154. fieldsOldRemove = []
  1155. else:
  1156. fieldsOldRemove = fieldsOldComp[:-1]
  1157. for nodeFieldOld in fieldsOldRemove:
  1158. actionOldNode = self.getActionField(nodeFieldOld)
  1159. if actionOldNode == "insert" or actionOldNode == "append":
  1160. pass
  1161. else:
  1162. if nodeFieldOld.nextSibling and\
  1163. self.getTypeField(nodeFieldOld.nextSibling) == "br":
  1164. xmlArea.removeChild(nodeFieldOld.nextSibling)
  1165. xmlArea.removeChild(nodeFieldOld)
  1166. return True
  1167. def getSepListToField(self, xmlField):
  1168. """Выдает элементы распределенного массива
  1169. Область предок поля, в этой области ищутся
  1170. элементы распределенного массива
  1171. """
  1172. nameField = self.getNameField(xmlField)
  1173. if not nameField:
  1174. return []
  1175. parentNode = xmlField.parentNode
  1176. if parentNode:
  1177. fieldsVal = xpath.Evaluate(\
  1178. "child::field[attribute::type='seplist'][child::name='%s'] "\
  1179. %(nameField), parentNode)
  1180. return fieldsVal
  1181. else:
  1182. return []
  1183. def removeComment(self, xmlArea):
  1184. """Удаляет комментарии в XML области"""
  1185. fieldNodes = xpath.Evaluate('descendant::field',xmlArea)
  1186. for fieldNode in fieldNodes:
  1187. if fieldNode.hasAttribute("type"):
  1188. if fieldNode.getAttribute("type") == "comment" or\
  1189. fieldNode.getAttribute("type") == "br":
  1190. parentNode = fieldNode.parentNode
  1191. parentNode.removeChild(fieldNode)
  1192. else:
  1193. if self.getActionField(fieldNode) == "drop":
  1194. pass
  1195. elif self.getActionField(fieldNode) == "join":
  1196. pass
  1197. else:
  1198. self.setActionField(fieldNode,"append")
  1199. def joinBody(self, baseBody, newBody):
  1200. """Объединяет две области Body"""
  1201. newFields = xpath.Evaluate('child::field',newBody)
  1202. xmlNewAreas = xpath.Evaluate('child::area',newBody)
  1203. for xmlNewArea in xmlNewAreas:
  1204. self.joinArea(baseBody,xmlNewArea)
  1205. joinNewFields = xpath.Evaluate("child::field[child::action='join']"
  1206. ,newBody)
  1207. self.addNewFielsOldArea(newFields, joinNewFields, baseBody)
  1208. def getRemoveNodeSepList(self, removeNodesDict, baseNode, xmNewlField):
  1209. """Находит элементы разделенного списка
  1210. Параметры:
  1211. removeNodesDict - Cловарь удаляемых полей разделенного списка
  1212. формируется программой
  1213. baseNode - Нода в которой идет поиск
  1214. xmNewlField - Нода field которая проверяется на принадлежность
  1215. к разделенному списку
  1216. """
  1217. flagNewNodeSeplist = False
  1218. if self.getTypeField(xmNewlField) == "seplist":
  1219. flagNewNodeSeplist = True
  1220. nameNewField = self.getNameField(xmNewlField)
  1221. if nameNewField:
  1222. if removeNodesDict.has_key(nameNewField):
  1223. return removeNodesDict[nameNewField]
  1224. else:
  1225. oldFields = xpath.Evaluate('child::field', baseNode)
  1226. removeNodes = []
  1227. lenOldFields = len(oldFields)
  1228. for i in range(lenOldFields):
  1229. oldNode = oldFields[i]
  1230. flagSep = self.getTypeField(oldNode) == "seplist"
  1231. if flagNewNodeSeplist:
  1232. flagSep = True
  1233. if flagSep and\
  1234. nameNewField == self.getNameField(oldNode):
  1235. removeNodes.append(oldNode)
  1236. if i+1<lenOldFields:
  1237. nextNode = oldFields[i+1]
  1238. if self.getTypeField(nextNode) == "br":
  1239. removeNodes.append(nextNode)
  1240. removeNodesDict[nameNewField] = removeNodes
  1241. return removeNodes
  1242. def addNewFielsOldArea(self, newFields, joinNewFields, xmlOldArea):
  1243. """Добавляет новые XML поля в область шаблона"""
  1244. removeNodesDict = {}
  1245. notRemoveNodesDict = {}
  1246. for notRemNode in joinNewFields:
  1247. nameField = self.getNameField(notRemNode)
  1248. if not notRemoveNodesDict.has_key(nameField):
  1249. notRemoveNodesDict[nameField] = []
  1250. notRemoveNodesDict[nameField].append(notRemNode)
  1251. else:
  1252. notRemoveNodesDict[nameField].append(notRemNode)
  1253. notSepListField = []
  1254. sepListField = []
  1255. for nField in newFields:
  1256. if self.getRemoveNodeSepList(removeNodesDict, xmlOldArea,
  1257. nField):
  1258. sepListField.append(nField)
  1259. else:
  1260. if self.getNameField(nField):
  1261. notSepListField.append(nField)
  1262. for name in notRemoveNodesDict.keys():
  1263. if removeNodesDict.has_key(name):
  1264. removeNodesDict[name] = []
  1265. for removeNodes in removeNodesDict.values():
  1266. if removeNodes:
  1267. if self.getTypeField(removeNodes[-1]) == "seplist":
  1268. removeNodes = removeNodes[:-1]
  1269. else:
  1270. removeNodes = removeNodes[:-2]
  1271. for removeNode in removeNodes:
  1272. xmlOldArea.removeChild(removeNode)
  1273. for node in sepListField:
  1274. node.setAttribute("type", "seplist")
  1275. if not (self.getActionField(node) == "join" or\
  1276. self.getActionField(node) == "drop"):
  1277. self.setActionField(node,"insert")
  1278. self.joinField(xmlOldArea, node)
  1279. for node in notSepListField:
  1280. if self.getTypeField(node) == "seplist":
  1281. self.setActionField(node, "append")
  1282. xmlOldArea.appendChild(node)
  1283. else:
  1284. self.joinField(xmlOldArea, node)
  1285. def insertBeforeSepAreas(self, xmlArea):
  1286. """Добавляет разделитель областей перед каждой областью"""
  1287. if not self.sepAreas:
  1288. return False
  1289. areaNodes = xpath.Evaluate('descendant::area',xmlArea)
  1290. for areaNode in areaNodes:
  1291. prevNode = areaNode.previousSibling
  1292. if prevNode:
  1293. parentNode = areaNode.parentNode
  1294. parentNode.insertBefore(self.sepAreas.cloneNode(True),
  1295. areaNode)
  1296. return True
  1297. def getAreaFields(self, nameArea, xmlArea):
  1298. """По имени области выводит названия и значения всех переменных
  1299. поиск ведется только в 1-х потомках области xmlArea
  1300. на выход словарь переменных {имя:значение}
  1301. """
  1302. namesAreaComare = xpath.Evaluate(\
  1303. "child::area/child::caption[child::name='%s']" %(nameArea),
  1304. xmlArea)
  1305. if not namesAreaComare:
  1306. return False
  1307. fields = xpath.Evaluate("child::field/child::name",
  1308. namesAreaComare[0].parentNode)
  1309. dictVar = {}
  1310. for fieldName in fields:
  1311. nodeField = fieldName.parentNode
  1312. fieldValue = xpath.Evaluate("child::value",nodeField)
  1313. name = fieldName.firstChild.nodeValue
  1314. value = ""
  1315. if fieldValue and fieldValue[0].firstChild:
  1316. value = fieldValue[0].firstChild.nodeValue
  1317. dictVar[name] = value
  1318. return dictVar
  1319. def getAreaFieldValues(self, nameArea, nameField, xmlArea):
  1320. """По имени области и имени переменной выводит значениe переменной
  1321. поиск ведется только в 1-х потомках области xmlArea
  1322. """
  1323. namesAreaComare = xpath.Evaluate(\
  1324. "child::area/child::caption[child::name='%s']" %(nameArea),
  1325. xmlArea)
  1326. fieldsVal = False
  1327. for areaComp in namesAreaComare:
  1328. fieldsVal = xpath.Evaluate(\
  1329. "child::field[child::name='%s'] "\
  1330. %(nameField), areaComp.parentNode)
  1331. if fieldsVal:
  1332. break
  1333. if not fieldsVal:
  1334. return False
  1335. fieldValue = xpath.Evaluate("child::value",
  1336. fieldsVal[0])
  1337. if not fieldValue:
  1338. return False
  1339. if fieldValue[0].firstChild:
  1340. return fieldValue[0].firstChild.nodeValue
  1341. else:
  1342. return ""
  1343. def getAllAreas(self):
  1344. """Выдает все области"""
  1345. return xpath.Evaluate('descendant::area', self.body)
  1346. def getArea(self, nameArea, xmlArea):
  1347. """По имени области находит области (первый потомок xmlArea)"""
  1348. namesAreaComare = xpath.Evaluate(\
  1349. "child::area/child::caption[child::name='%s']" %(nameArea),
  1350. xmlArea)
  1351. return map(lambda x: x.parentNode, namesAreaComare)
  1352. def joinArea(self, baseNode, xmlNewArea):
  1353. """Объединяет область c областью Body (xmlNewArea c baseNode)"""
  1354. def appendArea(baseNode, xmlNewArea):
  1355. fieldsRemove = xpath.Evaluate(\
  1356. "descendant::field[child::action='drop']", xmlNewArea)
  1357. for rmNode in fieldsRemove:
  1358. parentNode = rmNode.parentNode
  1359. parentNode.removeChild(rmNode)
  1360. captionAreasRemove = xpath.Evaluate(\
  1361. "descendant::area/child::caption[child::action='drop']",
  1362. xmlNewArea)
  1363. for rmNodeCapt in captionAreasRemove:
  1364. rmNode = rmNodeCapt.parentNode
  1365. parentNode = rmNode.parentNode
  1366. parentNode.removeChild(rmNode)
  1367. self.setActionArea(xmlNewArea, "append")
  1368. # Добавляем разделитель областей во вложенные области
  1369. areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
  1370. for areaNode in areaNodes:
  1371. self.setActionArea(areaNode,"append")
  1372. parentNode = areaNode.parentNode
  1373. parentNode.insertBefore(self.sepAreas.cloneNode(True),
  1374. areaNode)
  1375. baseNode.appendChild(xmlNewArea)
  1376. # Добавляем разделитель областей
  1377. baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)
  1378. nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
  1379. nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
  1380. if not nodesNames:
  1381. # Добавляем область
  1382. if nodesNewArea:
  1383. newAreaAction = self.getActionArea(xmlNewArea)
  1384. if not (newAreaAction == "drop" or newAreaAction == "replace"):
  1385. appendArea(baseNode, xmlNewArea)
  1386. return True
  1387. if not nodesNames or not nodesNewArea:
  1388. return False
  1389. nameArea = ""
  1390. if nodesNewArea[0].firstChild:
  1391. nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
  1392. flagFindArea = False
  1393. baseNodes = []
  1394. for oName in nodesNames:
  1395. newAreaAction = self.getActionArea(xmlNewArea)
  1396. oArea = oName.parentNode.parentNode
  1397. oNameTxt = ""
  1398. if oName.firstChild:
  1399. oNameTxt = oName.firstChild.nodeValue
  1400. if nameArea == oNameTxt:
  1401. flagFindArea = True
  1402. # При использовании удаления
  1403. if newAreaAction == "drop":
  1404. prevNode = oName.parentNode.parentNode.previousSibling
  1405. removePrevNodes = []
  1406. while (prevNode) and self.getTypeField(prevNode) == "br":
  1407. removePrevNodes.append(prevNode)
  1408. prevNode = prevNode.previousSibling
  1409. for removeNode in removePrevNodes:
  1410. baseNode.removeChild(removeNode)
  1411. baseNode.removeChild(oName.parentNode.parentNode)
  1412. continue
  1413. elif newAreaAction == "replace":
  1414. oldAreaNode = oName.parentNode.parentNode
  1415. newAreaCaption = xpath.Evaluate('child::caption',
  1416. xmlNewArea)[0]
  1417. oldAreaCaption = xpath.Evaluate('child::caption',
  1418. oldAreaNode)[0]
  1419. if newAreaCaption and oldAreaCaption:
  1420. xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
  1421. self.setActionArea(xmlNewArea,"replace")
  1422. baseNode.replaceChild(xmlNewArea,
  1423. oldAreaNode)
  1424. continue
  1425. baseNodes.append(oName.parentNode.parentNode)
  1426. newFields = xpath.Evaluate('child::field',xmlNewArea)
  1427. joinNewFields = xpath.Evaluate(\
  1428. "child::field[child::action='join']"
  1429. ,xmlNewArea)
  1430. self.addNewFielsOldArea(newFields, joinNewFields, oArea)
  1431. if not flagFindArea:
  1432. # Добавляем область
  1433. if not (newAreaAction == "drop" or\
  1434. newAreaAction == "replace"):
  1435. appendArea(baseNode, xmlNewArea)
  1436. else:
  1437. tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
  1438. for na in tmpXmlNewAreas:
  1439. for bn in baseNodes:
  1440. self.joinArea(bn, na)
  1441. return True
  1442. def joinDoc(self, xmlNewDoc):
  1443. """Объединяет два документа"""
  1444. newRootNode = xmlNewDoc.documentElement
  1445. newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
  1446. newImportBodyNode = self.doc.importNode(newBodyNode, True)
  1447. # Перед объединение области с документом
  1448. # удаляем комментарии
  1449. self.removeComment(newImportBodyNode)
  1450. self.joinBody(self.body, newImportBodyNode)
  1451. # расставляем BR
  1452. self.insertBRtoBody(self.body)
  1453. def getQuoteField(self, xmlField):
  1454. """Выдает текст из поля"""
  1455. xmlQuotes = xpath.Evaluate('child::quote',xmlField)
  1456. br = ""
  1457. if xmlField.hasAttribute("type") and\
  1458. xmlField.getAttribute("type") == "br":
  1459. br = "\n"
  1460. if xmlQuotes:
  1461. field = xmlQuotes[0]
  1462. if field.firstChild:
  1463. return field.firstChild.nodeValue + br
  1464. return "" + br
  1465. def getFieldsArea(self, xmlArea):
  1466. """Выдает потомков XML области"""
  1467. xmlFields = []
  1468. childNodes = xmlArea.childNodes
  1469. for node in childNodes:
  1470. if node.nodeType == node.ELEMENT_NODE:
  1471. if node.tagName == "area" or node.tagName == "field":
  1472. xmlFields.append(node)
  1473. return xmlFields
  1474. def getTypeField(self, xmlField):
  1475. """Выдает тип поля"""
  1476. if xmlField.hasAttribute("type"):
  1477. return xmlField.getAttribute("type")
  1478. else:
  1479. return False
  1480. def getNameField(self, xmlField):
  1481. """Выдает имя поля"""
  1482. xmlNameFields = xpath.Evaluate('child::name', xmlField)
  1483. if xmlNameFields and xmlNameFields[0].firstChild:
  1484. return xmlNameFields[0].firstChild.nodeValue
  1485. else:
  1486. return False
  1487. def getNameArea(self, xmlArea):
  1488. """Выдает имя области"""
  1489. xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
  1490. if xmlNameAreas and xmlNameAreas[0].firstChild:
  1491. return xmlNameAreas[0].firstChild.nodeValue
  1492. else:
  1493. return False
  1494. def xmlToText(self, xmlAreas, text):
  1495. """Преобразует список XML областей в текст"""
  1496. def getQuotesArea(xmlArea):
  1497. quotes = []
  1498. xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
  1499. for node in xmlQuotes:
  1500. if node.firstChild:
  1501. quotes.append(node.firstChild.nodeValue)
  1502. if len(quotes) == 0:
  1503. quotes.append("")
  1504. quotes.append("")
  1505. elif len(quotes) == 1:
  1506. quotes.append("")
  1507. return quotes
  1508. for i in xmlAreas:
  1509. if i.tagName == "area":
  1510. quotesI = getQuotesArea(i)
  1511. startAreaI = quotesI[0]
  1512. endAreaI = quotesI[1]
  1513. text.append(startAreaI)
  1514. xmlFieldsI = self.getFieldsArea(i)
  1515. for f in xmlFieldsI:
  1516. if f.tagName == "area":
  1517. quotesF = getQuotesArea(f)
  1518. startAreaF = quotesF[0]
  1519. endAreaF = quotesF[1]
  1520. text.append(startAreaF)
  1521. xmlFieldsF = self.getFieldsArea(f)
  1522. self.xmlToText(xmlFieldsF, text)
  1523. text.append(endAreaF)
  1524. else:
  1525. fieldF = self.getQuoteField(f)
  1526. text.append(fieldF)
  1527. text.append(endAreaI)
  1528. else:
  1529. fieldI = self.getQuoteField(i)
  1530. text.append(fieldI)
  1531. def getActionField(self, xmlField):
  1532. """Выдает свойство action XML поля"""
  1533. xmlActions = xpath.Evaluate('child::action',xmlField)
  1534. if xmlActions and xmlActions[0].firstChild:
  1535. return xmlActions[0].firstChild.nodeValue
  1536. else:
  1537. return False
  1538. def getFieldValues(self, xmlField):
  1539. """Выдает значения XML поля в виде массива"""
  1540. vals = []
  1541. xmlValues = xpath.Evaluate('child::value',xmlField)
  1542. if xmlValues:
  1543. for node in xmlValues:
  1544. if node.firstChild:
  1545. vals.append(node.firstChild.nodeValue)
  1546. return vals
  1547. def getActionArea(self, xmlArea):
  1548. """Выдает свойство action XML области"""
  1549. xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
  1550. if xmlActions and xmlActions[0].firstChild:
  1551. return xmlActions[0].firstChild.nodeValue
  1552. else:
  1553. return False
  1554. def delActionNodeArea(self, xmlArea):
  1555. """Удаляет свойство action XML области"""
  1556. xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
  1557. if xmlActions and xmlActions[0].firstChild:
  1558. parentNode = xmlActions[0].parentNode
  1559. parentNode.removeChild(xmlActions[0])
  1560. return True
  1561. else:
  1562. return False
  1563. def delActionNodeField(self, xmlField):
  1564. """Удаляет свойство action XML поля"""
  1565. xmlActions = xpath.Evaluate('child::action',xmlField)
  1566. if xmlActions and xmlActions[0].firstChild:
  1567. parentNode = xmlActions[0].parentNode
  1568. parentNode.removeChild(xmlActions[0])
  1569. return True
  1570. else:
  1571. return False
  1572. # Создает распределенные списки
  1573. def postParserListSeplist(self, xmlArea):
  1574. """Создает распределенные списки из элементов области"""
  1575. # Потомки
  1576. childNodes = self.getFieldsArea(xmlArea)
  1577. # содержит списки нод полей с одинаковыми именами в одной области
  1578. fieldsSeplist = {}
  1579. for node in childNodes:
  1580. if node.tagName == "area":
  1581. self.postParserListSeplist(node)
  1582. else:
  1583. fieldName = False
  1584. xmlFieldNameNodes = xpath.Evaluate('child::name',node)
  1585. if xmlFieldNameNodes and xmlFieldNameNodes[0].firstChild:
  1586. fieldName = xmlFieldNameNodes[0].firstChild.nodeValue
  1587. if fieldName:
  1588. if fieldsSeplist.has_key(fieldName):
  1589. fieldsSeplist[fieldName].append(node)
  1590. else:
  1591. fieldsSeplist[fieldName] = []
  1592. fieldsSeplist[fieldName].append(node)
  1593. for listNodes in fieldsSeplist.values():
  1594. if len(listNodes) > 1:
  1595. for node in listNodes:
  1596. node.setAttribute("type", "seplist")
  1597. def insertBRtoBody(self, xmlArea):
  1598. """Добавляет необходимые переводы строк
  1599. """
  1600. # Потомки
  1601. childNodes = self.getFieldsArea(xmlArea)
  1602. # нода BR
  1603. fieldXMLBr = self.createField("br",[],"",[],False, False)
  1604. # разделитель поля
  1605. fieldSplit = False
  1606. # Предыдущая нода
  1607. lastNode = False
  1608. # Cледующая нода
  1609. nextNode = False
  1610. lenChildNodes = len(childNodes)
  1611. for i in range(lenChildNodes):
  1612. node = childNodes[i]
  1613. lastTmpNode = node
  1614. # Нода area
  1615. if node.tagName == "area":
  1616. if self.getActionArea(node) == "append" or\
  1617. self.getActionArea(node) == "join":
  1618. self.delActionNodeArea(node)
  1619. if lastNode and lastNode.hasAttribute("type") and\
  1620. lastNode.getAttribute("type") == "br" or\
  1621. lastNode and lastNode.hasAttribute("type") and\
  1622. lastNode.getAttribute("type") == "comment":
  1623. indNext = i + 1
  1624. if indNext == lenChildNodes:
  1625. xmlArea.appendChild(fieldXMLBr.cloneNode(True))
  1626. else:
  1627. nextNode = childNodes[indNext]
  1628. lastTmpNode = xmlArea.insertBefore(\
  1629. fieldXMLBr.cloneNode(True),
  1630. nextNode)
  1631. else:
  1632. xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
  1633. node)
  1634. self.insertBRtoBody(node)
  1635. # Нода field
  1636. else:
  1637. if self.getActionField(node) == "append" or\
  1638. self.getActionField(node) == "join":
  1639. self.delActionNodeField(node)
  1640. if lastNode and lastNode.hasAttribute("type") and\
  1641. lastNode.getAttribute("type") == "br" or\
  1642. lastNode and lastNode.hasAttribute("type") and\
  1643. lastNode.getAttribute("type") == "comment":
  1644. indNext = i + 1
  1645. if indNext == lenChildNodes:
  1646. xmlArea.appendChild(fieldXMLBr.cloneNode(True))
  1647. else:
  1648. nextNode = childNodes[indNext]
  1649. lastTmpNode = xmlArea.insertBefore(\
  1650. fieldXMLBr.cloneNode(True),
  1651. nextNode)
  1652. else:
  1653. xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
  1654. node)
  1655. lastNode = lastTmpNode
  1656. def postParserList(self):
  1657. """Находит подходящие XML области и делаем из них поля-массивы"""
  1658. xmlAreas = xpath.Evaluate('descendant::area', self.body)
  1659. for xmlArea in xmlAreas:
  1660. flagListXml = True
  1661. fieldValues = []
  1662. xmlFields = xpath.Evaluate('child::field',xmlArea)
  1663. if not xmlFields:
  1664. flagListXml = False
  1665. lenXmlFields = len(xmlFields)
  1666. lenBrArea = 0
  1667. for xmlField in xmlFields:
  1668. xmlNames = xpath.Evaluate('child::name',xmlField)
  1669. xmlVals = xpath.Evaluate('child::value',xmlField)
  1670. if xmlField.hasAttribute("type") and\
  1671. xmlField.getAttribute("type") == "br":
  1672. lenBrArea += 1
  1673. continue
  1674. if not xmlNames and not xmlVals:
  1675. flagListXml = False
  1676. break
  1677. if xmlNames and xmlNames[0].firstChild and\
  1678. xmlNames[0].firstChild.nodeValue:
  1679. flagListXml = False
  1680. break
  1681. if not (xmlVals and xmlVals[0].firstChild and\
  1682. xmlVals[0].firstChild.nodeValue):
  1683. flagListXml = False
  1684. break
  1685. else:
  1686. fieldValues.append(xmlVals[0].firstChild.nodeValue)
  1687. if lenXmlFields == lenBrArea:
  1688. flagListXml = False
  1689. if flagListXml:
  1690. nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
  1691. fieldName = ""
  1692. if nameNode.firstChild:
  1693. fieldName = nameNode.firstChild.nodeValue
  1694. listArea = []
  1695. self.xmlToText([xmlArea],listArea)
  1696. fieldQuote = "".join(listArea)
  1697. fieldXMLBr = False
  1698. if fieldQuote and fieldQuote[-1] == "\n":
  1699. fieldQuote = fieldQuote[:-1]
  1700. fieldXMLBr = self.createField("br",[],"",[],False, False)
  1701. fieldXML = self.createField("list",
  1702. [fieldQuote],
  1703. fieldName, fieldValues,
  1704. False, False)
  1705. areaAction = self.getActionArea(xmlArea)
  1706. if areaAction:
  1707. self.setActionField(fieldXML, areaAction)
  1708. parentNode = xmlArea.parentNode
  1709. parentNode.insertBefore(fieldXML,xmlArea)
  1710. if fieldXMLBr:
  1711. parentNode.insertBefore(fieldXMLBr,xmlArea)
  1712. parentNode.removeChild(xmlArea)
  1713. class blocText:
  1714. """Разбиваем текст на блоки"""
  1715. def splitTxtToBloc(self, text ,openTxtBloc,closeTxtBloc,
  1716. commentTxtBloc, sepField):
  1717. """Делит текст на блоки (без заголовков)
  1718. openTxtBloc - регулярное выражение для начала блока
  1719. closeTxtBloc - регулярное выражение для конца блока
  1720. commentTxtBloc - регулярное выражение - комментарий
  1721. возвращает блоки текста
  1722. """
  1723. blocs = []
  1724. level = 0
  1725. # Нахождение нескольких блоков в строке
  1726. # разделители линий, разделителями могут быть ("","\n")
  1727. sepsLines = []
  1728. # линии
  1729. txtLines = []
  1730. # Исходные строки
  1731. txtLinesSrc = text.splitlines()
  1732. for line in txtLinesSrc:
  1733. lineBR = ""
  1734. lineTmpA = line
  1735. closeBl = False
  1736. txtLinesTmp = []
  1737. commentSpl = commentTxtBloc.split(line)
  1738. flagCommentLine = False
  1739. if commentSpl[0].strip():
  1740. closeBl = True
  1741. if len(commentSpl) > 1:
  1742. commentBl = commentTxtBloc.search(line)
  1743. textLine =commentSpl[0]
  1744. commentLine = line[commentBl.start(0):]
  1745. lineTmpA = textLine
  1746. flagCommentLine = True
  1747. while (closeBl):
  1748. closeBl = sepField.search(lineTmpA)
  1749. if closeBl:
  1750. lineTmpB = lineTmpA[closeBl.end(0):]
  1751. txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
  1752. lineTmpA = lineTmpB
  1753. if lineTmpA.strip():
  1754. txtLinesTmp.append(lineTmpA)
  1755. # Если есть значение и комментарий в строке
  1756. if flagCommentLine:
  1757. for l in txtLinesTmp:
  1758. txtLines.append(l)
  1759. sepsLines.append("")
  1760. if not txtLinesTmp:
  1761. txtLines.append(textLine)
  1762. sepsLines.append("")
  1763. txtLines.append(commentLine)
  1764. sepsLines.append("\n")
  1765. # Если есть несколько блоков в строке
  1766. elif len(txtLinesTmp)>1 and txtLinesTmp[1].strip():
  1767. lenTmpLines = len(txtLinesTmp)
  1768. for l in range(lenTmpLines):
  1769. txtLines.append(txtLinesTmp[l])
  1770. if l == lenTmpLines-1:
  1771. sepsLines.append("\n")
  1772. else:
  1773. sepsLines.append("")
  1774. # Cтрока не преобразована
  1775. else:
  1776. txtLines.append(line)
  1777. sepsLines.append("\n")
  1778. # разбивание на блоки
  1779. z = 0
  1780. bl = ""
  1781. for i in txtLines:
  1782. if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
  1783. level += len(openTxtBloc.split(i)) - 1
  1784. if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
  1785. level -= len(closeTxtBloc.split(i)) - 1
  1786. bl += i + sepsLines[z]
  1787. if level == 0:
  1788. if bl:
  1789. blocs.append(bl)
  1790. bl = ""
  1791. z += 1
  1792. # cоздание блоков с элементами не входящими в блоки
  1793. realBlocs = []
  1794. z = 0
  1795. bl = ""
  1796. for i in blocs:
  1797. txtLines = i.splitlines()
  1798. if len(txtLines) > 0:
  1799. line = txtLines[0]
  1800. else:
  1801. line = i
  1802. if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
  1803. if bl:
  1804. realBlocs.append(bl)
  1805. bl = ""
  1806. realBlocs.append(i)
  1807. else:
  1808. bl += i
  1809. z += 1
  1810. if bl:
  1811. realBlocs.append(bl)
  1812. bl = ""
  1813. if level == 0:
  1814. if text and text[-1] != "\n":
  1815. tmpBlocs = realBlocs.pop()
  1816. tmpBlocs = tmpBlocs[:-1]
  1817. realBlocs.append(tmpBlocs)
  1818. return realBlocs
  1819. else:
  1820. return []
  1821. def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
  1822. """ Делит текст на области (с заголовками)
  1823. reTextHeader - регулярное выражение для заголовка области
  1824. reTextArea - регулярное выражение для всей области
  1825. numGroupArea - номер групы результата поиска по регулярному выражению
  1826. по всей области
  1827. возвращает два списка: первый - заголовки, второй - тела областей без
  1828. заголоков
  1829. """
  1830. # Заголовки областей
  1831. headersArea = []
  1832. # Тексты областей без заголовков
  1833. textBodyArea = []
  1834. r = reTextArea.search(text)
  1835. if not r:
  1836. headersArea.append("")
  1837. textBodyArea.append(text)
  1838. return (headersArea, textBodyArea)
  1839. txtWr = text
  1840. while r:
  1841. textArea = r.group(numGroupArea)
  1842. txtSpl = txtWr.split(textArea)
  1843. area = txtSpl[0]
  1844. txtWr = txtSpl[1]
  1845. if area:
  1846. headersArea.append("")
  1847. textBodyArea.append(area)
  1848. res = reTextHeader.search(textArea)
  1849. header = textArea[:res.end()]
  1850. body = textArea[res.end():]
  1851. headersArea.append(header)
  1852. textBodyArea.append(body)
  1853. if txtWr:
  1854. r = reTextArea.search(txtWr)
  1855. else:
  1856. r = False
  1857. if txtWr:
  1858. headersArea.append("")
  1859. textBodyArea.append(txtWr)
  1860. return (headersArea, textBodyArea)
  1861. def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
  1862. """ Делит текст на блоки (с заголовками)
  1863. captionTxtBloc - регулярное выражение для заголовка блока
  1864. bodyTxtBloc - регулярное выражение для тела блока
  1865. возвращает два списка: первый - заголовки, второй - тела блоков
  1866. """
  1867. # Заголовки блоков
  1868. headersTxt = []
  1869. # Тексты блоков
  1870. blocsTxt = []
  1871. r = captionTxtBloc.search(text)
  1872. if r:
  1873. headersTxt.append(r.group(0))
  1874. txtSpl = text.partition(r.group(0))
  1875. blocTxt = txtSpl[0]
  1876. txtWr = txtSpl[2]
  1877. rb = bodyTxtBloc.search(blocTxt)
  1878. if not blocTxt:
  1879. blocsTxt.append(blocTxt)
  1880. if rb:
  1881. blocsTxt.append(rb.group(0))
  1882. while (r):
  1883. r = captionTxtBloc.search(txtWr)
  1884. if r:
  1885. headersTxt.append(r.group(0))
  1886. txtSpl = txtWr.partition(r.group(0))
  1887. blocTxt = txtSpl[0]
  1888. txtWr = txtSpl[2]
  1889. rb = bodyTxtBloc.search(blocTxt)
  1890. if rb:
  1891. blocsTxt.append(rb.group(0))
  1892. else:
  1893. blocsTxt.append(txtWr)
  1894. if headersTxt and blocsTxt:
  1895. if len(headersTxt)>len(blocsTxt):
  1896. blocsTxt.insert(0,"")
  1897. elif len(headersTxt)<len(blocsTxt):
  1898. headersTxt.insert(0,"")
  1899. if len(headersTxt)!=len(blocsTxt):
  1900. return False
  1901. return (headersTxt, blocsTxt)
  1902. else:
  1903. return False
  1904. class _file(_error):
  1905. """Класс для работы с файлами
  1906. """
  1907. def __init__(self):
  1908. # Имя файла конфигурационного файла
  1909. self.nameFileConfig = ""
  1910. # Содержимое конфигурационного файла
  1911. self.textConfig = ""
  1912. # Имя файла шаблона
  1913. self.nameFileTemplate = ""
  1914. # Содержимое шаблона
  1915. self.textTemplate = ""
  1916. # Дескриптор файла шаблона
  1917. self.F_TEMPL = False
  1918. # Дескриптор файла конфигурационного файла
  1919. self.F_CONF = False
  1920. def saveConfFile(self):
  1921. """Записать конфигурацию"""
  1922. if self.F_CONF:
  1923. self.F_CONF.truncate(0)
  1924. self.F_CONF.seek(0)
  1925. if not self.textConfig:
  1926. self.textConfig = self.textTemplate
  1927. try:
  1928. self.F_CONF.write(self.textConfig)
  1929. except:
  1930. self.setError(_("unable to open the file:" ) +
  1931. self.nameFileConfig)
  1932. return False
  1933. self.F_CONF.flush()
  1934. return True
  1935. def openTemplFile(self, nameFileTemplate):
  1936. """Открыть файл шаблона"""
  1937. F_TEMPL = False
  1938. try:
  1939. F_TEMPL = open(nameFileTemplate, "r")
  1940. except:
  1941. self.setError(_("unable to open the file:" ) + nameFileTemplate)
  1942. return False
  1943. return F_TEMPL
  1944. def closeTemplFile(self):
  1945. if self.F_TEMPL:
  1946. self.F_TEMPL.close()
  1947. self.F_TEMPL = False
  1948. def __closeOldFile(self):
  1949. if self.F_CONF:
  1950. self.F_CONF.close()
  1951. self.F_CONF = False
  1952. def __openConfFile(self, nameFileConfig):
  1953. """Отктрыть конфигурационный файл"""
  1954. F_CONF = False
  1955. try:
  1956. if os.path.islink(nameFileConfig):
  1957. # если ссылка то удаляем её
  1958. os.unlink(nameFileConfig)
  1959. F_CONF = open (nameFileConfig, "r+")
  1960. except:
  1961. try:
  1962. F_CONF = open(nameFileConfig, "w+")
  1963. except:
  1964. self.setError(_("unable to open the file:" ) + nameFileConfig)
  1965. return False
  1966. return F_CONF
  1967. def openFiles(self, nameFileTemplate, nameFileConfig):
  1968. """Открывает шаблон и конфигурационный файл"""
  1969. self.textConfig = ""
  1970. self.textTemplate = ""
  1971. self.closeFiles()
  1972. self.F_TEMPL = False
  1973. self.F_CONF = False
  1974. self.nameFileConfig = os.path.abspath(nameFileConfig)
  1975. self.nameFileTemplate = os.path.abspath(nameFileTemplate)
  1976. self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
  1977. self.F_CONF = self.__openConfFile(self.nameFileConfig)
  1978. if self.F_TEMPL and self.F_CONF:
  1979. self.textTemplate = self.F_TEMPL.read()
  1980. self.textConfig = self.F_CONF.read()
  1981. def __del__(self):
  1982. self.closeFiles()
  1983. def closeFiles(self):
  1984. """Закрытие файлов"""
  1985. self.closeTemplFile()
  1986. self.__closeOldFile()
  1987. class utfBin:
  1988. """Класс для преобразования в utf-8
  1989. преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
  1990. обратное преобразование
  1991. методы класса encode и decode
  1992. """
  1993. def _retUTF(self, char):
  1994. byte = ord(char)
  1995. if byte<=127:
  1996. return ('_ch_',1)
  1997. elif byte<=191:
  1998. return ('_nb_',1)
  1999. elif byte<=223:
  2000. return ('_fb_',2)
  2001. elif byte<=239:
  2002. return ('_fb_',3)
  2003. elif byte<=247:
  2004. return ('_fb_',4)
  2005. else:
  2006. return ('_er_',1)
  2007. def _sumbUtf(self, symbols, lenTail):
  2008. if not symbols:
  2009. return (False,0)
  2010. lenSymb = len(symbols)
  2011. if lenSymb >= 4:
  2012. l = 4
  2013. elif lenSymb >= 3:
  2014. l = 3
  2015. elif lenSymb >= 2:
  2016. l = 2
  2017. else:
  2018. if symbols[0] == '_ch_':
  2019. return (True,1)
  2020. else:
  2021. return (False,1)
  2022. result = False
  2023. for i in range(l):
  2024. if i == 0 and symbols[i] != '_fb_':
  2025. break
  2026. elif i > 0 and symbols[i] != '_nb_':
  2027. break
  2028. if lenTail>1 and lenTail != i:
  2029. return (False,1)
  2030. if i > 0:
  2031. result = True
  2032. return (result, i)
  2033. def _intToChar(self, x):
  2034. he = hex(x)[2:]
  2035. exec("ret = '\\x%s'" %he)
  2036. return ret
  2037. def _hexToChar(self, he):
  2038. exec("ret = '\\x%s'" %he)
  2039. return ret
  2040. def encode(self, text):
  2041. """Кодирует смешанный формат в UTF-8"""
  2042. ind = 0
  2043. l = 0
  2044. utf = []
  2045. lenUtf = []
  2046. indErr = []
  2047. i = 0
  2048. for ch in text:
  2049. r, l = self._retUTF(ch)
  2050. utf.append(r)
  2051. lenUtf.append(l)
  2052. i+=1
  2053. while 1:
  2054. if utf[ind] == '_fb_':
  2055. res, l = self._sumbUtf(utf[ind:],lenUtf[ind])
  2056. if res is False:
  2057. indErr.append(ind)
  2058. if l>0:
  2059. ind +=l
  2060. if ind >= len(utf):
  2061. break
  2062. else:
  2063. if utf[ind] != '_ch_':
  2064. indErr.append(ind)
  2065. ind +=1
  2066. if ind >= len(utf):
  2067. break
  2068. if indErr:
  2069. lenIndErr = len(indErr)
  2070. block = []
  2071. blocks = []
  2072. if lenIndErr > 1:
  2073. i = 1
  2074. while 1:
  2075. if i == 1:
  2076. block.append(indErr[i-1])
  2077. if indErr[i] - indErr[i-1] == 1:
  2078. block.append(indErr[i])
  2079. else:
  2080. if block:
  2081. blocks.append(block)
  2082. block = []
  2083. block.append(indErr[i])
  2084. i +=1
  2085. if i >= lenIndErr:
  2086. break
  2087. else:
  2088. block.append(indErr[0])
  2089. if block:
  2090. blocks.append(block)
  2091. listErr = []
  2092. for block in blocks:
  2093. string = ""
  2094. for elem in block:
  2095. string += hex(ord(text[elem]))[-2:]
  2096. listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
  2097. textOut = text
  2098. deltaInd = 0
  2099. for erEl in listErr:
  2100. startInd = erEl[0] + deltaInd
  2101. endInd = erEl[2] + 1 + deltaInd
  2102. textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
  2103. deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
  2104. #if i == 1:
  2105. #break
  2106. #i += 1
  2107. return textOut
  2108. def decode(self, text):
  2109. """Декодирует UTF-8 в смешанный формат"""
  2110. varStart = "__hex__\?"
  2111. varEnd = "\?__hex__"
  2112. # -1 Это экранирование '?' которое тоже считается
  2113. deltVarStart = len(varStart)-1
  2114. deltVarEnd = len(varEnd)-1
  2115. reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
  2116. resS = reVar.search(text)
  2117. textTemplateTmp = text
  2118. while resS:
  2119. mark = textTemplateTmp[resS.start():resS.end()]
  2120. hexString = mark[deltVarStart:-deltVarEnd]
  2121. i = 0
  2122. stringInsert = ""
  2123. hexCode = ""
  2124. for ch in hexString:
  2125. if i>=1:
  2126. hexCode += ch
  2127. stringInsert += self._hexToChar(hexCode)
  2128. hexCode = ""
  2129. i = 0
  2130. else:
  2131. hexCode += ch
  2132. i += 1
  2133. textTemplateTmp = textTemplateTmp.replace(mark, stringInsert)
  2134. resS = reVar.search(textTemplateTmp)
  2135. return textTemplateTmp
  2136. class templateFormat:
  2137. """Методы получения классов и объектов форматов шаблонов"""
  2138. # Импортированные классы поддерживаемых форматов шаблонов
  2139. importFormats = {}
  2140. def getClassObj(self, nameClassTemplate):
  2141. """Создает класс шаблона по имени"""
  2142. if nameClassTemplate in self.importFormats:
  2143. classFormat = self.importFormats[nameClassTemplate]
  2144. else:
  2145. try:
  2146. classFormat = getattr(__import__("format.%s"%nameClassTemplate,
  2147. globals(), locals(),
  2148. [nameClassTemplate]),
  2149. nameClassTemplate)
  2150. except (ImportError, AttributeError):
  2151. #Создаем объект из self.newObjProt с помощью
  2152. # метаклассов
  2153. if nameClassTemplate in self.newObjProt:
  2154. # Прототип класса
  2155. nameProt = self.newObjProt[nameClassTemplate]
  2156. if nameProt in self.importFormats:
  2157. classProt = self.importFormats[nameProt]
  2158. else:
  2159. try:
  2160. classProt = getattr(__import__("format.%s"%nameProt,
  2161. globals(), locals(),
  2162. [nameProt]),
  2163. nameProt)
  2164. except (ImportError, AttributeError):
  2165. return False
  2166. self.importFormats[nameProt] = classProt
  2167. classFormat = self.createNewClass(nameClassTemplate,
  2168. (classProt,))
  2169. else:
  2170. return False
  2171. self.importFormats[nameClassTemplate] = classFormat
  2172. return classFormat
  2173. def getFormatObj(self, formatTemplate, textTemplate):
  2174. """Создание объекта формата шаблона.
  2175. Объект создается на основании формата шаблона и текста шаблона"""
  2176. classFormat = self.getClassObj(formatTemplate)
  2177. if classFormat:
  2178. return classFormat(textTemplate)
  2179. else:
  2180. return False
  2181. class _shareTemplate:
  2182. """Общие аттрибуты для классов шаблонов"""
  2183. # Метка начала переменной
  2184. varStart = "#-"
  2185. # Метка конца переменной
  2186. varEnd = "-#"
  2187. _deltVarStart = len(varStart)
  2188. _deltVarEnd = len(varEnd)
  2189. def getDataUser(self, groupsInfo=False):
  2190. """Получить информацию о пользователе"""
  2191. userName = self.objVar.Get("ur_login")
  2192. if not userName:
  2193. userName = "root"
  2194. import pwd
  2195. try:
  2196. pwdObj = pwd.getpwnam(userName)
  2197. uid = pwdObj.pw_uid
  2198. gid = pwdObj.pw_gid
  2199. homeDir = pwdObj.pw_dir
  2200. except:
  2201. cl_overriding.printERROR(_("User %s not found")%str(userName))
  2202. cl_overriding.exit(1)
  2203. if groupsInfo:
  2204. import grp
  2205. try:
  2206. groupName = grp.getgrgid(gid).gr_name
  2207. except:
  2208. cl_overriding.printERROR(\
  2209. _("Id of group %s not found")%str(gid))
  2210. cl_overriding.exit(1)
  2211. groupsNames = map(lambda x: x.gr_name,\
  2212. filter(lambda x: userName in x.gr_mem, grp.getgrall()))
  2213. groupsNames = [groupName] + groupsNames
  2214. return uid, gid, homeDir, groupsNames
  2215. return uid, gid, homeDir
  2216. class templateFunction(_error, _shareTemplate, _shareTermsFunction):
  2217. """Класс для функций шаблонов"""
  2218. # Словарь установленных программ {"имя программы":[версии]}
  2219. installProg = {}
  2220. # Cписок просканированных категорий установленных программ
  2221. installCategory = []
  2222. # Флаг сканирования всех установленных программ
  2223. flagAllPkgScan = False
  2224. # Список названий функций шаблона
  2225. namesTemplateFunction = []
  2226. # Словарь {название функции шаблона: функция шаблона, ...}
  2227. templateFunction = {}
  2228. # Регулярное выражение для сложения
  2229. sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
  2230. # Регулярное выражение для умножениея и деления
  2231. sMD = re.compile("[^\-\+\*\/]+")
  2232. # директория установленных программ
  2233. basePkgDir = "/var/db/pkg"
  2234. # стек глобальных переменных
  2235. stackGlobalVars = []
  2236. # регулярное выражение для поиска версии
  2237. reFindVer = re.compile("(?<=-)(?:\d+)(?:(?:\.\d+)*)"
  2238. "(?:[a-z]?)(?:(?:_(?:pre|p|beta|alpha|rc)\d*)*)"
  2239. "(?:-r\d+)?$")
  2240. reEmptyLoad = re.compile("^\s*$|^\s*;|^\s*#")
  2241. # Имя обрабатываемого шаблона
  2242. nameTemplate = ""
  2243. # Текст функции шаблона
  2244. functText = ""
  2245. def __init__(self, objVar):
  2246. # Если не определен словарь функций шаблона
  2247. # import services api
  2248. from cl_api import packagesAPI, APIError
  2249. self.packagesAPI = packagesAPI
  2250. self.APIError = APIError
  2251. if not self.templateFunction:
  2252. # префикс функций шаблона
  2253. pref = "func"
  2254. # cписок [(название функции, функция), ...]
  2255. dictFunc = filter(lambda x: x[0].startswith(pref) and\
  2256. hasattr(x[1],"__call__"),
  2257. self.__class__.__dict__.items())
  2258. # удаляем у названия функции префикс и переводим остаток названия
  2259. # в нижний регистр
  2260. dictFunc = map(lambda x: (x[0][len(pref):].lower(), x[1]), dictFunc)
  2261. # Формируем словарь функций шаблона
  2262. self.templateFunction.update(dictFunc)
  2263. # Формируем список функций шаблона
  2264. for nameFunction in self.templateFunction.keys():
  2265. self.namesTemplateFunction.append(nameFunction)
  2266. # Объект хранения переменных
  2267. self.objVar = objVar
  2268. # Директория другой системы
  2269. self._chrootDir = self.objVar.Get("cl_chroot_path")
  2270. if self._chrootDir != '/':
  2271. # Изменение директории к базе пакетов
  2272. self.basePkgDir = pathJoin(self._chrootDir, self.basePkgDir)
  2273. self.basePkgDir = os.path.normpath(self.basePkgDir)
  2274. # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
  2275. self._baseDir=pathJoin(self._chrootDir,self.objVar.Get("cl_root_path"))
  2276. self._baseDir = os.path.normpath(self._baseDir)
  2277. self._reFunc = re.compile(("%s%s%s")\
  2278. %(self.varStart,self._reFunctionText,self.varEnd),re.M)
  2279. # Аттрибуты для функции шаблона ini()
  2280. # Первоначальный словарь переменных для ini()
  2281. self.prevDictIni = {}
  2282. # Текущий словарь переменных для ini()
  2283. self.currDictIni = {}
  2284. # Время модификации конфигурационного файла для ini()
  2285. self.timeIni = -1
  2286. self.uid, self.gid, self.homeDir, self.groups =\
  2287. self.getDataUser(groupsInfo=True)
  2288. # Домашняя директория, плюс базовая директория
  2289. self.homeDir = pathJoin(self._baseDir, self.homeDir)
  2290. # path to configuration file for ini() function
  2291. # if action is desktop configuration, then path in user directory
  2292. # else config file place in /etc/calculate
  2293. if self.objVar.Get('cl_action') == "desktop":
  2294. self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
  2295. self.modeConfigIni = 0640
  2296. else:
  2297. self.pathConfigIni = pathJoin(self._chrootDir,'/etc/calculate')
  2298. self.modeConfigIni = 0644
  2299. self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env")
  2300. # Словарь времен модификации env файлов
  2301. self.timeConfigsIni = {}
  2302. # Словарь хранения переменых полученных функцией env() из env файлов
  2303. self.valuesVarEnv = {}
  2304. # Словарь хранения опций для функции info()
  2305. self.optionsInfo = {}
  2306. # файл параметров сервисов
  2307. envFile = self.objVar.Get("cl_env_server_path")
  2308. # объект конвертирования из старого remote env файла
  2309. self.convObj = False
  2310. if os.access(envFile, os.R_OK):
  2311. self.convObj = False
  2312. elif os.access("/var/calculate/remote/calculate.env", os.R_OK):
  2313. from convertenv import convertEnv
  2314. self.convObj = convertEnv()
  2315. def equalTerm(self, term, localVars):
  2316. """Метод для вычисления выражения"""
  2317. terms = self.sNum.findall(term)
  2318. if terms:
  2319. strNumers = []
  2320. for n in terms:
  2321. strNum = n.strip()
  2322. if "*" in strNum or "/" in strNum:
  2323. strNum = self.multAndDiv(strNum,localVars)
  2324. try:
  2325. num = int(strNum)
  2326. except:
  2327. minus = False
  2328. if strNum[:1] == "-":
  2329. minus = True
  2330. strNum = strNum[1:]
  2331. if localVars.has_key(strNum):
  2332. try:
  2333. num = int(localVars[strNum])
  2334. except:
  2335. self.printErrTemplate()
  2336. cl_overriding.printERROR(\
  2337. _("error, variable %s not a number")%
  2338. str(strNum))
  2339. cl_overriding.exit(1)
  2340. elif self.objVar.exists(strNum):
  2341. try:
  2342. num = int(self.objVar.Get(strNum))
  2343. except:
  2344. self.printErrTemplate()
  2345. cl_overriding.printERROR(\
  2346. _("error, variable %s not a number")%
  2347. str(strNum))
  2348. cl_overriding.exit(1)
  2349. else:
  2350. self.printErrTemplate()
  2351. cl_overriding.printERROR(\
  2352. _("error, local variable %s is not defined")%
  2353. str(strNum))
  2354. cl_overriding.exit(1)
  2355. if minus:
  2356. num = -num
  2357. strNumers.append(num)
  2358. return sum(strNumers)
  2359. self.printErrTemplate()
  2360. cl_overriding.printERROR(_("error, template term %s, incorrect data")\
  2361. %str(term))
  2362. cl_overriding.exit(1)
  2363. def multAndDiv(self, term, localVars):
  2364. """Метод для умножения и деления"""
  2365. termTmp = term
  2366. varsLocal = self.sMD.findall(term)
  2367. for var in varsLocal:
  2368. flagVarTxt = True
  2369. try:
  2370. int(var)
  2371. except:
  2372. flagVarTxt = False
  2373. if flagVarTxt:
  2374. continue
  2375. varReplace = str(self.equalTerm(var, localVars))
  2376. termTmp = termTmp.replace(var,varReplace)
  2377. ret = eval(termTmp)
  2378. return ret
  2379. def funcSum(self, funArgv, resS, localVars, textTemplateTmp):
  2380. """Функция шаблона, вычисляет функцию sum()"""
  2381. terms = funArgv.replace(" ","").split(",")
  2382. # Название локальной переменной
  2383. nameLocVar = terms[0]
  2384. if not localVars.has_key(nameLocVar):
  2385. localVars[nameLocVar] = 0
  2386. if len(terms) == 2:
  2387. if terms[1].strip():
  2388. localVars[nameLocVar] = self.equalTerm(terms[1], localVars)
  2389. replace = str(localVars[nameLocVar])
  2390. else:
  2391. replace = ""
  2392. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2393. textTemplateTmp[resS.end():]
  2394. elif len(terms) == 3:
  2395. if terms[1].strip():
  2396. replaceInt = self.equalTerm(terms[1], localVars)
  2397. replace = str(replaceInt)
  2398. else:
  2399. replace = ""
  2400. localVars[nameLocVar] = self.equalTerm(terms[2], localVars)
  2401. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2402. textTemplateTmp[resS.end():]
  2403. else:
  2404. self.printErrTemplate()
  2405. cl_overriding.exit(1)
  2406. return textTemplateTmp
  2407. def funcExists(self, funArgv, resS, localVars, textTemplateTmp):
  2408. """Функция шаблона exists(),
  2409. проверяет существование файла, если существует выдает '1'
  2410. если второй параметр root, то проверка осуществляется от корня.
  2411. """
  2412. terms = map(lambda x: x.strip(), funArgv.split(","))
  2413. if len(terms) > 2:
  2414. self.printErrTemplate()
  2415. cl_overriding.exit(1)
  2416. fileName = terms[0]
  2417. flagNotRootFS = True
  2418. if len(terms) == 2:
  2419. if terms[1] == "root":
  2420. flagNotRootFS = False
  2421. else:
  2422. self.printErrTemplate()
  2423. cl_overriding.printERROR(\
  2424. _("The second argument of the function is not 'root'"))
  2425. cl_overriding.exit(1)
  2426. if fileName[0] == "~":
  2427. # Получаем директорию пользователя
  2428. fileName = os.path.join(self.homeDir,
  2429. fileName.partition("/")[2],"")[:-1]
  2430. elif fileName[0] != "/":
  2431. self.printErrTemplate()
  2432. cl_overriding.printERROR(_("wrong path '%s'")%fileName)
  2433. cl_overriding.exit(1)
  2434. else:
  2435. if flagNotRootFS:
  2436. fileName = pathJoin(self._baseDir, fileName)
  2437. replace = ""
  2438. if os.path.exists(fileName):
  2439. replace = "1"
  2440. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2441. textTemplateTmp[resS.end():]
  2442. return textTemplateTmp
  2443. def funcLoad(self, funArgv, resS, localVars, textTemplateTmp):
  2444. """Функция шаблона load(),
  2445. если файл существует читает из файла локальную переменную
  2446. если один параметр - выводит значение локальной переменной
  2447. """
  2448. terms = funArgv.split(",")
  2449. if terms:
  2450. lenTerms = len(terms)
  2451. if not terms[0].strip() or\
  2452. (lenTerms==2 and not terms[1].strip()) or\
  2453. (lenTerms==3 and not terms[2].strip()) or\
  2454. lenTerms>3:
  2455. self.printErrTemplate()
  2456. cl_overriding.exit(1)
  2457. else:
  2458. self.printErrTemplate()
  2459. cl_overriding.exit(1)
  2460. flagNotRootFS = True
  2461. if lenTerms == 3:
  2462. if terms[2] =="root":
  2463. flagNotRootFS = False
  2464. else:
  2465. self.printErrTemplate()
  2466. cl_overriding.printERROR(\
  2467. _("The third argument of the function is not 'root'"))
  2468. cl_overriding.exit(1)
  2469. if lenTerms >= 2:
  2470. if not terms[0] in ["ver","num","char","key","empty"]:
  2471. self.printErrTemplate()
  2472. cl_overriding.printERROR(\
  2473. _("the first argument of the function is not "
  2474. "'ver' or 'num' or 'char' or 'empty'"))
  2475. cl_overriding.exit(1)
  2476. if lenTerms == 1:
  2477. fileName = terms[0].strip()
  2478. else:
  2479. fileName = terms[1].strip()
  2480. # Если домашняя директория
  2481. if fileName[0] == "~":
  2482. # Получаем директорию пользователя
  2483. fileName = os.path.join(self.homeDir,
  2484. fileName.partition("/")[2],"")[:-1]
  2485. elif fileName[0] != "/":
  2486. self.printErrTemplate()
  2487. cl_overriding.printERROR(_("wrong path '%s'")%fileName)
  2488. cl_overriding.exit(1)
  2489. else:
  2490. if flagNotRootFS:
  2491. fileName = pathJoin(self._baseDir,fileName)
  2492. replace = ""
  2493. if os.path.exists(fileName):
  2494. FD = open(fileName)
  2495. replace = FD.read().strip()
  2496. FD.close
  2497. if replace and lenTerms >= 2 and terms[0] == "empty":
  2498. replace ="\n".join(filter(lambda x: not self.reEmptyLoad.search(x),
  2499. replace.split("\n")))
  2500. if not replace and lenTerms >= 2 and terms[0] in ["ver","num"]:
  2501. replace = "0"
  2502. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2503. textTemplateTmp[resS.end():]
  2504. return textTemplateTmp
  2505. def sharePkg(self, pkgs):
  2506. """Получение имен и номеров версий программ"""
  2507. pkgs.sort()
  2508. installProg = {}
  2509. for pkg in pkgs:
  2510. findVer = self.reFindVer.search(pkg)
  2511. if findVer:
  2512. version = findVer.group()
  2513. name = pkg.split(version)[0][:-1]
  2514. if name in installProg:
  2515. installProg[name].append(version)
  2516. else:
  2517. installProg[name] = [version]
  2518. return installProg
  2519. def getInstallPkgGentoo(self):
  2520. """Выдает словарь инсталлированных программ и номеров версий"""
  2521. pkgs = []
  2522. def getFilesDir(pkgs, dirname, names):
  2523. for nameFile in names:
  2524. absNameFile = os.path.join(dirname,nameFile)
  2525. if os.path.isdir(absNameFile):
  2526. tail = absNameFile.split(self.basePkgDir)
  2527. if len(tail)==2:
  2528. tail = tail[1].split('/')
  2529. if len(tail)==3 and tail[1]!='virtual':
  2530. pkgs.append(tail[2])
  2531. return True
  2532. os.path.walk(self.basePkgDir,getFilesDir, pkgs)
  2533. return self.sharePkg(pkgs)
  2534. def pkg(self, nameProg, installProg):
  2535. """Выдает установленные версии по имени программы"""
  2536. if nameProg in installProg:
  2537. return installProg[nameProg][-1]
  2538. else:
  2539. return ""
  2540. def funcPkg(self, funArgv, resS, localVars, textTemplateTmp):
  2541. """Функция шаблона pkg(), выдает номер версии программы"""
  2542. # Название программы
  2543. nameProg = funArgv.replace(" ","")
  2544. # Замена функции в тексте шаблона
  2545. replace = ""
  2546. if "/" in nameProg:
  2547. if nameProg in self.installProg:
  2548. replace = self.pkg(nameProg, self.installProg)
  2549. else:
  2550. category, spl, nProg = nameProg.partition("/")
  2551. if not category in self.installCategory:
  2552. self.installCategory.append(category)
  2553. pathCategory = os.path.join(self.basePkgDir, category)
  2554. if os.path.exists(pathCategory):
  2555. pkgs = os.listdir(pathCategory)
  2556. pkgs = map(lambda x: os.path.join(category,x),
  2557. pkgs)
  2558. installProg = self.sharePkg(pkgs)
  2559. replace = self.pkg(nameProg, installProg)
  2560. self.installProg.update(
  2561. filter(lambda x:not x[0] in self.installProg,
  2562. installProg.items()))
  2563. else:
  2564. if not self.flagAllPkgScan:
  2565. installProg = self.getInstallPkgGentoo()
  2566. self.installProg.update(
  2567. filter(lambda x:not x[0] in self.installProg,
  2568. installProg.items()))
  2569. templateFunction.flagAllPkgScan = True
  2570. replace = self.pkg(nameProg, self.installProg)
  2571. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2572. textTemplateTmp[resS.end():]
  2573. return textTemplateTmp
  2574. def funcRnd(self, funArgv, resS, localVars, textTemplateTmp):
  2575. """Функция шаблона rnd(), выдает строку случайных символов
  2576. первый аргумент:
  2577. 'num' - числа,
  2578. 'pas' - цифры и буквы
  2579. 'uuid' - цифры и строчные буквы a-f
  2580. второй аргумент:
  2581. количество символов
  2582. """
  2583. terms = funArgv.replace(" ","").split(",")
  2584. if not terms[0].strip() or\
  2585. (len(terms)==2 and not terms[1].strip()) or\
  2586. len(terms)!=2:
  2587. self.printErrTemplate()
  2588. cl_overriding.exit(1)
  2589. fArgvNames = {'num':string.digits,
  2590. 'pas':string.ascii_letters + string.digits,
  2591. 'uuid':string.ascii_lowercase[:6] + string.digits}
  2592. if not terms[0] in fArgvNames:
  2593. self.printErrTemplate()
  2594. cl_overriding.printERROR(\
  2595. _("the first argument of the function "
  2596. "must be 'num','pas' or 'uuid'"))
  2597. cl_overriding.exit(1)
  2598. try:
  2599. lenStr = int(terms[1])
  2600. except:
  2601. self.printErrTemplate()
  2602. cl_overriding.printERROR(\
  2603. _("the second argument of the function is not a number"))
  2604. cl_overriding.exit(1)
  2605. choiceStr = fArgvNames[terms[0]]
  2606. replace = ''.join([random.choice(choiceStr) for i in xrange(lenStr)])
  2607. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2608. textTemplateTmp[resS.end():]
  2609. return textTemplateTmp
  2610. def funcCase(self, funArgv, resS, localVars, textTemplateTmp):
  2611. """Функция шаблона case(), выдает переменную в определенном регистре
  2612. первый аргумент:
  2613. 'upper' - верхний регистр,
  2614. 'lower' - нижний регистр,
  2615. 'capitalize' - первая буква в верхнем регистре
  2616. второй аргумент:
  2617. название переменной
  2618. """
  2619. terms = funArgv.replace(" ","").split(",")
  2620. if not terms[0].strip() or\
  2621. (len(terms)==2 and not terms[1].strip()) or len(terms)!=2:
  2622. self.printErrTemplate()
  2623. cl_overriding.exit(1)
  2624. fArgvNames = ['upper','lower','capitalize']
  2625. if not terms[0] in fArgvNames:
  2626. self.printErrTemplate()
  2627. cl_overriding.printERROR(_("the first argument of the function is "
  2628. "not 'upper' or 'lower' or 'capitalize'"))
  2629. cl_overriding.exit(1)
  2630. try:
  2631. strValue = str(self.objVar.Get(terms[1]))
  2632. except:
  2633. cl_overriding.printERROR(_("error in template %s")\
  2634. %self.nameTemplate)
  2635. cl_overriding.printERROR(_("error, variable %s not found")%
  2636. str(terms[1]))
  2637. cl_overriding.exit(1)
  2638. replace = ""
  2639. strValue = _toUNICODE(strValue)
  2640. if terms[0] == 'upper':
  2641. replace = strValue.upper()
  2642. elif terms[0] == 'lower':
  2643. replace = strValue.lower()
  2644. elif terms[0] == 'capitalize':
  2645. replace = strValue.capitalize()
  2646. if replace:
  2647. replace = replace.encode("UTF-8")
  2648. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2649. textTemplateTmp[resS.end():]
  2650. return textTemplateTmp
  2651. def funcPush(self, funArgv, resS, localVars, textTemplateTmp):
  2652. """локальная функция записывает значение переменной
  2653. в стек глобальных переменных
  2654. """
  2655. terms = funArgv.replace(" ","").split(",")
  2656. # Название локальной переменной
  2657. nameLocVar = terms[0]
  2658. flagFoundVar = False
  2659. if nameLocVar in localVars.keys():
  2660. flagFoundVar = True
  2661. value = localVars[nameLocVar]
  2662. else:
  2663. try:
  2664. value = self.objVar.Get(nameLocVar)
  2665. flagFoundVar = True
  2666. except:
  2667. pass
  2668. if flagFoundVar:
  2669. # Если переменная существует
  2670. if len(terms) == 1:
  2671. self.stackGlobalVars.append(str(value))
  2672. else:
  2673. self.printErrTemplate()
  2674. cl_overriding.printERROR(_("error, variable %s exists")\
  2675. %str(nameLocVar))
  2676. cl_overriding.exit(1)
  2677. else:
  2678. # Если переменная не существует
  2679. if len(terms) == 1:
  2680. self.printErrTemplate()
  2681. cl_overriding.printERROR(_("error, variable %s does not exist")\
  2682. %str(nameLocVar))
  2683. cl_overriding.exit(1)
  2684. elif len(terms) == 2:
  2685. value = terms[1].strip()
  2686. self.stackGlobalVars.append(str(value))
  2687. localVars[nameLocVar] = value
  2688. else:
  2689. self.printErrTemplate()
  2690. cl_overriding.exit(1)
  2691. replace = ""
  2692. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2693. textTemplateTmp[resS.end():]
  2694. return textTemplateTmp
  2695. def funcPop(self, funArgv, resS, localVars, textTemplateTmp):
  2696. """локальная функция получает значение
  2697. из стека глобальных переменных и присваивает локальной переменной
  2698. """
  2699. terms = funArgv.replace(" ","").split(",")
  2700. # Название локальной переменной
  2701. nameLocVar = terms[0]
  2702. if len(terms) == 1:
  2703. if self.stackGlobalVars:
  2704. localVars[nameLocVar] = self.stackGlobalVars.pop()
  2705. else:
  2706. self.printErrTemplate()
  2707. cl_overriding.printERROR(\
  2708. _("error, global variables stack is empty"))
  2709. cl_overriding.exit(1)
  2710. else:
  2711. self.printErrTemplate()
  2712. cl_overriding.exit(1)
  2713. replace = ""
  2714. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2715. textTemplateTmp[resS.end():]
  2716. return textTemplateTmp
  2717. def loadVarsIni(self, iniFileName):
  2718. """ Читает файл fileName
  2719. создает и заполняет переменные на основе этого файла
  2720. Используеться совместно c funcIni
  2721. """
  2722. localVarsIni = {}
  2723. # получить объект ini файла
  2724. config = iniParser(iniFileName)
  2725. # получаем все секции из конфигурационного файла
  2726. allsect = config.getAllSectionNames()
  2727. if not allsect:
  2728. if self.getError():
  2729. # Очистка ошибки
  2730. _error.error = []
  2731. return localVarsIni
  2732. # Заполняем переменные для funcIni
  2733. for sect in allsect:
  2734. sectVars = config.getAreaVars(sect)
  2735. for name in sectVars.keys():
  2736. nameVar = "%s.%s"%(sect,name)
  2737. valueVar = sectVars[name]
  2738. localVarsIni[nameVar] = valueVar
  2739. return localVarsIni
  2740. def getTimeFile(self, fileName):
  2741. # Получаем время модификации файла
  2742. nameEnvFile = os.path.split(fileName)[1]
  2743. if nameEnvFile in self.timeConfigsIni:
  2744. return self.timeConfigsIni[nameEnvFile]
  2745. return 0
  2746. def funcIni(self, funArgv, resS, localVars, textTemplateTmp):
  2747. """локальная функция записывает и считывает значение переменной
  2748. из ini файла ~./calculate/ini.env
  2749. """
  2750. # Создаем директорию
  2751. if not os.path.exists(self.pathConfigIni):
  2752. os.makedirs(self.pathConfigIni)
  2753. os.chown(self.pathConfigIni, self.uid, self.gid)
  2754. termsRaw = funArgv.split(",")
  2755. flagFirst = True
  2756. terms = []
  2757. for term in termsRaw:
  2758. if flagFirst:
  2759. terms.append(term.replace(" ",""))
  2760. flagFirst = False
  2761. else:
  2762. val = term.strip()
  2763. # Флаг (не найдены кавычки)
  2764. flagNotFoundQuote = True
  2765. for el in ('"',"'"):
  2766. if val.startswith(el) and val.endswith(el):
  2767. terms.append(val[1:-1])
  2768. flagNotFoundQuote = False
  2769. break
  2770. if flagNotFoundQuote:
  2771. if not val:
  2772. terms.append(None)
  2773. else:
  2774. terms.append(val)
  2775. # Название локальной переменной
  2776. nameLocVar = terms[0]
  2777. namesVar = nameLocVar.split(".")
  2778. if len(namesVar) == 1:
  2779. nameLocVar = "main.%s"%nameLocVar
  2780. elif len(namesVar)>2:
  2781. self.printErrTemplate()
  2782. cl_overriding.exit(1)
  2783. replace = ""
  2784. # Получаем время модификации конфигурационного файла
  2785. curTime = self.getTimeFile(self.fileConfigIni)
  2786. if len(terms) == 1:
  2787. if self.timeIni != curTime:
  2788. # читаем переменные из файла
  2789. self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
  2790. self.currDictIni= {}
  2791. self.currDictIni.update(self.prevDictIni)
  2792. self.timeIni = self.getTimeFile(self.fileConfigIni)
  2793. if nameLocVar in self.currDictIni.keys():
  2794. if self.currDictIni[nameLocVar] is None:
  2795. replace = ""
  2796. else:
  2797. replace = self.currDictIni[nameLocVar].encode("UTF-8")
  2798. elif len(terms) == 2:
  2799. if self.timeIni != curTime:
  2800. # читаем переменные из файла
  2801. self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
  2802. self.currDictIni= {}
  2803. self.currDictIni.update(self.prevDictIni)
  2804. self.timeIni = self.getTimeFile(self.fileConfigIni)
  2805. # Значение локальной переменной
  2806. valueLocVar = terms[1]
  2807. self.currDictIni[nameLocVar] = valueLocVar
  2808. elif len(terms) == 3:
  2809. if not terms[2] in ['url','purl','unicode']:
  2810. self.printErrTemplate()
  2811. cl_overriding.printERROR(_("the third argument of the function"
  2812. " is not 'url' or 'purl' or 'unicode'"))
  2813. cl_overriding.exit(1)
  2814. if terms[1]:
  2815. self.printErrTemplate()
  2816. cl_overriding.exit(1)
  2817. if self.timeIni != curTime:
  2818. # читаем переменные из файла
  2819. self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
  2820. self.currDictIni= {}
  2821. self.currDictIni.update(self.prevDictIni)
  2822. self.timeIni = self.getTimeFile(self.fileConfigIni)
  2823. if nameLocVar in self.currDictIni.keys():
  2824. unicodeValue = self.currDictIni[nameLocVar]
  2825. if unicodeValue is None:
  2826. unicodeValue = ""
  2827. if terms[2] in ('url', 'purl'):
  2828. replace = unicodeValue.encode("UTF-8").\
  2829. __repr__()[1:-1].replace('\\x','%').\
  2830. replace(' ','%20')
  2831. if terms[2] == 'purl':
  2832. replace = replace.replace('/','%2f')
  2833. elif terms[2] == 'unicode':
  2834. replace = unicodeValue.__repr__()[2:-1]
  2835. else:
  2836. self.printErrTemplate()
  2837. cl_overriding.exit(1)
  2838. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2839. textTemplateTmp[resS.end():]
  2840. return (textTemplateTmp)
  2841. def funcReplace(self, funArgv, resS, localVars, textTemplateTmp):
  2842. """локальная функция заменяет в значении переменной old на new
  2843. replace(old, new, name_var_template)
  2844. одинарные и двойные кавычки должны быть обязательно использованы
  2845. в первых двух аргументах old и new
  2846. "test\ntest" - преобразование строки (строка с переводом)
  2847. 'test\ntest' - без преобразования (одна строка)
  2848. """
  2849. def getStrArgv(terms):
  2850. """Определяет в двойных или одинарных кавычках параметры
  2851. Результат [(тип, аргумент),...] [("double", arg1).]
  2852. """
  2853. listArgv = []
  2854. for term in terms:
  2855. if term.startswith('"') and term.endswith('"'):
  2856. replTerms = [(r"\'", "'"), (r'\"', '"'), (r'\n', '\n'),
  2857. (r'\r', '\r'), (r'\t', '\t'), (r"\\", "\\")]
  2858. textArgv = term[1:-1]
  2859. for replTerm in replTerms:
  2860. textArgv = textArgv.replace(*replTerm)
  2861. listArgv.append(textArgv)
  2862. elif term.startswith("'") and term.endswith("'"):
  2863. listArgv.append(term[1:-1])
  2864. else:
  2865. self.printErrTemplate()
  2866. cl_overriding.exit(1)
  2867. return listArgv
  2868. terms = map(lambda x: x.strip(), funArgv.split(","))
  2869. if len(terms) != 3:
  2870. self.printErrTemplate()
  2871. cl_overriding.exit(1)
  2872. listArgv = getStrArgv(terms[:2])
  2873. old = listArgv[0]
  2874. new = listArgv[1]
  2875. nameVar = terms[2]
  2876. # Получаем значение переменной
  2877. if nameVar in localVars:
  2878. value = str(localVars[nameVar])
  2879. else:
  2880. try:
  2881. value = str(self.objVar.Get(nameVar))
  2882. except:
  2883. self.printErrTemplate()
  2884. cl_overriding.printERROR(_("not found template variable '%s'")\
  2885. %str(nameVar))
  2886. cl_overriding.exit(1)
  2887. replace = value.replace(old,new)
  2888. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2889. textTemplateTmp[resS.end():]
  2890. return textTemplateTmp
  2891. def funcEnv(self, funArgv, resS, localVars, textTemplateTmp):
  2892. """Функция шаблона env(), выдает значение переменной из env файлов
  2893. """
  2894. terms = funArgv.replace(" ","").split(",")
  2895. if len(terms) != 1:
  2896. self.printErrTemplate()
  2897. cl_overriding.exit(1)
  2898. nameVar = terms[0]
  2899. replace = ''
  2900. if nameVar in self.valuesVarEnv:
  2901. replace = self.valuesVarEnv[nameVar]
  2902. else:
  2903. # Получаем значение из env файлов
  2904. value = self.objVar.GetIniVar(nameVar)
  2905. if value is False:
  2906. self.printErrTemplate()
  2907. errMsg = self.getError()
  2908. if errMsg:
  2909. cl_overriding.printERROR(errMsg)
  2910. cl_overriding.exit(1)
  2911. self.valuesVarEnv[nameVar] = value
  2912. replace = value
  2913. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2914. textTemplateTmp[resS.end():]
  2915. return textTemplateTmp
  2916. def funcServer(self, funArgv, resS, localVars, textTemplateTmp):
  2917. """Функция шаблона info(), выдает значение опций сервиса
  2918. из /var/calculate/remote/calculate.env
  2919. """
  2920. terms = funArgv.replace(" ","").split(",")
  2921. if len(terms)==0 or len(terms)>2:
  2922. self.printErrTemplate()
  2923. cl_overriding.exit(1)
  2924. nameLocalVar = ""
  2925. if len(terms)==2:
  2926. if not terms[1]:
  2927. self.printErrTemplate()
  2928. cl_overriding.exit(1)
  2929. nameLocalVar = terms[1]
  2930. textLine = terms[0]
  2931. vals = textLine.split(".")
  2932. if len(vals)!= 2:
  2933. self.printErrTemplate()
  2934. cl_overriding.exit(1)
  2935. if filter(lambda x: not x.strip(), vals):
  2936. self.printErrTemplate()
  2937. cl_overriding.exit(1)
  2938. service, option = vals
  2939. if not service or not option:
  2940. self.printErrTemplate()
  2941. cl_overriding.exit(1)
  2942. if not self.optionsInfo:
  2943. # файл /var/calculate/remote/server.env
  2944. envFile = self.objVar.Get("cl_env_server_path")
  2945. # получаем словарь всех информационных переменных
  2946. if self.convObj:
  2947. optInfo = self.convObj.convert()
  2948. else:
  2949. optInfo = self.objVar.GetRemoteInfo(envFile)
  2950. if optInfo is False:
  2951. self.printErrTemplate()
  2952. cl_overriding.exit(1)
  2953. if optInfo:
  2954. self.optionsInfo = optInfo
  2955. replace = ''
  2956. if service in self.optionsInfo and option in self.optionsInfo[service]:
  2957. value = self.optionsInfo[service][option]
  2958. if nameLocalVar:
  2959. localVars[nameLocalVar] = value
  2960. else:
  2961. replace = value
  2962. elif nameLocalVar:
  2963. localVars[nameLocalVar] = ""
  2964. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2965. textTemplateTmp[resS.end():]
  2966. return textTemplateTmp
  2967. def funcGroups(self, funArgv, resS, localVars, textTemplateTmp):
  2968. """Функция шаблона groups(),
  2969. проверяет нахождение пользователя в группах, если находится выдает '1'
  2970. """
  2971. terms = map(lambda x: x.strip(), funArgv.split(","))
  2972. groupNames = set(terms)
  2973. userGroups = set(self.groups)
  2974. replace = ""
  2975. if groupNames & userGroups:
  2976. replace = "1"
  2977. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  2978. textTemplateTmp[resS.end():]
  2979. return textTemplateTmp
  2980. def funcBelong(self, funArgv, resS, localVars, textTemplateTmp):
  2981. """Функция шаблона belong().
  2982. В случае установки переменной os_belongs_pkg=имя пакета, и совпадения
  2983. имени пакета в переменной и имени пакета в функции выдает "1" иначе ""
  2984. Если переменная os_belongs_pkg пуста выдает "1"
  2985. """
  2986. terms = funArgv.replace(" ","").split(",")
  2987. if len(terms) != 1:
  2988. self.printErrTemplate()
  2989. cl_overriding.exit(1)
  2990. funcPkg = terms[0]
  2991. if not funcPkg:
  2992. funcPkg = os.path.split(os.path.dirname(self.nameTemplate))[1]
  2993. if not funcPkg:
  2994. cl_overriding.printERROR(_("incorrect template path"))
  2995. self.printErrTemplate()
  2996. cl_overriding.exit(1)
  2997. pkg = self.objVar.Get("cl_belong_pkg")
  2998. replace = ""
  2999. if pkg:
  3000. if pkg == funcPkg:
  3001. replace = "1"
  3002. else:
  3003. replace = "1"
  3004. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  3005. textTemplateTmp[resS.end():]
  3006. return textTemplateTmp
  3007. def funcList(self, funArgv, resS, localVars, textTemplateTmp):
  3008. """Функция шаблона list().
  3009. Если первый аргумент является именем локальной или глобальной
  3010. переменной и значение переменной является списком, выдает
  3011. элемент списка по второму аргументу индексу.
  3012. Первый элемент имеет индекс 0
  3013. """
  3014. terms = funArgv.replace(" ","").split(",")
  3015. # У функции должно быть два аргумента
  3016. if len(terms) != 2:
  3017. self.printErrTemplate()
  3018. cl_overriding.exit(1)
  3019. # Название локальной или глобальной переменной
  3020. nameLocVar = terms[0]
  3021. strIndex = terms[1]
  3022. try:
  3023. intIndex = int(strIndex)
  3024. except:
  3025. cl_overriding.printERROR(_("'%s' is not a number")%strIndex)
  3026. self.printErrTemplate()
  3027. cl_overriding.exit(1)
  3028. flagFoundVar = False
  3029. if nameLocVar in localVars.keys():
  3030. flagFoundVar = True
  3031. value = localVars[nameLocVar]
  3032. else:
  3033. try:
  3034. value = self.objVar.Get(nameLocVar)
  3035. flagFoundVar = True
  3036. except:
  3037. pass
  3038. if not flagFoundVar:
  3039. # Если переменная не существует
  3040. cl_overriding.printERROR(_("error, variable %s does not exist")\
  3041. %str(nameLocVar))
  3042. self.printErrTemplate()
  3043. cl_overriding.exit(1)
  3044. if not type(value) in (list,tuple):
  3045. # Значение переменной не список или кортеж
  3046. cl_overriding.printERROR(_("value of %s is not a list or a tuple")\
  3047. %str(nameLocVar))
  3048. self.printErrTemplate()
  3049. cl_overriding.exit(1)
  3050. try:
  3051. if len(value) > intIndex:
  3052. replace = str(value[intIndex])
  3053. else:
  3054. replace = ""
  3055. except:
  3056. cl_overriding.printERROR(_("wrong %s")%strIndex)
  3057. self.printErrTemplate()
  3058. cl_overriding.exit(1)
  3059. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  3060. textTemplateTmp[resS.end():]
  3061. return textTemplateTmp
  3062. def funcDisk(self, funArgv, resS, localVars, textTemplateTmp):
  3063. """Функция шаблона disk().
  3064. Первый аргумент ищется в значении переменной os_disk_install
  3065. (значение os_install_disk_mount - список точек монтирования при установке)
  3066. второй аргумент используется для поиска в переменной
  3067. os_disk_второй_аргумент (значение os_disk_второй_аргумент - список)
  3068. В os_install_disk_mount ищется первый аргумент, находим его индекс
  3069. результат - элемент cписка из os_disk_второй_аргумент с этим индексом
  3070. """
  3071. terms = funArgv.replace(" ","").split(",")
  3072. # У функции должно быть два аргумента
  3073. if len(terms) != 2:
  3074. self.printErrTemplate()
  3075. cl_overriding.exit(1)
  3076. # Название глобальной переменной
  3077. mountPoint = terms[0]
  3078. lastElementVar = terms[1]
  3079. if not mountPoint or mountPoint[:1] !="/":
  3080. cl_overriding.printERROR(_("wrong %s")%lastElementVar)
  3081. self.printErrTemplate()
  3082. cl_overriding.exit(1)
  3083. nameVar = "os_install_disk_mount"
  3084. try:
  3085. valueVar = self.objVar.Get(nameVar)
  3086. except:
  3087. # Если переменная не существует
  3088. cl_overriding.printERROR(_("error, variable %s does not exist")%
  3089. nameVar)
  3090. self.printErrTemplate()
  3091. cl_overriding.exit(1)
  3092. nameElementVar = "os_install_disk_%s"%lastElementVar
  3093. try:
  3094. valueElementVar = self.objVar.Get(nameElementVar)
  3095. except:
  3096. # Если переменная не существует
  3097. nameElementVar = "os_disk_%s"%lastElementVar
  3098. try:
  3099. valueElementVar = self.objVar.Get(nameElementVar)
  3100. except:
  3101. cl_overriding.printERROR(_("wrong %s")%lastElementVar)
  3102. cl_overriding.printERROR(_("error, variable %s does not exist")\
  3103. %nameElementVar)
  3104. self.printErrTemplate()
  3105. cl_overriding.exit(1)
  3106. if not type(valueVar) in (list,tuple):
  3107. # Значение переменной не список или кортеж
  3108. cl_overriding.printERROR(_("value of %s is not a list or a tuple")\
  3109. %nameVar)
  3110. self.printErrTemplate()
  3111. cl_overriding.exit(1)
  3112. if not type(valueElementVar) in (list,tuple):
  3113. # Значение переменной не список или кортеж
  3114. cl_overriding.printERROR(_("value of %s is not a list or a tuple")\
  3115. %nameElementVar)
  3116. self.printErrTemplate()
  3117. cl_overriding.exit(1)
  3118. if len(valueVar) != len(valueElementVar):
  3119. cl_overriding.printERROR(\
  3120. _("size %(name)s is not equal to the size of %(nameElement)s")\
  3121. %{'name':nameVar, 'nameElement':nameElementVar})
  3122. self.printErrTemplate()
  3123. cl_overriding.exit(1)
  3124. index = None
  3125. for num, mPoint in enumerate(valueVar):
  3126. if mountPoint == mPoint:
  3127. index = num
  3128. break
  3129. if index is None:
  3130. for num, mPoint in enumerate(valueVar):
  3131. if "/" == mPoint:
  3132. index = num
  3133. break
  3134. if index is None:
  3135. cl_overriding.printERROR(_("mount point '\\' or '\\%s' not found "
  3136. "in the value of variable os_disk_install")%mountPoint)
  3137. self.printErrTemplate()
  3138. cl_overriding.exit(1)
  3139. replace = valueElementVar[index]
  3140. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  3141. textTemplateTmp[resS.end():]
  3142. return textTemplateTmp
  3143. def funcModule(self, funArgv, resS, localVars, textTemplateTmp):
  3144. """Функция шаблона module(), выдает значение аттрибута api.
  3145. аргумент:
  3146. путь_к_атрибуту - путь к аттрибуту
  3147. возможные пути:
  3148. имя_пакета.var.имя_переменной - получаем значение переменной
  3149. имя_пакета.имя_метода_api - выполнение метода, получение результата
  3150. all.имя_метода_api - выполнение метода для всех пакетов с api
  3151. """
  3152. terms = funArgv.replace(" ","").split(",")
  3153. if len(terms)!=1:
  3154. self.printErrTemplate()
  3155. cl_overriding.exit(1)
  3156. pathObj = terms[0]
  3157. if not '.' in pathObj:
  3158. self.printErrTemplate()
  3159. cl_overriding.exit(1)
  3160. pkgApiObj = self.packagesAPI()
  3161. try:
  3162. value = eval('pkgApiObj.%s'%pathObj)
  3163. except self.APIError, e:
  3164. cl_overriding.printERROR(str(e))
  3165. self.printErrTemplate()
  3166. cl_overriding.exit(1)
  3167. except Exception, e:
  3168. value = ""
  3169. if value is True:
  3170. replace = '1'
  3171. elif value in (False, None):
  3172. replace = ''
  3173. else:
  3174. replace = str(value)
  3175. textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
  3176. textTemplateTmp[resS.end():]
  3177. return textTemplateTmp
  3178. def printErrTemplate(self):
  3179. """Печать ошибки при обработке функций шаблона"""
  3180. cl_overriding.printERROR(_("error in template %s")%self.nameTemplate)
  3181. cl_overriding.printERROR(_("error, template term '%s'")\
  3182. %str(self.functText))
  3183. def applyFuncTemplate(self, textTemplate, nameTemplate):
  3184. """Применяет функции к тексту шаблона"""
  3185. # Локальные переменные
  3186. localVars = {}
  3187. # Имя обрабатываемого шаблона
  3188. self.nameTemplate = nameTemplate
  3189. # Регулярное выражение для поиска функции в шаблоне
  3190. reFunc = self._reFunc
  3191. resS = reFunc.search(textTemplate)
  3192. textTemplateTmp = textTemplate
  3193. flagIniFunc = False
  3194. while resS:
  3195. mark = textTemplateTmp[resS.start():resS.end()]
  3196. self.functText = mark[self._deltVarStart:-self._deltVarEnd]
  3197. funcName, spl, funcEnd = self.functText.partition("(")
  3198. if funcName in self.namesTemplateFunction:
  3199. # аргументы функции - '(' аргументы ')'
  3200. funArgv = funcEnd.rpartition(")")[0]
  3201. # вызов функции шаблона
  3202. textTemplateTmp = self.templateFunction[funcName](self, funArgv,
  3203. resS, localVars,
  3204. textTemplateTmp)
  3205. resS = reFunc.search(textTemplateTmp)
  3206. if funcName == "ini":
  3207. flagIniFunc = True
  3208. else:
  3209. self.printErrTemplate()
  3210. cl_overriding.printERROR(\
  3211. _("function of templates '%s' not found")\
  3212. %str(self.functText))
  3213. cl_overriding.exit(1)
  3214. if flagIniFunc:
  3215. # Очистка файла в случае его ошибочного чтения
  3216. if not self.prevDictIni and os.path.exists(self.fileConfigIni):
  3217. FD = open(self.fileConfigIni, "r+")
  3218. FD.truncate(0)
  3219. FD.seek(0)
  3220. FD.close()
  3221. # Если конф. файл модифицирован шаблоном
  3222. curTime = self.getTimeFile(self.fileConfigIni)
  3223. if curTime != self.timeIni:
  3224. # Считаем переменные из конф. файла
  3225. self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
  3226. self.currDictIni.update(self.prevDictIni)
  3227. self.timeIni = curTime
  3228. # Если словари переменных не совпадают
  3229. if self.prevDictIni != self.currDictIni:
  3230. # Запишем переменные в конфигурационный файл
  3231. # Создание объекта парсера
  3232. config = iniParser(self.fileConfigIni)
  3233. # set specified mode for ini file
  3234. config.setMode(self.modeConfigIni)
  3235. # секции будущего конфигурационного файла
  3236. sects = list(set(map(lambda x: x.split(".")[0],\
  3237. self.currDictIni.keys())))
  3238. # запись переменных в файл
  3239. for sect in sects:
  3240. dictVar = {}
  3241. for varName in self.currDictIni.keys():
  3242. if varName.startswith("%s."%sect):
  3243. nameVar = varName.rpartition(".")[2]
  3244. valueVar = self.currDictIni[varName]
  3245. if valueVar is None:
  3246. config.delVar(sect,nameVar)
  3247. else:
  3248. dictVar[nameVar] = valueVar
  3249. if dictVar:
  3250. # Запись переменных в секцию
  3251. config.setVar(sect, dictVar)
  3252. # читаем переменные из файла
  3253. self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
  3254. self.currDictIni.update(self.prevDictIni)
  3255. self.timeConfigsIni[self.fileConfigIni] = float(time.time())
  3256. self.timeIni = self.getTimeFile(self.fileConfigIni)
  3257. # Меняем владельца в случае необходимости
  3258. if os.path.exists(self.fileConfigIni):
  3259. uid, gid = getModeFile(self.fileConfigIni, "owner")
  3260. if self.uid!=uid or self.gid!=gid:
  3261. os.chown(self.fileConfigIni, self.uid, self.gid)
  3262. return textTemplateTmp
  3263. class template(_file,_terms,_warning,xmlShare,templateFormat,_shareTemplate):
  3264. """Класс для работы с шаблонами
  3265. На вход 2 параметра: объект хранения переменных, имя сервиса - не
  3266. обязательный параметр
  3267. """
  3268. # Название файла шаблона директории
  3269. templDirNameFile = ".calculate_directory"
  3270. titleEnd = "For modify this file, create %(conf_path)s.clt template."
  3271. protectPaths = []
  3272. if "CONFIG_PROTECT" in os.environ:
  3273. protectPaths = ["/etc"] + filter(lambda x: x.strip(),
  3274. os.environ["CONFIG_PROTECT"].split(" "))
  3275. protectPaths = map(lambda x: os.path.normpath(x), protectPaths)
  3276. def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[],
  3277. cltObj=True, cltFilter=True, printWarning=True):
  3278. # Предупреждения
  3279. self.warning = []
  3280. # Печатать ли предупреждения о корневых шаблонах без cl_name==pkg
  3281. self.printWarning = printWarning
  3282. # Необрабатываемые директории
  3283. self.dirsFilter = dirsFilter
  3284. # Необрабатываемые файлы
  3285. self.filesFilter = filesFilter
  3286. _file.__init__(self)
  3287. # Словарь для создания объектов новых классов по образцу
  3288. self.newObjProt = {'proftpd':'apache'}
  3289. # Заголовок title
  3290. self.__titleHead = "--------------------------------------\
  3291. ----------------------------------------"
  3292. self._titleBody = ""
  3293. self._titleList = ("Modified", "Processing template files" + ":")
  3294. self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(self.varStart,
  3295. self.varEnd),re.M)
  3296. # Условия
  3297. self._reTermBloc = re.compile("#\?(?P<rTerm>[a-zA-Z0-9\-_]+)\
  3298. (?P<func>\((%s+|)\))?\
  3299. (?P<lTerm>[\>\<\=\!\&\|]+\
  3300. [\>\<\=\!\|\&\(\)%s]*)#\
  3301. \n*(?P<body>.+?)\n*#(?P=rTerm)#(?P<end>[ ,\t]*\n?)"\
  3302. %(self._reFunctionArgvText, self._reFunctionArgvInSquareBrackets),
  3303. re.M|re.S)
  3304. # Объект с переменными
  3305. self.objVar = objVar
  3306. # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
  3307. self._baseDir = pathJoin(self.objVar.Get("cl_chroot_path"),
  3308. self.objVar.Get("cl_root_path"))
  3309. self._baseDir = os.path.normpath(self._baseDir)
  3310. # Последняя часть директории шаблона (имя сервиса: samba, mail)
  3311. self._servDir = servDir
  3312. if self._servDir:
  3313. if self._servDir[0] != "/":
  3314. self._servDir = "/" + self._servDir
  3315. if self._servDir[-1] != "/":
  3316. self._servDir += "/"
  3317. self._servDir = os.path.split(self._servDir)[0]
  3318. # Созданные директории
  3319. self.createdDirs = []
  3320. # Примененные файлы
  3321. self.filesApply = []
  3322. # номер обрабатываемого файла
  3323. self.numberProcessTempl = 0
  3324. # имя текущей программы
  3325. _nameProgram = self.objVar.Get("cl_name").capitalize()
  3326. # версия текущей программы
  3327. _versionProgram = self.objVar.Get("cl_ver")
  3328. # имя и версия текущей программы
  3329. self.programVersion = "%s %s"%(_nameProgram, _versionProgram)
  3330. # Словарь директорий с количеством файлов шаблонов
  3331. self.dictTemplates = {}
  3332. # Общее количество шаблонов
  3333. self.allTemplates = 0
  3334. # Объект функций шаблона
  3335. self.functObj = templateFunction(self.objVar)
  3336. # Метод применения функций к шаблонам
  3337. self.applyFuncTemplate = self.functObj.applyFuncTemplate
  3338. # Объект для определения типа файла шаблона
  3339. self.typeFileObj = typeFile()
  3340. self.uid, self.gid, self.homeDir = self.getDataUser()
  3341. # Домашняя директория, плюс базовая директория
  3342. self.homeDir = pathJoin(self._baseDir, self.homeDir)
  3343. # Глобальный словарь обработанных шаблонов файлов
  3344. # {путь к конф. файлу:[имена шаблонов] ...}
  3345. self.dictProcessedTemplates = {}
  3346. if cltObj is True:
  3347. # Объект templateClt
  3348. self.cltObj = templateClt(self.objVar)
  3349. elif cltObj:
  3350. # Объект templateClt
  3351. self.cltObj = cltObj
  3352. else:
  3353. # Объект templateClt
  3354. self.cltObj = False
  3355. # Фильтровать ли шаблоны clt по конфигурационным файлам обычных шаблонов
  3356. self.cltFilter = cltFilter
  3357. # autoupdate файлы
  3358. self.autoUpdateFiles = []
  3359. self.autoUpdateDirs = []
  3360. # список выполненных файлов
  3361. self.executedFiles = []
  3362. def executeTemplate(self, path, execPath):
  3363. """Execute template"""
  3364. if os.system("""{interpreter} {cmdfile}""".format(
  3365. interpreter=execPath, cmdfile=path)) == 0:
  3366. self.executedFiles.append((path,execPath))
  3367. return True
  3368. else:
  3369. return False
  3370. def __octToInt(self, strOct):
  3371. """Преобразование восьмеричного в целое (ввод строка, вывод число)"""
  3372. if strOct:
  3373. try:
  3374. res = string.atoi(strOct, 8)
  3375. except ValueError:
  3376. self.setError(_("Invalid oct value: ") + str(strOct))
  3377. return False
  3378. return res
  3379. else:
  3380. self.setError(_("Empty oct value"))
  3381. return False
  3382. def getTemplateType(self):
  3383. """выдать тип шаблона (text, bin)"""
  3384. return self.getFileType(self.nameFileTemplate)
  3385. def getFileType(self, fileName):
  3386. """выдать тип файла (text, bin)"""
  3387. isBin = self.typeFileObj.isBinary(fileName)
  3388. typeTemplate = "bin"
  3389. if isBin is True:
  3390. typeTemplate = "bin"
  3391. elif isBin is False:
  3392. typeTemplate = "text"
  3393. else:
  3394. self.setError(_("ERROR") + ": getFileType()")
  3395. self.setError(isBin)
  3396. return False
  3397. return typeTemplate
  3398. def createDir(self, dirName, mode=False, uid=False, gid=False):
  3399. """Создает директорию"""
  3400. if os.access(dirName, os.F_OK):
  3401. return True
  3402. else:
  3403. dMode = False
  3404. prevDir, tmpSubdir = os.path.split(dirName)
  3405. createDirs = []
  3406. while not os.access(prevDir, os.F_OK) and prevDir:
  3407. createDirs.append(prevDir)
  3408. prevDir = os.path.split(prevDir)[0]
  3409. try:
  3410. dUid,dGid = getModeFile(prevDir,"owner")
  3411. except OSError:
  3412. self.setError(_("No access to the directory: " ) + prevDir)
  3413. return False
  3414. if not mode is False:
  3415. dMode = mode
  3416. if not uid is False:
  3417. dUid = uid
  3418. if not gid is False:
  3419. dGid = gid
  3420. createDirs.reverse()
  3421. for nameDir in createDirs:
  3422. try:
  3423. if dMode:
  3424. os.mkdir(nameDir, dMode)
  3425. os.chmod(nameDir, dMode)
  3426. else:
  3427. os.mkdir(nameDir)
  3428. os.chown(nameDir, dUid, dGid)
  3429. except:
  3430. self.setError(_("Failed to create the directory: " ) +
  3431. nameDir)
  3432. return False
  3433. try:
  3434. if dMode:
  3435. os.mkdir(dirName, dMode)
  3436. os.chmod(dirName, dMode)
  3437. else:
  3438. os.mkdir(dirName)
  3439. os.chown(dirName, dUid, dGid)
  3440. createDirs.append(dirName)
  3441. except:
  3442. self.setError(_("Failed to create the directory: " ) + dirName)
  3443. return False
  3444. return createDirs
  3445. def applyVarsTemplate(self, textTemplate, nameTemplate):
  3446. """ Заменяет переменные на их значения
  3447. """
  3448. resS = self._reVar.search(textTemplate)
  3449. textTemplateTmp = textTemplate
  3450. while resS:
  3451. mark = textTemplateTmp[resS.start():resS.end()]
  3452. varName = mark[self._deltVarStart:-self._deltVarEnd]
  3453. varValue = ""
  3454. try:
  3455. varValue = str(self.objVar.Get(varName))
  3456. except self.objVar.DataVarsError, e:
  3457. cl_overriding.printERROR(_("error in template %s")%nameTemplate)
  3458. cl_overriding.printERROR(e)
  3459. cl_overriding.exit(1)
  3460. textTemplateTmp = textTemplateTmp.replace(mark, varValue)
  3461. resS = self._reVar.search(textTemplateTmp)
  3462. return textTemplateTmp
  3463. def applyTermsTemplate(self,textTemplate,nameTemplate):
  3464. """ Применяет условия, к условным блокам текста
  3465. """
  3466. def function(text):
  3467. """Функция обработки функций в заголовке"""
  3468. return self.applyFuncTemplate(text, nameTemplate)
  3469. textTerm = ""
  3470. resS = self._reTermBloc.search(textTemplate)
  3471. textTemplateTmp = textTemplate
  3472. while resS:
  3473. mark = resS.group(0)
  3474. body = resS.group("body")
  3475. end = resS.group("end")
  3476. parent = resS.group("func")
  3477. if not parent:
  3478. parent = ""
  3479. term = resS.group("rTerm") + parent +\
  3480. resS.group("lTerm")
  3481. if self._equalTerm(term, _("invalid template content: ")+\
  3482. nameTemplate, function):
  3483. textTemplateTmp = textTemplateTmp.replace(mark, body+end)
  3484. else:
  3485. textTemplateTmp = textTemplateTmp.replace(mark, "")
  3486. resS = self._reTermBloc.search(textTemplateTmp)
  3487. return textTemplateTmp
  3488. def getNeedTemplate(self, fileTemplate):
  3489. """Применяем правила к названию файла"""
  3490. dirP,fileP = os.path.split(fileTemplate)
  3491. if fileP:
  3492. spFile = fileP.split("?")
  3493. realFileName = spFile[0]
  3494. if len(spFile)>1:
  3495. flagTrue = False
  3496. for term in spFile[1:]:
  3497. if self._equalTerm(term, _("invalid template name: ")+\
  3498. fileTemplate):
  3499. flagTrue = True
  3500. break
  3501. if flagTrue:
  3502. return True
  3503. else:
  3504. return False
  3505. else:
  3506. return True
  3507. else:
  3508. self.setError(_("invalid template name: ")+ str(fileTemplate))
  3509. return False
  3510. def getTitle(self, comment, commentList, configPath=""):
  3511. """Выдает заголовок шаблона ( версия и.т.д)"""
  3512. if configPath and self.protectPaths:
  3513. flagFoundPath = False
  3514. for protectPath in self.protectPaths:
  3515. if self._baseDir != "/":
  3516. lenBaseDir = len(self._baseDir)
  3517. if len(configPath)>lenBaseDir and\
  3518. configPath[:lenBaseDir] == self._baseDir:
  3519. configPath = configPath[lenBaseDir:]
  3520. if configPath.startswith(protectPath + "/"):
  3521. flagFoundPath = True
  3522. break
  3523. if flagFoundPath:
  3524. commentList = commentList +\
  3525. [self.titleEnd%{'conf_path':configPath}]
  3526. if comment:
  3527. commentFirst = comment
  3528. commentInsert = comment
  3529. commentLast = comment
  3530. flagList = False
  3531. # В случае открывающего и закрывающего комментария
  3532. if type(comment) == types.TupleType and len(comment) == 2:
  3533. commentFirst = comment[0]
  3534. commentInsert = ""
  3535. commentLast = comment[1]
  3536. flagList = True
  3537. if flagList:
  3538. self._titleBody = commentFirst + "\n"
  3539. else:
  3540. self._titleBody = commentFirst + self.__titleHead + "\n"
  3541. z = 0
  3542. flagFirst = True
  3543. for com in list(self._titleList) + [""]*(len(commentList)):
  3544. if com:
  3545. if flagFirst:
  3546. self._titleBody += commentInsert + " " + com + " "+\
  3547. self.programVersion + "\n"
  3548. flagFirst = False
  3549. else:
  3550. self._titleBody += commentInsert + " " + com + "\n"
  3551. else:
  3552. self._titleBody += commentInsert + " " +\
  3553. commentList[z] + "\n"
  3554. z += 1
  3555. if flagList:
  3556. self._titleBody += commentLast +"\n"
  3557. else:
  3558. self._titleBody += commentLast + self.__titleHead + "\n"
  3559. return self._titleBody
  3560. else:
  3561. return ""
  3562. def numberAllTemplates(self, number):
  3563. """Количество шаблонов
  3564. Вызов происходит перед наложением шаблонов
  3565. в момент вызова в number находится количество обрабатываемых файлов
  3566. Наследуемая функция
  3567. Используется для отображения прогресса при наложениии шаблонов
  3568. """
  3569. return True
  3570. def numberProcessTemplates(self, number):
  3571. """Номер текущего обрабатываемого шаблона
  3572. Вызов происходит при наложении шаблона
  3573. в момент вызова в number находится номер обрабатываемого шаблона
  3574. Наследуемая функция
  3575. Используется для отображения прогресса при наложениии шаблонов
  3576. """
  3577. return True
  3578. def getHeaderText(self, text):
  3579. textLines = text.splitlines()
  3580. paramLine = ""
  3581. if textLines:
  3582. textLine = textLines[0]
  3583. rePar = re.compile(\
  3584. "\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$",re.I)
  3585. reP = rePar.search(textLine)
  3586. if reP:
  3587. reL = False
  3588. reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
  3589. reLs = reLns.search(text)
  3590. if reLs:
  3591. reL = reLs
  3592. paramLine = text[reP.end():reLs.end()]
  3593. paramLine = paramLine.replace("\\"," ")
  3594. else:
  3595. reLn = re.compile("\n")
  3596. reL = reLn.search(text)
  3597. paramLine = textLine[reP.end():]
  3598. return paramLine
  3599. def getTemplateDirs(self, dirsTemplates):
  3600. """Check template variable cl_name in first directories and files"""
  3601. skipDirs = []
  3602. skipTemplates = []
  3603. for dirsTemplate in dirsTemplates:
  3604. filesAndDirs = map(lambda x: os.path.join(dirsTemplate,x),
  3605. os.listdir(dirsTemplate))
  3606. for dirFile in filesAndDirs:
  3607. if os.path.isdir(dirFile):
  3608. flagDir = True
  3609. templatePath = os.path.join(dirFile,self.templDirNameFile)
  3610. if not os.path.isfile(templatePath):
  3611. skipDirs.append(dirFile)
  3612. continue
  3613. else:
  3614. flagDir = False
  3615. templatePath = dirFile
  3616. if os.path.isfile(templatePath):
  3617. if self.getFileType(templatePath) == "bin":
  3618. skipTemplates.append(dirFile)
  3619. else:
  3620. textTemplate = open(templatePath).read()
  3621. if textTemplate:
  3622. headerLine = self.getHeaderText(textTemplate)
  3623. if headerLine:
  3624. if not "cl_name==" in headerLine:
  3625. if flagDir:
  3626. skipDirs.append(dirFile)
  3627. else:
  3628. skipTemplates.append(dirFile)
  3629. else:
  3630. if flagDir:
  3631. skipDirs.append(dirFile)
  3632. else:
  3633. skipTemplates.append(dirFile)
  3634. else:
  3635. skipTemplates.append(dirFile)
  3636. if skipDirs or skipTemplates:
  3637. # print warning
  3638. from cl_print import color_print
  3639. printObj = color_print()
  3640. setWARNING = lambda x: self.setWarning(x) and\
  3641. self.printWarning and\
  3642. printObj.printWARNING(x)
  3643. setWARNING(_("No conditions of checking the value of "
  3644. "variable 'cl_name'"))
  3645. skipDirTemplates = []
  3646. for skipDir in skipDirs:
  3647. skipTempl = os.path.join(skipDir,self.templDirNameFile)
  3648. if os.path.isfile(skipTempl):
  3649. skipDirTemplates.append(skipTempl)
  3650. if skipTemplates or skipDirTemplates:
  3651. setWARNING(_("Skipped templates:"))
  3652. for skipTemplate in skipTemplates + skipDirTemplates:
  3653. setWARNING(" "*6 + skipTemplate)
  3654. if skipDirs:
  3655. setWARNING(_("Skipped directories:"))
  3656. for skipDir in skipDirs:
  3657. setWARNING(" "*6 + skipDir)
  3658. setWARNING("")
  3659. setWARNING(_("Headers of directory templates and headers of files "
  3660. "on the first level should include 'cl_name' variable."))
  3661. setWARNING(_("Example:"))
  3662. setWARNING("# Calculate cl_name==calculate-install")
  3663. return skipDirs + skipTemplates
  3664. def applyTemplates(self):
  3665. """Применяет шаблоны к конфигурационным файлам"""
  3666. def createDictTemplates(path, prefix, dictTemplates):
  3667. """Создает словарь {"директория":"кол-во шаблонов" ...}
  3668. и считает общее количество шаблонов
  3669. """
  3670. # Количество шаблонов
  3671. self.allTemplates += 1
  3672. dirTemplate = os.path.split(path)[0]
  3673. while(True):
  3674. if dirTemplate in dictTemplates.keys():
  3675. dictTemplates[dirTemplate] += 1
  3676. else:
  3677. dictTemplates[dirTemplate] = 1
  3678. if dirTemplate == prefix:
  3679. break
  3680. dirTemplate = os.path.split(dirTemplate)[0]
  3681. return dictTemplates
  3682. if not self.objVar.defined("cl_template_path"):
  3683. self.setError(_("undefined variable: ") + "cl_template_path")
  3684. return False
  3685. dirsTemplates = self.objVar.Get("cl_template_path")
  3686. # Созданные директории
  3687. self.createdDirs = []
  3688. # Примененные файлы
  3689. self.filesApply = []
  3690. # Номер применяемого шаблона
  3691. self.numberProcessTempl = 0
  3692. # Словарь директорий с количеством файлов шаблонов
  3693. self.dictTemplates = {}
  3694. # Количество шаблонов
  3695. self.allTemplates = 0
  3696. # Установка по умолчанию аттрибутов для функциии шаблонов ini()
  3697. # Время доступа к конфигурационному файлу функции шаблона ini()
  3698. self.functObj.timeIni = -1
  3699. # Первоначальный словарь переменных для ini()
  3700. self.functObj.prevDictIni = {}
  3701. # Текущий словарь переменных для ini()
  3702. self.functObj.currDictIni = {}
  3703. # Словарь времен модификации env файлов для ini()
  3704. self.functObj.timeConfigsIni = {}
  3705. if self._servDir:
  3706. tmpDirsTemplates = []
  3707. for dirP in dirsTemplates:
  3708. dirTempl = dirP + self._servDir
  3709. if os.access(dirTempl, os.F_OK):
  3710. # Если директория существует
  3711. tmpDirsTemplates.append(dirTempl)
  3712. dirsTemplates = tmpDirsTemplates
  3713. scanObj = scanDirectory()
  3714. scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
  3715. self.dictTemplates)
  3716. # Считаем количество шаблонов
  3717. dirsTemplatesExists = filter(lambda x: os.path.exists(x), dirsTemplates)
  3718. if not dirsTemplatesExists:
  3719. self.setError(_("No such template directories") +\
  3720. ": %s"%", ".join(map(lambda x: "'%s'"%x ,dirsTemplates)))
  3721. return (self.createdDirs, self.filesApply)
  3722. # check cl_name in first template dirs and files
  3723. skipTemplates = self.getTemplateDirs(dirsTemplatesExists)
  3724. if not os.environ.get("EBUILD_PHASE",""):
  3725. for dirTemplate in dirsTemplatesExists:
  3726. scanObj.scanningDirectory(dirTemplate)
  3727. # Считаем количество шаблонов clt
  3728. if self.cltObj:
  3729. # Считаем количество шаблонов clt
  3730. self.cltObj.countsNumberTemplates()
  3731. # не считать количество файлов в объекте self.cltObj
  3732. self.cltObj.checkNumberTemplate = False
  3733. # начальный номер clt шаблона
  3734. self.cltObj.numberProcessTempl = self.allTemplates
  3735. # метод показывающий номер clt шаблона
  3736. self.cltObj.numberProcessTemplates = self.numberProcessTemplates
  3737. # общее количество шаблонов
  3738. self.allTemplates += self.cltObj.allTemplates
  3739. self.cltObj.allTemplates = self.allTemplates
  3740. self.numberAllTemplates(self.allTemplates)
  3741. # Обрабатываем шаблоны
  3742. for dirTemplate in dirsTemplatesExists:
  3743. if self.scanningTemplates(dirTemplate,
  3744. skipTemplates=skipTemplates) is False:
  3745. return False
  3746. if self.cltObj:
  3747. # Созданные директории
  3748. self.cltObj.createdDirs = self.createdDirs
  3749. # Примененные файлы
  3750. self.cltObj.filesApply = self.filesApply
  3751. # Словарь директорий с количеством файлов шаблонов
  3752. self.cltObj.dictTemplates = self.dictTemplates
  3753. # Количество шаблонов
  3754. self.cltObj.allTemplates = self.allTemplates
  3755. # Установка по умолчанию аттрибутов для функциии шаблонов ini()
  3756. # Время доступа к конфигурационному файлу функции шаблона ini()
  3757. self.cltObj.functObj = self.functObj
  3758. # Словарь примененных файлов шаблонов
  3759. self.cltObj.dictProcessedTemplates = self.dictProcessedTemplates
  3760. self.cltObj.autoUpdateFiles = self.autoUpdateFiles
  3761. self.cltObj.autoUpdateDirs = self.autoUpdateDirs
  3762. if self.cltFilter:
  3763. # Шаблоны + .clt которые будут применены
  3764. self.cltObj.filterApplyTemplates +=\
  3765. map(lambda x: pathJoin('/', x.partition(self._baseDir)[2]),
  3766. self.dictProcessedTemplates.keys())
  3767. if not self.cltObj.applyTemplates():
  3768. return False
  3769. return (self.createdDirs, self.filesApply)
  3770. def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
  3771. optDir={}, skipTemplates=[]):
  3772. """Сканирование и обработка шаблонов в директории scanDir"""
  3773. ret = True
  3774. if not prefix:
  3775. prefix = os.path.realpath(scanDir)
  3776. if not flagDir:
  3777. # проверка корневой директории
  3778. retDir = self.processingDirectory(scanDir, scanDir, optDir)
  3779. if retDir is None:
  3780. return None
  3781. elif retDir is False:
  3782. return False
  3783. pathDir, objHead = retDir
  3784. optDir["path"] = pathDir
  3785. if not objHead is True:
  3786. if objHead.typeAppend == "skip":
  3787. # Установка опции пропуска директории
  3788. optDir["skip"] = True
  3789. if "autoupdate" in objHead.params:
  3790. optDir["autoupdate"] = True
  3791. if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
  3792. for fileOrDir in sorted(os.listdir(scanDir)):
  3793. absPath = os.path.join(scanDir,fileOrDir)
  3794. if skipTemplates and absPath in skipTemplates:
  3795. continue
  3796. stInfo = os.lstat(absPath)
  3797. statInfo = stInfo[stat.ST_MODE]
  3798. if stat.S_ISREG(statInfo):
  3799. if not self.processingFile(absPath, prefix, optDir):
  3800. ret = False
  3801. break
  3802. elif stat.S_ISDIR(statInfo):
  3803. # Обработка директории
  3804. retDir = self.processingDirectory(absPath, prefix,
  3805. optDir)
  3806. if retDir is None:
  3807. continue
  3808. elif retDir is False:
  3809. ret = False
  3810. break
  3811. # Опции следующей директории
  3812. optNextDir = {}
  3813. pathDir, objHead = retDir
  3814. optNextDir["path"] = pathDir
  3815. if not objHead is True:
  3816. if objHead.typeAppend == "skip":
  3817. # Установка опции пропуска директории
  3818. optNextDir["skip"] = True
  3819. if "autoupdate" in objHead.params:
  3820. optNextDir["autoupdate"] = True
  3821. ret = self.scanningTemplates(absPath, prefix, True,
  3822. optNextDir)
  3823. if ret is False:
  3824. break
  3825. return ret
  3826. def processingFile(self, path, prefix, optFile):
  3827. """Обработка в случае шаблона файла"""
  3828. self.numberProcessTempl += 1
  3829. self.numberProcessTemplates(self.numberProcessTempl)
  3830. # Пропуск шаблонов директорий
  3831. if self.templDirNameFile == os.path.split(path)[1]:
  3832. return True
  3833. # Проверка на переменные в названии файла
  3834. if not self.getNeedTemplate(path):
  3835. if self.getError():
  3836. return False
  3837. return True
  3838. if self.getError():
  3839. return False
  3840. nameFileConfig = path.partition(prefix)[2]
  3841. # файл в системе без условий
  3842. nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\
  3843. nameFileConfig.split("/")))
  3844. # Записываем в переменную обрабатываемый файл
  3845. self.objVar.Set("cl_pass_file",nameFileConfig)
  3846. filesApl = self.joinTemplate(path, nameFileConfig, optFile)
  3847. if self.getError():
  3848. return False
  3849. if filesApl:
  3850. # Настоящее имя конфигурационного файла
  3851. nameFileConfig = filesApl[0]
  3852. # Пишем время модификации *.env файлов
  3853. if nameFileConfig.endswith(".env"):
  3854. nameEnvFile = os.path.basename(nameFileConfig)
  3855. self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
  3856. self.filesApply += filesApl
  3857. return True
  3858. def processingDirectory(self, path, prefix, opt):
  3859. """Обработка в случае директории если возвращаем None то пропуск дир."""
  3860. # Файл шаблона директории
  3861. dirInfoFile = os.path.join(path, self.templDirNameFile)
  3862. newDir = pathJoin(self._baseDir, path.partition(prefix)[2])
  3863. newDir = "/".join(map(lambda x:x.split("?")[0], newDir.split("/")))
  3864. # Применяем шаблон
  3865. pathDir, objHeadDir, createdDirs =\
  3866. self.getApplyHeadDir(newDir, dirInfoFile, opt)
  3867. if createdDirs:
  3868. self.createdDirs += createdDirs
  3869. if objHeadDir:
  3870. return pathDir, objHeadDir
  3871. else:
  3872. if self.getError():
  3873. return False
  3874. # Добавление количества файлов в пропущенной директории
  3875. if path in self.dictTemplates.keys():
  3876. self.numberProcessTempl += self.dictTemplates[path]
  3877. return None
  3878. def getApplyHeadDir(self, newDir, templateDirFile, optDir):
  3879. """Применяет шаблон к директории (права, владелец, и.т. д)"""
  3880. def function(text):
  3881. """Функция обработки функций в заголовке"""
  3882. return self.applyFuncTemplate(text, templateDirFile)
  3883. def chownConfDir(nameDirConfig, uid, gid, nameFileTemplate):
  3884. """Изменение владельца конфигурационной директории"""
  3885. try:
  3886. os.chown(nameDirConfig, uid, gid)
  3887. except:
  3888. import pwd, grp
  3889. try:
  3890. userName = pwd.getpwuid(uid).pw_name
  3891. except:
  3892. userName = str(uid)
  3893. try:
  3894. groupName = grp.getgrgid(gid).gr_name
  3895. except:
  3896. groupName = str(gid)
  3897. owner = userName + ":" + groupName
  3898. self.setError(_("Failed to apply template file %s")\
  3899. %nameFileTemplate)
  3900. self.setError(_("error") + " " +\
  3901. "'chown %s %s'"%(owner, nameDirConfig))
  3902. return False
  3903. return True
  3904. applyDir = newDir
  3905. # Родительская директория
  3906. if optDir.get("path"):
  3907. path = optDir["path"]
  3908. else:
  3909. if applyDir == self._baseDir:
  3910. path = os.path.dirname(self._baseDir)
  3911. else:
  3912. path = os.path.split(applyDir)[1]
  3913. path = pathJoin(self._baseDir, path)
  3914. if not os.path.exists(templateDirFile):
  3915. if applyDir != self._baseDir:
  3916. applyDir = os.path.join(path, os.path.split(applyDir)[1])
  3917. # Фильтрация шаблонов по названию директории
  3918. realPath = os.path.join("/",applyDir.partition(self._baseDir)[2])
  3919. if realPath in self.dirsFilter:
  3920. return ("", False, [])
  3921. # Создаем директорию если необходимо
  3922. crDirs = self.createDir(applyDir, False, self.uid, self.gid)
  3923. if not crDirs:
  3924. return ("", False, [])
  3925. if "autoupdate" in optDir:
  3926. self.autoUpdateDirs.append(applyDir)
  3927. if crDirs is True:
  3928. return (applyDir, True, [])
  3929. else:
  3930. return (applyDir, True, crDirs)
  3931. try:
  3932. FD = open(templateDirFile)
  3933. textTemplate = FD.read()
  3934. FD.close()
  3935. except:
  3936. self.setError(_("Error in opening template") + ": " +\
  3937. templateDirFile)
  3938. return ("", False, [])
  3939. if " env=" in textTemplate:
  3940. return ("", False, [])
  3941. # Заменяем переменные на их значения
  3942. textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile)
  3943. # Заменяем функции на их значения
  3944. textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile)
  3945. # Обработка заголовка
  3946. objHead = dirHeader(templateDirFile,textTemplate,self.objVar,function)
  3947. # Директория с профилями не будет применена
  3948. if not objHead.headerTerm:
  3949. if objHead.getError():
  3950. self.setError(_("Incorrect template") + ": " +\
  3951. templateDirFile)
  3952. return ("", False, [])
  3953. # Пропускаем директорию
  3954. if objHead.typeAppend == "skip":
  3955. applyDir = path
  3956. return (applyDir, objHead, [])
  3957. # Изменяем название родительской директории
  3958. if "path" in objHead.params:
  3959. path = objHead.params['path']
  3960. if path and path[0] == "~":
  3961. # Получаем путь с заменой ~ на директорию пользователя
  3962. path = os.path.join(self.homeDir,
  3963. path.partition("/")[2],"")[:-1]
  3964. elif not path or path and path[0] != "/":
  3965. self.setError(_("Wrong value 'path' in the template") + ": " +\
  3966. templateDirFile)
  3967. return ("", False, [])
  3968. else:
  3969. path = pathJoin(self._baseDir, path)
  3970. # Изменяем название директории
  3971. if "name" in objHead.params:
  3972. nameDir = objHead.params['name']
  3973. if "/" in nameDir or nameDir == ".." or nameDir == ".":
  3974. self.setError(_("Wrong value 'name' in the template") + ": " +\
  3975. templateDirFile)
  3976. return ("", False, [])
  3977. # Новый путь к директории
  3978. applyDir = pathJoin(path, nameDir)
  3979. else:
  3980. applyDir = pathJoin(path, os.path.split(applyDir)[1])
  3981. # Фильтрация шаблонов по названию директории
  3982. realPath = os.path.join("/",applyDir.partition(self._baseDir)[2])
  3983. if realPath in self.dirsFilter:
  3984. return ("", False, [])
  3985. # Удаляем директорию
  3986. if objHead.typeAppend == "remove":
  3987. if os.path.isdir(applyDir):
  3988. # удаляем директорию
  3989. try:
  3990. removeDir(applyDir)
  3991. except:
  3992. self.setError(_("Failed to delete the directory: " ) +\
  3993. applyDir)
  3994. return ("", False, [])
  3995. # Очищаем директорию
  3996. if objHead.typeAppend == "clear":
  3997. if os.path.isdir(applyDir):
  3998. for rmPath in os.listdir(applyDir):
  3999. removePath = pathJoin(applyDir, rmPath)
  4000. if os.path.isdir(removePath):
  4001. # удаляем директорию
  4002. try:
  4003. removeDir(removePath)
  4004. except:
  4005. self.setError(
  4006. _("Failed to delete the directory: ") +\
  4007. removePath)
  4008. else:
  4009. try:
  4010. os.unlink(removePath)
  4011. except:
  4012. self.setError(_("Failed to delete: " ) + removePath)
  4013. return ("", False, [])
  4014. # Созданные директории
  4015. createdDirs = []
  4016. # chmod - изменяем права
  4017. if "chmod" in objHead.params:
  4018. mode = self.__octToInt(objHead.params['chmod'])
  4019. if mode:
  4020. if not os.path.exists(applyDir):
  4021. crDirs = self.createDir(applyDir, mode, self.uid, self.gid)
  4022. if not crDirs:
  4023. return ("", False, [])
  4024. if not crDirs is True:
  4025. createdDirs += crDirs
  4026. else:
  4027. os.chmod(applyDir, mode)
  4028. else:
  4029. self.setError(_("Wrong value 'chmod' in the template") + ": " +\
  4030. templateDirFile)
  4031. return ("", False, [])
  4032. # chown - изменяем владельца и группу
  4033. if "chown" in objHead.params:
  4034. owner = objHead.params['chown']
  4035. if owner:
  4036. if ":" in owner:
  4037. strUid, strGid = owner.split(":")
  4038. import pwd
  4039. uid = self.getUidFromPasswd(strUid)
  4040. try:
  4041. uid = pwd.getpwnam(strUid).pw_uid
  4042. except:
  4043. self.setError(_("No such user on the system: ")
  4044. + strUid)
  4045. self.setError(_("Wrong value 'chown' in the template")+\
  4046. ": " + templateDirFile)
  4047. return ("", False, [])
  4048. gid = self.getGidFromGroup(strGid)
  4049. try:
  4050. import grp
  4051. gid = grp.getgrnam(strGid).gr_gid
  4052. except:
  4053. self.setError(_("Group not found on the system: ")
  4054. +strGid)
  4055. self.setError(_("Wrong value 'chown' in the template")+\
  4056. ": "+ templateDirFile)
  4057. return ("", False, [])
  4058. if not os.path.exists(applyDir):
  4059. crDirs = self.createDir(applyDir, False, uid, gid)
  4060. if not crDirs:
  4061. return ("", False, [])
  4062. if not crDirs is True:
  4063. createdDirs += crDirs
  4064. else:
  4065. if not chownConfDir(applyDir, uid, gid,
  4066. templateDirFile):
  4067. return ("", False, [])
  4068. else:
  4069. self.setError(_("Wrong value 'chown' in the template") +
  4070. ": " + templateDirFile)
  4071. return ("", False, [])
  4072. else:
  4073. self.setError(_("Wrong value 'chown' in the template") + ": " +\
  4074. templateDirFile)
  4075. return ("", False, [])
  4076. else:
  4077. # Устанавливаем владельцем директории, пользователя по умолчанию
  4078. # (переменная шаблона ur_login)
  4079. if os.path.exists(applyDir):
  4080. tUid, tGid = getModeFile(applyDir, mode="owner")
  4081. if (self.uid, self.gid) != (tUid, tGid):
  4082. if not chownConfDir(applyDir, self.uid, self.gid,
  4083. templateDirFile):
  4084. return ("", False, [])
  4085. else:
  4086. crDirs = self.createDir(applyDir, False, self.uid, self.gid)
  4087. if not crDirs:
  4088. return ("", False, [])
  4089. if not crDirs is True:
  4090. createdDirs += crDirs
  4091. if not objHead:
  4092. applyDir = ""
  4093. if applyDir:
  4094. if "autoupdate" in optDir or "autoupdate" in objHead.params:
  4095. self.autoUpdateDirs.append(applyDir)
  4096. return (applyDir, objHead, createdDirs)
  4097. def getUidFromPasswd(self,strUid):
  4098. """Get uid by username from chroot passwd file"""
  4099. passwdFile = os.path.join(self._baseDir,'etc/passwd')
  4100. if os.path.exists(passwdFile):
  4101. mapUid = dict(
  4102. filter(lambda x:x[0] and x[1],
  4103. map(lambda x:x.split(':')[0:3:2],
  4104. filter(lambda x:not x.startswith('#'),
  4105. open(passwdFile,'r')))))
  4106. if strUid in mapUid:
  4107. return int(mapUid[strUid])
  4108. return None
  4109. def getGidFromGroup(self,strGid):
  4110. """Get gid by groupname from chroot group file"""
  4111. groupFile = os.path.join(self._baseDir,'etc/group')
  4112. if os.path.exists(groupFile):
  4113. mapGid = dict(
  4114. filter(lambda x:x[0] and x[1],
  4115. map(lambda x:x.split(':')[0:3:2],
  4116. filter(lambda x:not x.startswith('#'),
  4117. open(groupFile,'r')))))
  4118. if strGid in mapGid:
  4119. return int(mapGid[strGid])
  4120. return None
  4121. def getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig,
  4122. templateFileType, optFile):
  4123. """Применяет заголовок к шаблону (права, владелец, и.т. д)"""
  4124. def function(text):
  4125. """Функция обработки функций в заголовке"""
  4126. return self.applyFuncTemplate(text,nameFileTemplate)
  4127. def preReturn(pathProg):
  4128. """Действия перед выходом из метода"""
  4129. if pathProg:
  4130. os.chdir(pathProg)
  4131. def chownConfFile(nameFileConfig, uid, gid, nameFileTemplate,
  4132. checkExists=True):
  4133. """Изменение владельца конфигурационного файла"""
  4134. try:
  4135. if checkExists and not os.path.exists(nameFileConfig):
  4136. # Создание файла
  4137. FD = open(nameFileConfig, "w")
  4138. FD.close()
  4139. os.chown(nameFileConfig, uid, gid)
  4140. except:
  4141. import pwd, grp
  4142. try:
  4143. userName = pwd.getpwuid(uid).pw_name
  4144. except:
  4145. userName = str(uid)
  4146. try:
  4147. groupName = grp.getgrgid(gid).gr_name
  4148. except:
  4149. groupName = str(gid)
  4150. owner = userName + ":" + groupName
  4151. self.setError(_("Failed to apply template file %s")\
  4152. %nameFileTemplate)
  4153. self.setError(_("error") + " " +\
  4154. "'chown %s %s'"%(owner, nameFileConfig))
  4155. return False
  4156. return True
  4157. def chmodConfFile(nameFileConfig, mode, nameFileTemplate,
  4158. checkExists=True):
  4159. """Изменения режима доступа конфигурационного файла"""
  4160. try:
  4161. if checkExists and not os.path.exists(pathOldFile):
  4162. # Создание файла
  4163. FD = open(nameFileConfig, "w")
  4164. FD.close()
  4165. os.chmod(nameFileConfig, mode)
  4166. except:
  4167. self.setError(_("Failed to apply template file %s")\
  4168. %nameFileTemplate)
  4169. self.setError(\
  4170. _("error") + " " +\
  4171. "'chmod %s %s'"%(str(oct(mode)), nameFileConfig))
  4172. return False
  4173. return True
  4174. self.closeFiles()
  4175. pathProg = ""
  4176. # Файлы в системе к которым были применены шаблоны
  4177. applyFiles = [nameFileConfig]
  4178. # В случае бинарного типа файла читаем шаблон
  4179. if templateFileType == "bin":
  4180. self.nameFileTemplate = os.path.abspath(nameFileTemplate)
  4181. self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
  4182. if not self.F_TEMPL:
  4183. self.setError(_("Error in opening template") + ": " +\
  4184. templateDirFile)
  4185. return False
  4186. self.textTemplate = self.F_TEMPL.read()
  4187. self.closeTemplFile()
  4188. objHeadNew = fileHeader(nameFileTemplate, self.textTemplate, False,
  4189. templateFileType ,objVar=self.objVar,
  4190. function=function)
  4191. # файл шаблона не будет применен
  4192. if not objHeadNew.headerTerm:
  4193. if objHeadNew.getError():
  4194. self.setError(_("Incorrect template") + ": " +\
  4195. nameFileTemplate)
  4196. return ([], False)
  4197. # Родительская директория
  4198. path = optFile["path"]
  4199. # Изменяем название родительской директории
  4200. if "path" in objHeadNew.params:
  4201. path = objHeadNew.params['path']
  4202. if path and path[0] == "~":
  4203. # Получаем путь с заменой ~ на директорию пользователя
  4204. path = os.path.join(self.homeDir,path.partition("/")[2],"")[:-1]
  4205. elif not path or path and path[0] != "/":
  4206. self.setError(_("Wrong value 'path' in the template") + ": " +\
  4207. nameFileTemplate)
  4208. return ([], False)
  4209. else:
  4210. path = pathJoin(self._baseDir, path)
  4211. # Путь к оригинальному файлу - pathOldFile
  4212. # Изменяем путь к оригинальному файлу
  4213. if objHeadNew.params.has_key("name"):
  4214. nameFile = objHeadNew.params['name']
  4215. if "/" in nameFile or nameFile == ".." or nameFile == ".":
  4216. self.setError(_("Wrong value 'name' in the template") + ": " +\
  4217. nameFileTemplate)
  4218. return ([], False)
  4219. # Новый путь к оригинальному файлу
  4220. pathOldFile = pathJoin(path,nameFile)
  4221. else:
  4222. pathOldFile = pathJoin(path,os.path.split(nameFileConfig)[1])
  4223. applyFiles = [pathOldFile]
  4224. # Фильтрация шаблонов по названию файла
  4225. realPath = os.path.join("/",pathOldFile.partition(self._baseDir)[2])
  4226. if realPath in self.filesFilter:
  4227. return ([], False)
  4228. typeAppendTemplate = objHeadNew.typeAppend
  4229. # Параметр exec
  4230. if "exec" in objHeadNew.params:
  4231. execPath = objHeadNew.params['exec']
  4232. if not os.access(execPath,os.X_OK):
  4233. self.setError(_("Wrong value 'exec' in the template") + ": " +\
  4234. nameFileTemplate)
  4235. self.setError(_("Failed to execute %s") %execPath)
  4236. return ([], False)
  4237. if typeAppendTemplate == "join":
  4238. self.setError(_("Wrong value 'append=join' in the template") +\
  4239. ": " + nameFileTemplate)
  4240. return ([], False)
  4241. # Очищаем оригинальный файл
  4242. if typeAppendTemplate == "clear":
  4243. try:
  4244. open(pathOldFile, "w").truncate(0)
  4245. except:
  4246. self.setError(_("Template error") + ": " +\
  4247. nameFileTemplate)
  4248. self.setError(_("Failed to clear the file") + ": " +\
  4249. pathOldFile)
  4250. return (applyFiles, False)
  4251. # Удаляем оригинальный файл
  4252. if typeAppendTemplate == "remove":
  4253. if os.path.islink(pathOldFile):
  4254. # удаляем ссылку
  4255. try:
  4256. os.unlink(pathOldFile)
  4257. except:
  4258. self.setError(_("Template error") + ": " +\
  4259. nameFileTemplate)
  4260. self.setError(_("Failed to delete the link") + ": " +\
  4261. pathOldFile)
  4262. return ([], False)
  4263. if os.path.isfile(pathOldFile):
  4264. # удаляем файл
  4265. try:
  4266. os.remove(pathOldFile)
  4267. except:
  4268. self.setError(_("Template error") + ": " +\
  4269. nameFileTemplate)
  4270. self.setError(_("Failed to delete the file") + ": " +\
  4271. pathOldFile)
  4272. return ([], False)
  4273. return (applyFiles, False)
  4274. # Пропускаем обработку шаблона
  4275. elif typeAppendTemplate == "skip":
  4276. return ([], False)
  4277. # Создаем директорию для файла если ее нет
  4278. if not os.path.exists(path):
  4279. if not self.createDir(path):
  4280. return ([], False)
  4281. # В случае force
  4282. if objHeadNew.params.has_key("force"):
  4283. if os.path.islink(pathOldFile):
  4284. # удаляем ссылку
  4285. try:
  4286. os.unlink(pathOldFile)
  4287. except:
  4288. self.setError(_("Template error") + ": " +\
  4289. nameFileTemplate)
  4290. self.setError(_("Failed to delete the link") + ": " +\
  4291. pathOldFile)
  4292. return ([], False)
  4293. if os.path.isfile(pathOldFile):
  4294. # удаляем файл
  4295. try:
  4296. os.remove(pathOldFile)
  4297. except:
  4298. self.setError(_("Template error") + ": " +\
  4299. nameFileTemplate)
  4300. self.setError(_("Failed to delete the file") + ": " +\
  4301. pathOldFile)
  4302. return ([], False)
  4303. flagSymlink = False
  4304. flagForce = False
  4305. # Если есть параметр mirror
  4306. if objHeadNew.params.has_key("mirror"):
  4307. if objHeadNew.params.has_key("link"):
  4308. templateFile = objHeadNew.params['link']
  4309. templateFile = pathJoin(self._baseDir, templateFile)
  4310. if not os.path.exists(templateFile):
  4311. if os.path.exists(pathOldFile):
  4312. try:
  4313. os.remove(pathOldFile)
  4314. except:
  4315. self.setError(_("Template error") + ": " +\
  4316. nameFileTemplate)
  4317. self.setError(_("Failed to delete the file") + \
  4318. ": " + pathOldFile)
  4319. return ([], False)
  4320. elif not os.path.exists(pathOldFile):
  4321. return ([], False)
  4322. # Если есть указатель на файл шаблона (link)
  4323. if objHeadNew.params.has_key("link") and\
  4324. not objHeadNew.params.has_key("symbolic"):
  4325. templateFile = objHeadNew.params['link']
  4326. templateFile = pathJoin(self._baseDir, templateFile)
  4327. foundTemplateFile = os.path.exists(templateFile)
  4328. if foundTemplateFile:
  4329. try:
  4330. F_CONF = self.openTemplFile(templateFile)
  4331. buff = F_CONF.read()
  4332. F_CONF.close()
  4333. fMode, fUid, fGid = getModeFile(templateFile)
  4334. except:
  4335. self.setError(_("Template error") + ": " +\
  4336. nameFileTemplate)
  4337. self.setError(_("Failed to open the file") + ": " +\
  4338. templateFile)
  4339. return ([], False)
  4340. if os.path.exists(pathOldFile):
  4341. try:
  4342. os.remove(pathOldFile)
  4343. except:
  4344. self.setError(_("Template error") + ": " +\
  4345. nameFileTemplate)
  4346. self.setError(_("Failed to delete the file") + ": " +\
  4347. pathOldFile)
  4348. return ([], False)
  4349. if foundTemplateFile:
  4350. try:
  4351. FD = open(pathOldFile, "w+")
  4352. FD.write(buff)
  4353. FD.close()
  4354. except:
  4355. self.setError(_("Template error") + ": " +\
  4356. nameFileTemplate)
  4357. self.setError(_("Failed to create the file") + " '%s'"\
  4358. %pathOldFile)
  4359. return ([], False)
  4360. oMode = getModeFile(pathOldFile, mode="mode")
  4361. # Если права не совпадают, меняем права
  4362. if fMode != oMode:
  4363. if not chmodConfFile(pathOldFile, fMode, nameFileTemplate,
  4364. checkExists=False):
  4365. return ([], False)
  4366. # Если символическая ссылка
  4367. if objHeadNew.params.has_key("symbolic"):
  4368. prevOldFile = pathOldFile
  4369. pathOldFile = objHeadNew.params['link']
  4370. flagSymlink = True
  4371. if not "/" == pathOldFile[0]:
  4372. pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
  4373. pathProg = os.getcwd()
  4374. try:
  4375. os.chdir(pathLink)
  4376. except:
  4377. self.setError(_("Template error") + ": " +\
  4378. nameFileTemplate)
  4379. self.setError(
  4380. _("Failed to change the current directory to")+\
  4381. " " + pathLink)
  4382. return ([], False)
  4383. # chmod - изменяем права
  4384. if objHeadNew.params.has_key("chmod"):
  4385. mode = self.__octToInt(objHeadNew.params['chmod'])
  4386. if mode:
  4387. if not chmodConfFile(pathOldFile, mode, nameFileTemplate):
  4388. preReturn(pathProg)
  4389. return ([], False)
  4390. else:
  4391. self.setError(_("Wrong value 'chmod' in the template") + ": " +\
  4392. nameFileTemplate)
  4393. preReturn(pathProg)
  4394. return ([], False)
  4395. # chown - изменяем владельца и группу
  4396. if objHeadNew.params.has_key("chown"):
  4397. owner = objHeadNew.params['chown']
  4398. if owner:
  4399. if ":" in owner:
  4400. strUid, strGid = owner.split(":")
  4401. if strUid.isdigit():
  4402. uid = int(strUid)
  4403. else:
  4404. uid = self.getUidFromPasswd(strUid)
  4405. import pwd
  4406. try:
  4407. if uid is None:
  4408. uid = pwd.getpwnam(strUid).pw_uid
  4409. except:
  4410. self.setError(_("No such user on the system: ") +
  4411. strUid)
  4412. self.setError(
  4413. _("Wrong value 'chown' in the template") +
  4414. ": "+ nameFileTemplate)
  4415. preReturn(pathProg)
  4416. return ([], False)
  4417. if strGid.isdigit():
  4418. gid = int(strGid)
  4419. else:
  4420. gid = self.getGidFromGroup(strGid)
  4421. try:
  4422. if gid is None:
  4423. import grp
  4424. gid = grp.getgrnam(strGid).gr_gid
  4425. except:
  4426. self.setError(_("Group not found on the system: ") +
  4427. strGid)
  4428. self.setError(
  4429. _("Wrong value 'chown' in the template") +
  4430. ": "+ nameFileTemplate)
  4431. preReturn(pathProg)
  4432. return ([], False)
  4433. # Изменяем владельца файла
  4434. if not chownConfFile(pathOldFile,uid,gid,nameFileTemplate):
  4435. preReturn(pathProg)
  4436. return ([], False)
  4437. else:
  4438. self.setError(_("Wrong value 'chown' in the template") +
  4439. ": " + nameFileTemplate)
  4440. preReturn(pathProg)
  4441. return ([], False)
  4442. else:
  4443. self.setError(_("Wrong value 'chown' in the template") + ": " +\
  4444. nameFileTemplate)
  4445. preReturn(pathProg)
  4446. return ([], False)
  4447. if not flagSymlink:
  4448. self.openFiles(nameFileTemplate, pathOldFile)
  4449. if self.getError():
  4450. return ([], False)
  4451. if not objHeadNew.params.has_key("chown"):
  4452. # Устанавливаем владельцем конфигурационного файла,
  4453. # пользователя по умолчанию (переменная шаблона ur_login)
  4454. if os.path.exists(pathOldFile):
  4455. tUid, tGid = getModeFile(pathOldFile, mode="owner")
  4456. if (self.uid, self.gid) != (tUid, tGid):
  4457. # Изменяем владельца файла
  4458. if not chownConfFile(pathOldFile, self.uid, self.gid,
  4459. nameFileTemplate, checkExists=False):
  4460. preReturn(pathProg)
  4461. return ([], False)
  4462. if flagSymlink:
  4463. if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
  4464. try:
  4465. if os.path.islink(prevOldFile):
  4466. # если ссылка то удаляем её
  4467. os.unlink(prevOldFile)
  4468. else:
  4469. # иначе удаляем файл
  4470. os.remove(prevOldFile)
  4471. except:
  4472. self.setError(_("Template error") + ": " +\
  4473. nameFileTemplate)
  4474. self.setError(_("Failed to delete the file") + ": " +\
  4475. prevOldFile)
  4476. preReturn(pathProg)
  4477. return ([], False)
  4478. if not "/" == pathOldFile[0]:
  4479. applyFiles = [prevOldFile]#,os.path.join(pathLink,pathOldFile)]
  4480. else:
  4481. applyFiles = [prevOldFile]#,pathOldFile]
  4482. try:
  4483. os.symlink(pathOldFile, prevOldFile)
  4484. except:
  4485. self.setError(_("Template error") + ": " +\
  4486. nameFileTemplate)
  4487. self.setError(_("Failed to create a symbolic link") + " :" +\
  4488. "%s -> %s"%(prevOldFile, pathOldFile))
  4489. preReturn(pathProg)
  4490. return ([], False)
  4491. if not objHeadNew.body.strip():
  4492. preReturn(pathProg)
  4493. return (applyFiles, False)
  4494. else:
  4495. applyFiles = [pathOldFile]
  4496. if pathProg:
  4497. os.chdir(pathProg)
  4498. # Если файлы заменяются не нужно их обрабатывать дальше
  4499. if typeAppendTemplate == "replace" and\
  4500. not objHeadNew.params.has_key("symbolic") and\
  4501. objHeadNew.params.has_key("link"):
  4502. preReturn(pathProg)
  4503. return ([], False)
  4504. if not pathOldFile in self.dictProcessedTemplates:
  4505. self.dictProcessedTemplates[pathOldFile] = []
  4506. self.dictProcessedTemplates[pathOldFile].append(nameFileTemplate)
  4507. preReturn(pathProg)
  4508. if "autoupdate" in optFile or "autoupdate" in objHeadNew.params:
  4509. self.autoUpdateFiles += applyFiles
  4510. return (applyFiles, objHeadNew)
  4511. def createNewClass(self, name, bases, attrs={}):
  4512. """Создает объект нового класса
  4513. createNewClass(self, name, bases, attrs)
  4514. name - имя класса - str,
  4515. bases - cписок наследуемых классов - (tuple),
  4516. attrs - аттрибуты класса - {dict}
  4517. """
  4518. class newMethod:
  4519. #Объединяем конфигурации
  4520. def join(self, newObj):
  4521. if newObj.__class__.__name__ == self.__class__.__name__:
  4522. self.docObj.joinDoc(newObj.doc)
  4523. # Пост обработка
  4524. if 'postXML' in dir(self):
  4525. self.postXML()
  4526. attrsNew = {}
  4527. attrsNew["configName"] = name
  4528. if attrs:
  4529. for key in attrs.keys():
  4530. attrsNew[key] = attrs[key]
  4531. newCl = type(name, bases + (newMethod, object,), attrsNew)
  4532. return newCl
  4533. def fileIsUtf(self, fileName):
  4534. """Проверяет файл на кодировку UTF-8"""
  4535. if os.path.exists(fileName):
  4536. FD = open(os.path.abspath(fileName))
  4537. newTemplate = FD.read()
  4538. FD.close()
  4539. try:
  4540. newTemplate.decode("UTF-8")
  4541. except:
  4542. return False
  4543. return True
  4544. def joinTemplate(self, nameFileTemplate, nameFileConfig, optFile={}):
  4545. """Объединения шаблона и конф. файла
  4546. join(nameFileTemplate, nameFileConfig, ListOptTitle)
  4547. Объединение шаблона nameFileTemplate и конф. файла nameFileConfig,
  4548. ListOptTitle - список строк которые добавятся в заголовок
  4549. optFile = опции для шаблона
  4550. """
  4551. # Выполняем условия для блока текста а так-же заменяем переменные
  4552. self.nameFileTemplate = os.path.abspath(nameFileTemplate)
  4553. self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
  4554. self.textTemplate = self.F_TEMPL.read()
  4555. self.closeTemplFile()
  4556. # Флаг копирования шаблона в конфигурационный файл
  4557. flagCopyTemplate = True
  4558. if " env=" in self.textTemplate.partition('\n')[0]:
  4559. return False
  4560. # Тип шаблона бинарный или текстовый
  4561. templateFileType = self.getTemplateType()
  4562. if templateFileType != "bin":
  4563. # Вычисляем условные блоки
  4564. self.textTemplate = self.applyTermsTemplate(self.textTemplate,
  4565. nameFileTemplate)
  4566. # Заменяем переменные на их значения
  4567. self.textTemplate = self.applyVarsTemplate(self.textTemplate,
  4568. nameFileTemplate)
  4569. # Вычисляем функции
  4570. self.textTemplate = self.applyFuncTemplate(self.textTemplate,
  4571. nameFileTemplate)
  4572. flagCopyTemplate = False
  4573. if not optFile:
  4574. optFile = {"path":os.path.split(nameFileConfig)[0]}
  4575. filesApply, objHeadNew = self.getApplyHeadTemplate(nameFileTemplate,
  4576. nameFileConfig,
  4577. templateFileType,
  4578. optFile)
  4579. if not objHeadNew:
  4580. return filesApply
  4581. # Настоящее имя конфигурационного файла
  4582. nameFileConfig = filesApply[0]
  4583. # Флаг - кодировка с бинарными примесями у файла шаблона включаем при
  4584. # условии текстового файла и кодировки отличной от UTF-8
  4585. flagNotUtf8New = False
  4586. # Флаг - кодировка с бинарными примесями у оригинального файла
  4587. flagNotUtf8Old = False
  4588. if not flagCopyTemplate:
  4589. # проверяем кодировку шаблона
  4590. if not self.fileIsUtf(nameFileTemplate):
  4591. flagNotUtf8New = True
  4592. if not (objHeadNew.params.has_key("link") and\
  4593. objHeadNew.params.has_key("symbolic")):
  4594. # проверяем кодировку оригинального файла
  4595. if not self.fileIsUtf(nameFileConfig):
  4596. flagNotUtf8Old = True
  4597. self.textTemplate = objHeadNew.body
  4598. # Список примененных шаблонов
  4599. ListOptTitle = []
  4600. if nameFileConfig in self.dictProcessedTemplates:
  4601. ListOptTitle = self.dictProcessedTemplates[nameFileConfig]
  4602. # Титл конфигурационного файла
  4603. title = ""
  4604. if ListOptTitle:
  4605. title = self.getTitle(objHeadNew.comment, ListOptTitle,
  4606. configPath=nameFileConfig)
  4607. title = title.encode("UTF-8")
  4608. objHeadOld = False
  4609. if objHeadNew.comment:
  4610. objHeadOld = fileHeader(nameFileConfig, self.textConfig,
  4611. objHeadNew.comment)
  4612. elif objHeadNew.fileType and\
  4613. objHeadNew.typeAppend in ("before", "after"):
  4614. configFileType = self.getFileType(nameFileConfig)
  4615. objHeadOld = fileHeader(nameFileConfig, self.textConfig,
  4616. fileType=configFileType)
  4617. # Строка вызова скрипта (#!/bin/bash ...)
  4618. execStr = ""
  4619. if objHeadNew.execStr:
  4620. execStr = objHeadNew.execStr
  4621. elif objHeadOld and objHeadOld.execStr:
  4622. execStr = objHeadOld.execStr
  4623. if objHeadNew.fileType:
  4624. formatTemplate = objHeadNew.fileType
  4625. typeAppendTemplate = objHeadNew.typeAppend
  4626. if formatTemplate == "patch":
  4627. if typeAppendTemplate != "patch":
  4628. self.setError(\
  4629. _("Wrong option append=%(type)s in template %(file)s")\
  4630. %{"type":typeAppendTemplate,"file":nameFileTemplate})
  4631. return False
  4632. # создаем объект формата шаблона
  4633. objTempl = self.getFormatObj(formatTemplate, self.textTemplate)
  4634. if not objTempl:
  4635. self.setError(\
  4636. _("Incorrect header parmeter format=%s in the template")\
  4637. %formatTemplate + " " + nameFileTemplate)
  4638. return False
  4639. if objHeadOld and objHeadOld.body:
  4640. self.textConfig = objHeadOld.body
  4641. # обработка конфигурационного файла
  4642. self.textTemplate = objTempl.processingFile(self.textConfig)
  4643. if objTempl.getError():
  4644. self.setError(_("Wrong template") + ": " +\
  4645. nameFileTemplate)
  4646. return False
  4647. if execStr:
  4648. self.textConfig = execStr + title + self.textTemplate
  4649. else:
  4650. self.textConfig = title + self.textTemplate
  4651. self.saveConfFile()
  4652. if 'exec' in objHeadNew.params:
  4653. if not self.executeTemplate(self.nameFileConfig,
  4654. objHeadNew.params['exec']):
  4655. self.setError(_("Wrong template") + ": " +\
  4656. nameFileTemplate)
  4657. self.setError(_("Failed to execute") + ": " +\
  4658. self.nameFileConfig)
  4659. return False
  4660. return False
  4661. return filesApply
  4662. # Создаем объект в случае параметра format в заголовке
  4663. if (typeAppendTemplate == "replace" or\
  4664. typeAppendTemplate == "before" or\
  4665. typeAppendTemplate == "after") and\
  4666. not (formatTemplate == "bin" or\
  4667. formatTemplate == "raw"):
  4668. # Преобразовываем бинарные файлы
  4669. if flagNotUtf8New:
  4670. objTxtCoder = utfBin()
  4671. self.textTemplate = objTxtCoder.encode(self.textTemplate)
  4672. # создаем объект формата шаблона
  4673. objTemplNew = self.getFormatObj(formatTemplate,
  4674. self.textTemplate)
  4675. if not objTemplNew:
  4676. self.setError(\
  4677. _("Incorrect header parmeter format=%s in the template")\
  4678. %formatTemplate + " " + nameFileTemplate)
  4679. return False
  4680. if "xml_" in formatTemplate:
  4681. if objTemplNew.getError():
  4682. self.setError(_("Wrong template") + ": " +\
  4683. nameFileTemplate)
  4684. return False
  4685. # Имя файла внутри xml xfce конфигурационных файлов
  4686. nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
  4687. objTemplNew.setNameBodyNode(nameRootNode)
  4688. # Объект Документ
  4689. docObj = objTemplNew.docObj
  4690. # Удаление комментариев из документа
  4691. docObj.removeComment(docObj.getNodeBody())
  4692. # Добавление необходимых переводов строк
  4693. docObj.insertBRtoBody(docObj.getNodeBody())
  4694. # Добавление необходимых разделителей между областями
  4695. docObj.insertBeforeSepAreas(docObj.getNodeBody())
  4696. # Пост обработка
  4697. if 'postXML' in dir(objTemplNew):
  4698. objTemplNew.postXML()
  4699. # Получение текстового файла из XML документа
  4700. self.textTemplate = objTemplNew.getConfig().encode("UTF-8")
  4701. # Если не UTF-8 производим преобразование
  4702. if flagNotUtf8New:
  4703. self.textTemplate = objTxtCoder.decode(self.textTemplate)
  4704. # Титл для объединения
  4705. if ListOptTitle:
  4706. title = self.getTitle(objTemplNew._comment,
  4707. ListOptTitle,
  4708. configPath=nameFileConfig)
  4709. title = title.encode("UTF-8")
  4710. # Замена
  4711. if typeAppendTemplate == "replace":
  4712. if "xml_" in formatTemplate:
  4713. data = self.textTemplate.split("\n")
  4714. data.insert(1,title)
  4715. self.textConfig = "\n".join(data)
  4716. else:
  4717. if objHeadNew.execStr:
  4718. self.textConfig = objHeadNew.execStr+title+\
  4719. self.textTemplate
  4720. else:
  4721. self.textConfig = title + self.textTemplate
  4722. self.saveConfFile()
  4723. if 'exec' in objHeadNew.params:
  4724. if not self.executeTemplate(self.nameFileConfig,
  4725. objHeadNew.params['exec']):
  4726. self.setError(_("Wrong template") + ": " +\
  4727. nameFileTemplate)
  4728. self.setError(_("Failed to execute") + ": " +\
  4729. self.nameFileConfig)
  4730. return False
  4731. return False
  4732. return filesApply
  4733. # Вверху
  4734. elif typeAppendTemplate == "before":
  4735. if "xml_" in formatTemplate:
  4736. self.setError(\
  4737. _("Wrong option append=before in template %s")\
  4738. %nameFileTemplate)
  4739. return False
  4740. if objHeadOld and objHeadOld.body:
  4741. self.textConfig = objHeadOld.body
  4742. if self.textTemplate and self.textTemplate[-1] == "\n":
  4743. tmpTemplate = self.textTemplate + self.textConfig
  4744. else:
  4745. tmpTemplate = self.textTemplate + "\n" + self.textConfig
  4746. if execStr:
  4747. self.textConfig = execStr + title + tmpTemplate
  4748. else:
  4749. self.textConfig = title + tmpTemplate
  4750. self.saveConfFile()
  4751. if 'exec' in objHeadNew.params:
  4752. if not self.executeTemplate(self.nameFileConfig,
  4753. objHeadNew.params['exec']):
  4754. self.setError(_("Wrong template") + ": " +\
  4755. nameFileTemplate)
  4756. self.setError(_("Failed to execute") + ": " +\
  4757. self.nameFileConfig)
  4758. return False
  4759. return False
  4760. return filesApply
  4761. # Внизу
  4762. elif typeAppendTemplate == "after":
  4763. if "xml_" in formatTemplate:
  4764. self.setError(\
  4765. _("Wrong option append=after in template %s")\
  4766. %nameFileTemplate)
  4767. return False
  4768. if objHeadOld and objHeadOld.body:
  4769. self.textConfig = objHeadOld.body
  4770. if self.textTemplate[-1] == "\n":
  4771. tmpTemplate = self.textConfig + self.textTemplate
  4772. else:
  4773. tmpTemplate = self.textConfig + "\n" + self.textTemplate
  4774. if execStr:
  4775. self.textConfig = execStr + title + tmpTemplate
  4776. else:
  4777. self.textConfig = title + tmpTemplate
  4778. self.saveConfFile()
  4779. if 'exec' in objHeadNew.params:
  4780. if not self.executeTemplate(self.nameFileConfig,
  4781. objHeadNew.params['exec']):
  4782. self.setError(_("Wrong template") + ": " +\
  4783. nameFileTemplate)
  4784. self.setError(_("Failed to execute") + ": " +\
  4785. self.nameFileConfig)
  4786. return False
  4787. return False
  4788. return filesApply
  4789. # Объединение
  4790. elif typeAppendTemplate == "join":
  4791. if flagNotUtf8New:
  4792. objTxtCoder = utfBin()
  4793. self.textTemplate = objTxtCoder.encode(self.textTemplate)
  4794. if formatTemplate =="raw":
  4795. self.setError(\
  4796. _("Incorrect header parmeter append=%s in the template")\
  4797. %typeAppendTemplate + " " + nameFileTemplate)
  4798. return False
  4799. # создаем объект формата шаблона
  4800. objTemplNew = self.getFormatObj(formatTemplate,
  4801. self.textTemplate)
  4802. if not objTemplNew:
  4803. self.setError(\
  4804. _("Incorrect header parmeter format=%s in the template")\
  4805. %formatTemplate + " " + nameFileTemplate)
  4806. return False
  4807. if "xml_" in formatTemplate:
  4808. if objTemplNew.getError():
  4809. self.setError(_("Wrong template") + ": " +\
  4810. nameFileTemplate)
  4811. return False
  4812. nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
  4813. objTemplNew.setNameBodyNode(nameRootNode)
  4814. # Титл для объединения
  4815. if ListOptTitle:
  4816. title = self.getTitle(objTemplNew._comment,
  4817. ListOptTitle,
  4818. configPath=nameFileConfig)
  4819. title = title.encode("UTF-8")
  4820. # В случае пустого конфигурационного файла
  4821. reNoClean = re.compile("[^\s]",re.M)
  4822. if not self.textConfig or\
  4823. not reNoClean.search(self.textConfig):
  4824. self.textConfig = ""
  4825. objHeadOld = fileHeader(nameFileConfig, self.textConfig,
  4826. objTemplNew._comment)
  4827. if objHeadOld.body:
  4828. self.textConfig = objHeadOld.body
  4829. else:
  4830. self.textConfig = ""
  4831. if flagNotUtf8Old:
  4832. objTxtCoder = utfBin()
  4833. self.textConfig = objTxtCoder.encode(self.textConfig)
  4834. # создаем объект формата шаблона для конфигурационного файла
  4835. objTemplOld = self.getFormatObj(formatTemplate,
  4836. self.textConfig)
  4837. if not objTemplOld:
  4838. self.setError(_("Error in template %s") %nameFileConfig)
  4839. return False
  4840. if "xml_" in formatTemplate:
  4841. if objTemplOld.getError():
  4842. self.setError(_("Wrong template") + ": " +\
  4843. nameFileConfig)
  4844. return False
  4845. nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
  4846. objTemplOld.setNameBodyNode(nameRootNode)
  4847. objTemplOld.join(objTemplNew)
  4848. if "xml_" in formatTemplate:
  4849. if objTemplOld.getError():
  4850. self.setError(_("Wrong template") + ": " +\
  4851. nameFileTemplate)
  4852. return False
  4853. data = objTemplOld.getConfig().encode("UTF-8").split("\n")
  4854. data.insert(1,title)
  4855. self.textConfig = "\n".join(data)
  4856. else:
  4857. if execStr:
  4858. self.textConfig = execStr + title +\
  4859. objTemplOld.getConfig().encode("UTF-8")
  4860. else:
  4861. self.textConfig = title +\
  4862. objTemplOld.getConfig().encode("UTF-8")
  4863. # Декодируем если кодировка не UTF-8
  4864. if flagNotUtf8New or flagNotUtf8Old:
  4865. self.textTemplate = objTxtCoder.decode(self.textTemplate)
  4866. self.textConfig = objTxtCoder.decode(self.textConfig)
  4867. self.saveConfFile()
  4868. if 'exec' in objHeadNew.params:
  4869. if not self.executeTemplate(self.nameFileConfig,
  4870. objHeadNew.params['exec']):
  4871. self.setError(_("Wrong template") + ": " +\
  4872. nameFileTemplate)
  4873. self.setError(_("Failed to execute") + ": " +\
  4874. self.nameFileConfig)
  4875. return False
  4876. return False
  4877. return filesApply
  4878. else:
  4879. self.setError(_("Wrong (type append) template") + ": " +\
  4880. typeAppendTemplate)
  4881. return False
  4882. else:
  4883. self.setError(_("Template type not found: ") + nameFileTemplate)
  4884. return False
  4885. return filesApply
  4886. class scanDirectoryClt:
  4887. """Класс для cканирования директорий с файлами .clt"""
  4888. # Расширение файла шаблона
  4889. extFileTemplate = ".clt"
  4890. lenExtFileTemplate = len(extFileTemplate)
  4891. filterApplyTemplates = []
  4892. def processingFile(self, path, prefix):
  4893. """Обработка в случае файла"""
  4894. return True
  4895. def scanningTemplates(self, scanDir, prefix=None, flagDir=False):
  4896. """Сканирование и обработка шаблонов в директории scanDir"""
  4897. ret = True
  4898. if not prefix:
  4899. prefix = os.path.realpath(scanDir)
  4900. if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
  4901. for fileOrDir in sorted(os.listdir(scanDir)):
  4902. absPath = os.path.join(scanDir,fileOrDir)
  4903. stInfo = os.lstat(absPath)
  4904. statInfo = stInfo[stat.ST_MODE]
  4905. if fileOrDir.endswith(self.extFileTemplate) and\
  4906. stat.S_ISREG(statInfo):
  4907. if not self.filterApplyTemplates or\
  4908. absPath[:-self.lenExtFileTemplate] in\
  4909. self.filterApplyTemplates:
  4910. if not self.processingFile(absPath, prefix):
  4911. ret = False
  4912. break
  4913. elif stat.S_ISDIR(statInfo):
  4914. ret = self.scanningTemplates(absPath, prefix, True)
  4915. if ret is False:
  4916. break
  4917. return ret
  4918. class templateClt(scanDirectoryClt, template):
  4919. """Класс для обработки шаблонов c расширением .clt"""
  4920. def __init__(self, objVar):
  4921. self.checkNumberTemplate = True
  4922. template.__init__(self, objVar, cltObj=False)
  4923. applyPackages = ["calculate-install"]
  4924. self.flagApplyTemplates = False
  4925. if self.objVar.Get("cl_name") in applyPackages:
  4926. self.flagApplyTemplates = True
  4927. # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
  4928. self._chrootDir = os.path.normpath(self.objVar.Get("cl_chroot_path"))
  4929. self._baseDir = pathJoin(self._chrootDir,
  4930. self.objVar.Get("cl_root_path"))
  4931. self._baseDir = os.path.normpath(self._baseDir)
  4932. def applyTemplate(self, path):
  4933. """Применение отдельного .clt шаблона"""
  4934. if not self.flagApplyTemplates:
  4935. return True
  4936. return self.processingFile(path, "")
  4937. def processingFile(self, path, prefix):
  4938. """Обработка в случае шаблона файла"""
  4939. self.numberProcessTempl += 1
  4940. self.numberProcessTemplates(self.numberProcessTempl)
  4941. # Пропуск шаблонов директорийscanningTemplates
  4942. if self.templDirNameFile == os.path.split(path)[1]:
  4943. return True
  4944. # Проверка на переменные в названии файла
  4945. if not self.getNeedTemplate(path):
  4946. if self.getError():
  4947. return False
  4948. return True
  4949. if self.getError():
  4950. return False
  4951. if prefix and prefix[-1] == "/":
  4952. prefix = prefix[:-1]
  4953. if prefix:
  4954. nameFileConfig = path.partition(prefix)[2]
  4955. else:
  4956. nameFileConfig = path
  4957. nameFileConfig = nameFileConfig[:-self.lenExtFileTemplate]
  4958. nameFileConfig = pathJoin(self._baseDir, nameFileConfig)
  4959. # файл в системе без условий
  4960. nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\
  4961. nameFileConfig.split("/")))
  4962. # Записываем в переменную обрабатываемый файл
  4963. self.objVar.Set("cl_pass_file",nameFileConfig)
  4964. filesApl = self.joinTemplate(path, nameFileConfig)
  4965. if self.getError():
  4966. return False
  4967. if filesApl:
  4968. # Настоящее имя конфигурационного файла
  4969. nameFileConfig = filesApl[0]
  4970. # Пишем время модификации *.env файлов
  4971. if nameFileConfig.endswith(".env"):
  4972. nameEnvFile = os.path.basename(nameFileConfig)
  4973. self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
  4974. self.filesApply += filesApl
  4975. return nameFileConfig
  4976. else:
  4977. return True
  4978. def countsNumberTemplates(self, dirsTemplates=[]):
  4979. """Считаем количество шаблонов"""
  4980. def createDictTemplates(path, prefix, dictTemplates):
  4981. """Создает словарь {"директория":"кол-во шаблонов" ...}
  4982. и считает общее количество шаблонов
  4983. """
  4984. # Количество шаблонов
  4985. self.allTemplates += 1
  4986. dirTemplate = os.path.split(path)[0]
  4987. while(True):
  4988. if dirTemplate in dictTemplates.keys():
  4989. dictTemplates[dirTemplate] += 1
  4990. else:
  4991. dictTemplates[dirTemplate] = 1
  4992. if dirTemplate == prefix:
  4993. break
  4994. dirTemplate = os.path.split(dirTemplate)[0]
  4995. return dictTemplates
  4996. if not dirsTemplates:
  4997. dirsTemplates = self.objVar.Get("cl_template_clt_path")
  4998. dirsTemplates.sort()
  4999. scanObj = scanDirectoryClt()
  5000. scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
  5001. self.dictTemplates)
  5002. # Считаем количество шаблонов
  5003. for dirTemplate in dirsTemplates:
  5004. scanObj.scanningTemplates(dirTemplate, "/")
  5005. def applyTemplates(self):
  5006. """Применяет шаблоны к конфигурационным файлам"""
  5007. if not self.flagApplyTemplates:
  5008. return ([],[])
  5009. if not self.objVar.defined("cl_template_clt_path"):
  5010. self.setError(_("undefined variable: ") + "cl_template_clt_path")
  5011. return False
  5012. dirsTemplates = self.objVar.Get("cl_template_clt_path")
  5013. dirsTemplates.sort()
  5014. if self.checkNumberTemplate:
  5015. # Созданные директории
  5016. self.createdDirs = []
  5017. # Примененные файлы
  5018. self.filesApply = []
  5019. # Номер применяемого шаблона
  5020. self.numberProcessTempl = 0
  5021. # Словарь директорий с количеством файлов шаблонов
  5022. self.dictTemplates = {}
  5023. # Количество шаблонов
  5024. self.allTemplates = 0
  5025. # Установка по умолчанию аттрибутов для функциии шаблонов ini()
  5026. # Время доступа к конфигурационному файлу функции шаблона ini()
  5027. self.functObj.timeIni = -1
  5028. # Первоначальный словарь переменных для ini()
  5029. self.functObj.prevDictIni = {}
  5030. # Текущий словарь переменных для ini()
  5031. self.functObj.currDictIni = {}
  5032. # Словарь времен модификации env файлов для ini()
  5033. self.functObj.timeConfigsIni = {}
  5034. # Считаем количество шаблонов
  5035. self.countsNumberTemplates(dirsTemplates=dirsTemplates)
  5036. self.numberAllTemplates(self.allTemplates)
  5037. # Обрабатываем шаблоны
  5038. for dirTemplate in dirsTemplates:
  5039. if self.scanningTemplates(dirTemplate, self._chrootDir) is False:
  5040. return False
  5041. return (self.createdDirs, self.filesApply)
  5042. class IniError(Exception):
  5043. pass
  5044. class iniParser(_error, templateFormat):
  5045. """Класс для работы с ini файлами
  5046. """
  5047. def __init__(self, iniFile):
  5048. # название ini файла
  5049. self.iniFile = iniFile
  5050. # права создаваемого ini-файла
  5051. self.mode = 0640
  5052. # Cоответствует ли формат файла нужному
  5053. self.checkIni = None
  5054. self.FD = None
  5055. self.readOnly = False
  5056. def setMode(self, mode):
  5057. """установка прав создаваемого ini-файла"""
  5058. self.mode = mode
  5059. def openIniFile(self):
  5060. if not os.access(self.iniFile, os.R_OK):
  5061. return ""
  5062. self.FD = open(self.iniFile, "r")
  5063. fcntl.flock(self.FD.fileno(), fcntl.LOCK_EX)
  5064. textIni = self.FD.read()
  5065. return textIni
  5066. def openRWIniFile(self):
  5067. if not os.access(self.iniFile, os.R_OK):
  5068. if not os.path.exists(self.iniFile):
  5069. try:
  5070. # Создание файла
  5071. self.FD = open(self.iniFile, "w+")
  5072. fcntl.flock(self.FD.fileno(), fcntl.LOCK_EX)
  5073. os.chmod(self.iniFile, self.mode)
  5074. except:
  5075. error = _("Unable to create the file") + ": " + self.iniFile
  5076. self.setError(error)
  5077. raise IniError(error)
  5078. return ""
  5079. try:
  5080. self.FD = open(self.iniFile, "r+")
  5081. except (IOError,OSError),e:
  5082. self.FD = open(self.iniFile, "r")
  5083. self.readOnly = True
  5084. fcntl.flock(self.FD.fileno(), fcntl.LOCK_EX)
  5085. textIni = self.FD.read()
  5086. return textIni
  5087. def writeIniFile(self, txtConfig):
  5088. if self.readOnly:
  5089. self.setError(_("Unable to write to the file") +
  5090. ": " + self.iniFile)
  5091. return False
  5092. if not self.FD:
  5093. self.setError(_("Unable to write to the file") +
  5094. ": " + self.iniFile)
  5095. return False
  5096. self.FD.truncate(0)
  5097. self.FD.seek(0)
  5098. self.FD.write(txtConfig)
  5099. return True
  5100. def setVar(self, strHeader, dictVar):
  5101. """Заменяет или добавляет область и переменные
  5102. Добавляет область в ini-файл или объединяет с существующей
  5103. strHeader - имя области
  5104. dictVar - словарь переменных
  5105. """
  5106. try:
  5107. textIni = self.openRWIniFile()
  5108. nameFomat = self.checkIniFile(textIni)
  5109. if not nameFomat:
  5110. return False
  5111. if type(strHeader) in (tuple, list):
  5112. # формат plasma
  5113. classObj = self.getClassObj("plasma")
  5114. else:
  5115. if nameFomat == "plasma":
  5116. self.setError(_("Trying to write a variable of 'samba' format"
  5117. " to file %s (format - 'plasma')")
  5118. %self.iniFile)
  5119. return False
  5120. # формат samba
  5121. classObj = self.getClassObj("samba")
  5122. # создаем объект
  5123. # и записываем в него содержимое ini-файла
  5124. objIni = classObj(textIni)
  5125. # создаем текст из строки заголовка и
  5126. # словаря переменных области
  5127. txtConfig = objIni.createTxtConfig(strHeader, dictVar)
  5128. # создаем объект и записываем в него текст
  5129. objIniAdd = classObj(txtConfig)
  5130. # объединяем объекты для получения результирующего текста
  5131. objIni.join(objIniAdd)
  5132. # получаем текст
  5133. txtConfig = objIni.getConfig().encode("UTF-8")
  5134. # записываем его в ini файл
  5135. if not self.writeIniFile(txtConfig):
  5136. return False
  5137. return True
  5138. except IniError:
  5139. return False
  5140. finally:
  5141. self._closeFD()
  5142. def _closeFD(self):
  5143. if self.FD:
  5144. try:
  5145. self.FD.close()
  5146. except:
  5147. pass
  5148. self.FD = None
  5149. def isEmptyFile(self, textIni):
  5150. """Если файл пустой или содержит только комментарии - False
  5151. иначе - True
  5152. """
  5153. if textIni.strip():
  5154. if filter(lambda x: x.strip(),
  5155. map(lambda x:x[0].split(";")[0],
  5156. map(lambda x: x.split("#"),
  5157. textIni.splitlines()))):
  5158. return False
  5159. else:
  5160. return True
  5161. else:
  5162. return True
  5163. def checkIniFile(self, textIni):
  5164. """Проверка на правильность формата файла"""
  5165. if self.checkIni is None:
  5166. # Ошибка
  5167. if textIni == False:
  5168. self.checkIni = False
  5169. return False
  5170. self.checkIni = "samba"
  5171. # В файле есть данные
  5172. if not self.isEmptyFile(textIni):
  5173. try:
  5174. objIni = self.getClassObj("plasma")(textIni)
  5175. except:
  5176. self.setError(_("Incorrect file format") + ": " + \
  5177. self.iniFile)
  5178. self.checkIni = False
  5179. return self.checkIni
  5180. allAreas = objIni.docObj.getAllAreas()
  5181. for xmlArea in allAreas:
  5182. parentNode = xmlArea.parentNode
  5183. if parentNode and parentNode.tagName == "area":
  5184. self.checkIni = "plasma"
  5185. break
  5186. if self.checkIni == "samba":
  5187. objIni = self.getClassObj("samba")(textIni)
  5188. xmlBody = objIni.docObj.getNodeBody()
  5189. if not xmlBody.firstChild:
  5190. self.checkIni = False
  5191. return self.checkIni
  5192. def delVar(self, strHeader, nameVar):
  5193. """Удаляем переменную из ini файла"""
  5194. delNameVar = "!%s" %(nameVar)
  5195. dictVar = {delNameVar:"del"}
  5196. res = self.setVar(strHeader, dictVar)
  5197. return res
  5198. def delArea(self, strHeader):
  5199. """Удаляем область из ini файла"""
  5200. if type(strHeader) in (tuple, list):
  5201. # Формат plasma
  5202. delStrHeader = list(strHeader[:])
  5203. delStrHeader[-1] = "!%s"%delStrHeader[-1]
  5204. else:
  5205. # Формат samba
  5206. delStrHeader = "!%s" %(strHeader)
  5207. dictVar = {"del":"del"}
  5208. res = self.setVar(delStrHeader, dictVar)
  5209. return res
  5210. def getVar(self, strHeader, nameVar, checkExistVar=False):
  5211. """Получаем значение переменной из ini-файла"""
  5212. textIni = self.openIniFile()
  5213. if self.FD:
  5214. self.FD.close()
  5215. self.FD = None
  5216. nameFomat = self.checkIniFile(textIni)
  5217. if not nameFomat:
  5218. return False
  5219. formatPlasma = False
  5220. if type(strHeader) in (tuple, list):
  5221. # формат plasma
  5222. classObj = self.getClassObj("plasma")
  5223. formatPlasma = True
  5224. else:
  5225. if nameFomat == "plasma":
  5226. self.setError(_("Trying to fetch a variable of 'samba' format"
  5227. " from file %s (format - 'plasma')")\
  5228. %self.iniFile)
  5229. return False
  5230. # формат samba
  5231. classObj = self.getClassObj("samba")
  5232. # создаем объект и записываем в него содержимое ini-файла
  5233. objIni = classObj(textIni)
  5234. # получаем ноду body
  5235. xmlBody = objIni.docObj.getNodeBody()
  5236. flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader,
  5237. formatPlasma)
  5238. if flagFound and xmlBody:
  5239. if formatPlasma:
  5240. strHeader = strHeader[-1]
  5241. # находим в области переменную
  5242. res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody)
  5243. else:
  5244. res = False
  5245. if checkExistVar:
  5246. if res is False:
  5247. return False, ""
  5248. else:
  5249. return True, res
  5250. else:
  5251. if res is False:
  5252. return ""
  5253. else:
  5254. return res
  5255. def getLastNode(self, objIni, xmlBody, strHeader, formatPlasma):
  5256. """Ищет область в XML в которой область с переменными"""
  5257. flagFound = True
  5258. if not strHeader:
  5259. flagFound = False
  5260. return flagFound,xmlBody
  5261. lenStrHeader = len(strHeader)
  5262. if formatPlasma and lenStrHeader>0:
  5263. xmlAreas = [xmlBody]
  5264. for i in xrange(lenStrHeader-1):
  5265. flagFound = False
  5266. for xmlArea in xmlAreas:
  5267. xmlAreas = objIni.docObj.getArea(strHeader[i], xmlArea)
  5268. if xmlAreas:
  5269. flagFound = True
  5270. break
  5271. if xmlAreas:
  5272. xmlBody = xmlAreas[0]
  5273. return flagFound,xmlBody
  5274. def getAreaVars(self, strHeader):
  5275. """Получаем все переменнные области из ini-файла"""
  5276. textIni = self.openIniFile()
  5277. if self.FD:
  5278. self.FD.close()
  5279. self.FD = None
  5280. nameFomat = self.checkIniFile(textIni)
  5281. if not nameFomat:
  5282. return False
  5283. formatPlasma = False
  5284. if type(strHeader) in (tuple, list):
  5285. # формат plasma
  5286. classObj = self.getClassObj("plasma")
  5287. formatPlasma = True
  5288. else:
  5289. if nameFomat == "plasma":
  5290. self.setError(_("Trying to fetch all variables of 'samba' "
  5291. "format from file %s (format - 'plasma')")
  5292. %self.iniFile)
  5293. return False
  5294. # формат samba
  5295. classObj = self.getClassObj("samba")
  5296. # создаем объект типа samba и записываем в него содержимое ini-файла
  5297. objIni = classObj(textIni)
  5298. # получаем ноду body
  5299. xmlBody = objIni.docObj.getNodeBody()
  5300. flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader,
  5301. formatPlasma)
  5302. if flagFound and xmlBody:
  5303. if formatPlasma:
  5304. strHeader = strHeader[-1]
  5305. # если находим область то выдаем словарем все переменные иначе False
  5306. res = objIni.docObj.getAreaFields(strHeader, xmlBody)
  5307. else:
  5308. res = False
  5309. if res is False:
  5310. return {}
  5311. else:
  5312. return res
  5313. def getAllSectionNames(self):
  5314. """Получаем все имена секций определенных в ini файле
  5315. Если формат ini файла plasma то имя секции -
  5316. имена нескольких секций через запятую
  5317. """
  5318. textIni = self.openIniFile()
  5319. if self.FD:
  5320. self.FD.close()
  5321. self.FD = None
  5322. nameFomat = self.checkIniFile(textIni)
  5323. if not nameFomat:
  5324. return False
  5325. if nameFomat == "samba":
  5326. # создаем объект типа samba и записываем в него содержимое ini-файла
  5327. objIni = self.getClassObj("samba")(textIni)
  5328. elif nameFomat == "plasma":
  5329. # создаем объект типа plasma и записываем в него содержимое
  5330. # ini-файла
  5331. objIni = self.getClassObj("plasma")(textIni)
  5332. else:
  5333. return []
  5334. xmlNodes = objIni.docObj.getAllAreas()
  5335. # Имена секций ini файла
  5336. namesSection = []
  5337. if nameFomat == "plasma":
  5338. for xmlNode in xmlNodes:
  5339. nSect = objIni.docObj.getNameArea(xmlNode)
  5340. if nSect:
  5341. namesSect = [nSect]
  5342. parentNode = xmlNode.parentNode
  5343. while parentNode != objIni.docObj.body:
  5344. nameSect = objIni.docObj.getNameArea(parentNode)
  5345. if nameSect:
  5346. namesSect.append(nameSect)
  5347. parentNode = parentNode.parentNode
  5348. else:
  5349. return []
  5350. namesSection.append(",".join(reversed(namesSect)))
  5351. elif nameFomat == "samba":
  5352. # получаем ноду body
  5353. for xmlNode in xmlNodes:
  5354. nSect = objIni.docObj.getNameArea(xmlNode)
  5355. if nSect:
  5356. namesSection.append(nSect)
  5357. return namesSection