Example ASRs

From Codawiki

This is a dump of several ASRs known to work on the ASR redevelopment branches, in some form or another. Updates are welcome.

Table of contents

Hashing File Replicas

If the SHA1 hashes of each file are identical, then pick a replica and make it the consistent version. Adapted from Patrick Walsh's post on Dealing with conflicts. Be careful with local/global conflicts, as cfs purgeml may do more than just drop this one entry.

Rule

 # If the contents of a file are identical, send any copy to the servers
 
 *:
         cfs cs
         cfs beginrepair $=
 
         # Obtain a replica's name
         replica=`ls $= | head -1`
 
         # Now its content hash
         sum1=`sha1sum $=/$replica | cut -d" " -f1`
 
         # Compare it against all other replicas
         for conf in $=/*; do
                 sum2=`sha1sum $conf | cut -d" " -f1`
                 if [ "$sum1" != "$sum2" ]
                 then
                         cfs endrepair $=
                         exit 1
                 fi
         done
 
         # At this point, all replicas are identical.
 
         case $? in
 
           $?S   )
 
                 cp $=/$replica /tmp/$>
                 cfs endrepair $=
 
                 # Make sure the whole file hit the local file system
                 sum2=`sha1sum /tmp/$> | cut -d" " -f1`
                 if [ "$sum1" != "$sum2" ]
                 then
                         exit 1
                 fi
 
                 # Send our "consistent" file to the servers
                 filerepair $= /tmp/$>
                 cfs fr $:
 
                 # Make sure the whole file hit the servers
                 sum2=`sha1sum $= | cut -d" " -f1`
                 if [ "$sum1" != "$sum2" ]
                 filerepair $= /tmp/$>
                 cfs fr $:
                
                 rm /tmp/$>
                 ;;
   
           $?L   )
           $?M   )
                 cfs purgeml $:
                 ;;
   
         esac

Trivial Directory Conflicts

Compiled Object Files

A resolver to stop building when a conflict is encountered, remove the conflict, and restart the build. Note this is dangerous for local/global, because there might be other CML entries that get wiped with the cfs purgeml call.

Rule

 *.o: $*.c
 
         killall make
 
         case $? in
 
           $?S   )
                 removeinc $=
                 ;;
   
           $?L   )
           $?M   )
                 cfs purgeml $:
                 ;;
 
         esac
 
         make -f $</Makefile

OpenOffice Documents and Spreadsheets

An OpenOffice.org v1/v2 document or spreadsheet resolver (OpenDocument standard). NOTE: v1 needs to be verified.

Rules

 *.sxw:
         $@/ASRs/ooasr.sh $=
 
 *.sxc
         $@/ASRs/ooasr.sh $=
 
 *.odt:
         $@/ASRs/ooasr.sh $=
 
 *.ods:
         $@/ASRs/ooasr.sh $=

ooasr.sh

 #!/bin/sh
 
 conflict=$1
 rootdir=/coda/coda.cs.cmu.edu/usr/awolbach/ASRs
 
 cfs cs
 cfs expand $conflict                                   # expose replicas
 
 FILELIST=$(ls -l $1 |\                                 # build list of replicas
 awk -v conf="$1" '
    BEGIN{ list = "" };
    { list = (list conf "/" $NF " "); }
    END{ print list }
 ')
 
 mergefile=$($rootdir/odmerge.sh $FILELIST)             # take multiple doc's and merge them
 
 cfs collapse $conflict                                 # hide replicas
 
 cfs discardlocal /coda/coda.cs.cmu.edu/usr/awolbach    # discard conflicting update
 cp $mergefile $conflict                                # overwrite with merged file
 
 cfs fr                                                 # reintegrate merged file
 
 echo 'y' | cfs fl $conflict

odmerge.sh

 #!/bin/sh
 
 pwd=`pwd`
 
 # find most recent version
 recent=""
 for file in $*
 do
     if [ -z "$recent" -o "$file" -nt "$recent" ] ; then
         recent="$file"
     fi
 done
 
 echo "Assuming most recent copy is $recent" >&2
 
 # set up temporary directory and extract the most recent copy.
 tmpname="/tmp/oomerge.$RANDOM"
 cp "$recent" "$tmpname.zip"
 mkdir $tmpname
 ( cd $tmpname
 #
 # here is a little function which adds a file to the manifest
 # Usage: add_manifest <file>
 #
 add_manifest () {
     sed 's~\(</manifest:manifest>\)~<manifest:file-entry manifest:media-type="" manifest:full-path="'"$1"'"/>\n\1~' < META-INF/manifest.xml > tmp.xml
     mv tmp.xml META-INF/manifest.xml
 }
 
 #
 # here is a little function which adds a new file to the list of versions.
 # Usage: add_version <file> <comment> <author> <ISO-date>
 #
 # todo: should update META-INF/manifest.xml as well
 #
 n=1
 add_version () {
     # have we seen this file before?
     sum=`md5sum "$1" | cut -c-32`
     grep -q $sum dedup && return
     echo $sum >> dedup
 
     # find an available Versions/VersionN
     while [ -f Versions/Version$n ] ; do n=`expr $n + 1` ; done
 
     cp $1 Versions/Version$n
 
     # update VersionList.xml
     sed 's~\(</VL:version-list>\)~<VL:version-entry VL:title="Version'$n'" VL:comment="'"$2"'" VL:creator="'"$3"'" dc:date-time="'"$4"'"/>\n\1~' < VersionList.xml > tmp.xml
     mv tmp.xml VersionList.xml
 
     # update META-INF/manifest.xml
     add_manifest "Versions/Version$n"
 }
 
 # we only need to extract some files as zip can update the archive in-place
 unzip -q "$tmpname.zip" META-INF/manifest.xml VersionList.xml Versions/\* \
     content.xml meta.xml 2>/dev/null
 
 # create VersionList.xml and Versions/ directory if they are missing
 if [ ! -f "VersionList.xml" ] ; then
     cat > "VersionList.xml" << EOF
 <?xml version="1.0" encoding="UTF-8"?>
 <VL:version-list xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:VL="http://openoffice.org/2001/versions-list">
 </VL:version-list>
 EOF
     add_manifest "VersionList.xml"
 fi
 if [ ! -d "Versions" ] ; then
     mkdir "Versions"
     add_manifest "Versions/"
 fi
 
 # build list of versions to avoid duplicates during merge
 find "Versions" -type f -print0 | xargs -0 md5sum > dedup
 
 # iterate through the list of files, extract and merge their version histories
 for file in $*
 do
     [ "$file" = "$recent" ] && continue
     [ ! -f "$file" ] && continue
     echo "Merging $file" >&2
     cp "$file" tmp.zip
 
     mkdir tmp
     ( cd tmp ; unzip -q ../tmp.zip meta.xml META-INF/manifest.xml VersionList.xml Versions/\* 2>/dev/null)
     if [ -d tmp/Versions ] ; then
         for version in `find tmp/Versions -type f` ; do
             v=`basename "$version"`
             echo "Merging $file/$v" >&2
             comment=`sed -n 's~.*VL:title="'$v'"[^>]*VL:comment="\([^"]*\)".*~\1~p' < tmp/VersionList.xml`
             creator=`sed -n 's~.*VL:title="'$v'"[^>]*VL:creator="\([^"]*\)".*~\1~p' < tmp/VersionList.xml`
             datetime=`sed -n 's~.*VL:title="'$v'"[^>]*dc:date-time="\([^"]*\)".*~\1~p' < tmp/VersionList.xml`
             add_version "$version" "$comment" "$creator" "$datetime"
         done
     fi
 
     # remove VersionList.xml, Versions/VersionN and Thumbnail files from
     # the zip file we are about to add to the archive
     zip -q -d tmp.zip VersionList.xml Versions/\* Thumbnails/\* 2>/dev/null
 
     # strip VersionList.xml, Versions/VersionN and Thumbnail files from
     # manifest.xml
     cat tmp/META-INF/manifest.xml | grep -v Version | grep -v Thumbnails > tmp.xml
     mv tmp.xml tmp/META-INF/manifest.xml
     ( cd tmp ; zip -q ../tmp.zip META-INF/manifest.xml )
 
     # extract author information
     author=`sed -n 's~.*<dc:creator>\(.*\)</dc:creator>.*~\1~p' < tmp/meta.xml`
     rm -rf tmp
 
     mtime=`date -Iseconds -r"$file" | sed 's/[+-]....$//'`
     add_version tmp.zip "$file" "$author" "$mtime"
     rm -f tmp.zip
 done
 
 # clean up temporary files
 rm -f dedup
 
 # Update content.xml...
 id=$RANDOM
 isodate=`date -Iseconds | sed 's/[+-]....$//'`
 prettydate=`date --utc`
 sed 's~\(<office:text>\)~\1<text:tracked-changes text:track-changes="false"><text:changed-region text:id="asr-'$id'"><text:insertion><office:change-info><dc:creator>Coda ASR</dc:creator><dc:date>'"$isodate"'</dc:date></office:change-info></text:insertion></text:changed-region></text:tracked-changes><text:p><text:change-start text:change-id="asr-'$id'"/>Coda found conflicting versions of this document. The version you see was considered the most recent based on the last modification time but all other versions were preserved as well. Go to File/Versions... to review and compare this version against the others.</text:p><text:p>---- Coda ASR, '"$prettydate"' ----<text:change-end text:change-id="asr-'$id'"/></text:p>~' < content.xml > tmp.xml
 mv tmp.xml content.xml
 
 # wheee, it works for OOOv2 files as well (except they use the .odt extension)
 # Do we really care? We can just save '/tmp/oomerge.zip', since it will be
 # blasted over the conflict by filerepair anyways.
 zip -q -D -r "$tmpname.zip" * )
 
 rm -rf $tmpname
 echo "$tmpname.zip"