Merge pull request #9213 from atom/dh-async-repo

Async Git Repository class
This commit is contained in:
Josh Abernathy
2016-01-15 16:17:41 -05:00
129 changed files with 12134 additions and 43 deletions

1028
src/git-repository-async.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -77,7 +77,7 @@ class GitRepositoryProvider
unless repo
repo = GitRepository.open(gitDirPath, {@project, @config})
return null unless repo
repo.onDidDestroy(=> delete @pathToRepository[gitDirPath])
repo.async.onDidDestroy(=> delete @pathToRepository[gitDirPath])
@pathToRepository[gitDirPath] = repo
repo.refreshIndex()
repo.refreshStatus()

View File

@@ -3,6 +3,7 @@
_ = require 'underscore-plus'
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
fs = require 'fs-plus'
GitRepositoryAsync = require './git-repository-async'
GitUtils = require 'git-utils'
Task = require './task'
@@ -75,6 +76,13 @@ class GitRepository
unless @repo?
throw new Error("No Git repository found searching path: #{path}")
asyncOptions = _.clone(options)
# GitRepository itself will handle these cases by manually calling through
# to the async repo.
asyncOptions.refreshOnWindowFocus = false
asyncOptions.subscribeToBuffers = false
@async = GitRepositoryAsync.open(path, asyncOptions)
@statuses = {}
@upstream = {ahead: 0, behind: 0}
for submodulePath, submoduleRepo of @repo.submodules
@@ -117,6 +125,10 @@ class GitRepository
@subscriptions.dispose()
@subscriptions = null
if @async?
@async.destroy()
@async = null
# Public: Invoke the given callback when this GitRepository's destroy() method
# is invoked.
#
@@ -316,6 +328,9 @@ class GitRepository
# Returns a {Number} representing the status. This value can be passed to
# {::isStatusModified} or {::isStatusNew} to get more information.
getPathStatus: (path) ->
# Trigger events emitted on the async repo as well
@async.refreshStatusForPath(path)
repo = @getRepo(path)
relativePath = @relativize(path)
currentPathStatus = @statuses[relativePath] ? 0
@@ -460,27 +475,35 @@ class GitRepository
# Refreshes the current git status in an outside process and asynchronously
# updates the relevant properties.
#
# Returns a promise that resolves when the repository has been refreshed.
refreshStatus: ->
@handlerPath ?= require.resolve('./repository-status-handler')
asyncRefresh = @async.refreshStatus()
syncRefresh = new Promise (resolve, reject) =>
@handlerPath ?= require.resolve('./repository-status-handler')
relativeProjectPaths = @project?.getPaths()
.map (path) => @relativize(path)
.filter (path) -> path.length > 0
relativeProjectPaths = @project?.getPaths()
.map (path) => @relativize(path)
.filter (path) -> path.length > 0
@statusTask?.terminate()
@statusTask = Task.once @handlerPath, @getPath(), relativeProjectPaths, ({statuses, upstream, branch, submodules}) =>
statusesUnchanged = _.isEqual(statuses, @statuses) and
_.isEqual(upstream, @upstream) and
_.isEqual(branch, @branch) and
_.isEqual(submodules, @submodules)
@statusTask?.terminate()
@statusTask = Task.once @handlerPath, @getPath(), relativeProjectPaths, ({statuses, upstream, branch, submodules}) =>
statusesUnchanged = _.isEqual(statuses, @statuses) and
_.isEqual(upstream, @upstream) and
_.isEqual(branch, @branch) and
_.isEqual(submodules, @submodules)
@statuses = statuses
@upstream = upstream
@branch = branch
@submodules = submodules
@statuses = statuses
@upstream = upstream
@branch = branch
@submodules = submodules
for submodulePath, submoduleRepo of @getRepo().submodules
submoduleRepo.upstream = submodules[submodulePath]?.upstream ? {ahead: 0, behind: 0}
for submodulePath, submoduleRepo of @getRepo().submodules
submoduleRepo.upstream = submodules[submodulePath]?.upstream ? {ahead: 0, behind: 0}
unless statusesUnchanged
@emitter.emit 'did-change-statuses'
resolve()
unless statusesUnchanged
@emitter.emit 'did-change-statuses'
return Promise.all([asyncRefresh, syncRefresh])

View File

@@ -706,7 +706,7 @@ class TextEditor extends Model
checkoutHead = =>
@project.repositoryForDirectory(new Directory(@getDirectoryPath()))
.then (repository) =>
repository?.checkoutHeadForEditor(this)
repository?.async.checkoutHeadForEditor(this)
if @config.get('editor.confirmCheckoutHeadRevision')
@applicationDelegate.confirm

View File

@@ -85,9 +85,9 @@ Tooltip.prototype.init = function (element, options) {
}
}
this.options.selector ?
(this._options = extend({}, this.options, { trigger: 'manual', selector: '' })) :
this.fixTitle()
this.options.selector
? (this._options = extend({}, this.options, { trigger: 'manual', selector: '' }))
: this.fixTitle()
}
Tooltip.prototype.getDefaults = function () {
@@ -190,9 +190,9 @@ Tooltip.prototype.show = function () {
if (this.options.animation) tip.classList.add('fade')
var placement = typeof this.options.placement === 'function' ?
this.options.placement.call(this, tip, this.element) :
this.options.placement
var placement = typeof this.options.placement === 'function'
? this.options.placement.call(this, tip, this.element)
: this.options.placement
var autoToken = /\s?auto?\s?/i
var autoPlace = autoToken.test(placement)
@@ -214,11 +214,11 @@ Tooltip.prototype.show = function () {
var orgPlacement = placement
var viewportDim = this.viewport.getBoundingClientRect()
placement = placement === 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
placement === 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
placement === 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
placement === 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
placement
placement = placement === 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'
: placement === 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom'
: placement === 'right' && pos.right + actualWidth > viewportDim.width ? 'left'
: placement === 'left' && pos.left - actualWidth < viewportDim.left ? 'right'
: placement
tip.classList.remove(orgPlacement)
tip.classList.add(placement)
@@ -330,10 +330,10 @@ Tooltip.prototype.hasContent = function () {
}
Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
return placement === 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
placement === 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
placement === 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
/* placement === 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
return placement === 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 }
: placement === 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 }
: placement === 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth }
:/* placement === 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
}
Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {