From 9845988e5e3cc1bec0ae98476f04b46dabc94f5a Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Mon, 28 Dec 2009 22:02:04 +0200 Subject: First commit --- README | 25 +++++++++++ archive.sh | 8 ++++ awcli.sh | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.py | 7 +++ config.pyc | Bin 0 -> 320 bytes fcs.png | Bin 0 -> 354418 bytes finalstore.py | 79 +++++++++++++++++++++++++++++++++ presscut.pyc | Bin 0 -> 2831 bytes restore.sh | 8 ++++ 9 files changed, 265 insertions(+) create mode 100644 README create mode 100755 archive.sh create mode 100755 awcli.sh create mode 100644 config.py create mode 100644 config.pyc create mode 100644 fcs.png create mode 100755 finalstore.py create mode 100644 presscut.pyc create mode 100755 restore.sh diff --git a/README b/README new file mode 100644 index 0000000..e85cbd3 --- /dev/null +++ b/README @@ -0,0 +1,25 @@ +## 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 runner.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 of what happened + +### Restore ### +- User selects assets in FCSvr and clicks Restore. +- restore.sh writes the file paths to /tmp/fcs_toRestore +- 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 +- In FCSvr, open Administration > Devices > Archive and set the pahts of the archive and restore +scripts +- Configure your PressSTORE archive plan + +##Configuration## +... diff --git a/archive.sh b/archive.sh new file mode 100755 index 0000000..7b8f8be --- /dev/null +++ b/archive.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Collect archived assets to a text file +DST="/tmp/finalstore/archive" +if [ ! -d $DST ]; then + mkdir -p $DST +fi +echo $1 >> "${DST}/$(date +'%s').txt" +exit 0 diff --git a/awcli.sh b/awcli.sh new file mode 100755 index 0000000..e682ebc --- /dev/null +++ b/awcli.sh @@ -0,0 +1,138 @@ +#!/bin/sh +# This is a modified version of awcli.sh that comes bundled with PresSTORE +# The differences are: +# - returning the Job ID +# - support for servers running on other hosts +# +# See the file "license.txt" for information on usage and +# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +# +# Override locale settings +# + +source /Library/Application\ Support/TV\ Tools/FinalStore/config.py + +LC_ALL="C"; export LC_ALL + +usage() { + echo "usage: $0 [archive | restore] plan_name file1 file2 ... fileN" + exit 1 +} +clierr() { + echo "`$nc -c geterror`" + 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 + +# +# Check the operation. +# + +task="$1" +if test "$task" != "archive" -a "$task" != "restore"; then + usage +fi + +# +# Check the name of the Archive plan to use +# Bail-out if the plan is missing +# + +shift +aplan="$1" +dummy=`$nc -c ArchivePlan $aplan describe` +if test $? -ne 0; then + echo "$0: archive plan $aplan not found" + exit 1 +fi + +# +# Refuse to work when no files given +# + +shift +if test "$#" -eq 0; then + echo "$0 no files to $task" + exit 1 +fi + +# +# Now do the archive or restore task +# + +case $task in + archive) + # Create archive selection object + as=`$nc -c ArchiveSelection create localhost $aplan` + if test $? -ne 0; then + clierr + fi + # Add files to it + adfile=0 + for file do + 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 + fi + adfile=`expr $adfile + 1` + fi + done + # Submit archive job + if test $adfile -eq 0; then + echo "$0: no files selected for $task" + else + jobid=`$nc -c ArchiveSelection $as submit 1` + echo $jobid + if test $? -ne 0; then + clierr + fi + fi + ;; + + restore) + # Get the database for the given plan + dbase=`$nc -c ArchivePlan $aplan database` + if test $? -ne 0; then + clierr + fi + # Create restore selection object + rs=`$nc -c RestoreSelection create localhost` + if test $? -ne 0; then + clierr + fi + # Add files to it + for file do + aentry=`$nc -c ArchiveEntry handle localhost "{$file}" $dbase` + if test $? -ne 0; then + clierr + fi + apath=`$nc -c RestoreSelection $rs addentry $aentry` + if test $? -ne 0; then + clierr + fi + done + # Submit the restore job + jobid=`$nc -c RestoreSelection $rs submit 1` + echo $jobid + if test $? -ne 0; then + clierr + fi + ;; +esac + +exit 0 diff --git a/config.py b/config.py new file mode 100644 index 0000000..2ca0313 --- /dev/null +++ b/config.py @@ -0,0 +1,7 @@ +# This file is shared between Bash and Python +# so keep it clean! +USER="" +HOST="" +ARCHIVEPLAN="10001" +PASSWORD="" +NC="/usr/local/aw/bin/nsdchat" diff --git a/config.pyc b/config.pyc new file mode 100644 index 0000000..d9e6926 Binary files /dev/null and b/config.pyc differ diff --git a/fcs.png b/fcs.png new file mode 100644 index 0000000..0448a99 Binary files /dev/null and b/fcs.png differ diff --git a/finalstore.py b/finalstore.py new file mode 100755 index 0000000..40e5bf4 --- /dev/null +++ b/finalstore.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python -Wall +# This is only run from launchd +# @author Filipp Lepalaan +# @updated 10.12.2009 +# @created 09.12.2009 + +import sys, time, os, glob, traceback +from config import * +from subprocess import * + +""" + Time saver for posting Growl notifications +""" +def growl(str): + icon = sys.path[0] + "/fcs.png" + cmd = ["/usr/local/bin/growlnotify", "-s", "-m", str, "--image", icon] + try: + Popen(cmd, shell=False).communicate() + except Exception, e: + print "Growl failed" + + +""" + Forward the files to awcli + Wait for presstore to finish +""" +def doit(task, f, ap): + assets = [] + # Gather up all the assets marked for processing + for l in f.readlines(): + s = l.strip() + print "Processing " + l + if not s: break + assets.append(s) + + # Get rid of these as soon as possible + f.close() + os.unlink(f.name) + + awcli = sys.path[0] + "/awcli.sh" + r = Popen([awcli, task, ap] + assets, stdout=PIPE, shell=False).communicate() + jid = r[0].strip() + + print task + " job ID is " + jid + growl("Started %s job %s (%d assets)" % (task, jid, len(assets))) + + # Wait for the job to finish + sock = "awsock:/%s:%s@%s:9001" % (USER, PASSWORD, HOST) + cmd = "Job %s status" % (jid) + + while True: + try: + check = Popen([NC, "-s", sock , "-c", cmd], stdout=PIPE, shell=False) + s = check.communicate()[0].strip() + except Exception, e: + print traceback.print_exc(file=sys.stdout) + if s == "completed" or s == "cancelled" : break + time.sleep(2) + + growl("%s %s job %s" % (s.capitalize(), task, jid)) + +# DO IT +try: + for f in glob.glob("/tmp/finalstore/archive/*.txt"): + d = open(f, "r") + doit("archive", d, ARCHIVEPLAN) +except Exception, e: + print "Nothing to archive" + +try: + for f in glob.glob("/tmp/finalstore/restore/*.txt"): + d = open(f, "r") + doit("restore", d, ARCHIVEPLAN) +except Exception, e: + print "Nothing ro restore" + +# To not upset launchd +time.sleep(5) +sys.exit(0) diff --git a/presscut.pyc b/presscut.pyc new file mode 100644 index 0000000..80a4617 Binary files /dev/null and b/presscut.pyc differ diff --git a/restore.sh b/restore.sh new file mode 100755 index 0000000..1443eed --- /dev/null +++ b/restore.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Collect restored assets to a text file +DST="/tmp/finalstore/restore" +if [ ! -d $DST ]; then + mkdir -p $DST +fi +echo $1 >> "${DST}/$(date +'%s').txt" +exit 0 -- cgit v1.2.3