/
watchlion.py
executable file
·137 lines (123 loc) · 4.87 KB
/
watchlion.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python
from optparse import OptionParser
import logging
import os
import subprocess
import sys
import time
import yaml
from fsevents import Observer, Stream
"""
https://developer.apple.com/library/mac/#documentation/Darwin/Reference/FSEvents_Ref/Reference/reference.html#//apple_ref/doc/c_ref/kFSEventStreamEventFlagNone
"""
# FSEventStreamEventFlags
NONE = kFSEventStreamEventFlagNone = 0x00000
MUST_SCAN_SUB_DIRS = kFSEventStreamEventFlagMustScanSubDirs = 0x00001
USER_DROPPED = kFSEventStreamEventFlagUserDropped = 0x00002
KERNEl_DROPPED = kFSEventStreamEventFlagKernelDropped = 0x00004
EVENT_IDS_WRAPPED = kFSEventStreamEventFlagEventIdsWrapped = 0x00008
HISTORY_DONE = kFSEventStreamEventFlagHistoryDone = 0x00010
ROOT_CHANGED = kFSEventStreamEventFlagRootChanged = 0x00020
MOUNT = kFSEventStreamEventFlagMount = 0x00040
UNMOUNT = kFSEventStreamEventFlagUnmount = 0x00080 # These flags are only set if you specified the FileEvents
# flags when creating the stream.
CREATED = kFSEventStreamEventFlagItemcreated = 0x00100
REMOVED = kFSEventStreamEventFlagItemremoved = 0x00200
INODEMETAMOD = kFSEventStreamEventFlagIteminodemetamod = 0x00400
RENAMED = kFSEventStreamEventFlagItemrenamed = 0x00800
MODIFIED = kFSEventStreamEventFlagItemmodified = 0x01000
FINDERINFOMOD = kFSEventStreamEventFlagItemfinderinfomod = 0x02000
CHANGEOWNER = kFSEventStreamEventFlagItemchangeowner = 0x04000
XATTRMOD = kFSEventStreamEventFlagItemxattrmod = 0x08000
ISFILE = kFSEventStreamEventFlagItemisfile = 0x10000
ISDIR = kFSEventStreamEventFlagItemisdir = 0x20000
ISSYMLINK = kFSEventStreamEventFlagItemissymlink = 0x40000
FSEventStreamEventMap = {
NONE : "NONE",
MUST_SCAN_SUB_DIRS : "MUST_SCAN_SUB_DIRS",
USER_DROPPED : "USER_DROPPED",
KERNEl_DROPPED : "KERNEl_DROPPED",
EVENT_IDS_WRAPPED : "EVENT_IDS_WRAPPED",
HISTORY_DONE : "HISTORY_DONE",
ROOT_CHANGED : "ROOT_CHANGED",
MOUNT : "MOUNT",
UNMOUNT : "UNMOUNT",
CREATED : "CREATED",
REMOVED : "REMOVED",
INODEMETAMOD : "INODEMETAMOD",
RENAMED : "RENAMED",
MODIFIED : "MODIFIED",
FINDERINFOMOD : "FINDERINFOMOD",
CHANGEOWNER : "CHANGEOWNER",
XATTRMOD : "XATTRMOD",
ISFILE : "ISFILE",
ISDIR : "ISDIR",
ISSYMLINK : "ISSYMLINK",
}
BUILD_CMD = dict()
CONFIG_PATH = None
WATCH_EVENTS = (USER_DROPPED, UNMOUNT, CREATED, REMOVED, RENAMED, MODIFIED)
WATCH_EXTENSIONS = tuple()
def is_watch_event(file_event):
return file_event.mask in WATCH_EVENTS
def set_watch_extension(arg):
global WATCH_EXTENSIONS
WATCH_EXTENSIONS = arg
def is_watch_extension(file_event):
return os.path.splitext(file_event.name)[1] in WATCH_EXTENSIONS
def set_build_cmd(arg):
global BUILD_CMD
BUILD_CMD = arg
def callback(file_event):
logging.debug("%s, %s, %s" % (FSEventStreamEventMap[file_event.mask], file_event.cookie, file_event.name))
if file_event.name == CONFIG_PATH:
load_config()
return
cmd = BUILD_CMD.get(os.path.splitext(file_event.name)[1].lstrip("."), "make")
if is_watch_event(file_event) and is_watch_extension(file_event):
logging.info(cmd)
try:
subprocess.check_call(cmd, shell=True)
except (subprocess.CalledProcessError, OSError) as e:
logging.warning(e)
def parse_options():
parser = OptionParser()
parser.add_option("-c", "--config", dest="config", default=".watchlion.yaml", help="path to config FILE", metavar="FILE")
(options, _args) = parser.parse_args()
global CONFIG_PATH
CONFIG_PATH = os.path.abspath(options.config)
logging.debug("parse_options: %s" % options)
return options
def load_config(options=[0]):
if CONFIG_PATH is None:
options[0] = parse_options()
logging.info("load_config: loading %s" % options[0].config)
try:
config = yaml.load(open(options[0].config).read())
except Exception as e:
logging.error("%s: %s" % (e.__class__.__name__, e))
if not WATCH_EXTENSIONS:
sys.exit(1)
else:
logging.debug("load_config: loaded %s" % config)
set_watch_extension([".%s" % i for i in config["build"].keys()])
set_build_cmd(config["build"])
if "loglevel" in config:
logging.getLogger().setLevel(config["loglevel"].upper())
def main():
logging.basicConfig(level=logging.INFO)
load_config()
observer = Observer()
observer.setDaemon(True)
observer.start()
observer.schedule(Stream(callback, ".", file_events=True))
try:
while True:
time.sleep(10)
except KeyboardInterrupt:
pass
finally:
observer.stop()
print("")
if __name__ == "__main__":
main()