1
+ from watchdog .observers import Observer
2
+ from watchdog .events import FileSystemEventHandler
3
+ import time , os , Queue , threading , subprocess
4
+
5
+ def shellquote (s ):
6
+ return "'" + s .replace ("'" , "'\\ ''" ) + "'"
7
+
8
+ class FileNotifications (FileSystemEventHandler ):
9
+ def catch_all_handler (self , event ):
10
+ if ((event .is_directory and event .src_path == local_dir ) == False ):
11
+ changed_files .put (self .f )
12
+
13
+ def on_moved (self , event ):
14
+ self .f = FileCommand (FileCommand .MOVE , event .src_path , event .dest_path )
15
+ self .catch_all_handler (event )
16
+
17
+ def on_created (self , event ):
18
+ self .f = FileCommand (FileCommand .UPDATE , event .src_path )
19
+ self .catch_all_handler (event )
20
+
21
+ def on_deleted (self , event ):
22
+ self .f = FileCommand (FileCommand .DELETE , event .src_path )
23
+ self .catch_all_handler (event )
24
+
25
+ def on_modified (self , event ):
26
+ self .f = FileCommand (FileCommand .UPDATE , event .src_path )
27
+ self .catch_all_handler (event )
28
+
29
+ class FileCommand (threading .Thread ):
30
+ MOVE = 1
31
+ DELETE = 2
32
+ UPDATE = 3
33
+
34
+ def __init__ (self , action , src_path , dest_path = '' ):
35
+ super (FileCommand , self ).__init__ ()
36
+
37
+ if (action != self .MOVE and action != self .DELETE and action != self .UPDATE ):
38
+ raise ValueError ('Must specify a valid action.' )
39
+ self .action = action
40
+
41
+ if (src_path is None ):
42
+ raise ValueError ('Must specify a file path.' )
43
+ self .path = src_path
44
+
45
+ if (action == self .MOVE and dest_path is None ):
46
+ raise ValueError ('Must specify a destination path (dest_path) when moving files.' )
47
+ self .dest_path = dest_path
48
+
49
+ def run (self ):
50
+ if (self .action == self .UPDATE and os .path .exists (self .path ) == False ):
51
+ return
52
+
53
+ l = len (local_dir )
54
+ f = remote_dir + self .path [l :]
55
+ ef = shellquote (f )
56
+
57
+ if (self .action == self .MOVE ):
58
+ print 'Move ' + self .path [l :]+ ' to ' + self .dest_path [l :]
59
+ cmd = ['ssh' , remote_host , 'if [ -e ' + ef + ' ]; then mv ' + ef + ' ' + remote_dir + self .dest_path [l :]+ '; fi' ]
60
+ elif (self .action == self .DELETE ):
61
+ print 'Delete ' + self .path [l :]
62
+ cmd = ['ssh' , remote_host , 'if [ -e ' + ef + ' ]; then rm ' + ef + '; fi' ]
63
+ elif (self .action == self .UPDATE ):
64
+ print 'Update ' + self .path [l :]
65
+ cmd = ['rsync' , self .path , '-e' , 'ssh' , remote_host + ':/' + f ]
66
+ else :
67
+ raise ValueError ('Must specify a destination path (dest_path) when moving files.' )
68
+
69
+ if cmd is not None :
70
+ subprocess .call (cmd )
71
+
72
+ class Sync (threading .Thread ):
73
+ def run (self ):
74
+ while True :
75
+ f = changed_files .get ()
76
+ f .run ()
77
+ changed_files .task_done ()
78
+
79
+ remote_host = 'your-remote-server'
80
+ remote_dir = '/home/user/hole'
81
+ local_dir = '/Users/user/hol'
82
+
83
+ changed_files = Queue .Queue (4 )
84
+ event_handler = FileNotifications ()
85
+ Sync ().start ()
86
+
87
+ observer = Observer ()
88
+ observer .schedule (event_handler , local_dir )
89
+ observer .start ()
90
+ try :
91
+ while True :
92
+ time .sleep (1 )
93
+ except KeyboardInterrupt :
94
+ observer .stop ()
95
+ observer .join ()
0 commit comments