3 use vars qw(@ISA @EXPORT_OK);
6 @EXPORT_OK = qw(generate_article generate_all generate_button
7 regen_and_refresh generate_extras pregenerate_list generate_one_extra generate_base content_one_extra response_one_extra);
8 use Constants qw($GENERATE_BUTTON $SHOPID $AUTO_GENERATE);
10 use BSE::WebUtil qw(refresh_to_admin);
13 our $VERSION = "1.006";
15 # returns non-zero if the Regenerate button should work
17 if ($GENERATE_BUTTON) {
18 if (my $ref = ref $GENERATE_BUTTON) {
20 return $GENERATE_BUTTON->();
23 # assumed to be an object
24 return $GENERATE_BUTTON->want_button();
34 # regenerate an individual article
36 my ($articles, $article, $cfg) = @_;
38 $cfg ||= BSE::Cfg->single;
41 if ($article->is_dynamic) {
42 my $debug_jit = $cfg->entry('debug', 'jit_dynamic_regen');
43 $outname = $article->cached_filename($cfg);
44 if ($article->{flags} !~ /R/ &&
45 $cfg->entry('basic', 'jit_dynamic_pregen')) {
46 $debug_jit and print STDERR "JIT: $article->{id} - deleting $outname\n";
47 # just delete the file, page.pl will make it if needed
53 $outname = $article->link_to_filename($cfg)
54 or return; # no output for this article
57 if ($article->flags =~ /P/ && $article->{parentid} != -1) {
58 # link to parent, remove the file
63 my $genname = $article->{generator};
66 my $gen = $genname->new(articles=>$articles, cfg=>$cfg, top=>$article);
68 my $content = $gen->generate($article, $articles);
69 my $tempname = $outname . ".work";
71 _write_text($tempname, $content, $cfg);
73 rename($tempname, $outname)
74 or die "Cannot rename $tempname to $outname: $!";
77 sub generate_article {
78 my ($articles, $article, $cfg) = @_;
81 generate_low($articles, $article, $cfg)
82 if $article->{link} && $article->{template};
84 if ($article->{parentid} != -1) {
85 $article = $articles->getByPkey($article->{parentid});
94 my ($cfg, $article, $type) = @_;
96 my $section = "$type settings";
99 for my $field (Article->columns) {
100 if ($cfg->entry($section, $field)) {
101 $article->{$field} = $cfg->entryVar($section, $field);
106 sub _search_presets {
109 # build a dummy article
110 use Constants qw($SEARCH_TITLE $SEARCH_TITLE_IMAGE $CGI_URI);
112 my %article = map { $_, '' } Article->columns;
113 @article{qw(id parentid title titleImage displayOrder link level listed force_dynamic)} =
114 (-4, -1, $SEARCH_TITLE, $SEARCH_TITLE_IMAGE, 0, $CGI_URI."/search.pl", 0, 1, 1);
116 $article{link} = $cfg->entryErr('site', 'url') . $article{link};
118 _cfg_presets($cfg, \%article, "search");
127 my $shop_base = Articles->getByPkey($SHOPID);
128 my $shop = { map { $_ => $shop_base->{$_} } $shop_base->columns };
129 $shop->{link} =~ /^\w+:/
130 or $shop->{link} = $cfg->entryErr('site', 'url') . $shop->{link};
131 $shop->{id} = -3; # some random negative number
133 _cfg_presets($cfg, $shop, "shop");
138 sub _extras_presets {
139 my ($cfg, $presets) = @_;
142 my %article = map { $_, '' } Article->columns;
143 $article{displayOrder} = 1;
145 $article{parentid} = -1;
146 $article{link} = $cfg->entryErr('site', 'url');
147 _cfg_presets($cfg, \%article, $presets);
154 search => [ "search" ],
157 'cart', 'checkoutnew', 'checkoutfinal',
171 for my $type (keys %builtin_extras) {
172 for my $name (@{$builtin_extras{$type}}) {
173 $builtin_lookup{$name} = $type;
179 my ($cfg, $extra) = @_;
182 if ($builtin_extras{$extra->{set}}) {
183 $result{abs_urls} = $abs_urls{$extra->{set}};
186 $result{abs_urls} = $cfg->entry("$extra->{type} settings", "abs_urls", 0);
192 sub pregenerate_list {
195 my $template_dir = $cfg->entryVar('paths', 'templates');
197 # this will change to a directory that can be safely blown away
198 my $pregen_path = $template_dir;
206 base => $_ . "_base.tmpl",
207 type => $builtin_lookup{$_},
208 set => $builtin_lookup{$_},
210 outpath => $pregen_path,
211 abs_urls => $abs_urls{$builtin_lookup{$_}},
213 }, keys %builtin_lookup
218 my %pregen = $cfg->entries('pregenerate');
219 for my $out (keys %pregen) {
220 my ($type, $input) = split ',', $pregen{$out}, 2;
228 outpath => $pregen_path,
234 if (open my $extras, "$template_dir/extras.txt") {
238 if (/^(\S+)\s+(\S+)/) {
246 outpath => $cfg->content_base_path,
255 $a->{sort} <=> $b->{sort}
256 || $a->{set} cmp $b->{set}
257 || $a->{type} cmp $b->{type}
258 || lc $a->{name} cmp lc $b->{name}
262 sub _make_extra_art {
263 my ($cfg, $extra) = @_;
265 if ($extra->{set} eq "shop") {
266 return _shop_presets($cfg);
268 elsif ($extra->{set} eq "search") {
269 return _search_presets($cfg);
271 elsif ($extra->{set} eq "pregen"
272 || $extra->{set} eq "extras") {
273 return _extras_presets($cfg, $extra->{type});
276 confess "Unknown extras set $extra->{set}";
280 sub _make_extra_gen {
281 my ($cfg, $extra) = @_;
283 my $article = _make_extra_art($cfg, $extra);
284 require Generate::Article;
290 if ($extra->{dynamic}) {
291 $opts{force_dynamic} = 1;
293 require Generate::Article;
294 my $gen = Generate::Article->new(%opts);
296 return ($article, $gen);
299 sub _common_one_extra {
300 my ($articles, $extra, $cfg) = @_;
302 my ($article, $gen) = _make_extra_gen($cfg, $extra);
304 %acts = $gen->baseActs($articles, \%acts, $article);
305 if (_extras_cfg($cfg, $extra)->{abs_urls}) {
306 my $oldurl = $acts{url};
309 my $value = $oldurl->(@_);
310 $value =~ /^<:/ and return $value;
311 unless ($value =~ /^\w+:/) {
312 # put in the base site url
313 $value = $cfg->entryErr('site', 'url').$value;
319 my $content = BSE::Template->get_page($extra->{base}, $cfg, \%acts,
320 undef, undef, $gen->variables);
322 return wantarray ? ( $content, $article ) : $content;
325 sub response_one_extra {
326 my ($articles, $extra) = @_;
328 my $cfg = BSE::Cfg->single;
329 my $content = _common_one_extra($articles, $extra, $cfg);
331 return BSE::Template->make_response($content, BSE::Template->get_type($cfg, $extra->{template}));
334 sub content_one_extra {
335 my ($articles, $extra) = @_;
337 my $cfg = BSE::Cfg->single;
338 return _common_one_extra($articles, $extra, $cfg);
341 sub generate_one_extra {
342 my ($articles, $extra) = @_;
344 my $cfg = BSE::Cfg->single;
345 my $content = _common_one_extra($articles, $extra, $cfg);
346 my $outname = $extra->{outpath} . "/". $extra->{name};
347 my $workname = $outname . ".work";
348 _write_text($workname, $content, $cfg);
350 rename $workname, $outname
351 or die "Cannot rename $workname to $outname: $!";
357 my $cfg = delete $opts{cfg} || BSE::Cfg->single;
359 my $articles = delete $opts{articles} || "Articles";
360 my $extras = delete $opts{extras} || [ pregenerate_list($cfg) ];
362 my $progress = delete $opts{progress} || sub {};
366 $a->{sort} <=> $b->{sort}
367 || $a->{type} cmp $b->{type}
368 || lc $a->{name} cmp lc $b->{name}
372 $progress->({ type => "extras", count => $count, info => "count" }, "$count base pages");
377 for my $extra (@extras) {
378 if ($extra->{set} ne $set || $extra->{type} ne $type) {
379 ($article, $gen) = _make_extra_gen($cfg, $extra);
380 %acts = $gen->baseActs($articles, \%acts, $article);
381 if (_extras_cfg($cfg, $extra)->{abs_urls}) {
382 my $oldurl = $acts{url};
385 my $value = $oldurl->(@_);
386 $value =~ /^<:/ and return $value;
387 unless ($value =~ /^\w+:/) {
388 # put in the base site url
389 $value = $cfg->entryErr('site', 'url').$value;
394 $progress->($extra, "Generating $extra->{name}");
395 my $content = BSE::Template->get_page($extra->{base}, $cfg, \%acts,
396 undef, undef, $gen->variables);
397 my $outname = $extra->{outpath} . "/". $extra->{name};
398 my $workname = $outname . ".work";
399 _write_text($workname, $content, $cfg);
401 rename $workname, $outname
402 or die "Cannot rename $workname to $outname: $!";
408 my ($articles, $cfg, $callback) = @_;
410 my @articleids = $articles->allids;
412 $callback->("Generating articles (".scalar(@articleids)." to do)")
416 Squirrel::Table->caching(1);
418 for my $articleid (@articleids) {
419 my $article = $articles->getByPkey($articleid);
421 if ($article->{link} && $article->{template}) {
422 #$callback->("Article $articleid");
423 generate_low($articles, $article, $cfg);
425 my $newpc = $index / @articleids * 100;
427 if ($callback && $newpc >= $pc + 1 || abs($newpc-100) < 0.01) {
428 $callback->(sprintf("%5d: %.1f%% done - elapsed: %.1f", $articleid, $newpc, $now - $allstart)) if $callback;
433 my $last_section = "";
434 my $progress = $callback ? sub {
436 if (!$data->{count} && $data->{set} ne $last_section) {
437 $callback->("Regenerating $data->{set} pages");
438 $last_section = $data->{set};
442 generate_base(cfg => $cfg, articles => $articles, progress => $progress);
444 $callback->("Total of ".(time()-$allstart)." seconds") if $callback;
448 my ($filename, $data, $cfg) = @_;
450 open my $fh, ">", $filename
451 or die "Cannot create $filename: $!";
453 my $charset = $cfg->charset;
454 binmode $fh, ":encoding($charset)";
457 or die "Cannot write $filename: $!";
459 or die "Cannot close $filename: $!";