[Unison-hackers] [unison-svn] r504 - trunk/src
vouillon at seas.upenn.edu
vouillon at seas.upenn.edu
Thu Aug 9 10:06:21 EDT 2012
Author: vouillon
Date: 2012-08-09 10:06:21 -0400 (Thu, 09 Aug 2012)
New Revision: 504
Added:
trunk/src/fswatchold.ml
trunk/src/fswatchold.mli
Modified:
trunk/src/.depend
trunk/src/Makefile.OCaml
trunk/src/RECENTNEWS
trunk/src/mkProjectInfo.ml
trunk/src/os.ml
trunk/src/os.mli
trunk/src/test.ml
trunk/src/uigtk2.ml
trunk/src/uimacbridge.ml
trunk/src/uimacbridgenew.ml
trunk/src/uitext.ml
trunk/src/update.ml
trunk/src/update.mli
Log:
* Bumped version number: incompatible protocol changes
* Improvements to the file watching functionality:
- retries paths with failures using an exponential backoff algorithm
- the information returned by the file watchers are used
independently for each replica; thus, when only one replica has
changes, Unison will only rescan this replica
- when available, used by the graphical UIs to speed up rescanning
(can be disabled by setting the new 'watch' preference to false)
Modified: trunk/src/.depend
===================================================================
--- trunk/src/.depend 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/.depend 2012-08-09 14:06:21 UTC (rev 504)
@@ -1,359 +1,371 @@
-abort.cmi: uutil.cmi
-bytearray.cmi:
-case.cmi: ubase/prefs.cmi
-checksum.cmi:
-clroot.cmi:
+abort.cmi: uutil.cmi
+bytearray.cmi:
+case.cmi: ubase/prefs.cmi
+checksum.cmi:
+clroot.cmi:
common.cmi: uutil.cmi props.cmi path.cmi osx.cmi os.cmi name.cmi fspath.cmi \
- fileinfo.cmi
+ fileinfo.cmi
copy.cmi: uutil.cmi props.cmi path.cmi osx.cmi os.cmi lwt/lwt.cmi fspath.cmi \
- fileinfo.cmi common.cmi
-external.cmi: lwt/lwt.cmi
+ fileinfo.cmi common.cmi
+external.cmi: lwt/lwt.cmi
fileinfo.cmi: system.cmi props.cmi ubase/prefs.cmi path.cmi osx.cmi \
- fspath.cmi
+ fspath.cmi
files.cmi: uutil.cmi system.cmi props.cmi path.cmi lwt/lwt_util.cmi \
- lwt/lwt.cmi common.cmi
-fileutil.cmi:
-fingerprint.cmi: uutil.cmi path.cmi fspath.cmi
+ lwt/lwt.cmi common.cmi
+fileutil.cmi:
+fingerprint.cmi: uutil.cmi path.cmi fspath.cmi
fpcache.cmi: system.cmi props.cmi path.cmi osx.cmi os.cmi fspath.cmi \
- fileinfo.cmi
-fs.cmi: system/system_intf.cmo fspath.cmi
-fspath.cmi: system.cmi path.cmi name.cmi
-globals.cmi: ubase/prefs.cmi pred.cmi path.cmi lwt/lwt.cmi common.cmi
-lock.cmi: system.cmi
-name.cmi:
-os.cmi: system.cmi props.cmi path.cmi name.cmi fspath.cmi fileinfo.cmi
-osx.cmi: uutil.cmi ubase/prefs.cmi path.cmi fspath.cmi fingerprint.cmi
-path.cmi: pred.cmi name.cmi
-pred.cmi:
-props.cmi: uutil.cmi ubase/prefs.cmi path.cmi osx.cmi fspath.cmi
-recon.cmi: props.cmi path.cmi common.cmi
+ fileinfo.cmi
+fs.cmi: system/system_intf.cmo fspath.cmi
+fspath.cmi: system.cmi path.cmi name.cmi
+fswatchold.cmi: path.cmi lwt/lwt.cmi fspath.cmi
+globals.cmi: ubase/prefs.cmi pred.cmi path.cmi lwt/lwt.cmi common.cmi
+lock.cmi: system.cmi
+name.cmi:
+os.cmi: uutil.cmi system.cmi props.cmi path.cmi name.cmi fspath.cmi \
+ fileinfo.cmi
+osx.cmi: uutil.cmi ubase/prefs.cmi path.cmi fspath.cmi fingerprint.cmi
+path.cmi: pred.cmi name.cmi
+pred.cmi:
+props.cmi: uutil.cmi ubase/prefs.cmi path.cmi osx.cmi fspath.cmi
+recon.cmi: props.cmi path.cmi common.cmi
remote.cmi: ubase/prefs.cmi lwt/lwt.cmi fspath.cmi common.cmi clroot.cmi \
- bytearray.cmi
-sortri.cmi: common.cmi
-stasher.cmi: update.cmi ubase/prefs.cmi path.cmi os.cmi fspath.cmi
-strings.cmi:
-system.cmi: system/system_intf.cmo
-terminal.cmi: lwt/lwt_unix.cmi
-test.cmi:
-transfer.cmi: uutil.cmi lwt/lwt.cmi bytearray.cmi
-transport.cmi: uutil.cmi lwt/lwt.cmi common.cmi
-tree.cmi:
-ui.cmi:
-uicommon.cmi: uutil.cmi ubase/prefs.cmi path.cmi lwt/lwt.cmi common.cmi
-uigtk.cmi: uicommon.cmi
-uigtk2.cmi: uicommon.cmi
-uitext.cmi: uicommon.cmi
-unicode.cmi:
+ bytearray.cmi
+sortri.cmi: common.cmi
+stasher.cmi: update.cmi ubase/prefs.cmi path.cmi os.cmi fspath.cmi
+strings.cmi:
+system.cmi: system/system_intf.cmo
+terminal.cmi: lwt/lwt_unix.cmi
+test.cmi:
+transfer.cmi: uutil.cmi lwt/lwt.cmi bytearray.cmi
+transport.cmi: uutil.cmi lwt/lwt.cmi common.cmi
+tree.cmi:
+ui.cmi:
+uicommon.cmi: uutil.cmi ubase/prefs.cmi path.cmi lwt/lwt.cmi common.cmi
+uigtk.cmi: uicommon.cmi
+uigtk2.cmi: uicommon.cmi
+uitext.cmi: uicommon.cmi
+unicode.cmi:
update.cmi: uutil.cmi tree.cmi props.cmi path.cmi osx.cmi os.cmi name.cmi \
- lwt/lwt.cmi fspath.cmi fileinfo.cmi common.cmi
-uutil.cmi:
-xferhint.cmi: ubase/prefs.cmi path.cmi os.cmi fspath.cmi
-abort.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi ubase/prefs.cmi abort.cmi
-abort.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx ubase/prefs.cmx abort.cmi
-bytearray.cmo: bytearray.cmi
-bytearray.cmx: bytearray.cmi
-case.cmo: ubase/util.cmi unicode.cmi ubase/prefs.cmi case.cmi
-case.cmx: ubase/util.cmx unicode.cmx ubase/prefs.cmx case.cmi
-checksum.cmo: checksum.cmi
-checksum.cmx: checksum.cmi
-clroot.cmo: ubase/util.cmi ubase/rx.cmi ubase/prefs.cmi clroot.cmi
-clroot.cmx: ubase/util.cmx ubase/rx.cmx ubase/prefs.cmx clroot.cmi
+ ubase/myMap.cmi lwt/lwt.cmi fspath.cmi fileinfo.cmi common.cmi
+uutil.cmi:
+xferhint.cmi: ubase/prefs.cmi path.cmi os.cmi fspath.cmi
+abort.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi ubase/prefs.cmi abort.cmi
+abort.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx ubase/prefs.cmx abort.cmi
+bytearray.cmo: bytearray.cmi
+bytearray.cmx: bytearray.cmi
+case.cmo: ubase/util.cmi unicode.cmi ubase/prefs.cmi case.cmi
+case.cmx: ubase/util.cmx unicode.cmx ubase/prefs.cmx case.cmi
+checksum.cmo: checksum.cmi
+checksum.cmx: checksum.cmi
+clroot.cmo: ubase/util.cmi ubase/rx.cmi ubase/prefs.cmi clroot.cmi
+clroot.cmx: ubase/util.cmx ubase/rx.cmx ubase/prefs.cmx clroot.cmi
common.cmo: uutil.cmi ubase/util.cmi ubase/safelist.cmi props.cmi path.cmi \
- osx.cmi os.cmi name.cmi fspath.cmi fileinfo.cmi common.cmi
+ osx.cmi os.cmi name.cmi fspath.cmi fileinfo.cmi common.cmi
common.cmx: uutil.cmx ubase/util.cmx ubase/safelist.cmx props.cmx path.cmx \
- osx.cmx os.cmx name.cmx fspath.cmx fileinfo.cmx common.cmi
+ osx.cmx os.cmx name.cmx fspath.cmx fileinfo.cmx common.cmi
copy.cmo: xferhint.cmi uutil.cmi ubase/util.cmi update.cmi transfer.cmi \
ubase/trace.cmi ubase/safelist.cmi remote.cmi props.cmi ubase/prefs.cmi \
path.cmi osx.cmi os.cmi lwt/lwt_util.cmi lwt/lwt.cmi globals.cmi \
fspath.cmi fs.cmi fpcache.cmi fingerprint.cmi fileinfo.cmi external.cmi \
- common.cmi clroot.cmi bytearray.cmi abort.cmi copy.cmi
+ common.cmi clroot.cmi bytearray.cmi abort.cmi copy.cmi
copy.cmx: xferhint.cmx uutil.cmx ubase/util.cmx update.cmx transfer.cmx \
ubase/trace.cmx ubase/safelist.cmx remote.cmx props.cmx ubase/prefs.cmx \
path.cmx osx.cmx os.cmx lwt/lwt_util.cmx lwt/lwt.cmx globals.cmx \
fspath.cmx fs.cmx fpcache.cmx fingerprint.cmx fileinfo.cmx external.cmx \
- common.cmx clroot.cmx bytearray.cmx abort.cmx copy.cmi
+ common.cmx clroot.cmx bytearray.cmx abort.cmx copy.cmi
external.cmo: ubase/util.cmi system.cmi ubase/safelist.cmi lwt/lwt_util.cmi \
- lwt/lwt_unix.cmi lwt/lwt.cmi external.cmi
+ lwt/lwt_unix.cmi lwt/lwt.cmi external.cmi
external.cmx: ubase/util.cmx system.cmx ubase/safelist.cmx lwt/lwt_util.cmx \
- lwt/lwt_unix.cmx lwt/lwt.cmx external.cmi
+ lwt/lwt_unix.cmx lwt/lwt.cmx external.cmi
fileinfo.cmo: ubase/util.cmi system.cmi props.cmi ubase/prefs.cmi path.cmi \
- osx.cmi fspath.cmi fs.cmi fileinfo.cmi
+ osx.cmi fspath.cmi fs.cmi fileinfo.cmi
fileinfo.cmx: ubase/util.cmx system.cmx props.cmx ubase/prefs.cmx path.cmx \
- osx.cmx fspath.cmx fs.cmx fileinfo.cmi
+ osx.cmx fspath.cmx fs.cmx fileinfo.cmi
files.cmo: xferhint.cmi uutil.cmi ubase/util.cmi update.cmi ubase/trace.cmi \
system.cmi stasher.cmi ubase/safelist.cmi ubase/rx.cmi remote.cmi \
props.cmi ubase/prefs.cmi path.cmi osx.cmi os.cmi name.cmi \
lwt/lwt_util.cmi lwt/lwt_unix.cmi lwt/lwt.cmi globals.cmi fspath.cmi \
fs.cmi fingerprint.cmi fileinfo.cmi external.cmi copy.cmi common.cmi \
- abort.cmi files.cmi
+ abort.cmi files.cmi
files.cmx: xferhint.cmx uutil.cmx ubase/util.cmx update.cmx ubase/trace.cmx \
system.cmx stasher.cmx ubase/safelist.cmx ubase/rx.cmx remote.cmx \
props.cmx ubase/prefs.cmx path.cmx osx.cmx os.cmx name.cmx \
lwt/lwt_util.cmx lwt/lwt_unix.cmx lwt/lwt.cmx globals.cmx fspath.cmx \
fs.cmx fingerprint.cmx fileinfo.cmx external.cmx copy.cmx common.cmx \
- abort.cmx files.cmi
-fileutil.cmo: fileutil.cmi
-fileutil.cmx: fileutil.cmi
-fingerprint.cmo: uutil.cmi ubase/util.cmi fspath.cmi fs.cmi fingerprint.cmi
-fingerprint.cmx: uutil.cmx ubase/util.cmx fspath.cmx fs.cmx fingerprint.cmi
+ abort.cmx files.cmi
+fileutil.cmo: fileutil.cmi
+fileutil.cmx: fileutil.cmi
+fingerprint.cmo: uutil.cmi ubase/util.cmi path.cmi fspath.cmi fs.cmi \
+ fingerprint.cmi
+fingerprint.cmx: uutil.cmx ubase/util.cmx path.cmx fspath.cmx fs.cmx \
+ fingerprint.cmi
fpcache.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi system.cmi \
- ubase/safelist.cmi props.cmi path.cmi osx.cmi os.cmi fileinfo.cmi \
- fpcache.cmi
+ ubase/safelist.cmi props.cmi ubase/prefs.cmi path.cmi osx.cmi os.cmi \
+ fspath.cmi fileinfo.cmi fpcache.cmi
fpcache.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx system.cmx \
- ubase/safelist.cmx props.cmx path.cmx osx.cmx os.cmx fileinfo.cmx \
- fpcache.cmi
-fs.cmo: fspath.cmi fs.cmi
-fs.cmx: fspath.cmx fs.cmi
+ ubase/safelist.cmx props.cmx ubase/prefs.cmx path.cmx osx.cmx os.cmx \
+ fspath.cmx fileinfo.cmx fpcache.cmi
+fs.cmo: fspath.cmi fs.cmi
+fs.cmx: fspath.cmx fs.cmi
fspath.cmo: uutil.cmi ubase/util.cmi system.cmi ubase/rx.cmi path.cmi \
- name.cmi fileutil.cmi fspath.cmi
+ name.cmi fileutil.cmi fspath.cmi
fspath.cmx: uutil.cmx ubase/util.cmx system.cmx ubase/rx.cmx path.cmx \
- name.cmx fileutil.cmx fspath.cmi
+ name.cmx fileutil.cmx fspath.cmi
+fswatchold.cmo: uutil.cmi ubase/util.cmi system.cmi ubase/safelist.cmi \
+ ubase/prefs.cmi pred.cmi path.cmi os.cmi lwt/lwt_unix.cmi lwt/lwt.cmi \
+ globals.cmi fspath.cmi fswatchold.cmi
+fswatchold.cmx: uutil.cmx ubase/util.cmx system.cmx ubase/safelist.cmx \
+ ubase/prefs.cmx pred.cmx path.cmx os.cmx lwt/lwt_unix.cmx lwt/lwt.cmx \
+ globals.cmx fspath.cmx fswatchold.cmi
globals.cmo: ubase/util.cmi ubase/trace.cmi ubase/safelist.cmi remote.cmi \
ubase/prefs.cmi pred.cmi path.cmi os.cmi name.cmi lwt/lwt_util.cmi \
- lwt/lwt_unix.cmi lwt/lwt.cmi common.cmi clroot.cmi globals.cmi
+ lwt/lwt_unix.cmi lwt/lwt.cmi common.cmi clroot.cmi globals.cmi
globals.cmx: ubase/util.cmx ubase/trace.cmx ubase/safelist.cmx remote.cmx \
ubase/prefs.cmx pred.cmx path.cmx os.cmx name.cmx lwt/lwt_util.cmx \
- lwt/lwt_unix.cmx lwt/lwt.cmx common.cmx clroot.cmx globals.cmi
-library_info.cmo:
-library_info.cmx:
-linkgtk.cmo: uigtk.cmi main.cmo
-linkgtk.cmx: uigtk.cmx main.cmx
-linkgtk2.cmo: uigtk2.cmi main.cmo
-linkgtk2.cmx: uigtk2.cmx main.cmx
-linktext.cmo: uitext.cmi main.cmo
-linktext.cmx: uitext.cmx main.cmx
-lock.cmo: ubase/util.cmi system.cmi lock.cmi
-lock.cmx: ubase/util.cmx system.cmx lock.cmi
+ lwt/lwt_unix.cmx lwt/lwt.cmx common.cmx clroot.cmx globals.cmi
+linkgtk.cmo: uigtk.cmi main.cmo
+linkgtk.cmx: uigtk.cmx main.cmx
+linkgtk2.cmo: uigtk2.cmi main.cmo
+linkgtk2.cmx: uigtk2.cmx main.cmx
+linktext.cmo: uitext.cmi main.cmo
+linktext.cmx: uitext.cmx main.cmx
+lock.cmo: ubase/util.cmi system.cmi lock.cmi
+lock.cmx: ubase/util.cmx system.cmx lock.cmi
main.cmo: uutil.cmi ubase/util.cmi uitext.cmi uicommon.cmi strings.cmi \
- ubase/safelist.cmi remote.cmi ubase/prefs.cmi os.cmi
+ ubase/safelist.cmi remote.cmi ubase/prefs.cmi os.cmi
main.cmx: uutil.cmx ubase/util.cmx uitext.cmx uicommon.cmx strings.cmx \
- ubase/safelist.cmx remote.cmx ubase/prefs.cmx os.cmx
-mkProjectInfo.cmo:
-mkProjectInfo.cmx:
-name.cmo: ubase/util.cmi ubase/rx.cmi case.cmi name.cmi
-name.cmx: ubase/util.cmx ubase/rx.cmx case.cmx name.cmi
-os.cmo: uutil.cmi ubase/util.cmi system.cmi ubase/safelist.cmi props.cmi \
- ubase/prefs.cmi path.cmi osx.cmi name.cmi fspath.cmi fs.cmi \
- fingerprint.cmi fileinfo.cmi os.cmi
-os.cmx: uutil.cmx ubase/util.cmx system.cmx ubase/safelist.cmx props.cmx \
- ubase/prefs.cmx path.cmx osx.cmx name.cmx fspath.cmx fs.cmx \
- fingerprint.cmx fileinfo.cmx os.cmi
+ ubase/safelist.cmx remote.cmx ubase/prefs.cmx os.cmx
+mkProjectInfo.cmo:
+mkProjectInfo.cmx:
+name.cmo: ubase/util.cmi ubase/rx.cmi case.cmi name.cmi
+name.cmx: ubase/util.cmx ubase/rx.cmx case.cmx name.cmi
+os.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi system.cmi \
+ ubase/safelist.cmi props.cmi ubase/prefs.cmi path.cmi osx.cmi name.cmi \
+ fspath.cmi fs.cmi fingerprint.cmi fileinfo.cmi os.cmi
+os.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx system.cmx \
+ ubase/safelist.cmx props.cmx ubase/prefs.cmx path.cmx osx.cmx name.cmx \
+ fspath.cmx fs.cmx fingerprint.cmx fileinfo.cmx os.cmi
osx.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi system.cmi \
ubase/safelist.cmi ubase/prefs.cmi path.cmi name.cmi fspath.cmi fs.cmi \
- fingerprint.cmi osx.cmi
+ fingerprint.cmi osx.cmi
osx.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx system.cmx \
ubase/safelist.cmx ubase/prefs.cmx path.cmx name.cmx fspath.cmx fs.cmx \
- fingerprint.cmx osx.cmi
+ fingerprint.cmx osx.cmi
path.cmo: ubase/util.cmi ubase/safelist.cmi ubase/rx.cmi pred.cmi name.cmi \
- fileutil.cmi case.cmi path.cmi
+ fileutil.cmi case.cmi path.cmi
path.cmx: ubase/util.cmx ubase/safelist.cmx ubase/rx.cmx pred.cmx name.cmx \
- fileutil.cmx case.cmx path.cmi
-pixmaps.cmo:
-pixmaps.cmx:
+ fileutil.cmx case.cmx path.cmi
+pixmaps.cmo:
+pixmaps.cmx:
pred.cmo: ubase/util.cmi ubase/safelist.cmi ubase/rx.cmi ubase/prefs.cmi \
- case.cmi pred.cmi
+ case.cmi pred.cmi
pred.cmx: ubase/util.cmx ubase/safelist.cmx ubase/rx.cmx ubase/prefs.cmx \
- case.cmx pred.cmi
+ case.cmx pred.cmi
props.cmo: uutil.cmi ubase/util.cmi ubase/prefs.cmi path.cmi osx.cmi \
- lwt/lwt_unix.cmi fspath.cmi fs.cmi external.cmi props.cmi
+ lwt/lwt_unix.cmi fspath.cmi fs.cmi external.cmi props.cmi
props.cmx: uutil.cmx ubase/util.cmx ubase/prefs.cmx path.cmx osx.cmx \
- lwt/lwt_unix.cmx fspath.cmx fs.cmx external.cmx props.cmi
+ lwt/lwt_unix.cmx fspath.cmx fs.cmx external.cmx props.cmi
recon.cmo: ubase/util.cmi update.cmi tree.cmi ubase/trace.cmi sortri.cmi \
ubase/safelist.cmi props.cmi ubase/prefs.cmi pred.cmi path.cmi name.cmi \
- globals.cmi fileinfo.cmi common.cmi recon.cmi
+ globals.cmi fileinfo.cmi common.cmi recon.cmi
recon.cmx: ubase/util.cmx update.cmx tree.cmx ubase/trace.cmx sortri.cmx \
ubase/safelist.cmx props.cmx ubase/prefs.cmx pred.cmx path.cmx name.cmx \
- globals.cmx fileinfo.cmx common.cmx recon.cmi
+ globals.cmx fileinfo.cmx common.cmx recon.cmi
remote.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi terminal.cmi system.cmi \
ubase/safelist.cmi ubase/prefs.cmi os.cmi lwt/lwt_util.cmi \
lwt/lwt_unix.cmi lwt/lwt.cmi fspath.cmi fs.cmi common.cmi clroot.cmi \
- case.cmi bytearray.cmi remote.cmi
+ case.cmi bytearray.cmi remote.cmi
remote.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx terminal.cmx system.cmx \
ubase/safelist.cmx ubase/prefs.cmx os.cmx lwt/lwt_util.cmx \
lwt/lwt_unix.cmx lwt/lwt.cmx fspath.cmx fs.cmx common.cmx clroot.cmx \
- case.cmx bytearray.cmx remote.cmi
+ case.cmx bytearray.cmx remote.cmi
sortri.cmo: ubase/util.cmi ubase/safelist.cmi ubase/prefs.cmi pred.cmi \
- path.cmi common.cmi sortri.cmi
+ path.cmi common.cmi sortri.cmi
sortri.cmx: ubase/util.cmx ubase/safelist.cmx ubase/prefs.cmx pred.cmx \
- path.cmx common.cmx sortri.cmi
+ path.cmx common.cmx sortri.cmi
stasher.cmo: xferhint.cmi ubase/util.cmi update.cmi system.cmi \
ubase/safelist.cmi remote.cmi props.cmi ubase/prefs.cmi pred.cmi path.cmi \
osx.cmi os.cmi lwt/lwt_unix.cmi lwt/lwt.cmi globals.cmi fspath.cmi \
- fingerprint.cmi fileutil.cmi fileinfo.cmi copy.cmi common.cmi stasher.cmi
+ fingerprint.cmi fileutil.cmi fileinfo.cmi copy.cmi common.cmi stasher.cmi
stasher.cmx: xferhint.cmx ubase/util.cmx update.cmx system.cmx \
ubase/safelist.cmx remote.cmx props.cmx ubase/prefs.cmx pred.cmx path.cmx \
osx.cmx os.cmx lwt/lwt_unix.cmx lwt/lwt.cmx globals.cmx fspath.cmx \
- fingerprint.cmx fileutil.cmx fileinfo.cmx copy.cmx common.cmx stasher.cmi
-strings.cmo: strings.cmi
-strings.cmx: strings.cmi
-system.cmo: system.cmi
-system.cmx: system.cmi
+ fingerprint.cmx fileutil.cmx fileinfo.cmx copy.cmx common.cmx stasher.cmi
+strings.cmo: strings.cmi
+strings.cmx: strings.cmi
+system.cmo: system.cmi
+system.cmx: system.cmi
terminal.cmo: system.cmi ubase/rx.cmi lwt/lwt_unix.cmi lwt/lwt.cmi \
- terminal.cmi
+ terminal.cmi
terminal.cmx: system.cmx ubase/rx.cmx lwt/lwt_unix.cmx lwt/lwt.cmx \
- terminal.cmi
+ terminal.cmi
test.cmo: uutil.cmi ubase/util.cmi update.cmi uicommon.cmi transport.cmi \
ubase/trace.cmi stasher.cmi ubase/safelist.cmi remote.cmi recon.cmi \
ubase/prefs.cmi path.cmi os.cmi lwt/lwt_util.cmi lwt/lwt_unix.cmi \
lwt/lwt.cmi globals.cmi fspath.cmi fs.cmi fingerprint.cmi common.cmi \
- test.cmi
+ test.cmi
test.cmx: uutil.cmx ubase/util.cmx update.cmx uicommon.cmx transport.cmx \
ubase/trace.cmx stasher.cmx ubase/safelist.cmx remote.cmx recon.cmx \
ubase/prefs.cmx path.cmx os.cmx lwt/lwt_util.cmx lwt/lwt_unix.cmx \
lwt/lwt.cmx globals.cmx fspath.cmx fs.cmx fingerprint.cmx common.cmx \
- test.cmi
+ test.cmi
transfer.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi ubase/safelist.cmi \
- lwt/lwt.cmi checksum.cmi bytearray.cmi transfer.cmi
+ lwt/lwt.cmi checksum.cmi bytearray.cmi transfer.cmi
transfer.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx ubase/safelist.cmx \
- lwt/lwt.cmx checksum.cmx bytearray.cmx transfer.cmi
+ lwt/lwt.cmx checksum.cmx bytearray.cmx transfer.cmi
transport.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi remote.cmi props.cmi \
ubase/prefs.cmi path.cmi osx.cmi lwt/lwt_util.cmi lwt/lwt.cmi globals.cmi \
- files.cmi common.cmi abort.cmi transport.cmi
+ files.cmi common.cmi abort.cmi transport.cmi
transport.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx remote.cmx props.cmx \
ubase/prefs.cmx path.cmx osx.cmx lwt/lwt_util.cmx lwt/lwt.cmx globals.cmx \
- files.cmx common.cmx abort.cmx transport.cmi
-tree.cmo: ubase/safelist.cmi tree.cmi
-tree.cmx: ubase/safelist.cmx tree.cmi
+ files.cmx common.cmx abort.cmx transport.cmi
+tree.cmo: ubase/safelist.cmi tree.cmi
+tree.cmx: ubase/safelist.cmx tree.cmi
uicommon.cmo: xferhint.cmi uutil.cmi ubase/util.cmi update.cmi \
ubase/trace.cmi system.cmi stasher.cmi ubase/safelist.cmi remote.cmi \
recon.cmi props.cmi ubase/prefs.cmi path.cmi osx.cmi os.cmi name.cmi \
lwt/lwt_unix.cmi lwt/lwt.cmi globals.cmi fspath.cmi files.cmi \
- fileinfo.cmi common.cmi clroot.cmi case.cmi uicommon.cmi
+ fileinfo.cmi common.cmi clroot.cmi case.cmi uicommon.cmi
uicommon.cmx: xferhint.cmx uutil.cmx ubase/util.cmx update.cmx \
ubase/trace.cmx system.cmx stasher.cmx ubase/safelist.cmx remote.cmx \
recon.cmx props.cmx ubase/prefs.cmx path.cmx osx.cmx os.cmx name.cmx \
lwt/lwt_unix.cmx lwt/lwt.cmx globals.cmx fspath.cmx files.cmx \
- fileinfo.cmx common.cmx clroot.cmx case.cmx uicommon.cmi
+ fileinfo.cmx common.cmx clroot.cmx case.cmx uicommon.cmi
uigtk.cmo: uutil.cmi ubase/util.cmi update.cmi uitext.cmi uicommon.cmi \
transport.cmi ubase/trace.cmi system.cmi strings.cmi sortri.cmi \
ubase/safelist.cmi remote.cmi recon.cmi ubase/prefs.cmi pixmaps.cmo \
path.cmi os.cmi lwt/lwt_util.cmi lwt/lwt_unix.cmi lwt/lwt.cmi globals.cmi \
- files.cmi common.cmi clroot.cmi uigtk.cmi
+ files.cmi common.cmi clroot.cmi uigtk.cmi
uigtk.cmx: uutil.cmx ubase/util.cmx update.cmx uitext.cmx uicommon.cmx \
transport.cmx ubase/trace.cmx system.cmx strings.cmx sortri.cmx \
ubase/safelist.cmx remote.cmx recon.cmx ubase/prefs.cmx pixmaps.cmx \
path.cmx os.cmx lwt/lwt_util.cmx lwt/lwt_unix.cmx lwt/lwt.cmx globals.cmx \
- files.cmx common.cmx clroot.cmx uigtk.cmi
+ files.cmx common.cmx clroot.cmx uigtk.cmi
uigtk2.cmo: uutil.cmi ubase/util.cmi update.cmi unicode.cmi uitext.cmi \
uicommon.cmi transport.cmi ubase/trace.cmi system.cmi strings.cmi \
sortri.cmi ubase/safelist.cmi remote.cmi recon.cmi ubase/prefs.cmi \
pixmaps.cmo path.cmi os.cmi lwt/lwt_util.cmi lwt/lwt_unix.cmi lwt/lwt.cmi \
- globals.cmi files.cmi common.cmi clroot.cmi case.cmi uigtk2.cmi
+ globals.cmi files.cmi common.cmi clroot.cmi case.cmi uigtk2.cmi
uigtk2.cmx: uutil.cmx ubase/util.cmx update.cmx unicode.cmx uitext.cmx \
uicommon.cmx transport.cmx ubase/trace.cmx system.cmx strings.cmx \
sortri.cmx ubase/safelist.cmx remote.cmx recon.cmx ubase/prefs.cmx \
pixmaps.cmx path.cmx os.cmx lwt/lwt_util.cmx lwt/lwt_unix.cmx lwt/lwt.cmx \
- globals.cmx files.cmx common.cmx clroot.cmx case.cmx uigtk2.cmi
+ globals.cmx files.cmx common.cmx clroot.cmx case.cmx uigtk2.cmi
uimacbridge.cmo: xferhint.cmi uutil.cmi ubase/util.cmi update.cmi \
uicommon.cmi transport.cmi ubase/trace.cmi terminal.cmi system.cmi \
stasher.cmi ubase/safelist.cmi remote.cmi recon.cmi ubase/prefs.cmi \
path.cmi os.cmi main.cmo lwt/lwt_util.cmi lwt/lwt_unix.cmi lwt/lwt.cmi \
- globals.cmi fspath.cmi files.cmi common.cmi clroot.cmi
+ globals.cmi fspath.cmi files.cmi common.cmi clroot.cmi
uimacbridge.cmx: xferhint.cmx uutil.cmx ubase/util.cmx update.cmx \
uicommon.cmx transport.cmx ubase/trace.cmx terminal.cmx system.cmx \
stasher.cmx ubase/safelist.cmx remote.cmx recon.cmx ubase/prefs.cmx \
path.cmx os.cmx main.cmx lwt/lwt_util.cmx lwt/lwt_unix.cmx lwt/lwt.cmx \
- globals.cmx fspath.cmx files.cmx common.cmx clroot.cmx
+ globals.cmx fspath.cmx files.cmx common.cmx clroot.cmx
uimacbridgenew.cmo: xferhint.cmi uutil.cmi ubase/util.cmi update.cmi \
unicode.cmi uicommon.cmi transport.cmi ubase/trace.cmi terminal.cmi \
system.cmi stasher.cmi ubase/safelist.cmi remote.cmi recon.cmi \
ubase/prefs.cmi path.cmi os.cmi main.cmo lwt/lwt_util.cmi \
lwt/lwt_unix.cmi lwt/lwt.cmi globals.cmi fspath.cmi files.cmi common.cmi \
- clroot.cmi
+ clroot.cmi
uimacbridgenew.cmx: xferhint.cmx uutil.cmx ubase/util.cmx update.cmx \
unicode.cmx uicommon.cmx transport.cmx ubase/trace.cmx terminal.cmx \
system.cmx stasher.cmx ubase/safelist.cmx remote.cmx recon.cmx \
ubase/prefs.cmx path.cmx os.cmx main.cmx lwt/lwt_util.cmx \
lwt/lwt_unix.cmx lwt/lwt.cmx globals.cmx fspath.cmx files.cmx common.cmx \
- clroot.cmx
+ clroot.cmx
uitext.cmo: uutil.cmi ubase/util.cmi update.cmi uicommon.cmi transport.cmi \
ubase/trace.cmi system.cmi ubase/safelist.cmi remote.cmi recon.cmi \
ubase/prefs.cmi path.cmi lwt/lwt_util.cmi lwt/lwt_unix.cmi lwt/lwt.cmi \
- globals.cmi common.cmi uitext.cmi
+ globals.cmi fswatchold.cmi common.cmi uitext.cmi
uitext.cmx: uutil.cmx ubase/util.cmx update.cmx uicommon.cmx transport.cmx \
ubase/trace.cmx system.cmx ubase/safelist.cmx remote.cmx recon.cmx \
ubase/prefs.cmx path.cmx lwt/lwt_util.cmx lwt/lwt_unix.cmx lwt/lwt.cmx \
- globals.cmx common.cmx uitext.cmi
-unicode.cmo: unicode_tables.cmo unicode.cmi
-unicode.cmx: unicode_tables.cmx unicode.cmi
-unicode_tables.cmo:
-unicode_tables.cmx:
+ globals.cmx fswatchold.cmx common.cmx uitext.cmi
+unicode.cmo: unicode_tables.cmo unicode.cmi
+unicode.cmx: unicode_tables.cmx unicode.cmi
+unicode_tables.cmo:
+unicode_tables.cmx:
update.cmo: xferhint.cmi uutil.cmi ubase/util.cmi tree.cmi ubase/trace.cmi \
system.cmi ubase/safelist.cmi remote.cmi props.cmi ubase/proplist.cmi \
ubase/prefs.cmi pred.cmi path.cmi osx.cmi os.cmi name.cmi ubase/myMap.cmi \
- lwt/lwt_unix.cmi lwt/lwt.cmi lock.cmi globals.cmi fspath.cmi fpcache.cmi \
- fingerprint.cmi fileinfo.cmi common.cmi case.cmi update.cmi
+ lwt/lwt_unix.cmi lwt/lwt.cmi lock.cmi globals.cmi fswatchold.cmi \
+ fspath.cmi fpcache.cmi fingerprint.cmi fileinfo.cmi common.cmi case.cmi \
+ update.cmi
update.cmx: xferhint.cmx uutil.cmx ubase/util.cmx tree.cmx ubase/trace.cmx \
system.cmx ubase/safelist.cmx remote.cmx props.cmx ubase/proplist.cmx \
ubase/prefs.cmx pred.cmx path.cmx osx.cmx os.cmx name.cmx ubase/myMap.cmx \
- lwt/lwt_unix.cmx lwt/lwt.cmx lock.cmx globals.cmx fspath.cmx fpcache.cmx \
- fingerprint.cmx fileinfo.cmx common.cmx case.cmx update.cmi
-uutil.cmo: ubase/util.cmi ubase/trace.cmi uutil.cmi
-uutil.cmx: ubase/util.cmx ubase/trace.cmx uutil.cmi
+ lwt/lwt_unix.cmx lwt/lwt.cmx lock.cmx globals.cmx fswatchold.cmx \
+ fspath.cmx fpcache.cmx fingerprint.cmx fileinfo.cmx common.cmx case.cmx \
+ update.cmi
+uutil.cmo: ubase/util.cmi ubase/trace.cmi ubase/projectInfo.cmo uutil.cmi
+uutil.cmx: ubase/util.cmx ubase/trace.cmx ubase/projectInfo.cmx uutil.cmi
xferhint.cmo: ubase/util.cmi ubase/trace.cmi ubase/prefs.cmi path.cmi os.cmi \
- fspath.cmi xferhint.cmi
+ fspath.cmi xferhint.cmi
xferhint.cmx: ubase/util.cmx ubase/trace.cmx ubase/prefs.cmx path.cmx os.cmx \
- fspath.cmx xferhint.cmi
-lwt/lwt.cmo: lwt/lwt.cmi
-lwt/lwt.cmx: lwt/lwt.cmi
-lwt/lwt_unix.cmo: lwt/lwt_unix.cmi
-lwt/lwt_unix.cmx: lwt/lwt_unix.cmi
-lwt/lwt_util.cmo: lwt/lwt.cmi lwt/lwt_util.cmi
-lwt/lwt_util.cmx: lwt/lwt.cmx lwt/lwt_util.cmi
-lwt/pqueue.cmo: lwt/pqueue.cmi
-lwt/pqueue.cmx: lwt/pqueue.cmi
-system/system_generic.cmo:
-system/system_generic.cmx:
-system/system_intf.cmo:
-system/system_intf.cmx:
-system/system_win.cmo: unicode.cmi system/system_generic.cmo ubase/rx.cmi
-system/system_win.cmx: unicode.cmx system/system_generic.cmx ubase/rx.cmx
-ubase/myMap.cmo: ubase/myMap.cmi
-ubase/myMap.cmx: ubase/myMap.cmi
+ fspath.cmx xferhint.cmi
+lwt/lwt.cmo: lwt/lwt.cmi
+lwt/lwt.cmx: lwt/lwt.cmi
+lwt/lwt_unix.cmo: lwt/lwt_unix.cmi
+lwt/lwt_unix.cmx: lwt/lwt_unix.cmi
+lwt/lwt_util.cmo: lwt/lwt.cmi lwt/lwt_util.cmi
+lwt/lwt_util.cmx: lwt/lwt.cmx lwt/lwt_util.cmi
+lwt/pqueue.cmo: lwt/pqueue.cmi
+lwt/pqueue.cmx: lwt/pqueue.cmi
+system/system_generic.cmo:
+system/system_generic.cmx:
+system/system_intf.cmo:
+system/system_intf.cmx:
+system/system_win.cmo: unicode.cmi system/system_generic.cmo ubase/rx.cmi
+system/system_win.cmx: unicode.cmx system/system_generic.cmx ubase/rx.cmx
+ubase/myMap.cmo: ubase/myMap.cmi
+ubase/myMap.cmx: ubase/myMap.cmi
ubase/prefs.cmo: ubase/util.cmi ubase/uarg.cmi system.cmi ubase/safelist.cmi \
- ubase/prefs.cmi
+ ubase/prefs.cmi
ubase/prefs.cmx: ubase/util.cmx ubase/uarg.cmx system.cmx ubase/safelist.cmx \
- ubase/prefs.cmi
-ubase/proplist.cmo: ubase/util.cmi ubase/proplist.cmi
-ubase/proplist.cmx: ubase/util.cmx ubase/proplist.cmi
-ubase/rx.cmo: ubase/rx.cmi
-ubase/rx.cmx: ubase/rx.cmi
-ubase/safelist.cmo: ubase/safelist.cmi
-ubase/safelist.cmx: ubase/safelist.cmi
+ ubase/prefs.cmi
+ubase/projectInfo.cmo:
+ubase/projectInfo.cmx:
+ubase/proplist.cmo: ubase/util.cmi ubase/proplist.cmi
+ubase/proplist.cmx: ubase/util.cmx ubase/proplist.cmi
+ubase/rx.cmo: ubase/rx.cmi
+ubase/rx.cmx: ubase/rx.cmi
+ubase/safelist.cmo: ubase/safelist.cmi
+ubase/safelist.cmx: ubase/safelist.cmi
ubase/trace.cmo: ubase/util.cmi system.cmi ubase/safelist.cmi ubase/prefs.cmi \
- ubase/trace.cmi
+ ubase/trace.cmi
ubase/trace.cmx: ubase/util.cmx system.cmx ubase/safelist.cmx ubase/prefs.cmx \
- ubase/trace.cmi
-ubase/uarg.cmo: ubase/util.cmi system.cmi ubase/safelist.cmi ubase/uarg.cmi
-ubase/uarg.cmx: ubase/util.cmx system.cmx ubase/safelist.cmx ubase/uarg.cmi
-ubase/uprintf.cmo: ubase/uprintf.cmi
-ubase/uprintf.cmx: ubase/uprintf.cmi
+ ubase/trace.cmi
+ubase/uarg.cmo: ubase/util.cmi system.cmi ubase/safelist.cmi ubase/uarg.cmi
+ubase/uarg.cmx: ubase/util.cmx system.cmx ubase/safelist.cmx ubase/uarg.cmi
+ubase/uprintf.cmo: ubase/uprintf.cmi
+ubase/uprintf.cmx: ubase/uprintf.cmi
ubase/util.cmo: ubase/uprintf.cmi system.cmi ubase/safelist.cmi \
- ubase/util.cmi
+ ubase/util.cmi
ubase/util.cmx: ubase/uprintf.cmx system.cmx ubase/safelist.cmx \
- ubase/util.cmi
-lwt/lwt.cmi:
-lwt/lwt_unix.cmi: lwt/lwt.cmi
-lwt/lwt_util.cmi: lwt/lwt.cmi
-lwt/pqueue.cmi:
-ubase/myMap.cmi:
-ubase/prefs.cmi: ubase/util.cmi system.cmi
-ubase/proplist.cmi:
-ubase/rx.cmi:
-ubase/safelist.cmi:
-ubase/trace.cmi: ubase/prefs.cmi
-ubase/uarg.cmi:
-ubase/uprintf.cmi:
-ubase/util.cmi: system.cmi
-lwt/example/editor.cmo: lwt/lwt_unix.cmi
-lwt/example/editor.cmx: lwt/lwt_unix.cmx
-lwt/example/relay.cmo: lwt/lwt_unix.cmi lwt/lwt.cmi
-lwt/example/relay.cmx: lwt/lwt_unix.cmx lwt/lwt.cmx
-lwt/generic/lwt_unix_impl.cmo: lwt/pqueue.cmi lwt/lwt.cmi
-lwt/generic/lwt_unix_impl.cmx: lwt/pqueue.cmx lwt/lwt.cmx
-lwt/win/lwt_unix_impl.cmo: lwt/pqueue.cmi lwt/lwt.cmi
-lwt/win/lwt_unix_impl.cmx: lwt/pqueue.cmx lwt/lwt.cmx
-system/generic/system_impl.cmo: system/system_generic.cmo
-system/generic/system_impl.cmx: system/system_generic.cmx
-system/win/system_impl.cmo: system/system_win.cmo system/system_generic.cmo
-system/win/system_impl.cmx: system/system_win.cmx system/system_generic.cmx
+ ubase/util.cmi
+lwt/lwt.cmi:
+lwt/lwt_unix.cmi: lwt/lwt.cmi
+lwt/lwt_util.cmi: lwt/lwt.cmi
+lwt/pqueue.cmi:
+ubase/myMap.cmi:
+ubase/prefs.cmi: ubase/util.cmi system.cmi
+ubase/proplist.cmi:
+ubase/rx.cmi:
+ubase/safelist.cmi:
+ubase/trace.cmi: ubase/prefs.cmi
+ubase/uarg.cmi:
+ubase/uprintf.cmi:
+ubase/util.cmi: system.cmi
+lwt/example/editor.cmo: lwt/lwt_unix.cmi
+lwt/example/editor.cmx: lwt/lwt_unix.cmx
+lwt/example/relay.cmo: lwt/lwt_unix.cmi lwt/lwt.cmi
+lwt/example/relay.cmx: lwt/lwt_unix.cmx lwt/lwt.cmx
+lwt/generic/lwt_unix_impl.cmo: lwt/pqueue.cmi lwt/lwt.cmi
+lwt/generic/lwt_unix_impl.cmx: lwt/pqueue.cmx lwt/lwt.cmx
+lwt/win/lwt_unix_impl.cmo: lwt/pqueue.cmi lwt/lwt.cmi
+lwt/win/lwt_unix_impl.cmx: lwt/pqueue.cmx lwt/lwt.cmx
+system/generic/system_impl.cmo: system/system_generic.cmo
+system/generic/system_impl.cmx: system/system_generic.cmx
+system/win/system_impl.cmo: system/system_win.cmo system/system_generic.cmo
+system/win/system_impl.cmx: system/system_win.cmx system/system_generic.cmx
Modified: trunk/src/Makefile.OCaml
===================================================================
--- trunk/src/Makefile.OCaml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/Makefile.OCaml 2012-08-09 14:06:21 UTC (rev 504)
@@ -226,7 +226,7 @@
abort.cmo osx.cmo external.cmo \
props.cmo fileinfo.cmo os.cmo lock.cmo clroot.cmo common.cmo \
tree.cmo checksum.cmo terminal.cmo \
- transfer.cmo xferhint.cmo remote.cmo globals.cmo \
+ transfer.cmo xferhint.cmo remote.cmo globals.cmo fswatchold.cmo \
fpcache.cmo update.cmo copy.cmo stasher.cmo \
files.cmo sortri.cmo recon.cmo transport.cmo \
strings.cmo uicommon.cmo uitext.cmo test.cmo
Modified: trunk/src/RECENTNEWS
===================================================================
--- trunk/src/RECENTNEWS 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/RECENTNEWS 2012-08-09 14:06:21 UTC (rev 504)
@@ -1,3 +1,15 @@
+CHANGES FROM VERSION 2.46.-1
+
+* Bumped version number: incompatible protocol changes
+* Improvements to the file watching functionality:
+ - retries paths with failures using an exponential backoff algorithm
+ - the information returned by the file watchers are used
+ independently for each replica; thus, when only one replica has
+ changes, Unison will only rescan this replica
+ - when available, used by the graphical UIs to speed up rescanning
+ (can be disabled by setting the new 'watch' preference to false)
+
+-------------------------------
CHANGES FROM VERSION 2.45.15
* transfer.ml: updated debugging code; in particular, turns an
Added: trunk/src/fswatchold.ml
===================================================================
--- trunk/src/fswatchold.ml (rev 0)
+++ trunk/src/fswatchold.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -0,0 +1,167 @@
+(* Unison file synchronizer: src/fswatcherold.ml *)
+(* Copyright 1999-2012, Benjamin C. Pierce
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*)
+
+(* FIX: we should check that the child process has not died and
+ restart it if so... *)
+
+(* FIX: the names of the paths being watched should get included
+ in the name of the watcher's state file *)
+
+let useWatcher =
+ Prefs.createBool "watch" true
+ "!when set, use a file watcher process to detect changes"
+ "Unison uses a file watcher process, when available, to detect filesystem \
+ changes; this is used to speed up update detection, and for continuous \
+ synchronization (\\verb|-repeat watch| preference. Setting this flag to \
+ false disable the use of this process."
+
+let debug = Util.debug "fswatch"
+
+let watchinterval = 5
+
+let watcherTemp archHash n = Os.fileInUnisonDir (n ^ archHash)
+
+let watchercmd archHash root =
+ let fsmonfile =
+ Filename.concat (Filename.dirname Sys.executable_name) "fsmonitor.py" in
+ if not (Sys.file_exists fsmonfile) then
+ None
+ else begin
+ (* FIX: is the quoting of --follow parameters going to work on Win32?
+ (2/2012: tried adding Uutil.quotes -- maybe this is OK now?) *)
+ (* FIX -- need to find the program using watcherosx preference *)
+ let changefile = watcherTemp archHash "changes" in
+ let statefile = watcherTemp archHash "state" in
+ let paths = Safelist.map Path.toString (Prefs.read Globals.paths) in
+ let followpaths = Pred.extern Path.followPred in
+ let follow = Safelist.map
+ (fun s -> "--follow '" ^ Uutil.quotes s ^ "'")
+ followpaths in
+ (* BCP (per Josh Berdine, 5/2012): changed startup command from this...
+ let cmd = Printf.sprintf "fsmonitor.py %s --outfile %s --statefile %s %s %s\n"
+ ... to this: *)
+ let cmd = Printf.sprintf "python \"%s\" \"%s\" --outfile \"%s\" --statefile \"%s\" %s %s\n"
+ fsmonfile
+ root
+ (System.fspathToPrintString changefile)
+ (System.fspathToPrintString statefile)
+ (String.concat " " follow)
+ (String.concat " " paths) in
+ debug (fun() -> Util.msg "watchercmd = %s\n" cmd);
+ Some (changefile,cmd)
+ end
+
+module StringSet= Set.Make (String)
+module RootMap = Map.Make (String)
+type watcherinfo = {file: System.fspath;
+ mutable ch:Pervasives.in_channel option;
+ chars: Buffer.t;
+ mutable lines: string list}
+let watchers : watcherinfo RootMap.t ref = ref RootMap.empty
+
+let trim_duplicates l =
+ let rec loop l = match l with
+ [] -> l
+ | [s] -> l
+ | s1::s2::rest ->
+ if Util.startswith s1 s2 || Util.startswith s2 s1 then
+ loop (s2::rest)
+ else
+ s1 :: (loop (s2::rest)) in
+ loop (Safelist.sort String.compare l)
+
+let readAvailableLinesFromWatcher wi =
+ let ch = match wi.ch with Some(c) -> c | None -> assert false in
+ let rec loop () =
+ match try Some(input_char ch) with End_of_file -> None with
+ None ->
+ ()
+ | Some(c) ->
+ if c = '\n' then begin
+ wi.lines <- Buffer.contents wi.chars :: wi.lines;
+ Buffer.clear wi.chars;
+ loop ()
+ end else begin
+ Buffer.add_char wi.chars c;
+ loop ()
+ end in
+ loop ()
+
+let readChanges wi =
+ if wi.ch = None then
+ (* Watcher channel not built yet *)
+ if System.file_exists wi.file then begin
+ (* Build it and go *)
+ let c = System.open_in_bin wi.file in
+ wi.ch <- Some c;
+ readAvailableLinesFromWatcher wi;
+ end else begin
+ (* Wait for change file to be built *)
+ debug (fun() -> Util.msg
+ "Waiting for change file %s\n"
+ (System.fspathToPrintString wi.file))
+ end
+ else
+ (* Watcher running and channel built: go ahead and read *)
+ readAvailableLinesFromWatcher wi
+
+let getChanges archHash =
+ let wi = RootMap.find archHash !watchers in
+ readChanges wi;
+ let res = wi.lines in
+ wi.lines <- [];
+ List.map Path.fromString (trim_duplicates res)
+
+let start archHash fspath =
+ if not (Prefs.read useWatcher) then
+ false
+ else if not (RootMap.mem archHash !watchers) then begin
+ (* Watcher process not running *)
+ match watchercmd archHash (Fspath.toString fspath) with
+ Some (changefile,cmd) ->
+ debug (fun() -> Util.msg
+ "Starting watcher on fspath %s\n"
+ (Fspath.toDebugString fspath));
+ let _ = System.open_process_out cmd in
+ let wi = {file = changefile; ch = None;
+ lines = []; chars = Buffer.create 80} in
+ watchers := RootMap.add archHash wi !watchers;
+ true
+ | None ->
+ false
+ end else begin
+ (* If already running, discard all pending changes *)
+ ignore (getChanges archHash);
+ true
+ end
+
+let wait archHash =
+ if not (RootMap.mem archHash !watchers) then
+ raise (Util.Fatal "No file monitoring helper program found")
+ else begin
+ let wi = RootMap.find archHash !watchers in
+ let rec loop () =
+ readChanges wi;
+ if wi.lines = [] then begin
+ debug (fun() -> Util.msg "Sleeping for %d seconds...\n" watchinterval);
+ Lwt.bind (Lwt_unix.sleep (float watchinterval)) (fun () ->
+ loop ())
+ end else
+ Lwt.return ()
+ in
+ loop ()
+ end
Added: trunk/src/fswatchold.mli
===================================================================
--- trunk/src/fswatchold.mli (rev 0)
+++ trunk/src/fswatchold.mli 2012-08-09 14:06:21 UTC (rev 504)
@@ -0,0 +1,4 @@
+
+val start : string -> Fspath.t -> bool
+val getChanges : string -> Path.t list
+val wait : string -> unit Lwt.t
Modified: trunk/src/mkProjectInfo.ml
===================================================================
--- trunk/src/mkProjectInfo.ml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/mkProjectInfo.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -5,8 +5,8 @@
let projectName = "unison"
let majorVersion = 2
-let minorVersion = 45
-let pointVersionOrigin = 487 (* Revision that corresponds to point version 0 *)
+let minorVersion = 46
+let pointVersionOrigin = 504 (* Revision that corresponds to point version 0 *)
(* Documentation:
This is a program to construct a version of the form Major.Minor.Point,
@@ -78,3 +78,4 @@
+
Modified: trunk/src/os.ml
===================================================================
--- trunk/src/os.ml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/os.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -50,6 +50,10 @@
if s = "" then tempFileSuffixFixed
else "." ^ s ^ tempFileSuffixFixed
+let isTempFile file =
+ Util.endswith file tempFileSuffixFixed &&
+ Util.startswith file tempFilePrefix
+
(*****************************************************************************)
(* QUERYING THE FILESYSTEM *)
(*****************************************************************************)
@@ -124,10 +128,7 @@
(* removeBackupIfUnwanted fspath newPath; *)
(* false *)
(* end *)
- else if
- Util.endswith file tempFileSuffixFixed &&
- Util.startswith file tempFilePrefix
- then begin
+ else if isTempFile file then begin
if Util.endswith file !tempFileSuffix then begin
let p = Path.child path filename in
let i = Fileinfo.get false fspath p in
Modified: trunk/src/os.mli
===================================================================
--- trunk/src/os.mli 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/os.mli 2012-08-09 14:06:21 UTC (rev 504)
@@ -5,6 +5,7 @@
val tempPath : ?fresh:bool -> Fspath.t -> Path.local -> Path.local
val tempFilePrefix : string
+val isTempFile : string -> bool
val includeInTempNames : string -> unit
val exists : Fspath.t -> Path.local -> bool
Modified: trunk/src/test.ml
===================================================================
--- trunk/src/test.ml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/test.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -214,7 +214,7 @@
let sync ?(verbose=false) () =
let (reconItemList, _, _) =
- Recon.reconcileAll (Update.findUpdates()) in
+ Recon.reconcileAll (Update.findUpdates None) in
if verbose then begin
Util.msg "Sync result:\n";
displayRis reconItemList
Modified: trunk/src/uigtk2.ml
===================================================================
--- trunk/src/uigtk2.ml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/uigtk2.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -125,6 +125,7 @@
mutable bytesToTransfer : Uutil.Filesize.t;
mutable whatHappened : (Util.confirmation * string option) option}
let theState = ref [||]
+let unsynchronizedPaths = ref None
module IntSet = Set.Make (struct type t = int let compare = compare end)
@@ -3368,7 +3369,7 @@
let findUpdates () =
let t = Trace.startTimer "Checking for updates" in
Trace.status "Looking for changes";
- let updates = Update.findUpdates () in
+ let updates = Update.findUpdates ~wantWatcher:() !unsynchronizedPaths in
Trace.showTimer t;
updates in
let reconcile updates =
@@ -3396,6 +3397,8 @@
bytesToTransfer = Uutil.Filesize.zero;
whatHappened = None })
reconItemList);
+ unsynchronizedPaths :=
+ Some (List.map (fun ri -> ri.path1) reconItemList, []);
current := IntSet.empty;
displayMain();
progressBarPulse := false; sync_action := None; displayGlobalProgress 0.;
@@ -3645,6 +3648,10 @@
if skippedCount = 0 then [] else
[Printf.sprintf "%d skipped" skippedCount]
in
+ unsynchronizedPaths :=
+ Some (List.map (fun (si, _, _) -> si.ri.path1)
+ (failureList @ partialList @ skippedList),
+ []);
Trace.status
(Printf.sprintf "Synchronization complete %s"
(String.concat ", " (failures @ partials @ skipped)));
@@ -3891,6 +3898,7 @@
let loadProfile p reload =
debug (fun()-> Util.msg "Loading profile %s..." p);
Trace.status "Loading profile";
+ unsynchronizedPaths := None;
Uicommon.initPrefs p
(fun () -> if not reload then displayWaitMessage ())
getFirstRoot getSecondRoot termInteract;
@@ -4123,9 +4131,13 @@
let confirmBigDeletes = Prefs.read Globals.confirmBigDeletes in
Prefs.set Globals.paths failedpaths;
Prefs.set Globals.confirmBigDeletes false;
+ (* Modifying global paths does not play well with filesystem
+ monitoring, so we disable it. *)
+ unsynchronizedPaths := None;
detectCmd();
Prefs.set Globals.paths paths;
- Prefs.set Globals.confirmBigDeletes confirmBigDeletes)
+ Prefs.set Globals.confirmBigDeletes confirmBigDeletes;
+ unsynchronizedPaths := None)
"Re_check Unsynchronized Items");
ignore (fileMenu#add_separator ());
Modified: trunk/src/uimacbridge.ml
===================================================================
--- trunk/src/uimacbridge.ml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/uimacbridge.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -17,6 +17,7 @@
mutable whatHappened : Util.confirmation option;
mutable statusMessage : string option };;
let theState = ref [| |];;
+let unsynchronizedPaths = ref None;;
let unisonDirectory() = System.fspathToPrintString Os.unisonDir
;;
@@ -126,6 +127,7 @@
(* Load the profile and command-line arguments *)
(* Restore prefs to their default values, if necessary *)
if not !firstTime then Prefs.resetToDefaults();
+ unsynchronizedPaths := None;
(* Tell the preferences module the name of the profile *)
Prefs.profileName := Some(profileName);
@@ -232,7 +234,7 @@
let t = Trace.startTimer "Checking for updates" in
let findUpdates () =
Trace.status "Looking for changes";
- let updates = Update.findUpdates () in
+ let updates = Update.findUpdates ~wantWatcher:() !unsynchronizedPaths in
Trace.showTimer t;
updates in
let reconcile updates = Recon.reconcileAll updates in
@@ -252,6 +254,8 @@
whatHappened = None; statusMessage = None })
reconItemList in
theState := Array.of_list stateItemList;
+ unsynchronizedPaths :=
+ Some (List.map (fun ri -> ri.path1) reconItemList, []);
if dangerousPaths <> [] then begin
Prefs.set Globals.batch false;
Util.warn (Uicommon.dangerousPathMsg dangerousPaths)
@@ -388,25 +392,72 @@
Update.commitUpdates();
Trace.showTimer t;
+ let failureList =
+ Array.fold_right
+ (fun si l ->
+ match si.whatHappened with
+ Some (Util.Failed err) ->
+ (si, [err], "transport failure") :: l
+ | _ ->
+ l)
+ !theState []
+ in
+ let failureCount = List.length failureList in
let failures =
- let count =
- Array.fold_left
- (fun l si ->
- l + (match si.whatHappened with Some(Util.Failed(_)) -> 1 | _ -> 0))
- 0 !theState in
- if count = 0 then "" else
- Printf.sprintf "%d failure%s" count (if count=1 then "" else "s") in
+ if failureCount = 0 then [] else
+ [Printf.sprintf "%d failure%s"
+ failureCount (if failureCount = 1 then "" else "s")]
+ in
+ let partialList =
+ Array.fold_right
+ (fun si l ->
+ match si.whatHappened with
+ Some Util.Succeeded
+ when partiallyProblematic si.ri &&
+ not (problematic si.ri) ->
+ let errs =
+ match si.ri.replicas with
+ Different diff -> diff.errors1 @ diff.errors2
+ | _ -> assert false
+ in
+ (si, errs,
+ "partial transfer (errors during update detection)") :: l
+ | _ ->
+ l)
+ !theState []
+ in
+ let partialCount = List.length partialList in
+ let partials =
+ if partialCount = 0 then [] else
+ [Printf.sprintf "%d partially transferred" partialCount]
+ in
+ let skippedList =
+ Array.fold_right
+ (fun si l ->
+ match si.ri.replicas with
+ Problem err ->
+ (si, [err], "error during update detection") :: l
+ | Different diff when diff.direction = Conflict ->
+ (si, [],
+ if diff.default_direction = Conflict then
+ "conflict"
+ else "skipped") :: l
+ | _ ->
+ l)
+ !theState []
+ in
+ let skippedCount = List.length skippedList in
let skipped =
- let count =
- Array.fold_left
- (fun l si ->
- l + (if problematic si.ri then 1 else 0))
- 0 !theState in
- if count = 0 then "" else
- Printf.sprintf "%d skipped" count in
+ if skippedCount = 0 then [] else
+ [Printf.sprintf "%d skipped" skippedCount]
+ in
+ unsynchronizedPaths :=
+ Some (List.map (fun (si, _, _) -> si.ri.path1)
+ (failureList @ partialList @ skippedList),
+ []);
Trace.status
- (Printf.sprintf "Synchronization complete %s%s%s"
- failures (if failures=""||skipped="" then "" else ", ") skipped);
+ (Printf.sprintf "Synchronization complete %s"
+ (String.concat ", " (failures @ partials @ skipped)));
end;;
Callback.register "unisonSynchronize" unisonSynchronize;;
Modified: trunk/src/uimacbridgenew.ml
===================================================================
--- trunk/src/uimacbridgenew.ml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/uimacbridgenew.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -18,6 +18,7 @@
mutable whatHappened : Util.confirmation option;
mutable statusMessage : string option };;
let theState = ref [| |];;
+let unsynchronizedPaths = ref None;;
let unisonDirectory() = System.fspathToString Os.unisonDir
;;
@@ -230,6 +231,7 @@
(* Load the profile and command-line arguments *)
(* Restore prefs to their default values, if necessary *)
if not !firstTime then Prefs.resetToDefaults();
+ unsynchronizedPaths := None;
if profileName <> "" then begin
(* Tell the preferences module the name of the profile *)
@@ -356,7 +358,7 @@
let t = Trace.startTimer "Checking for updates" in
let findUpdates () =
Trace.status "Looking for changes";
- let updates = Update.findUpdates () in
+ let updates = Update.findUpdates ~wantWatcher:() !unsynchronizedPaths in
Trace.showTimer t;
updates in
let reconcile updates = Recon.reconcileAll updates in
@@ -381,6 +383,8 @@
whatHappened = None; statusMessage = None })
reconItemList in
theState := Array.of_list stateItemList;
+ unsynchronizedPaths :=
+ Some (List.map (fun ri -> ri.path1) reconItemList, []);
if dangerousPaths <> [] then begin
Prefs.set Globals.batch false;
Util.warn (Uicommon.dangerousPathMsg dangerousPaths)
@@ -615,36 +619,69 @@
Trace.showTimer t;
commitUpdates ();
+ let failureList =
+ Array.fold_right
+ (fun si l ->
+ match si.whatHappened with
+ Some (Util.Failed err) ->
+ (si, [err], "transport failure") :: l
+ | _ ->
+ l)
+ !theState []
+ in
+ let failureCount = List.length failureList in
let failures =
- let count =
- Array.fold_left
- (fun l si ->
- l + (match si.whatHappened with Some(Util.Failed(_)) -> 1 | _ -> 0))
- 0 !theState in
- if count = 0 then [] else
- [Printf.sprintf "%d failure%s" count (if count=1 then "" else "s")] in
+ if failureCount = 0 then [] else
+ [Printf.sprintf "%d failure%s"
+ failureCount (if failureCount = 1 then "" else "s")]
+ in
+ let partialList =
+ Array.fold_right
+ (fun si l ->
+ match si.whatHappened with
+ Some Util.Succeeded
+ when partiallyProblematic si.ri &&
+ not (problematic si.ri) ->
+ let errs =
+ match si.ri.replicas with
+ Different diff -> diff.errors1 @ diff.errors2
+ | _ -> assert false
+ in
+ (si, errs,
+ "partial transfer (errors during update detection)") :: l
+ | _ ->
+ l)
+ !theState []
+ in
+ let partialCount = List.length partialList in
let partials =
- let count =
- Array.fold_left
- (fun l si ->
- l + match si.whatHappened with
- Some Util.Succeeded
- when partiallyProblematic si.ri &&
- not (problematic si.ri) ->
- 1
- | _ ->
- 0)
- 0 !theState in
- if count = 0 then [] else
- [Printf.sprintf "%d partially transferred" count] in
+ if partialCount = 0 then [] else
+ [Printf.sprintf "%d partially transferred" partialCount]
+ in
+ let skippedList =
+ Array.fold_right
+ (fun si l ->
+ match si.ri.replicas with
+ Problem err ->
+ (si, [err], "error during update detection") :: l
+ | Different diff when diff.direction = Conflict ->
+ (si, [],
+ if diff.default_direction = Conflict then
+ "conflict"
+ else "skipped") :: l
+ | _ ->
+ l)
+ !theState []
+ in
+ let skippedCount = List.length skippedList in
let skipped =
- let count =
- Array.fold_left
- (fun l si ->
- l + (if problematic si.ri then 1 else 0))
- 0 !theState in
- if count = 0 then [] else
- [Printf.sprintf "%d skipped" count] in
+ if skippedCount = 0 then [] else
+ [Printf.sprintf "%d skipped" skippedCount]
+ in
+ unsynchronizedPaths :=
+ Some (List.map (fun (si, _, _) -> si.ri.path1)
+ (failureList @ partialList @ skippedList),
+ []);
Trace.status
(Printf.sprintf "Synchronization complete %s"
(String.concat ", " (failures @ partials @ skipped)));
Modified: trunk/src/uitext.ml
===================================================================
--- trunk/src/uitext.ml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/uitext.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -654,7 +654,7 @@
end
end
-let synchronizeOnce () =
+let synchronizeOnce ?wantWatcher ?skipRecentFiles pathsOpt =
let showStatus path =
if path = "" then Util.set_infos "" else
let max_len = 70 in
@@ -675,7 +675,7 @@
debug (fun() -> Util.msg "temp: Globals.paths = %s\n"
(String.concat " "
(Safelist.map Path.toString (Prefs.read Globals.paths))));
- let updates = Update.findUpdates() in
+ let updates = Update.findUpdates ?wantWatcher pathsOpt in
Uutil.setUpdateStatusPrinter None;
Util.set_infos "";
@@ -698,192 +698,79 @@
(exitStatus, failedPaths)
end
-let originalValueOfPathsPreference = ref []
-
(* ----------------- Filesystem watching mode ---------------- *)
-(* FIX: we should check that the child process has not died and
- restart it if so... *)
+let watchinterval = 1. (* Minimal interval between two synchronizations *)
+let retrydelay = 5. (* Minimal delay to retry failed paths *)
+let maxdelay = 30. *. 60. (* Maximal delay to retry failed paths *)
-(* FIX: the names of the paths being watched should get included
- in the name of the watcher's state file *)
+module PathMap = Map.Make (Path)
-let watchinterval = 5
-
-let watcherTemp r n =
- let s = n ^ (Update.archiveHash (Fspath.canonize (Some r))) in
- Os.fileInUnisonDir s
-
-let watchercmd r =
- (* FIX: is the quoting of --follow parameters going to work on Win32?
- (2/2012: tried adding Uutil.quotes -- maybe this is OK now?) *)
- (* FIX -- need to find the program using watcherosx preference *)
- let root = Fspath.toString (snd r) in
- let changefile = watcherTemp root "changes" in
- let statefile = watcherTemp root "state" in
- let paths = Safelist.map Path.toString !originalValueOfPathsPreference in
- let followpaths = Pred.extern Path.followPred in
- let follow = Safelist.map
- (fun s -> "--follow '" ^ Uutil.quotes s ^ "'")
- followpaths in
-(* BCP (per Josh Berdine, 5/2012): changed startup command from this...
- let cmd = Printf.sprintf "fsmonitor.py %s --outfile %s --statefile %s %s %s\n"
- ... to this: *)
- let fsmonfile = Filename.concat (Filename.dirname Sys.executable_name) "fsmonitor.py" in
- let cmd = Printf.sprintf "python \"%s\" \"%s\" --outfile \"%s\" --statefile \"%s\" %s %s\n"
- fsmonfile
- root
- (System.fspathToPrintString changefile)
- (System.fspathToPrintString statefile)
- (String.concat " " follow)
- (String.concat " " paths) in
- debug (fun() -> Util.msg "watchercmd = %s\n" cmd);
- (changefile,cmd)
-
-module RootMap = Map.Make (struct type t = Common.root
- let compare = Pervasives.compare
- end)
-(* Using string concatenation to accumulate characters is
- a bit inefficient, but it's not clear how much it matters in the
- grand scheme of things. Current experience suggests that this
- implementation performs well enough. *)
-type watcherinfo = {file: System.fspath;
- ch:Pervasives.in_channel option ref;
- chars: string ref;
- lines: string list ref}
-let watchers : watcherinfo RootMap.t ref = ref RootMap.empty
-
-let trim_duplicates l =
- let rec loop l = match l with
- [] -> l
- | [s] -> l
- | s1::s2::rest ->
- if Util.startswith s1 s2 || Util.startswith s2 s1 then
- loop (s2::rest)
- else
- s1 :: (loop (s2::rest)) in
- loop (Safelist.sort String.compare l)
-
-let getAvailableLinesFromWatcher wi =
- let ch = match !(wi.ch) with Some(c) -> c | None -> assert false in
- let rec loop () =
- match try Some(input_char ch) with End_of_file -> None with
- None ->
- let res = !(wi.lines) in
- wi.lines := [];
- trim_duplicates res
- | Some(c) ->
- if c = '\n' then begin
- wi.lines := !(wi.chars) :: !(wi.lines);
- wi.chars := "";
- loop ()
- end else begin
- wi.chars := (!(wi.chars)) ^ (String.make 1 c);
- loop ()
- end in
- loop ()
-
-let suckOnWatcherFileLocal r =
- Util.convertUnixErrorsToFatal
- "Reading changes from watcher process "
- (fun () ->
- (* Make sure there's a watcher running *)
- try
- let wi = RootMap.find r !watchers in
- if !(wi.ch) = None then
- (* Watcher channel not built yet *)
- if System.file_exists wi.file then begin
- (* Build it and go *)
- let c = System.open_in_bin wi.file in
- wi.ch := Some(c);
- getAvailableLinesFromWatcher wi
- end else begin
- (* Wait for change file to be built *)
- debug (fun() -> Util.msg
- "Waiting for change file %s\n"
- (System.fspathToPrintString wi.file));
- []
- end
- else begin
- (* Watcher running and channel built: go ahead and read *)
- getAvailableLinesFromWatcher wi
- end
- with Not_found -> begin
- (* Watcher process not running *)
- let (changefile,cmd) = watchercmd r in
- debug (fun() -> Util.msg
- "Starting watcher on root %s\n" (Common.root2string r));
- let _ = System.open_process_out cmd in
- let wi = {file = changefile; ch = ref None;
- lines = ref []; chars = ref ""} in
- watchers := RootMap.add r wi !watchers;
- []
- end)
-
-let suckOnWatcherFileRoot: Common.root -> Common.root -> (string list) Lwt.t =
+let waitForChangesRoot: Common.root -> unit -> unit Lwt.t =
Remote.registerRootCmd
- "suckOnWatcherFile"
- (fun (fspath, r) ->
- Lwt.return (suckOnWatcherFileLocal r))
+ "waitForChanges"
+ (fun (fspath, _) -> Fswatchold.wait (Update.archiveHash fspath))
-let suckOnWatcherFiles () =
- Safelist.concat
- (Lwt_unix.run (
- Globals.allRootsMap (fun r -> suckOnWatcherFileRoot r r)))
+let waitForChanges t =
+ let dt = t -. Unix.gettimeofday () in
+ if dt > 0. then begin
+ let timeout = if dt <= maxdelay then [Lwt_unix.sleep dt] else [] in
+ Lwt_unix.run
+ (Globals.allRootsMap (fun r -> Lwt.return (waitForChangesRoot r ()))
+ >>= fun l ->
+ Lwt.choose (timeout @ l))
+ end
-let shouldNotIgnore p =
- let rec test prefix rest =
- if Globals.shouldIgnore prefix then
- false
- else match (Path.deconstruct rest) with
- None -> true
- | Some(n,rest') ->
- test (Path.child prefix n) rest'
- in
- test Path.empty (Path.fromString p)
-
let synchronizePathsFromFilesystemWatcher () =
- (* Make sure the confirmbigdeletes preference is turned off. If it's on,
- then all deletions will fail because every deletion will count as
- a "big deletion"! *)
- Prefs.set Globals.confirmBigDeletes false;
+ let rec loop isStart delayInfo =
+ let t = Unix.gettimeofday () in
+ let (delayedPaths, readyPaths) =
+ PathMap.fold
+ (fun p (t', _) (delayed, ready) ->
+ if t' <= t then (delayed, p :: ready) else (p :: delayed, ready))
+ delayInfo ([], [])
+ in
+ let (exitStatus, failedPaths) =
+ synchronizeOnce ~wantWatcher:() ~skipRecentFiles:()
+ (if isStart then None else Some (readyPaths, delayedPaths))
+ in
+ (* After a failure, we retry at once, then use an exponential backoff *)
+ let delayInfo =
+ Safelist.fold_left
+ (fun newDelayInfo p ->
+ PathMap.add p
+ (try
+ let (t', d) = PathMap.find p delayInfo in
+ if t' > t then (t', d) else
+ let d = max retrydelay (min maxdelay (2. *. d)) in
+ (t +. d, d)
+ with Not_found ->
+ (t, 0.))
+ newDelayInfo)
+ PathMap.empty
+ (Safelist.append delayedPaths failedPaths)
+ in
+ Lwt_unix.run (Lwt_unix.sleep watchinterval);
+ let nextTime =
+ PathMap.fold (fun _ (t, d) t' -> min t t') delayInfo 1e20 in
+ waitForChanges nextTime;
+ loop false delayInfo
+ in
+ loop true PathMap.empty
- let rec loop failedPaths =
- let newpathsraw = suckOnWatcherFiles () in
- debug (fun () -> Util.msg
- "Changed paths: %s\n" (String.concat " " newpathsraw));
- let newpaths = Safelist.filter shouldNotIgnore newpathsraw in
- if newpaths <> [] then
- display (Printf.sprintf "Changed paths: %s%s\n"
- (if newpaths=[] then "" else "\n ")
- (String.concat "\n " newpaths));
- let p = failedPaths @ (Safelist.map Path.fromString newpaths) in
- if p <> [] then begin
- Prefs.set Globals.paths p;
- let (exitStatus,newFailedPaths) = synchronizeOnce() in
- debug (fun() -> Util.msg "Sleeping for %d seconds...\n" watchinterval);
- Unix.sleep watchinterval;
- loop newFailedPaths
- end else begin
- debug (fun() -> Util.msg "Nothing changed: sleeping for %d seconds...\n"
- watchinterval);
- Unix.sleep watchinterval;
- loop []
- end in
- loop []
-
(* ----------------- Repetition ---------------- *)
-let synchronizeUntilNoFailures () =
- let rec loop triesLeft =
- let (exitStatus,failedPaths) = synchronizeOnce() in
+let synchronizeUntilNoFailures repeatMode =
+ let rec loop triesLeft pathsOpt =
+ let (exitStatus, failedPaths) =
+ synchronizeOnce
+ ?wantWatcher:(if repeatMode then Some () else None) pathsOpt in
if failedPaths <> [] && triesLeft <> 0 then begin
- loop (triesLeft - 1)
+ loop (triesLeft - 1) (Some (failedPaths, []))
end else begin
- Prefs.set Globals.paths !originalValueOfPathsPreference;
exitStatus
end in
- loop (Prefs.read Uicommon.retry)
+ loop (Prefs.read Uicommon.retry) None
let rec synchronizeUntilDone () =
let repeatinterval =
@@ -898,7 +785,7 @@
^Prefs.read Uicommon.repeat
^") should be either a number or 'watch'\n")) in
- let exitStatus = synchronizeUntilNoFailures() in
+ let exitStatus = synchronizeUntilNoFailures(repeatinterval >= 0) in
if repeatinterval < 0 then
exitStatus
else begin
@@ -958,10 +845,6 @@
setWarnPrinter();
Trace.statusFormatter := formatStatus;
- (* Save away the user's path preferences in case they are needed for
- restarting/repeating *)
- originalValueOfPathsPreference := Prefs.read Globals.paths;
-
let exitStatus = synchronizeUntilDone() in
(* Put the terminal back in "sane" mode, if necessary, and quit. *)
Modified: trunk/src/update.ml
===================================================================
--- trunk/src/update.ml 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/update.ml 2012-08-09 14:06:21 UTC (rev 504)
@@ -1074,7 +1074,66 @@
(Os.myCanonicalHostName ()))))
(Prefs.read mountpoints)
+(***********************************************************************
+ Set of paths
+************************************************************************)
+type pathTree = PathTreeLeaf
+ | PathTreeNode of pathTree NameMap.t
+
+let rec addPathToTree path tree =
+ match Path.deconstruct path, tree with
+ None, _ | _, Some PathTreeLeaf ->
+ PathTreeLeaf
+ | Some (nm, p), None ->
+ PathTreeNode (NameMap.add nm (addPathToTree p None) NameMap.empty)
+ | Some (nm, p), Some (PathTreeNode children) ->
+ let t = try Some (NameMap.find nm children) with Not_found -> None in
+ PathTreeNode (NameMap.add nm (addPathToTree p t) children)
+
+let rec removePathFromTree path tree =
+ match Path.deconstruct path, tree with
+ None, _ ->
+ None
+ | Some (nm, p), PathTreeLeaf ->
+ Some tree
+ | Some (nm, p), PathTreeNode children ->
+ try
+ let t = NameMap.find nm children in
+ match removePathFromTree p t with
+ None ->
+ let newChildren = NameMap.remove nm children in
+ if NameMap.is_empty children then None else
+ Some (PathTreeNode newChildren)
+ | Some t ->
+ Some (PathTreeNode (NameMap.add nm t children))
+ with Not_found ->
+ Some tree
+
+let pathTreeOfList l =
+ Safelist.fold_left (fun t p -> Some (addPathToTree p t)) None l
+
+let removePathsFromTree l treeOpt =
+ Safelist.fold_left
+ (fun t p ->
+ match t with
+ None -> None
+ | Some t -> removePathFromTree p t)
+ treeOpt l
+
+let rec getSubTree path tree =
+ match Path.deconstruct path, tree with
+ None, _ ->
+ Some tree
+ | Some (nm, p), PathTreeLeaf ->
+ Some PathTreeLeaf
+ | Some (nm, p), PathTreeNode children ->
+ try
+ let t = NameMap.find nm children in
+ getSubTree p t
+ with Not_found ->
+ None
+
(***********************************************************************
UPDATE DETECTION
************************************************************************)
@@ -1126,6 +1185,7 @@
{ fastCheck : bool;
dirFastCheck : bool;
dirStamp : Props.dirChangedStamp;
+ archHash : string;
showStatus : bool }
(** Status display **)
@@ -1423,9 +1483,11 @@
let path' = Path.child path nm in
debugverbose (fun () -> Util.msg
"buildUpdateChildren(handleChild): %s\n" (Path.toString path'));
- (* BCP 6/10: Added check for ignored path, but I'm not completely
- sure this is the right place for it: *)
if Globals.shouldIgnore path' then begin
+ (* We have to ignore paths which are in the archive but no
+ longer exists in the filesystem. Note that we cannot
+ reach this point for files that exists on the filesystem
+ ([hasIgnoredChildren] below would have been true). *)
debugignore (fun()->Util.msg "buildUpdateChildren: ignoring path %s\n"
(Path.toString path'));
archive
@@ -1628,6 +1690,98 @@
with
Util.Transient(s) -> None, Error(s)
+(* Compute the updates for the tree of paths [tree] against archive. *)
+let rec buildUpdatePathTree archive fspath here tree scanInfo =
+ match tree, archive with
+ PathTreeNode children, ArchiveDir (archDesc, archChildren) ->
+ let curChildren =
+ lazy (List.fold_left (fun m (nm, st) -> NameMap.add nm st m)
+ NameMap.empty (getChildren fspath here))
+ in
+ let updates = ref [] in
+ let archUpdated = ref false in
+ let newChi = ref archChildren in
+ let handleChild nm archive status tree' =
+ let path' = Path.child here nm in
+ if Os.isTempFile (Name.toString nm) || Globals.shouldIgnore path' then
+ archive
+ else begin
+ match status with
+ `Ok | `Abs ->
+ let (arch,uiChild) =
+ buildUpdatePathTree archive fspath path' tree' scanInfo in
+ if uiChild <> NoUpdates then
+ updates := (nm, uiChild) :: !updates;
+ begin match arch with
+ None -> archive
+ | Some arch -> archUpdated := true; arch
+ end
+ | `Dup ->
+ let uiChild =
+ Error
+ ("Two or more files on a case-sensitive system have names \
+ identical except for case. They cannot be synchronized \
+ to a case-insensitive file system. (File '" ^
+ Path.toString path' ^ "')")
+ in
+ updates := (nm, uiChild) :: !updates;
+ archive
+ | `BadEnc ->
+ let uiChild =
+ Error ("The file name is not encoded in Unicode. (File '"
+ ^ Path.toString path' ^ "')")
+ in
+ updates := (nm, uiChild) :: !updates;
+ archive
+ | `BadName ->
+ let uiChild =
+ Error
+ ("The name of this Unix file is not allowed under Windows. \
+ (File '" ^ Path.toString path' ^ "')")
+ in
+ updates := (nm, uiChild) :: !updates;
+ archive
+ end
+ in
+ NameMap.iter
+ (fun nm tree' ->
+ let inArchive = NameMap.mem nm archChildren in
+ let arch =
+ if tree' = PathTreeLeaf || not inArchive then begin
+ let (nm', st) =
+ try
+ NameMap.findi nm (Lazy.force curChildren)
+ with Not_found -> try
+ (fst (NameMap.findi nm archChildren), `Abs)
+ with Not_found ->
+ (nm, `Abs)
+ in
+ let arch =
+ try NameMap.find nm archChildren with Not_found -> NoArchive
+ in
+ handleChild nm' arch st tree'
+ end else begin
+ let (nm', arch) = NameMap.findi nm archChildren in
+ handleChild nm' arch `Ok tree'
+ end
+ in
+ if inArchive then newChi := NameMap.add nm arch !newChi)
+ children;
+ (begin if !archUpdated then
+ Some (ArchiveDir (archDesc, !newChi))
+ else
+ None
+ end,
+ if !updates <> [] then
+ (* The Recon module relies on the updates to be sorted *)
+ Updates (Dir (archDesc, Safelist.rev !updates, PropsSame, false),
+ oldInfoOf archive)
+ else
+ NoUpdates)
+ | _ ->
+ showStatus scanInfo here;
+ buildUpdateRec archive fspath here scanInfo
+
(* Compute the updates for [path] against archive. Also returns an
archive, which is the old archive with time stamps updated
appropriately (i.e., for those files whose contents remain
@@ -1635,12 +1789,11 @@
contents. The directory permissions along the path are also
collected, in case we need to build the directory hierarchy
on one side. *)
-let rec buildUpdate archive fspath fullpath here path dirStamp scanInfo =
+let rec buildUpdate archive fspath fullpath here path pathTree scanInfo =
match Path.deconstruct path with
None ->
- showStatus scanInfo here;
let (arch, ui) =
- buildUpdateRec archive fspath here scanInfo in
+ buildUpdatePathTree archive fspath here pathTree scanInfo in
(begin match arch with
None -> archive
| Some arch -> arch
@@ -1707,8 +1860,8 @@
let otherChildren = NameMap.remove name children in
let (arch, updates, localPath, props) =
buildUpdate
- archChild fspath fullpath (Path.child here name') path'
- dirStamp scanInfo
+ archChild fspath fullpath (Path.child here name')
+ path' pathTree scanInfo
in
let children =
if arch = NoArchive then otherChildren else
@@ -1720,8 +1873,8 @@
| _ ->
let (arch, updates, localPath, props) =
buildUpdate
- NoArchive fspath fullpath (Path.child here name') path'
- dirStamp scanInfo
+ NoArchive fspath fullpath (Path.child here name')
+ path' pathTree scanInfo
in
assert (arch = NoArchive);
(archive, updates, localPath,
@@ -1766,10 +1919,16 @@
(Proplist.add rsrcKey newRsrc props)));
stamp
+(* This contains the list of synchronized paths and the directory stamps
+ used by the previous update detection, when a watcher process is used.
+ This make it possible to know when the state of the watcher process
+ needs to be reset. *)
+let previousFindOptions = Hashtbl.create 7
+
(* for the given path, find the archive and compute the list of update
items; as a side effect, update the local archive w.r.t. time-stamps for
unchanged files *)
-let findLocal fspath pathList:
+let findLocal wantWatcher fspath pathList subpaths :
(Path.local * Common.updateItem * Props.t list) list =
debug (fun() -> Util.msg
"findLocal %s (%s)\n" (Fspath.toDebugString fspath)
@@ -1793,24 +1952,79 @@
as Windows does not update directory modification times
on FAT filesystems. *)
dirFastCheck = useFastChecking () && Util.osType = `Unix;
- dirStamp = dirStamp;
+ dirStamp = dirStamp; archHash = archiveHash fspath;
showStatus = not !Trace.runningasserver }
in
let (cacheFilename, _) = archiveName fspath FPCache in
let cacheFile = Os.fileInUnisonDir cacheFilename in
Fpcache.init scanInfo.fastCheck (Prefs.read ignoreArchives) cacheFile;
+ let unchangedOptions =
+ try
+ Hashtbl.find previousFindOptions scanInfo.archHash
+ = (scanInfo.dirStamp, pathList)
+ with Not_found ->
+ false
+ in
+ let paths =
+ match subpaths with
+ Some (unsynchronizedPaths, blacklistedPaths) when unchangedOptions ->
+ let (>>) x f = f x in
+ let paths =
+ Fswatchold.getChanges scanInfo.archHash
+ (* We do not really need to filter here (they are filtered also
+ by [buildUpdatePathTree], but that might reduce greatly and
+ cheaply number of paths to consider... *)
+ >> List.filter (fun path -> not (Globals.shouldIgnore path))
+ in
+ let filterPaths paths subpaths =
+ let number_list l =
+ let i = ref (-1) in
+ Safelist.map (fun x -> incr i; (!i, x)) l
+ in
+ paths >> (* We number paths, to be able to recover their
+ initial order. *)
+ number_list
+ >> (* We put longest paths first, in order to deal
+ correctly with nested paths (tough that might be
+ overkill...) *)
+ List.sort (fun (_, p1) (_, p2) -> Path.compare p2 p1)
+ >> (* We extract the set of changed paths included in
+ each synchronized path *)
+ List.fold_left
+ (fun (l, tree) (i, p) ->
+ match tree with
+ None ->
+ ((i, (p, None)) :: l, None)
+ | Some tree ->
+ ((i, (p, getSubTree p tree)) :: l,
+ removePathFromTree p tree))
+ ([], pathTreeOfList subpaths)
+ >> fst
+ >> (* Finally, we restaure the initial order *)
+ List.sort (fun (i1, _) (i2, _) -> compare i1 i2)
+ >> List.map snd
+ in
+ filterPaths pathList (Safelist.append unsynchronizedPaths paths)
+ | _ ->
+ if wantWatcher && Fswatchold.start scanInfo.archHash fspath then
+ Hashtbl.replace previousFindOptions
+ scanInfo.archHash (scanInfo.dirStamp, pathList)
+ else
+ Hashtbl.remove previousFindOptions scanInfo.archHash;
+ Safelist.map (fun p -> (p, Some PathTreeLeaf)) pathList
+ in
let (archive, updates) =
Safelist.fold_right
- (fun path (arch, upd) ->
- if Globals.shouldIgnore path then
- (arch, (translatePathLocal fspath path, NoUpdates, []) :: upd)
- else
- let (arch', ui, localPath, props) =
- buildUpdate
- arch fspath path Path.empty path dirStamp scanInfo
- in
- arch', (localPath, ui, props) :: upd)
- pathList (archive, [])
+ (fun (path, pathTreeOpt) (arch, upd) ->
+ match pathTreeOpt with
+ Some pathTree when not (Globals.shouldIgnore path) ->
+ let (arch', ui, localPath, props) =
+ buildUpdate arch fspath path Path.empty path pathTree scanInfo
+ in
+ (arch', (localPath, ui, props) :: upd)
+ | _ ->
+ (arch, (translatePathLocal fspath path, NoUpdates, []) :: upd))
+ paths (archive, [])
in
Fpcache.finish ();
(*
@@ -1824,10 +2038,10 @@
let findOnRoot =
Remote.registerRootCmd
"find"
- (fun (fspath, pathList) ->
- Lwt.return (findLocal fspath pathList))
+ (fun (fspath, (wantWatcher, pathList, subpaths)) ->
+ Lwt.return (findLocal wantWatcher fspath pathList subpaths))
-let findUpdatesOnPaths pathList =
+let findUpdatesOnPaths ?wantWatcher pathList subpaths =
Lwt_unix.run
(loadArchives true >>= (fun (ok, checksums) ->
begin if ok then Lwt.return checksums else begin
@@ -1850,7 +2064,7 @@
let t = Trace.startTimer "Collecting changes" in
Globals.allRootsMapWithWaitingAction (fun r ->
debug (fun() -> Util.msg "findOnRoot %s\n" (root2string r));
- findOnRoot r pathList)
+ findOnRoot r (wantWatcher <> None, pathList, subpaths))
(fun (host, _) ->
begin match host with
Remote _ -> Uutil.showUpdateStatus "";
@@ -1870,10 +2084,10 @@
Trace.status "";
Lwt.return result))))
-let findUpdates () =
+let findUpdates ?wantWatcher subpaths =
(* TODO: We should filter the paths to remove duplicates (including prefixes)
and ignored paths *)
- findUpdatesOnPaths (Prefs.read Globals.paths)
+ findUpdatesOnPaths ?wantWatcher (Prefs.read Globals.paths) subpaths
(*****************************************************************************)
@@ -2253,7 +2467,7 @@
(* ...and check that this is a good description of what's out in the world *)
let scanInfo =
{ fastCheck = false; dirFastCheck = false;
- dirStamp = Props.changedDirStamp;
+ dirStamp = Props.changedDirStamp; archHash = "" (* Not used *);
showStatus = false } in
let (_, uiNew) = buildUpdateRec archive fspath localPath scanInfo in
markPossiblyUpdatedRec fspath pathInArchive uiNew;
Modified: trunk/src/update.mli
===================================================================
--- trunk/src/update.mli 2012-08-07 20:06:46 UTC (rev 503)
+++ trunk/src/update.mli 2012-08-09 14:06:21 UTC (rev 504)
@@ -18,10 +18,16 @@
(* Retrieve the actual names of the roots *)
val getRootsName : unit -> string
-(* Structures describing dirty files/dirs (1 per path given in the -path preference) *)
+(* Perform update detection. Optionally, takes as input the list of
+ paths known not to be synchronized and a list of paths not to
+ check. Returns structures describing dirty files/dirs (1 per path
+ given in the -path preference). An option controls whether we
+ would like to use the external filesytem monitoring process. *)
val findUpdates :
- unit -> ((Path.local * Common.updateItem * Props.t list) *
- (Path.local * Common.updateItem * Props.t list)) list
+ ?wantWatcher:unit ->
+ (Path.t list * Path.t list) option ->
+ ((Path.local * Common.updateItem * Props.t list) *
+ (Path.local * Common.updateItem * Props.t list)) list
(* Take a tree of equal update contents and update the archive accordingly. *)
val markEqual :
More information about the Unison-hackers
mailing list