mirror of
https://github.com/atom/atom.git
synced 2026-01-22 21:38:10 -05:00
Merge pull request #5535 from atom/directory-provider
Introduce atom.directory-provider service.
This commit is contained in:
40
spec/default-directory-provider-spec.coffee
Normal file
40
spec/default-directory-provider-spec.coffee
Normal file
@@ -0,0 +1,40 @@
|
||||
DefaultDirectoryProvider = require "../src/default-directory-provider"
|
||||
path = require "path"
|
||||
temp = require "temp"
|
||||
|
||||
describe "DefaultDirectoryProvider", ->
|
||||
describe ".directoryForURISync(uri)", ->
|
||||
it "returns a Directory with a path that matches the uri", ->
|
||||
provider = new DefaultDirectoryProvider()
|
||||
tmp = temp.mkdirSync()
|
||||
|
||||
directory = provider.directoryForURISync(tmp)
|
||||
expect(directory.getPath()).toEqual tmp
|
||||
|
||||
it "normalizes its input before creating a Directory for it", ->
|
||||
provider = new DefaultDirectoryProvider()
|
||||
tmp = temp.mkdirSync()
|
||||
nonNormalizedPath = tmp + path.sep + ".." + path.sep + path.basename(tmp)
|
||||
expect(tmp.contains("..")).toBe false
|
||||
expect(nonNormalizedPath.contains("..")).toBe true
|
||||
|
||||
directory = provider.directoryForURISync(nonNormalizedPath)
|
||||
expect(directory.getPath()).toEqual tmp
|
||||
|
||||
it "creates a Directory for its parent dir when passed a file", ->
|
||||
provider = new DefaultDirectoryProvider()
|
||||
tmp = temp.mkdirSync()
|
||||
file = path.join(tmp, "example.txt")
|
||||
fs.writeFileSync(file, "data")
|
||||
|
||||
directory = provider.directoryForURISync(file)
|
||||
expect(directory.getPath()).toEqual tmp
|
||||
|
||||
describe ".directoryForURI(uri)", ->
|
||||
it "returns a Promise that resolves to a Directory with a path that matches the uri", ->
|
||||
provider = new DefaultDirectoryProvider()
|
||||
tmp = temp.mkdirSync()
|
||||
|
||||
waitsForPromise ->
|
||||
provider.directoryForURI(tmp).then (directory) ->
|
||||
expect(directory.getPath()).toEqual tmp
|
||||
@@ -14,6 +14,70 @@ describe "Project", ->
|
||||
atom.project.setPaths([atom.project.getDirectories()[0]?.resolve('dir')])
|
||||
|
||||
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 "tries to update repositories when a new RepositoryProvider is registered", ->
|
||||
tmp = temp.mkdirSync('atom-project')
|
||||
atom.project.setPaths([tmp])
|
||||
|
||||
35
src/default-directory-provider.coffee
Normal file
35
src/default-directory-provider.coffee
Normal file
@@ -0,0 +1,35 @@
|
||||
{Directory} = require 'pathwatcher'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
|
||||
module.exports =
|
||||
class DefaultDirectoryProvider
|
||||
|
||||
# Public: Create a Directory that corresponds to the specified URI.
|
||||
#
|
||||
# * `uri` {String} The path to the directory to add. This is guaranteed not to
|
||||
# be contained by a {Directory} in `atom.project`.
|
||||
#
|
||||
# Returns:
|
||||
# * {Directory} if the given URI is compatible with this provider.
|
||||
# * `null` if the given URI is not compatibile with this provider.
|
||||
directoryForURISync: (uri) ->
|
||||
projectPath = path.normalize(uri)
|
||||
|
||||
directoryPath = if fs.isDirectorySync(projectPath)
|
||||
projectPath
|
||||
else
|
||||
path.dirname(projectPath)
|
||||
|
||||
new Directory(directoryPath)
|
||||
|
||||
# Public: Create a Directory that corresponds to the specified URI.
|
||||
#
|
||||
# * `uri` {String} The path to the directory to add. This is guaranteed not to
|
||||
# be contained by a {Directory} in `atom.project`.
|
||||
#
|
||||
# Returns a Promise that resolves to:
|
||||
# * {Directory} if the given URI is compatible with this provider.
|
||||
# * `null` if the given URI is not compatibile with this provider.
|
||||
directoryForURI: (uri) ->
|
||||
Promise.resolve(@directoryForURISync(uri))
|
||||
@@ -8,9 +8,9 @@ Q = require 'q'
|
||||
{Model} = require 'theorist'
|
||||
{Subscriber} = require 'emissary'
|
||||
{Emitter} = require 'event-kit'
|
||||
DefaultDirectoryProvider = require './default-directory-provider'
|
||||
Serializable = require 'serializable'
|
||||
TextBuffer = require 'text-buffer'
|
||||
{Directory} = require 'pathwatcher'
|
||||
Grim = require 'grim'
|
||||
|
||||
TextEditor = require './text-editor'
|
||||
@@ -41,6 +41,14 @@ class Project extends Model
|
||||
@rootDirectories = []
|
||||
@repositories = []
|
||||
|
||||
@directoryProviders = [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
|
||||
# to either a {Repository} or null. Ideally, the {Directory} would be used
|
||||
# as the key; however, there can be multiple {Directory} objects created for
|
||||
@@ -159,7 +167,7 @@ class Project extends Model
|
||||
|
||||
# Public: Get an {Array} of {String}s containing the paths of the project's
|
||||
# directories.
|
||||
getPaths: -> rootDirectory.path for rootDirectory in @rootDirectories
|
||||
getPaths: -> rootDirectory.getPath() for rootDirectory in @rootDirectories
|
||||
getPath: ->
|
||||
Grim.deprecate("Use ::getPaths instead")
|
||||
@getPaths()[0]
|
||||
@@ -182,22 +190,22 @@ class Project extends Model
|
||||
Grim.deprecate("Use ::setPaths instead")
|
||||
@setPaths([path])
|
||||
|
||||
# Public: Add a path the project's list of root paths
|
||||
# Public: Add a path to the project's list of root paths
|
||||
#
|
||||
# * `projectPath` {String} The path to the directory to add.
|
||||
addPath: (projectPath, options) ->
|
||||
projectPath = path.normalize(projectPath)
|
||||
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
|
||||
|
||||
directoryPath = if fs.isDirectorySync(projectPath)
|
||||
projectPath
|
||||
else
|
||||
path.dirname(projectPath)
|
||||
|
||||
return if @getPaths().some (existingPath) ->
|
||||
(directoryPath is existingPath) or
|
||||
(directoryPath.indexOf(path.join(existingPath, path.sep)) is 0)
|
||||
|
||||
directory = new Directory(directoryPath)
|
||||
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')
|
||||
@rootDirectories.push(directory)
|
||||
|
||||
repo = null
|
||||
|
||||
Reference in New Issue
Block a user