Fossil SCM is a lightweight SCM system based on SQLite. I use it a lot. Though Logseq supports GIT and I also use GIT, it is too heavy to use git for personal users. I would like to see logseq-db can integrate fossil for providing version control features.
I just found a local-first and SQLite-based note-taking software, Trilium. Trilium supports note versioning, which is fascinating. I’d like to have this feauture in logseq-db. I think, based on SQLite and fossil, note-versioning might be an obvious feature to have.
I managed to integrate logseq and fossil with autohotkey. Using the script below:
What the scripts do:
Commit changes in graph folder to repo every 10m when logseq is running, with comment “A”.
If the logseq is exited , Commit changes in graph folder to repo, with comment “A”, then autohotkey script exit.
When ctrl-s is pressed when logseq is activated, commit changes in graph folder to repo, with comment “M”.
Update local graph from repo at logseq startup.
Benefits of using fossil scm:
Same benefits as git(work from multiple places with same graph, versioning, etc).
Light weight.
Fossil scm provides a builting web gui to do diff between versions
There are four scripts:
startlogseqandmonitor_v3.ahk
syncall2db_auto.bat
syncall2db_manual.bat
updatedb.bat
In theory, the batch commands can be integrated into ahk. But I failed to figure out how to do it after several hours.
The fossil scm repo for logseq graphs should be created at first and works with the batch files.
These scripts assume that logseq graphs is stored in <C:\Users\administrator\Documents\logseqdb\graphs>, fossil command stdout put is redirected to c:\temp
The fossil scm repo can be configured to sync with a remote fossil server for multiple places. Or just sync to local repo and then sync the repo files with other file sync service such as Syncthing.
These scripts can not handle all edge case, keep eyes on logs from time to time!
startlogseqandmonitor_v3.ahk
; Define application paths
app_a_exepath := "C:\Users\administrator\AppData\Local\Logseq\Logseq.exe" ; Replace with the actual path of app_a
app_a_workingpath := "C:\Users\administrator\AppData\Local\Logseq\app-0.10.9" ; Replace with the actual path of app_a
; Check if Logseq.exe is already running
Process, Exist, Logseq.exe
if (ErrorLevel > 0)
{
; If Logseq.exe is already running, get its PID
PID_AppA := ErrorLevel
MsgBox, Logseq.exe is already running. PID: %PID_AppA%
CheckFossilLogs()
}
else
{
; If Logseq.exe is not running, sync and update the Logseq database with the remote database before starting Logseq
SyncAndUpdateLogseqDB()
CheckFossilLogs()
; Start Logseq
Run, % app_a_exepath, % app_a_workingpath
Sleep, 30000 ; Wait for 30 seconds to ensure app_a has started
; Get the actual PID of Logseq.exe
Process, Exist, Logseq.exe
PID_AppA := ErrorLevel
if PID_AppA > 0
{
MsgBox, Logseq.exe has been started. PID: %PID_AppA%
}
else
{
MsgBox, Logseq.exe failed to start.
}
}
; Feature 1: Check if app_a is running every 30 seconds and call app_b based on conditions
SetTimer, CheckAppAStatus, 600000 ; Check every 600 seconds
; Feature 2: Use #IfWinActive to ensure Ctrl+S only works when app_a is in the foreground. Note that #IfWinActive is a directive preprocessor instruction, which is parsed when the script is loaded, not dynamically at runtime. Therefore, variables (such as %PID_AppA%) cannot be directly used in #IfWinActive
#IfWinActive ahk_exe Logseq.exe
{
^s:: ; Ctrl+S
SyncToDBManual()
CheckFossilLogs()
return
}
#IfWinActive ; End condition directive
; Timer function to check the status of app_a
CheckAppAStatus:
Process, Exist, %PID_AppA%
if (ErrorLevel = 0)
{
; If app_a is no longer running, call app_b and exit the script
SyncToDBAuto()
CheckFossilLogs()
MsgBox, Logseq is no longer running. Exiting script.
ExitApp
}
SyncToDBAuto()
CheckFossilLogs()
; MsgBox, Auto commit every 10 minutes.
return
; Define a function to check the fossil logs in the temp directory
CheckFossilLogs()
{
; Define directory and search pattern
dir := "c:\temp"
pattern := "fossil*.log"
; Loop through the files in the directory
Sleep 2000 ; wait for completion of preceding actions
Loop, Files, %dir%\%pattern%, F
{
; Open the file and read its content
file_path := A_LoopFileFullPath
FileRead, file_content, %file_path%
; MsgBox, 0, Fossil Sync Failure, % file_content, 6
; Check if the file content contains "New_Version:" and display a tray icon notification
if (InStr(file_content, "New_Version:", true) > 0)
{
TrayTip Logseq Sync, New Changes Committed
Sleep 3000 ; Let it display for 3 seconds.
HideTrayTip()
;TrayTip #2, This is the second notification.
;Sleep 3000
}
; Check if the file content contains "sync failure"
if (InStr(file_content, "sync failure", true) > 0)
{
; Pop up a message box
; MsgBox, 0, Fossil Sync Failure, % file_content, 6
MsgBox, 0, Fossil Sync Failure, Remote fossil repo sync failure!, 6
; Forcefully terminate all running fossil.exe processes
Process, Close, fossil.exe
}
}
}
; Define a function to perform sync and update operations
SyncAndUpdateLogseqDB()
{
; Define working directory and log file path
app_exepath := "C:\Users\administrator\Documents\logseqdb\updatedb.bat"
app_workingpath := "C:\Users\administrator\Documents\logseqdb"
; Execute the app command
Run, % app_exepath, % app_workingpath, Hide
}
; Define a function to perform automatic commits at regular intervals
SyncToDBAuto()
{
; Define working directory and log file path
app_exepath := "C:\Users\administrator\Documents\logseqdb\syncall2db_auto.bat"
app_workingpath := "C:\Users\administrator\Documents\logseqdb"
; Execute the app command
Run, % app_exepath, % app_workingpath, Hide
}
; Define a function to perform manual commits via Ctrl-S in the Logseq interface
SyncToDBManual()
{
; Define working directory and log file path
app_exepath := "C:\Users\administrator\Documents\logseqdb\syncall2db_manual.bat"
app_workingpath := "C:\Users\administrator\Documents\logseqdb"
; Execute the app command
Run, % app_exepath, % app_workingpath, Hide
}
; Copy this function into your script to use it.
; https://documentation.help/AutoHotkey-en/TrayTip.htm
HideTrayTip() {
;TrayTip ; Attempt to hide it the normal way.
if SubStr(A_OSVersion,1,3) = "10." {
Menu Tray, NoIcon
Sleep 200 ; It may be necessary to adjust this sleep.
Menu Tray, Icon
}
}
syncall2db_auto.bat
cd C:\Users\administrator\Documents\logseqdb\graphs\
fossil sync > c:\temp\fossil_sync.log
fossil update > c:\temp\fossil_update.log
syncall2db_manual.bat
cd C:\Users\administrator\Documents\logseqdb\graphs\
fossil addremove > c:\temp\fossil_addremove.log
fossil commit --no-prompt --no-warnings --comment "M" > c:\temp\fossil_commit.log
updatedb.bat
cd C:\Users\administrator\Documents\logseqdb\graphs\
fossil addremove > c:\temp\fossil_addremove.log
fossil commit --no-prompt --no-warnings --comment "M" > c:\temp\fossil_commit.log
Just found I have mistaken the contents of batch files, the right ones are below.
syncall2db_auto.bat
cd C:\Users\administrator\Documents\logseqdb\graphs\
fossil addremove > c:\temp\fossil_addremove.log
fossil commit --no-prompt --no-warnings --comment "A" > c:\temp\fossil_commit.log
syncall2db_manual.bat
cd C:\Users\administrator\Documents\logseqdb\graphs\
fossil addremove > c:\temp\fossil_addremove.log
fossil commit --no-prompt --no-warnings --comment "M" > c:\temp\fossil_commit.log
updatedb.bat
cd C:\Users\administrator\Documents\logseqdb\graphs\
fossil sync > c:\temp\fossil_sync.log
fossil update > c:\temp\fossil_update.log