App-Cleo-0.004/000755 000765 000765 00000000000 12313731204 013011 5ustar00jeffjeff000000 000000 App-Cleo-0.004/bin/000755 000765 000765 00000000000 12313731204 013561 5ustar00jeffjeff000000 000000 App-Cleo-0.004/Changes000644 000765 000765 00000000744 12313730564 014321 0ustar00jeffjeff000000 000000 0.004 2014-03-23 09:15:48 America/Los_Angeles - Fixed off-by-one error 0.003 2014-03-10 01:57:48 America/Los_Angeles - Just minor POD edits and refactoring. 0.002 2014-03-09 14:55:03 America/Los_Angeles - The "?" and "!" playback controls have been removed, since they didn't work as advertised anyway. - Added "r" and "p" playback controls to redo the current or previous commands. 0.001 2014-03-09 12:04:46 America/Los_Angeles - Initial release. App-Cleo-0.004/examples/000755 000765 000765 00000000000 12313731204 014627 5ustar00jeffjeff000000 000000 App-Cleo-0.004/lib/000755 000765 000765 00000000000 12313731204 013557 5ustar00jeffjeff000000 000000 App-Cleo-0.004/Makefile.PL000644 000765 000765 00000001502 12307162362 014767 0ustar00jeffjeff000000 000000 use strict; use warnings; use ExtUtils::MakeMaker; #----------------------------------------------------------------------------- WriteMakefile( NAME => 'App::Cleo', VERSION_FROM => 'lib/App/Cleo.pm', LICENSE => 'perl_5', PREREQ_PM => { 'Term::ReadKey' => '0', 'Term::ANSIColor' => '0', 'File::Slurp' => '0', 'Time::HiRes' => '0', 'strict' => '0', 'warnings' => '0', }, EXE_FILES => ['bin/cleo'], META_MERGE => { resources => { repository => { type => 'git', url => 'git@github.com:thaljef/App-Cleo.github', web => 'https://github.com/thaljef/App-Cleo', }, }, 'meta-spec' => { version => 2 }, }, ); App-Cleo-0.004/MANIFEST000644 000765 000765 00000000435 12313731204 014144 0ustar00jeffjeff000000 000000 bin/cleo Changes examples/pinto.demo lib/App/Cleo.pm Makefile.PL MANIFEST This list of files README.md t/compile.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) App-Cleo-0.004/META.json000644 000765 000765 00000002147 12313731204 014436 0ustar00jeffjeff000000 000000 { "abstract" : "unknown", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.86, CPAN::Meta::Converter version 2.133380", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "App-Cleo", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "File::Slurp" : "0", "Term::ANSIColor" : "0", "Term::ReadKey" : "0", "Time::HiRes" : "0", "strict" : "0", "warnings" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "type" : "git", "web" : "https://github.com/thaljef/App-Cleo" } }, "version" : "0.004" } App-Cleo-0.004/META.yml000644 000765 000765 00000001104 12313731204 014256 0ustar00jeffjeff000000 000000 --- abstract: unknown author: - unknown build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.86, CPAN::Meta::Converter version 2.133380' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: App-Cleo no_index: directory: - t - inc requires: File::Slurp: 0 Term::ANSIColor: 0 Term::ReadKey: 0 Time::HiRes: 0 strict: 0 warnings: 0 resources: repository: https://github.com/thaljef/App-Cleo version: 0.004 App-Cleo-0.004/README.md000644 000765 000765 00000005451 12307277313 014306 0ustar00jeffjeff000000 000000 # NAME cleo - Play back shell commands for live demonstrations # SYNOPSIS cleo COMMAND_FILE # DESCRIPTION `cleo` is a utility for playing back pre-recorded shell commands in a live demonstration. `cleo` displays the commands as if you had actually typed them and then executes them interactively. There is probably an easy way to do this with `expect` or a similar tool. But I couldn't figure it out, so I built this. Your mileage may vary. # PLAYBACK `cleo` always pauses and waits for a keypress before displaying a command and before executing it. Pressing any key besides those listed below will advance the playback: Key Action ------------------------------------------------------------------ s skip the current command r redo the current command p redo the previous command q quit playback # COMMANDS `cleo` reads commands from a file. Each line is treated as one command. Blank lines and those starting with `#` will be ignored. The commands themselves can be anything that you would type into an interactive shell. You can also add a few special tokens that `cleo` recognizes: - `!!!` Commands starting with `!!!` (three exclamation points) are not displayed and will be executed immediately. This is useful for running setup commands at the beginning of your demonstration. - `%%%` Within a command, `%%%` (three percent signs) will cause `cleo` to pause and wait for a keypress before displaying the rest of the command. This is useful if you want to stop in the middle of a command to give some explanation. Otherwise, `cleo` displays and executes the commands verbatim. Note that some interactive commands like `vim` are picky about STDOUT and STDIN. To make them work properly with `cleo`, you may need to force them to attach to the terminal like this: (exec < /dev/tty vim) # EXAMPLE I use this for giving demonstrations of [pinto](https://metacpan.org/pod/pinto), such as the one seen at [https://www.youtube.com/watch?v=H-JkFXm8Xgk](https://www.youtube.com/watch?v=H-JkFXm8Xgk) (the live demonstration part starts around 10:47). The command file that I use for that presentation is included inside this distribution at `examples/pinto.demo`. This file is for illustration only, so don't expect it to actually work for you. # LIMITATIONS `cleo` only works on Unix-like platforms. It may work on Windows if you use Cygwin. Personally, I have only used `cleo` on Mac OS X. # TODO - Jump to arbitrary command number - Support backspacing in recorded command - Support multi-line recorded commands - Write unit tests # AUTHOR Jeffrey Ryan Thalhammer # COPYRIGHT Copyright (c) 2014, Imaginative Software Systems App-Cleo-0.004/t/000755 000765 000765 00000000000 12313731204 013254 5ustar00jeffjeff000000 000000 App-Cleo-0.004/t/compile.t000644 000765 000765 00000000244 12307050225 015071 0ustar00jeffjeff000000 000000 #!perl use strict; use warnings; use Test::More; #---------------------------------------------------------------------------- use_ok('App::Cleo'); done_testing;App-Cleo-0.004/lib/App/000755 000765 000765 00000000000 12313731204 014277 5ustar00jeffjeff000000 000000 App-Cleo-0.004/lib/App/Cleo.pm000644 000765 000765 00000007604 12313730607 015534 0ustar00jeffjeff000000 000000 package App::Cleo; use strict; use warnings; use Term::ReadKey; use Term::ANSIColor qw(colored); use File::Slurp qw(read_file); use Time::HiRes qw(usleep); our $VERSION = 0.004; #----------------------------------------------------------------------------- sub new { my $class = shift; my $self = { shell => $ENV{SHELL} || '/bin/bash', prompt => colored( ['green'], '(%d)$ '), delay => 25_000, @_, }; return bless $self, $class; } #----------------------------------------------------------------------------- sub run { my ($self, $commands) = @_; my $type = ref $commands; my @commands = !$type ? read_file($commands) : $type eq 'SCALAR' ? split "\n", ${$commands} : $type eq 'ARRAY' ? @{$commands} : die "Unsupported type: $type"; open my $fh, '|-', $self->{shell} or die $!; $self->{fh} = $fh; ReadMode('raw'); local $| = 1; chomp @commands; @commands = grep { /^\s*[^\#;]\S+/ } @commands; CMD: for (my $i = 0; $i < @commands; $i++) { my $cmd = $commands[$i]; chomp $cmd; $self->do_cmd($cmd) and next CMD if $cmd =~ s/^!!!//; print sprintf $self->{prompt}, $i; my @steps = split /%%%/, $cmd; while (my $step = shift @steps) { my $key = ReadKey(0); print "\n" if $key =~ m/[srp]/; last CMD if $key eq 'q'; next CMD if $key eq 's'; redo CMD if $key eq 'r'; $i--, redo CMD if $key eq 'p'; $step .= ' ' if not @steps; my @chars = split '', $step; print and usleep $self->{delay} for @chars; } my $key = ReadKey(0); print "\n"; last CMD if $key eq 'q'; next CMD if $key eq 's'; redo CMD if $key eq 'r'; $i--, redo CMD if $key eq 'p'; $self->do_cmd($cmd); } ReadMode('restore'); print "\n"; return $self; } #----------------------------------------------------------------------------- sub do_cmd { my ($self, $cmd) = @_; my $cmd_is_finished; local $SIG{ALRM} = sub {$cmd_is_finished = 1}; $cmd =~ s/%%%//g; my $fh = $self->{fh}; print $fh "$cmd\n"; print $fh "kill -14 $$\n"; $fh->flush; # Wait for signal that command has ended until ($cmd_is_finished) {} $cmd_is_finished = 0; return 1; } #----------------------------------------------------------------------------- 1; =pod =head1 NAME App::Cleo - Play back shell commands for live demonstrations =head1 SYNOPSIS use App::Cleo my $cleo = App::Cleo->new(%options); $cleo->run($commands); =head1 DESCRIPTION App::Cleo is the back-end for the L utility. Please see the L documentation for details on how to use this. =head1 CONSTRUCTOR The constructor accepts arguments as key-value pairs. The following keys are supported: =over 4 =item delay Number of milliseconds to wait before displaying each character of the command. The default is C<25_000>. =item prompt String to use for the artificial prompt. The token C<%d> will be substituted with the number of the current command. The default is C<(%d)$>. =item shell Path to the shell command that will be used to run the commands. Defaults to either the C environment variable or C. =back =head1 METHODS =over 4 =item run( $commands ) Starts playback of commands. If the argument is a string, it will be treated as a file name and commands will be read from the file. If the argument is a scalar reference, it will be treated as a string of commands separated by newlines. If the argument is an array reference, then each element of the array will be treated as a command. =back =head1 AUTHOR Jeffrey Ryan Thalhammer =head1 COPYRIGHT Copyright (c) 2014, Imaginative Software Systems =cut App-Cleo-0.004/examples/pinto.demo000644 000765 000765 00000003334 12307276457 016652 0ustar00jeffjeff000000 000000 # Create a clean local lib !!!perlbrew use perl-5.16.3 !!!perlbrew lib delete perl-5.16.3@demo !!!perlbrew lib create perl-5.16.3@demo !!!exit # Trick cpanm into installing Pinto and a few prereqs !!!rm -rf ~/opt/local/pinto/lib/perl5/HTTP* !!!rm -rf ~/opt/local/pinto/lib/perl5/Pinto* !!!rm -rf ~/opt/local/pinto/lib/perl5/darwin-2level/auto/Pinto # Delete the Pinto repo !!!rm -rf MyModules # Final environment setup !!!perlbrew use perl-5.16.3@demo !!!export PERL_CPANM_OPT=--notest # Live portion starts here echo 'Here we go!'; clear # Install pinto curl -L http://getpinto.stratopan.com | bash # Create repository pinto %%%--root MyModules %%%init %%%--source file:///Users/jeff/tmp/CPAN-Today # Show repository structure find MyModules -type f # Set ENV var, so we can be lazy export PINTO_REPOSITORY_ROOT=$PWD/MyModules # Pull Dancer from CPAN and install pinto install%%% --do-pull%%% Dancer # Show stack contents pinto list clear # URI is broken so inject our patched one pinto add%%% ~/tmp/URI-1.58_PATCHED.tar.gz # Pin our URI so it doesn't change pinto pin%%% URI # Edit config file to travel forward in time (exec < /dev/tty vim MyModules/.pinto/config/pinto.ini) # Pull newer Dancer and install pinto install --do-pull Dancer%%%~1.3116 # Show log to explain the pin pinto log # Make a copy of the stack pinto copy%%% master foo # Show the stack listing pinto stacks # Unpin URI on the copied stack pinto unpin%%% --stack foo%%% URI # Upgrade Dancer pinto install --do-pull --stack foo%%% Dancer~1.3116 # Compare the stacks pinto diff%%% master foo # Unpin URI on master too pinto unpin URI # Pull Dancer to master pinto pull Dancer~1.3116 # Compare stacks again pinto diff master foo # The end echo 'Thank You!' exit App-Cleo-0.004/bin/cleo000644 000765 000765 00000006235 12307277140 014443 0ustar00jeffjeff000000 000000 #!/usr/bin/env perl use strict; use warnings; use App::Cleo; our $VERSION = 0.003; #----------------------------------------------------------------------------- die 'Usage: cleo COMMAND_FILE' if not @ARGV; my $cleo = App::Cleo->new; $cleo->run(shift); exit; #----------------------------------------------------------------------------- =pod =head1 NAME cleo - Play back shell commands for live demonstrations =head1 SYNOPSIS cleo COMMAND_FILE =head1 DESCRIPTION C is a utility for playing back pre-recorded shell commands in a live demonstration. C displays the commands as if you had actually typed them and then executes them interactively. There is probably an easy way to do this with C or a similar tool. But I couldn't figure it out, so I built this. Your mileage may vary. =head1 PLAYBACK C always pauses and waits for a keypress before displaying a command and before executing it. Pressing any key besides those listed below will advance the playback: Key Action ------------------------------------------------------------------ s skip the current command r redo the current command p redo the previous command q quit playback =head1 COMMANDS C reads commands from a file. Each line is treated as one command. Blank lines and those starting with C<#> will be ignored. The commands themselves can be anything that you would type into an interactive shell. You can also add a few special tokens that C recognizes: =over 4 =item C Commands starting with C (three exclamation points) are not displayed and will be executed immediately. This is useful for running setup commands at the beginning of your demonstration. =item C<%%%> Within a command, C<%%%> (three percent signs) will cause C to pause and wait for a keypress before displaying the rest of the command. This is useful if you want to stop in the middle of a command to give some explanation. =back Otherwise, C displays and executes the commands verbatim. Note that some interactive commands like C are picky about STDOUT and STDIN. To make them work properly with C, you may need to force them to attach to the terminal like this: (exec < /dev/tty vim) =head1 EXAMPLE I use this for giving demonstrations of L, such as the one seen at L (the live demonstration part starts around 10:47). The command file that I use for that presentation is included inside this distribution at F. This file is for illustration only, so don't expect it to actually work for you. =head1 LIMITATIONS C only works on Unix-like platforms. It may work on Windows if you use Cygwin. Personally, I have only used C on Mac OS X. =head1 TODO =over 4 =item Jump to arbitrary command number =item Support backspacing in recorded command =item Support multi-line recorded commands =item Write unit tests =back =head1 AUTHOR Jeffrey Ryan Thalhammer =head1 COPYRIGHT Copyright (c) 2014, Imaginative Software Systems =cut