Versioned Backup Files

This forum allows you to share scripts with other Zeus users. Please do not post bug reports, feature requests or questions to this forum, but rather use it exclusively for posting scripts or for the discussion of scripts that have been posted.
Post Reply
jussij
Site Admin
Posts: 2650
Joined: Fri Aug 13, 2004 5:10 pm

Versioned Backup Files

Post by jussij »

The code below should be saved to the versions.py file in the following Zeus zScript folder:

Code: Select all

C:\Users\<user Id>\AppData\Local\Programs\Zeus\zScript\versions.py
For details on how to use the script refer to the comments found in the macro itself.

The code represents the latest iteration of this versions.py file and it includes changes from the discussion thread found 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)
#
# 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\versions.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\versions.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.)
#
#              By default the backups are written to this folder:
#
#                   C:\Users\<User Id>\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\
#
##############################################################################################################################################
#              (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 sys
import zeus
import shutil
import getpass

def save_trigger():

    # The backup mode (or scheme) to use for creating the time stamped backup file
    BACKUP_MODE = "MODE_01"

    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 directory will be locted in current users folder
        BACKUP_DIR = os.path.expanduser("~\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\")
    elif (BACKUP_MODE == "MODE_07") or (BACKUP_MODE == "MODE_08"):
        # backup directory will be locted off the directory of file
        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 non-document files
    if not zeus.is_document(): return

    # ignore any un-named files
    if not zeus.is_named(): return

    # useful for debugging
    # debug_info = ""
    # debug_info += "zeus_argv_0 : " + str(zeus.argv(0), 'utf-8') + "\n"
    # debug_info += "zeus_argv_1 : " + str(zeus.argv(1), 'utf-8') + "\n"
    # debug_info += "zeus_argv_2 : " + str(zeus.argv(2), 'utf-8') + "\n"
    # debug_info += "zeus_argv_3 : " + str(zeus.argv(3), 'utf-8') + "\n"
    # debug_info += "zeus_argv_4 : " + str(zeus.argv(4), 'utf-8') + "\n"
    # debug_info += "zeus_argv_5 : " + str(zeus.argv(5), 'utf-8') + "\n"
    # zeus.message_box(1, debug_info, "Arguments")

    # look for the modified flag is passed in as the fifth argument
    result = re.match("(Modified=(.*))", str(zeus.argv(1), 'utf-8'))

    # debugging
    # zeus.message_box(1, "result := " + str(result))

    # 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)
    # zeus.message_box(1, "sys.version := " + sys.version)

    # 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(4), 'utf-8').replace('FileName=', '')

    # Zeus adds quotes for files containing spaces so remove those quotes
    fullfilename = fullfilename.replace('"', '')

    # don't backup the backup files
    if fullfilename.lower().find(BACKUP_DIR.lower()) != -1:
        return;

    # split the full file into it's parts
    current_dir, current_file = os.path.split(fullfilename)

    # if the file does not exist assume this is a ftp file
    if not os.path.exists(fullfilename):
        # get the local temp file name used for remote files
        result = re.match("(LocalFileName=(.*))", str(zeus.argv(2), 'utf-8'))

        # this would be an unexpected result
        if not result or not result.group(1): return

        # use the local file name as the source
        fullfilename = result.group(2)

        # if the file does not exist something must have gone wrong
        if not os.path.exists(fullfilename):
            return;

        # update the file directory details
        current_dir, file_base = os.path.split(fullfilename)

    # debugging
    # zeus.message_box(1, "fullfilename := " + fullfilename)

    zeus.message("Writing backup: " + current_file);

    # 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, "current_file := " + current_file)
    #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(zeus.macro_tag("$DT<dd>").decode('utf8'))

    # 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 + "\\" + zeus.macro_tag("$DT<yyyy>").decode('utf-8') + "\\" + zeus.macro_tag("$DT<MMM>").decode('utf-8') + "\\Week - " + week_of_month + "\\"
    elif BACKUP_MODE == "MODE_02":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>").decode('utf-8') + "\\" + zeus.macro_tag("$DT<MM>").decode('utf-8') + "\\Week - " + week_of_month + "\\"
    if BACKUP_MODE == "MODE_03":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>").decode('utf-8') + "\\" + zeus.macro_tag("$DT<MMM>").decode('utf-8') + "\\" + zeus.macro_tag("$DT<dd>").decode('utf-8') + "\\"
    elif BACKUP_MODE == "MODE_04":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>").decode('utf-8') + "\\" + zeus.macro_tag("$DT<MM>").decode('utf-8') + "\\" + zeus.macro_tag("$DT<dd>").decode('utf-8') + "\\"
    elif BACKUP_MODE == "MODE_05":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>").decode('utf-8') + "\\" + zeus.macro_tag("$DT<MMM>").decode('utf-8') + "\\"
    elif BACKUP_MODE == "MODE_06":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>").decode('utf-8') + "\\" + zeus.macro_tag("$DT<MM>").decode('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)
    # 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 + zeus.macro_tag("__$DT<dd-MMM-yyyy>__$T<HHmmss>").decode('utf-8') + file_extension
        else:
           backup_filename = file_base + zeus.macro_tag("__$DT<yyyy-MM-dd>__$T<HHmmss>").decode('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)
        shutil.copy2(fullfilename, backup_filepath)

        zeus.message("Backup complete.");

    except Exception as e:
        zeus.message_box(0, 'Versions Error:\n\n{}'.format(str(e)), 'Zeus IDE')

save_trigger() # run the macro
Last edited by jussij on Wed Jul 10, 2013 4:16 am, edited 1 time in total.
rayleech
Posts: 1
Joined: Thu May 16, 2013 1:29 am

Post by rayleech »

Script solved my version problem. Thanks Jussi!
wilsondevo
Posts: 11
Joined: Thu May 05, 2011 4:50 am

Re: Versioned Backup Files

Post by wilsondevo »

The Python 2.x code listed in the CODE panel is called 'Zeus_Versioned_Backup_V397.py' and is a modified version of the original 'Versioned Backup Files Macro' macro script and can be used with Zeus versions such as Zeus V3.97j.

The original 'Versioned Backup Files Macro' was initially tried with Zeus V3.98j but this version of Zeus uses Python 3.6 and the original macro code was not compatible.

The original Python 2.x macro code was then converted to a Python 3.6 version and is listed in a subsequent reply.

After the conversion was performed a comparable Python 2.x version was then also created to match the new Python 3.6 version, since some other usability mods were introduced into the new version for my own versioned backup scheme requirements.

Summary

'Zeus_Versioned_Backup_V397.py' - Python 2.x version for use with Zeus V3.97j (this reply)

'Zeus_Versioned_Backup_V398.py' - Python 3.x version for use with Zeus V3.98j (next reply)

I hope this may be of some use to Zeus users concerned with maintaining versioned backups.

'Zeus_Versioned_Backup_V397.py' - below

Code: Select all

##############################################################################################################################################
#
# Name: Versioned Backup Files Macro
#
# Original Author: Jussi Jumppanen
#
# Current Author: WilsonDevo (Modified) (this version)
#
# Language: Python Macro (V2.x - Does not work with Python V3.x)
#
# Zeus Usage: V3.97j (using C:\Program Files (x86)\Zeus\python26.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, Editor Options menu
#              and in the Triggers section attach the macro to the "File Save
#              Prefix" trigger option. (e.g.)
#
#              Options|Editor Options...|Triggers|File Save Prefix = $zud\zScript\Zeus_Versioned_Backup_V397.py
#
#              The backups are saved as per the following scheme (e.g.)
#
#              Original file:           C:\Users\frank\work\ShoppingList.txt
#
#              Time-stamped backup:     C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\ShoppingList__17-Jun-2017__081623.txt
#              (created by this script and only when the file has been modified)
#
#              Non time-stamped backup: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\ShoppingList.txt
#              (created by Zeus itself if it has been enabled in Options|Editor Options...|Backup)
#
#              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.
#
#       The time stamped backup files are stored in one single global directory rather than in the currently edited file's
#       directory in order to make finding and managing the time stamped backups easy.
#
#       This can be easily changed using the 'version_dir' string in the code below to store the backups in a 'special' directory
#       within the currently edited file's directory, if this backup mechanism is desired (e.g.)
#
#       C:\Users\frank\work\!version\ShoppingList__17-Jun-2017__081623.txt
#
##############################################################################################################################################

import os
import re
import zeus
import shutil
import getpass

def save_trigger():
    # this macro expects to be passed at least two arguments
    if zeus.argc < 2: return

    # ignore any non-document files
    if not zeus.is_document(): return

    # look for the modified flag is passed in as the second argument
    result = re.match('Modified=(.*)', zeus.argv(1))

    # this would be an unexpected result
    if not result or not result.group(1): return

    # get the modified flag
    modified = result.group(1)

    # debugging
    # zeus.message_box(1, "modified := " + modified)

    # ignore files that have not been modified
    if modified <> "true": return

    # trigger will pass in the full file name as the first argument
    fullfilename = zeus.argv(0)

    # split the full file into it's parts
    current_dir, current_file = os.path.split(fullfilename)

    # The current active logged-in user
    current_user = getpass.getuser();

    # split the file name into it's parts
    file_base, file_extension = os.path.splitext(current_file)

    # This is the time-stamped backup directory (e.g.)
    #
    # C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\
    #
    # also specify the normal Zeus non time-stamped backup within Zeus itself
    #
    # 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
    #
    version_dir = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"

    # Use this alternative method to store the time stamped backup in a 'special' directory
    # within the currently edited file's directory e.g '!version'
    #
    # version_dir = os.path.join(current_dir, "!version\\")

    # debugging
    # zeus.message_box(1, "current_dir := " + current_dir + "\ncurrent_file := " + current_file + "\nfile_base := " + file_base + "\nfile_extension := " + file_extension)

    # make sure it exists
    if not os.path.exists(version_dir):
        os.makedirs(version_dir)

    # Time stamped backup file name is 'originalFilename__dd-MMM-yyyy__HHmmss.fileExtension' (e.g.)
    #
    # Original file:            ShoppingList.txt
    #
    # Time stamped backup file: ShoppingList__17-Jun-2017__081623.txt
    #
    backup_filename = file_base +  zeus.macro_tag("__$DT<dd-MMM-yyyy>__$T<HHmmss>" + 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 file to the backup location
    shutil.copy2(fullfilename, backup_filepath)

save_trigger() # run the macro

Last edited by wilsondevo on Sat Jun 17, 2017 3:50 pm, edited 1 time in total.
wilsondevo
Posts: 11
Joined: Thu May 05, 2011 4:50 am

Re: Versioned Backup Files

Post by wilsondevo »

Summary

'Zeus_Versioned_Backup_V397.py' - Python 2.x version for use with Zeus V3.97j (previous reply)

'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 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 backups are saved as per the following scheme (e.g.)
#
#              Original file:           C:\Users\frank\work\ShoppingList.txt
#
#              Time-stamped backup:     C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\ShoppingList__17-Jun-2017__081623.txt
#              (created by this script and only when the file has been modified)
#
#              Non time-stamped backup: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\ShoppingList.txt
#              (created by Zeus itself if it has been enabled in Options|Editor Options...|Backup)
#
#              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.
#
#       The time stamped backup files are stored in one single global directory rather than in the currently edited file's
#       directory in order to make finding and managing the time stamped backups easy.
#
#       This can be easily changed using the 'version_dir' string in the code below to store the backups in a 'special' directory
#       within the currently edited file's directory, if this backup mechanism is desired (e.g.)
#
#       C:\Users\frank\work\!version\ShoppingList__17-Jun-2017__081623.txt
#
##############################################################################################################################################

import os
import re
import zeus
import shutil
import getpass

def save_trigger():

    # this macro expects to be passed at least two arguments
    if zeus.argc() < 2: 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=', '')

    # debugging
    # zeus.message_box(1, "fullfilename := " + fullfilename)

    # split the full file into it's parts
    current_dir, current_file = os.path.split(fullfilename)

    # The current active logged-in user
    current_user = getpass.getuser();

    # split the file name into it's parts
    file_base, file_extension = os.path.splitext(current_file)

    # This is the time-stamped backup directory (e.g.)
    #
    # C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\
    #
    # also specify the normal Zeus non time-stamped backup within Zeus itself
    #
    # 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
    #
    version_dir = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"

    # Use this alternative method to store the time stamped backup in a 'special' directory
    # within the currently edited file's directory e.g '!version'
    #
    # version_dir = os.path.join(current_dir, "!version\\")

    # debugging
    # zeus.message_box(1, "current_dir := " + current_dir + "\ncurrent_file := " + current_file + "\nfile_base := " + file_base + "\nfile_extension := " + file_extension)

    # make sure it exists
    if not os.path.exists(version_dir):
        os.makedirs(version_dir)

    # Time stamped backup file name is 'originalFilename__dd-MMM-yyyy__HHmmss.fileExtension' (e.g.)
    #
    # Original file:            ShoppingList.txt
    #
    # Time stamped backup file: ShoppingList__17-Jun-2017__081623.txt
    #
    backup_filename = file_base + str(zeus.macro_tag("__$DT<dd-MMM-yyyy>__$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 file to the backup location
    shutil.copy2(fullfilename, backup_filepath)

save_trigger() # run the macro


jussij
Site Admin
Posts: 2650
Joined: Fri Aug 13, 2004 5:10 pm

Re: Versioned Backup Files

Post by jussij »

Thanks for this much improved backup macro :)

I've taken your version, made a few minor changes (added a comment, try/catch and handling files with spaces) and that version shown below has been added to the official Zeus installer:

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\versions.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\versions.py
#
#              The backups are saved as per the following scheme (e.g.)
#
#              Original file:           C:\Users\frank\work\ShoppingList.txt
#
#              Time-stamped backup:     C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\ShoppingList__17-Jun-2017__081623.txt
#              (created by this script and only when the file has been modified)
#
#              Non time-stamped backup: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\ShoppingList.txt
#              (created by Zeus itself if it has been enabled in Options|Editor Options...|Backup)
#
#              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.
#
#       The time stamped backup files are stored in one single global directory rather than in the currently edited file's
#       directory in order to make finding and managing the time stamped backups easy.
#
#       This can be easily changed using the 'version_dir' string in the code below to store the backups in a 'special' directory
#       within the currently edited file's directory, if this backup mechanism is desired (e.g.)
#
#       C:\Users\frank\work\!version\ShoppingList__17-Jun-2017__081623.txt
#
##############################################################################################################################################

import os
import re
import zeus
import shutil
import getpass

def save_trigger():

    # this macro expects to be passed at least two arguments
    if zeus.argc() < 2: return

    # ignore any non-document files
    if not zeus.is_document(): return

    # debugging
    # zeus.message_box("zeus_argv_0 := " + str(zeus.argv(0), 'utf-8'))
    # zeus.message_box("zeus_argv_1 := " + str(zeus.argv(1), 'utf-8'))
    # zeus.message_box("zeus_argv_2 := " + str(zeus.argv(2), 'utf-8'))
    # zeus.message_box("zeus_argv_3 := " + str(zeus.argv(3), 'utf-8'))
    # zeus.message_box("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("modified_1 := " + modified_1)

    # get the modified flag
    modified_2 = result.group(2)

    # debugging
    # zeus.message_box("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("fullfilename := " + fullfilename)

    # split the full file into it's parts
    current_dir, current_file = os.path.split(fullfilename)

    # The current active logged-in user
    current_user = getpass.getuser()

    # split the file name into it's parts
    file_base, file_extension = os.path.splitext(current_file)

    # This is the time-stamped backup directory (e.g.)
    #
    # C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\
    #
    # also specify the normal Zeus non time-stamped backup within Zeus itself
    #
    # 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
    #
    version_dir = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"
    # zeus.message_box("version_dir := " + version_dir + "\ncurrent_user := " + current_user)

    # Use this alternative method to store the time stamped backup in a 'special' directory
    # within the currently edited file's directory e.g '!version'
    #
    # version_dir = os.path.join(current_dir, "!version\\")

    # debugging
    # zeus.message_box("current_dir := " + current_dir + "\ncurrent_file := " + current_file + "\nfile_base := " + file_base + "\nfile_extension := " + file_extension)

    try:
        # make sure it exists
        if not os.path.exists(version_dir):
            os.makedirs(version_dir)

        # Time stamped backup file name is 'originalFilename__dd-MMM-yyyy__HHmmss.fileExtension' (e.g.)
        #
        # Original file:            ShoppingList.txt
        #
        # Time stamped backup file: ShoppingList__17-Jun-2017__081623.txt
        #
        backup_filename = file_base + str(zeus.macro_tag("__$DT<dd-MMM-yyyy>__$T<HHmmss>"), 'utf-8') + file_extension

        # the full backup file path
        backup_filepath = os.path.join(version_dir, backup_filename)

        # debugging
        # zeus.message_box("fullfilename := " + fullfilename + "\nbackup_filepath := " + backup_filepath)

        # copy the file to the backup location
        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
Cheers Jussi
wilsondevo
Posts: 11
Joined: Thu May 05, 2011 4:50 am

Re: Versioned Backup Files

Post by wilsondevo »

No worries Jussi.

Glad to contribute something to the amazing Zeus editor !

Just for completeness, here is the old Python 2.x version of the backup script incorporating your subsequent mods
for any Zeus users who may be still using an old V3.97 version.

Summary

'Zeus_Versioned_Backup_V397.py' - Python 2.x version for use with Zeus V3.97j (this reply)

'Zeus_Versioned_Backup_V397.py' - below

Code: Select all

##############################################################################################################################################
#
# Name: Versioned Backup Files Macro
#
# Original Author: Jussi Jumppanen
#
# Current Author: WilsonDevo (Modified) (this version)
#
# Language: Python Macro (V2.x - Does not work with Python V3.x)
#
# Zeus Usage: V3.97j (using C:\Program Files (x86)\Zeus\python26.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, Editor Options menu
#              and in the Triggers section attach the macro to the "File Save Prefix" trigger option. (e.g.)
#
#                 Options|Editor Options...|Triggers|File Save Prefix = $zud\zScript\Zeus_Versioned_Backup_V397.py
#
#              The backups are saved as per the following scheme (e.g.)
#
#              Original file:           C:\Users\frank\work\ShoppingList.txt
#
#              Time-stamped backup:     C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\ShoppingList__17-Jun-2017__081623.txt
#              (created by this script and only when the file has been modified)
#
#              Non time-stamped backup: C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\ShoppingList.txt
#              (created by Zeus itself if it has been enabled in Options|Editor Options...|Backup)
#
#              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.
#
#       The time stamped backup files are stored in one single global directory rather than in the currently edited file's
#       directory in order to make finding and managing the time stamped backups easy.
#
#       This can be easily changed using the 'version_dir' string in the code below to store the backups in a 'special' directory
#       within the currently edited file's directory, if this backup mechanism is desired (e.g.)
#
#       C:\Users\frank\work\!version\ShoppingList__17-Jun-2017__081623.txt
#
##############################################################################################################################################

import os
import re
import zeus
import shutil
import getpass

def save_trigger():
    # this macro expects to be passed at least two arguments
    if zeus.argc < 2: return

    # ignore any non-document files
    if not zeus.is_document(): return

    # look for the modified flag is passed in as the second argument
    result = re.match('Modified=(.*)', zeus.argv(1))

    # this would be an unexpected result
    if not result or not result.group(1): return

    # get the modified flag
    modified = result.group(1)

    # debugging
    # zeus.message_box(1, "modified := " + modified)

    # ignore files that have not been modified
    if modified <> "true": return

    # trigger will pass in the full file name as the first argument
    fullfilename = zeus.argv(0)

    # 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)

    # The current active logged-in user
    current_user = getpass.getuser()

    # split the file name into it's parts
    file_base, file_extension = os.path.splitext(current_file)

    # This is the time-stamped backup directory (e.g.)
    #
    # C:\Users\frank\EDITOR_BACKUPS\ZEUS_BACKUPS\TIME_STAMPED\
    #
    # also specify the normal Zeus non time-stamped backup within Zeus itself
    #
    # 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
    #
    version_dir = "C:\\Users\\" + current_user + "\\EDITOR_BACKUPS\\ZEUS_BACKUPS\\TIME_STAMPED\\"

    # debugging
    # zeus.message_box(1, "version_dir := " + version_dir + "\ncurrent_user := " + current_user)

    # Use this alternative method to store the time stamped backup in a 'special' directory
    # within the currently edited file's directory e.g '!version'
    #
    # version_dir = os.path.join(current_dir, "!version\\")

    # debugging
    # zeus.message_box(1, "current_dir := " + current_dir + "\ncurrent_file := " + current_file + "\nfile_base := " + file_base + "\nfile_extension := " + file_extension)

    try:
        # make sure it exists
        if not os.path.exists(version_dir): os.makedirs(version_dir)

        # Time stamped backup file name is 'originalFilename__dd-MMM-yyyy__HHmmss.fileExtension' (e.g.)
        #
        # Original file:            ShoppingList.txt
        #
        # Time stamped backup file: ShoppingList__17-Jun-2017__081623.txt
        #
        backup_filename = file_base +  zeus.macro_tag("__$DT<dd-MMM-yyyy>__$T<HHmmss>" + 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 file to the backup location
        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

wilsondevo
Posts: 11
Joined: Thu May 05, 2011 4:50 am

Re: Versioned Backup Files

Post by wilsondevo »

This is a more elaborate Python 2.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_V397.py' - Python 2.x version for use with Zeus V3.97j (this reply)

'Zeus_Versioned_Backup_V397.py' - below

Code: Select all

##############################################################################################################################################
#
# Name: Versioned Backup Files Macro
#
# Original Author: Jussi Jumppanen
#
# Current Author: WilsonDevo (Modified) (this version)
#
# Language: Python Macro (V2.x - Does not work with Python V3.x)
#
# Zeus Usage: V3.97j (using C:\Program Files (x86)\Zeus\python26.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, Editor Options menu
#              and in the Triggers section attach the macro to the "File Save Prefix" trigger option. (e.g.)
#
#                 Options|Editor Options...|Triggers|File Save Prefix = $zud\zScript\Zeus_Versioned_Backup_V397.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

    # look for the modified flag is passed in as the second argument
    result = re.match('Modified=(.*)', zeus.argv(1))

    # this would be an unexpected result
    if not result or not result.group(1): return

    # get the modified flag
    modified = result.group(1)

    # debugging
    # zeus.message_box(1, "modified := " + modified)

    # ignore files that have not been modified
    if modified <> "true": return

    # trigger will pass in the full file name as the first argument
    fullfilename = zeus.argv(0)

    # 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(zeus.macro_tag("$DT<dd>"))

    # 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 + "\\" + zeus.macro_tag("$DT<yyyy>") + "\\" + zeus.macro_tag("$DT<MMM>") + "\\" + week_of_month + "\\"
    elif BACKUP_MODE == "MODE_02":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>") + "\\" + zeus.macro_tag("$DT<MM>") + "\\" + week_of_month + "\\"
    if BACKUP_MODE == "MODE_03":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>") + "\\" + zeus.macro_tag("$DT<MMM>") + "\\" + zeus.macro_tag("$DT<dd>") + "\\"
    elif BACKUP_MODE == "MODE_04":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>") + "\\" + zeus.macro_tag("$DT<MM>") + "\\" + zeus.macro_tag("$DT<dd>") + "\\"
    elif BACKUP_MODE == "MODE_05":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>") + "\\" + zeus.macro_tag("$DT<MMM>") + "\\"
    elif BACKUP_MODE == "MODE_06":
       version_dir = BACKUP_DIR + file_extension_subst + "\\" + zeus.macro_tag("$DT<yyyy>") + "\\" + zeus.macro_tag("$DT<MM>") + "\\"
    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 := " + file_extension)

    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 + zeus.macro_tag("__$DT<dd-MMM-yyyy>__$T<HHmmss>") + file_extension
        else:
           backup_filename = file_base + zeus.macro_tag("__$DT<yyyy-MM-dd>__$T<HHmmss>") + 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
Last edited by wilsondevo on Tue Jul 04, 2017 1:22 pm, edited 2 times in total.
wilsondevo
Posts: 11
Joined: Thu May 05, 2011 4:50 am

Re: Versioned Backup Files

Post by wilsondevo »

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
Last edited by wilsondevo on Tue Jul 04, 2017 1:20 pm, edited 2 times in total.
jussij
Site Admin
Posts: 2650
Joined: Fri Aug 13, 2004 5:10 pm

Re: Versioned Backup Files

Post by jussij »

Thanks for this updated macro :)

I've included this latest version into the official Zeus installer.

Cheers Jussi
wilsondevo
Posts: 11
Joined: Thu May 05, 2011 4:50 am

Re: Versioned Backup Files

Post by wilsondevo »

Hi Jussi,

I have added the following line to the Python 2.x and Python 3.x versions of the backup script.

Code: Select all

        if  current_dir != "": shutil.copy2(fullfilename, backup_filepath)
This was needed to avoid an exception that was being generated when a new file was created (e.g. 'untitled.txt'), some new content was added and then it was saved.

Since the 'untitled.txt' file has been created within the Zeus session with 'Create a new document', then it does not have a 'current_dir' yet, so the 'shutil.copy()' command fails.

The first versioned backup of the new file will be created when it is saved for the second time.

Cheers - WilsonDevo
jussij
Site Admin
Posts: 2650
Joined: Fri Aug 13, 2004 5:10 pm

Re: Versioned Backup Files

Post by jussij »

While using your macro I did run into this issue.

I fixed this with the following code change towards the top of the macro ;)

Code: Select all

    # 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
Cheers Jussi
Post Reply