Мои статические веб-страницы создаются из огромного набора шаблонов, которые межвключены с помощью Шаблонного Инструментария "импорт" и "включают", таким образом, page.html похож на это:
[% INCLUDE top %]
[% IMPORT middle %]
Затем вершина могла бы иметь еще больше включенных файлов.
У меня есть очень многие эти файлы, и они должны быть выполнены до, создают веб-страницы на различных языках (английский, французский, и т.д., не языки программирования). Это - очень сложный процесс и когда один файл обновляется, я хотел бы смочь автоматически переделать только необходимые файлы, с помощью make-файла или чего-то подобного.
Есть ли любые инструменты как makedepend
для файлов C, которые синтаксический анализ может обработать шаблоны инструментария по шаблону и создать список зависимости для использования в make-файле?
Или есть ли лучшие способы автоматизировать этот процесс?
Template Toolkit
действительно поставляется со своим собственным сценарием командной строки под названием ttree
для создания веб-сайтов TT ala make.
Вот файл ttree.cfg
, который я часто использую в проектах веб-сайтов TT здесь, на моем Mac:
# directories
src = ./src
lib = ./lib
lib = ./content
dest = ./html
# pre process these site file
pre_process = site.tt
# copy these files
copy = \.(png|gif|jpg)$
# ignore following
ignore = \b(CVS|RCS)\b
ignore = ^#
ignore = ^\.DS_Store$
ignore = ^._
# other options
verbose
recurse
Просто запустив ttree -f ttree.cfg
, сайт будет перестроен. в dest
обновляется только то, что было изменено в исходном коде (в src
) или в моих библиотеках (в lib
).
Более подробные сведения о зависимостях можно найти в Зависимости шаблона
.
Обновление - И вот моя попытка получить список зависимостей путем создания подкласса Template :: Provider
:
{
package MyProvider;
use base 'Template::Provider';
# see _dump_cache in Template::Provider
sub _dump_deps {
my $self = shift;
if (my $node = $self->{ HEAD }) {
while ($node) {
my ($prev, $name, $data, $load, $next) = @$node;
say {*STDERR} "$name called from " . $data->{caller}
if exists $data->{caller};
$node = $node->[ 4 ];
}
}
}
}
use Template;
my $provider = MyProvider->new;
my $tt = Template->new({
LOAD_TEMPLATES => $provider,
});
$tt->process( 'root.tt', {} ) or die $tt->error;
$provider->_dump_deps;
В приведенном выше коде отображаются все вызванные зависимости (через INCLUDE, INSERT, PROCESS и WRAPPER) и где вызывается из всего дерева root.tt
. Таким образом, вы можете построить файл зависимостей ttree
.
/ I3az /
Прочитав документацию по ttree, я решил создать что-нибудь сам. Я отправляю его сюда на случай, если он пригодится следующему человеку. Однако это не общее решение, оно работает только в нескольких ограниченных случаях. Это сработало для этого проекта, поскольку все файлы находятся в одном каталоге и нет повторяющихся включений. Я задокументировал недостатки в виде комментариев перед каждой процедурой.
Если есть простой способ сделать то же самое с ttree, которое я пропустил, дайте мне знать.
my @dependencies = make_depend ("first_file.html.tmpl");
# Bugs:
# Insists files end with .tmpl (mine all do)
# Does not check the final list for duplicates.
sub make_depend
{
my ($start_file) = @_;
die unless $start_file && $start_file =~ /\.tmpl/ && -f $start_file;
my $dir = $start_file;
$dir =~ s:/[^/]*$::;
$start_file =~ s:\Q$dir/::;
my @found_files;
find_files ([$start_file], \@found_files, $dir);
return @found_files;
}
# Bugs:
# Doesn't check for including the same file twice.
# Doesn't allow for a list of directories or subdirectories to find the files.
# Warning about files which aren't found switched off, due to
# [% INCLUDE $file %]
sub find_files
{
my ($files_ref, $foundfiles_ref, $dir) = @_;
for my $file (@$files_ref) {
my $full_name = "$dir/$file";
if (-f $full_name) {
push @$foundfiles_ref, $full_name;
my @includes = get_includes ($full_name);
if (@includes) {
find_files (\@includes, $foundfiles_ref, $dir);
}
} else {
# warn "$full_name not found";
}
}
}
# Only recognizes two includes, [% INCLUDE abc.tmpl %] and [% INCLUDE "abc.tmpl" %]
sub get_includes
{
my ($start_file) = @_;
my @includes;
open my $input, "<", $start_file or die "Can't open $start_file: $!";
while (<$input>) {
while (/\[\%-?\s+INCLUDE\s+(?:"([^"]+)"|(.*))\s+-?\%\]/g) {
my $filename = $1 ? $1 : $2;
push @includes, $filename;
}
}
close $input or die $!;
return @includes;
}
На случай, если все, что вас волнует, это поиск имен файлов, упомянутых в директивах, таких как INCLUDE
, PROCESS
, WRAPPER
и т.д., можно представить себе даже использование sed
или perl
из командной строки в генерировать зависимости.
Однако, если есть более тонкие зависимости (например, вы ссылаетесь на изображение с помощью
в своем HTML-документе, размер которого рассчитывается с помощью подключаемого модуля изображения , проблема может стать гораздо менее податливый.
Я на самом деле не тестировал его, но может сработать что-то вроде следующего:
#!/usr/bin/perl
use strict; use warnings;
use File::Find;
use File::Slurp;
use Regex::PreSuf;
my ($top) = @ARGV;
my $directive_re = presuf qw( INCLUDE IMPORT PROCESS );
my $re = qr{
\[%-? \s+ $directive_re \s+ (\S.+) \s+ -?%\]
}x;
find(\&wanted => $top);
sub wanted {
return unless /\.html\z/i;
my $doc = read_file $File::Find::name;
printf "%s : %s\n", $_, join(" \\\n", $doc =~ /$re/g );
}