File: parse-man.pl

package info (click to toggle)
libconfig-model-openssh-perl 2.9.9.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 640 kB
  • sloc: perl: 4,596; makefile: 12
file content (145 lines) | stat: -rw-r--r-- 4,407 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/perl

use strict;
use warnings;
use 5.22.0;
use utf8;
use open      qw(:std :utf8);    # undeclared streams in UTF-8

use lib 'contrib/lib';
use lib 'lib';

use IO::Pipe;
use Path::Tiny;
use Config::Model 2.134; # load_data __skip_order parameter
use Config::Model::Itself 2.012;
use Config::Model::Exception;
use YAML::XS qw/LoadFile/;

use experimental qw/postderef signatures/ ;

use ParseMan;

# make sure that Ssh models are created from scratch
path('lib/Config/Model/models/')->remove_tree;

sub parse_man_page ($man_page_name) {
    my $path = `man --path $man_page_name`;
    chomp $path;
    my $pipe = IO::Pipe->new();
    $pipe->reader("zcat $path | man2html");
    my @lines = $pipe->getlines;
    $pipe->close;
    return parse_html_man_page(join('',@lines));
}

sub store_description ($obj, @desc) {
    $obj->fetch_element("description")->store(join("\n\n", @desc));
}

sub create_ssh_model ($meta_root) {
    say "Processing ssh documentation...";

    create_class_boilerplate ($meta_root, ssh_system => 'Ssh');
    create_class_boilerplate ($meta_root, ssh_system => 'Ssh::HostElement');

    # extract data from ssh man pages
    my $data = parse_man_page( 'ssh_config' ) ;

    foreach my $element ($data->{element_list}->@*) {
        my @desc = $data->{element_data}{$element}->@*;
        my $load_string = create_load_data(ssh => $element, @desc);
        my $target = $element =~ /^(Host|Match)$/ ? 'Ssh' : 'Ssh::HostElement';
        my $obj = $meta_root->grab(qq!class:$target element:"$element"!);
        $obj->load($load_string);
        store_description($obj, @desc);
    }

    $meta_root->load(qq!class:Ssh include="Ssh::HostElement"!);
}

sub create_sshd_model ($meta_root) {
    say "Processing sshd documentation...";

    create_class_boilerplate ($meta_root, sshd_system => 'Sshd');
    create_class_boilerplate ($meta_root, sshd_system => 'Sshd::MatchElement');

    my $data = parse_man_page( 'sshd_config' ) ;

    # retrieve list of keywords that can fit in Match block
    my $is_match = extract_list_from_desc($data->{element_data}{'Match'});

    foreach my $element ($data->{element_list}->@*) {
        my @desc = $data->{element_data}{$element}->@*;
        my $load_string = create_load_data(sshd => $element, @desc);
        my $target = $is_match->{$element} ? 'Sshd::MatchElement' : 'Sshd';
        my $obj = $meta_root->grab(qq!class:$target element:"$element"!);
        $obj->load($load_string);
        store_description($obj, @desc);
    }

    $meta_root->load(qq!class:Sshd include="Sshd::MatchElement"!);
}

sub extract_list_from_desc ($desc_ref) {
    my $str = $desc_ref->[$#$desc_ref];
    my @keywords = ( $str =~ /B<(\w+)>/g );
    my %is_match = map { $_ => 1 ; } grep { $_ ne 'Match' } @keywords;
    return \%is_match;
}

sub load_yaml_model ($meta_root,$class) {
    my $file = 'contrib/'.lc($class).'.yml';
    $file =~ s/::/-/g;
    say "Creating $class from $file...";
    $meta_root->load_data(LoadFile($file));
}

# Itself constructor returns an object to read or write the data
# structure containing the model to be edited
my $rw_obj = Config::Model::Itself -> new () ;

# now load the existing model to be edited
$rw_obj -> read_all() ;
my $meta_root = $rw_obj->meta_root;

load_yaml_model($meta_root,"Ssh::PortForward");

say "Creating ssh model...";
create_ssh_model($meta_root);

say "loading ssh model addendum from ssh-fixup.yaml";
$meta_root->load_data(LoadFile('contrib/ssh-fixup.yaml'));

say "loading ssh model IPQoS element from fixup-element-ipqos.yml";
$meta_root
    ->grab("class:Ssh::HostElement element:IPQoS")
    ->load_data(LoadFile('contrib/fixup-element-ipqos.yml'));

# This class include Ssh model and must be loaded after Ssh model is
# created
load_yaml_model($meta_root,"SystemSsh");

say "Ssh model is done...";

say "Generating Sshd model";

load_yaml_model($meta_root,"Sshd::MatchCondition");

create_sshd_model($meta_root);

# requires Sshd::MatchElement
load_yaml_model($meta_root,"Sshd::MatchBlock");

say "loading sshd model addendum from sshd-fixup.yaml";
$meta_root->load_data(LoadFile('contrib/sshd-fixup.yaml'));

say "loading ssh model IPQoS element from fixup-element-ipqos.yml";
$meta_root
    ->grab("class:Sshd::MatchElement element:IPQoS")
    ->load_data(LoadFile('contrib/fixup-element-ipqos.yml'));

say "Saving ssh and sshd models...";
$rw_obj->write_all;

say "Done.";