Skip to content
This repository has been archived by the owner on May 19, 2023. It is now read-only.

Scandal #2

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 47 additions & 97 deletions lib/load-paths-handler.coffee
Original file line number Diff line number Diff line change
@@ -1,107 +1,57 @@
async = require 'async'
fs = require 'fs'
path = require 'path'
_ = require 'underscore-plus'
{GitRepository} = require 'atom'
{Minimatch} = require 'minimatch'
GitUtils = require 'git-utils'
{PathSearcher, PathScanner, search} = require 'scandal'

PathsChunkSize = 100

emittedPaths = new Set

class PathLoader
constructor: (@rootPath, ignoreVcsIgnores, @traverseSymlinkDirectories, @ignoredNames) ->
@paths = []
@realPathCache = {}
@repo = null
if ignoreVcsIgnores
repo = GitRepository.open(@rootPath, refreshOnWindowFocus: false)
@repo = repo if repo?.relativize(path.join(@rootPath, 'test')) is 'test'

load: (done) ->
@loadPath @rootPath, =>
@flushPaths()
@repo?.destroy()
done()

isIgnored: (loadedPath) ->
relativePath = path.relative(@rootPath, loadedPath)
if @repo?.isPathIgnored(relativePath)
true
else
for ignoredName in @ignoredNames
return true if ignoredName.match(relativePath)

pathLoaded: (loadedPath, done) ->
unless @isIgnored(loadedPath) or emittedPaths.has(loadedPath)
@paths.push(loadedPath)
emittedPaths.add(loadedPath)

if @paths.length is PathsChunkSize
@flushPaths()
done()

flushPaths: ->
emit('load-paths:paths-found', @paths)
@paths = []

loadPath: (pathToLoad, done) ->
return done() if @isIgnored(pathToLoad)
fs.lstat pathToLoad, (error, stats) =>
return done() if error?
if stats.isSymbolicLink()
@isInternalSymlink pathToLoad, (isInternal) =>
return done() if isInternal
fs.stat pathToLoad, (error, stats) =>
return done() if error?
if stats.isFile()
@pathLoaded(pathToLoad, done)
else if stats.isDirectory()
if @traverseSymlinkDirectories
@loadFolder(pathToLoad, done)
else
done()
else
done()
else if stats.isDirectory()
@loadFolder(pathToLoad, done)
else if stats.isFile()
@pathLoaded(pathToLoad, done)
else
done()

loadFolder: (folderPath, done) ->
fs.readdir folderPath, (error, children=[]) =>
async.each(
children,
(childName, next) =>
@loadPath(path.join(folderPath, childName), next)
done
)

isInternalSymlink: (pathToLoad, done) ->
fs.realpath pathToLoad, @realPathCache, (err, realPath) =>
if err
done(false)
else
done(realPath.search(@rootPath) is 0)

module.exports = (rootPaths, followSymlinks, ignoreVcsIgnores, ignores=[]) ->
ignoredNames = []
for ignore in ignores when ignore
try
ignoredNames.push(new Minimatch(ignore, matchBase: true, dot: true))
catch error
console.warn "Error parsing ignore pattern (#{ignore}): #{error.message}"
module.exports = (rootPaths, options={}) ->
pathsSearched = 0
PATHS_COUNTER_SEARCHED_CHUNK = 100
emittedPaths = new Set

async.each(
rootPaths,
(rootPath, next) ->
new PathLoader(
rootPath,
ignoreVcsIgnores,
followSymlinks,
ignoredNames
).load(next)
options2 = _.extend {}, options,
inclusions: processPaths(rootPath, options.inclusions)
globalExclusions: processPaths(rootPath, options.globalExclusions)

if options.ignoreProjectParentVcsIgnores
repo = GitUtils.open(rootPath)
if repo and '' isnt repo.relativize(rootPath)
options2.excludeVcsIgnores = false

scanner = new PathScanner(rootPath, options2)

paths = []

scanner.on 'path-found', (path) ->
unless emittedPaths.has(path)
paths.push path
emittedPaths.add(path)
pathsSearched++
if pathsSearched % PATHS_COUNTER_SEARCHED_CHUNK is 0
emit('load-paths:paths-found', paths)
paths = []
scanner.on 'finished-scanning', ->
emit('load-paths:paths-found', paths)
next()
scanner.scan()

@async()
)

