шаблонная конфигурация в python или perl? - PullRequest
2 голосов
/ 28 июля 2011

Я пытаюсь реализовать шаблонный файл конфигурации. Я бы предпочел Python, но я бы тоже ответил на Perl. Я использовал Perl для моего примера.

Я немного искал и нашел - Python один файл конфигурации - ConfigObj - генератор конфигурационных файлов python - ePerl но я не смог от них решить мою проблему.

Я пытаюсь сгенерировать файл конфигурации в основном в формате INI (даже с разделами):

# Comments
VAR1 = value1
EDITOR = vi

и мне нужно, чтобы он генерировался из шаблона, в который я встраиваю язык сценариев в текст:

# Config:
MYPWD = <:   `pwd`  :>

Текст между '<:' и ':>' будет написан на языке сценариев (python или perl). Как и в случае с шаблоном, его стандартный вывод захватывается и вставляется в полученный текст. Шаблон, используемый в примере, в основном eperl, но я бы предпочел python, если он доступен.

и, наконец, определенные переменные должны использоваться повторно:

# Config:
CODE_HOME = /some/path
CODE_BIN = <:=$CODE_HOME:>/bin

Вот исходный файл теста, который я прочитал:

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# platform.cfg
# This one variable
VAR =value
# this is a templated variable. The langage is perl, but could be python.
HELLO= <: print 'World' :>
# This is a multi-line code which should resolve to a single line value.
LONGER = <:
 if (1) {
    print "abc ";
 }
 $pwd = `/bin/pwd`;
 chomp($pwd);
 print $pwd;
:>
# Another one to test the carriage returns.
MULTIPLE = /<: print "proj" :>/<: print "tahiti":>/<: 
print "pd/1/";
$system = `grep -w VAR platform.cfg | egrep -v 'print|platform.cfg' | cut -d = -f 2-`;
chomp($system);
print $system;
:>
# variables dependent from the previous variable definition
VAR1 = <: print $VAR :>1
# variables dependent from the previous variable definition
VAR2 = <: print $VAR1 :>2
# variables dependent from the previous variable definition
VAR3 = <: print $VAR2 :>3
# variables dependent from the previous variable definition
VAR4 = <: print $VAR3 :>4
# BTW, multi-line comments are significant
# and should be preserved as the documentation for the
# variable just below:
VAR5 = <: print $VAR4 :>5
VAR6 = <: print $VAR5 :>6
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

И я хочу получить этот результат из сценария. Я не мог понять, как сделать так, чтобы переменные, определенные в файле конфигурации, были частью интерпретатора?

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# platform.cfg
# This one variable
VAR =value
# this is a templated variable. The langage is perl, but could be python.
HELLO= World
# This is a multi-line code which should resolve to a single line value.
LONGER = abc /src/byop/CODE
# Another one to test the carriage returns.
MULTIPLE = /proj/tahiti/pd/1/value
# variables dependent from the previous variable definition
VAR1 = value1
# variables dependent from the previous variable definition
VAR2 = value12
# variables dependent from the previous variable definition
VAR3 = value123
# variables dependent from the previous variable definition
VAR4 = value1234
# BTW, multi-line comments are significant
# and should be preserved as the documentation for the
# variable just below:
VAR5 = value12345
VAR6 = value123456
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Спасибо за ваши предложения.

Ответы [ 2 ]

4 голосов
/ 28 июля 2011

Я разработал Template :: MasonLite именно для этой цели.Я генерировал множество конфигурационных файлов (в моем случае - конфигурации Apache), и мне нужно было запустить скрипт на нескольких хостах без дополнительных зависимостей.Поэтому я разработал урезанную версию HTML :: Mason, которая может быть встроена непосредственно в мой скрипт (дополнительно ~ 70 строк).Шаблонный синтаксис Mason использует Perl для любой логики (условия, циклы и т. Д.), А не для создания совершенно нового языка.

Реализация Template :: MasonLite не используется в CPAN (только вссылка выше), потому что я не хотел загромождать CPAN еще одним движком шаблонов, а также не было ясно, какое имя должен иметь модуль.

В то время, когда я его разрабатывал, я использовал cfengine, в котором не было никакоговменяемая форма шаблонизации.С тех пор я перешел на марионетку, которая включает язык шаблонов.Я все еще использую Template :: MasonLite для создания слайдов презентации .

1 голос
/ 28 июля 2011

Если вы не возражаете против использования другого синтаксиса, есть несколько библиотек шаблонов, которые вы могли бы использовать, mako похож по духу, Jinaj2 также довольно хорош.Перейти с проверенной и проверенной библиотекой!Если вы действительно хотите реализовать свою собственную библиотеку шаблонов, это может дать вам начало:

import re, StringIO, sys

def exec_block(block, variables):
    """Captures output of exec'd code block"""
    code = compile(block.strip(), '<string>', 'exec')
    _stdout, result = sys.stdout, StringIO.StringIO()
    sys.stdout = sys.__stdout__ = result
    exec(code, variables)
    sys.stdout = sys.__stdout__ = _stdout
    return result.getvalue()

def format_template(template):
    """Replaces code blocks with {0} for string formating later"""
    def sub_blocks(matchobj):
        """re.sub function, adds match to blocks and replaces with {0}"""
        blocks.append(matchobj.group(0)[2:-2].strip())
        return '{0}'

    blocks = []
    template = re.sub(r'<:.+?:>', sub_blocks, template, flags=re.DOTALL).splitlines()
    blocks.reverse()
    return blocks, template

def render_template(blocks, template):
    """renders template, execs each code block and stores variables as we go"""
    composed, variables = [], {}
    for line in template:
        if '{0}' in line:
            replacement = exec_block(blocks.pop(), variables).strip()
            line = line.format(replacement)
        if not line.startswith('#') and '=' in line:
            k, v = [x.strip() for x in line.split('=')]
            variables[k] = v
        composed.append(line)
    return '\n'.join(composed)

if __name__ == '__main__':
    import sys
    with open(sys.argv[1]) as f:
        blocks, template = format_template(f.read())
        print rend_template(blocks, template)

, которая в основном работает так же, как описано выше, за исключением использования Python для блоков кода.Поддерживает только один блок на присваивание, что на самом деле кажется мне лучшим подходом.Вы можете передать ему файл конфигурации, например:

VAR = value
LONGER = <:
    print 'something'
:>
VAR1 = <: print VAR :>1
# comment
VAR2 = <: print VAR1 :>2
VAR3 = <: print VAR2 :>3
VAR4 = <: print VAR3 :>4

И он будет исполнять каждый блок, отображая переменные для вас:

VAR = value
LONGER = something
VAR1 = value1
# comment
VAR2 = value12
VAR3 = value123
VAR4 = value1234
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...