add helper to correctly resolve links
authorDietmar Maurer <dietmar@proxmox.com>
Thu, 6 Oct 2016 15:29:03 +0000 (17:29 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 6 Oct 2016 15:29:03 +0000 (17:29 +0200)
just a start, not ready to use ...

Makefile
asciidoc-pve.in [new file with mode: 0644]
scan-adoc-refs [new file with mode: 0755]

index cf166fe..562e22e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -157,6 +157,14 @@ PVE_ADMIN_GUIDE_SOURCES=                   \
        GFDL.adoc                               \
        attributes.txt
 
        GFDL.adoc                               \
        attributes.txt
 
+link-refs.json: scan-adoc-refs ${PVE_ADMIN_GUIDE_SOURCES}
+       ./scan-adoc-refs ${PVE_ADMIN_GUIDE_SOURCES} >link-refs.json
+
+asciidoc-pve: asciidoc-pve.in link-refs.json
+       cat asciidoc-pve.in link-refs.json >asciidoc-pve.tmp
+       chmod +x asciidoc-pve.tmp
+       mv asciidoc-pve.tmp asciidoc-pve
+
 WIKI_IMPORTS=                                                                  \
        section-pve-usbstick-plain.html                                         \
        section-getting-help-plain.html                                         \
 WIKI_IMPORTS=                                                                  \
        section-pve-usbstick-plain.html                                         \
        section-getting-help-plain.html                                         \
@@ -297,5 +305,5 @@ update: clean
        make all
 
 clean: 
        make all
 
 clean: 
-       rm -rf *.tmp.xml *.html *.pdf *.epub *.tmp *.1 *.5 *.8 *.deb *.changes build api-viewer/apidoc.js chapter-*.html chapter-*-plain.html chapter-*.html pve-admin-guide.chunked
+       rm -rf *.tmp.xml *.html *.pdf *.epub *.tmp *.1 *.5 *.8 *.deb *.changes build api-viewer/apidoc.js chapter-*.html chapter-*-plain.html chapter-*.html pve-admin-guide.chunked asciidoc-pve link-refs.json
        find . -name '*~' -exec rm {} ';'
        find . -name '*~' -exec rm {} ';'
diff --git a/asciidoc-pve.in b/asciidoc-pve.in
new file mode 100644 (file)
index 0000000..550cd4b
--- /dev/null
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use JSON;
+
+my $data_str = "";
+while (<main::DATA>) { $data_str .= $_; }
+
+my $fileinfo = decode_json($data_str);
+    
+print to_json($fileinfo, { pretty => 1 });
+
+die "implement something useful instead";
+
+__END__
diff --git a/scan-adoc-refs b/scan-adoc-refs
new file mode 100755 (executable)
index 0000000..a4e46d1
--- /dev/null
@@ -0,0 +1,199 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use IO::File;
+use JSON;
+
+use Data::Dumper;
+
+my $environments = {
+    default => 1,
+    wiki => 1,
+    manvolnum => 1,
+    pvelogo => 0, # ignore
+};
+
+my $resolve_skip_files = {
+    default => {},
+    wiki => { 'pve-admin-guide.adoc' => 1 },
+    manvolnum => {},
+};
+
+my $fileinfo = {};
+
+my $start_env = [];
+foreach my $e (keys %$environments) {
+    push @$start_env, $e if $environments->{$e};
+}
+
+my $env_stack = [$start_env];
+my $env_name_stack = [];
+
+sub reset_environment_stack {
+    $env_stack = [$start_env];
+    $env_name_stack = [];
+}
+
+sub push_environment {
+    my ($env, $not) = @_;
+
+    die "undefined environment '$env'\n" if !defined($environments->{$env});
+
+    return if !$environments->{$env}; # do not track
+    
+    if ($not) {
+       my $new_env = [];
+       foreach my $e (@{$env_stack->[-1]}) {
+           if ($e ne $env) {
+               push @$new_env, $e;
+           }
+       }
+       die "empty environment" if !scalar($new_env);
+       push @$env_stack, $new_env;
+    } else {
+       push @$env_stack, [$env];
+    }
+    
+    push @$env_name_stack, $env;
+}
+
+sub pop_environment {
+    my ($env) = @_;
+
+    die "undefined environment '$env'\n" if !defined($environments->{$env});
+   
+    return if !$environments->{$env}; # do not track
+
+    pop @$env_stack;
+    my $res = pop @$env_name_stack;
+    
+    die "environment missmatch ($res != $env)\n" if $res ne $env;
+}
+
+sub register_include {
+    my ($filename, $include_filename, $env_list) = @_;
+
+    return if $include_filename !~ m/\.adoc$/; # skip attributes.txt
+
+    foreach my $e (@$env_list) {
+       $fileinfo->{include}->{$e}->{$filename}->{$include_filename} = 1;
+    }
+}
+
+sub register_blockid {
+    my ($filename, $blockid, $env_list) = @_;
+
+    foreach my $e (@$env_list) {
+       my $fn = $fileinfo->{blockid}->{$e}->{$blockid};
+       die "blockid '$blockid' already defined in $fn" 
+           if defined($fn);
+       $fileinfo->{blockid}->{$e}->{$blockid} = $filename;
+    }
+}
+
+sub scan_adoc_file {
+    my ($filename) = @_;
+
+    reset_environment_stack();
+    
+    # print "SCAN $filename\n";
+
+    my $fh = IO::File->new("$filename", "r") or
+       die "unable to open file '$filename' - $!\n";
+
+    my $env_last_line = {};
+    
+    while (defined (my $line = <$fh>)) {
+       if ($line =~ m/^if(n?)def::(\S+)\[(.*)\]\s*$/) {
+           my ($not, $env, $text) = ($1, $2);
+           die "unsuported ifdef usage - implement me" if $text;
+           push_environment($env, $not);
+           next;
+       } elsif ($line =~ m/^endif::(\S+)\[(.*)\]\s*$/) {
+           my ($env, $text) = ($1, $2);
+           die "unsuported ifdef usage - implement me" if $text;
+           pop_environment($env);
+           next;
+       } elsif ($line =~ m/^include::(\S+)\[.*\]\s*$/) {
+           register_include($filename, $1, $env_stack->[-1]);
+           next;
+       }
+
+       # try to detect titles
+       foreach my $e (@{$env_stack->[-1]}) {
+           my $title = $fileinfo->{titles}->{$e}->{$filename};
+           next if defined($title);
+
+           if (($line =~ m/^=====+/) || ($line =~ m/^-----+/)) {
+               $fileinfo->{titles}->{$e}->{$filename} = $env_last_line->{$e};
+           }
+           $env_last_line->{$e} = $line;
+           chomp $env_last_line->{$e};
+       }
+       
+       # fixme: also scan <<>>
+       
+       while ($line =~ m/xref:([^\s\[\]]+)\[([^\]]*)\]/g) {
+           # print "$filename xref:$1 [$2]\n";
+       }
+
+       if ($line =~ m/^\[\[(.*)\]\]\s*$/) {
+           my $blockid = $1;
+           die "implement me" if $blockid =~m/,/;
+           register_blockid($filename, $blockid, $env_stack->[-1]);
+       }
+    } 
+}
+
+my $scanned_files = {};
+while (my $filename = shift) {
+    next if $filename !~ m/\.adoc$/; # skip attributes.txt
+    next if $scanned_files->{$filename};
+
+    scan_adoc_file($filename);
+    $scanned_files->{$filename} = 1;
+}
+
+sub resolve_link_target {
+    my ($env, $filename) = @_;
+
+    my $include_hash = $fileinfo->{include}->{$env};
+
+    my $repeat = 1;
+
+    while ($repeat) {
+       $repeat = 0;
+       foreach my $fn (keys %$include_hash) {
+           next if $resolve_skip_files->{$env}->{$fn};
+           if ($include_hash->{$fn}->{$filename}) {
+               $filename = $fn;
+               $repeat = 1;
+               last;
+           }
+       }
+    }
+    
+    return $filename;
+}
+
+# now resolve blockids
+foreach my $e (@$start_env) {
+    my $blockid_hash = $fileinfo->{blockid}->{$e};
+    foreach my $blockid (keys %$blockid_hash) {
+       my $fn = resolve_link_target($e, $blockid_hash->{$blockid});
+       if ($e eq 'wiki') {
+           my $title = $fileinfo->{titles}->{$e}->{$fn};
+           $title =~ s/\s/_/g;
+           $title =~ s/\{pve\}/Proxmox VE/g;
+           die "found not title for '$fn' in env '$e'" if !$title;
+           $fileinfo->{blockid_target}->{$e}->{$blockid} = "link:/wiki/$title#$blockid";
+       } else {
+           $fileinfo->{blockid_target}->{$e}->{$blockid} = $fn;
+       }
+    }
+}
+
+
+print to_json($fileinfo, { pretty => 1 } );
+