processPaths = (rootPath, paths) ->
return paths unless paths?.length > 0
rootPathBase = path.basename(rootPath)
results = []
for givenPath in paths
segments = givenPath.split(path.sep)
firstSegment = segments.shift()
results.push(givenPath)
if firstSegment is rootPathBase
if segments.length is 0
results.push(path.join("**", "*"))
else
results.push(path.join(segments...))
results
16 changes: 10 additions & 6 deletions lib/path-loader.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@ module.exports =
startTask: (callback) ->
projectPaths = []
taskPath = require.resolve('./load-paths-handler')
followSymlinks = atom.config.get 'core.followSymlinks'

ignoredNames = atom.config.get('fuzzy-finder.ignoredNames') ? []
ignoredNames = ignoredNames.concat(atom.config.get('core.ignoredNames') ? [])
ignoreVcsIgnores = atom.config.get('core.excludeVcsIgnoredPaths')

options =
excludeVcsIgnores: atom.config.get 'core.excludeVcsIgnoredPaths'
exclusions: ignoredNames
follow: atom.config.get 'core.followSymlinks'
includeHidden: true
ignoreProjectParentVcsIgnores: true

task = Task.once(
taskPath,
atom.project.getPaths(),
followSymlinks,
ignoreVcsIgnores,
ignoredNames, ->
callback(projectPaths)
options,
-> callback(projectPaths)
)

task.on 'load-paths:paths-found', (paths) ->
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
"fs-plus": "^2.0.0",
"fuzzaldrin": "^2.0",
"fuzzaldrin-plus": "^0.1",
"git-utils": "^4.0",
"humanize-plus": "~1.4.2",
"minimatch": "~0.3.0",
"scandal": "^2.2",
"temp": "~0.8.1",
"underscore-plus": "^1.0.0",
"wrench": "^1.5"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/master
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
97ff2919c02606bcad55588f3fa723b5a357470f
30 changes: 29 additions & 1 deletion spec/fuzzy-finder-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ describe 'FuzzyFinder', ->

it "passes the indexed paths into the project view when it is created", ->
{projectPaths} = fuzzyFinder
expect(projectPaths.length).toBe 18
expect(projectPaths.length).toBe 30
projectView = fuzzyFinder.createProjectView()
expect(projectView.paths).toBe projectPaths
expect(projectView.reloadPaths).toBe false
Expand Down Expand Up @@ -876,6 +876,7 @@ describe 'FuzzyFinder', ->
beforeEach ->
projectPath = atom.project.getDirectories()[0].resolve('git/working-dir')
fs.moveSync(path.join(projectPath, 'git.git'), path.join(projectPath, '.git'))
fs.moveSync(path.join(projectPath, 'another-repo', 'git.git'), path.join(projectPath, 'another-repo', '.git'))
atom.project.setPaths([rootDir2, projectPath])

gitDirectory = atom.project.getDirectories()[1]
Expand Down Expand Up @@ -996,3 +997,30 @@ describe 'FuzzyFinder', ->

runs ->
expect(projectView.list.find("li:contains(file.txt)")).toExist()

describe "when the project's path is a repository inside another repository", ->
beforeEach ->
ignoreFile = path.join(projectPath, '.gitignore')
fs.writeFileSync(ignoreFile, '*')
atom.project.setPaths([gitDirectory.resolve('another-repo')])

ignoreFile = path.join(gitDirectory.resolve('another-repo'), '.gitignore')
fs.writeFileSync(ignoreFile, 'd.txt')

it "excludes paths that are git ignored in the child repository", ->
dispatchCommand('toggle-file-finder')
projectView.setMaxItems(Infinity)

waitForPathsToDisplay(projectView)

runs ->
expect(projectView.list.find("li:contains(d.txt)")).not.toExist()

it "does not exclude the entire child repository if the parent repository is ignoring it", ->
dispatchCommand('toggle-file-finder')
projectView.setMaxItems(Infinity)

waitForPathsToDisplay(projectView)

runs ->
expect(projectView.list.find("li:contains(c.txt)")).toExist()