#[Copyright 2023 ITwrx. This file is part of EZ-Bkup. EZ-Bkup is released under the General Public License 3.0. See COPYING or for details.]# import owlkettle import std/osproc, std/os #import asynctools #import threadpool import edit_routine_dialog import "../models/routine", "../shared" viewable RoutineList: ## Displays a list of routines routineModel: RoutineModel ## Model of all routines runStatus: string rsyncRun: tuple[output: string, exitCode: int] proc changed(state: bool) var thread: Thread[RoutineListState] #var rsyncRun: tuple[output: string, exitCode: int] proc rsyncThread(list: RoutineListState, rsyncCommand: string) {.thread.} = while true: list.rsyncRun = execCmdEx(rsyncCommand) list.redrawFromThread() sleep(1000) method view(list: RoutineListState): Widget {.locks: "unknown".} = result = gui: ScrolledWindow: Box: orient = OrientY if list.routineModel.routineSeq().len() > 0: ListBox: for it, routine in list.routineModel.routineSeq(): Box: orient = OrientY margin = 6 spacing = 6 Box: orient = OrientX margin = 6 spacing = 6 Label: text = "" & routine.name & "" xAlign = 0 useMarkup = true # Edit Button Button {.expand: false.}: #icon = "entity-edit" icon = "entity-edit-dark-theme" tooltip = "Edit this Routine." proc clicked() = ## Opens the EditRoutineDialog for updating the existing routine let (res, state) = list.app.open: gui: EditRoutineDialog: routine = routine mode = EditRoutineUpdate if res.kind == DialogAccept: # The "Update" button was clicked list.routineModel.update(EditRoutineDialogState(state).routine) # Delete Button Button {.expand: false.}: icon = "user-trash-symbolic" tooltip = "Delete this Routine. Warning: will not ask you to confirm." proc clicked() = list.routineModel.delete(routine.id) if routine.selByDef: Box: orient = OrientY margin = 6 spacing = 6 Label: text = "Sources:" xAlign = 0 useMarkup = true #routineSeq returns an empty string when no sources exist. if routine.sources.len != 0: for it, routineSource in routine.sources: Box: orient = OrientX spacing = 6 margin = 6 Label: text = routineSource xAlign = 0 else: Box: orient = OrientX spacing = 6 margin = 6 Label: text = "Routine will be ignored. Source required." xAlign = 0 useMarkup = true Label: text = "Destinations:" xAlign = 0 useMarkup = true #routineSeq returns an empty string when no destinations exist. if routine.destinations.len != 0: for it, routineDestination in routine.destinations: Box: orient = OrientX spacing = 6 margin = 6 Label: text = routineDestination xAlign = 0 else: Box: orient = OrientX spacing = 6 margin = 6 Label: text = "Routine will be ignored. Destination required." xAlign = 0 useMarkup = true Box {.expand: false.}: orient = OrientX spacing = 6 margin = 6 Label {.expand: false.}: text = "Status: " xAlign = 0 useMarkup = true Label: if list.runStatus != "": text = list.runStatus else: text = "Waiting patiently..." xAlign = 0 margin = 6 useMarkup = true # Run Button Button {.expand: false.}: Box: orient = OrientX spacing = 6 margin = 6 Icon: name = "media-floppy" pixelSize = 40 margin = 4 Label {.expand: false.}: text = "Run Bkup!" xAlign = 0 useMarkup = true proc clicked() = list.runStatus = "Running Bkup..." #var rsyncRun: tuple[output: string, exitCode: int] var rsyncErrors: seq[string] var routineRunCount = 0 for routine in list.routineModel.routineSeq(): #using this as "selected" for now. if routine.selByDef == true: #skip routines that don't have at least one source and one destination. if routine.sources.len != 0 and routine.destinations.len != 0: routineRuncount += 1 for source in routine.sources: for destination in routine.destinations: list.runStatus = "Bkup " & source & " to " & destination & "..." #try without requiring superuser privs by default. #rsyncRun = execCmdEx("rsync -aq " & source & " " & destination) let rsyncRunCmd = "rsync -aq " & source & " " & destination #let rsyncThreadProcCall = rsyncThread(rsyncRunCmd) createThread(thread, rsyncThread(list, rsyncRunCmd), list) #createThread(thread, rsyncThreadProcCall, list) #rsyncRun = spawn execCmdEx("rsync -aq " & source & " " & destination) #sync() #rsyncRun = await asynctools.execProcess("rsync -aq " & source & " " & destination) if list.rsyncRun.exitCode != 0: #handle permission denied error. if list.rsyncRun.exitCode == 23: let rsyncRunCmd = "SUDO_ASKPASS=" & getAskPassPath() & " sudo -A rsync -aq " & source & " " & destination #rsyncRun = execCmdEx(rsyncRunCmd) #rsyncRun = spawn execCmdEx(rsyncRunCmd) #sync() createThread(thread, rsyncThread(rsyncRunCmd), list) #rsyncRun = await asynctools.execProcess(rsyncRunCmd) if list.rsyncRun.exitCode != 0: rsyncErrors.add("EZ-Bkup's rsync process(es) returned error (" & $rsyncRun.output & ") while attempting to back up " & source & " to " & destination) else: rsyncErrors.add("EZ-Bkup's rsync process(es) returned error (" & $rsyncRun.output & ") while attempting to back up " & source & " to " & destination) #makes the "Bkup Complete" msg below wait on the rsyncRun to finish. if list.rsyncRun.exitCode == 1 or list.rsyncRun.exitCode == 0: if rsyncErrors.len > 0: list.runStatus = "Error! Please see the log at ~/.ez-bkup/errors.log" for err in rsyncErrors: writeErrorToLog(err) echo err elif routineRunCount == 0: list.runStatus = "Meh. No Bkup Routines were run." else: list.runStatus = "Bkup Complete!" else: Box {.expand: false.}: orient = OrientY margin = 6 spacing = 12 Label: text = "You don't have any Bkup Routines!!! 🙂" xAlign = 0 useMarkup = true Label: text = "Please click on the + Routine button above to create your first Routine." xAlign = 0 useMarkup = true export RoutineList