mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2025-01-07 15:49:23 +03:00
Merge pull request #8527 from atom/mb-add-child-root-folder
Allow adding a root folder that's within another root folder
This commit is contained in:
commit
014243637b
@ -16,103 +16,29 @@ describe "Project", ->
|
||||
# Wait for project's service consumers to be asynchronously added
|
||||
waits(1)
|
||||
|
||||
describe "constructor", ->
|
||||
it "enables a custom DirectoryProvider to supersede the DefaultDirectoryProvider", ->
|
||||
remotePath = "ssh://foreign-directory:8080/"
|
||||
class DummyDirectory
|
||||
constructor: (@path) ->
|
||||
getPath: -> @path
|
||||
getFile: -> existsSync: -> false
|
||||
getSubdirectory: -> existsSync: -> false
|
||||
isRoot: -> true
|
||||
off: ->
|
||||
contains: (filePath) -> filePath.startsWith(remotePath)
|
||||
|
||||
directoryProvider =
|
||||
directoryForURISync: (uri) ->
|
||||
if uri.startsWith("ssh://")
|
||||
new DummyDirectory(uri)
|
||||
else
|
||||
null
|
||||
directoryForURI: (uri) -> throw new Error("This should not be called.")
|
||||
atom.packages.serviceHub.provide(
|
||||
"atom.directory-provider", "0.1.0", directoryProvider)
|
||||
|
||||
tmp = temp.mkdirSync()
|
||||
atom.project.setPaths([tmp, remotePath])
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories.length).toBe 2
|
||||
|
||||
localDirectory = directories[0]
|
||||
expect(localDirectory.getPath()).toBe tmp
|
||||
expect(localDirectory instanceof Directory).toBe true
|
||||
|
||||
dummyDirectory = directories[1]
|
||||
expect(dummyDirectory.getPath()).toBe remotePath
|
||||
expect(dummyDirectory instanceof DummyDirectory).toBe true
|
||||
|
||||
expect(atom.project.getPaths()).toEqual([tmp, remotePath])
|
||||
|
||||
# Make sure that DummyDirectory.contains() is honored.
|
||||
remotePathSubdirectory = remotePath + "a/subdirectory"
|
||||
atom.project.addPath(remotePathSubdirectory)
|
||||
expect(atom.project.getDirectories().length).toBe 2
|
||||
|
||||
# Make sure that a new DummyDirectory that is not contained by the first
|
||||
# DummyDirectory can be added.
|
||||
otherRemotePath = "ssh://other-foreign-directory:8080/"
|
||||
atom.project.addPath(otherRemotePath)
|
||||
newDirectories = atom.project.getDirectories()
|
||||
expect(newDirectories.length).toBe 3
|
||||
otherDummyDirectory = newDirectories[2]
|
||||
expect(otherDummyDirectory.getPath()).toBe otherRemotePath
|
||||
expect(otherDummyDirectory instanceof DummyDirectory).toBe true
|
||||
|
||||
it "uses the default directory provider if no custom provider can handle the URI", ->
|
||||
directoryProvider =
|
||||
directoryForURISync: (uri) -> null
|
||||
directoryForURI: (uri) -> throw new Error("This should not be called.")
|
||||
atom.packages.serviceHub.provide(
|
||||
"atom.directory-provider", "0.1.0", directoryProvider)
|
||||
|
||||
tmp = temp.mkdirSync()
|
||||
atom.project.setPaths([tmp])
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories.length).toBe 1
|
||||
expect(directories[0].getPath()).toBe tmp
|
||||
|
||||
it "gets the parent directory from the default directory provider if it's a local directory", ->
|
||||
tmp = temp.mkdirSync()
|
||||
atom.project.setPaths([path.join(tmp, "not-existing")])
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories.length).toBe 1
|
||||
expect(directories[0].getPath()).toBe tmp
|
||||
|
||||
it "only normalizes the directory path if it isn't on the local filesystem", ->
|
||||
nonLocalFsDirectory = "custom_proto://abc/def"
|
||||
atom.project.setPaths([nonLocalFsDirectory])
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories.length).toBe 1
|
||||
expect(directories[0].getPath()).toBe path.normalize(nonLocalFsDirectory)
|
||||
|
||||
it "tries to update repositories when a new RepositoryProvider is registered", ->
|
||||
tmp = temp.mkdirSync('atom-project')
|
||||
atom.project.setPaths([tmp])
|
||||
describe "when a new repository-provider is added", ->
|
||||
it "uses it to create repositories for any directories that need one", ->
|
||||
projectPath = temp.mkdirSync('atom-project')
|
||||
atom.project.setPaths([projectPath])
|
||||
expect(atom.project.getRepositories()).toEqual [null]
|
||||
expect(atom.project.repositoryProviders.length).toEqual 1
|
||||
|
||||
# Register a new RepositoryProvider.
|
||||
dummyRepository = destroy: ->
|
||||
repositoryProvider =
|
||||
dummyRepository = {destroy: -> null}
|
||||
|
||||
atom.packages.serviceHub.provide("atom.repository-provider", "0.1.0", {
|
||||
repositoryForDirectory: (directory) -> Promise.resolve(dummyRepository)
|
||||
repositoryForDirectorySync: (directory) -> dummyRepository
|
||||
atom.packages.serviceHub.provide(
|
||||
"atom.repository-provider", "0.1.0", repositoryProvider)
|
||||
})
|
||||
|
||||
waitsFor -> atom.project.repositoryProviders.length is 2
|
||||
runs -> expect(atom.project.getRepositories()).toEqual [dummyRepository]
|
||||
repository = null
|
||||
|
||||
it "does not update @repositories if every path has a Repository", ->
|
||||
waitsFor "repository to be updated", ->
|
||||
repository = atom.project.getRepositories()[0]
|
||||
|
||||
runs ->
|
||||
expect(repository).toBe dummyRepository
|
||||
|
||||
it "does not create any new repositories if every directory has a repository", ->
|
||||
repositories = atom.project.getRepositories()
|
||||
expect(repositories.length).toEqual 1
|
||||
[repository] = repositories
|
||||
@ -336,12 +262,13 @@ describe "Project", ->
|
||||
# Verify that the result is cached.
|
||||
expect(atom.project.repositoryForDirectory(directory)).toBe(promise)
|
||||
|
||||
describe ".setPaths(path)", ->
|
||||
describe ".setPaths(paths)", ->
|
||||
describe "when path is a file", ->
|
||||
it "sets its path to the files parent directory and updates the root directory", ->
|
||||
atom.project.setPaths([require.resolve('./fixtures/dir/a')])
|
||||
expect(atom.project.getPaths()[0]).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
expect(atom.project.getDirectories()[0].path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
filePath = require.resolve('./fixtures/dir/a')
|
||||
atom.project.setPaths([filePath])
|
||||
expect(atom.project.getPaths()[0]).toEqual path.dirname(filePath)
|
||||
expect(atom.project.getDirectories()[0].path).toEqual path.dirname(filePath)
|
||||
|
||||
describe "when path is a directory", ->
|
||||
it "assigns the directories and repositories", ->
|
||||
@ -372,17 +299,86 @@ describe "Project", ->
|
||||
expect(onDidChangePathsSpy.callCount).toBe 1
|
||||
expect(onDidChangePathsSpy.mostRecentCall.args[0]).toEqual(paths)
|
||||
|
||||
describe "when path is null", ->
|
||||
it "sets its path and root directory to null", ->
|
||||
describe "when no paths are given", ->
|
||||
it "clears its path", ->
|
||||
atom.project.setPaths([])
|
||||
expect(atom.project.getPaths()[0]?).toBeFalsy()
|
||||
expect(atom.project.getDirectories()[0]?).toBeFalsy()
|
||||
expect(atom.project.getPaths()).toEqual []
|
||||
expect(atom.project.getDirectories()).toEqual []
|
||||
|
||||
it "normalizes the path to remove consecutive slashes, ., and .. segments", ->
|
||||
atom.project.setPaths(["#{require.resolve('./fixtures/dir/a')}#{path.sep}b#{path.sep}#{path.sep}.."])
|
||||
expect(atom.project.getPaths()[0]).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
expect(atom.project.getDirectories()[0].path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
|
||||
it "only normalizes the directory path if it isn't on the local filesystem", ->
|
||||
nonLocalFsDirectory = "custom_proto://abc/def"
|
||||
atom.project.setPaths([nonLocalFsDirectory])
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories.length).toBe 1
|
||||
expect(directories[0].getPath()).toBe path.normalize(nonLocalFsDirectory)
|
||||
|
||||
describe "when a custom directory provider has been added", ->
|
||||
describe "when custom provider handles the given path", ->
|
||||
it "creates a directory using that provider", ->
|
||||
class DummyDirectory
|
||||
constructor: (@path) ->
|
||||
getPath: -> @path
|
||||
getFile: -> {existsSync: -> false}
|
||||
getSubdirectory: -> {existsSync: -> false}
|
||||
isRoot: -> true
|
||||
existsSync: -> /does-exist/.test(@path)
|
||||
off: ->
|
||||
contains: (filePath) -> filePath.startsWith(@path)
|
||||
|
||||
atom.packages.serviceHub.provide("atom.directory-provider", "0.1.0", {
|
||||
directoryForURISync: (uri) ->
|
||||
if uri.startsWith("ssh://")
|
||||
new DummyDirectory(uri)
|
||||
else
|
||||
null
|
||||
})
|
||||
|
||||
localPath = temp.mkdirSync('local-path')
|
||||
remotePath = "ssh://foreign-directory:8080/exists"
|
||||
|
||||
atom.project.setPaths([localPath, remotePath])
|
||||
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories[0].getPath()).toBe localPath
|
||||
expect(directories[0] instanceof Directory).toBe true
|
||||
expect(directories[1].getPath()).toBe remotePath
|
||||
expect(directories[1] instanceof DummyDirectory).toBe true
|
||||
|
||||
# Make sure that DummyDirectory.contains() is honored.
|
||||
remotePathSubdirectory = remotePath + "a/subdirectory"
|
||||
atom.project.addPath(remotePathSubdirectory)
|
||||
expect(atom.project.getDirectories().length).toBe 2
|
||||
|
||||
# Make sure that a new DummyDirectory that is not contained by the first
|
||||
# DummyDirectory can be added.
|
||||
otherRemotePath = "ssh://other-foreign-directory:8080/"
|
||||
atom.project.addPath(otherRemotePath)
|
||||
newDirectories = atom.project.getDirectories()
|
||||
expect(newDirectories.length).toBe 3
|
||||
otherDummyDirectory = newDirectories[2]
|
||||
expect(otherDummyDirectory.getPath()).toBe otherRemotePath
|
||||
expect(otherDummyDirectory instanceof DummyDirectory).toBe true
|
||||
|
||||
describe "when a custom provider does not handle the path", ->
|
||||
it "creates a local directory for the path", ->
|
||||
directoryProvider =
|
||||
directoryForURISync: (uri) -> null
|
||||
directoryForURI: (uri) -> throw new Error("This should not be called.")
|
||||
|
||||
atom.packages.serviceHub.provide(
|
||||
"atom.directory-provider", "0.1.0", directoryProvider)
|
||||
|
||||
tmp = temp.mkdirSync()
|
||||
atom.project.setPaths([tmp])
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories.length).toBe 1
|
||||
expect(directories[0].getPath()).toBe tmp
|
||||
|
||||
describe ".addPath(path)", ->
|
||||
it "calls callbacks registered with ::onDidChangePaths", ->
|
||||
onDidChangePathsSpy = jasmine.createSpy('onDidChangePaths spy')
|
||||
@ -396,20 +392,26 @@ describe "Project", ->
|
||||
expect(onDidChangePathsSpy.callCount).toBe 1
|
||||
expect(onDidChangePathsSpy.mostRecentCall.args[0]).toEqual([oldPath, newPath])
|
||||
|
||||
describe "when the project already has the path or one of its descendants", ->
|
||||
it "doesn't add it again", ->
|
||||
onDidChangePathsSpy = jasmine.createSpy('onDidChangePaths spy')
|
||||
atom.project.onDidChangePaths(onDidChangePathsSpy)
|
||||
it "doesn't add redundant paths", ->
|
||||
onDidChangePathsSpy = jasmine.createSpy('onDidChangePaths spy')
|
||||
atom.project.onDidChangePaths(onDidChangePathsSpy)
|
||||
[oldPath] = atom.project.getPaths()
|
||||
|
||||
[oldPath] = atom.project.getPaths()
|
||||
# Doesn't re-add an existing root directory
|
||||
atom.project.addPath(oldPath)
|
||||
expect(atom.project.getPaths()).toEqual([oldPath])
|
||||
expect(onDidChangePathsSpy).not.toHaveBeenCalled()
|
||||
|
||||
atom.project.addPath(oldPath)
|
||||
atom.project.addPath(path.join(oldPath, "some-file.txt"))
|
||||
atom.project.addPath(path.join(oldPath, "a-dir"))
|
||||
atom.project.addPath(path.join(oldPath, "a-dir", "oh-git"))
|
||||
# Doesn't add an entry for a file-path within an existing root directory
|
||||
atom.project.addPath(path.join(oldPath, 'some-file.txt'))
|
||||
expect(atom.project.getPaths()).toEqual([oldPath])
|
||||
expect(onDidChangePathsSpy).not.toHaveBeenCalled()
|
||||
|
||||
expect(atom.project.getPaths()).toEqual([oldPath])
|
||||
expect(onDidChangePathsSpy).not.toHaveBeenCalled()
|
||||
# Does add an entry for a directory within an existing directory
|
||||
newPath = path.join(oldPath, "a-dir")
|
||||
atom.project.addPath(newPath)
|
||||
expect(atom.project.getPaths()).toEqual([oldPath, newPath])
|
||||
expect(onDidChangePathsSpy).toHaveBeenCalled()
|
||||
|
||||
describe ".removePath(path)", ->
|
||||
onDidChangePathsSpy = null
|
||||
@ -440,19 +442,22 @@ describe "Project", ->
|
||||
expect(atom.project.getRepositories()[0].isSubmodule("src")).toBe false
|
||||
|
||||
it "removes a path that is represented as a URI", ->
|
||||
ftpURI = "ftp://example.com/some/folder"
|
||||
directoryProvider =
|
||||
atom.packages.serviceHub.provide("atom.directory-provider", "0.1.0", {
|
||||
directoryForURISync: (uri) ->
|
||||
# Dummy implementation of Directory for which GitRepositoryProvider
|
||||
# will not try to create a GitRepository.
|
||||
getPath: -> ftpURI
|
||||
getSubdirectory: -> {}
|
||||
isRoot: -> true
|
||||
off: ->
|
||||
atom.packages.serviceHub.provide(
|
||||
"atom.directory-provider", "0.1.0", directoryProvider)
|
||||
{
|
||||
getPath: -> uri
|
||||
getSubdirectory: -> {}
|
||||
isRoot: -> true
|
||||
existsSync: -> true
|
||||
off: ->
|
||||
}
|
||||
})
|
||||
|
||||
ftpURI = "ftp://example.com/some/folder"
|
||||
|
||||
atom.project.setPaths([ftpURI])
|
||||
expect(atom.project.getPaths()).toEqual [ftpURI]
|
||||
|
||||
atom.project.removePath(ftpURI)
|
||||
expect(atom.project.getPaths()).toEqual []
|
||||
|
||||
@ -494,6 +499,19 @@ describe "Project", ->
|
||||
url = "http://the-path"
|
||||
expect(atom.project.relativizePath(url)).toEqual [null, url]
|
||||
|
||||
describe "when the given path is inside more than one root folder", ->
|
||||
it "uses the root folder that is closest to the given path", ->
|
||||
atom.project.addPath(path.join(atom.project.getPaths()[0], 'a-dir'))
|
||||
|
||||
inputPath = path.join(atom.project.getPaths()[1], 'somewhere/something.txt')
|
||||
|
||||
expect(atom.project.getDirectories()[0].contains(inputPath)).toBe true
|
||||
expect(atom.project.getDirectories()[1].contains(inputPath)).toBe true
|
||||
expect(atom.project.relativizePath(inputPath)).toEqual [
|
||||
atom.project.getPaths()[1],
|
||||
'somewhere/something.txt'
|
||||
]
|
||||
|
||||
describe ".contains(path)", ->
|
||||
it "returns whether or not the given path is in one of the root directories", ->
|
||||
rootPath = atom.project.getPaths()[0]
|
||||
|
@ -34,12 +34,11 @@ class Project extends Model
|
||||
@rootDirectories = []
|
||||
@repositories = []
|
||||
|
||||
@directoryProviders = [new DefaultDirectoryProvider()]
|
||||
@directoryProviders = []
|
||||
@defaultDirectoryProvider = new DefaultDirectoryProvider()
|
||||
atom.packages.serviceHub.consume(
|
||||
'atom.directory-provider',
|
||||
'^0.1.0',
|
||||
# New providers are added to the front of @directoryProviders because
|
||||
# DefaultDirectoryProvider is a catch-all that will always provide a Directory.
|
||||
(provider) => @directoryProviders.unshift(provider))
|
||||
|
||||
# Mapping from the real path of a {Directory} to a {Promise} that resolves
|
||||
@ -48,8 +47,6 @@ class Project extends Model
|
||||
# the same real path, so it is not a good key.
|
||||
@repositoryPromisesByPath = new Map()
|
||||
|
||||
# Note that the GitRepositoryProvider is registered synchronously so that
|
||||
# it is available immediately on startup.
|
||||
@repositoryProviders = [new GitRepositoryProvider(this)]
|
||||
atom.packages.serviceHub.consume(
|
||||
'atom.repository-provider',
|
||||
@ -186,18 +183,16 @@ class Project extends Model
|
||||
#
|
||||
# * `projectPath` {String} The path to the directory to add.
|
||||
addPath: (projectPath, options) ->
|
||||
for directory in @getDirectories()
|
||||
# Apparently a Directory does not believe it can contain itself, so we
|
||||
# must also check whether the paths match.
|
||||
return if directory.contains(projectPath) or directory.getPath() is projectPath
|
||||
|
||||
directory = null
|
||||
for provider in @directoryProviders
|
||||
break if directory = provider.directoryForURISync?(projectPath)
|
||||
if directory is null
|
||||
# This should never happen because DefaultDirectoryProvider should always
|
||||
# return a Directory.
|
||||
throw new Error(projectPath + ' could not be resolved to a directory')
|
||||
directory ?= @defaultDirectoryProvider.directoryForURISync(projectPath)
|
||||
|
||||
directoryExists = directory.existsSync()
|
||||
for rootDirectory in @getDirectories()
|
||||
return if rootDirectory.getPath() is directory.getPath()
|
||||
return if not directoryExists and rootDirectory.contains(directory.getPath())
|
||||
|
||||
@rootDirectories.push(directory)
|
||||
|
||||
repo = null
|
||||
@ -267,10 +262,13 @@ class Project extends Model
|
||||
# * `relativePath` {String} The relative path from the project directory to
|
||||
# the given path.
|
||||
relativizePath: (fullPath) ->
|
||||
for rootDirectory in @rootDirectories
|
||||
relativePath = rootDirectory.relativize(fullPath)
|
||||
return [rootDirectory.getPath(), relativePath] unless relativePath is fullPath
|
||||
[null, fullPath]
|
||||
result = [null, fullPath]
|
||||
if fullPath?
|
||||
for rootDirectory in @rootDirectories
|
||||
relativePath = rootDirectory.relativize(fullPath)
|
||||
if relativePath?.length < result[1].length
|
||||
result = [rootDirectory.getPath(), relativePath]
|
||||
result
|
||||
|
||||
# Public: Determines whether the given path (real or symbolic) is inside the
|
||||
# project's directory.
|
||||
|
Loading…
Reference in New Issue
Block a user