source: client/trunk/lib/Sophie/Cli.pm @ 4

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