@ -4,7 +4,7 @@ EZ-Bkup is released under the General Public License 3.0.
See COPYING or < https : / / www . gnu . org / licenses / > for details . ] #
See COPYING or < https : / / www . gnu . org / licenses / > for details . ] #
import owlkettle
import owlkettle
import osproc , os , logging , sequtils , times
import std / osproc , std / os , std / logging
import edit_routine_dialog
import edit_routine_dialog
import " ../models/routine " , " ../shared "
import " ../models/routine " , " ../shared "
@ -13,10 +13,15 @@ viewable RoutineList:
runStatus : string
runStatus : string
selected : seq [ RoutineId ]
selected : seq [ RoutineId ]
# hey, hook.
hooks :
hooks :
# yes, you, the build hook.
build :
build :
# i love you. :)
state . selected = selectedPreload ( )
state . selected = selectedPreload ( )
proc changed ( state : bool )
var thread : Thread [ RoutineListState ]
var thread : Thread [ RoutineListState ]
proc rsyncThread ( list : RoutineListState ) {. thread . } =
proc rsyncThread ( list : RoutineListState ) {. thread . } =
@ -27,8 +32,6 @@ proc rsyncThread(list: RoutineListState) {.thread.} =
createDir ( appPath )
createDir ( appPath )
var logger = newFileLogger ( appPath & " /errors.log " )
var logger = newFileLogger ( appPath & " /errors.log " )
let dt = now ( )
let nowDT = dt . format ( " M-d-YYYY h:mm:ss tt " )
#i'm not sure if using threadvar here is needed, but doing it just in case. :)
#i'm not sure if using threadvar here is needed, but doing it just in case. :)
var rsyncRunCmd {. threadvar . } : string
var rsyncRunCmd {. threadvar . } : string
@ -48,45 +51,43 @@ proc rsyncThread(list: RoutineListState) {.thread.} =
for source in routine . sources :
for source in routine . sources :
for destination in routine . destinations :
for destination in routine . destinations :
#try without requiring superuser privs by default.
#try without requiring superuser privs by default.
#quote sources and destinations to handle possible spaces.
rsyncRunCmd = " rsync -aq " & source & " " & destination
rsyncRunCmd = " rsync -aq " & " ' " & source & " ' " & " " & " ' " & destination & " ' "
rsyncRun = execCmdEx ( rsyncRunCmd )
rsyncRun = execCmdEx ( rsyncRunCmd )
if rsyncRun . exitCode ! = 0 :
if rsyncRun . exitCode ! = 0 :
#handle permission denied error.
#handle permission denied error.
if rsyncRun . exitCode = = 23 :
if rsyncRun . exitCode = = 23 :
rsyncRun . exitCode = 0
rsyncRun . exitCode = 0
#quote sources and destinations to handle possible spaces.
#rsyncRunCmd = "SUDO_ASKPASS=" & getAskPassPath() & " sudo -A rsync -aq " & source & " " & destination
rsyncRunCmd = " pkexec rsync -aq " & " ' " & source & " ' " & " " & " ' " & destination & " ' "
rsyncRunCmd = " pkexec rsync -aq " & source & " " & destination
rsyncRun = execCmdEx ( rsyncRunCmd )
rsyncRun = execCmdEx ( rsyncRunCmd )
if rsyncRun . exitCode ! = 0 :
if rsyncRun . exitCode ! = 0 :
rsyncErrors . add ( " ( " & nowDT & " ) " & " EZ-Bkup ' s rsync process(es) returned error ( " & $ rsyncRun . output & " ) while attempting to back up " & source & " to " & destination )
rsyncErrors . add ( " EZ-Bkup ' s rsync process(es) returned error ( " & $ rsyncRun . output & " ) while attempting to back up " & source & " to " & destination )
#handle non-perms related error.
#handle non-perms related error.
else :
else :
rsyncErrors . add ( " ( " & nowDT & " ) " & " EZ-Bkup ' s rsync process(es) returned error ( " & $ rsyncRun . output & " ) while attempting to back up " & source & " to " & destination )
rsyncErrors . add ( " EZ-Bkup ' s rsync process(es) returned error ( " & $ rsyncRun . output & " ) while attempting to back up " & source & " to " & destination )
#explicitly check that sources were copied to destinations.
#explicitly check that sources were copied to destinations.
#just using file names, mod times, and size (same as bkup run itself).
#just using file names, mod times, and size (same as bkup run itself).
#quote sources and destinations to handle possible spaces.
rsyncCheckCmd = " rsync -rn " & source & " " & destination
rsyncCheckCmd = " rsync -rn " & " ' " & source & " ' " & " " & " ' " & destination & " ' "
rsyncCheckRun = execCmdEx ( rsyncCheckCmd )
rsyncCheckRun = execCmdEx ( rsyncCheckCmd )
if rsyncCheckRun . exitCode ! = 0 :
if rsyncCheckRun . exitCode ! = 0 :
#handle permission denied error.
#handle permission denied error.
if rsyncCheckRun . exitCode = = 23 :
if rsyncCheckRun . exitCode = = 23 :
rsyncCheckRun . exitCode = 0
rsyncCheckRun . exitCode = 0
#quote sources and destinations to handle possible spaces.
#rsyncCheckCmd = "SUDO_ASKPASS=" & getAskPassPath() & " sudo -A rsync -rn " & source & " " & destination
rsyncCheckCmd = " pkexec rsync -rn " & " ' " & source & " ' " & " " & " ' " & destination & " ' "
rsyncCheckCmd = " pkexec rsync -rn " & source & " " & destination
rsyncCheckRun = execCmdEx ( rsyncCheckCmd )
rsyncCheckRun = execCmdEx ( rsyncCheckCmd )
if rsyncCheckRun . exitCode ! = 0 :
if rsyncCheckRun . exitCode ! = 0 :
rsyncErrors . add ( " ( " & nowDT & " ) " & " EZ-Bkup ' s rsync process(es) returned error ( " & $ rsyncRun . output & " ) while attempting to verify that " & source & " got backed up to " & destination )
rsyncErrors . add ( " EZ-Bkup ' s rsync process(es) returned error ( " & $ rsyncRun . output & " ) while attempting to verify that " & source & " got backed up to " & destination )
#handle non-perms related error.
#handle non-perms related error.
else :
else :
rsyncErrors . add ( " ( " & nowDT & " ) " & " EZ-Bkup ' s rsync process(es) returned error ( " & $ rsyncRun . output & " ) while attempting to verify that " & source & " got backed up to " & destination )
rsyncErrors . add ( " EZ-Bkup ' s rsync process(es) returned error ( " & $ rsyncRun . output & " ) while attempting to verify that " & source & " got backed up to " & destination )
if rsyncErrors . len > 0 :
if rsyncErrors . len > 0 :
list . runStatus = " <span color= \" #ff6b6b \" size= \" large \" >Error! Please see ~/.ez-bkup/errors.log</span> "
list . runStatus = " <span color= \" #ff6b6b \" size= \" large \" >Error! Please see ~/.ez-bkup/errors.log</span> "
for err in rsyncErrors :
for err in rsyncErrors :
logger . log ( lvlError , err )
logger . log ( lvlError , err )
elif routineRunCount = = 0 :
elif routineRunCount = = 0 :
list . runStatus = " <span color= \" #FFA651 \" size= \" large \" >No Bkup Routines were enabled. None were run.</span> "
list . runStatus = " <span color= \" #FFA651 \" size= \" large \" >Meh. No Bkup Routines were run.</span> "
else :
else :
list . runStatus = " <span color= \" #6fffa3 \" size= \" large \" >Bkup Complete!</span> "
list . runStatus = " <span color= \" #6fffa3 \" size= \" large \" >Bkup Complete!</span> "
@ -94,10 +95,6 @@ proc rsyncThread(list: RoutineListState) {.thread.} =
method view ( list : RoutineListState ) : Widget =
method view ( list : RoutineListState ) : Widget =
result = gui :
result = gui :
Box :
orient = OrientY
Box :
orient = OrientY
ScrolledWindow :
ScrolledWindow :
Box :
Box :
orient = OrientY
orient = OrientY
@ -113,7 +110,7 @@ method view(list: RoutineListState): Widget =
margin = 6
margin = 6
spacing = 6
spacing = 6
Switch {. expand : false , vAlign : AlignCenter . } :
Switch {. expand : false , vAlign : AlignCenter . } :
state = sequtils . any ( list . selected , proc ( id : RoutineId ) : bool = id = = routine . id )
state = routine . selByDef
tooltip = " Enable/Disable this Routine for the current Bkup run. "
tooltip = " Enable/Disable this Routine for the current Bkup run. "
proc changed ( state : bool ) =
proc changed ( state : bool ) =
if state = = true :
if state = = true :
@ -122,6 +119,9 @@ method view(list: RoutineListState): Widget =
let index = list . selected . find ( routine . id )
let index = list . selected . find ( routine . id )
if index ! = - 1 :
if index ! = - 1 :
list . selected . delete ( index )
list . selected . delete ( index )
if not list . changed . isNil :
list . changed . callback ( true )
Label :
Label :
text = " <span size= \" large \" > " & routine . name & " </span> "
text = " <span size= \" large \" > " & routine . name & " </span> "
xAlign = 0
xAlign = 0
@ -140,14 +140,12 @@ method view(list: RoutineListState): Widget =
if res . kind = = DialogAccept :
if res . kind = = DialogAccept :
# The "Update" button was clicked
# The "Update" button was clicked
list . routineModel . update ( EditRoutineDialogState ( state ) . routine )
list . routineModel . update ( EditRoutineDialogState ( state ) . routine )
list . selected = selectedPreload ( )
# Delete Button
# Delete Button
Button {. expand : false . } :
Button {. expand : false . } :
icon = " user-trash-symbolic "
icon = " user-trash-symbolic "
tooltip = " Delete this Routine. Warning: will not ask you to confirm. "
tooltip = " Delete this Routine. Warning: will not ask you to confirm. "
proc clicked ( ) =
proc clicked ( ) =
list . routineModel . delete ( routine . id )
list . routineModel . delete ( routine . id )
list . selected = selectedPreload ( )
if routine . id in list . selected :
if routine . id in list . selected :
Box :
Box :
orient = OrientY
orient = OrientY
@ -199,25 +197,6 @@ method view(list: RoutineListState): Widget =
text = " <span color= \" #ff6b6b \" >Routine will be ignored. Destination required.</span> "
text = " <span color= \" #ff6b6b \" >Routine will be ignored. Destination required.</span> "
xAlign = 0
xAlign = 0
useMarkup = true
useMarkup = true
else :
Box {. expand : false . } :
orient = OrientY
margin = 6
spacing = 12
Label :
text = " <span size= \" large \" >You don ' t have any Bkup Routines!!! 🙂</span> "
xAlign = 0
useMarkup = true
Label :
text = " <span size= \" large \" >Please click on the + Routine button above to create your first Routine.</span> "
xAlign = 0
useMarkup = true
if list . routineModel . routineSeq ( ) . len ( ) > 0 :
Box {. expand : false . } :
orient = OrientY
Box {. expand : false . } :
orient = OrientY
Box {. expand : false . } :
Box {. expand : false . } :
orient = OrientX
orient = OrientX
spacing = 6
spacing = 6
@ -263,12 +242,7 @@ method view(list: RoutineListState): Widget =
list . runStatus = " <span color= \" #ff6b6b \" size= \" large \" >Missing Source(s)/Destination(s) in selected Routine(s).</span> "
list . runStatus = " <span color= \" #ff6b6b \" size= \" large \" >Missing Source(s)/Destination(s) in selected Routine(s).</span> "
else :
else :
createThread ( thread , rsyncThread , list )
createThread ( thread , rsyncThread , list )
else :
#[if not list.routineModel.routineSeq().len() > 0:
Box :
orient = OrientX
spacing = 6
margin = 6
Box {. expand : false . } :
Box {. expand : false . } :
orient = OrientY
orient = OrientY
margin = 6
margin = 6
@ -280,5 +254,5 @@ method view(list: RoutineListState): Widget =
Label :
Label :
text = " <span size= \" large \" >Please click on the + Routine button above to create your first Routine.</span> "
text = " <span size= \" large \" >Please click on the + Routine button above to create your first Routine.</span> "
xAlign = 0
xAlign = 0
useMarkup = true ] #
useMarkup = true
export RoutineList
export RoutineList