You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7235 lines
309 KiB

  1. #-*- coding: utf-8 -*-
  2. # Copyright 2008-2010 Mir Calculate. 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 cl_base
  18. import stat
  19. import re
  20. import xml.dom.minidom
  21. from xml import xpath
  22. import subprocess
  23. import types
  24. import copy
  25. import random
  26. import string
  27. import time
  28. tr = cl_base.lang()
  29. tr.setLocalDomain('cl_lib')
  30. tr.setLanguage(sys.modules[__name__])
  31. class _error:
  32. # Здесь ошибки, если они есть
  33. error = []
  34. def getError(self):
  35. """Выдать ошибки"""
  36. if not self.error:
  37. return False
  38. error = ""
  39. for e in self.error:
  40. error += e + "\n"
  41. return error
  42. def setError(self, error):
  43. """Установка ошибки"""
  44. self.error.append(error)
  45. return True
  46. class _terms(_error):
  47. """Вычисление условий применяемых в профилях
  48. """
  49. # регулярное выражение для не версии
  50. _re_not_Version = re.compile("[^0-9\.]|^$")
  51. # регулярное выражение для функции
  52. _reFunction = re.compile(\
  53. "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\)")
  54. # Регулярное выражение для названия переменной
  55. _reDenyName = re.compile("[^a-zA-Z0-9\_\-]")
  56. # Регулярное выражение для сравниваемого значения
  57. _reDenyValue = re.compile("[^0-9a-zA-Z_\.-]")
  58. def _convertVers(self, verA, verB):
  59. """Конвертирование номеров версий для корректного сравнения
  60. """
  61. elemA = verA.split(".")
  62. elemB = verB.split(".")
  63. if len(elemA) > len(elemB):
  64. maxElemB = len(elemB)-1
  65. for i in range(len(elemA)):
  66. if i > maxElemB:
  67. elemB.append("0")
  68. else:
  69. maxElemA = len(elemA)-1
  70. for i in range(len(elemB)):
  71. if i > maxElemA:
  72. elemA.append("0")
  73. for i in range(len(elemB)):
  74. lenA = len(elemA[i])
  75. lenB = len(elemB[i])
  76. if lenA == lenB:
  77. pass
  78. elif lenA > lenB:
  79. res = lenA - lenB
  80. for z in range(res):
  81. elemB[i] = "0" + elemB[i]
  82. elif lenB > lenA:
  83. res = lenB - lenA
  84. for z in range(res):
  85. elemA[i] = "0" + elemA[i]
  86. return (".".join(elemA), ".".join(elemB))
  87. def _equalTerm(self, term, textError, function=False):
  88. """Вычисление логических выражений для условий
  89. Для корректной работы в классе который наследует этот класс
  90. должен быть объявлен аттрибут self.objVar
  91. (объект для работы с переменными)
  92. function - функция для для обработки функций в заголовке блока
  93. """
  94. trm = {"&":" and ","||":" or "}
  95. rule = ["==", "!=", ">=", "<=", ">", "<"]
  96. listEqual = []
  97. for k in trm.keys():
  98. if k in term:
  99. term = term.replace(k,trm[k])
  100. trs = term.split(" ")
  101. for t in trs:
  102. flagRule = False
  103. for sepF in rule:
  104. if sepF in t:
  105. flagRule = True
  106. vals = t.split(sepF)
  107. break
  108. if not flagRule:
  109. flagLog = False
  110. for k in trm.values():
  111. if k.strip() == t:
  112. flagLog = True
  113. break
  114. if not flagLog:
  115. self.setError("'%s'"%term + " " + _("incorrect"))
  116. self.setError (textError)
  117. return False
  118. else:
  119. listEqual.append(k)
  120. else:
  121. #проверка на допустимость названия переменной
  122. flagFunction = False
  123. if self._reDenyName.search(vals[0]):
  124. #проверка на допустимость функции
  125. flagError = True
  126. if function:
  127. searchFunct = self._reFunction.search(vals[0])
  128. if searchFunct:
  129. flagError = False
  130. flagFunction = True
  131. if flagError:
  132. self.setError("'%s'"%term + " " + _("incorrect"))
  133. self.setError(textError)
  134. return False
  135. #проверка на допустимость значения
  136. if self._reDenyValue.search(vals[1]):
  137. self.setError("'%s'"%term + " " + _("incorrect"))
  138. self.setError(textError)
  139. return False
  140. flagIntTypeVar = None
  141. if flagFunction:
  142. valVars = function("#-%s-#"%vals[0])
  143. if valVars is False:
  144. self.setError("'%s'"%term + " " + _("incorrect"))
  145. self.setError(textError)
  146. return False
  147. if "load" == searchFunct.group(1):
  148. if re.search("\(\s*num\s*,",vals[0]):
  149. if valVars:
  150. try:
  151. valVars = int(valVars)
  152. except:
  153. self.setError("'%s'"%term + " " + \
  154. _("incorrect"))
  155. self.setError (textError)
  156. return False
  157. flagIntTypeVar = True
  158. else:
  159. flagIntTypeVar = False
  160. else:
  161. if valVars == "" and\
  162. not self._re_not_Version.search(vals[1]):
  163. valVars = "0"
  164. elif vals[1] == "" and\
  165. not self._re_not_Version.search(valVars):
  166. vals[1] = "0"
  167. else:
  168. try:
  169. valVars = self.objVar.Get(vals[0])
  170. except self.objVar.DataVarsError, e:
  171. print textError
  172. print e
  173. cl_base.exit(1)
  174. # Номера версий для ini
  175. flagNotIniFunct = True
  176. # Два значения не пусты
  177. flagNotEmptyVals = not (valVars == "" and vals[1] == "")
  178. if flagFunction and flagNotEmptyVals and\
  179. searchFunct.group(1) == "ini":
  180. # Проверка значения на версию
  181. if not self._re_not_Version.search(valVars) and\
  182. not self._re_not_Version.search(vals[1]):
  183. verFile, verVar = self._convertVers(vals[1],valVars)
  184. exec(\
  185. "res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
  186. if res:
  187. listEqual.append("1")
  188. else:
  189. listEqual.append("0")
  190. flagNotIniFunct = False
  191. # Cравниваем номера версий
  192. if flagNotIniFunct:
  193. if flagNotEmptyVals and\
  194. ("_ver" in vals[0] or\
  195. (flagFunction and searchFunct.group(1) == "pkg") or\
  196. (flagFunction and searchFunct.group(1) == "load" and\
  197. re.search("\(\s*ver\s*,",vals[0]))):
  198. # Проверка значения на версию
  199. if self._re_not_Version.search(vals[1]):
  200. self.setError("'%s'"%term + " " + _("incorrect"))
  201. self.setError (_("Value is not version"))
  202. return False
  203. # Проверка значения функции на версию
  204. if self._re_not_Version.search(valVars):
  205. self.setError("'%s'"%term + " " + _("incorrect"))
  206. self.setError (_("Value function is not version"))
  207. return False
  208. verFile, verVar = self._convertVers(vals[1],valVars)
  209. exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
  210. if res:
  211. listEqual.append("1")
  212. else:
  213. listEqual.append("0")
  214. flagNotIniFunct = False
  215. else:
  216. if flagIntTypeVar == None:
  217. flagIntTypeVar = True
  218. try:
  219. valVars = int(valVars)
  220. except:
  221. flagIntTypeVar = False
  222. if flagIntTypeVar:
  223. if not vals[1].strip():
  224. vals[1] = 0
  225. try:
  226. valFile = int(vals[1])
  227. except:
  228. self.setError("'%s'"%term +" " +_("incorrect"))
  229. self.setError (textError)
  230. return False
  231. valVar = valVars
  232. exec("res=(%d%s%d)"%(valVar,sepF,valFile))
  233. if res:
  234. listEqual.append("1")
  235. else:
  236. listEqual.append("0")
  237. else:
  238. if sepF == "!=" or sepF == "==":
  239. if not vals[1].strip():
  240. vals[1] = ""
  241. valFile = vals[1]
  242. valVar = valVars
  243. exec(\
  244. "res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\
  245. "'"+")")
  246. if res:
  247. listEqual.append("1")
  248. else:
  249. listEqual.append("0")
  250. else:
  251. if not flagNotEmptyVals:
  252. listEqual.append("0")
  253. else:
  254. self.setError("'%s'"%term + " "\
  255. + _("incorrect"))
  256. self.setError (textError)
  257. return False
  258. exec("res=(%s)"%("".join(listEqual)))
  259. return res
  260. class fileHeader(_terms):
  261. """Обработка заголовков профилей и конфигурационных файлов
  262. """
  263. # Допустимые параметры заголовка
  264. allowParam = ["format", "format_conf", "comment", "append", "force",
  265. "link", "mirror", "symbolic", "chmod", "chown", "name"]
  266. # Корректность заголовка
  267. headerCorrect = True
  268. # Тип профиля
  269. fileType = ""
  270. # Тип вставки профиля
  271. typeAppend = ""
  272. # Возможные типы вставки профилей
  273. _fileAppend = "join", "before", "after", "replace", "remove"
  274. # Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
  275. execStr = ""
  276. # Символ комментария
  277. comment = False
  278. # Выражение для поиска строки интерпретатора
  279. reExecStr = re.compile("^#!.+\s*",re.I)
  280. # условные операторы
  281. terms = ('>', '<', '==', '!=', '>=', '<=')
  282. # параметры без значения
  283. listParNotVal = ("symbolic", "force", "mirror")
  284. # Результат вычисления условия в заголовке
  285. headerTerm = True
  286. # Сообщение о ошибке
  287. errorMessage = ""
  288. def __init__(self, text, comment=False, fileType=False, objVar=False,
  289. function=False):
  290. self.body = text
  291. # Объект с переменными
  292. self.objVar=objVar
  293. # Параметры описанные в заголовке файла профиля
  294. self.params = {}
  295. # некорректные параметры
  296. incorrectParams = set([])
  297. # Удаление Заголовка Calculate
  298. if comment:
  299. # В случае текста XML
  300. if type(comment) == types.TupleType and len(comment) == 2:
  301. _titleList = (_("Modified"), _("File of a profile"))
  302. reCalcHeader =\
  303. re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\
  304. comment[0],
  305. _titleList[0].decode("UTF-8"),
  306. _titleList[1].decode("UTF-8"),
  307. comment[1],
  308. ),
  309. re.M|re.I|re.U)
  310. textUnicode = text.decode("UTF-8")
  311. reS = reCalcHeader.search(textUnicode)
  312. if reS:
  313. textBody = textUnicode[:reS.start()]+textUnicode[reS.end():]
  314. if textBody:
  315. self.body = textBody.encode("UTF-8")
  316. else:
  317. reCalcHeader =\
  318. re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\
  319. comment,
  320. comment,
  321. comment,
  322. comment,
  323. ),
  324. re.M|re.I)
  325. reS = reCalcHeader.search(text)
  326. if reS:
  327. self.body = text[reS.end():]
  328. if fileType != False:
  329. if fileType=="bin":
  330. self.params["format"] = fileType
  331. self.fileType = self._getType()
  332. self.typeAppend = self._getAppend()
  333. else:
  334. textLines = text.splitlines()
  335. if textLines:
  336. textLine = textLines[0]
  337. rePar = re.compile("\s*#\s*calculate\s+",re.I)
  338. reP = rePar.search(textLine)
  339. if reP:
  340. reL = False
  341. reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
  342. reLs = reLns.search(text)
  343. if reLs:
  344. reL = reLs
  345. paramLine = text[reP.end():reLs.end()]
  346. paramLine = paramLine.replace("\\"," ")
  347. else:
  348. reLn = re.compile("\n")
  349. reL = reLn.search(text)
  350. paramLine = textLine[reP.end():]
  351. if reL:
  352. self.body = text[reL.end():]
  353. else:
  354. self.body = ""
  355. paramList = re.split("\s+",paramLine)
  356. if paramList:
  357. for i in paramList:
  358. foundTerm = False
  359. for term in self.terms:
  360. if term in i:
  361. foundTerm = True
  362. if function:
  363. rezTerm = self._equalTerm(i,\
  364. _("header profile not valid: ") + \
  365. i,function)
  366. else:
  367. rezTerm = self._equalTerm(i,\
  368. _("header profile not valid: ") + \
  369. i)
  370. if not rezTerm:
  371. self.headerTerm = False
  372. break
  373. if not foundTerm:
  374. par = i.split("=")
  375. if len(par) == 1:
  376. if i in self.listParNotVal:
  377. self.params[i] = "True"
  378. else:
  379. if i.strip():
  380. incorrectParams = set([i])
  381. elif len(par) == 2:
  382. self.params[par[0]] = par[1]
  383. self.comment = self._getComment()
  384. self.fileType = self._getType()
  385. self.typeAppend = self._getAppend()
  386. reExecRes = self.reExecStr.search(self.body)
  387. if reExecRes:
  388. self.execStr = self.body[reExecRes.start():reExecRes.end()]
  389. self.body = self.body[reExecRes.end():]
  390. if not incorrectParams:
  391. incorrectParams = set(self.params.keys()) - set(self.allowParam)
  392. if incorrectParams:
  393. self.headerTerm = False
  394. self.headerCorrect = False
  395. self.errorMessage = _("incorrect header parameters - '%s'")\
  396. % " ".join(list(incorrectParams))
  397. def _getType(self):
  398. """Выдать тип файла"""
  399. if self.params.has_key("format"):
  400. return self.params["format"]
  401. else:
  402. return "raw"
  403. def _getAppend(self):
  404. """Выдать тип добавления файла"""
  405. if self.params.has_key("append") and self.params["append"] in\
  406. self._fileAppend:
  407. return self.params["append"]
  408. else:
  409. if self.fileType != "raw" and self.fileType != "bin" and\
  410. self.fileType != "":
  411. self.params["append"] = "join"
  412. return "join"
  413. self.params["append"] = "replace"
  414. return "replace"
  415. def _getComment(self):
  416. """Выдать символ комментария файла"""
  417. if self.params.has_key("comment"):
  418. return self.params["comment"]
  419. else:
  420. return False
  421. class dirHeader(_terms):
  422. """Обработка заголовков профилей директорий
  423. """
  424. # Допустимые параметры заголовка
  425. allowParam = ["append", "chmod", "chown", "name"]
  426. # Корректность заголовка
  427. headerCorrect = True
  428. # Тип вставки профиля
  429. typeAppend = ""
  430. # Возможные типы вставки профилей
  431. _fileAppend = "join", "remove"
  432. # условные операторы
  433. terms = ('>', '<', '==', '!=', '>=', '<=')
  434. # параметры без значения
  435. listParNotVal = ("symbolic", "force")
  436. # Результат вычисления условия в заголовке
  437. headerTerm = True
  438. # Сообщение о ошибке
  439. errorMessage = ""
  440. def __init__(self, text, objVar=False, function=False):
  441. self.body = text
  442. # Объект с переменными
  443. self.objVar=objVar
  444. # Параметры описанные в заголовке файла профиля
  445. self.params = {}
  446. # некорректные параметры
  447. incorrectParams = set([])
  448. textLines = text.splitlines()
  449. flagErrorBody = False
  450. if textLines:
  451. textLine = textLines[0]
  452. rePar = re.compile("\s*#\s*calculate\s+",re.I)
  453. reP = rePar.search(textLine)
  454. if reP:
  455. reL = False
  456. reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
  457. reLs = reLns.search(text)
  458. if reLs:
  459. reL = reLs
  460. paramLine = text[reP.end():reLs.end()]
  461. paramLine = paramLine.replace("\\"," ")
  462. else:
  463. reLn = re.compile("\n")
  464. reL = reLn.search(text)
  465. paramLine = textLine[reP.end():]
  466. if reL:
  467. self.body = text[reL.end():]
  468. else:
  469. self.body = ""
  470. if self.body.strip():
  471. self.headerTerm = False
  472. self.headerCorrect = False
  473. self.errorMessage = _("incorrect text in profile: '%s'")\
  474. %self.body
  475. flagErrorBody = True
  476. if not flagErrorBody:
  477. paramList = re.split("\s+",paramLine)
  478. if paramList:
  479. for i in paramList:
  480. foundTerm = False
  481. for term in self.terms:
  482. if term in i:
  483. foundTerm = True
  484. if function:
  485. rezTerm = self._equalTerm(i,\
  486. _("header profile not valid: ") + \
  487. i,function)
  488. else:
  489. rezTerm = self._equalTerm(i,\
  490. _("header profile not valid: ") + \
  491. i)
  492. if not rezTerm:
  493. self.headerTerm = False
  494. break
  495. if not foundTerm:
  496. par = i.split("=")
  497. if len(par) == 1:
  498. if i in self.listParNotVal:
  499. self.params[i] = "True"
  500. else:
  501. if i.strip():
  502. incorrectParams = set([i])
  503. elif len(par) == 2:
  504. self.params[par[0]] = par[1]
  505. self.typeAppend = self._getAppend()
  506. if not flagErrorBody:
  507. if not incorrectParams:
  508. incorrectParams = set(self.params.keys()) - set(self.allowParam)
  509. if incorrectParams:
  510. self.headerTerm = False
  511. self.headerCorrect = False
  512. self.errorMessage = _("incorrect header parameters - '%s'")\
  513. % " ".join(list(incorrectParams))
  514. def _getAppend(self):
  515. """Выдать тип добавления директории"""
  516. if self.params.has_key("append") and self.params["append"] in\
  517. self._fileAppend:
  518. return self.params["append"]
  519. else:
  520. return "join"
  521. class objShare:
  522. """Общий клас для объектов, наследуем
  523. """
  524. def createFieldTerm(self, name, value, quote, docObj):
  525. """Создание поля переменная - значение
  526. при создании поля проверяется первый символ названия переменной
  527. и добавляется тег action
  528. "!" - <action>drop</action> удаляет
  529. "+" - <action>join</action> добавляет
  530. "-" - <action>replace</action> заменяет
  531. """
  532. fieldAction = False
  533. if name:
  534. if name[0] == "!" or name[0] == "-" or name[0] == "+":
  535. qnt = self.removeSymbolTerm(quote)
  536. fieldXML = docObj.createField("var",[qnt],
  537. name[1:], [value],
  538. False, False)
  539. if name[0] == "!":
  540. fieldAction = "drop"
  541. elif name[0] == "+":
  542. fieldXML.setAttribute("type", "seplist")
  543. fieldAction = "join"
  544. else:
  545. fieldXML = docObj.createField("var",
  546. [quote.replace("\n","")],
  547. name, [value],
  548. False, False)
  549. else:
  550. fieldXML = docObj.createField("var",
  551. [quote.replace("\n","")],
  552. name, [value],
  553. False, False)
  554. if fieldAction:
  555. docObj.setActionField(fieldXML, fieldAction)
  556. return fieldXML
  557. def removeSymbolTerm(self, text):
  558. """Удаляет первый символ названия переменной в строке
  559. Если первый встречающийся символ с начала строки
  560. '+', '-', '!' то он из этой строки будет удален,
  561. если перед этим символом были пробельные символы,
  562. то они будут сохранены, так-же если в строке есть символ
  563. перевода строки он будет удален.
  564. """
  565. reTerm = re.compile("^[ \t]*(\!|\+|\-)")
  566. textNS = text.replace("\n","")
  567. res = reTerm.search(textNS)
  568. if res:
  569. textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
  570. return textNS
  571. def getConfig(self):
  572. """Выдает конфигурационный файл"""
  573. listConfigTxt = []
  574. childNodes = self.docObj.getNodeBody().childNodes
  575. for node in childNodes:
  576. if node.nodeType == node.ELEMENT_NODE:
  577. if node.tagName == "field":
  578. listConfigTxt.append(self.docObj.getQuoteField(node))
  579. elif node.tagName == "area":
  580. self.docObj.xmlToText([node], listConfigTxt)
  581. return "".join(listConfigTxt)
  582. def splitToFields(self, txtBloc):
  583. """Разбиваем текст на поля (объекты) которые имеют следующие аттрибуты
  584. self.name - если переменная то имя переменной
  585. self.value - если у переменной есть значение то значение переменной
  586. self.comment - если комментарий то текст комментария
  587. self.br - если перевод строки то текст перед переводом из пробелов
  588. Результат список объектов полей
  589. """
  590. finBloc = "\n"
  591. if txtBloc[-1] != "\n":
  592. finBloc = ""
  593. linesBlocTmp = txtBloc.splitlines()
  594. linesBloc = []
  595. brBloc = []
  596. z = 0
  597. lenLines = len(linesBlocTmp)
  598. for i in linesBlocTmp:
  599. if self.reComment.split(i)[0]:
  600. findCooment = self.reComment.search(i)
  601. comment = False
  602. par = i
  603. if findCooment:
  604. par = i[:findCooment.start()]
  605. comment = i[findCooment.start():]
  606. fields = self.reSepFields.split(par)
  607. lenFields = len(fields)
  608. if lenFields>1:
  609. for fi in range(lenFields-1):
  610. linesBloc.append(fields[fi]+ self.sepFields)
  611. if fi == lenFields-2:
  612. if comment:
  613. brBloc.append("")
  614. else:
  615. if (lenLines-1)== z:
  616. brBloc.append(finBloc)
  617. else:
  618. brBloc.append("\n")
  619. else:
  620. brBloc.append("")
  621. if comment:
  622. linesBloc.append(comment)
  623. if (lenLines-1)== z:
  624. brBloc.append(finBloc)
  625. else:
  626. brBloc.append("\n")
  627. else:
  628. linesBloc.append(i)
  629. if (lenLines-1)== z:
  630. brBloc.append(finBloc)
  631. else:
  632. brBloc.append("\n")
  633. else:
  634. linesBloc.append(i)
  635. if (lenLines-1)== z:
  636. brBloc.append(finBloc)
  637. else:
  638. brBloc.append("\n")
  639. z +=1
  640. fields = self.setDataField(linesBloc, brBloc)
  641. return fields
  642. class xmlShare:
  643. """Общий класс для объектов XML, наследуем
  644. """
  645. def _createElement(self, doc, tagName, text="", attributes={}):
  646. """Создание нового XML элемента"""
  647. element = doc.createElement(tagName)
  648. if text:
  649. txtNode = doc.createTextNode(self._toUNICODE(text))
  650. element.appendChild(txtNode)
  651. for attr in attributes.keys():
  652. attribute = doc.createAttribute(attr)
  653. attribute.nodeValue = attributes[attr]
  654. element.setAttributeNode(attribute)
  655. return element
  656. def _toUNICODE(self,val):
  657. """перевод текста в юникод"""
  658. if 'unicode' in "%s" %(type(val)):
  659. return val
  660. else:
  661. return val.decode('UTF-8')
  662. class xmlNode(xmlShare):
  663. """Класс для создания нод без аттрибутов
  664. """
  665. def __init__(self):
  666. self.node = False
  667. def createNode(self, doc, tagName, text=""):
  668. """Создает XML элемент без аттрибутов"""
  669. self.node=self._createElement(doc, tagName, text)
  670. return self.node
  671. def getNode(self):
  672. return self.node
  673. class xmlCaption:
  674. """Класс XML заголовок
  675. """
  676. def __init__(self):
  677. #Заголовок области XML нода
  678. self.caption = False
  679. def createCaption(self, doc, name, quotes, action=False):
  680. """Создание заголовка области"""
  681. tmpNode = xmlNode()
  682. self.caption = tmpNode.createNode(doc, "caption")
  683. nameNode = tmpNode.createNode(doc, "name",name)
  684. self.caption.appendChild(nameNode)
  685. if action:
  686. actNode = tmpNode.createNode(doc, "action", action)
  687. self.caption.appendChild(actNode)
  688. for q in quotes:
  689. quoteNode = tmpNode.createNode(doc, "quote", q)
  690. self.caption.appendChild(quoteNode)
  691. return self.caption
  692. def getCaption(self):
  693. """Выдает XML ноду заголовка области"""
  694. return self.caption
  695. class xmlField(xmlShare):
  696. """Класс для работы с XML полем
  697. """
  698. def __init__(self):
  699. # XML нода поле
  700. self.field = False
  701. def createField(self, doc, typeField, quotes, name="",
  702. values=[],action=False):
  703. """Cоздание XML ноды поле"""
  704. self.field = self._createElement(doc, "field", "", {"type":typeField})
  705. if name:
  706. nameNode = self._createElement(doc, "name", name)
  707. self.field.appendChild(nameNode)
  708. for v in values:
  709. valueNode = self._createElement(doc, "value", v)
  710. self.field.appendChild(valueNode)
  711. if action:
  712. actNode = self._createElement(doc, "action", action)
  713. self.field.appendChild(actNode)
  714. for q in quotes:
  715. quoteNode = self._createElement(doc, "quote", q)
  716. self.field.appendChild(quoteNode)
  717. return self.field
  718. class xmlFields:
  719. """Класс, в котором находится список ХМL нод field
  720. """
  721. def __init__(self):
  722. self.fields = []
  723. def appendField(self, field):
  724. """Добавить XML ноду field"""
  725. self.fields.append(field)
  726. return self.fields
  727. def getFields(self):
  728. """Выдать список XML нод"""
  729. return self.fields
  730. class xmlArea:
  731. """Класс для работы с XML областью
  732. """
  733. def __init__(self):
  734. # Область
  735. self.area = False
  736. def createArea(self, doc, xmlCaption, xmlFields):
  737. """Создание XML области"""
  738. tmpNode = xmlNode()
  739. self.area = tmpNode.createNode(doc, "area")
  740. if xmlCaption and xmlCaption.getCaption():
  741. self.area.appendChild(xmlCaption.getCaption())
  742. if xmlFields:
  743. fields = xmlFields.getFields()
  744. for field in fields:
  745. self.area.appendChild(field)
  746. return self.area
  747. class xmlDoc:
  748. """Класс для работы с XML документом
  749. """
  750. def __init__(self):
  751. # документ
  752. self.doc = False
  753. # главная нода
  754. self.root = False
  755. # тело документа
  756. self.body = False
  757. # Заголовок области - временный (в реальности один объект заголовок)
  758. self.tmpCaption = False
  759. # Поля - временные (в реальности один объект поля)
  760. self.tmpFields = False
  761. # Разделитель областей - по умолчанию перевод строки "\n"
  762. self.sepAreas = False
  763. # Разделитель разделенных списков - по умолчанию перевод строки "\n"
  764. #self.sepSplitFields = False
  765. def createDoc(self, typeDoc, version):
  766. """Создание нового документа новый документ"""
  767. docTxt = '<?xml version="1.0" encoding="UTF-8"?><cxmlconf><head>'
  768. docTxt += '<ver>%s</ver>'% version
  769. docTxt += '<format>%s</format>' % typeDoc
  770. docTxt += '</head><body></body></cxmlconf>'
  771. self.doc = xml.dom.minidom.parseString(docTxt)
  772. self.root = self.doc.documentElement
  773. self.body = xpath.Evaluate('child::body',self.root)[0]
  774. # установка разделителя областей
  775. self.sepAreas = self.createField("br",[],"",[],False,False)
  776. # установка разделителя областей разделенных списков
  777. #self.sepSplitFields = self.createField("br",[],"",[],False,False)
  778. return self.doc
  779. def addField(self, field):
  780. """Добавляет поле во временный список
  781. Из этого списка в дальнейшем формируется XML область
  782. """
  783. if not self.tmpFields:
  784. self.tmpFields = xmlFields()
  785. self.tmpFields.appendField(field)
  786. def createCaption(self, name, quotes, action=False):
  787. """Cоздает заголовок области
  788. Помещает заголовок в временный артибут
  789. Используется при создании области
  790. """
  791. self.tmpCaption = xmlCaption()
  792. return self.tmpCaption.createCaption(self.doc, name, quotes, action)
  793. def createField(self, typeField, quotes=[], name="",
  794. values=[] ,action=False,addTmpField=True):
  795. """Cоздает поле
  796. Если установлена переменнная addTmpField
  797. добавляет поле во временный список
  798. """
  799. fieldObj = xmlField()
  800. field = fieldObj.createField(self.doc, typeField, quotes, name,
  801. values, action)
  802. if addTmpField:
  803. self.addField(field)
  804. return field
  805. def clearTmpFields(self):
  806. """Очищает временный список"""
  807. self.tmpFields = False
  808. def createArea(self):
  809. """Cоздает область
  810. Область создается на основании временного атрибута и временного списка
  811. """
  812. areaObj = xmlArea()
  813. area = areaObj.createArea(self.doc, self.tmpCaption, self.tmpFields)
  814. self.clearTmpCaptionAndFields()
  815. return area
  816. def clearTmpCaptionAndFields(self):
  817. """Очищает временный аттрибут и временный список"""
  818. self.tmpCaption = False
  819. self.tmpFields = False
  820. def getNodeRoot(self):
  821. """Выдает корневую ноду"""
  822. return self.root
  823. def getNodeBody(self):
  824. """Выдает ноду body"""
  825. return self.body
  826. def setActionField(self, xmlField, actionTxt):
  827. """Устанавливает свойство action для XML поля"""
  828. xmlActions = xpath.Evaluate('child::action',xmlField)
  829. if xmlActions and xmlActions[0].firstChild:
  830. xmlActions[0].firstChild.nodeValue = actionTxt
  831. else:
  832. nodeObj = xmlNode()
  833. newNode = nodeObj.createNode(self.doc, "action", actionTxt)
  834. xmlField.appendChild(newNode)
  835. def setActionArea(self, xmlArea, actionTxt):
  836. """Устанавливает свойство action для XML области"""
  837. xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
  838. xmlCaptions = xpath.Evaluate('child::caption',xmlArea)
  839. if xmlActions and xmlActions[0].firstChild:
  840. xmlActions[0].firstChild.nodeValue = actionTxt
  841. else:
  842. if xmlCaptions:
  843. nodeObj = xmlNode()
  844. newNode = nodeObj.createNode(self.doc, "action", actionTxt)
  845. xmlCaptions[0].appendChild(newNode)
  846. def joinField(self, xmlArea, xmlNewField):
  847. """Объединяет XML ноду область и XML ноду поле"""
  848. newNameField = self.getNameField(xmlNewField)
  849. if not newNameField or not newNameField.strip():
  850. return False
  851. fieldsOldComp = xpath.Evaluate("child::field[child::name='%s']"\
  852. %(newNameField), xmlArea)
  853. # Если поле не найдено добавляем его
  854. typeNewField = self.getTypeField(xmlNewField)
  855. if not fieldsOldComp and typeNewField != "seplist":
  856. if self.getActionField(xmlNewField) != "drop":
  857. self.setActionField(xmlNewField, "append")
  858. xmlArea.appendChild(xmlNewField)
  859. return True
  860. newFieldsAction = self.getActionField(xmlNewField)
  861. newValues = self.getFieldValues(xmlNewField)
  862. flagCompare = True
  863. for nodeFieldOld in fieldsOldComp:
  864. if newFieldsAction == "drop":
  865. if nodeFieldOld.nextSibling and\
  866. self.getTypeField(nodeFieldOld.nextSibling) == "br":
  867. xmlArea.removeChild(nodeFieldOld.nextSibling)
  868. elif nodeFieldOld.previousSibling and\
  869. self.getTypeField(nodeFieldOld.previousSibling) == "br":
  870. xmlArea.removeChild(nodeFieldOld.previousSibling)
  871. xmlArea.removeChild(nodeFieldOld)
  872. continue
  873. oldValues = self.getFieldValues(nodeFieldOld)
  874. # Сравнение значений переменной профиля и файла
  875. if set(newValues) != set(oldValues):
  876. flagCompare = False
  877. if self.getActionField(xmlNewField) == "drop":
  878. return True
  879. appSplLst = []
  880. insSplLst = []
  881. if typeNewField == "seplist":
  882. if fieldsOldComp:
  883. xmlOldField = fieldsOldComp[-1]
  884. else:
  885. xmlOldField = False
  886. seplistNewXML = self.getSepListToField(xmlNewField)
  887. if seplistNewXML:
  888. for nodeSeplist in seplistNewXML:
  889. if self.getActionField(nodeSeplist) != "drop":
  890. if newFieldsAction == "join":
  891. flagCompareSeplist = False
  892. newValues = self.getFieldValues(nodeSeplist)
  893. for nodeFieldOld in fieldsOldComp:
  894. oldValues = self.getFieldValues(nodeFieldOld)
  895. for newValue in newValues:
  896. if newValue in oldValues:
  897. flagCompareSeplist = True
  898. break
  899. if not flagCompareSeplist:
  900. nextNode = xmlOldField.nextSibling
  901. newInsNode = nodeSeplist.cloneNode(True)
  902. self.setActionField(newInsNode,"append")
  903. if nextNode:
  904. appSplLst.append((newInsNode,
  905. nextNode,
  906. "insert"))
  907. else:
  908. appSplLst.append((newInsNode,
  909. False,
  910. "append"))
  911. else:
  912. newInsNode = nodeSeplist.cloneNode(True)
  913. if self.getActionField(newInsNode) == "join":
  914. self.setActionField(newInsNode,"append")
  915. if xmlOldField:
  916. insSplLst.append((newInsNode,
  917. xmlOldField,
  918. "insert"))
  919. else:
  920. insSplLst.append((newInsNode,
  921. False,
  922. "append"))
  923. #xmlArea.insertBefore(\
  924. #nodeSeplist.cloneNode(True),
  925. #xmlOldField)
  926. parentNode = nodeSeplist.parentNode
  927. parentNode.removeChild(nodeSeplist)
  928. insNodesRepl = []
  929. for newNode, nxtNode, app in insSplLst:
  930. flagCompareSeplist = False
  931. newValues = self.getFieldValues(newNode)
  932. for nodeRepl, nxtNode, app in insNodesRepl:
  933. oldValues = self.getFieldValues(nodeRepl)
  934. for newValue in newValues:
  935. if newValue in oldValues:
  936. flagCompareSeplist = True
  937. break
  938. if not flagCompareSeplist:
  939. if xmlOldField:
  940. insNodesRepl.append((newNode, nxtNode, app))
  941. for newNode, nxtNode, app in insNodesRepl:
  942. if app == "insert":
  943. xmlArea.insertBefore(newNode,nxtNode)
  944. elif app == "append":
  945. xmlArea.appendChild(newNode)
  946. if xmlOldField:
  947. parentNode = xmlOldField.parentNode
  948. if parentNode and newFieldsAction != "join":
  949. parentNode.removeChild(xmlOldField)
  950. for newNode, nxtNode, app in appSplLst:
  951. if app == "insert":
  952. xmlArea.insertBefore(newNode,nxtNode)
  953. elif app == "append":
  954. xmlArea.appendChild(newNode)
  955. if not flagCompare and typeNewField != "seplist":
  956. # Устанавливаем action=replace
  957. self.setActionField(xmlNewField, "replace")
  958. # Если параметры поля не сходятся заменяем поле
  959. xmlArea.replaceChild(xmlNewField.cloneNode(True),
  960. fieldsOldComp[-1])
  961. if newFieldsAction == "join":
  962. fieldsOldRemove = []
  963. else:
  964. fieldsOldRemove = fieldsOldComp[:-1]
  965. for nodeFieldOld in fieldsOldRemove:
  966. actionOldNode = self.getActionField(nodeFieldOld)
  967. if actionOldNode == "insert" or actionOldNode == "append":
  968. pass
  969. else:
  970. if nodeFieldOld.nextSibling and\
  971. self.getTypeField(nodeFieldOld.nextSibling) == "br":
  972. xmlArea.removeChild(nodeFieldOld.nextSibling)
  973. xmlArea.removeChild(nodeFieldOld)
  974. return True
  975. def getSepListToField(self, xmlField):
  976. """Выдает элементы распределенного массива
  977. Область предок поля, в этой области ищутся
  978. элементы распределенного массива
  979. """
  980. nameField = self.getNameField(xmlField)
  981. if not nameField:
  982. return []
  983. parentNode = xmlField.parentNode
  984. #print parentNode.toprettyxml()
  985. if parentNode:
  986. fieldsVal = xpath.Evaluate(\
  987. "child::field[attribute::type='seplist'][child::name='%s'] "\
  988. %(nameField), parentNode)
  989. #print nameField
  990. return fieldsVal
  991. else:
  992. return []
  993. def removeComment(self, xmlArea):
  994. """Удаляет комментарии в XML области"""
  995. fieldNodes = xpath.Evaluate('descendant::field',xmlArea)
  996. for fieldNode in fieldNodes:
  997. if fieldNode.hasAttribute("type"):
  998. if fieldNode.getAttribute("type") == "comment" or\
  999. fieldNode.getAttribute("type") == "br":
  1000. parentNode = fieldNode.parentNode
  1001. parentNode.removeChild(fieldNode)
  1002. else:
  1003. if self.getActionField(fieldNode) == "drop":
  1004. pass
  1005. elif self.getActionField(fieldNode) == "join":
  1006. pass
  1007. else:
  1008. self.setActionField(fieldNode,"append")
  1009. def joinBody(self, baseBody, newBody):
  1010. """Объединяет две области Body"""
  1011. newFields = xpath.Evaluate('child::field',newBody)
  1012. xmlNewAreas = xpath.Evaluate('child::area',newBody)
  1013. for xmlNewArea in xmlNewAreas:
  1014. self.joinArea(baseBody,xmlNewArea)
  1015. joinNewFields = xpath.Evaluate("child::field[child::action='join']"
  1016. ,newBody)
  1017. self.addNewFielsOldArea(newFields, joinNewFields, baseBody)
  1018. def getRemoveNodeSepList(self, removeNodesDict, baseNode, xmNewlField):
  1019. """Находит элементы разделенного списка
  1020. Параметры:
  1021. removeNodesDict - Cловарь удаляемых полей разделенного списка
  1022. формируется программой
  1023. baseNode - Нода в которой идет поиск
  1024. xmNewlField - Нода field которая проверяется на принадлежность
  1025. к разделенному списку
  1026. """
  1027. flagNewNodeSeplist = False
  1028. if self.getTypeField(xmNewlField) == "seplist":
  1029. flagNewNodeSeplist = True
  1030. nameNewField = self.getNameField(xmNewlField)
  1031. if nameNewField:
  1032. if removeNodesDict.has_key(nameNewField):
  1033. return removeNodesDict[nameNewField]
  1034. else:
  1035. oldFields = xpath.Evaluate('child::field', baseNode)
  1036. removeNodes = []
  1037. lenOldFields = len(oldFields)
  1038. for i in range(lenOldFields):
  1039. oldNode = oldFields[i]
  1040. flagSep = self.getTypeField(oldNode) == "seplist"
  1041. if flagNewNodeSeplist:
  1042. flagSep = True
  1043. if flagSep and\
  1044. nameNewField == self.getNameField(oldNode):
  1045. removeNodes.append(oldNode)
  1046. if i+1<lenOldFields:
  1047. nextNode = oldFields[i+1]
  1048. if self.getTypeField(nextNode) == "br":
  1049. removeNodes.append(nextNode)
  1050. removeNodesDict[nameNewField] = removeNodes
  1051. return removeNodes
  1052. def addNewFielsOldArea(self, newFields, joinNewFields, xmlOldArea):
  1053. """Добавляет новые XML поля в область профиля"""
  1054. removeNodesDict = {}
  1055. notRemoveNodesDict = {}
  1056. for notRemNode in joinNewFields:
  1057. nameField = self.getNameField(notRemNode)
  1058. if not notRemoveNodesDict.has_key(nameField):
  1059. notRemoveNodesDict[nameField] = []
  1060. notRemoveNodesDict[nameField].append(notRemNode)
  1061. else:
  1062. notRemoveNodesDict[nameField].append(notRemNode)
  1063. notSepListField = []
  1064. sepListField = []
  1065. for nField in newFields:
  1066. if self.getRemoveNodeSepList(removeNodesDict, xmlOldArea,
  1067. nField):
  1068. sepListField.append(nField)
  1069. else:
  1070. if self.getNameField(nField):
  1071. notSepListField.append(nField)
  1072. for name in notRemoveNodesDict.keys():
  1073. if removeNodesDict.has_key(name):
  1074. removeNodesDict[name] = []
  1075. for removeNodes in removeNodesDict.values():
  1076. if removeNodes:
  1077. if self.getTypeField(removeNodes[-1]) == "seplist":
  1078. removeNodes = removeNodes[:-1]
  1079. else:
  1080. removeNodes = removeNodes[:-2]
  1081. for removeNode in removeNodes:
  1082. xmlOldArea.removeChild(removeNode)
  1083. for node in sepListField:
  1084. node.setAttribute("type", "seplist")
  1085. if not (self.getActionField(node) == "join" or\
  1086. self.getActionField(node) == "drop"):
  1087. self.setActionField(node,"insert")
  1088. self.joinField(xmlOldArea, node)
  1089. #else:
  1090. #self.setActionField(node, "append")
  1091. #baseBody.appendChild(node)
  1092. for node in notSepListField:
  1093. if self.getTypeField(node) == "seplist":
  1094. #if removeNodesDict.has_key(self.getNameField(node)):
  1095. #print removeNodesDict[self.getNameField(node)]
  1096. self.setActionField(node, "append")
  1097. xmlOldArea.appendChild(node)
  1098. else:
  1099. self.joinField(xmlOldArea, node)
  1100. def insertBeforeSepAreas(self, xmlArea):
  1101. """Добавляет разделитель областей перед каждой областью"""
  1102. if not self.sepAreas:
  1103. return False
  1104. areaNodes = xpath.Evaluate('descendant::area',xmlArea)
  1105. for areaNode in areaNodes:
  1106. prevNode = areaNode.previousSibling
  1107. if prevNode:
  1108. parentNode = areaNode.parentNode
  1109. parentNode.insertBefore(self.sepAreas.cloneNode(True),
  1110. areaNode)
  1111. return True
  1112. def getAreaFields(self, nameArea, xmlArea):
  1113. """По имени области выводит названия и значения всех переменных
  1114. поиск ведется только в 1-х потомках области xmlArea
  1115. на выход словарь переменных {имя:значение}
  1116. """
  1117. namesAreaComare = xpath.Evaluate(\
  1118. "child::area/child::caption[child::name='%s']" %(nameArea),
  1119. xmlArea)
  1120. if not namesAreaComare:
  1121. return False
  1122. fields = xpath.Evaluate("child::field/child::name",
  1123. namesAreaComare[0].parentNode)
  1124. dictVar = {}
  1125. for fieldName in fields:
  1126. nodeField = fieldName.parentNode
  1127. fieldValue = xpath.Evaluate("child::value",nodeField)
  1128. name = fieldName.firstChild.nodeValue
  1129. value = ""
  1130. if fieldValue and fieldValue[0].firstChild:
  1131. value = fieldValue[0].firstChild.nodeValue
  1132. dictVar[name] = value
  1133. return dictVar
  1134. def getAreaFieldValues(self, nameArea, nameField, xmlArea):
  1135. """По имени области и имени переменной выводит значениe переменной
  1136. поиск ведется только в 1-х потомках области xmlArea
  1137. """
  1138. namesAreaComare = xpath.Evaluate(\
  1139. "child::area/child::caption[child::name='%s']" %(nameArea),
  1140. xmlArea)
  1141. fieldsVal = False
  1142. for areaComp in namesAreaComare:
  1143. fieldsVal = xpath.Evaluate(\
  1144. "child::field[child::name='%s'] "\
  1145. %(nameField), areaComp.parentNode)
  1146. if fieldsVal:
  1147. break
  1148. if not fieldsVal:
  1149. return False
  1150. fieldValue = xpath.Evaluate("child::value",
  1151. fieldsVal[0])
  1152. return fieldValue[0].firstChild.nodeValue
  1153. def getAllAreas(self):
  1154. """Выдает все области"""
  1155. return xpath.Evaluate('descendant::area', self.body)
  1156. def getArea(self, nameArea, xmlArea):
  1157. """По имени области находит области (первый потомок xmlArea)"""
  1158. namesAreaComare = xpath.Evaluate(\
  1159. "child::area/child::caption[child::name='%s']" %(nameArea),
  1160. xmlArea)
  1161. return map(lambda x: x.parentNode, namesAreaComare)
  1162. def joinArea(self, baseNode, xmlNewArea):
  1163. """Объединяет область c областью Body (xmlNewArea c baseNode)"""
  1164. def appendArea(baseNode, xmlNewArea):
  1165. fieldsRemove = xpath.Evaluate(\
  1166. "descendant::field[child::action='drop']", xmlNewArea)
  1167. for rmNode in fieldsRemove:
  1168. parentNode = rmNode.parentNode
  1169. parentNode.removeChild(rmNode)
  1170. captionAreasRemove = xpath.Evaluate(\
  1171. "descendant::area/child::caption[child::action='drop']",
  1172. xmlNewArea)
  1173. for rmNodeCapt in captionAreasRemove:
  1174. rmNode = rmNodeCapt.parentNode
  1175. parentNode = rmNode.parentNode
  1176. parentNode.removeChild(rmNode)
  1177. self.setActionArea(xmlNewArea, "append")
  1178. # Добавляем разделитель областей во вложенные области
  1179. areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
  1180. for areaNode in areaNodes:
  1181. self.setActionArea(areaNode,"append")
  1182. parentNode = areaNode.parentNode
  1183. parentNode.insertBefore(self.sepAreas.cloneNode(True),
  1184. areaNode)
  1185. baseNode.appendChild(xmlNewArea)
  1186. # Добавляем разделитель областей
  1187. baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)
  1188. nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
  1189. nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
  1190. if not nodesNames:
  1191. # Добавляем область
  1192. if nodesNewArea:
  1193. newAreaAction = self.getActionArea(xmlNewArea)
  1194. if not (newAreaAction == "drop" or newAreaAction == "replace"):
  1195. appendArea(baseNode, xmlNewArea)
  1196. return True
  1197. if not nodesNames or not nodesNewArea:
  1198. return False
  1199. nameArea = ""
  1200. if nodesNewArea[0].firstChild:
  1201. nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
  1202. flagFindArea = False
  1203. baseNodes = []
  1204. for oName in nodesNames:
  1205. newAreaAction = self.getActionArea(xmlNewArea)
  1206. oArea = oName.parentNode.parentNode
  1207. oNameTxt = ""
  1208. if oName.firstChild:
  1209. oNameTxt = oName.firstChild.nodeValue
  1210. if nameArea == oNameTxt:
  1211. flagFindArea = True
  1212. # При использовании удаления
  1213. if newAreaAction == "drop":
  1214. prevNode = oName.parentNode.parentNode.previousSibling
  1215. removePrevNodes = []
  1216. while (prevNode) and self.getTypeField(prevNode) == "br":
  1217. removePrevNodes.append(prevNode)
  1218. prevNode = prevNode.previousSibling
  1219. for removeNode in removePrevNodes:
  1220. baseNode.removeChild(removeNode)
  1221. baseNode.removeChild(oName.parentNode.parentNode)
  1222. continue
  1223. elif newAreaAction == "replace":
  1224. oldAreaNode = oName.parentNode.parentNode
  1225. newAreaCaption = xpath.Evaluate('child::caption',
  1226. xmlNewArea)[0]
  1227. oldAreaCaption = xpath.Evaluate('child::caption',
  1228. oldAreaNode)[0]
  1229. if newAreaCaption and oldAreaCaption:
  1230. xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
  1231. self.setActionArea(xmlNewArea,"replace")
  1232. baseNode.replaceChild(xmlNewArea,
  1233. oldAreaNode)
  1234. continue
  1235. baseNodes.append(oName.parentNode.parentNode)
  1236. newFields = xpath.Evaluate('child::field',xmlNewArea)
  1237. joinNewFields = xpath.Evaluate(\
  1238. "child::field[child::action='join']"
  1239. ,xmlNewArea)
  1240. self.addNewFielsOldArea(newFields, joinNewFields, oArea)
  1241. if not flagFindArea:
  1242. # Добавляем область
  1243. if not (newAreaAction == "drop" or\
  1244. newAreaAction == "replace"):
  1245. appendArea(baseNode, xmlNewArea)
  1246. else:
  1247. tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
  1248. for na in tmpXmlNewAreas:
  1249. for bn in baseNodes:
  1250. self.joinArea(bn, na)
  1251. return True
  1252. def joinDoc(self, xmlNewDoc):
  1253. """Объединяет два документа"""
  1254. newRootNode = xmlNewDoc.documentElement
  1255. newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
  1256. newImportBodyNode = self.doc.importNode(newBodyNode, True)
  1257. # Перед объединение области с документом
  1258. # удаляем комментарии
  1259. self.removeComment(newImportBodyNode)
  1260. self.joinBody(self.body, newImportBodyNode)
  1261. # расставляем BR
  1262. self.insertBRtoBody(self.body)
  1263. def getQuoteField(self, xmlField):
  1264. """Выдает текст из поля"""
  1265. xmlQuotes = xpath.Evaluate('child::quote',xmlField)
  1266. br = ""
  1267. if xmlField.hasAttribute("type") and\
  1268. xmlField.getAttribute("type") == "br":
  1269. br = "\n"
  1270. if xmlQuotes:
  1271. field = xmlQuotes[0]
  1272. if field.firstChild:
  1273. return field.firstChild.nodeValue + br
  1274. return "" + br
  1275. def getFieldsArea(self, xmlArea):
  1276. """Выдает потомков XML области"""
  1277. xmlFields = []
  1278. childNodes = xmlArea.childNodes
  1279. for node in childNodes:
  1280. if node.nodeType == node.ELEMENT_NODE:
  1281. if node.tagName == "area" or node.tagName == "field":
  1282. xmlFields.append(node)
  1283. return xmlFields
  1284. def getTypeField(self, xmlField):
  1285. """Выдает тип поля"""
  1286. if xmlField.hasAttribute("type"):
  1287. return xmlField.getAttribute("type")
  1288. else:
  1289. return False
  1290. def getNameField(self, xmlField):
  1291. """Выдает имя поля"""
  1292. xmlNameFields = xpath.Evaluate('child::name', xmlField)
  1293. if xmlNameFields and xmlNameFields[0].firstChild:
  1294. return xmlNameFields[0].firstChild.nodeValue
  1295. else:
  1296. return False
  1297. def getNameArea(self, xmlArea):
  1298. """Выдает имя области"""
  1299. xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
  1300. if xmlNameAreas and xmlNameAreas[0].firstChild:
  1301. return xmlNameAreas[0].firstChild.nodeValue
  1302. else:
  1303. return False
  1304. def xmlToText(self, xmlAreas, text):
  1305. """Преобразует список XML областей в текст"""
  1306. def getQuotesArea(xmlArea):
  1307. quotes = []
  1308. xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
  1309. for node in xmlQuotes:
  1310. if node.firstChild:
  1311. quotes.append(node.firstChild.nodeValue)
  1312. if len(quotes) == 0:
  1313. quotes.append("")
  1314. quotes.append("")
  1315. elif len(quotes) == 1:
  1316. quotes.append("")
  1317. return quotes
  1318. for i in xmlAreas:
  1319. if i.tagName == "area":
  1320. quotesI = getQuotesArea(i)
  1321. startAreaI = quotesI[0]
  1322. endAreaI = quotesI[1]
  1323. text.append(startAreaI)
  1324. xmlFieldsI = self.getFieldsArea(i)
  1325. for f in xmlFieldsI:
  1326. if f.tagName == "area":
  1327. quotesF = getQuotesArea(f)
  1328. startAreaF = quotesF[0]
  1329. endAreaF = quotesF[1]
  1330. text.append(startAreaF)
  1331. xmlFieldsF = self.getFieldsArea(f)
  1332. self.xmlToText(xmlFieldsF, text)
  1333. text.append(endAreaF)
  1334. else:
  1335. fieldF = self.getQuoteField(f)
  1336. text.append(fieldF)
  1337. text.append(endAreaI)
  1338. else:
  1339. fieldI = self.getQuoteField(i)
  1340. text.append(fieldI)
  1341. def getActionField(self, xmlField):
  1342. """Выдает свойство action XML поля"""
  1343. xmlActions = xpath.Evaluate('child::action',xmlField)
  1344. if xmlActions and xmlActions[0].firstChild:
  1345. return xmlActions[0].firstChild.nodeValue
  1346. else:
  1347. return False
  1348. def getFieldValues(self, xmlField):
  1349. """Выдает значения XML поля в виде массива"""
  1350. vals = []
  1351. xmlValues = xpath.Evaluate('child::value',xmlField)
  1352. if xmlValues:
  1353. for node in xmlValues:
  1354. if node.firstChild:
  1355. vals.append(node.firstChild.nodeValue)
  1356. return vals
  1357. def getActionArea(self, xmlArea):
  1358. """Выдает свойство action XML области"""
  1359. xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
  1360. if xmlActions and xmlActions[0].firstChild:
  1361. return xmlActions[0].firstChild.nodeValue
  1362. else:
  1363. return False
  1364. def delActionNodeArea(self, xmlArea):
  1365. """Удаляет свойство action XML области"""
  1366. xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
  1367. if xmlActions and xmlActions[0].firstChild:
  1368. parentNode = xmlActions[0].parentNode
  1369. parentNode.removeChild(xmlActions[0])
  1370. return True
  1371. else:
  1372. return False
  1373. def delActionNodeField(self, xmlField):
  1374. """Удаляет свойство action XML поля"""
  1375. xmlActions = xpath.Evaluate('child::action',xmlField)
  1376. if xmlActions and xmlActions[0].firstChild:
  1377. parentNode = xmlActions[0].parentNode
  1378. parentNode.removeChild(xmlActions[0])
  1379. return True
  1380. else:
  1381. return False
  1382. # Создает распределенные списки
  1383. def postParserListSeplist(self, xmlArea):
  1384. """Создает распределенные списки из элементов области"""
  1385. # Потомки
  1386. childNodes = self.getFieldsArea(xmlArea)
  1387. # содержит списки нод полей с одинаковыми именами в одной области
  1388. fieldsSeplist = {}
  1389. for node in childNodes:
  1390. if node.tagName == "area":
  1391. self.postParserListSeplist(node)
  1392. else:
  1393. fieldName = False
  1394. xmlFieldNameNodes = xpath.Evaluate('child::name',node)
  1395. if xmlFieldNameNodes and xmlFieldNameNodes[0].firstChild:
  1396. fieldName = xmlFieldNameNodes[0].firstChild.nodeValue
  1397. if fieldName:
  1398. if fieldsSeplist.has_key(fieldName):
  1399. fieldsSeplist[fieldName].append(node)
  1400. else:
  1401. fieldsSeplist[fieldName] = []
  1402. fieldsSeplist[fieldName].append(node)
  1403. for listNodes in fieldsSeplist.values():
  1404. if len(listNodes) > 1:
  1405. for node in listNodes:
  1406. node.setAttribute("type", "seplist")
  1407. def insertBRtoBody(self, xmlArea):
  1408. """Добавляет необходимые переводы строк
  1409. """
  1410. # Потомки
  1411. childNodes = self.getFieldsArea(xmlArea)
  1412. # нода BR
  1413. fieldXMLBr = self.createField("br",[],"",[],False, False)
  1414. # разделитель поля
  1415. fieldSplit = False
  1416. # Предыдущая нода
  1417. lastNode = False
  1418. # Cледующая нода
  1419. nextNode = False
  1420. lenChildNodes = len(childNodes)
  1421. for i in range(lenChildNodes):
  1422. node = childNodes[i]
  1423. lastTmpNode = node
  1424. # Нода area
  1425. if node.tagName == "area":
  1426. if self.getActionArea(node) == "append" or\
  1427. self.getActionArea(node) == "join":
  1428. self.delActionNodeArea(node)
  1429. if lastNode and lastNode.hasAttribute("type") and\
  1430. lastNode.getAttribute("type") == "br" or\
  1431. lastNode and lastNode.hasAttribute("type") and\
  1432. lastNode.getAttribute("type") == "comment":
  1433. indNext = i + 1
  1434. if indNext == lenChildNodes:
  1435. xmlArea.appendChild(fieldXMLBr.cloneNode(True))
  1436. else:
  1437. nextNode = childNodes[indNext]
  1438. lastTmpNode = xmlArea.insertBefore(\
  1439. fieldXMLBr.cloneNode(True),
  1440. nextNode)
  1441. else:
  1442. xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
  1443. node)
  1444. self.insertBRtoBody(node)
  1445. # Нода field
  1446. else:
  1447. if self.getActionField(node) == "append" or\
  1448. self.getActionField(node) == "join":
  1449. self.delActionNodeField(node)
  1450. if lastNode and lastNode.hasAttribute("type") and\
  1451. lastNode.getAttribute("type") == "br" or\
  1452. lastNode and lastNode.hasAttribute("type") and\
  1453. lastNode.getAttribute("type") == "comment":
  1454. indNext = i + 1
  1455. if indNext == lenChildNodes:
  1456. xmlArea.appendChild(fieldXMLBr.cloneNode(True))
  1457. else:
  1458. nextNode = childNodes[indNext]
  1459. lastTmpNode = xmlArea.insertBefore(\
  1460. fieldXMLBr.cloneNode(True),
  1461. nextNode)
  1462. else:
  1463. xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
  1464. node)
  1465. lastNode = lastTmpNode
  1466. def postParserList(self):
  1467. """Находит подходящие XML области и делаем из них поля-массивы"""
  1468. xmlAreas = xpath.Evaluate('descendant::area', self.body)
  1469. for xmlArea in xmlAreas:
  1470. flagListXml = True
  1471. fieldValues = []
  1472. xmlFields = xpath.Evaluate('child::field',xmlArea)
  1473. if not xmlFields:
  1474. flagListXml = False
  1475. lenXmlFields = len(xmlFields)
  1476. lenBrArea = 0
  1477. for xmlField in xmlFields:
  1478. xmlNames = xpath.Evaluate('child::name',xmlField)
  1479. xmlVals = xpath.Evaluate('child::value',xmlField)
  1480. if xmlField.hasAttribute("type") and\
  1481. xmlField.getAttribute("type") == "br":
  1482. lenBrArea += 1
  1483. continue
  1484. if not xmlNames and not xmlVals:
  1485. flagListXml = False
  1486. break
  1487. if xmlNames and xmlNames[0].firstChild and\
  1488. xmlNames[0].firstChild.nodeValue:
  1489. flagListXml = False
  1490. break
  1491. if not (xmlVals and xmlVals[0].firstChild and\
  1492. xmlVals[0].firstChild.nodeValue):
  1493. flagListXml = False
  1494. break
  1495. else:
  1496. fieldValues.append(xmlVals[0].firstChild.nodeValue)
  1497. if lenXmlFields == lenBrArea:
  1498. flagListXml = False
  1499. if flagListXml:
  1500. nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
  1501. fieldName = ""
  1502. if nameNode.firstChild:
  1503. fieldName = nameNode.firstChild.nodeValue
  1504. listArea = []
  1505. self.xmlToText([xmlArea],listArea)
  1506. fieldQuote = "".join(listArea)
  1507. fieldXMLBr = False
  1508. if fieldQuote and fieldQuote[-1] == "\n":
  1509. fieldQuote = fieldQuote[:-1]
  1510. fieldXMLBr = self.createField("br",[],"",[],False, False)
  1511. fieldXML = self.createField("list",
  1512. [fieldQuote],
  1513. fieldName, fieldValues,
  1514. False, False)
  1515. areaAction = self.getActionArea(xmlArea)
  1516. if areaAction:
  1517. self.setActionField(fieldXML, areaAction)
  1518. parentNode = xmlArea.parentNode
  1519. parentNode.insertBefore(fieldXML,xmlArea)
  1520. if fieldXMLBr:
  1521. parentNode.insertBefore(fieldXMLBr,xmlArea)
  1522. parentNode.removeChild(xmlArea)
  1523. class blocText:
  1524. """Разбиваем текст на блоки"""
  1525. def splitTxtToBloc(self, text ,openTxtBloc,closeTxtBloc,
  1526. commentTxtBloc, sepField):
  1527. """Делит текст на блоки (без заголовков)
  1528. openTxtBloc - регулярное выражение для начала блока
  1529. closeTxtBloc - регулярное выражение для конца блока
  1530. commentTxtBloc - регулярное выражение - комментарий
  1531. возвращает блоки текста
  1532. """
  1533. blocs = []
  1534. level = 0
  1535. # Нахождение нескольких блоков в строке
  1536. # разделители линий, разделителями могут быть ("","\n")
  1537. sepsLines = []
  1538. # линии
  1539. txtLines = []
  1540. # Исходные строки
  1541. txtLinesSrc = text.splitlines()
  1542. for line in txtLinesSrc:
  1543. lineBR = ""
  1544. lineTmpA = line
  1545. closeBl = False
  1546. txtLinesTmp = []
  1547. commentSpl = commentTxtBloc.split(line)
  1548. flagCommentLine = False
  1549. if commentSpl[0].strip():
  1550. closeBl = True
  1551. if len(commentSpl) > 1:
  1552. commentBl = commentTxtBloc.search(line)
  1553. textLine =commentSpl[0]
  1554. commentLine = line[commentBl.start(0):]
  1555. lineTmpA = textLine
  1556. flagCommentLine = True
  1557. while (closeBl):
  1558. closeBl = sepField.search(lineTmpA)
  1559. if closeBl:
  1560. lineTmpB = lineTmpA[closeBl.end(0):]
  1561. txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
  1562. lineTmpA = lineTmpB
  1563. if lineTmpA.strip():
  1564. txtLinesTmp.append(lineTmpA)
  1565. # Если есть значение и комментарий в строке
  1566. if flagCommentLine:
  1567. for l in txtLinesTmp:
  1568. txtLines.append(l)
  1569. sepsLines.append("")
  1570. if not txtLinesTmp:
  1571. txtLines.append(textLine)
  1572. sepsLines.append("")
  1573. txtLines.append(commentLine)
  1574. sepsLines.append("\n")
  1575. # Если есть несколько блоков в строке
  1576. elif len(txtLinesTmp)>1 and txtLinesTmp[1].strip():
  1577. lenTmpLines = len(txtLinesTmp)
  1578. for l in range(lenTmpLines):
  1579. txtLines.append(txtLinesTmp[l])
  1580. if l == lenTmpLines-1:
  1581. sepsLines.append("\n")
  1582. else:
  1583. sepsLines.append("")
  1584. # Cтрока не преобразована
  1585. else:
  1586. txtLines.append(line)
  1587. sepsLines.append("\n")
  1588. # разбивание на блоки
  1589. z = 0
  1590. bl = ""
  1591. for i in txtLines:
  1592. if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
  1593. level += len(openTxtBloc.split(i)) - 1
  1594. if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
  1595. level -= len(closeTxtBloc.split(i)) - 1
  1596. bl += i + sepsLines[z]
  1597. if level == 0:
  1598. if bl:
  1599. blocs.append(bl)
  1600. bl = ""
  1601. z += 1
  1602. # cоздание блоков с элементами не входящими в блоки
  1603. realBlocs = []
  1604. z = 0
  1605. bl = ""
  1606. for i in blocs:
  1607. txtLines = i.splitlines()
  1608. if len(txtLines) > 0:
  1609. line = txtLines[0]
  1610. else:
  1611. line = i
  1612. if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
  1613. if bl:
  1614. realBlocs.append(bl)
  1615. bl = ""
  1616. realBlocs.append(i)
  1617. else:
  1618. bl += i
  1619. z += 1
  1620. if bl:
  1621. realBlocs.append(bl)
  1622. bl = ""
  1623. if level == 0:
  1624. if text and text[-1] != "\n":
  1625. tmpBlocs = realBlocs.pop()
  1626. tmpBlocs = tmpBlocs[:-1]
  1627. realBlocs.append(tmpBlocs)
  1628. return realBlocs
  1629. else:
  1630. return []
  1631. def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
  1632. """ Делит текст на области (с заголовками)
  1633. reTextHeader - регулярное выражение для заголовка области
  1634. reTextArea - регулярное выражение для всей области
  1635. numGroupArea - номер групы результата поиска по регулярному выражению
  1636. по всей области
  1637. возвращает два списка: первый - заголовки, второй - тела областей без
  1638. заголоков
  1639. """
  1640. # Заголовки областей
  1641. headersArea = []
  1642. # Тексты областей без заголовков
  1643. textBodyArea = []
  1644. r = reTextArea.search(text)
  1645. if not r:
  1646. headersArea.append("")
  1647. textBodyArea.append(text)
  1648. return (headersArea, textBodyArea)
  1649. txtWr = text
  1650. while r:
  1651. textArea = r.group(numGroupArea)
  1652. txtSpl = txtWr.split(textArea)
  1653. area = txtSpl[0]
  1654. txtWr = txtSpl[1]
  1655. if area:
  1656. headersArea.append("")
  1657. textBodyArea.append(area)
  1658. res = reTextHeader.search(textArea)
  1659. header = textArea[:res.end()]
  1660. body = textArea[res.end():]
  1661. headersArea.append(header)
  1662. textBodyArea.append(body)
  1663. if txtWr:
  1664. r = reTextArea.search(txtWr)
  1665. else:
  1666. r = False
  1667. if txtWr:
  1668. headersArea.append("")
  1669. textBodyArea.append(txtWr)
  1670. return (headersArea, textBodyArea)
  1671. def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
  1672. """ Делит текст на блоки (с заголовками)
  1673. captionTxtBloc - регулярное выражение для заголовка блока
  1674. bodyTxtBloc - регулярное выражение для тела блока
  1675. возвращает два списка: первый - заголовки, второй - тела блоков
  1676. """
  1677. # Заголовки блоков
  1678. headersTxt = []
  1679. # Тексты блоков
  1680. blocsTxt = []
  1681. r = captionTxtBloc.search(text)
  1682. if r:
  1683. headersTxt.append(r.group(0))
  1684. txtSpl = text.split(r.group(0))
  1685. blocTxt = txtSpl[0]
  1686. txtWr = txtSpl[1]
  1687. rb = bodyTxtBloc.search(blocTxt)
  1688. if not blocTxt:
  1689. blocsTxt.append(blocTxt)
  1690. if rb:
  1691. blocsTxt.append(rb.group(0))
  1692. while (r):
  1693. r = captionTxtBloc.search(txtWr)
  1694. if r:
  1695. headersTxt.append(r.group(0))
  1696. txtSpl = txtWr.split(r.group(0))
  1697. blocTxt = txtSpl[0]
  1698. txtWr = txtSpl[1]
  1699. rb = bodyTxtBloc.search(blocTxt)
  1700. if rb:
  1701. blocsTxt.append(rb.group(0))
  1702. else:
  1703. blocsTxt.append(txtWr)
  1704. if headersTxt and blocsTxt:
  1705. if len(headersTxt)>len(blocsTxt):
  1706. blocsTxt.insert(0,"")
  1707. elif len(headersTxt)<len(blocsTxt):
  1708. headersTxt.insert(0,"")
  1709. if len(headersTxt)!=len(blocsTxt):
  1710. return False
  1711. return (headersTxt, blocsTxt)
  1712. else:
  1713. return False
  1714. class _file(_error):
  1715. """Класс для работы с файлами
  1716. """
  1717. def __init__(self):
  1718. # Имя файла старого профиля
  1719. self.nameFileOld = ""
  1720. # Старый профиль
  1721. self.oldProfile = ""
  1722. # Имя файла нового профиля
  1723. self.nameFileNew = ""
  1724. # Новый профиль
  1725. self.newProfile = ""
  1726. # Дескриптор файла нового профиля
  1727. self.FN = False
  1728. # Дескриптор файла старого профиля
  1729. self.FO = False
  1730. # Владелец и режим доступа файла профиля
  1731. self._mode = False
  1732. self._uid = False
  1733. self._gid = False
  1734. self.openNewFile = self.__openNewFile
  1735. self.absFileName = self.__absFileName
  1736. self.closeNewFile = self.__closeNewFile
  1737. def getFileType(self, profile="New"):
  1738. """выдать тип файла (text, bin)
  1739. """
  1740. if self.nameFileNew:
  1741. nameFile = self.nameFileNew
  1742. if profile=="Old" and self.nameFileOld:
  1743. nameFile = self.nameFileOld
  1744. sp = subprocess.Popen("file '%s'"%nameFile, stdin=subprocess.PIPE,
  1745. stdout=subprocess.PIPE, stderr=subprocess.PIPE,
  1746. close_fds=True, shell=True)
  1747. fout, fin, ferr = (sp.stdout, sp.stdin, sp.stderr)
  1748. fin.close()
  1749. textLine = fout.readline()
  1750. fout.readlines()
  1751. fout.close()
  1752. retText = ""
  1753. if textLine:
  1754. listTextLine = textLine.split(":")
  1755. if len(listTextLine) == 2:
  1756. textFormats = ["text", "XML"]
  1757. retText = "bin"
  1758. fileTypeString = listTextLine[1]
  1759. for textFormat in textFormats:
  1760. if textFormat in fileTypeString:
  1761. retText = "text"
  1762. break
  1763. ferr.close()
  1764. return retText
  1765. def scanDirs(self, profilesDirs):
  1766. """Сканирует дерево каталогов выдает два списка: директории, файлы"""
  1767. dirs = []
  1768. class dirProf:
  1769. def __init__(self):
  1770. self.baseDir = False
  1771. self.dirs = []
  1772. self.files = []
  1773. self.links = []
  1774. self.sockets = []
  1775. self.fifo = []
  1776. def getFilesDir(dirP, dirname,names):
  1777. for nameFile in names:
  1778. absNameFile = dirname + "/" + nameFile
  1779. if os.path.islink(absNameFile):
  1780. dest = absNameFile
  1781. src = os.readlink(absNameFile)
  1782. dirP.links.append((src,dest))
  1783. elif os.path.isfile(absNameFile):
  1784. dirP.files.append(absNameFile)
  1785. elif os.path.isdir(absNameFile):
  1786. dirP.dirs.append(absNameFile)
  1787. elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]):
  1788. dirP.sockets.append(absNameFile)
  1789. elif stat.S_ISFIFO(os.stat(absNameFile)[stat.ST_MODE]):
  1790. dirP.fifo.append(absNameFile)
  1791. for profileDir in profilesDirs:
  1792. if profileDir:
  1793. dirP = dirProf()
  1794. dirP.baseDir = profileDir
  1795. dirs.append(dirP)
  1796. os.path.walk(profileDir,getFilesDir, dirP)
  1797. return dirs
  1798. def __absFileName(self, nameFile):
  1799. """Вычисление пути к файлу"""
  1800. pathList = nameFile.split("/")
  1801. chortNameFile = pathList.pop()
  1802. absPath = os.path.abspath("/".join(pathList))
  1803. File = absPath + "/" + chortNameFile
  1804. return File
  1805. def saveOldFile(self):
  1806. """Записать конфигурацию"""
  1807. if self.FO:
  1808. self.FO.truncate(0)
  1809. self.FO.seek(0)
  1810. if not self.oldProfile:
  1811. self.oldProfile = self.newProfile
  1812. try:
  1813. self.FO.write(self.oldProfile)
  1814. except:
  1815. self.setError (_("not open file:" ) + self.nameFileOld)
  1816. return False
  1817. self.FO.flush()
  1818. return True
  1819. def getModeFile(self, nameFile):
  1820. """Выдает информацию о файле
  1821. права файла, владелец, группа файла (777,test, group)
  1822. """
  1823. fd = os.open(nameFile, os.O_RDONLY)
  1824. fst = os.fstat(fd)
  1825. uid = fst.st_uid
  1826. gid = fst.st_gid
  1827. mode = stat.S_IMODE(fst.st_mode)
  1828. os.close(fd)
  1829. return (mode,uid,gid)
  1830. def __openNewFile(self, nameFileNew):
  1831. """Открыть файл профиля"""
  1832. FN = False
  1833. try:
  1834. FN = open (nameFileNew, "r")
  1835. self._mode,self._uid,self._gid = self.getModeFile(nameFileNew)
  1836. except:
  1837. self.setError (_("not open file:" ) + nameFileNew)
  1838. return False
  1839. return FN
  1840. def __closeNewFile(self):
  1841. if self.FN:
  1842. self.FN.close()
  1843. self.FN = False
  1844. def __closeOldFile(self):
  1845. if self.FO:
  1846. self.FO.close()
  1847. self.FO = False
  1848. def __openOldFile(self, nameFileOld, mode, uid, gid):
  1849. """Октрыть конфигурационный файл"""
  1850. FO = False
  1851. try:
  1852. if os.path.islink(nameFileOld):
  1853. # если ссылка то удаляем её
  1854. os.unlink(nameFileOld)
  1855. FO = open (nameFileOld, "r+")
  1856. except:
  1857. try:
  1858. fd = os.open(nameFileOld, os.O_CREAT)
  1859. os.close(fd)
  1860. os.chmod(nameFileOld, mode)
  1861. os.chown(nameFileOld,uid,gid)
  1862. FO = open(nameFileOld, "r+")
  1863. except:
  1864. self.setError (_("not open file:" ) + nameFileOld)
  1865. return False
  1866. return FO
  1867. def openFiles(self, nameFileNew, nameFileOld):
  1868. """Открывает два профайла новый и старый"""
  1869. self.oldProfile = ""
  1870. self.newProfile = ""
  1871. self.closeFiles()
  1872. self.FN = False
  1873. self.FO = False
  1874. self.nameFileOld = self.__absFileName(nameFileOld)
  1875. self.nameFileNew = self.__absFileName(nameFileNew)
  1876. self.FN = self.__openNewFile(self.nameFileNew)
  1877. self.FO = self.__openOldFile(self.nameFileOld,
  1878. self._mode, self._uid, self._gid)
  1879. if self.FN and self.FO:
  1880. self.newProfile = self.FN.read()
  1881. self.oldProfile = self.FO.read()
  1882. def __del__(self):
  1883. self.closeFiles()
  1884. def closeFiles(self):
  1885. """Закрытие файлов"""
  1886. self.__closeNewFile()
  1887. self.__closeOldFile()
  1888. class utfBin:
  1889. """Класс для преобразования в utf-8
  1890. преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
  1891. обратное преобразование
  1892. методы класса encode и decode
  1893. """
  1894. def _retUTF(self, char):
  1895. byte = ord(char)
  1896. if byte<=127:
  1897. return ('_ch_',1)
  1898. elif byte<=191:
  1899. return ('_nb_',1)
  1900. elif byte<=223:
  1901. return ('_fb_',2)
  1902. elif byte<=239:
  1903. return ('_fb_',3)
  1904. elif byte<=247:
  1905. return ('_fb_',4)
  1906. else:
  1907. return ('_er_',1)
  1908. def _sumbUtf(self, symbols, lenTail):
  1909. if not symbols:
  1910. return (False,0)
  1911. lenSymb = len(symbols)
  1912. if lenSymb >= 4:
  1913. l = 4
  1914. elif lenSymb >= 3:
  1915. l = 3
  1916. elif lenSymb >= 2:
  1917. l = 2
  1918. else:
  1919. if symbols[0] == '_ch_':
  1920. return (True,1)
  1921. else:
  1922. return (False,1)
  1923. result = False
  1924. for i in range(l):
  1925. if i == 0 and symbols[i] != '_fb_':
  1926. break
  1927. elif i > 0 and symbols[i] != '_nb_':
  1928. break
  1929. if lenTail>1 and lenTail != i:
  1930. return (False,1)
  1931. if i > 0:
  1932. result = True
  1933. return (result, i)
  1934. def _intToChar(self, x):
  1935. he = hex(x)[2:]
  1936. exec("ret = '\\x%s'" %he)
  1937. return ret
  1938. def _hexToChar(self, he):
  1939. exec("ret = '\\x%s'" %he)
  1940. return ret
  1941. def encode(self, text):
  1942. """Кодирует смешанный формат в UTF-8"""
  1943. ind = 0
  1944. l = 0
  1945. utf = []
  1946. lenUtf = []
  1947. indErr = []
  1948. i = 0
  1949. for ch in text:
  1950. r, l = self._retUTF(ch)
  1951. utf.append(r)
  1952. lenUtf.append(l)
  1953. i+=1
  1954. while 1:
  1955. if utf[ind] == '_fb_':
  1956. res, l = self._sumbUtf(utf[ind:],lenUtf[ind])
  1957. if res is False:
  1958. indErr.append(ind)
  1959. if l>0:
  1960. ind +=l
  1961. if ind >= len(utf):
  1962. break
  1963. else:
  1964. if utf[ind] != '_ch_':
  1965. indErr.append(ind)
  1966. ind +=1
  1967. if ind >= len(utf):
  1968. break
  1969. if indErr:
  1970. lenIndErr = len(indErr)
  1971. block = []
  1972. blocks = []
  1973. if lenIndErr > 1:
  1974. i = 1
  1975. while 1:
  1976. if i == 1:
  1977. block.append(indErr[i-1])
  1978. if indErr[i] - indErr[i-1] == 1:
  1979. block.append(indErr[i])
  1980. else:
  1981. if block:
  1982. blocks.append(block)
  1983. block = []
  1984. block.append(indErr[i])
  1985. i +=1
  1986. if i >= lenIndErr:
  1987. break
  1988. else:
  1989. block.append(indErr[0])
  1990. if block:
  1991. blocks.append(block)
  1992. listErr = []
  1993. for block in blocks:
  1994. string = ""
  1995. for elem in block:
  1996. string += hex(ord(text[elem]))[-2:]
  1997. listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
  1998. textOut = text
  1999. deltaInd = 0
  2000. for erEl in listErr:
  2001. startInd = erEl[0] + deltaInd
  2002. endInd = erEl[2] + 1 + deltaInd
  2003. textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
  2004. deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
  2005. #if i == 1:
  2006. #break
  2007. #i += 1
  2008. return textOut
  2009. def decode(self, text):
  2010. """Декодирует UTF-8 в смешанный формат"""
  2011. varStart = "__hex__\?"
  2012. varEnd = "\?__hex__"
  2013. # -1 Это экранирование '?' которое тоже считается
  2014. deltVarStart = len(varStart)-1
  2015. deltVarEnd = len(varEnd)-1
  2016. reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
  2017. resS = reVar.search(text)
  2018. textProfileTmp = text
  2019. while resS:
  2020. mark = textProfileTmp[resS.start():resS.end()]
  2021. hexString = mark[deltVarStart:-deltVarEnd]
  2022. i = 0
  2023. stringInsert = ""
  2024. hexCode = ""
  2025. for ch in hexString:
  2026. if i>=1:
  2027. hexCode += ch
  2028. stringInsert += self._hexToChar(hexCode)
  2029. hexCode = ""
  2030. i = 0
  2031. else:
  2032. hexCode += ch
  2033. i += 1
  2034. textProfileTmp = textProfileTmp.replace(mark, stringInsert)
  2035. resS = reVar.search(textProfileTmp)
  2036. return textProfileTmp
  2037. def getUserDataInLDAP(self, userName):
  2038. """Получаем домашнюю директорию пользователя из LDAP"""
  2039. if not self.conLdap:
  2040. import cl_utils2
  2041. data = self.getLDAPDataInConfig()
  2042. if not data:
  2043. return ""
  2044. serverName, usersDN, bindDN, bindPW = data
  2045. # Подключаемся к LDAP
  2046. ldapObj = cl_utils2.ldapFun(bindDN, bindPW, serverName)
  2047. if self.getError():
  2048. return ""
  2049. self.conLdap = ldapObj.conLdap
  2050. searchScope = ldap.SCOPE_ONELEVEL
  2051. searchFilter = "uid=%s" %(userName)
  2052. retrieveAttributes = ["uidNumber",
  2053. "gidNumber"
  2054. "homeDirectory"]
  2055. resSearch = ldapObj.ldapSearch(usersDN, searchScope,
  2056. searchFilter, retrieveAttributes)
  2057. if resSearch:
  2058. if resSearch[0][0][1].has_key('uidNumber') and\
  2059. resSearch[0][0][1].has_key('gidNumber') and\
  2060. resSearch[0][0][1].has_key('homeDirectory'):
  2061. uid = searchUser[0][0][1]['uidNumber'][0]
  2062. gid = searchUser[0][0][1]['gidNumber'][0]
  2063. homeDir = resSearch[0][0][1]['homeDirectory'][0]
  2064. return uid, gid, homeDir
  2065. return ""
  2066. class processingTemplates:
  2067. """Класс для обработки шаблонов"""
  2068. def processingFile(self, path, prefix):
  2069. """Обработка в случае профиля файла"""
  2070. return True
  2071. def processingDirectory(self, path, prefix):
  2072. """Обработка в случае директории если возвращаем None то пропуск дир."""
  2073. return True
  2074. def scanningTemplates(self, scanDir, skipFile=[], skipDir=[],
  2075. prefix=None, flagDir=False):
  2076. """Время последней модификации внутри директории scanDir"""
  2077. ret = True
  2078. if not prefix:
  2079. prefix = os.path.join(scanDir,"")[:-1]
  2080. if not flagDir:
  2081. # проверка корневой директории
  2082. retDir = self.processingDirectory(scanDir, scanDir)
  2083. if retDir is None:
  2084. return None
  2085. elif retDir is False:
  2086. return False
  2087. if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
  2088. for fileOrDir in sorted(os.listdir(scanDir)):
  2089. absPath = os.path.join(scanDir,fileOrDir)
  2090. relPath = absPath.split(prefix)[1]
  2091. stInfo = os.lstat(absPath)
  2092. statInfo = stInfo[stat.ST_MODE]
  2093. if stat.S_ISREG(statInfo):
  2094. # Обработка файла
  2095. if relPath in skipFile:
  2096. continue
  2097. if not self.processingFile(absPath, prefix):
  2098. ret = False
  2099. break
  2100. elif stat.S_ISDIR(statInfo):
  2101. # Обработка директории
  2102. if relPath in skipDir:
  2103. continue
  2104. retDir = self.processingDirectory(absPath, prefix)
  2105. if retDir is None:
  2106. continue
  2107. elif retDir is False:
  2108. ret = False
  2109. break
  2110. ret = self.scanningTemplates(absPath, skipFile,
  2111. skipDir, prefix, True)
  2112. if ret is False:
  2113. break
  2114. return ret
  2115. class profile(_file, _terms, xmlShare, processingTemplates):
  2116. """Класс для работы с профилями
  2117. На вход 2 параметра: объект хранения переменных, имя сервиса - не
  2118. обязательный параметр
  2119. """
  2120. # Словарь установленных программ {"имя программы":[версии]}
  2121. installProg = {}
  2122. # Cписок просканированных категорий установленных программ
  2123. installCategory = []
  2124. # Флаг сканирования всех установленных программ
  2125. flagAllPkgScan = False
  2126. # Название файла профиля директории
  2127. profDirNameFile = ".calculate_directory"
  2128. # стек глобальных переменных
  2129. stackGlobalVars = []
  2130. # директория установленных программ
  2131. basePkgDir = "/var/db/pkg"
  2132. # регулярное выражение для поиска версии
  2133. reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*")
  2134. def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[]):
  2135. # Необрабатываемые директории
  2136. self.dirsFilter = dirsFilter
  2137. # Необрабатываемые файлы
  2138. self.filesFilter = filesFilter
  2139. _file.__init__(self)
  2140. # Словарь для создания объектов новых классов по образцу
  2141. self.newObjProt = {'proftpd':(apache,),}
  2142. # Заголовок title
  2143. self.__titleHead = "--------------------------------------\
  2144. ----------------------------------------"
  2145. self._titleBody = ""
  2146. self._titleList = (_("Modified"), _("File of a profile"))
  2147. # Метки
  2148. varStart = "#-"
  2149. varEnd = "-#"
  2150. self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M)
  2151. self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.\'\"~]+%s")\
  2152. %(varStart,varEnd),re.M)
  2153. self._deltVarStart = len(varStart)
  2154. self._deltVarEnd = len(varEnd)
  2155. # Условия
  2156. self._reTermBloc = re.compile("#\?(?P<rTerm>[a-zA-Z0-9\-_]+)\
  2157. (?P<func>\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\))?\
  2158. (?P<lTerm>[\>\<\=\!\&\|]+\
  2159. [a-zA-Z0-9\>\<\=\!\|\&\-\+\*\/_\.\,\(\)\'\"~]*)#\
  2160. \n*(?P<body>.+?)\n*#(?P=rTerm)#(?P<end>[ ,\t]*\n?)",re.M|re.S)
  2161. # Объект с переменными
  2162. self.objVar = objVar
  2163. # Базовая директория переноса профилей "/mnt/calculate" или "/" и.т.д
  2164. baseDir = self.objVar.Get("cl_root_path")
  2165. #self._baseDir = os.path.split(baseDir)[0]
  2166. self._baseDir = baseDir
  2167. if self._baseDir == "/":
  2168. self._baseDir = ""
  2169. # Последняя часть директории профиля (имя сервиса: samba, mail)
  2170. self._servDir = servDir
  2171. if self._servDir:
  2172. if self._servDir[0] != "/":
  2173. self._servDir = "/" + self._servDir
  2174. if self._servDir[-1] != "/":
  2175. self._servDir += "/"
  2176. self._servDir = os.path.split(self._servDir)[0]
  2177. # Созданные директории
  2178. self.createdDirs = []
  2179. # Примененные файлы
  2180. self.filesApply = []
  2181. # номер обрабатываемого файла
  2182. self.numberProcessProf = 0
  2183. # имя текущей программы
  2184. _nameProgram = self.objVar.Get("cl_name").capitalize()
  2185. # версия текущей программы
  2186. _versionProgram = self.objVar.Get("cl_ver")
  2187. # имя и версия текущей программы
  2188. self.programVersion = "%s %s"%(_nameProgram, _versionProgram)
  2189. # Словарь измененных директорий
  2190. self.changeDirs = {}
  2191. # Словарь директорий с количесвом файлов шаблонов
  2192. self.dictTemplates = {}
  2193. # Общее количество шаблонов
  2194. self.allTemplates = 0
  2195. # Аттрибуты для функции шаблона ini()
  2196. # Первоначальный словарь переменных для ini()
  2197. self.prevDictIni = {}
  2198. # Текущий словарь переменных для ini()
  2199. self.currDictIni = {}
  2200. # Время модификации конфигурационного файла для ini()
  2201. self.timeIni = -1
  2202. self.uid, self.gid, self.homeDir = self.getDataUser()
  2203. # Путь к конфигурационному файлу для ini()
  2204. self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
  2205. self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env")
  2206. # Словарь времен модификации env файлов
  2207. self.timeConfigsIni = {}
  2208. def getDataUser(self):
  2209. """Получить информацию о пользователе"""
  2210. userName = self.objVar.Get("ur_login")
  2211. if not userName:
  2212. userName = "root"
  2213. import pwd
  2214. try:
  2215. pwdObj = pwd.getpwnam(userName)
  2216. uid = pwdObj.pw_uid
  2217. gid = pwdObj.pw_gid
  2218. homeDir = pwdObj.pw_dir
  2219. except:
  2220. print _("Can not found user %s")%str(userName)
  2221. cl_base.exit(1)
  2222. return uid, gid, homeDir
  2223. # Преобразование восьмеричного в целое (ввод строка, вывод число)
  2224. def __octToInt(self, strOct):
  2225. if strOct:
  2226. try:
  2227. exec("res =" + "0" + strOct)
  2228. except:
  2229. self.setError (_("Not valid oct value: ") + str(strOct))
  2230. return False
  2231. return res
  2232. else:
  2233. self.setError (_("Empty oct value"))
  2234. return False
  2235. def removeDir(self, rmDir):
  2236. """Рекурсивное удаление директории
  2237. входной параметр директория
  2238. Обязательно должен быть определен метод self.printERROR
  2239. """
  2240. if not os.path.exists(rmDir):
  2241. self.printERROR(_("Not found remove dir %s") %rmDir)
  2242. return False
  2243. fileObj = _file()
  2244. # Сканируем директорию
  2245. scanObjs = fileObj.scanDirs([rmDir])
  2246. for socketRm in scanObjs[0].sockets:
  2247. # Удаляем сокеты
  2248. if os.path.exists(socketRm):
  2249. os.remove(socketRm)
  2250. for linkRm in scanObjs[0].links:
  2251. # Удаляем ссылки
  2252. os.unlink(linkRm[1])
  2253. for fileRm in scanObjs[0].files:
  2254. # Удаляем файлы
  2255. os.remove(fileRm)
  2256. scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x)))
  2257. for dirRm in scanObjs[0].dirs:
  2258. # Удаляем директории
  2259. os.rmdir(dirRm)
  2260. if rmDir:
  2261. os.rmdir(rmDir)
  2262. return True
  2263. def createDir(self, baseProfDir, profDir, baseDirMv, createDir):
  2264. """Создает директорию
  2265. baseDirMv + результат вычитания из profDir baseProfDir
  2266. createDir - создаваемая директория
  2267. """
  2268. if baseDirMv and not os.access(baseDirMv, os.F_OK):
  2269. os.makedirs(baseDirMv)
  2270. # Созданные директории
  2271. createDirs = []
  2272. baseDir = baseProfDir
  2273. if baseProfDir[-1] == "/":
  2274. baseDir = baseProfDir[:-1]
  2275. # Директория в системе относительно baseDirMv без условий
  2276. if baseDirMv:
  2277. dirMvNoTerm = createDir.partition(baseDirMv)[2]
  2278. else:
  2279. dirMvNoTerm = createDir
  2280. # директория в системе
  2281. dirMv = profDir.partition(baseDir)[2]
  2282. if len(dirMv)>1 and dirMv[-1] == "/":
  2283. dirMv = dirMv[:-1]
  2284. ## директория в системе без условий
  2285. #dirMvNoTerm = "/".join(map(lambda x:x.split("?")[0],\
  2286. #dirMv.split("/")))
  2287. listDirMv = dirMv.split("/")
  2288. listDirMvNoTerm = dirMvNoTerm.split("/")
  2289. if len(listDirMv) != len(listDirMvNoTerm):
  2290. self.setError (_("Error in profile") + " :" + profDir)
  2291. return False
  2292. genIn = listDirMv.__iter__()
  2293. genOut = listDirMvNoTerm.__iter__()
  2294. inAndOutDirs = map(lambda x: [x,genOut.next()], genIn)
  2295. createDirs = []
  2296. createDir = []
  2297. while (len(inAndOutDirs)>1):
  2298. tmpDirIn = baseDir+"/".join(map(lambda x:x[0], inAndOutDirs))
  2299. tmpDirOut = baseDirMv + "/".join(map(lambda x:x[1],\
  2300. inAndOutDirs))
  2301. if os.access(tmpDirOut, os.F_OK):
  2302. break
  2303. else:
  2304. createDir.append((tmpDirIn, tmpDirOut))
  2305. inAndOutDirs.pop()
  2306. createDir.reverse()
  2307. for crDirIn,crDirOut in createDir:
  2308. try:
  2309. mode,uid,gid = self.getModeFile(crDirIn)
  2310. except OSError:
  2311. self.setError (_("not access dir:" ) + crDirIn)
  2312. return False
  2313. createDirs.append(crDirOut)
  2314. os.mkdir(crDirOut, mode)
  2315. os.chown(crDirOut, uid, gid)
  2316. return createDirs
  2317. def applyVarsProfile(self, textProfile, nameProfile):
  2318. """ Заменяет переменные на их значения
  2319. """
  2320. resS = self._reVar.search(textProfile)
  2321. textProfileTmp = textProfile
  2322. while resS:
  2323. mark = textProfileTmp[resS.start():resS.end()]
  2324. varName = mark[self._deltVarStart:-self._deltVarEnd]
  2325. varValue = ""
  2326. try:
  2327. varValue = str(self.objVar.Get(varName))
  2328. except self.objVar.DataVarsError, e:
  2329. print _("error in profile %s")%nameProfile
  2330. print e
  2331. cl_base.exit(1)
  2332. textProfileTmp = textProfileTmp.replace(mark, varValue)
  2333. resS = self._reVar.search(textProfileTmp)
  2334. return textProfileTmp
  2335. def applyFuncProfile(self, textProfile, nameProfile, nameSystemFile):
  2336. """ Применяет функции к тексту профиля
  2337. """
  2338. def equalTerm(term, sNum, sMD, localVars):
  2339. """Локальная функция для вычисления выражения"""
  2340. terms = sNum.findall(term)
  2341. if terms:
  2342. strNumers = []
  2343. for n in terms:
  2344. strNum = n.strip()
  2345. if "*" in strNum or "/" in strNum:
  2346. strNum = multAndDiv(strNum,sNum,sMD,localVars)
  2347. try:
  2348. num = int(strNum)
  2349. except:
  2350. minus = False
  2351. if strNum[:1] == "-":
  2352. minus = True
  2353. strNum = strNum[1:]
  2354. if localVars.has_key(strNum):
  2355. try:
  2356. num = int(localVars[strNum])
  2357. except:
  2358. print _("error in profile %s")%nameProfile
  2359. print _("error local var %s not int")\
  2360. %str(strNum)
  2361. cl_base.exit(1)
  2362. elif self.objVar.exists(strNum):
  2363. try:
  2364. num = int(self.objVar.Get(strNum))
  2365. except:
  2366. print _("error in profile %s")%nameProfile
  2367. print _("error var %s not int")%str(strNum)
  2368. cl_base.exit(1)
  2369. else:
  2370. print _("error in profile %s")%nameProfile
  2371. print _("error local var %s not defined")\
  2372. %str(strNum)
  2373. cl_base.exit(1)
  2374. if minus:
  2375. num =-num
  2376. strNumers.append(num)
  2377. return sum(strNumers)
  2378. print _("error in profile %s")%nameProfile
  2379. print _("error profile term %s, incorrect data")%str(term)
  2380. cl_base.exit(1)
  2381. def multAndDiv(term,sNum,sMD,localVars):
  2382. """локальная функция для умножения и деления"""
  2383. termTmp = term
  2384. varsLocal = sMD.findall(term)
  2385. for var in varsLocal:
  2386. flagVarTxt = True
  2387. try:
  2388. int(var)
  2389. except:
  2390. flagVarTxt = False
  2391. if flagVarTxt:
  2392. continue
  2393. varReplace = str(equalTerm(var,sNum,sMD,localVars))
  2394. termTmp = termTmp.replace(var,varReplace)
  2395. ret = eval(termTmp)
  2396. return ret
  2397. def funcSum(funTxt,resS,localVars,textProfileTmp):
  2398. """локальная функция вычисляет первую функцию sum() в профиле"""
  2399. terms = funTxt[4:-1].replace(" ","").split(",")
  2400. # Название локальной переменной
  2401. nameLocVar = terms[0]
  2402. if not localVars.has_key(nameLocVar):
  2403. localVars[nameLocVar] = 0
  2404. if len(terms) == 2:
  2405. if terms[1].strip():
  2406. localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD,
  2407. localVars)
  2408. replace = str(localVars[nameLocVar])
  2409. else:
  2410. replace = ""
  2411. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2412. textProfileTmp[resS.end():]
  2413. elif len(terms) == 3:
  2414. if terms[1].strip():
  2415. replaceInt = equalTerm(terms[1],sNum,sMD,localVars)
  2416. replace = str(replaceInt)
  2417. else:
  2418. replace = ""
  2419. localVars[nameLocVar] = equalTerm(terms[2],
  2420. sNum,sMD,localVars)
  2421. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2422. textProfileTmp[resS.end():]
  2423. else:
  2424. print _("error in profile %s")%nameProfile
  2425. print _("error profile term %s")%str(funTxt)
  2426. cl_base.exit(1)
  2427. return textProfileTmp
  2428. def funcExists(funTxt,resS,textProfileTmp):
  2429. """если файл существует читает из файла локальную переменную
  2430. если один параметр - выводит значение локальной переменной
  2431. """
  2432. terms = funTxt[7:-1].replace(" ","").split(",")
  2433. if len(terms) !=1:
  2434. print _("error in profile %s")%nameProfile
  2435. print _("error profile term %s")%str(funTxt)
  2436. cl_base.exit(1)
  2437. fileName = terms[0].strip()
  2438. if fileName[0] == "~":
  2439. # Получаем директорию пользователя
  2440. fileName = os.path.join(self.homeDir,
  2441. fileName.partition("/")[2],"")[:-1]
  2442. elif fileName[0] != "/":
  2443. path = os.path.split(nameSystemFile)[0]
  2444. fileName=os.path.join(path,fileName)
  2445. replace = ""
  2446. if os.path.exists(fileName):
  2447. replace = "1"
  2448. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2449. textProfileTmp[resS.end():]
  2450. return textProfileTmp
  2451. def funcLoad(funTxt,resS,textProfileTmp):
  2452. """если файл существует читает из файла локальную переменную
  2453. если один параметр - выводит значение локальной переменной
  2454. """
  2455. terms = funTxt[5:-1].replace(" ","").split(",")
  2456. if not terms[0].strip() or\
  2457. (len(terms)==2 and not terms[1].strip()) or\
  2458. len(terms)>2:
  2459. print _("error in profile %s")%nameProfile
  2460. print _("error profile term %s")%str(funTxt)
  2461. cl_base.exit(1)
  2462. if len(terms) == 2:
  2463. if not terms[0] in ["ver","num","char","key"]:
  2464. print _("error in profile %s")%nameProfile
  2465. print _("error profile term %s")%str(funTxt)
  2466. print _("first argument function is not 'ver' or 'num' or\
  2467. 'char'")
  2468. cl_base.exit(1)
  2469. if len(terms) == 1:
  2470. fileName = terms[0].strip()
  2471. # Если домашняя директория
  2472. if fileName[0] == "~":
  2473. # Получаем директорию пользователя
  2474. fileName = os.path.join(self.homeDir,
  2475. fileName.partition("/")[2],"")[:-1]
  2476. elif fileName[0] != "/":
  2477. path = os.path.split(nameSystemFile)[0]
  2478. fileName=os.path.join(path,fileName)
  2479. else:
  2480. fileName = terms[1].strip()
  2481. # Если домашняя директория
  2482. if fileName[0] == "~":
  2483. # Получаем директорию пользователя
  2484. fileName = os.path.join(self.homeDir,
  2485. fileName.partition("/")[2],"")[:-1]
  2486. elif fileName[1] != "/":
  2487. path = os.path.split(nameSystemFile)[0]
  2488. fileName=os.path.join(path,fileName)
  2489. replace = ""
  2490. if os.path.exists(fileName):
  2491. FD = open(fileName)
  2492. replace = FD.read().strip()
  2493. FD.close
  2494. if not replace and len(terms) == 2 and terms[0] in ["ver","num"]:
  2495. replace = "0"
  2496. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2497. textProfileTmp[resS.end():]
  2498. return textProfileTmp
  2499. def getInstallPkgGentoo():
  2500. """Выдает словарь инсталлированных программ и номеров версий"""
  2501. pkgs = []
  2502. def getFilesDir(pkgs, dirname, names):
  2503. for nameFile in names:
  2504. absNameFile = os.path.join(dirname,nameFile)
  2505. if os.path.isdir(absNameFile):
  2506. tail = absNameFile.split(self.basePkgDir)
  2507. if len(tail)==2:
  2508. tail = tail[1].split('/')
  2509. if len(tail)==3 and tail[1]!='virtual':
  2510. pkgs.append(tail[2])
  2511. return True
  2512. os.path.walk(self.basePkgDir,getFilesDir, pkgs)
  2513. return sharePkg(pkgs)
  2514. def sharePkg(pkgs):
  2515. """Получение имен и номеров версий программ"""
  2516. pkgs.sort()
  2517. installProg = {}
  2518. for pkg in pkgs:
  2519. findVer = self.reFindVer.search(pkg)
  2520. if findVer:
  2521. version = findVer.group()
  2522. name = pkg.split(version)[0][:-1]
  2523. if name in installProg:
  2524. installProg[name].append(version)
  2525. else:
  2526. installProg[name] = [version]
  2527. return installProg
  2528. def pkg(nameProg, installProg):
  2529. """Выдает установленные версии по имени программы"""
  2530. if nameProg in installProg:
  2531. return installProg[nameProg][-1]
  2532. else:
  2533. return ""
  2534. def funcPkg(funTxt,resS,textProfileTmp):
  2535. """локальная функция выдает номер версии программы"""
  2536. terms = funTxt[4:-1].replace(" ","")
  2537. # Название программы
  2538. nameProg = terms
  2539. # Замена функции в тексте шаблона
  2540. replace = ""
  2541. if "/" in nameProg:
  2542. if nameProg in self.installProg:
  2543. replace = pkg(nameProg, self.installProg)
  2544. else:
  2545. category, spl, nProg = terms.partition("/")
  2546. if not category in self.installCategory:
  2547. self.installCategory.append(category)
  2548. pathCategory = os.path.join(self.basePkgDir, category)
  2549. if os.path.exists(pathCategory):
  2550. pkgs = os.listdir(pathCategory)
  2551. pkgs = map(lambda x: os.path.join(category,x),
  2552. pkgs)
  2553. installProg = sharePkg(pkgs)
  2554. replace = pkg(nameProg, installProg)
  2555. self.installProg.update(installProg)
  2556. else:
  2557. if not self.flagAllPkgScan:
  2558. installProg = getInstallPkgGentoo()
  2559. self.installProg.update(installProg)
  2560. profile.flagAllPkgScan = True
  2561. replace = pkg(nameProg, self.installProg)
  2562. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2563. textProfileTmp[resS.end():]
  2564. return textProfileTmp
  2565. def funcRnd(funTxt,resS,textProfileTmp):
  2566. """локальная функция выдает строку случайных символов
  2567. первый аргумент:
  2568. 'num' - числа,
  2569. 'pas' - цифры и буквы
  2570. второй аргумент:
  2571. количество символов
  2572. """
  2573. terms = funTxt[4:-1].replace(" ","").split(",")
  2574. if not terms[0].strip() or\
  2575. (len(terms)==2 and not terms[1].strip()) or\
  2576. len(terms)!=2:
  2577. print _("error in profile %s")%nameProfile
  2578. print _("error profile term %s")%str(funTxt)
  2579. cl_base.exit(1)
  2580. fArgvNames = ['num','pas']
  2581. if not terms[0] in fArgvNames:
  2582. print _("error in profile %s")%nameProfile
  2583. print _("error profile term %s")%str(funTxt)
  2584. print _("first argument function is not 'num' or 'pas'")
  2585. cl_base.exit(1)
  2586. try:
  2587. lenStr = int(terms[1])
  2588. except:
  2589. print _("error in profile %s")%nameProfile
  2590. print _("error profile term %s")%str(funTxt)
  2591. print _("two argument function is not number")
  2592. cl_base.exit(1)
  2593. if terms[0] == fArgvNames[0]:
  2594. replace=''.join([random.choice(string.digits)\
  2595. for i in xrange(lenStr)])
  2596. elif terms[0] == fArgvNames[1]:
  2597. replace=''.join([random.choice(string.ascii_letters + \
  2598. string.digits) for i in xrange(lenStr)])
  2599. else:
  2600. print _("error in profile %s")%nameProfile
  2601. print _("error profile term %s")%str(funTxt)
  2602. cl_base.exit(1)
  2603. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2604. textProfileTmp[resS.end():]
  2605. return textProfileTmp
  2606. def funcCase(funTxt,resS,textProfileTmp):
  2607. """локальная функция выдает переменную в определенном регистре
  2608. первый аргумент:
  2609. 'upper' - верхний регистр,
  2610. 'lower' - нижний регистр,
  2611. 'capitalize' - первая буква в верхнем регистре
  2612. второй аргумент:
  2613. название переменной
  2614. """
  2615. terms = funTxt[5:-1].replace(" ","").split(",")
  2616. if not terms[0].strip() or\
  2617. (len(terms)==2 and not terms[1].strip()) or len(terms)!=2:
  2618. print _("error in profile %s")%nameProfile
  2619. print _("error profile term %s")%str(funTxt)
  2620. cl_base.exit(1)
  2621. fArgvNames = ['upper','lower','capitalize']
  2622. if not terms[0] in fArgvNames:
  2623. print _("error in profile %s")%nameProfile
  2624. print _("error profile term %s")%str(funTxt)
  2625. print _("first argument function is not 'upper' or 'lower' or\
  2626. 'capitalize'")
  2627. cl_base.exit(1)
  2628. try:
  2629. strValue = str(self.objVar.Get(terms[1]))
  2630. except:
  2631. print _("error in profile %s")%nameProfile
  2632. print _("error var %s not found")%str(terms[1])
  2633. cl_base.exit(1)
  2634. replace = ""
  2635. strValue = self._toUNICODE(strValue)
  2636. if terms[0] == 'upper':
  2637. replace = strValue.upper()
  2638. elif terms[0] == 'lower':
  2639. replace = strValue.lower()
  2640. elif terms[0] == 'capitalize':
  2641. replace = strValue.capitalize()
  2642. if replace:
  2643. replace = replace.encode("UTF-8")
  2644. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2645. textProfileTmp[resS.end():]
  2646. return textProfileTmp
  2647. def funcPush(funTxt,resS,localVars,textProfileTmp):
  2648. """локальная функция записывает значение переменной
  2649. в стек глобальных переменных
  2650. """
  2651. terms = funTxt[5:-1].replace(" ","").split(",")
  2652. # Название локальной переменной
  2653. nameLocVar = terms[0]
  2654. flagFoundVar = False
  2655. if nameLocVar in localVars.keys():
  2656. flagFoundVar = True
  2657. value = localVars[nameLocVar]
  2658. else:
  2659. try:
  2660. value = self.objVar.Get(nameLocVar)
  2661. flagFoundVar = True
  2662. except:
  2663. pass
  2664. if flagFoundVar:
  2665. # Если переменная существует
  2666. if len(terms) == 1:
  2667. self.stackGlobalVars.append(str(value))
  2668. else:
  2669. print _("error in profile %s")%nameProfile
  2670. print _("error profile term %s")%str(funTxt)
  2671. print _("error var %s exists")%str(nameLocVar)
  2672. cl_base.exit(1)
  2673. else:
  2674. # Если переменная не существует
  2675. if len(terms) == 1:
  2676. print _("error in profile %s")%nameProfile
  2677. print _("error profile term %s")%str(funTxt)
  2678. print _("error var %s not exists")%str(nameLocVar)
  2679. cl_base.exit(1)
  2680. elif len(terms) == 2:
  2681. value = terms[1].strip()
  2682. self.stackGlobalVars.append(str(value))
  2683. localVars[nameLocVar] = value
  2684. else:
  2685. print _("error in profile %s")%nameProfile
  2686. print _("error profile term %s")%str(funTxt)
  2687. cl_base.exit(1)
  2688. replace = ""
  2689. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2690. textProfileTmp[resS.end():]
  2691. return textProfileTmp
  2692. def funcPop(funTxt,resS,localVars,textProfileTmp):
  2693. """локальная функция получает значение
  2694. из стека глобальных переменных и присвает локальной переменной
  2695. """
  2696. terms = funTxt[4:-1].replace(" ","").split(",")
  2697. # Название локальной переменной
  2698. nameLocVar = terms[0]
  2699. if len(terms) == 1:
  2700. if self.stackGlobalVars:
  2701. localVars[nameLocVar] = self.stackGlobalVars.pop()
  2702. else:
  2703. print _("error in profile %s")%nameProfile
  2704. print _("error profile term %s")%str(funTxt)
  2705. print _("error, gloval variables stack is empty")
  2706. cl_base.exit(1)
  2707. else:
  2708. print _("error in profile %s")%nameProfile
  2709. print _("error profile term %s")%str(funTxt)
  2710. cl_base.exit(1)
  2711. replace = ""
  2712. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2713. textProfileTmp[resS.end():]
  2714. return textProfileTmp
  2715. def loadVarsIni(iniFileName):
  2716. """ Читает файл fileName
  2717. создает и заполняет переменные на основе этого файла
  2718. Используеться совместно c funcIni
  2719. """
  2720. localVarsIni = {}
  2721. # Выходим если есть предыдущие ошибки
  2722. if self.getError():
  2723. return False
  2724. # получить объект ini файла
  2725. config = cl_base.iniParser(iniFileName)
  2726. # получаем все секции из конфигурационного файла
  2727. allsect = config.getAllSectionNames()
  2728. if not allsect:
  2729. if self.getError():
  2730. # Очистка ошибки
  2731. _error.error = []
  2732. return localVarsIni
  2733. # Заполняем переменные для funcIni
  2734. for sect in allsect:
  2735. sectVars = config.getAreaVars(sect)
  2736. for name in sectVars.keys():
  2737. nameVar = "%s.%s"%(sect,name)
  2738. valueVar = sectVars[name]
  2739. localVarsIni[nameVar] = valueVar
  2740. return localVarsIni
  2741. def getTimeFile(fileName):
  2742. # Получаем время модификации файла
  2743. if fileName in self.timeConfigsIni:
  2744. return self.timeConfigsIni[fileName]
  2745. return 0
  2746. def funcIni(funTxt, resS, textProfileTmp):
  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, int(self.uid), int(self.gid))
  2754. termsRaw = funTxt[4:-1].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. terms.append(val)
  2772. # Название локальной переменной
  2773. nameLocVar = terms[0]
  2774. namesVar = nameLocVar.split(".")
  2775. if len(namesVar) == 1:
  2776. nameLocVar = "main.%s"%nameLocVar
  2777. elif len(namesVar)>2:
  2778. print _("error in profile %s")%nameProfile
  2779. print _("error profile term %s")%str(funTxt)
  2780. cl_base.exit(1)
  2781. replace = ""
  2782. # Получаем время модификации конфигурационного файла
  2783. curTime = getTimeFile(self.fileConfigIni)
  2784. if len(terms) == 1:
  2785. if self.timeIni != curTime:
  2786. # читаем переменные из файла
  2787. self.prevDictIni = loadVarsIni(self.fileConfigIni)
  2788. self.currDictIni.update(self.prevDictIni)
  2789. self.timeIni = getTimeFile(self.fileConfigIni)
  2790. if nameLocVar in self.currDictIni.keys():
  2791. replace = self.currDictIni[nameLocVar]
  2792. elif len(terms) == 2:
  2793. if self.timeIni != curTime:
  2794. # читаем переменные из файла
  2795. self.prevDictIni = loadVarsIni(self.fileConfigIni)
  2796. self.currDictIni.update(self.prevDictIni)
  2797. self.timeIni = getTimeFile(self.fileConfigIni)
  2798. # Значение локальной переменной
  2799. valueLocVar = terms[1]
  2800. self.currDictIni[nameLocVar] = valueLocVar
  2801. else:
  2802. print _("error in profile %s")%nameProfile
  2803. print _("error profile term %s")%str(funTxt)
  2804. cl_base.exit(1)
  2805. textProfileTmp = textProfileTmp[:resS.start()] + replace +\
  2806. textProfileTmp[resS.end():]
  2807. return (textProfileTmp)
  2808. # Локальные переменные
  2809. localVars = {}
  2810. # Регулярное выражние для сложения
  2811. sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
  2812. # Регулярное выражение для умножениея и деления
  2813. sMD = re.compile("[^\-\+\*\/]+")
  2814. resS = self._reFunc.search(textProfile)
  2815. textProfileTmp = textProfile
  2816. flagIniFunc = False
  2817. while resS:
  2818. mark = textProfileTmp[resS.start():resS.end()]
  2819. funTxt = mark[self._deltVarStart:-self._deltVarEnd]
  2820. # Функция sum
  2821. if funTxt.startswith("sum("):
  2822. textProfileTmp = funcSum(funTxt,resS,localVars,textProfileTmp)
  2823. resS = self._reFunc.search(textProfileTmp)
  2824. # Функция load
  2825. elif funTxt.startswith("load("):
  2826. textProfileTmp = funcLoad(funTxt,resS,textProfileTmp)
  2827. resS = self._reFunc.search(textProfileTmp)
  2828. elif funTxt.startswith("pkg("):
  2829. textProfileTmp = funcPkg(funTxt,resS,textProfileTmp)
  2830. resS = self._reFunc.search(textProfileTmp)
  2831. elif funTxt.startswith("rnd("):
  2832. textProfileTmp = funcRnd(funTxt,resS,textProfileTmp)
  2833. resS = self._reFunc.search(textProfileTmp)
  2834. elif funTxt.startswith("case("):
  2835. textProfileTmp = funcCase(funTxt,resS,textProfileTmp)
  2836. resS = self._reFunc.search(textProfileTmp)
  2837. elif funTxt.startswith("pop("):
  2838. textProfileTmp = funcPop(funTxt,resS,localVars,textProfileTmp)
  2839. resS = self._reFunc.search(textProfileTmp)
  2840. elif funTxt.startswith("push("):
  2841. textProfileTmp = funcPush(funTxt,resS,localVars,textProfileTmp)
  2842. resS = self._reFunc.search(textProfileTmp)
  2843. elif funTxt.startswith("ini("):
  2844. flagIniFunc = True
  2845. textProfileTmp = funcIni(funTxt, resS, textProfileTmp)
  2846. resS = self._reFunc.search(textProfileTmp)
  2847. elif funTxt.startswith("exists("):
  2848. textProfileTmp = funcExists(funTxt, resS, textProfileTmp)
  2849. resS = self._reFunc.search(textProfileTmp)
  2850. else:
  2851. resS = False
  2852. if flagIniFunc:
  2853. # Очистка файла в случае его ошибочного чтения
  2854. if not self.prevDictIni and os.path.exists(self.fileConfigIni):
  2855. FD = open(self.fileConfigIni, "r+")
  2856. FD.truncate(0)
  2857. FD.seek(0)
  2858. FD.close()
  2859. # Если конф. файл модифицирован шаблоном
  2860. curTime = getTimeFile(self.fileConfigIni)
  2861. if curTime != self.timeIni:
  2862. # Считаем переменные из конф. файла
  2863. self.prevDictIni = loadVarsIni(self.fileConfigIni)
  2864. self.currDictIni.update(self.prevDictIni)
  2865. self.timeIni = curTime
  2866. # Если словари переменных не совпадают
  2867. if self.prevDictIni != self.currDictIni:
  2868. # Запишем переменные в конфигурационный файл
  2869. # Создание объекта парсера
  2870. config = cl_base.iniParser(self.fileConfigIni)
  2871. # секции будущего конфигурационного файла
  2872. sects = list(set(map(lambda x: x.split(".")[0],\
  2873. self.currDictIni.keys())))
  2874. # запись переменных в файл
  2875. for sect in sects:
  2876. dictVar = {}
  2877. for varName in self.currDictIni.keys():
  2878. if varName.startswith("%s."%sect):
  2879. nameVar = varName.rpartition(".")[2]
  2880. valueVar = self.currDictIni[varName]
  2881. if valueVar:
  2882. dictVar[nameVar] = valueVar
  2883. if dictVar:
  2884. # Запись переменных в секцию
  2885. config.setVar(sect, dictVar)
  2886. # читаем переменные из файла
  2887. self.prevDictIni = loadVarsIni(self.fileConfigIni)
  2888. self.currDictIni.update(self.prevDictIni)
  2889. self.timeConfigsIni[self.fileConfigIni] = float(time.time())
  2890. self.timeIni = getTimeFile(self.fileConfigIni)
  2891. # Меняем владельца в случае необходимости
  2892. if os.path.exists(self.fileConfigIni):
  2893. fd = os.open(self.fileConfigIni, os.O_RDONLY)
  2894. fst = os.fstat(fd)
  2895. uid = fst.st_uid
  2896. gid = fst.st_gid
  2897. os.close(fd)
  2898. if self.uid!=uid or self.gid!=gid:
  2899. os.chown(self.fileConfigIni, int(self.uid), int(self.gid))
  2900. return textProfileTmp
  2901. def applyTermsProfile(self, textProfile, nameProfile, nameSystemFile=False):
  2902. """ Применяет условия, к условным блокам текста
  2903. """
  2904. textTerm = ""
  2905. resS = self._reTermBloc.search(textProfile)
  2906. textProfileTmp = textProfile
  2907. def function(text):
  2908. """Функция обработки функций в заголовке"""
  2909. return self.applyFuncProfile(text, nameProfile, nameSystemFile)
  2910. if nameSystemFile:
  2911. while resS:
  2912. mark = resS.group(0)
  2913. body = resS.group("body")
  2914. end = resS.group("end")
  2915. parent = resS.group("func")
  2916. if not parent:
  2917. parent = ""
  2918. term = resS.group("rTerm") + parent +\
  2919. resS.group("lTerm")
  2920. if self._equalTerm(term, _("content profile not valid: ")+\
  2921. nameProfile, function):
  2922. textProfileTmp = textProfileTmp.replace(mark, body+end)
  2923. else:
  2924. textProfileTmp = textProfileTmp.replace(mark, "")
  2925. resS = self._reTermBloc.search(textProfileTmp)
  2926. else:
  2927. while resS:
  2928. mark = resS.group(0)
  2929. body = resS.group("body")
  2930. end = resS.group("end")
  2931. term = resS.group("rTerm") + resS.group("lTerm")
  2932. if self._equalTerm(term, _("content profile not valid: ")+\
  2933. nameProfile):
  2934. textProfileTmp = textProfileTmp.replace(mark, body+end)
  2935. else:
  2936. textProfileTmp = textProfileTmp.replace(mark, "")
  2937. resS = self._reTermBloc.search(textProfileTmp)
  2938. return textProfileTmp
  2939. def getNeedProfile(self, fileProfile):
  2940. """Применяем правила к названию файла"""
  2941. dirP,fileP = os.path.split(fileProfile)
  2942. if fileP:
  2943. spFile = fileP.split("?")
  2944. realFileName = spFile[0]
  2945. if len(spFile)>1:
  2946. flagTrue = False
  2947. for term in spFile[1:]:
  2948. if self._equalTerm(term, _("name profile not valid: ")+\
  2949. fileProfile):
  2950. flagTrue = True
  2951. break
  2952. if flagTrue:
  2953. return True
  2954. else:
  2955. return False
  2956. else:
  2957. return True
  2958. else:
  2959. self.setError (_("name profile not valid: ")+ str(fileProfile))
  2960. return False
  2961. def getTitle(self, comment, commentList):
  2962. """Выдает заголовок профиля ( версия и.т.д)"""
  2963. if comment:
  2964. commentFirst = comment
  2965. commentInsert = comment
  2966. commentLast = comment
  2967. flagList = False
  2968. # В случае открывающего и закрывающего комментария
  2969. if type(comment) == types.TupleType and len(comment) == 2:
  2970. commentFirst = comment[0]
  2971. commentInsert = ""
  2972. commentLast = comment[1]
  2973. flagList = True
  2974. if flagList:
  2975. self._titleBody = commentFirst + "\n"
  2976. else:
  2977. self._titleBody = commentFirst + self.__titleHead + "\n"
  2978. z = 0
  2979. lenCommentList = len(commentList) - 1
  2980. for com in self._titleList:
  2981. if lenCommentList < z:
  2982. self._titleBody += commentInsert + " " + com + "\n"
  2983. else:
  2984. self._titleBody += commentInsert + " " + com +\
  2985. " " + commentList[z] + "\n"
  2986. z += 1
  2987. if flagList:
  2988. self._titleBody += commentLast +"\n"
  2989. else:
  2990. self._titleBody += commentLast + self.__titleHead + "\n"
  2991. return self._titleBody
  2992. else:
  2993. return ""
  2994. def numberAllProfiles(self, number):
  2995. """Количество профилей
  2996. Вызов происходит перед наложением профилей
  2997. в момент вызова в number находится количество обрабатываемых файлов
  2998. Наследуемая функция
  2999. Используется для отображения прогресса при наложениии профилей
  3000. """
  3001. return True
  3002. def numberProcessProfiles(self, number):
  3003. """Номер текущего обрабатываемого профиля
  3004. Вызов происходит при наложении профиля
  3005. в момент вызова в number находится номер обрабатываемого профиля
  3006. Наследуемая функция
  3007. Используется для отображения прогресса при наложениии профилей
  3008. """
  3009. return True
  3010. def scanDirs(self, profilesDirs, objVar=False):
  3011. """Измененный метод сканирования директорий"""
  3012. dirs = []
  3013. class dirProf:
  3014. def __init__(self):
  3015. self.baseDir = False
  3016. self.dirs = []
  3017. self.files = []
  3018. self.links = []
  3019. self.sockets = []
  3020. flagError = False
  3021. blockDirs = []
  3022. def getFilesDir(dirP, dirname, names):
  3023. for nameFile in names:
  3024. absNameFile = dirname + "/" + nameFile
  3025. findBlock = False
  3026. for blDir in blockDirs:
  3027. st,mid,end = absNameFile.partition(blDir)
  3028. if (not st) and mid and end:
  3029. findBlock = True
  3030. break
  3031. if not findBlock:
  3032. if os.path.islink(absNameFile):
  3033. dest = absNameFile
  3034. src = os.readlink(absNameFile)
  3035. dirP.links.append((src,dest))
  3036. elif os.path.isfile(absNameFile):
  3037. # Добавляем файлы кроме описаний директорий
  3038. if self.profDirNameFile != nameFile:
  3039. dirP.files.append(absNameFile)
  3040. elif os.path.isdir(absNameFile):
  3041. # Обработка условий в названии директории
  3042. if self.getNeedProfile(absNameFile):
  3043. if self.getError():
  3044. blockDirs.append(absNameFile)
  3045. flagError = True
  3046. break
  3047. dirP.dirs.append(absNameFile)
  3048. else:
  3049. if self.getError():
  3050. blockDirs.append(absNameFile)
  3051. flagError = True
  3052. break
  3053. blockDirs.append(absNameFile)
  3054. elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]):
  3055. dirP.sockets.append(absNameFile)
  3056. for profileDir in profilesDirs:
  3057. if profileDir:
  3058. # Обработка условий в названии директории
  3059. if self.getNeedProfile(profileDir):
  3060. if self.getError():
  3061. flagError = True
  3062. break
  3063. dirP = dirProf()
  3064. dirP.baseDir = profileDir
  3065. dirs.append(dirP)
  3066. os.path.walk(profileDir, getFilesDir, dirP)
  3067. else:
  3068. if self.getError():
  3069. flagError = True
  3070. break
  3071. if flagError:
  3072. return []
  3073. return dirs
  3074. def applyProfiles(self):
  3075. """Применяет профили к конфигурационным файлам"""
  3076. def createDictTemplates(path, prefix, dictTemplates):
  3077. """Создает словарь {"директория":"кол-во шаблонов" ...}
  3078. и считает общее количество шаблонов
  3079. """
  3080. # Количество шаблонов
  3081. self.allTemplates += 1
  3082. dirTemplate = os.path.split(path)[0]
  3083. while(True):
  3084. if dirTemplate in dictTemplates.keys():
  3085. dictTemplates[dirTemplate] += 1
  3086. else:
  3087. dictTemplates[dirTemplate] = 1
  3088. if dirTemplate == prefix:
  3089. break
  3090. dirTemplate = os.path.split(dirTemplate)[0]
  3091. return dictTemplates
  3092. if not self.objVar.defined("cl_profile_path"):
  3093. self.setError (_("not defined Var: ") + "cl_profile_path")
  3094. return False
  3095. dirsProfiles = self.objVar.Get("cl_profile_path")
  3096. dirsProfiles.sort()
  3097. # Словарь измененных директорий
  3098. self.changeDirs = {}
  3099. # Созданные директории
  3100. self.createdDirs = []
  3101. # Примененные файлы
  3102. self.filesApply = []
  3103. # Номер применяемого шаблона
  3104. self.numberProcessProf = 0
  3105. # Словарь директорий с количеством файлов шаблонов
  3106. self.dictTemplates = {}
  3107. # Количество шаблонов
  3108. self.allTemplates = 0
  3109. # Время доступа к конфигурационному файлу функции шаблона ini()
  3110. self.timeIni = -1
  3111. # Первоначальный словарь переменных для ini()
  3112. self.prevDictIni = {}
  3113. # Текущий словарь переменных для ini()
  3114. self.currDictIni = {}
  3115. # Словарь времен модификации env файлов
  3116. self.timeConfigsIni = {}
  3117. if self._servDir:
  3118. tmpDirsProfiles = []
  3119. for dirP in dirsProfiles:
  3120. dirProf = dirP + self._servDir
  3121. if os.access(dirProf, os.F_OK):
  3122. # Если директория существует
  3123. tmpDirsProfiles.append(dirProf)
  3124. dirsProfiles = tmpDirsProfiles
  3125. scanObj = processingTemplates()
  3126. scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
  3127. self.dictTemplates)
  3128. # Считаем количество шаблонов
  3129. for dirTemplate in dirsProfiles:
  3130. scanObj.scanningTemplates(dirTemplate,
  3131. skipFile=self.filesFilter,
  3132. skipDir=self.dirsFilter)
  3133. self.numberAllProfiles(self.allTemplates)
  3134. for dirTemplate in dirsProfiles:
  3135. if self.scanningTemplates(dirTemplate,
  3136. skipFile=self.filesFilter,
  3137. skipDir=self.dirsFilter) is False:
  3138. return False
  3139. return (self.createdDirs, self.filesApply)
  3140. def processingFile(self, path, prefix):
  3141. """Обработка в случае профиля файла"""
  3142. self.numberProcessProf += 1
  3143. self.numberProcessProfiles(self.numberProcessProf)
  3144. # Пропуск шаблонов директорий
  3145. if self.profDirNameFile == os.path.split(path)[1]:
  3146. return True
  3147. if self.getNeedProfile(path):
  3148. if self.getError():
  3149. return False
  3150. fileProfileChange = path
  3151. findChangeDir = False
  3152. listD = self.changeDirs.items()
  3153. listD.reverse()
  3154. for dirChangeIn, dirChangeOut in listD:
  3155. st,mid,end = path.partition(dirChangeIn)
  3156. if (not st) and mid and end:
  3157. findChangeDir = True
  3158. break
  3159. if findChangeDir:
  3160. oldFile = dirChangeOut + end
  3161. else:
  3162. oldFile = path.partition(prefix)[2]
  3163. # файл в системе без условий
  3164. oldFile = "/".join(map(lambda x:x.split("?")[0],\
  3165. oldFile.split("/")))
  3166. if not findChangeDir:
  3167. oldFile = self._baseDir + oldFile
  3168. # Фильтрация профилей по названию файла
  3169. if oldFile in self.filesFilter:
  3170. return True
  3171. listProfTitle = prefix.split("/")[-2:]
  3172. profTitle = '"' + "/".join(listProfTitle) + '"'
  3173. # Записываем в переменную обрабатываемый файл
  3174. self.objVar.Set("cl_pass_file",oldFile)
  3175. # Пишем время модификации *.env файлов
  3176. if oldFile.endswith(".env"):
  3177. self.timeConfigsIni[oldFile] = float(time.time())
  3178. filesApl = self.join(path, oldFile,
  3179. (self.programVersion,profTitle))
  3180. if filesApl:
  3181. self.filesApply += filesApl
  3182. else:
  3183. if self.getError():
  3184. #print self.getError()
  3185. return False
  3186. return True
  3187. def processingDirectory(self, path, prefix):
  3188. """Обработка в случае директории если возвращаем None то пропуск дир."""
  3189. # Файл шаблона директории
  3190. dirInfoFile = os.path.join(path, self.profDirNameFile)
  3191. # Проверяем заголовок
  3192. ret = self.__isApplyHeadDir(dirInfoFile)
  3193. if not ret:
  3194. if self.getError():
  3195. self.setError(_("Incorrect profile: " ) + dirInfoFile)
  3196. return False
  3197. # Добавление количества файлов в пропущенной директории
  3198. if path in self.dictTemplates.keys():
  3199. self.numberProcessProf += self.dictTemplates[path]
  3200. return None
  3201. newDir = self._baseDir + path.partition(prefix)[2]
  3202. newDir = "/".join(map(lambda x:x.split("?")[0],\
  3203. newDir.split("/")))
  3204. # Применяем шаблон
  3205. pathDir, objHeadDir = self.__getApplyHeadDir(newDir,
  3206. dirInfoFile,
  3207. self.changeDirs)
  3208. # Фильтрация профилей по названию директории
  3209. if pathDir in self.dirsFilter:
  3210. # Добавление количества файлов в пропущенной директории
  3211. if path in self.dictTemplates.keys():
  3212. self.numberProcessProf += self.dictTemplates[path]
  3213. return None
  3214. if objHeadDir:
  3215. if isinstance(objHeadDir, dirHeader):
  3216. if not objHeadDir.headerCorrect:
  3217. self.setError(_("Incorrect profile: " ) +\
  3218. dirInfoFile)
  3219. self.setError(objHeadDir.errorMessage)
  3220. return False
  3221. if not objHeadDir.headerTerm:
  3222. if objHeadDir.getError():
  3223. self.setError(_("Incorrect profile: " ) +\
  3224. dirInfoFile)
  3225. return False
  3226. if objHeadDir.params.has_key("name"):
  3227. self.changeDirs[path] = pathDir
  3228. crDirs = self.createDir(prefix, path,
  3229. self._baseDir, pathDir)
  3230. if crDirs is False:
  3231. return False
  3232. self.createdDirs += crDirs
  3233. else:
  3234. if self.getError():
  3235. self.setError(_("Incorrect profile: " ) +\
  3236. dirInfoFile)
  3237. return False
  3238. # Добавление количества файлов в пропущенной директории
  3239. if path in self.dictTemplates.keys():
  3240. self.numberProcessProf += self.dictTemplates[path]
  3241. return None
  3242. return True
  3243. def __getGenHeadDir(self, newDir, profileDirFile, changeDirs):
  3244. """Определяет название создаваемой директории"""
  3245. def function(text):
  3246. """Функция обработки функций в заголовке"""
  3247. return self.applyFuncProfile(text, newDir, profileDirFile)
  3248. newDirMv = newDir
  3249. findChangeDir = False
  3250. #Меняем путь к директории
  3251. listD = changeDirs.items()
  3252. listD.reverse()
  3253. for dirChangeIn, dirChangeOut in listD:
  3254. st,mid,end = profileDirFile.partition(dirChangeIn)
  3255. if (not st) and mid:
  3256. findChangeDir = True
  3257. break
  3258. if findChangeDir:
  3259. pathRel = dirChangeOut
  3260. lenPathRel = len(pathRel.split("/"))
  3261. lenNewDir = len(newDir.split("/"))
  3262. lenEndDir = lenNewDir - lenPathRel
  3263. tmpDir = newDir
  3264. namesDirs = []
  3265. for i in range(lenEndDir):
  3266. namesDirs.append(os.path.split(tmpDir)[1])
  3267. tmpDir = os.path.split(tmpDir)[0]
  3268. namesDirs.reverse()
  3269. nameDir = "/".join(namesDirs)
  3270. newDirMv = os.path.join(pathRel, nameDir)
  3271. applyDir = newDirMv
  3272. if not os.path.exists(profileDirFile):
  3273. return (applyDir, True)
  3274. try:
  3275. FD = open(profileDirFile)
  3276. textProfile = FD.read()
  3277. FD.close()
  3278. except:
  3279. self.setError(_("Error open profile: " ) +\
  3280. profileDirFile)
  3281. return (applyDir, False)
  3282. objHead = dirHeader(textProfile, self.objVar,function)
  3283. if not objHead.headerCorrect:
  3284. self.setError(_("Incorrect profile: " ) +\
  3285. profileDirFile)
  3286. self.setError(objHead.errorMessage)
  3287. return (applyDir, False)
  3288. if not objHead.headerTerm:
  3289. if objHead.getError():
  3290. self.setError(_("Incorrect profile: " ) +\
  3291. profileDirFile)
  3292. return (applyDir, False)
  3293. # Изменяем название директории
  3294. if objHead.params.has_key("name"):
  3295. nameDir = objHead.params['name']
  3296. if "/" in nameDir or nameDir == ".." or nameDir == ".":
  3297. self.setError (_("False value 'name' in profile: " ) +\
  3298. profileDirFile)
  3299. return (applyDir, False)
  3300. if not findChangeDir:
  3301. pathRel = os.path.split(os.path.abspath(newDirMv))[0]
  3302. # Новый путь к оригинальному файлу
  3303. newDirMv = os.path.join(pathRel, nameDir)
  3304. applyDir = newDirMv
  3305. # При удаленнии директории
  3306. if objHead.typeAppend == "remove":
  3307. return (applyDir, False)
  3308. return (applyDir, objHead)
  3309. def scanProfiles(self, serviceName=False, dirObjs=False):
  3310. """Сканирует директории профилей - выводит список файлов"""
  3311. if not self.objVar.defined("cl_profile_path"):
  3312. self.setError (_("not defined Var: ") + "cl_profile_path")
  3313. return False
  3314. if not dirObjs:
  3315. if serviceName :
  3316. self._servDir = serviceName
  3317. if self._servDir:
  3318. if self._servDir[0] != "/":
  3319. self._servDir = "/" + self._servDir
  3320. if self._servDir[-1] != "/":
  3321. self._servDir += "/"
  3322. self._servDir = os.path.split(self._servDir)[0]
  3323. dirsProfiles = self.objVar.Get("cl_profile_path")
  3324. if self._servDir:
  3325. tmpDirsProfiles = []
  3326. for dirP in dirsProfiles:
  3327. dirProf = dirP + self._servDir
  3328. if os.access(dirProf, os.F_OK):
  3329. # Если директория существует
  3330. tmpDirsProfiles.append(dirProf)
  3331. else:
  3332. tmpDirsProfiles.append(False)
  3333. dirsProfiles = tmpDirsProfiles
  3334. dirObjs = self.scanDirs(dirsProfiles,self.objVar)
  3335. #файлы к которым были применены профили
  3336. filesApply = []
  3337. # Словарь измененных директорий
  3338. changeDirs = {}
  3339. dirObjsApply = []
  3340. for dirObj in dirObjs:
  3341. dirInfoFile = os.path.join(dirObj.baseDir, self.profDirNameFile)
  3342. ret = self.__isApplyHeadDir(dirInfoFile)
  3343. if ret:
  3344. dirObjsApply.append(dirObj)
  3345. else:
  3346. if self.getError():
  3347. self.setError(_("Incorrect profile: " ) +\
  3348. dirInfoFile)
  3349. return False
  3350. for dirObj in dirObjsApply:
  3351. # сортируем файлы по названию
  3352. if dirObj.files:
  3353. dirObj.files.sort()
  3354. # сортируем директории по названию
  3355. if dirObj.dirs:
  3356. dirObj.dirs.sort()
  3357. blockDirs = []
  3358. for dirProfile in dirObj.dirs:
  3359. newDir = self._baseDir + dirProfile.partition(dirObj.baseDir)[2]
  3360. newDir = "/".join(map(lambda x:x.split("?")[0],\
  3361. newDir.split("/")))
  3362. # Проверяем условие на директорию
  3363. dirInfoFile = os.path.join(dirProfile, self.profDirNameFile)
  3364. pathDir, objHeadDir = self.__getGenHeadDir(newDir,
  3365. dirInfoFile,
  3366. changeDirs)
  3367. # Фильтрация профилей по названию директории
  3368. if pathDir in self.dirsFilter:
  3369. blockDirs.append(dirProfile)
  3370. continue
  3371. if objHeadDir:
  3372. if isinstance(objHeadDir, dirHeader):
  3373. if not objHeadDir.headerCorrect:
  3374. self.setError(_("Incorrect profile: " ) +\
  3375. dirInfoFile)
  3376. self.setError(objHeadDir.errorMessage)
  3377. return False
  3378. if not objHeadDir.headerTerm:
  3379. if objHeadDir.getError():
  3380. self.setError(_("Incorrect profile: " ) +\
  3381. dirInfoFile)
  3382. return False
  3383. if objHeadDir.params.has_key("name"):
  3384. changeDirs[dirProfile] = pathDir
  3385. else:
  3386. if self.getError():
  3387. self.setError(_("Incorrect profile: " ) +\
  3388. dirInfoFile)
  3389. return False
  3390. blockDirs.append(dirProfile)
  3391. for fileProfile in dirObj.files:
  3392. findBlock = False
  3393. for blDir in blockDirs:
  3394. st,mid,end = fileProfile.partition(blDir)
  3395. if (not st) and mid and end:
  3396. findBlock = True
  3397. break
  3398. if findBlock:
  3399. continue
  3400. if self.getNeedProfile(fileProfile):
  3401. if self.getError():
  3402. #print self.getError()
  3403. return False
  3404. fileProfileChange = fileProfile
  3405. findChangeDir = False
  3406. listD = changeDirs.items()
  3407. listD.reverse()
  3408. for dirChangeIn, dirChangeOut in listD:
  3409. st,mid,end = fileProfile.partition(dirChangeIn)
  3410. if (not st) and mid and end:
  3411. findChangeDir = True
  3412. break
  3413. if findChangeDir:
  3414. oldFile = dirChangeOut + end
  3415. else:
  3416. oldFile = fileProfile.partition(dirObj.baseDir)[2]
  3417. # файл в системе без условий
  3418. oldFile = "/".join(map(lambda x:x.split("?")[0],\
  3419. oldFile.split("/")))
  3420. if not findChangeDir:
  3421. oldFile = self._baseDir + oldFile
  3422. # Фильтрация профилей по названию файла
  3423. if oldFile in self.filesFilter:
  3424. continue
  3425. filesApply.append(oldFile)
  3426. else:
  3427. if self.getError():
  3428. return False
  3429. return filesApply
  3430. def __isApplyHeadDir(self, profileDirFile):
  3431. """Будет ли применен профиль корневой директории
  3432. Возвращает True, False
  3433. """
  3434. def function(text):
  3435. """Функция обработки функций в заголовке"""
  3436. return self.applyFuncProfile(text, "", profileDirFile)
  3437. if not os.path.exists(profileDirFile):
  3438. return True
  3439. try:
  3440. FD = open(profileDirFile)
  3441. textProfile = FD.read()
  3442. FD.close()
  3443. except:
  3444. self.setError(_("Error open profile: " ) +\
  3445. profileDirFile)
  3446. return False
  3447. # Заменяем переменные на их значения
  3448. textProfile = self.applyVarsProfile(textProfile, profileDirFile)
  3449. # Обработка заголовка
  3450. objHead = dirHeader(textProfile, self.objVar,function)
  3451. if not objHead.headerCorrect:
  3452. self.setError(_("Incorrect profile: " ) +\
  3453. profileDirFile)
  3454. self.setError(objHead.errorMessage)
  3455. return False
  3456. if not objHead.headerTerm:
  3457. if objHead.getError():
  3458. self.setError(_("Incorrect profile: " ) +\
  3459. profileDirFile)
  3460. return False
  3461. ## Изменяем название директории
  3462. #if objHead.params.has_key("name"):
  3463. #self.setError (_("Invalid name 'name' in profile: " ) +\
  3464. #profileDirFile)
  3465. #return False
  3466. ## Удаляем директорию
  3467. #if objHead.typeAppend == "remove":
  3468. #self.setError (_("Invalid name 'remove' in profile: " ) +\
  3469. #profileDirFile)
  3470. #return False
  3471. ## chmod - изменяем права
  3472. #if objHead.params.has_key("chmod"):
  3473. #self.setError (_("Invalid name 'chmod' in profile: " ) +\
  3474. #profileDirFile)
  3475. #return False
  3476. ## chown - изменяем владельца и группу
  3477. #if objHead.params.has_key("chown"):
  3478. #self.setError (_("Invalid name 'chown' in profile: " ) +\
  3479. #profileDirFile)
  3480. #return False
  3481. return True
  3482. def __getApplyHeadDir(self, newDir, profileDirFile, changeDirs):
  3483. """Применяет профиль к директории (права, владелец, и.т. д)"""
  3484. def function(text):
  3485. """Функция обработки функций в заголовке"""
  3486. return self.applyFuncProfile(text, newDir, profileDirFile)
  3487. newDirMv = newDir
  3488. findChangeDir = False
  3489. #Меняем путь к директории
  3490. listD = changeDirs.items()
  3491. listD.reverse()
  3492. for dirChangeIn, dirChangeOut in listD:
  3493. st,mid,end = profileDirFile.partition(dirChangeIn)
  3494. if (not st) and mid:
  3495. findChangeDir = True
  3496. break
  3497. if findChangeDir:
  3498. pathRel = dirChangeOut
  3499. lenPathRel = len(pathRel.split("/"))
  3500. lenNewDir = len(newDir.split("/"))
  3501. lenEndDir = lenNewDir - lenPathRel
  3502. tmpDir = newDir
  3503. namesDirs = []
  3504. for i in range(lenEndDir):
  3505. namesDirs.append(os.path.split(tmpDir)[1])
  3506. tmpDir = os.path.split(tmpDir)[0]
  3507. namesDirs.reverse()
  3508. nameDir = "/".join(namesDirs)
  3509. newDirMv = os.path.join(pathRel, nameDir)
  3510. applyDir = newDirMv
  3511. if not os.path.exists(profileDirFile):
  3512. return (applyDir, True)
  3513. try:
  3514. FD = open(profileDirFile)
  3515. textProfile = FD.read()
  3516. FD.close()
  3517. except:
  3518. self.setError(_("Error open profile: " ) +\
  3519. profileDirFile)
  3520. return (applyDir, False)
  3521. # Заменяем переменные на их значения
  3522. textProfile = self.applyVarsProfile(textProfile, profileDirFile)
  3523. # Обработка заголовка
  3524. objHead = dirHeader(textProfile, self.objVar,function)
  3525. if not objHead.headerCorrect:
  3526. self.setError(_("Incorrect profile: " ) +\
  3527. profileDirFile)
  3528. self.setError(objHead.errorMessage)
  3529. return (applyDir, False)
  3530. if not objHead.headerTerm:
  3531. if objHead.getError():
  3532. self.setError(_("Incorrect profile: " ) +\
  3533. profileDirFile)
  3534. return (applyDir, False)
  3535. # Изменяем название директории
  3536. if objHead.params.has_key("name"):
  3537. nameDir = objHead.params['name']
  3538. if "/" in nameDir or nameDir == ".." or nameDir == ".":
  3539. self.setError (_("False value 'name' in profile: " ) +\
  3540. profileDirFile)
  3541. return (applyDir, False)
  3542. if not findChangeDir:
  3543. pathRel = os.path.split(os.path.abspath(newDirMv))[0]
  3544. # Новый путь к оригинальному файлу
  3545. newDirMv = os.path.join(pathRel, nameDir)
  3546. applyDir = newDirMv
  3547. # Удаляем директорию
  3548. if objHead.typeAppend == "remove":
  3549. if os.path.isdir(newDirMv):
  3550. # удаляем директорию
  3551. try:
  3552. self.removeDir(newDirMv)
  3553. except:
  3554. self.setError(_("Can not delete dir: " ) +\
  3555. newDirMv)
  3556. return (applyDir, False)
  3557. # chmod - изменяем права
  3558. if objHead.params.has_key("chmod"):
  3559. mode = self.__octToInt(objHead.params['chmod'])
  3560. if mode:
  3561. if not os.path.exists(newDirMv):
  3562. os.mkdir(newDirMv, mode)
  3563. else:
  3564. os.chmod(newDirMv, mode)
  3565. else:
  3566. self.setError (_("False value 'chmod' in profile: " ) +\
  3567. profileDirFile)
  3568. return (applyDir, False)
  3569. # chown - изменяем владельца и группу
  3570. if objHead.params.has_key("chown"):
  3571. owner = objHead.params['chown']
  3572. if owner:
  3573. if ":" in owner:
  3574. strUid, strGid = owner.split(":")
  3575. import pwd
  3576. try:
  3577. uid = pwd.getpwnam(strUid)[2]
  3578. except:
  3579. self.setError (_("Not user in this system: ") + strUid)
  3580. self.setError (_("False value 'chown' in profile: " )+\
  3581. profileDirFile)
  3582. return (applyDir, False)
  3583. try:
  3584. import grp
  3585. gid = grp.getgrnam(strGid)[2]
  3586. except:
  3587. self.setError (_("Not group in this system: ")+strGid)
  3588. self.setError (_("False value 'chown' in profile: " )+\
  3589. profileDirFile)
  3590. return (applyDir, False)
  3591. if not os.path.exists(newDirMv):
  3592. dirProfile = os.path.split(profileDirFile)[0]
  3593. try:
  3594. mode,uidTmp,gidTmp = self.getModeFile(dirProfile)
  3595. except OSError:
  3596. self.setError (_("not access dir:" ) + newDirMv)
  3597. return (applyDir, False)
  3598. os.mkdir(newDirMv, mode)
  3599. os.chown(newDirMv, uid, gid)
  3600. else:
  3601. self.setError (_("False value 'chown' in profile: " ) +\
  3602. profileDirFile)
  3603. return (applyDir, False)
  3604. else:
  3605. self.setError (_("False value 'chown' in profile: " ) +\
  3606. profileDirFile)
  3607. return (applyDir, False)
  3608. return (applyDir, objHead)
  3609. def __getApplyHeadProfile(self ,newFile, oldFile, copyFile):
  3610. """Применяет заголовок к профилю (права, владелец, и.т. д)"""
  3611. def function(text):
  3612. """Функция обработки функций в заголовке"""
  3613. return self.applyFuncProfile(text, newFile, oldFile)
  3614. self.closeFiles()
  3615. # Файлы в системе к которым были применены профили
  3616. applyFiles = [oldFile]
  3617. if copyFile:
  3618. self.nameFileNew = self.absFileName(newFile)
  3619. self.FN = self.openNewFile(self.nameFileNew)
  3620. self.newProfile = self.FN.read()
  3621. self.closeNewFile()
  3622. objHeadNew = fileHeader(self.newProfile, False,
  3623. self.getFileType(),objVar=self.objVar,
  3624. function=function)
  3625. if not objHeadNew.headerCorrect:
  3626. self.setError(_("Incorrect profile: " ) +\
  3627. newFile)
  3628. self.setError(objHeadNew.errorMessage)
  3629. return (applyFiles, False)
  3630. if not objHeadNew.headerTerm:
  3631. if objHeadNew.getError():
  3632. self.setError(_("Incorrect profile: " ) +\
  3633. newFile)
  3634. return (applyFiles, False)
  3635. pathProg = ""
  3636. # Путь к оригинальному файлу
  3637. pathOldFile = oldFile
  3638. # Изменяем путь к оригинальному файлу
  3639. if objHeadNew.params.has_key("name"):
  3640. nameFile = objHeadNew.params['name']
  3641. if "/" in nameFile or nameFile == ".." or nameFile == ".":
  3642. self.setError (_("False value 'name' in profile: " ) + newFile)
  3643. return False
  3644. pathRel = os.path.split(os.path.abspath(oldFile))[0]
  3645. # Новый путь к оригинальному файлу
  3646. pathOldFile = os.path.join(pathRel,nameFile)
  3647. # В случае force
  3648. if objHeadNew.params.has_key("force"):
  3649. if os.path.islink(pathOldFile):
  3650. # удаляем ссылку
  3651. try:
  3652. os.unlink(pathOldFile)
  3653. except:
  3654. self.setError(_("Can not delete link: " ) +\
  3655. pathOldFile)
  3656. return (applyFiles, False)
  3657. if os.path.isfile(pathOldFile):
  3658. # удаляем файл
  3659. try:
  3660. os.remove(pathOldFile)
  3661. except:
  3662. self.setError(_("Can not delete file: " ) +\
  3663. pathOldFile)
  3664. return (applyFiles, False)
  3665. # Удаляем оригинальный файл
  3666. if objHeadNew.typeAppend == "remove":
  3667. if os.path.islink(pathOldFile):
  3668. # удаляем ссылку
  3669. try:
  3670. os.unlink(pathOldFile)
  3671. except:
  3672. self.setError(_("Can not delete link: " ) +\
  3673. pathOldFile)
  3674. if os.path.isfile(pathOldFile):
  3675. # удаляем файл
  3676. try:
  3677. os.remove(pathOldFile)
  3678. except:
  3679. self.setError(_("Can not delete file: " ) +\
  3680. pathOldFile)
  3681. return (applyFiles, False)
  3682. flagSymlink = False
  3683. flagForce = False
  3684. # Если есть параметр mirror
  3685. if objHeadNew.params.has_key("mirror"):
  3686. if objHeadNew.params.has_key("link"):
  3687. profileFile = objHeadNew.params['link']
  3688. if not os.path.exists(profileFile):
  3689. if os.path.exists(pathOldFile):
  3690. os.remove(pathOldFile)
  3691. return (applyFiles, False)
  3692. elif not os.path.exists(pathOldFile):
  3693. return (applyFiles, False)
  3694. # Если есть указатель на файл профиля (link)
  3695. if objHeadNew.params.has_key("link") and\
  3696. not objHeadNew.params.has_key("symbolic"):
  3697. profileFile = objHeadNew.params['link']
  3698. foundProfileFile = os.path.exists(profileFile)
  3699. if foundProfileFile:
  3700. FO = self.openNewFile(profileFile)
  3701. buff = FO.read()
  3702. FO.close()
  3703. if os.path.exists(pathOldFile):
  3704. os.remove(pathOldFile)
  3705. if foundProfileFile:
  3706. fd = os.open(pathOldFile, os.O_CREAT)
  3707. os.close(fd)
  3708. os.chmod(pathOldFile, self._mode)
  3709. os.chown(pathOldFile, self._uid, self._gid)
  3710. FON = open (pathOldFile, "r+")
  3711. FON.write(buff)
  3712. FON.close()
  3713. # Если символическая ссылка
  3714. if objHeadNew.params.has_key("symbolic"):
  3715. prevOldFile = pathOldFile
  3716. pathOldFile = objHeadNew.params['link']
  3717. flagSymlink = True
  3718. if not "/" == pathOldFile[0]:
  3719. pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
  3720. pathProg = os.getcwd()
  3721. os.chdir(pathLink)
  3722. # chmod - изменяем права
  3723. if objHeadNew.params.has_key("chmod"):
  3724. mode = self.__octToInt(objHeadNew.params['chmod'])
  3725. if mode:
  3726. if not os.path.exists(pathOldFile):
  3727. fd = os.open(pathOldFile, os.O_CREAT)
  3728. os.close(fd)
  3729. os.chmod(pathOldFile, mode)
  3730. else:
  3731. self.setError (_("False value 'chmod' in profile: " ) +\
  3732. newFile)
  3733. return (applyFiles, False)
  3734. # chown - изменяем владельца и группу
  3735. if objHeadNew.params.has_key("chown"):
  3736. owner = objHeadNew.params['chown']
  3737. if owner:
  3738. if ":" in owner:
  3739. strUid, strGid = owner.split(":")
  3740. import pwd
  3741. try:
  3742. uid = pwd.getpwnam(strUid)[2]
  3743. except:
  3744. self.setError (_("Not user in this system: ") + strUid)
  3745. self.setError (_("False value 'chown' in profile: " )+\
  3746. newFile)
  3747. return (applyFiles, False)
  3748. try:
  3749. import grp
  3750. gid = grp.getgrnam(strGid)[2]
  3751. except:
  3752. self.setError (_("Not group in this system: ")+strGid)
  3753. self.setError (_("False value 'chown' in profile: " )+\
  3754. newFile)
  3755. return (applyFiles, False)
  3756. if not os.path.exists(pathOldFile):
  3757. FO = self.openNewFile(newFile)
  3758. FO.close()
  3759. fd = os.open(pathOldFile, os.O_CREAT)
  3760. os.close(fd)
  3761. os.chmod(pathOldFile, self._mode)
  3762. os.chown(pathOldFile, uid, gid)
  3763. else:
  3764. self.setError (_("False value 'chown' in profile: " ) +\
  3765. newFile)
  3766. return (applyFiles, False)
  3767. else:
  3768. self.setError (_("False value 'chown' in profile: " ) +\
  3769. newFile)
  3770. return (applyFiles, False)
  3771. self.openFiles(newFile, pathOldFile)
  3772. if flagSymlink:
  3773. if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
  3774. if os.path.islink(prevOldFile):
  3775. # если ссылка то удаляем её
  3776. os.unlink(prevOldFile)
  3777. else:
  3778. # иначе удаляем файл
  3779. os.remove(prevOldFile)
  3780. if not "/" == pathOldFile[0]:
  3781. os.symlink(pathOldFile, prevOldFile)
  3782. applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)]
  3783. else:
  3784. os.symlink(pathOldFile, prevOldFile)
  3785. applyFiles = [prevOldFile,pathOldFile]
  3786. if not objHeadNew.body.strip():
  3787. return (applyFiles, False)
  3788. else:
  3789. applyFiles = [pathOldFile]
  3790. if pathProg:
  3791. os.chdir(pathProg)
  3792. # Если файлы заменяются не нужно их обрабатывать дальше
  3793. if objHeadNew.typeAppend == "replace" and\
  3794. not objHeadNew.params.has_key("symbolic") and\
  3795. objHeadNew.params.has_key("link"):
  3796. return (applyFiles, False)
  3797. return (applyFiles, objHeadNew)
  3798. def createNewClass(self, name, bases, attrs={}):
  3799. """Создает объект нового класса
  3800. createNewClass(self, name, bases, attrs)
  3801. name - имя класса - str,
  3802. bases - cписок наследуемых классов - (tuple),
  3803. attrs - аттрибуты класса - {dict}
  3804. """
  3805. class newMethod:
  3806. #Объединяем конфигурации
  3807. def join(self, newObj):
  3808. if newObj.__class__.__name__ == self.__class__.__name__:
  3809. self.docObj.joinDoc(newObj.doc)
  3810. # Пост обработка
  3811. if 'postXML' in dir(self):
  3812. self.postXML()
  3813. attrsNew = {}
  3814. attrsNew["configName"] = name
  3815. if attrs:
  3816. for key in attrs.keys():
  3817. attrsNew[key] = attrs[key]
  3818. newCl = type(name, bases + (newMethod, object,), attrsNew)
  3819. return newCl
  3820. def fileIsUtf(self, fileName):
  3821. """Проверяет файл на кодировку UTF-8"""
  3822. if os.path.exists(fileName):
  3823. FD = open(self.absFileName(fileName))
  3824. newProfile = FD.read()
  3825. FD.close()
  3826. try:
  3827. newProfile.decode("UTF-8")
  3828. except:
  3829. return False
  3830. return True
  3831. def join(self, newFile, oldFile, ListOptTitle):
  3832. """Объединения профиля и конф. файла
  3833. join(newFile, oldFile, ListOptTitle)
  3834. Объединение профиля newFile и конф. файла oldFile,
  3835. ListOptTitle - список строк которые добавятся в заголовок
  3836. """
  3837. # Выполняем условия для блока текста а так-же заменяем переменные
  3838. self.nameFileNew = self.absFileName(newFile)
  3839. self.FN = self.openNewFile(self.nameFileNew)
  3840. self.newProfile = self.FN.read()
  3841. self.closeNewFile()
  3842. copyFile = True
  3843. if self.getFileType() != "bin":
  3844. # Вычисляем условные блоки
  3845. self.newProfile = self.applyTermsProfile(self.newProfile,
  3846. newFile, oldFile)
  3847. #print "|%s|" %(self.newProfile)
  3848. # Заменяем переменные на их значения
  3849. self.newProfile = self.applyVarsProfile(self.newProfile,
  3850. newFile)
  3851. # Вычисляем функции
  3852. self.newProfile = self.applyFuncProfile(self.newProfile,
  3853. newFile, oldFile)
  3854. copyFile = False
  3855. filesApply, objHeadNew = self.__getApplyHeadProfile(newFile, oldFile,
  3856. copyFile)
  3857. if not objHeadNew:
  3858. return filesApply
  3859. # Флаг - кодировка с бинарными примесями у файла профиля включаем при
  3860. # условии текстового файла и кодировки отличной от UTF-8
  3861. flagNotUtf8New = False
  3862. # Флаг - кодировка с бинарными примесями у оригинального файла
  3863. flagNotUtf8Old = False
  3864. if not copyFile:
  3865. # проверяем кодировку профиля
  3866. if not self.fileIsUtf(newFile):
  3867. flagNotUtf8New = True
  3868. if not (objHeadNew.params.has_key("link") and\
  3869. objHeadNew.params.has_key("symbolic")):
  3870. # проверяем кодировку оригинального файла
  3871. if not self.fileIsUtf(oldFile):
  3872. flagNotUtf8Old = True
  3873. self.newProfile = objHeadNew.body
  3874. #if objHeadNew.fileType != "bin":
  3875. #self.newProfile = self.applyTermsProfile(self.newProfile,
  3876. #newFile)
  3877. #self.newProfile = self.applyVarsProfile(self.newProfile)
  3878. # Титл конфигурационного файла
  3879. title = ""
  3880. if ListOptTitle:
  3881. title = self.getTitle(objHeadNew.comment,
  3882. ListOptTitle)
  3883. title = title.encode("UTF-8")
  3884. objHeadOld = False
  3885. if objHeadNew.comment:
  3886. objHeadOld = fileHeader(self.oldProfile, objHeadNew.comment)
  3887. # Тестирование
  3888. #print self.nameFileOld
  3889. #print objHeadNew.typeAppend
  3890. if objHeadNew.fileType:
  3891. # Создаем объект в случае параметра format в заголовке
  3892. if (objHeadNew.typeAppend == "replace" or\
  3893. objHeadNew.typeAppend == "before" or\
  3894. objHeadNew.typeAppend == "after") and\
  3895. not (objHeadNew.fileType == "bin" or\
  3896. objHeadNew.fileType == "raw"):
  3897. # Преобразовываем бинарные файлы
  3898. if flagNotUtf8New:
  3899. objTxtCoder = utfBin()
  3900. self.newProfile = objTxtCoder.encode(self.newProfile)
  3901. try:
  3902. exec ("objProfNew=%s(self.newProfile)"%\
  3903. (objHeadNew.fileType))
  3904. except NameError:
  3905. #Создаем объект из self.newObjProt с помощью
  3906. # метаклассов
  3907. if self.newObjProt.has_key(objHeadNew.fileType):
  3908. objProfNewCl = self.createNewClass(\
  3909. objHeadNew.fileType,
  3910. self.newObjProt[objHeadNew.fileType])
  3911. objProfNew = objProfNewCl(self.newProfile)
  3912. else:
  3913. self.setError (\
  3914. _("False join profile for type profile: ")\
  3915. + objHeadNew.fileType + " : " +\
  3916. newFile)
  3917. return False
  3918. if "xml_" in objHeadNew.fileType:
  3919. if objProfNew.getError():
  3920. self.setError (_("False profile: " ) + newFile)
  3921. return False
  3922. nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
  3923. objProfNew.setNameBodyNode(nameRootNode)
  3924. # Объект Документ
  3925. docObj = objProfNew.docObj
  3926. # Удаление комментариев из документа
  3927. docObj.removeComment(docObj.getNodeBody())
  3928. # Добавление необходимых переводов строк
  3929. docObj.insertBRtoBody(docObj.getNodeBody())
  3930. # Добавление необходимых разделителей между областями
  3931. docObj.insertBeforeSepAreas(docObj.getNodeBody())
  3932. # Пост обработка
  3933. if 'postXML' in dir(objProfNew):
  3934. objProfNew.postXML()
  3935. # Получение текстового файла из XML документа
  3936. self.newProfile = objProfNew.getConfig().encode("UTF-8")
  3937. # Если не UTF-8 производим преобразование
  3938. if flagNotUtf8New:
  3939. self.newProfile = objTxtCoder.decode(self.newProfile)
  3940. # Титл для объединения
  3941. if ListOptTitle:
  3942. title = self.getTitle(objProfNew._comment,
  3943. ListOptTitle)
  3944. title = title.encode("UTF-8")
  3945. # Замена
  3946. if objHeadNew.typeAppend == "replace":
  3947. if "xml_" in objHeadNew.fileType:
  3948. data = self.newProfile.split("\n")
  3949. data.insert(1,title)
  3950. self.oldProfile = "\n".join(data)
  3951. else:
  3952. if objHeadNew.execStr:
  3953. self.oldProfile = objHeadNew.execStr+title+\
  3954. self.newProfile
  3955. else:
  3956. self.oldProfile = title + self.newProfile
  3957. self.saveOldFile()
  3958. return filesApply
  3959. # Впереди
  3960. elif objHeadNew.typeAppend == "before":
  3961. if "xml_" in objHeadNew.fileType:
  3962. self.setError (\
  3963. _("False option append=before in profile %s") %newFile)
  3964. return False
  3965. if objHeadOld and objHeadOld.body:
  3966. self.oldProfile = objHeadOld.body
  3967. if self.newProfile[-1] == "\n":
  3968. tmpProfile = self.newProfile + self.oldProfile
  3969. else:
  3970. tmpProfile = self.newProfile + "\n" + self.oldProfile
  3971. if objHeadNew.execStr:
  3972. self.oldProfile = objHeadNew.execStr + title + tmpProfile
  3973. elif objHeadOld.execStr:
  3974. self.oldProfile = objHeadOld.execStr + title + tmpProfile
  3975. else:
  3976. self.oldProfile = title + tmpProfile
  3977. #print self.oldProfile
  3978. self.saveOldFile()
  3979. return filesApply
  3980. # Cзади
  3981. elif objHeadNew.typeAppend == "after":
  3982. if "xml_" in objHeadNew.fileType:
  3983. self.setError (\
  3984. _("False option append=after in profile %s") %newFile)
  3985. return False
  3986. if objHeadOld and objHeadOld.body:
  3987. self.oldProfile = objHeadOld.body
  3988. if self.newProfile[-1] == "\n":
  3989. tmpProfile = self.oldProfile + self.newProfile
  3990. else:
  3991. tmpProfile = self.oldProfile + "\n" + self.newProfile
  3992. if objHeadNew.execStr:
  3993. self.oldProfile = objHeadNew.execStr + title + tmpProfile
  3994. elif objHeadOld.execStr:
  3995. self.oldProfile = objHeadOld.execStr + title + tmpProfile
  3996. else:
  3997. self.oldProfile = title + tmpProfile
  3998. self.saveOldFile()
  3999. return filesApply
  4000. # Объединение
  4001. elif objHeadNew.typeAppend == "join":
  4002. if flagNotUtf8New:
  4003. objTxtCoder = utfBin()
  4004. self.newProfile = objTxtCoder.encode(self.newProfile)
  4005. try:
  4006. exec ("objProfNew=%s(self.newProfile)"%\
  4007. (objHeadNew.fileType))
  4008. except NameError:
  4009. #Создаем объект из self.newObjProt с помощью
  4010. # метаклассов
  4011. if self.newObjProt.has_key(objHeadNew.fileType):
  4012. objProfNewCl = self.createNewClass(\
  4013. objHeadNew.fileType,
  4014. self.newObjProt[objHeadNew.fileType])
  4015. objProfNew = objProfNewCl(self.newProfile)
  4016. else:
  4017. self.setError (\
  4018. _("False join profile for type profile: ")\
  4019. + objHeadNew.fileType + " : " +\
  4020. newFile)
  4021. return False
  4022. if "xml_" in objHeadNew.fileType:
  4023. if objProfNew.getError():
  4024. self.setError (_("False profile: " ) + newFile)
  4025. return False
  4026. nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
  4027. objProfNew.setNameBodyNode(nameRootNode)
  4028. # Титл для объединения
  4029. if ListOptTitle:
  4030. title = self.getTitle(objProfNew._comment,
  4031. ListOptTitle)
  4032. title = title.encode("UTF-8")
  4033. # В случае пустого конфигурационного файла
  4034. reNoClean = re.compile("[^\s]",re.M)
  4035. if not self.oldProfile or\
  4036. not reNoClean.search(self.oldProfile):
  4037. self.oldProfile = ""
  4038. #if objHeadNew.execStr:
  4039. #self.oldProfile = objHeadNew.execStr + \
  4040. #title + objProfNew.getConfig().encode("UTF-8")
  4041. #else:
  4042. #self.oldProfile = title +\
  4043. #objProfNew.getConfig().encode("UTF-8")
  4044. #self.saveOldFile()
  4045. #return True
  4046. objHeadOld = fileHeader(self.oldProfile, objProfNew._comment)
  4047. if objHeadOld.body:
  4048. self.oldProfile = objHeadOld.body
  4049. else:
  4050. self.oldProfile = ""
  4051. if flagNotUtf8Old:
  4052. objTxtCoder = utfBin()
  4053. self.oldProfile = objTxtCoder.encode(self.oldProfile)
  4054. if self.newObjProt.has_key(objHeadNew.fileType):
  4055. objProfOldCl = self.createNewClass(\
  4056. objHeadNew.fileType,
  4057. self.newObjProt[objHeadNew.fileType])
  4058. objProfOld = objProfOldCl(self.oldProfile)
  4059. else:
  4060. exec ("objProfOld=%s(self.oldProfile)"%\
  4061. (objHeadNew.fileType))
  4062. if "xml_" in objHeadNew.fileType:
  4063. if objProfOld.getError():
  4064. self.setError (_("False profile: " ) + oldFile)
  4065. return False
  4066. nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
  4067. objProfOld.setNameBodyNode(nameRootNode)
  4068. #print "#%s#" %(objProfOld.docObj.body.toprettyxml())
  4069. #print "#%s#" %(objProfNew.docObj.body.toprettyxml())
  4070. objProfOld.join(objProfNew)
  4071. #print objProfOld.doc.toprettyxml()
  4072. #print objProfNew.doc.toprettyxml()
  4073. if "xml_" in objHeadNew.fileType:
  4074. if objProfOld.getError():
  4075. self.setError (_("False profile: " ) + newFile)
  4076. return False
  4077. data = \
  4078. objProfOld.getConfig().encode("UTF-8").split("\n")
  4079. data.insert(1,title)
  4080. self.oldProfile = "\n".join(data)
  4081. else:
  4082. if objHeadNew.execStr:
  4083. self.oldProfile = objHeadNew.execStr + title +\
  4084. objProfOld.getConfig().encode("UTF-8")
  4085. elif objHeadOld.execStr:
  4086. self.oldProfile = objHeadOld.execStr + title +\
  4087. objProfOld.getConfig().encode("UTF-8")
  4088. else:
  4089. self.oldProfile = title +\
  4090. objProfOld.getConfig().encode("UTF-8")
  4091. # Декодируем если кодировка не UTF-8
  4092. if flagNotUtf8New or flagNotUtf8Old:
  4093. self.newProfile = objTxtCoder.decode(self.newProfile)
  4094. self.oldProfile = objTxtCoder.decode(self.oldProfile)
  4095. self.saveOldFile()
  4096. return filesApply
  4097. else:
  4098. self.setError (_("False (type append) profile: " ) +\
  4099. objHeadNew.typeAppend)
  4100. return False
  4101. else:
  4102. self.setError (_("Type profile not found: ") + newFile)
  4103. return False
  4104. return filesApply
  4105. class samba(objShare):
  4106. """Класс для обработки конфигурационного файла типа samba
  4107. """
  4108. _comment = "#"
  4109. configName = "samba"
  4110. configVersion = "0.1"
  4111. reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M)
  4112. reBody = re.compile(".+",re.M|re.S)
  4113. reComment = re.compile("\s*%s.*|\s*;.*"%(_comment))
  4114. reSeparator = re.compile("\s*=\s*")
  4115. sepFields = "\n"
  4116. reSepFields = re.compile(sepFields)
  4117. def __init__(self,text):
  4118. self.text = text
  4119. self.blocTextObj = blocText()
  4120. self._splitToFields = self.splitToFields
  4121. # Объект документ
  4122. self.docObj = self._textToXML()
  4123. # XML документ
  4124. self.doc = self.docObj.doc
  4125. def postXML(self):
  4126. """Последующая постобработка XML"""
  4127. # Для добавления перевода строки между областями если его нет
  4128. #print self.docObj.body.toprettyxml()
  4129. xmlAreas = xpath.Evaluate("child::area", self.docObj.body)
  4130. for xmlArea in xmlAreas:
  4131. if xmlArea.previousSibling and\
  4132. self.docObj.getTypeField(xmlArea.previousSibling) == "br":
  4133. continue
  4134. firstArea = False
  4135. xmlFields = xpath.Evaluate("child::field", xmlArea)
  4136. if not (xmlFields and\
  4137. (self.docObj.getTypeField(xmlFields[-1]) == "br" or\
  4138. self.docObj.getTypeField(xmlFields[-1]) == "comment")):
  4139. if xmlArea.nextSibling:
  4140. parentNode = xmlArea.parentNode
  4141. nextNode = xmlArea.nextSibling
  4142. parentNode.insertBefore(self.docObj.createField("br",
  4143. [],"",[],
  4144. False,False),
  4145. nextNode)
  4146. # Удаление лишних переводов строк
  4147. childNodes = self.docObj.getFieldsArea(self.docObj.body)
  4148. lenBr = 0
  4149. removeBrNodes = []
  4150. for node in childNodes:
  4151. if node.tagName == "field" and\
  4152. self.docObj.getTypeField(node) == "br":
  4153. lenBr += 1
  4154. if lenBr > 2:
  4155. removeBrNodes.append(node)
  4156. else:
  4157. lenBr = 0
  4158. # Удаление
  4159. for rmNode in removeBrNodes:
  4160. self.docObj.body.removeChild(rmNode)
  4161. def join(self, sambaObj):
  4162. """Объединяем конфигурации"""
  4163. if isinstance(sambaObj, samba):
  4164. self.docObj.joinDoc(sambaObj.doc)
  4165. self.postXML()
  4166. def setDataField(self, txtLines, endtxtLines):
  4167. """Создаем список объектов с переменными"""
  4168. class fieldData:
  4169. def __init__(self):
  4170. self.name = False
  4171. self.value = False
  4172. self.comment = False
  4173. self.br = False
  4174. fields = []
  4175. field = fieldData()
  4176. z = 0
  4177. for k in txtLines:
  4178. textLine = k + endtxtLines[z]
  4179. z += 1
  4180. findComment = self.reComment.search(textLine)
  4181. if not textLine.strip():
  4182. field.br = textLine
  4183. fields.append(field)
  4184. field = fieldData()
  4185. elif findComment:
  4186. field.comment = textLine
  4187. fields.append(field)
  4188. field = fieldData()
  4189. else:
  4190. pars = textLine.strip()
  4191. nameValue = self.reSeparator.split(pars)
  4192. if len(nameValue) > 2:
  4193. valueList = nameValue[1:]
  4194. nameValue =[nameValue[0],"=".join(valueList)]
  4195. if len(nameValue) == 2:
  4196. name = nameValue[0]
  4197. value = nameValue[1].replace(self.sepFields,"")
  4198. field.name = name.replace(" ","").replace("\t","")
  4199. field.value = value
  4200. field.br = textLine
  4201. fields.append(field)
  4202. field = fieldData()
  4203. return fields
  4204. def splitCleanBloc(self, txtBloc):
  4205. """Делим блок на две части (переменные, пустые строки в конце)"""
  4206. txtLines = txtBloc.split("\n")
  4207. firstBloc = []
  4208. nextBloc = []
  4209. txtLines.reverse()
  4210. z = 0
  4211. for txtLine in txtLines:
  4212. if not txtLine.strip():
  4213. nextBloc.append(txtLine)
  4214. else:
  4215. break
  4216. z += 1
  4217. txtLines.reverse()
  4218. firstBloc = txtLines[:-z]
  4219. nextBloc.reverse()
  4220. if nextBloc:
  4221. firstBloc.append("")
  4222. if nextBloc and "\n".join(nextBloc):
  4223. return ("\n".join(firstBloc), "\n".join(nextBloc))
  4224. else:
  4225. return False
  4226. def getFullAreas(self, blocs):
  4227. """Делит текст на области, (Заголовок, тело)
  4228. Возвращает два списка: заголовки, тела
  4229. """
  4230. headsAreas = []
  4231. bodyAreas = []
  4232. if not blocs:
  4233. return []
  4234. lenBlocs = len(blocs[0])
  4235. for i in range(lenBlocs):
  4236. txtBloc = blocs[1][i]
  4237. clean = self.splitCleanBloc(txtBloc)
  4238. if clean:
  4239. headsAreas.append(blocs[0][i])
  4240. bodyAreas.append(clean[0])
  4241. headsAreas.append("")
  4242. bodyAreas.append(clean[1])
  4243. else:
  4244. headsAreas.append(blocs[0][i])
  4245. bodyAreas.append(blocs[1][i])
  4246. return (headsAreas, bodyAreas)
  4247. def createTxtConfig(self, strHeader, dictVar):
  4248. """Cоздает область с заголовком
  4249. создает текст конфигурационного файла в формате samba из
  4250. заголовка (строка) и словаря переменных
  4251. """
  4252. if not strHeader:
  4253. return ""
  4254. outTxt = "[" + strHeader + "]\n"
  4255. for key in dictVar.keys():
  4256. outTxt += "%s = %s\n" %(key,dictVar[key])
  4257. return outTxt
  4258. def _textToXML(self):
  4259. """Преобразует текст в XML"""
  4260. blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
  4261. blocs = self.getFullAreas(blTmp)
  4262. headers = []
  4263. startHeaders = []
  4264. finHeaders = []
  4265. docObj = xmlDoc()
  4266. docObj.createDoc(self.configName, self.configVersion)
  4267. rootNode = docObj.getNodeBody()
  4268. # Если пустой текст то создаем пустой документ
  4269. if not blocs:
  4270. return docObj
  4271. for h in blocs[0]:
  4272. listfinH = h.split("]")
  4273. finH = listfinH[0]
  4274. if "[" in finH:
  4275. startHeaders.append(finH + "]")
  4276. else:
  4277. startHeaders.append(finH)
  4278. if len(listfinH) == 2:
  4279. finHeaders.append(listfinH[1])
  4280. else:
  4281. finHeaders.append("")
  4282. headers.append(finH.replace("[","").replace("]","").strip())
  4283. bodys = blocs[1]
  4284. z = 0
  4285. for h in headers:
  4286. if not bodys[z]:
  4287. z += 1
  4288. continue
  4289. areaAction = False
  4290. if h:
  4291. if h[0] == "!":
  4292. docObj.createCaption(h[1:], [startHeaders[z],""])
  4293. areaAction = "drop"
  4294. elif h[0] == "-":
  4295. docObj.createCaption(h[1:], [startHeaders[z],""])
  4296. areaAction = "replace"
  4297. else:
  4298. docObj.createCaption(h, [startHeaders[z],""])
  4299. else:
  4300. docObj.createCaption(h, [startHeaders[z],""])
  4301. if "\n" in blocs[0][z]:
  4302. if self.reComment.search(finHeaders[z]):
  4303. docObj.createField('comment', [finHeaders[z]])
  4304. elif not finHeaders[z].strip() and\
  4305. finHeaders[z].replace("\n",""):
  4306. docObj.createField('br',
  4307. [finHeaders[z].replace("\n","")])
  4308. else:
  4309. docObj.createField('br')
  4310. fields = self._splitToFields(bodys[z])
  4311. for f in fields:
  4312. if f.name != False and f.value!=False and f.br!=False:
  4313. # Обработка условий для samba
  4314. if f.name[0] == "!" or f.name[0] == "-" or\
  4315. f.name[0] == "+":
  4316. qns = self.removeSymbolTerm(f.br)
  4317. xmlField = docObj.createField("var",
  4318. [qns],
  4319. f.name[1:], [f.value])
  4320. if f.name[0] == "!":
  4321. # Удаляемое в дальнейшем поле
  4322. docObj.setActionField(xmlField, "drop")
  4323. else:
  4324. docObj.createField("var",[f.br.replace("\n","")],
  4325. f.name, [f.value])
  4326. docObj.createField('br')
  4327. elif f.comment != False:
  4328. docObj.createField('comment', [f.comment])
  4329. elif f.br != False:
  4330. docObj.createField('br', [f.br.replace("\n","")])
  4331. if h.strip():
  4332. area = docObj.createArea()
  4333. if areaAction:
  4334. docObj.setActionArea(area, areaAction)
  4335. rootNode.appendChild(area)
  4336. else:
  4337. fieldsNodes = docObj.tmpFields.getFields()
  4338. for fieldNode in fieldsNodes:
  4339. rootNode.appendChild(fieldNode)
  4340. docObj.clearTmpFields()
  4341. z += 1
  4342. #print docObj.doc.toprettyxml()
  4343. return docObj
  4344. class compiz(samba):
  4345. """Класс для обработки конфигурационного файла типа compiz
  4346. """
  4347. _comment = "#"
  4348. configName = "compiz"
  4349. configVersion = "0.1"
  4350. reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M)
  4351. reBody = re.compile(".+",re.M|re.S)
  4352. reComment = re.compile("\s*%s.*"%(_comment))
  4353. reSeparator = re.compile("\s*=\s*")
  4354. sepFields = "\n"
  4355. reSepFields = re.compile(sepFields)
  4356. def __init__(self,text):
  4357. samba.__init__(self,text)
  4358. def join(self, compizObj):
  4359. """Объединяем конфигурации"""
  4360. if isinstance(compizObj, compiz):
  4361. self.docObj.joinDoc(compizObj.doc)
  4362. self.postXML()
  4363. class bind(objShare):
  4364. """Класс для обработки конфигурационного файла типа bind
  4365. """
  4366. _comment = "//"
  4367. configName = "bind"
  4368. configVersion = "0.1"
  4369. __openArea = "{"
  4370. __closeArea = "[ \t]*\}[ \t]*;[ \t]*"
  4371. sepFields = ";"
  4372. reOpen = re.compile(__openArea)
  4373. reClose = re.compile(__closeArea)
  4374. reCloseArea = re.compile(__closeArea + "\s*\Z")
  4375. reComment = re.compile("[ \t]+%s|^%s|(?<=;)%s"%(_comment,_comment,_comment))
  4376. reSepFields = re.compile(sepFields)
  4377. reSeparator = re.compile("[ \t]+")
  4378. def __init__(self,text):
  4379. self.text = text
  4380. self.blocTextObj = blocText()
  4381. # Объект документ
  4382. self.docObj = self.textToXML()
  4383. # Создаем поля-массивы
  4384. self.docObj.postParserList()
  4385. # XML документ
  4386. self.doc = self.docObj.doc
  4387. # Делим область на составные части
  4388. def findOpenClose(self, text, reOpen, reClose, reComment):
  4389. """Делит область на составные части
  4390. начальный текстовый блок,
  4391. открывающий блок,
  4392. блок-тело,
  4393. закрывающий блок
  4394. """
  4395. firstBloc = ""
  4396. startBloc = ""
  4397. bodyBloc = ""
  4398. endBloc = ""
  4399. textLines = text.splitlines()
  4400. findOpen = False
  4401. if textLines:
  4402. findOpen = reOpen.search(textLines[0])
  4403. openBl = reOpen.search(text)
  4404. if findOpen and reComment.split(text)[0].strip():
  4405. blocA = text[openBl.end():]
  4406. firstBloc = text[:openBl.start()]
  4407. startBloc = text[openBl.start():openBl.end()]
  4408. closeBl = reClose.search(blocA)
  4409. endBloc = blocA[closeBl.start():closeBl.end()]
  4410. bodyBloc = blocA[:closeBl.start()]
  4411. return (firstBloc, startBloc, bodyBloc, endBloc)
  4412. else:
  4413. return (firstBloc, startBloc, text, endBloc)
  4414. # Делим текст на области включая вложенные (areas массив областей)
  4415. def splitToAllArea(self, text, areas, reOpen, reClose, reCloseArea,
  4416. reComment, reSepFields):
  4417. """Делит текст на области включая вложенные
  4418. возвращает список объектов областей (переменная areas)
  4419. """
  4420. class area:
  4421. def __init__(self):
  4422. self.header = False
  4423. self.start = False
  4424. self.fields = []
  4425. self.end = False
  4426. blocs = self.blocTextObj.splitTxtToBloc(text,reOpen,reClose,
  4427. reComment,reSepFields)
  4428. for i in blocs:
  4429. areaA = area()
  4430. first,start,body,end = self.findOpenClose(i, reOpen, reCloseArea,
  4431. reComment)
  4432. areaA.header = first.replace(" ","").replace("\t","")
  4433. areaA.start = first + start
  4434. areaA.end = end
  4435. if areaA.end:
  4436. blocsA = self.blocTextObj.splitTxtToBloc(body,reOpen,reClose,
  4437. reComment,reSepFields)
  4438. if blocsA and blocsA[0] == body:
  4439. areaA.fields.append(body)
  4440. areas.append(areaA)
  4441. else:
  4442. for ar in blocsA:
  4443. self.splitToAllArea(ar, areaA.fields, reOpen,
  4444. reClose,
  4445. reCloseArea, reComment,
  4446. reSepFields)
  4447. areas.append(areaA)
  4448. else:
  4449. areaA.fields.append(body)
  4450. areas.append(areaA)
  4451. return areas
  4452. def setDataField(self, txtLines, endtxtLines):
  4453. """Создаем список объектов с переменными"""
  4454. class fieldData:
  4455. def __init__(self):
  4456. self.name = False
  4457. self.value = False
  4458. self.comment = False
  4459. self.br = False
  4460. fields = []
  4461. field = fieldData()
  4462. z = 0
  4463. for k in txtLines:
  4464. textLine = k + endtxtLines[z]
  4465. z += 1
  4466. findComment = self.reComment.search(textLine)
  4467. if not textLine.strip():
  4468. field.br = textLine
  4469. fields.append(field)
  4470. field = fieldData()
  4471. elif findComment:
  4472. field.comment = textLine
  4473. fields.append(field)
  4474. field = fieldData()
  4475. else:
  4476. pars = textLine.strip()
  4477. nameValue = self.reSeparator.split(pars)
  4478. if len (nameValue) == 1:
  4479. field.name = ""
  4480. field.value = textLine.replace(self.sepFields,"")
  4481. field.br = textLine
  4482. fields.append(field)
  4483. field = fieldData()
  4484. if len(nameValue) > 2:
  4485. valueList = nameValue[1:]
  4486. nameValue =[nameValue[0]," ".join(valueList).replace(\
  4487. self.sepFields,"")]
  4488. if len(nameValue) == 2:
  4489. name = nameValue[0]
  4490. value = nameValue[1].replace(self.sepFields,"")
  4491. field.name = name.replace(" ","").replace("\t","")
  4492. field.value = value
  4493. field.br = textLine
  4494. fields.append(field)
  4495. field = fieldData()
  4496. return fields
  4497. def createCaptionTerm(self, header, start, end, docObj):
  4498. """Создание пустой области с заголовком
  4499. при создании области проверяется первый символ заголовка
  4500. и добавляется тег action
  4501. "!" - <action>drop</action>
  4502. "-" - <action>replace</action>
  4503. """
  4504. areaAction = False
  4505. if header:
  4506. if header[0] == "!":
  4507. docObj.createCaption(header[1:], [start,
  4508. end.replace("\n","")])
  4509. areaAction = "drop"
  4510. elif header[0] == "-":
  4511. docObj.createCaption(header[1:], [start,
  4512. end.replace("\n","")])
  4513. areaAction = "replace"
  4514. else:
  4515. docObj.createCaption(header, [start,
  4516. end.replace("\n","")])
  4517. else:
  4518. docObj.createCaption(header, [start,
  4519. end.replace("\n","")])
  4520. areaXML = docObj.createArea()
  4521. if areaAction:
  4522. docObj.setActionArea(areaXML, areaAction)
  4523. return areaXML
  4524. def createXML(self, areas, rootNode, docObj):
  4525. """Создаем из массивов областей XML"""
  4526. for i in areas:
  4527. if str(i.__class__.__name__) == "area":
  4528. if i.header and i.start:
  4529. areaXML = self.createCaptionTerm(i.header, i.start,
  4530. i.end.replace("\n",""),
  4531. docObj)
  4532. else:
  4533. areaXML = rootNode
  4534. for f in i.fields:
  4535. if str(f.__class__.__name__) == "area":
  4536. if f.header and f.start:
  4537. areaXMLChild = self.createCaptionTerm(f.header,
  4538. f.start,
  4539. f.end.replace("\n",""),
  4540. docObj)
  4541. self.createXML(f.fields, areaXMLChild, docObj)
  4542. areaXML.appendChild(areaXMLChild)
  4543. else:
  4544. self.createXML(f.fields, areaXML, docObj)
  4545. if "\n" in f.end:
  4546. fieldXMLBr = docObj.createField("br",[],
  4547. "",[],
  4548. False, False)
  4549. areaXML.appendChild(fieldXMLBr)
  4550. else:
  4551. if not f:
  4552. continue
  4553. fields = self.splitToFields(f)
  4554. for field in fields:
  4555. if field.name != False:
  4556. fieldXML = self.createFieldTerm(field.name,
  4557. field.value,
  4558. field.br, docObj)
  4559. areaXML.appendChild(fieldXML)
  4560. if field.br[-1] == "\n":
  4561. fieldXMLBr = docObj.createField("br",[],
  4562. "",[],
  4563. False, False)
  4564. areaXML.appendChild(fieldXMLBr)
  4565. elif field.comment != False:
  4566. fieldXML = docObj.createField("comment",
  4567. [field.comment],
  4568. "", [],
  4569. False, False)
  4570. areaXML.appendChild(fieldXML)
  4571. elif field.br != False:
  4572. brText = field.br.replace("\n","")
  4573. if brText:
  4574. fieldXML = docObj.createField('br',
  4575. [brText],
  4576. "", [],
  4577. False, False)
  4578. else:
  4579. fieldXML = docObj.createField('br',
  4580. [],
  4581. "", [],
  4582. False, False)
  4583. areaXML.appendChild(fieldXML)
  4584. if i.header and i.start:
  4585. rootNode.appendChild(areaXML)
  4586. if "\n" in i.end:
  4587. fieldXMLBr = docObj.createField("br",[],
  4588. "",[],
  4589. False, False)
  4590. rootNode.appendChild(fieldXMLBr)
  4591. else:
  4592. fields = self.splitToFields(i)
  4593. for field in fields:
  4594. if field.name != False:
  4595. fieldXML = self.createFieldTerm(field.name,
  4596. field.value,
  4597. field.br, docObj)
  4598. rootNode.appendChild(fieldXML)
  4599. if field.br[-1] == "\n":
  4600. fieldXMLBr = docObj.createField("br",[],"", [],
  4601. False, False)
  4602. rootNode.appendChild(fieldXMLBr)
  4603. elif field.comment != False:
  4604. fieldXML = docObj.createField("comment",
  4605. [field.comment],
  4606. "", [],
  4607. False, False)
  4608. rootNode.appendChild(fieldXML)
  4609. elif field.br != False:
  4610. brText = field.br.replace("\n","")
  4611. if brText:
  4612. fieldXML = docObj.createField('br', [brText],"",[],
  4613. False, False)
  4614. else:
  4615. fieldXML = docObj.createField('br', [], "", [],
  4616. False, False)
  4617. rootNode.appendChild(fieldXML)
  4618. #rootNode.appendChild(areaXML)
  4619. def textToXML(self):
  4620. """Преобразуем текст в XML"""
  4621. areas = []
  4622. if self.text.strip():
  4623. self.splitToAllArea(self.text, areas, self.reOpen, self.reClose,
  4624. self.reCloseArea,self.reComment,self.reSepFields)
  4625. docObj = xmlDoc()
  4626. # Создание объекта документ c пустым разделителем между полями
  4627. docObj.createDoc(self.configName, self.configVersion)
  4628. if not areas:
  4629. return docObj
  4630. self.createXML(areas, docObj.getNodeBody(), docObj)
  4631. return docObj
  4632. def join(self, bindObj):
  4633. """Объединяем конфигурации"""
  4634. if isinstance(bindObj, bind):
  4635. self.docObj.joinDoc(bindObj.doc)
  4636. class apache(bind):
  4637. """Класс для обработки конфигурационного файла типа apache
  4638. """
  4639. _comment = "#"
  4640. configName = "apache"
  4641. configVersion = "0.1"
  4642. __headerArea = "[^\<\> \t]+[ \t]+[^\<\> \t]+"
  4643. __openArea = "[ \t]*\<%s\>"%(__headerArea)
  4644. __closeArea = "[ \t]*\<\/[^\<\>]+\>"
  4645. sepFields = "\n"
  4646. reOpen = re.compile(__openArea)
  4647. reClose = re.compile(__closeArea)
  4648. reCloseArea = re.compile(__closeArea + "\s*\Z")
  4649. reComment = re.compile("[ \t]*%s"%(_comment))
  4650. reSepFields = re.compile(sepFields)
  4651. reSeparator = re.compile("[ \t]+")
  4652. reHeader = re.compile(__headerArea)
  4653. def __init__(self,text):
  4654. self.text = text
  4655. self.blocTextObj = blocText()
  4656. # Объект документ
  4657. self.docObj = self.textToXML()
  4658. # Создаем поля-массивы
  4659. self.docObj.postParserList()
  4660. # Создаем поля разделенные массивы
  4661. self.docObj.postParserListSeplist(self.docObj.body)
  4662. # XML документ
  4663. self.doc = self.docObj.doc
  4664. def postXML(self):
  4665. """Последующая постобработка XML"""
  4666. # Для добавления перевода строки перед закрывающим тегом
  4667. # конфигурационного файла
  4668. xmlFields = xpath.Evaluate("child::fields", self.docObj.body)
  4669. if not (xmlFields and\
  4670. self.docObj.getTypeField(xmlFields[-1]) == "br"):
  4671. self.docObj.body.appendChild(self.docObj.createField("br",
  4672. [],"",[],
  4673. False,False))
  4674. xmlAreas = xpath.Evaluate("child::area", self.docObj.body)
  4675. for xmlArea in xmlAreas:
  4676. xmlFields = xpath.Evaluate("child::field", xmlArea)
  4677. if not (xmlFields and\
  4678. self.docObj.getTypeField(xmlFields[-1]) == "br"):
  4679. xmlArea.appendChild(self.docObj.createField("br",
  4680. [],"",[],
  4681. False,False))
  4682. def join(self, apacheObj):
  4683. """Объединяем конфигурации"""
  4684. if isinstance(apacheObj, apache):
  4685. #print self.docObj.doc.toprettyxml()
  4686. self.docObj.joinDoc(apacheObj.doc)
  4687. self.postXML()
  4688. # Делим область на составные части
  4689. def findOpenClose(self, text, reOpen, reClose, reComment, reHeader):
  4690. """Делит область на составные части
  4691. начальный текстовый блок,
  4692. открывающий блок,
  4693. блок-тело,
  4694. закрывающий блок
  4695. """
  4696. firstBloc = ""
  4697. startBloc = ""
  4698. bodyBloc = ""
  4699. endBloc = ""
  4700. textLines = text.splitlines()
  4701. findOpen = False
  4702. if textLines:
  4703. findOpen = reOpen.search(textLines[0])
  4704. openBl = reOpen.search(text)
  4705. if findOpen and reComment.split(text)[0].strip():
  4706. blocA = text[openBl.end():]
  4707. firstBloc = ""
  4708. startBloc = text[openBl.start():openBl.end()]
  4709. headBl = reHeader.search(startBloc)
  4710. if headBl:
  4711. firstBloc = headBl.group(0)
  4712. closeBl = reClose.search(blocA)
  4713. endBloc = blocA[closeBl.start():closeBl.end()]
  4714. bodyBloc = blocA[:closeBl.start()]
  4715. return (firstBloc, startBloc, bodyBloc, endBloc)
  4716. else:
  4717. return (firstBloc, startBloc, text, endBloc)
  4718. # Делим текст на области включая вложенные (areas массив областей)
  4719. def splitToAllArea(self, text, areas, reOpen, reClose, reCloseArea,
  4720. reComment, reSepFields, reHeader):
  4721. """Делит текст на области включая вложенные
  4722. возвращает список объектов областей (переменная areas)
  4723. """
  4724. class area:
  4725. def __init__(self):
  4726. self.header = False
  4727. self.start = False
  4728. self.fields = []
  4729. self.end = False
  4730. blocs = self.blocTextObj.splitTxtToBloc(text,reOpen,reClose,
  4731. reComment,reSepFields)
  4732. for i in blocs:
  4733. areaA = area()
  4734. first,start,body,end = self.findOpenClose(i, reOpen, reCloseArea,
  4735. reComment, reHeader)
  4736. areaA.header = first.replace(" ","").replace("\t","")
  4737. areaA.start = start
  4738. areaA.end = end
  4739. if areaA.end:
  4740. blocsA = self.blocTextObj.splitTxtToBloc(body,reOpen,reClose,
  4741. reComment,reSepFields)
  4742. if blocsA and blocsA[0] == body:
  4743. areaA.fields.append(body)
  4744. areas.append(areaA)
  4745. else:
  4746. for ar in blocsA:
  4747. self.splitToAllArea(ar, areaA.fields, reOpen,
  4748. reClose,
  4749. reCloseArea, reComment,
  4750. reSepFields, reHeader)
  4751. areas.append(areaA)
  4752. else:
  4753. areaA.fields.append(body)
  4754. areas.append(areaA)
  4755. def setDataField(self, txtLines, endtxtLines):
  4756. """Создаем список объектов с переменными"""
  4757. class fieldData:
  4758. def __init__(self):
  4759. self.name = False
  4760. self.value = False
  4761. self.comment = False
  4762. self.br = False
  4763. fields = []
  4764. field = fieldData()
  4765. z = 0
  4766. for k in txtLines:
  4767. textLine = k + endtxtLines[z]
  4768. #print "#"+brBloc[z]+"#"
  4769. z += 1
  4770. findComment = self.reComment.search(textLine)
  4771. if not textLine.strip():
  4772. field.br = textLine
  4773. fields.append(field)
  4774. field = fieldData()
  4775. elif findComment:
  4776. field.comment = textLine
  4777. fields.append(field)
  4778. field = fieldData()
  4779. else:
  4780. pars = textLine.strip()
  4781. nameValue = self.reSeparator.split(pars)
  4782. if len (nameValue) == 1:
  4783. field.name = ""
  4784. field.value = textLine.replace(self.sepFields,"")
  4785. field.br = textLine
  4786. fields.append(field)
  4787. field = fieldData()
  4788. if len(nameValue) == 3:
  4789. valueList = nameValue[2:]
  4790. nameValue =["".join(nameValue[:2])," ".join(valueList)]
  4791. if len(nameValue) > 3:
  4792. valueList = nameValue[1:]
  4793. nameValue =[nameValue[0]," ".join(valueList).replace(\
  4794. self.sepFields,"")]
  4795. if len(nameValue) == 2:
  4796. name = nameValue[0]
  4797. value = nameValue[1].replace(self.sepFields,"")
  4798. field.name = name.replace(" ","").replace("\t","")
  4799. field.value = value
  4800. field.br = textLine
  4801. fields.append(field)
  4802. field = fieldData()
  4803. return fields
  4804. def textToXML(self):
  4805. """Преобразуем тект в XML"""
  4806. areas = []
  4807. self.splitToAllArea(self.text, areas, self.reOpen, self.reClose,
  4808. self.reCloseArea,self.reComment,self.reSepFields,
  4809. self.reHeader)
  4810. docObj = xmlDoc()
  4811. # Создание объекта документ c пустым разделителем между полями
  4812. docObj.createDoc(self.configName, self.configVersion)
  4813. if not areas:
  4814. return docObj
  4815. self.createXML(areas, docObj.getNodeBody(), docObj)
  4816. return docObj
  4817. class postfix(apache):
  4818. """Класс для обработки конфигурационного файла типа postfix
  4819. """
  4820. _comment = "#"
  4821. configName = "postfix"
  4822. configVersion = "0.1"
  4823. sepFields = "\n"
  4824. reComment = re.compile("[ \t]*%s"%(_comment))
  4825. reSepFields = re.compile(sepFields)
  4826. # разделитель названия и значения переменной
  4827. reSeparator = re.compile("\s*=\s*")
  4828. def __init__(self,text):
  4829. self.text = text
  4830. # Объект документ
  4831. self.docObj = self.textToXML()
  4832. # Создаем поля разделенные массивы
  4833. self.docObj.postParserListSeplist(self.docObj.body)
  4834. # XML документ
  4835. self.doc = self.docObj.doc
  4836. def join(self, postfixObj):
  4837. """Объединяем конфигурации"""
  4838. if isinstance(postfixObj, postfix):
  4839. self.docObj.joinDoc(postfixObj.doc)
  4840. def textToXML(self):
  4841. """Преобразуем текст в XML"""
  4842. class area:
  4843. def __init__(self):
  4844. self.header = False
  4845. self.start = False
  4846. self.fields = []
  4847. self.end = False
  4848. areas = []
  4849. oneArea = area()
  4850. oneArea.header = ""
  4851. oneArea.start = ""
  4852. oneArea.fields = [self.text]
  4853. oneArea.end = ""
  4854. areas.append(oneArea)
  4855. docObj = xmlDoc()
  4856. # Создание объекта документ c пустым разделителем между полями
  4857. docObj.createDoc(self.configName, self.configVersion)
  4858. if not areas:
  4859. return docObj
  4860. self.createXML(areas, docObj.getNodeBody(), docObj)
  4861. return docObj
  4862. def setDataField(self, txtLines, endtxtLines):
  4863. """Cоздаем список объектов с переменными"""
  4864. class fieldData:
  4865. def __init__(self):
  4866. self.name = False
  4867. self.value = False
  4868. self.comment = False
  4869. self.br = False
  4870. fields = []
  4871. field = fieldData()
  4872. z = 0
  4873. for k in txtLines:
  4874. textLine = k + endtxtLines[z]
  4875. #print "#"+brBloc[z]+"#"
  4876. z += 1
  4877. findComment = self.reComment.search(textLine)
  4878. if not textLine.strip():
  4879. field.br = textLine
  4880. fields.append(field)
  4881. field = fieldData()
  4882. elif findComment:
  4883. field.comment = textLine
  4884. fields.append(field)
  4885. field = fieldData()
  4886. else:
  4887. pars = textLine.strip()
  4888. nameValue = self.reSeparator.split(pars)
  4889. if len (nameValue) == 1:
  4890. field.name = ""
  4891. field.value = textLine.replace(self.sepFields,"")
  4892. field.br = textLine
  4893. fields.append(field)
  4894. field = fieldData()
  4895. if len(nameValue) > 2:
  4896. valueList = nameValue[1:]
  4897. nameValue =[nameValue[0],"=".join(valueList).replace(\
  4898. self.sepFields,"")]
  4899. if len(nameValue) == 2:
  4900. name = nameValue[0]
  4901. value = nameValue[1].replace(self.sepFields,"")
  4902. field.name = name.replace(" ","").replace("\t","")
  4903. field.value = value
  4904. field.br = textLine
  4905. fields.append(field)
  4906. field = fieldData()
  4907. return fields
  4908. class ldap(samba):
  4909. """Класс для обработки конфигурационного файла типа ldap
  4910. """
  4911. _comment = "#"
  4912. configName = "ldap"
  4913. configVersion = "0.1"
  4914. # Регулярное выражение для заголовка области
  4915. reHeader = re.compile("^[\t ]*(access|syncrepl)[^\n]+\n?")
  4916. # Регулярное выражения для области
  4917. reArea = re.compile("([\t ]*(access|syncrepl)[^\n]+\
  4918. \n([\t ]+[^\n]+\n?)+)",re.M|re.S)
  4919. reComment = re.compile("\s*%s.*"%(_comment))
  4920. # разделитель между переменной и значением переменной
  4921. reSeparator = re.compile("\s+|\s*=\s*")
  4922. # разделитель полей
  4923. sepFields = "\n"
  4924. # регулярное выражение для разделителя полей
  4925. reSepFields = re.compile(sepFields)
  4926. def __init__(self,text):
  4927. self.text = text
  4928. self.blocTextObj = blocText()
  4929. self._splitToFields = self.splitToFields
  4930. # Объект документ
  4931. self.docObj = self._textToXML()
  4932. # Создаем поля-массивы
  4933. self.docObj.postParserList()
  4934. # Создаем поля разделенные массивы
  4935. self.docObj.postParserListSeplist(self.docObj.body)
  4936. # XML документ
  4937. self.doc = self.docObj.doc
  4938. def join(self, ldapObj):
  4939. """Объединяем конфигурации"""
  4940. if isinstance(ldapObj, ldap):
  4941. self.docObj.joinDoc(ldapObj.doc)
  4942. def setDataField(self, txtLines, endtxtLines):
  4943. """Создаем список объектов с переменными"""
  4944. class fieldData:
  4945. def __init__(self):
  4946. self.name = False
  4947. self.value = False
  4948. self.comment = False
  4949. self.br = False
  4950. fields = []
  4951. field = fieldData()
  4952. z = 0
  4953. for k in txtLines:
  4954. textLine = k + endtxtLines[z]
  4955. z += 1
  4956. findComment = self.reComment.search(textLine)
  4957. if not textLine.strip():
  4958. field.br = textLine
  4959. fields.append(field)
  4960. field = fieldData()
  4961. elif findComment:
  4962. field.comment = textLine
  4963. fields.append(field)
  4964. field = fieldData()
  4965. else:
  4966. pars = textLine.strip()
  4967. nameValue = self.reSeparator.split(pars)
  4968. if len(nameValue) > 2:
  4969. valueList = nameValue[2:]
  4970. nameValue =[nameValue[0]+nameValue[1]," ".join(valueList)]
  4971. if len(nameValue) == 2:
  4972. name = nameValue[0]
  4973. value = nameValue[1].replace(self.sepFields,"")
  4974. field.name = name.replace(" ","").replace("\t","")
  4975. field.value = value
  4976. field.br = textLine
  4977. fields.append(field)
  4978. field = fieldData()
  4979. return fields
  4980. def _textToXML(self):
  4981. """Преобразует текст в XML"""
  4982. blTmp = self.blocTextObj.findArea(self.text,self.reHeader,self.reArea)
  4983. blocs = self.getFullAreas(blTmp)
  4984. headers = []
  4985. startHeaders = []
  4986. finHeaders = []
  4987. docObj = xmlDoc()
  4988. docObj.createDoc(self.configName, self.configVersion)
  4989. rootNode = docObj.getNodeBody()
  4990. # Если пустой текст то создаем пустой документ
  4991. if not blocs:
  4992. return docObj
  4993. for h in blocs[0]:
  4994. headers.append(h.rstrip())
  4995. bodys = blocs[1]
  4996. z = 0
  4997. for h in headers:
  4998. if not bodys[z]:
  4999. z += 1
  5000. continue
  5001. areaAction = False
  5002. if h:
  5003. if h[0] == "!":
  5004. header = self.removeSymbolTerm(h.strip())
  5005. headerQuote = self.removeSymbolTerm(h)
  5006. docObj.createCaption(header,[headerQuote,""])
  5007. areaAction = "drop"
  5008. elif h[0] == "-":
  5009. header = self.removeSymbolTerm(h.strip())
  5010. headerQuote = self.removeSymbolTerm(h)
  5011. docObj.createCaption(header,[headerQuote,""])
  5012. areaAction = "replace"
  5013. else:
  5014. docObj.createCaption(h.strip(), [h.rstrip(),""])
  5015. else:
  5016. docObj.createCaption(h.strip(), [h.rstrip(),""])
  5017. if "\n" in blocs[0][z]:
  5018. resHead = self.reComment.search(h)
  5019. if resHead:
  5020. docObj.createField('comment',
  5021. blocs[0][z][resHead.start():])
  5022. else:
  5023. docObj.createField('br')
  5024. fields = self._splitToFields(bodys[z])
  5025. for f in fields:
  5026. if f.name != False and f.value!=False and f.br!=False:
  5027. # Обработка условий для samba
  5028. if f.name[0] == "!" or f.name[0] == "-" or\
  5029. f.name[0] == "+":
  5030. qns = self.removeSymbolTerm(f.br)
  5031. xmlField = docObj.createField("var",
  5032. [qns],
  5033. f.name[1:], [f.value])
  5034. if f.name[0] == "!":
  5035. # Удаляемое в дальнейшем поле
  5036. docObj.setActionField(xmlField, "drop")
  5037. elif f.name[0] == "+":
  5038. # Добавляем уникальное поле
  5039. xmlField.setAttribute("type", "seplist")
  5040. docObj.setActionField(xmlField, "join")
  5041. else:
  5042. docObj.createField("var",[f.br.replace("\n","")],
  5043. f.name, [f.value])
  5044. docObj.createField('br')
  5045. elif f.comment != False:
  5046. docObj.createField('comment', [f.comment])
  5047. elif f.br != False:
  5048. docObj.createField('br', [f.br.replace("\n","")])
  5049. if h.strip():
  5050. area = docObj.createArea()
  5051. if areaAction:
  5052. docObj.setActionArea(area, areaAction)
  5053. rootNode.appendChild(area)
  5054. else:
  5055. fieldsNodes = docObj.tmpFields.getFields()
  5056. for fieldNode in fieldsNodes:
  5057. rootNode.appendChild(fieldNode)
  5058. docObj.clearTmpFields()
  5059. z += 1
  5060. #print docObj.doc.toprettyxml()
  5061. return docObj
  5062. class dovecot(bind):
  5063. """Класс для обработки конфигурационного файла типа dovecot
  5064. """
  5065. _comment = "#"
  5066. configName = "dovecot"
  5067. configVersion = "0.1"
  5068. __openArea = "{"
  5069. __closeArea = "[ \t]*\}[ \t]*"
  5070. sepFields = "\n"
  5071. reOpen = re.compile(__openArea)
  5072. reClose = re.compile(__closeArea)
  5073. reCloseArea = re.compile(__closeArea + "\s*\Z")
  5074. reComment = re.compile("[ \t]*%s" %(_comment))
  5075. reSepFields = re.compile(sepFields)
  5076. # разделитель названия и значения переменной
  5077. reSeparator = re.compile("\s*=\s*")
  5078. def __init__(self, text):
  5079. bind.__init__(self,text)
  5080. def postXML(self, xmlArea=False):
  5081. """Последующая постобработка XML"""
  5082. # Добавляем перевод строки если его нет в конец области
  5083. if not xmlArea:
  5084. xmlArea = self.docObj.body
  5085. xmlFields = xpath.Evaluate("child::field", xmlArea)
  5086. if xmlFields and not (\
  5087. self.docObj.getTypeField(xmlFields[-1]) == "br" or\
  5088. self.docObj.getTypeField(xmlFields[-1]) == "comment"):
  5089. xmlArea.appendChild(self.docObj.createField("br",
  5090. [],"",[],
  5091. False,False))
  5092. xmlAreas = xpath.Evaluate("child::area", xmlArea)
  5093. for area in xmlAreas:
  5094. self.postXML(area)
  5095. def join(self, dovecotObj):
  5096. """Объединяем конфигурации"""
  5097. if isinstance(dovecotObj, dovecot):
  5098. #print self.docObj.doc.toprettyxml()
  5099. self.docObj.joinDoc(dovecotObj.doc)
  5100. # Для добавления перевода строки перед закрывающим тегом
  5101. # конфигурационного файла
  5102. self.postXML()
  5103. def setDataField(self, txtLines, endtxtLines):
  5104. """Создаем список объектов с переменными"""
  5105. class fieldData:
  5106. def __init__(self):
  5107. self.name = False
  5108. self.value = False
  5109. self.comment = False
  5110. self.br = False
  5111. fields = []
  5112. field = fieldData()
  5113. z = 0
  5114. for k in txtLines:
  5115. textLine = k + endtxtLines[z]
  5116. z += 1
  5117. findComment = self.reComment.search(textLine)
  5118. if not textLine.strip():
  5119. field.br = textLine
  5120. fields.append(field)
  5121. field = fieldData()
  5122. elif findComment:
  5123. field.comment = textLine
  5124. fields.append(field)
  5125. field = fieldData()
  5126. else:
  5127. pars = textLine.strip()
  5128. nameValue = self.reSeparator.split(pars)
  5129. if len (nameValue) == 1 and \
  5130. ( nameValue[0].startswith("!include") or
  5131. nameValue[0][1:].startswith("!include")):
  5132. field.name = textLine.replace(self.sepFields,"")
  5133. field.value = ""
  5134. field.br = textLine
  5135. fields.append(field)
  5136. field = fieldData()
  5137. elif len (nameValue) == 1:
  5138. field.name = ""
  5139. field.value = textLine.replace(self.sepFields,"")
  5140. field.br = textLine
  5141. fields.append(field)
  5142. field = fieldData()
  5143. elif len(nameValue) > 2:
  5144. valueList = nameValue[1:]
  5145. nameValue =[nameValue[0]," ".join(valueList).replace(\
  5146. self.sepFields,"")]
  5147. if len(nameValue) == 2:
  5148. name = nameValue[0]
  5149. value = nameValue[1].replace(self.sepFields,"")
  5150. field.name = name.replace(" ","").replace("\t","")
  5151. field.value = value
  5152. field.br = textLine
  5153. fields.append(field)
  5154. field = fieldData()
  5155. return fields
  5156. def createFieldTerm(self, name, value, quote, docObj):
  5157. """Создание поля переменная - значение
  5158. при создании поля проверяется первый символ названия переменной
  5159. и добавляется тег action
  5160. "!" - <action>drop</action> удаляет
  5161. "+" - <action>join</action> добавляет
  5162. "-" - <action>replace</action> заменяет
  5163. """
  5164. fieldAction = False
  5165. if name:
  5166. if name.startswith("!include") or name[1:].startswith("!include"):
  5167. prefix = "!"
  5168. name = re.sub(r"(include)\s*(\S)",r"\1 \2",name[1:])
  5169. else:
  5170. prefix = ""
  5171. if name[0] == "!" or name[0] == "-" or name[0] == "+":
  5172. qnt = self.removeSymbolTerm(quote)
  5173. fieldXML = docObj.createField("var",[qnt],
  5174. prefix+name[1:], [value],
  5175. False, False)
  5176. if name[0] == "!":
  5177. fieldAction = "drop"
  5178. elif name[0] == "+":
  5179. fieldXML.setAttribute("type", "seplist")
  5180. fieldAction = "join"
  5181. else:
  5182. fieldXML = docObj.createField("var",
  5183. [quote.replace("\n","")],
  5184. prefix+name, [value],
  5185. False, False)
  5186. else:
  5187. fieldXML = docObj.createField("var",
  5188. [quote.replace("\n","")],
  5189. name, [value],
  5190. False, False)
  5191. if fieldAction:
  5192. docObj.setActionField(fieldXML, fieldAction)
  5193. return fieldXML
  5194. class procmail(objShare):
  5195. """Класс для обработки конфигурационного файла типа procmail
  5196. """
  5197. _comment = "#"
  5198. configName = "procmail"
  5199. configVersion = "0.1"
  5200. sepFields = "\n"
  5201. reComment = re.compile("[ \t]*%s" %(_comment))
  5202. reSepFields = re.compile(sepFields)
  5203. # разделитель названия и значения переменной
  5204. reSeparator = re.compile("=")
  5205. def __init__(self, text):
  5206. self.text = text
  5207. self.docObj = self.textToXML()
  5208. self.doc = self.docObj.doc
  5209. def setDataField(self, txtLines, endtxtLines):
  5210. """Создаем список объектов с переменными"""
  5211. class fieldData:
  5212. def __init__(self):
  5213. self.name = False
  5214. self.value = False
  5215. self.comment = False
  5216. self.br = False
  5217. fields = []
  5218. field = fieldData()
  5219. z = 0
  5220. for k in txtLines:
  5221. textLine = k + endtxtLines[z]
  5222. z += 1
  5223. findComment = self.reComment.search(textLine)
  5224. if not textLine.strip():
  5225. field.br = textLine
  5226. fields.append(field)
  5227. field = fieldData()
  5228. elif findComment:
  5229. field.comment = textLine
  5230. fields.append(field)
  5231. field = fieldData()
  5232. else:
  5233. pars = textLine.strip()
  5234. nameValue = self.reSeparator.split(pars)
  5235. if len(nameValue) == 2:
  5236. name = nameValue[0]
  5237. value = nameValue[1].replace(self.sepFields,"")
  5238. field.name = name.replace(" ","").replace("\t","")
  5239. field.value = value
  5240. field.br = textLine
  5241. fields.append(field)
  5242. field = fieldData()
  5243. return fields
  5244. def textToXML(self):
  5245. docObj = xmlDoc()
  5246. docObj.createDoc(self.configName, self.configVersion)
  5247. if self.text:
  5248. nodeBody = docObj.getNodeBody()
  5249. fields = self.splitToFields(self.text)
  5250. for field in fields:
  5251. if field.name != False:
  5252. fieldXML = self.createFieldTerm(field.name,
  5253. field.value,
  5254. field.br, docObj)
  5255. nodeBody.appendChild(fieldXML)
  5256. if field.br[-1] == "\n":
  5257. fieldXMLBr = docObj.createField("br",[],
  5258. "",[],
  5259. False, False)
  5260. nodeBody.appendChild(fieldXMLBr)
  5261. elif field.comment != False:
  5262. fieldXML = docObj.createField("comment",
  5263. [field.comment],
  5264. "", [],
  5265. False, False)
  5266. nodeBody.appendChild(fieldXML)
  5267. elif field.br != False:
  5268. brText = field.br.replace("\n","")
  5269. if brText:
  5270. fieldXML = docObj.createField('br',
  5271. [brText],
  5272. "", [],
  5273. False, False)
  5274. else:
  5275. fieldXML = docObj.createField('br',
  5276. [],
  5277. "", [],
  5278. False, False)
  5279. nodeBody.appendChild(fieldXML)
  5280. return docObj
  5281. def join(self, procmailObj):
  5282. """Объединяем конфигурации"""
  5283. if isinstance(procmailObj, procmail):
  5284. #print self.docObj.doc.toprettyxml()
  5285. self.docObj.joinDoc(procmailObj.doc)
  5286. class kde(samba):
  5287. """Класс для обработки конфигурационного файла типа kde
  5288. """
  5289. _comment = "#"
  5290. configName = "kde"
  5291. configVersion = "0.1"
  5292. reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M)
  5293. reBody = re.compile(".+",re.M|re.S)
  5294. reComment = re.compile("^\s*%s.*"%(_comment))
  5295. reSeparator = re.compile("=")
  5296. sepFields = "\n"
  5297. reSepFields = re.compile(sepFields)
  5298. def __init__(self,text):
  5299. samba.__init__(self,text)
  5300. def _textToXML(self):
  5301. """Преобразует текст в XML"""
  5302. blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
  5303. blocs = self.getFullAreas(blTmp)
  5304. headers = []
  5305. startHeaders = []
  5306. finHeaders = []
  5307. docObj = xmlDoc()
  5308. docObj.createDoc(self.configName, self.configVersion)
  5309. rootNode = docObj.getNodeBody()
  5310. # Если пустой текст то создаем пустой документ
  5311. if not blocs:
  5312. return docObj
  5313. for h in blocs[0]:
  5314. reH = re.compile("]\s*$")
  5315. #listfinH = h.split("]")
  5316. listfinH = reH.split(h)
  5317. finH = listfinH[0]
  5318. if "[" in finH:
  5319. startHeaders.append(finH + "]")
  5320. else:
  5321. startHeaders.append(finH)
  5322. if len(listfinH) == 2:
  5323. finHeaders.append(listfinH[1])
  5324. else:
  5325. finHeaders.append("")
  5326. head=finH.replace("][",".").replace("[","").replace("]","").strip()
  5327. headers.append(head)
  5328. bodys = blocs[1]
  5329. z = 0
  5330. for h in headers:
  5331. if not bodys[z]:
  5332. z += 1
  5333. continue
  5334. areaAction = False
  5335. if h:
  5336. if h[0] == "!":
  5337. docObj.createCaption(h[1:], [startHeaders[z],""])
  5338. areaAction = "drop"
  5339. elif h[0] == "-":
  5340. docObj.createCaption(h[1:], [startHeaders[z],""])
  5341. areaAction = "replace"
  5342. else:
  5343. docObj.createCaption(h, [startHeaders[z],""])
  5344. else:
  5345. docObj.createCaption(h, [startHeaders[z],""])
  5346. if "\n" in blocs[0][z]:
  5347. if self.reComment.search(finHeaders[z]):
  5348. docObj.createField('comment', [finHeaders[z]])
  5349. elif not finHeaders[z].strip() and\
  5350. finHeaders[z].replace("\n",""):
  5351. docObj.createField('br',
  5352. [finHeaders[z].replace("\n","")])
  5353. else:
  5354. docObj.createField('br')
  5355. fields = self._splitToFields(bodys[z])
  5356. for f in fields:
  5357. if f.name != False and f.value!=False and f.br!=False:
  5358. # Обработка условий для samba
  5359. if f.name[0] == "!" or f.name[0] == "-" or\
  5360. f.name[0] == "+":
  5361. qns = self.removeSymbolTerm(f.br)
  5362. xmlField = docObj.createField("var",
  5363. [qns],
  5364. f.name[1:], [f.value])
  5365. if f.name[0] == "!":
  5366. # Удаляемое в дальнейшем поле
  5367. docObj.setActionField(xmlField, "drop")
  5368. else:
  5369. docObj.createField("var",[f.br.replace("\n","")],
  5370. f.name, [f.value])
  5371. docObj.createField('br')
  5372. elif f.comment != False:
  5373. docObj.createField('comment', [f.comment])
  5374. elif f.br != False:
  5375. docObj.createField('br', [f.br.replace("\n","")])
  5376. if h.strip():
  5377. area = docObj.createArea()
  5378. if areaAction:
  5379. docObj.setActionArea(area, areaAction)
  5380. rootNode.appendChild(area)
  5381. else:
  5382. fieldsNodes = docObj.tmpFields.getFields()
  5383. for fieldNode in fieldsNodes:
  5384. rootNode.appendChild(fieldNode)
  5385. docObj.clearTmpFields()
  5386. z += 1
  5387. #print docObj.doc.toprettyxml()
  5388. return docObj
  5389. def join(self, kdeObj):
  5390. """Объединяем конфигурации"""
  5391. if isinstance(kdeObj, kde):
  5392. self.docObj.joinDoc(kdeObj.doc)
  5393. self.postXML()
  5394. class xmlDocPlasma:
  5395. """Класс для замены метода joinArea в xmlDoc для plasma"""
  5396. # заменяемый метод для xmlDoc
  5397. def joinArea(self, baseNode, xmlNewArea):
  5398. """Объединяет область c областью Body (xmlNewArea c baseNode)"""
  5399. def appendArea(baseNode, xmlNewArea):
  5400. fieldsRemove = xpath.Evaluate(\
  5401. "descendant::field[child::action='drop']", xmlNewArea)
  5402. for rmNode in fieldsRemove:
  5403. parentNode = rmNode.parentNode
  5404. parentNode.removeChild(rmNode)
  5405. captionAreasRemove = xpath.Evaluate(\
  5406. "descendant::area/child::caption[child::action='drop']",
  5407. xmlNewArea)
  5408. for rmNodeCapt in captionAreasRemove:
  5409. rmNode = rmNodeCapt.parentNode
  5410. parentNode = rmNode.parentNode
  5411. parentNode.removeChild(rmNode)
  5412. self.setActionArea(xmlNewArea, "append")
  5413. # Добавляем разделитель областей во вложенные области
  5414. areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
  5415. for areaNode in areaNodes:
  5416. self.setActionArea(areaNode,"append")
  5417. parentNode = areaNode.parentNode
  5418. parentNode.insertBefore(self.sepAreas.cloneNode(True),
  5419. areaNode)
  5420. baseNode.appendChild(xmlNewArea)
  5421. # Добавляем разделитель областей
  5422. baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)
  5423. nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
  5424. nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
  5425. if not nodesNames:
  5426. # Добавляем область
  5427. if nodesNewArea:
  5428. newAreaAction = self.getActionArea(xmlNewArea)
  5429. if not (newAreaAction == "drop"):
  5430. appendArea(baseNode, xmlNewArea)
  5431. return True
  5432. if not nodesNames or not nodesNewArea:
  5433. return False
  5434. nameArea = ""
  5435. if nodesNewArea[0].firstChild:
  5436. nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
  5437. flagFindArea = False
  5438. baseNodes = []
  5439. for oName in nodesNames:
  5440. newAreaAction = self.getActionArea(xmlNewArea)
  5441. oArea = oName.parentNode.parentNode
  5442. oNameTxt = ""
  5443. if oName.firstChild:
  5444. oNameTxt = oName.firstChild.nodeValue
  5445. if nameArea == oNameTxt:
  5446. flagFindArea = True
  5447. # При использовании удаления
  5448. if newAreaAction == "drop":
  5449. prevNode = oName.parentNode.parentNode.previousSibling
  5450. removePrevNodes = []
  5451. while (prevNode) and self.getTypeField(prevNode) == "br":
  5452. removePrevNodes.append(prevNode)
  5453. prevNode = prevNode.previousSibling
  5454. for removeNode in removePrevNodes:
  5455. baseNode.removeChild(removeNode)
  5456. baseNode.removeChild(oName.parentNode.parentNode)
  5457. continue
  5458. elif newAreaAction == "replace":
  5459. oldAreaNode = oName.parentNode.parentNode
  5460. newAreaCaption = xpath.Evaluate('child::caption',
  5461. xmlNewArea)[0]
  5462. oldAreaCaption = xpath.Evaluate('child::caption',
  5463. oldAreaNode)[0]
  5464. if newAreaCaption and oldAreaCaption:
  5465. xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
  5466. self.setActionArea(xmlNewArea,"replace")
  5467. baseNode.replaceChild(xmlNewArea,
  5468. oldAreaNode)
  5469. continue
  5470. baseNodes.append(oName.parentNode.parentNode)
  5471. # Заменяем QUOTE
  5472. oldAreaNode = oName.parentNode.parentNode
  5473. oldAreaQuote = xpath.Evaluate('child::caption/quote',
  5474. oldAreaNode)[0]
  5475. if oldAreaQuote and\
  5476. not oldAreaQuote.firstChild:
  5477. newAreaQuote = xpath.Evaluate('child::caption/quote',
  5478. xmlNewArea)[0]
  5479. oldAreaCaption = xpath.Evaluate('child::caption',
  5480. oldAreaNode)[0]
  5481. if newAreaQuote and oldAreaCaption:
  5482. oldAreaCaption.replaceChild(newAreaQuote, oldAreaQuote)
  5483. newFields = xpath.Evaluate('child::field',xmlNewArea)
  5484. joinNewFields = xpath.Evaluate(\
  5485. "child::field[child::action='join']"
  5486. ,xmlNewArea)
  5487. self.addNewFielsOldArea(newFields, joinNewFields, oArea)
  5488. if not flagFindArea:
  5489. # Добавляем область
  5490. if not (newAreaAction == "drop"):
  5491. appendArea(baseNode, xmlNewArea)
  5492. else:
  5493. tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
  5494. for na in tmpXmlNewAreas:
  5495. for bn in baseNodes:
  5496. self.joinArea(bn, na)
  5497. return True
  5498. class plasma(samba):
  5499. """Класс для обработки конфигурационного файла типа kde
  5500. """
  5501. _comment = "#"
  5502. configName = "plasma"
  5503. configVersion = "0.1"
  5504. reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M)
  5505. reBody = re.compile(".+",re.M|re.S)
  5506. reComment = re.compile("^\s*%s.*"%(_comment))
  5507. reSeparator = re.compile("=")
  5508. sepFields = "\n"
  5509. reSepFields = re.compile(sepFields)
  5510. def __init__(self,text):
  5511. samba.__init__(self,text)
  5512. # Делим текст на области включая вложенные (areas массив областей)
  5513. def splitToAllArea(self, text, areas):
  5514. """Делит текст на области включая вложенные
  5515. возвращает список объектов областей (переменная areas)
  5516. """
  5517. class area:
  5518. def __init__(self):
  5519. self.header = False
  5520. self.start = False
  5521. self.fields = []
  5522. self.end = False
  5523. def findPathArea(listPath, areaF):
  5524. """Ищет путь в области
  5525. areaF - объект area
  5526. listPath - cписок названий областей
  5527. """
  5528. ret = False
  5529. if not listPath:
  5530. return ret
  5531. flagList = False
  5532. if type(areaF) == types.ListType:
  5533. fields = areaF
  5534. flagList = True
  5535. else:
  5536. fields = areaF.fields
  5537. if areaF.header == listPath[0]:
  5538. ret = areaF
  5539. else:
  5540. return ret
  5541. for i in fields:
  5542. if str(i.__class__.__name__) == "area":
  5543. add = False
  5544. if not flagList:
  5545. add = listPath.pop(0)
  5546. if not listPath:
  5547. break
  5548. ret = False
  5549. if i.header == listPath[0]:
  5550. ret = findPathArea(listPath, i)
  5551. break
  5552. else:
  5553. if add:
  5554. listPath.insert(0,add)
  5555. if ret == areaF and len(listPath)>1:
  5556. ret = False
  5557. return ret
  5558. blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
  5559. blocs = self.getFullAreas(blTmp)
  5560. reH = re.compile("\[([^\[\]]+)\]")
  5561. # Список имен блоков
  5562. namesBlockList = []
  5563. # Временные поля
  5564. fieldsTmp = []
  5565. # Добавляем заголовки
  5566. z = 0
  5567. for h in blocs[0]:
  5568. if not h:
  5569. if blocs[1][z] == "":
  5570. fieldsTmp.append("")
  5571. #fieldsTmp.append("\n")
  5572. else:
  5573. fieldsTmp.append(blocs[1][z])
  5574. #print '"' + blocs[1][z] + '"'
  5575. z += 1
  5576. continue
  5577. #print '"' + blocs[1][z] + '"'
  5578. z += 1
  5579. slpNamesBlock = reH.split(h)
  5580. # Отступ слева для заголовка
  5581. indentionLeft = slpNamesBlock[0]
  5582. namesBlock = filter(lambda x: x.strip(), slpNamesBlock)
  5583. #namesBlock = map(lambda x: self.removeSymbolTerm(x), namesBlock)
  5584. findArea = findPathArea(copy.copy(namesBlock), areas)
  5585. namesBlockList.append(namesBlock)
  5586. if findArea:
  5587. if len(namesBlock) > 1:
  5588. namesBlockView = map(lambda x: self.removeSymbolTerm(x),
  5589. namesBlock)
  5590. else:
  5591. namesBlockView = namesBlock
  5592. findArea.start = indentionLeft + "[" + \
  5593. "][".join(namesBlockView) + "]"
  5594. else:
  5595. i = 0
  5596. lenNamesBlock = len(namesBlock)
  5597. namesBlockTmp = []
  5598. for nameB in namesBlock:
  5599. namesBlockTmp.append(nameB)
  5600. findArea = findPathArea(copy.copy(namesBlockTmp), areas)
  5601. i += 1
  5602. if not findArea:
  5603. areaNew = area()
  5604. areaNew.header = nameB
  5605. if lenNamesBlock == i:
  5606. if len(namesBlock) > 1:
  5607. namesBlockView = map(\
  5608. lambda x: self.removeSymbolTerm(x),
  5609. namesBlock)
  5610. else:
  5611. namesBlockView = namesBlock
  5612. areaNew.start = indentionLeft + "[" + \
  5613. "][".join(namesBlockView) + "]"
  5614. else:
  5615. areaNew.start = ""
  5616. areaNew.end = ""
  5617. if i == 1:
  5618. if lenNamesBlock == i:
  5619. areas += fieldsTmp
  5620. areas.append(areaNew)
  5621. findAreaPrev = areas[-1]
  5622. else:
  5623. if lenNamesBlock == i:
  5624. findAreaPrev.fields += fieldsTmp
  5625. findAreaPrev.fields.append(areaNew)
  5626. findAreaPrev = findAreaPrev.fields[-1]
  5627. else:
  5628. findAreaPrev = findArea
  5629. fieldsTmp = []
  5630. i = 0
  5631. delt = 0
  5632. # Добавляем тела
  5633. for body in blocs[1]:
  5634. #print "#" + body + "#"
  5635. #print
  5636. if not blocs[0][i]:
  5637. i += 1
  5638. delt +=1
  5639. continue
  5640. ## В случае последнего комментария не добавляем перевод строки
  5641. #if self.reComment.search(body.splitlines()[-1]):
  5642. body = "\n" + body
  5643. namesBlock = namesBlockList[i-delt]
  5644. findArea = findPathArea(copy.copy(namesBlock), areas)
  5645. if findArea:
  5646. #if findArea.fields:
  5647. #if type(findArea.fields[0]) == types.StringType:
  5648. #findArea.fields.pop(0)
  5649. findArea.fields.insert(0, body)
  5650. i += 1
  5651. #eee = 1
  5652. #def prAreas(ar, eee):
  5653. #for a in ar:
  5654. #if type(a) == types.StringType:
  5655. #print 'field', a
  5656. #else:
  5657. #print "--------------------"
  5658. #print "HEADER =", a.header
  5659. #print "START =", a.start
  5660. #print "FIELDS =", a.fields
  5661. #print "LEVEL", eee
  5662. #if type(a) != types.StringType:
  5663. #if a.fields:
  5664. #eee += 1
  5665. #prAreas(a.fields, eee)
  5666. #prAreas(areas, eee)
  5667. return areas
  5668. def createCaptionTerm(self, header, start, end, docObj):
  5669. """Создание пустой области с заголовком
  5670. при создании области проверяется первый символ заголовка
  5671. и добавляется тег action
  5672. "!" - <action>drop</action>
  5673. "-" - <action>replace</action>
  5674. """
  5675. areaAction = False
  5676. if header:
  5677. if header[0] == "!":
  5678. docObj.createCaption(header[1:], [start,
  5679. end.replace("\n","")])
  5680. areaAction = "drop"
  5681. elif header[0] == "-":
  5682. docObj.createCaption(header[1:], [start,
  5683. end.replace("\n","")])
  5684. areaAction = "replace"
  5685. else:
  5686. docObj.createCaption(header, [start,
  5687. end.replace("\n","")])
  5688. else:
  5689. docObj.createCaption(header, [start,
  5690. end.replace("\n","")])
  5691. areaXML = docObj.createArea()
  5692. if areaAction:
  5693. docObj.setActionArea(areaXML, areaAction)
  5694. return areaXML
  5695. def createXML(self, areas, rootNode, docObj):
  5696. """Создаем из массивов областей XML"""
  5697. for i in areas:
  5698. if str(i.__class__.__name__) == "area":
  5699. if i.header:
  5700. areaXML = self.createCaptionTerm(i.header, i.start,
  5701. i.end.replace("\n",""),
  5702. docObj)
  5703. for f in i.fields:
  5704. if str(f.__class__.__name__) == "area":
  5705. if f.header:
  5706. areaXMLChild = self.createCaptionTerm(f.header,
  5707. f.start,
  5708. f.end.replace("\n",""),
  5709. docObj)
  5710. self.createXML(f.fields, areaXMLChild, docObj)
  5711. areaXML.appendChild(areaXMLChild)
  5712. else:
  5713. self.createXML(f.fields, areaXML, docObj)
  5714. if "\n" in f.end:
  5715. fieldXMLBr = docObj.createField("br",[],
  5716. "",[],
  5717. False, False)
  5718. areaXML.appendChild(fieldXMLBr)
  5719. else:
  5720. if not f:
  5721. continue
  5722. fields = self.splitToFields(f)
  5723. for field in fields:
  5724. if field.name != False:
  5725. fieldXML = self.createFieldTerm(field.name,
  5726. field.value,
  5727. field.br, docObj)
  5728. areaXML.appendChild(fieldXML)
  5729. if field.br[-1] == "\n":
  5730. fieldXMLBr = docObj.createField("br",[],
  5731. "",[],
  5732. False, False)
  5733. areaXML.appendChild(fieldXMLBr)
  5734. elif field.comment != False:
  5735. fieldXML = docObj.createField("comment",
  5736. [field.comment],
  5737. "", [],
  5738. False, False)
  5739. areaXML.appendChild(fieldXML)
  5740. elif field.br != False:
  5741. brText = field.br.replace("\n","")
  5742. if brText:
  5743. fieldXML = docObj.createField('br',
  5744. [brText],
  5745. "", [],
  5746. False, False)
  5747. else:
  5748. fieldXML = docObj.createField('br',
  5749. [],
  5750. "", [],
  5751. False, False)
  5752. if areaXML:
  5753. areaXML.appendChild(fieldXML)
  5754. if i.header:
  5755. rootNode.appendChild(areaXML)
  5756. if "\n" in i.end:
  5757. fieldXMLBr = docObj.createField("br",[],
  5758. "",[],
  5759. False, False)
  5760. rootNode.appendChild(fieldXMLBr)
  5761. else:
  5762. if not i:
  5763. continue
  5764. fields = self.splitToFields(i)
  5765. for field in fields:
  5766. if field.name != False:
  5767. fieldXML = self.createFieldTerm(field.name,
  5768. field.value,
  5769. field.br, docObj)
  5770. rootNode.appendChild(fieldXML)
  5771. if field.br[-1] == "\n":
  5772. fieldXMLBr = docObj.createField("br",[],"", [],
  5773. False, False)
  5774. rootNode.appendChild(fieldXMLBr)
  5775. elif field.comment != False:
  5776. fieldXML = docObj.createField("comment",
  5777. [field.comment],
  5778. "", [],
  5779. False, False)
  5780. rootNode.appendChild(fieldXML)
  5781. elif field.br != False:
  5782. brText = field.br.replace("\n","")
  5783. if brText:
  5784. fieldXML = docObj.createField('br', [brText],"",[],
  5785. False, False)
  5786. else:
  5787. fieldXML = docObj.createField('br', [], "", [],
  5788. False, False)
  5789. rootNode.appendChild(fieldXML)
  5790. #rootNode.appendChild(areaXML)
  5791. def createTxtConfig(self, strHeader, dictVar):
  5792. """Cоздает область с заголовком
  5793. создает текст конфигурационного файла в формате samba из
  5794. заголовка (строка) и словаря переменных
  5795. """
  5796. if not strHeader:
  5797. return ""
  5798. if type(strHeader) in (tuple, list):
  5799. outTxt = "".join(map(lambda x: "["+x+"]",strHeader))
  5800. if not outTxt:
  5801. return ""
  5802. outTxt += "\n"
  5803. else:
  5804. outTxt = "[" + strHeader + "]\n"
  5805. for key in dictVar.keys():
  5806. outTxt += "%s=%s\n" %(key,dictVar[key])
  5807. return outTxt
  5808. def _textToXML(self):
  5809. """Преобразуем текст в XML"""
  5810. areas = []
  5811. if self.text.strip():
  5812. self.splitToAllArea(self.text, areas)
  5813. #docObj = xmlDoc()
  5814. # Создаем новый класс xmlDoc с измененным методом joinArea
  5815. newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{})
  5816. # Создаем экземпляр нового класса
  5817. docObj = newClass()
  5818. # Создание объекта документ c пустым разделителем между полями
  5819. docObj.createDoc(self.configName, self.configVersion)
  5820. if not areas:
  5821. return docObj
  5822. self.createXML(areas, docObj.getNodeBody(), docObj)
  5823. return docObj
  5824. def postXML(self):
  5825. """Последующая постобработка XML"""
  5826. # Для добавления перевода строки между областями если его нет
  5827. #print self.docObj.body.toprettyxml()
  5828. def getQuotesArea(xmlArea):
  5829. quotes = []
  5830. xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
  5831. for node in xmlQuotes:
  5832. if node.firstChild:
  5833. quotes.append(node.firstChild.nodeValue)
  5834. if len(quotes) == 0:
  5835. quotes.append("")
  5836. quotes.append("")
  5837. elif len(quotes) == 1:
  5838. quotes.append("")
  5839. return quotes
  5840. xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body)
  5841. #print "-------------------------------------------------------"
  5842. #print xmlAreas
  5843. #if xmlAreas:
  5844. #prXmlArea = xmlAreas[0]
  5845. for xmlArea in xmlAreas:
  5846. # Перед пустой областью и после нее удаляем переводы строк
  5847. if getQuotesArea(xmlArea) == ["",""]:
  5848. #areaTXT = xpath.Evaluate("child::caption/name", xmlArea)[0]
  5849. #print "CL_AREA", areaTXT.firstChild
  5850. if xmlArea.previousSibling and\
  5851. self.docObj.getTypeField(xmlArea.previousSibling) == "br":
  5852. parentNode = xmlArea.previousSibling.parentNode
  5853. if xmlArea.previousSibling.previousSibling and\
  5854. self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br":
  5855. parentNode.removeChild(\
  5856. xmlArea.previousSibling.previousSibling)
  5857. parentNode.removeChild(xmlArea.previousSibling)
  5858. if xmlArea.nextSibling and\
  5859. self.docObj.getTypeField(xmlArea.nextSibling) == "br":
  5860. parentNode = xmlArea.nextSibling.parentNode
  5861. if xmlArea.nextSibling.nextSibling and\
  5862. self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br":
  5863. parentNode.removeChild(xmlArea.nextSibling.nextSibling)
  5864. parentNode.removeChild(xmlArea.nextSibling)
  5865. continue
  5866. # Собираем поля в кучку
  5867. xmlChildAreas = xpath.Evaluate("child::area", xmlArea)
  5868. if xmlChildAreas:
  5869. childNodes = self.docObj.getFieldsArea(xmlArea)
  5870. firstChildArea = xmlChildAreas[0]
  5871. if firstChildArea.previousSibling and\
  5872. self.docObj.getTypeField(firstChildArea.previousSibling)=="br":
  5873. if firstChildArea.previousSibling.previousSibling:
  5874. if self.docObj.getTypeField(\
  5875. firstChildArea.previousSibling.previousSibling)=="br":
  5876. firstChildArea = firstChildArea.previousSibling
  5877. flagFoundArea = False
  5878. it = 0
  5879. lenChild = len(childNodes)
  5880. for node in childNodes:
  5881. it += 1
  5882. if node.tagName == "area":
  5883. flagFoundArea = True
  5884. continue
  5885. if flagFoundArea and node.tagName == "field":
  5886. if self.docObj.getTypeField(node) == "var":
  5887. xmlArea.insertBefore(node, firstChildArea)
  5888. if it < lenChild:
  5889. if self.docObj.getTypeField(childNodes[it])==\
  5890. "br":
  5891. xmlArea.insertBefore(childNodes[it],
  5892. firstChildArea)
  5893. # Добавление перевода строк в если его нет между полями
  5894. if self.docObj.getTypeField(node) == "var" and\
  5895. node.previousSibling and\
  5896. not (self.docObj.getTypeField(node.previousSibling) in\
  5897. ("br","comment")):
  5898. xmlArea.insertBefore(self.docObj.createField("br",
  5899. [],"",[],
  5900. False,False),
  5901. node)
  5902. # Добавляем BR если его нет первым полем
  5903. xmlFields = xpath.Evaluate("child::field", xmlArea)
  5904. if not (xmlFields and\
  5905. (self.docObj.getTypeField(xmlFields[0]) == "br" or\
  5906. self.docObj.getTypeField(xmlFields[0]) == "comment")):
  5907. if xmlFields:
  5908. xmlArea.insertBefore(self.docObj.createField("br",
  5909. [],"",[],
  5910. False,False),
  5911. xmlFields[0])
  5912. # Если последним полем BR, удаляем его
  5913. if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br":
  5914. #print "DEL_BR", xmlFields[-1].nextSibling
  5915. #and\
  5916. if not xmlFields[-1].nextSibling:
  5917. xmlArea.removeChild(xmlFields[-1])
  5918. # Если предыдущим полем не (BR или комментарий) - добавляем BR
  5919. if xmlArea.previousSibling and\
  5920. not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\
  5921. self.docObj.getTypeField(xmlArea.previousSibling) == "comment"):
  5922. parentNode = xmlArea.parentNode
  5923. parentNode.insertBefore(self.docObj.createField("br",
  5924. [],"",[],
  5925. False,False),
  5926. xmlArea)
  5927. # Если есть предыдущее поле, и поле предыдущеее предыдущему
  5928. # не равно BR или комментарий то добавляем BR
  5929. if xmlArea.previousSibling:
  5930. prPrSibling = xmlArea.previousSibling.previousSibling
  5931. if prPrSibling and\
  5932. not (self.docObj.getTypeField(prPrSibling) == "br" or\
  5933. self.docObj.getTypeField(prPrSibling) == "comment"):
  5934. parentNode = xmlArea.parentNode
  5935. parentNode.insertBefore(self.docObj.createField("br",
  5936. [],"",[],
  5937. False,False),
  5938. xmlArea)
  5939. # Если после есть BR а за ним ничего нет, удаляем BR
  5940. if xmlArea.nextSibling and\
  5941. self.docObj.getTypeField(xmlArea.nextSibling) == "br":
  5942. if not xmlArea.nextSibling.nextSibling:
  5943. parentNode = xmlArea.nextSibling.parentNode
  5944. parentNode.removeChild(xmlArea.nextSibling)
  5945. def join(self, kdeObj):
  5946. """Объединяем конфигурации"""
  5947. if isinstance(kdeObj, plasma):
  5948. self.docObj.joinDoc(kdeObj.doc)
  5949. self.postXML()
  5950. class xml_xfce(_error):
  5951. """Класс для объединения xfce-xml файлов"""
  5952. # root нода
  5953. rootNode = False
  5954. # body нода
  5955. bodyNode = False
  5956. # Документ
  5957. doc = False
  5958. # Текст профиля
  5959. text = ""
  5960. # Комментарий
  5961. _comment = ("<!--","-->")
  5962. def __init__(self, text):
  5963. self.text = text
  5964. # Создаем пустой объект
  5965. self.docObj = type("_empty_class", (object,), {})()
  5966. # Названия аттрибутов для пустого объекта
  5967. emptyMethods = ["getNodeBody","removeComment","insertBRtoBody",
  5968. "insertBeforeSepAreas"]
  5969. # Добавляем необходимые аттрибуты пустому объекту
  5970. for method in emptyMethods:
  5971. setattr(self.docObj, method, self.emptyMethod)
  5972. # Создаем XML документ
  5973. self.doc = self.textToXML()
  5974. def emptyMethod(self, *arg , **argv):
  5975. """Пустой метод"""
  5976. return True
  5977. def setNameBodyNode(self, name):
  5978. """Устанавливает название для корневой ноды документа"""
  5979. if not self.bodyNode:
  5980. return False
  5981. self.bodyNode.setAttribute("name", name)
  5982. return True
  5983. def textToXML(self):
  5984. """Создание из текста XML документа
  5985. Храним xml в своем формате
  5986. """
  5987. if not self.text.strip():
  5988. self.text = '''<?xml version="1.0" encoding="UTF-8"?>
  5989. <channel version="1.0">
  5990. </channel>'''
  5991. try:
  5992. self.doc = xml.dom.minidom.parseString(self.text)
  5993. except:
  5994. self.setError(_("Can not text profile is XML"))
  5995. return False
  5996. self.rootNode = self.doc.documentElement
  5997. self.bodyNode = self.rootNode
  5998. return self.doc
  5999. def join(self, xml_xfceObj):
  6000. """Объединяем конфигурации"""
  6001. if isinstance(xml_xfceObj, xml_xfce):
  6002. try:
  6003. self.joinDoc(xml_xfceObj.doc)
  6004. except:
  6005. self.setError(_("Can not join profile"))
  6006. return False
  6007. return True
  6008. def _removeDropNodesAndAttrAction(self, xmlNode):
  6009. """Удаляет ноды с аттрибутом action='drop'
  6010. Также удаляет аттрибут action у всех нод
  6011. """
  6012. flagError = False
  6013. childNodes = xmlNode.childNodes
  6014. if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
  6015. if xmlNode.hasAttribute("action"):
  6016. nAction = xmlNode.getAttribute("action")
  6017. if not nAction in ("join","replace","drop"):
  6018. textError = _('''In the text, XML profile, look \
  6019. for a reserved attribute 'action' with the incorrect value.\n\
  6020. Valid values attribute 'action': \
  6021. (action="join", action="replace", action="drop")''')
  6022. self.setError(textError)
  6023. return False
  6024. xmlNode.removeAttribute("action")
  6025. if nAction == "drop":
  6026. parentNode = xmlNode.parentNode
  6027. if parentNode:
  6028. parentNode.removeChild(xmlNode)
  6029. if childNodes:
  6030. for node in childNodes:
  6031. if not self._removeDropNodesAndAttrAction(node):
  6032. flagError = True
  6033. break
  6034. if flagError:
  6035. return False
  6036. return True
  6037. def postXML(self):
  6038. """Последующая постобработка XML"""
  6039. # Удаляем теги action и удаляемые ноды
  6040. self._removeDropNodesAndAttrAction(self.bodyNode)
  6041. def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True):
  6042. """Объединение корневой ноды профиля и корневой ноды файла"""
  6043. xmlNode = xmlNewNode
  6044. childNodes = xmlNode.childNodes
  6045. nextOldNode = xmlOldNode
  6046. flagError = False
  6047. if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
  6048. n = xmlNode
  6049. path = u''
  6050. nName = u''
  6051. nType = u''
  6052. nValue = u''
  6053. nAction = u''
  6054. attrName = ''
  6055. attrType = ''
  6056. path = n.tagName
  6057. if n.hasAttribute("name"):
  6058. nName = n.getAttribute("name")
  6059. attrName = u"attribute::name='%s'"%nName
  6060. if n.hasAttribute("type"):
  6061. nType = n.getAttribute("type")
  6062. attrType = u"attribute::type='%s'"%nType
  6063. if n.hasAttribute("value"):
  6064. nValue = n.getAttribute("value")
  6065. if n.hasAttribute("action"):
  6066. nAction = n.getAttribute("action")
  6067. if not nAction in ("join","replace","drop"):
  6068. textError = _('''In the text, XML profile, look \
  6069. for a reserved attribute 'action' with the incorrect value.\n\
  6070. Valid values attribute 'action': \
  6071. (action="join", action="replace", action="drop")''')
  6072. self.setError(textError)
  6073. return False
  6074. if xmlOldNode.parentNode:
  6075. strAttr = [attrName, attrType]
  6076. findAttr = filter(lambda x: x, strAttr)
  6077. findAttrStr = ''
  6078. if findAttr:
  6079. strAttr = u' and '.join(findAttr)
  6080. findAttrStr = "[%s]"%strAttr
  6081. findPath = u"child::%s%s"%(path,findAttrStr)
  6082. # Рабочая нода
  6083. if flagRootNode:
  6084. workNode = xmlOldNode.parentNode
  6085. else:
  6086. workNode = xmlOldNode
  6087. oldNodes = xpath.Evaluate(findPath, workNode)
  6088. #print findPath
  6089. #print workNode
  6090. #print "----------------------------"
  6091. # Новая нода список
  6092. flagArray = False
  6093. if nType == "array":
  6094. flagArray = True
  6095. flagDrop = False
  6096. flagJoin = True
  6097. flagReplace = False
  6098. if nAction == "replace":
  6099. flagJoin = False
  6100. flagReplace = True
  6101. elif nAction == "drop":
  6102. flagJoin = False
  6103. flagDrop = True
  6104. if flagRootNode:
  6105. textError = _('Incorrect action="drop" in root node')
  6106. self.setError(textError)
  6107. return False
  6108. if oldNodes:
  6109. if len(oldNodes)>1:
  6110. textError = _("The uncertainty in this profile are \
  6111. the same nodes at one level")
  6112. self.setError(textError)
  6113. return False
  6114. nextOldNode = oldNodes[0]
  6115. # Замещаем ноду в случае массива
  6116. if flagArray and not flagDrop:
  6117. replaceXmlNode = xmlNode.cloneNode(True)
  6118. if nAction:
  6119. replaceXmlNode.removeAttribute("action")
  6120. workNode.replaceChild(replaceXmlNode,
  6121. nextOldNode)
  6122. flagJoin = False
  6123. flagReplace = False
  6124. childNodes = False
  6125. # Объединение нод
  6126. if flagJoin:
  6127. if nextOldNode.hasAttribute("value"):
  6128. oValue = nextOldNode.getAttribute("value")
  6129. if nValue != oValue:
  6130. nextOldNode.setAttribute("value",nValue)
  6131. # Замещение ноды
  6132. elif flagReplace:
  6133. replaceXmlNode = xmlNode.cloneNode(True)
  6134. if not\
  6135. self._removeDropNodesAndAttrAction(replaceXmlNode):
  6136. return False
  6137. workNode.replaceChild(replaceXmlNode,
  6138. nextOldNode)
  6139. childNodes = False
  6140. # Удаление ноды
  6141. elif flagDrop:
  6142. workNode.removeChild(nextOldNode)
  6143. childNodes = False
  6144. else:
  6145. # Добавление ноды
  6146. childNodes = False
  6147. if not flagDrop:
  6148. appendXmlNode = xmlNode.cloneNode(True)
  6149. if not\
  6150. self._removeDropNodesAndAttrAction(appendXmlNode):
  6151. return False
  6152. workNode.appendChild(appendXmlNode)
  6153. if childNodes:
  6154. for node in childNodes:
  6155. if not self._join(node, nextOldNode, False):
  6156. flagError = True
  6157. break
  6158. if flagError:
  6159. return False
  6160. return True
  6161. def joinDoc(self, doc):
  6162. """Объединение документа профиля и документа файла"""
  6163. if not self.doc:
  6164. self.setError(_("Can not text file is XML"))
  6165. return False
  6166. if not doc:
  6167. self.setError(_("Can not text profile is XML"))
  6168. return False
  6169. # Импортируем корневую ноду нового документа в текущий документ
  6170. #newImportBodyNode = self.doc.importNode(doc.documentElement, True)
  6171. # Объединение корневой ноды профиля и корневой ноды файла
  6172. if not self._join(doc.documentElement, self.bodyNode):
  6173. return False
  6174. return True
  6175. def getConfig(self):
  6176. """Получение текстового файла из XML документа"""
  6177. data = self.doc.toprettyxml(encoding='UTF-8').split("\n")
  6178. data = filter(lambda x: x.strip(), data)
  6179. return "\n".join(data).replace("\t"," ").decode("UTF-8")
  6180. class squid(procmail):
  6181. """Класс для обработки конфигурационного файла типа squid
  6182. """
  6183. configName = "squid"
  6184. configVersion = "0.1"
  6185. # разделитель названия и значения переменной
  6186. reSeparator = re.compile(" ")
  6187. def __init__(self, text):
  6188. procmail.__init__(self, text)
  6189. # Создаем поля-массивы
  6190. self.docObj.postParserList()
  6191. # Создаем поля разделенные массивы
  6192. self.docObj.postParserListSeplist(self.docObj.body)
  6193. def setDataField(self, txtLines, endtxtLines):
  6194. """Создаем список объектов с переменными"""
  6195. class fieldData:
  6196. def __init__(self):
  6197. self.name = False
  6198. self.value = False
  6199. self.comment = False
  6200. self.br = False
  6201. fields = []
  6202. field = fieldData()
  6203. z = 0
  6204. for k in txtLines:
  6205. textLine = k + endtxtLines[z]
  6206. z += 1
  6207. findComment = self.reComment.search(textLine)
  6208. flagVariable = True
  6209. if not textLine.strip():
  6210. field.br = textLine
  6211. fields.append(field)
  6212. field = fieldData()
  6213. flagVariable = False
  6214. elif findComment:
  6215. if textLine[:findComment.start()].strip():
  6216. field.comment = textLine[findComment.start():]
  6217. textLine = textLine[:findComment.start()]
  6218. else:
  6219. field.comment = textLine
  6220. flagVariable = False
  6221. fields.append(field)
  6222. field = fieldData()
  6223. if flagVariable:
  6224. pars = textLine.strip()
  6225. nameValue = self.reSeparator.split(pars)
  6226. if len(nameValue) > 2:
  6227. valueList = nameValue[1:]
  6228. nameValue =[nameValue[0]," ".join(valueList)]
  6229. if len(nameValue) == 2:
  6230. name = nameValue[0]
  6231. value = nameValue[1].replace(self.sepFields,"")
  6232. field.name = name.replace(" ","").replace("\t","")
  6233. field.value = value
  6234. field.br = textLine
  6235. fields.append(field)
  6236. field = fieldData()
  6237. return fields
  6238. def join(self, squidObj):
  6239. """Объединяем конфигурации"""
  6240. if isinstance(squidObj, squid):
  6241. #print squidObj.getConfig()
  6242. self.docObj.joinDoc(squidObj.doc)
  6243. class xml_xfcepanel(xml_xfce):
  6244. """Класс для объединения xfce-panel файлов"""
  6245. def __init__(self, text):
  6246. xml_xfce.__init__(self, text)
  6247. self.panelNumbers = {}
  6248. def textToXML(self):
  6249. """Создание из текста XML документа
  6250. Храним xml в своем формате
  6251. """
  6252. if not self.text.strip():
  6253. self.text = '''<?xml version="1.0" encoding="UTF-8"?>
  6254. <!DOCTYPE config SYSTEM "config.dtd">
  6255. <panels>
  6256. </panels>'''
  6257. try:
  6258. self.doc = xml.dom.minidom.parseString(self.text)
  6259. except:
  6260. self.setError(_("Can not text profile is XML"))
  6261. return False
  6262. self.rootNode = self.doc.documentElement
  6263. self.bodyNode = self.rootNode
  6264. return self.doc
  6265. def setNameBodyNode(self, name):
  6266. """Пустой метод"""
  6267. return True
  6268. def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
  6269. """Объединение корневой ноды профиля и корневой ноды файла"""
  6270. xmlNode = xmlNewNode
  6271. childNodes = xmlNode.childNodes
  6272. nextOldNode = xmlOldNode
  6273. flagError = False
  6274. if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
  6275. n = xmlNode
  6276. path = u''
  6277. nName = u''
  6278. flagArray = False
  6279. nValue = u''
  6280. nAction = u''
  6281. attrName = ''
  6282. attrType = ''
  6283. path = n.tagName
  6284. if path == "items":
  6285. flagArray = True
  6286. if not flagArray:
  6287. if n.hasAttribute("name"):
  6288. nName = n.getAttribute("name")
  6289. attrName = u"attribute::name='%s'"%nName
  6290. if n.hasAttribute("value"):
  6291. nValue = n.getAttribute("value")
  6292. if n.hasAttribute("action"):
  6293. nAction = n.getAttribute("action")
  6294. if not nAction in ("join","replace","drop"):
  6295. textError = _('''In the text, XML profile, look \
  6296. for a reserved attribute 'action' with the incorrect value.\n\
  6297. Valid values attribute 'action': \
  6298. (action="join", action="replace", action="drop")''')
  6299. self.setError(textError)
  6300. return False
  6301. if xmlOldNode.parentNode:
  6302. findAttrStr = ""
  6303. if attrName:
  6304. findAttrStr = "[%s]"%attrName
  6305. findPath = u"child::%s%s"%(path,findAttrStr)
  6306. # Рабочая нода
  6307. if flagRootNode:
  6308. workNode = xmlOldNode.parentNode
  6309. else:
  6310. workNode = xmlOldNode
  6311. oldNodes = xpath.Evaluate(findPath, workNode)
  6312. flagDrop = False
  6313. flagJoin = True
  6314. flagReplace = False
  6315. flagAppend = False
  6316. if nAction == "replace":
  6317. flagJoin = False
  6318. flagReplace = True
  6319. elif nAction == "drop":
  6320. flagJoin = False
  6321. flagDrop = True
  6322. if flagRootNode:
  6323. textError = _('Incorrect action="drop" in root node')
  6324. self.setError(textError)
  6325. return False
  6326. if path == "panel":
  6327. flagJoin = False
  6328. if levelNumber in self.panelNumbers.keys():
  6329. self.panelNumbers[levelNumber] += 1
  6330. else:
  6331. self.panelNumbers[levelNumber] = 0
  6332. if oldNodes:
  6333. if len(oldNodes)>1 and path != "panel":
  6334. textError = _("The uncertainty in this profile are \
  6335. the same nodes at one level")
  6336. self.setError(textError)
  6337. return False
  6338. if path == "panel":
  6339. if len(oldNodes)<=self.panelNumbers[levelNumber]:
  6340. nextOldNode = oldNodes[-1]
  6341. # Добавляем ноду
  6342. if not flagDrop:
  6343. flagAppend = True
  6344. flagReplace = False
  6345. childNodes = False
  6346. else:
  6347. nextOldNode=oldNodes[self.panelNumbers[levelNumber]]
  6348. else:
  6349. nextOldNode = oldNodes[0]
  6350. # Замещаем ноду в случае массива
  6351. if flagArray and not flagDrop:
  6352. replaceXmlNode = xmlNode.cloneNode(True)
  6353. if nAction:
  6354. replaceXmlNode.removeAttribute("action")
  6355. workNode.replaceChild(replaceXmlNode,
  6356. nextOldNode)
  6357. flagJoin = False
  6358. flagReplace = False
  6359. childNodes = False
  6360. # Объединение нод
  6361. if flagJoin:
  6362. if nextOldNode.hasAttribute("value"):
  6363. oValue = nextOldNode.getAttribute("value")
  6364. if nValue != oValue:
  6365. nextOldNode.setAttribute("value",nValue)
  6366. # Замещение ноды
  6367. elif flagReplace:
  6368. replaceXmlNode = xmlNode.cloneNode(True)
  6369. if not\
  6370. self._removeDropNodesAndAttrAction(replaceXmlNode):
  6371. return False
  6372. workNode.replaceChild(replaceXmlNode,
  6373. nextOldNode)
  6374. childNodes = False
  6375. # Удаление ноды
  6376. elif flagDrop:
  6377. workNode.removeChild(nextOldNode)
  6378. childNodes = False
  6379. else:
  6380. flagAppend = True
  6381. flagDrop = False
  6382. if flagAppend and not flagDrop:
  6383. # Добавление ноды
  6384. childNodes = False
  6385. if not flagDrop:
  6386. appendXmlNode = xmlNode.cloneNode(True)
  6387. if not\
  6388. self._removeDropNodesAndAttrAction(appendXmlNode):
  6389. return False
  6390. workNode.appendChild(appendXmlNode)
  6391. if childNodes:
  6392. for node in childNodes:
  6393. levelNumber +=1
  6394. if not self._join(node, nextOldNode, False, levelNumber):
  6395. flagError = True
  6396. break
  6397. levelNumber -= 1
  6398. if flagError:
  6399. return False
  6400. return True
  6401. def join(self, xml_xfceObj):
  6402. """Объединяем конфигурации"""
  6403. if isinstance(xml_xfceObj, xml_xfcepanel):
  6404. try:
  6405. self.joinDoc(xml_xfceObj.doc)
  6406. except:
  6407. self.setError(_("Can not join profile"))
  6408. return False
  6409. return True
  6410. class dhcp(bind):
  6411. """Класс для обработки конфигурационного файла типа dhcp
  6412. """
  6413. _comment = "#"
  6414. configName = "dhcp"
  6415. configVersion = "0.1"
  6416. __openArea = "{"
  6417. __closeArea = "[ \t]*\}[ \t]*"
  6418. sepFields = ";"
  6419. reOpen = re.compile(__openArea)
  6420. reClose = re.compile(__closeArea)
  6421. reCloseArea = re.compile(__closeArea + "\s*\Z")
  6422. reComment = re.compile("^[ \t]*%s"%(_comment))
  6423. reSepFields = re.compile(sepFields)
  6424. reSeparator = re.compile("[ \t]+")
  6425. def __init__(self,text):
  6426. bind.__init__(self,text)
  6427. def setDataField(self, txtLines, endtxtLines):
  6428. """Создаем список объектов с переменными"""
  6429. class fieldData:
  6430. def __init__(self):
  6431. self.name = False
  6432. self.value = False
  6433. self.comment = False
  6434. self.br = False
  6435. fields = []
  6436. field = fieldData()
  6437. z = 0
  6438. for k in txtLines:
  6439. textLine = k + endtxtLines[z]
  6440. z += 1
  6441. findComment = self.reComment.search(textLine)
  6442. if not textLine.strip():
  6443. field.br = textLine
  6444. fields.append(field)
  6445. field = fieldData()
  6446. elif findComment:
  6447. field.comment = textLine
  6448. fields.append(field)
  6449. field = fieldData()
  6450. else:
  6451. pars = textLine.strip()
  6452. nameValue = self.reSeparator.split(pars)
  6453. if len (nameValue) == 1:
  6454. field.name = textLine.replace(self.sepFields,"").strip()
  6455. field.value = ""
  6456. field.br = textLine
  6457. fields.append(field)
  6458. field = fieldData()
  6459. if len(nameValue) > 2:
  6460. nameCheck = nameValue[0]
  6461. if nameValue[0][:1] in ["+","-","!"]:
  6462. nameCheck = nameValue[0][1:]
  6463. if nameCheck == "option" or nameCheck == "hardware" or\
  6464. nameCheck == "set":
  6465. valueList = nameValue[2:]
  6466. nameValue =[nameValue[0]+nameValue[1],
  6467. " ".join(valueList).replace(\
  6468. self.sepFields,"")]
  6469. else:
  6470. valueList = nameValue[1:]
  6471. nameValue =[nameValue[0]," ".join(valueList).replace(\
  6472. self.sepFields,"")]
  6473. if len(nameValue) == 2:
  6474. name = nameValue[0]
  6475. value = nameValue[1].replace(self.sepFields,"")
  6476. field.name = name.replace(" ","").replace("\t","")
  6477. field.value = value
  6478. field.br = textLine
  6479. fields.append(field)
  6480. field = fieldData()
  6481. return fields
  6482. def join(self, dhcpObj):
  6483. """Объединяем конфигурации"""
  6484. if isinstance(dhcpObj, dhcp):
  6485. self.docObj.joinDoc(dhcpObj.doc)
  6486. class xml_gconf(xml_xfce):
  6487. """Класс для объединения gconf-xml файлов"""
  6488. # root нода
  6489. rootNode = False
  6490. # body нода
  6491. bodyNode = False
  6492. # Документ
  6493. doc = False
  6494. # Текст профиля
  6495. text = ""
  6496. # Текущее время в секундах
  6497. currentTime = ""
  6498. # Комментарий
  6499. _comment = ("<!--","-->")
  6500. # поддерживаемые аттрибуты тега entry. Пример <entry type="int"/>
  6501. supportEntryTypes = ("int", "bool", "float", "string", "list", "pair")
  6502. reStartTabs = re.compile("^(\t+)(.*)$")
  6503. def __init__(self, text):
  6504. self.text = text
  6505. # Создаем пустой объект
  6506. self.docObj = type("_empty_class", (object,), {})()
  6507. # Названия аттрибутов для пустого объекта
  6508. emptyMethods = ["getNodeBody","removeComment","insertBRtoBody",
  6509. "insertBeforeSepAreas"]
  6510. # Добавляем необходимые аттрибуты пустому объекту
  6511. for method in emptyMethods:
  6512. setattr(self.docObj, method, self.emptyMethod)
  6513. # Пустой метод (не нужно имя файла для корневой ноды)
  6514. setattr(self, "setNameBodyNode", self.emptyMethod)
  6515. # Создаем XML документ
  6516. self.doc = self.textToXML()
  6517. def getCurrentTime(self):
  6518. """Получение текущего времени в секундах"""
  6519. return str(int(time.time()))
  6520. def textToXML(self):
  6521. """Создание из текста XML документа
  6522. Храним xml в своем формате
  6523. """
  6524. if not self.text.strip():
  6525. self.text = '''<?xml version="1.0"?><gconf></gconf>'''
  6526. try:
  6527. self.doc = xml.dom.minidom.parseString(self.text)
  6528. except:
  6529. self.setError(_("Can not text profile is XML"))
  6530. return False
  6531. self.rootNode = self.doc.documentElement
  6532. self.bodyNode = self.rootNode
  6533. return self.doc
  6534. def cmpListsNodesEntry(self, listXmlA, listXmlB):
  6535. """Сравнение содержимого двух списков XML нод"""
  6536. getTextsNodes = lambda y: map(lambda x:\
  6537. x.toxml().replace(" ","").replace("\t","").replace("\n",""),
  6538. map(lambda x: x.hasAttribute("mtime") and\
  6539. x.removeAttribute("mtime") or x,
  6540. map(lambda x: x.cloneNode(True),
  6541. filter(lambda x: x.nodeType==x.ELEMENT_NODE, y))))
  6542. if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)):
  6543. return True
  6544. return False
  6545. def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
  6546. """Объединение корневой ноды профиля и корневой ноды файла"""
  6547. if levelNumber>1:
  6548. return True
  6549. xmlNode = xmlNewNode
  6550. childNodes = xmlNode.childNodes
  6551. nextOldNode = xmlOldNode
  6552. flagError = False
  6553. if xmlNode.nodeType == xmlNode.ELEMENT_NODE:
  6554. n = xmlNode
  6555. tagName = n.tagName
  6556. nAction = u''
  6557. nName = u''
  6558. nType = u''
  6559. nValue = u''
  6560. nSchema = u''
  6561. attrName = ''
  6562. if flagRootNode:
  6563. if not tagName == "gconf":
  6564. self.setError(_("The text is not a valid gconf-XML format \
  6565. (not found '<gconf>...</gconf>')"))
  6566. return False
  6567. flagType = False
  6568. flagValue = False
  6569. flagSchema = False
  6570. else:
  6571. if not tagName == "entry":
  6572. self.setError(_("The text is not a valid gconf-XML format \
  6573. (found '<gconf><%s>..</%s></gconf>'")%(tagName,tagName))
  6574. return False
  6575. if not n.hasAttribute("name"):
  6576. self.setError(_('Not found arrtibute "name" in tag entry'))
  6577. return False
  6578. flagType = n.hasAttribute("type")
  6579. flagValue = False
  6580. flagSchema = n.hasAttribute("schema")
  6581. if flagSchema:
  6582. nSchema = n.getAttribute("schema")
  6583. if not flagType and not flagSchema:
  6584. self.setError(_('Not found arrtibute "type" in tag entry'))
  6585. return False
  6586. nName = n.getAttribute("name")
  6587. attrName = u"attribute::name='%s'"%nName
  6588. if flagType:
  6589. flagValue = n.hasAttribute("value")
  6590. nType = n.getAttribute("type")
  6591. # Проверка правильности аттрибута type
  6592. if not nType in self.supportEntryTypes:
  6593. self.setError(\
  6594. _('Incorrect arrtibute "type" - <entry type="%s"/>')\
  6595. %nType)
  6596. return False
  6597. if flagValue:
  6598. nValue = n.getAttribute("value")
  6599. if n.hasAttribute("action"):
  6600. nAction = n.getAttribute("action")
  6601. if not nAction in ("join","replace","drop"):
  6602. textError = _('''In the text, XML profile, look \
  6603. for a reserved attribute 'action' with the incorrect value.\n\
  6604. Valid values attribute 'action': \
  6605. (action="join", action="replace", action="drop")''')
  6606. self.setError(textError)
  6607. return False
  6608. if xmlOldNode.parentNode:
  6609. findAttrStr = ""
  6610. if attrName:
  6611. findAttrStr = "[%s]"%attrName
  6612. findPath = u"child::%s%s"%(tagName,findAttrStr)
  6613. # Рабочая нода
  6614. if flagRootNode:
  6615. workNode = xmlOldNode.parentNode
  6616. else:
  6617. workNode = xmlOldNode
  6618. oldNodes = xpath.Evaluate(findPath, workNode)
  6619. # По умолчанию - объединение
  6620. flagJoin = True
  6621. flagReplace = False
  6622. flagDrop = False
  6623. # Замещаем ноду
  6624. if nType=="string" or nAction=="replace":
  6625. flagJoin = False
  6626. flagReplace = True
  6627. # Замещаем ноду в случае массива
  6628. elif nType == "list" or nType == "pair":
  6629. flagJoin = False
  6630. flagReplace = True
  6631. # Удаляем ноду
  6632. elif nAction == "drop":
  6633. flagJoin = False
  6634. flagDrop = True
  6635. if flagRootNode:
  6636. textError = _('Incorrect action="drop" in root node')
  6637. self.setError(textError)
  6638. return False
  6639. if oldNodes:
  6640. if len(oldNodes)>1:
  6641. textError = _("The uncertainty in this profile are \
  6642. the same nodes at one level")
  6643. self.setError(textError)
  6644. return False
  6645. nextOldNode = oldNodes[0]
  6646. # Объединение нод
  6647. if flagJoin:
  6648. if flagType and flagValue:
  6649. flagChange = False
  6650. foundValue = nextOldNode.hasAttribute("value")
  6651. if foundValue:
  6652. oValue = nextOldNode.getAttribute("value")
  6653. if nValue != oValue:
  6654. flagChange = True
  6655. else:
  6656. flagChange = True
  6657. if flagChange:
  6658. nextOldNode.setAttribute("mtime",
  6659. self.currentTime)
  6660. nextOldNode.setAttribute("value",nValue)
  6661. elif flagSchema:
  6662. flagChange = False
  6663. foundValue = nextOldNode.hasAttribute("schema")
  6664. if foundValue:
  6665. oSchema = nextOldNode.getAttribute("schema")
  6666. if nSchema != oSchema:
  6667. flagChange = True
  6668. else:
  6669. flagChange = True
  6670. if flagChange:
  6671. nextOldNode.setAttribute("mtime",
  6672. self.currentTime)
  6673. nextOldNode.setAttribute("schema",nSchema)
  6674. # Замещение ноды
  6675. elif flagReplace:
  6676. replaceXmlNode = xmlNode.cloneNode(True)
  6677. # Сравнение содержимого нод
  6678. if not self.cmpListsNodesEntry([replaceXmlNode],
  6679. [nextOldNode]):
  6680. replaceXmlNode.setAttribute("mtime",
  6681. self.currentTime)
  6682. if not\
  6683. self._removeDropNodesAndAttrAction(\
  6684. replaceXmlNode):
  6685. return False
  6686. workNode.replaceChild(replaceXmlNode,
  6687. nextOldNode)
  6688. childNodes = False
  6689. # Удаление ноды
  6690. elif flagDrop:
  6691. workNode.removeChild(nextOldNode)
  6692. childNodes = False
  6693. else:
  6694. # Добавление ноды
  6695. childNodes = False
  6696. if not flagDrop:
  6697. appendXmlNode = xmlNode.cloneNode(True)
  6698. appendXmlNode.setAttribute("mtime", self.currentTime)
  6699. if not\
  6700. self._removeDropNodesAndAttrAction(appendXmlNode):
  6701. return False
  6702. workNode.appendChild(appendXmlNode)
  6703. if childNodes:
  6704. for node in childNodes:
  6705. levelNumber +=1
  6706. if not self._join(node, nextOldNode, False, levelNumber):
  6707. flagError = True
  6708. break
  6709. levelNumber -= 1
  6710. if flagError:
  6711. return False
  6712. return True
  6713. def join(self, xml_gconfObj):
  6714. """Объединяем конфигурации"""
  6715. # Получаем текущее время
  6716. self.currentTime = self.getCurrentTime()
  6717. if isinstance(xml_gconfObj, xml_gconf):
  6718. try:
  6719. self.joinDoc(xml_gconfObj.doc)
  6720. except:
  6721. self.setError(_("Can not join profile"))
  6722. return False
  6723. return True
  6724. def getConfig(self):
  6725. """Получение текстового файла из XML документа"""
  6726. def expandStartTabs(s):
  6727. if s.startswith("\t"):
  6728. res = self.reStartTabs.findall(s)
  6729. return "".join((res[0][0].replace("\t"," "),res[0][1]))
  6730. else:
  6731. return s
  6732. data = self.doc.toprettyxml().split("\n")
  6733. data = map(lambda x: expandStartTabs(x),
  6734. filter(lambda x: x.strip(), data))
  6735. dataOut = []
  6736. z = 0
  6737. lenData = len(data)
  6738. lenM2 = lenData - 2
  6739. for i in xrange(lenData):
  6740. if z>0:
  6741. z -= 1
  6742. continue
  6743. if i < lenM2 and data[i].endswith(">") and not "<" in data[i+1]:
  6744. dataOut.append(data[i] + data[i+1].strip() + data[i+2].strip())
  6745. z = 2
  6746. continue
  6747. dataOut.append(data[i])
  6748. return "\n".join(dataOut)