-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdir_index.py
134 lines (104 loc) · 3.38 KB
/
dir_index.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
import os
from time import time, timezone
from pyinotify import WatchManager, Notifier, EventsCodes, ProcessEvent
import sys
from sqlalchemy import create_engine, event, func, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
wm = WatchManager()
mask = EventsCodes.FLAG_COLLECTIONS['OP_FLAGS']['IN_DELETE'] | EventsCodes.FLAG_COLLECTIONS['OP_FLAGS']['IN_CREATE']
db_uri = 'sqlite:////root/.dir_index.db'
engine = create_engine(db_uri, echo=False)
#noinspection PyUnusedLocal
@event.listens_for(engine, 'connect')
def set_sqlite_pragma(dbapi_con, con_record):
"""Set SQLite PRAGMA on connect.
:param dbapi_con:
:param con_record:
"""
dbapi_con.execute('PRAGMA journal_mode = MEMORY')
dbapi_con.execute('PRAGMA synchronous = 0')
dbapi_con.execute('PRAGMA cache_size = -1024')
dbapi_con.execute('PRAGMA foreign_keys=ON')
Session = sessionmaker(bind=engine)
"""session generator"""
Base = declarative_base()
class CountableBase(Base):
""" Abstract, countable Base """
__abstract__ = True
@classmethod
def count(cls, session=Session()):
""" count rows of self
:param session: the session to use
"""
# noinspection PyBroadException
try:
return session.query(func.count(cls.id)).first()[0]
except:
return 0
S = Session()
def mkts():
"""
Make a UTC timestamp as float.
:return: current UTC-timestamp
"""
return time() + timezone
class File(CountableBase):
""" File Schema
All recorded files
"""
__tablename__ = 'file'
__table_args__ = {'sqlite_autoincrement': True}
id = Column(Integer, primary_key=True)
created_at = Column(Integer, default=0)
updated_at = Column(Integer, default=0)
path = Column(String(255))
size = Column(Integer, default=0)
@classmethod
def find(cls, path):
"""
:param path: the path to search for
:return: File instance or None
:rtype: File
"""
return S.query(cls).filter_by(path=path)
@classmethod
def remove(cls, path):
S.query(cls).filter_by(path=path).delete()
Base.metadata.create_all(engine, checkfirst=True)
join = os.path.join
class PTmp(ProcessEvent):
# noinspection PyMethodMayBeStatic,PyPep8Naming
def process_IN_CREATE(self, ev):
p = join(ev.path, ev.name)
print('Create: %s' % p)
f = File.find(p)
if not f:
f = File()
f.path = p
f.created_at = mkts()
S.add(f)
else:
f.updated_at = mkts()
f.size = os.path.getsize(p)
# noinspection PyMethodMayBeStatic,PyPep8Naming
def process_IN_DELETE(self, ev):
p = join(ev.path, ev.name)
print('Remove: %s' % p)
File.remove(p)
notifier = Notifier(wm, PTmp())
wdd = wm.add_watch(sys.argv[1], mask, rec=True)
while True: # loop forever
try:
# process the queue of events as explained above
notifier.process_events()
if notifier.check_events():
# read notified events and enqeue them
notifier.read_events()
S.commit()
print('files: %s' % S.count())
# you can do some tasks here...
except KeyboardInterrupt:
# destroy the inotify's instance on this interrupt (stop monitoring)
notifier.stop()
break