Remove synchronous GitRepository's dependency on GitRepositoryAsync

Signed-off-by: Nathan Sobo <nathan@github.com>
This commit is contained in:
Max Brunsfeld 2016-07-13 14:02:05 -07:00 committed by Nathan Sobo
parent a4b9e94d7b
commit 7b11c31e07
5 changed files with 43 additions and 93 deletions

View File

@ -33,7 +33,7 @@ function copySubmoduleRepository () {
return workingDirectory
}
describe('GitRepositoryAsync', () => {
fdescribe('GitRepositoryAsync', () => {
let repo
afterEach(() => {

View File

@ -259,36 +259,6 @@ describe "GitRepository", ->
expect(repo.isStatusModified(status)).toBe false
expect(repo.isStatusNew(status)).toBe false
it 'caches the proper statuses when multiple project are open', ->
otherWorkingDirectory = copyRepository()
atom.project.setPaths([workingDirectory, otherWorkingDirectory])
waitsForPromise ->
atom.workspace.open('b.txt')
statusHandler = null
runs ->
repo = atom.project.getRepositories()[0]
statusHandler = jasmine.createSpy('statusHandler')
repo.onDidChangeStatuses statusHandler
repo.refreshStatus()
waitsFor ->
statusHandler.callCount > 0
runs ->
subDir = path.join(workingDirectory, 'dir')
fs.mkdirSync(subDir)
filePath = path.join(subDir, 'b.txt')
fs.writeFileSync(filePath, '')
status = repo.getCachedPathStatus(filePath)
expect(repo.isStatusModified(status)).toBe true
expect(repo.isStatusNew(status)).toBe false
it 'caches statuses that were looked up synchronously', ->
originalContent = 'undefined'
fs.writeFileSync(modifiedPath, 'making this path modified')

View File

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

View File

@ -83,12 +83,11 @@ class GitRepository
asyncOptions.subscribeToBuffers = false
@async = GitRepositoryAsync.open(path, asyncOptions)
@statuses = {}
@upstream = {ahead: 0, behind: 0}
for submodulePath, submoduleRepo of @repo.submodules
submoduleRepo.upstream = {ahead: 0, behind: 0}
@statusesByPath = {}
{@project, @config, refreshOnWindowFocus} = options
refreshOnWindowFocus ?= true
@ -126,14 +125,6 @@ class GitRepository
@subscriptions.dispose()
@subscriptions = null
if @async?
@async.destroy()
@async = null
# Public: Returns a {Boolean} indicating if this repository has been destroyed.
isDestroyed: ->
not @repo?
# Public: Invoke the given callback when this GitRepository's destroy() method
# is invoked.
#
@ -322,7 +313,7 @@ class GitRepository
getDirectoryStatus: (directoryPath) ->
directoryPath = "#{@relativize(directoryPath)}/"
directoryStatus = 0
for path, status of Object.assign({}, @async.getCachedPathStatuses(), @statusesByPath)
for path, status of @statuses
directoryStatus |= status if path.indexOf(directoryPath) is 0
directoryStatus
@ -335,24 +326,13 @@ class GitRepository
getPathStatus: (path) ->
repo = @getRepo(path)
relativePath = @relativize(path)
# This is a bit particular. If a package calls `getPathStatus` like this:
# - change the file
# - getPathStatus
# - change the file
# - getPathStatus
# We need to preserve the guarantee that each call to `getPathStatus` will
# synchronously emit 'did-change-status'. So we need to keep a cache of the
# statuses found from this call.
currentPathStatus = @getCachedRelativePathStatus(relativePath) ? 0
# Trigger events emitted on the async repo as well
@async.refreshStatusForPath(path)
currentPathStatus = @statuses[relativePath] ? 0
pathStatus = repo.getStatus(repo.relativize(path)) ? 0
pathStatus = 0 if repo.isStatusIgnored(pathStatus)
@statusesByPath[relativePath] = pathStatus
if pathStatus > 0
@statuses[relativePath] = pathStatus
else
delete @statuses[relativePath]
if currentPathStatus isnt pathStatus
@emitter.emit 'did-change-status', {path, pathStatus}
@ -364,11 +344,7 @@ class GitRepository
#
# Returns a status {Number} or null if the path is not in the cache.
getCachedPathStatus: (path) ->
relativePath = @relativize(path)
@getCachedRelativePathStatus(relativePath)
getCachedRelativePathStatus: (relativePath) ->
@statusesByPath[relativePath] ? @async.getCachedPathStatuses()[relativePath]
@statuses[@relativize(path)]
# Public: Returns true if the given status indicates modification.
#
@ -492,42 +468,29 @@ 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: ->
statusesChanged = false
@handlerPath ?= require.resolve('./repository-status-handler')
# Listen for `did-change-statuses` so we know if something changed. But we
# need to wait to propagate it until after we've set the branch and cleared
# the `statusesByPath` cache. So just set a flag, and we'll emit the event
# after refresh is done.
subscription = @async.onDidChangeStatuses ->
subscription?.dispose()
subscription = null
relativeProjectPaths = @project?.getPaths()
.map (path) => @relativize(path)
.filter (path) -> path.length > 0
statusesChanged = true
@statusTask?.terminate()
new Promise (resolve) =>
@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)
asyncRefresh = @async.refreshStatus().then =>
subscription?.dispose()
subscription = null
@branch = @async?.branch
@statusesByPath = {}
if statusesChanged
@emitter.emit 'did-change-statuses'
syncRefresh = new Promise (resolve, reject) =>
@handlerPath ?= require.resolve('./repository-status-handler')
@statusTask?.terminate()
@statusTask = Task.once @handlerPath, @getPath(), ({upstream, submodules}) =>
@statuses = statuses
@upstream = upstream
@branch = branch
@submodules = submodules
for submodulePath, submoduleRepo of @getRepo().submodules
submoduleRepo.upstream = submodules[submodulePath]?.upstream ? {ahead: 0, behind: 0}
unless statusesUnchanged
@emitter.emit 'did-change-statuses'
resolve()
return Promise.all([asyncRefresh, syncRefresh])

View File

@ -5,15 +5,32 @@ module.exports = (repoPath, paths = []) ->
repo = Git.open(repoPath)
upstream = {}
statuses = {}
submodules = {}
branch = null
if repo?
# Statuses in main repo
workingDirectoryPath = repo.getWorkingDirectory()
repoStatus = (if paths.length > 0 then repo.getStatusForPaths(paths) else repo.getStatus())
for filePath, status of repoStatus
statuses[filePath] = status
# Statuses in submodules
for submodulePath, submoduleRepo of repo.submodules
submodules[submodulePath] =
branch: submoduleRepo.getHead()
upstream: submoduleRepo.getAheadBehindCount()
workingDirectoryPath = submoduleRepo.getWorkingDirectory()
for filePath, status of submoduleRepo.getStatus()
absolutePath = path.join(workingDirectoryPath, filePath)
# Make path relative to parent repository
relativePath = repo.relativize(absolutePath)
statuses[relativePath] = status
upstream = repo.getAheadBehindCount()
branch = repo.getHead()
repo.release()
{upstream, submodules}
{statuses, upstream, branch, submodules}