#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
#SingleInstance force
; ==================== IMPORTANT NOTES =============================================================
; PL/SQL Developer has an amazing "desktop=" feature which allows you to autosave your workspace(s) and re-load all open windows on startup.
; However, this feature breaks when you have multiple monitor configurations, e.g. when remoting in from a laptop, or possibly saving the workspaces on a shared drive.
; In this situation, PL/SQL Developer puts single-monitor setups in the root folder, and multi-monitor setups in a folder named for the resolution of those desktops.
; So if you have a workspace open on one machine and then remote in, suddenly the autosave is happening to a different folder.
; Given that this is happening, but that I would prefer my workspaces to operate seamlessly regardless of how I am accessing them,
; I want something that can automatically detect when any ".cfg" file is created or updated in any of the folders and keep the others at the newest version.
; Also, PL/SQL Developer, when working in a single directory, will delete temporary files that are no longer in use. This script *would* keep those deleted files alive
; by continually copying them into other directories and back again. This won't really harm anything, since they won't be connected to any workspaces. So, to reduce
; clutter I have also added a check to detect when they are not in use. So for the root directory and each Monitors directory, this script will loop through non-cfg
; files, then parse the corresponding "desktop.*.cfg" file to see whether the filename appears in any of them. If not, it will delete it. Note that this means ANY FILE
; in this folder starting with "desktop." (and not ending in ".cfg" or ".ini") or ending in ".0xx" will be deleted if it does not belong to a PL/SQL Developer workspace.
; Sometimes we get "crash" files which are handled poorly by this script. I don't know how to detect when these ones are no longer necessary.
; EXTRA-IMPORTANT NOTE: This script is not very thoroughly vetted yet, and it deletes/overwrites files. Thus, *back up* the entire PLS-Recovery directory before *each* use.
; At some point, I'd love to have this run automatically, maybe several times per hour. As it stands, it should be run prior to opening workspaces and probably only then.
; Also, it needs to be run several times until there is no output, since it's moving and deleting files in a very specific order. Probably best to do this while no
; PL/SQL Developer windows are open so that files aren't being modified by both at the same time.
; ==================== GLOBAL VARIABLES ============================================================
; Turn on or off the copy/delete functions (this was useful during testing, but I might as well leave it in)
global do_copy = true
global do_delete = true
; Turn on or off detailed debug messages for the copy/delete functions
global msg_copy = false
global msg_delete = false
; ==================== MAIN PROGRAM ================================================================
file1 =
file2 =
file2dir =
cfgfile =
parsestr =
FileList = ; List files first to prevent errors as we operate on the files we're checking
FileList2 =
DirList =
Loop, Files, *, D
DirList = %DirList%%A_LoopFileName%`n
Loop, Parse, DirList, `n
{
if (InStr(A_LoopField, "Monitors") = 1)
{
file2dir = %A_LoopField%
if msg_copy or msg_delete
MsgBox, Found directory: %file2dir%
}
}
; For each .cfg in the root directory, check each folder and check if the file exists. If it doesn't, copy it. If it does, compare the dates.
Loop, Files, *
FileList = %FileList%%A_LoopFileName%`n
Loop, Parse, FileList, `n
{
file1 = %A_LoopField%
if (InStr(A_LoopField, ".cfg") >= 1)
{
if msg_copy
MsgBox Found config file: %file1%
Loop, Parse, DirList, `n
{
FileList2 =
if (InStr(A_LoopField, "Monitors") = 1)
{
if msg_copy
MsgBox Checking folder: %A_LoopField%
file2dir = %A_LoopField%
file2 = %file2dir%/%file1%
CompareFiles(file1, file2)
}
}
} else {
if (InStr(A_LoopField, "desktop.") = 1 and InStr(A_LoopField, ".ini") = 0)
{
if msg_delete
MsgBox, Found non-config %file1%
cfgfile := Substr(file1, 1, Instr(file1, ".", false, -1)) . "cfg"
ParseFile(cfgfile, file1, file1)
}
}
}
; Then, for each file in each of the folders, check if it exists in the root.
Loop, Parse, DirList, `n
{
FileList2 =
if (InStr(A_LoopField, "Monitors") = 1)
{
file2dir = %A_LoopField%
;MsgBox, Found dir %file2dir%
Loop, Files, %A_LoopField%\*
FileList2 = %FileList2%%A_LoopFileName%`n
Loop, Parse, FileList2, `n
{
FileList =
file2 = %A_LoopField%
if (InStr(A_LoopField, ".cfg") >= 1)
{
if msg_copy
MsgBox Found config file: %file2dir%/%file2%. Checking root.
CompareFiles(file2dir . "/" . file2, file2)
} else {
if (InStr(A_LoopField, "desktop.") = 1 and InStr(A_LoopField, ".ini") = 0) or (RegExMatch(A_LoopField, "[.][0-9][0-9][0-9]$") > 0)
{
if msg_delete
MsgBox, Found non-config %file2%
cfgfile := file2dir . "/" . Substr(file2, 1, Instr(file2, ".", false, -1)) . "cfg"
did_delete := ParseFile(cfgfile, file2, file2dir . "/" . file2)
if not %did_delete%
{
if msg_delete
MsgBox, Kept %file2%; comparing to root
CompareFiles(file2dir . "/" . file2, file2)
}
}
}
}
}
}
return
; ==================== FUNCTIONS ===================================================================
ParseFile(file, str, delfile)
{
did_delete = false
FileRead, filestr, %A_ScriptDir%/%file%
if ErrorLevel
MsgBox, Could not open file %file%: %A_LastError%
else
{
if msg_delete
MsgBox, Parsing %file% for string "%str%"
if (InStr(filestr, str) < 1)
{
MsgBox, Deleting %delfile%
if do_delete
{
FileDelete, %delfile%
did_delete = true
}
}
else
{
if msg_delete
MsgBox, File is in use by a workspace. Keeping.
}
}
return did_delete
}
OverwriteFile(srcFile, destFile)
{
MsgBox, Copying %srcFile% to %destFile%
if do_copy
FileCopy, %srcFile%, %destFile%, 1
}
CompareFiles(file1, file2)
{
; Compares the system date on file1 and file2 and updates the older with the most recent version
if msg_copy
MsgBox, Comparing %file1% with %file2%
IfNotExist, %file2%
OverwriteFile(file1, file2)
else
{
FileGetTime, time1, %file1%
FileGetTime, time2, %file2%
if time1 - time2 > 0
OverwriteFile(file1, file2)
if time2 - time1
OverwriteFile(file2, file1)
}
}