+5
-1
@@ -177,6 +177,10 @@ class GuiMainMenu(QMenuBar):
|
||||
self.theParent.docEditor.revealLocation()
|
||||
return True
|
||||
|
||||
def _doBackup(self):
|
||||
self.theProject.zipIt(True)
|
||||
return True
|
||||
|
||||
##
|
||||
# Menu Builders
|
||||
##
|
||||
@@ -703,7 +707,7 @@ class GuiMainMenu(QMenuBar):
|
||||
# Tools > Backup
|
||||
self.aBackupProject = QAction("Backup Project", self)
|
||||
self.aBackupProject.setStatusTip("Backup Project")
|
||||
self.aBackupProject.triggered.connect(self.theParent.backupProject)
|
||||
self.aBackupProject.triggered.connect(self._doBackup)
|
||||
self.toolsMenu.addAction(self.aBackupProject)
|
||||
|
||||
# Tools > Settings
|
||||
|
||||
+2
-9
@@ -45,7 +45,7 @@ from nw.gui import (
|
||||
GuiConfigEditor, GuiProjectEditor, GuiItemEditor, GuiProjectOutline,
|
||||
GuiSessionLogView, GuiDocMerge, GuiDocSplit, GuiProjectLoad
|
||||
)
|
||||
from nw.project import NWProject, NWDoc, NWIndex, NWBackup
|
||||
from nw.project import NWProject, NWDoc, NWIndex
|
||||
from nw.tools import countWords
|
||||
from nw.constants import nwFiles, nwItemType, nwAlert
|
||||
|
||||
@@ -333,7 +333,7 @@ class GuiMain(QMainWindow):
|
||||
if msgRes != QMessageBox.Yes:
|
||||
doBackup = False
|
||||
if doBackup:
|
||||
self.backupProject()
|
||||
self.theProject.zipIt(False)
|
||||
else:
|
||||
saveOK = True
|
||||
|
||||
@@ -450,13 +450,6 @@ class GuiMain(QMainWindow):
|
||||
|
||||
return True
|
||||
|
||||
def backupProject(self):
|
||||
"""Trigger the project backup process.
|
||||
"""
|
||||
theBackup = NWBackup(self, self.theProject)
|
||||
theBackup.zipIt()
|
||||
return True
|
||||
|
||||
##
|
||||
# Document Actions
|
||||
##
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from nw.project.backup import NWBackup
|
||||
from nw.project.document import NWDoc
|
||||
from nw.project.index import NWIndex
|
||||
from nw.project.project import NWProject
|
||||
|
||||
__all__ = [
|
||||
"NWBackup",
|
||||
"NWDoc",
|
||||
"NWIndex",
|
||||
"NWProject",
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""novelWriter Project Backup
|
||||
|
||||
novelWriter – Project Backup
|
||||
==============================
|
||||
Class handling project backups
|
||||
|
||||
File History:
|
||||
Created: 2019-06-16 [0.1.5]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2020, Veronica Berglyd Olsen
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import nw
|
||||
|
||||
from os import path
|
||||
from shutil import make_archive
|
||||
from datetime import datetime
|
||||
|
||||
from nw.constants import nwAlert
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class NWBackup():
|
||||
|
||||
def __init__(self, theParent, theProject):
|
||||
self.mainConf = nw.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theProject = theProject
|
||||
return
|
||||
|
||||
def zipIt(self):
|
||||
|
||||
if self.mainConf.backupPath is None or self.mainConf.backupPath == "":
|
||||
self.theParent.makeAlert((
|
||||
"Cannot backup project because no backup path is set. "
|
||||
"Please set a valid backup location in Tools > Preferences."
|
||||
), nwAlert.WARN)
|
||||
return False
|
||||
|
||||
if self.theProject.projName is None or self.theProject.projName == "":
|
||||
self.theParent.makeAlert((
|
||||
"Cannot backup project because no project name is set. "
|
||||
"Please set a Working Title in Project > Project Settings."
|
||||
), nwAlert.WARN)
|
||||
return False
|
||||
|
||||
if not path.isdir(self.mainConf.backupPath):
|
||||
self.theParent.makeAlert((
|
||||
"Cannot backup project because the backup path does not exist. "
|
||||
"Please set a valid backup location in Tools > Preferences."
|
||||
), nwAlert.WARN)
|
||||
return False
|
||||
|
||||
logger.info("Backing up project")
|
||||
self.theParent.statusBar.setStatus("Backing up project ...")
|
||||
|
||||
archName = ""
|
||||
for c in self.theProject.projName:
|
||||
if c.isalnum():
|
||||
archName += c
|
||||
else:
|
||||
archName += "_"
|
||||
|
||||
archName = archName+"_"+datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
baseName = path.join(self.mainConf.backupPath, archName)
|
||||
|
||||
try:
|
||||
self.theProject._clearLockFile()
|
||||
make_archive(baseName, "zip", self.theProject.projPath, ".")
|
||||
self.theProject._writeLockFile()
|
||||
logger.info("Backup written to: %s" % archName)
|
||||
except Exception as e:
|
||||
self.theParent.makeAlert(
|
||||
["Could not write backup archive.",str(e)],
|
||||
nwAlert.ERROR
|
||||
)
|
||||
return False
|
||||
|
||||
self.theParent.statusBar.setStatus("Project backup complete")
|
||||
|
||||
return True
|
||||
|
||||
# END Class NWBackup
|
||||
@@ -38,6 +38,7 @@ from lxml import etree
|
||||
from hashlib import sha256
|
||||
from datetime import datetime
|
||||
from time import time
|
||||
from shutil import make_archive
|
||||
|
||||
from nw.tools import projectMaintenance, OptionState
|
||||
from nw.common import checkString, checkBool, checkInt
|
||||
@@ -478,6 +479,80 @@ class NWProject():
|
||||
self.lockedBy = None
|
||||
return True
|
||||
|
||||
##
|
||||
# Backup Project
|
||||
##
|
||||
|
||||
def zipIt(self, doNotify):
|
||||
"""Create a zip file of the entire project.
|
||||
"""
|
||||
|
||||
logger.info("Backing up project")
|
||||
self.theParent.statusBar.setStatus("Backing up project ...")
|
||||
|
||||
if self.mainConf.backupPath is None or self.mainConf.backupPath == "":
|
||||
self.theParent.makeAlert((
|
||||
"Cannot backup project because no backup path is set. "
|
||||
"Please set a valid backup location in Tools > Preferences."
|
||||
), nwAlert.WARN)
|
||||
return False
|
||||
|
||||
if self.projName is None or self.projName == "":
|
||||
self.theParent.makeAlert((
|
||||
"Cannot backup project because no project name is set. "
|
||||
"Please set a Working Title in Project > Project Settings."
|
||||
), nwAlert.WARN)
|
||||
return False
|
||||
|
||||
if not path.isdir(self.mainConf.backupPath):
|
||||
self.theParent.makeAlert((
|
||||
"Cannot backup project because the backup path does not exist. "
|
||||
"Please set a valid backup location in Tools > Preferences."
|
||||
), nwAlert.WARN)
|
||||
return False
|
||||
|
||||
cleanName = ""
|
||||
for c in self.projName.strip():
|
||||
if c.isalpha() or c.isdigit() or c == " ":
|
||||
cleanName += c
|
||||
|
||||
baseDir = path.join(self.mainConf.backupPath, cleanName)
|
||||
if not path.isdir(baseDir):
|
||||
try:
|
||||
mkdir(baseDir)
|
||||
logger.debug("Created folder %s" % baseDir)
|
||||
except Exception as e:
|
||||
self.theParent.makeAlert(
|
||||
["Could not create backup folder.",str(e)],
|
||||
nwAlert.ERROR
|
||||
)
|
||||
return False
|
||||
|
||||
archName = "Backup on %s" % datetime.now().strftime("%Y-%m-%d at %H.%M.%S")
|
||||
baseName = path.join(baseDir, archName)
|
||||
|
||||
try:
|
||||
self._clearLockFile()
|
||||
make_archive(baseName, "zip", self.projPath, ".")
|
||||
self._writeLockFile()
|
||||
if doNotify:
|
||||
self.theParent.makeAlert(
|
||||
"Backup archive file written to: '%s.zip'" % path.join(cleanName, archName),
|
||||
nwAlert.INFO
|
||||
)
|
||||
else:
|
||||
logger.info("Backup written to: %s" % archName)
|
||||
except Exception as e:
|
||||
self.theParent.makeAlert(
|
||||
["Could not write backup archive.",str(e)],
|
||||
nwAlert.ERROR
|
||||
)
|
||||
return False
|
||||
|
||||
self.theParent.statusBar.setStatus("Project backed up to '%s.zip'" % baseName)
|
||||
|
||||
return True
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
Reference in New Issue
Block a user