[Unison-hackers] [unison-svn] r487 - in branches: . 2.45/doc 2.45/src 2.45/src/uimacnew09
bcpierce at seas.upenn.edu
bcpierce at seas.upenn.edu
Mon Apr 2 11:54:47 EDT 2012
Author: bcpierce
Date: 2012-04-02 11:54:47 -0400 (Mon, 02 Apr 2012)
New Revision: 487
Added:
branches/2.45/
branches/2.45/doc/changes.tex
branches/2.45/src/INSTALL.win32-msvc
branches/2.45/src/RECENTNEWS
branches/2.45/src/copy.mli
branches/2.45/src/globals.ml
branches/2.45/src/mkProjectInfo.ml
branches/2.45/src/uicommon.ml
branches/2.45/src/uicommon.mli
branches/2.45/src/uimacnew09/MyController.m
Removed:
branches/2.45/doc/changes.tex
branches/2.45/src/INSTALL.win32-msvc
branches/2.45/src/RECENTNEWS
branches/2.45/src/copy.mli
branches/2.45/src/globals.ml
branches/2.45/src/mkProjectInfo.ml
branches/2.45/src/uicommon.ml
branches/2.45/src/uicommon.mli
branches/2.45/src/uimacnew09/MyController.m
Log:
New release branch
Deleted: branches/2.45/doc/changes.tex
===================================================================
--- trunk/doc/changes.tex 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/doc/changes.tex 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,1840 +0,0 @@
-\begin{changesfromversion}{2.40.1}
-\item Added "BelowPath" patterns, that match a path as well as all paths below
- (convenient to use with no{deletion,update,creation}partial preferences)
-\item Added a "fat" preference that makes Unison use the right options
- when one of the replica is on a FAT filesystem.
-\item Allow "prefer/force=newer" even when not synchronizing modification
- times. (The reconciler will not be aware of the modification time
- of unchanged files, so the synchronization choices of Unison can be
- different from when "times=true", but the behavior remains sane:
- changed files with the most recent modification time will be
- propagated.)
-\item Minor fixes and improvements:
-\begin{itemize}
-\item Compare filenames up to decomposition in case sensitive mode when
- one host is running MacOSX and the unicode preference is set to
- true.
-\item Rsync: somewhat faster compressor
-\item Make Unicode the default on all architectures (it was only the
- default when a Mac OS X or Windows machine was involved).
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.32}
-\item Major enhancement: Unicode support.
-\begin{itemize}
-\item Unison should now handle unicode filenames correctly on all platforms.
-\item This functionality is controlled by a new preference {\tt unicode}.
-\item Unicode mode is now the default when one of the hosts is under
- Windows or MacOS. This may make upgrades a bit more painful (the
- archives cannot be reused), but this is a much saner default.
-\end{itemize}
-\item Partial transfer of directories. If an error occurs while
- transferring a directory, the part transferred so far is copied into
- place (and the archives are updated accordingly).
- The "maxerrors" preference controls how many transfer error Unison
- will accept before stopping the transfer of a directory (by default,
- only one). This makes it possible to transfer most of a directory
- even if there are some errors. Currently, only the first error is
- reported by the GUIs.
-
- Also, allow partial transfer of a directory when there was an error deep
- inside this directory during update detection. At the moment, this
- is only activated with the text and GTK UIs, which have been
- modified so that they show that the transfer is going to be partial
- and so that they can display all errors.
-\item Improvement to the code for resuming directory transfers:
-\begin{itemize}
-\item
- if a file was not correctly transferred (or the source has been
- modified since, with unchanged size), Unison performs a new
- transfer rather than failing
- \item spurious files are deleted (this can happen if a file is deleted
- on the source replica before resuming the transfer; not deleting
- the file would result in it reappearing on the target replica)
-\end{itemize}
-\item Experimental streaming protocol for transferring file contents (can
- be disabled by setting the directive "stream" to false): file
- contents is transfered asynchronously (without waiting for a response
- from the destination after each chunk sent) rather than using the
- synchronous RPC mechanism. As a consequence:
- \begin{itemize}
- \item
- Unison now transfers the contents of a single file at a time
- (Unison used to transfer several contents simultaneously in order
- to hide the connection latency.)
- \item the transfer of large files uses the full available bandwidth
- and is not slowed done due to the connection latency anymore
- \item we get performance improvement for small files as well by
- scheduling many files simultaneously (as scheduling a file for
- transfer consume little ressource: it does not mean allocating a
- large buffer anymore)
- \end{itemize}
-\item Changes to the internal implementation of the rsync algorithm:
-\begin{itemize}
-\item
- use longer blocks for large files (the size of a block is the
- square root of the size of the file for large files);
- \item transmit less checksum information per block (we still have less
- than one chance in a hundred million of transferring a file
- incorrectly, and Unison will catch any transfer error when
- fingerprinting the whole file)
- \item avoid transfer overhead (which was 4 bytes per block)
-\end{itemize}
- For a 1G file, the first optimization saves a factor 50 on the
- amount of data transferred from the target to the source (blocks
- are 32768 bytes rather than just 700 bytes). The two other
- optimizations save another factor of 2 (from 24 bytes per block
- down to 10).
-\item Implemented an on-disk file fingerprint cache to speed-up update
- detection after a crash: this way, Unison does not have do recompute
- all the file fingerprints from scratch.
- \begin{itemize}
- \item When Unison detects that the archive case-sensitivity mode
- does not match the current settings, it populates the fingerprint
- cache using the archive contents. This way, changing the
- case-sensitivity mode should be reasonably fast.
- \end{itemize}
-\item New preferences "noupdate=root", "nodeletion=root", "nocreation=root"
- that prevent Unison from performing files updates, deletions or
- creations on the given root. Also 'partial' versions of 'noupdate',
- 'nodeletion' and 'nocreation'
-\item Limit the number of simultaneous external copy program
- ("copymax" preference)
-\item New "links" preference. When set to false, Unison will report an
- error on symlinks during update detection. (This is the default
- when one host is running Windows but not Cygwin.) This is better
- than failing during propagation.
-\item Added a preference "halfduplex" to force half-duplex communication
- with the server. This may be useful on unreliable links (as a more
- efficient alternative to "maxthreads = 1").
-\item Renamed preference "pretendwin" to "ignoreinodenumbers" (an alias is
- kept for backwards compatibility).
-\item Ignore one-second differences when synchronizing modification time.
- (Technically, this is an incompatible archive format change, but it
- is backward compatible. To trigger a problem, a user would have to
- synchronize modification times on a filesystem with a two-second
- granularity and then downgrade to a previous version of Unison,
- which does not work well in such a case. Thus, it does not
- seem worthwhile to increment the archive format number, which would
- impact all users.)
-\item Do not keep many files simultaneously opened anymore when the rsync
- algorithm is in use.
-\item Add ``ignorearchives'' preference to ignore existing archives (to
- avoid forcing users to delete them manually, in situations where one
- archive has gotten deleted or corrupted).
-\item Mac OS
-\begin{itemize}
-\item fixed rsync bug which could result in an "index out of bounds"
- error when transferring resource forks.
-\item Fixed bug which made Unison ignore finder information and resource
- fork when compiled to 64bit on Mac OSX.
-\item should now be 64 bit clean (the Growl framework is not up to date,
- though)
-\item Made the bridge between Objective C and Ocaml code GC friendly
- (it was allocating ML values and putting them in an array which
- was not registered with the GC)
-\item use darker grey arrows (patch contributed by Eric Y. Kow)
-\end{itemize}
-\item GTK user interface
-\begin{itemize}
-\item assistant for creating profiles
-\item profile editor
-\item pop up a summary window when the replicas are not fully
- synchronized after transport
-\item display estimated remaining time and transfer rate on the
- progress bar
-\item allow simultaneous selection of several items
-\item Do not reload the preference file before a new update
- detection if it is unchanged
-\item disabled scrolling to the first unfinished item during transport.
- It goes way too fast when lot of small files are synchronized, and it
- makes it impossible to browse the file list during transport.
-\item take into account the "height" preference again
-\item the internal list of selected reconciler item was not always in
- sync with what was displayed (GTK bug?); workaround implemented
-\item Do not display "Looking for change" messages during propagation
- (when checking the targe is unchanged) but only during update detection
-\item Apply patch to fix some crashes in the OSX GUI, thanks to Onne Gorter.
-\end{itemize}
-\item Text UI
-\begin{itemize}
-\item During update detection, display status by updating a single line
-rather than generating a new line of output every so often. Should be less
-confusing.
-\end{itemize}
-\item Windows
-\begin{itemize}
-\item Fastcheck is now the default under Windows. People mostly use NTFS
- nowadays and the Unicode API provides an equivalent to inode numbers
- for this filesystem.
-\item Only use long UNC path for accessing replicas (as '..' is
- not handled with this format of paths, but can be useful)
-\item Windows text UI: now put the console into UTF-8 output mode. This
- is the right thing to do when in Unicode mode, and is no worse than
- what we had previously otherwise (the console use some esoteric
- encoding by default). This only works when using a Unicode font
- instead of the default raster font.
-\item Don't get the home directory from environment variable HOME under
- Windows (except for Cygwin binaries): we don't want the behavior of
- Unison to depends on whether it is run from a Cygwin shell (where
- HOME is set) or in any other way (where HOME is usually not set).
-\end{itemize}
-\item Miscellaneous fixes and improvements
-\begin{itemize}
-\item Made a server waiting on a socket more resilient to unexpected
- lost connections from the client.
-\item Small patch to property setting code suggested by Ulrich Gernkow.
-\item Several fixes to the change transfer functions (both the internal ones
- and external transfers using rsync). In particular, limit the number of
- simultaneous transfer using an rsync
- (as the rsync algorithm can use a large amount of memory when
- processing huge files)
-\item Keep track of which file contents are being transferred, and delay
- the transfer of a file when another file with the same contents is
- currently being transferred. This way, the second transfer can be
- skipped and replaced by a local copy.
-\item Experimental update detection optimization:
- do not read the contents of unchanged directories
-\item When a file transfer fails, turn off fastcheck for this file on the
- next sync.
-\item Fixed bug with case insensitive mode on a case sensitive filesystem:
-\begin{itemize}
-\item
- if file "a/a" is created on one replica and directory "A" is
- created on the other, the file failed to be synchronized the first
- time Unison is run afterwards, as Unison uses the wrong path "a/a"
- (if Unison is run again, the directories are in the archive, so
- the right path is used);
- \item if file "a" appears on one replica and file "A" appears on the
- other with different contents, Unison was unable to synchronize
- them.
-\end{itemize}
-\item Improved error reporting when the destination is updated during
- synchronization: Unison now tells which file has been updated, and how.
-\item Limit the length of temporary file names
-\item Case sensitivity information put in the archive (in a backward
- compatible way) and checked when the archive is loaded
-\item Got rid of the 16mb marshalling limit by marshalling to a bigarray.
-\item Resume copy of partially transferred files.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.31}
-\item Small user interface changes
-\begin{itemize}
-\item Small change to text UI "scanning..." messages, to print just
- directories (hopefully making it clearer that individual files are
- not necessarily being fingerprinted).
-\end{itemize}
-\item Minor fixes and improvements:
-\begin{itemize}
-\item Ignore one hour differences when deciding whether a file may have
- been updated. This avoids slow update detection after daylight
- saving time changes under Windows. This makes Unison slightly more
- likely to miss an update, but it should be safe enough.
-\item Fix a small bug that was affecting mainly windows users. We need to
- commit the archives at the end of the sync even if there are no
- updates to propagate because some files (in fact, if we've just
- switched to DST on windows, a LOT of files) might have new modtimes
- in the archive. (Changed the text UI only. It's less clear where
- to change the GUI.)
-\item Don't delete the temp file when a transfer fails due to a
- fingerprint mismatch (so that we can have a look and see why!) We've also
- added more debugging code togive more informative error messages when we
- encounter the dreaded and longstanding "assert failed during file
- transfer" bug
-\item Incorrect paths ("path" directive) now result in an error update
- item rather than a fatal error.
-\item Create parent directories (with correct permissions) during
- transport for paths which point to non-existent locations in the
- destination replica.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.27}
-\item If Unison is interrupted during a directory transfer, it will now
-leave the partially transferred directory intact in a temporary
-location. (This maintains the invariant that new files/directories are
-transferred either completely or not at all.) The next time Unison is run,
-it will continue filling in this temporary directory, skipping transferring
-files that it finds are already there.
-\item We've added experimental support for invoking an external file
-transfer tool for whole-file copies instead of Unison's built-in transfer
-protocol. Three new preferences have been added:
-\begin{itemize}
-\item {\tt copyprog} is a string giving the name (and command-line
-switches, if needed) of an external program that can be used to copy large
-files efficiently. By default, rsync is invoked, but other tools such as
-scp can be used instead by changing the value of this preference. (Although
-this is not its primary purpose, rsync is actually a pretty fast way of
-copying files that don't already exist on the receiving host.) For files
-that do already exist on (but that have been changed in one replica), Unison
-will always use its built-in implementation of the rsync algorithm.
-\item Added a "copyprogrest" preference, so that we can give different
-command lines for invoking the external copy utility depending on whether a
-partially transferred file already exists or not. (Rsync doesn't seem to
-care about this, but other utilities may.)
-\item {\tt copythreshold} is an integer (-1 by default), indicating above what
-filesize (in megabytes) Unison should use the external copying utility
-specified by copyprog. Specifying 0 will cause ALL copies to use the
-external program; a negative number will prevent any files from using it.
-(Default is -1.)
-\end{itemize}
-Thanks to Alan Schmitt for a huge amount of hacking and to an anonymous
-sponsor for suggesting and underwriting this extension.
-\item Small improvements:
-\begin{itemize}
-\item Added a new preference, {\tt dontchmod}. By default, Unison uses the
-{\tt chmod} system call to set the permission bits of files after it has
-copied them. But in some circumstances (and under some operating systems),
-the chmod call always fails. Setting this preference completely prevents
-Unison from ever calling {\tt chmod}.
-\item Don't ignore files that look like backup files if the {\tt
- backuplocation} preference is set to {\tt central}
-\item Shortened the names of several preferences. The old names are also
-still supported, for backwards compatibility, but they do not appear in the
-documentation.
-\item Lots of little documentation tidying. (In particular, preferences are
-separated into Basic and Advanced! This should hopefully make Unison a
-little more approachable for new users.
-\item Unison can sometimes fail to transfer a file, giving the unhelpful
-message "Destination updated during synchronization" even though the file
-has not been changed. This can be caused by programs that change either the
-file's contents \emph{or} the file's extended attributes without changing
-its modification time. It's not clear what is the best fix for this -- it
-is not Unison's fault, but it makes Unison's behavior puzzling -- but at
-least Unison can be more helpful about suggesting a workaround (running once
-with {\tt fastcheck} set to false). The failure message has been changed to
-give this advice.
-\item Further improvements to the OS X GUI (thanks to Alan Schmitt and Craig
-Federighi).
-\end{itemize}
-\item Very preliminary support for triggering Unison from an external
- filesystem-watching utility. The current implementation is very
- simple, not efficient, and almost completely untested---not ready
- for real users. But if someone wants to help improve it (e.g.,
- by writing a filesystem watcher for your favorite OS), please make
- yourself known!
-
- On the Unison side, the new behavior is very simple:
- \begin{itemize}
- \item use the text UI
- \item start Unison with the command-line flag "-repeat FOO",
- where FOO is name of a file where Unison should look
- for notifications of changes
- \item when it starts up, Unison will read the whole contents
- of this file (on both hosts), which should be a
- newline-separated list of paths (relative to the root
- of the synchronization) and synchronize just these paths,
- as if it had been started with the "-path=xxx" option for
- each one of them
- \item when it finishes, it will sleep for a few seconds and then
- examine the watchfile again; if anything has been added, it
- will read the new paths, synchronize them, and go back to
- sleep
- \item that's it!
- \end{itemize}
- To use this to drive Unison "incrementally," just start it in
- this mode and start up a tool (on each host) to watch for
- new changes to the filesystem and append the appropriate paths
- to the watchfile. Hopefully such tools should not be too hard
- to write.
-\item Bug fixes:
-\begin{itemize}
-\item Fixed a bug that was causing new files to be created with
- permissions 0x600 instead of using a reasonable default (like
- 0x644), if the 'perms' flag was set to 0. (Bug reported by Ben
- Crowell.)
-\item Follow maxthreads preference when transferring directories.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.17}
-\item Major rewrite and cleanup of the whole Mac OS X graphical user
-interface by Craig Federighi. Thanks, Craig!!!
-\item Small fix to ctime (non-)handling in update detection under windows
- with fastcheck.
-\item Several small fixes to the GTK2 UI to make it work better under
-Windows [thanks to Karl M for these].
-\item The backup functionality has been completely rewritten. The external
-interface has not changed, but numerous bugs, irregular behaviors, and
-cross-platform inconsistencies have been corrected.
-\item The Unison project now accepts donations via PayPal. If you'd like to
-donate, you can find a link to the donation page on the
-\URL{http://www.cis.upenn.edu/~bcpierce/unison/lists.html}{Unison home
- page}.
-\item Some important safety improvements:
-\begin{itemize}
-\item Added a new \verb|mountpoint| preference, which can be used to specify
-a path that must exist in both replicas at the end of update detection
-(otherwise Unison aborts). This can be used to avoid potentially dangerous
-situations when Unison is used with removable media such as external hard
-drives and compact flash cards.
-\item The confirmation of ``big deletes'' is now controlled by a boolean preference
- \verb|confirmbigdeletes|. Default is true, which gives the same behavior as
- previously. (This functionality is at least partly superceded by the
- \verb|mountpoint| preference, but it has been left in place in case it is
- useful to some people.)
- \item If Unison is asked to ``follow'' a symbolic link but there is
- nothing at the other end of the link, it will now flag this path as an
- error, rather than treating the symlink itself as missing or deleted.
- This avoids a potentially dangerous situation where a followed symlink
- points to an external filesystem that might be offline when Unison is run
- (whereupon Unison would cheerfully delete the corresponding files in the
- other replica!).
-\end{itemize}
-
-\item Smaller changes:
-\begin{itemize}
-\item Added \verb|forcepartial| and \verb|preferpartial| preferences, which
-behave like \verb|force| and \verb|prefer| but can be specified on a
-per-path basis. [Thanks to Alan Schmitt for this.]
-\item A bare-bones self test feature was added, which runs unison through
- some of its paces and checks that the results are as expected. The
- coverage of the tests is still very limited, but the facility has already
- been very useful in debugging the new backup functionality (especially in
- exposing some subtle cross-platform issues).
-\item Refined debugging code so that the verbosity of individual modules
- can be controlled separately. Instead of just putting '-debug
- verbose' on the command line, you can put '-debug update+', which
- causes all the extra messages in the Update module, but not other
- modules, to be printed. Putting '-debug verbose' causes all modules
- to print with maximum verbosity.
-\item Removed \verb|mergebatch| preference. (It never seemed very useful, and
- its semantics were confusing.)
-\item Rewrote some of the merging functionality, for better cooperation
- with external Harmony instances.
-\item Changed the temp file prefix from \verb|.#| to \verb|.unison|.
-\item Compressed the output from the text user interface (particularly
- when run with the \verb|-terse| flag) to make it easier to interpret the
- results when Unison is run several times in succession from a script.
-\item Diff and merge functions now work under Windows.
-\item Changed the order of arguments to the default diff command (so that
- the + and - annotations in diff's output are reversed).
-\item Added \verb|.mpp| files to the ``never fastcheck'' list (like
-\verb|.xls| files).
-\end{itemize}
-
-\item Many small bugfixes, including:
-\begin{itemize}
-\item Fixed a longstanding bug regarding fastcheck and daylight saving time
- under Windows when Unison is set up to synchronize modification times.
- (Modification times cannot be updated in the archive in this case,
- so we have to ignore one hour differences.)
-\item Fixed a bug that would occasionally cause the archives to be left in
- non-identical states on the two hosts after synchronization.
-\item Fixed a bug that prevented Unison from communicating correctly between
- 32- and 64-bit architectures.
-\item On windows, file creation times are no longer used as a proxy for
- inode numbers. (This is unfortunate, as it makes fastcheck a little less
- safe. But it turns out that file creation times are not reliable
- under Windows: if a file is removed and a new file is created in its
- place, the new one will sometimes be given the same creation date as the
- old one!)
-\item Set read-only file to R/W on OSX before attempting to change other attributes.
-\item Fixed bug resulting in spurious "Aborted" errors during transport
-(thanks to Jerome Vouillon)
-\item Enable diff if file contents have changed in one replica, but
-only properties in the other.
-\item Removed misleading documentation for 'repeat' preference.
-\item Fixed a bug in merging code where Unison could sometimes deadlock
- with the external merge program, if the latter produced large
- amounts of output.
-\item Workaround for a bug compiling gtk2 user interface against current versions
- of gtk2+ libraries.
-\item Added a better error message for "ambiguous paths".
-\item Squashed a longstanding bug that would cause file transfer to fail
- with the message ``Failed: Error in readWrite: Is a directory.''
-\item Replaced symlinks with copies of their targets in the Growl framework in src/uimac.
- This should make the sources easier to check out from the svn repository on WinXP
- systems.
-\item Added a workaround (suggested by Karl M.) for the problem discussed
- on the unison users mailing list where, on the Windows platform, the
- server would hang when transferring files. I conjecture that
- the problem has to do with the RPC mechanism, which was used to
- make a call {\em back} from the server to the client (inside the Trace.log
- function) so that the log message would be appended to the log file on
- the client. The workaround is to dump these messages (about when
- xferbycopying shortcuts are applied and whether they succeed) just to the
- standard output of the Unison process, not to the log file.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.13.0}
-\item The features for performing backups and for invoking external merge
-programs have been completely rewritten by Stephane Lescuyer (thanks,
-Stephane!). The user-visible functionality should not change, but the
-internals have been rationalized and there are a number of new features.
-See the manual (in particular, the description of the \verb|backupXXX|
-preferences) for details.
-\item Incorporated patches for ipv6 support, contributed by Samuel Thibault.
-(Note that, due to a bug in the released OCaml 3.08.3 compiler, this code
-will not actually work with ipv6 unless compiled with the CVS version of the
-OCaml compiler, where the bug has been fixed; however, ipv4 should continue
-to work normally.)
-\item OSX interface:
-\begin{itemize}
-\item Incorporated Ben Willmore's cool new icon for the Mac UI.
-\end{itemize}
-\item Small fixes:
-\begin{itemize}
-\item Fixed off by one error in month numbers (in printed dates) reported
- by Bob Burger
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.12.0}
-\item New convention for release numbering: Releases will continue to be
-given numbers of the form \verb|X.Y.Z|, but,
-from now on, just the major version number (\verb|X.Y|) will be considered
-significant when checking compatibility between client and server versions.
-The third component of the version number will be used only to identify
-``patch levels'' of releases.
-
-This change goes hand in hand with a change to the procedure for making new
-releases. Candidate releases will initially be given ``beta release''
-status when they are announced for public consumption. Any bugs that are
-discovered will be fixed in a separate branch of the source repository
-(without changing the major version number) and new tarballs re-released as
-needed. When this process converges, the patched beta version will be
-dubbed stable.
-\item Warning (failure in batch mode) when one path is completely emptied.
- This prevents Unison from deleting everything on one replica when
- the other disappear.
-\item Fix diff bug (where no difference is shown the first time the diff
- command is given).
-\item User interface changes:
-\begin{itemize}
-\item Improved workaround for button focus problem (GTK2 UI)
-\item Put leading zeroes in date fields
-\item More robust handling of character encodings in GTK2 UI
-\item Changed format of modification time displays, from \verb|modified at hh:mm:ss on dd MMM, yyyy|
-to \verb|modified on yyyy-mm-dd hh:mm:ss|
-\item Changed time display to include seconds (so that people on FAT
- filesystems will not be confused when Unison tries to update a file
- time to an odd number of seconds and the filesystem truncates it to
- an even number!)
-\item Use the diff "-u" option by default when showing differences between files
- (the output is more readable)
-\item In text mode, pipe the diff output to a pager if the environment
- variable PAGER is set
-\item Bug fixes and cleanups in ssh password prompting. Now works with
- the GTK2 UI under Linux. (Hopefully the Mac OS X one is not broken!)
-\item Include profile name in the GTK2 window name
-\item Added bindings ',' (same as '<') and '.' (same as '>') in the GTK2 UI
-\end{itemize}
-\item Mac GUI:
-\begin{itemize}
-\item actions like < and > scroll to the next item as necessary.
-\item Restart has a menu item and keyboard shortcut (command-R).
-\item
- Added a command-line tool for Mac OS X. It can be installed from
- the Unison menu.
-\item New icon.
-\item Handle the "help" command-line argument properly.
-\item Handle profiles given on the command line properly.
-\item When a profile has been selected, the profile dialog is replaced by a
- "connecting" message while the connection is being made. This
- gives better feedback.
-\item Size of left and right columns is now large enough so that
- "PropsChanged" is not cut off.
-\end{itemize}
-\item Minor changes:
-\begin{itemize}
-\item Disable multi-threading when both roots are local
-\item Improved error handling code. In particular, make sure all files
- are closed in case of a transient failure
-\item Under Windows, use \verb|$UNISON| for home directory as a last resort
- (it was wrongly moved before \verb|$HOME| and \verb|$USERPROFILE| in
- Unison 2.12.0)
-\item Reopen the logfile if its name changes (profile change)
-\item Double-check that permissions and modification times have been
- properly set: there are some combination of OS and filesystem on
- which setting them can fail in a silent way.
-\item Check for bad Windows filenames for pure Windows synchronization
- also (not just cross architecture synchronization).
- This way, filenames containing backslashes, which are not correctly
- handled by unison, are rejected right away.
-\item Attempt to resolve issues with synchronizing modification times
- of read-only files under Windows
-\item Ignore chmod failures when deleting files
-\item Ignore trailing dots in filenames in case insensitive mode
-\item Proper quoting of paths, files and extensions ignored using the UI
-\item The strings CURRENT1 and CURRENT2 are now correctly substitued when
- they occur in the diff preference
-\item Improvements to syncing resource forks between Macs via a non-Mac system.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.10.2}
-\item \incompatible{} Archive format has changed.
-\item Source code availability: The Unison sources are now managed using
- Subversion. One nice side-effect is that anonymous checkout is now
- possible, like this:
-\begin{verbatim}
- svn co https://cvs.cis.upenn.edu:3690/svnroot/unison/
-\end{verbatim}
-We will also continue to export a ``developer tarball'' of the current
-(modulo one day) sources in the web export directory. To receive commit logs
-for changes to the sources, subscribe to the \verb|unison-hackers| list
-(\ONEURL{http://www.cis.upenn.edu/~bcpierce/unison/lists.html}).
-\item Text user interface:
-\begin{itemize}
-\item Substantial reworking of the internal logic of the text UI to make it
-a bit easier to modify.
-\item The {\tt dumbtty} flag in the text UI is automatically set to true if
-the client is running on a Unix system and the {\tt EMACS} environment
-variable is set to anything other than the empty string.
-\end{itemize}
-\item Native OS X gui:
-\begin{itemize}
-\item Added a synchronize menu item with keyboard shortcut
-\item Added a merge menu item, still needs to be debugged
-\item Fixes to compile for Panther
-\item Miscellaneous improvements and bugfixes
-\end{itemize}
-\item Small changes:
-\begin{itemize}
-\item Changed the filename checking code to apply to Windows only, instead
- of OS X as well.
-\item Finder flags now synchronized
-\item Fallback in copy.ml for filesystem that do not support \verb|O_EXCL|
-\item Changed buffer size for local file copy (was highly inefficient with
- synchronous writes)
-\item Ignore chmod failure when deleting a directory
-\item Fixed assertion failure when resolving a conflict content change /
- permission changes in favor of the content change.
-\item Workaround for transferring large files using rsync.
-\item Use buffered I/O for files (this is the only way to open files in binary
- mode under Cygwin).
-\item On non-Cygwin Windows systems, the UNISON environment variable is now checked first to determine
- where to look for Unison's archive and preference files, followed by \verb|HOME| and
- \verb|USERPROFILE| in that order. On Unix and Cygwin systems, \verb|HOME| is used.
-\item Generalized \verb|diff| preference so that it can be given either as just
- the command name to be used for calculating diffs or else a whole command
- line, containing the strings \verb|CURRENT1| and \verb|CURRENT2|, which will be replaced
- by the names of the files to be diff'ed before the command is called.
-\item Recognize password prompts in some newer versions of ssh.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.9.20}
-\item \incompatible{} Archive format has changed.
-\item Major functionality changes:
-\begin{itemize}
-\item Major tidying and enhancement of 'merge' functionality. The main
- user-visible change is that the external merge program may either write
- the merged output to a single new file, as before, or it may modify one or
- both of its input files, or it may write {\em two} new files. In the
- latter cases, its modifications will be copied back into place on both the
- local and the remote host, and (if the two files are now equal) the
- archive will be updated appropriately. More information can be found in
- the user manual. Thanks to Malo Denielou and Alan Schmitt for these
- improvements.
-
- Warning: the new merging functionality is not completely compatible with
- old versions! Check the manual for details.
-\item Files larger than 2Gb are now supported.
-\item Added preliminary (and still somewhat experimental) support for the
- Apple OS X operating system.
-\begin{itemize}
-\item Resource forks should be transferred correctly. (See the manual for
-details of how this works when synchronizing HFS with non-HFS volumes.)
-Synchronization of file type and creator information is also supported.
-\item On OSX systems, the name of the directory for storing Unison's
-archives, preference files, etc., is now determined as follows:
-\begin{itemize}
- \item if \verb+~/.unison+ exists, use it
- \item otherwise, use \verb|~/Library/Application Support/Unison|,
- creating it if necessary.
-\end{itemize}
-\item A preliminary native-Cocoa user interface is under construction. This
-still needs some work, and some users experience unpredictable crashes, so
-it is only for hackers for now. Run make with {\tt UISTYLE=mac} to build
-this interface.
-\end{itemize}
-\end{itemize}
-
-\item Minor functionality changes:
-\begin{itemize}
-\item Added an {\tt ignorelocks} preference, which forces Unison to override left-over
- archive locks. (Setting this preference is dangerous! Use it only if you
- are positive you know what you are doing.)
-% BCP: removed later
-% \item Running with the {\tt -timers} flag set to true will now show the total time taken
-% to check for updates on each directory. (This can be helpful for tidying directories to improve
-% update detection times.)
-\item Added a new preference {\tt assumeContentsAreImmutable}. If a directory
- matches one of the patterns set in this preference, then update detection
- is skipped for files in this directory. (The
- purpose is to speed update detection for cases like Mail folders, which
- contain lots and lots of immutable files.) Also a preference
- {\tt assumeContentsAreImmutableNot}, which overrides the first, similarly
- to {\tt ignorenot}. (Later amendment: these preferences are now called
- {\tt immutable} and {\tt immutablenot}.)
-\item The {\tt ignorecase} flag has been changed from a boolean to a three-valued
- preference. The default setting, called {\tt default}, checks the operating systems
- running on the client and server and ignores filename case if either of them is
- OSX or Windows. Setting ignorecase to {\tt true} or {\tt false} overrides
- this behavior. If you have been setting {\tt ignorecase} on the command
- line using {\tt -ignorecase=true} or {\tt -ignorecase=false}, you will
- need to change to {\tt -ignorecase true} or {\tt -ignorecase false}.
-\item a new preference, 'repeat', for the text user interface (only). If 'repeat' is set to
- a number, then, after it finishes synchronizing, Unison will wait for that many seconds and
- then start over, continuing this way until it is killed from outside. Setting repeat to true
- will automatically set the batch preference to true.
-\item Excel files are now handled specially, so that the {\tt fastcheck}
- optimization is skipped even if the {\tt fastcheck} flag is set. (Excel
- does some naughty things with modtimes, making this optimization
- unreliable and leading to failures during change propagation.)
-\item The ignorecase flag has been changed from a boolean to a three-valued
- preference. The default setting, called 'default', checks the operating systems
- running on the client and server and ignores filename case if either of them is
- OSX or Windows. Setting ignorecase to 'true' or 'false' overrides this behavior.
-\item Added a new preference, 'repeat', for the text user interface (only,
- at the moment). If 'repeat' is set to a number, then, after it finishes
- synchronizing, Unison will wait for that many seconds and then start over,
- continuing this way until it is killed from outside. Setting repeat to
- true will automatically set the batch preference to true.
-\item The 'rshargs' preference has been split into 'rshargs' and 'sshargs'
- (mainly to make the documentation clearer). In fact, 'rshargs' is no longer
- mentioned in the documentation at all, since pretty much everybody uses
- ssh now anyway.
-\end{itemize}
-\item Documentation
-\begin{itemize}
-\item The web pages have been completely redesigned and reorganized.
- (Thanks to Alan Schmitt for help with this.)
-\end{itemize}
-\item User interface improvements
-\begin{itemize}
-\item Added a GTK2 user interface, capable (among other things) of displaying filenames
- in any locale encoding. Kudos to Stephen Tse for contributing this code!
-\item The text UI now prints a list of failed and skipped transfers at the end of
- synchronization.
-\item Restarting update detection from the graphical UI will reload the current
- profile (which in particular will reset the -path preference, in case
- it has been narrowed by using the ``Recheck unsynchronized items''
- command).
-\item Several small improvements to the text user interface, including a
- progress display.
-\end{itemize}
-\item Bug fixes (too numerous to count, actually, but here are some):
-\begin{itemize}
-\item The {\tt maxthreads} preference works now.
-\item Fixed bug where warning message about uname returning an unrecognized
- result was preventing connection to server. (The warning is no longer
- printed, and all systems where 'uname' returns anything other than 'Darwin'
- are assumed not to be running OS X.)
-\item Fixed a problem on OS X that caused some valid file names (e.g.,
- those including colons) to be considered invalid.
-\item Patched Path.followLink to follow links under cygwin in addition to Unix
- (suggested by Matt Swift).
-\item Small change to the storeRootsName function, suggested by bliviero at
- ichips.intel.com, to fix a problem in unison with the `rootalias'
- option, which allows you to tell unison that two roots contain the same
- files. Rootalias was being applied after the hosts were
- sorted, so it wouldn't work properly in all cases.
-\item Incorporated a fix by Dmitry Bely for setting utimes of read-only files
- on Win32 systems.
-\end{itemize}
-\item Installation / portability:
-\begin{itemize}
-\item Unison now compiles with OCaml version 3.07 and later out of the box.
-\item Makefile.OCaml fixed to compile out of the box under OpenBSD.
-\item a few additional ports (e.g. OpenBSD, Zaurus/IPAQ) are now mentioned in
- the documentation
-\item Unison can now be installed easily on OSX systems using the Fink
- package manager
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.9.1}
-\item Added a preference {\tt maxthreads} that can be used to limit the
-number of simultaneous file transfers.
-\item Added a {\tt backupdir} preference, which controls where backup
-files are stored.
-\item Basic support added for OSX. In particular, Unison now recognizes
-when one of the hosts being synchronized is running OSX and switches to
-a case-insensitive treatment of filenames (i.e., 'foo' and 'FOO' are
-considered to be the same file).
- (OSX is not yet fully working,
- however: in particular, files with resource forks will not be
- synchronized correctly.)
-\item The same hash used to form the archive name is now also added to
-the names of the temp files created during file transfer. The reason for
-this is that, during update detection, we are going to silently delete
-any old temp files that we find along the way, and we want to prevent
-ourselves from deleting temp files belonging to other instances of Unison
-that may be running in parallel, e.g. synchronizing with a different
-host. Thanks to Ruslan Ermilov for this suggestion.
-\item Several small user interface improvements
-\item Documentation
-\begin{itemize}
-\item FAQ and bug reporting instructions have been split out as separate
- HTML pages, accessible directly from the unison web page.
-\item Additions to FAQ, in particular suggestions about performance
-tuning.
-\end{itemize}
-\item Makefile
-\begin{itemize}
-\item Makefile.OCaml now sets UISTYLE=text or UISTYLE=gtk automatically,
- depending on whether it finds lablgtk installed
-\item Unison should now compile ``out of the box'' under OSX
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.8.1}
-\item Changing profile works again under Windows
-\item File movement optimization: Unison now tries to use local copy instead of
- transfer for moved or copied files. It is controled by a boolean option
- ``xferbycopying''.
-\item Network statistics window (transfer rate, amount of data transferred).
- [NB: not available in Windows-Cygwin version.]
-\item symlinks work under the cygwin version (which is dynamically linked).
-\item Fixed potential deadlock when synchronizing between Windows and
-Unix
-\item Small improvements:
- \begin{itemize}
- \item If neither the {\tt USERPROFILE} nor the {\tt HOME} environment
- variables are set, then Unison will put its temporary commit log
- (called {\tt DANGER.README}) into the directory named by the
- {\tt UNISON} environment variable, if any; otherwise it will use
- {\tt C:}.
- \item alternative set of values for fastcheck: yes = true; no = false;
- default = auto.
- \item -silent implies -contactquietly
- \end{itemize}
-\item Source code:
- \begin{itemize}
- \item Code reorganization and tidying. (Started breaking up some of the
- basic utility modules so that the non-unison-specific stuff can be
- made available for other projects.)
- \item several Makefile and docs changes (for release);
- \item further comments in ``update.ml'';
- \item connection information is not stored in global variables anymore.
- \end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.7.78}
-\item Small bugfix to textual user interface under Unix (to avoid leaving
- the terminal in a bad state where it would not echo inputs after Unison
- exited).
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.7.39}
-\item Improvements to the main web page (stable and beta version docs are
- now both accessible).
-\item User manual revised.
-\item Added some new preferences:
-\begin{itemize}
-\item ``sshcmd'' and ``rshcmd'' for specifying paths to ssh and rsh programs.
-\item ``contactquietly'' for suppressing the ``contacting server'' message
-during Unison startup (under the graphical UI).
-\end{itemize}
-\item Bug fixes:
-\begin{itemize}
-\item Fixed small bug in UI that neglected to change the displayed column
- headers if loading a new profile caused the roots to change.
-\item Fixed a bug that would put the text UI into an infinite loop if it
- encountered a conflict when run in batch mode.
-\item Added some code to try to fix the display of non-Ascii characters in
- filenames on Windows systems in the GTK UI. (This code is currently
- untested---if you're one of the people that had reported problems with
- display of non-ascii filenames, we'd appreciate knowing if this actually
- fixes things.)
-\item `\verb|-prefer/-force newer|' works properly now.
- (The bug was reported by Sebastian Urbaniak and Sean Fulton.)
-\end{itemize}
-\item User interface and Unison behavior:
-\begin{itemize}
-\item Renamed `Proceed' to `Go' in the graphical UI.
-\item Added exit status for the textual user interface.
-\item Paths that are not synchronized because of conflicts or errors during
- update detection are now noted in the log file.
-\item \verb|[END]| messages in log now use a briefer format
-\item Changed the text UI startup sequence so that
- {\tt ./unison -ui text} will use the default profile instead of failing.
-\item Made some improvements to the error messages.
-\item Added some debugging messages to remote.ml.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.7.7}
-\item Incorporated, once again, a multi-threaded transport sub-system.
- It transfers several files at the same time, thereby making much
- more effective use of available network bandwidth. Unlike the
- earlier attempt, this time we do not rely on the native thread
- library of OCaml. Instead, we implement a light-weight,
- non-preemptive multi-thread library in OCaml directly. This version
- appears stable.
-
- Some adjustments to unison are made to accommodate the multi-threaded
- version. These include, in particular, changes to the
- user interface and logging, for example:
- \begin{itemize}
- \item Two log entries for each transferring task, one for the
- beginning, one for the end.
- \item Suppressed warning messages against removing temp files left
- by a previous unison run, because warning does not work nicely
- under multi-threading. The temp file names are made less likely
- to coincide with the name of a file created by the user. They
- take the form \\ \verb|.#<filename>.<serial>.unison.tmp|.
- [N.b. This was later changed to \verb|.unison.<filename>.<serial>.unison.tmp|.]
- \end{itemize}
-\item Added a new command to the GTK user interface: pressing 'f' causes
- Unison to start a new update detection phase, using as paths {\em just}
- those paths that have been detected as changed and not yet marked as
- successfully completed. Use this command to quickly restart Unison on
- just the set of paths still needing attention after a previous run.
-\item Made the {\tt ignorecase} preference user-visible, and changed the
- initialization code so that it can be manually set to true, even if
- neither host is running Windows. (This may be useful, e.g., when using
- Unison running on a Unix system with a FAT volume mounted.)
-\item Small improvements and bug fixes:
- \begin{itemize}
- \item Errors in preference files now generate fatal errors rather than
- warnings at startup time. (I.e., you can't go on from them.) Also,
- we fixed a bug that was preventing these warnings from appearing in the
- text UI, so some users who have been running (unsuspectingly) with
- garbage in their prefs files may now get error reports.
- \item Error reporting for preference files now provides file name and
- line number.
- \item More intelligible message in the case of identical change to the same
- files: ``Nothing to do: replicas have been changed only in identical
- ways since last sync.''
- \item Files with prefix '.\#' excluded when scanning for preference
- files.
- \item Rsync instructions are send directly instead of first
- marshaled.
- \item Won't try forever to get the fingerprint of a continuously changing file:
- unison will give up after certain number of retries.
- \item Other bug fixes, including the one reported by Peter Selinger
- (\verb|force=older preference| not working).
- \end{itemize}
-\item Compilation:
- \begin{itemize}
- \item Upgraded to the new OCaml 3.04 compiler, with the LablGtk
- 1.2.3 library (patched version used for compiling under Windows).
- \item Added the option to compile unison on the Windows platform with
- Cygwin GNU C compiler. This option only supports building
- dynamically linked unison executables.
- \end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.7.4}
-\item Fixed a silly (but debilitating) bug in the client startup sequence.
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.7.1}
-\item Added \verb|addprefsto| preference, which (when set) controls which
-preference file new preferences (e.g. new ignore patterns) are added to.
-\item Bug fix: read the initial connection header one byte at a time, so
-that we don't block if the header is shorter than expected. (This bug
-did not affect normal operation --- it just made it hard to tell when you
-were trying to use Unison incorrectly with an old version of the server,
-since it would hang instead of giving an error message.)
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.6.59}
-\item Changed \verb|fastcheck| from a boolean to a string preference. Its
- legal values are \verb|yes| (for a fast check), \verb|no| (for a safe
- check), or \verb|default| (for a fast check---which also happens to be
- safe---when running on Unix and a safe check when on Windows). The default
- is \verb|default|.
- \item Several preferences have been renamed for consistency. All
- preference names are now spelled out in lowercase. For backward
- compatibility, the old names still work, but they are not mentioned in
- the manual any more.
-\item The temp files created by the 'diff' and 'merge' commands are now
- named by {\em pre}pending a new prefix to the file name, rather than
- appending a suffix. This should avoid confusing diff/merge programs
- that depend on the suffix to guess the type of the file contents.
-\item We now set the keepalive option on the server socket, to make sure
- that the server times out if the communication link is unexpectedly broken.
-\item Bug fixes:
-\begin{itemize}
-\item When updating small files, Unison now closes the destination file.
-\item File permissions are properly updated when the file is behind a
- followed link.
-\item Several other small fixes.
-\end{itemize}
-\end{changesfromversion}
-
-
-\begin{changesfromversion}{2.6.38}
-\item Major Windows performance improvement!
-
-We've added a preference \verb|fastcheck| that makes Unison look only at
-a file's creation time and last-modified time to check whether it has
-changed. This should result in a huge speedup when checking for updates
-in large replicas.
-
- When this switch is set, Unison will use file creation times as
- 'pseudo inode numbers' when scanning Windows replicas for updates,
- instead of reading the full contents of every file. This may cause
- Unison to miss propagating an update if the create time,
- modification time, and length of the file are all unchanged by
- the update (this is not easy to achieve, but it can be done).
- However, Unison will never {\em overwrite} such an update with
- a change from the other replica, since it
- always does a safe check for updates just before propagating a
- change. Thus, it is reasonable to use this switch most of the time
- and occasionally run Unison once with {\tt fastcheck} set to false,
- if you are worried that Unison may have overlooked an update.
-
- Warning: This change is has not yet been thoroughly field-tested. If you
- set the \verb|fastcheck| preference, pay careful attention to what
- Unison is doing.
-
-\item New functionality: centralized backups and merging
-\begin{itemize}
-\item This version incorporates two pieces of major new functionality,
- implemented by Sylvain Roy during a summer internship at Penn: a
- {\em centralized backup} facility that keeps a full backup of
- (selected files
- in) each replica, and a {\em merging} feature that allows Unison to
- invoke an external file-merging tool to resolve conflicting changes to
- individual files.
-
-\item Centralized backups:
-\begin{itemize}
- \item Unison now maintains full backups of the last-synchronized versions
- of (some of) the files in each replica; these function both as
- backups in the usual sense
- and as the ``common version'' when invoking external
- merge programs.
- \item The backed up files are stored in a directory ~/.unison/backup on each
- host. (The name of this directory can be changed by setting
- the environment variable \verb|UNISONBACKUPDIR|.)
- \item The predicate \verb|backup| controls which files are actually
- backed up:
- giving the preference '\verb|backup = Path *|' causes backing up
- of all files.
- \item Files are added to the backup directory whenever unison updates
- its archive. This means that
- \begin{itemize}
- \item When unison reconstructs its archive from scratch (e.g.,
- because of an upgrade, or because the archive files have
- been manually deleted), all files will be backed up.
- \item Otherwise, each file will be backed up the first time unison
- propagates an update for it.
- \end{itemize}
- \item The preference \verb|backupversions| controls how many previous
- versions of each file are kept. The default is 2 (i.e., the last
- synchronized version plus one backup).
- \item For backward compatibility, the \verb|backups| preference is also
- still supported, but \verb|backup| is now preferred.
- \item It is OK to manually delete files from the backup directory (or to throw
- away the directory itself). Before unison uses any of these files for
- anything important, it checks that its fingerprint matches the one
- that it expects.
-\end{itemize}
-
-\item Merging:
-\begin{itemize}
- \item Both user interfaces offer a new 'merge' command, invoked by pressing
- 'm' (with a changed file selected).
- \item The actual merging is performed by an external program.
- The preferences \verb|merge| and \verb|merge2| control how this
- program is invoked. If a backup exists for this file (see the
- \verb|backup| preference), then the \verb|merge| preference is used for
- this purpose; otherwise \verb|merge2| is used. In both cases, the
- value of the preference should be a string representing the command
- that should be passed to a shell to invoke the
- merge program. Within this string, the special substrings
- \verb|CURRENT1|, \verb|CURRENT2|, \verb|NEW|, and \verb|OLD| may appear
- at any point. Unison will substitute these as follows before invoking
- the command:
- \begin{itemize}
- \item \relax\verb|CURRENT1| is replaced by the name of the local
- copy of the file;
- \item \relax\verb|CURRENT2| is replaced by the name of a temporary
- file, into which the contents of the remote copy of the file have
- been transferred by Unison prior to performing the merge;
- \item \relax\verb|NEW| is replaced by the name of a temporary
- file that Unison expects to be written by the merge program when
- it finishes, giving the desired new contents of the file; and
- \item \relax\verb|OLD| is replaced by the name of the backed up
- copy of the original version of the file (i.e., its state at the
- end of the last successful run of Unison), if one exists
- (applies only to \verb|merge|, not \verb|merge2|).
- \end{itemize}
- For example, on Unix systems setting the \verb|merge| preference to
-\begin{verbatim}
- merge = diff3 -m CURRENT1 OLD CURRENT2 > NEW
-\end{verbatim}
- will tell Unison to use the external \verb|diff3| program for merging.
-
- A large number of external merging programs are available. For
- example, \verb|emacs| users may find the following convenient:
-\begin{verbatim}
- merge2 = emacs -q --eval '(ediff-merge-files "CURRENT1" "CURRENT2"
- nil "NEW")'
- merge = emacs -q --eval '(ediff-merge-files-with-ancestor
- "CURRENT1" "CURRENT2" "OLD" nil "NEW")'
-\end{verbatim}
-(These commands are displayed here on two lines to avoid running off the
-edge of the page. In your preference file, each should be written on a
-single line.)
-
- \item If the external program exits without leaving any file at the
- path \verb|NEW|,
- Unison considers the merge to have failed. If the merge program writes
- a file called \verb|NEW| but exits with a non-zero status code,
- then Unison
- considers the merge to have succeeded but to have generated conflicts.
- In this case, it attempts to invoke an external editor so that the
- user can resolve the conflicts. The value of the \verb|editor|
- preference controls what editor is invoked by Unison. The default
- is \verb|emacs|.
-
- \item Please send us suggestions for other useful values of the
- \verb|merge2| and \verb|merge| preferences -- we'd like to give several
- examples in the manual.
-\end{itemize}
-\end{itemize}
-
-\item Smaller changes:
-\begin{itemize}
-\item When one preference file includes another, unison no longer adds the
- suffix '\verb|.prf|' to the included file by default. If a file with
- precisely the given name exists in the .unison directory, it will be used;
- otherwise Unison will
- add \verb|.prf|, as it did before. (This change means that included
- preference files can be named \verb|blah.include| instead of
- \verb|blah.prf|, so that unison will not offer them in its 'choose
- a preference file' dialog.)
-\item For Linux systems, we now offer both a statically linked and a dynamically
- linked executable. The static one is larger, but will probably run on more
- systems, since it doesn't depend on the same versions of dynamically
- linked library modules being available.
-\item Fixed the \verb|force| and \verb|prefer| preferences, which were
- getting the propagation direction exactly backwards.
-\item Fixed a bug in the startup code that would cause unison to crash
- when the default profile (\verb|~/.unison/default.prf|) does not exist.
-\item Fixed a bug where, on the run when a profile is first created,
- Unison would confusingly display the roots in reverse order in the user
- interface.
-\end{itemize}
-
-\item For developers:
-\begin{itemize}
-\item We've added a module dependency diagram to the source distribution, in
- \verb|src/DEPENDENCIES.ps|, to help new prospective developers with
- navigating the code.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.6.11}
-\item \incompatible{} Archive format has changed.
-
-\item \incompatible{} The startup sequence has been completely rewritten
-and greatly simplified. The main user-visible change is that the
-\verb|defaultpath| preference has been removed. Its effect can be
-approximated by using multiple profiles, with \verb|include| directives
-to incorporate common settings. All uses of \verb|defaultpath| in
-existing profiles should be changed to \verb|path|.
-
-Another change in startup behavior that will affect some users is that it
-is no longer possible to specify roots {\em both} in the profile {\em
- and} on the command line.
-
-You can achieve a similar effect, though, by breaking your profile into
-two:
-\begin{verbatim}
-
- default.prf =
- root = blah
- root = foo
- include common
-
- common.prf =
- <everything else>
-\end{verbatim}
-Now do
-\begin{verbatim}
- unison common root1 root2
-\end{verbatim}
-when you want to specify roots explicitly.
-
-\item The \verb|-prefer| and \verb|-force| options have been extended to
-allow users to specify that files with more recent modtimes should be
-propagated, writing either \verb|-prefer newer| or \verb|-force newer|.
-(For symmetry, Unison will also accept \verb|-prefer older| or
-\verb|-force older|.) The \verb|-force older/newer| options can only be
-used when \verb|-times| is also set.
-
-The graphical user interface provides access to these facilities on a
-one-off basis via the \verb|Actions| menu.
-
-\item Names of roots can now be ``aliased'' to allow replicas to be
-relocated without changing the name of the archive file where Unison
-stores information between runs. (This feature is for experts only. See
-the ``Archive Files'' section of the manual for more information.)
-
-\item Graphical user-interface:
-\begin{itemize}
-\item A new command is provided in the Synchronization menu for
- switching to a new profile without restarting Unison from scratch.
-\item The GUI also supports one-key shortcuts for commonly
-used profiles. If a profile contains a preference of the form
-%
-'\verb|key = n|', where \verb|n| is a single digit, then pressing this
-key will cause Unison to immediately switch to this profile and begin
-synchronization again from scratch. (Any actions that may have been
-selected for a set of changes currently being displayed will be
-discarded.)
-
-\item Each profile may include a preference '\verb|label = <string>|' giving a
- descriptive string that described the options selected in this profile.
- The string is listed along with the profile name in the profile selection
- dialog, and displayed in the top-right corner of the main Unison window.
-\end{itemize}
-
-\item Minor:
-\begin{itemize}
-\item Fixed a bug that would sometimes cause the 'diff' display to order
- the files backwards relative to the main user interface. (Thanks
- to Pascal Brisset for this fix.)
-\item On Unix systems, the graphical version of Unison will check the
- \verb|DISPLAY| variable and, if it is not set, automatically fall back
- to the textual user interface.
-\item Synchronization paths (\verb|path| preferences) are now matched
- against the ignore preferences. So if a path is both specified in a
- \verb|path| preference and ignored, it will be skipped.
-\item Numerous other bugfixes and small improvements.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.6.1}
-\item The synchronization of modification times has been disabled for
- directories.
-
-\item Preference files may now include lines of the form
- \verb+include <name>+, which will cause \verb+name.prf+ to be read
- at that point.
-
-\item The synchronization of permission between Windows and Unix now
- works properly.
-
-\item A binding \verb|CYGWIN=binmode| in now added to the environment
- so that the Cygwin port of OpenSSH works properly in a non-Cygwin
- context.
-
-\item The \verb|servercmd| and \verb|addversionno| preferences can now
- be used together: \verb|-addversionno| appends an appropriate
- \verb+-NNN+ to the server command, which is found by using the value
- of the \verb|-servercmd| preference if there is one, or else just
- \verb|unison|.
-
-\item Both \verb|'-pref=val'| and \verb|'-pref val'| are now allowed for
- boolean values. (The former can be used to set a preference to false.)
-
-\item Lot of small bugs fixed.
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.5.31}
-\item The \verb|log| preference is now set to \verb|true| by default,
- since the log file seems useful for most users.
-\item Several miscellaneous bugfixes (most involving symlinks).
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.5.25}
-\item \incompatible{} Archive format has changed (again).
-
-\item Several significant bugs introduced in 2.5.25 have been fixed.
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.5.1}
-\item \incompatible{} Archive format has changed. Make sure you
-synchronize your replicas before upgrading, to avoid spurious
-conflicts. The first sync after upgrading will be slow.
-
-\item New functionality:
-\begin{itemize}
-\item Unison now synchronizes file modtimes, user-ids, and group-ids.
-
-These new features are controlled by a set of new preferences, all of
-which are currently \verb|false| by default.
-
-\begin{itemize}
-\item When the \verb|times| preference is set to \verb|true|, file
-modification times are propaged. (Because the representations of time
-may not have the same granularity on both replicas, Unison may not always
-be able to make the modtimes precisely equal, but it will get them as
-close as the operating systems involved allow.)
-\item When the \verb|owner| preference is set to \verb|true|, file
-ownership information is synchronized.
-\item When the \verb|group| preference is set to \verb|true|, group
-information is synchronized.
-\item When the \verb|numericIds| preference is set to \verb|true|, owner
-and group information is synchronized numerically. By default, owner and
-group numbers are converted to names on each replica and these names are
-synchronized. (The special user id 0 and the special group 0 are never
-mapped via user/group names even if this preference is not set.)
-\end{itemize}
-
-\item Added an integer-valued preference \verb|perms| that can be used to
-control the propagation of permission bits. The value of this preference
-is a mask indicating which permission bits should be synchronized. It is
-set by default to $0o1777$: all bits but the set-uid and set-gid bits are
-synchronised (synchronizing theses latter bits can be a security hazard).
-If you want to synchronize all bits, you can set the value of this
-preference to $-1$.
-
-\item Added a \verb|log| preference (default \verb|false|), which makes
-Unison keep a complete record of the changes it makes to the replicas.
-By default, this record is written to a file called \verb|unison.log| in
-the user's home directory (the value of the \verb|HOME| environment
-variable). If you want it someplace else, set the \verb|logfile|
-preference to the full pathname you want Unison to use.
-
-\item Added an \verb|ignorenot| preference that maintains a set of patterns
- for paths that should definitely {\em not} be ignored, whether or not
- they match an \verb|ignore| pattern. (That is, a path will now be ignored
- iff it matches an ignore pattern and does not match any ignorenot patterns.)
-\end{itemize}
-
-\item User-interface improvements:
-\begin{itemize}
-\item Roots are now displayed in the user interface in the same order
-as they were given on the command line or in the preferences file.
-\item When the \verb|batch| preference is set, the graphical user interface no
- longer waits for user confirmation when it displays a warning message: it
- simply pops up an advisory window with a Dismiss button at the bottom and
- keeps on going.
-\item Added a new preference for controlling how many status messages are
- printed during update detection: \verb|statusdepth| controls the maximum
- depth for paths on the local machine (longer paths are not displayed, nor
- are non-directory paths). The value should be an integer; default is 1.
-\item Removed the \verb|trace| and \verb|silent| preferences. They did
-not seem very useful, and there were too many preferences for controlling
-output in various ways.
-\item The text UI now displays just the default command (the one that
-will be used if the user just types \verb|<return>|) instead of all
-available commands. Typing \verb|?| will print the full list of
-possibilities.
-\item The function that finds the canonical hostname of the local host
-(which is used, for example, in calculating the name of the archive file
-used to remember which files have been synchronized) normally uses the
-\verb|gethostname| operating system call. However, if the environment
-variable \verb|UNISONLOCALHOSTNAME| is set, its value will now be used
-instead. This makes it easier to use Unison in situations where a
-machine's name changes frequently (e.g., because it is a laptop and gets
-moved around a lot).
-\item File owner and group are now displayed in the ``detail window'' at
-the bottom of the screen, when unison is configured to synchronize them.
-\end{itemize}
-
-\item For hackers:
-\begin{itemize}
-\item Updated to Jacques Garrigue's new version of \verb|lablgtk|, which
- means we can throw away our local patched version.
-
- If you're compiling the GTK version of unison from sources, you'll need
- to update your copy of lablgtk to the developers release.
- (Warning: installing lablgtk under Windows is currently a bit
- challenging.)
-
-\item The TODO.txt file (in the source distribution) has been cleaned up
-and reorganized. The list of pending tasks should be much easier to
-make sense of, for people that may want to contribute their programming
-energies. There is also a separate file BUGS.txt for open bugs.
-\item The Tk user interface has been removed (it was not being maintained
-and no longer compiles).
-\item The \verb|debug| preference now prints quite a bit of additional
-information that should be useful for identifying sources of problems.
-\item The version number of the remote server is now checked right away
- during the connection setup handshake, rather than later. (Somebody
- sent a bug report of a server crash that turned out to come from using
- inconsistent versions: better to check this earlier and in a way that
- can't crash either client or server.)
-\item Unison now runs correctly on 64-bit architectures (e.g. Alpha
-linux). We will not be distributing binaries for these architectures
-ourselves (at least for a while) but if someone would like to make them
-available, we'll be glad to provide a link to them.
-\end{itemize}
-
-\item Bug fixes:
-\begin{itemize}
-\item Pattern matching (e.g. for \verb|ignore|) is now case-insensitive
- when Unison is in case-insensitive mode (i.e., when one of the replicas
- is on a windows machine).
-\item Some people had trouble with mysterious failures during
- propagation of updates, where files would be falsely reported as having
- changed during synchronization. This should be fixed.
-\item Numerous smaller fixes.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.4.1}
-\item Added a number of 'sorting modes' for the user interface. By
-default, conflicting changes are displayed at the top, and the rest of
-the entries are sorted in alphabetical order. This behavior can be
-changed in the following ways:
-\begin{itemize}
-\item Setting the \verb|sortnewfirst| preference to \verb|true| causes
-newly created files to be displayed before changed files.
-\item Setting \verb|sortbysize| causes files to be displayed in
-increasing order of size.
-\item Giving the preference \verb|sortfirst=<pattern>| (where
-\verb|<pattern>| is a path descriptor in the same format as 'ignore' and 'follow'
-patterns, causes paths matching this pattern to be displayed first.
-\item Similarly, giving the preference \verb|sortlast=<pattern>|
-causes paths matching this pattern to be displayed last.
-\end{itemize}
-The sorting preferences are described in more detail in the user manual.
-The \verb|sortnewfirst| and \verb|sortbysize| flags can also be accessed
-from the 'Sort' menu in the grpahical user interface.
-
-\item Added two new preferences that can be used to change unison's
-fundamental behavior to make it more like a mirroring tool instead of
-a synchronizer.
-\begin{itemize}
-\item Giving the preference \verb|prefer| with argument \verb|<root>|
-(by adding \verb|-prefer <root>| to the command line or \verb|prefer=<root>|)
-to your profile) means that, if there is a conflict, the contents of
-\verb|<root>|
-should be propagated to the other replica (with no questions asked).
-Non-conflicting changes are treated as usual.
-\item Giving the preference \verb|force| with argument \verb|<root>|
-will make unison resolve {\em all} differences in favor of the given
-root, even if it was the other replica that was changed.
-\end{itemize}
-These options should be used with care! (More information is available in
-the manual.)
-
-\item Small changes:
-\begin{itemize}
-\item
-Changed default answer to 'Yes' in all two-button dialogs in the
- graphical interface (this seems more intuitive).
-
-\item The \verb|rsync| preference has been removed (it was used to
-activate rsync compression for file transfers, but rsync compression is
-now enabled by default).
-\item In the text user interface, the arrows indicating which direction
-changes are being
- propagated are printed differently when the user has overridded Unison's
- default recommendation (\verb|====>| instead of \verb|---->|). This
- matches the behavior of the graphical interface, which displays such
- arrows in a different color.
-\item Carriage returns (Control-M's) are ignored at the ends of lines in
- profiles, for Windows compatibility.
-\item All preferences are now fully documented in the user manual.
-\end{itemize}
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.3.12}
-\item \incompatible{} Archive format has changed. Make sure you
-synchronize your replicas before upgrading, to avoid spurious
-conflicts. The first sync after upgrading will be slow.
-
-\item New/improved functionality:
-\begin{itemize}
-\item A new preference -sortbysize controls the order in which changes
- are displayed to the user: when it is set to true, the smallest
- changed files are displayed first. (The default setting is false.)
-\item A new preference -sortnewfirst causes newly created files to be
- listed before other updates in the user interface.
-\item We now allow the ssh protocol to specify a port.
-\item Incompatible change: The unison: protocol is deprecated, and we added
- file: and socket:. You may have to modify your profiles in the
- .unison directory.
- If a replica is specified without an explicit protocol, we now
- assume it refers to a file. (Previously "//saul/foo" meant to use
- SSH to connect to saul, then access the foo directory. Now it means
- to access saul via a remote file mechanism such as samba; the old
- effect is now achieved by writing {\tt ssh://saul/foo}.)
-\item Changed the startup sequence for the case where roots are given but
- no profile is given on the command line. The new behavior is to
- use the default profile (creating it if it does not exist), and
- temporarily override its roots. The manual claimed that this case
- would work by reading no profile at all, but AFAIK this was never
- true.
-\item In all user interfaces, files with conflicts are always listed first
-\item A new preference 'sshversion' can be used to control which version
- of ssh should be used to connect to the server. Legal values are 1 and 2.
- (Default is empty, which will make unison use whatever version of ssh
- is installed as the default 'ssh' command.)
-\item The situation when the permissions of a file was updated the same on
- both side is now handled correctly (we used to report a spurious conflict)
-
-\end{itemize}
-
-\item Improvements for the Windows version:
-\begin{itemize}
-\item The fact that filenames are treated case-insensitively under
-Windows should now be handled correctly. The exact behavior is described
-in the cross-platform section of the manual.
-\item It should be possible to synchronize with Windows shares, e.g.,
- //host/drive/path.
-\item Workarounds to the bug in syncing root directories in Windows.
-The most difficult thing to fix is an ocaml bug: Unix.opendir fails on
-c: in some versions of Windows.
-\end{itemize}
-
-\item Improvements to the GTK user interface (the Tk interface is no
-longer being maintained):
-\begin{itemize}
-\item The UI now displays actions differently (in blue) when they have been
- explicitly changed by the user from Unison's default recommendation.
-\item More colorful appearance.
-\item The initial profile selection window works better.
-\item If any transfers failed, a message to this effect is displayed along with
- 'Synchronization complete' at the end of the transfer phase (in case they
- may have scrolled off the top).
-\item Added a global progress meter, displaying the percentage of {\em total}
- bytes that have been transferred so far.
-\end{itemize}
-
-\item Improvements to the text user interface:
-\begin{itemize}
-\item The file details will be displayed automatically when a
- conflict is been detected.
-\item when a warning is generated (e.g. for a temporary
- file left over from a previous run of unison) Unison will no longer
- wait for a response if it is running in -batch mode.
-\item The UI now displays a short list of possible inputs each time it waits
- for user interaction.
-\item The UI now quits immediately (rather than looping back and starting
- the interaction again) if the user presses 'q' when asked whether to
- propagate changes.
-\item Pressing 'g' in the text user interface will proceed immediately
- with propagating updates, without asking any more questions.
-\end{itemize}
-
-\item Documentation and installation changes:
-\begin{itemize}
-\item The manual now includes a FAQ, plus sections on common problems and
-on tricks contributed by users.
-\item Both the download page and the download directory explicitly say
-what are the current stable and beta-test version numbers.
-\item The OCaml sources for the up-to-the-minute developers' version (not
-guaranteed to be stable, or even to compile, at any given time!) are now
-available from the download page.
-\item Added a subsection to the manual describing cross-platform
- issues (case conflicts, illegal filenames)
-\end{itemize}
-
-\item Many small bug fixes and random improvements.
-
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.3.1}
-\item Several bug fixes. The most important is a bug in the rsync
-module that would occasionally cause change propagation to fail with a
-'rename' error.
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.2}
-\item The multi-threaded transport system is now disabled by default.
-(It is not stable enough yet.)
-\item Various bug fixes.
-\item A new experimental feature:
-
- The final component of a -path argument may now be the wildcard
- specifier \verb|*|. When Unison sees such a path, it expands this path on
- the client into into the corresponding list of paths by listing the
- contents of that directory.
-
- Note that if you use wildcard paths from the command line, you will
- probably need to use quotes or a backslash to prevent the * from
- being interpreted by your shell.
-
- If both roots are local, the contents of the first one will be used
- for expanding wildcard paths. (Nb: this is the first one {\em after} the
- canonization step -- i.e., the one that is listed first in the user
- interface -- not the one listed first on the command line or in the
- preferences file.)
-\end{changesfromversion}
-
-\begin{changesfromversion}{2.1}
-\item The transport subsystem now includes an implementation by
-Sylvain Gommier and Norman Ramsey of Tridgell and Mackerras's
-\verb|rsync| protocol. This protocol achieves much faster
-transfers when only a small part of a large file has been changed by
-sending just diffs. This feature is mainly helpful for transfers over
-slow links---on fast local area networks it can actually degrade
-performance---so we have left it off by default. Start unison with
-the \verb|-rsync| option (or put \verb|rsync=true| in your preferences
-file) to turn it on.
-
-\item ``Progress bars'' are now diplayed during remote file transfers,
-showing what percentage of each file has been transferred so far.
-
-\item The version numbering scheme has changed. New releases will now
- be have numbers like 2.2.30, where the second component is
- incremented on every significant public release and the third
- component is the ``patch level.''
-
-\item Miscellaneous improvements to the GTK-based user interface.
-\item The manual is now available in PDF format.
-
-\item We are experimenting with using a multi-threaded transport
-subsystem to transfer several files at the same time, making
-much more effective use of available network bandwidth. This feature
-is not completely stable yet, so by default it is disabled in the
-release version of Unison.
-
-If you want to play with the multi-threaded version, you'll need to
-recompile Unison from sources (as described in the documentation),
-setting the THREADS flag in Makefile.OCaml to true. Make sure that
-your OCaml compiler has been installed with the \verb|-with-pthreads|
-configuration option. (You can verify this by checking whether the
-file \verb|threads/threads.cma| in the OCaml standard library
-directory contains the string \verb|-lpthread| near the end.)
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.292}
-\item Reduced memory footprint (this is especially important during
-the first run of unison, where it has to gather information about all
-the files in both repositories).
-\item Fixed a bug that would cause the socket server under NT to fail
- after the client exits.
-\item Added a SHIFT modifier to the Ignore menu shortcut keys in GTK
- interface (to avoid hitting them accidentally).
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.231}
-\item Tunneling over ssh is now supported in the Windows version. See
-the installation section of the manual for detailed instructions.
-
-\item The transport subsystem now includes an implementation of the
-\verb|rsync| protocol, built by Sylvain Gommier and Norman Ramsey.
-This protocol achieves much faster transfers when only a small part of
-a large file has been changed by sending just diffs. The rsync
-feature is off by default in the current version. Use the
-\verb|-rsync| switch to turn it on. (Nb. We still have a lot of
-tuning to do: you may not notice much speedup yet.)
-
-\item We're experimenting with a multi-threaded transport subsystem,
-written by Jerome Vouillon. The downloadable binaries are still
-single-threaded: if you want to try the multi-threaded version, you'll
-need to recompile from sources. (Say \verb|make THREADS=true|.)
-Native thread support from the compiler is required. Use the option
-\verb|-threads N| to select the maximal number of concurrent
-threads (default is 5). Multi-threaded
-and single-threaded clients/servers can interoperate.
-
-\item A new GTK-based user interface is now available, thanks to
-Jacques Garrigue. The Tk user interface still works, but we'll be
-shifting development effort to the GTK interface from now on.
-\item OCaml 3.00 is now required for compiling Unison from sources.
-The modules \verb|uitk| and \verb|myfileselect| have been changed to
-use labltk instead of camltk. To compile the Tk interface in Windows,
-you must have ocaml-3.00 and tk8.3. When installing tk8.3, put it in
-\verb|c:\Tcl| rather than the suggested \verb|c:\Program Files\Tcl|,
-and be sure to install the headers and libraries (which are not
-installed by default).
-
-\item Added a new \verb|-addversionno| switch, which causes unison to
-use \verb|unison-<currentversionnumber>| instead of just \verb|unison|
-as the remote server command. This allows multiple versions of unison
-to coexist conveniently on the same server: whichever version is run
-on the client, the same version will be selected on the server.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.219}
-\item \incompatible{} Archive format has changed. Make sure you
-synchronize your replicas before upgrading, to avoid spurious
-conflicts. The first sync after upgrading will be slow.
-
-\item This version fixes several annoying bugs, including:
-\begin{itemize}
-\item Some cases where propagation of file permissions was not
-working.
-\item umask is now ignored when creating directories
-\item directories are create writable, so that a read-only directory and
- its contents can be propagated.
-\item Handling of warnings generated by the server.
-\item Synchronizing a path whose parent is not a directory on both sides is
-now flagged as erroneous.
-\item Fixed some bugs related to symnbolic links and nonexistant roots.
-\begin{itemize}
-\item
- When a change (deletion or new contents) is propagated onto a
- 'follow'ed symlink, the file pointed to by the link is now changed.
- (We used to change the link itself, which doesn't fit our assertion
- that 'follow' means the link is completely invisible)
- \item When one root did not exist, propagating the other root on top of it
- used to fail, becuase unison could not calculate the working directory
- into which to write changes. This should be fixed.
-\end{itemize}
-\end{itemize}
-
-\item A human-readable timestamp has been added to Unison's archive files.
-
-\item The semantics of Path and Name regular expressions now
-correspond better.
-
-\item Some minor improvements to the text UI (e.g. a command for going
-back to previous items)
-
-\item The organization of the export directory has changed --- should
-be easier to find / download things now.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.200}
-\item \incompatible{} Archive format has changed. Make sure you
-synchronize your replicas before upgrading, to avoid spurious
-conflicts. The first sync after upgrading will be slow.
-
-\item This version has not been tested extensively on Windows.
-
-\item Major internal changes designed to make unison safer to run
-at the same time as the replicas are being changed by the user.
-
-\item Internal performance improvements.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.190}
-\item \incompatible{} Archive format has changed. Make sure you
-synchronize your replicas before upgrading, to avoid spurious
-conflicts. The first sync after upgrading will be slow.
-
-\item A number of internal functions have been changed to reduce the
-amount of memory allocation, especially during the first
-synchronization. This should help power users with very big replicas.
-
-\item Reimplementation of low-level remote procedure call stuff, in
-preparation for adding rsync-like smart file transfer in a later
-release.
-
-\item Miscellaneous bug fixes.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.180}
-\item \incompatible{} Archive format has changed. Make sure you
-synchronize your replicas before upgrading, to avoid spurious
-conflicts. The first sync after upgrading will be slow.
-
-\item Fixed some small bugs in the interpretation of ignore patterns.
-
-\item Fixed some problems that were preventing the Windows version
-from working correctly when click-started.
-
-\item Fixes to treatment of file permissions under Windows, which were
-causing spurious reports of different permissions when synchronizing
-between windows and unix systems.
-
-\item Fixed one more non-tail-recursive list processing function,
-which was causing stack overflows when synchronizing very large
-replicas.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.169}
-\item The text user interface now provides commands for ignoring
- files.
-\item We found and fixed some {\em more} non-tail-recursive list
- processing functions. Some power users have reported success with
- very large replicas.
-\item \incompatible
-Files ending in \verb|.tmp| are no longer ignored automatically. If you want
-to ignore such files, put an appropriate ignore pattern in your profile.
-
-\item \incompatible{} The syntax of {\tt ignore} and {\tt follow}
-patterns has changed. Instead of putting a line of the form
-\begin{verbatim}
- ignore = <regexp>
-\end{verbatim}
- in your profile ({\tt .unison/default.prf}), you should put:
-\begin{verbatim}
- ignore = Regex <regexp>
-\end{verbatim}
-Moreover, two other styles of pattern are also recognized:
-\begin{verbatim}
- ignore = Name <name>
-\end{verbatim}
-matches any path in which one component matches \verb|<name>|, while
-\begin{verbatim}
- ignore = Path <path>
-\end{verbatim}
-matches exactly the path \verb|<path>|.
-
-Standard ``globbing'' conventions can be used in \verb|<name>| and
-\verb|<path>|:
-\begin{itemize}
-\item a \verb|?| matches any single character except \verb|/|
-\item a \verb|*| matches any sequence of characters not including \verb|/|
-\item \verb|[xyz]| matches any character from the set $\{{\tt x},
- {\tt y}, {\tt z} \}$
-\item \verb|{a,bb,ccc}| matches any one of \verb|a|, \verb|bb|, or
- \verb|ccc|.
-\end{itemize}
-
-See the user manual for some examples.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.146}
-\item Some users were reporting stack overflows when synchronizing
- huge directories. We found and fixed some non-tail-recursive list
- processing functions, which we hope will solve the problem. Please
- give it a try and let us know.
-\item Major additions to the documentation.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.142}
-\item Major internal tidying and many small bugfixes.
-\item Major additions to the user manual.
-\item Unison can now be started with no arguments -- it will prompt
-automatically for the name of a profile file containing the roots to
-be synchronized. This makes it possible to start the graphical UI
-from a desktop icon.
-\item Fixed a small bug where the text UI on NT was raising a 'no such
- signal' exception.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.139}
-\item The precompiled windows binary in the last release was compiled
-with an old OCaml compiler, causing propagation of permissions not to
-work (and perhaps leading to some other strange behaviors we've heard
-reports about). This has been corrected. If you're using precompiled
-binaries on Windows, please upgrade.
-\item Added a \verb|-debug| command line flag, which controls debugging
-of various modules. Say \verb|-debug XXX| to enable debug tracing for
-module \verb|XXX|, or \verb|-debug all| to turn on absolutely everything.
-\item Fixed a small bug where the text UI on NT was raising a 'no such signal'
-exception.
-\end{changesfromversion}
-
-\begin{changesfromversion}{1.111}
-\item \incompatible{} The names and formats of the preference files in
-the .unison directory have changed. In particular:
-\begin{itemize}
-\item the file ``prefs'' should be renamed to default.prf
-\item the contents of the file ``ignore'' should be merged into
- default.prf. Each line of the form \verb|REGEXP| in ignore should
- become a line of the form \verb|ignore = REGEXP| in default.prf.
-\end{itemize}
-\item Unison now handles permission bits and symbolic links. See the
-manual for details.
-
-\item You can now have different preference files in your .unison
-directory. If you start unison like this
-\begin{verbatim}
- unison profilename
-\end{verbatim}
-(i.e. with just one ``anonymous'' command-line argument), then the
-file \verb|~/.unison/profilename.prf| will be loaded instead of
-\verb|default.prf|.
-
-\item Some improvements to terminal handling in the text user interface
-
-\item Added a switch -killServer that terminates the remote server process
-when the unison client is shutting down, even when using sockets for
-communication. (By default, a remote server created using ssh/rsh is
-terminated automatically, while a socket server is left running.)
-\item When started in 'socket server' mode, unison prints 'server started' on
- stderr when it is ready to accept connections.
- (This may be useful for scripts that want to tell when a socket-mode server
- has finished initalization.)
-\item We now make a nightly mirror of our current internal development
- tree, in case anyone wants an up-to-the-minute version to hack
- around with.
-\item Added a file CONTRIB with some suggestions for how to help us
-make Unison better.
-\end{changesfromversion}
-
Copied: branches/2.45/doc/changes.tex (from rev 486, trunk/doc/changes.tex)
===================================================================
--- branches/2.45/doc/changes.tex (rev 0)
+++ branches/2.45/doc/changes.tex 2012-04-02 15:54:47 UTC (rev 487)
@@ -0,0 +1,1901 @@
+\begin{changesfromversion}{2.40.63}
+\item New preference {\tt fastercheckUNSAFE}, which can be used (with care!)
+to achieve {\em much} faster update detection when all the common files in
+the two replicas are known to be identical. See the manual for more
+information.
+
+This feature should still be considered experimental, but it's ready for
+other people to try out.
+\item Added option {\tt clientHostName}. If specified, it will be used to as
+the client host name, overriding {\tt UNISONLOCALHOSTNAME} and the actual
+host name.
+\item OS X GUI:
+\begin{itemize}
+\item fix crash under Lion, because of problems with the toolbar, using the
+fix suggested in {\tt http://blitzbasic.com/Community/posts.php?topic=95778}.
+
+\item uimacnew09 is now the standard graphical interface on OSX
+\item A small improvement to the uimacnew09 interface from Alan Schmitt
+ and Steve Kalkwarf: when Unison is run with the -batch flag, the
+ interface will now automatically propagate changes and terminate,
+ without waiting for user interaction.
+\item Show a modal warning window if there is no archive for the hosts. The
+user can then choose to exit or proceed (proceed is the default). The window
+is not shown if the {\tt batch} preference is true.
+\item file details panel selectable
+\end{itemize}
+\item GTK GUI:
+\begin{itemize}
+\item New version of uigtk2.ml from Matt Zagrabelny that reorganizes the
+icons in a slightly more intuitive way.
+\end{itemize}
+\item Minor fixes:
+\begin{itemize}
+\item Setting the {\tt prefer} preference to {\tt older} or {\tt newer} now
+propagates deletions when there is no conflict.
+\item Correctly quote the path when running merge commands.
+\item Add quotes to paths when calling external file watcher utility.
+\item Incorporate a patch to fsmonitor.py (the external filewatcher
+ utility) from Tomasz Zernicki to make it work better under Windows.
+\item Incorporated new version of fsmonitor.py from Christophe Gohle
+\item Fixed incompatibility with OpenSSH 5.6.
+\item Fixed fingerprint cache: do not cache file properties
+\item Some spelling corrections in documentation and comments from Stephane
+Glondu
+\item Fixed O_APPEND mode for open under Windows (the previous attempt in
+ revision 422 was incomplete)
+\item Fixed String.sub invalid argument error when an AppleDouble file does
+ not contain a finder information field
+\item Trim duplicate paths when using "-repeat watch"
+\item Unison now passes path arguments and --follow directives to
+ fsmonitor.py. This seems to work except for one small issue with
+ how fsmonitor.py treats {\tt -follow} directives for directories that
+ don't exist (or maybe this is an issue with how it treats any kind
+ of monitoring when the thing being monitored doesn't exist?). If we
+ create a symlink to a nonexistant directory, give Unison (hence
+ fsmonitor.py) a 'follow' directive for the symlink, start unison, and
+ {\em then} create the directory, fsmonitor.py misses the change.
+\item Lines added in profile files by unison always start at a new line
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.40.1}
+\item Added "BelowPath" patterns, that match a path as well as all paths below
+ (convenient to use with no{deletion,update,creation}partial preferences)
+\item Added a "fat" preference that makes Unison use the right options
+ when one of the replica is on a FAT filesystem.
+\item Allow "prefer/force=newer" even when not synchronizing modification
+ times. (The reconciler will not be aware of the modification time
+ of unchanged files, so the synchronization choices of Unison can be
+ different from when "times=true", but the behavior remains sane:
+ changed files with the most recent modification time will be
+ propagated.)
+\item Minor fixes and improvements:
+\begin{itemize}
+\item Compare filenames up to decomposition in case sensitive mode when
+ one host is running MacOSX and the unicode preference is set to
+ true.
+\item Rsync: somewhat faster compressor
+\item Make Unicode the default on all architectures (it was only the
+ default when a Mac OS X or Windows machine was involved).
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.32}
+\item Major enhancement: Unicode support.
+\begin{itemize}
+\item Unison should now handle unicode filenames correctly on all platforms.
+\item This functionality is controlled by a new preference {\tt unicode}.
+\item Unicode mode is now the default when one of the hosts is under
+ Windows or MacOS. This may make upgrades a bit more painful (the
+ archives cannot be reused), but this is a much saner default.
+\end{itemize}
+\item Partial transfer of directories. If an error occurs while
+ transferring a directory, the part transferred so far is copied into
+ place (and the archives are updated accordingly).
+ The "maxerrors" preference controls how many transfer error Unison
+ will accept before stopping the transfer of a directory (by default,
+ only one). This makes it possible to transfer most of a directory
+ even if there are some errors. Currently, only the first error is
+ reported by the GUIs.
+
+ Also, allow partial transfer of a directory when there was an error deep
+ inside this directory during update detection. At the moment, this
+ is only activated with the text and GTK UIs, which have been
+ modified so that they show that the transfer is going to be partial
+ and so that they can display all errors.
+\item Improvement to the code for resuming directory transfers:
+\begin{itemize}
+\item
+ if a file was not correctly transferred (or the source has been
+ modified since, with unchanged size), Unison performs a new
+ transfer rather than failing
+ \item spurious files are deleted (this can happen if a file is deleted
+ on the source replica before resuming the transfer; not deleting
+ the file would result in it reappearing on the target replica)
+\end{itemize}
+\item Experimental streaming protocol for transferring file contents (can
+ be disabled by setting the directive "stream" to false): file
+ contents is transfered asynchronously (without waiting for a response
+ from the destination after each chunk sent) rather than using the
+ synchronous RPC mechanism. As a consequence:
+ \begin{itemize}
+ \item
+ Unison now transfers the contents of a single file at a time
+ (Unison used to transfer several contents simultaneously in order
+ to hide the connection latency.)
+ \item the transfer of large files uses the full available bandwidth
+ and is not slowed done due to the connection latency anymore
+ \item we get performance improvement for small files as well by
+ scheduling many files simultaneously (as scheduling a file for
+ transfer consume little ressource: it does not mean allocating a
+ large buffer anymore)
+ \end{itemize}
+\item Changes to the internal implementation of the rsync algorithm:
+\begin{itemize}
+\item
+ use longer blocks for large files (the size of a block is the
+ square root of the size of the file for large files);
+ \item transmit less checksum information per block (we still have less
+ than one chance in a hundred million of transferring a file
+ incorrectly, and Unison will catch any transfer error when
+ fingerprinting the whole file)
+ \item avoid transfer overhead (which was 4 bytes per block)
+\end{itemize}
+ For a 1G file, the first optimization saves a factor 50 on the
+ amount of data transferred from the target to the source (blocks
+ are 32768 bytes rather than just 700 bytes). The two other
+ optimizations save another factor of 2 (from 24 bytes per block
+ down to 10).
+\item Implemented an on-disk file fingerprint cache to speed-up update
+ detection after a crash: this way, Unison does not have do recompute
+ all the file fingerprints from scratch.
+ \begin{itemize}
+ \item When Unison detects that the archive case-sensitivity mode
+ does not match the current settings, it populates the fingerprint
+ cache using the archive contents. This way, changing the
+ case-sensitivity mode should be reasonably fast.
+ \end{itemize}
+\item New preferences "noupdate=root", "nodeletion=root", "nocreation=root"
+ that prevent Unison from performing files updates, deletions or
+ creations on the given root. Also 'partial' versions of 'noupdate',
+ 'nodeletion' and 'nocreation'
+\item Limit the number of simultaneous external copy program
+ ("copymax" preference)
+\item New "links" preference. When set to false, Unison will report an
+ error on symlinks during update detection. (This is the default
+ when one host is running Windows but not Cygwin.) This is better
+ than failing during propagation.
+\item Added a preference "halfduplex" to force half-duplex communication
+ with the server. This may be useful on unreliable links (as a more
+ efficient alternative to "maxthreads = 1").
+\item Renamed preference "pretendwin" to "ignoreinodenumbers" (an alias is
+ kept for backwards compatibility).
+\item Ignore one-second differences when synchronizing modification time.
+ (Technically, this is an incompatible archive format change, but it
+ is backward compatible. To trigger a problem, a user would have to
+ synchronize modification times on a filesystem with a two-second
+ granularity and then downgrade to a previous version of Unison,
+ which does not work well in such a case. Thus, it does not
+ seem worthwhile to increment the archive format number, which would
+ impact all users.)
+\item Do not keep many files simultaneously opened anymore when the rsync
+ algorithm is in use.
+\item Add ``ignorearchives'' preference to ignore existing archives (to
+ avoid forcing users to delete them manually, in situations where one
+ archive has gotten deleted or corrupted).
+\item Mac OS
+\begin{itemize}
+\item fixed rsync bug which could result in an "index out of bounds"
+ error when transferring resource forks.
+\item Fixed bug which made Unison ignore finder information and resource
+ fork when compiled to 64bit on Mac OSX.
+\item should now be 64 bit clean (the Growl framework is not up to date,
+ though)
+\item Made the bridge between Objective C and Ocaml code GC friendly
+ (it was allocating ML values and putting them in an array which
+ was not registered with the GC)
+\item use darker grey arrows (patch contributed by Eric Y. Kow)
+\end{itemize}
+\item GTK user interface
+\begin{itemize}
+\item assistant for creating profiles
+\item profile editor
+\item pop up a summary window when the replicas are not fully
+ synchronized after transport
+\item display estimated remaining time and transfer rate on the
+ progress bar
+\item allow simultaneous selection of several items
+\item Do not reload the preference file before a new update
+ detection if it is unchanged
+\item disabled scrolling to the first unfinished item during transport.
+ It goes way too fast when lot of small files are synchronized, and it
+ makes it impossible to browse the file list during transport.
+\item take into account the "height" preference again
+\item the internal list of selected reconciler item was not always in
+ sync with what was displayed (GTK bug?); workaround implemented
+\item Do not display "Looking for change" messages during propagation
+ (when checking the targe is unchanged) but only during update detection
+\item Apply patch to fix some crashes in the OSX GUI, thanks to Onne Gorter.
+\end{itemize}
+\item Text UI
+\begin{itemize}
+\item During update detection, display status by updating a single line
+rather than generating a new line of output every so often. Should be less
+confusing.
+\end{itemize}
+\item Windows
+\begin{itemize}
+\item Fastcheck is now the default under Windows. People mostly use NTFS
+ nowadays and the Unicode API provides an equivalent to inode numbers
+ for this filesystem.
+\item Only use long UNC path for accessing replicas (as '..' is
+ not handled with this format of paths, but can be useful)
+\item Windows text UI: now put the console into UTF-8 output mode. This
+ is the right thing to do when in Unicode mode, and is no worse than
+ what we had previously otherwise (the console use some esoteric
+ encoding by default). This only works when using a Unicode font
+ instead of the default raster font.
+\item Don't get the home directory from environment variable HOME under
+ Windows (except for Cygwin binaries): we don't want the behavior of
+ Unison to depends on whether it is run from a Cygwin shell (where
+ HOME is set) or in any other way (where HOME is usually not set).
+\end{itemize}
+\item Miscellaneous fixes and improvements
+\begin{itemize}
+\item Made a server waiting on a socket more resilient to unexpected
+ lost connections from the client.
+\item Small patch to property setting code suggested by Ulrich Gernkow.
+\item Several fixes to the change transfer functions (both the internal ones
+ and external transfers using rsync). In particular, limit the number of
+ simultaneous transfer using an rsync
+ (as the rsync algorithm can use a large amount of memory when
+ processing huge files)
+\item Keep track of which file contents are being transferred, and delay
+ the transfer of a file when another file with the same contents is
+ currently being transferred. This way, the second transfer can be
+ skipped and replaced by a local copy.
+\item Experimental update detection optimization:
+ do not read the contents of unchanged directories
+\item When a file transfer fails, turn off fastcheck for this file on the
+ next sync.
+\item Fixed bug with case insensitive mode on a case sensitive filesystem:
+\begin{itemize}
+\item
+ if file "a/a" is created on one replica and directory "A" is
+ created on the other, the file failed to be synchronized the first
+ time Unison is run afterwards, as Unison uses the wrong path "a/a"
+ (if Unison is run again, the directories are in the archive, so
+ the right path is used);
+ \item if file "a" appears on one replica and file "A" appears on the
+ other with different contents, Unison was unable to synchronize
+ them.
+\end{itemize}
+\item Improved error reporting when the destination is updated during
+ synchronization: Unison now tells which file has been updated, and how.
+\item Limit the length of temporary file names
+\item Case sensitivity information put in the archive (in a backward
+ compatible way) and checked when the archive is loaded
+\item Got rid of the 16mb marshalling limit by marshalling to a bigarray.
+\item Resume copy of partially transferred files.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.31}
+\item Small user interface changes
+\begin{itemize}
+\item Small change to text UI "scanning..." messages, to print just
+ directories (hopefully making it clearer that individual files are
+ not necessarily being fingerprinted).
+\end{itemize}
+\item Minor fixes and improvements:
+\begin{itemize}
+\item Ignore one hour differences when deciding whether a file may have
+ been updated. This avoids slow update detection after daylight
+ saving time changes under Windows. This makes Unison slightly more
+ likely to miss an update, but it should be safe enough.
+\item Fix a small bug that was affecting mainly windows users. We need to
+ commit the archives at the end of the sync even if there are no
+ updates to propagate because some files (in fact, if we've just
+ switched to DST on windows, a LOT of files) might have new modtimes
+ in the archive. (Changed the text UI only. It's less clear where
+ to change the GUI.)
+\item Don't delete the temp file when a transfer fails due to a
+ fingerprint mismatch (so that we can have a look and see why!) We've also
+ added more debugging code togive more informative error messages when we
+ encounter the dreaded and longstanding "assert failed during file
+ transfer" bug
+\item Incorrect paths ("path" directive) now result in an error update
+ item rather than a fatal error.
+\item Create parent directories (with correct permissions) during
+ transport for paths which point to non-existent locations in the
+ destination replica.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.27}
+\item If Unison is interrupted during a directory transfer, it will now
+leave the partially transferred directory intact in a temporary
+location. (This maintains the invariant that new files/directories are
+transferred either completely or not at all.) The next time Unison is run,
+it will continue filling in this temporary directory, skipping transferring
+files that it finds are already there.
+\item We've added experimental support for invoking an external file
+transfer tool for whole-file copies instead of Unison's built-in transfer
+protocol. Three new preferences have been added:
+\begin{itemize}
+\item {\tt copyprog} is a string giving the name (and command-line
+switches, if needed) of an external program that can be used to copy large
+files efficiently. By default, rsync is invoked, but other tools such as
+scp can be used instead by changing the value of this preference. (Although
+this is not its primary purpose, rsync is actually a pretty fast way of
+copying files that don't already exist on the receiving host.) For files
+that do already exist on (but that have been changed in one replica), Unison
+will always use its built-in implementation of the rsync algorithm.
+\item Added a "copyprogrest" preference, so that we can give different
+command lines for invoking the external copy utility depending on whether a
+partially transferred file already exists or not. (Rsync doesn't seem to
+care about this, but other utilities may.)
+\item {\tt copythreshold} is an integer (-1 by default), indicating above what
+filesize (in megabytes) Unison should use the external copying utility
+specified by copyprog. Specifying 0 will cause ALL copies to use the
+external program; a negative number will prevent any files from using it.
+(Default is -1.)
+\end{itemize}
+Thanks to Alan Schmitt for a huge amount of hacking and to an anonymous
+sponsor for suggesting and underwriting this extension.
+\item Small improvements:
+\begin{itemize}
+\item Added a new preference, {\tt dontchmod}. By default, Unison uses the
+{\tt chmod} system call to set the permission bits of files after it has
+copied them. But in some circumstances (and under some operating systems),
+the chmod call always fails. Setting this preference completely prevents
+Unison from ever calling {\tt chmod}.
+\item Don't ignore files that look like backup files if the {\tt
+ backuplocation} preference is set to {\tt central}
+\item Shortened the names of several preferences. The old names are also
+still supported, for backwards compatibility, but they do not appear in the
+documentation.
+\item Lots of little documentation tidying. (In particular, preferences are
+separated into Basic and Advanced! This should hopefully make Unison a
+little more approachable for new users.
+\item Unison can sometimes fail to transfer a file, giving the unhelpful
+message "Destination updated during synchronization" even though the file
+has not been changed. This can be caused by programs that change either the
+file's contents \emph{or} the file's extended attributes without changing
+its modification time. It's not clear what is the best fix for this -- it
+is not Unison's fault, but it makes Unison's behavior puzzling -- but at
+least Unison can be more helpful about suggesting a workaround (running once
+with {\tt fastcheck} set to false). The failure message has been changed to
+give this advice.
+\item Further improvements to the OS X GUI (thanks to Alan Schmitt and Craig
+Federighi).
+\end{itemize}
+\item Very preliminary support for triggering Unison from an external
+ filesystem-watching utility. The current implementation is very
+ simple, not efficient, and almost completely untested---not ready
+ for real users. But if someone wants to help improve it (e.g.,
+ by writing a filesystem watcher for your favorite OS), please make
+ yourself known!
+
+ On the Unison side, the new behavior is very simple:
+ \begin{itemize}
+ \item use the text UI
+ \item start Unison with the command-line flag "-repeat FOO",
+ where FOO is name of a file where Unison should look
+ for notifications of changes
+ \item when it starts up, Unison will read the whole contents
+ of this file (on both hosts), which should be a
+ newline-separated list of paths (relative to the root
+ of the synchronization) and synchronize just these paths,
+ as if it had been started with the "-path=xxx" option for
+ each one of them
+ \item when it finishes, it will sleep for a few seconds and then
+ examine the watchfile again; if anything has been added, it
+ will read the new paths, synchronize them, and go back to
+ sleep
+ \item that's it!
+ \end{itemize}
+ To use this to drive Unison "incrementally," just start it in
+ this mode and start up a tool (on each host) to watch for
+ new changes to the filesystem and append the appropriate paths
+ to the watchfile. Hopefully such tools should not be too hard
+ to write.
+\item Bug fixes:
+\begin{itemize}
+\item Fixed a bug that was causing new files to be created with
+ permissions 0x600 instead of using a reasonable default (like
+ 0x644), if the 'perms' flag was set to 0. (Bug reported by Ben
+ Crowell.)
+\item Follow maxthreads preference when transferring directories.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.17}
+\item Major rewrite and cleanup of the whole Mac OS X graphical user
+interface by Craig Federighi. Thanks, Craig!!!
+\item Small fix to ctime (non-)handling in update detection under windows
+ with fastcheck.
+\item Several small fixes to the GTK2 UI to make it work better under
+Windows [thanks to Karl M for these].
+\item The backup functionality has been completely rewritten. The external
+interface has not changed, but numerous bugs, irregular behaviors, and
+cross-platform inconsistencies have been corrected.
+\item The Unison project now accepts donations via PayPal. If you'd like to
+donate, you can find a link to the donation page on the
+\URL{http://www.cis.upenn.edu/~bcpierce/unison/lists.html}{Unison home
+ page}.
+\item Some important safety improvements:
+\begin{itemize}
+\item Added a new \verb|mountpoint| preference, which can be used to specify
+a path that must exist in both replicas at the end of update detection
+(otherwise Unison aborts). This can be used to avoid potentially dangerous
+situations when Unison is used with removable media such as external hard
+drives and compact flash cards.
+\item The confirmation of ``big deletes'' is now controlled by a boolean preference
+ \verb|confirmbigdeletes|. Default is true, which gives the same behavior as
+ previously. (This functionality is at least partly superceded by the
+ \verb|mountpoint| preference, but it has been left in place in case it is
+ useful to some people.)
+ \item If Unison is asked to ``follow'' a symbolic link but there is
+ nothing at the other end of the link, it will now flag this path as an
+ error, rather than treating the symlink itself as missing or deleted.
+ This avoids a potentially dangerous situation where a followed symlink
+ points to an external filesystem that might be offline when Unison is run
+ (whereupon Unison would cheerfully delete the corresponding files in the
+ other replica!).
+\end{itemize}
+
+\item Smaller changes:
+\begin{itemize}
+\item Added \verb|forcepartial| and \verb|preferpartial| preferences, which
+behave like \verb|force| and \verb|prefer| but can be specified on a
+per-path basis. [Thanks to Alan Schmitt for this.]
+\item A bare-bones self test feature was added, which runs unison through
+ some of its paces and checks that the results are as expected. The
+ coverage of the tests is still very limited, but the facility has already
+ been very useful in debugging the new backup functionality (especially in
+ exposing some subtle cross-platform issues).
+\item Refined debugging code so that the verbosity of individual modules
+ can be controlled separately. Instead of just putting '-debug
+ verbose' on the command line, you can put '-debug update+', which
+ causes all the extra messages in the Update module, but not other
+ modules, to be printed. Putting '-debug verbose' causes all modules
+ to print with maximum verbosity.
+\item Removed \verb|mergebatch| preference. (It never seemed very useful, and
+ its semantics were confusing.)
+\item Rewrote some of the merging functionality, for better cooperation
+ with external Harmony instances.
+\item Changed the temp file prefix from \verb|.#| to \verb|.unison|.
+\item Compressed the output from the text user interface (particularly
+ when run with the \verb|-terse| flag) to make it easier to interpret the
+ results when Unison is run several times in succession from a script.
+\item Diff and merge functions now work under Windows.
+\item Changed the order of arguments to the default diff command (so that
+ the + and - annotations in diff's output are reversed).
+\item Added \verb|.mpp| files to the ``never fastcheck'' list (like
+\verb|.xls| files).
+\end{itemize}
+
+\item Many small bugfixes, including:
+\begin{itemize}
+\item Fixed a longstanding bug regarding fastcheck and daylight saving time
+ under Windows when Unison is set up to synchronize modification times.
+ (Modification times cannot be updated in the archive in this case,
+ so we have to ignore one hour differences.)
+\item Fixed a bug that would occasionally cause the archives to be left in
+ non-identical states on the two hosts after synchronization.
+\item Fixed a bug that prevented Unison from communicating correctly between
+ 32- and 64-bit architectures.
+\item On windows, file creation times are no longer used as a proxy for
+ inode numbers. (This is unfortunate, as it makes fastcheck a little less
+ safe. But it turns out that file creation times are not reliable
+ under Windows: if a file is removed and a new file is created in its
+ place, the new one will sometimes be given the same creation date as the
+ old one!)
+\item Set read-only file to R/W on OSX before attempting to change other attributes.
+\item Fixed bug resulting in spurious "Aborted" errors during transport
+(thanks to Jerome Vouillon)
+\item Enable diff if file contents have changed in one replica, but
+only properties in the other.
+\item Removed misleading documentation for 'repeat' preference.
+\item Fixed a bug in merging code where Unison could sometimes deadlock
+ with the external merge program, if the latter produced large
+ amounts of output.
+\item Workaround for a bug compiling gtk2 user interface against current versions
+ of gtk2+ libraries.
+\item Added a better error message for "ambiguous paths".
+\item Squashed a longstanding bug that would cause file transfer to fail
+ with the message ``Failed: Error in readWrite: Is a directory.''
+\item Replaced symlinks with copies of their targets in the Growl framework in src/uimac.
+ This should make the sources easier to check out from the svn repository on WinXP
+ systems.
+\item Added a workaround (suggested by Karl M.) for the problem discussed
+ on the unison users mailing list where, on the Windows platform, the
+ server would hang when transferring files. I conjecture that
+ the problem has to do with the RPC mechanism, which was used to
+ make a call {\em back} from the server to the client (inside the Trace.log
+ function) so that the log message would be appended to the log file on
+ the client. The workaround is to dump these messages (about when
+ xferbycopying shortcuts are applied and whether they succeed) just to the
+ standard output of the Unison process, not to the log file.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.13.0}
+\item The features for performing backups and for invoking external merge
+programs have been completely rewritten by Stephane Lescuyer (thanks,
+Stephane!). The user-visible functionality should not change, but the
+internals have been rationalized and there are a number of new features.
+See the manual (in particular, the description of the \verb|backupXXX|
+preferences) for details.
+\item Incorporated patches for ipv6 support, contributed by Samuel Thibault.
+(Note that, due to a bug in the released OCaml 3.08.3 compiler, this code
+will not actually work with ipv6 unless compiled with the CVS version of the
+OCaml compiler, where the bug has been fixed; however, ipv4 should continue
+to work normally.)
+\item OSX interface:
+\begin{itemize}
+\item Incorporated Ben Willmore's cool new icon for the Mac UI.
+\end{itemize}
+\item Small fixes:
+\begin{itemize}
+\item Fixed off by one error in month numbers (in printed dates) reported
+ by Bob Burger
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.12.0}
+\item New convention for release numbering: Releases will continue to be
+given numbers of the form \verb|X.Y.Z|, but,
+from now on, just the major version number (\verb|X.Y|) will be considered
+significant when checking compatibility between client and server versions.
+The third component of the version number will be used only to identify
+``patch levels'' of releases.
+
+This change goes hand in hand with a change to the procedure for making new
+releases. Candidate releases will initially be given ``beta release''
+status when they are announced for public consumption. Any bugs that are
+discovered will be fixed in a separate branch of the source repository
+(without changing the major version number) and new tarballs re-released as
+needed. When this process converges, the patched beta version will be
+dubbed stable.
+\item Warning (failure in batch mode) when one path is completely emptied.
+ This prevents Unison from deleting everything on one replica when
+ the other disappear.
+\item Fix diff bug (where no difference is shown the first time the diff
+ command is given).
+\item User interface changes:
+\begin{itemize}
+\item Improved workaround for button focus problem (GTK2 UI)
+\item Put leading zeroes in date fields
+\item More robust handling of character encodings in GTK2 UI
+\item Changed format of modification time displays, from \verb|modified at hh:mm:ss on dd MMM, yyyy|
+to \verb|modified on yyyy-mm-dd hh:mm:ss|
+\item Changed time display to include seconds (so that people on FAT
+ filesystems will not be confused when Unison tries to update a file
+ time to an odd number of seconds and the filesystem truncates it to
+ an even number!)
+\item Use the diff "-u" option by default when showing differences between files
+ (the output is more readable)
+\item In text mode, pipe the diff output to a pager if the environment
+ variable PAGER is set
+\item Bug fixes and cleanups in ssh password prompting. Now works with
+ the GTK2 UI under Linux. (Hopefully the Mac OS X one is not broken!)
+\item Include profile name in the GTK2 window name
+\item Added bindings ',' (same as '<') and '.' (same as '>') in the GTK2 UI
+\end{itemize}
+\item Mac GUI:
+\begin{itemize}
+\item actions like < and > scroll to the next item as necessary.
+\item Restart has a menu item and keyboard shortcut (command-R).
+\item
+ Added a command-line tool for Mac OS X. It can be installed from
+ the Unison menu.
+\item New icon.
+\item Handle the "help" command-line argument properly.
+\item Handle profiles given on the command line properly.
+\item When a profile has been selected, the profile dialog is replaced by a
+ "connecting" message while the connection is being made. This
+ gives better feedback.
+\item Size of left and right columns is now large enough so that
+ "PropsChanged" is not cut off.
+\end{itemize}
+\item Minor changes:
+\begin{itemize}
+\item Disable multi-threading when both roots are local
+\item Improved error handling code. In particular, make sure all files
+ are closed in case of a transient failure
+\item Under Windows, use \verb|$UNISON| for home directory as a last resort
+ (it was wrongly moved before \verb|$HOME| and \verb|$USERPROFILE| in
+ Unison 2.12.0)
+\item Reopen the logfile if its name changes (profile change)
+\item Double-check that permissions and modification times have been
+ properly set: there are some combination of OS and filesystem on
+ which setting them can fail in a silent way.
+\item Check for bad Windows filenames for pure Windows synchronization
+ also (not just cross architecture synchronization).
+ This way, filenames containing backslashes, which are not correctly
+ handled by unison, are rejected right away.
+\item Attempt to resolve issues with synchronizing modification times
+ of read-only files under Windows
+\item Ignore chmod failures when deleting files
+\item Ignore trailing dots in filenames in case insensitive mode
+\item Proper quoting of paths, files and extensions ignored using the UI
+\item The strings CURRENT1 and CURRENT2 are now correctly substitued when
+ they occur in the diff preference
+\item Improvements to syncing resource forks between Macs via a non-Mac system.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.10.2}
+\item \incompatible{} Archive format has changed.
+\item Source code availability: The Unison sources are now managed using
+ Subversion. One nice side-effect is that anonymous checkout is now
+ possible, like this:
+\begin{verbatim}
+ svn co https://cvs.cis.upenn.edu:3690/svnroot/unison/
+\end{verbatim}
+We will also continue to export a ``developer tarball'' of the current
+(modulo one day) sources in the web export directory. To receive commit logs
+for changes to the sources, subscribe to the \verb|unison-hackers| list
+(\ONEURL{http://www.cis.upenn.edu/~bcpierce/unison/lists.html}).
+\item Text user interface:
+\begin{itemize}
+\item Substantial reworking of the internal logic of the text UI to make it
+a bit easier to modify.
+\item The {\tt dumbtty} flag in the text UI is automatically set to true if
+the client is running on a Unix system and the {\tt EMACS} environment
+variable is set to anything other than the empty string.
+\end{itemize}
+\item Native OS X gui:
+\begin{itemize}
+\item Added a synchronize menu item with keyboard shortcut
+\item Added a merge menu item, still needs to be debugged
+\item Fixes to compile for Panther
+\item Miscellaneous improvements and bugfixes
+\end{itemize}
+\item Small changes:
+\begin{itemize}
+\item Changed the filename checking code to apply to Windows only, instead
+ of OS X as well.
+\item Finder flags now synchronized
+\item Fallback in copy.ml for filesystem that do not support \verb|O_EXCL|
+\item Changed buffer size for local file copy (was highly inefficient with
+ synchronous writes)
+\item Ignore chmod failure when deleting a directory
+\item Fixed assertion failure when resolving a conflict content change /
+ permission changes in favor of the content change.
+\item Workaround for transferring large files using rsync.
+\item Use buffered I/O for files (this is the only way to open files in binary
+ mode under Cygwin).
+\item On non-Cygwin Windows systems, the UNISON environment variable is now checked first to determine
+ where to look for Unison's archive and preference files, followed by \verb|HOME| and
+ \verb|USERPROFILE| in that order. On Unix and Cygwin systems, \verb|HOME| is used.
+\item Generalized \verb|diff| preference so that it can be given either as just
+ the command name to be used for calculating diffs or else a whole command
+ line, containing the strings \verb|CURRENT1| and \verb|CURRENT2|, which will be replaced
+ by the names of the files to be diff'ed before the command is called.
+\item Recognize password prompts in some newer versions of ssh.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.9.20}
+\item \incompatible{} Archive format has changed.
+\item Major functionality changes:
+\begin{itemize}
+\item Major tidying and enhancement of 'merge' functionality. The main
+ user-visible change is that the external merge program may either write
+ the merged output to a single new file, as before, or it may modify one or
+ both of its input files, or it may write {\em two} new files. In the
+ latter cases, its modifications will be copied back into place on both the
+ local and the remote host, and (if the two files are now equal) the
+ archive will be updated appropriately. More information can be found in
+ the user manual. Thanks to Malo Denielou and Alan Schmitt for these
+ improvements.
+
+ Warning: the new merging functionality is not completely compatible with
+ old versions! Check the manual for details.
+\item Files larger than 2Gb are now supported.
+\item Added preliminary (and still somewhat experimental) support for the
+ Apple OS X operating system.
+\begin{itemize}
+\item Resource forks should be transferred correctly. (See the manual for
+details of how this works when synchronizing HFS with non-HFS volumes.)
+Synchronization of file type and creator information is also supported.
+\item On OSX systems, the name of the directory for storing Unison's
+archives, preference files, etc., is now determined as follows:
+\begin{itemize}
+ \item if \verb+~/.unison+ exists, use it
+ \item otherwise, use \verb|~/Library/Application Support/Unison|,
+ creating it if necessary.
+\end{itemize}
+\item A preliminary native-Cocoa user interface is under construction. This
+still needs some work, and some users experience unpredictable crashes, so
+it is only for hackers for now. Run make with {\tt UISTYLE=mac} to build
+this interface.
+\end{itemize}
+\end{itemize}
+
+\item Minor functionality changes:
+\begin{itemize}
+\item Added an {\tt ignorelocks} preference, which forces Unison to override left-over
+ archive locks. (Setting this preference is dangerous! Use it only if you
+ are positive you know what you are doing.)
+% BCP: removed later
+% \item Running with the {\tt -timers} flag set to true will now show the total time taken
+% to check for updates on each directory. (This can be helpful for tidying directories to improve
+% update detection times.)
+\item Added a new preference {\tt assumeContentsAreImmutable}. If a directory
+ matches one of the patterns set in this preference, then update detection
+ is skipped for files in this directory. (The
+ purpose is to speed update detection for cases like Mail folders, which
+ contain lots and lots of immutable files.) Also a preference
+ {\tt assumeContentsAreImmutableNot}, which overrides the first, similarly
+ to {\tt ignorenot}. (Later amendment: these preferences are now called
+ {\tt immutable} and {\tt immutablenot}.)
+\item The {\tt ignorecase} flag has been changed from a boolean to a three-valued
+ preference. The default setting, called {\tt default}, checks the operating systems
+ running on the client and server and ignores filename case if either of them is
+ OSX or Windows. Setting ignorecase to {\tt true} or {\tt false} overrides
+ this behavior. If you have been setting {\tt ignorecase} on the command
+ line using {\tt -ignorecase=true} or {\tt -ignorecase=false}, you will
+ need to change to {\tt -ignorecase true} or {\tt -ignorecase false}.
+\item a new preference, 'repeat', for the text user interface (only). If 'repeat' is set to
+ a number, then, after it finishes synchronizing, Unison will wait for that many seconds and
+ then start over, continuing this way until it is killed from outside. Setting repeat to true
+ will automatically set the batch preference to true.
+\item Excel files are now handled specially, so that the {\tt fastcheck}
+ optimization is skipped even if the {\tt fastcheck} flag is set. (Excel
+ does some naughty things with modtimes, making this optimization
+ unreliable and leading to failures during change propagation.)
+\item The ignorecase flag has been changed from a boolean to a three-valued
+ preference. The default setting, called 'default', checks the operating systems
+ running on the client and server and ignores filename case if either of them is
+ OSX or Windows. Setting ignorecase to 'true' or 'false' overrides this behavior.
+\item Added a new preference, 'repeat', for the text user interface (only,
+ at the moment). If 'repeat' is set to a number, then, after it finishes
+ synchronizing, Unison will wait for that many seconds and then start over,
+ continuing this way until it is killed from outside. Setting repeat to
+ true will automatically set the batch preference to true.
+\item The 'rshargs' preference has been split into 'rshargs' and 'sshargs'
+ (mainly to make the documentation clearer). In fact, 'rshargs' is no longer
+ mentioned in the documentation at all, since pretty much everybody uses
+ ssh now anyway.
+\end{itemize}
+\item Documentation
+\begin{itemize}
+\item The web pages have been completely redesigned and reorganized.
+ (Thanks to Alan Schmitt for help with this.)
+\end{itemize}
+\item User interface improvements
+\begin{itemize}
+\item Added a GTK2 user interface, capable (among other things) of displaying filenames
+ in any locale encoding. Kudos to Stephen Tse for contributing this code!
+\item The text UI now prints a list of failed and skipped transfers at the end of
+ synchronization.
+\item Restarting update detection from the graphical UI will reload the current
+ profile (which in particular will reset the -path preference, in case
+ it has been narrowed by using the ``Recheck unsynchronized items''
+ command).
+\item Several small improvements to the text user interface, including a
+ progress display.
+\end{itemize}
+\item Bug fixes (too numerous to count, actually, but here are some):
+\begin{itemize}
+\item The {\tt maxthreads} preference works now.
+\item Fixed bug where warning message about uname returning an unrecognized
+ result was preventing connection to server. (The warning is no longer
+ printed, and all systems where 'uname' returns anything other than 'Darwin'
+ are assumed not to be running OS X.)
+\item Fixed a problem on OS X that caused some valid file names (e.g.,
+ those including colons) to be considered invalid.
+\item Patched Path.followLink to follow links under cygwin in addition to Unix
+ (suggested by Matt Swift).
+\item Small change to the storeRootsName function, suggested by bliviero at
+ ichips.intel.com, to fix a problem in unison with the `rootalias'
+ option, which allows you to tell unison that two roots contain the same
+ files. Rootalias was being applied after the hosts were
+ sorted, so it wouldn't work properly in all cases.
+\item Incorporated a fix by Dmitry Bely for setting utimes of read-only files
+ on Win32 systems.
+\end{itemize}
+\item Installation / portability:
+\begin{itemize}
+\item Unison now compiles with OCaml version 3.07 and later out of the box.
+\item Makefile.OCaml fixed to compile out of the box under OpenBSD.
+\item a few additional ports (e.g. OpenBSD, Zaurus/IPAQ) are now mentioned in
+ the documentation
+\item Unison can now be installed easily on OSX systems using the Fink
+ package manager
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.9.1}
+\item Added a preference {\tt maxthreads} that can be used to limit the
+number of simultaneous file transfers.
+\item Added a {\tt backupdir} preference, which controls where backup
+files are stored.
+\item Basic support added for OSX. In particular, Unison now recognizes
+when one of the hosts being synchronized is running OSX and switches to
+a case-insensitive treatment of filenames (i.e., 'foo' and 'FOO' are
+considered to be the same file).
+ (OSX is not yet fully working,
+ however: in particular, files with resource forks will not be
+ synchronized correctly.)
+\item The same hash used to form the archive name is now also added to
+the names of the temp files created during file transfer. The reason for
+this is that, during update detection, we are going to silently delete
+any old temp files that we find along the way, and we want to prevent
+ourselves from deleting temp files belonging to other instances of Unison
+that may be running in parallel, e.g. synchronizing with a different
+host. Thanks to Ruslan Ermilov for this suggestion.
+\item Several small user interface improvements
+\item Documentation
+\begin{itemize}
+\item FAQ and bug reporting instructions have been split out as separate
+ HTML pages, accessible directly from the unison web page.
+\item Additions to FAQ, in particular suggestions about performance
+tuning.
+\end{itemize}
+\item Makefile
+\begin{itemize}
+\item Makefile.OCaml now sets UISTYLE=text or UISTYLE=gtk automatically,
+ depending on whether it finds lablgtk installed
+\item Unison should now compile ``out of the box'' under OSX
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.8.1}
+\item Changing profile works again under Windows
+\item File movement optimization: Unison now tries to use local copy instead of
+ transfer for moved or copied files. It is controled by a boolean option
+ ``xferbycopying''.
+\item Network statistics window (transfer rate, amount of data transferred).
+ [NB: not available in Windows-Cygwin version.]
+\item symlinks work under the cygwin version (which is dynamically linked).
+\item Fixed potential deadlock when synchronizing between Windows and
+Unix
+\item Small improvements:
+ \begin{itemize}
+ \item If neither the {\tt USERPROFILE} nor the {\tt HOME} environment
+ variables are set, then Unison will put its temporary commit log
+ (called {\tt DANGER.README}) into the directory named by the
+ {\tt UNISON} environment variable, if any; otherwise it will use
+ {\tt C:}.
+ \item alternative set of values for fastcheck: yes = true; no = false;
+ default = auto.
+ \item -silent implies -contactquietly
+ \end{itemize}
+\item Source code:
+ \begin{itemize}
+ \item Code reorganization and tidying. (Started breaking up some of the
+ basic utility modules so that the non-unison-specific stuff can be
+ made available for other projects.)
+ \item several Makefile and docs changes (for release);
+ \item further comments in ``update.ml'';
+ \item connection information is not stored in global variables anymore.
+ \end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.7.78}
+\item Small bugfix to textual user interface under Unix (to avoid leaving
+ the terminal in a bad state where it would not echo inputs after Unison
+ exited).
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.7.39}
+\item Improvements to the main web page (stable and beta version docs are
+ now both accessible).
+\item User manual revised.
+\item Added some new preferences:
+\begin{itemize}
+\item ``sshcmd'' and ``rshcmd'' for specifying paths to ssh and rsh programs.
+\item ``contactquietly'' for suppressing the ``contacting server'' message
+during Unison startup (under the graphical UI).
+\end{itemize}
+\item Bug fixes:
+\begin{itemize}
+\item Fixed small bug in UI that neglected to change the displayed column
+ headers if loading a new profile caused the roots to change.
+\item Fixed a bug that would put the text UI into an infinite loop if it
+ encountered a conflict when run in batch mode.
+\item Added some code to try to fix the display of non-Ascii characters in
+ filenames on Windows systems in the GTK UI. (This code is currently
+ untested---if you're one of the people that had reported problems with
+ display of non-ascii filenames, we'd appreciate knowing if this actually
+ fixes things.)
+\item `\verb|-prefer/-force newer|' works properly now.
+ (The bug was reported by Sebastian Urbaniak and Sean Fulton.)
+\end{itemize}
+\item User interface and Unison behavior:
+\begin{itemize}
+\item Renamed `Proceed' to `Go' in the graphical UI.
+\item Added exit status for the textual user interface.
+\item Paths that are not synchronized because of conflicts or errors during
+ update detection are now noted in the log file.
+\item \verb|[END]| messages in log now use a briefer format
+\item Changed the text UI startup sequence so that
+ {\tt ./unison -ui text} will use the default profile instead of failing.
+\item Made some improvements to the error messages.
+\item Added some debugging messages to remote.ml.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.7.7}
+\item Incorporated, once again, a multi-threaded transport sub-system.
+ It transfers several files at the same time, thereby making much
+ more effective use of available network bandwidth. Unlike the
+ earlier attempt, this time we do not rely on the native thread
+ library of OCaml. Instead, we implement a light-weight,
+ non-preemptive multi-thread library in OCaml directly. This version
+ appears stable.
+
+ Some adjustments to unison are made to accommodate the multi-threaded
+ version. These include, in particular, changes to the
+ user interface and logging, for example:
+ \begin{itemize}
+ \item Two log entries for each transferring task, one for the
+ beginning, one for the end.
+ \item Suppressed warning messages against removing temp files left
+ by a previous unison run, because warning does not work nicely
+ under multi-threading. The temp file names are made less likely
+ to coincide with the name of a file created by the user. They
+ take the form \\ \verb|.#<filename>.<serial>.unison.tmp|.
+ [N.b. This was later changed to \verb|.unison.<filename>.<serial>.unison.tmp|.]
+ \end{itemize}
+\item Added a new command to the GTK user interface: pressing 'f' causes
+ Unison to start a new update detection phase, using as paths {\em just}
+ those paths that have been detected as changed and not yet marked as
+ successfully completed. Use this command to quickly restart Unison on
+ just the set of paths still needing attention after a previous run.
+\item Made the {\tt ignorecase} preference user-visible, and changed the
+ initialization code so that it can be manually set to true, even if
+ neither host is running Windows. (This may be useful, e.g., when using
+ Unison running on a Unix system with a FAT volume mounted.)
+\item Small improvements and bug fixes:
+ \begin{itemize}
+ \item Errors in preference files now generate fatal errors rather than
+ warnings at startup time. (I.e., you can't go on from them.) Also,
+ we fixed a bug that was preventing these warnings from appearing in the
+ text UI, so some users who have been running (unsuspectingly) with
+ garbage in their prefs files may now get error reports.
+ \item Error reporting for preference files now provides file name and
+ line number.
+ \item More intelligible message in the case of identical change to the same
+ files: ``Nothing to do: replicas have been changed only in identical
+ ways since last sync.''
+ \item Files with prefix '.\#' excluded when scanning for preference
+ files.
+ \item Rsync instructions are send directly instead of first
+ marshaled.
+ \item Won't try forever to get the fingerprint of a continuously changing file:
+ unison will give up after certain number of retries.
+ \item Other bug fixes, including the one reported by Peter Selinger
+ (\verb|force=older preference| not working).
+ \end{itemize}
+\item Compilation:
+ \begin{itemize}
+ \item Upgraded to the new OCaml 3.04 compiler, with the LablGtk
+ 1.2.3 library (patched version used for compiling under Windows).
+ \item Added the option to compile unison on the Windows platform with
+ Cygwin GNU C compiler. This option only supports building
+ dynamically linked unison executables.
+ \end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.7.4}
+\item Fixed a silly (but debilitating) bug in the client startup sequence.
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.7.1}
+\item Added \verb|addprefsto| preference, which (when set) controls which
+preference file new preferences (e.g. new ignore patterns) are added to.
+\item Bug fix: read the initial connection header one byte at a time, so
+that we don't block if the header is shorter than expected. (This bug
+did not affect normal operation --- it just made it hard to tell when you
+were trying to use Unison incorrectly with an old version of the server,
+since it would hang instead of giving an error message.)
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.6.59}
+\item Changed \verb|fastcheck| from a boolean to a string preference. Its
+ legal values are \verb|yes| (for a fast check), \verb|no| (for a safe
+ check), or \verb|default| (for a fast check---which also happens to be
+ safe---when running on Unix and a safe check when on Windows). The default
+ is \verb|default|.
+ \item Several preferences have been renamed for consistency. All
+ preference names are now spelled out in lowercase. For backward
+ compatibility, the old names still work, but they are not mentioned in
+ the manual any more.
+\item The temp files created by the 'diff' and 'merge' commands are now
+ named by {\em pre}pending a new prefix to the file name, rather than
+ appending a suffix. This should avoid confusing diff/merge programs
+ that depend on the suffix to guess the type of the file contents.
+\item We now set the keepalive option on the server socket, to make sure
+ that the server times out if the communication link is unexpectedly broken.
+\item Bug fixes:
+\begin{itemize}
+\item When updating small files, Unison now closes the destination file.
+\item File permissions are properly updated when the file is behind a
+ followed link.
+\item Several other small fixes.
+\end{itemize}
+\end{changesfromversion}
+
+
+\begin{changesfromversion}{2.6.38}
+\item Major Windows performance improvement!
+
+We've added a preference \verb|fastcheck| that makes Unison look only at
+a file's creation time and last-modified time to check whether it has
+changed. This should result in a huge speedup when checking for updates
+in large replicas.
+
+ When this switch is set, Unison will use file creation times as
+ 'pseudo inode numbers' when scanning Windows replicas for updates,
+ instead of reading the full contents of every file. This may cause
+ Unison to miss propagating an update if the create time,
+ modification time, and length of the file are all unchanged by
+ the update (this is not easy to achieve, but it can be done).
+ However, Unison will never {\em overwrite} such an update with
+ a change from the other replica, since it
+ always does a safe check for updates just before propagating a
+ change. Thus, it is reasonable to use this switch most of the time
+ and occasionally run Unison once with {\tt fastcheck} set to false,
+ if you are worried that Unison may have overlooked an update.
+
+ Warning: This change is has not yet been thoroughly field-tested. If you
+ set the \verb|fastcheck| preference, pay careful attention to what
+ Unison is doing.
+
+\item New functionality: centralized backups and merging
+\begin{itemize}
+\item This version incorporates two pieces of major new functionality,
+ implemented by Sylvain Roy during a summer internship at Penn: a
+ {\em centralized backup} facility that keeps a full backup of
+ (selected files
+ in) each replica, and a {\em merging} feature that allows Unison to
+ invoke an external file-merging tool to resolve conflicting changes to
+ individual files.
+
+\item Centralized backups:
+\begin{itemize}
+ \item Unison now maintains full backups of the last-synchronized versions
+ of (some of) the files in each replica; these function both as
+ backups in the usual sense
+ and as the ``common version'' when invoking external
+ merge programs.
+ \item The backed up files are stored in a directory ~/.unison/backup on each
+ host. (The name of this directory can be changed by setting
+ the environment variable \verb|UNISONBACKUPDIR|.)
+ \item The predicate \verb|backup| controls which files are actually
+ backed up:
+ giving the preference '\verb|backup = Path *|' causes backing up
+ of all files.
+ \item Files are added to the backup directory whenever unison updates
+ its archive. This means that
+ \begin{itemize}
+ \item When unison reconstructs its archive from scratch (e.g.,
+ because of an upgrade, or because the archive files have
+ been manually deleted), all files will be backed up.
+ \item Otherwise, each file will be backed up the first time unison
+ propagates an update for it.
+ \end{itemize}
+ \item The preference \verb|backupversions| controls how many previous
+ versions of each file are kept. The default is 2 (i.e., the last
+ synchronized version plus one backup).
+ \item For backward compatibility, the \verb|backups| preference is also
+ still supported, but \verb|backup| is now preferred.
+ \item It is OK to manually delete files from the backup directory (or to throw
+ away the directory itself). Before unison uses any of these files for
+ anything important, it checks that its fingerprint matches the one
+ that it expects.
+\end{itemize}
+
+\item Merging:
+\begin{itemize}
+ \item Both user interfaces offer a new 'merge' command, invoked by pressing
+ 'm' (with a changed file selected).
+ \item The actual merging is performed by an external program.
+ The preferences \verb|merge| and \verb|merge2| control how this
+ program is invoked. If a backup exists for this file (see the
+ \verb|backup| preference), then the \verb|merge| preference is used for
+ this purpose; otherwise \verb|merge2| is used. In both cases, the
+ value of the preference should be a string representing the command
+ that should be passed to a shell to invoke the
+ merge program. Within this string, the special substrings
+ \verb|CURRENT1|, \verb|CURRENT2|, \verb|NEW|, and \verb|OLD| may appear
+ at any point. Unison will substitute these as follows before invoking
+ the command:
+ \begin{itemize}
+ \item \relax\verb|CURRENT1| is replaced by the name of the local
+ copy of the file;
+ \item \relax\verb|CURRENT2| is replaced by the name of a temporary
+ file, into which the contents of the remote copy of the file have
+ been transferred by Unison prior to performing the merge;
+ \item \relax\verb|NEW| is replaced by the name of a temporary
+ file that Unison expects to be written by the merge program when
+ it finishes, giving the desired new contents of the file; and
+ \item \relax\verb|OLD| is replaced by the name of the backed up
+ copy of the original version of the file (i.e., its state at the
+ end of the last successful run of Unison), if one exists
+ (applies only to \verb|merge|, not \verb|merge2|).
+ \end{itemize}
+ For example, on Unix systems setting the \verb|merge| preference to
+\begin{verbatim}
+ merge = diff3 -m CURRENT1 OLD CURRENT2 > NEW
+\end{verbatim}
+ will tell Unison to use the external \verb|diff3| program for merging.
+
+ A large number of external merging programs are available. For
+ example, \verb|emacs| users may find the following convenient:
+\begin{verbatim}
+ merge2 = emacs -q --eval '(ediff-merge-files "CURRENT1" "CURRENT2"
+ nil "NEW")'
+ merge = emacs -q --eval '(ediff-merge-files-with-ancestor
+ "CURRENT1" "CURRENT2" "OLD" nil "NEW")'
+\end{verbatim}
+(These commands are displayed here on two lines to avoid running off the
+edge of the page. In your preference file, each should be written on a
+single line.)
+
+ \item If the external program exits without leaving any file at the
+ path \verb|NEW|,
+ Unison considers the merge to have failed. If the merge program writes
+ a file called \verb|NEW| but exits with a non-zero status code,
+ then Unison
+ considers the merge to have succeeded but to have generated conflicts.
+ In this case, it attempts to invoke an external editor so that the
+ user can resolve the conflicts. The value of the \verb|editor|
+ preference controls what editor is invoked by Unison. The default
+ is \verb|emacs|.
+
+ \item Please send us suggestions for other useful values of the
+ \verb|merge2| and \verb|merge| preferences -- we'd like to give several
+ examples in the manual.
+\end{itemize}
+\end{itemize}
+
+\item Smaller changes:
+\begin{itemize}
+\item When one preference file includes another, unison no longer adds the
+ suffix '\verb|.prf|' to the included file by default. If a file with
+ precisely the given name exists in the .unison directory, it will be used;
+ otherwise Unison will
+ add \verb|.prf|, as it did before. (This change means that included
+ preference files can be named \verb|blah.include| instead of
+ \verb|blah.prf|, so that unison will not offer them in its 'choose
+ a preference file' dialog.)
+\item For Linux systems, we now offer both a statically linked and a dynamically
+ linked executable. The static one is larger, but will probably run on more
+ systems, since it doesn't depend on the same versions of dynamically
+ linked library modules being available.
+\item Fixed the \verb|force| and \verb|prefer| preferences, which were
+ getting the propagation direction exactly backwards.
+\item Fixed a bug in the startup code that would cause unison to crash
+ when the default profile (\verb|~/.unison/default.prf|) does not exist.
+\item Fixed a bug where, on the run when a profile is first created,
+ Unison would confusingly display the roots in reverse order in the user
+ interface.
+\end{itemize}
+
+\item For developers:
+\begin{itemize}
+\item We've added a module dependency diagram to the source distribution, in
+ \verb|src/DEPENDENCIES.ps|, to help new prospective developers with
+ navigating the code.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.6.11}
+\item \incompatible{} Archive format has changed.
+
+\item \incompatible{} The startup sequence has been completely rewritten
+and greatly simplified. The main user-visible change is that the
+\verb|defaultpath| preference has been removed. Its effect can be
+approximated by using multiple profiles, with \verb|include| directives
+to incorporate common settings. All uses of \verb|defaultpath| in
+existing profiles should be changed to \verb|path|.
+
+Another change in startup behavior that will affect some users is that it
+is no longer possible to specify roots {\em both} in the profile {\em
+ and} on the command line.
+
+You can achieve a similar effect, though, by breaking your profile into
+two:
+\begin{verbatim}
+
+ default.prf =
+ root = blah
+ root = foo
+ include common
+
+ common.prf =
+ <everything else>
+\end{verbatim}
+Now do
+\begin{verbatim}
+ unison common root1 root2
+\end{verbatim}
+when you want to specify roots explicitly.
+
+\item The \verb|-prefer| and \verb|-force| options have been extended to
+allow users to specify that files with more recent modtimes should be
+propagated, writing either \verb|-prefer newer| or \verb|-force newer|.
+(For symmetry, Unison will also accept \verb|-prefer older| or
+\verb|-force older|.) The \verb|-force older/newer| options can only be
+used when \verb|-times| is also set.
+
+The graphical user interface provides access to these facilities on a
+one-off basis via the \verb|Actions| menu.
+
+\item Names of roots can now be ``aliased'' to allow replicas to be
+relocated without changing the name of the archive file where Unison
+stores information between runs. (This feature is for experts only. See
+the ``Archive Files'' section of the manual for more information.)
+
+\item Graphical user-interface:
+\begin{itemize}
+\item A new command is provided in the Synchronization menu for
+ switching to a new profile without restarting Unison from scratch.
+\item The GUI also supports one-key shortcuts for commonly
+used profiles. If a profile contains a preference of the form
+%
+'\verb|key = n|', where \verb|n| is a single digit, then pressing this
+key will cause Unison to immediately switch to this profile and begin
+synchronization again from scratch. (Any actions that may have been
+selected for a set of changes currently being displayed will be
+discarded.)
+
+\item Each profile may include a preference '\verb|label = <string>|' giving a
+ descriptive string that described the options selected in this profile.
+ The string is listed along with the profile name in the profile selection
+ dialog, and displayed in the top-right corner of the main Unison window.
+\end{itemize}
+
+\item Minor:
+\begin{itemize}
+\item Fixed a bug that would sometimes cause the 'diff' display to order
+ the files backwards relative to the main user interface. (Thanks
+ to Pascal Brisset for this fix.)
+\item On Unix systems, the graphical version of Unison will check the
+ \verb|DISPLAY| variable and, if it is not set, automatically fall back
+ to the textual user interface.
+\item Synchronization paths (\verb|path| preferences) are now matched
+ against the ignore preferences. So if a path is both specified in a
+ \verb|path| preference and ignored, it will be skipped.
+\item Numerous other bugfixes and small improvements.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.6.1}
+\item The synchronization of modification times has been disabled for
+ directories.
+
+\item Preference files may now include lines of the form
+ \verb+include <name>+, which will cause \verb+name.prf+ to be read
+ at that point.
+
+\item The synchronization of permission between Windows and Unix now
+ works properly.
+
+\item A binding \verb|CYGWIN=binmode| in now added to the environment
+ so that the Cygwin port of OpenSSH works properly in a non-Cygwin
+ context.
+
+\item The \verb|servercmd| and \verb|addversionno| preferences can now
+ be used together: \verb|-addversionno| appends an appropriate
+ \verb+-NNN+ to the server command, which is found by using the value
+ of the \verb|-servercmd| preference if there is one, or else just
+ \verb|unison|.
+
+\item Both \verb|'-pref=val'| and \verb|'-pref val'| are now allowed for
+ boolean values. (The former can be used to set a preference to false.)
+
+\item Lot of small bugs fixed.
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.5.31}
+\item The \verb|log| preference is now set to \verb|true| by default,
+ since the log file seems useful for most users.
+\item Several miscellaneous bugfixes (most involving symlinks).
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.5.25}
+\item \incompatible{} Archive format has changed (again).
+
+\item Several significant bugs introduced in 2.5.25 have been fixed.
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.5.1}
+\item \incompatible{} Archive format has changed. Make sure you
+synchronize your replicas before upgrading, to avoid spurious
+conflicts. The first sync after upgrading will be slow.
+
+\item New functionality:
+\begin{itemize}
+\item Unison now synchronizes file modtimes, user-ids, and group-ids.
+
+These new features are controlled by a set of new preferences, all of
+which are currently \verb|false| by default.
+
+\begin{itemize}
+\item When the \verb|times| preference is set to \verb|true|, file
+modification times are propaged. (Because the representations of time
+may not have the same granularity on both replicas, Unison may not always
+be able to make the modtimes precisely equal, but it will get them as
+close as the operating systems involved allow.)
+\item When the \verb|owner| preference is set to \verb|true|, file
+ownership information is synchronized.
+\item When the \verb|group| preference is set to \verb|true|, group
+information is synchronized.
+\item When the \verb|numericIds| preference is set to \verb|true|, owner
+and group information is synchronized numerically. By default, owner and
+group numbers are converted to names on each replica and these names are
+synchronized. (The special user id 0 and the special group 0 are never
+mapped via user/group names even if this preference is not set.)
+\end{itemize}
+
+\item Added an integer-valued preference \verb|perms| that can be used to
+control the propagation of permission bits. The value of this preference
+is a mask indicating which permission bits should be synchronized. It is
+set by default to $0o1777$: all bits but the set-uid and set-gid bits are
+synchronised (synchronizing theses latter bits can be a security hazard).
+If you want to synchronize all bits, you can set the value of this
+preference to $-1$.
+
+\item Added a \verb|log| preference (default \verb|false|), which makes
+Unison keep a complete record of the changes it makes to the replicas.
+By default, this record is written to a file called \verb|unison.log| in
+the user's home directory (the value of the \verb|HOME| environment
+variable). If you want it someplace else, set the \verb|logfile|
+preference to the full pathname you want Unison to use.
+
+\item Added an \verb|ignorenot| preference that maintains a set of patterns
+ for paths that should definitely {\em not} be ignored, whether or not
+ they match an \verb|ignore| pattern. (That is, a path will now be ignored
+ iff it matches an ignore pattern and does not match any ignorenot patterns.)
+\end{itemize}
+
+\item User-interface improvements:
+\begin{itemize}
+\item Roots are now displayed in the user interface in the same order
+as they were given on the command line or in the preferences file.
+\item When the \verb|batch| preference is set, the graphical user interface no
+ longer waits for user confirmation when it displays a warning message: it
+ simply pops up an advisory window with a Dismiss button at the bottom and
+ keeps on going.
+\item Added a new preference for controlling how many status messages are
+ printed during update detection: \verb|statusdepth| controls the maximum
+ depth for paths on the local machine (longer paths are not displayed, nor
+ are non-directory paths). The value should be an integer; default is 1.
+\item Removed the \verb|trace| and \verb|silent| preferences. They did
+not seem very useful, and there were too many preferences for controlling
+output in various ways.
+\item The text UI now displays just the default command (the one that
+will be used if the user just types \verb|<return>|) instead of all
+available commands. Typing \verb|?| will print the full list of
+possibilities.
+\item The function that finds the canonical hostname of the local host
+(which is used, for example, in calculating the name of the archive file
+used to remember which files have been synchronized) normally uses the
+\verb|gethostname| operating system call. However, if the environment
+variable \verb|UNISONLOCALHOSTNAME| is set, its value will now be used
+instead. This makes it easier to use Unison in situations where a
+machine's name changes frequently (e.g., because it is a laptop and gets
+moved around a lot).
+\item File owner and group are now displayed in the ``detail window'' at
+the bottom of the screen, when unison is configured to synchronize them.
+\end{itemize}
+
+\item For hackers:
+\begin{itemize}
+\item Updated to Jacques Garrigue's new version of \verb|lablgtk|, which
+ means we can throw away our local patched version.
+
+ If you're compiling the GTK version of unison from sources, you'll need
+ to update your copy of lablgtk to the developers release.
+ (Warning: installing lablgtk under Windows is currently a bit
+ challenging.)
+
+\item The TODO.txt file (in the source distribution) has been cleaned up
+and reorganized. The list of pending tasks should be much easier to
+make sense of, for people that may want to contribute their programming
+energies. There is also a separate file BUGS.txt for open bugs.
+\item The Tk user interface has been removed (it was not being maintained
+and no longer compiles).
+\item The \verb|debug| preference now prints quite a bit of additional
+information that should be useful for identifying sources of problems.
+\item The version number of the remote server is now checked right away
+ during the connection setup handshake, rather than later. (Somebody
+ sent a bug report of a server crash that turned out to come from using
+ inconsistent versions: better to check this earlier and in a way that
+ can't crash either client or server.)
+\item Unison now runs correctly on 64-bit architectures (e.g. Alpha
+linux). We will not be distributing binaries for these architectures
+ourselves (at least for a while) but if someone would like to make them
+available, we'll be glad to provide a link to them.
+\end{itemize}
+
+\item Bug fixes:
+\begin{itemize}
+\item Pattern matching (e.g. for \verb|ignore|) is now case-insensitive
+ when Unison is in case-insensitive mode (i.e., when one of the replicas
+ is on a windows machine).
+\item Some people had trouble with mysterious failures during
+ propagation of updates, where files would be falsely reported as having
+ changed during synchronization. This should be fixed.
+\item Numerous smaller fixes.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.4.1}
+\item Added a number of 'sorting modes' for the user interface. By
+default, conflicting changes are displayed at the top, and the rest of
+the entries are sorted in alphabetical order. This behavior can be
+changed in the following ways:
+\begin{itemize}
+\item Setting the \verb|sortnewfirst| preference to \verb|true| causes
+newly created files to be displayed before changed files.
+\item Setting \verb|sortbysize| causes files to be displayed in
+increasing order of size.
+\item Giving the preference \verb|sortfirst=<pattern>| (where
+\verb|<pattern>| is a path descriptor in the same format as 'ignore' and 'follow'
+patterns, causes paths matching this pattern to be displayed first.
+\item Similarly, giving the preference \verb|sortlast=<pattern>|
+causes paths matching this pattern to be displayed last.
+\end{itemize}
+The sorting preferences are described in more detail in the user manual.
+The \verb|sortnewfirst| and \verb|sortbysize| flags can also be accessed
+from the 'Sort' menu in the grpahical user interface.
+
+\item Added two new preferences that can be used to change unison's
+fundamental behavior to make it more like a mirroring tool instead of
+a synchronizer.
+\begin{itemize}
+\item Giving the preference \verb|prefer| with argument \verb|<root>|
+(by adding \verb|-prefer <root>| to the command line or \verb|prefer=<root>|)
+to your profile) means that, if there is a conflict, the contents of
+\verb|<root>|
+should be propagated to the other replica (with no questions asked).
+Non-conflicting changes are treated as usual.
+\item Giving the preference \verb|force| with argument \verb|<root>|
+will make unison resolve {\em all} differences in favor of the given
+root, even if it was the other replica that was changed.
+\end{itemize}
+These options should be used with care! (More information is available in
+the manual.)
+
+\item Small changes:
+\begin{itemize}
+\item
+Changed default answer to 'Yes' in all two-button dialogs in the
+ graphical interface (this seems more intuitive).
+
+\item The \verb|rsync| preference has been removed (it was used to
+activate rsync compression for file transfers, but rsync compression is
+now enabled by default).
+\item In the text user interface, the arrows indicating which direction
+changes are being
+ propagated are printed differently when the user has overridded Unison's
+ default recommendation (\verb|====>| instead of \verb|---->|). This
+ matches the behavior of the graphical interface, which displays such
+ arrows in a different color.
+\item Carriage returns (Control-M's) are ignored at the ends of lines in
+ profiles, for Windows compatibility.
+\item All preferences are now fully documented in the user manual.
+\end{itemize}
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.3.12}
+\item \incompatible{} Archive format has changed. Make sure you
+synchronize your replicas before upgrading, to avoid spurious
+conflicts. The first sync after upgrading will be slow.
+
+\item New/improved functionality:
+\begin{itemize}
+\item A new preference -sortbysize controls the order in which changes
+ are displayed to the user: when it is set to true, the smallest
+ changed files are displayed first. (The default setting is false.)
+\item A new preference -sortnewfirst causes newly created files to be
+ listed before other updates in the user interface.
+\item We now allow the ssh protocol to specify a port.
+\item Incompatible change: The unison: protocol is deprecated, and we added
+ file: and socket:. You may have to modify your profiles in the
+ .unison directory.
+ If a replica is specified without an explicit protocol, we now
+ assume it refers to a file. (Previously "//saul/foo" meant to use
+ SSH to connect to saul, then access the foo directory. Now it means
+ to access saul via a remote file mechanism such as samba; the old
+ effect is now achieved by writing {\tt ssh://saul/foo}.)
+\item Changed the startup sequence for the case where roots are given but
+ no profile is given on the command line. The new behavior is to
+ use the default profile (creating it if it does not exist), and
+ temporarily override its roots. The manual claimed that this case
+ would work by reading no profile at all, but AFAIK this was never
+ true.
+\item In all user interfaces, files with conflicts are always listed first
+\item A new preference 'sshversion' can be used to control which version
+ of ssh should be used to connect to the server. Legal values are 1 and 2.
+ (Default is empty, which will make unison use whatever version of ssh
+ is installed as the default 'ssh' command.)
+\item The situation when the permissions of a file was updated the same on
+ both side is now handled correctly (we used to report a spurious conflict)
+
+\end{itemize}
+
+\item Improvements for the Windows version:
+\begin{itemize}
+\item The fact that filenames are treated case-insensitively under
+Windows should now be handled correctly. The exact behavior is described
+in the cross-platform section of the manual.
+\item It should be possible to synchronize with Windows shares, e.g.,
+ //host/drive/path.
+\item Workarounds to the bug in syncing root directories in Windows.
+The most difficult thing to fix is an ocaml bug: Unix.opendir fails on
+c: in some versions of Windows.
+\end{itemize}
+
+\item Improvements to the GTK user interface (the Tk interface is no
+longer being maintained):
+\begin{itemize}
+\item The UI now displays actions differently (in blue) when they have been
+ explicitly changed by the user from Unison's default recommendation.
+\item More colorful appearance.
+\item The initial profile selection window works better.
+\item If any transfers failed, a message to this effect is displayed along with
+ 'Synchronization complete' at the end of the transfer phase (in case they
+ may have scrolled off the top).
+\item Added a global progress meter, displaying the percentage of {\em total}
+ bytes that have been transferred so far.
+\end{itemize}
+
+\item Improvements to the text user interface:
+\begin{itemize}
+\item The file details will be displayed automatically when a
+ conflict is been detected.
+\item when a warning is generated (e.g. for a temporary
+ file left over from a previous run of unison) Unison will no longer
+ wait for a response if it is running in -batch mode.
+\item The UI now displays a short list of possible inputs each time it waits
+ for user interaction.
+\item The UI now quits immediately (rather than looping back and starting
+ the interaction again) if the user presses 'q' when asked whether to
+ propagate changes.
+\item Pressing 'g' in the text user interface will proceed immediately
+ with propagating updates, without asking any more questions.
+\end{itemize}
+
+\item Documentation and installation changes:
+\begin{itemize}
+\item The manual now includes a FAQ, plus sections on common problems and
+on tricks contributed by users.
+\item Both the download page and the download directory explicitly say
+what are the current stable and beta-test version numbers.
+\item The OCaml sources for the up-to-the-minute developers' version (not
+guaranteed to be stable, or even to compile, at any given time!) are now
+available from the download page.
+\item Added a subsection to the manual describing cross-platform
+ issues (case conflicts, illegal filenames)
+\end{itemize}
+
+\item Many small bug fixes and random improvements.
+
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.3.1}
+\item Several bug fixes. The most important is a bug in the rsync
+module that would occasionally cause change propagation to fail with a
+'rename' error.
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.2}
+\item The multi-threaded transport system is now disabled by default.
+(It is not stable enough yet.)
+\item Various bug fixes.
+\item A new experimental feature:
+
+ The final component of a -path argument may now be the wildcard
+ specifier \verb|*|. When Unison sees such a path, it expands this path on
+ the client into into the corresponding list of paths by listing the
+ contents of that directory.
+
+ Note that if you use wildcard paths from the command line, you will
+ probably need to use quotes or a backslash to prevent the * from
+ being interpreted by your shell.
+
+ If both roots are local, the contents of the first one will be used
+ for expanding wildcard paths. (Nb: this is the first one {\em after} the
+ canonization step -- i.e., the one that is listed first in the user
+ interface -- not the one listed first on the command line or in the
+ preferences file.)
+\end{changesfromversion}
+
+\begin{changesfromversion}{2.1}
+\item The transport subsystem now includes an implementation by
+Sylvain Gommier and Norman Ramsey of Tridgell and Mackerras's
+\verb|rsync| protocol. This protocol achieves much faster
+transfers when only a small part of a large file has been changed by
+sending just diffs. This feature is mainly helpful for transfers over
+slow links---on fast local area networks it can actually degrade
+performance---so we have left it off by default. Start unison with
+the \verb|-rsync| option (or put \verb|rsync=true| in your preferences
+file) to turn it on.
+
+\item ``Progress bars'' are now diplayed during remote file transfers,
+showing what percentage of each file has been transferred so far.
+
+\item The version numbering scheme has changed. New releases will now
+ be have numbers like 2.2.30, where the second component is
+ incremented on every significant public release and the third
+ component is the ``patch level.''
+
+\item Miscellaneous improvements to the GTK-based user interface.
+\item The manual is now available in PDF format.
+
+\item We are experimenting with using a multi-threaded transport
+subsystem to transfer several files at the same time, making
+much more effective use of available network bandwidth. This feature
+is not completely stable yet, so by default it is disabled in the
+release version of Unison.
+
+If you want to play with the multi-threaded version, you'll need to
+recompile Unison from sources (as described in the documentation),
+setting the THREADS flag in Makefile.OCaml to true. Make sure that
+your OCaml compiler has been installed with the \verb|-with-pthreads|
+configuration option. (You can verify this by checking whether the
+file \verb|threads/threads.cma| in the OCaml standard library
+directory contains the string \verb|-lpthread| near the end.)
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.292}
+\item Reduced memory footprint (this is especially important during
+the first run of unison, where it has to gather information about all
+the files in both repositories).
+\item Fixed a bug that would cause the socket server under NT to fail
+ after the client exits.
+\item Added a SHIFT modifier to the Ignore menu shortcut keys in GTK
+ interface (to avoid hitting them accidentally).
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.231}
+\item Tunneling over ssh is now supported in the Windows version. See
+the installation section of the manual for detailed instructions.
+
+\item The transport subsystem now includes an implementation of the
+\verb|rsync| protocol, built by Sylvain Gommier and Norman Ramsey.
+This protocol achieves much faster transfers when only a small part of
+a large file has been changed by sending just diffs. The rsync
+feature is off by default in the current version. Use the
+\verb|-rsync| switch to turn it on. (Nb. We still have a lot of
+tuning to do: you may not notice much speedup yet.)
+
+\item We're experimenting with a multi-threaded transport subsystem,
+written by Jerome Vouillon. The downloadable binaries are still
+single-threaded: if you want to try the multi-threaded version, you'll
+need to recompile from sources. (Say \verb|make THREADS=true|.)
+Native thread support from the compiler is required. Use the option
+\verb|-threads N| to select the maximal number of concurrent
+threads (default is 5). Multi-threaded
+and single-threaded clients/servers can interoperate.
+
+\item A new GTK-based user interface is now available, thanks to
+Jacques Garrigue. The Tk user interface still works, but we'll be
+shifting development effort to the GTK interface from now on.
+\item OCaml 3.00 is now required for compiling Unison from sources.
+The modules \verb|uitk| and \verb|myfileselect| have been changed to
+use labltk instead of camltk. To compile the Tk interface in Windows,
+you must have ocaml-3.00 and tk8.3. When installing tk8.3, put it in
+\verb|c:\Tcl| rather than the suggested \verb|c:\Program Files\Tcl|,
+and be sure to install the headers and libraries (which are not
+installed by default).
+
+\item Added a new \verb|-addversionno| switch, which causes unison to
+use \verb|unison-<currentversionnumber>| instead of just \verb|unison|
+as the remote server command. This allows multiple versions of unison
+to coexist conveniently on the same server: whichever version is run
+on the client, the same version will be selected on the server.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.219}
+\item \incompatible{} Archive format has changed. Make sure you
+synchronize your replicas before upgrading, to avoid spurious
+conflicts. The first sync after upgrading will be slow.
+
+\item This version fixes several annoying bugs, including:
+\begin{itemize}
+\item Some cases where propagation of file permissions was not
+working.
+\item umask is now ignored when creating directories
+\item directories are create writable, so that a read-only directory and
+ its contents can be propagated.
+\item Handling of warnings generated by the server.
+\item Synchronizing a path whose parent is not a directory on both sides is
+now flagged as erroneous.
+\item Fixed some bugs related to symnbolic links and nonexistant roots.
+\begin{itemize}
+\item
+ When a change (deletion or new contents) is propagated onto a
+ 'follow'ed symlink, the file pointed to by the link is now changed.
+ (We used to change the link itself, which doesn't fit our assertion
+ that 'follow' means the link is completely invisible)
+ \item When one root did not exist, propagating the other root on top of it
+ used to fail, becuase unison could not calculate the working directory
+ into which to write changes. This should be fixed.
+\end{itemize}
+\end{itemize}
+
+\item A human-readable timestamp has been added to Unison's archive files.
+
+\item The semantics of Path and Name regular expressions now
+correspond better.
+
+\item Some minor improvements to the text UI (e.g. a command for going
+back to previous items)
+
+\item The organization of the export directory has changed --- should
+be easier to find / download things now.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.200}
+\item \incompatible{} Archive format has changed. Make sure you
+synchronize your replicas before upgrading, to avoid spurious
+conflicts. The first sync after upgrading will be slow.
+
+\item This version has not been tested extensively on Windows.
+
+\item Major internal changes designed to make unison safer to run
+at the same time as the replicas are being changed by the user.
+
+\item Internal performance improvements.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.190}
+\item \incompatible{} Archive format has changed. Make sure you
+synchronize your replicas before upgrading, to avoid spurious
+conflicts. The first sync after upgrading will be slow.
+
+\item A number of internal functions have been changed to reduce the
+amount of memory allocation, especially during the first
+synchronization. This should help power users with very big replicas.
+
+\item Reimplementation of low-level remote procedure call stuff, in
+preparation for adding rsync-like smart file transfer in a later
+release.
+
+\item Miscellaneous bug fixes.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.180}
+\item \incompatible{} Archive format has changed. Make sure you
+synchronize your replicas before upgrading, to avoid spurious
+conflicts. The first sync after upgrading will be slow.
+
+\item Fixed some small bugs in the interpretation of ignore patterns.
+
+\item Fixed some problems that were preventing the Windows version
+from working correctly when click-started.
+
+\item Fixes to treatment of file permissions under Windows, which were
+causing spurious reports of different permissions when synchronizing
+between windows and unix systems.
+
+\item Fixed one more non-tail-recursive list processing function,
+which was causing stack overflows when synchronizing very large
+replicas.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.169}
+\item The text user interface now provides commands for ignoring
+ files.
+\item We found and fixed some {\em more} non-tail-recursive list
+ processing functions. Some power users have reported success with
+ very large replicas.
+\item \incompatible
+Files ending in \verb|.tmp| are no longer ignored automatically. If you want
+to ignore such files, put an appropriate ignore pattern in your profile.
+
+\item \incompatible{} The syntax of {\tt ignore} and {\tt follow}
+patterns has changed. Instead of putting a line of the form
+\begin{verbatim}
+ ignore = <regexp>
+\end{verbatim}
+ in your profile ({\tt .unison/default.prf}), you should put:
+\begin{verbatim}
+ ignore = Regex <regexp>
+\end{verbatim}
+Moreover, two other styles of pattern are also recognized:
+\begin{verbatim}
+ ignore = Name <name>
+\end{verbatim}
+matches any path in which one component matches \verb|<name>|, while
+\begin{verbatim}
+ ignore = Path <path>
+\end{verbatim}
+matches exactly the path \verb|<path>|.
+
+Standard ``globbing'' conventions can be used in \verb|<name>| and
+\verb|<path>|:
+\begin{itemize}
+\item a \verb|?| matches any single character except \verb|/|
+\item a \verb|*| matches any sequence of characters not including \verb|/|
+\item \verb|[xyz]| matches any character from the set $\{{\tt x},
+ {\tt y}, {\tt z} \}$
+\item \verb|{a,bb,ccc}| matches any one of \verb|a|, \verb|bb|, or
+ \verb|ccc|.
+\end{itemize}
+
+See the user manual for some examples.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.146}
+\item Some users were reporting stack overflows when synchronizing
+ huge directories. We found and fixed some non-tail-recursive list
+ processing functions, which we hope will solve the problem. Please
+ give it a try and let us know.
+\item Major additions to the documentation.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.142}
+\item Major internal tidying and many small bugfixes.
+\item Major additions to the user manual.
+\item Unison can now be started with no arguments -- it will prompt
+automatically for the name of a profile file containing the roots to
+be synchronized. This makes it possible to start the graphical UI
+from a desktop icon.
+\item Fixed a small bug where the text UI on NT was raising a 'no such
+ signal' exception.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.139}
+\item The precompiled windows binary in the last release was compiled
+with an old OCaml compiler, causing propagation of permissions not to
+work (and perhaps leading to some other strange behaviors we've heard
+reports about). This has been corrected. If you're using precompiled
+binaries on Windows, please upgrade.
+\item Added a \verb|-debug| command line flag, which controls debugging
+of various modules. Say \verb|-debug XXX| to enable debug tracing for
+module \verb|XXX|, or \verb|-debug all| to turn on absolutely everything.
+\item Fixed a small bug where the text UI on NT was raising a 'no such signal'
+exception.
+\end{changesfromversion}
+
+\begin{changesfromversion}{1.111}
+\item \incompatible{} The names and formats of the preference files in
+the .unison directory have changed. In particular:
+\begin{itemize}
+\item the file ``prefs'' should be renamed to default.prf
+\item the contents of the file ``ignore'' should be merged into
+ default.prf. Each line of the form \verb|REGEXP| in ignore should
+ become a line of the form \verb|ignore = REGEXP| in default.prf.
+\end{itemize}
+\item Unison now handles permission bits and symbolic links. See the
+manual for details.
+
+\item You can now have different preference files in your .unison
+directory. If you start unison like this
+\begin{verbatim}
+ unison profilename
+\end{verbatim}
+(i.e. with just one ``anonymous'' command-line argument), then the
+file \verb|~/.unison/profilename.prf| will be loaded instead of
+\verb|default.prf|.
+
+\item Some improvements to terminal handling in the text user interface
+
+\item Added a switch -killServer that terminates the remote server process
+when the unison client is shutting down, even when using sockets for
+communication. (By default, a remote server created using ssh/rsh is
+terminated automatically, while a socket server is left running.)
+\item When started in 'socket server' mode, unison prints 'server started' on
+ stderr when it is ready to accept connections.
+ (This may be useful for scripts that want to tell when a socket-mode server
+ has finished initalization.)
+\item We now make a nightly mirror of our current internal development
+ tree, in case anyone wants an up-to-the-minute version to hack
+ around with.
+\item Added a file CONTRIB with some suggestions for how to help us
+make Unison better.
+\end{changesfromversion}
+
Deleted: branches/2.45/src/INSTALL.win32-msvc
===================================================================
--- trunk/src/INSTALL.win32-msvc 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/src/INSTALL.win32-msvc 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,512 +0,0 @@
-Installation notes to build Unison on Windows systems, with Visual C++
-
-[The following instructions were tested for Unison 2.9.1 on a Windows
-2000 machine running OCaml 3.04 -- that was a long time ago, so there
-may be some discrepancies with current versions of things. If you
-notice any, please send a correction to unison-users at yahoogroups.com.]
-
-Contents
-
-1.Setting up the Windows system
- 1.1 General requirements
- 1.2 A Unix-like layer: CygWin
- 1.3 Visual C++
- 1.4 The OCaml compiler
-2.Compiling Unison
- 2.1 Text user interface
- 2.2 Tk user interface
- 2.3 Gtk user interface
-3.Using new public versions of Tk/Gtk/LablGtk
- 3.1 Using a new version of Tcl/Tk
- 3.2 Patching a new version of Gtk
- 3.3 Patching a new version of LablGtk
- 3.4 Making patches from the public sources
-Appendix
- A.Windows text format
- B.'.bashrc'
- C.Windows files and directories names
- D.Windows icons
-
-
-
-Section 1 - Setting up the Windows system
-
-
-1.1 General requirements
-
- We will assume your are logged in as a regular user. We will mention cases
-when you need to be granted administrator permissions.
-
- We will work in your home directory.
-
- For a complete installation from scratch, you will need about 300 Mb.
-
- CygWin, a Unix-like layer, is needed to be able to use GNU tools
-like 'bash', 'make', 'sed', 'patch', etc.
-
- The native Win32 port of OCaml distribution version 3.04 is required.
-It itself requires Visual C++ 6.0.
-
-1.2 A Unix-like layer: CygWin
-
- Download CygWin from 'http://www.cygwin.com/':
-* click "install cygwin now" and follow the instruction to set up cygwin.
- install the essential packages such as "make", "fileutil", "openssh", etc.
- set the root directory (e.g. 'd:\cygwin')
-
- Setup 'bash':
-* click on 'bash'.
-* enter 'export HOME=/home/<username>', make the directory, then 'cd'.
-* create a '.bashrc' in CygWin's root directory to suit your
- needs (see Appendix B for an example).
-* check the environment variable OSTYPE with 'echo $OSTYPE'. If the result is
- not 'cygwin' or 'cygwin20', then add 'export OSTYPE=cygwin' to the
- '.bashrc' file. This variable helps the unison Makefile (project
- file) to understand that we are compiling under Windows platform.
-
- Remember you can access the whole Windows filesystem with a Unix
-path through '/cygdrive/<drive letter>/<path>' (e.g. '/cygdrive/c/winnt'
-stands for 'C:\WinNT')
-
-
-1.3 Visual C++
-
- Run the installation program from the CD with Administrator
-permissions. We only need Visual C++ and MsDN is not required.
-
- To check out your installation, use 'bash' to enter 'cl /?'.
-
- If something goes wrong :
-* your path must contain the Visual C++ 'bin' directory; you may have to
- enter something like
- 'export PATH=$PATH:/cygdrive/progra~1/micros~1/vc98/bin'.
-* your path must contain the Visual Studio '.dll' files' directory; you may
- have to enter something like
- 'export PATH=$PATH:/cygdrive/progra~1/micros~1/common/msdev98/bin'.
-* the Visual C++ compiler must be able to access the headers; you may have to
- enter something like 'export INCLUDE='C:\progra~1\micros~1\vc98\include''
- (path between single quotes).
-* the Visual C++ linker must be able to access the libraries; you may have to
- enter something like 'export LIB='C:\progra~1\micros~1\vc98\lib'' (path
- between single quotes).
-
-
-1.4 The OCaml compiler
-
- Download the Native Win32 port of OCaml 3.04 from
-'http://caml.inria.fr/ocaml/distrib.html'. It's a self-extracting binary.
-
- Run it with Administrator permissions (only use 8 characters-long
-names in the installation directory).
-
- To check out your installation, use 'bash' to enter 'ocamlc -v'.
-
- If something goes wrong :
-* your path must contain the OCaml 'bin' directory; you may have to enter
- something like 'export PATH=$PATH:/cygdrive/c/ocaml/bin'.
-* 'ocamlc -v' must report the OCaml 'lib' directory; you may have to enter
- something like "export CAMLLIB='C:\ocaml\lib'" (path between single
- quotes).
-
-1.5 Microsoft Macro Assembler (MASM32)
-
-Download MASM32 from http://www.masm32.com/masmdl.htm, unzip and install
-it. Add the MASM32 bin directory (e.g. C:\masm32\bin) to your Path. Test
-the assembler with
-
- ml
-
-Your shell should answer with
-
- Microsoft (R) Macro Assembler Version 6.14.8444
- Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
-
- usage: ML [ options ] filelist [ /link linkoptions]
- Run "ML /help" or "ML /?" for more info
-
-
-Section 2 - Compiling Unison
-
-
-2.1 Text user interface
-
- Unpack the Unison sources.
-
- Using 'bash', enter 'make clean', then 'make UISTYLE=text' to compile.
-
- If something goes wrong :
-* if 'make' reports 'missing separator', be sure the makefiles are in
- Unix text format (see Appendix A).
-* if .depend is not provided, create one using
- 'ocamldep *.mli *.ml > .depend'; you will have to convert this file
- to Unix text format (see Appendix A).
-* the minor 'etags' error is reported when 'emacs' is missing; you may
- want to install it.
-
-2.2 Gtk user interface
-
- You need the Gtk libraries (already installed if you got the Tcl/Tk
-libraries). Get the 'guilib.tar.gz' tarball from the 'resources'
-directory of the Unison web site and unpack it in your Ocaml 'lib'
-directory. This will create a 'guilib' directory containing the
-libraries.
-
- Now you need the LablGtk extension to OCaml.
- First, the Gtk development package is required. Get the
-'wingtk.patched.tar.gz' tarball from the 'resources' directory of the
-Unison web site and unpack it. This will create a 'wingtk' directory.
-
- Now, get the 'lablgtk-1.2.3-msvc-static.tar.gz' tarball from the
-'resources' directory of the Unison web site and unpack it somewhere
-(a building location, just for the compilation). This will create a
-'lablgtk-1.2.3-static' directory. Edit the 'config.make.nt' file to
-set up the access path to your OCaml 'lib' directory and to the
-'wingtk' directory you created in the previous step. In
-'lablgtk-1.2.3-static/src', run 'nmake -f Makefile.nt'. If you can use
-the OCaml native-code compiler, run 'nmake -f Makefile.nt opt' too. If
-you can't, you probably need the MASM assembler, also available in the
-'resources' directory of the Unison web site. If everything goes
-well, run 'nmake -f Makefile.nt install' to install the software. You
-may want to remove the compilation directory 'lablgtk-1.2.3-static'.
-
- Using 'bash' in the Unison sources directory, enter 'make clean'
-then 'make UISTYLE=gtk'.
-
- Run 'unison.exe' with the Gtk .dll's in your search path (they can
-be found in the 'guilib' directory), unless you built with the
-NATIVE=true option.
-
- "unison.exe" built with NATIVE=true option is statically linked.
-This means that the executable doesn't refer to Cygwin and Gtk DLLs,
-and can therefore be distributed as a standalone application.
-
-
-Section 3 - Using new public versions of Tk/Gtk/LablGtk
-
-3.1 Patching a new version of Gtk
-
- Download the 'wingtk.patch.tar.gz' tarball from the 'resources'
-directory of the Unison web site and unpack it. Follow the
-instructions in the 'README.patch' file to download the Gtk sources,
-to patch them and to build the new static and dynamic libraries.
-
- Important: if a patch fails for any reason, try to apply the patches on a
- Unix system.
-
- Copy those new libraries to your 'ocaml/lib/guilib' directory, along
-with the .dll's (dynamic version).
-
- Using the new version of 'wingtk', recompile LablGtk (see section 2.3).
-
-
-3.2 Patching a new version of LablGtk
-
- Download lablgtk-1.2.3.tar.gz from the LablGtk homepage
-<http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/lablgtk.html>. Unpack
-it.
-
- Download the 'lablgtk-1.2.3-msvc-static.patch.gz' from the 'resources'
-directory of the Unison web site. Apply the patch by typing:
- 'patch < lablgtk.patch'
-above the 'lablgtk' directory.
-
- Important: if a patch fails for any reason, try to apply the patches on a
- Unix system.
-
-
-3.3 Making patches from the public sources
-
- The way from public Gtk/LablGtk sources to the provided Gtk/LablGtk
-dynamic/static extension has been somehow perilous. We strongly
-recommand using the provided sources and patches as a base for your
-further enhancements.
-
- To be exhaustive, here are the steps followed to create the provided
-sources (hoping it would help when trying to adapt a new version):
-
- WinGtk:
-
-* Download the Gtk win32 sources from
- 'http://www.gimp.org/~tml/gimp/win32//downloads.html'. We need
- 'glib-src-yyyymmdd' and 'gtk+-src-yyyymmdd' where 'yyyymmdd' is the
- release date. Version 2000/04/16 of these files was used.
-
-* We will make new Windows Makefiles from the old ones. Here is how to
- convert a Makefile:
- - change all '/MD' to '/MT' to use the same windows system
- libraries than ocaml
- (e.g. 'OPTIMIZE = -Ox -MD' becomes 'OPTIMIZE = -Ox -MT')
- - turns all '.dll' targets to '.lib' ones using
- 'MKLIB = lib /nologo /out:'
- you must remove all references to '.def' files
- you must remove all references to other '.lib' and '.res' but
- you will have to provide them when linking an executable later
- (e.g.
- glib-$(GLIB_VER).dll : $(glib_OBJECTS) glib.def
- $(CC) $(CFLAGS) -LD -Feglib-$(GLIB_VER).dll $(glib_OBJECTS) \
- user32.lib advapi32.lib wsock32.lib $(LDFLAGS) /def:glib.def
- becomes:
- glib-$(GLIB_VER).lib : $(glib_OBJECTS)
- $(MKLIB)glib-$(GLIB_VER).lib $(glib_OBJECTS)
- )
- - remove all '-GD' compilation flags
- (e.g.
- .c.obj :
- $(CC) $(CFLAGS) -GD -c -DGLIB_COMPILATION \
- -DG_LOG_DOMAIN=g_log_domain_glib $<
- becomes:
- .c.obj :
- $(CC) $(CFLAGS) -c -DGLIB_COMPILATION \
- -DG_LOG_DOMAIN=g_log_domain_glib $<
- )
- - provides the right libraries when linking executables
- (e.g.
- testgtk.exe : gtk-$(GTK_VER).dll testgtk.obj
- $(CC) $(CFLAGS) testgtk.obj gtk-$(GTK_VER).lib \
- ..\gdk\gdk-$(GTK_VER).lib $(GLIB)\glib-$(GLIB_VER).lib \
- $(LDFLAGS)
- becomes:
- testgtk.exe : gtk-$(GTK_VER).lib testgtk.obj
- $(CC) $(CFLAGS) testgtk.obj gtk-$(GTK_VER).lib \
- ..\gdk\gdk-$(GTK_VER).lib ..\gdk\win32\gdk-win32.lib \
- $(GLIB)\glib-$(GLIB_VER).lib $(GLIB)\gmodule-$(GLIB_VER).lib \
- user32.lib advapi32.lib wsock32.lib gdi32.lib imm32.lib \
- shell32.lib ole32.lib ../gdk/win32/gdk.res $(LDFLAGS)
- )
-
-* Convert 'glib/makefile.msc' and remove all references to the
- 'gthread' and 'pthread' directories and libraries from it (but keep
- 'gthread.obj').
-
-* Erase the 'gthread' directory.
-
-* Comment out the '#include <psapi.h>' line in
- 'glib/gmodule/gmodule-win32.c'.
-
-* You should now be able to compile the 'glib' and 'gmodule' libraries
- by typing 'nmake -f <new makefile>'. You can test it with 'testglib'
- and the other test programs. Remember to provide those two libraries
- when linking programs.
-
-* In 'gtk+/config.h.win32', undefine the following variables by
- commenting out their definition lines:
- HAVE_WINTAB, ENABLE_NLS, HAVE_GETTEXT, HAVE_LIBINTL
-
-* Convert 'gtk+/gdk/win32/makefile.msc' and remove all references to
- 'WTKIT', 'wntab32x', 'INTL' and 'gnu-intl' from it.
-
-* In 'gtk+/gdk/win32/rc/gdk.rc', comment out ',BUILDNUMBER'.
-
-* In 'gtk+/gdk/win32/gdkcursor-win32.c', replace 'gdk_DLLInstance' by
- 'gdk_ProgInstance'.
-
-* You should now be able to compile 'gdk-win32.lib'.
-
-* Convert 'gtk+/gdk/makefile.msc' and remove all references to
- 'WTKIT', 'wntab32x', 'INTL' and 'gnu-intl' from it. Include
- 'gdk-win32.lib' as an object for the 'gdk' library.
-
-* You should now be able to compile the 'gdk' library. Remember to
- provide 'win32/gdk.res' as well as the 'gdk' library when linking
- programs.
-
-* Convert 'gtk+/gtk/makefile.msc' and remove all references to
- 'WTKIT', 'wntab32x', 'INTL', 'gnu-intl' and 'PTHREAD' from it.
-
-* Be sure to include all needed libraries in the '.exe' files' compilation
- command lines.
- In most case you need the following:
- gtk-$(GTK_VER).lib ..\gdk\gdk-$(GTK_VER).lib \
- $(GLIB)\glib-$(GLIB_VER).lib $(GLIB)\gmodule-$(GLIB_VER).lib \
- user32.lib advapi32.lib wsock32.lib gdi32.lib imm32.lib shell32.lib \
- ole32.lib \
- ../gdk/win32/gdk.res
-
-* You should now be able to compile the 'gtk' library. You can test it
- with 'testglib' and the other test programs.
-
-* With some cleaning of the Makefiles, it is also possible to build a
- dynamic version of the libraries, along with the .dll's, so that we
- finally obtain static/dynamic sources.
-
-* Make a patch with 'diff -Nr -C 5 <old dir> <new dir>' (you have to
- use the GNU diffutils' 'diff'). You will apply the patch with
- 'patch -p1 < <patch file>'.
-
- LablGtk:
-
-* Download LablGtk from 'http://www.gtk.org' or
- 'ftp://ftp.inria.fr/lang/caml-light/bazar-ocaml/'.
-
-* You can remove all subdirectories.
-
-* Edit 'config.make.nt' to include the right Gtk libraries.
-
-* Comment out all references to 'gutter' to be found in the sources
- with 'grep gutter *.h *.c *.mli *.ml'.
-
-* Compile with 'nmake -f Makefile.nt'. If you can use the OCaml
- native-code compiler, run 'nmake -f Makefile.nt opt' too. If you
- can't, you probably need the MASM assembler. It was downloaded from
- 'http://www.cs.uu.nl/wais/html/na-dir/assembly-language/x86/microsoft.html'.
-
-* Make a patch as for WinGtk.
-
-
-
-Appendix A - Windows text format
-
-Windows and Unix use different text file formats. This section
-explains how to convert a file from a format to another.
-
-A.1 Text format conversion
-
- In order to convert a dos text file to a unix text file, we have to
-remove all extra characters that are :
-* carriage return or CR or ^M (ctrl-M) or \x0d or \o13 or \r
-* dos end-of-file or SUB or ^Z (ctrl-Z) or \x1a or \o26
-
-A.2 Conversion tools
-
- On a Unix-like top level (e.g any unix system or cygwin), you can use:
-
-* dos -> unix
- - tr -d '\15\32' < dosfile.txt > unixfile.txt
- - awk '{ sub("\r$", ""); print }' dosfile.txt > unixfile.txt
- - perl -p -e 's/\r$//' < dosfile.txt > unixfile.txt
-
-* unix -> dos
- - awk 'sub("$", "\r")' unixfile.txt > dosfile.txt
- - perl -p -e 's/$/\r/' < unixfile.txt > dosfile.txt
-
- You may want to use a short script like the following to convert
-more than one file at a time (doesn't work recursively; use at your
-own risk):
-
- #!/bin/sh
- echo dos2unix
- for F in "$@"
- do
- echo converting "$F"
- tr -d '\15\32' < $F > $F.tmp
- mv -f $F.tmp $F
- done
-
-A.3 Transmission issues
-
- If you transfer files using 'ftp' between a Unix system and a
-Windows system, be sure to run it in binary mode to disable any
-automatic conversion. To switch to binary mode, enter 'binary' (or
-simply 'bin').
-
-
-
-Appendix B - '.bashrc'.
-
- Copy the following '.bashrc' as a base to your own one. Be sure this
-file is in Unix text format.
-
-# .bashrc
-# gommier at saul.cis.upenn.edu
-
-export HOME=/
-export PS1="[\u@\h \w]$ "
-cd
-
-# Set up Path
-# $PATH currently contains the Windows Path converted to Unix path,
-export PATH=./:/bin:$PATH
-echo "Current path is :"
-echo $PATH
-echo " "
-
-# end
-
-
-
-Appendix C - Windows files and directories names
-
- Here are some general rules for applications creating names for
-directories and files or processing names supplied by the user:
-
-* Use any character in the current code page for a name, but do not
- use a path separator, a character in the range 0 through 31, or any
- character explicitly disallowed by the file system. A name can
- contain characters in the extended character set (128-255).
-
-* Use the backslash (\), the forward slash (/), or both to separate
- components in a path. No other character is acceptable as a path
- separator. Note that UNC names must adhere to the following format:
- \\server\share.
-
-* Use a period (.) as a directory component in a path to represent the
- current directory.
-
-* Use two consecutive periods (..) as a directory component in a path
- to represent the parent of the current directory.
-
-* Use a period (.) to separate the base file name from the extension
- in a directory name or file name.
-
-* Do not use the following characters in directory names or file
- names, because they are reserved: < > : " / \ |
-
-* Do not use device names, such as aux, con, lpt1, and prn, as file
- names or directory names.
-
-* Process a path as a null-terminated string. The maximum length for a
- path, including a trailing backslash, is given by MAX_PATH.
-
-* The Unicode versions of several functions permit paths that exceed
- the MAX_PATH length if the path has the "\\?\" prefix. The "\\?\"
- tells the function to turn off path parsing. However, each component
- in the path cannot be more than MAX_PATH characters long. Use the
- "\\?\" prefix with paths for local storage devices and the
- "\\?\UNC\" prefix with paths having the Universal Naming Convention
- (UNC) format. The "\\?\" is ignored as part of the path. For
- example, "\\?\C:\myworld\private" is seen as "C:\myworld\private",
- and "\\?\UNC\bill_g_1\hotstuff\coolapps" is seen as
- "\\bill_g_1\hotstuff\coolapps".
-
-* Do not assume case sensitivity. Consider names such as OSCAR, Oscar,
- and oscar to be the same.
-
-
-
-Appendix D - Windows icons
-
- Here are some general informations on how to make your Windows
-program have a nice icon.
-
-* What we mean by icon is a set of bitmaps that are displayed by
- Windows to represent your program on the desktop, on the top left
- corner of each window, etc. For your program's binary to include an
- icon, you will have to draw each bitmap and to store them in .bmp
- files, then to archive them in a .ico file, then to archive that
- icon file in a .res file along with other resources, and finally to
- link your program with that very .res file.
-
-* Current graphic formats for icons are 16 x 16, 32 x 32 and 48 x 48
- pixels with 16 or 256 colors. One format must always exist for
- compatibility with all Windows versions: the 32 x 32 x 16 format.
- Furthermore, the colors refer to the standard palette (sometimes
- called www palette), which means you mustn't use optimized palette
- when turning RGB colors to indexed colors. If you need subtle nuances,
- remember you can interleave pixels of two different colors to create
- the impression of a third, average one.
-
-* Once your bitmaps are ready, you can use the Visual C++ IDE to create
- your .ico file. Use the resource tool bar to create a 'new icon'.
- Open your .bmp files and simply cut and paste them into the icon
- window. You have to select the proper device (or format) for each
- bitmap before achieving the copy. When your icon (i.e. set of bitmaps)
- is ready, right-click on the icon name in the resource list window to
- export it.
- Note: you should never trust that IDE when dealing with colors, since
- it seems to get quickly lost between 16 or 256 colors.
-
-* To include your icon into a resource file, add a line for it into the
- .rc script file and compile with rc to create the .res file.
-
-* Just add the .res file to the link command line to have your binary
- include the icon.
Copied: branches/2.45/src/INSTALL.win32-msvc (from rev 486, trunk/src/INSTALL.win32-msvc)
===================================================================
--- branches/2.45/src/INSTALL.win32-msvc (rev 0)
+++ branches/2.45/src/INSTALL.win32-msvc 2012-04-02 15:54:47 UTC (rev 487)
@@ -0,0 +1,512 @@
+Installation notes to build Unison on Windows systems, with Visual C++
+
+[The following instructions were tested for Unison 2.9.1 on a Windows
+2000 machine running OCaml 3.04 -- that was a long time ago, so there
+may be some discrepancies with current versions of things. If you
+notice any, please send a correction to unison-users at yahoogroups.com.]
+
+Contents
+
+1.Setting up the Windows system
+ 1.1 General requirements
+ 1.2 A Unix-like layer: CygWin
+ 1.3 Visual C++
+ 1.4 The OCaml compiler
+2.Compiling Unison
+ 2.1 Text user interface
+ 2.2 Tk user interface
+ 2.3 Gtk user interface
+3.Using new public versions of Tk/Gtk/LablGtk
+ 3.1 Using a new version of Tcl/Tk
+ 3.2 Patching a new version of Gtk
+ 3.3 Patching a new version of LablGtk
+ 3.4 Making patches from the public sources
+Appendix
+ A.Windows text format
+ B.'.bashrc'
+ C.Windows files and directories names
+ D.Windows icons
+
+
+
+Section 1 - Setting up the Windows system
+
+
+1.1 General requirements
+
+ We will assume your are logged in as a regular user. We will mention cases
+when you need to be granted administrator permissions.
+
+ We will work in your home directory.
+
+ For a complete installation from scratch, you will need about 300 Mb.
+
+ CygWin, a Unix-like layer, is needed to be able to use GNU tools
+like 'bash', 'make', 'sed', 'patch', etc.
+
+ The native Win32 port of OCaml distribution version 3.04 is required.
+It itself requires Visual C++ 6.0.
+
+1.2 A Unix-like layer: CygWin
+
+ Download CygWin from 'http://www.cygwin.com/':
+* click "install cygwin now" and follow the instruction to set up cygwin.
+ install the essential packages such as "make", "fileutil", "openssh", etc.
+ set the root directory (e.g. 'd:\cygwin')
+
+ Setup 'bash':
+* click on 'bash'.
+* enter 'export HOME=/home/<username>', make the directory, then 'cd'.
+* create a '.bashrc' in CygWin's root directory to suit your
+ needs (see Appendix B for an example).
+* check the environment variable OSTYPE with 'echo $OSTYPE'. If the result is
+ not 'cygwin' or 'cygwin20', then add 'export OSTYPE=cygwin' to the
+ '.bashrc' file. This variable helps the unison Makefile (project
+ file) to understand that we are compiling under Windows platform.
+
+ Remember you can access the whole Windows filesystem with a Unix
+path through '/cygdrive/<drive letter>/<path>' (e.g. '/cygdrive/c/winnt'
+stands for 'C:\WinNT')
+
+
+1.3 Visual C++
+
+ Run the installation program from the CD with Administrator
+permissions. We only need Visual C++ and MsDN is not required.
+
+ To check out your installation, use 'bash' to enter 'cl /?'.
+
+ If something goes wrong :
+* your path must contain the Visual C++ 'bin' directory; you may have to
+ enter something like
+ 'export PATH=$PATH:/cygdrive/progra~1/micros~1/vc98/bin'.
+* your path must contain the Visual Studio '.dll' files' directory; you may
+ have to enter something like
+ 'export PATH=$PATH:/cygdrive/progra~1/micros~1/common/msdev98/bin'.
+* the Visual C++ compiler must be able to access the headers; you may have to
+ enter something like 'export INCLUDE='C:\progra~1\micros~1\vc98\include''
+ (path between single quotes).
+* the Visual C++ linker must be able to access the libraries; you may have to
+ enter something like 'export LIB='C:\progra~1\micros~1\vc98\lib'' (path
+ between single quotes).
+
+
+1.4 The OCaml compiler
+
+ Download the Native Win32 port of OCaml 3.04 from
+'http://caml.inria.fr/ocaml/distrib.html'. It's a self-extracting binary.
+
+ Run it with Administrator permissions (only use 8 characters-long
+names in the installation directory).
+
+ To check out your installation, use 'bash' to enter 'ocamlc -v'.
+
+ If something goes wrong :
+* your path must contain the OCaml 'bin' directory; you may have to enter
+ something like 'export PATH=$PATH:/cygdrive/c/ocaml/bin'.
+* 'ocamlc -v' must report the OCaml 'lib' directory; you may have to enter
+ something like "export CAMLLIB='C:\ocaml\lib'" (path between single
+ quotes).
+
+1.5 Microsoft Macro Assembler (MASM32)
+
+Download MASM32 from http://www.masm32.com/masmdl.htm, unzip and install
+it. Add the MASM32 bin directory (e.g. C:\masm32\bin) to your Path. Test
+the assembler with
+
+ ml
+
+Your shell should answer with
+
+ Microsoft (R) Macro Assembler Version 6.14.8444
+ Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
+
+ usage: ML [ options ] filelist [ /link linkoptions]
+ Run "ML /help" or "ML /?" for more info
+
+
+Section 2 - Compiling Unison
+
+
+2.1 Text user interface
+
+ Unpack the Unison sources.
+
+ Using 'bash', enter 'make clean', then 'make UISTYLE=text' to compile.
+
+ If something goes wrong :
+* if 'make' reports 'missing separator', be sure the makefiles are in
+ Unix text format (see Appendix A).
+* if .depend is not provided, create one using
+ 'ocamldep *.mli *.ml > .depend'; you will have to convert this file
+ to Unix text format (see Appendix A).
+* the minor 'etags' error is reported when 'emacs' is missing; you may
+ want to install it.
+
+2.2 Gtk user interface
+
+ You need the Gtk libraries (already installed if you got the Tcl/Tk
+libraries). Get the 'guilib.tar.gz' tarball from the 'resources'
+directory of the Unison web site and unpack it in your Ocaml 'lib'
+directory. This will create a 'guilib' directory containing the
+libraries.
+
+ Now you need the LablGtk extension to OCaml.
+ First, the Gtk development package is required. Get the
+'wingtk.patched.tar.gz' tarball from the 'resources' directory of the
+Unison web site and unpack it. This will create a 'wingtk' directory.
+
+ Now, get the 'lablgtk-1.2.3-msvc-static.tar.gz' tarball from the
+'resources' directory of the Unison web site and unpack it somewhere
+(a building location, just for the compilation). This will create a
+'lablgtk-1.2.3-static' directory. Edit the 'config.make.nt' file to
+set up the access path to your OCaml 'lib' directory and to the
+'wingtk' directory you created in the previous step. In
+'lablgtk-1.2.3-static/src', run 'nmake -f Makefile.nt'. If you can use
+the OCaml native-code compiler, run 'nmake -f Makefile.nt opt' too. If
+you can't, you probably need the MASM assembler, also available in the
+'resources' directory of the Unison web site. If everything goes
+well, run 'nmake -f Makefile.nt install' to install the software. You
+may want to remove the compilation directory 'lablgtk-1.2.3-static'.
+
+ Using 'bash' in the Unison sources directory, enter 'make clean'
+then 'make UISTYLE=gtk'.
+
+ Run 'unison.exe' with the Gtk .dll's in your search path (they can
+be found in the 'guilib' directory), unless you built with the
+NATIVE=true option.
+
+ "unison.exe" built with NATIVE=true option is statically linked.
+This means that the executable doesn't refer to Cygwin and Gtk DLLs,
+and can therefore be distributed as a standalone application.
+
+
+Section 3 - Using new public versions of Tk/Gtk/LablGtk
+
+3.1 Patching a new version of Gtk
+
+ Download the 'wingtk.patch.tar.gz' tarball from the 'resources'
+directory of the Unison web site and unpack it. Follow the
+instructions in the 'README.patch' file to download the Gtk sources,
+to patch them and to build the new static and dynamic libraries.
+
+ Important: if a patch fails for any reason, try to apply the patches on a
+ Unix system.
+
+ Copy those new libraries to your 'ocaml/lib/guilib' directory, along
+with the .dll's (dynamic version).
+
+ Using the new version of 'wingtk', recompile LablGtk (see section 2.3).
+
+
+3.2 Patching a new version of LablGtk
+
+ Download lablgtk-1.2.3.tar.gz from the LablGtk homepage
+<http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/lablgtk.html>. Unpack
+it.
+
+ Download the 'lablgtk-1.2.3-msvc-static.patch.gz' from the 'resources'
+directory of the Unison web site. Apply the patch by typing:
+ 'patch < lablgtk.patch'
+above the 'lablgtk' directory.
+
+ Important: if a patch fails for any reason, try to apply the patches on a
+ Unix system.
+
+
+3.3 Making patches from the public sources
+
+ The way from public Gtk/LablGtk sources to the provided Gtk/LablGtk
+dynamic/static extension has been somehow perilous. We strongly
+recommand using the provided sources and patches as a base for your
+further enhancements.
+
+ To be exhaustive, here are the steps followed to create the provided
+sources (hoping it would help when trying to adapt a new version):
+
+ WinGtk:
+
+* Download the Gtk win32 sources from
+ 'http://www.gimp.org/~tml/gimp/win32//downloads.html'. We need
+ 'glib-src-yyyymmdd' and 'gtk+-src-yyyymmdd' where 'yyyymmdd' is the
+ release date. Version 2000/04/16 of these files was used.
+
+* We will make new Windows Makefiles from the old ones. Here is how to
+ convert a Makefile:
+ - change all '/MD' to '/MT' to use the same windows system
+ libraries than ocaml
+ (e.g. 'OPTIMIZE = -Ox -MD' becomes 'OPTIMIZE = -Ox -MT')
+ - turns all '.dll' targets to '.lib' ones using
+ 'MKLIB = lib /nologo /out:'
+ you must remove all references to '.def' files
+ you must remove all references to other '.lib' and '.res' but
+ you will have to provide them when linking an executable later
+ (e.g.
+ glib-$(GLIB_VER).dll : $(glib_OBJECTS) glib.def
+ $(CC) $(CFLAGS) -LD -Feglib-$(GLIB_VER).dll $(glib_OBJECTS) \
+ user32.lib advapi32.lib wsock32.lib $(LDFLAGS) /def:glib.def
+ becomes:
+ glib-$(GLIB_VER).lib : $(glib_OBJECTS)
+ $(MKLIB)glib-$(GLIB_VER).lib $(glib_OBJECTS)
+ )
+ - remove all '-GD' compilation flags
+ (e.g.
+ .c.obj :
+ $(CC) $(CFLAGS) -GD -c -DGLIB_COMPILATION \
+ -DG_LOG_DOMAIN=g_log_domain_glib $<
+ becomes:
+ .c.obj :
+ $(CC) $(CFLAGS) -c -DGLIB_COMPILATION \
+ -DG_LOG_DOMAIN=g_log_domain_glib $<
+ )
+ - provides the right libraries when linking executables
+ (e.g.
+ testgtk.exe : gtk-$(GTK_VER).dll testgtk.obj
+ $(CC) $(CFLAGS) testgtk.obj gtk-$(GTK_VER).lib \
+ ..\gdk\gdk-$(GTK_VER).lib $(GLIB)\glib-$(GLIB_VER).lib \
+ $(LDFLAGS)
+ becomes:
+ testgtk.exe : gtk-$(GTK_VER).lib testgtk.obj
+ $(CC) $(CFLAGS) testgtk.obj gtk-$(GTK_VER).lib \
+ ..\gdk\gdk-$(GTK_VER).lib ..\gdk\win32\gdk-win32.lib \
+ $(GLIB)\glib-$(GLIB_VER).lib $(GLIB)\gmodule-$(GLIB_VER).lib \
+ user32.lib advapi32.lib wsock32.lib gdi32.lib imm32.lib \
+ shell32.lib ole32.lib ../gdk/win32/gdk.res $(LDFLAGS)
+ )
+
+* Convert 'glib/makefile.msc' and remove all references to the
+ 'gthread' and 'pthread' directories and libraries from it (but keep
+ 'gthread.obj').
+
+* Erase the 'gthread' directory.
+
+* Comment out the '#include <psapi.h>' line in
+ 'glib/gmodule/gmodule-win32.c'.
+
+* You should now be able to compile the 'glib' and 'gmodule' libraries
+ by typing 'nmake -f <new makefile>'. You can test it with 'testglib'
+ and the other test programs. Remember to provide those two libraries
+ when linking programs.
+
+* In 'gtk+/config.h.win32', undefine the following variables by
+ commenting out their definition lines:
+ HAVE_WINTAB, ENABLE_NLS, HAVE_GETTEXT, HAVE_LIBINTL
+
+* Convert 'gtk+/gdk/win32/makefile.msc' and remove all references to
+ 'WTKIT', 'wntab32x', 'INTL' and 'gnu-intl' from it.
+
+* In 'gtk+/gdk/win32/rc/gdk.rc', comment out ',BUILDNUMBER'.
+
+* In 'gtk+/gdk/win32/gdkcursor-win32.c', replace 'gdk_DLLInstance' by
+ 'gdk_ProgInstance'.
+
+* You should now be able to compile 'gdk-win32.lib'.
+
+* Convert 'gtk+/gdk/makefile.msc' and remove all references to
+ 'WTKIT', 'wntab32x', 'INTL' and 'gnu-intl' from it. Include
+ 'gdk-win32.lib' as an object for the 'gdk' library.
+
+* You should now be able to compile the 'gdk' library. Remember to
+ provide 'win32/gdk.res' as well as the 'gdk' library when linking
+ programs.
+
+* Convert 'gtk+/gtk/makefile.msc' and remove all references to
+ 'WTKIT', 'wntab32x', 'INTL', 'gnu-intl' and 'PTHREAD' from it.
+
+* Be sure to include all needed libraries in the '.exe' files' compilation
+ command lines.
+ In most case you need the following:
+ gtk-$(GTK_VER).lib ..\gdk\gdk-$(GTK_VER).lib \
+ $(GLIB)\glib-$(GLIB_VER).lib $(GLIB)\gmodule-$(GLIB_VER).lib \
+ user32.lib advapi32.lib wsock32.lib gdi32.lib imm32.lib shell32.lib \
+ ole32.lib \
+ ../gdk/win32/gdk.res
+
+* You should now be able to compile the 'gtk' library. You can test it
+ with 'testglib' and the other test programs.
+
+* With some cleaning of the Makefiles, it is also possible to build a
+ dynamic version of the libraries, along with the .dll's, so that we
+ finally obtain static/dynamic sources.
+
+* Make a patch with 'diff -Nr -C 5 <old dir> <new dir>' (you have to
+ use the GNU diffutils' 'diff'). You will apply the patch with
+ 'patch -p1 < <patch file>'.
+
+ LablGtk:
+
+* Download LablGtk from 'http://www.gtk.org' or
+ 'ftp://ftp.inria.fr/lang/caml-light/bazar-ocaml/'.
+
+* You can remove all subdirectories.
+
+* Edit 'config.make.nt' to include the right Gtk libraries.
+
+* Comment out all references to 'gutter' to be found in the sources
+ with 'grep gutter *.h *.c *.mli *.ml'.
+
+* Compile with 'nmake -f Makefile.nt'. If you can use the OCaml
+ native-code compiler, run 'nmake -f Makefile.nt opt' too. If you
+ can't, you probably need the MASM assembler. It was downloaded from
+ 'http://www.cs.uu.nl/wais/html/na-dir/assembly-language/x86/microsoft.html'.
+
+* Make a patch as for WinGtk.
+
+
+
+Appendix A - Windows text format
+
+Windows and Unix use different text file formats. This section
+explains how to convert a file from a format to another.
+
+A.1 Text format conversion
+
+ In order to convert a dos text file to a unix text file, we have to
+remove all extra characters that are :
+* carriage return or CR or ^M (ctrl-M) or \x0d or \o13 or \r
+* dos end-of-file or SUB or ^Z (ctrl-Z) or \x1a or \o26
+
+A.2 Conversion tools
+
+ On a Unix-like top level (e.g any unix system or cygwin), you can use:
+
+* dos -> unix
+ - tr -d '\15\32' < dosfile.txt > unixfile.txt
+ - awk '{ sub("\r$", ""); print }' dosfile.txt > unixfile.txt
+ - perl -p -e 's/\r$//' < dosfile.txt > unixfile.txt
+
+* unix -> dos
+ - awk 'sub("$", "\r")' unixfile.txt > dosfile.txt
+ - perl -p -e 's/$/\r/' < unixfile.txt > dosfile.txt
+
+ You may want to use a short script like the following to convert
+more than one file at a time (doesn't work recursively; use at your
+own risk):
+
+ #!/bin/sh
+ echo dos2unix
+ for F in "$@"
+ do
+ echo converting "$F"
+ tr -d '\15\32' < $F > $F.tmp
+ mv -f $F.tmp $F
+ done
+
+A.3 Transmission issues
+
+ If you transfer files using 'ftp' between a Unix system and a
+Windows system, be sure to run it in binary mode to disable any
+automatic conversion. To switch to binary mode, enter 'binary' (or
+simply 'bin').
+
+
+
+Appendix B - '.bashrc'.
+
+ Copy the following '.bashrc' as a base to your own one. Be sure this
+file is in Unix text format.
+
+# .bashrc
+# gommier at saul.cis.upenn.edu
+
+export HOME=/
+export PS1="[\u@\h \w]$ "
+cd
+
+# Set up Path
+# $PATH currently contains the Windows Path converted to Unix path,
+export PATH=./:/bin:$PATH
+echo "Current path is :"
+echo $PATH
+echo " "
+
+# end
+
+
+
+Appendix C - Windows files and directories names
+
+ Here are some general rules for applications creating names for
+directories and files or processing names supplied by the user:
+
+* Use any character in the current code page for a name, but do not
+ use a path separator, a character in the range 0 through 31, or any
+ character explicitly disallowed by the file system. A name can
+ contain characters in the extended character set (128-255).
+
+* Use the backslash (\), the forward slash (/), or both to separate
+ components in a path. No other character is acceptable as a path
+ separator. Note that UNC names must adhere to the following format:
+ \\server\share.
+
+* Use a period (.) as a directory component in a path to represent the
+ current directory.
+
+* Use two consecutive periods (..) as a directory component in a path
+ to represent the parent of the current directory.
+
+* Use a period (.) to separate the base file name from the extension
+ in a directory name or file name.
+
+* Do not use the following characters in directory names or file
+ names, because they are reserved: < > : " / \ |
+
+* Do not use device names, such as aux, con, lpt1, and prn, as file
+ names or directory names.
+
+* Process a path as a null-terminated string. The maximum length for a
+ path, including a trailing backslash, is given by MAX_PATH.
+
+* The Unicode versions of several functions permit paths that exceed
+ the MAX_PATH length if the path has the "\\?\" prefix. The "\\?\"
+ tells the function to turn off path parsing. However, each component
+ in the path cannot be more than MAX_PATH characters long. Use the
+ "\\?\" prefix with paths for local storage devices and the
+ "\\?\UNC\" prefix with paths having the Universal Naming Convention
+ (UNC) format. The "\\?\" is ignored as part of the path. For
+ example, "\\?\C:\myworld\private" is seen as "C:\myworld\private",
+ and "\\?\UNC\bill_g_1\hotstuff\coolapps" is seen as
+ "\\bill_g_1\hotstuff\coolapps".
+
+* Do not assume case sensitivity. Consider names such as OSCAR, Oscar,
+ and oscar to be the same.
+
+
+
+Appendix D - Windows icons
+
+ Here is some general information on how to make your Windows
+program have a nice icon.
+
+* What we mean by icon is a set of bitmaps that are displayed by
+ Windows to represent your program on the desktop, on the top left
+ corner of each window, etc. For your program's binary to include an
+ icon, you will have to draw each bitmap and to store them in .bmp
+ files, then to archive them in a .ico file, then to archive that
+ icon file in a .res file along with other resources, and finally to
+ link your program with that very .res file.
+
+* Current graphic formats for icons are 16 x 16, 32 x 32 and 48 x 48
+ pixels with 16 or 256 colors. One format must always exist for
+ compatibility with all Windows versions: the 32 x 32 x 16 format.
+ Furthermore, the colors refer to the standard palette (sometimes
+ called www palette), which means you mustn't use optimized palette
+ when turning RGB colors to indexed colors. If you need subtle nuances,
+ remember you can interleave pixels of two different colors to create
+ the impression of a third, average one.
+
+* Once your bitmaps are ready, you can use the Visual C++ IDE to create
+ your .ico file. Use the resource tool bar to create a 'new icon'.
+ Open your .bmp files and simply cut and paste them into the icon
+ window. You have to select the proper device (or format) for each
+ bitmap before achieving the copy. When your icon (i.e. set of bitmaps)
+ is ready, right-click on the icon name in the resource list window to
+ export it.
+ Note: you should never trust that IDE when dealing with colors, since
+ it seems to get quickly lost between 16 or 256 colors.
+
+* To include your icon into a resource file, add a line for it into the
+ .rc script file and compile with rc to create the .res file.
+
+* Just add the .res file to the link command line to have your binary
+ include the icon.
Deleted: branches/2.45/src/RECENTNEWS
===================================================================
--- trunk/src/RECENTNEWS 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/src/RECENTNEWS 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,305 +0,0 @@
-CHANGES FROM VERSION 2.44.12
-
-* Update copyright dates
-
-* Add quotes to paths when calling external file watcher utility
-
--------------------------------
-CHANGES FROM VERSION 2.44.11
-
-* Correctly quote the path when running merge commands
-
--------------------------------
-CHANGES FROM VERSION 2.44.10
-
-* Added option clientHostName. If specified, it will be used to as the client
- host name, overriding UNISONLOCALHOSTNAME and the actual host name.
-
--------------------------------
-CHANGES FROM VERSION 2.44.9
-
-- OS X GUI: fix crash under Lion, because of problems with the toolbar, using
- the fix suggested in http://blitzbasic.com/Community/posts.php?topic=95778.
-
-- OS X GUI: show a modal warning window if there is no archive for the hosts.
- The user can then choose to exit or proceed (proceed is the default). The
- window is not shown if "batch" is true.
-
--------------------------------
-CHANGES FROM VERSION 2.44.8
-
-* Change uimacnew09 icon to classic "U with arrows"
-
-* Incorporate a patch to fsmonitor.py (the external filewatcher
- utility) from Tomasz Zernicki to make it work better under Windows.
--------------------------------
-CHANGES FROM VERSION 2.44.6
-
-* A small improvement to the uimacnew09 interface from Alan Schmitt
- and Steve Kalkwarf: when Unison is run with the -batch flag, the
- interface will now automatically propagate changes and terminate,
- without waiting for user interaction.
-
-* uimacnew09 is now the standard graphical interface on OSX
--------------------------------
-CHANGES FROM VERSION 2.44.5
-
-- uimacnew09: file details panel selectable
-- uimacnew09: automatically quit when done synchronizing if called from the command line with "-batch"
-
--------------------------------
-CHANGES FROM VERSION 2.44.4
-
-- fixed a bug when calling the Unison macnew09 GUI from the command line with a profile specified
-- now possible to use the "-batch" option when calling the macnew09 GUI on the command line
-
--------------------------------
-CHANGES FROM VERSION 2.44.2
-
-* Some spelling corrections in documentation and comments from Stephane Glondu
-
--------------------------------
-CHANGES FROM VERSION 2.44.0
-
-* Small patch from Stephane Glondu to make Unison compile with Ocaml 3.12.
-
-* New version of uigtk2.ml from Matt Zagrabelny that reorganizes the
- icons in a slightly more intuitive way.
-
-* Finished implementing the "fastercheckUNSAFE" option, which can be
- used (with care!) to achieve *much* faster update detection when all
- the common files in the two replicas are known to be identical. See
- the documentation for more information.
-
- This feature should still be considered experimental, but it's ready
- for other people to try out.
-
--------------------------------
-CHANGES FROM VERSION 2.43.12
-
-* Small patch from Stephane Glondu to make Unison compile with Ocaml 3.12.
-
-* New version of uigtk2.ml from Matt Zagrabelny that reorganizes the
- icons in a slightly more intuitive way.
-
-* Incorporated new version of fsmonitor.py from Christophe Gohle
-
--------------------------------
-CHANGES FROM VERSION 2.43.10
-
-* Fixed incompatibility with OpenSSH 5.6.
-
--------------------------------
-CHANGES FROM VERSION 2.43.7
-
-* Fixed fingerprint cache: do not cache file properties
-* Fixed O_APPEND mode for open under Windows (the previous attempt in
- revision 422 was incomplete)
-* Fixed String.sub invalid argument error when an AppleDouble file does
- not contain a finder information field
-
--------------------------------
-CHANGES FROM VERSION 2.43.6
-
-* A small fix suggested by Jerome. Still thinking about what needs to
- change to get newly created files to transfer without failing.
-
--------------------------------
-CHANGES FROM VERSION 2.43.0
-
-* See if we can get revisionString to update automatically now...
-
--------------------------------
-CHANGES FROM VERSION 2.43.0
-
-* Bump revisionString -- not sure why this isn't happening automatically.
-
--------------------------------
-CHANGES FROM VERSION 2.43.-30
-
-* Experimental implementation of a new "faster check" mode for update
- detection. When this mode is enabled (by running with
- 'fastercheckUNSAFE=true'), Unison will skip calculating fingerprints
- of the contents of files that it has not seen before -- it just uses
- the file's size as a pseudo-fingerprint, allowing the archives to be
- built very quickly.
-
- This feature has not been extensively tested -- if you use it on
- live replicas, please pay careful attention to what Unison is doing.
- Also, note that the cost of faster update detection is that it is
- possible Unison will miss a conflict; this flag should be used only
- when the replicas are known to be identical.
-
- Here's the full documentation.
-
-let fastercheckUNSAFE =
- Prefs.createBool "fastercheckUNSAFE"
- false "!skip computing fingerprints for new files (experts only!)"
- ( "THIS FEATURE IS STILL EXPERIMENTAL AND SHOULD BE USED WITH EXTREME CAUTION. "
- ^ "\n\n"
- ^ "When this flag is set to {\\tt true}, Unison will compute a 'pseudo-"
- ^ "fingerprint' the first time it sees a file (either because the file is "
- ^ "new or because Unison is running for the first time). This enormously "
- ^ "speeds update detection, but it must be used with care, as it can cause "
- ^ "Unison to miss conflicts: If "
- ^ "a given path in the filesystem contains files on {\\em both} sides that "
- ^ "Unison has not yet seen, and if those files have the same length but different "
- ^ "contents, then Unison will not notice the presence of a conflict. If, later, one "
- ^ "of the files is changed, the changed file will be propagated, overwriting "
- ^ "the other. "
- ^ "\n\n"
- ^ "Moreover, even when the files are initially identical, setting this flag can lead "
- ^ "to potentially confusing behavior: "
- ^ "if a newly created file is later touched without being modified, Unison will "
- ^ "treat this "
- ^ "conservatively as a potential change (since it has no record of the earlier "
- ^ "contents) and show it as needing to be propagated to the other replica. "
- ^ "\n\n"
- ^ "Most users should leave this flag off -- the small time savings of not "
- ^ "fingerprinting new files is not worth the cost in terms of safety. However, "
- ^ "it can be very useful for power users with huge replicas that are known to "
- ^ "be already synchronized (e.g., because one replica is a newly created duplicate "
- ^ "of the other, or because they have previously been synchronized with Unison but "
- ^ "Unison's archives need to be rebuilt). In such situations, it is recommended "
- ^ "that this flag be set only for the initial run of Unison, so that new archives "
- ^ "can be created quickly, and then turned off for normal use.")
-
--------------------------------
-CHANGES FROM VERSION 2.43.-29
-
-* Added support for "pseudo-fingerprints", as a first step to
- implementing super-fast initial scans, following recent discussion
- on the unison-hackers list
-
--------------------------------
-CHANGES FROM VERSION 2.42.-29
-
-* Small patch from Stephane Glondu to make Unison compile with Ocaml 3.12.
-
-
--------------------------------
-CHANGES FROM VERSION 2.41.-27
-
-* Try again to fix version number
-
-
-
-
-
--------------------------------
-CHANGES FROM VERSION 2.41.-27
-
-* Fix version number
-
-
-
-
-
--------------------------------
-CHANGES FROM VERSION 2.41.-28
-
-* Trim duplicate paths when using "-repeat watch"
-
-* Bump version number, since protocol has changed (should have done
- this a few commits ago)
-
-
-
-
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-* Correct a bug in the watcher startup code for remote sync
-
-
-
-
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-* Unison now passes path arguments and --follow directives to
- fsmonitor.py. This seems to work except for one small issue with
- how fsmonitor.py treats --follow directives for directories that
- don't exist (or maybe this is an issue with how it treats any kind
- of monitoring when the thing being monitored doesn't exist?). If I
- create a symlink to a nonexistant directory, give Unison (hence
- fsmonitor.py) a 'follow' directive for the symlink, start unison, and
- *then* create the directory, fsmonitor.py misses the change.
-
-
-
-
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-* More progress on file watching
-* Add external fsmonitor.py script to svn repo
-
-* If you want to play with the filewatching functionality, here's
- what you do:
- - add fsmonitor.py to your search path (or make a symlink to
- it from somewhere on your search path) on both machines that
- you're going to synchronize
- - recompile the text ui ('make text') on both machines
- - start unison with "-repeat watch" on the command line
-
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-* Progress on filesystem watching (see uitext.ml)
-
-* Update copyright dates, while I'm thinking about it :-)
-
-
-
-
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-* Progress on filesystem watching (see uitext.ml)
-
-* Update copyright dates, while I'm thinking about it :-)
-
-
-
-
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-* One more fix to Unicode case sensitive mode
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-Lines added in profile files by unison always start at a new line
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-* Fix to Unicode case sensitive mode (call the right function for
- comparing file names).
-* "prefer = older/newer" now propagates deletions when there is no
- conflict
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-* Fixed Unicode decomposition tables
-
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-Move old 2.40 branch aside to make room for a new beta version with
-same major number
--------------------------------
-CHANGES FROM VERSION 2.40.16
-
-Update documentation
-
--------------------------------
Copied: branches/2.45/src/RECENTNEWS (from rev 486, trunk/src/RECENTNEWS)
===================================================================
Deleted: branches/2.45/src/copy.mli
===================================================================
--- trunk/src/copy.mli 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/src/copy.mli 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,28 +0,0 @@
-
-(* Transfer a file from one replica to the other *)
-val file :
- Common.root (* root of source *)
- -> Path.local (* path of source *)
- -> Common.root (* root of target *)
- -> Fspath.t (* fspath of target *)
- -> Path.local (* path of target (temp location) *)
- -> Path.local (* path of "real" (original) target *)
- -> [`Update of (Uutil.Filesize.t * Uutil.Filesize.t) | `Copy]
- -> Props.t (* permissions for new file *)
- -> Os.fullfingerprint (* fingerprint of file *)
- -> Fileinfo.stamp option (* source file stamp, if available *)
- -> Osx.ressStamp (* ressource info of file *)
- -> Uutil.File.t (* file's index in UI (for progress bars) *)
- -> Fileinfo.t Lwt.t (* information regarding the transferred file *)
-
-val localFile :
- Fspath.t (* fspath of source *)
- -> Path.local (* path of source *)
- -> Fspath.t (* fspath of target *)
- -> Path.local (* path of target *)
- -> Path.local (* path of "real" [original] target *)
- -> [`Update of (Uutil.Filesize.t * Uutil.Filesize.t) | `Copy]
- -> Props.t (* permissions for new file *)
- -> Uutil.Filesize.t (* fork length *)
- -> Uutil.File.t option (* file's index in UI (for progress bars), if appropriate *)
- -> unit
Copied: branches/2.45/src/copy.mli (from rev 486, trunk/src/copy.mli)
===================================================================
--- branches/2.45/src/copy.mli (rev 0)
+++ branches/2.45/src/copy.mli 2012-04-02 15:54:47 UTC (rev 487)
@@ -0,0 +1,28 @@
+
+(* Transfer a file from one replica to the other *)
+val file :
+ Common.root (* root of source *)
+ -> Path.local (* path of source *)
+ -> Common.root (* root of target *)
+ -> Fspath.t (* fspath of target *)
+ -> Path.local (* path of target (temp location) *)
+ -> Path.local (* path of "real" (original) target *)
+ -> [`Update of (Uutil.Filesize.t * Uutil.Filesize.t) | `Copy]
+ -> Props.t (* permissions for new file *)
+ -> Os.fullfingerprint (* fingerprint of file *)
+ -> Fileinfo.stamp option (* source file stamp, if available *)
+ -> Osx.ressStamp (* resource info of file *)
+ -> Uutil.File.t (* file's index in UI (for progress bars) *)
+ -> Fileinfo.t Lwt.t (* information regarding the transferred file *)
+
+val localFile :
+ Fspath.t (* fspath of source *)
+ -> Path.local (* path of source *)
+ -> Fspath.t (* fspath of target *)
+ -> Path.local (* path of target *)
+ -> Path.local (* path of "real" [original] target *)
+ -> [`Update of (Uutil.Filesize.t * Uutil.Filesize.t) | `Copy]
+ -> Props.t (* permissions for new file *)
+ -> Uutil.Filesize.t (* fork length *)
+ -> Uutil.File.t option (* file's index in UI (for progress bars), if appropriate *)
+ -> unit
Deleted: branches/2.45/src/globals.ml
===================================================================
--- trunk/src/globals.ml 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/src/globals.ml 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,306 +0,0 @@
-(* Unison file synchronizer: src/globals.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/>.
-*)
-
-
-open Common
-
-let debug = Trace.debug "globals"
-
-(*****************************************************************************)
-(* ROOTS and PATHS *)
-(*****************************************************************************)
-
-let rawroots =
- Prefs.createStringList "root"
- "root of a replica (should be used exactly twice)"
- ("Each use of this preference names the root of one of the replicas "
- ^ "for Unison to synchronize. Exactly two roots are needed, so normal "
- ^ "modes of usage are either to give two values for \\verb|root| in the "
- ^ "profile, or to give no values in the profile and provide two "
- ^ "on the command line. "
- ^ "Details of the syntax of roots can be found in "
- ^ "\\sectionref{roots}{Roots}.\n\n"
- ^ "The two roots can be given in either order; Unison will sort them "
- ^ "into a canonical order before doing anything else. It also tries to "
- ^ "`canonize' the machine names and paths that appear in the roots, so "
- ^ "that, if Unison is invoked later with a slightly different name "
- ^ "for the same root, it will be able to locate the correct archives.")
-
-let setRawRoots l = Prefs.set rawroots (Safelist.rev l)
-
-let rawRoots () = Safelist.rev (Prefs.read rawroots)
-
-let rawRootPair () =
- match rawRoots () with
- [r1; r2] -> (r1, r2)
- | _ -> assert false
-
-let theroots = ref []
-
-open Lwt
-let installRoots termInteract =
- let roots = rawRoots () in
- if Safelist.length roots <> 2 then
- raise (Util.Fatal (Printf.sprintf
- "Wrong number of roots: 2 expected, but %d provided (%s)\n(Maybe you specified roots both on the command line and in the profile?)"
- (Safelist.length roots)
- (String.concat ", " roots) ));
- Safelist.fold_right
- (fun r cont ->
- Remote.canonizeRoot r (Clroot.parseRoot r) termInteract
- >>= (fun r' ->
- cont >>= (fun l ->
- return (r' :: l))))
- roots (return []) >>= (fun roots' ->
- theroots := roots';
- return ())
-
-(* Alternate interface, should replace old interface eventually *)
-let installRoots2 () =
- debug (fun () -> Util.msg "Installing roots...");
- let roots = rawRoots () in
- theroots :=
- Safelist.map Remote.canonize ((Safelist.map Clroot.parseRoot) roots);
- theroots := !theroots
-
-let roots () =
- match !theroots with
- [root1;root2] -> (root1,root2)
- | _ -> assert false
-
-let rootsList() = !theroots
-
-let rootsInCanonicalOrder() = Common.sortRoots (!theroots)
-
-let localRoot () = List.hd (rootsInCanonicalOrder ())
-
-let reorderCanonicalListToUsersOrder l =
- if rootsList() = rootsInCanonicalOrder() then l
- else Safelist.rev l
-
-let rec nice_rec i
- : unit Lwt.t =
- if i <= 0 then
- Lwt.return ()
- else
- Lwt_unix.yield() >>= (fun () -> nice_rec (i - 1))
-
-(* [nice r] yields 5 times on local roots [r] to give processes
- corresponding to remote roots a chance to run *)
-let nice r =
- if List.exists (fun r -> fst r <> Local) (rootsList ()) && fst r = Local then
- nice_rec 5
- else
- Lwt.return ()
-
-let allRootsIter f =
- Lwt_util.iter
- (fun r -> nice r >>= (fun () -> f r)) (rootsInCanonicalOrder ())
-
-let allRootsIter2 f l =
- let l = Safelist.combine (rootsList ()) l in
- Lwt_util.iter (fun (r, v) -> nice r >>= (fun () -> f r v))
- (Safelist.sort (fun (r, _) (r', _) -> Common.compareRoots r r') l)
-
-let allRootsMap f =
- Lwt_util.map
- (fun r -> nice r >>= (fun () -> f r >>= (fun v -> return (r, v))))
- (rootsInCanonicalOrder ()) >>= (fun l ->
- return (Safelist.map snd (reorderCanonicalListToUsersOrder l)))
-
-let allRootsMapWithWaitingAction f wa =
- Lwt_util.map_with_waiting_action
- (fun r -> nice r >>= (fun () -> f r >>= (fun v -> return (r, v))))
- (fun r -> wa r)
- (rootsInCanonicalOrder ()) >>= (fun l ->
- return (Safelist.map snd (reorderCanonicalListToUsersOrder l)))
-
-let replicaHostnames () =
- Safelist.map
- (function (Local, _) -> ""
- | (Remote h,_) -> h)
- (rootsList())
-
-let allHostsIter f =
- let rec iter l =
- match l with
- [] ->
- return ()
- | root :: rem ->
- f root >>= (fun () ->
- iter rem)
- in
- iter (replicaHostnames ())
-
-let allHostsMap f = Safelist.map f (replicaHostnames())
-
-let paths =
- Prefs.create "path" []
- "path to synchronize"
- ("When no \\verb|path| preference is given, Unison will simply synchronize "
- ^ "the two entire replicas, beginning from the given pair of roots. "
- ^ "If one or more \\verb|path| preferences are given, then Unison will "
- ^ "synchronize only these paths and their children. (This is useful "
- ^ "for doing a fast sync of just one directory, for example.) "
- ^ "Note that {\\tt path} preferences are intepreted literally---they "
- ^ "are not regular expressions.")
- (fun oldpaths string -> Safelist.append oldpaths [Path.fromString string])
- (fun l -> Safelist.map Path.toString l)
-
-(* FIX: this does weird things in case-insensitive mode... *)
-let globPath lr p =
- let p = Path.forceLocal p in
- debug (fun() ->
- Util.msg "Checking path '%s' for expansions\n"
- (Path.toDebugString p) );
- match Path.deconstructRev p with
- Some(n,parent) when (Name.toString n = "*") -> begin
- debug (fun() -> Util.msg "Expanding path %s\n" (Path.toString p));
- match lr with
- None -> raise (Util.Fatal (Printf.sprintf
- "Path %s ends with *, %s"
- (Path.toString p)
- "but first root (after canonizing) is non-local"))
- | Some lrfspath ->
- Safelist.map (fun c -> Path.makeGlobal (Path.child parent c))
- (Os.childrenOf lrfspath parent)
- end
- | _ -> [Path.makeGlobal p]
-
-let expandWildcardPaths() =
- let lr =
- match rootsInCanonicalOrder() with
- [(Local, fspath); _] -> Some fspath
- | _ -> None in
- Prefs.set paths
- (Safelist.flatten_map (globPath lr) (Prefs.read paths))
-
-(*****************************************************************************)
-(* PROPAGATION OF PREFERENCES *)
-(*****************************************************************************)
-
-let propagatePrefsTo =
- Remote.registerHostCmd
- "installPrefs"
- (fun prefs -> return (Prefs.load prefs))
-
-let propagatePrefs () =
- let prefs = Prefs.dump() in
- let toHost root =
- match root with
- (Local, _) -> return ()
- | (Remote host,_) ->
- propagatePrefsTo host prefs
- in
- allRootsIter toHost
-
-(*****************************************************************************)
-(* PREFERENCES AND PREDICATES *)
-(*****************************************************************************)
-
-let batch =
- Prefs.createBool "batch" false "batch mode: ask no questions at all"
- ("When this is set to {\\tt true}, the user "
- ^ "interface will ask no questions at all. Non-conflicting changes "
- ^ "will be propagated; conflicts will be skipped.")
-
-let confirmBigDeletes =
- Prefs.createBool "confirmbigdel" true
- "!ask about whole-replica (or path) deletes"
- ("When this is set to {\\tt true}, Unison will request an extra confirmation if it appears "
- ^ "that the entire replica has been deleted, before propagating the change. If the {\\tt batch} "
- ^ "flag is also set, synchronization will be aborted. When the {\\tt path} preference is used, "
- ^ "the same confirmation will be requested for top-level paths. (At the moment, this flag only "
- ^ "affects the text user interface.) See also the {\\tt mountpoint} preference.")
-
-let () = Prefs.alias confirmBigDeletes "confirmbigdeletes"
-
-let ignorePred =
- Pred.create "ignore"
- ("Including the preference \\texttt{-ignore \\ARG{pathspec}} causes Unison to "
- ^ "completely ignore paths that match \\ARG{pathspec} (as well as their "
- ^ "children). This is useful for avoiding synchronizing temporary "
- ^ "files, object files, etc. The syntax of \\ARG{pathspec} is "
- ^ "described in \\sectionref{pathspec}{Path Specification}, and further "
- ^ "details on ignoring paths is found in"
- ^ " \\sectionref{ignore}{Ignoring Paths}.")
-
-let ignorenotPred =
- Pred.create "ignorenot"
- ("This preference overrides the preference \\texttt{ignore}.
- It gives a list of patterns
- (in the same format as
- \\verb|ignore|) for paths that should definitely {\\em not} be ignored,
- whether or not they happen to match one of the \\verb|ignore| patterns.
- \\par Note that the semantics of {\\tt ignore} and {\\tt ignorenot} is a
- little counter-intuitive. When detecting updates, Unison examines
- paths in depth-first order, starting from the roots of the replicas
- and working downwards. Before examining each path, it checks whether
- it matches {\\tt ignore} and does not match {\\tt ignorenot}; in this case
- it skips this path {\\em and all its descendants}. This means that,
- if some parent of a given path matches an {\\tt ignore} pattern, then
- it will be skipped even if the path itself matches an {\\tt ignorenot}
- pattern. In particular, putting {\\tt ignore = Path *} in your profile
- and then using {\\tt ignorenot} to select particular paths to be
- synchronized will not work. Instead, you should use the {\\tt path}
- preference to choose particular paths to synchronize.")
-
-let shouldIgnore p =
- let p = Path.toString p in
- (Pred.test ignorePred p) && not (Pred.test ignorenotPred p)
-
-let addRegexpToIgnore re =
- let oldRE = Pred.extern ignorePred in
- let newRE = re::oldRE in
- Pred.intern ignorePred newRE
-
-let merge =
- Pred.create "merge" ~advanced:true
- ("This preference can be used to run a merge program which will create "
- ^ "a new version for each of the files and the backup, "
- ^ "with the last backup and the both replicas. Setting the {\\tt merge} "
- ^ "preference for a path will also cause this path to be backed up, "
- ^ "just like {\tt backup}. "
- ^ "The syntax of \\ARG{pathspec>cmd} is "
- ^ "described in \\sectionref{pathspec}{Path Specification}, and further "
- ^ "details on Merging functions are present in "
- ^ "\\sectionref{merge}{Merging files}.")
-
-let shouldMerge p = Pred.test merge (Path.toString p)
-
-let mergeCmdForPath p = Pred.assoc merge (Path.toString p)
-
-let someHostIsRunningWindows =
- Prefs.createBool "someHostIsRunningWindows" false "*" ""
-
-let allHostsAreRunningWindows =
- Prefs.createBool "allHostsAreRunningWindows" false "*" ""
-
-let fatFilesystem =
- Prefs.createBool "fat" ~local:true false
- "use appropriate options for FAT filesystems"
- ("When this is set to {\\tt true}, Unison will use appropriate options \
- to synchronize efficiently and without error a replica located on a \
- FAT filesystem on a non-Windows machine: \
- do not synchronize permissions ({\\tt perms = 0}); \
- never use chmod ({\tt dontchmod = true}); \
- treat filenames as case insensitive ({\\tt ignorecase = true}); \
- do not attempt to synchronize symbolic links ({\\tt links = false}); \
- ignore inode number changes when detecting updates \
- ({\\tt ignoreinodenumbers = true}). \
- Any of these change can be overridden by explicitely setting \
- the corresponding preference in the profile.")
Copied: branches/2.45/src/globals.ml (from rev 486, trunk/src/globals.ml)
===================================================================
--- branches/2.45/src/globals.ml (rev 0)
+++ branches/2.45/src/globals.ml 2012-04-02 15:54:47 UTC (rev 487)
@@ -0,0 +1,306 @@
+(* Unison file synchronizer: src/globals.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/>.
+*)
+
+
+open Common
+
+let debug = Trace.debug "globals"
+
+(*****************************************************************************)
+(* ROOTS and PATHS *)
+(*****************************************************************************)
+
+let rawroots =
+ Prefs.createStringList "root"
+ "root of a replica (should be used exactly twice)"
+ ("Each use of this preference names the root of one of the replicas "
+ ^ "for Unison to synchronize. Exactly two roots are needed, so normal "
+ ^ "modes of usage are either to give two values for \\verb|root| in the "
+ ^ "profile, or to give no values in the profile and provide two "
+ ^ "on the command line. "
+ ^ "Details of the syntax of roots can be found in "
+ ^ "\\sectionref{roots}{Roots}.\n\n"
+ ^ "The two roots can be given in either order; Unison will sort them "
+ ^ "into a canonical order before doing anything else. It also tries to "
+ ^ "`canonize' the machine names and paths that appear in the roots, so "
+ ^ "that, if Unison is invoked later with a slightly different name "
+ ^ "for the same root, it will be able to locate the correct archives.")
+
+let setRawRoots l = Prefs.set rawroots (Safelist.rev l)
+
+let rawRoots () = Safelist.rev (Prefs.read rawroots)
+
+let rawRootPair () =
+ match rawRoots () with
+ [r1; r2] -> (r1, r2)
+ | _ -> assert false
+
+let theroots = ref []
+
+open Lwt
+let installRoots termInteract =
+ let roots = rawRoots () in
+ if Safelist.length roots <> 2 then
+ raise (Util.Fatal (Printf.sprintf
+ "Wrong number of roots: 2 expected, but %d provided (%s)\n(Maybe you specified roots both on the command line and in the profile?)"
+ (Safelist.length roots)
+ (String.concat ", " roots) ));
+ Safelist.fold_right
+ (fun r cont ->
+ Remote.canonizeRoot r (Clroot.parseRoot r) termInteract
+ >>= (fun r' ->
+ cont >>= (fun l ->
+ return (r' :: l))))
+ roots (return []) >>= (fun roots' ->
+ theroots := roots';
+ return ())
+
+(* Alternate interface, should replace old interface eventually *)
+let installRoots2 () =
+ debug (fun () -> Util.msg "Installing roots...");
+ let roots = rawRoots () in
+ theroots :=
+ Safelist.map Remote.canonize ((Safelist.map Clroot.parseRoot) roots);
+ theroots := !theroots
+
+let roots () =
+ match !theroots with
+ [root1;root2] -> (root1,root2)
+ | _ -> assert false
+
+let rootsList() = !theroots
+
+let rootsInCanonicalOrder() = Common.sortRoots (!theroots)
+
+let localRoot () = List.hd (rootsInCanonicalOrder ())
+
+let reorderCanonicalListToUsersOrder l =
+ if rootsList() = rootsInCanonicalOrder() then l
+ else Safelist.rev l
+
+let rec nice_rec i
+ : unit Lwt.t =
+ if i <= 0 then
+ Lwt.return ()
+ else
+ Lwt_unix.yield() >>= (fun () -> nice_rec (i - 1))
+
+(* [nice r] yields 5 times on local roots [r] to give processes
+ corresponding to remote roots a chance to run *)
+let nice r =
+ if List.exists (fun r -> fst r <> Local) (rootsList ()) && fst r = Local then
+ nice_rec 5
+ else
+ Lwt.return ()
+
+let allRootsIter f =
+ Lwt_util.iter
+ (fun r -> nice r >>= (fun () -> f r)) (rootsInCanonicalOrder ())
+
+let allRootsIter2 f l =
+ let l = Safelist.combine (rootsList ()) l in
+ Lwt_util.iter (fun (r, v) -> nice r >>= (fun () -> f r v))
+ (Safelist.sort (fun (r, _) (r', _) -> Common.compareRoots r r') l)
+
+let allRootsMap f =
+ Lwt_util.map
+ (fun r -> nice r >>= (fun () -> f r >>= (fun v -> return (r, v))))
+ (rootsInCanonicalOrder ()) >>= (fun l ->
+ return (Safelist.map snd (reorderCanonicalListToUsersOrder l)))
+
+let allRootsMapWithWaitingAction f wa =
+ Lwt_util.map_with_waiting_action
+ (fun r -> nice r >>= (fun () -> f r >>= (fun v -> return (r, v))))
+ (fun r -> wa r)
+ (rootsInCanonicalOrder ()) >>= (fun l ->
+ return (Safelist.map snd (reorderCanonicalListToUsersOrder l)))
+
+let replicaHostnames () =
+ Safelist.map
+ (function (Local, _) -> ""
+ | (Remote h,_) -> h)
+ (rootsList())
+
+let allHostsIter f =
+ let rec iter l =
+ match l with
+ [] ->
+ return ()
+ | root :: rem ->
+ f root >>= (fun () ->
+ iter rem)
+ in
+ iter (replicaHostnames ())
+
+let allHostsMap f = Safelist.map f (replicaHostnames())
+
+let paths =
+ Prefs.create "path" []
+ "path to synchronize"
+ ("When no \\verb|path| preference is given, Unison will simply synchronize "
+ ^ "the two entire replicas, beginning from the given pair of roots. "
+ ^ "If one or more \\verb|path| preferences are given, then Unison will "
+ ^ "synchronize only these paths and their children. (This is useful "
+ ^ "for doing a fast sync of just one directory, for example.) "
+ ^ "Note that {\\tt path} preferences are intepreted literally---they "
+ ^ "are not regular expressions.")
+ (fun oldpaths string -> Safelist.append oldpaths [Path.fromString string])
+ (fun l -> Safelist.map Path.toString l)
+
+(* FIX: this does weird things in case-insensitive mode... *)
+let globPath lr p =
+ let p = Path.forceLocal p in
+ debug (fun() ->
+ Util.msg "Checking path '%s' for expansions\n"
+ (Path.toDebugString p) );
+ match Path.deconstructRev p with
+ Some(n,parent) when (Name.toString n = "*") -> begin
+ debug (fun() -> Util.msg "Expanding path %s\n" (Path.toString p));
+ match lr with
+ None -> raise (Util.Fatal (Printf.sprintf
+ "Path %s ends with *, %s"
+ (Path.toString p)
+ "but first root (after canonizing) is non-local"))
+ | Some lrfspath ->
+ Safelist.map (fun c -> Path.makeGlobal (Path.child parent c))
+ (Os.childrenOf lrfspath parent)
+ end
+ | _ -> [Path.makeGlobal p]
+
+let expandWildcardPaths() =
+ let lr =
+ match rootsInCanonicalOrder() with
+ [(Local, fspath); _] -> Some fspath
+ | _ -> None in
+ Prefs.set paths
+ (Safelist.flatten_map (globPath lr) (Prefs.read paths))
+
+(*****************************************************************************)
+(* PROPAGATION OF PREFERENCES *)
+(*****************************************************************************)
+
+let propagatePrefsTo =
+ Remote.registerHostCmd
+ "installPrefs"
+ (fun prefs -> return (Prefs.load prefs))
+
+let propagatePrefs () =
+ let prefs = Prefs.dump() in
+ let toHost root =
+ match root with
+ (Local, _) -> return ()
+ | (Remote host,_) ->
+ propagatePrefsTo host prefs
+ in
+ allRootsIter toHost
+
+(*****************************************************************************)
+(* PREFERENCES AND PREDICATES *)
+(*****************************************************************************)
+
+let batch =
+ Prefs.createBool "batch" false "batch mode: ask no questions at all"
+ ("When this is set to {\\tt true}, the user "
+ ^ "interface will ask no questions at all. Non-conflicting changes "
+ ^ "will be propagated; conflicts will be skipped.")
+
+let confirmBigDeletes =
+ Prefs.createBool "confirmbigdel" true
+ "!ask about whole-replica (or path) deletes"
+ ("When this is set to {\\tt true}, Unison will request an extra confirmation if it appears "
+ ^ "that the entire replica has been deleted, before propagating the change. If the {\\tt batch} "
+ ^ "flag is also set, synchronization will be aborted. When the {\\tt path} preference is used, "
+ ^ "the same confirmation will be requested for top-level paths. (At the moment, this flag only "
+ ^ "affects the text user interface.) See also the {\\tt mountpoint} preference.")
+
+let () = Prefs.alias confirmBigDeletes "confirmbigdeletes"
+
+let ignorePred =
+ Pred.create "ignore"
+ ("Including the preference \\texttt{-ignore \\ARG{pathspec}} causes Unison to "
+ ^ "completely ignore paths that match \\ARG{pathspec} (as well as their "
+ ^ "children). This is useful for avoiding synchronizing temporary "
+ ^ "files, object files, etc. The syntax of \\ARG{pathspec} is "
+ ^ "described in \\sectionref{pathspec}{Path Specification}, and further "
+ ^ "details on ignoring paths is found in"
+ ^ " \\sectionref{ignore}{Ignoring Paths}.")
+
+let ignorenotPred =
+ Pred.create "ignorenot"
+ ("This preference overrides the preference \\texttt{ignore}.
+ It gives a list of patterns
+ (in the same format as
+ \\verb|ignore|) for paths that should definitely {\\em not} be ignored,
+ whether or not they happen to match one of the \\verb|ignore| patterns.
+ \\par Note that the semantics of {\\tt ignore} and {\\tt ignorenot} is a
+ little counter-intuitive. When detecting updates, Unison examines
+ paths in depth-first order, starting from the roots of the replicas
+ and working downwards. Before examining each path, it checks whether
+ it matches {\\tt ignore} and does not match {\\tt ignorenot}; in this case
+ it skips this path {\\em and all its descendants}. This means that,
+ if some parent of a given path matches an {\\tt ignore} pattern, then
+ it will be skipped even if the path itself matches an {\\tt ignorenot}
+ pattern. In particular, putting {\\tt ignore = Path *} in your profile
+ and then using {\\tt ignorenot} to select particular paths to be
+ synchronized will not work. Instead, you should use the {\\tt path}
+ preference to choose particular paths to synchronize.")
+
+let shouldIgnore p =
+ let p = Path.toString p in
+ (Pred.test ignorePred p) && not (Pred.test ignorenotPred p)
+
+let addRegexpToIgnore re =
+ let oldRE = Pred.extern ignorePred in
+ let newRE = re::oldRE in
+ Pred.intern ignorePred newRE
+
+let merge =
+ Pred.create "merge" ~advanced:true
+ ("This preference can be used to run a merge program which will create "
+ ^ "a new version for each of the files and the backup, "
+ ^ "with the last backup and the both replicas. Setting the {\\tt merge} "
+ ^ "preference for a path will also cause this path to be backed up, "
+ ^ "just like {\tt backup}. "
+ ^ "The syntax of \\ARG{pathspec>cmd} is "
+ ^ "described in \\sectionref{pathspec}{Path Specification}, and further "
+ ^ "details on Merging functions are present in "
+ ^ "\\sectionref{merge}{Merging files}.")
+
+let shouldMerge p = Pred.test merge (Path.toString p)
+
+let mergeCmdForPath p = Pred.assoc merge (Path.toString p)
+
+let someHostIsRunningWindows =
+ Prefs.createBool "someHostIsRunningWindows" false "*" ""
+
+let allHostsAreRunningWindows =
+ Prefs.createBool "allHostsAreRunningWindows" false "*" ""
+
+let fatFilesystem =
+ Prefs.createBool "fat" ~local:true false
+ "use appropriate options for FAT filesystems"
+ ("When this is set to {\\tt true}, Unison will use appropriate options \
+ to synchronize efficiently and without error a replica located on a \
+ FAT filesystem on a non-Windows machine: \
+ do not synchronize permissions ({\\tt perms = 0}); \
+ never use chmod ({\tt dontchmod = true}); \
+ treat filenames as case insensitive ({\\tt ignorecase = true}); \
+ do not attempt to synchronize symbolic links ({\\tt links = false}); \
+ ignore inode number changes when detecting updates \
+ ({\\tt ignoreinodenumbers = true}). \
+ Any of these change can be overridden by explicitly setting \
+ the corresponding preference in the profile.")
Deleted: branches/2.45/src/mkProjectInfo.ml
===================================================================
--- trunk/src/mkProjectInfo.ml 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/src/mkProjectInfo.ml 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,67 +0,0 @@
-(* Program for printing project info into a Makefile. Documentation below. *)
-
-(* FIX: When the time comes for the next alpha-release, remember to
- increment the archive version number first. See update.ml. *)
-
-let projectName = "unison"
-let majorVersion = 2
-let minorVersion = 44
-let pointVersionOrigin = 471 (* Revision that corresponds to point version 0 *)
-
-(* Documentation:
- This is a program to construct a version of the form Major.Minor.Point,
- e.g., 2.10.4.
- The Point release number is calculated from the Subversion revision number,
- so it will be automatically incremented on svn commit.
- The Major and Minor numbers are hard coded, as is the revision number
- corresponding to the 0 point release.
-
- If you want to increment the Major or Minor number, you will have to do a
- little thinking to get the Point number back to 0. Suppose the current svn
- revision number is 27, and we have below
-
- let majorVersion = 2
- let minorVersion = 11
- let pointVersionOrigin = 3
-
- This means that the current Unison version is 2.11.24, since 27-3 = 24.
- If we want to change the release to 3.0.0 we need to change things to
-
- let majorVersion = 3
- let minorVersion = 0
- let pointVersionOrigin = 28
-
- and then do a svn commit.
-
- The first two lines are obvious. The last line says that Subversion
- revision 28 corresponds to a 0 point release. Since we were at revision
- 27 and we're going to do a commit before making a release, we
- will be at 28 after the commit and this will be Unison version 3.0.0.
-*)
-
-(* ---------------------------------------------------------------------- *)
-(* You shouldn't need to edit below. *)
-
-let revisionString = "$Rev$";;
-
-let pointVersion =
- Scanf.sscanf revisionString "$Rev: %d " (fun x -> x) - pointVersionOrigin;;
-
-Printf.printf "MAJORVERSION=%d.%d\n" majorVersion minorVersion;;
-Printf.printf "VERSION=%d.%d.%d\n" majorVersion minorVersion pointVersion;;
-Printf.printf "NAME=%s\n" projectName;;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Copied: branches/2.45/src/mkProjectInfo.ml (from rev 486, trunk/src/mkProjectInfo.ml)
===================================================================
--- branches/2.45/src/mkProjectInfo.ml (rev 0)
+++ branches/2.45/src/mkProjectInfo.ml 2012-04-02 15:54:47 UTC (rev 487)
@@ -0,0 +1,68 @@
+(* Program for printing project info into a Makefile. Documentation below. *)
+
+(* FIX: When the time comes for the next alpha-release, remember to
+ increment the archive version number first. See update.ml. *)
+
+let projectName = "unison"
+let majorVersion = 2
+let minorVersion = 45
+let pointVersionOrigin = 485 (* Revision that corresponds to point version 0 *)
+
+(* Documentation:
+ This is a program to construct a version of the form Major.Minor.Point,
+ e.g., 2.10.4.
+ The Point release number is calculated from the Subversion revision number,
+ so it will be automatically incremented on svn commit.
+ The Major and Minor numbers are hard coded, as is the revision number
+ corresponding to the 0 point release.
+
+ If you want to increment the Major or Minor number, you will have to do a
+ little thinking to get the Point number back to 0. Suppose the current svn
+ revision number is 27, and we have below
+
+ let majorVersion = 2
+ let minorVersion = 11
+ let pointVersionOrigin = 3
+
+ This means that the current Unison version is 2.11.24, since 27-3 = 24.
+ If we want to change the release to 3.0.0 we need to change things to
+
+ let majorVersion = 3
+ let minorVersion = 0
+ let pointVersionOrigin = 28
+
+ and then do a svn commit.
+
+ The first two lines are obvious. The last line says that Subversion
+ revision 28 corresponds to a 0 point release. Since we were at revision
+ 27 and we're going to do a commit before making a release, we
+ will be at 28 after the commit and this will be Unison version 3.0.0.
+*)
+
+(* ---------------------------------------------------------------------- *)
+(* You shouldn't need to edit below. *)
+
+let revisionString = "$Rev$";;
+
+let pointVersion =
+ Scanf.sscanf revisionString "$Rev: %d " (fun x -> x) - pointVersionOrigin;;
+
+Printf.printf "MAJORVERSION=%d.%d\n" majorVersion minorVersion;;
+Printf.printf "VERSION=%d.%d.%d\n" majorVersion minorVersion pointVersion;;
+Printf.printf "NAME=%s\n" projectName;;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Deleted: branches/2.45/src/uicommon.ml
===================================================================
--- trunk/src/uicommon.ml 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/src/uicommon.ml 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,759 +0,0 @@
-(* Unison file synchronizer: src/uicommon.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/>.
-*)
-
-
-open Common
-open Lwt
-
-(**********************************************************************
- UI selection
- **********************************************************************)
-
-type interface =
- Text
- | Graphic
-
-module type UI =
-sig
- val start : interface -> unit
- val defaultUi : interface
-end
-
-
-(**********************************************************************
- Preferences
- **********************************************************************)
-
-let auto =
- Prefs.createBool "auto" false "automatically accept default (nonconflicting) actions"
- ("When set to {\\tt true}, this flag causes the user "
- ^ "interface to skip asking for confirmations on "
- ^ "non-conflicting changes. (More precisely, when the user interface "
- ^ "is done setting the propagation direction for one entry and is about "
- ^ "to move to the next, it will skip over all non-conflicting entries "
- ^ "and go directly to the next conflict.)" )
-
-(* This has to be here rather than in uigtk.ml, because it is part of what
- gets sent to the server at startup *)
-let mainWindowHeight =
- Prefs.createInt "height" 15
- "!height (in lines) of main window in graphical interface"
- ("Used to set the height (in lines) of the main window in the graphical "
- ^ "user interface.")
-
-let expert =
- Prefs.createBool "expert" false
- "*Enable some developers-only functionality in the UI" ""
-
-let profileLabel =
- Prefs.createString "label" ""
- "!provide a descriptive string label for this profile"
- ("Used in a profile to provide a descriptive string documenting its "
- ^ "settings. (This is useful for users that switch between several "
- ^ "profiles, especially using the `fast switch' feature of the "
- ^ "graphical user interface.)")
-
-let profileKey =
- Prefs.createString "key" ""
- "!define a keyboard shortcut for this profile (in some UIs)"
- ("Used in a profile to define a numeric key (0-9) that can be used in "
- ^ "the graphical user interface to switch immediately to this profile.")
-(* This preference is not actually referred to in the code anywhere, since
- the keyboard shortcuts are constructed by a separate scan of the preference
- file in uigtk.ml, but it must be present to prevent the preferences module
- from complaining about 'key = n' lines in profiles. *)
-
-let contactquietly =
- Prefs.createBool "contactquietly" false
- "!suppress the 'contacting server' message during startup"
- ("If this flag is set, Unison will skip displaying the "
- ^ "`Contacting server' message (which some users find annoying) "
- ^ "during startup.")
-
-let contactingServerMsg () =
- Printf.sprintf "Contacting server..."
-
-let repeat =
- Prefs.createString "repeat" ""
- "!synchronize repeatedly (text interface only)"
- ("Setting this preference causes the text-mode interface to synchronize "
- ^ "repeatedly, rather than doing it just once and stopping. If the "
- ^ "argument is a number, Unison will pause for that many seconds before "
- ^ "beginning again.")
-
-(* ^ "If the argument is a path, Unison will wait for the "
- ^ "file at this path---called a {\\em changelog}---to "
- ^ "be modified (on either the client or the server "
- ^ "machine), read the contents of the changelog (which should be a newline-"
- ^ "separated list of paths) on both client and server, "
- ^ "combine the results, "
- ^ "and start again, using the list of paths read from the changelogs as the "
- ^ " '-path' preference for the new run. The idea is that an external "
- ^ "process will watch the filesystem and, when it thinks something may have "
- ^ "changed, write the changed pathname to its local changelog where Unison "
- ^ "will find it the next time it looks. If the changelogs have not been "
- ^ "modified, Unison will wait, checking them again every few seconds."
-*)
-
-let retry =
- Prefs.createInt "retry" 0
- "!re-try failed synchronizations N times (text ui only)"
- ("Setting this preference causes the text-mode interface to try again "
- ^ "to synchronize "
- ^ "updated paths where synchronization fails. Each such path will be "
- ^ "tried N times."
- )
-
-let confirmmerge =
- Prefs.createBool "confirmmerge" false
- "!ask for confirmation before commiting results of a merge"
- ("Setting this preference causes both the text and graphical interfaces"
- ^ " to ask the user if the results of a merge command may be commited "
- ^ " to the replica or not. Since the merge command works on temporary files,"
- ^ " the user can then cancel all the effects of applying the merge if it"
- ^ " turns out that the result is not satisfactory. In "
- ^ " batch-mode, this preference has no effect. Default is false.")
-
-let runTestsPrefName = "selftest"
-let runtests =
- Prefs.createBool runTestsPrefName false
- "!run internal tests and exit"
- ("Run internal tests and exit. This option is mostly for developers and must be used "
- ^ "carefully: in particular, "
- ^ "it will delete the contents of both roots, so that it can install its own files "
- ^ "for testing. This flag only makes sense on the command line. When it is "
- ^ "provided, no preference file is read: all preferences must be specified on the"
- ^ "command line. Also, since the self-test procedure involves overwriting the roots "
- ^ "and backup directory, the names of the roots and of the backupdir preference "
- ^ "must include the string "
- ^ "\"test\" or else the tests will be aborted. (If these are not given "
- ^ "on the command line, dummy "
- ^ "subdirectories in the current directory will be created automatically.)")
-
-(* This ref is set to Test.test during initialization, avoiding a circular
- dependency *)
-let testFunction = ref (fun () -> assert false)
-
-(**********************************************************************
- Formatting functions
- **********************************************************************)
-
-(* When no archives were found, we omit 'new' in status descriptions, since
- *all* files would be marked new and this won't make sense to the user. *)
-let choose s1 s2 = if !Update.foundArchives then s1 else s2
-
-let showprev =
- Prefs.createBool "showprev" false
- "*Show previous properties, if they differ from current"
- ""
-
-(* The next function produces nothing unless the "showprev"
- preference is set. This is because it tends to make the
- output trace too long and annoying. *)
-let prevProps newprops ui =
- if not (Prefs.read showprev) then ""
- else match ui with
- NoUpdates | Error _
- -> ""
- | Updates (_, New) ->
- " (new)"
- | Updates (_, Previous(_,oldprops,_,_)) ->
- (* || Props.similar newprops oldprops *)
- " (was: "^(Props.toString oldprops)^")"
-
-let replicaContentDesc rc =
- Props.toString (Props.setLength rc.desc (snd rc.size))
-
-let replicaContent2string rc sep =
- let d s = s ^ sep ^ replicaContentDesc rc ^ prevProps rc.desc rc.ui in
- match rc.typ, rc.status with
- `ABSENT, `Unchanged ->
- "absent"
- | _, `Unchanged ->
- "unchanged "
- ^(Util.truncateString (Fileinfo.type2string rc.typ) 7)
- ^ sep
- ^ replicaContentDesc rc
- | `ABSENT, `Deleted -> "deleted"
- | `FILE, `Created ->
- d (choose "new file " "file ")
- | `FILE, `Modified ->
- d "changed file "
- | `FILE, `PropsChanged ->
- d "changed props "
- | `SYMLINK, `Created ->
- d (choose "new symlink " "symlink ")
- | `SYMLINK, `Modified ->
- d "changed symlink "
- | `DIRECTORY, `Created ->
- d (choose "new dir " "dir ")
- | `DIRECTORY, `Modified ->
- d "changed dir "
- | `DIRECTORY, `PropsChanged ->
- d "dir props changed"
-
- (* Some cases that can't happen... *)
- | `ABSENT, (`Created | `Modified | `PropsChanged)
- | `SYMLINK, `PropsChanged
- | (`FILE|`SYMLINK|`DIRECTORY), `Deleted ->
- assert false
-
-let replicaContent2shortString rc =
- match rc.typ, rc.status with
- _, `Unchanged -> " "
- | `ABSENT, `Deleted -> "deleted "
- | `FILE, `Created -> choose "new file" "file "
- | `FILE, `Modified -> "changed "
- | `FILE, `PropsChanged -> "props "
- | `SYMLINK, `Created -> choose "new link" "link "
- | `SYMLINK, `Modified -> "chgd lnk"
- | `DIRECTORY, `Created -> choose "new dir " "dir "
- | `DIRECTORY, `Modified -> "chgd dir"
- | `DIRECTORY, `PropsChanged -> "props "
- (* Cases that can't happen... *)
- | `ABSENT, (`Created | `Modified | `PropsChanged)
- | `SYMLINK, `PropsChanged
- | (`FILE|`SYMLINK|`DIRECTORY), `Deleted
- -> assert false
-
-let roots2niceStrings length = function
- (Local,fspath1), (Local,fspath2) ->
- let name1, name2 = Fspath.differentSuffix fspath1 fspath2 in
- (Util.truncateString name1 length, Util.truncateString name2 length)
- | (Local,fspath1), (Remote host, fspath2) ->
- (Util.truncateString "local" length, Util.truncateString host length)
- | (Remote host, fspath1), (Local,fspath2) ->
- (Util.truncateString host length, Util.truncateString "local" length)
- | _ -> assert false (* BOGUS? *)
-
-let details2string theRi sep =
- match theRi.replicas with
- Problem s ->
- Printf.sprintf "Error: %s\n" s
- | Different {rc1 = rc1; rc2 = rc2} ->
- let root1str, root2str =
- roots2niceStrings 12 (Globals.roots()) in
- Printf.sprintf "%s : %s\n%s : %s"
- root1str (replicaContent2string rc1 sep)
- root2str (replicaContent2string rc2 sep)
-
-let displayPath previousPath path =
- let previousNames = Path.toNames previousPath in
- let names = Path.toNames path in
- if names = [] then "/" else
- (* Strip the greatest common prefix of previousNames and names
- from names. level is the number of names in the greatest
- common prefix. *)
- let rec loop level names1 names2 =
- match (names1,names2) with
- (hd1::tl1,hd2::tl2) ->
- if Name.compare hd1 hd2 = 0
- then loop (level+1) tl1 tl2
- else (level,names2)
- | _ -> (level,names2) in
- let (level,suffixNames) = loop 0 previousNames names in
- let suffixPath =
- Safelist.fold_left Path.child Path.empty suffixNames in
- let spaces = String.make (level*3) ' ' in
- spaces ^ (Path.toString suffixPath)
-
-let roots2string () =
- let replica1, replica2 = roots2niceStrings 12 (Globals.roots()) in
- (Printf.sprintf "%s %s " replica1 replica2)
-
-type action = AError | ASkip of bool | ALtoR of bool | ARtoL of bool | AMerge
-
-let direction2action partial dir =
- match dir with
- Conflict -> ASkip partial
- | Replica1ToReplica2 -> ALtoR partial
- | Replica2ToReplica1 -> ARtoL partial
- | Merge -> AMerge
-
-let action2niceString action =
- match action with
- AError -> "error"
- | ASkip _ -> "<-?->"
- | ALtoR false -> "---->"
- | ALtoR true -> "--?->"
- | ARtoL false -> "<----"
- | ARtoL true -> "<-?--"
- | AMerge -> "<-M->"
-
-let reconItem2stringList oldPath theRI =
- match theRI.replicas with
- Problem s ->
- (" ", AError, " ", displayPath oldPath theRI.path1)
- | Different diff ->
- let partial = diff.errors1 <> [] || diff.errors2 <> [] in
- (replicaContent2shortString diff.rc1,
- direction2action partial diff.direction,
- replicaContent2shortString diff.rc2,
- displayPath oldPath theRI.path1)
-
-let reconItem2string oldPath theRI status =
- let (r1, action, r2, path) = reconItem2stringList oldPath theRI in
- Format.sprintf "%s %s %s %s %s" r1 (action2niceString action) r2 status path
-
-let exn2string = function
- Sys.Break -> "Terminated!"
- | Util.Fatal(s) -> Printf.sprintf "Fatal error: %s" s
- | Util.Transient(s) -> Printf.sprintf "Error: %s" s
- | Unix.Unix_error (err, fun_name, arg) ->
- Printf.sprintf "Uncaught unix error: %s failed%s: %s%s"
- fun_name
- (if String.length arg > 0 then Format.sprintf " on \"%s\"" arg else "")
- (Unix.error_message err)
- (match err with
- Unix.EUNKNOWNERR n -> Format.sprintf " (code %d)" n
- | _ -> "")
- | Invalid_argument s -> Printf.sprintf "Invalid argument: %s" s
- | other -> Printf.sprintf "Uncaught exception %s" (Printexc.to_string other)
-
-(* precondition: uc = File (Updates(_, ..) on both sides *)
-let showDiffs ri printer errprinter id =
- match ri.replicas with
- Problem _ ->
- errprinter
- "Can't diff files: there was a problem during update detection"
- | Different {rc1 = {typ = `FILE; ui = ui1}; rc2 = {typ = `FILE; ui = ui2}} ->
- let (root1,root2) = Globals.roots() in
- begin
- try Files.diff root1 ri.path1 ui1 root2 ri.path2 ui2 printer id
- with Util.Transient e -> errprinter e
- end
- | Different _ ->
- errprinter "Can't diff: path doesn't refer to a file in both replicas"
-
-
-exception Synch_props of Common.reconItem
-
-(**********************************************************************
- Common error messages
- **********************************************************************)
-
-let dangerousPathMsg dangerousPaths =
- if dangerousPaths = [Path.empty] then
- "The root of one of the replicas has been completely emptied.\n\
- Unison may delete everything in the other replica. (Set the \n\
- 'confirmbigdel' preference to false to disable this check.)\n"
- else
- Printf.sprintf
- "The following paths have been completely emptied in one replica:\n \
- %s\n\
- Unison may delete everything below these paths in the other replica.\n
- (Set the 'confirmbigdel' preference to false to disable this check.)\n"
- (String.concat "\n "
- (Safelist.map (fun p -> "'" ^ (Path.toString p) ^ "'")
- dangerousPaths))
-
-(**********************************************************************
- Useful patterns for ignoring paths
- **********************************************************************)
-
-let quote s =
- let len = String.length s in
- let buf = String.create (2 * len) in
- let pos = ref 0 in
- for i = 0 to len - 1 do
- match s.[i] with
- '*' | '?' | '[' | '{' | '}' | ',' | '\\' as c ->
- buf.[!pos] <- '\\'; buf.[!pos + 1] <- c; pos := !pos + 2
- | c ->
- buf.[!pos] <- c; pos := !pos + 1
- done;
- "{" ^ String.sub buf 0 !pos ^ "}"
-
-let ignorePath path = "Path " ^ quote (Path.toString path)
-
-let ignoreName path =
- match Path.finalName path with
- Some name -> "Name " ^ quote (Name.toString name)
- | None -> assert false
-
-let ignoreExt path =
- match Path.finalName path with
- Some name ->
- let str = Name.toString name in
- begin try
- let pos = String.rindex str '.' in
- let ext = String.sub str pos (String.length str - pos) in
- "Name {,.}*" ^ quote ext
- with Not_found -> (* str does not contain '.' *)
- "Name " ^ quote str
- end
- | None ->
- assert false
-
-let addIgnorePattern theRegExp =
- if theRegExp = "Path " then
- raise (Util.Transient "Can't ignore the root path!");
- Globals.addRegexpToIgnore theRegExp;
- let r = Prefs.add "ignore" theRegExp in
- Trace.status r;
- (* Make sure the server has the same ignored paths (in case, for
- example, we do a "rescan") *)
- Lwt_unix.run (Globals.propagatePrefs ())
-
-(**********************************************************************
- Profile and command-line parsing
- **********************************************************************)
-
-let coreUsageMsg =
- "Usage: " ^ Uutil.myName
- ^ " [options]\n"
- ^ " or " ^ Uutil.myName
- ^ " root1 root2 [options]\n"
- ^ " or " ^ Uutil.myName
- ^ " profilename [options]\n"
-
-let shortUsageMsg =
- coreUsageMsg ^ "\n"
- ^ "For a list of options, type \"" ^ Uutil.myName ^ " -help\".\n"
- ^ "For a tutorial on basic usage, type \"" ^ Uutil.myName
- ^ " -doc tutorial\".\n"
- ^ "For other documentation, type \"" ^ Uutil.myName ^ " -doc topics\".\n"
-
-let usageMsg = coreUsageMsg
-
-let debug = Trace.debug "startup"
-
-(* ---- *)
-
-(*FIX: remove when Unison version > 2.40 *)
-let _ =
-Remote.registerRootCmd "_unicodeCaseSensitive_" (fun _ -> Lwt.return ())
-let supportUnicodeCaseSensitive () =
- if Uutil.myMajorVersion > "2.40" (* The test is correct until 2.99... *) then
- Lwt.return true
- else begin
- Globals.allRootsMap
- (fun r -> Remote.commandAvailable r "_unicodeCaseSensitive_")
- >>= fun l ->
- Lwt.return (List.for_all (fun x -> x) l)
- end
-
-(* Determine the case sensitivity of a root (does filename FOO==foo?) *)
-let architecture =
- Remote.registerRootCmd
- "architecture"
- (fun (_,()) -> return (Util.osType = `Win32, Osx.isMacOSX, Util.isCygwin))
-
-(* During startup the client determines the case sensitivity of each root.
- If any root is case insensitive, all roots must know this -- it's
- propagated in a pref. Also, detects HFS (needed for resource forks) and
- Windows (needed for permissions) and does some sanity checking. *)
-let validateAndFixupPrefs () =
- Props.validatePrefs();
- let supportUnicodeCaseSensitive = supportUnicodeCaseSensitive () in
- Globals.allRootsMap (fun r -> architecture r ()) >>= (fun archs ->
- supportUnicodeCaseSensitive >>= fun unicodeCS ->
- let someHostIsRunningWindows =
- Safelist.exists (fun (isWin, _, _) -> isWin) archs in
- let allHostsAreRunningWindows =
- Safelist.for_all (fun (isWin, _, _) -> isWin) archs in
- let someHostIsRunningBareWindows =
- Safelist.exists (fun (isWin, _, isCyg) -> isWin && not isCyg) archs in
- let someHostRunningOsX =
- Safelist.exists (fun (_, isOSX, _) -> isOSX) archs in
- let someHostIsCaseInsensitive =
- someHostIsRunningWindows || someHostRunningOsX in
- if Prefs.read Globals.fatFilesystem then begin
- Prefs.overrideDefault Props.permMask 0;
- Prefs.overrideDefault Props.dontChmod true;
- Prefs.overrideDefault Case.caseInsensitiveMode `True;
- Prefs.overrideDefault Fileinfo.allowSymlinks `False;
- Prefs.overrideDefault Fileinfo.ignoreInodeNumbers true
- end;
- Case.init someHostIsCaseInsensitive (someHostRunningOsX && unicodeCS);
- Props.init someHostIsRunningWindows;
- Osx.init someHostRunningOsX;
- Fileinfo.init someHostIsRunningBareWindows;
- Prefs.set Globals.someHostIsRunningWindows someHostIsRunningWindows;
- Prefs.set Globals.allHostsAreRunningWindows allHostsAreRunningWindows;
- return ())
-
-(* ---- *)
-
-let promptForRoots getFirstRoot getSecondRoot =
- (* Ask the user for the roots *)
- let r1 = match getFirstRoot() with None -> exit 0 | Some r -> r in
- let r2 = match getSecondRoot() with None -> exit 0 | Some r -> r in
- (* Remember them for this run, ordering them so that the first
- will come out on the left in the UI *)
- Globals.setRawRoots [r1; r2];
- (* Save them in the current profile *)
- ignore (Prefs.add "root" r1);
- ignore (Prefs.add "root" r2)
-
-(* ---- *)
-
-(* The first time we load preferences, we also read the command line
- arguments; if we re-load prefs (because the user selected a new profile)
- we ignore the command line *)
-let firstTime = ref(true)
-
-(* Roots given on the command line *)
-let cmdLineRawRoots = ref []
-
-(* BCP: WARNING: Some of the code from here is duplicated in uimacbridge...! *)
-let initPrefs ~profileName ~displayWaitMessage ~getFirstRoot ~getSecondRoot
- ~termInteract =
- (* Restore prefs to their default values, if necessary *)
- if not !firstTime then Prefs.resetToDefaults();
- Globals.setRawRoots !cmdLineRawRoots;
-
- (* Tell the preferences module the name of the profile *)
- Prefs.profileName := Some(profileName);
-
- (* Check whether the -selftest flag is present on the command line *)
- let testFlagPresent =
- Util.StringMap.mem runTestsPrefName (Prefs.scanCmdLine usageMsg) in
-
- (* If the -selftest flag is present, then we skip loading the preference file.
- (This is prevents possible confusions where settings from a preference
- file could cause unit tests to fail.) *)
- if not testFlagPresent then begin
- (* If the profile does not exist, create an empty one (this should only
- happen if the profile is 'default', since otherwise we will already
- have checked that the named one exists). *)
- if not(System.file_exists (Prefs.profilePathname profileName)) then
- Prefs.addComment "Unison preferences file";
-
- (* Load the profile *)
- (debug (fun() -> Util.msg "about to load prefs");
- Prefs.loadTheFile());
-
- (* Now check again that the -selftest flag has not been set, and barf otherwise *)
- if Prefs.read runtests then raise (Util.Fatal
- "The 'test' flag should only be given on the command line")
- end;
-
- (* Parse the command line. This will override settings from the profile. *)
- (* JV (6/09): always reparse the command line *)
- if true (*!firstTime*) then begin
- debug (fun() -> Util.msg "about to parse command line");
- Prefs.parseCmdLine usageMsg;
- end;
-
- (* Install dummy roots and backup directory if we are running self-tests *)
- if Prefs.read runtests then begin
- if Globals.rawRoots() = [] then
- Prefs.loadStrings ["root = test-a.tmp"; "root = test-b.tmp"];
- if (Prefs.read Stasher.backupdir) = "" then
- Prefs.loadStrings ["backupdir = test-backup.tmp"];
- end;
-
- (* Print the preference settings *)
- debug (fun() -> Prefs.dumpPrefsToStderr() );
-
- (* If no roots are given either on the command line or in the profile,
- ask the user *)
- if Globals.rawRoots() = [] then begin
- promptForRoots getFirstRoot getSecondRoot;
- end;
-
- Recon.checkThatPreferredRootIsValid();
-
- (* The following step contacts the server, so warn the user it could take
- some time *)
- if not (Prefs.read contactquietly || Prefs.read Trace.terse) then
- displayWaitMessage();
-
- (* Canonize the names of the roots, sort them (with local roots first),
- and install them in Globals. *)
- Lwt_unix.run (Globals.installRoots termInteract);
-
- (* If both roots are local, disable the xferhint table to save time *)
- begin match Globals.roots() with
- ((Local,_),(Local,_)) -> Prefs.set Xferhint.xferbycopying false
- | _ -> ()
- end;
-
- (* FIX: This should be before Globals.installRoots *)
- (* Check to be sure that there is at most one remote root *)
- let numRemote =
- Safelist.fold_left
- (fun n (w,_) -> match w with Local -> n | Remote _ -> n+1)
- 0
- (Globals.rootsList()) in
- if numRemote > 1 then
- raise(Util.Fatal "cannot synchronize more than one remote root");
-
- (* If no paths were specified, then synchronize the whole replicas *)
- if Prefs.read Globals.paths = [] then Prefs.set Globals.paths [Path.empty];
-
- (* Expand any "wildcard" paths [with final component *] *)
- Globals.expandWildcardPaths();
-
- Update.storeRootsName ();
-
- if
- numRemote > 0 && not (Prefs.read contactquietly || Prefs.read Trace.terse)
- then
- Util.msg "Connected [%s]\n"
- (Util.replacesubstring (Update.getRootsName()) ", " " -> ");
-
- debug (fun() ->
- Printf.eprintf "Roots: \n";
- Safelist.iter (fun clr -> Printf.eprintf " %s\n" clr)
- (Globals.rawRoots ());
- Printf.eprintf " i.e. \n";
- Safelist.iter (fun clr -> Printf.eprintf " %s\n"
- (Clroot.clroot2string (Clroot.parseRoot clr)))
- (Globals.rawRoots ());
- Printf.eprintf " i.e. (in canonical order)\n";
- Safelist.iter (fun r ->
- Printf.eprintf " %s\n" (root2string r))
- (Globals.rootsInCanonicalOrder());
- Printf.eprintf "\n");
-
- Lwt_unix.run
- (validateAndFixupPrefs () >>=
- Globals.propagatePrefs);
-
- (* Initializes some backups stuff according to the preferences just loaded from the profile.
- Important to do it here, after prefs are propagated, because the function will also be
- run on the server, if any. Also, this should be done each time a profile is reloaded
- on this side, that's why it's here. *)
- Stasher.initBackups ();
-
- firstTime := false
-
-(**********************************************************************
- Common startup sequence
- **********************************************************************)
-
-let anonymousArgs =
- Prefs.createStringList "rest"
- "*roots or profile name" ""
-
-let testServer =
- Prefs.createBool "testserver" false
- "exit immediately after the connection to the server"
- ("Setting this flag on the command line causes Unison to attempt to "
- ^ "connect to the remote server and, if successful, print a message "
- ^ "and immediately exit. Useful for debugging installation problems. "
- ^ "Should not be set in preference files.")
-
-(* For backward compatibility *)
-let _ = Prefs.alias testServer "testServer"
-
-(* ---- *)
-
-let uiInit
- ~(reportError : string -> unit)
- ~(tryAgainOrQuit : string -> bool)
- ~(displayWaitMessage : unit -> unit)
- ~(getProfile : unit -> string option)
- ~(getFirstRoot : unit -> string option)
- ~(getSecondRoot : unit -> string option)
- ~(termInteract : (string -> string -> string) option) =
-
- (* Make sure we have a directory for archives and profiles *)
- Os.createUnisonDir();
-
- (* Extract any command line profile or roots *)
- let clprofile = ref None in
- begin
- try
- let args = Prefs.scanCmdLine usageMsg in
- match Util.StringMap.find "rest" args with
- [] -> ()
- | [profile] -> clprofile := Some profile
- | [root2;root1] -> cmdLineRawRoots := [root1;root2]
- | [root2;root1;profile] ->
- cmdLineRawRoots := [root1;root2];
- clprofile := Some profile
- | _ ->
- (reportError(Printf.sprintf
- "%s was invoked incorrectly (too many roots)" Uutil.myName);
- exit 1)
- with Not_found -> ()
- end;
-
- (* Print header for debugging output *)
- debug (fun() ->
- Printf.eprintf "%s, version %s\n\n" Uutil.myName Uutil.myVersion);
- debug (fun() -> Util.msg "initializing UI");
-
- debug (fun () ->
- (match !clprofile with
- None -> Util.msg "No profile given on command line"
- | Some s -> Printf.eprintf "Profile '%s' given on command line" s);
- (match !cmdLineRawRoots with
- [] -> Util.msg "No roots given on command line"
- | [root1;root2] ->
- Printf.eprintf "Roots '%s' and '%s' given on command line"
- root1 root2
- | _ -> assert false));
-
- let profileName =
- begin match !clprofile with
- None ->
- let clroots_given = !cmdLineRawRoots <> [] in
- let n =
- if not(clroots_given) then begin
- (* Ask the user to choose a profile or create a new one. *)
- clprofile := getProfile();
- match !clprofile with
- None -> exit 0 (* None means the user wants to quit *)
- | Some x -> x
- end else begin
- (* Roots given on command line.
- The profile should be the default. *)
- clprofile := Some "default";
- "default"
- end in
- n
- | Some n ->
- let f = Prefs.profilePathname n in
- if not(System.file_exists f)
- then (reportError (Printf.sprintf "Profile %s does not exist"
- (System.fspathToPrintString f));
- exit 1);
- n
- end in
-
- (* Load the profile and command-line arguments *)
- initPrefs
- profileName displayWaitMessage getFirstRoot getSecondRoot termInteract;
-
- (* Turn on GC messages, if the '-debug gc' flag was provided *)
- if Trace.enabled "gc" then Gc.set {(Gc.get ()) with Gc.verbose = 0x3F};
-
- if Prefs.read testServer then exit 0;
-
- (* BCPFIX: Should/can this be done earlier?? *)
- Files.processCommitLogs();
-
- (* Run unit tests if requested *)
- if Prefs.read runtests then begin
- (!testFunction)();
- exit 0
- end
-
-(* Exit codes *)
-let perfectExit = 0 (* when everything's okay *)
-let skippyExit = 1 (* when some items were skipped, but no failure occurred *)
-let failedExit = 2 (* when there's some non-fatal failure *)
-let fatalExit = 3 (* when fatal failure occurred *)
-let exitCode = function
- (false, false) -> 0
- | (true, false) -> 1
- | _ -> 2
-(* (anySkipped?, anyFailure?) -> exit code *)
Copied: branches/2.45/src/uicommon.ml (from rev 486, trunk/src/uicommon.ml)
===================================================================
--- branches/2.45/src/uicommon.ml (rev 0)
+++ branches/2.45/src/uicommon.ml 2012-04-02 15:54:47 UTC (rev 487)
@@ -0,0 +1,759 @@
+(* Unison file synchronizer: src/uicommon.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/>.
+*)
+
+
+open Common
+open Lwt
+
+(**********************************************************************
+ UI selection
+ **********************************************************************)
+
+type interface =
+ Text
+ | Graphic
+
+module type UI =
+sig
+ val start : interface -> unit
+ val defaultUi : interface
+end
+
+
+(**********************************************************************
+ Preferences
+ **********************************************************************)
+
+let auto =
+ Prefs.createBool "auto" false "automatically accept default (nonconflicting) actions"
+ ("When set to {\\tt true}, this flag causes the user "
+ ^ "interface to skip asking for confirmations on "
+ ^ "non-conflicting changes. (More precisely, when the user interface "
+ ^ "is done setting the propagation direction for one entry and is about "
+ ^ "to move to the next, it will skip over all non-conflicting entries "
+ ^ "and go directly to the next conflict.)" )
+
+(* This has to be here rather than in uigtk.ml, because it is part of what
+ gets sent to the server at startup *)
+let mainWindowHeight =
+ Prefs.createInt "height" 15
+ "!height (in lines) of main window in graphical interface"
+ ("Used to set the height (in lines) of the main window in the graphical "
+ ^ "user interface.")
+
+let expert =
+ Prefs.createBool "expert" false
+ "*Enable some developers-only functionality in the UI" ""
+
+let profileLabel =
+ Prefs.createString "label" ""
+ "!provide a descriptive string label for this profile"
+ ("Used in a profile to provide a descriptive string documenting its "
+ ^ "settings. (This is useful for users that switch between several "
+ ^ "profiles, especially using the `fast switch' feature of the "
+ ^ "graphical user interface.)")
+
+let profileKey =
+ Prefs.createString "key" ""
+ "!define a keyboard shortcut for this profile (in some UIs)"
+ ("Used in a profile to define a numeric key (0-9) that can be used in "
+ ^ "the graphical user interface to switch immediately to this profile.")
+(* This preference is not actually referred to in the code anywhere, since
+ the keyboard shortcuts are constructed by a separate scan of the preference
+ file in uigtk.ml, but it must be present to prevent the preferences module
+ from complaining about 'key = n' lines in profiles. *)
+
+let contactquietly =
+ Prefs.createBool "contactquietly" false
+ "!suppress the 'contacting server' message during startup"
+ ("If this flag is set, Unison will skip displaying the "
+ ^ "`Contacting server' message (which some users find annoying) "
+ ^ "during startup.")
+
+let contactingServerMsg () =
+ Printf.sprintf "Contacting server..."
+
+let repeat =
+ Prefs.createString "repeat" ""
+ "!synchronize repeatedly (text interface only)"
+ ("Setting this preference causes the text-mode interface to synchronize "
+ ^ "repeatedly, rather than doing it just once and stopping. If the "
+ ^ "argument is a number, Unison will pause for that many seconds before "
+ ^ "beginning again.")
+
+(* ^ "If the argument is a path, Unison will wait for the "
+ ^ "file at this path---called a {\\em changelog}---to "
+ ^ "be modified (on either the client or the server "
+ ^ "machine), read the contents of the changelog (which should be a newline-"
+ ^ "separated list of paths) on both client and server, "
+ ^ "combine the results, "
+ ^ "and start again, using the list of paths read from the changelogs as the "
+ ^ " '-path' preference for the new run. The idea is that an external "
+ ^ "process will watch the filesystem and, when it thinks something may have "
+ ^ "changed, write the changed pathname to its local changelog where Unison "
+ ^ "will find it the next time it looks. If the changelogs have not been "
+ ^ "modified, Unison will wait, checking them again every few seconds."
+*)
+
+let retry =
+ Prefs.createInt "retry" 0
+ "!re-try failed synchronizations N times (text ui only)"
+ ("Setting this preference causes the text-mode interface to try again "
+ ^ "to synchronize "
+ ^ "updated paths where synchronization fails. Each such path will be "
+ ^ "tried N times."
+ )
+
+let confirmmerge =
+ Prefs.createBool "confirmmerge" false
+ "!ask for confirmation before committing results of a merge"
+ ("Setting this preference causes both the text and graphical interfaces"
+ ^ " to ask the user if the results of a merge command may be committed "
+ ^ " to the replica or not. Since the merge command works on temporary files,"
+ ^ " the user can then cancel all the effects of applying the merge if it"
+ ^ " turns out that the result is not satisfactory. In "
+ ^ " batch-mode, this preference has no effect. Default is false.")
+
+let runTestsPrefName = "selftest"
+let runtests =
+ Prefs.createBool runTestsPrefName false
+ "!run internal tests and exit"
+ ("Run internal tests and exit. This option is mostly for developers and must be used "
+ ^ "carefully: in particular, "
+ ^ "it will delete the contents of both roots, so that it can install its own files "
+ ^ "for testing. This flag only makes sense on the command line. When it is "
+ ^ "provided, no preference file is read: all preferences must be specified on the"
+ ^ "command line. Also, since the self-test procedure involves overwriting the roots "
+ ^ "and backup directory, the names of the roots and of the backupdir preference "
+ ^ "must include the string "
+ ^ "\"test\" or else the tests will be aborted. (If these are not given "
+ ^ "on the command line, dummy "
+ ^ "subdirectories in the current directory will be created automatically.)")
+
+(* This ref is set to Test.test during initialization, avoiding a circular
+ dependency *)
+let testFunction = ref (fun () -> assert false)
+
+(**********************************************************************
+ Formatting functions
+ **********************************************************************)
+
+(* When no archives were found, we omit 'new' in status descriptions, since
+ *all* files would be marked new and this won't make sense to the user. *)
+let choose s1 s2 = if !Update.foundArchives then s1 else s2
+
+let showprev =
+ Prefs.createBool "showprev" false
+ "*Show previous properties, if they differ from current"
+ ""
+
+(* The next function produces nothing unless the "showprev"
+ preference is set. This is because it tends to make the
+ output trace too long and annoying. *)
+let prevProps newprops ui =
+ if not (Prefs.read showprev) then ""
+ else match ui with
+ NoUpdates | Error _
+ -> ""
+ | Updates (_, New) ->
+ " (new)"
+ | Updates (_, Previous(_,oldprops,_,_)) ->
+ (* || Props.similar newprops oldprops *)
+ " (was: "^(Props.toString oldprops)^")"
+
+let replicaContentDesc rc =
+ Props.toString (Props.setLength rc.desc (snd rc.size))
+
+let replicaContent2string rc sep =
+ let d s = s ^ sep ^ replicaContentDesc rc ^ prevProps rc.desc rc.ui in
+ match rc.typ, rc.status with
+ `ABSENT, `Unchanged ->
+ "absent"
+ | _, `Unchanged ->
+ "unchanged "
+ ^(Util.truncateString (Fileinfo.type2string rc.typ) 7)
+ ^ sep
+ ^ replicaContentDesc rc
+ | `ABSENT, `Deleted -> "deleted"
+ | `FILE, `Created ->
+ d (choose "new file " "file ")
+ | `FILE, `Modified ->
+ d "changed file "
+ | `FILE, `PropsChanged ->
+ d "changed props "
+ | `SYMLINK, `Created ->
+ d (choose "new symlink " "symlink ")
+ | `SYMLINK, `Modified ->
+ d "changed symlink "
+ | `DIRECTORY, `Created ->
+ d (choose "new dir " "dir ")
+ | `DIRECTORY, `Modified ->
+ d "changed dir "
+ | `DIRECTORY, `PropsChanged ->
+ d "dir props changed"
+
+ (* Some cases that can't happen... *)
+ | `ABSENT, (`Created | `Modified | `PropsChanged)
+ | `SYMLINK, `PropsChanged
+ | (`FILE|`SYMLINK|`DIRECTORY), `Deleted ->
+ assert false
+
+let replicaContent2shortString rc =
+ match rc.typ, rc.status with
+ _, `Unchanged -> " "
+ | `ABSENT, `Deleted -> "deleted "
+ | `FILE, `Created -> choose "new file" "file "
+ | `FILE, `Modified -> "changed "
+ | `FILE, `PropsChanged -> "props "
+ | `SYMLINK, `Created -> choose "new link" "link "
+ | `SYMLINK, `Modified -> "chgd lnk"
+ | `DIRECTORY, `Created -> choose "new dir " "dir "
+ | `DIRECTORY, `Modified -> "chgd dir"
+ | `DIRECTORY, `PropsChanged -> "props "
+ (* Cases that can't happen... *)
+ | `ABSENT, (`Created | `Modified | `PropsChanged)
+ | `SYMLINK, `PropsChanged
+ | (`FILE|`SYMLINK|`DIRECTORY), `Deleted
+ -> assert false
+
+let roots2niceStrings length = function
+ (Local,fspath1), (Local,fspath2) ->
+ let name1, name2 = Fspath.differentSuffix fspath1 fspath2 in
+ (Util.truncateString name1 length, Util.truncateString name2 length)
+ | (Local,fspath1), (Remote host, fspath2) ->
+ (Util.truncateString "local" length, Util.truncateString host length)
+ | (Remote host, fspath1), (Local,fspath2) ->
+ (Util.truncateString host length, Util.truncateString "local" length)
+ | _ -> assert false (* BOGUS? *)
+
+let details2string theRi sep =
+ match theRi.replicas with
+ Problem s ->
+ Printf.sprintf "Error: %s\n" s
+ | Different {rc1 = rc1; rc2 = rc2} ->
+ let root1str, root2str =
+ roots2niceStrings 12 (Globals.roots()) in
+ Printf.sprintf "%s : %s\n%s : %s"
+ root1str (replicaContent2string rc1 sep)
+ root2str (replicaContent2string rc2 sep)
+
+let displayPath previousPath path =
+ let previousNames = Path.toNames previousPath in
+ let names = Path.toNames path in
+ if names = [] then "/" else
+ (* Strip the greatest common prefix of previousNames and names
+ from names. level is the number of names in the greatest
+ common prefix. *)
+ let rec loop level names1 names2 =
+ match (names1,names2) with
+ (hd1::tl1,hd2::tl2) ->
+ if Name.compare hd1 hd2 = 0
+ then loop (level+1) tl1 tl2
+ else (level,names2)
+ | _ -> (level,names2) in
+ let (level,suffixNames) = loop 0 previousNames names in
+ let suffixPath =
+ Safelist.fold_left Path.child Path.empty suffixNames in
+ let spaces = String.make (level*3) ' ' in
+ spaces ^ (Path.toString suffixPath)
+
+let roots2string () =
+ let replica1, replica2 = roots2niceStrings 12 (Globals.roots()) in
+ (Printf.sprintf "%s %s " replica1 replica2)
+
+type action = AError | ASkip of bool | ALtoR of bool | ARtoL of bool | AMerge
+
+let direction2action partial dir =
+ match dir with
+ Conflict -> ASkip partial
+ | Replica1ToReplica2 -> ALtoR partial
+ | Replica2ToReplica1 -> ARtoL partial
+ | Merge -> AMerge
+
+let action2niceString action =
+ match action with
+ AError -> "error"
+ | ASkip _ -> "<-?->"
+ | ALtoR false -> "---->"
+ | ALtoR true -> "--?->"
+ | ARtoL false -> "<----"
+ | ARtoL true -> "<-?--"
+ | AMerge -> "<-M->"
+
+let reconItem2stringList oldPath theRI =
+ match theRI.replicas with
+ Problem s ->
+ (" ", AError, " ", displayPath oldPath theRI.path1)
+ | Different diff ->
+ let partial = diff.errors1 <> [] || diff.errors2 <> [] in
+ (replicaContent2shortString diff.rc1,
+ direction2action partial diff.direction,
+ replicaContent2shortString diff.rc2,
+ displayPath oldPath theRI.path1)
+
+let reconItem2string oldPath theRI status =
+ let (r1, action, r2, path) = reconItem2stringList oldPath theRI in
+ Format.sprintf "%s %s %s %s %s" r1 (action2niceString action) r2 status path
+
+let exn2string = function
+ Sys.Break -> "Terminated!"
+ | Util.Fatal(s) -> Printf.sprintf "Fatal error: %s" s
+ | Util.Transient(s) -> Printf.sprintf "Error: %s" s
+ | Unix.Unix_error (err, fun_name, arg) ->
+ Printf.sprintf "Uncaught unix error: %s failed%s: %s%s"
+ fun_name
+ (if String.length arg > 0 then Format.sprintf " on \"%s\"" arg else "")
+ (Unix.error_message err)
+ (match err with
+ Unix.EUNKNOWNERR n -> Format.sprintf " (code %d)" n
+ | _ -> "")
+ | Invalid_argument s -> Printf.sprintf "Invalid argument: %s" s
+ | other -> Printf.sprintf "Uncaught exception %s" (Printexc.to_string other)
+
+(* precondition: uc = File (Updates(_, ..) on both sides *)
+let showDiffs ri printer errprinter id =
+ match ri.replicas with
+ Problem _ ->
+ errprinter
+ "Can't diff files: there was a problem during update detection"
+ | Different {rc1 = {typ = `FILE; ui = ui1}; rc2 = {typ = `FILE; ui = ui2}} ->
+ let (root1,root2) = Globals.roots() in
+ begin
+ try Files.diff root1 ri.path1 ui1 root2 ri.path2 ui2 printer id
+ with Util.Transient e -> errprinter e
+ end
+ | Different _ ->
+ errprinter "Can't diff: path doesn't refer to a file in both replicas"
+
+
+exception Synch_props of Common.reconItem
+
+(**********************************************************************
+ Common error messages
+ **********************************************************************)
+
+let dangerousPathMsg dangerousPaths =
+ if dangerousPaths = [Path.empty] then
+ "The root of one of the replicas has been completely emptied.\n\
+ Unison may delete everything in the other replica. (Set the \n\
+ 'confirmbigdel' preference to false to disable this check.)\n"
+ else
+ Printf.sprintf
+ "The following paths have been completely emptied in one replica:\n \
+ %s\n\
+ Unison may delete everything below these paths in the other replica.\n
+ (Set the 'confirmbigdel' preference to false to disable this check.)\n"
+ (String.concat "\n "
+ (Safelist.map (fun p -> "'" ^ (Path.toString p) ^ "'")
+ dangerousPaths))
+
+(**********************************************************************
+ Useful patterns for ignoring paths
+ **********************************************************************)
+
+let quote s =
+ let len = String.length s in
+ let buf = String.create (2 * len) in
+ let pos = ref 0 in
+ for i = 0 to len - 1 do
+ match s.[i] with
+ '*' | '?' | '[' | '{' | '}' | ',' | '\\' as c ->
+ buf.[!pos] <- '\\'; buf.[!pos + 1] <- c; pos := !pos + 2
+ | c ->
+ buf.[!pos] <- c; pos := !pos + 1
+ done;
+ "{" ^ String.sub buf 0 !pos ^ "}"
+
+let ignorePath path = "Path " ^ quote (Path.toString path)
+
+let ignoreName path =
+ match Path.finalName path with
+ Some name -> "Name " ^ quote (Name.toString name)
+ | None -> assert false
+
+let ignoreExt path =
+ match Path.finalName path with
+ Some name ->
+ let str = Name.toString name in
+ begin try
+ let pos = String.rindex str '.' in
+ let ext = String.sub str pos (String.length str - pos) in
+ "Name {,.}*" ^ quote ext
+ with Not_found -> (* str does not contain '.' *)
+ "Name " ^ quote str
+ end
+ | None ->
+ assert false
+
+let addIgnorePattern theRegExp =
+ if theRegExp = "Path " then
+ raise (Util.Transient "Can't ignore the root path!");
+ Globals.addRegexpToIgnore theRegExp;
+ let r = Prefs.add "ignore" theRegExp in
+ Trace.status r;
+ (* Make sure the server has the same ignored paths (in case, for
+ example, we do a "rescan") *)
+ Lwt_unix.run (Globals.propagatePrefs ())
+
+(**********************************************************************
+ Profile and command-line parsing
+ **********************************************************************)
+
+let coreUsageMsg =
+ "Usage: " ^ Uutil.myName
+ ^ " [options]\n"
+ ^ " or " ^ Uutil.myName
+ ^ " root1 root2 [options]\n"
+ ^ " or " ^ Uutil.myName
+ ^ " profilename [options]\n"
+
+let shortUsageMsg =
+ coreUsageMsg ^ "\n"
+ ^ "For a list of options, type \"" ^ Uutil.myName ^ " -help\".\n"
+ ^ "For a tutorial on basic usage, type \"" ^ Uutil.myName
+ ^ " -doc tutorial\".\n"
+ ^ "For other documentation, type \"" ^ Uutil.myName ^ " -doc topics\".\n"
+
+let usageMsg = coreUsageMsg
+
+let debug = Trace.debug "startup"
+
+(* ---- *)
+
+(*FIX: remove when Unison version > 2.40 *)
+let _ =
+Remote.registerRootCmd "_unicodeCaseSensitive_" (fun _ -> Lwt.return ())
+let supportUnicodeCaseSensitive () =
+ if Uutil.myMajorVersion > "2.40" (* The test is correct until 2.99... *) then
+ Lwt.return true
+ else begin
+ Globals.allRootsMap
+ (fun r -> Remote.commandAvailable r "_unicodeCaseSensitive_")
+ >>= fun l ->
+ Lwt.return (List.for_all (fun x -> x) l)
+ end
+
+(* Determine the case sensitivity of a root (does filename FOO==foo?) *)
+let architecture =
+ Remote.registerRootCmd
+ "architecture"
+ (fun (_,()) -> return (Util.osType = `Win32, Osx.isMacOSX, Util.isCygwin))
+
+(* During startup the client determines the case sensitivity of each root.
+ If any root is case insensitive, all roots must know this -- it's
+ propagated in a pref. Also, detects HFS (needed for resource forks) and
+ Windows (needed for permissions) and does some sanity checking. *)
+let validateAndFixupPrefs () =
+ Props.validatePrefs();
+ let supportUnicodeCaseSensitive = supportUnicodeCaseSensitive () in
+ Globals.allRootsMap (fun r -> architecture r ()) >>= (fun archs ->
+ supportUnicodeCaseSensitive >>= fun unicodeCS ->
+ let someHostIsRunningWindows =
+ Safelist.exists (fun (isWin, _, _) -> isWin) archs in
+ let allHostsAreRunningWindows =
+ Safelist.for_all (fun (isWin, _, _) -> isWin) archs in
+ let someHostIsRunningBareWindows =
+ Safelist.exists (fun (isWin, _, isCyg) -> isWin && not isCyg) archs in
+ let someHostRunningOsX =
+ Safelist.exists (fun (_, isOSX, _) -> isOSX) archs in
+ let someHostIsCaseInsensitive =
+ someHostIsRunningWindows || someHostRunningOsX in
+ if Prefs.read Globals.fatFilesystem then begin
+ Prefs.overrideDefault Props.permMask 0;
+ Prefs.overrideDefault Props.dontChmod true;
+ Prefs.overrideDefault Case.caseInsensitiveMode `True;
+ Prefs.overrideDefault Fileinfo.allowSymlinks `False;
+ Prefs.overrideDefault Fileinfo.ignoreInodeNumbers true
+ end;
+ Case.init someHostIsCaseInsensitive (someHostRunningOsX && unicodeCS);
+ Props.init someHostIsRunningWindows;
+ Osx.init someHostRunningOsX;
+ Fileinfo.init someHostIsRunningBareWindows;
+ Prefs.set Globals.someHostIsRunningWindows someHostIsRunningWindows;
+ Prefs.set Globals.allHostsAreRunningWindows allHostsAreRunningWindows;
+ return ())
+
+(* ---- *)
+
+let promptForRoots getFirstRoot getSecondRoot =
+ (* Ask the user for the roots *)
+ let r1 = match getFirstRoot() with None -> exit 0 | Some r -> r in
+ let r2 = match getSecondRoot() with None -> exit 0 | Some r -> r in
+ (* Remember them for this run, ordering them so that the first
+ will come out on the left in the UI *)
+ Globals.setRawRoots [r1; r2];
+ (* Save them in the current profile *)
+ ignore (Prefs.add "root" r1);
+ ignore (Prefs.add "root" r2)
+
+(* ---- *)
+
+(* The first time we load preferences, we also read the command line
+ arguments; if we re-load prefs (because the user selected a new profile)
+ we ignore the command line *)
+let firstTime = ref(true)
+
+(* Roots given on the command line *)
+let cmdLineRawRoots = ref []
+
+(* BCP: WARNING: Some of the code from here is duplicated in uimacbridge...! *)
+let initPrefs ~profileName ~displayWaitMessage ~getFirstRoot ~getSecondRoot
+ ~termInteract =
+ (* Restore prefs to their default values, if necessary *)
+ if not !firstTime then Prefs.resetToDefaults();
+ Globals.setRawRoots !cmdLineRawRoots;
+
+ (* Tell the preferences module the name of the profile *)
+ Prefs.profileName := Some(profileName);
+
+ (* Check whether the -selftest flag is present on the command line *)
+ let testFlagPresent =
+ Util.StringMap.mem runTestsPrefName (Prefs.scanCmdLine usageMsg) in
+
+ (* If the -selftest flag is present, then we skip loading the preference file.
+ (This is prevents possible confusions where settings from a preference
+ file could cause unit tests to fail.) *)
+ if not testFlagPresent then begin
+ (* If the profile does not exist, create an empty one (this should only
+ happen if the profile is 'default', since otherwise we will already
+ have checked that the named one exists). *)
+ if not(System.file_exists (Prefs.profilePathname profileName)) then
+ Prefs.addComment "Unison preferences file";
+
+ (* Load the profile *)
+ (debug (fun() -> Util.msg "about to load prefs");
+ Prefs.loadTheFile());
+
+ (* Now check again that the -selftest flag has not been set, and barf otherwise *)
+ if Prefs.read runtests then raise (Util.Fatal
+ "The 'test' flag should only be given on the command line")
+ end;
+
+ (* Parse the command line. This will override settings from the profile. *)
+ (* JV (6/09): always reparse the command line *)
+ if true (*!firstTime*) then begin
+ debug (fun() -> Util.msg "about to parse command line");
+ Prefs.parseCmdLine usageMsg;
+ end;
+
+ (* Install dummy roots and backup directory if we are running self-tests *)
+ if Prefs.read runtests then begin
+ if Globals.rawRoots() = [] then
+ Prefs.loadStrings ["root = test-a.tmp"; "root = test-b.tmp"];
+ if (Prefs.read Stasher.backupdir) = "" then
+ Prefs.loadStrings ["backupdir = test-backup.tmp"];
+ end;
+
+ (* Print the preference settings *)
+ debug (fun() -> Prefs.dumpPrefsToStderr() );
+
+ (* If no roots are given either on the command line or in the profile,
+ ask the user *)
+ if Globals.rawRoots() = [] then begin
+ promptForRoots getFirstRoot getSecondRoot;
+ end;
+
+ Recon.checkThatPreferredRootIsValid();
+
+ (* The following step contacts the server, so warn the user it could take
+ some time *)
+ if not (Prefs.read contactquietly || Prefs.read Trace.terse) then
+ displayWaitMessage();
+
+ (* Canonize the names of the roots, sort them (with local roots first),
+ and install them in Globals. *)
+ Lwt_unix.run (Globals.installRoots termInteract);
+
+ (* If both roots are local, disable the xferhint table to save time *)
+ begin match Globals.roots() with
+ ((Local,_),(Local,_)) -> Prefs.set Xferhint.xferbycopying false
+ | _ -> ()
+ end;
+
+ (* FIX: This should be before Globals.installRoots *)
+ (* Check to be sure that there is at most one remote root *)
+ let numRemote =
+ Safelist.fold_left
+ (fun n (w,_) -> match w with Local -> n | Remote _ -> n+1)
+ 0
+ (Globals.rootsList()) in
+ if numRemote > 1 then
+ raise(Util.Fatal "cannot synchronize more than one remote root");
+
+ (* If no paths were specified, then synchronize the whole replicas *)
+ if Prefs.read Globals.paths = [] then Prefs.set Globals.paths [Path.empty];
+
+ (* Expand any "wildcard" paths [with final component *] *)
+ Globals.expandWildcardPaths();
+
+ Update.storeRootsName ();
+
+ if
+ numRemote > 0 && not (Prefs.read contactquietly || Prefs.read Trace.terse)
+ then
+ Util.msg "Connected [%s]\n"
+ (Util.replacesubstring (Update.getRootsName()) ", " " -> ");
+
+ debug (fun() ->
+ Printf.eprintf "Roots: \n";
+ Safelist.iter (fun clr -> Printf.eprintf " %s\n" clr)
+ (Globals.rawRoots ());
+ Printf.eprintf " i.e. \n";
+ Safelist.iter (fun clr -> Printf.eprintf " %s\n"
+ (Clroot.clroot2string (Clroot.parseRoot clr)))
+ (Globals.rawRoots ());
+ Printf.eprintf " i.e. (in canonical order)\n";
+ Safelist.iter (fun r ->
+ Printf.eprintf " %s\n" (root2string r))
+ (Globals.rootsInCanonicalOrder());
+ Printf.eprintf "\n");
+
+ Lwt_unix.run
+ (validateAndFixupPrefs () >>=
+ Globals.propagatePrefs);
+
+ (* Initializes some backups stuff according to the preferences just loaded from the profile.
+ Important to do it here, after prefs are propagated, because the function will also be
+ run on the server, if any. Also, this should be done each time a profile is reloaded
+ on this side, that's why it's here. *)
+ Stasher.initBackups ();
+
+ firstTime := false
+
+(**********************************************************************
+ Common startup sequence
+ **********************************************************************)
+
+let anonymousArgs =
+ Prefs.createStringList "rest"
+ "*roots or profile name" ""
+
+let testServer =
+ Prefs.createBool "testserver" false
+ "exit immediately after the connection to the server"
+ ("Setting this flag on the command line causes Unison to attempt to "
+ ^ "connect to the remote server and, if successful, print a message "
+ ^ "and immediately exit. Useful for debugging installation problems. "
+ ^ "Should not be set in preference files.")
+
+(* For backward compatibility *)
+let _ = Prefs.alias testServer "testServer"
+
+(* ---- *)
+
+let uiInit
+ ~(reportError : string -> unit)
+ ~(tryAgainOrQuit : string -> bool)
+ ~(displayWaitMessage : unit -> unit)
+ ~(getProfile : unit -> string option)
+ ~(getFirstRoot : unit -> string option)
+ ~(getSecondRoot : unit -> string option)
+ ~(termInteract : (string -> string -> string) option) =
+
+ (* Make sure we have a directory for archives and profiles *)
+ Os.createUnisonDir();
+
+ (* Extract any command line profile or roots *)
+ let clprofile = ref None in
+ begin
+ try
+ let args = Prefs.scanCmdLine usageMsg in
+ match Util.StringMap.find "rest" args with
+ [] -> ()
+ | [profile] -> clprofile := Some profile
+ | [root2;root1] -> cmdLineRawRoots := [root1;root2]
+ | [root2;root1;profile] ->
+ cmdLineRawRoots := [root1;root2];
+ clprofile := Some profile
+ | _ ->
+ (reportError(Printf.sprintf
+ "%s was invoked incorrectly (too many roots)" Uutil.myName);
+ exit 1)
+ with Not_found -> ()
+ end;
+
+ (* Print header for debugging output *)
+ debug (fun() ->
+ Printf.eprintf "%s, version %s\n\n" Uutil.myName Uutil.myVersion);
+ debug (fun() -> Util.msg "initializing UI");
+
+ debug (fun () ->
+ (match !clprofile with
+ None -> Util.msg "No profile given on command line"
+ | Some s -> Printf.eprintf "Profile '%s' given on command line" s);
+ (match !cmdLineRawRoots with
+ [] -> Util.msg "No roots given on command line"
+ | [root1;root2] ->
+ Printf.eprintf "Roots '%s' and '%s' given on command line"
+ root1 root2
+ | _ -> assert false));
+
+ let profileName =
+ begin match !clprofile with
+ None ->
+ let clroots_given = !cmdLineRawRoots <> [] in
+ let n =
+ if not(clroots_given) then begin
+ (* Ask the user to choose a profile or create a new one. *)
+ clprofile := getProfile();
+ match !clprofile with
+ None -> exit 0 (* None means the user wants to quit *)
+ | Some x -> x
+ end else begin
+ (* Roots given on command line.
+ The profile should be the default. *)
+ clprofile := Some "default";
+ "default"
+ end in
+ n
+ | Some n ->
+ let f = Prefs.profilePathname n in
+ if not(System.file_exists f)
+ then (reportError (Printf.sprintf "Profile %s does not exist"
+ (System.fspathToPrintString f));
+ exit 1);
+ n
+ end in
+
+ (* Load the profile and command-line arguments *)
+ initPrefs
+ profileName displayWaitMessage getFirstRoot getSecondRoot termInteract;
+
+ (* Turn on GC messages, if the '-debug gc' flag was provided *)
+ if Trace.enabled "gc" then Gc.set {(Gc.get ()) with Gc.verbose = 0x3F};
+
+ if Prefs.read testServer then exit 0;
+
+ (* BCPFIX: Should/can this be done earlier?? *)
+ Files.processCommitLogs();
+
+ (* Run unit tests if requested *)
+ if Prefs.read runtests then begin
+ (!testFunction)();
+ exit 0
+ end
+
+(* Exit codes *)
+let perfectExit = 0 (* when everything's okay *)
+let skippyExit = 1 (* when some items were skipped, but no failure occurred *)
+let failedExit = 2 (* when there's some non-fatal failure *)
+let fatalExit = 3 (* when fatal failure occurred *)
+let exitCode = function
+ (false, false) -> 0
+ | (true, false) -> 1
+ | _ -> 2
+(* (anySkipped?, anyFailure?) -> exit code *)
Deleted: branches/2.45/src/uicommon.mli
===================================================================
--- trunk/src/uicommon.mli 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/src/uicommon.mli 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,117 +0,0 @@
-(* Unison file synchronizer: src/uicommon.mli *)
-(* Copyright 1999-2012, Benjamin C. Pierce (see COPYING for details) *)
-
-(* Kinds of UI *)
-type interface =
- Text
- | Graphic
-
-(* The interface of a concrete UI implementation *)
-module type UI =
-sig
- val start : interface -> unit
- val defaultUi : interface
-end
-
-(* User preference: when true, ask fewer questions *)
-val auto : bool Prefs.t
-
-(* User preference: How tall to make the main window in the GTK ui *)
-val mainWindowHeight : int Prefs.t
-
-(* User preference: Expert mode *)
-val expert : bool Prefs.t
-
-(* User preference: Whether to display 'contacting server' message *)
-val contactquietly : bool Prefs.t
-
-(* User preference: The 'contacting server' message itself *)
-val contactingServerMsg : unit -> string
-
-(* User preference: Descriptive label for this profile *)
-val profileLabel : string Prefs.t
-
-(* User preference: Synchronize repeatedly *)
-val repeat : string Prefs.t
-
-(* User preference: Try failing paths N times *)
-val retry : int Prefs.t
-
-(* User preference: confirmation before commiting merge results *)
-val confirmmerge : bool Prefs.t
-
-(* Format the information about current contents of a path in one replica (the second argument
- is used as a separator) *)
-val details2string : Common.reconItem -> string -> string
-
-(* Format a path, eliding initial components that are the same as the
- previous path *)
-val displayPath : Path.t -> Path.t -> string
-
-(* Format the names of the roots for display at the head of the
- corresponding columns in the UI *)
-val roots2string : unit -> string
-
-(* Format a reconItem (and its status string) for display, eliding
- initial components that are the same as the previous path *)
-val reconItem2string : Path.t -> Common.reconItem -> string -> string
-
-type action = AError | ASkip of bool | ALtoR of bool | ARtoL of bool | AMerge
-
-(* Same as previous function, but returns a tuple of strings *)
-val reconItem2stringList :
- Path.t -> Common.reconItem -> string * action * string * string
-
-(* Format an exception for display *)
-val exn2string : exn -> string
-
-(* Calculate and display differences for a file *)
-val showDiffs :
- Common.reconItem (* what path *)
- -> (string->string->unit) (* how to display the (title and) result *)
- -> (string->unit) (* how to display errors *)
- -> Uutil.File.t (* id for transfer progress reports *)
- -> unit
-
-val dangerousPathMsg : Path.t list -> string
-
-(* Utilities for adding ignore patterns *)
-val ignorePath : Path.t -> string
-val ignoreName : Path.t -> string
-val ignoreExt : Path.t -> string
-val addIgnorePattern : string -> unit
-
-val usageMsg : string
-
-val shortUsageMsg : string
-
-val uiInit :
- reportError:(string -> unit) ->
- tryAgainOrQuit:(string -> bool) ->
- displayWaitMessage:(unit -> unit) ->
- getProfile:(unit -> string option) ->
- getFirstRoot:(unit -> string option) ->
- getSecondRoot:(unit -> string option) ->
- termInteract:(string -> string -> string) option ->
- unit
-
-val initPrefs :
- profileName:string ->
- displayWaitMessage:(unit->unit) ->
- getFirstRoot:(unit->string option) ->
- getSecondRoot:(unit->string option) ->
- termInteract:(string -> string -> string) option ->
- unit
-
-val validateAndFixupPrefs : unit -> unit Lwt.t
-
-(* Exit codes *)
-val perfectExit: int (* when everything's okay *)
-val skippyExit: int (* when some items were skipped, but no failure occurred *)
-val failedExit: int (* when there's some non-fatal failure *)
-val fatalExit: int (* when fatal failure occurred *)
-val exitCode: bool * bool -> int
-(* (anySkipped?, anyFailure?) -> exit code *)
-
-(* Initialization *)
-val testFunction : (unit->unit) ref
Copied: branches/2.45/src/uicommon.mli (from rev 486, trunk/src/uicommon.mli)
===================================================================
--- branches/2.45/src/uicommon.mli (rev 0)
+++ branches/2.45/src/uicommon.mli 2012-04-02 15:54:47 UTC (rev 487)
@@ -0,0 +1,117 @@
+(* Unison file synchronizer: src/uicommon.mli *)
+(* Copyright 1999-2012, Benjamin C. Pierce (see COPYING for details) *)
+
+(* Kinds of UI *)
+type interface =
+ Text
+ | Graphic
+
+(* The interface of a concrete UI implementation *)
+module type UI =
+sig
+ val start : interface -> unit
+ val defaultUi : interface
+end
+
+(* User preference: when true, ask fewer questions *)
+val auto : bool Prefs.t
+
+(* User preference: How tall to make the main window in the GTK ui *)
+val mainWindowHeight : int Prefs.t
+
+(* User preference: Expert mode *)
+val expert : bool Prefs.t
+
+(* User preference: Whether to display 'contacting server' message *)
+val contactquietly : bool Prefs.t
+
+(* User preference: The 'contacting server' message itself *)
+val contactingServerMsg : unit -> string
+
+(* User preference: Descriptive label for this profile *)
+val profileLabel : string Prefs.t
+
+(* User preference: Synchronize repeatedly *)
+val repeat : string Prefs.t
+
+(* User preference: Try failing paths N times *)
+val retry : int Prefs.t
+
+(* User preference: confirmation before committing merge results *)
+val confirmmerge : bool Prefs.t
+
+(* Format the information about current contents of a path in one replica (the second argument
+ is used as a separator) *)
+val details2string : Common.reconItem -> string -> string
+
+(* Format a path, eliding initial components that are the same as the
+ previous path *)
+val displayPath : Path.t -> Path.t -> string
+
+(* Format the names of the roots for display at the head of the
+ corresponding columns in the UI *)
+val roots2string : unit -> string
+
+(* Format a reconItem (and its status string) for display, eliding
+ initial components that are the same as the previous path *)
+val reconItem2string : Path.t -> Common.reconItem -> string -> string
+
+type action = AError | ASkip of bool | ALtoR of bool | ARtoL of bool | AMerge
+
+(* Same as previous function, but returns a tuple of strings *)
+val reconItem2stringList :
+ Path.t -> Common.reconItem -> string * action * string * string
+
+(* Format an exception for display *)
+val exn2string : exn -> string
+
+(* Calculate and display differences for a file *)
+val showDiffs :
+ Common.reconItem (* what path *)
+ -> (string->string->unit) (* how to display the (title and) result *)
+ -> (string->unit) (* how to display errors *)
+ -> Uutil.File.t (* id for transfer progress reports *)
+ -> unit
+
+val dangerousPathMsg : Path.t list -> string
+
+(* Utilities for adding ignore patterns *)
+val ignorePath : Path.t -> string
+val ignoreName : Path.t -> string
+val ignoreExt : Path.t -> string
+val addIgnorePattern : string -> unit
+
+val usageMsg : string
+
+val shortUsageMsg : string
+
+val uiInit :
+ reportError:(string -> unit) ->
+ tryAgainOrQuit:(string -> bool) ->
+ displayWaitMessage:(unit -> unit) ->
+ getProfile:(unit -> string option) ->
+ getFirstRoot:(unit -> string option) ->
+ getSecondRoot:(unit -> string option) ->
+ termInteract:(string -> string -> string) option ->
+ unit
+
+val initPrefs :
+ profileName:string ->
+ displayWaitMessage:(unit->unit) ->
+ getFirstRoot:(unit->string option) ->
+ getSecondRoot:(unit->string option) ->
+ termInteract:(string -> string -> string) option ->
+ unit
+
+val validateAndFixupPrefs : unit -> unit Lwt.t
+
+(* Exit codes *)
+val perfectExit: int (* when everything's okay *)
+val skippyExit: int (* when some items were skipped, but no failure occurred *)
+val failedExit: int (* when there's some non-fatal failure *)
+val fatalExit: int (* when fatal failure occurred *)
+val exitCode: bool * bool -> int
+(* (anySkipped?, anyFailure?) -> exit code *)
+
+(* Initialization *)
+val testFunction : (unit->unit) ref
Deleted: branches/2.45/src/uimacnew09/MyController.m
===================================================================
--- trunk/src/uimacnew09/MyController.m 2012-03-10 16:12:51 UTC (rev 485)
+++ branches/2.45/src/uimacnew09/MyController.m 2012-04-02 15:54:47 UTC (rev 487)
@@ -1,1213 +0,0 @@
-/* Copyright (c) 2003, see file COPYING for details. */
-
-#import "MyController.h"
-
-/* The following two define are a workaround for an incompatibility between
-Ocaml 3.11.2 (and older) and the Mac OS X header files */
-#define uint64 uint64_caml
-#define int64 int64_caml
-
-#define CAML_NAME_SPACE
-#include <caml/callback.h>
-#include <caml/alloc.h>
-#include <caml/mlvalues.h>
-#include <caml/memory.h>
-
- at interface NSString (_UnisonUtil)
-- (NSString *)trim;
- at end
-
- at implementation MyController
-
-static MyController *me; // needed by reloadTable and displayStatus, below
-
-// BCP (11/09): Added per Onne Gorter:
-// if user closes main window, terminate app, instead of keeping an empty app around with no window
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
- return YES;
-}
-
-- (id)init
-{
- if (([super init])) {
-
- /* Initialize locals */
- me = self;
- doneFirstDiff = NO;
-
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
- /* By default, invite user to install cltool */
- @"YES", @"CheckCltool",
- @"NO", @"openProfileAtStartup",
- @"", @"profileToOpen",
- @"NO", @"deleteLogOnExit",
- @"", @"detailsFont",
- @"", @"diffFont",
- nil];
-
- [defaults registerDefaults:appDefaults];
- fontChangeTarget = nil;
- }
-
- return self;
-}
-
-- (void) applicationWillTerminate:(NSNotification *)aNotification {
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- [defaults setObject:[NSArchiver archivedDataWithRootObject:[detailsTextView font]] forKey:@"detailsFont"];
- [defaults setObject:[NSArchiver archivedDataWithRootObject:[diffView font]] forKey:@"diffFont"];
- [defaults synchronize];
-}
-
-- (void)awakeFromNib
-{
- [splitView setAutosaveName:@"splitView"];
-
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSFont *defaultFont = [NSFont fontWithName:@"Monaco" size:11];
- NSData *detailsFontData = [defaults dataForKey:@"detailsFont"];
- if (detailsFontData) {
- NSFont *tmpFont = (NSFont*) [NSUnarchiver unarchiveObjectWithData:detailsFontData];
- if (tmpFont)
- [detailsTextView setFont:tmpFont];
- else
- [detailsTextView setFont:defaultFont];
- } else
- [detailsTextView setFont:defaultFont];
-
- NSData *diffFontData = [defaults dataForKey:@"diffFont"];
- if (diffFontData) {
- NSFont *tmpFont = (NSFont*) [NSUnarchiver unarchiveObjectWithData:diffFontData];
- if (tmpFont)
- [diffView setFont:tmpFont];
- else
- [diffView setFont:defaultFont];
- } else
- [diffView setFont:defaultFont];
-
- blankView = [[NSView alloc] init];
-
- /* Double clicking in the profile list will open the profile */
- [[profileController tableView] setTarget:self];
- [[profileController tableView] setDoubleAction:@selector(openButton:)];
-
- [tableView setAutoresizesOutlineColumn:NO];
-
- // use combo-cell for path
- [[tableView tableColumnWithIdentifier:@"path"] setDataCell:[[[ImageAndTextCell alloc] init] autorelease]];
-
- // Custom progress cell
- ProgressCell *progressCell = [[[ProgressCell alloc] init] autorelease];
- [[tableView tableColumnWithIdentifier:@"percentTransferred"] setDataCell:progressCell];
-
- /* Set up the version string in the about box. We use a custom
- about box just because PRCS doesn't seem capable of getting the
- version into the InfoPlist.strings file; otherwise we'd use the
- standard about box. */
- [versionText setStringValue:ocamlCall("S", "unisonGetVersion")];
-
- /* Command-line processing */
- OCamlValue *clprofile = (id)ocamlCall("@", "unisonInit0");
-
- BOOL areRootsSet = (long)ocamlCall("i", "areRootsSet") ? YES : NO;
- if (areRootsSet) {
- NSLog(@"Roots are on the command line");
- }
- else {
- NSLog(@"Roots are not set on the command line");
- }
-
- /* Add toolbar */
- toolbar = [[[UnisonToolbar alloc]
- initWithIdentifier: @"unisonToolbar" :self :tableView] autorelease];
- [mainWindow setToolbar: toolbar];
- [toolbar takeTableModeView:tableModeSelector];
- [self initTableMode];
-
-
- /* Set up the first window the user will see */
- if (clprofile) {
- /* A profile name was given on the command line */
- NSString *profileName = [clprofile getField:0 withType:'S'];
- [self profileSelected:profileName];
-
- /* If invoked from terminal we need to bring the app to the front */
- [NSApp activateIgnoringOtherApps:YES];
-
- /* Start the connection */
- [self connect:profileName];
- }
- else if (areRootsSet) {
- /* If invoked from terminal we need to bring the app to the front */
- [NSApp activateIgnoringOtherApps:YES];
- /* Start the connection with the empty profile name, indicating roots only */
- [self connect:@""];
- }
- else {
- /* If invoked from terminal we need to bring the app to the front */
- [NSApp activateIgnoringOtherApps:YES];
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"openProfileAtStartup"]) {
- NSString *profileToOpen = [[NSUserDefaults standardUserDefaults]
- stringForKey:@"profileToOpen"];
- if ([[profileToOpen trim] compare:@""] != NSOrderedSame &&
- [[profileController getProfiles] indexOfObject:profileToOpen] != NSNotFound) {
- [self profileSelected:profileToOpen];
- [self connect:profileToOpen];
- } else {
- /* Bring up the dialog to choose a profile */
- [self chooseProfiles];
- }
- } else {
- /* Bring up the dialog to choose a profile */
- [self chooseProfiles];
- }
- }
-
- [mainWindow display];
- [mainWindow makeKeyAndOrderFront:nil];
-
- /* unless user has clicked Don't ask me again, ask about cltool */
- if ( ([[NSUserDefaults standardUserDefaults] boolForKey:@"CheckCltool"]) &&
- (![[NSFileManager defaultManager]
- fileExistsAtPath:@"/usr/bin/unison"]) )
- [self raiseCltoolWindow:nil];
-}
-
-- (IBAction) checkOpenProfileChanged:(id)sender {
- [profileBox setEnabled:[checkOpenProfile state]];
- if ([profileBox isEnabled] && [profileBox indexOfSelectedItem] < 0) {
- [profileBox selectItemAtIndex:0];
- [[NSUserDefaults standardUserDefaults] setObject:[profileBox itemObjectValueAtIndex:0] forKey:@"profileToOpen"];
- }
-}
-
-- (IBAction) chooseFont:(id)sender {
- [[NSFontPanel sharedFontPanel] makeKeyAndOrderFront:self];
- [[NSFontManager sharedFontManager] setDelegate:self];
- fontChangeTarget = sender;
-}
-
-- (void) changeFont:(id)sender {
- NSFont *newFont = [sender convertFont:[detailsTextView font]];
- if (fontChangeTarget == chooseDetailsFont)
- [detailsTextView setFont:newFont];
- else if (fontChangeTarget == chooseDiffFont)
- [diffView setFont:newFont];
- [self updateFontDisplay];
-}
-
-- (void) updateFontDisplay {
- NSFont *detailsFont = [detailsTextView font];
- NSFont *diffFont = [diffView font];
- [detailsFontLabel setStringValue:[NSString stringWithFormat:@"%@ : %d", [detailsFont displayName], (NSInteger) [detailsFont pointSize]]];
- [diffFontLabel setStringValue:[NSString stringWithFormat:@"%@ : %d", [diffFont displayName], (NSInteger) [diffFont pointSize]]];
-}
-
-- (void)chooseProfiles
-{
- [mainWindow setContentView:blankView];
- [self resizeWindowToSize:[chooseProfileView frame].size];
- [mainWindow setContentMinSize:
- NSMakeSize(NSWidth([[mainWindow contentView] frame]),150)];
- [mainWindow setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- [mainWindow setContentView:chooseProfileView];
- [toolbar setView:@"chooseProfileView"];
- [mainWindow setTitle:@"Unison"];
-
- // profiles get keyboard input
- [mainWindow makeFirstResponder:[profileController tableView]];
- [chooseProfileView display];
-}
-
-- (IBAction)createButton:(id)sender
-{
- [preferencesController reset];
- [mainWindow setContentView:blankView];
- [self resizeWindowToSize:[preferencesView frame].size];
- [mainWindow setContentMinSize:
- NSMakeSize(400,NSHeight([[mainWindow contentView] frame]))];
- [mainWindow setContentMaxSize:
- NSMakeSize(FLT_MAX,NSHeight([[mainWindow contentView] frame]))];
- [mainWindow setContentView:preferencesView];
- [toolbar setView:@"preferencesView"];
-}
-
-- (IBAction)saveProfileButton:(id)sender
-{
- if ([preferencesController validatePrefs]) {
- // so the list contains the new profile
- [profileController initProfiles];
- [self chooseProfiles];
- }
-}
-
-- (IBAction)cancelProfileButton:(id)sender
-{
- [self chooseProfiles];
-}
-
-/* Only valid once a profile has been selected */
-- (NSString *)profile {
- return myProfile;
-}
-
-- (void)profileSelected:(NSString *)aProfile
-{
- [aProfile retain];
- [myProfile release];
- myProfile = aProfile;
- [mainWindow setTitle: [NSString stringWithFormat:@"Unison: %@", myProfile]];
-}
-
-- (IBAction)showPreferences:(id)sender {
- [profileBox removeAllItems];
- [profileBox addItemsWithObjectValues:[profileController getProfiles]];
- NSUInteger index = [[profileController getProfiles] indexOfObject:
- [[NSUserDefaults standardUserDefaults]
- stringForKey:@"profileToOpen"]];
- if (index == NSNotFound) {
- [checkOpenProfile setState:NSOffState];
- [profileBox setStringValue:@""];
- } else
- [profileBox selectItemAtIndex:index];
-
- [profileBox setEnabled:[checkOpenProfile state]];
- if ([profileBox isEnabled] && [profileBox indexOfSelectedItem] < 0)
- [profileBox selectItemAtIndex:0];
-
- [self updateFontDisplay];
-
- [self raiseWindow:preferencesWindow];
-}
-
-- (IBAction)restartButton:(id)sender
-{
- [tableView setEditable:NO];
- [self chooseProfiles];
-}
-
-- (IBAction)rescan:(id)sender
-{
- /* There is a delay between turning off the button and it
- actually being disabled. Make sure we don't respond. */
- if ([self validateItem:@selector(rescan:)]) {
- waitingForPassword = NO;
- [self afterOpen];
- }
-}
-
-- (IBAction)openButton:(id)sender
-{
- NSString *profile = [profileController selected];
- [self profileSelected:profile];
- [self connect:profile];
- return;
-}
-
-- (void)updateToolbar
-{
- [toolbar validateVisibleItems];
- [tableModeSelector setEnabled:((syncable && !duringSync) || afterSync)];
-
- // Why?
- [updatesView setNeedsDisplay:YES];
-}
-
-- (void)updateTableViewWithReset:(BOOL)shouldResetSelection
-{
- [tableView reloadData];
- if (shouldResetSelection) {
- [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
- shouldResetSelection = NO;
- }
- [updatesView setNeedsDisplay:YES];
-}
-
-- (void)updateProgressBar:(NSNumber *)newProgress
-{
- // NSLog(@"Updating progress bar: %i - %i", (int)[newProgress doubleValue], (int)[progressBar doubleValue]);
- [progressBar incrementBy:([newProgress doubleValue] - [progressBar doubleValue])];
-}
-
-- (void)updateTableViewSelection
-{
- int n = [tableView numberOfSelectedRows];
- if (n == 1) [self displayDetails:[tableView itemAtRow:[tableView selectedRow]]];
- else [self clearDetails];
-}
-
-- (void)outlineViewSelectionDidChange:(NSNotification *)note
-{
- [self updateTableViewSelection];
-}
-
-- (void)connect:(NSString *)profileName
-{
- // contact server, propagate prefs
- NSLog(@"Connecting to %@...", profileName);
-
- // Switch to ConnectingView
- [mainWindow setContentView:blankView];
- [self resizeWindowToSize:[updatesView frame].size];
- [mainWindow setContentMinSize:NSMakeSize(150,150)];
- [mainWindow setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- [mainWindow setContentView:ConnectingView];
- [toolbar setView:@"connectingView"];
-
- // Update (almost) immediately
- [ConnectingView display];
- [connectingAnimation startAnimation:self];
-
- syncable = NO;
- afterSync = NO;
-
- [self updateToolbar];
-
- // will spawn thread on OCaml side and callback when complete
- (void)ocamlCall("xS", "unisonInit1", profileName);
-}
-
-CAMLprim value unisonInit1Complete(value v)
-{
- id pool = [[NSAutoreleasePool alloc] init];
- if (v == Val_unit) {
- NSLog(@"Connected.");
- [me->connectingAnimation stopAnimation:me];
- [me->preconn release];
- me->preconn = NULL;
- [me performSelectorOnMainThread:@selector(afterOpen:) withObject:nil waitUntilDone:FALSE];
- } else {
- // prompting required
- me->preconn = [[OCamlValue alloc] initWithValue:Field(v,0)]; // value of Some
- [me performSelectorOnMainThread:@selector(unisonInit1Complete:) withObject:nil waitUntilDone:FALSE];
- }
- [pool release];
- return Val_unit;
-}
-
-- (void)unisonInit1Complete:(id)ignore
-{
- @try {
- OCamlValue *prompt = ocamlCall("@@", "openConnectionPrompt", preconn);
- if (!prompt) {
- // turns out, no prompt needed, but must finish opening connection
- ocamlCall("x@", "openConnectionEnd", preconn);
- NSLog(@"Connected.");
- waitingForPassword = NO;
- [self afterOpen];
- return;
- }
- waitingForPassword = YES;
-
- [self raisePasswordWindow:[prompt getField:0 withType:'S']];
- } @catch (NSException *ex) {
- NSRunAlertPanel(@"Connection Error", [ex description], @"OK", nil, nil);
- [self chooseProfiles];
- return;
- }
-
- NSLog(@"Connected.");
-}
-
-- (void)raisePasswordWindow:(NSString *)prompt
-{
- // FIX: some prompts don't ask for password, need to look at it
- NSLog(@"Got the prompt: '%@'",prompt);
- if ((long)ocamlCall("iS", "unisonPasswordMsg", prompt)) {
- [passwordPrompt setStringValue:@"Please enter your password"];
- [NSApp beginSheet:passwordWindow
- modalForWindow:mainWindow
- modalDelegate:nil
- didEndSelector:nil
- contextInfo:nil];
- return;
- }
- if ((long)ocamlCall("iS", "unisonPassphraseMsg", prompt)) {
- [passwordPrompt setStringValue:@"Please enter your passphrase"];
- [NSApp beginSheet:passwordWindow
- modalForWindow:mainWindow
- modalDelegate:nil
- didEndSelector:nil
- contextInfo:nil];
- return;
- }
- if ((long)ocamlCall("iS", "unisonAuthenticityMsg", prompt)) {
- int i = NSRunAlertPanel(@"New host",prompt,@"Yes",@"No",nil);
- if (i == NSAlertDefaultReturn) {
- ocamlCall("x at s", "openConnectionReply", preconn, "yes");
- prompt = ocamlCall("S@", "openConnectionPrompt", preconn);
- if (!prompt) {
- // all done with prompts, finish opening connection
- ocamlCall("x@", "openConnectionEnd", preconn);
- waitingForPassword = NO;
- [self afterOpen];
- return;
- }
- else {
- [self raisePasswordWindow:[NSString
- stringWithUTF8String:String_val(Field(prompt,0))]];
- return;
- }
- }
- if (i == NSAlertAlternateReturn) {
- ocamlCall("x@", "openConnectionCancel", preconn);
- return;
- }
- else {
- NSLog(@"Unrecognized response '%d' from NSRunAlertPanel",i);
- ocamlCall("x@", "openConnectionCancel", preconn);
- return;
- }
- }
- NSLog(@"Unrecognized message from ssh: %@",prompt);
- ocamlCall("x@", "openConnectionCancel", preconn);
-}
-
-// The password window will invoke this when Enter occurs, b/c we
-// are the delegate.
-- (void)controlTextDidEndEditing:(NSNotification *)notification
-{
- NSNumber *reason = [[notification userInfo] objectForKey:@"NSTextMovement"];
- int code = [reason intValue];
- if (code == NSReturnTextMovement)
- [self endPasswordWindow:self];
-}
-// Or, the Continue button will invoke this when clicked
-- (IBAction)endPasswordWindow:(id)sender
-{
- [passwordWindow orderOut:self];
- [NSApp endSheet:passwordWindow];
- if ([sender isEqualTo:passwordCancelButton]) {
- ocamlCall("x@", "openConnectionCancel", preconn);
- [self chooseProfiles];
- return;
- }
- NSString *password = [passwordText stringValue];
- ocamlCall("x at S", "openConnectionReply", preconn, password);
-
- OCamlValue *prompt = ocamlCall("@@", "openConnectionPrompt", preconn);
- if (!prompt) {
- // all done with prompts, finish opening connection
- ocamlCall("x@", "openConnectionEnd", preconn);
- waitingForPassword = NO;
- [self afterOpen];
- }
- else {
- [self raisePasswordWindow:[prompt getField:0 withType:'S']];
- }
-}
-
-- (void)afterOpen:(id)ignore
-{
- [self afterOpen];
-}
-
-- (void)afterOpen
-{
- if (waitingForPassword) return;
- // move to updates window after clearing it
- [self updateReconItems:nil];
- [progressBar setDoubleValue:0.0];
- [progressBar stopAnimation:self];
- // [self clearDetails];
- [mainWindow setContentView:blankView];
- [self resizeWindowToSize:[updatesView frame].size];
- [mainWindow setContentMinSize:
- NSMakeSize(NSWidth([[mainWindow contentView] frame]),200)];
- [mainWindow setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- [mainWindow setContentView:updatesView];
- [toolbar setView:@"updatesView"];
-
- syncable = NO;
- afterSync = NO;
-
- [tableView deselectAll:self];
- [self updateToolbar];
- [self updateProgressBar:[NSNumber numberWithDouble:0.0]];
-
- // this should depend on the number of reconitems, and is now done
- // in updateReconItems:
- // reconItems table gets keyboard input
- //[mainWindow makeFirstResponder:tableView];
- [tableView scrollRowToVisible:0];
-
- [preconn release];
- preconn = nil; // so old preconn can be garbage collected
- // This will run in another thread spawned in OCaml and will return immediately
- // We'll get a call back to unisonInit2Complete() when it is complete
- ocamlCall("x", "unisonInit2");
-}
-
-- (void)doSync
-{
- [tableView setEditable:NO];
- syncable = NO;
- duringSync = YES;
-
- [self updateToolbar];
-
- // This will run in another thread spawned in OCaml and will return immediately
- // We'll get a call back to syncComplete() when it is complete
- ocamlCall("x", "unisonSynchronize");
-}
-
-- (IBAction)syncButton:(id)sender
-{
- [self doSync];
-}
-
-
-- (void)afterUpdate:(id)retainedReconItems
-{
- // NSLog(@"In afterUpdate:...");
- [self updateReconItems:retainedReconItems];
- [retainedReconItems release];
-
- [notificationController updateFinishedFor:[self profile]];
-
- // label the left and right columns with the roots
- NSString *leftHost = [(NSString *)ocamlCall("S", "unisonFirstRootString") trim];
- NSString *rightHost = [(NSString *)ocamlCall("S", "unisonSecondRootString") trim];
- /*
- [[[tableView tableColumnWithIdentifier:@"left"] headerCell] setObjectValue:lefthost];
- [[[tableView tableColumnWithIdentifier:@"right"] headerCell] setObjectValue:rightHost];
- */
- [mainWindow setTitle: [NSString stringWithFormat:@"Unison: %@ (%@ <-> %@)",
- [self profile], leftHost, rightHost]];
-
- // initial sort
- [tableView setSortDescriptors:[NSArray arrayWithObjects:
- [[tableView tableColumnWithIdentifier:@"fileSizeString"] sortDescriptorPrototype],
- [[tableView tableColumnWithIdentifier:@"path"] sortDescriptorPrototype],
- nil]];
-
- [self updateTableViewWithReset:([reconItems count] > 0)];
- [self updateToolbar];
- isBatchSet = (long)ocamlCall("i", "isBatchSet") ? YES : NO;
- if (isBatchSet) {
- NSLog(@"batch set on the command line");
- }
- else {
- NSLog(@"batch not set on the command line");
- }
-
- if (isBatchSet) {
- [self doSync];
- }
-}
-
-CAMLprim value unisonInit2Complete(value v)
-{
- id pool = [[NSAutoreleasePool alloc] init];
- [me performSelectorOnMainThread:@selector(afterUpdate:) withObject:[[OCamlValue alloc] initWithValue:v] waitUntilDone:FALSE];
- [pool release];
- return Val_unit;
-}
-
-- (void)afterSync:(id)ignore
-{
- [notificationController syncFinishedFor:[self profile]];
- duringSync = NO;
- afterSync = YES;
- [self updateToolbar];
-
- int i;
- for (i = 0; i < [reconItems count]; i++) {
- [[reconItems objectAtIndex:i] resetProgress];
- }
-
- [self updateTableViewSelection];
-
- [self updateTableViewWithReset:FALSE];
-}
-
-- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
-{
- [_timer invalidate];
-
- switch (returnCode) {
- case NSAlertAlternateReturn:
- return;
- break;
-
- default:
- [[NSApplication sharedApplication] performSelector: @selector(terminate:) withObject: nil afterDelay: 0.0];
- break;
- }
-}
-
-- (void)updateCountdown
-{
- if (_secondsRemaining == 0) {
- [_timer invalidate];
- [[_timeoutAlert window] orderOut: nil];
- [self alertDidEnd: _timeoutAlert returnCode: NSAlertDefaultReturn contextInfo: nil];
- } else {
- [_timeoutAlert setMessageText: [NSString stringWithFormat: @"Unison will quit in %lu seconds", _secondsRemaining]];
- _secondsRemaining--;
- }
-}
-
-
-- (void)quitIfBatch:(id)ignore
-{
- if (isBatchSet) {
- NSLog(@"Automatically quitting because of -batch");
- _timeoutAlert = [NSAlert alertWithMessageText: @"" defaultButton: @"Quit" alternateButton: @"Cancel" otherButton: nil informativeTextWithFormat: @""];
-
- _secondsRemaining = 10;
-
- _timer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(updateCountdown) userInfo: nil repeats: YES];
-
- [_timeoutAlert beginSheetModalForWindow: mainWindow modalDelegate: self didEndSelector: @selector(alertDidEnd:returnCode:contextInfo:) contextInfo: NULL];
- }
-}
-
-CAMLprim value syncComplete()
-{
- id pool = [[NSAutoreleasePool alloc] init];
- [me performSelectorOnMainThread:@selector(afterSync:) withObject:nil waitUntilDone:FALSE];
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"deleteLogOnExit"])
- [[NSFileManager defaultManager] removeItemAtPath:[@"~/unison.log" stringByExpandingTildeInPath] error:nil];
- [pool release];
-
- [me performSelectorOnMainThread:@selector(quitIfBatch:) withObject:nil waitUntilDone:FALSE];
-
- return Val_unit;
-}
-
-// A function called from ocaml
-- (void)reloadTable:(NSNumber *)i
-{
- // NSLog(@"*** ReloadTable: %i", [i intValue]);
-
- [[reconItems objectAtIndex:[i intValue]] resetProgress];
- [self updateTableViewWithReset:FALSE];
-}
-
-CAMLprim value reloadTable(value row)
-{
- id pool = [[NSAutoreleasePool alloc] init];
- // NSLog(@"OCaml says... ReloadTable: %i", Int_val(row));
- NSNumber *num = [[NSNumber alloc] initWithInt:Int_val(row)];
- [me performSelectorOnMainThread:@selector(reloadTable:) withObject:num waitUntilDone:FALSE];
- [num release];
- [pool release];
- return Val_unit;
-}
-
-- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
- if (item == nil) item = rootItem;
- return [[item children] count];
-}
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
- return [item isKindOfClass:[ParentReconItem class]];
-}
-
-- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item {
- if (item == nil) item = rootItem;
- return [[item children] objectAtIndex:index];
-}
-
-- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
- NSString *identifier = [tableColumn identifier];
- if (item == nil) item = rootItem;
-
- if ([identifier isEqualToString:@"percentTransferred"] && (!duringSync && !afterSync)) return nil;
-
- return [item valueForKey:identifier];
-}
-
-static NSDictionary *_SmallGreyAttributes = nil;
-
-- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
- NSString *identifier = [tableColumn identifier];
- if ([identifier isEqualToString:@"path"]) {
- // The file icon
- [(ImageAndTextCell*)cell setImage:[item fileIcon]];
-
- // For parents, format the file count into the text
- long fileCount = [item fileCount];
- if (fileCount > 1) {
- NSString *countString = [NSString stringWithFormat:@" (%ld files)", fileCount];
- NSString *fullString = [(NSString *)[cell objectValue] stringByAppendingString:countString];
- NSMutableAttributedString *as = [[NSMutableAttributedString alloc] initWithString:fullString];
-
- if (!_SmallGreyAttributes) {
- NSColor *txtColor = [NSColor grayColor];
- NSFont *txtFont = [NSFont systemFontOfSize:9.0];
- _SmallGreyAttributes = [[NSDictionary dictionaryWithObjectsAndKeys:txtFont,
- NSFontAttributeName, txtColor, NSForegroundColorAttributeName, nil] retain];
- }
- [as setAttributes:_SmallGreyAttributes range:NSMakeRange([fullString length] - [countString length], [countString length])];
- [cell setAttributedStringValue:as];
- [as release];
- }
- } else if ([identifier isEqualToString:@"percentTransferred"]) {
- [(ProgressCell*)cell setIcon:[item direction]];
- [(ProgressCell*)cell setStatusString:[item progressString]];
- [(ProgressCell*)cell setIsActive:[item isKindOfClass:[LeafReconItem class]]];
- }
-}
-
-- (void)outlineView:(NSOutlineView *)outlineView
- sortDescriptorsDidChange:(NSArray *)oldDescriptors {
- NSArray *originalSelection = [outlineView selectedObjects];
-
- // do we want to catch case of object changes to allow resort in same direction for progress / direction?
- // Could check if our objects change and if the first item at the head of new and old were the same
- [rootItem sortUsingDescriptors:[outlineView sortDescriptors]];
- [outlineView reloadData];
- [outlineView setSelectedObjects:originalSelection];
-}
-
-// Delegate methods
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item {
- return NO;
-}
-
-- (NSMutableArray *)reconItems // used in ReconTableView only
-{
- return reconItems;
-}
-
-- (int)tableMode
-{
- return [tableModeSelector selectedSegment];
-}
-
-- (IBAction)tableModeChanged:(id)sender
-{
- [[NSUserDefaults standardUserDefaults] setInteger:[self tableMode]+1 forKey:@"TableLayout"];
- [self updateForChangedItems];
-}
-
-- (void)initTableMode
-{
- int mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"TableLayout"] - 1;
- if (mode == -1) mode = 1;
- [tableModeSelector setSelectedSegment:mode];
-}
-
-- (void)updateReconItems:(OCamlValue *)caml_reconItems
-{
- [reconItems release];
- reconItems = [[NSMutableArray alloc] init];
- long i, n =[caml_reconItems count];
- for (i=0; i<n; i++) {
- LeafReconItem *item = [[LeafReconItem alloc] initWithRiAndIndex:(id)[caml_reconItems getField:i withType:'@'] index:i];
- [reconItems addObject:item];
- [item release];
- }
- [self updateForChangedItems];
-}
-
-- (void)expandConflictedParent:(ParentReconItem *)parent
-{
- if ([parent hasConflictedChildren]) {
- // NSLog(@"Expanding conflictedParent: %@", [parent fullPath]);
- [tableView expandItem:parent expandChildren:NO];
- NSArray *children = [parent children];
- int i = 0, count = [children count];
- for (;i < count; i++) {
- id child = [children objectAtIndex:i];
- if ([child isKindOfClass:[ParentReconItem class]]) [self expandConflictedParent:child];
- }
- }
-}
-
-- (void)updateForChangedItems
-{
- int tableMode = [self tableMode];
-
- [rootItem release];
- ParentReconItem *root = rootItem = [[ParentReconItem alloc] init];
-
- if (tableMode != 0 && [reconItems count]) {
- // Special roll-up root item for outline displays
- root = [[ParentReconItem alloc] init];
- [rootItem addChild:root nested:NO];
- [root setPath:@"All Changes..."];
- [root setFullPath:@""];
- [root release];
- }
-
- int j = 0, n =[reconItems count];
- for (; j<n; j++) {
- [root addChild:[reconItems objectAtIndex:j] nested:(tableMode != 0)];
- }
-
- if (tableMode == 1) [root collapseParentsWithSingleChildren:YES];
-
- [tableView reloadData];
-
- if (NO) {
- // Pre-expand entire tree
- int i = [[rootItem children] count];
- while (i--) {
- [tableView expandItem:[[rootItem children] objectAtIndex:i] expandChildren:YES];
- }
- } else if (tableMode != 0) {
- // Always open root node
- [tableView expandItem:rootItem expandChildren:NO];
-
- // then smart expand to reveal conflicts / changes in direction
- [self expandConflictedParent:root];
-
- // then open more levels if we can do so without causing scrolling
- [tableView expandChildrenIfSpace];
- }
-
- // Make sure details get updated (or cleared)
- [self updateTableViewSelection];
-
- // Only enable sync if there are reconitems
- if ([reconItems count]>0) {
- [tableView setEditable:YES];
-
- // reconItems table gets keyboard input
- [mainWindow makeFirstResponder:tableView];
-
- syncable = YES;
- }
- else {
- [tableView setEditable:NO];
- afterSync = YES; // rescan should be enabled
-
- // reconItems table no longer gets keyboard input
- [mainWindow makeFirstResponder:nil];
- }
- [self updateToolbar];
-}
-
-- (id)updateForIgnore:(id)item
-{
- long j = (long)ocamlCall("ii", "unisonUpdateForIgnore", [reconItems indexOfObjectIdenticalTo:item]);
- NSLog(@"Updating for ignore...");
- [self updateReconItems:(OCamlValue *)ocamlCall("@", "unisonState")];
- return [reconItems objectAtIndex:j];
-}
-
-// A function called from ocaml
-CAMLprim value displayStatus(value s)
-{
- id pool = [[NSAutoreleasePool alloc] init];
- NSString *str = [[NSString alloc] initWithUTF8String:String_val(s)];
- // NSLog(@"displayStatus: %@", str);
- [me performSelectorOnMainThread:@selector(statusTextSet:) withObject:str waitUntilDone:FALSE];
- [str release];
- [pool release];
- return Val_unit;
-}
-
-- (void)statusTextSet:(NSString *)s {
- /* filter out strings with # reconitems, and empty strings */
- if (!NSEqualRanges([s rangeOfString:@"reconitems"],
- NSMakeRange(NSNotFound,0))) return;
- [statusText setStringValue:s];
-}
-
-// Called from ocaml to dislpay progress bar
-CAMLprim value displayGlobalProgress(value p)
-{
- id pool = [[NSAutoreleasePool alloc] init];
- NSNumber *num = [[NSNumber alloc] initWithDouble:Double_val(p)];
- [me performSelectorOnMainThread:@selector(updateProgressBar:)
- withObject:num waitUntilDone:FALSE];
- [num release];
- [pool release];
- return Val_unit;
-}
-
-// Called from ocaml to display diff
-CAMLprim value displayDiff(value s, value s2)
-{
- id pool = [[NSAutoreleasePool alloc] init];
- [me performSelectorOnMainThread:@selector(diffViewTextSet:)
- withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:String_val(s)],
- [NSString stringWithUTF8String:String_val(s2)], nil]
- waitUntilDone:FALSE];
- [pool release];
- return Val_unit;
-}
-
-// Called from ocaml to display diff error messages
-CAMLprim value displayDiffErr(value s)
-{
- id pool = [[NSAutoreleasePool alloc] init];
- NSString * str = [NSString stringWithUTF8String:String_val(s)];
- str = [[str componentsSeparatedByString:@"\n"] componentsJoinedByString:@" "];
- [me->statusText performSelectorOnMainThread:@selector(setStringValue:)
- withObject:str waitUntilDone:FALSE];
- [pool release];
- return Val_unit;
-}
-
-- (void)diffViewTextSet:(NSArray *)args
-{
- [self diffViewTextSet:[args objectAtIndex:0] bodyText:[args objectAtIndex:1]];
-}
-
-- (void)diffViewTextSet:(NSString *)title bodyText:(NSString *)body {
- if ([body length]==0) return;
- [diffWindow setTitle:title];
- //[diffView setFont:diffFont];
- [diffView setString:body];
- if (!doneFirstDiff) {
- /* On first open, position the diff window to the right of
- the main window, but without going off the mainwindow's screen */
- float screenOriginX = [[mainWindow screen] visibleFrame].origin.x;
- float screenWidth = [[mainWindow screen] visibleFrame].size.width;
- float mainOriginX = [mainWindow frame].origin.x;
- float mainOriginY = [mainWindow frame].origin.y;
- float mainWidth = [mainWindow frame].size.width;
- float mainHeight = [mainWindow frame].size.height;
- float diffWidth = [diffWindow frame].size.width;
-
- float diffX = mainOriginX+mainWidth;
- float maxX = screenOriginX+screenWidth-diffWidth;
- if (diffX > maxX) diffX = maxX;
- float diffY = mainOriginY + mainHeight;
-
- NSPoint diffOrigin = NSMakePoint(diffX,diffY);
- [diffWindow cascadeTopLeftFromPoint:diffOrigin];
-
- doneFirstDiff = YES;
- }
- [diffWindow orderFront:nil];
-}
-
-- (void)displayDetails:(ReconItem *)item
-{
- //[detailsTextView setFont:diffFont];
- NSString *text = [item details];
- if (!text) text = @"";
- [detailsTextView setStringValue:text];
-}
-
-- (void)clearDetails
-{
- [detailsTextView setStringValue:@""];
-}
-
-- (IBAction)raiseCltoolWindow:(id)sender
-{
- [cltoolPref setState:[[NSUserDefaults standardUserDefaults] boolForKey:@"CheckCltool"] ? NSOffState : NSOnState];
- [self raiseWindow: cltoolWindow];
-}
-
-- (IBAction)cltoolYesButton:(id)sender;
-{
- [[NSUserDefaults standardUserDefaults] setBool:([cltoolPref state] != NSOnState) forKey:@"CheckCltool"];
- [self installCommandLineTool:self];
- [cltoolWindow close];
-}
-
-- (IBAction)cltoolNoButton:(id)sender;
-{
- [[NSUserDefaults standardUserDefaults] setBool:([cltoolPref state] != NSOnState) forKey:@"CheckCltool"];
- [cltoolWindow close];
-}
-
-- (IBAction)raiseAboutWindow:(id)sender
-{
- [self raiseWindow: aboutWindow];
-}
-
-- (void)raiseWindow:(NSWindow *)theWindow
-{
- NSRect screenFrame = [[mainWindow screen] visibleFrame];
- NSRect mainWindowFrame = [mainWindow frame];
- NSRect theWindowFrame = [theWindow frame];
-
- float winX = mainWindowFrame.origin.x +
- (mainWindowFrame.size.width - theWindowFrame.size.width)/2;
- float winY = mainWindowFrame.origin.y +
- (mainWindowFrame.size.height + theWindowFrame.size.height)/2;
-
- if (winX<screenFrame.origin.x) winX=screenFrame.origin.x;
- float maxX = screenFrame.origin.x+screenFrame.size.width-
- theWindowFrame.size.width;
- if (winX>maxX) winX=maxX;
- float minY = screenFrame.origin.y+theWindowFrame.size.height;
- if (winY<minY) winY=minY;
- float maxY = screenFrame.origin.y+screenFrame.size.height;
- if (winY>maxY) winY=maxY;
-
- [theWindow cascadeTopLeftFromPoint:
- NSMakePoint(winX,winY)];
-
- [theWindow makeKeyAndOrderFront:nil];
-}
-
-- (IBAction)onlineHelp:(id)sender
-{
- [[NSWorkspace sharedWorkspace]
- openURL:[NSURL URLWithString:@"http://www.cis.upenn.edu/~bcpierce/unison/docs.html"]];
-}
-
-/* from http://developer.apple.com/documentation/Security/Conceptual/authorization_concepts/index.html */
-#include <Security/Authorization.h>
-#include <Security/AuthorizationTags.h>
-- (IBAction)installCommandLineTool:(id)sender
-{
- /* Install the command-line tool in /usr/bin/unison.
- Requires root privilege, so we ask for it and
- pass the task off to /bin/sh. */
-
- OSStatus myStatus;
-
- AuthorizationFlags myFlags = kAuthorizationFlagDefaults;
- AuthorizationRef myAuthorizationRef;
- myStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
- myFlags, &myAuthorizationRef);
- if (myStatus != errAuthorizationSuccess) return;
-
- {
- AuthorizationItem myItems = {kAuthorizationRightExecute, 0,
- NULL, 0};
- AuthorizationRights myRights = {1, &myItems};
- myFlags = kAuthorizationFlagDefaults |
- kAuthorizationFlagInteractionAllowed |
- kAuthorizationFlagPreAuthorize |
- kAuthorizationFlagExtendRights;
- myStatus =
- AuthorizationCopyRights(myAuthorizationRef,&myRights,NULL,myFlags,NULL);
- }
- if (myStatus == errAuthorizationSuccess) {
- NSBundle *bundle = [NSBundle mainBundle];
- NSString *bundle_path = [bundle bundlePath];
- NSString *exec_path =
- [bundle_path stringByAppendingString:@"/Contents/MacOS/cltool"];
- // Not sure why but this doesn't work:
- // [bundle pathForResource:@"cltool" ofType:nil];
-
- if (exec_path == nil) return;
- char *args[] = { "-f", (char *)[exec_path UTF8String],
- "/usr/bin/unison", NULL };
-
- myFlags = kAuthorizationFlagDefaults;
- myStatus = AuthorizationExecuteWithPrivileges
- (myAuthorizationRef, "/bin/cp", myFlags, args,
- NULL);
- }
- AuthorizationFree (myAuthorizationRef, kAuthorizationFlagDefaults);
-
- /*
- if (myStatus == errAuthorizationCanceled)
- NSLog(@"The attempt was canceled\n");
- else if (myStatus)
- NSLog(@"There was an authorization error: %ld\n", myStatus);
- */
-}
-
-- (BOOL)validateItem:(IBAction *) action
-{
- if (action == @selector(syncButton:)) return syncable;
- // FIXME Restarting during sync is disabled because it causes UI corruption
- else if (action == @selector(restartButton:)) return !duringSync;
- else if (action == @selector(rescan:)) return ((syncable && !duringSync) || afterSync);
- else return YES;
-}
-
-- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
-{
- return [self validateItem:[menuItem action]];
-}
-
-- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
-{
- return [self validateItem:[toolbarItem action]];
-}
-
-- (void)resizeWindowToSize:(NSSize)newSize
-{
- NSRect aFrame;
-
- float newHeight = newSize.height+[self toolbarHeightForWindow:mainWindow];
- float newWidth = newSize.width;
-
- aFrame = [NSWindow contentRectForFrameRect:[mainWindow frame]
- styleMask:[mainWindow styleMask]];
-
- aFrame.origin.y += aFrame.size.height;
- aFrame.origin.y -= newHeight;
- aFrame.size.height = newHeight;
- aFrame.size.width = newWidth;
-
- aFrame = [NSWindow frameRectForContentRect:aFrame
- styleMask:[mainWindow styleMask]];
-
- [mainWindow setFrame:aFrame display:YES animate:YES];
-}
-
-- (float)toolbarHeightForWindow:(NSWindow *)window
-{
- NSToolbar *aToolbar;
- float toolbarHeight = 0.0;
- NSRect windowFrame;
-
- aToolbar = [window toolbar];
- if(aToolbar && [aToolbar isVisible])
- {
- windowFrame = [NSWindow contentRectForFrameRect:[window frame]
- styleMask:[window styleMask]];
- toolbarHeight = NSHeight(windowFrame)
- - NSHeight([[window contentView] frame]);
- }
- return toolbarHeight;
-}
-
-CAMLprim value fatalError(value s)
-{
- NSString *str = [[NSString alloc] initWithUTF8String:String_val(s)];
-
- [me performSelectorOnMainThread:@selector(fatalError:) withObject:str waitUntilDone:FALSE];
- [str release];
- return Val_unit;
-}
-
-- (void)fatalError:(NSString *)msg {
- NSRunAlertPanel(@"Fatal error", msg, @"Exit", nil, nil);
- exit(1);
-}
-
-/* Returns true if we need to exit, false if we proceed */
-
-CAMLprim value warnPanel(value s)
-{
- NSString *str = [[NSString alloc] initWithUTF8String:String_val(s)];
-
- [me performSelectorOnMainThread:@selector(warnPanel:) withObject:str waitUntilDone:TRUE];
- [str release];
- if (me -> shouldExitAfterWarning) {
- return Val_true;
- } else {
- return Val_false;
- }
-}
-
-- (void)warnPanel:(NSString *)msg {
- int warnVal = NSRunAlertPanel(@"Warning", msg, @"Proceed", @"Exit", nil);
- NSLog(@"Warning Panel Returned %d",warnVal);
- if (warnVal == NSAlertAlternateReturn) {
- shouldExitAfterWarning = YES;
- } else {
- shouldExitAfterWarning = FALSE;
- }
-}
-
- at end
-
- at implementation NSString (_UnisonUtil)
-- (NSString *)trim
-{
- NSCharacterSet *ws = [NSCharacterSet whitespaceCharacterSet];
- int len = [self length], i = len;
- while (i && [ws characterIsMember:[self characterAtIndex:i-1]]) i--;
- return (i == len) ? self : [self substringToIndex:i];
-}
- at end
Copied: branches/2.45/src/uimacnew09/MyController.m (from rev 486, trunk/src/uimacnew09/MyController.m)
===================================================================
--- branches/2.45/src/uimacnew09/MyController.m (rev 0)
+++ branches/2.45/src/uimacnew09/MyController.m 2012-04-02 15:54:47 UTC (rev 487)
@@ -0,0 +1,1215 @@
+/* Copyright (c) 2003, see file COPYING for details. */
+
+#import "MyController.h"
+
+/* The following two define are a workaround for an incompatibility between
+Ocaml 3.11.2 (and older) and the Mac OS X header files */
+#define uint64 uint64_caml
+#define int64 int64_caml
+
+#define CAML_NAME_SPACE
+#include <caml/callback.h>
+#include <caml/alloc.h>
+#include <caml/mlvalues.h>
+#include <caml/memory.h>
+
+ at interface NSString (_UnisonUtil)
+- (NSString *)trim;
+ at end
+
+ at implementation MyController
+
+static MyController *me; // needed by reloadTable and displayStatus, below
+
+// BCP (11/09): Added per Onne Gorter:
+// if user closes main window, terminate app, instead of keeping an empty app around with no window
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
+ return YES;
+}
+
+- (id)init
+{
+ if (([super init])) {
+
+ /* Initialize locals */
+ me = self;
+ doneFirstDiff = NO;
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
+ /* By default, invite user to install cltool */
+ @"YES", @"CheckCltool",
+ @"NO", @"openProfileAtStartup",
+ @"", @"profileToOpen",
+ @"NO", @"deleteLogOnExit",
+ @"", @"detailsFont",
+ @"", @"diffFont",
+ nil];
+
+ [defaults registerDefaults:appDefaults];
+ fontChangeTarget = nil;
+ }
+
+ return self;
+}
+
+- (void) applicationWillTerminate:(NSNotification *)aNotification {
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setObject:[NSArchiver archivedDataWithRootObject:[detailsTextView font]] forKey:@"detailsFont"];
+ [defaults setObject:[NSArchiver archivedDataWithRootObject:[diffView font]] forKey:@"diffFont"];
+ [defaults synchronize];
+}
+
+- (void)awakeFromNib
+{
+ [splitView setAutosaveName:@"splitView"];
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ NSFont *defaultFont = [NSFont fontWithName:@"Monaco" size:11];
+ NSData *detailsFontData = [defaults dataForKey:@"detailsFont"];
+ if (detailsFontData) {
+ NSFont *tmpFont = (NSFont*) [NSUnarchiver unarchiveObjectWithData:detailsFontData];
+ if (tmpFont)
+ [detailsTextView setFont:tmpFont];
+ else
+ [detailsTextView setFont:defaultFont];
+ } else
+ [detailsTextView setFont:defaultFont];
+
+ NSData *diffFontData = [defaults dataForKey:@"diffFont"];
+ if (diffFontData) {
+ NSFont *tmpFont = (NSFont*) [NSUnarchiver unarchiveObjectWithData:diffFontData];
+ if (tmpFont)
+ [diffView setFont:tmpFont];
+ else
+ [diffView setFont:defaultFont];
+ } else
+ [diffView setFont:defaultFont];
+
+ blankView = [[NSView alloc] init];
+
+ /* Double clicking in the profile list will open the profile */
+ [[profileController tableView] setTarget:self];
+ [[profileController tableView] setDoubleAction:@selector(openButton:)];
+
+ [tableView setAutoresizesOutlineColumn:NO];
+
+ // use combo-cell for path
+ [[tableView tableColumnWithIdentifier:@"path"] setDataCell:[[[ImageAndTextCell alloc] init] autorelease]];
+
+ // Custom progress cell
+ ProgressCell *progressCell = [[[ProgressCell alloc] init] autorelease];
+ [[tableView tableColumnWithIdentifier:@"percentTransferred"] setDataCell:progressCell];
+
+ /* Set up the version string in the about box. We use a custom
+ about box just because PRCS doesn't seem capable of getting the
+ version into the InfoPlist.strings file; otherwise we'd use the
+ standard about box. */
+ [versionText setStringValue:ocamlCall("S", "unisonGetVersion")];
+
+ /* Command-line processing */
+ OCamlValue *clprofile = (id)ocamlCall("@", "unisonInit0");
+
+ BOOL areRootsSet = (long)ocamlCall("i", "areRootsSet") ? YES : NO;
+ if (areRootsSet) {
+ NSLog(@"Roots are on the command line");
+ }
+ else {
+ NSLog(@"Roots are not set on the command line");
+ }
+
+ /* Add toolbar */
+ toolbar = [[[UnisonToolbar alloc]
+ initWithIdentifier: @"unisonToolbar" :self :tableView] autorelease];
+ [mainWindow setToolbar: toolbar];
+ [toolbar takeTableModeView:tableModeSelector];
+ [self initTableMode];
+
+
+ /* Set up the first window the user will see */
+ if (clprofile) {
+ /* A profile name was given on the command line */
+ NSString *profileName = [clprofile getField:0 withType:'S'];
+ [self profileSelected:profileName];
+
+ /* If invoked from terminal we need to bring the app to the front */
+ [NSApp activateIgnoringOtherApps:YES];
+
+ /* Start the connection */
+ [self connect:profileName];
+ }
+ else if (areRootsSet) {
+ /* If invoked from terminal we need to bring the app to the front */
+ [NSApp activateIgnoringOtherApps:YES];
+ /* Start the connection with the empty profile name, indicating roots only */
+ [self connect:@""];
+ }
+ else {
+ /* If invoked from terminal we need to bring the app to the front */
+ [NSApp activateIgnoringOtherApps:YES];
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"openProfileAtStartup"]) {
+ NSString *profileToOpen = [[NSUserDefaults standardUserDefaults]
+ stringForKey:@"profileToOpen"];
+ if ([[profileToOpen trim] compare:@""] != NSOrderedSame &&
+ [[profileController getProfiles] indexOfObject:profileToOpen] != NSNotFound) {
+ [self profileSelected:profileToOpen];
+ [self connect:profileToOpen];
+ } else {
+ /* Bring up the dialog to choose a profile */
+ [self chooseProfiles];
+ }
+ } else {
+ /* Bring up the dialog to choose a profile */
+ [self chooseProfiles];
+ }
+ }
+
+ [mainWindow display];
+ [mainWindow makeKeyAndOrderFront:nil];
+
+ /* unless user has clicked Don't ask me again, ask about cltool */
+ if ( ([[NSUserDefaults standardUserDefaults] boolForKey:@"CheckCltool"]) &&
+ (![[NSFileManager defaultManager]
+ fileExistsAtPath:@"/usr/bin/unison"]) )
+ [self raiseCltoolWindow:nil];
+}
+
+- (IBAction) checkOpenProfileChanged:(id)sender {
+ [profileBox setEnabled:[checkOpenProfile state]];
+ if ([profileBox isEnabled] && [profileBox indexOfSelectedItem] < 0) {
+ [profileBox selectItemAtIndex:0];
+ [[NSUserDefaults standardUserDefaults] setObject:[profileBox itemObjectValueAtIndex:0] forKey:@"profileToOpen"];
+ }
+}
+
+- (IBAction) chooseFont:(id)sender {
+ [[NSFontPanel sharedFontPanel] makeKeyAndOrderFront:self];
+ [[NSFontManager sharedFontManager] setDelegate:self];
+ fontChangeTarget = sender;
+}
+
+- (void) changeFont:(id)sender {
+ NSFont *newFont = [sender convertFont:[detailsTextView font]];
+ if (fontChangeTarget == chooseDetailsFont)
+ [detailsTextView setFont:newFont];
+ else if (fontChangeTarget == chooseDiffFont)
+ [diffView setFont:newFont];
+ [self updateFontDisplay];
+}
+
+- (void) updateFontDisplay {
+ NSFont *detailsFont = [detailsTextView font];
+ NSFont *diffFont = [diffView font];
+ [detailsFontLabel setStringValue:[NSString stringWithFormat:@"%@ : %d", [detailsFont displayName], (NSInteger) [detailsFont pointSize]]];
+ [diffFontLabel setStringValue:[NSString stringWithFormat:@"%@ : %d", [diffFont displayName], (NSInteger) [diffFont pointSize]]];
+}
+
+- (void)chooseProfiles
+{
+ [mainWindow setContentView:blankView];
+ [self resizeWindowToSize:[chooseProfileView frame].size];
+ [mainWindow setContentMinSize:
+ NSMakeSize(NSWidth([[mainWindow contentView] frame]),150)];
+ [mainWindow setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [mainWindow setContentView:chooseProfileView];
+ [toolbar setView:@"chooseProfileView"];
+ [mainWindow setTitle:@"Unison"];
+
+ // profiles get keyboard input
+ [mainWindow makeFirstResponder:[profileController tableView]];
+ [chooseProfileView display];
+}
+
+- (IBAction)createButton:(id)sender
+{
+ [preferencesController reset];
+ [mainWindow setContentView:blankView];
+ [self resizeWindowToSize:[preferencesView frame].size];
+ [mainWindow setContentMinSize:
+ NSMakeSize(400,NSHeight([[mainWindow contentView] frame]))];
+ [mainWindow setContentMaxSize:
+ NSMakeSize(FLT_MAX,NSHeight([[mainWindow contentView] frame]))];
+ [mainWindow setContentView:preferencesView];
+ [toolbar setView:@"preferencesView"];
+}
+
+- (IBAction)saveProfileButton:(id)sender
+{
+ if ([preferencesController validatePrefs]) {
+ // so the list contains the new profile
+ [profileController initProfiles];
+ [self chooseProfiles];
+ }
+}
+
+- (IBAction)cancelProfileButton:(id)sender
+{
+ [self chooseProfiles];
+}
+
+/* Only valid once a profile has been selected */
+- (NSString *)profile {
+ return myProfile;
+}
+
+- (void)profileSelected:(NSString *)aProfile
+{
+ [aProfile retain];
+ [myProfile release];
+ myProfile = aProfile;
+ [mainWindow setTitle: [NSString stringWithFormat:@"Unison: %@", myProfile]];
+}
+
+- (IBAction)showPreferences:(id)sender {
+ [profileBox removeAllItems];
+ [profileBox addItemsWithObjectValues:[profileController getProfiles]];
+ NSUInteger index = [[profileController getProfiles] indexOfObject:
+ [[NSUserDefaults standardUserDefaults]
+ stringForKey:@"profileToOpen"]];
+ if (index == NSNotFound) {
+ [checkOpenProfile setState:NSOffState];
+ [profileBox setStringValue:@""];
+ } else
+ [profileBox selectItemAtIndex:index];
+
+ [profileBox setEnabled:[checkOpenProfile state]];
+ if ([profileBox isEnabled] && [profileBox indexOfSelectedItem] < 0)
+ [profileBox selectItemAtIndex:0];
+
+ [self updateFontDisplay];
+
+ [self raiseWindow:preferencesWindow];
+}
+
+- (IBAction)restartButton:(id)sender
+{
+ [tableView setEditable:NO];
+ [self chooseProfiles];
+}
+
+- (IBAction)rescan:(id)sender
+{
+ /* There is a delay between turning off the button and it
+ actually being disabled. Make sure we don't respond. */
+ if ([self validateItem:@selector(rescan:)]) {
+ waitingForPassword = NO;
+ [self afterOpen];
+ }
+}
+
+- (IBAction)openButton:(id)sender
+{
+ NSString *profile = [profileController selected];
+ [self profileSelected:profile];
+ [self connect:profile];
+ return;
+}
+
+- (void)updateToolbar
+{
+ [toolbar validateVisibleItems];
+ [tableModeSelector setEnabled:((syncable && !duringSync) || afterSync)];
+
+ // Why?
+ [updatesView setNeedsDisplay:YES];
+}
+
+- (void)updateTableViewWithReset:(BOOL)shouldResetSelection
+{
+ [tableView reloadData];
+ if (shouldResetSelection) {
+ [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
+ shouldResetSelection = NO;
+ }
+ [updatesView setNeedsDisplay:YES];
+}
+
+- (void)updateProgressBar:(NSNumber *)newProgress
+{
+ // NSLog(@"Updating progress bar: %i - %i", (int)[newProgress doubleValue], (int)[progressBar doubleValue]);
+ [progressBar incrementBy:([newProgress doubleValue] - [progressBar doubleValue])];
+}
+
+- (void)updateTableViewSelection
+{
+ int n = [tableView numberOfSelectedRows];
+ if (n == 1) [self displayDetails:[tableView itemAtRow:[tableView selectedRow]]];
+ else [self clearDetails];
+}
+
+- (void)outlineViewSelectionDidChange:(NSNotification *)note
+{
+ [self updateTableViewSelection];
+}
+
+- (void)connect:(NSString *)profileName
+{
+ // contact server, propagate prefs
+ NSLog(@"Connecting to %@...", profileName);
+
+ // Switch to ConnectingView
+ [mainWindow setContentView:blankView];
+ [self resizeWindowToSize:[updatesView frame].size];
+ [mainWindow setContentMinSize:NSMakeSize(150,150)];
+ [mainWindow setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [mainWindow setContentView:ConnectingView];
+ [toolbar setView:@"connectingView"];
+
+ // Update (almost) immediately
+ [ConnectingView display];
+ [connectingAnimation startAnimation:self];
+
+ syncable = NO;
+ afterSync = NO;
+
+ [self updateToolbar];
+
+ // will spawn thread on OCaml side and callback when complete
+ (void)ocamlCall("xS", "unisonInit1", profileName);
+}
+
+CAMLprim value unisonInit1Complete(value v)
+{
+ id pool = [[NSAutoreleasePool alloc] init];
+ if (v == Val_unit) {
+ NSLog(@"Connected.");
+ [me->connectingAnimation stopAnimation:me];
+ [me->preconn release];
+ me->preconn = NULL;
+ [me performSelectorOnMainThread:@selector(afterOpen:) withObject:nil waitUntilDone:FALSE];
+ } else {
+ // prompting required
+ me->preconn = [[OCamlValue alloc] initWithValue:Field(v,0)]; // value of Some
+ [me performSelectorOnMainThread:@selector(unisonInit1Complete:) withObject:nil waitUntilDone:FALSE];
+ }
+ [pool release];
+ return Val_unit;
+}
+
+- (void)unisonInit1Complete:(id)ignore
+{
+ @try {
+ OCamlValue *prompt = ocamlCall("@@", "openConnectionPrompt", preconn);
+ if (!prompt) {
+ // turns out, no prompt needed, but must finish opening connection
+ ocamlCall("x@", "openConnectionEnd", preconn);
+ NSLog(@"Connected.");
+ waitingForPassword = NO;
+ [self afterOpen];
+ return;
+ }
+ waitingForPassword = YES;
+
+ [self raisePasswordWindow:[prompt getField:0 withType:'S']];
+ } @catch (NSException *ex) {
+ NSRunAlertPanel(@"Connection Error", [ex description], @"OK", nil, nil);
+ [self chooseProfiles];
+ return;
+ }
+
+ NSLog(@"Connected.");
+}
+
+- (void)raisePasswordWindow:(NSString *)prompt
+{
+ // FIX: some prompts don't ask for password, need to look at it
+ NSLog(@"Got the prompt: '%@'",prompt);
+ if ((long)ocamlCall("iS", "unisonPasswordMsg", prompt)) {
+ [passwordPrompt setStringValue:@"Please enter your password"];
+ [NSApp beginSheet:passwordWindow
+ modalForWindow:mainWindow
+ modalDelegate:nil
+ didEndSelector:nil
+ contextInfo:nil];
+ return;
+ }
+ if ((long)ocamlCall("iS", "unisonPassphraseMsg", prompt)) {
+ [passwordPrompt setStringValue:@"Please enter your passphrase"];
+ [NSApp beginSheet:passwordWindow
+ modalForWindow:mainWindow
+ modalDelegate:nil
+ didEndSelector:nil
+ contextInfo:nil];
+ return;
+ }
+ if ((long)ocamlCall("iS", "unisonAuthenticityMsg", prompt)) {
+ int i = NSRunAlertPanel(@"New host",prompt,@"Yes",@"No",nil);
+ if (i == NSAlertDefaultReturn) {
+ ocamlCall("x at s", "openConnectionReply", preconn, "yes");
+ prompt = ocamlCall("S@", "openConnectionPrompt", preconn);
+ if (!prompt) {
+ // all done with prompts, finish opening connection
+ ocamlCall("x@", "openConnectionEnd", preconn);
+ waitingForPassword = NO;
+ [self afterOpen];
+ return;
+ }
+ else {
+ [self raisePasswordWindow:[NSString
+ stringWithUTF8String:String_val(Field(prompt,0))]];
+ return;
+ }
+ }
+ if (i == NSAlertAlternateReturn) {
+ ocamlCall("x@", "openConnectionCancel", preconn);
+ return;
+ }
+ else {
+ NSLog(@"Unrecognized response '%d' from NSRunAlertPanel",i);
+ ocamlCall("x@", "openConnectionCancel", preconn);
+ return;
+ }
+ }
+ NSLog(@"Unrecognized message from ssh: %@",prompt);
+ ocamlCall("x@", "openConnectionCancel", preconn);
+}
+
+// The password window will invoke this when Enter occurs, b/c we
+// are the delegate.
+- (void)controlTextDidEndEditing:(NSNotification *)notification
+{
+ NSNumber *reason = [[notification userInfo] objectForKey:@"NSTextMovement"];
+ int code = [reason intValue];
+ if (code == NSReturnTextMovement)
+ [self endPasswordWindow:self];
+}
+// Or, the Continue button will invoke this when clicked
+- (IBAction)endPasswordWindow:(id)sender
+{
+ [passwordWindow orderOut:self];
+ [NSApp endSheet:passwordWindow];
+ if ([sender isEqualTo:passwordCancelButton]) {
+ ocamlCall("x@", "openConnectionCancel", preconn);
+ [self chooseProfiles];
+ return;
+ }
+ NSString *password = [passwordText stringValue];
+ ocamlCall("x at S", "openConnectionReply", preconn, password);
+
+ OCamlValue *prompt = ocamlCall("@@", "openConnectionPrompt", preconn);
+ if (!prompt) {
+ // all done with prompts, finish opening connection
+ ocamlCall("x@", "openConnectionEnd", preconn);
+ waitingForPassword = NO;
+ [self afterOpen];
+ }
+ else {
+ [self raisePasswordWindow:[prompt getField:0 withType:'S']];
+ }
+}
+
+- (void)afterOpen:(id)ignore
+{
+ [self afterOpen];
+}
+
+- (void)afterOpen
+{
+ if (waitingForPassword) return;
+ // move to updates window after clearing it
+ [self updateReconItems:nil];
+ [progressBar setDoubleValue:0.0];
+ [progressBar stopAnimation:self];
+ // [self clearDetails];
+ [mainWindow setContentView:blankView];
+ [self resizeWindowToSize:[updatesView frame].size];
+ [mainWindow setContentMinSize:
+ NSMakeSize(NSWidth([[mainWindow contentView] frame]),200)];
+ [mainWindow setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [mainWindow setContentView:updatesView];
+ [toolbar setView:@"updatesView"];
+
+ syncable = NO;
+ afterSync = NO;
+
+ [tableView deselectAll:self];
+ [self updateToolbar];
+ [self updateProgressBar:[NSNumber numberWithDouble:0.0]];
+
+ // this should depend on the number of reconitems, and is now done
+ // in updateReconItems:
+ // reconItems table gets keyboard input
+ //[mainWindow makeFirstResponder:tableView];
+ [tableView scrollRowToVisible:0];
+
+ [preconn release];
+ preconn = nil; // so old preconn can be garbage collected
+ // This will run in another thread spawned in OCaml and will return immediately
+ // We'll get a call back to unisonInit2Complete() when it is complete
+ ocamlCall("x", "unisonInit2");
+}
+
+- (void)doSync
+{
+ [tableView setEditable:NO];
+ syncable = NO;
+ duringSync = YES;
+
+ [self updateToolbar];
+
+ // This will run in another thread spawned in OCaml and will return immediately
+ // We'll get a call back to syncComplete() when it is complete
+ ocamlCall("x", "unisonSynchronize");
+}
+
+- (IBAction)syncButton:(id)sender
+{
+ [self doSync];
+}
+
+
+- (void)afterUpdate:(id)retainedReconItems
+{
+ // NSLog(@"In afterUpdate:...");
+ [self updateReconItems:retainedReconItems];
+ [retainedReconItems release];
+
+ [notificationController updateFinishedFor:[self profile]];
+
+ // label the left and right columns with the roots
+ NSString *leftHost = [(NSString *)ocamlCall("S", "unisonFirstRootString") trim];
+ NSString *rightHost = [(NSString *)ocamlCall("S", "unisonSecondRootString") trim];
+ /*
+ [[[tableView tableColumnWithIdentifier:@"left"] headerCell] setObjectValue:lefthost];
+ [[[tableView tableColumnWithIdentifier:@"right"] headerCell] setObjectValue:rightHost];
+ */
+ [mainWindow setTitle: [NSString stringWithFormat:@"Unison: %@ (%@ <-> %@)",
+ [self profile], leftHost, rightHost]];
+
+ // initial sort
+ [tableView setSortDescriptors:[NSArray arrayWithObjects:
+ [[tableView tableColumnWithIdentifier:@"fileSizeString"] sortDescriptorPrototype],
+ [[tableView tableColumnWithIdentifier:@"path"] sortDescriptorPrototype],
+ nil]];
+
+ [self updateTableViewWithReset:([reconItems count] > 0)];
+ [self updateToolbar];
+ isBatchSet = (long)ocamlCall("i", "isBatchSet") ? YES : NO;
+ if (isBatchSet) {
+ NSLog(@"batch set on the command line");
+ }
+ else {
+ NSLog(@"batch not set on the command line");
+ }
+
+ if (isBatchSet) {
+ [self doSync];
+ }
+}
+
+CAMLprim value unisonInit2Complete(value v)
+{
+ id pool = [[NSAutoreleasePool alloc] init];
+ [me performSelectorOnMainThread:@selector(afterUpdate:) withObject:[[OCamlValue alloc] initWithValue:v] waitUntilDone:FALSE];
+ [pool release];
+ return Val_unit;
+}
+
+- (void)afterSync:(id)ignore
+{
+ [notificationController syncFinishedFor:[self profile]];
+ duringSync = NO;
+ afterSync = YES;
+ [self updateToolbar];
+
+ int i;
+ for (i = 0; i < [reconItems count]; i++) {
+ [[reconItems objectAtIndex:i] resetProgress];
+ }
+
+ [self updateTableViewSelection];
+
+ [self updateTableViewWithReset:FALSE];
+}
+
+- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
+{
+ [_timer invalidate];
+
+ switch (returnCode) {
+ case NSAlertAlternateReturn:
+ return;
+ break;
+
+ default:
+ [[NSApplication sharedApplication] performSelector: @selector(terminate:) withObject: nil afterDelay: 0.0];
+ break;
+ }
+}
+
+- (void)updateCountdown
+{
+ if (_secondsRemaining == 0) {
+ [_timer invalidate];
+ [[_timeoutAlert window] orderOut: nil];
+ [self alertDidEnd: _timeoutAlert returnCode: NSAlertDefaultReturn contextInfo: nil];
+ } else {
+ [_timeoutAlert setMessageText: [NSString stringWithFormat: @"Unison will quit in %lu seconds", _secondsRemaining]];
+ _secondsRemaining--;
+ }
+}
+
+
+- (void)quitIfBatch:(id)ignore
+{
+ if (isBatchSet) {
+ NSLog(@"Automatically quitting because of -batch");
+ _timeoutAlert = [NSAlert alertWithMessageText: @"" defaultButton: @"Quit" alternateButton: @"Cancel" otherButton: nil informativeTextWithFormat: @""];
+
+ _secondsRemaining = 10;
+
+ _timer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(updateCountdown) userInfo: nil repeats: YES];
+
+ [_timeoutAlert beginSheetModalForWindow: mainWindow modalDelegate: self didEndSelector: @selector(alertDidEnd:returnCode:contextInfo:) contextInfo: NULL];
+ }
+}
+
+// TODO: (BCP, 3/2012) Note that the string literal "~/unison.log" here is wrong --
+// this is a user-settable preference (in ubase/trace.ml) and we should ask for its value.
+CAMLprim value syncComplete()
+{
+ id pool = [[NSAutoreleasePool alloc] init];
+ [me performSelectorOnMainThread:@selector(afterSync:) withObject:nil waitUntilDone:FALSE];
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"deleteLogOnExit"])
+ [[NSFileManager defaultManager] removeItemAtPath:[@"~/unison.log" stringByExpandingTildeInPath] error:nil];
+ [pool release];
+
+ [me performSelectorOnMainThread:@selector(quitIfBatch:) withObject:nil waitUntilDone:FALSE];
+
+ return Val_unit;
+}
+
+// A function called from ocaml
+- (void)reloadTable:(NSNumber *)i
+{
+ // NSLog(@"*** ReloadTable: %i", [i intValue]);
+
+ [[reconItems objectAtIndex:[i intValue]] resetProgress];
+ [self updateTableViewWithReset:FALSE];
+}
+
+CAMLprim value reloadTable(value row)
+{
+ id pool = [[NSAutoreleasePool alloc] init];
+ // NSLog(@"OCaml says... ReloadTable: %i", Int_val(row));
+ NSNumber *num = [[NSNumber alloc] initWithInt:Int_val(row)];
+ [me performSelectorOnMainThread:@selector(reloadTable:) withObject:num waitUntilDone:FALSE];
+ [num release];
+ [pool release];
+ return Val_unit;
+}
+
+- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
+ if (item == nil) item = rootItem;
+ return [[item children] count];
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
+ return [item isKindOfClass:[ParentReconItem class]];
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item {
+ if (item == nil) item = rootItem;
+ return [[item children] objectAtIndex:index];
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
+ NSString *identifier = [tableColumn identifier];
+ if (item == nil) item = rootItem;
+
+ if ([identifier isEqualToString:@"percentTransferred"] && (!duringSync && !afterSync)) return nil;
+
+ return [item valueForKey:identifier];
+}
+
+static NSDictionary *_SmallGreyAttributes = nil;
+
+- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
+ NSString *identifier = [tableColumn identifier];
+ if ([identifier isEqualToString:@"path"]) {
+ // The file icon
+ [(ImageAndTextCell*)cell setImage:[item fileIcon]];
+
+ // For parents, format the file count into the text
+ long fileCount = [item fileCount];
+ if (fileCount > 1) {
+ NSString *countString = [NSString stringWithFormat:@" (%ld files)", fileCount];
+ NSString *fullString = [(NSString *)[cell objectValue] stringByAppendingString:countString];
+ NSMutableAttributedString *as = [[NSMutableAttributedString alloc] initWithString:fullString];
+
+ if (!_SmallGreyAttributes) {
+ NSColor *txtColor = [NSColor grayColor];
+ NSFont *txtFont = [NSFont systemFontOfSize:9.0];
+ _SmallGreyAttributes = [[NSDictionary dictionaryWithObjectsAndKeys:txtFont,
+ NSFontAttributeName, txtColor, NSForegroundColorAttributeName, nil] retain];
+ }
+ [as setAttributes:_SmallGreyAttributes range:NSMakeRange([fullString length] - [countString length], [countString length])];
+ [cell setAttributedStringValue:as];
+ [as release];
+ }
+ } else if ([identifier isEqualToString:@"percentTransferred"]) {
+ [(ProgressCell*)cell setIcon:[item direction]];
+ [(ProgressCell*)cell setStatusString:[item progressString]];
+ [(ProgressCell*)cell setIsActive:[item isKindOfClass:[LeafReconItem class]]];
+ }
+}
+
+- (void)outlineView:(NSOutlineView *)outlineView
+ sortDescriptorsDidChange:(NSArray *)oldDescriptors {
+ NSArray *originalSelection = [outlineView selectedObjects];
+
+ // do we want to catch case of object changes to allow resort in same direction for progress / direction?
+ // Could check if our objects change and if the first item at the head of new and old were the same
+ [rootItem sortUsingDescriptors:[outlineView sortDescriptors]];
+ [outlineView reloadData];
+ [outlineView setSelectedObjects:originalSelection];
+}
+
+// Delegate methods
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item {
+ return NO;
+}
+
+- (NSMutableArray *)reconItems // used in ReconTableView only
+{
+ return reconItems;
+}
+
+- (int)tableMode
+{
+ return [tableModeSelector selectedSegment];
+}
+
+- (IBAction)tableModeChanged:(id)sender
+{
+ [[NSUserDefaults standardUserDefaults] setInteger:[self tableMode]+1 forKey:@"TableLayout"];
+ [self updateForChangedItems];
+}
+
+- (void)initTableMode
+{
+ int mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"TableLayout"] - 1;
+ if (mode == -1) mode = 1;
+ [tableModeSelector setSelectedSegment:mode];
+}
+
+- (void)updateReconItems:(OCamlValue *)caml_reconItems
+{
+ [reconItems release];
+ reconItems = [[NSMutableArray alloc] init];
+ long i, n =[caml_reconItems count];
+ for (i=0; i<n; i++) {
+ LeafReconItem *item = [[LeafReconItem alloc] initWithRiAndIndex:(id)[caml_reconItems getField:i withType:'@'] index:i];
+ [reconItems addObject:item];
+ [item release];
+ }
+ [self updateForChangedItems];
+}
+
+- (void)expandConflictedParent:(ParentReconItem *)parent
+{
+ if ([parent hasConflictedChildren]) {
+ // NSLog(@"Expanding conflictedParent: %@", [parent fullPath]);
+ [tableView expandItem:parent expandChildren:NO];
+ NSArray *children = [parent children];
+ int i = 0, count = [children count];
+ for (;i < count; i++) {
+ id child = [children objectAtIndex:i];
+ if ([child isKindOfClass:[ParentReconItem class]]) [self expandConflictedParent:child];
+ }
+ }
+}
+
+- (void)updateForChangedItems
+{
+ int tableMode = [self tableMode];
+
+ [rootItem release];
+ ParentReconItem *root = rootItem = [[ParentReconItem alloc] init];
+
+ if (tableMode != 0 && [reconItems count]) {
+ // Special roll-up root item for outline displays
+ root = [[ParentReconItem alloc] init];
+ [rootItem addChild:root nested:NO];
+ [root setPath:@"All Changes..."];
+ [root setFullPath:@""];
+ [root release];
+ }
+
+ int j = 0, n =[reconItems count];
+ for (; j<n; j++) {
+ [root addChild:[reconItems objectAtIndex:j] nested:(tableMode != 0)];
+ }
+
+ if (tableMode == 1) [root collapseParentsWithSingleChildren:YES];
+
+ [tableView reloadData];
+
+ if (NO) {
+ // Pre-expand entire tree
+ int i = [[rootItem children] count];
+ while (i--) {
+ [tableView expandItem:[[rootItem children] objectAtIndex:i] expandChildren:YES];
+ }
+ } else if (tableMode != 0) {
+ // Always open root node
+ [tableView expandItem:rootItem expandChildren:NO];
+
+ // then smart expand to reveal conflicts / changes in direction
+ [self expandConflictedParent:root];
+
+ // then open more levels if we can do so without causing scrolling
+ [tableView expandChildrenIfSpace];
+ }
+
+ // Make sure details get updated (or cleared)
+ [self updateTableViewSelection];
+
+ // Only enable sync if there are reconitems
+ if ([reconItems count]>0) {
+ [tableView setEditable:YES];
+
+ // reconItems table gets keyboard input
+ [mainWindow makeFirstResponder:tableView];
+
+ syncable = YES;
+ }
+ else {
+ [tableView setEditable:NO];
+ afterSync = YES; // rescan should be enabled
+
+ // reconItems table no longer gets keyboard input
+ [mainWindow makeFirstResponder:nil];
+ }
+ [self updateToolbar];
+}
+
+- (id)updateForIgnore:(id)item
+{
+ long j = (long)ocamlCall("ii", "unisonUpdateForIgnore", [reconItems indexOfObjectIdenticalTo:item]);
+ NSLog(@"Updating for ignore...");
+ [self updateReconItems:(OCamlValue *)ocamlCall("@", "unisonState")];
+ return [reconItems objectAtIndex:j];
+}
+
+// A function called from ocaml
+CAMLprim value displayStatus(value s)
+{
+ id pool = [[NSAutoreleasePool alloc] init];
+ NSString *str = [[NSString alloc] initWithUTF8String:String_val(s)];
+ // NSLog(@"displayStatus: %@", str);
+ [me performSelectorOnMainThread:@selector(statusTextSet:) withObject:str waitUntilDone:FALSE];
+ [str release];
+ [pool release];
+ return Val_unit;
+}
+
+- (void)statusTextSet:(NSString *)s {
+ /* filter out strings with # reconitems, and empty strings */
+ if (!NSEqualRanges([s rangeOfString:@"reconitems"],
+ NSMakeRange(NSNotFound,0))) return;
+ [statusText setStringValue:s];
+}
+
+// Called from ocaml to dislpay progress bar
+CAMLprim value displayGlobalProgress(value p)
+{
+ id pool = [[NSAutoreleasePool alloc] init];
+ NSNumber *num = [[NSNumber alloc] initWithDouble:Double_val(p)];
+ [me performSelectorOnMainThread:@selector(updateProgressBar:)
+ withObject:num waitUntilDone:FALSE];
+ [num release];
+ [pool release];
+ return Val_unit;
+}
+
+// Called from ocaml to display diff
+CAMLprim value displayDiff(value s, value s2)
+{
+ id pool = [[NSAutoreleasePool alloc] init];
+ [me performSelectorOnMainThread:@selector(diffViewTextSet:)
+ withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:String_val(s)],
+ [NSString stringWithUTF8String:String_val(s2)], nil]
+ waitUntilDone:FALSE];
+ [pool release];
+ return Val_unit;
+}
+
+// Called from ocaml to display diff error messages
+CAMLprim value displayDiffErr(value s)
+{
+ id pool = [[NSAutoreleasePool alloc] init];
+ NSString * str = [NSString stringWithUTF8String:String_val(s)];
+ str = [[str componentsSeparatedByString:@"\n"] componentsJoinedByString:@" "];
+ [me->statusText performSelectorOnMainThread:@selector(setStringValue:)
+ withObject:str waitUntilDone:FALSE];
+ [pool release];
+ return Val_unit;
+}
+
+- (void)diffViewTextSet:(NSArray *)args
+{
+ [self diffViewTextSet:[args objectAtIndex:0] bodyText:[args objectAtIndex:1]];
+}
+
+- (void)diffViewTextSet:(NSString *)title bodyText:(NSString *)body {
+ if ([body length]==0) return;
+ [diffWindow setTitle:title];
+ //[diffView setFont:diffFont];
+ [diffView setString:body];
+ if (!doneFirstDiff) {
+ /* On first open, position the diff window to the right of
+ the main window, but without going off the mainwindow's screen */
+ float screenOriginX = [[mainWindow screen] visibleFrame].origin.x;
+ float screenWidth = [[mainWindow screen] visibleFrame].size.width;
+ float mainOriginX = [mainWindow frame].origin.x;
+ float mainOriginY = [mainWindow frame].origin.y;
+ float mainWidth = [mainWindow frame].size.width;
+ float mainHeight = [mainWindow frame].size.height;
+ float diffWidth = [diffWindow frame].size.width;
+
+ float diffX = mainOriginX+mainWidth;
+ float maxX = screenOriginX+screenWidth-diffWidth;
+ if (diffX > maxX) diffX = maxX;
+ float diffY = mainOriginY + mainHeight;
+
+ NSPoint diffOrigin = NSMakePoint(diffX,diffY);
+ [diffWindow cascadeTopLeftFromPoint:diffOrigin];
+
+ doneFirstDiff = YES;
+ }
+ [diffWindow orderFront:nil];
+}
+
+- (void)displayDetails:(ReconItem *)item
+{
+ //[detailsTextView setFont:diffFont];
+ NSString *text = [item details];
+ if (!text) text = @"";
+ [detailsTextView setStringValue:text];
+}
+
+- (void)clearDetails
+{
+ [detailsTextView setStringValue:@""];
+}
+
+- (IBAction)raiseCltoolWindow:(id)sender
+{
+ [cltoolPref setState:[[NSUserDefaults standardUserDefaults] boolForKey:@"CheckCltool"] ? NSOffState : NSOnState];
+ [self raiseWindow: cltoolWindow];
+}
+
+- (IBAction)cltoolYesButton:(id)sender;
+{
+ [[NSUserDefaults standardUserDefaults] setBool:([cltoolPref state] != NSOnState) forKey:@"CheckCltool"];
+ [self installCommandLineTool:self];
+ [cltoolWindow close];
+}
+
+- (IBAction)cltoolNoButton:(id)sender;
+{
+ [[NSUserDefaults standardUserDefaults] setBool:([cltoolPref state] != NSOnState) forKey:@"CheckCltool"];
+ [cltoolWindow close];
+}
+
+- (IBAction)raiseAboutWindow:(id)sender
+{
+ [self raiseWindow: aboutWindow];
+}
+
+- (void)raiseWindow:(NSWindow *)theWindow
+{
+ NSRect screenFrame = [[mainWindow screen] visibleFrame];
+ NSRect mainWindowFrame = [mainWindow frame];
+ NSRect theWindowFrame = [theWindow frame];
+
+ float winX = mainWindowFrame.origin.x +
+ (mainWindowFrame.size.width - theWindowFrame.size.width)/2;
+ float winY = mainWindowFrame.origin.y +
+ (mainWindowFrame.size.height + theWindowFrame.size.height)/2;
+
+ if (winX<screenFrame.origin.x) winX=screenFrame.origin.x;
+ float maxX = screenFrame.origin.x+screenFrame.size.width-
+ theWindowFrame.size.width;
+ if (winX>maxX) winX=maxX;
+ float minY = screenFrame.origin.y+theWindowFrame.size.height;
+ if (winY<minY) winY=minY;
+ float maxY = screenFrame.origin.y+screenFrame.size.height;
+ if (winY>maxY) winY=maxY;
+
+ [theWindow cascadeTopLeftFromPoint:
+ NSMakePoint(winX,winY)];
+
+ [theWindow makeKeyAndOrderFront:nil];
+}
+
+- (IBAction)onlineHelp:(id)sender
+{
+ [[NSWorkspace sharedWorkspace]
+ openURL:[NSURL URLWithString:@"http://www.cis.upenn.edu/~bcpierce/unison/docs.html"]];
+}
+
+/* from http://developer.apple.com/documentation/Security/Conceptual/authorization_concepts/index.html */
+#include <Security/Authorization.h>
+#include <Security/AuthorizationTags.h>
+- (IBAction)installCommandLineTool:(id)sender
+{
+ /* Install the command-line tool in /usr/bin/unison.
+ Requires root privilege, so we ask for it and
+ pass the task off to /bin/sh. */
+
+ OSStatus myStatus;
+
+ AuthorizationFlags myFlags = kAuthorizationFlagDefaults;
+ AuthorizationRef myAuthorizationRef;
+ myStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
+ myFlags, &myAuthorizationRef);
+ if (myStatus != errAuthorizationSuccess) return;
+
+ {
+ AuthorizationItem myItems = {kAuthorizationRightExecute, 0,
+ NULL, 0};
+ AuthorizationRights myRights = {1, &myItems};
+ myFlags = kAuthorizationFlagDefaults |
+ kAuthorizationFlagInteractionAllowed |
+ kAuthorizationFlagPreAuthorize |
+ kAuthorizationFlagExtendRights;
+ myStatus =
+ AuthorizationCopyRights(myAuthorizationRef,&myRights,NULL,myFlags,NULL);
+ }
+ if (myStatus == errAuthorizationSuccess) {
+ NSBundle *bundle = [NSBundle mainBundle];
+ NSString *bundle_path = [bundle bundlePath];
+ NSString *exec_path =
+ [bundle_path stringByAppendingString:@"/Contents/MacOS/cltool"];
+ // Not sure why but this doesn't work:
+ // [bundle pathForResource:@"cltool" ofType:nil];
+
+ if (exec_path == nil) return;
+ char *args[] = { "-f", (char *)[exec_path UTF8String],
+ "/usr/bin/unison", NULL };
+
+ myFlags = kAuthorizationFlagDefaults;
+ myStatus = AuthorizationExecuteWithPrivileges
+ (myAuthorizationRef, "/bin/cp", myFlags, args,
+ NULL);
+ }
+ AuthorizationFree (myAuthorizationRef, kAuthorizationFlagDefaults);
+
+ /*
+ if (myStatus == errAuthorizationCanceled)
+ NSLog(@"The attempt was canceled\n");
+ else if (myStatus)
+ NSLog(@"There was an authorization error: %ld\n", myStatus);
+ */
+}
+
+- (BOOL)validateItem:(IBAction *) action
+{
+ if (action == @selector(syncButton:)) return syncable;
+ // FIXME Restarting during sync is disabled because it causes UI corruption
+ else if (action == @selector(restartButton:)) return !duringSync;
+ else if (action == @selector(rescan:)) return ((syncable && !duringSync) || afterSync);
+ else return YES;
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
+{
+ return [self validateItem:[menuItem action]];
+}
+
+- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
+{
+ return [self validateItem:[toolbarItem action]];
+}
+
+- (void)resizeWindowToSize:(NSSize)newSize
+{
+ NSRect aFrame;
+
+ float newHeight = newSize.height+[self toolbarHeightForWindow:mainWindow];
+ float newWidth = newSize.width;
+
+ aFrame = [NSWindow contentRectForFrameRect:[mainWindow frame]
+ styleMask:[mainWindow styleMask]];
+
+ aFrame.origin.y += aFrame.size.height;
+ aFrame.origin.y -= newHeight;
+ aFrame.size.height = newHeight;
+ aFrame.size.width = newWidth;
+
+ aFrame = [NSWindow frameRectForContentRect:aFrame
+ styleMask:[mainWindow styleMask]];
+
+ [mainWindow setFrame:aFrame display:YES animate:YES];
+}
+
+- (float)toolbarHeightForWindow:(NSWindow *)window
+{
+ NSToolbar *aToolbar;
+ float toolbarHeight = 0.0;
+ NSRect windowFrame;
+
+ aToolbar = [window toolbar];
+ if(aToolbar && [aToolbar isVisible])
+ {
+ windowFrame = [NSWindow contentRectForFrameRect:[window frame]
+ styleMask:[window styleMask]];
+ toolbarHeight = NSHeight(windowFrame)
+ - NSHeight([[window contentView] frame]);
+ }
+ return toolbarHeight;
+}
+
+CAMLprim value fatalError(value s)
+{
+ NSString *str = [[NSString alloc] initWithUTF8String:String_val(s)];
+
+ [me performSelectorOnMainThread:@selector(fatalError:) withObject:str waitUntilDone:FALSE];
+ [str release];
+ return Val_unit;
+}
+
+- (void)fatalError:(NSString *)msg {
+ NSRunAlertPanel(@"Fatal error", msg, @"Exit", nil, nil);
+ exit(1);
+}
+
+/* Returns true if we need to exit, false if we proceed */
+
+CAMLprim value warnPanel(value s)
+{
+ NSString *str = [[NSString alloc] initWithUTF8String:String_val(s)];
+
+ [me performSelectorOnMainThread:@selector(warnPanel:) withObject:str waitUntilDone:TRUE];
+ [str release];
+ if (me -> shouldExitAfterWarning) {
+ return Val_true;
+ } else {
+ return Val_false;
+ }
+}
+
+- (void)warnPanel:(NSString *)msg {
+ int warnVal = NSRunAlertPanel(@"Warning", msg, @"Proceed", @"Exit", nil);
+ NSLog(@"Warning Panel Returned %d",warnVal);
+ if (warnVal == NSAlertAlternateReturn) {
+ shouldExitAfterWarning = YES;
+ } else {
+ shouldExitAfterWarning = FALSE;
+ }
+}
+
+ at end
+
+ at implementation NSString (_UnisonUtil)
+- (NSString *)trim
+{
+ NSCharacterSet *ws = [NSCharacterSet whitespaceCharacterSet];
+ int len = [self length], i = len;
+ while (i && [ws characterIsMember:[self characterAtIndex:i-1]]) i--;
+ return (i == len) ? self : [self substringToIndex:i];
+}
+ at end
More information about the Unison-hackers
mailing list