[Unison-hackers] [unison-svn] r471 - trunk/src
bcpierce at seas.upenn.edu
bcpierce at seas.upenn.edu
Wed Oct 27 14:23:28 EDT 2010
Author: bcpierce
Date: 2010-10-27 14:23:28 -0400 (Wed, 27 Oct 2010)
New Revision: 471
Modified:
trunk/src/RECENTNEWS
trunk/src/fsmonitor.py
trunk/src/mkProjectInfo.ml
Log:
* Incorporated new version of fsmonitor.py from Christophe Gohle
Modified: trunk/src/RECENTNEWS
===================================================================
--- trunk/src/RECENTNEWS 2010-10-14 18:23:04 UTC (rev 470)
+++ trunk/src/RECENTNEWS 2010-10-27 18:23:28 UTC (rev 471)
@@ -1,3 +1,8 @@
+CHANGES FROM VERSION 2.43.12
+
+* Incorporated new version of fsmonitor.py from Christophe Gohle
+
+-------------------------------
CHANGES FROM VERSION 2.43.10
* Fixed incompatibility with OpenSSH 5.6.
Modified: trunk/src/fsmonitor.py
===================================================================
--- trunk/src/fsmonitor.py 2010-10-14 18:23:04 UTC (rev 470)
+++ trunk/src/fsmonitor.py 2010-10-27 18:23:28 UTC (rev 471)
@@ -74,70 +74,99 @@
mymesg('failed to open log file %s for writing',op.outfile)
def mangle_filename(path):
- """because the FSEvents system returns 'real' paths we have to figure out
+ """because the FSEvents system returns 'real' paths we have to figure out
if they have been aliased by a symlink and a 'follow' directive in the unison
configuration or from the command line.
This is done here for path. The return value is the path name using symlinks
"""
- try:
- op.symlinks
- except AttributeError:
- #lets create a dictionary of symlinks that are treated transparently here
- op.symlinks = {}
- fl = op.follow
- try:
- foll = [f.split(' ',1) for f in fl]
- except TypeError:
- foll = []
- for k,v in foll:
- if not k=='Path':
- mymesg('We don\'t support anything but path specifications in follow directives. Especially not %s',k)
- else:
- p = v.strip('{}')
- op.symlinks[os.path.realpath(os.path.join(op.root,p))]=p
+ try:
+ op.symlinks
+ except AttributeError:
+ make_symlinks()
+ #now lets do it
+ result = path
+ for key in op.symlinks:
+ #print path, key
+ if path.startswith(key):
+ result = os.path.join(op.root,os.path.join(op.symlinks[key]+path[len(key):]))
+ #print 'Match!', result
- #now lets do it
- result = path
- for key in op.symlinks:
- #print path, key
- if path.startswith(key):
- result = os.path.join(op.root,op.symlinks[key]+path[len(key):])
- #print 'Match!', result
-
- return result
+ return result
+
+def make_symlinks():
+ #lets create a dictionary of symlinks that are treated transparently here
+ op.symlinks = {}
+ fl = op.follow
+ try:
+ foll = [f.split(' ',1) for f in fl]
+ except TypeError:
+ foll = []
+ for k,v in foll:
+ if not k=='Path':
+ mymesg('We don\'t support anything but path specifications in follow directives. Especially not %s',k)
+ else:
+ p = v.strip('{}')
+ if not p[-1]=='/':
+ p+='/'
+ op.symlinks[os.path.realpath(os.path.join(op.root,p))]=p
+ mydebug('make_symlinks: symlinks to follow %s',op.symlinks)
def relpath(root,path):
- """returns the path relative to root (which should be absolute)
- if it is not a path below root or if root is not absolute it returns None
- """
+ """returns the path relative to root (which should be absolute)
+ if it is not a path below root or if root is not absolute it returns None
+ """
- if not os.path.isabs(root):
- return None
+ if not os.path.isabs(root):
+ return None
- abspath = os.path.abspath(path)
- mydebug('relpath: abspath(%s) = %s', path, abspath)
+ abspath = os.path.abspath(path)
+ mydebug('relpath: abspath(%s) = %s', path, abspath)
- #make sure the root and abspath both end with a '/'
- if not root[-1]=='/':
- root += '/'
- if not abspath[-1]=='/':
- abspath += '/'
+ #make sure the root and abspath both end with a '/'
+ if not root[-1]=='/':
+ root += '/'
+ if not abspath[-1]=='/':
+ abspath += '/'
- mydebug('relpath: root = %s', root)
+ mydebug('relpath: root = %s', root)
- #print root, abspath
- if not abspath[:len(root)]==root:
- #print abspath[:len(root)], root
- return None
+ #print root, abspath
+ if not abspath[:len(root)]==root:
+ #print abspath[:len(root)], root
+ return None
+ mydebug('relpath: relpath = %s',abspath[len(root):])
+ return abspath[len(root):]
- return abspath[len(root):]
-
def my_abspath(path):
"""expand path including shell variables and homedir
to the absolute path
"""
return os.path.abspath(os.path.expanduser(os.path.expandvars(path)))
+
+def update_follow(path):
+ """ tries to find a follow directive that matches path
+ and if path refers to a symbolic link the real path of the symbolic
+ link is returned. """
+ try:
+ op.symlinks
+ except AttributeError:
+ make_symlinks()
+ rpath = relpath(op.root, path)
+ mydebug('update_follow: rpath %s', rpath)
+ result = None
+ foll = None
+ for k in op.symlinks:
+ v = op.symlinks[k]
+ if v==rpath:
+ result = os.path.realpath(os.path.abspath(path))
+ foll = v
+ mydebug('update_follow: link %s, real %s',v,result)
+ break
+ if result:
+ op.symlinks[result] = foll
+
+ return result, foll
def conf_parser(conffilepath, delimiter = '=', dic = {}):
"""parse the unison configuration file at conffilename and populate a dictionary
@@ -146,7 +175,7 @@
try:
conffile = open(conffilepath,'r')
except IOError:
- mymesg('could not open configuration file at %s',conffilepath)
+ mydebug('could not open configuration file at %s',conffilepath)
return None
res = dic
@@ -174,6 +203,8 @@
import pyinotify
class HandleEvents(pyinotify.ProcessEvent):
+ wm = None
+
#def process_IN_CREATE(self, event):
# print "Creating:", event.pathname
@@ -193,20 +224,68 @@
# print "attributes:", event.pathname
def process_default(self, event):
- print "Default:", event
+ mydebug('process_default: event %s', event)
+# code for adding dirs is obsolete since there is the auto_add option
+# if event.dir:
+# if event.mask&pyinotify.IN_CREATE:
+# print 'create:', event.pathname , self.add_watch(event.pathname,rec=True)
+# elif event.mask&pyinotify.IN_DELETE:
+# print 'remove', event.pathname, self.remove_watch(event.pathname)
+# pass
+# elif event.mask&pyinotify.IN_MOVED_FROM:
+# print 'move from', event.pathname, self.remove_watch(event.pathname, rec=True)
+# pass
+# elif event.mask&pyinotify.IN_MOVED_TO:
+# print 'move to', event.pathname, self.add_watch(event.pathname,rec=True)
+# else:
+# pass
+ #handle creation of links that should be followed
+ if os.path.islink(event.pathname):
+ #special handling for links
+ mydebug('process_default: link %s created/changed. Checking for follows', event.pathname)
+ p, l = update_follow(event.pathname)
+ if p:
+ self.add_watch(p,rec=True,auto_add=True)
+ mydebug('process_default: follow link %s to %s',l,p)
+ #TODO: should handle deletion of links that are followed (delete the respective watches)
update_changes([event.pathname])
+
+ def remove_watch(self, pathname, **kwargs):
+ if self.watches.has_key(pathname):
+ return self.wm.rm_watch(self.watches.pop(pathname),**kwargs)
+ return None
+
+ def add_watch(self, pathname, **kwargs):
+ neww = self.wm.add_watch(pathname, self.mask, **kwargs)
+ self.watches.update(neww)
+ return neww
+
+ def init_watches(self, abspaths, follows):
+ self.watches = {}
+ for abspath in abspaths:
+ self.watches.update(self.wm.add_watch(abspath,self.mask,rec=True,auto_add=True))
+ #we have to add watches for follow statements since pyinotify does
+ #not do recursion across symlinks
+ make_symlinks()
+ for link in op.symlinks:
+ mydebug('following symbolic link %s',link)
+ if not self.watches.has_key(link):
+ self.watches.update(self.wm.add_watch(link,self.mask,rec=True,auto_add=True))
+
+ mydebug('init_watches: added paths %s\n based on paths %s\n and follows %s',self.watches,op.abspaths, op.follow)
def linuxwatcher():
p = HandleEvents()
wm = pyinotify.WatchManager() # Watch Manager
- mask = pyinotify.IN_CREATE | pyinotify.IN_DELETE | pyinotify.IN_MODIFY | pyinotify.IN_ATTRIB | pyinotify.IN_MOVED_TO | pyinotify.IN_MOVED_FROM # watched events
+ p.wm = wm
+ p.mask = pyinotify.IN_CREATE | pyinotify.IN_DELETE | pyinotify.IN_MODIFY | pyinotify.IN_ATTRIB | pyinotify.IN_MOVED_TO | pyinotify.IN_MOVED_FROM # watched events
notifier = pyinotify.Notifier(wm, p)
- watches = [wm.add_watch(abspath,mask,rec=True) for abspath in op.abspaths]
- print op.abspaths, watches
+ p.init_watches(op.abspaths, op.follow)
notifier.loop()
-
+
+
#################################################
# END Linux specific code
#################################################
@@ -302,6 +381,7 @@
result.extend(filelevel_approx(path))
mydebug('Dirs sent: %s',eventPaths)
+ #TODO: handle creation/deletion of links that should be followed
update_changes(result)
try:
@@ -312,11 +392,27 @@
mymesg('failed to open status file %s', op.absstatus)
def my_FSEventStreamCreate(paths):
- if op.verbose:
- print 'selected paths are: %s'%paths
+ mydebug('my_FSEventStreamCreate: selected paths are: %s',paths)
if op.sinceWhen == 'now':
op.sinceWhen = kFSEventStreamEventIdSinceNow
+
+ try:
+ op.symlinks
+ except AttributeError:
+ make_symlinks()
+
+ for sl in op.symlinks:
+ #check if that path is already there
+ found=False
+ ln = op.symlinks[sl]
+ for path in paths:
+ if relpath(op.root,path)==ln:
+ found = True
+ break
+ if not found:
+ mydebug('my_FSEventStreamCreate: watch followed link %s',ln)
+ paths.append(os.path.join(op.root,ln))
streamRef = FSEventStreamCreate(kCFAllocatorDefault,
fsevents_callback,
@@ -326,7 +422,7 @@
float(op.latency),
int(op.flags))
if streamRef is None:
- print("ERROR: FSEVentStreamCreate() => NULL")
+ mymesg("ERROR: FSEVentStreamCreate() => NULL")
return None
if op.verbose:
@@ -339,10 +435,10 @@
def macosxwatcher():
#since when? if it is 'now' try to read state
if op.sinceWhen == 'now':
- dict = conf_parser(op.absstatus)
- if dict and dict.has_key('last_item'):
- #print dict['last_item'][-1]
- op.sinceWhen = dict['last_item'][-1]
+ di = conf_parser(op.absstatus)
+ if di and di.has_key('last_item'):
+ #print di['last_item'][-1]
+ op.sinceWhen = di['last_item'][-1]
#print op.sinceWhen
streamRef = my_FSEventStreamCreate(op.abspaths)
Modified: trunk/src/mkProjectInfo.ml
===================================================================
--- trunk/src/mkProjectInfo.ml 2010-10-14 18:23:04 UTC (rev 470)
+++ trunk/src/mkProjectInfo.ml 2010-10-27 18:23:28 UTC (rev 471)
@@ -54,3 +54,4 @@
+
More information about the Unison-hackers
mailing list