Index: /trunk/DataStoreServer/Makefile.am
===================================================================
--- /trunk/DataStoreServer/Makefile.am	(revision 16673)
+++ /trunk/DataStoreServer/Makefile.am	(revision 16673)
@@ -0,0 +1,3 @@
+SUBDIRS = scripts
+
+CLEANFILES = *~ core core.*
Index: /trunk/DataStoreServer/autogen.sh
===================================================================
--- /trunk/DataStoreServer/autogen.sh	(revision 16673)
+++ /trunk/DataStoreServer/autogen.sh	(revision 16673)
@@ -0,0 +1,103 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+PROJECT=DataStoreServer
+TEST_TYPE=-f
+# change this to be a unique filename in the top level dir
+FILE=autogen.sh
+
+DIE=0
+
+LIBTOOLIZE=libtoolize
+ACLOCAL="aclocal $ACLOCAL_FLAGS"
+AUTOHEADER=autoheader
+AUTOMAKE=automake
+AUTOCONF=autoconf
+
+#($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || {
+#        echo
+#        echo "You must have $LIBTOOlIZE installed to compile $PROJECT."
+#        echo "Download the appropriate package for your distribution,"
+#        echo "or get the source tarball at http://ftp.gnu.org/gnu/libtool/"
+#        DIE=1
+#}
+
+($ACLOCAL --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $ACLOCAL installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+        DIE=1
+}
+
+#($AUTOHEADER --version) < /dev/null > /dev/null 2>&1 || {
+#        echo
+#        echo "You must have $AUTOHEADER installed to compile $PROJECT."
+#        echo "Download the appropriate package for your distribution,"
+#        echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+#        DIE=1
+#}
+
+($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOMAKE installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+        DIE=1
+}
+
+($AUTOCONF --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOCONF installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+        DIE=1
+}
+
+if test "$DIE" -eq 1; then
+        exit 1
+fi
+
+test $TEST_TYPE $FILE || {
+        echo "You must run this script in the top-level $PROJECT directory"
+        exit 1
+}
+
+if test -z "$*"; then
+        echo "I am going to run ./configure with no arguments - if you wish "
+        echo "to pass any to it, please specify them on the $0 command line."
+fi
+
+#$LIBTOOLIZE --copy --force || echo "$LIBTOOlIZE failed"
+$ACLOCAL || echo "$ACLOCAL failed"
+#$AUTOHEADER || echo "$AUTOHEADER failed"
+$AUTOMAKE --add-missing --force-missing --copy || echo "$AUTOMAKE failed"
+$AUTOCONF || echo "$AUTOCONF failed"
+
+cd $ORIGDIR
+
+run_configure=true
+for arg in $*; do
+    case $arg in
+        --no-configure)
+            run_configure=false
+            ;;
+        *)
+            ;;
+    esac
+done
+
+if $run_configure; then
+    $srcdir/configure --enable-maintainer-mode "$@"
+    echo
+    echo "Now type 'make' to compile $PROJECT."
+else
+    echo
+    echo "Now run 'configure' and 'make' to compile $PROJECT."
+fi
Index: /trunk/DataStoreServer/configure.ac
===================================================================
--- /trunk/DataStoreServer/configure.ac	(revision 16673)
+++ /trunk/DataStoreServer/configure.ac	(revision 16673)
@@ -0,0 +1,16 @@
+AC_PREREQ(2.59)
+
+AC_INIT([DataStoreServer], [1.0.0], [ipp-support@ifa.hawaii.edu])
+AC_CONFIG_SRCDIR([scripts])
+
+AM_INIT_AUTOMAKE([1.6 foreign dist-bzip2])
+AM_MAINTAINER_MODE
+
+AC_PROG_INSTALL
+
+AC_CONFIG_FILES([
+  Makefile
+  scripts/Makefile
+])
+
+AC_OUTPUT
Index: /trunk/DataStoreServer/scripts/Makefile.am
===================================================================
--- /trunk/DataStoreServer/scripts/Makefile.am	(revision 16673)
+++ /trunk/DataStoreServer/scripts/Makefile.am	(revision 16673)
@@ -0,0 +1,9 @@
+
+installdir = $(bindir)
+
+install_files = \
+	dsreg
+
+install_SCRIPTS = $(install_files)
+
+ACLOCAL_AMFLAGS = -I m4
Index: /trunk/DataStoreServer/scripts/dsreg
===================================================================
--- /trunk/DataStoreServer/scripts/dsreg	(revision 16673)
+++ /trunk/DataStoreServer/scripts/dsreg	(revision 16673)
@@ -0,0 +1,330 @@
+#!/usr/bin/env perl
+#
+# Mock-up datastore registration
+#
+# Does not enforce validity of metadata items.
+#
+
+use strict;
+
+use Getopt::Long qw( GetOptions );
+use Pod::Usage qw( pod2usage );
+use Digest::MD5::File qw( file_md5_hex ); 
+
+my $add;
+my $del;
+
+my $ds_dir = './dsroot';
+my $product;
+my $fileset;
+
+### fill in some bogus values here
+my $type = 'OBJECT';
+my $ra = '00:00:00.00';
+my $dec = '00:00:00.00';
+my $equinox = 2000;
+my $etime = 30.0;
+my $filter = 'z';
+my $airmass = 1.2;
+
+my $date;
+
+#
+# parse args
+#
+
+GetOptions(
+    'add'               => \$add,
+    'del'               => \$del,
+    'dsdir|ds=s'        => \$ds_dir,
+    'type|t=s'          => \$type,
+    'ra|r=s'            => \$ra,
+    'dec|d=s'           => \$dec,
+    'equinox|eq=f'      => \$equinox,
+    'etime|ex|e=f'      => \$etime,
+    'filter|f=s'        => \$filter,
+	'date=s'			=> \$date,
+    'airmass|a=f'       => \$airmass,
+) or pod2usage(2);
+
+my $err;
+
+$err .= "Must specify a product and a fileset.\n"
+    unless $#ARGV == 1;
+
+# will exit if neither or both -add and -del were specified
+$err .= "Must specify either -add or -del.\n"
+    unless $add xor $del;
+
+$err .= "Datastore not found at '$ds_dir'.\n"
+    if stat("$ds_dir/index.txt") == undef;
+
+# bail if any of the above args were improper
+show_usage($err)
+    if defined($err);
+
+$product = shift;
+
+show_usage("Invalid product '$product'.")
+    unless stat("$ds_dir/$product/index.txt") != undef;
+
+$fileset = shift;
+
+#
+# run
+#
+
+# allow write for the mockup
+umask 0011;
+
+
+#
+# delete fileset
+#
+if ($del) {
+    if (stat("$ds_dir/$product/$fileset/index.txt") == undef) {
+        print "Fileset '$fileset' doesn't exist under $product.\n";
+        exit(3);
+    }
+
+    # When iterating through the product index below, we rememeber the
+    # fileset and time of the newest (assumes chrono order) fileset that is
+    # not the fileset we're deleting, just in case we have to update the
+    # root index.
+    my $last_fileset;
+    my $last_time;
+
+
+    # Read the product index into a buffer, minus $fileset's entry
+
+    open(IO, "$ds_dir/$product/index.txt")
+        or die("Failed to open '$ds_dir/$product/index.txt' for reading\n");
+
+    my $buf;
+
+    while (<IO>) {
+        my ($fs, $time, my $tmp) = split(/\|/, $_, 3);
+        $fs =~ s/^\s+|\s+$//;
+       
+        # skip the one we're removing
+        next if $fs eq $fileset;
+
+        # record the last one that wasn't the one we're removing
+        $last_fileset = $fs;
+        $last_time = $time;
+
+        $buf .= $_;
+    }
+
+    close(IO);
+
+
+    # Write the new index
+
+    open(IO, ">", "$ds_dir/$product/index.txt")
+        or die("Failed to open '$ds_dir/$product/index.txt' for writing\n");
+        
+    print IO $buf;
+    close(IO);
+    
+
+    # Remove the fileset index file
+
+    unlink("$ds_dir/$product/$fileset/index.txt")
+        or die("Failed to delete '$ds_dir/$product/$fileset/index.txt'\n");
+
+
+    # Check the root index; if the fileset we just removed was the
+    # 'most_recent' one, then replace it.
+
+    my $doreplace = 0;
+    
+    open(IO, "$ds_dir/index.txt")
+        or die("Failed to open '$ds_dir/index.txt' for reading\n");
+
+    $buf = '';
+
+    while (<IO>) {
+        my ($prod, $oldrecent, $oldtime, $extra) = split(/\|/, $_, 4);
+        $prod =~ s/^\s+|\s+$//;
+        
+        if ($prod ne $product) {
+            $buf .= $_;
+            next;
+        }
+
+        if ($oldrecent ne $fileset) {
+            $buf .= $_;
+            next;
+        }
+        
+        $buf .= "$prod|$last_fileset|$last_time|$extra";
+        $doreplace = 1;
+    }
+
+    close(IO);
+
+    # Write the new root index if needed
+    if ($doreplace) {
+        open(IO, ">", "$ds_dir/index.txt")
+            or die("Failed to open '$ds_dir/index.txt' for writing\n");
+        
+        print IO $buf;
+        close(IO);
+    }
+ 
+    print "Removed $fileset from $product.\n";
+}
+
+
+#
+# add fileset
+#
+else {
+    unless (stat("$ds_dir/$product/$fileset/index.txt") == undef) {
+        print "Fileset '$fileset' already exists under $product.\n";
+        exit(4);
+    }
+
+    
+	# Create the fileset index
+
+    open(IO, ">", "$ds_dir/$product/$fileset/index.txt")
+        or die("Failed to open '$ds_dir/$product/$fileset/index.txt' for writing");
+    print IO "# fileID      |bytes   |md5sum                          |type|chipname\n";
+    
+    #print "-- Send file list with lines of the form 'fileID type chipname' "
+    #    ."followed by EOF.\n";
+
+
+    # Read file data from STDIN
+
+    my $lineno = 0;
+
+    while (<STDIN>) {
+        $lineno++;
+        
+        unless (/([A-Za-z0-9-_.]+)\s+([A-Za-z0-9-_.]+)\s+([A-Za-z0-9-_.]+)/) {
+            print "Line $lineno: ignored malformed input line.\n";
+            next;
+        }
+
+        # $1 = file id
+        # $2 = type
+        # $3 = chip
+
+        my @finfo = stat("$ds_dir/$product/$fileset/$1");
+
+        unless (@finfo) {
+            print "Line $lineno: referenced file "
+                ."($ds_dir/$product/$fileset/$1) does not exist.\n";
+            next;
+        }
+        
+        # Get MD5 sum
+        my $md5 = file_md5_hex("$ds_dir/$product/$fileset/$1");
+
+        # Write line to the fileset index
+        print IO "$1|$finfo[7]|$md5|$2|$3\n";
+    }
+
+    close(IO);
+    
+	
+    # Add reference to the new fileset to the product index
+
+	$date = get_iso8601() if not defined($date);
+
+	#FIXME this should probably be inserted in order!
+
+    my $indexstr =
+        "$fileset|$date|$type|$ra  $dec $equinox|$etime|$filter|$airmass";
+
+    #open(IO, ">>", "$ds_dir/$product/index.txt")
+    #    or die("Failed to open $ds_dir/$product/index.txt\n");
+    open(IO, ">>", "$ds_dir/$product/index.lst")
+        or die("Failed to open $ds_dir/$product/index.lst\n");
+    print IO $indexstr, "\n";
+    close(IO);
+
+
+     # Update the root listing to reflect the new most-recent fileset
+
+    open(IO, "$ds_dir/index.txt")
+        or die("Failed to open '$ds_dir/index.txt' for reading\n");
+
+    my $buf;
+
+    while (<IO>) {
+        my ($prod, $oldrecent, $oldtime, $extra) = split(/\|/, $_, 4);
+        $prod =~ s/^\s+|\s+$//;
+        
+        if ($prod ne $product) {
+            $buf .= $_;
+            next;
+        }
+
+        $buf .= "$prod|$fileset|$date|$extra";
+    }
+
+    close(IO);
+
+
+    # Write the new index
+
+    open(IO, ">", "$ds_dir/index.txt")
+        or die("Failed to open '$ds_dir/index.txt' for writing\n");
+        
+    print IO $buf;
+    close(IO);
+    
+    print "Added $fileset to $product.\n";
+}
+
+sub show_usage {
+    my $str = shift;
+
+    chomp $str;
+
+    my @tmp = split(/\//, $0);
+
+    pod2usage(
+        -msg => 
+"usage: $tmp[$#tmp] [-add|-del] product fileset [options]
+
+Commands:
+
+    -del        Remove a fileset.
+    -add        Add a new fileset with the given metadata options.
+                File information will be read per-line from STDIN, in the form:
+                    fileID type chipname
+                These entries are read until EOF is sent.
+Options:
+    
+    -dsdir      Specify the path to the Datastore (defaults to CWD).
+    
+ (The following metadata is optional because this is just a mock-up.)
+
+    -date       ISO8601 date string. (File timestamp used if not specified.)
+    -type       Fileset type.
+    -ra         Telescope pointing RA.
+    -dec        Telescope pointing Dec.
+    -equinox    Equinox.
+    -etime      Exposure time.
+    -filter     Filter used.
+    -airmass    Air mass.
+    
+$str",
+        -exitval => 2
+    );
+}
+
+# get the current UTC time in iso8601 format
+# this is used if no time parameter is specified
+sub get_iso8601() {
+    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
+        gmtime(time);
+
+    return sprintf("%4d-%02d-%02dT%02d:%02d:%02dZ",
+        $year+1900, $mon+1, $mday, $hour, $min, $sec);
+}
