source: server/trunk/admin/lib/Sophie/Cli.pm @ 14

Last change on this file since 14 was 11, checked in by nanardon, 14 years ago
  • improve admin part
File size: 8.3 KB
Line 
1package Sophie::Cli;
2
3# $Id: Cli.pm 4321 2010-10-26 16:28:15Z nanardon $
4
5use strict;
6use warnings;
7use Term::ReadLine;
8use Text::ParseWords;
9use Getopt::Long;
10use RPC::XML;
11$RPC::XML::FORCE_STRING_ENCODING = 1;
12
13{
14    open (my $fh, "/dev/tty" )
15        or eval 'sub Term::ReadLine::findConsole { ("&STDIN", "&STDERR") }';
16    die $@ if $@;
17    close ($fh);
18}
19
20my $term = Term::ReadLine->new('LA CLI');
21$term->MinLine(99999);
22my $OUT = $term->OUT || \*STDOUT;
23
24sub denv {
25    my ($base, $dist, $vers, $arch) = @_;
26    my $env = __PACKAGE__->new(
27        {
28            prompt => sub {
29                sprintf('%s - %s - %s > ',
30                    $_[0]->{dist}{distribution},
31                    $_[0]->{dist}{release},
32                    $_[0]->{dist}{arch},
33                );
34            },
35            dist => {
36                distribution => $dist,
37                release => $vers,
38                arch => $arch,
39            },
40        },
41        $base,
42    );
43
44    $env->add_func('show', {
45            code => sub {
46                my ($self) = @_;
47
48                my $res = $self->xmlreq('distrib.struct',
49                    $self->{dist},
50                );
51                print $OUT join ('', map { "$_->{label}\n" } @{ $res->value });
52            }
53        }
54    );
55
56    $env->add_func('setpath', {
57            code => sub {
58                my ($self, $media, $path) = @_;
59                my $res = $self->xmlreq('admin.media_path',
60                    $self->{dist},
61                    $media,
62                    $path,
63                );
64            },
65            completion => sub {
66                my ($self, $start, $media) = @_;
67                if ($media) {
68                    return (<$start*>)
69                } else {
70                my $res = $self->xmlreq('distrib.struct',
71                    $self->{dist},
72                );
73                return map { $_->{label} } @{ $res->value };
74                }
75            },
76        }
77    );
78    $env->add_func('listpath', {
79            code => sub {
80                my ($self, $media) = @_;
81                my $res = $self->xmlreq('admin.list_path',
82                    $self->{dist},
83                    $media,
84                );
85                print $OUT join ('', map { "$_\n" } @{ $res->value });
86            },
87            completion => sub {
88                my ($self, $start) = @_;
89                my $res = $self->xmlreq('distrib.struct',
90                    $self->{dist},
91                );
92                return map { $_->{label} } @{ $res->value };
93            },
94        }
95    );
96    $env->add_func('addmedia', {
97            code => sub {
98                my ($self, $media, $group) = @_;
99                my $res = $self->xmlreq('admin.add_media',$self->{dist},
100                    { dist_label => $media,
101                      group_label => $group },
102                );
103                print $OUT join ('', map { "$_->{label}\n" } @{ $res->value });
104            },
105            completion => sub {
106                my ($self) = @_;
107                my $res = $self->xmlreq('distrib.struct',
108                    $self->{dist},
109                );
110                return map { $_->{label} } @{ $res->value };
111            },
112        }
113    );
114
115
116    $env
117}
118
119sub globalenv {
120    my ($base) = @_;
121    my $env = __PACKAGE__->new({}, $base);
122
123    $env->add_func('select',
124        {
125            code => sub {
126                my ($self, $dist, $ver, $arch) = @_;
127                if (!($dist && $ver && $arch)) {
128                    print $OUT "missing argument\n";
129                    return;
130                }
131                denv($self->base, $dist, $ver, $arch)->cli();
132            },
133            completion => sub {
134                my ($self, undef, @args) = @_;
135                my $res = $self->xmlreq(
136                    'distrib.list', @args);
137                return  map { $_ } @{$res->value};
138            },
139        },
140    );
141    $env->add_func('create',
142        {
143            code => sub {
144                my ($self, $dist, $ver, $arch, $label, ) = @_;
145                my $res = $self->xmlreq('admin.create', $dist, $ver, $arch);
146                print $OUT join (' ', map { $_ } @{ $res->value });
147            },
148            completion => sub {
149                my ($self, undef, @args) = @_;
150                my $res = $self->xmlreq(
151                    'distrib.list', @args);
152                return  map { $_ } @{$res->value};
153            },
154        },
155    );
156    $env->add_func('content',
157        { 
158            help => '',
159            code => sub {
160                my ($self, $dist, $ver) = @_;
161                my $res = $self->xmlreq(
162                    'distrib.list', $dist, $ver);
163                print $OUT join (' ', map { $_ } @{ $res->value });
164            },
165            completion => sub {
166                my ($self, undef, @args) = @_;
167                my $res = $self->xmlreq(
168                    'distrib.list', @args);
169                return  map { $_ } @{$res->value};
170            },
171        }
172    );
173
174    $env
175}
176
177sub new {
178    my ($class, $env, $base) = @_;
179    bless($env, $class);
180    $env->{_base} = $base;
181    $env->add_func('quit', { help => 'quit - exit the tool',
182            code => sub { print "\n"; exit(0) }, });
183    $env->add_func('exit', { help => "exit current mode",
184            code => sub { return "EXIT" }, });
185    $env->add_func('help', {
186        help => 'help [command] - print help about command',
187        completion => sub {
188            if (!$_[2]) { return sort keys %{ $_[0]->{funcs} || {}} }
189        },
190        code => sub {
191            my ($self, $name) = @_;
192            if (!$name) {
193                print $OUT join(', ', sort keys %{ $self->{funcs} || {}}) . "\n";
194            } elsif ($self->{funcs}{$name}{alias}) {
195                print $OUT "$name is an alias for " . join(' ',
196                    @{$self->{funcs}{$name}{alias}}) . "\n";
197            } elsif ($self->{funcs}{$name}{help}) {
198                print $OUT $self->{funcs}{$name}{help} . "\n";
199            } else {
200                print $OUT "No help availlable\n";
201            }
202        },
203    });
204
205    $env;
206}
207
208sub base { $_[0]->{_base} }
209
210sub cli {
211    my ($self) = @_;
212    while (1) {
213        $term->Attribs->{completion_function} = sub {
214            $self->complete($_[0], shellwords(substr($_[1], 0, $_[2])));
215        };
216        defined (my $line = $term->readline($self->prompt)) or do {
217            print $OUT "\n";
218            return;
219        };
220        $term->addhistory($line);
221        my $res = $self->run(shellwords($line));
222        $self->rollback;
223        if ($res && $res eq 'EXIT') { print $OUT "\n"; return }
224    }
225}
226
227sub prompt {
228    my ($self) = @_;
229    if (!$self->{prompt}) {
230        return "LA cli > ";
231    } else {
232        $self->{prompt}->($self);
233    }
234}
235
236sub add_func {
237    my ($self, $name, $param) = @_;
238    $self->{funcs}{$name} = $param;
239}
240
241sub getoption {
242    my ($self, $opt, @args) = @_;
243    local @ARGV = @args;
244    Getopt::Long::Configure("pass_through");
245    GetOptions(%{ $opt });
246
247    return @ARGV;
248}
249
250sub parse_arg {
251    my ($self, $name, @args) = @_;
252    return @args;
253}
254
255sub complete {
256    my ($self, $lastw, $name, @args) = @_;
257    if (!$name) {
258        return grep { /^\Q$lastw\E/ } sort
259            (keys %{ $self->{funcs} || {}});
260    } elsif ($self->{funcs}{$name}{alias}) {
261        $self->complete($lastw, @{$self->{funcs}{$name}{alias}}, @args);
262    } elsif ($self->{funcs}{$name}{completion}) {
263        my @res;
264        eval {
265        my @pargs = $self->parse_arg($name, @args);
266        @res = $self->{funcs}{$name}{completion}->($self, $lastw, @pargs);
267        };
268        return map { my $t = $_; $t =~ s/\s/\\ /g; $t } grep { $_ &&
269            /^\Q$lastw\E/ } @res;
270       
271    } else {
272        return ();
273    }
274}
275
276sub run {
277    my ($self, $name, @args) = @_;
278    return if (!$name);
279    if (!exists($self->{funcs}{$name})) {
280        print $OUT "No command $name found\n";
281    } elsif ($self->{funcs}{$name}{alias}) {
282        $self->run(@{$self->{funcs}{$name}{alias}}, @args);
283    } elsif ($self->{funcs}{$name}{code}) {
284        eval {
285        my @pargs = $self->parse_arg($name, @args);
286        $self->{funcs}{$name}{code}->($self, @args);
287        };
288    } else {
289        print $OUT "No command $name found\n";
290    }
291}
292
293sub xmlreq {
294    my ($self, $code, @args) = @_;
295    $self->base->send_request(
296        $code, @args,
297    );
298}
299
300sub commit {
301    my ($self) = @_;
302}
303
304sub rollback {
305    my ($self) = @_;
306}
307
3081;
Note: See TracBrowser for help on using the repository browser.