experimental script to do a bi-directional sync

hello all,

Here’s an extremely experimental script for doing a bi-directional sync in dtpro 1.2. I’m asking for brave souls who know some applescript to help me debug it. Right now it seems to work pretty well for me, but I certainly wouldn’t want to even think of trying it if you don’t have your data backed up. You can use the script in one of two ways, either attach it as a script to a folder and it will bi-directionally everything in the folder out to the file system, and index everyting in the file system into dtpro. Use at your own risk and with backups, but if you are interested in having this work as much as I am, you might be willing to lend a hand. Using it at the moment means, though, that you are willing to lose data and try to figure out what went wrong!!!

One extra warning, for those interested in helping to debug and look for problems: for better or worse, this script uses a lot of recursion to do what it needs to do. This introduces a bit of redundancy that I can’t at the moment figure out how to get rid of, but if you see a way, I’m all ears.

Oh, you must run this against a folder that is represented in the external (normal) file system of the finder, and has already been ‘indexed’ (using the file menu). Suggestions about the myriad of error checking that should be added are also welcome.

Naturally, what I am hoping is that some of you find this useful…



p.s. I should note that there are a whole range of file system collisions for which this script is not yet prepared. DTpro allows one to have two files in one group with the same name, and the file system does not. I currently have no way of checking this, partly because I’m trying to find the most elegant way to do so. I suppose an array that remembered files saved to the current directory would do the trick. Until that is added, though, beware…

----index bi-directionally 1.0b
----by eric oberle 
----a first try at a bi-directional sync update for devonthink pro
---warning: has no error checking, very well might destroy data.
---do not use on things not backed up; report errors to dt bulletin board

property Unnamed_file_number : 0

on triggered(theRecord)
	tell application "DEVONthink Pro"
		--if indexed of theRecord is false then error "this script requires it to be attached to an indexed folder"
		set top_path to path of theRecord
		set comment of theRecord to top_path
		my index_theunindexed(theRecord, top_path & "/")
		with timeout of 500 seconds
			synchronize record theRecord
		end timeout
	end tell
end triggered

on run
	tell application "DEVONthink Pro"
		set current_rec to the selection
		repeat with a_rec in current_rec
			set top_path to path of a_rec
			my index_theunindexed(a_rec, top_path & "/")
			with timeout of 500 seconds
				synchronize record a_rec
			end timeout
		end repeat
	end tell
end run

on index_theunindexed(top_rec, top_path)
	set try_export to ""
	tell application "DEVONthink Pro"
			set the_children to get children of top_rec
		end try
		---set parent_location to get location of top_rec
		repeat with this_child in the_children
			if type of this_child is group then
				---set the_path to location of top_rec
				set the_name to name of top_rec
				if indexed of this_child is false then ---we need to create this folder, so lower level items have somewhere to go.
					log "making " & top_path & (name of this_child)
						log message "ran mkdir on " & top_path & " :" & (do shell script ("mkdir " & top_path & this_child))
					end try
				end if
				---right now this assumes that no folder has been renamed....
				---could try to detect right here if path ≠ top_rec + name, and then fix paths for  everything below it so that path names in dt correspond to real folders in finder.....
				---go all the way to highest branches of tree, find leaves and then come back here to lower branch
				my index_theunindexed(this_child, (top_path & (name of this_child) & "/"))
				if indexed of this_child is false then
					log "right now on " & path of top_rec
					----delay 10
					log "Exporting " & name of this_child
					----delay 30
					export record this_child to top_path
					log "about to delete…" & name of this_child
					---delay 20
					delete record this_child
				end if
				if indexed of this_child is false then
					set import_path to name of this_child
					---check to see if the filename is blank....file system can't handle that....
					if import_path is "" then
						set import_path to "unnamed_" & (Unnamed_file_number as string)
						set name of this_child to import_path
						set Unnamed_file_number to Unnamed_file_number + 1
					end if
					if import_path is "" then set import_path to "unnamed_folder"
					set export_path to (path of top_rec)
					log "now exporting to*" & export_path & "* name: *" & (name of this_child) & "* will reimport from top_path: " & top_path & "* import_path: *" & import_path
						set try_export to export record this_child to top_path
						log try_export
						if try_export is false then error "could not export " & export_path & (name of this_child)
					on error
						display dialog "could not export " & export_path & (name of this_child)
						set try_export to false
					end try
					log message ("bi-directional sync now indexing: " & import_path) as Unicode text
						if try_export is not "" then delete record this_child in top_rec
					end try
					set import_path to export_path & "/" & import_path
					indicate import_path to top_rec
				end if
			end if
		end repeat
	end tell
end index_theunindexed


This is what I was looking for for ages…
Keep up the good work.

@Eric: How about implementing this idea into an upcoming release 2.0x ?