This is a more elaborate Python
3.x version of the versioned backup script incorporating
eight different
backup modes.
Each backup mode stores the time stamped backup file in a directory conforming to a particular file extension and/or date hierarchy.
Choose the backup mode that suits your needs or create your own by modifying the Python script.
Summary
'Zeus_Versioned_Backup_V398.py' - Python
3.x version for use with Zeus V3.98j (this reply)
'Zeus_Versioned_Backup_V398.py' - below
Code: Select all
##############################################################################################################################################
#
# Name: Versioned Backup Files Macro
#
# Original Author: Jussi Jumppanen
#
# Current Author: WilsonDevo (Modified) (this version)
#
# Language: Python Macro (V3.x - Does not work with Python V2.x)
#
# Zeus Usage: V3.98j (using C:\Program Files (x86)\Zeus\python36.dll) (e.g.)
#
# Description: This macro creates a time stamped backup of the file every time the file is saved.
#
# To configure this macro, for all document types, use the Options, Default Document Type menu
# and attach the macro to the "File Save Prefix" trigger option. (e.g.)
#
# Options|Default Document Type...|Triggers|File Save Prefix = $zud\zScript\Zeus_Versioned_Backup_V398.py
#
# To configure this macro, for a particular document type, use the Options, Trigger Options menu
# and attach the macro to the "File Save Prefix" trigger option. (e.g.)
#
# Options|Trigger Options...|File Save Prefix = $zud\zScript\Zeus_Versioned_Backup_V398.py
#
# The time stamped backups are created using one of six possible backup modes and are controlled by
# the 'BACKUP_MODE' and 'BACKUP_DIR' strings. The different backups modes are listed below using examples.
#
# The most fine grained backup directory location includes the week number of the month (BACKUP_MODE=01 or 02)
# or the day of the month (BACKUP_MODE=03 or 04) in an attempt to make managing the backups easier.
#
# For example, old backups beyond a certain age can be quickly identified and deleted using their directory name
# as an indication of their age rather than sifting through the time stamped backup files using either their
# filename or their file date as a selector. (e.g. I can quickly delete all Python (.py) time stamped backup files
# created in April 2017, because they are now redundant, just by deleting the '...\.py\2017\Apr\...' directory.)
#
# Being able to locate a particular time stamped backup file easily, in times of high stress, is also much easier with
# a logical hierarchical backup directory structure.
#
# (The simplest backup mode is BACKUP_MODE=8 but this means that the time stamped backups are created in a
# a sub-directory of the current file's directory. If the current file's directory is accidentally deleted then
# all of the time stamped backups will also have been deleted. Each backup scheme will have its own pros and cons, however.)
#
##############################################################################################################################################
# (e.g.)
#
# Original file 1: C:\Users\frank\work\ProjectProposal
# Original file 2: C:\Users\frank\play\ShoppingList.txt
#
##############################################################################################################################################
# BACKUP_MODE = "MODE_01"
# BACKUP_DIR = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"
#
# Time-stamped backup 1: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\(no ext)\2017\May\01\ProjectProposal__03-May-2017__094512 (i.e. week 01 of month)
# Time-stamped backup 2: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\.txt\2017\Jun\03\ShoppingList__17-Jun-2017__081623.txt (i.e. week 03 of month)
##############################################################################################################################################
# BACKUP_MODE = "MODE_02"
# BACKUP_DIR = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"
#
# Time-stamped backup 1: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\(no ext)\2017\05\01\ProjectProposal__2017-05-03__094512 (i.e. week 01 of month)
# Time-stamped backup 2: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\.txt\2017\06\03\ShoppingList__2017-06-17__081623.txt (i.e. week 03 of month)
##############################################################################################################################################
# BACKUP_MODE = "MODE_03"
# BACKUP_DIR = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"
#
# Time-stamped backup 1: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\(no ext)\2017\May\03\ProjectProposal__03-May-2017__094512 (i.e. day 03 of month)
# Time-stamped backup 2: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\.txt\2017\Jun\17\ShoppingList__17-Jun-2017__081623.txt (i.e. day 17 of month)
##############################################################################################################################################
# BACKUP_MODE = "MODE_04"
# BACKUP_DIR = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"
#
# Time-stamped backup 1: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\(no ext)\2017\05\03\ProjectProposal__2017-05-03__094512 (i.e. day 03 of month)
# Time-stamped backup 2: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\.txt\2017\06\17\ShoppingList__2017-06-17__081623.txt (i.e. day 17 of month)
##############################################################################################################################################
# BACKUP_MODE = "MODE_05"
# BACKUP_DIR = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"
#
# Time-stamped backup 1: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\(no ext)\2017\May\ProjectProposal__03-May-2017__094512
# Time-stamped backup 2: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\.txt\2017\Jun\ShoppingList__17-Jun-2017__081623.txt
##############################################################################################################################################
# BACKUP_MODE = "MODE_06"
# BACKUP_DIR = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"
#
# Time-stamped backup 1: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\(no ext)\2017\05\ProjectProposal__2017-05-03__094512
# Time-stamped backup 2: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\.txt\2017\06\ShoppingList__2017-06-17__081623.txt
##############################################################################################################################################
# BACKUP_MODE = "MODE_07"
# BACKUP_DIR = "!version\\"
#
# Time-stamped backup 1: C:\Users\frank\work\!version\(no ext)\ProjectProposal__2017-05-03__094512
# Time-stamped backup 2: C:\Users\frank\play\!version\.txt\ShoppingList__17-Jun-2017__081623.txt
##############################################################################################################################################
# BACKUP_MODE = "MODE_08"
# BACKUP_DIR = "!version\\"
#
# Time-stamped backup 1: C:\Users\frank\work\!version\ProjectProposal__2017-05-03__094512
# Time-stamped backup 2: C:\Users\frank\play\!version\ShoppingList__17-Jun-2017__081623.txt
##############################################################################################################################################
# Non time-stamped backup 1 : C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\ProjectProposal
# Non time-stamped backup 2 : C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\ShoppingList.txt
#
# (created by Zeus itself - if it has been enabled e.g.)
#
# Options|Editor Options|Backup||Backup Mode = Use existing file name
# Options|Editor Options|Backup||Backup Details||Alternative backup directory = C:\Users\$UserID\EDITOR_BACKUPS\ZEUS_BACKUPS
#
# The non time-stamped backup, if enabled, provides an extra file backup and represents
# the most 'current backup'.
#
# See the code below for more info on configuring this backup scheme
#
##############################################################################################################################################
#
# Note: The time stamped backup IS created when a 'FileSave' operation is performed.
#
# Note: The time stamped backup IS NOT created when a 'FileSaveAll' or 'FileSaveAllNamed' operation is performed.
#
##############################################################################################################################################
#
# Note: This script over time could generate hundreds of time stamped backup files but since Zeus is often used to
# edit program code that exists in text format then the total hard disk space consumed should be manageable
# since individual program code files are generally not large in size.
#
##############################################################################################################################################
import os
import re
import zeus
import shutil
import getpass
def save_trigger():
# The current active logged-in user
current_user = getpass.getuser()
# The backup mode (or scheme) to use for creating the time stamped backup file
BACKUP_MODE = "MODE_03"
if (BACKUP_MODE == "MODE_01") or (BACKUP_MODE == "MODE_02") or (BACKUP_MODE == "MODE_03") or \
(BACKUP_MODE == "MODE_04") or (BACKUP_MODE == "MODE_05") or (BACKUP_MODE == "MODE_06"):
BACKUP_DIR = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"
elif (BACKUP_MODE == "MODE_07") or (BACKUP_MODE == "MODE_08"):
BACKUP_DIR = "!version\\"
else:
zeus.message_box(1, "BACKUP_MODE=" + BACKUP_MODE + " is not supported.\n\nBackup not created.")
return
# this macro expects to be passed at least two arguments
if zeus.argc() < 2: return
# ignore any un-named files
if not zeus.is_named(): return
# ignore any non-document files
if not zeus.is_document(): return
# debugging
# zeus.message_box(1, "zeus_argv_0 := " + str(zeus.argv(0), 'utf-8'))
# zeus.message_box(1, "zeus_argv_1 := " + str(zeus.argv(1), 'utf-8'))
# zeus.message_box(1, "zeus_argv_2 := " + str(zeus.argv(2), 'utf-8'))
# zeus.message_box(1, "zeus_argv_3 := " + str(zeus.argv(3), 'utf-8'))
# zeus.message_box(1, "zeus_argv_4 := " + str(zeus.argv(4), 'utf-8'))
# look for the modified flag is passed in as the fifth argument
result = re.match("(Modified=(.*))", str(zeus.argv(4), 'utf-8'))
# this would be an unexpected result
if not result or not result.group(1): return
# debugging
# modified_1 = result.group(1)
# zeus.message_box(1, "modified_1 := " + modified_1)
# get the modified flag
modified_2 = result.group(2)
# debugging
# zeus.message_box(1, "modified_2 := " + modified_2)
# ignore files that have not been modified
if modified_2 != "true": return
# trigger will pass in the full file name as the first argument
# strip out string 'FileName='
fullfilename = str(zeus.argv(0), 'utf-8').replace('FileName=', '')
# Zeus adds quotes for files containing spaces so remove those quotes
fullfilename = fullfilename.replace('"', '')
# debugging
# zeus.message_box(1, "fullfilename := " + fullfilename)
# split the full file into it's parts
current_dir, current_file = os.path.split(fullfilename)
# split the file name into it's parts
file_base, file_extension = os.path.splitext(current_file)
# Check for the case when a file has no file extension
if file_extension == "":
file_extension_subst = "(no ext)"
else:
file_extension_subst = file_extension
# debugging
# zeus.message_box(1, "file_extension := " + file_extension)
# zeus.message_box(1, "file_extension_subst := " + file_extension_subst)
# Convert the day of the month to an integer
day_of_week = int(str(zeus.macro_tag("$DT<dd>"), 'utf-8'))
# Determine which week of the month it is
if day_of_week < 8:
week_of_month = "01"
elif day_of_week < 15:
week_of_month = "02"
elif day_of_week < 22:
week_of_month = "03"
else:
week_of_month = "04"
# Generate the directory path where the time stamped backup file will be created based on the chosen backup mode
if BACKUP_MODE == "MODE_01":
version_dir = BACKUP_DIR + file_extension_subst + "\\" + str(zeus.macro_tag("$DT<yyyy>"), 'utf-8') + "\\" + str(zeus.macro_tag("$DT<MMM>"), 'utf-8') + "\\" + week_of_month + "\\"
elif BACKUP_MODE == "MODE_02":
version_dir = BACKUP_DIR + file_extension_subst + "\\" + str(zeus.macro_tag("$DT<yyyy>"), 'utf-8') + "\\" + str(zeus.macro_tag("$DT<MM>"), 'utf-8') + "\\" + week_of_month + "\\"
if BACKUP_MODE == "MODE_03":
version_dir = BACKUP_DIR + file_extension_subst + "\\" + str(zeus.macro_tag("$DT<yyyy>"), 'utf-8') + "\\" + str(zeus.macro_tag("$DT<MMM>"), 'utf-8') + "\\" + str(zeus.macro_tag("$DT<dd>"), 'utf-8') + "\\"
elif BACKUP_MODE == "MODE_04":
version_dir = BACKUP_DIR + file_extension_subst + "\\" + str(zeus.macro_tag("$DT<yyyy>"), 'utf-8') + "\\" + str(zeus.macro_tag("$DT<MM>"), 'utf-8') + "\\" + str(zeus.macro_tag("$DT<dd>"), 'utf-8') + "\\"
elif BACKUP_MODE == "MODE_05":
version_dir = BACKUP_DIR + file_extension_subst + "\\" + str(zeus.macro_tag("$DT<yyyy>"), 'utf-8') + "\\" + str(zeus.macro_tag("$DT<MMM>"), 'utf-8') + "\\"
elif BACKUP_MODE == "MODE_06":
version_dir = BACKUP_DIR + file_extension_subst + "\\" + str(zeus.macro_tag("$DT<yyyy>"), 'utf-8') + "\\" + str(zeus.macro_tag("$DT<MM>"), 'utf-8') + "\\"
elif BACKUP_MODE == "MODE_07":
version_dir = os.path.join(current_dir, BACKUP_DIR + file_extension_subst + "\\")
elif BACKUP_MODE == "MODE_08":
version_dir = os.path.join(current_dir, BACKUP_DIR)
# debugging
# zeus.message_box(1, "version_dir := " + version_dir + "\ncurrent_user := " + current_user)
# debugging
# zeus.message_box(1, "current_dir := " + current_dir + "\ncurrent_file := " + current_file + "\nfile_base := " + file_base + "\nfile_extension_subst := " + file_extension_subst)
try:
# make sure it exists
if not os.path.exists(version_dir): os.makedirs(version_dir)
# Generate the time stamped backup file name
if (BACKUP_MODE == "MODE_01") or (BACKUP_MODE == "MODE_03") or (BACKUP_MODE == "MODE_05"):
backup_filename = file_base + str(zeus.macro_tag("__$DT<dd-MMM-yyyy>__$T<HHmmss>"), 'utf-8') + file_extension
else:
backup_filename = file_base + str(zeus.macro_tag("__$DT<yyyy-MM-dd>__$T<HHmmss>"), 'utf-8') + file_extension
# the full backup file path
backup_filepath = os.path.join(version_dir, backup_filename)
# debugging
# zeus.message_box(1, "fullfilename := " + fullfilename + "\nbackup_filepath := " + backup_filepath)
# copy the original file to the backup location (i.e. create the time stamped backup file)
if current_dir != "": shutil.copy2(fullfilename, backup_filepath)
except Exception as e:
zeus.message_box(0, 'Versions Error:\n\n{}'.format(str(e)), 'Zeus IDE')
save_trigger() # run the macro