$30 off During Our Annual Pro Sale. View Details »

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.

Brad Lhotsky

June 20, 2016
Tweet

More Decks by Brad Lhotsky

Other Decks in Programming

Transcript

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

    View Slide

  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!

    View Slide

  3. Command Line Interfaces
    • Curses / NCurses
    • GNU ReadLine
    • STDIN, STDOUT,
    STDOUT
    • May require user
    interaction beyond
    the options, i.e.
    menus, prompts.

    View Slide

  4. UNIX Philosophy
    “Do one thing, well.”

    View Slide

  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

    View Slide

  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

    View Slide

  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
    ...

    View Slide

  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

    View Slide

  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;
    ...
    }

    View Slide

  10. use Getopt::Long::Descriptive
    my ($opt, $usage) = describe_options(
    'my-program %o ',
    [ '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;

    View Slide

  11. use Getopt::Long::Descriptive
    ...and running "my-program --help" will produce:
    my-program [-psv] [long options...]
    -s --server server to connect to
    -p --port port to connect to
    -v --verbose print extra stuff
    --help print usage message and exit

    View Slide

  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});

    View Slide

  13. use Term::ReadLine
    • perldoc Term::ReadLine
    • Using readline() to get input facilitates
    history navigation

    View Slide

  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?

    View Slide

  15. Other Great Modules
    • Core:
    • File::Basename, File::Spec,
    File::Path, File::Temp
    • App::Cmd
    • Dist::Zilla
    • Path::Tiny
    • Pod::Weaver
    • ::Section::Collect::FromOther

    View Slide

  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!

    View Slide

  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.

    View Slide

  18. CLI::Helpers Input
    my $dir = prompt "Pick a color",
    menu => [qw(
    red orange yellow
    green
    blue indigo violet
    )];

    View Slide

  19. CLI::Helpers Input
    Pick a color
    1. blue
    2. green
    3. indigo
    4. orange
    5. red
    6. violet
    7. yellow
    Selection (1-7):

    View Slide

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

    View Slide

  21. CLI::Helpers Input
    Which way?
    1. Go north.
    2. Go south.
    Selection (1-2): 1
    You move north.

    View Slide

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

    View Slide

  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

    View Slide

  24. CLI::Helpers Output
    • Functions for sending output places
    • Controlled by user options on the
    command line

    View Slide

  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)

    View Slide

  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!

    View Slide

  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:

    View Slide

  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."
    );

    View Slide

  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!

    View Slide

  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.");

    View Slide

  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.

    View Slide

  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!

    View Slide

  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");

    View Slide

  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");

    View Slide

  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));

    View Slide

  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

    View Slide

  37. perldoc CLI::Helpers

    View Slide

  38. Thank you!
    [email protected]
    https://twitter.com/reyjrar
    https://github.com/reyjrar
    https://speakerdeck.com/reyjrar
    https://www.craigslist.org/about/craigslist_is_hiring

    View Slide