Author: spadkins
Date: Sat Mar 7 11:08:54 2009
New Revision: 12576
Added:
p5ee/trunk/App-Repository/bin/dash (contents, props changed)
Log:
new
Added: p5ee/trunk/App-Repository/bin/dash
==============================================================================
--- (empty file)
+++ p5ee/trunk/App-Repository/bin/dash Sat Mar 7 11:08:54 2009
@@ -0,0 +1,340 @@
+#!/usr/bin/perl -w
+
+use Date::Format;
+
+use App::Options (
+ options => [ qw(dbhost dbname dbuser dbpass repository table params
columns headings compact decimals subtotal_columns totals
+ distinct cache_skip cache_refresh silent) ],
+ option => {
+ repository => {
+ default => "default",
+ description => "Name of the repository to get the rows from",
+ },
+ table => {
+ description => "Table name (i.e. --table=customer)",
+ },
+ params => {
+ description => "List of params (var=value pairs) (i.e.
--params=\"last_name=Jones|first_name=Mike\")",
+ },
+ columns => {
+ description => "List of columns (comma-separated list) (i.e.
--columns=first_name,last_name)",
+ },
+ headings => {
+ description => "List of heading abbreviations (comma-separated)
(i.e. --headings=first,last)",
+ },
+ compact => {
+ description => "Trim titles to make compact table",
+ },
+ decimals => {
+ description => "Number of decimal places to print on floats",
+ default => "2",
+ },
+ subtotal_columns => {
+ description => "Print sub-totals at the end",
+ },
+ totals => {
+ description => "Print totals at the end",
+ },
+ cache_skip => {
+ description => "Skip any cached values for the table",
+ },
+ cache_refresh => {
+ description => "Skip any cached values for the table but save the
results in the cache",
+ },
+ distinct => {
+ description => "Select only distinct rows",
+ },
+ silent => {
+ default => 0,
+ description => "Do not emit prompts or other messages (useful
during scripted use)",
+ },
+ },
+);
+
+use App;
+use strict;
+
+my $LOADED_TERM_READLINE = 0;
+my $term = undef;
+
+$| = 1; # autoflush stdout
+
+{
+ my $context = App->context();
+ my $options = $context->{options};
+ &init($options);
+ my $silent = $options->{silent};
+ my $done = 0;
+ my ($command, $command_entry);
+ my $prompt = "dash";
+ while (!$done) {
+ $command_entry = &get_command_entry($prompt, $options);
+ $command = &get_command_from_command_entry($command_entry);
+ if (!$command) {
+ #print "I didn't understand that.\n";
+ #print "Please try 'help' for help on the available commands and
their use\n";
+ }
+ elsif ($command eq "help" || $command eq "?") {
+ &show_help($command_entry);
+ }
+ elsif ($command eq "repository") {
+ &set_repository($command_entry);
+ }
+ elsif ($command eq "select") {
+ &show_select($command_entry);
+ }
+ elsif ($command eq "exit") {
+ $done = 1;
+ }
+ else {
+ print "I don't know the '$command' command.\n";
+ print "Please try 'help' for help on the available commands and
their use\n";
+ }
+ }
+ print "Goodbye\n" if (!$silent);
+}
+
+sub init {
+ my ($options) = @_;
+ eval { use Term::ReadLine; };
+ if ($@) {
+ $LOADED_TERM_READLINE = 0;
+ }
+ else {
+ $LOADED_TERM_READLINE = 1;
+ $term = Term::ReadLine->new($options->{app});
+ }
+}
+
+sub get_command_entry {
+ my ($prompt, $options) = @_;
+ my ($command_entry);
+ if ($LOADED_TERM_READLINE) {
+ $command_entry = &get_command_entry_readline($prompt, $options);
+ }
+ else {
+ $command_entry = &get_command_entry_std($prompt, $options);
+ }
+ return($command_entry);
+}
+
+sub get_command_entry_std {
+ my ($prompt, $options) = @_;
+ print "$prompt> " if (!$options->{silent});
+ my $command_entry = <STDIN>;
+ return($command_entry);
+}
+
+sub get_command_entry_readline {
+ my ($prompt, $options) = @_;
+ my $readline_prompt = $options->{silent} ? "" : "$prompt> ";
+ my $command_entry = $term->readline($readline_prompt);
+ return($command_entry);
+}
+
+sub get_command_from_command_entry {
+ my ($command_entry) = @_;
+ my ($command);
+ if ($command_entry =~ /^([a-zA-Z_\?]+)/) {
+ $command = $1;
+ }
+ return($command);
+}
+
+sub show_help {
+ my ($command_entry) = @_;
+ print "============================================================\n";
+ print "COMMANDS:\n";
+ print "============================================================\n";
+ print "help - [synonym: ?] show this list of commands\n";
+ print "exit - quit the program\n";
+}
+
+sub set_repository {
+ my ($command_entry) = @_;
+}
+
+sub show_select {
+ my ($command_entry) = @_;
+ my $context = App->context();
+ my $db = $context->repository($App::options{repository});
+ my $rows = $db->_do($command_entry);
+ foreach my $row (@$rows) {
+ print "ROW:[", join("|", @$row), "]\n";
+ }
+}
+
+sub foo {
+ my $context = App->context();
+ my $db = $context->repository($App::options{repository});
+ my $table = $App::options{table};
+ my ($columns, $params, $headings, $get_options, $cache_rows);
+ if ($table && $App::options{hashkey}) {
+ my $hashkey = $App::options{hashkey};
+ my $table_def = $db->get_table_def($table);
+ my $cache_name = $table_def->{cache_name};
+ if ($cache_name) {
+ my $cache = $context->shared_datastore($cache_name);
+ my $ref = $cache->get_ref($hashkey);
+ if (!$ref) {
+ warn "Nothing in the [$cache_name] cache for table [$table]
with hashkey [$hashkey]\n";
+ }
+ else {
+ ($table, $params, $columns, $cache_rows, $get_options) = @$ref;
+ $get_options->{cache_skip} = 1;
+ print $db->dump([$table, $params, $columns, $get_options]);
+ }
+ }
+ else {
+ warn "cache_name option is not set on table $table";
+ }
+ }
+ else {
+ if ($App::options{columns}) {
+ $columns = [ split(/,/, $App::options{columns}) ];
+ }
+ else {
+ $columns = $db->_get_default_columns($table);
+ }
+ die "Must supply the --params option\n" if (! defined
$App::options{params});
+ $params = { split(/[=>\|]+/, $App::options{params}) };
+ $headings = $App::options{headings} ? [ split(/,/,
$App::options{headings}) ] : [];
+ $get_options = { extend_columns => 1 };
+ }
+ $get_options->{distinct} = 1 if ($App::options{distinct});
+ $get_options->{cache_skip} = 1 if ($App::options{cache_skip});
+ $get_options->{cache_refresh} = 1 if ($App::options{cache_refresh});
+ my $rows = $db->get_rows($table, $params, $columns, $get_options);
+ my ($subtotal_rows, $total_rows);
+ if ($App::options{subtotal_columns}) {
+ my $subtotal_columns = [ split(/,/, $App::options{subtotal_columns}) ];
+ $subtotal_rows = $db->summarize_rows($table, $rows, $columns,
$subtotal_columns);
+ }
+ if ($App::options{totals}) {
+ $total_rows = $db->summarize_rows($table, $rows, $columns);
+ }
+ if ($subtotal_rows) {
+ push(@$rows, @$subtotal_rows);
+ }
+ if ($total_rows) {
+ push(@$rows, @$total_rows);
+ }
+ my $formats = [];
+ &print_table($rows, $columns, $formats, { compact =>
$App::options{compact}, headings => $headings });
+}
+
+sub print_table {
+ &App::sub_entry if ($App::trace);
+ my ($rows, $columns, $formats, $options) = @_;
+ my ($row, $r, $c, $elem, $format, $len, $f, $heading);
+ my (@autoformat);
+ my $headings = $options->{headings};
+
+ # compute the number of columns as the max columns of any row
+ my $max_columns = 0;
+ for ($r = 0; $r <= $#$rows; $r++) {
+ $row = $rows->[$r];
+ if ($max_columns < $#$row + 1) {
+ $max_columns = $#$row + 1;
+ }
+ }
+
+ # compute automatic sprintf formats
+ for ($c = 0; $c < $max_columns; $c++) {
+
+ if (! defined $autoformat[$c]) {
+ $autoformat[$c] = {
+ max_length => 0,
+ type => 2, # 0=string, 1=float, 2=integer
+ min => undef,
+ max => undef,
+ };
+ }
+ $f = $autoformat[$c];
+
+ # set the length of the column by the length of its heading
+ $heading = ($headings && $headings->[$c]) ? $headings->[$c] : "";
+ if ($heading) {
+ $len = length($heading);
+ if ($len > $f->{max_length}) {
+ $f->{max_length} = $len;
+ }
+ }
+ elsif (! $options->{compact}) {
+ $len = length($columns->[$c]);
+ if ($len > $f->{max_length}) {
+ $f->{max_length} = $len;
+ }
+ }
+
+ for ($r = 0; $r <= $#$rows; $r++) {
+ $row = $rows->[$r];
+ if ($c <= $#$row && defined $row->[$c]) {
+ $elem = $row->[$c];
+ $len = length($elem);
+ if ($elem =~ /^-?[0-9]*\.[0-9]+$/) { # float
+ $len = length(sprintf("%.$App::options{decimals}f",$elem));
+ $f->{type} = 1 if ($f->{type} > 1);
+ if (!defined $f->{min} || $elem < $f->{min}) {
+ $f->{min} = $elem;
+ }
+ if (!defined $f->{max} || $elem < $f->{max}) {
+ $f->{max} = $elem;
+ }
+ }
+ elsif ($elem =~ /^-?[0-9]+$/) { # integer
+ if (!defined $f->{min} || $elem < $f->{min}) {
+ $f->{min} = $elem;
+ }
+ if (!defined $f->{max} || $elem < $f->{max}) {
+ $f->{max} = $elem;
+ }
+ }
+ else {
+ $f->{type} = 0;
+ }
+ $f->{max_length} = $len if ($len > $f->{max_length});
+ }
+ }
+ &determine_sprintf_fmt($f);
+ }
+ for ($c = 0; $c <= $#$columns; $c++) {
+ $format = $autoformat[$c]->{title_fmt} || "%s";
+ print " " if ($c > 0);
+ $heading = ($headings && $headings->[$c]) ? $headings->[$c] :
$columns->[$c];
+ printf($format, $heading);
+ }
+ print "\n";
+ for ($r = 0; $r <= $#$rows; $r++) {
+ $row = $rows->[$r];
+ for ($c = 0; $c <= $#$row; $c++) {
+ $format = $autoformat[$c]->{fmt} || "%s";
+ print " " if ($c > 0);
+ printf($format, $row->[$c]);
+ }
+ print "\n";
+ }
+ &App::sub_exit() if ($App::trace);
+}
+
+sub determine_sprintf_fmt {
+ &App::sub_entry if ($App::trace);
+ my ($f) = @_;
+ my ($width, $int_len, $fract_len);
+ if ($f->{type} == 1) { # float
+ $f->{title_fmt} = "%$f->{max_length}.$f->{max_length}s";
+ $f->{fmt} = "%$f->{max_length}.$App::options{decimals}f";
+ }
+ elsif ($f->{type} == 2) { # integer
+ $f->{title_fmt} = "%$f->{max_length}.$f->{max_length}s";
+ $f->{fmt} = "%$f->{max_length}d";
+ }
+ else { # string
+ $f->{title_fmt} = "%-$f->{max_length}.$f->{max_length}s";
+ $f->{fmt} = "%-$f->{max_length}s";
+ }
+ &App::sub_exit($f->{fmt}) if ($App::trace);
+}
+
+exit (0);
+