Advertisement
sbicknel

Tomato Timer

Jan 14th, 2018
829
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 13.17 KB | None | 0 0
  1. #!/bin/bash -
  2. # ---------------------------------------------------------------------------
  3. # tomato -
  4.  
  5. # Copyright 2018, Scott Bicknell [email protected]
  6.  
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11.  
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. # GNU General Public License at <http://www.gnu.org/licenses/> for
  16. # more details.
  17.  
  18. # Usage: tomato [-h|--help]
  19.  
  20. # Revision history:
  21. # 2017-05-28 Created by new_script ver. 3.3
  22. # ---------------------------------------------------------------------------
  23.  
  24. PATH='/usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/home/sbicknell/.local/bin:/home/sbicknell/bin'
  25.  
  26. # =============================================================================
  27. # Debugging assistance
  28. # =============================================================================
  29. set -euo pipefail
  30. IFS=$'\n\t'
  31.  
  32. # =============================================================================
  33. # Constants
  34. # =============================================================================
  35. declare -r PROGNAME=${0##*/}    # program filename
  36. declare -r VERSION="0.1"    # program version number
  37. if [[ -d $HOME/tmp ]]; then
  38.     declare -r TMPDIR="$HOME/tmp"
  39. else
  40.     declare -r TMPDIR='/tmp'
  41. fi
  42.  
  43. # =============================================================================
  44. # Parse configuration
  45. # =============================================================================
  46.  
  47. # source configuration file if it exists.  Document expected values here
  48. if [[ -f $HOME/.${PROGNAME}rc ]]; then
  49.     # shellcheck source=/home/sbicknell/.bash-template.shrc
  50.     source "$HOME/.${PROGNAME}rc"
  51. fi
  52.  
  53. # =============================================================================
  54. # Set command line option parser
  55. # =============================================================================
  56.  
  57. # Test for GNU getopt, which will return '4'.  All others will return 0 and
  58. # output '--'. Use GNU getopt or bash getopts.  This is used by the usage()
  59. # and help() functions and by the option parsing code to determine what
  60. # options to enable and what help text to display after determining which
  61. # parser to use.
  62. set +e
  63. if ! getopt -T >/dev/null 2>&1; then
  64.     parser='getopt'
  65. else
  66.     parser='getopts'
  67. fi
  68. set -e
  69.  
  70. # =============================================================================
  71. # Function definitions
  72. # =============================================================================
  73. temp_file() { # Create temporary files. Automatically deleted at exit
  74.     set +e
  75.     tmpfile=$(mktemp "$TMPDIR/$PROGNAME.$RANDOM.$$.XXXXXX") ||
  76.     error_exit "creating temporary file failed"
  77.     set -e
  78.     exec 3>"$tmpfile"
  79.     rm "$tmpfile"
  80. }
  81.  
  82. lock_file() { # Create a lock file
  83.     set +e
  84.     mkdir -p "$TMPDIR/$PROGNAME" || error_exit "$PROGNAME already running"
  85.     set -e
  86. }
  87.  
  88. clean_up() { # Perform pre-exit housekeeping
  89.     if [[ -d $TMPDIR/$PROGNAME ]]; then
  90.     set +e
  91.     if [[ -d $TMPDIR/$PROGNAME ]]; then
  92.         rmdir "$TMPDIR/$PROGNAME" || error "removing $TMPDIR/$PROGNAME failed"
  93.     fi
  94.     set -e
  95.     fi
  96. }
  97.  
  98. message() { # Display messages to the user
  99.     printf '%s: %s\n' "$PROGNAME" "$@"
  100. }
  101.  
  102. error() { # Display messages to the user on standard error
  103.     message "$@" >&2
  104. }
  105.  
  106. # exit with an error message (default is "unspecified error") and a
  107. # customizable error code (default is 1).
  108. error_exit() {
  109.     error "${1:-'unspecified error'}"
  110.     clean_up
  111.     exit "${2:-1}"
  112. }
  113.  
  114. graceful_exit() {
  115.     clean_up
  116.     exit
  117. }
  118.  
  119. version() {
  120.     printf '%s %s\n' "$PROGNAME" "$VERSION"
  121. }
  122.  
  123. usage() {
  124.     if [[ $parser =~ ^getopt$ ]]; then # using GNU getopt
  125.     echo -e "Usage:"
  126.     echo -e "        $PROGNAME -h|--help"
  127.     echo -e "        $PROGNAME -u|--usage"
  128.     echo -e "        $PROGNAME -v|--version"
  129.     else # using bash getopts
  130.     echo -e "Usage:"
  131.     echo -e "        $PROGNAME -h"
  132.     echo -e "        $PROGNAME -u"
  133.     echo -e "        $PROGNAME -v"
  134.     fi
  135. }
  136.  
  137. help_message() {
  138.     if [[ $parser =~ ^getopt$ ]]; then # using GNU getopt
  139.     # shellcheck disable=SC2119
  140.     pg <<- EOF
  141.     $PROGNAME ver. $VERSION
  142.  
  143.     Description:
  144.         Program description.
  145.  
  146.     $(usage)
  147.  
  148.     Options:
  149.         -h, --help    Display this help message and exit.
  150.         -u, --usage   Display a shorter usage message and exit.
  151.         -v, --version Display version information and exit.
  152. EOF
  153.     return
  154.     else
  155.     # shellcheck disable=SC2119
  156.     pg <<- EOF
  157.     $PROGNAME ver. $VERSION
  158.  
  159.     Description:
  160.         Program description.
  161.  
  162.     $(usage)
  163.  
  164.     Options:
  165.         -h Display this help message and exit.
  166.         -u Display a shorter usage message and exit.
  167.         -v Display version information and exit.
  168. EOF
  169.     return
  170.     fi
  171. }
  172.  
  173.  
  174. #======================================================================
  175. # Format a file (or standard input) and display it or page it if
  176. # necessary
  177. #     pg [-n] [file]
  178. #        -n add line numbers to output
  179. #======================================================================
  180. # shellcheck disable=SC2120
  181. pg () {
  182.  
  183.     local    ncols=0                                # columns used for line numbering
  184.     set +u
  185.     local -r promptLines=$(echo -e "$PS1" | wc -l)  # number of lines taken by PS1 prompt
  186.     set -u
  187.     # shellcheck disable=SC2154
  188.     {
  189.     local -A num
  190.     num[cat]=''   # parameter for turning on line numbering in cat (-n)
  191.     num[less]=''  # parameter for turning on line numbering in less (-N)
  192.     }
  193.  
  194.     # capture standard input
  195.     # huge files can, of course, fill all available memory
  196.     while IFS='' read -r -t 0.1 line; do
  197.         if ! [[ -v pipeFile ]]; then
  198.             if [[ "${1:-}" = '-n' ]]; then
  199.                 ncols=8
  200.             fi
  201.             local -a pipeFile   # array of lines from piped file
  202.             local inc           # amount to increment lineCount each pass through loop
  203.             local lineCount=0   # total number of formatted lines of output
  204.         fi
  205.  
  206.         # add current text line to list of lines, determine how many formatted lines
  207.         # will result from it, and increment the total number of lines by that many
  208.         pipeFile=( "${pipeFile[@]}" "$line" )
  209.         inc=$(fmt -s -w $(( COLUMNS - ncols )) <<< "$line" | wc -l)
  210.         lineCount=$(( lineCount + inc ))
  211.     done
  212.  
  213.     # set up line numbering
  214.     if [[ "${1:-}" = '-n' ]]; then
  215.         ncols=8
  216.     num[cat]='-n'   # parameter for turning on line numbering in cat
  217.     num[less]='-N'  # parameter for turning on line numbering in less
  218.         shift
  219.     fi
  220.  
  221.     # if taking input from a file
  222.     if [[ $# -gt 0 ]]; then     # is there a file names to process?
  223.         if [[ -f "${1:-}" ]]; then  # and is it a regular file?
  224.  
  225.             # format file and feed it to either less or cat
  226.             fmt -s -w $(( COLUMNS - ncols )) "${1:-}" |
  227.             if [[ $(fmt -s -w $(( COLUMNS - ncols )) "${1:-}" | wc -l) \
  228.                 -gt $(( LINES - promptLines )) ]]; then
  229.         set +u
  230.                 command less -R ${num[less]}
  231.         set -u
  232.             else
  233.         set +u
  234.                 command cat ${num[cat]}
  235.         set -u
  236.             fi
  237.         elif [[ -d "${1:-}" ]]; then
  238.             printf '%s: %s: Is a directory\n' 'pg' "${1:-}" >&2
  239.         else
  240.             printf '%s: %s: No such file or directory\n' 'pg' "${1:-}" >&2
  241.         fi
  242.     elif [[ -v pipeFile ]]; then # taking input from standard input
  243.         for line in "${pipeFile[@]}"; do
  244.             echo "$line"
  245.         done |
  246.         fmt -s -w $(( COLUMNS - ncols )) |
  247.         if [[ lineCount -gt $(( LINES - promptLines )) ]]; then
  248.         set +u
  249.             command less -R ${num[less]}
  250.         set -u
  251.         elif [[ lineCount -gt 0 ]]; then
  252.         set +u
  253.             command cat ${num[cat]}
  254.         set -u
  255.         else
  256.             :
  257.         fi
  258.     fi
  259. }
  260.  
  261. # =============================================================================
  262. # Exception handlers
  263. # =============================================================================
  264. signal_exit() { # Handle trapped signals
  265.     case ${1:-} in
  266.     INT)
  267.         error_exit "Program interrupted by user"
  268.         ;;
  269.     QUIT)
  270.         error_exit "Exiting..."
  271.         ;;
  272.     TERM)
  273.         error_exit "Program terminated"
  274.         ;;
  275.     HUP)
  276.         error_exit "Controlling process died"
  277.         ;;
  278.     *)
  279.         error_exit "Terminating on ${1:-} signal"
  280.         ;;
  281.     esac
  282. }
  283.  
  284. # Trap signals
  285. trap "signal_exit TERM" TERM HUP
  286. trap "signal_exit INT"  INT
  287.  
  288. # =============================================================================
  289. # Parse command line arguments
  290. # =============================================================================
  291.  
  292. if [[ $parser =~ ^getopt$ ]]; then
  293.     #while [[ -n $1 ]]; do
  294.     #    case $1 in
  295.     #   --help)
  296.     #       help_message
  297.     #       graceful_exit
  298.     #       ;;
  299.     #   --*)
  300.     #       usage
  301.     #       error_exit "Unknown option $1"
  302.     #       ;;
  303.     #   -[A-Za-z])
  304.     #       break
  305.     #       ;;
  306.     #   *)
  307.     #       echo "Argument $1 to process..."
  308.     #       ;;
  309.     #    esac
  310.     #    shift
  311.     #done
  312.     #
  313.     # Follow short options with : to indicate required parameters and :: to
  314.     # indicate optional parameters.  Optional arguments to short options cannot
  315.     # have any white space separating them from the option.  Short options that
  316.     # do not have required or optional arguments may be strung together after a
  317.     # single - character.  Long options with optional arguments must have an
  318.     # equal sign separating them from the option name without white space.
  319.     # Otherwise, required arguments may be separated from the long option name
  320.     # with an equal sign or whitespace.  Separate long options with commas in the
  321.     # optstring of the optarg command line.  '--' is added to the end of the
  322.     # parsed options to indicate the end of command line options and arguments and
  323.     # is expected to be handled by a '--' case in the option-parsing section of
  324.     # code.  It should include a shift followed by a break statement.
  325.     #
  326.     # case "$1" in
  327.     #   '-c'|'--c-long') # This has an optional argument
  328.     #   case "$2" in
  329.     #       '')
  330.     #       echo 'Option c, no argument'
  331.     #       ;;
  332.     #       *)
  333.     #       echo 'Option c, argument '$2'"
  334.     #       ;;
  335.     #   esac
  336.     #   shift 2
  337.     #   continue
  338.     #   ;;
  339.     #   '--') # end of argument list
  340.     #   shift
  341.     #   break
  342.     #   ;;
  343.     #   *) # if we are here then optarg had an internal error
  344.     #   echo 'Internal error!' >&2
  345.     #   exit 1
  346.     #   ;;
  347.     # esac
  348.    
  349.     set +e
  350.     temp=$(getopt -o 'huv' --long 'help,usage,version' -n "$PROGNAME" -- "$@")
  351.     set -e
  352.     case "$?" in
  353.     1)  # unspecified arguments encountered
  354.         error_exit 'usage error (use -h for help)'
  355.         ;;
  356.     2)  # getopt command line syntax error
  357.         error_exit "getopt usage error (use 'man getopt' for help)"
  358.         ;;
  359.     3)  # getopt runtime error
  360.         error_exit 'getopt internal error'
  361.         ;;
  362.     esac
  363.     eval set -- "$temp"
  364.     unset temp
  365.     while true; do
  366.     case "${1:-}" in
  367.         '-h'|'--help')
  368.         help_message
  369.         # shift
  370.         # continue
  371.         graceful_exit
  372.         ;;
  373.         '-u'|'--usage')
  374.         usage
  375.         # shift
  376.         # continue
  377.         graceful_exit
  378.         ;;
  379.         '-v'|'--version')
  380.         version
  381.         # shift
  382.         # continue
  383.         graceful_exit
  384.         ;;
  385.         '--') # end of argument list
  386.         shift
  387.         break
  388.         ;;
  389.     esac
  390.     done
  391. else # use getopts
  392.     # parse command-line
  393.     set +e
  394.     while getopts ":huv" opt; do
  395.     case "$opt" in
  396.         h)  # Display long help message
  397.         set -e
  398.         help_message
  399.         graceful_exit
  400.         ;;
  401.         u)  # Display short usage message
  402.         set -e
  403.         usage
  404.         graceful_exit
  405.         ;;
  406.         v)  # Display version
  407.         set -e
  408.         version
  409.         graceful_exit
  410.         ;;
  411.         \?) # Handle invalid options
  412.         set -e
  413.         error_exit "invalid option: -$OPTARG"
  414.         ;;
  415.         :)  # Handle missing option arguments
  416.         set -e
  417.         error_exit "option -$OPTARG requires an argument."
  418.         ;;
  419.     esac
  420.     done  
  421.     shift $(( OPTIND - 1 ))
  422.     set -e
  423. fi
  424.  
  425. # either tell another instance to quit or look for a quit message
  426. cd "$TMPDIR"
  427. if [[ -p tomato ]]; then
  428.     echo 'quit' > tomato && graceful_exit
  429. fi
  430. mkfifo tomato
  431. {
  432.     until read -r; do
  433.     sleep 1
  434.     done < tomato
  435.     rm tomato
  436.     kdialog --title="${PROGNAME^}" --icon='org.kde.plasma.timer' \
  437.     --passivepopup "Stopping tomato timer" &
  438.     killall "$PROGNAME"
  439. } &
  440. # tomato timer workflow
  441. kdialog --title="${PROGNAME^}" --icon='org.kde.plasma.timer' \
  442.     --passivepopup 'Starting tomato timer. Start working' &
  443. declare sessions=0
  444. while true; do
  445.     sleep 25m
  446.     sessions=$(( sessions + 1 ))
  447.     if [[ $sessions -lt 4 ]]; then
  448.     kdialog --title="${PROGNAME^}" --icon='org.kde.plasma.timer' \
  449.         --passivepopup 'Take a 5-minute break' &
  450.     sleep 5m
  451.     else
  452.     sessions=0
  453.     kdialog --title="${PROGNAME^}" --icon='org.kde.plasma.timer' \
  454.         --passivepopup 'Take a 15-minute break' &
  455.     sleep 15m
  456.     fi
  457.     kdialog --title="${PROGNAME^}" --icon='org.kde.plasma.timer' \
  458.     --passivepopup 'Get back to work' &
  459. done
  460.  
  461. graceful_exit
  462.  
  463. # vim: set tabstop=8 softtabstop=4 shiftwidth=4 noexpandtab number relativenumber:
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement