source: LATMOS-Accounts/lib/LATMOS/Accounts/Cli.pm @ 848

Last change on this file since 848 was 848, checked in by nanardon, 14 years ago
  • add delete function

factorize help code

  • Property svn:keywords set to Id
File size: 15.2 KB
Line 
1package LATMOS::Accounts::Cli;
2
3# $Id$
4
5use strict;
6use warnings;
7use LATMOS::Accounts::Log;
8use LATMOS::Accounts::Utils;
9use Term::ReadLine;
10use Text::ParseWords;
11
12my $term = Term::ReadLine->new('LA CLI');
13my $OUT = $term->OUT || \*STDOUT;
14
15sub globalenv {
16    my ($labase) = @_;
17    my $env = LATMOS::Accounts::Cli->new({ prompt => sub { $_[0]->base->label . " cli > " }, },
18        $labase);
19    $env->add_func('ls', {
20            help => 'ls object_type - list object of type object_type', 
21            completion => sub {
22                if(!$_[2]) {
23                    return $_[0]->base->list_supported_objects
24                } else { () }
25            },
26            code => sub {
27                if ($_[1]) {
28                    print $OUT map { "$_\n" } $_[0]->base->list_objects($_[1]);
29                } else {
30                    print $OUT "Object type missing";
31                }
32            },
33        });
34    $env->add_func('search', {
35            help => 'search objecttype filter1 [filter2...] - search object according filter',
36            completion => sub {
37                if(!$_[2]) {
38                    return $_[0]->base->list_supported_objects
39                } else { return() }
40            },
41            code => sub {
42                my ($env, @args) = @_;
43                if ($_[1]) {
44                    my @res = $env->base->search_objects(@args);
45                    print $OUT map { "$_\n" } @res;
46                    $env->{_lastsearch} = \@res;
47                    $env->{_lastsearchtype} = $args[0];
48                } else {
49                    print $OUT "Object type missing";
50                }
51            },
52        });
53    $env->add_func('select', {
54            help => 'select object_type - select objects to perform action on it',
55            completion => sub {
56                if ($_[2]) {
57                    return $_[0]->base->list_objects($_[2]);
58                } else {
59                    return '@', $_[0]->base->list_supported_objects;
60                }
61            },
62            code => sub {
63                my ($env, $otype, @ids) = @_;
64                my @objs;
65                if ($otype eq '@') {
66                    if (@{$env->{_lastsearch}}) {
67                        $otype = $env->{_lastsearchtype};
68                        @ids = @{$env->{_lastsearch}};
69                    } else {
70                        print $OUT "No results store from previous search";
71                        return;
72                    }
73                }
74                if (!@ids) {
75                    print $OUT 'not enough arguments';
76                    return;
77                }
78                foreach (@ids) {
79                    my $obj = $env->base->get_object($otype, $_) or do {
80                        print $OUT "Cannot get $otype $_";
81                        return;
82                    };
83                    push(@objs, $obj);
84                }
85                print $OUT "Selecting $otype " . join(', ', @ids);
86                objenv($_[0]->base, $otype, @objs)->cli();
87            },
88        });
89    $env->add_func('user',  { alias => [qw'select user' ] });
90    $env->add_func('group', { alias => [qw'select group'] });
91    return $env
92}
93
94sub objenv {
95    my ($labase, $otype, @objs) = @_;
96    my $objenv = LATMOS::Accounts::Cli->new(
97        {
98            prompt => sub {
99                sprintf("%s %s/%s > ",
100                    $_[0]->base->label,
101                    $_[0]->{_otype},
102                    @{$_[0]->{_objects}} > 1 ? '(' .
103                    scalar(@{$_[0]->{_objects}}) . ' obj.)' : $_[0]->{_objects}[0]->id,
104                );
105            },
106        },
107        $labase
108    );
109    $objenv->{_otype} = $otype;
110    $objenv->{_objects} = [ @objs ];
111    $objenv->add_func('show', {
112        help => 'show attributes - show an attributes of object',
113        code => sub {
114            my ($env, $attr) = @_;
115            if (!$attr) {
116                foreach (@{$env->{_objects}}) {
117                    print $OUT $_->dump;
118                }
119            } else {
120                foreach (@{$env->{_objects}}) {
121                    print $OUT sort map { ($_ || '') . "\n" } $_->get_attributes($attr);
122                }
123            }
124        },
125        completion => sub {
126            if (!$_[2]) {
127                return $_[0]->base->list_canonical_fields($_[0]->{_otype}, 'r')
128            }
129        },
130    });
131    $objenv->add_func('print', {
132        help => 'print fmt - show attributes using template',
133        code => sub {
134            my ($env, $fmt) = @_;
135            foreach (@{$env->{_objects}}) {
136                print $OUT $_->queryformat($fmt) . "\n";
137            }
138        },
139    });
140    $objenv->add_func('unset', {
141        help => 'unset attribute - unset specified attribute',
142        code => sub {
143            my ($env, $attr) = @_;
144            $attr or do {
145                print $OUT "Attributes must be specified";
146                return;
147            };
148            foreach (@{$env->{_objects}}) {
149                defined $_->set_c_fields($attr => undef) or do {
150                    print $OUT "cannot unset attributes $attr for " . $_->id;
151                    return;
152                };
153            }
154            $env->base->commit;
155            print $OUT "Changes applied";
156        },
157        completion => sub {
158            my ($env, $lastw, @args) = @_;
159            if (!$args[0]) {
160                return $env->base->list_canonical_fields($env->{_otype}, 'w')
161            }
162        },
163    });
164    $objenv->add_func('set', {
165        help => 'set attribute value - set an attributes to single value "value"',
166        code => sub {
167            my ($env, $attr, @value) = @_;
168            @value or do {
169                print $OUT "attribute and value must be specified";
170                return;
171            };
172            foreach (@{$env->{_objects}}) {
173                defined $_->set_c_fields($attr => @value <= 1 ? $value[0] :
174                    \@value) or do {
175                    $_->base->rollback;
176                    printf $OUT "Cannot set $attr to %s for %s", join(', ',
177                        @value), $_->id;
178                    return;
179                };
180            }
181            $env->base->commit;
182            print $OUT "done";
183        },
184        completion => sub {
185            my ($env, $lastw, @args) = @_;
186            if (!$args[0]) {
187                return $env->base->list_canonical_fields($env->{_otype}, 'w')
188            } else {
189                if ($env->base->obj_attr_allowed_values($env->{_otype}, $args[0])) {
190                    return $env->base->obj_attr_allowed_values($env->{_otype}, $args[0])
191                }
192                for ($args[0]) {
193                    /^manager|managedBy$/ and return
194                        $env->base->search_objects('user');
195                    /^department$/ and return
196                        $env->base->search_objects('group', 'sutype=dpmt');
197                    /^contratType$/ and return
198                        $env->base->search_objects('group', 'sutype=contrattype');
199                    /^site$/ and return
200                        $env->base->search_objects('site');
201                    if (@{$env->{_objects}} == 1) {
202                        return $env->{_objects}[0]->get_attributes($args[0]);
203                    }
204                }
205            }
206        },
207    });
208    $objenv->add_func('list', {
209        help => 'list current selected objects',
210        code => sub {
211            printf $OUT "%s: %s", $_[0]->{_otype}, join(', ', map { $_->id }
212            @{$_[0]->{_objects}});
213        }
214    });
215    $objenv->add_func('edit', {
216            help => 'edit [object] - edit selected object using vi',
217            completion => sub {
218                return map { $_->id } @{$_[0]->{_objects}}
219            },
220            code => sub {
221                my ($env, $id) = @_;
222                my $obj;
223                if ($id) {
224                    $obj = grep { $_->id = $id } @{$env->{_objects}} or do {
225                        print $OUT "$id is not part of selected objects";
226                        return;
227                    };
228                } elsif (@{$env->{_objects}} == 1) {
229                    $obj = $env->{_objects}[0]
230                } else {
231                    print $OUT "multiple objects selected but can edit only one,"
232                    . "please specify which one";
233                    return;
234                }
235                my $res = LATMOS::Accounts::Utils::dump_read_temp_file(
236                    sub {
237                        my ($fh) = @_;
238                        $obj->text_dump($fh,
239                            {
240                                empty_attr => 1,
241                                only_rw => 1,
242                            }
243                        );
244                    },
245                    sub {
246                        my ($fh) = @_;
247                        my %attr = LATMOS::Accounts::Utils::parse_obj_file($fh);
248                        my $res = $obj->set_c_fields(%attr);
249                        if ($res) {
250                            print $OUT "Changes applied";
251                            $env->base->commit;
252                        }
253                        else { print $OUT "Error applying changes" }
254                        return $res ? 1 : 0;
255                    }
256                );
257            },
258        });
259    $objenv->add_func('delete', {
260        help => 'delete - delete selected object',
261        code => sub {
262            my ($env) = @_;
263            printf $OUT "%s: %s\ndelete selected objects ? (yes/NO) ",
264            $env->{_otype}, join(', ', map { $_->id } @{$env->{_objects}});
265            my $reply = <STDIN> || ''; chomp($reply);
266            if ($reply eq 'yes') {
267                foreach (@{$env->{_objects}}) {
268                    $env->base->delete_object($env->{_otype}, $_->id) or do {
269                        print $OUT "Cannot delete " . $_->id;
270                        return;
271                    };
272                }
273                $env->base->commit;
274                return "EXIT";
275            } else {
276                print $OUT "cancel !"
277            }
278        },
279    });
280
281    if (lc($otype) eq 'user') {
282        $objenv->add_func('group', {
283            help => 'group add|remove goupname',
284            code => sub {
285                my ($env, $action, @groups) = @_;
286                foreach my $obj (@{$env->{_objects}}) {
287                    my %gr;
288                    foreach ($obj->get_attributes('memberOf')) {
289                        $gr{$_} = 1;
290                    }
291                    if ($action eq 'add') {
292                        $gr{$_} = 1 foreach(@groups);
293                    } elsif ($action eq 'remove') {
294                        delete($gr{$_}) foreach(@groups);
295                    } else {
296                        print $OUT 'invalid action';
297                        return;
298                    }
299                    defined $obj->set_c_fields('memberOf' => [ keys %gr ]) or do {
300                        print $OUT "cannot set memberOf attributes for " .
301                        $obj->id;
302                        return;
303                    };
304                }
305                $env->base->commit;
306            },
307            completion => sub {
308                if (!$_[2]) {
309                    return (qw(add remove));
310                } else {
311                    return $_[0]->base->search_objects('group');
312                }
313            },
314        });
315    } elsif ($otype eq 'group') {
316        $objenv->add_func('member', {
317            help => 'member add|remove user',
318            code => sub {
319                my ($env, $action, @groups) = @_;
320                foreach my $obj (@{$env->{_objects}}) {
321                    my %gr;
322                    foreach ($obj->get_attributes('memberUID')) {
323                        $gr{$_} = 1;
324                    }
325                    if ($action eq 'add') {
326                        $gr{$_} = 1 foreach(@groups);
327                    } elsif ($action eq 'remove') {
328                        delete($gr{$_}) foreach(@groups);
329                    } else {
330                        print $OUT 'invalid action';
331                        return;
332                    }
333                    defined $obj->set_c_fields('memberUID' => [ keys %gr ]) or do {
334                        print $OUT "cannot set memberUID attributes for " .
335                        $obj->id;
336                        return;
337                    };
338                }
339                $env->base->commit;
340            },
341            completion => sub {
342                if (!$_[2]) {
343                    return (qw(add remove));
344                } else {
345                    return $_[0]->base->search_objects('user');
346                }
347            },
348        });
349    }
350
351    return $objenv;
352}
353
354sub new {
355    my ($class, $env, $labase) = @_;
356    bless($env, $class);
357    $env->{_labase} = $labase;
358    $env->add_func('quit', { help => 'quit - exit the tool',
359            code => sub { print "\n"; exit(0) }, });
360    $env->add_func('exit', { help => "exit current mode",
361            code => sub { return "EXIT" }, });
362    $env->add_func('help', {
363        help => 'help [command] - print help about command',
364        completion => sub {
365            if (!$_[2]) { return sort keys %{ $_[0]->{funcs} || {}} }
366        },
367        code => sub {
368            my ($self, $name) = @_;
369            if (!$name) {
370                print $OUT join(', ', sort keys %{ $self->{funcs} || {}});
371            } elsif ($self->{funcs}{$name}{alias}) {
372                print $OUT "$name is an alias for " . join(' ',
373                    @{$self->{funcs}{$name}{alias}});
374            } elsif ($self->{funcs}{$name}{help}) {
375                print $OUT $self->{funcs}{$name}{help};
376            } else {
377                print $OUT "No help availlable";
378            }
379        },
380    });
381
382    $env;
383}
384
385sub base { $_[0]->{_labase} }
386
387sub cli {
388    my ($self) = @_;
389    while (1) {
390        $term->Attribs->{completion_function} = sub {
391            $self->complete($_[0], shellwords(substr($_[1], 0, $_[2])));
392        };
393        defined (my $line = $term->readline($self->prompt)) or return;
394        my $res = $self->run(shellwords($line));
395        $self->base->rollback;
396        if ($res && $res eq 'EXIT') { return }
397    }
398}
399
400sub prompt {
401    my ($self) = @_;
402    if (!$self->{prompt}) {
403        return "LA cli > ";
404    } else {
405        $self->{prompt}->($self);
406    }
407}
408
409sub add_func {
410    my ($self, $name, $param) = @_;
411    $self->{funcs}{$name} = $param;
412}
413
414sub parse_arg {
415    my ($self, $name, @args) = @_;
416    if ($self->{funcs}{$name}{opt}) {
417        @ARGV = @args;
418    } else {
419        return @args;
420    }
421    return @ARGV;
422}
423
424sub complete {
425    my ($self, $lastw, $name, @args) = @_;
426    if (!$name) {
427        return grep { /^\Q$lastw\E/ } sort
428            (keys %{ $self->{funcs} || {}});
429    } elsif ($self->{funcs}{$name}{alias}) {
430        $self->complete($lastw, @{$self->{funcs}{$name}{alias}}, @args);
431    } elsif ($self->{funcs}{$name}{completion}) {
432        my @pargs = $self->parse_arg($name, @args);
433        return map { my $t = $_; $t =~ s/\s/\\ /g; $t } grep { $_ && /^\Q$lastw\E/ } $self->{funcs}{$name}{completion}->($self, $lastw, @pargs);
434    } else {
435        return ();
436    }
437}
438
439sub run {
440    my ($self, $name, @args) = @_;
441    return if (!$name);
442    if ($self->{funcs}{$name}{alias}) {
443        $self->run(@{$self->{funcs}{$name}{alias}}, @args);
444    } elsif ($self->{funcs}{$name}{code}) {
445        my @pargs = $self->parse_arg($name, @args);
446        $self->{funcs}{$name}{code}->($self, @args);
447    }
448}
449
4501;
Note: See TracBrowser for help on using the repository browser.