source: trunk/LATMOS-Accounts/lib/LATMOS/Accounts/Cli/Base.pm @ 2212

Last change on this file since 2212 was 2212, checked in by nanardon, 5 years ago

Add options query like la-query

File size: 10.2 KB
Line 
1package LATMOS::Accounts::Cli::Base;
2
3# $Id: Cli.pm 2145 2018-08-29 18:15:46Z nanardon $
4
5use strict;
6use warnings;
7use Moose;
8use LATMOS::Accounts::Cli::Context;
9use LATMOS::Accounts::Log;
10use LATMOS::Accounts::Utils;
11use Term::ReadLine;
12use Text::ParseWords;
13use Getopt::Long;
14
15=head1 NAME
16
17LATMOS::Accounts::Cli - Command line interface functions
18
19=head1 DESCRIPTION
20
21This module handle envirronment and functons for L<la-cli> tools.
22
23=cut
24
25has Context => ( is => 'ro', isa => 'LATMOS::Accounts::Cli::Context' );
26
27=head1 FUNCTIONS
28
29=cut
30
31=head1 CLI FUNCTIONS
32
33=cut
34
35sub BUILD {
36    my $self = shift;
37
38    my $OUT = $self->Context->Out;
39
40    if ($self->base->is_transactionnal) {
41        $self->add_func(
42            'transaction', {
43                help => 'change transaction mode',
44                code => sub {
45                    $self->Context->TransMode($_[1] eq 'on' ? 1 : 0);
46                },
47                completion => sub {
48                    $self->Context->TransMode == 0 ? 'on' : 'off';
49                },
50            }
51        );
52        $self->add_func(
53            'begin', {
54                help => 'Start transaction',
55                code => sub {
56                    $self->Context->TransStarted(1);
57                },
58            }
59        );
60        $self->add_func(
61            'commit', {
62                help => 'commit pending change',
63                code => sub {
64                    $_[0]->_commit;
65                },
66            }
67        );
68        $self->add_func(
69            'rollback', {
70                help => 'commit pending change',
71                code => sub {
72                    $_[0]->_rollback;
73                },
74            }
75        );
76    }
77    if ($self->base->can('CreateAlias')) {
78        $self->add_func(
79            'newalias', {
80                help => 'Create an alias object',
81                code => sub {
82                    my ($self, $otype, $name, $for) = @_;
83                    if ($self->base->CreateAlias($otype, $name, $for)) {
84                        print $OUT "Alias $otype/$name Created\n";
85                        $self->commit;
86                    }
87                },
88                completion => sub {
89                    if ($_[3]) {
90                        return $_[0]->base->list_objects($_[2]);
91                    } elsif (!$_[2]) {
92                        return $_[0]->base->list_supported_objects;
93                    } else {
94                        return;
95                    }
96                }
97            },
98        );
99        $self->add_func(
100            'rmalias', {
101                help => 'Remove an alias object',
102                code => sub {
103                    my ($self, $otype, $name) = @_;
104                    if ($self->base->RemoveAlias($otype, $name)) {
105                        print $OUT "Alias $otype/$name Removed\n";
106                        $self->commit;
107                    }
108                },
109                completion => sub {
110                    if (!$_[2]) {
111                        return $_[0]->base->list_supported_objects;
112                    } else {
113                        return $_[0]->base->search_objects($_[2], 'oalias=*');
114                    }
115                }
116            },
117        );
118        $self->add_func(
119            'updalias', {
120                help => 'Update an alias object',
121                code => sub {
122                    my ($self, $otype, $name, $for) = @_;
123                    my $obj = $self->base->GetAlias($otype, $name) or do {
124                        print $OUT "No alias $otype/$name found";
125                        return;
126                    };
127                    if ($obj->set_c_fields(oalias => $for)) {
128                        print $OUT "Alias $otype/$name Updated\n";
129                        $self->commit;
130                    }
131                },
132                completion => sub {
133                    if ($_[3]) {
134                        return $_[0]->base->list_objects($_[2]);
135                    } elsif($_[2]) {
136                        return $_[0]->base->search_objects($_[2], 'oalias=*');
137                    } else {
138                        return $_[0]->base->list_supported_objects;
139                    }
140                }
141            },
142        );
143    }
144    $self->add_func('quit', { help => 'quit - exit the tool',
145            code => sub { print "\n"; exit(0) }, });
146    $self->add_func('exit', { help => "exit current mode",
147            code => sub { return "EXIT" }, });
148    $self->add_func('help', {
149        help => 'help [command] - print help about command',
150        completion => sub {
151            if (!$_[2]) { return sort keys %{ $_[0]->{funcs} || {}} }
152        },
153        code => sub {
154            my ($self, $name) = @_;
155            if (!$name) {
156                print $OUT join(', ', sort keys %{ $self->{funcs} || {}}) . "\n";
157            } elsif ($self->{funcs}{$name}{alias}) {
158                print $OUT "$name is an alias for " . join(' ',
159                    @{$self->{funcs}{$name}{alias}}) . "\n";
160            } elsif ($self->{funcs}{$name}{help}) {
161                print $OUT $self->{funcs}{$name}{help} . "\n";
162            } else {
163                print $OUT "No help availlable\n";
164            }
165        },
166    });
167
168    $self->add_func( 'query' => {
169            proxy => '*',
170            help  => 'show attribute',
171            completion => sub { },
172            code => sub {
173                my $env = shift;
174                my @args = $self->getoption(
175                    {
176                        'o|object=s' => \my $otype,
177                        'e|empty'    => \my $empty_attr,
178                        'ro'         => \my $with_ro,
179                        'fmt=s'      => \my $fmt,
180                        'filefmt=s'  => \my $filefmt,
181                    }, @_
182                );
183                $otype ||= 'user';
184
185                my $objs = $self->Context->{objs};
186
187                if (! $objs ) {
188                    foreach my $name (@args) {
189                        my $obj = $self->base->get_object( $otype, $name) or do {
190                            $self->print("Cannot get object $otype/$name\n");
191                            next;
192                        };
193                        push(@{ $objs }, $obj);
194                    }
195                }
196
197                if ($filefmt){
198                    open(my $hfmt, '<', $filefmt) or die "Cannot open $filefmt\n";
199                    $fmt ||= ''; # avoid undef warning
200                    while (<$hfmt>) {
201                        chomp($fmt .= $_);
202                    }
203                    close $hfmt;
204                }
205
206                foreach (@{ $objs }) {
207                    if ($fmt) {
208                        $self->print($_->queryformat($fmt));
209                    } else {
210                        $_->text_dump( $self->Context->Out, {
211                            empty_attr => $empty_attr,
212                            only_rw => !$with_ro,
213                        } );
214                    }
215                }
216            },
217    } );
218}
219
220=head2 base
221
222Return the attached base object.
223
224=cut
225
226sub base { $_[0]->Context->base }
227sub term { $_[0]->Context->Term }
228sub print { shift->Context->print(@_) }
229
230=head2 cli
231
232Start the main loop
233
234=cut
235
236sub cli {
237    my ($self) = @_;
238
239    my $term = $_[0]->Context->Term;
240
241    while (1) {
242        $term->Attribs->{completion_function} = sub {
243            $self->complete($_[0], shellwords(substr($_[1], 0, $_[2])));
244        };
245        defined (my $line = $term->readline($self->prompt)) or do {
246            $self->print("\n");
247            return;
248        };
249        $term->addhistory($line);
250        my $res = $self->run(shellwords($line));
251        $self->rollback if (!$self->Context->TransMode);
252        if ($res && $res eq 'EXIT') { $self->print("\n"); return }
253    }
254}
255
256=head2 prompt
257
258Wait user to input command
259
260=cut
261
262sub promptPrefix { 'LA cli' }
263
264sub prompt {
265    my ($self) = @_;
266    my $pr = $self->promptPrefix;
267    return sprintf(
268        "%s%s%s ",
269        $pr,
270        $self->Context->TransStarted ? '-' : '=',
271        $self->Context->TransMode  ? '#' : '>',
272    );
273}
274
275=head2 add_func ($name, $param)
276
277Add new function in the envirronment
278
279=cut
280
281# TODO: hide this
282
283sub add_func {
284    my ($self, $name, $param) = @_;
285    $self->{funcs}{$name} = $param;
286}
287
288=head2 getoption ($opt, @args)
289
290Parse commmand line
291
292=cut
293
294sub getoption {
295    my ($self, $opt, @args) = @_;
296    local @ARGV = @args;
297    Getopt::Long::Configure("pass_through");
298    GetOptions(%{ $opt });
299
300    return @ARGV;
301}
302
303=head2 complete
304
305Return possible words according current entered words
306
307=cut
308
309sub complete {
310    my ($self, $lastw, $name, @args) = @_;
311    if (!$name) {
312        return grep { /^\Q$lastw\E/ } sort
313            (keys %{ $self->{funcs} || {}});
314    } elsif ($self->{funcs}{$name}{alias}) {
315        $self->complete($lastw, @{$self->{funcs}{$name}{alias}}, @args);
316    } elsif ($self->{funcs}{$name}{completion}) {
317        return map { my $t = $_; $t =~ s/\s/\\ /g; $t } grep { $_ && /^\Q$lastw\E/ } $self->{funcs}{$name}{completion}->($self, $lastw, @args);
318    } else {
319        return ();
320    }
321}
322
323=head2 run ($name, @args)
324
325Run functions
326
327=cut
328
329sub run {
330    my ($self, $name, @args) = @_;
331    return if (!$name);
332    if (!exists($self->{funcs}{$name})) {
333        $self->print("No command $name found\n");
334    } elsif ($self->{funcs}{$name}{alias}) {
335        $self->run(@{$self->{funcs}{$name}{alias}}, @args);
336    } elsif ($self->{funcs}{$name}{code}) {
337        $self->{funcs}{$name}{code}->($self, @args);
338    } else {
339        $self->print("No command $name found\n");
340    }
341}
342
343=head2 commit
344
345Call commit to base unelss in transaction mode
346
347=cut
348
349sub commit {
350    my ($self) = @_;
351    $self->Context->commit;
352}
353
354sub _commit {
355    my ($self) = @_;
356    $self->Context->_commit;
357}
358
359=head2 rollback
360
361Perform rollback unless in transaction mode
362
363=cut
364
365sub rollback {
366    my ($self) = @_;
367    $self->Context->rollback;
368}
369
370sub _rollback {
371    my ($self) = @_;
372    $self->Context->_rollback;
373}
374
3751;
376
377__END__
378
379=head1 SEE ALSO
380
381L<LATMOS::Accounts>
382
383=head1 AUTHOR
384
385Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
386
387=head1 COPYRIGHT AND LICENSE
388
389Copyright (C) 2008, 2009, 2010, 2011, 2012 CNRS SA/CETP/LATMOS
390
391This library is free software; you can redistribute it and/or modify
392it under the same terms as Perl itself, either Perl version 5.10.0 or,
393at your option, any later version of Perl 5 you may have available.
394
395=cut
Note: See TracBrowser for help on using the repository browser.