feat: add --no-overwrite
This commit is contained in:
parent
5e93595624
commit
a8d1cfed84
2 changed files with 56 additions and 17 deletions
47
README.md
47
README.md
|
|
@ -1,39 +1,60 @@
|
||||||
FlickSave -- automatic snapshot each time you hit save
|
FlickSave -- automatic snapshot each time you hit save
|
||||||
======================================================
|
======================================================
|
||||||
|
|
||||||
FlickSave automagically backup a timestamped snapshot of a file that you edit with any program, without getting in your way.
|
FlickSave automagically perform an action each time you touch a watched file.
|
||||||
|
|
||||||
|
For instance, FlickSave can backup a timestamped snapshot of a file that you edit with any program, without getting in your way.
|
||||||
|
|
||||||
For example, each time you hit `Ctrl-S` within a drawing software,
|
For example, each time you hit `Ctrl-S` within a drawing software,
|
||||||
FlickSave will make a copy the current version of your file,
|
FlickSave will make a copy the current version of your file,
|
||||||
along with the precise date of this version.
|
along with the precise date of this version.
|
||||||
|
|
||||||
This may be useful for digital artists that want to prepare a time-lapse of their on-going work without having to think about it.
|
This may be useful for digital artists that want to prepare a time-lapse of their on-going work without having to think about it.
|
||||||
|
You can even do an automatic Git commit the same way.
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
You should start FlickSave with the file you want to save as an argument
|
You should start FlickSave with the file you want to save as an argument
|
||||||
and let it run during the time you want to create snapshots.
|
and let it run during the time you want to let it perform your action.
|
||||||
Once started, it will watch for modifications on the given file
|
Once started, it will watch for modifications on the given file
|
||||||
and create the snapshots by himself each time something happens.
|
and, for instance, create the snapshots by himself each time something happens.
|
||||||
|
|
||||||
By default, the snapshot has the same name than the targeted file, with the addition of the timestamp.
|
Currently, FlickSave can perform the following actions:
|
||||||
|
|
||||||
|
- `--save`: save a timestamped snapshot of the watched file,
|
||||||
|
- `--inkscape`: export a timestamped PNG of a watched SVG,
|
||||||
|
- `--git`: commit the modifications of the watched file,
|
||||||
|
- `--log`: print a message stating that the watched file was touched.
|
||||||
|
|
||||||
|
You can pass multiple actions.
|
||||||
|
For instance, you can both export a PNG and do a Git commit.
|
||||||
|
|
||||||
|
By default, timestamped snapshots have the same name than the targeted file, with the addition of the timestamp.
|
||||||
For instance, with a target file named `test.svg`, a snapshot will look like `test_2017-11-28T21:02:59.svg`.
|
For instance, with a target file named `test.svg`, a snapshot will look like `test_2017-11-28T21:02:59.svg`.
|
||||||
|
|
||||||
|
|
||||||
### Synopsis
|
### Synopsis
|
||||||
|
|
||||||
`flicksave.py [-h] [-d DIRECTORY] [-y DELAY] [-s SEPARATOR] [-t TEMPLATE] [-v {DEBUG,INFO,WARNING,ERROR}] target`
|
`flicksave.py [-h] [--save] [--inkscape] [--git] [--log] [-d DIRECTORY] [-y DELAY] [-s SEPARATOR] [-t TEMPLATE] [-w] [-v {DEBUG,INFO,WARNING,ERROR}] [-e {opened,moved,deleted,created,modified,closed}...] target`
|
||||||
|
|
||||||
### Required positional argument
|
### Required positional argument
|
||||||
|
|
||||||
`target`: The file to save each time it's modified.
|
`target`: The file to watch.
|
||||||
|
|
||||||
### Optional arguments
|
### Optional arguments
|
||||||
|
|
||||||
* `-h`, `--help`: show this help message and exit.
|
* `-h`, `--help`: show this help message and exit.
|
||||||
|
* `--save`: Save a snapshot of the watched file.
|
||||||
|
* `--inkscape`: Save a PNG snpashot of the watched SVG file.
|
||||||
|
* `--git`: Commit the watched file if it has been modified.
|
||||||
|
* `--log`: Print a message when the watched file is touched.
|
||||||
* `-d DIRECTORY`, `--directory DIRECTORY`: The directory in which to copy the saved versions. (default: .)
|
* `-d DIRECTORY`, `--directory DIRECTORY`: The directory in which to copy the saved versions. (default: .)
|
||||||
* `-y DELAY`, `--delay DELAY`: The minimum time (in seconds) between the creation of different saved files. (default: 10)
|
* `-y DELAY`, `--delay DELAY`: The minimum time (in seconds) between the creation of different saved files. (default: 10)
|
||||||
* `-s SEPARATOR`, `--separator SEPARATOR`: Separator character between the file name and the date stamp. (default: _)
|
* `-s SEPARATOR`, `--separator SEPARATOR`: Separator character between the file name and the date stamp. (default: _)
|
||||||
* `-t TEMPLATE`, `--template TEMPLATE`: Template of the date stamp. (default: %Y-%m-%dT%H:%M:%S)
|
* `-t TEMPLATE`, `--template TEMPLATE`: Template of the date stamp. (default: %Y-%m-%dT%H:%M:%S)
|
||||||
|
* `-e {opened,moved,deleted,created,modified,closed}...`, `--events`: The events touching the watched file for which you want your action perfomed. You can pass multiple (space-separated) events, then the action will be performed for each of them. (default: modified)
|
||||||
|
* `-w`, `--no-overwrite`: Do not overwrite snapshots created at the same time, but append a number to their name (especially useful if you watch several events).
|
||||||
* `-v {DEBUG,INFO,WARNING,ERROR}`, `--verbose {DEBUG,INFO,WARNING,ERROR}`: Verbosity level. (default: WARNING)
|
* `-v {DEBUG,INFO,WARNING,ERROR}`, `--verbose {DEBUG,INFO,WARNING,ERROR}`: Verbosity level. (default: WARNING)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -43,19 +64,25 @@ For instance, with a target file named `test.svg`, a snapshot will look like `te
|
||||||
|
|
||||||
Just start FlickSave with your target file as an argument:
|
Just start FlickSave with your target file as an argument:
|
||||||
|
|
||||||
$ ./flicksave.py my_file.svg
|
$ ./flicksave.py --save my_file.svg
|
||||||
|
|
||||||
Then edit your file and save it.
|
Then edit your file and save it.
|
||||||
As usual, hit `Ctrl-C` (or close the terminal) to stop FlickSave.
|
As usual, hit `Ctrl-C` (or close the terminal) to stop FlickSave.
|
||||||
|
|
||||||
If you want to specify a directory in which to put your snapshots, with no more than one separate file every minute:
|
If you want to specify a directory in which to put your snapshots, with no more than one separate file every minute:
|
||||||
|
|
||||||
$ ./flicksave.py -d flicksave -y 60 my_file.xcf
|
$ ./flicksave.py --inkscape -d flicksave -y 60 my_file.svg
|
||||||
|
|
||||||
If you want to see what's going on and when the snapshots are created, ask it to be more verbose:
|
You may want to save both the file before and after it was modified by any
|
||||||
|
program:
|
||||||
|
|
||||||
|
$ ./flicksave.py --save --events opened closed --no-overwrite my_file
|
||||||
|
|
||||||
|
If you want to see what's going on and when the action(s) are called,
|
||||||
|
ask it to be more verbose:
|
||||||
|
|
||||||
$ touch test.txt
|
$ touch test.txt
|
||||||
$ ./flicksave.py -v INFO test.txt &
|
$ ./flicksave.py --log -v INFO test.txt &
|
||||||
[1] 4303
|
[1] 4303
|
||||||
echo "." >> test.txt
|
echo "." >> test.txt
|
||||||
2017-11-29T21:15:51 -- ./test.txt -> ./test_2017-11-29T21:15:51.txt
|
2017-11-29T21:15:51 -- ./test.txt -> ./test_2017-11-29T21:15:51.txt
|
||||||
|
|
|
||||||
24
flicksave.py
24
flicksave.py
|
|
@ -65,10 +65,12 @@ class Save(Operator):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Save({self.last_date})"
|
return f"Save({self.last_date})"
|
||||||
|
|
||||||
def __init__(self, save_dir, date_sep, date_template):
|
def __init__(self, save_dir, date_sep, date_template, no_overwrite = False):
|
||||||
self.date_template = date_template
|
self.date_template = date_template
|
||||||
self.save_dir = save_dir
|
self.save_dir = save_dir
|
||||||
self.date_sep = date_sep
|
self.date_sep = date_sep
|
||||||
|
self.no_overwrite = no_overwrite
|
||||||
|
|
||||||
# Make a glob search expression with the date template.
|
# Make a glob search expression with the date template.
|
||||||
self.fields = {'Y':4,'m':2,'d':2,'H':2,'M':2,'S':2}
|
self.fields = {'Y':4,'m':2,'d':2,'H':2,'M':2,'S':2}
|
||||||
self.glob_template = self.date_template
|
self.glob_template = self.date_template
|
||||||
|
|
@ -85,7 +87,6 @@ class Save(Operator):
|
||||||
flickname = name + self.date_sep + tag + ext
|
flickname = name + self.date_sep + tag + ext
|
||||||
return os.path.join(self.save_dir, flickname)
|
return os.path.join(self.save_dir, flickname)
|
||||||
|
|
||||||
|
|
||||||
def find_last_save(self, target):
|
def find_last_save(self, target):
|
||||||
full = os.path.expanduser(target)
|
full = os.path.expanduser(target)
|
||||||
head = os.path.basename(full)
|
head = os.path.basename(full)
|
||||||
|
|
@ -112,6 +113,12 @@ class Save(Operator):
|
||||||
|
|
||||||
def save(self, flick):
|
def save(self, flick):
|
||||||
flickfile = self.as_file(flick)
|
flickfile = self.as_file(flick)
|
||||||
|
if self.no_overwrite and os.path.is_file(flickfile):
|
||||||
|
index = 1
|
||||||
|
while os.path.is_file(flickfile):
|
||||||
|
name,ext = os.path.splitext(flickfile)
|
||||||
|
flickfile = name+self.date_sep+index+ext
|
||||||
|
index += 1
|
||||||
logging.info("Copy %s as %s", target, flickfile)
|
logging.info("Copy %s as %s", target, flickfile)
|
||||||
try:
|
try:
|
||||||
shutil.copy(target, flickfile)
|
shutil.copy(target, flickfile)
|
||||||
|
|
@ -148,11 +155,12 @@ class Command(Save):
|
||||||
You can omit one of the named arguments.
|
You can omit one of the named arguments.
|
||||||
For example: 'touch {flick}'"""
|
For example: 'touch {flick}'"""
|
||||||
|
|
||||||
def __init__(self, command, save_dir = ".", date_sep = "_", date_template = '%Y-%m-%dT%H:%M:%S', alt_ext = None):
|
def __init__(self, command, save_dir = ".", date_sep = "_", date_template = '%Y-%m-%dT%H:%M:%S', alt_ext = None, no_overwrite = False):
|
||||||
super(type(self),self).__init__(save_dir, date_sep, date_template)
|
super(type(self),self).__init__(save_dir, date_sep, date_template)
|
||||||
|
|
||||||
self.cmd = command
|
self.cmd = command
|
||||||
self.alt_ext = alt_ext
|
self.alt_ext = alt_ext
|
||||||
|
self.no_overwrite = no_overwrite
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Command(\"{self.cmd}\",{self.save_dir}, {self.date_sep},{self.date_template},{self.alt_ext})"
|
return f"Command(\"{self.cmd}\",{self.save_dir}, {self.date_sep},{self.date_template},{self.alt_ext})"
|
||||||
|
|
@ -281,6 +289,9 @@ if __name__=="__main__":
|
||||||
parser.add_argument("-t","--template", default='%Y-%m-%dT%H:%M:%S',
|
parser.add_argument("-t","--template", default='%Y-%m-%dT%H:%M:%S',
|
||||||
help="Template of the date stamp.")
|
help="Template of the date stamp.")
|
||||||
|
|
||||||
|
parser.add_argument("-w", "--no-overwrite", action="store_true",
|
||||||
|
help="Do not overwrite snapshots created at the same time, but append a number to their name.")
|
||||||
|
|
||||||
parser.add_argument("-v","--verbose", choices=['DEBUG','INFO','WARNING','ERROR'], default='INFO',
|
parser.add_argument("-v","--verbose", choices=['DEBUG','INFO','WARNING','ERROR'], default='INFO',
|
||||||
help="Verbosity level.")
|
help="Verbosity level.")
|
||||||
log_as = { 'DEBUG' :logging.DEBUG,
|
log_as = { 'DEBUG' :logging.DEBUG,
|
||||||
|
|
@ -289,7 +300,6 @@ if __name__=="__main__":
|
||||||
'ERROR' :logging.ERROR }
|
'ERROR' :logging.ERROR }
|
||||||
|
|
||||||
|
|
||||||
# TODO HERE: keep help in existing, put instance in available
|
|
||||||
existing = {
|
existing = {
|
||||||
"save":
|
"save":
|
||||||
["Save a snapshot of the target file.",
|
["Save a snapshot of the target file.",
|
||||||
|
|
@ -317,13 +327,15 @@ if __name__=="__main__":
|
||||||
|
|
||||||
logging.basicConfig(level=log_as[asked.verbose], format='%(asctime)s -- %(message)s', datefmt=asked.template)
|
logging.basicConfig(level=log_as[asked.verbose], format='%(asctime)s -- %(message)s', datefmt=asked.template)
|
||||||
|
|
||||||
|
# Add instances, now that we have all parameters.
|
||||||
available = existing;
|
available = existing;
|
||||||
available["save"][1] = Save(asked.directory, asked.separator, asked.template)
|
available["save"][1] = Save(asked.directory, asked.separator, asked.template, asked.no_overwrite)
|
||||||
available["inkscape"][1] = Command("inkscape {target} --without-gui --export-png={flick} --export-area-page", asked.directory, asked.separator, asked.template, "png")
|
available["inkscape"][1] = Command("inkscape {target} --without-gui --export-png={flick} --export-area-page", asked.directory, asked.separator, asked.template, "png", asked.no_overwrite)
|
||||||
available["git"][1] = Command("git add {target} ; git commit -m 'Automatic flicksave commit: {flick}'")
|
available["git"][1] = Command("git add {target} ; git commit -m 'Automatic flicksave commit: {flick}'")
|
||||||
available["log"][1] = Log()
|
available["log"][1] = Log()
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
|
# Check that both available and existing are aligned.
|
||||||
for op in existing:
|
for op in existing:
|
||||||
assert op in available
|
assert op in available
|
||||||
for op in available:
|
for op in available:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue