Set up the atom.repository-provider service and implement GitRepositoryProvider.

I tested this by creating a dummy implementation of an `HgRepositoryProvider`
(with the optional `createRepositorySync()` method implemented) and an `HgRepository`
in an Atom package with the following stanza in the `package.json`:

```
  "providedServices": {
    "atom.repository-provider": {
      "versions": {
        "0.1.0": "createHgRepositoryProvider"
      }
    }
  },
```

I opened a path with an Hg repository from the command line using Atom.
I verified that `atom.project.repositoryProviders` contains both a
`GitRepositoryProvider` and an `HgRepositoryProvider`.

I also verified that running the following printed out an `HgRepository`:

```
var Directory = require('pathwatcher').Directory;
atom.project.repositoryForDirectory(
    new Directory(atom.project.getPath(), /* symlink */ false)).then(
        function(repo) { console.log('repo: %o', repo); });
```

One thing that stands out to me about the current API for the
atom.repository-provider service is that the function used to create
a `RepositoryProvider` does not receive any arguments. If the creation
of the `GitRepositoryProvider` were done via the service, this would
be a problem because it needs a reference to `atom.project`, which is
not defined when it is created. (We work around this because it is
created in `Project`'s constructor, so it can pass `this` to
`new GitRepositoryProvider()`.)

We would have to create a `RepositoryProviderFactory` or something if
we wanted to specify arguments when creating a `RepositoryProvider`,
in general. Maybe that's too crazy / not an issue, in practice.

Though note that `GitRepository` cannot access `atom.project` lazily
because it uses it in its constructor to do the following:

```
if @project?
  @subscriptions.add @project.eachBuffer (buffer) => @subscribeToBuffer(buffer)
```

So long as we can guarantee that `atom.project` is defined before the
other providers are initialized, I think we should be OK.

Follow-up work:
* Replace the use of `RepositoryProvider.createRepositorySync()` with
`RepositoryProvider.repositoryForDirectory()` in `Project.setPaths()`.
* Replace all uses of `Project.getRepositories()` with
`Project.repositoryForDirectory()` in packages that are bundled with Atom
by default.
* Implement `Directory.exists()` and/or `Directory.existsSync()` and update
`git-repositor-provider.coffee`, as appropriate.
* Eliminate `GitRepositoryProvider.repositoryForDirectory()`'s use of
synchronous methods.
* Somewhat orthogonal to this diff, but the following fields need to be
removed from `Project` because they enforce the idea of a single root:
`path`, `rootDirectory`, and `repo`. This has implications around the
existing use of `@rootDirectory?.off()` and `@destroyRepo()`.
This commit is contained in:
Michael Bolin
2015-02-10 17:43:59 -05:00
parent 04d015a7e0
commit e04f17fe5f
3 changed files with 150 additions and 6 deletions

View File

@@ -101,8 +101,13 @@ class GitRepository
# Public: Destroy this {GitRepository} object.
#
# This destroys any tasks and subscriptions and releases the underlying
# libgit2 repository handle.
# libgit2 repository handle. This method is idempotent.
destroy: ->
if @emitter?
@emitter.emit 'did-destroy'
@emitter.off()
@emitter = null
if @statusTask?
@statusTask.terminate()
@statusTask = null
@@ -111,7 +116,14 @@ class GitRepository
@repo.release()
@repo = null
@subscriptions.dispose()
if @subscriptions?
@subscriptions.dispose()
@subscriptions = null
# Public: Invoke the given callback when this GitRepository's destroy() method
# is invoked.
onDestroy: (callback) ->
@emitter.on 'did-destroy', callback
###
Section: Event Subscription