-
Notifications
You must be signed in to change notification settings - Fork 682
Mercurial Support
Discusses the various aspects of how Mercurial is supported in Nuclide (e.g., HgRepositoryClient
and friends)
Currently, there is support for Git and Mercurial within Nuclide. Git support is entirely provided by Atom Core via the GitRepository
class.
There is currently no support for remote Git repositories.
Mercurial support (both local and remote repositories) is implemented by the Nuclide team via the following packages:
-
nuclide-hg-repository: Atom package. This package exists because Atom consumes a service ("atom.repository-provider") through its service-hub as the way to add support for repositories other than the built-in Git. A provider for the "atom.repository-provider" service has to implement the function:
repositoryForDirectorySync(directory: Directory): ?Repository
which should return a custom implementation of a "Repository" if the givenDirectory
if possible. Sonuclide-hg-repository
provides theHgRepositoryProvider
service. TheHgRepositoryProvider
determines whether a givenDirectory
object is part of an Hg repository, and returns anHgRepositoryClient
if so. -
nuclide-hg-repository-client: npm package. Contains the
HgRepositoryClient
class, which is Nuclide's Hg version of Atom'sGitRepository
. TheHgRepositoryClient
is the "client" component of the HgService, which is a service implemented with the Nuclide service framework. The Client mostly wraps the functionality provided by theLocalHgService
, and adds caching. -
nuclide-hg-repository-base: npm package. Contains the
HgService
interface, as well as the nitty-gritty implementation of the HgService. The "service" implementation is broken up between two classes,LocalHgService
andLocalHgServiceBase
.LocalHgService
wrapsLocalHgServiceBase
and hooks intowatchman
.
The recommended way to get a reference to a Repository object when developing with Nuclide is:
var {repositoryForPath} = require('nuclide-hg-git-bridge');
var aRepo = repositoryForPath(aNuclideUri);
This method achieves the same thing as Atom's built-in method, repositoryForDirectory
, but there are two issues:
- Nuclide's
RemoteDirectory
implementation currently does not implement a method thatrepositoryForDirectory
calls, so you will hit exceptions. - Even if it did, the
repositoryForPath
will be more performant because it does not require a round-trip to the server for remote repositories.
- As of August 2015,
HgRepositoryClient
has a number of methods for parity withGitRepository
that are unimplemented stubs. Please see the code for more details. - Perhaps the most notable difference between
HgRepositoryClient
andGitRepository
is thatHgRepositoryClient
does not publicly expose any methods that fetch information from Mercurial synchronously. The synchronous method calls onHgRepositoryClient
, such asgetDirectoryStatus
, read from a cache, and thus may provide stale data. We have, however, added public asynchronous methods that provide up-to-date data:
-
getStatuses
is the async version ofgetPathStatus
. -
getDiffStatsForPath
is the async version ofgetDiffStats
. -
getLineDiffsForPath
is the async version ofgetLineDiffs
.
-
HgRepositoryClient
updates line diff information on each editor "save" event, rather than continuously. As a result, the line highlighting provided by thegit-diff
package and the number of added/removed lines displayed in the status bar may be stale in-between saves.
The available GitRepository
methods are listed in the Atom docs.
HgRepositoryClient
currently provides most of the same methods, but some methods are stubs -- not yet implemented because they haven't been needed. HgRepositoryClient
also provides methods not available on GitRepository, e.g.:
fetchCurrentBookmark
fetchFileContentAtRevision
getBlameAtHead
In general, the best way to find the available Hg methods is to read HgService
and HgRepositoryClient.js
.
You should understand how the service framework works. That being said, you can look at a simple example of a method that just fetches data without caching.
A few useful features of the Repository object (Git and Hg) are the methods:
onDidChangeStatus
onDidChangeStatuses
These methods allow Atom features that consume source control information to get notified when source control state changes, so they can update accordingly. For example, you see this in the file tree, which can highlight the new/modified/ignored status of files and directories. As part of the contract, if you ask a Repository for information after receiving these notifications, you should get updated information.
The problem for HgService
is then: We need to update the information in HgRepositoryClient
to mirror the state of the Hg repository. But how do we detect when the state of an Hg repository changes?
Our solution is to use watchman, a file-watching service developed and open-sourced by Facebook.
We use watchman to determine:
- When a regular (non-source-control, non-generated) file is modified. This is a good indication that its source control status may have changed.
- When the '.hgignore' file is modified. This is a good indication that our cached list of 'ignored' files may be outdated.
- When the '.hg/wlock' file is created/deleted. This is a lock file that is present whenever Hg is modifying the "working directory" (the Hg term for "files within the Hg repo"). We watch this lock because: ** While it's present, we want watchman to ignore any changes in the working directory, because it might be really noisy -- e.g. during a rebase. ** After it's gone, we should invalidate our caches of Hg information, because we don't know what Hg did (rebase, commit, etc).
- When the '.hg/dirstate' file is modified. This is a fallback for times when the '.hg/wlock' can't be detected, because it's around for such a short time. The dirstate is persistent, so watchman always updates us about changes to it.
- When the '.hg/bookmarks.current' file is modified. This file contains the name of the current Hg bookmark.
- When the arc build lock file is present. This works similar to '.hg/wlock', except for arc build.
Watchman enables the following methods on HgService
:
onFilesDidChange
onHgIgnoreFileDidChange
onHgBookmarkDidChange
onHgRepoStateDidChange
TODO