library.org 9.7 KB

Library Management for Small Users

Introduction

CLOSED: [2016-04-16 Sat 15:15]

As a person who has a lot of books, I like to be able to keep track of them. I've tried other pre-built solutions, but they've been flaky and don't do well for the types of books I have. I've also tried to use basic spreadsheets, but in the end, they've not been able to keep up with my desire to search through or produce reports. So, when I stumbled on GNU recutils, I decided that building a script around it would be useful. This is the script and system.

TOC   ignore

WORKING File Format

  # -*- mode: rec -*-

  %rec: Book
  %doc: Foo
  %key: ID
  %unique: Title
  %type: ID int
  %type: Title line
  %type: Author line
  %type: LCCN line
  %type: ISBN regexp /[0-9]*X?/
  %type: Publisher line
  %type: Copyright int
  %type: Location line
  %type: Inserted date
  %mandatory: Title Author LCCN Inserted
  %allowed: ISBN Publisher Copyright Location
  %auto: ID Inserted

WORKING Initialize

  function initialize {
      OLD=`pwd`
      mkdir -p ${LIBRARYDIRECTORY}
      cd ${LIBRARYDIRECTORY}
      [[ -ne `basename ${LIBRARYFILE}` ]] && \
          cat <<EOF > `basename ${LIBRARYFILE}`
  <<file-format>>
  EOF
  }

WORKING Handle Git

  function do-git {
      FIRST=$1
      if [[ $FIRST == "init" ]] ; then
          OLD=`pwd`
          cd ${LIBRARYDIRECTORY}
          git $@
          cd ${OLD}
      else
          if [[ $GIT == "detect" ]] ; then
              OLD=`pwd`
              cd ${LIBRARYDIRECTORY}
              git $@
              cd ${OLD}
          fi
      fi
  }

WORKING Run Queries

  function run-query {
      recsel -t Book $@ ${LIBRARYFILE}
  }

WORKING Add Book

  function add-single {
      echo -n "Title: "
      read TITLE
      echo -n "Author: "
      read AUTHOR
      echo -n "LCCN: "
      read LCCN
      echo -n "Copyright: "
      read COPYRIGHT
      echo -n "Publisher: "
      read PUBLISHER
      echo -n "ISBN: "
      read ISBN
      echo -n "Location: "
      read LOCATION
      recins -t Book \
             -f Title -v "${TITLE}" \
             -f Author -v "${AUTHOR}" \
             -f LCCN -v "${LCCN}" \
             -f Copyright -v "${COPYRIGHT}" \
             -f Publisher -v "${PUBLISHER}" \
             -f ISBN -v "${ISBN}" \
             -f Location -v "${LOCATION}" \
             ${LIBRARYFILE}
      do-git add `basename ${LIBRARYFILE}`
      do-git commit -m "Added record for \"${TITLE}\""
  }

WORKING Add Books in Bulk

  function bulk-add {
      GITOLD=${GIT}
      GIT=FALSE
      for i in {1..$1} ; do
          echo "Adding book number ${i}"
          add-single
      done
      GIT=${GITOLD}
      do-git add `basename ${LIBRARYFILE}`
      do-git commit -m "Added ${1} records"
  }

WORKING View the File in Emacs with Rec Mode

  function view-in-emacs {
      emacsclient --alternate-editor="" -n ${LIBRARYFILE}
  }

WORKING Handle Reporting

  function do-report {
      NAME=$1
      shift
      case ${NAME} in
          list)
              for report in ${LIBRARYDIRECTORY}/*.report ;
              do
                  echo " - $(basename -- ${report} .report)"
              done
          ;;
          new)
              REPORT=$1
              shift
              echo "# -*- mode: sh-script -*-" > ${LIBRARYDIRECTORY}/${REPORT}.report
              emacsclient --alternate-editor="" -n ${LIBRARYDIRECTORY}/${REPORT}.report
          ;;
          ,*)
              if [[ -e ${LIBRARYDIRECTORY}/${NAME}.report ]] ; then
                 sh ${LIBRARYDIRECTORY}/${NAME}.report $@
              fi
      esac
  }

WORKING Edit Field

  function do-edit {
      ID=$1
      shift
      FIELD=$1
      shift

      if [[ $FIELD = "Withdrawn" ]] ; then
          recins -e "ID = ${ID}" \
                 -f "Withdrawn" -v `date "%a, %d %b %Y %H:%M:%S %z"` \
                 ${LIBRARYFILE}
      else
          VALUE=$1
          shift
          recins -e "ID = ${ID}" \
                 -f "${FIELD}" -v "${VALUE}" \
                 ${LIBRARYFILE}
      fi
      do-git add `basename ${LIBRARYFILE}`
      do-git commit -m "Edited record id ${ID}"
  }

WORKING Help Message

  if [[ $# -eq 0 ]] ; then
      echo "library [ help | query query-expressions | add | emacs | git [ other-args ] | bulk-add number | report [ name | list | new name ] | edit id field [ value ] | init ]"
      exit
  fi

  function display-help {
      cat <<EOF
  library [ help | query query-expressions | add | emacs | git [ other-args ] | bulk-add number | report [ name | list | new name ] | edit id field [ value ] | init ]

  help:     Display this help message.
  query:    Query Library Database.
  add:      Add a singular book record.
  emacs:    View records in emacs.
  edit:     Edit the value of a specified field in a specified record.
  git:      Run a git command.
  report:   Run a report.
  init:     Initialize the database.
  bulk-add: Add a specified number of records.
  EOF
  }

WORKING Process Commands

  COMMAND=$1
  shift

  case ${COMMAND} in
      help)
          display-help
          exit
          ;;
      query)
          run-query $@
          exit
          ;;
      add)
          add-single
          exit
          ;;
      git)
          do-git $@
          exit
          ;;
      bulk-add)
          bulk-add $@
          exit
          ;;
      report)
          do-report $@
          exit
          ;;
      emacs)
          view-in-emacs
          exit
          ;;
      edit)
          do-edit $@
          exit
          ;;
      init)
          initialize
          exit
          ;;
      ,*)
          display-help
          exit
  esac

Packaging

CLOSED: [2016-04-16 Sat 15:20]

Finally, this is what puts the application together. Placing each function in its place, making sure that everything is included is done here, fairly simply, by referencing the code block and being expanded here.

  LIBRARYFILE=~/.library/library.rec
  LIBRARYDIRECTORY=~/.library
  GIT=detect

  <<help-message>>

  <<handle-reports>>

  <<handle-git>>

  <<handle-query>>

  <<add-book>>

  <<add-in-bulk>>

  <<edit-field>>

  <<initialize-database>>

  <<view-in-emacs>>

  <<process-commands>>