App-Ordo
view release on metacpan or search on metacpan
lib/App/Ordo.pm view on Meta::CPAN
package App::Ordo;
use strict;
use warnings;
use feature qw(say);
use Moo;
use Exporter 'import';
use JSON qw(encode_json);
use File::Path qw(make_path);
use File::Copy qw(copy);
use File::ShareDir qw(dist_file);
use Term::ANSIColor qw(colored);
use Term::ReadLine::Perl5;
use Term::ReadKey qw(ReadMode ReadKey GetTerminalSize);
use Email::Valid;
use App::Ordo::API;
our @EXPORT_OK = qw(
$CURRENT_PATH
extract_command
epoch_to_tminus
epoch_to_duration
);
our $VERSION = '0.06';
our $CURRENT_PATH = '/';
has 'api' => (
is => 'lazy',
default => sub { App::Ordo::API->new },
);
# ------------------------------------------------------------------
# Session / Auth
# ------------------------------------------------------------------
sub ensure_session {
my ($self) = @_;
my $config = $self->api->config;
my $token = $config->{token} // '';
my $res = $self->api->call('login_user', { token => $token });
if ($res->{success}) {
$CURRENT_PATH = $res->{path} // '/';
say colored(["bold green"], "Connected to " . $self->api->config->{api} . " as $res->{email}");
return $res;
}
say colored(["bold yellow"], "No valid token found");
return $self->prompt_for_token;
}
sub prompt_for_token {
my $self = shift;
while (1) {
print colored(["bold white"], "Enter API token: ");
chomp(my $token = <STDIN>);
$token =~ s/^\s+|\s+$//g;
my $res = $self->api->call('login_user', { token => $token });
if ($res->{success} && $res->{level} >= 1) {
my $config = $self->api->config;
$config->{token} = $token;
open my $fh, '>', $self->api->config_file or die "Cannot save config: $!";
print $fh encode_json($config);
close $fh;
$CURRENT_PATH = $res->{path} // '/';
say colored(["bold green"], "Logged in successfully");
return $res;
}
say colored(["bold red"], $res->{message} || "Invalid token");
}
}
# ------------------------------------------------------------------
# Interactive Shell
# ------------------------------------------------------------------
sub run_interactive {
my $self = shift;
$self->ensure_session;
my $term = Term::ReadLine::Perl5->new('ordo');
say colored(["bold white"], "\nWelcome to Ordo - the hierarchical job scheduler");
say "Type 'help' for commands, Ctrl-D to exit.\n";
while (defined(my $line = $term->readline("ordo:$CURRENT_PATH> "))) {
$line =~ s/^\s+|\s+$//g;
next unless $line;
my @args = extract_command($line);
App::Ordo::Runner->new(api => $self->api)->run(@args);
}
say colored(["bold yellow"], "\nGoodbye!");
}
# ------------------------------------------------------------------
# Command line parsing
# ------------------------------------------------------------------
sub extract_command {
my ($line) = @_;
return () unless defined $line;
my @args;
my $current = '';
my $in_quote = '';
for my $char (split //, $line) {
if ($in_quote) {
$current .= $char;
$in_quote = '' if $char eq $in_quote;
} elsif ($char eq '"' || $char eq "'") {
$in_quote = $char;
$current .= $char;
} elsif ($char =~ /\s/) {
push @args, $current if length $current;
$current = '';
} else {
$current .= $char;
}
}
push @args, $current if length $current;
# Strip surrounding quotes
@args = map { /^['"](.*)['"]$/ ? $1 : $_ } @args;
return @args;
}
# ------------------------------------------------------------------
# Time formatting helpers
# ------------------------------------------------------------------
sub epoch_to_tminus {
my $epoch = shift;
return '' unless $epoch && $epoch =~ /^\d+$/;
my $current_epoch = time;
my $diff = $current_epoch - $epoch;
return $diff < 60 ? "${diff}s ago"
: $diff < 3600 ? int($diff/60) . "m ago"
: $diff < 86400 ? int($diff/3600) . "h ago"
: int($diff/86400) . "d ago";
}
sub epoch_to_duration {
my ($start, $end) = @_;
return '' unless $start;
$end //= time;
my $diff_seconds = abs($end - $start);
my $days = int($diff_seconds / (24 * 60 * 60));
$diff_seconds %= (24 * 60 * 60);
my $hours = int($diff_seconds / (60 * 60));
$diff_seconds %= (60 * 60);
my $minutes = int($diff_seconds / 60);
my $seconds = $diff_seconds % 60;
my $duration = sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds);
if ($days) {
$duration .= " +$days" . 'd';
}
( run in 0.471 second using v1.01-cache-2.11-cpan-9581c071862 )