rename "watchyap" and clean up a bit
This commit is contained in:
parent
081f06dd89
commit
4d6ae12296
4 changed files with 59 additions and 52 deletions
44
README.md
44
README.md
|
|
@ -1,12 +1,12 @@
|
||||||
FlickSave -- automatic snapshot each time you hit save
|
WatchYap -- automatic action each time you hit save
|
||||||
======================================================
|
===================================================
|
||||||
|
|
||||||
FlickSave automagically perform an action each time you touch watched files.
|
WatchYap automagically perform an action each time you touch watched files.
|
||||||
|
|
||||||
For instance, FlickSave can backup a timestamped snapshot of a file that you edit with any program, without getting in your way.
|
For instance, WatchYap 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,
|
WatchYap 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.
|
||||||
|
|
@ -15,12 +15,12 @@ You can even do an automatic Git commit the same way.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
You should start FlickSave with the files you want to save as argument(s)
|
You should start WatchYap with the files you want to save as argument(s)
|
||||||
and let it run during the time you want to perform your action(s).
|
and let it run during the time you want to perform your action(s).
|
||||||
Once started, it will watch for modifications on the given file(s)
|
Once started, it will watch for modifications on the given file(s)
|
||||||
and, for instance, create the snapshots by himself each time something happens.
|
and, for instance, create the snapshots by himself each time something happens.
|
||||||
|
|
||||||
Currently, FlickSave can perform the following actions:
|
Currently, WatchYap can perform the following actions:
|
||||||
|
|
||||||
- `--save`,
|
- `--save`,
|
||||||
- `--inkscape`,
|
- `--inkscape`,
|
||||||
|
|
@ -40,7 +40,7 @@ For instance, with a target file named `test.svg`, a snapshot will look like `te
|
||||||
|
|
||||||
### Synopsis
|
### Synopsis
|
||||||
|
|
||||||
`flicksave.py [-h] [--save] [--inkscape] [--git] [--log] [--dbus] [-d DIRECTORY] [-y DELAY] [-s SEPARATOR] [-t TEMPLATE] [-w] [-v {DEBUG,INFO,WARNING,ERROR}] [-e {opened,moved,deleted,created,modified,closed}...] target [target ...]`
|
`watchyap.py [-h] [--save] [--inkscape] [--git] [--log] [--dbus] [-d DIRECTORY] [-y DELAY] [-s SEPARATOR] [-t TEMPLATE] [-w] [-v {DEBUG,INFO,WARNING,ERROR}] [-e {opened,moved,deleted,created,modified,closed}...] target [target ...]`
|
||||||
|
|
||||||
### Required positional argument
|
### Required positional argument
|
||||||
|
|
||||||
|
|
@ -89,49 +89,49 @@ Other:
|
||||||
|
|
||||||
### Command line
|
### Command line
|
||||||
|
|
||||||
Just start FlickSave with your target file as an argument:
|
Just start WatchYap with your target file as an argument:
|
||||||
|
|
||||||
$ flicksave --save my_file.svg
|
$ watchyap --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 WatchYap.
|
||||||
|
|
||||||
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 --inkscape --directory flicksave --delay 60 my_file.svg
|
$ watchyap --inkscape --directory watchyap --delay 60 my_file.svg
|
||||||
|
|
||||||
You can call sevral actions, for instance export a PNG and commit the source SVG:
|
You can call sevral actions, for instance export a PNG and commit the source SVG:
|
||||||
|
|
||||||
$ flicksave --inkscape --git my_file.svg
|
$ watchyap --inkscape --git my_file.svg
|
||||||
|
|
||||||
You can use your shell to create the file list:
|
You can use your shell to create the file list:
|
||||||
|
|
||||||
$ flicksave --git *.py
|
$ watchyap --git *.py
|
||||||
|
|
||||||
And even handle files in subdirectories:
|
And even handle files in subdirectories:
|
||||||
|
|
||||||
$ flicksave --log */*.log
|
$ watchyap --log */*.log
|
||||||
|
|
||||||
You may want to save both the file before and after it was modified by any
|
You may want to save both the file before and after it was modified by any
|
||||||
program:
|
program:
|
||||||
|
|
||||||
$ flicksave --save --events opened closed --no-overwrite my_file
|
$ watchyap --save --events opened closed --no-overwrite my_file
|
||||||
|
|
||||||
You can export PNGs and commit their source across sub-directories,
|
You can export PNGs and commit their source across sub-directories,
|
||||||
and be notified when it's done:
|
and be notified when it's done:
|
||||||
|
|
||||||
$ flicksave --inkscape --git --dbus --events closed */*.svg
|
$ watchyap --inkscape --git --dbus --events closed */*.svg
|
||||||
|
|
||||||
You can also prepare the list of files to watch by using a subcommand:
|
You can also prepare the list of files to watch by using a subcommand:
|
||||||
|
|
||||||
$ flicksave --log $(find . -type f -name *.png | grep -v test)
|
$ watchyap --log $(find . -type f -name *.png | grep -v test)
|
||||||
|
|
||||||
If you want to pass your own command:
|
If you want to pass your own command:
|
||||||
|
|
||||||
$ flicksave --cmd "git commit -a -m 'whatever'" my_file
|
$ watchyap --cmd "git commit -a -m 'whatever'" my_file
|
||||||
$ flicksave --cmd "git add {target} ; git commit -m 'Automated commit' ; git tag '{timestamp}'"
|
$ watchyap --cmd "git add {target} ; git commit -m 'Automated commit' ; git tag '{timestamp}'"
|
||||||
$ flicksave --cmd "echo '{flick}' > watching_pipe" *.log
|
$ watchyap --cmd "echo '{flick}' > watching_pipe" *.log
|
||||||
|
$ watchyap --alt-ext .jpg --cmd "convert -antialias {target} {flick}" my_file.png
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
flicksave.py
|
|
||||||
1
watchyap
Symbolic link
1
watchyap
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
watchyap.py
|
||||||
|
|
@ -19,6 +19,8 @@ except Exception as e:
|
||||||
else:
|
else:
|
||||||
HAS_DBUS = True
|
HAS_DBUS = True
|
||||||
|
|
||||||
|
from operator import attrgetter
|
||||||
|
|
||||||
from watchdog.observers import Observer
|
from watchdog.observers import Observer
|
||||||
from watchdog.events import LoggingEventHandler
|
from watchdog.events import LoggingEventHandler
|
||||||
from watchdog.events import FileSystemEventHandler
|
from watchdog.events import FileSystemEventHandler
|
||||||
|
|
@ -67,10 +69,10 @@ class Flicker:
|
||||||
|
|
||||||
|
|
||||||
class Handler(FileSystemEventHandler):
|
class Handler(FileSystemEventHandler):
|
||||||
"""Event handler, will call a sequence of operators at each event matching the target."""
|
"""Event handler, will call a sequence of actions at each event matching the target."""
|
||||||
def __init__(self, operators, flicker, watched_events = ["modified"] ):
|
def __init__(self, actions, flicker, watched_events = ["modified"] ):
|
||||||
self.flicker = flicker
|
self.flicker = flicker
|
||||||
self.ops = operators
|
self.ops = actions
|
||||||
self.watched_events = watched_events
|
self.watched_events = watched_events
|
||||||
|
|
||||||
def on_any_event(self, event):
|
def on_any_event(self, event):
|
||||||
|
|
@ -102,14 +104,14 @@ class Handler(FileSystemEventHandler):
|
||||||
logging.debug("Not handling event:" + ", ".join([i for i in [is_dir, is_not_target, is_not_watched] if i != ""]))
|
logging.debug("Not handling event:" + ", ".join([i for i in [is_dir, is_not_target, is_not_watched] if i != ""]))
|
||||||
|
|
||||||
|
|
||||||
class Operator:
|
class Action:
|
||||||
"""Interface example for an Operator (but can actually be any callable with the same signature)."""
|
"""Interface example for an Action (but can actually be any callable with the same signature)."""
|
||||||
|
|
||||||
def __call__(self, target, flick, event, alt_ext = None):
|
def __call__(self, target, flick, event, alt_ext = None):
|
||||||
raise NotImplemented
|
raise NotImplemented
|
||||||
|
|
||||||
|
|
||||||
class Save(Operator):
|
class Save(Action):
|
||||||
"""Make a copy of the target file.
|
"""Make a copy of the target file.
|
||||||
Takes care to create a missing directory if necessary."""
|
Takes care to create a missing directory if necessary."""
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
@ -209,7 +211,7 @@ class Command(Save):
|
||||||
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, no_overwrite = False):
|
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(Command,self).__init__(save_dir, date_sep, date_template)
|
||||||
|
|
||||||
self.cmd = command
|
self.cmd = command
|
||||||
self.alt_ext = alt_ext
|
self.alt_ext = alt_ext
|
||||||
|
|
@ -249,7 +251,7 @@ class Command(Save):
|
||||||
logging.debug("Command ended.")
|
logging.debug("Command ended.")
|
||||||
|
|
||||||
|
|
||||||
class Log(Operator):
|
class Log(Action):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "Log()"
|
return "Log()"
|
||||||
|
|
||||||
|
|
@ -258,9 +260,9 @@ class Log(Operator):
|
||||||
|
|
||||||
|
|
||||||
if HAS_DBUS:
|
if HAS_DBUS:
|
||||||
class DBus(Operator):
|
class DBus(Action):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "Log()"
|
return "DBus()"
|
||||||
|
|
||||||
def __call__(self, target, flick, event, alt_ext = None):
|
def __call__(self, target, flick, event, alt_ext = None):
|
||||||
logging.info(f"File {target} was {event.event_type}")
|
logging.info(f"File {target} was {event.event_type}")
|
||||||
|
|
@ -278,7 +280,7 @@ if HAS_DBUS:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def flicksave(globbed_targets, operators=None, delay=10, watched=["modified"]):
|
def watchyap(globbed_targets, actions=None, delay=10, watched=["modified"]):
|
||||||
"""Start the watch thread."""
|
"""Start the watch thread."""
|
||||||
|
|
||||||
targets = [os.path.abspath(p) for p in globbed_targets]
|
targets = [os.path.abspath(p) for p in globbed_targets]
|
||||||
|
|
@ -291,7 +293,7 @@ def flicksave(globbed_targets, operators=None, delay=10, watched=["modified"]):
|
||||||
|
|
||||||
flicker = Flicker(targets, delay)
|
flicker = Flicker(targets, delay)
|
||||||
|
|
||||||
handler = Handler(operators, flicker, watched)
|
handler = Handler(actions, flicker, watched)
|
||||||
|
|
||||||
# Start the watch thread.
|
# Start the watch thread.
|
||||||
observer = Observer()
|
observer = Observer()
|
||||||
|
|
@ -310,8 +312,13 @@ if __name__=="__main__":
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
class SortingHelpFormatter(argparse.HelpFormatter):
|
||||||
|
def add_arguments(self, actions):
|
||||||
|
actions = sorted(actions, key=attrgetter('option_strings'))
|
||||||
|
super(SortingHelpFormatter, self).add_arguments(actions)
|
||||||
|
|
||||||
class SaneHelpFormatter(
|
class SaneHelpFormatter(
|
||||||
argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter
|
SortingHelpFormatter, argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -323,18 +330,18 @@ if __name__=="__main__":
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
Copy the file each time it is modified:
|
Copy the file each time it is modified:
|
||||||
flicksave --save my_file
|
watchyap --save my_file
|
||||||
Copy the file in a subdirectory each time it is modified:
|
Copy the file in a subdirectory each time it is modified:
|
||||||
flicksave --directory snapshots --save my_file
|
watchyap --directory snapshots --save my_file
|
||||||
Export a PNG from a watched SVG, each time you hit 'save' in inkscape:
|
Export a PNG from a watched SVG, each time you hit 'save' in inkscape:
|
||||||
flicksave --inkscape my_file
|
watchyap --inkscape my_file
|
||||||
Git commit the file if it has been modified, but not before 30 seconds after the previous commit:
|
Git commit the file if it has been modified, but not before 30 seconds after the previous commit:
|
||||||
flicksave --git --delay 30 my_file
|
watchyap --git --delay 30 my_file
|
||||||
Copy the file each time is is opened or closed:
|
Copy the file each time is is opened or closed:
|
||||||
flicksave --events opened closed --save my_file
|
watchyap --events opened closed --save my_file
|
||||||
You may want to save both the file before and after it was modified by any
|
You may want to save both the file before and after it was modified by any
|
||||||
program:
|
program:
|
||||||
flicksave --save --events opened closed --no-overwrite my_file
|
watchyap --save --events opened closed --no-overwrite my_file
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# Optional arguments.
|
# Optional arguments.
|
||||||
|
|
@ -367,7 +374,7 @@ Examples:
|
||||||
'WARNING':logging.WARNING,
|
'WARNING':logging.WARNING,
|
||||||
'ERROR' :logging.ERROR }
|
'ERROR' :logging.ERROR }
|
||||||
|
|
||||||
parser.add_argument("--version", action="store_true",
|
parser.add_argument("-V", "--version", action="store_true",
|
||||||
help="Show program's version number and exit.")
|
help="Show program's version number and exit.")
|
||||||
|
|
||||||
asked = parser.parse_known_args()[0]
|
asked = parser.parse_known_args()[0]
|
||||||
|
|
@ -430,7 +437,7 @@ Examples:
|
||||||
|
|
||||||
if HAS_GIT:
|
if HAS_GIT:
|
||||||
logging.debug("`git` command found")
|
logging.debug("`git` command found")
|
||||||
available["git"][1] = Command("git add {target} ; git commit -m 'Automatic flicksave commit of {target} at {timestamp}'")
|
available["git"][1] = Command("git add {target} ; git commit -m 'Automatic watchyap commit of {target} at {timestamp}'")
|
||||||
else:
|
else:
|
||||||
print("WARNING: `git` command not found, the --inkscape action is disabled.", file=sys.stderr)
|
print("WARNING: `git` command not found, the --inkscape action is disabled.", file=sys.stderr)
|
||||||
|
|
||||||
|
|
@ -463,7 +470,7 @@ Examples:
|
||||||
for op in available:
|
for op in available:
|
||||||
assert op in existing
|
assert op in existing
|
||||||
|
|
||||||
logging.debug("Available operators:")
|
logging.debug("Available actions:")
|
||||||
for name in available:
|
for name in available:
|
||||||
logging.debug("\t%s",name)
|
logging.debug("\t%s",name)
|
||||||
|
|
||||||
|
|
@ -475,27 +482,27 @@ Examples:
|
||||||
|
|
||||||
asked = parser.parse_args()
|
asked = parser.parse_args()
|
||||||
|
|
||||||
operators = []
|
actions = []
|
||||||
requested = vars(asked)
|
requested = vars(asked)
|
||||||
def instance(name):
|
def instance(name):
|
||||||
return available[name][1]
|
return available[name][1]
|
||||||
for it in [iz for iz in requested if iz in available and requested[iz]]:
|
for it in [iz for iz in requested if iz in available and requested[iz]]:
|
||||||
operators.append(instance(it))
|
actions.append(instance(it))
|
||||||
|
|
||||||
if len(operators) == 0:
|
if len(actions) == 0:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"WARNING: you did not asked for any snapshot command, "
|
"WARNING: you did not asked for any snapshot command, "
|
||||||
"I will only log when you save the file, but not perform any action. "
|
"I will only log when you save the file, but not perform any action. "
|
||||||
"Use one of the following option if you want me to do something: "
|
"Use one of the following option if you want me to do something: "
|
||||||
+", ".join(["--"+str(k) for k in available.keys()])
|
+", ".join(["--"+str(k) for k in available.keys()])
|
||||||
)
|
)
|
||||||
operators.append(Log())
|
actions.append(Log())
|
||||||
|
|
||||||
logging.debug("Used operators:")
|
logging.debug("Used actions:")
|
||||||
for op in operators:
|
for op in actions:
|
||||||
logging.debug("\t%s", op)
|
logging.debug("\t%s", op)
|
||||||
|
|
||||||
# Start it.
|
# Start it.
|
||||||
logging.debug(asked.targets)
|
logging.debug(asked.targets)
|
||||||
flicksave(asked.targets, operators, asked.delay, asked.events)
|
watchyap(asked.targets, actions, asked.delay, asked.events)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue