Writing CLI Tools for Other People

Writing CLI Tools for Other People

A talk on how to write a CLI tool for other people using Perl and some CPAN Modules.

8d96f5c273062cb617255e630fe0705c?s=128

Brad Lhotsky

June 20, 2016
Tweet

Transcript

  1. Writing CLI Tools for Other People Presented by Brad Lhotsky

  2. What is CLI? • Run from the Terminal, e.g. a

    shell • They don’t need no stinkin' mouse • They can work with things like Expect • I can use them remotely without a GUI/ Web Browser • Computers can run them too!
  3. Command Line Interfaces • Curses / NCurses • GNU ReadLine

    • STDIN, STDOUT, STDOUT • May require user interaction beyond the options, i.e. menus, prompts.
  4. UNIX Philosophy “Do one thing, well.”

  5. Enable Composability • I need to pipe your output to

    sort • I need to pipe input to your program • I need columnar data or the ability to affect the output record separator • At the very least, give me a plugin interface
  6. Documentation • You need to write those docs before you

    show me your cool utility • Support --help if not --manual • Tell users where to go for more information • Maybe write a trendy blog post and throw it at reddit or HN
  7. Example Uses • OMG, Major Pet Peeve • Show me

    how you use the tool • Show me how you expect arguments • Show me what you get when you run it! ... --start When to start --stop When to stop ...
  8. CLI Tools in Perl • Prolific and Infinite • Specific

    to Generic • If you can, upload to CPAN!! • App::* • Great chance to see how others will use your code! • We are the glue of the internet, after all
  9. Magic Diamond • Use the magic diamond to accept input

    • Consistent with expectations of UNIX tools • Can accept input from STDIN • Given a list of files, it reads their content while(my $line = <>) { chomp($line); next unless $line; ... }
  10. use Getopt::Long::Descriptive my ($opt, $usage) = describe_options( 'my-program %o <some-arg>',

    [ 'server|s=s', "server to connect to", { required => 1 } ], [ 'port|p=i', "port to connect to", { default => 79 } ], [], [ 'verbose|v', "print extra stuff" ], [ 'help', "print usage message and exit" ], ); print($usage->text), exit if $opt->help; Client->connect( $opt->server, $opt->port ); print "Connected!\n" if $opt->verbose;
  11. use Getopt::Long::Descriptive ...and running "my-program --help" will produce: my-program [-psv]

    [long options...] <some-arg> -s --server server to connect to -p --port port to connect to -v --verbose print extra stuff --help print usage message and exit
  12. use Pod::Usage # Print POD SYNOPSIS and exit 0; pod2usage(0);

    # Print SYNOPSIS, ARGUMENTS, OPTIONS, exit 0; pod2usage({ -verbose => 1}); # Print full POD, exit 1 pod2usage({ -verbose => 2, -exitval => 1});
  13. use Term::ReadLine • perldoc Term::ReadLine • Using readline() to get

    input facilitates history navigation
  14. use Term::ANSIColor • perldoc Term::ANSIColor • Colors can provide vital

    clues in large text dumps • Some users don't like them • Most people interact with git, check their ~/.gitconfig to see if they like colors?
  15. Other Great Modules • Core: • File::Basename, File::Spec, File::Path, File::Temp

    • App::Cmd • Dist::Zilla • Path::Tiny • Pod::Weaver • ::Section::Collect::FromOther
  16. Introducing CLI::Helpers • Wraps input and out operations for CLI

    utilities in neat ways • Based on years of writing personal and shared CLI tools • I like it, you might too!
  17. CLI::Helpers Input use CLI::Helpers qw(:input); die "Aborting run" unless confirm("Are

    you sure?"); Inspired by IO::Prompt(er) but not in a confusing state of deprecation or maintenance or compatibility.
  18. CLI::Helpers Input my $dir = prompt "Pick a color", menu

    => [qw( red orange yellow green blue indigo violet )];
  19. CLI::Helpers Input Pick a color 1. blue 2. green 3.

    indigo 4. orange 5. red 6. violet 7. yellow Selection (1-7):
  20. CLI::Helpers Input my %menu = ( north => "Go north.",

    south => "Go south.", ); my $dir = prompt "Which way?", menu => \%menu; print "You move $dir\n";
  21. CLI::Helpers Input Which way? 1. Go north. 2. Go south.

    Selection (1-2): 1 You move north.
  22. CLI::Helpers Input my $i = prompt "Enter an integer:", validate

    => { "not an integer" => sub { /^\d+$/ }, }; print "You entered: $i\n";
  23. CLI::Helpers Input Enter an integer: three ERROR: not an integer

    Enter an integer: 3.0 ERROR: not an integer Enter an integer: 3 You entered: 3
  24. CLI::Helpers Output • Functions for sending output places • Controlled

    by user options on the command line
  25. CLI::Helpers @ARGV From CLI::Helpers: --color Boolean, enable/disable color, default use

    git settings --data-file Path to a file to write lines tagged with 'data => 1' --debug Show developer output --debug-class Show debug messages originating from a specific package, default: main --quiet Show no output (for cron) --syslog Generate messages to syslog as well --syslog-debug Enable debug messages to syslog if in use, default false --syslog-facility Default "local0" --syslog-tag The program name, default is the script name --verbose Incremental, increase verbosity (Alias is -v)
  26. CLI::Helpers Output output("Hello, World"); verbose({indent=>1},"Well, hi there too!"); $ perl

    clih.pl Hello, World! $ perl clih.pl --verbose Hello, World! Well, hi there too!
  27. CLI::Helpers Output output({color=>'blue'}, "Hello, World!"); $ perl clih.pl Hello, World!

    $ perl clih.pl Hello, World! Default: git config ui.color auto:
  28. CLI::Helpers Output output({clear=>1,sticky=>1}, "Thanks for using my great utility!" );

    output( "Hello, World!", " This is going to be awesome.", " Please enjoy." );
  29. CLI::Helpers Output $ perl clih.pl Thanks for using my great

    utility! Hello, World! This is going to be awesome. Please enjoy. Thanks for using my great utility!
  30. CLI::Helpers Debug output("Hello, World!"); debug({clear=>1}, sprintf "EYES ONLY: it is

    %d!", time ); verbose({indent=>1}, "And hello to you, fine sir.");
  31. CLI::Helpers Debug $ perl clih.pl Hello, World! $ perl clih.pl

    --verbose Hello, World! And hello to you, fine sir. $ perl clih.pl --debug Hello, World! EYES ONLY: it is 1466366341! And hello to you, fine sir.
  32. CLI::Helpers Debug perl clih.pl --debug --debug-class=CLI::Helpers CLI::Helpers Definitions --- COLOR:

    1 DEBUG: 1 DEBUG_CLASS: CLI::Helpers KV_FORMAT: ': ' QUIET: 0 SYSLOG: 0 SYSLOG_DEBUG: 0 SYSLOG_FACILITY: local0 SYSLOG_TAG: clih.pl VERBOSE: 0 Hello, World!
  33. CLI::Helpers Syslog $ perl clih.pl --syslog Hello, World! $ tail

    -1 /var/log/system.log Jun 19 13:04:26 tech1-71s clih.pl[27058]: Hello, World! output("Hello, World");
  34. CLI::Helpers Syslog $ perl clih.pl --syslog --quiet $ tail -1

    /var/log/system.log Jun 19 13:06:27 tech1-71s clih.pl[32218]: Hello, World! output("Hello, World");
  35. CLI::Helpers Data Files $ perl clih.pl --data-file test.out Hello, World!

    one two three four five $ cat test.out one two three four five output("Hello, World!"); my @row = qw(one two three four five); output({data=>1}, join("\t", @row));
  36. CLI::Helpers Output Options color Term::ANSIColor color word clear Number of

    new lines before text sticky Text output in line and then again at termination indent Indentation level level Number of v's syslog_level Syslog severity level no_syslog Even if --syslog is present, don't syslog this line IMPORTANT Even if --quiet is enabled, output this line stderr Output this line to STDERR instead of STDOUT data This line will go to the data file
  37. perldoc CLI::Helpers

  38. Thank you! brad.lhotsky@gmail.com https://twitter.com/reyjrar https://github.com/reyjrar https://speakerdeck.com/reyjrar https://www.craigslist.org/about/craigslist_is_hiring