Changeset 2209 for trunk/LATMOS-Accounts/lib/LATMOS/Accounts/Cli.pm
- Timestamp:
- 02/20/19 10:53:50 (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LATMOS-Accounts/lib/LATMOS/Accounts/Cli.pm
r2205 r2209 5 5 use strict; 6 6 use warnings; 7 use Moose; 7 8 use LATMOS::Accounts::Log; 8 9 use LATMOS::Accounts::Utils; … … 10 11 use Text::ParseWords; 11 12 use Getopt::Long; 13 use LATMOS::Accounts::Cli::Object; 14 15 extends 'LATMOS::Accounts::Cli::Base'; 12 16 13 17 =head1 NAME … … 21 25 =cut 22 26 23 {24 open (my $fh, "/dev/tty" )25 or eval 'sub Term::ReadLine::findConsole { ("&STDIN", "&STDERR") }';26 die $@ if $@;27 close ($fh);28 }29 30 our $term = Term::ReadLine->new('LA CLI');31 $term->MinLine(99999);32 my $OUT = $term->OUT || \*STDOUT;33 34 our $trans_mode = 0;35 my $trans_start = 0;36 37 27 =head1 FUNCTIONS 38 28 … … 45 35 =cut 46 36 47 sub globalenv { 48 my ($labase) = @_; 49 my $env = LATMOS::Accounts::Cli->new({ prompt => sub { $_[0]->base->label . " cli" }, }, 50 $labase); 51 $env->add_func('unexported', { 37 sub BUILD { 38 my ( $self ) = @_; 39 40 my $labase = $self->base; 41 my $OUT = $self->Context->Out; 42 43 $self->add_func('unexported', { 52 44 help => 'unexported yes|no|show - switch or show base mode regarding' . 53 45 ' unexported objects', … … 58 50 }, 59 51 code => sub { 60 my ($ env, $arg) = @_;52 my ($self, $arg) = @_; 61 53 if ($arg eq 'yes') { 62 $ env->base->unexported(1);54 $self->base->unexported(1); 63 55 print $OUT "Unexported are now show\n"; 64 56 } elsif ($arg eq 'no') { 65 $ env->base->unexported(0);57 $self->base->unexported(0); 66 58 print $OUT "Unexported are no longer show\n"; 67 59 } elsif ($arg eq 'show') { 68 print $OUT "Unexported objects " . ($ env->base->unexported ?60 print $OUT "Unexported objects " . ($self->base->unexported ? 69 61 "enable" : "disable") . "\n"; 70 62 } else { … … 73 65 }, 74 66 }); 75 $ env->add_func('ls', {67 $self->add_func('ls', { 76 68 help => 'ls object_type - list object of type object_type', 77 69 completion => sub { … … 88 80 }, 89 81 }); 90 $ env->add_func('search', {82 $self->add_func('search', { 91 83 help => 'search objecttype filter1 [filter2...] - search object according filter', 92 84 completion => sub { … … 96 88 }, 97 89 code => sub { 98 my ($ env, @args) = @_;90 my ($self, @args) = @_; 99 91 if ($_[1]) { 100 my @res = $ env->base->search_objects(@args);92 my @res = $self->base->search_objects(@args); 101 93 print $OUT map { "$_\n" } @res; 102 $ env->{_lastsearch} = \@res;103 $ env->{_lastsearchtype} = $args[0];94 $self->{_lastsearch} = \@res; 95 $self->{_lastsearchtype} = $args[0]; 104 96 } else { 105 97 print $OUT "Object type missing\n"; … … 107 99 }, 108 100 }); 109 $ env->add_func('expired', {101 $self->add_func('expired', { 110 102 help => 'expired [delay] - list expired account more than delay (default is now)', 111 103 code => sub { 112 my ($ env, $expire) = @_;113 my @users = $ env->base->find_expired_users($expire);104 my ($self, $expire) = @_; 105 my @users = $self->base->find_expired_users($expire); 114 106 print $OUT map { "$_\n" } @users; 115 $ env->{_lastsearchtype} = 'user';116 $ env->{_lastsearch} = \@users;117 }, 118 }) if ($ env->base->can('find_expired_users'));119 $ env->add_func('expires', {107 $self->{_lastsearchtype} = 'user'; 108 $self->{_lastsearch} = \@users; 109 }, 110 }) if ($self->base->can('find_expired_users')); 111 $self->add_func('expires', { 120 112 help => 'expires [delay] - list account expiring before delay (default is 1 month)', 121 113 code => sub { 122 my ($ env, $expire) = @_;123 my @users = $ env->base->find_next_expire_users($expire);114 my ($self, $expire) = @_; 115 my @users = $self->base->find_next_expire_users($expire); 124 116 print $OUT map { "$_\n" } @users; 125 $ env->{_lastsearchtype} = 'user';126 $ env->{_lastsearch} = \@users;127 }, 128 }) if ($ env->base->can('find_next_expire_users'));129 $ env->add_func('select', {117 $self->{_lastsearchtype} = 'user'; 118 $self->{_lastsearch} = \@users; 119 }, 120 }) if ($self->base->can('find_next_expire_users')); 121 $self->add_func('select', { 130 122 help => 'select object_type - select objects to perform action on it', 131 123 completion => sub { … … 137 129 }, 138 130 code => sub { 139 my ($ env, $otype, @ids) = @_;131 my ($self, $otype, @ids) = @_; 140 132 my @objs; 141 133 if ($otype eq '@') { 142 if (@{$ env->{_lastsearch} || []}) {143 $otype = $ env->{_lastsearchtype};144 @ids = @{$ env->{_lastsearch}};134 if (@{$self->{_lastsearch} || []}) { 135 $otype = $self->{_lastsearchtype}; 136 @ids = @{$self->{_lastsearch}}; 145 137 } else { 146 138 print $OUT "No results store from previous search\n"; … … 153 145 } 154 146 foreach (@ids) { 155 my $obj = $ env->base->get_object($otype, $_) or do {147 my $obj = $self->base->get_object($otype, $_) or do { 156 148 print $OUT "Cannot get $otype $_\n"; 157 149 return; … … 160 152 } 161 153 print $OUT "Selecting $otype " . join(', ', @ids) . "\n"; 162 objenv($_[0]->base, $otype, @objs)->cli(); 154 LATMOS::Accounts::Cli::Object->new( 155 Context => $self->Context, 156 otype => $otype, 157 objs => \@objs, 158 )->cli(); 163 159 }, 164 160 }); 165 $ env->add_func('create', {166 code => sub { 167 my ($ env, $otype) = @_;168 my $helper = $ env->base->ochelper($otype);161 $self->add_func('create', { 162 code => sub { 163 my ($self, $otype) = @_; 164 my $helper = $self->base->ochelper($otype); 169 165 my $info = undef; 170 166 while (1) { … … 175 171 if ($status eq 'CREATED') { 176 172 print $OUT "Object created\n"; 177 $ env->commit;173 $self->commit; 178 174 } else { 179 175 print $OUT "Nothing done\n"; 180 $ env->rollback;176 $self->rollback; 181 177 } 182 178 return; … … 184 180 185 181 if ($info->{name}{ask}) { 186 my $line = $ term->readline("Name of the object ?");182 my $line = $self->Context->Term->readline("Name of the object ?"); 187 183 $info->{name}{content} = $line; 188 184 } 189 185 foreach my $attr (@{$info->{ask} || []}) { 190 $ term->Attribs->{completion_function} = sub {186 $self->Context->Term->Attribs->{completion_function} = sub { 191 187 $info->{contents}{$attr} 192 188 }; 193 my $line = $ term->readline(sprintf(' %s %s? ',189 my $line = $self->Context->Term->readline(sprintf(' %s %s? ', 194 190 $attr, 195 191 $info->{contents}{$attr} … … 203 199 } 204 200 ); 205 $ env->add_func('exchangeip',201 $self->add_func('exchangeip', 206 202 { 207 203 help => 'Exchange two IP on host', 208 204 code => sub { 209 my ($ env, @args) = @_;205 my ($self, @args) = @_; 210 206 my ($ip1, $ip2) = 211 207 grep { $_ && $_ =~ /\d+\.\d+\.\d+\.\d+/ } @args; … … 214 210 return; 215 211 } 216 if ($ env->base->nethost_exchange_ip($ip1, $ip2)) {212 if ($self->base->nethost_exchange_ip($ip1, $ip2)) { 217 213 print $OUT "$ip1 and $ip2 get exchange\n"; 218 $ env->commit;219 } else { 220 $ env->rollback;214 $self->commit; 215 } else { 216 $self->rollback; 221 217 } 222 218 }, 223 219 completion => sub { 224 my ($ env, $carg, @args) = @_;220 my ($self, $carg, @args) = @_; 225 221 if ($args[-1] && $args[-1] !~ m/\d+\.\d+\.\d+\.\d+/) { 226 if (my $obj = $ env->base->get_object('nethost', $args[-1])) {222 if (my $obj = $self->base->get_object('nethost', $args[-1])) { 227 223 return $obj->get_attributes('ip'); 228 224 } 229 225 } else { 230 226 my @list = 231 ($ env->base->attributes_summary('nethost', 'ip'),232 $ env->base->list_objects('nethost'));227 ($self->base->attributes_summary('nethost', 'ip'), 228 $self->base->list_objects('nethost')); 233 229 return @list; 234 230 } … … 236 232 } 237 233 ); 238 $env->add_func('user', { alias => [qw'select user' ] }); 239 $env->add_func('group', { alias => [qw'select group'] }); 240 return $env 241 } 242 243 =head2 objenv ($labase, $otype, @objs) 244 245 Return a C<cli> envirronment over object. 246 247 =cut 248 249 sub objenv { 250 my ($labase, $otype, @objs) = @_; 251 my $objenv = LATMOS::Accounts::Cli->new( 252 { 253 prompt => sub { 254 sprintf("%s %s/%s", 255 $_[0]->base->label, 256 $_[0]->{_otype}, 257 @{$_[0]->{_objects}} > 1 ? '(' . 258 scalar(@{$_[0]->{_objects}}) . ' obj.)' : $_[0]->{_objects}[0]->id, 259 ); 260 }, 261 }, 262 $labase 263 ); 264 $objenv->{_otype} = $otype; 265 $objenv->{_objects} = [ @objs ]; 266 $objenv->add_func('+', { 267 help => 'add item to selection', 268 code => sub { 269 my ($env, @ids) = @_; 270 my %ids = map { $_->id => 1 } @{$env->{_objects}}; 271 foreach (@ids) { 272 $ids{$_} and next; 273 my $o = $env->base->get_object($env->{_otype}, $_) or next; 274 push(@{$env->{_objects}}, $o); 275 } 276 printf $OUT "select is now %s: %s\n", $env->{_otype}, join(', ', map { 277 $_->id } @{$env->{_objects}}); 278 }, 279 completion => sub { 280 my ($env, undef, @ids) = @_; 281 my %ids = map { $_->id => 1 } @{$env->{_objects}}; 282 return ( grep { ! $ids{$_} } $env->base->list_objects($env->{_otype})); 283 }, 284 } 285 ); 286 $objenv->add_func('-', { 287 help => 'add item to selection', 288 code => sub { 289 my ($env, @ids) = @_; 290 my %ids = map { $_ => 1 } @ids; 291 my @newobjs = grep { !$ids{$_->id} } @{$env->{_objects}}; 292 293 if (!@newobjs) { 294 print $OUT "This would remove all objects from the list...\n"; 295 return; 296 } else { 297 @{$env->{_objects}} = @newobjs; 298 } 299 printf $OUT "select is now %s: %s\n", $env->{_otype}, join(', ', map { 300 $_->id } @{$env->{_objects}}); 301 }, 302 completion => sub { 303 my ($env, undef, @ids) = @_; 304 my %ids = map { $_ => 1 } @ids; 305 grep { !$ids{$_} } map { $_->id } @{$env->{_objects}}; 306 }, 307 } 308 ); 309 $objenv->add_func('show', { 310 help => 'show attributes - show an attributes of object', 311 code => sub { 312 my ($env, $attr) = @_; 313 if (!$attr) { 314 foreach (@{$env->{_objects}}) { 315 print $OUT $_->dump; 316 } 317 } else { 318 foreach my $u (@{$env->{_objects}}) { 319 print $OUT sort map { $u->id . ': ' .($_ || '') . "\n" } $u->get_attributes($attr); 320 } 321 } 322 }, 323 completion => sub { 324 if (!$_[2]) { 325 return $_[0]->base->list_canonical_fields($_[0]->{_otype}, 'r') 326 } 327 }, 328 }); 329 $objenv->add_func('print', { 330 help => 'print fmt - show attributes using template', 331 code => sub { 332 my ($env, $fmt) = @_; 333 if (!defined($fmt)) { 334 print $OUT "no format given"; 335 return; 336 } 337 foreach (@{$env->{_objects}}) { 338 print $OUT $_->queryformat($fmt) . "\n"; 339 } 340 }, 341 }); 342 $objenv->add_func('unset', { 343 help => 'unset attribute - unset specified attribute', 344 code => sub { 345 my ($env, $attr) = @_; 346 $attr or do { 347 print $OUT "Attributes must be specified"; 348 return; 349 }; 350 foreach (@{$env->{_objects}}) { 351 defined $_->set_c_fields($attr => undef) or do { 352 print $OUT "cannot unset attributes $attr for " . $_->id . 353 "\n"; 354 return; 355 }; 356 } 357 $env->commit; 358 print $OUT "Changes applied\n"; 359 }, 360 completion => sub { 361 my ($env, $lastw, @args) = @_; 362 if (!$args[0]) { 363 return $env->base->list_canonical_fields($env->{_otype}, 'w') 364 } 365 }, 366 }); 367 $objenv->add_func('set', { 368 help => 'set attribute value - set an attributes to single value "value"', 369 code => sub { 370 my ($env, $attr, @value) = @_; 371 @value or do { 372 print $OUT "attribute and value must be specified\n"; 373 return; 374 }; 375 foreach (@{$env->{_objects}}) { 376 defined $_->set_c_fields($attr => @value <= 1 ? $value[0] : 377 \@value) or do { 378 $_->base->rollback; 379 printf $OUT "Cannot set $attr to %s for %s\n", join(', ', 380 @value), $_->id; 381 return; 382 }; 383 } 384 $env->commit; 385 print $OUT "Done.\n"; 386 }, 387 completion => sub { 388 my ($env, $lastw, @args) = @_; 389 if (!$args[0]) { 390 return $env->base->list_canonical_fields($env->{_otype}, 'w') 391 } else { 392 my $attr = $env->base->attribute($env->{_otype}, $args[0]); 393 if ($attr->has_values_list) { 394 $attr->can_values; 395 } elsif (@{$env->{_objects}} == 1) { 396 return 397 $env->{_objects}[0]->get_attributes($args[0]); 398 } 399 } 400 }, 401 }); 402 $objenv->add_func('add', { 403 help => 'add a value to an attribute', 404 code => sub { 405 my ($env, $attr, @value) = @_; 406 @value or do { 407 print $OUT "attribute and value must be specified\n"; 408 return; 409 }; 410 foreach (@{$env->{_objects}}) { 411 my @attrv = grep { $_ } $_->get_attributes($attr); 412 defined $_->set_c_fields($attr => [ @attrv, @value ]) or do { 413 $_->base->rollback; 414 printf $OUT "Cannot set $attr to %s for %s\n", join(', ', 415 @value), $_->id; 416 return; 417 }; 418 } 419 $env->commit; 420 print $OUT "done\n"; 421 }, 422 completion => sub { 423 my ($env, $lastw, @args) = @_; 424 if (!$args[0]) { 425 return grep { 426 $env->base->attribute($env->{_otype}, $_)->{multiple} 427 } $env->base->list_canonical_fields($env->{_otype}, 'w') 428 } else { 429 my $attr = $env->base->attribute($env->{_otype}, $args[0]); 430 if ($attr->has_values_list) { 431 $attr->can_values; 432 } elsif (@{$env->{_objects}} == 1) { 433 return 434 $env->{_objects}[0]->get_attributes($args[0]); 435 } 436 } 437 }, 438 }); 439 $objenv->add_func('remove', { 440 help => 'remove a value from an attribute', 441 code => sub { 442 my ($env, $attr, @value) = @_; 443 @value or do { 444 print $OUT "attribute and value must be specified\n"; 445 return; 446 }; 447 foreach (@{$env->{_objects}}) { 448 my @attrv = grep { $_ } $_->get_attributes($attr); 449 foreach my $r (@value) { 450 @attrv = grep { $_ ne $r } @attrv; 451 } 452 defined $_->set_c_fields($attr => @attrv ? [ @attrv ] : undef) or do { 453 $_->rollback; 454 printf $OUT "Cannot set $attr to %s for %s\n", join(', ', 455 @value), $_->id; 456 return; 457 }; 458 } 459 $env->commit; 460 print $OUT "done\n"; 461 }, 462 completion => sub { 463 my ($env, $lastw, @args) = @_; 464 if (!$args[0]) { 465 return grep { 466 $env->base->attribute($env->{_otype}, $_)->{multiple} 467 } $env->base->list_canonical_fields($env->{_otype}, 'w') 468 } else { 469 my $attr = $env->base->attribute($env->{_otype}, $args[0]); 470 if (@{$env->{_objects}} == 1) { 471 return 472 $env->{_objects}[0]->get_attributes($args[0]); 473 } 474 } 475 }, 476 }); 477 $objenv->add_func('list', { 478 help => 'list current selected objects', 479 code => sub { 480 printf $OUT "%s: %s\n", $_[0]->{_otype}, join(', ', map { $_->id } 481 @{$_[0]->{_objects}}); 482 } 483 }); 484 $objenv->add_func('edit', { 485 help => 'edit [object] - edit selected object using vi', 486 completion => sub { 487 return map { $_->id } @{$_[0]->{_objects}} 488 }, 489 code => sub { 490 my ($env, $id) = @_; 491 my $obj; 492 if ($id) { 493 $obj = grep { $_->id = $id } @{$env->{_objects}} or do { 494 print $OUT "$id is not part of selected objects\n"; 495 return; 496 }; 497 } elsif (@{$env->{_objects}} == 1) { 498 $obj = $env->{_objects}[0] 499 } else { 500 print $OUT "multiple objects selected but can edit only one," 501 . "please specify which one\n"; 502 return; 503 } 504 my $res = LATMOS::Accounts::Utils::dump_read_temp_file( 505 sub { 506 my ($fh) = @_; 507 $obj->text_dump($fh, 508 { 509 empty_attr => 1, 510 only_rw => 1, 511 } 512 ); 513 }, 514 sub { 515 my ($fh) = @_; 516 my %attr = LATMOS::Accounts::Utils::parse_obj_file($fh); 517 my $res = $obj->set_c_fields(%attr); 518 if ($res) { 519 print $OUT "Changes applied\n"; 520 $env->commit; 521 } 522 else { print $OUT "Error applying changes\n" } 523 return $res ? 1 : 0; 524 } 525 ); 526 }, 527 }); 528 $objenv->add_func('delete', { 529 help => 'delete - delete selected object', 530 code => sub { 531 my ($env) = @_; 532 printf $OUT "%s: %s\ndelete selected objects ? (yes/NO)\n", 533 $env->{_otype}, join(', ', map { $_->id } @{$env->{_objects}}); 534 my $reply = <STDIN> || ''; chomp($reply); 535 if ($reply eq 'yes') { 536 foreach (@{$env->{_objects}}) { 537 $env->base->delete_object($env->{_otype}, $_->id) or do { 538 print $OUT "Cannot delete " . $_->id . "\n"; 539 return; 540 }; 541 } 542 $env->commit; 543 return "EXIT"; 544 } else { 545 print $OUT "cancel !\n" 546 } 547 }, 548 }); 549 if (grep { $objenv->base->attribute($otype, $_)->reference } 550 $objenv->base->list_canonical_fields($otype, 'r')) { 551 $objenv->add_func('select', { 552 help => 'select attribute [object]', 553 code => sub { 554 my ($env, $attrname, @objects) = @_; 555 556 my $attr = $env->base->attribute( 557 $env->{_otype}, 558 $attrname 559 ) or do { 560 print $OUT "No attribute $attrname"; 561 return; 562 }; 563 my $totype = $attr->reference or return; 564 565 if (! @objects) { 566 @objects = grep { $_ } 567 map { $_->get_attributes($attrname) } @{$env->{_objects}}; 568 } 569 { 570 my %uniq = map { $_ => 1 } @objects; 571 @objects = keys %uniq; 572 } 573 my @objs = (grep { $_ } map { $env->base->get_object($totype, $_) } 574 @objects); 575 return if (!@objs); 576 print $OUT "Selecting $otype " . join(', ', map { $_->id } @objs) . "\n"; 577 objenv($_[0]->base, $totype, @objs)->cli(); 578 }, 579 completion => sub { 580 if ($_[2]) { 581 my $totype = $_[0]->base->attribute($_[0]->{_otype}, 582 $_[2])->reference or return; 583 return grep { $_ } 584 map { $_->get_attributes($_[2]) } 585 @{$_[0]->{_objects}}; 586 } else { 587 return grep { $_[0]->base->attribute($otype, $_)->reference } 588 $_[0]->base->list_canonical_fields($otype, 'r'); 589 } 590 }, 591 } 592 ); 593 } 594 595 if (lc($otype) eq 'user') { 596 $objenv->add_func('group', { 597 help => 'group add|remove|primary goupname', 598 code => sub { 599 my ($env, $action, @groups) = @_; 600 foreach my $obj (@{$env->{_objects}}) { 601 if ($action eq 'primary') { 602 my $gid = $groups[0]; 603 if ($gid !~ /^\d/) { 604 my $gobj = $env->base->get_object('group', $gid) or 605 do { 606 print $OUT "Cannot find group $gid\n"; 607 return; 608 }; 609 $gid = $gobj->get_attributes('gidNumber'); 610 } 611 $obj->set_c_fields('gidNumber', $gid); 612 } else { 613 my %gr; 614 foreach ($obj->get_attributes('memberOf')) { 615 $gr{$_} = 1; 616 } 617 if ($action eq 'add') { 618 $gr{$_} = 1 foreach(@groups); 619 } elsif ($action eq 'remove') { 620 delete($gr{$_}) foreach(@groups); 621 } else { 622 print $OUT 'invalid action' . "\n"; 623 return; 624 } 625 defined $obj->set_c_fields('memberOf' => [ keys %gr ]) or do { 626 print $OUT "cannot set memberOf attributes for " . 627 $obj->id . "\n"; 628 return; 629 }; 630 } 631 } 632 $env->commit; 633 }, 634 completion => sub { 635 if (!$_[2]) { 636 return (qw(add remove primary)); 637 } else { 638 if ($_[2] eq 'remove') { 639 my %uniq = map { $_ => 1 } 640 grep { $_ } 641 map { $_->get_attributes('memberOf') } 642 @{$_[0]->{_objects}}; 643 return sort keys %uniq; 644 } else { 645 return $_[0]->base->search_objects('group'); 646 } 647 } 648 }, 649 }); 650 } elsif ($otype eq 'group') { 651 $objenv->add_func('member', { 652 help => 'member add|remove user', 653 code => sub { 654 my ($env, $action, @groups) = @_; 655 foreach my $obj (@{$env->{_objects}}) { 656 my %gr; 657 foreach ($obj->get_attributes('memberUID')) { 658 $gr{$_} = 1; 659 } 660 if ($action eq 'add') { 661 $gr{$_} = 1 foreach(@groups); 662 } elsif ($action eq 'remove') { 663 delete($gr{$_}) foreach(@groups); 664 } else { 665 print $OUT 'invalid action' . "\n"; 666 return; 667 } 668 defined $obj->set_c_fields('memberUID' => [ keys %gr ]) or do { 669 print $OUT "cannot set memberUID attributes for " . 670 $obj->id . "\n"; 671 return; 672 }; 673 } 674 $env->commit; 675 }, 676 completion => sub { 677 if (!$_[2]) { 678 return (qw(add remove)); 679 } else { 680 if ($_[2] eq 'remove') { 681 my %uniq = map { $_ => 1 } 682 grep { $_ } 683 map { $_->get_attributes('member') } 684 @{$_[0]->{_objects}}; 685 return sort keys %uniq; 686 } else { 687 return $_[0]->base->search_objects('user'); 688 } 689 } 690 }, 691 }); 692 } 693 694 return $objenv; 695 } 696 697 =head1 OBJECT FUNCTIONS 698 699 =head2 new ($env, $labase) 700 701 Create an envirronment object. 702 703 C<$env> is functions descriptions. 704 705 =cut 706 707 sub new { 708 my ($class, $env, $labase) = @_; 709 bless($env, $class); 710 $env->{_labase} = $labase; 711 712 if ($labase->is_transactionnal) { 713 $env->add_func( 714 'transaction', { 715 help => 'change transaction mode', 716 code => sub { 717 $trans_mode = $_[1] eq 'on' ? 1 : 0; 718 }, 719 completion => sub { 720 $trans_mode == 0 ? 'on' : 'off'; 721 }, 722 } 723 ); 724 $env->add_func( 725 'begin', { 726 help => 'Start transaction', 727 code => sub { 728 $trans_start = 1; 729 }, 730 } 731 ); 732 $env->add_func( 733 'commit', { 734 help => 'commit pending change', 735 code => sub { 736 $_[0]->_commit; 737 }, 738 } 739 ); 740 $env->add_func( 741 'rollback', { 742 help => 'commit pending change', 743 code => sub { 744 $_[0]->_rollback; 745 }, 746 } 747 ); 748 } 749 if ($labase->can('CreateAlias')) { 750 $env->add_func( 751 'newalias', { 752 help => 'Create an alias object', 753 code => sub { 754 my ($self, $otype, $name, $for) = @_; 755 if ($self->base->CreateAlias($otype, $name, $for)) { 756 print $OUT "Alias $otype/$name Created\n"; 757 $self->commit; 758 } 759 }, 760 completion => sub { 761 if ($_[3]) { 762 return $_[0]->base->list_objects($_[2]); 763 } elsif (!$_[2]) { 764 return $_[0]->base->list_supported_objects; 765 } else { 766 return; 767 } 768 } 769 }, 770 ); 771 $env->add_func( 772 'rmalias', { 773 help => 'Remove an alias object', 774 code => sub { 775 my ($self, $otype, $name) = @_; 776 if ($self->base->RemoveAlias($otype, $name)) { 777 print $OUT "Alias $otype/$name Removed\n"; 778 $self->commit; 779 } 780 }, 781 completion => sub { 782 if (!$_[2]) { 783 return $_[0]->base->list_supported_objects; 784 } else { 785 return $_[0]->base->search_objects($_[2], 'oalias=*'); 786 } 787 } 788 }, 789 ); 790 $env->add_func( 791 'updalias', { 792 help => 'Update an alias object', 793 code => sub { 794 my ($self, $otype, $name, $for) = @_; 795 my $obj = $self->base->GetAlias($otype, $name) or do { 796 print $OUT "No alias $otype/$name found"; 797 return; 798 }; 799 if ($obj->set_c_fields(oalias => $for)) { 800 print $OUT "Alias $otype/$name Updated\n"; 801 $self->commit; 802 } 803 }, 804 completion => sub { 805 if ($_[3]) { 806 return $_[0]->base->list_objects($_[2]); 807 } elsif($_[2]) { 808 return $_[0]->base->search_objects($_[2], 'oalias=*'); 809 } else { 810 return $_[0]->base->list_supported_objects; 811 } 812 } 813 }, 814 ); 815 } 816 $env->add_func('quit', { help => 'quit - exit the tool', 817 code => sub { print "\n"; exit(0) }, }); 818 $env->add_func('exit', { help => "exit current mode", 819 code => sub { return "EXIT" }, }); 820 $env->add_func('help', { 821 help => 'help [command] - print help about command', 822 completion => sub { 823 if (!$_[2]) { return sort keys %{ $_[0]->{funcs} || {}} } 824 }, 825 code => sub { 826 my ($self, $name) = @_; 827 if (!$name) { 828 print $OUT join(', ', sort keys %{ $self->{funcs} || {}}) . "\n"; 829 } elsif ($self->{funcs}{$name}{alias}) { 830 print $OUT "$name is an alias for " . join(' ', 831 @{$self->{funcs}{$name}{alias}}) . "\n"; 832 } elsif ($self->{funcs}{$name}{help}) { 833 print $OUT $self->{funcs}{$name}{help} . "\n"; 834 } else { 835 print $OUT "No help availlable\n"; 836 } 837 }, 838 }); 839 840 $env; 841 } 842 843 =head2 base 844 845 Return the attached base object. 846 847 =cut 848 849 sub base { $_[0]->{_labase} } 850 851 =head2 cli 852 853 Start the main loop 854 855 =cut 856 857 sub cli { 858 my ($self) = @_; 859 while (1) { 860 $term->Attribs->{completion_function} = sub { 861 $self->complete($_[0], shellwords(substr($_[1], 0, $_[2]))); 862 }; 863 defined (my $line = $term->readline($self->prompt)) or do { 864 print $OUT "\n"; 865 return; 866 }; 867 $term->addhistory($line); 868 my $res = $self->run(shellwords($line)); 869 $self->rollback if (!$trans_mode); 870 if ($res && $res eq 'EXIT') { print $OUT "\n"; return } 871 } 872 } 873 874 =head2 prompt 875 876 Wait user to input command 877 878 =cut 879 880 sub prompt { 881 my ($self) = @_; 882 my $pr = $self->{prompt} 883 ? $self->{prompt}->($self) 884 : "LA cli"; 885 return sprintf( 886 "%s%s%s ", 887 $pr, 888 $trans_start ? '-' : '=', 889 $trans_mode ? '#' : '>', 890 ); 891 } 892 893 =head2 add_func ($name, $param) 894 895 Add new function in the envirronment 896 897 =cut 898 899 # TODO: hide this 900 901 sub add_func { 902 my ($self, $name, $param) = @_; 903 $self->{funcs}{$name} = $param; 904 } 905 906 =head2 getoption ($opt, @args) 907 908 Parse commmand line 909 910 =cut 911 912 sub getoption { 913 my ($self, $opt, @args) = @_; 914 local @ARGV = @args; 915 Getopt::Long::Configure("pass_through"); 916 GetOptions(%{ $opt }); 917 918 return @ARGV; 919 } 920 921 =head2 complete 922 923 Return possible words according current entered words 924 925 =cut 926 927 sub complete { 928 my ($self, $lastw, $name, @args) = @_; 929 if (!$name) { 930 return grep { /^\Q$lastw\E/ } sort 931 (keys %{ $self->{funcs} || {}}); 932 } elsif ($self->{funcs}{$name}{alias}) { 933 $self->complete($lastw, @{$self->{funcs}{$name}{alias}}, @args); 934 } elsif ($self->{funcs}{$name}{completion}) { 935 return map { my $t = $_; $t =~ s/\s/\\ /g; $t } grep { $_ && /^\Q$lastw\E/ } $self->{funcs}{$name}{completion}->($self, $lastw, @args); 936 } else { 937 return (); 938 } 939 } 940 941 =head2 run ($name, @args) 942 943 Run functions 944 945 =cut 946 947 sub run { 948 my ($self, $name, @args) = @_; 949 return if (!$name); 950 if (!exists($self->{funcs}{$name})) { 951 print $OUT "No command $name found\n"; 952 } elsif ($self->{funcs}{$name}{alias}) { 953 $self->run(@{$self->{funcs}{$name}{alias}}, @args); 954 } elsif ($self->{funcs}{$name}{code}) { 955 $self->{funcs}{$name}{code}->($self, @args); 956 } else { 957 print $OUT "No command $name found\n"; 958 } 959 } 960 961 =head2 commit 962 963 Call commit to base unelss in transaction mode 964 965 =cut 966 967 sub commit { 968 my ($self) = @_; 969 if ($trans_mode || $trans_start) { 970 $trans_start = 1; 971 } else { 972 $self->_commit; 973 } 974 } 975 976 sub _commit { 977 my ($self) = @_; 978 $self->base->commit; 979 $trans_start = 0; 980 } 981 982 =head2 rollback 983 984 Perform rollback unless in transaction mode 985 986 =cut 987 988 sub rollback { 989 my ($self) = @_; 990 if ($trans_mode) { 991 print $OUT "All pending changes get rollback\n"; 992 } 993 if (!$trans_start) { 994 $self->_rollback; 995 } 996 } 997 998 sub _rollback { 999 my ($self) = @_; 1000 $self->base->rollback; 1001 $trans_start = 0; 234 $self->add_func('user', { alias => [qw'select user' ] }); 235 $self->add_func('group', { alias => [qw'select group'] }); 236 return $self 1002 237 } 1003 238
Note: See TracChangeset
for help on using the changeset viewer.