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.
# -*- 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
function initialize { OLD=`pwd` mkdir -p ${LIBRARYDIRECTORY} cd ${LIBRARYDIRECTORY} [[ -ne `basename ${LIBRARYFILE}` ]] && \ cat <<EOF > `basename ${LIBRARYFILE}` <<file-format>> EOF }
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 }
function run-query { recsel -t Book $@ ${LIBRARYFILE} }
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}\"" }
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" }
function view-in-emacs { emacsclient --alternate-editor="" -n ${LIBRARYFILE} }
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 }
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}" }
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 }
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
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>>