From 876f379aab094ffb029c6c8f17ff2d73d92a8f1e Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Tue, 29 Dec 2009 11:48:29 +0200 Subject: Only archive stuff once, better config, bugfixes, etc --- README | 27 +++++++++++++++++------ archive.sh | 2 +- awcli.sh | 51 ++++++++++++++++++++++++++++++++------------ config.py | 12 ++++++----- config.pyc | Bin 320 -> 0 bytes fi.tvtools.finalstore.plist | 16 ++++++++++++++ finalstore.py | 12 ++++++++--- restore.sh | 2 +- 8 files changed, 91 insertions(+), 31 deletions(-) delete mode 100644 config.pyc create mode 100644 fi.tvtools.finalstore.plist diff --git a/README b/README index c1f34ed..8d6db1d 100644 --- a/README +++ b/README @@ -1,25 +1,38 @@ +## Features ## +- Uses Growl for status notifications +- Smart enough to only archive an asset once +- Allows running archive and FCSvr services on separate machines +- Keeps a log of tasks +- Supports archiving/restoring multiple assets at once + ## How it works ## ### Archive ### - User selects assets in FCSvr and clicks Archive. FCSvr moves the asset to it's Archive Device and marks it as archived -- archive.sh writes the file paths to /tmp/fcs_toArchive -- launchd job (fi.tvtools.finalstore) runs finalstore.py every n seconds +- archive.sh writes the archived file path(s) to /tmp/finalstore/archive/.txt +- launchd job (fi.tvtools.finalstore) runs finalstore.py every 20 seconds - finalstore.py forwards the file list to a customized awcli.sh, waits for the job to finish and runs growlnotify to let the user know of what happened ### Restore ### - User selects assets in FCSvr and clicks Restore. -- restore.sh writes the file paths to /tmp/fcs_toRestore +- restore.sh writes the file paths to /tmp/finalstore/restore/.txt - launchd job (fi.tvtools.finalstore) runs finalstore.py every n seconds - finalstore.py forwards the file list to a customized awcli.sh, waits for the job to finish and runs growlnotify to let the user know what happened ## Installation ## - -- Drag the finalstore folder to /Library/Application Support/TV Tools/finalstore +- Drag the FinalStore folder to /Library/Application Support/TV Tools - In FCSvr, open Administration > Devices > Archive and set the pahts of the archive and restore scripts - Configure your PressSTORE archive plan +- In System Preferences > Final Cut Server, increase the Retry Count and Timeout values (for example 100/10). This is necessary for the restore process, to give PresSTORE time to retrieve the assets. +- Edit FinalStore/config.py to match your configuration +- Load the launchd job. Either create an alias or copy fi.tvtools.finalstore.plist into /Library/LaunchDaemons and: + + sudo launchctl load -w /Library/LaunchDaemons/fi.tvtools.finalstore.plist + +- Install Growl + growlnotify on the Final Cut Server. Optionally enable network notifications, if you want to send them to your Final Cut Server.app users. -##Configuration## -... +## Why is this thing so complicated? ## +The main reason is because Final Cut Server only sends one archive/restore asset path at a time. This means we need a lot more files to keep track of them. diff --git a/archive.sh b/archive.sh index 7b8f8be..855e439 100755 --- a/archive.sh +++ b/archive.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Collect archived assets to a text file +# Collect archive asset to a text file DST="/tmp/finalstore/archive" if [ ! -d $DST ]; then mkdir -p $DST diff --git a/awcli.sh b/awcli.sh index e682ebc..e0a2b12 100755 --- a/awcli.sh +++ b/awcli.sh @@ -3,6 +3,8 @@ # The differences are: # - returning the Job ID # - support for servers running on other hosts +# - store the "asset id" as the description +# - separating configuration data into an external file # # See the file "license.txt" for information on usage and # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -13,6 +15,11 @@ source /Library/Application\ Support/TV\ Tools/FinalStore/config.py +if [[ -z $AWUSER ]]; then + echo "Configuration incomplete, please check config.py" + exit 1 +fi + LC_ALL="C"; export LC_ALL usage() { @@ -24,15 +31,7 @@ clierr() { exit 1 } -# -# Locate the nsdchat utility -# - -if test -z "$AWPST_HOME"; then - nc="${NC} -s awsock:/${USER}:${PASSWORD}@${HOST}:9001" -else - nc=$AWPST_HOME/bin/nsdchat -fi +nc="${NC} -s awsock:/${AWUSER}:${AWPASSWORD}@${AWHOST}:${AWPORT}" # # Check the operation. @@ -77,24 +76,45 @@ case $task in if test $? -ne 0; then clierr fi + # Create restore selection for checking if asset's been already archived + rs=`$nc -c RestoreSelection create localhost` + if test $? -ne 0; then + clierr + fi # Add files to it adfile=0 for file do + if [[ ! -z $FSLOG ]]; then + echo "$(date) $task $file" >> $FSLOG + fi if test ! -r "$file"; then echo "$0: $file: no such file" elif test ! -f "$file"; then echo "$0: $file: not a plain file" else - aentry=`$nc -c ArchiveSelection $as addentry "{$file}"` - if test $? -ne 0; then - clierr + aid=$(echo -n "$file" | md5) + # Check if asset has already been archived + dummy=`$nc -c RestoreSelection $rs findentry $aplan {description == $aid}` + if [[ -z "$dummy" ]]; then + clierr + fi + if [[ "$dummy" -lt 1 ]]; then + aentry=`$nc -c ArchiveSelection $as addentry "{$file}" description $aid` + if test $? -ne 0; then + clierr + fi + adfile=`expr $adfile + 1` + else + # Asset already in archive, just delete from FCSvr archive device + rm "$file" fi - adfile=`expr $adfile + 1` fi done # Submit archive job if test $adfile -eq 0; then - echo "$0: no files selected for $task" + # Nothing to archive - either no valid files, or all already archived + echo "-1" + exit 0 else jobid=`$nc -c ArchiveSelection $as submit 1` echo $jobid @@ -117,6 +137,9 @@ case $task in fi # Add files to it for file do + if [[ ! -z $FSLOG ]]; then + echo "$(date) $task $file" >> $FSLOG + fi aentry=`$nc -c ArchiveEntry handle localhost "{$file}" $dbase` if test $? -ne 0; then clierr diff --git a/config.py b/config.py index 2ca0313..5d6d5d7 100644 --- a/config.py +++ b/config.py @@ -1,7 +1,9 @@ # This file is shared between Bash and Python -# so keep it clean! -USER="" -HOST="" -ARCHIVEPLAN="10001" -PASSWORD="" +# so keep it tight (no spaces between names and values)! +AWUSER="" +AWHOST="" +AWPORT="9001" +AWPASSWORD="" +ARCHIVEPLAN="" +FSLOG="/var/log/finalstore.log" NC="/usr/local/aw/bin/nsdchat" diff --git a/config.pyc b/config.pyc deleted file mode 100644 index d9e6926..0000000 Binary files a/config.pyc and /dev/null differ diff --git a/fi.tvtools.finalstore.plist b/fi.tvtools.finalstore.plist new file mode 100644 index 0000000..b55efe2 --- /dev/null +++ b/fi.tvtools.finalstore.plist @@ -0,0 +1,16 @@ + + + + + Label + fi.tvtools.finalstore + ProgramArguments + + /Library/Application Support/TV Tools/FinalStore/finalstore.py + + StartInterval + 20 + AbandonProcessGroup + + + diff --git a/finalstore.py b/finalstore.py index f7d9cd9..218cc37 100755 --- a/finalstore.py +++ b/finalstore.py @@ -18,7 +18,6 @@ def growl(str): Popen(cmd, shell=False).communicate() except Exception, e: print "Failed to initialize Growl" - """ Forward the files to awcli @@ -41,11 +40,18 @@ def doit(task, f, ap): r = Popen([awcli, task, ap] + assets, stdout=PIPE, shell=False).communicate() jid = r[0].strip() + if jid == "-1": + growl("Asset already archived") + sys.exit(0) + print task + " job ID is " + jid - growl("Started %s job %s (%d assets)" % (task, jid, len(assets))) + ac = len(assets) + sfx = "s" + if ac == 1 : sfx = "" + growl("Started %s job %s (%d asset%s)" % (task, jid, ac, sfx)) # Wait for the job to finish - sock = "awsock:/%s:%s@%s:9001" % (USER, PASSWORD, HOST) + sock = "awsock:/%s:%s@%s:%s" % (AWUSER, AWPASSWORD, AWHOST, AWPORT) cmd = "Job %s status" % (jid) while True: diff --git a/restore.sh b/restore.sh index 1443eed..d6ee040 100755 --- a/restore.sh +++ b/restore.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Collect restored assets to a text file +# Collect restore asset to a text file DST="/tmp/finalstore/restore" if [ ! -d $DST ]; then mkdir -p $DST -- cgit v1.2.3