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

Last change on this file since 285 was 285, checked in by nanardon, 14 years ago
  • add function to delete expired sessions
File size: 12.8 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                    my $res = $self->xmlreq('admin.ls_local', $start);
69                    return @{ $res->value };
70                } else {
71                my $res = $self->xmlreq('distrib.struct',
72                    $self->{dist},
73                );
74                return map { $_->{label} } @{ $res->value };
75                }
76            },
77        }
78    );
79    $env->add_func('unsetpath', {
80            code => sub {
81                my ($self, $media, $path) = @_;
82                my $res = $self->xmlreq('admin.media_remove_path',
83                    $self->{dist},
84                    $media,
85                    $path,
86                );
87            },
88            completion => sub {
89                my ($self, $start, $media) = @_;
90                if ($media) {
91                    my $res = $self->xmlreq('admin.list_path',
92                        $self->{dist},
93                        $media,
94                    );
95                    return @{ $res->value };
96                } else {
97                my $res = $self->xmlreq('distrib.struct',
98                    $self->{dist},
99                );
100                return map { $_->{label} } @{ $res->value };
101                }
102            },
103        }
104    );
105    $env->add_func('listpath', {
106            code => sub {
107                my ($self, $media) = @_;
108                my $res = $self->xmlreq('admin.list_path',
109                    $self->{dist},
110                    $media,
111                );
112                print $OUT join ('', map { "$_\n" } @{ $res->value });
113            },
114            completion => sub {
115                my ($self, $start) = @_;
116                my $res = $self->xmlreq('distrib.struct',
117                    $self->{dist},
118                );
119                return map { $_->{label} } @{ $res->value };
120            },
121        }
122    );
123    $env->add_func('replace_path',
124        {
125            help => '',
126            code => sub {
127                my ($self, $path, $newpath) = @_;
128                my $res = $self->xmlreq(
129                    '/admin/replace_path', $path, $newpath);
130                print $OUT join (' ', map { $_ } @{ $res->value });
131                print $OUT "\n";
132            },
133            completion => sub {
134                my ($self, $start, $oldpath) = @_;
135                if ($oldpath) {
136                    my $res = $self->xmlreq('admin.ls_local', $start);
137                    return @{ $res->value };
138                } else {
139                    my $res = $self->xmlreq('admin.list_path',
140                        $self->{dist},
141                    );
142                    return @{ $res->value };
143                }
144            },
145        }
146    );
147    $env->add_func('remove_media',
148        {
149            help => '',
150            code => sub {
151                my ($self, $media) = @_;
152                my $res = $self->xmlreq(
153                    '/admin/remove_media', $self->{dist}, $media);
154                print $OUT join (' ', map { $_ } @{ $res->value });
155                print $OUT "\n";
156            },
157            completion => sub {
158                my ($self) = @_;
159                my $res = $self->xmlreq('distrib.struct',
160                    $self->{dist},
161                );
162                return map { $_->{label} } @{ $res->value };
163            },
164        }
165    );
166    $env->add_func('addmedia', {
167            code => sub {
168                my ($self, $media, $group) = @_;
169                my $res = $self->xmlreq('admin.add_media',$self->{dist},
170                    { label => $media,
171                      group_label => $group },
172                );
173                print $OUT join ('', map { "$_->{label}\n" } @{ $res->value });
174            },
175            completion => sub {
176                my ($self, $start, $label) = @_;
177                my $res = $self->xmlreq('distrib.struct',
178                    $self->{dist},
179                );
180                return ((map { $_->{label} } @{ $res->value }), $label ?
181                    ($label) : ())
182            },
183        }
184    );
185
186
187    $env
188}
189
190sub globalenv {
191    my ($base) = @_;
192    my $env = __PACKAGE__->new({}, $base);
193
194    $env->add_func('delete_expired_sessions',
195        {
196            code => sub {
197                my ($self, $match) = @_;
198                my $res =
199                $self->xmlreq('admin.maintenance.delete_expired_sessions', $match);
200                if ($res) {
201                    print $OUT (map { "$_\n" } @{ $res->value });
202                }
203            }
204        }
205    );
206    $env->add_func('list_user',
207        {
208            code => sub {
209                my ($self, $match) = @_;
210                my $res = $self->xmlreq('admin.list_user', $match);
211                if ($res) {
212                    print $OUT (map { "$_\n" } @{ $res->value });
213                }
214            }
215        }
216    );
217    $env->add_func('delete_user',
218        {
219            code => sub {
220                my ($self, $match) = @_;
221                my $res = $self->xmlreq('admin.delete_user', $match);
222                if ($res) {
223                    print $OUT $res->value . "\n";
224                }
225            },
226            completion => sub {
227                my ($self, undef, @args) = @_;
228                my $res = $self->xmlreq(
229                    'admin.list_user');
230                return @{$res->value};
231            },
232        }
233    );
234    $env->add_func('set_password',
235        {
236            code => sub {
237                my ($self, $match, $password) = @_;
238                my $res = $self->xmlreq('admin.set_user_password', $match,
239                    $password);
240                if ($res) {
241                    print $OUT $res->value . "\n";
242                }
243            },
244            completion => sub {
245                my ($self, undef, $user) = @_;
246                if (!$user) {
247                my $res = $self->xmlreq(
248                    'admin.list_user');
249                return @{$res->value};
250                } else { return }
251            },
252        }
253    );
254    $env->add_func('create_user',
255        {
256            code => sub {
257                my ($self, $user, $password) = @_;
258                my $res = $self->xmlreq('admin.create_user', $user, $password);
259                if ($res) {
260                    print $OUT $res->value . "\n";
261                }
262            },
263        }
264    );
265    $env->add_func('select',
266        {
267            code => sub {
268                my ($self, $dist, $ver, $arch) = @_;
269                if (!($dist && $ver && $arch)) {
270                    print $OUT "missing argument\n";
271                    return;
272                }
273                denv($self->base, $dist, $ver, $arch)->cli();
274            },
275            completion => sub {
276                my ($self, undef, @args) = @_;
277                my $res = $self->xmlreq(
278                    'distrib.list', @args);
279                return @{$res->value};
280            },
281        },
282    );
283    $env->add_func('create',
284        {
285            code => sub {
286                my ($self, $dist, $ver, $arch, $label, ) = @_;
287                my $res = $self->xmlreq('admin.create', $dist, $ver, $arch);
288                print $OUT join (' ', map { $_ } @{ $res->value });
289            },
290            completion => sub {
291                my ($self, undef, @args) = @_;
292                my $res = $self->xmlreq(
293                    'distrib.list', @args);
294                return  map { $_ } @{$res->value};
295            },
296        },
297    );
298    $env->add_func('content',
299        { 
300            help => '',
301            code => sub {
302                my ($self, $dist, $ver) = @_;
303                my $res = $self->xmlreq(
304                    'distrib.list', $dist, $ver);
305                print $OUT join (' ', map { $_ } @{ $res->value });
306            },
307            completion => sub {
308                my ($self, undef, @args) = @_;
309                my $res = $self->xmlreq(
310                    'distrib.list', @args);
311                return  map { $_ } @{$res->value};
312            },
313        }
314    );
315
316    $env
317}
318
319sub new {
320    my ($class, $env, $base) = @_;
321    bless($env, $class);
322    $env->{_base} = $base;
323    $env->add_func('quit', { help => 'quit - exit the tool',
324            code => sub { print "\n"; exit(0) }, });
325    $env->add_func('exit', { help => "exit current mode",
326            code => sub { return "EXIT" }, });
327    $env->add_func('help', {
328        help => 'help [command] - print help about command',
329        completion => sub {
330            if (!$_[2]) { return sort keys %{ $_[0]->{funcs} || {}} }
331        },
332        code => sub {
333            my ($self, $name) = @_;
334            if (!$name) {
335                print $OUT join(', ', sort keys %{ $self->{funcs} || {}}) . "\n";
336            } elsif ($self->{funcs}{$name}{alias}) {
337                print $OUT "$name is an alias for " . join(' ',
338                    @{$self->{funcs}{$name}{alias}}) . "\n";
339            } elsif ($self->{funcs}{$name}{help}) {
340                print $OUT $self->{funcs}{$name}{help} . "\n";
341            } else {
342                print $OUT "No help availlable\n";
343            }
344        },
345    });
346
347    $env;
348}
349
350sub base { $_[0]->{_base} }
351
352sub cli {
353    my ($self) = @_;
354    while (1) {
355        $term->Attribs->{completion_function} = sub {
356            $self->complete($_[0], shellwords(substr($_[1], 0, $_[2])));
357        };
358        defined (my $line = $term->readline($self->prompt)) or do {
359            print $OUT "\n";
360            return;
361        };
362        $term->addhistory($line);
363        my $res = $self->run(shellwords($line));
364        $self->rollback;
365        if ($res && $res eq 'EXIT') { print $OUT "\n"; return }
366    }
367}
368
369sub prompt {
370    my ($self) = @_;
371    if (!$self->{prompt}) {
372        return "LA cli > ";
373    } else {
374        $self->{prompt}->($self);
375    }
376}
377
378sub add_func {
379    my ($self, $name, $param) = @_;
380    $self->{funcs}{$name} = $param;
381}
382
383sub getoption {
384    my ($self, $opt, @args) = @_;
385    local @ARGV = @args;
386    Getopt::Long::Configure("pass_through");
387    GetOptions(%{ $opt });
388
389    return @ARGV;
390}
391
392sub parse_arg {
393    my ($self, $name, @args) = @_;
394    return @args;
395}
396
397sub complete {
398    my ($self, $lastw, $name, @args) = @_;
399    if (!$name) {
400        return grep { /^\Q$lastw\E/ } sort
401            (keys %{ $self->{funcs} || {}});
402    } elsif ($self->{funcs}{$name}{alias}) {
403        $self->complete($lastw, @{$self->{funcs}{$name}{alias}}, @args);
404    } elsif ($self->{funcs}{$name}{completion}) {
405        my @res;
406        eval {
407        my @pargs = $self->parse_arg($name, @args);
408        @res = $self->{funcs}{$name}{completion}->($self, $lastw, @pargs);
409        };
410        return map { my $t = $_; $t =~ s/\s/\\ /g; $t } grep { $_ &&
411            /^\Q$lastw\E/ } @res;
412       
413    } else {
414        return ();
415    }
416}
417
418sub run {
419    my ($self, $name, @args) = @_;
420    return if (!$name);
421    if (!exists($self->{funcs}{$name})) {
422        print $OUT "No command $name found\n";
423    } elsif ($self->{funcs}{$name}{alias}) {
424        $self->run(@{$self->{funcs}{$name}{alias}}, @args);
425    } elsif ($self->{funcs}{$name}{code}) {
426        eval {
427        my @pargs = $self->parse_arg($name, @args);
428        $self->{funcs}{$name}{code}->($self, @args);
429        };
430    } else {
431        print $OUT "No command $name found\n";
432    }
433}
434
435sub xmlreq {
436    my ($self, $code, @args) = @_;
437    my $res = $self->base->send_request(
438        $code, @args,
439    );
440}
441
442sub commit {
443    my ($self) = @_;
444}
445
446sub rollback {
447    my ($self) = @_;
448}
449
4501;
Note: See TracBrowser for help on using the repository browser.