mirror of https://github.com/actions/toolkit
pull/271/head
parent
e29784d870
commit
e8758cfefd
|
@ -370,6 +370,7 @@ describe('glob (search)', () => {
|
|||
await fs.mkdir(root, {recursive: true})
|
||||
await fs.writeFile(path.join(root, 'file'), 'test file content')
|
||||
await createSymlinkDir(root, path.join(root, 'symDir'))
|
||||
await fs.stat(path.join(root, 'symDir'))
|
||||
|
||||
const itemPaths = await glob.glob(path.join(root, 'symDir'))
|
||||
expect(itemPaths).toHaveLength(2)
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as fs from 'fs'
|
|||
import * as path from 'path'
|
||||
import * as patternHelper from './internal-pattern-helper'
|
||||
import {IGlobOptions} from './internal-glob-options'
|
||||
import {MatchResult} from './internal-match-result'
|
||||
import {MatchKind} from './internal-match-kind'
|
||||
import {Pattern} from './internal-pattern'
|
||||
import {SearchState} from './internal-search-state'
|
||||
|
||||
|
@ -24,12 +24,9 @@ export async function glob(
|
|||
// Parse patterns
|
||||
const patterns: Pattern[] = patternHelper.parse([pattern], options)
|
||||
|
||||
// Get search paths
|
||||
const searchPaths: string[] = patternHelper.getSearchPaths(patterns)
|
||||
|
||||
// Search
|
||||
const result: string[] = []
|
||||
for (const searchPath of searchPaths) {
|
||||
// Push the search paths
|
||||
const stack: SearchState[] = []
|
||||
for (const searchPath of patternHelper.getSearchPaths(patterns)) {
|
||||
// Exists? Note, intentionally using lstat. Detection for broken symlink
|
||||
// will be performed later (if following symlinks).
|
||||
try {
|
||||
|
@ -41,49 +38,56 @@ export async function glob(
|
|||
throw err
|
||||
}
|
||||
|
||||
// Push the first item
|
||||
const stack: SearchState[] = [new SearchState(searchPath, 1)]
|
||||
const traversalChain: string[] = [] // used to detect cycles
|
||||
stack.unshift(new SearchState(searchPath, 1))
|
||||
}
|
||||
|
||||
while (stack.length) {
|
||||
// Pop
|
||||
const item = stack.pop() as SearchState
|
||||
const stats: fs.Stats | undefined = await stat(
|
||||
item,
|
||||
options,
|
||||
traversalChain
|
||||
)
|
||||
const result: string[] = []
|
||||
|
||||
// Broken symlink or symlink cycle detected
|
||||
if (!stats) {
|
||||
// Search
|
||||
const traversalChain: string[] = [] // used to detect cycles
|
||||
while (stack.length) {
|
||||
// Pop
|
||||
const item = stack.pop() as SearchState
|
||||
|
||||
// Match
|
||||
const match = patternHelper.match(patterns, item.path)
|
||||
if (!match) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Stat
|
||||
const stats: fs.Stats | undefined = await stat(
|
||||
item,
|
||||
options,
|
||||
traversalChain
|
||||
)
|
||||
|
||||
// Broken symlink, or symlink cycle detected, or no longer exists
|
||||
if (!stats) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Directory
|
||||
if (stats.isDirectory()) {
|
||||
// Matched
|
||||
if (match & MatchKind.Directory) {
|
||||
result.push(item.path)
|
||||
}
|
||||
// Descend?
|
||||
else if (!patternHelper.partialMatch(patterns, item.path)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Match
|
||||
const matchResult = patternHelper.match(patterns, item.path)
|
||||
|
||||
// Directory
|
||||
if (stats.isDirectory()) {
|
||||
// Matched
|
||||
if (matchResult & MatchResult.Directory) {
|
||||
result.push(item.path)
|
||||
}
|
||||
// Descend?
|
||||
else if (!patternHelper.partialMatch(patterns, item.path)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Push the child items in reverse
|
||||
const childLevel = item.level + 1
|
||||
const childItems = (await fs.promises.readdir(item.path)).map(
|
||||
x => new SearchState(path.join(item.path, x), childLevel)
|
||||
)
|
||||
stack.push(...childItems.reverse())
|
||||
}
|
||||
// File
|
||||
else if (matchResult & MatchResult.File) {
|
||||
result.push(item.path)
|
||||
}
|
||||
// Push the child items in reverse
|
||||
const childLevel = item.level + 1
|
||||
const childItems = (await fs.promises.readdir(item.path)).map(
|
||||
x => new SearchState(path.join(item.path, x), childLevel)
|
||||
)
|
||||
stack.push(...childItems.reverse())
|
||||
}
|
||||
// File
|
||||
else if (match & MatchKind.File) {
|
||||
result.push(item.path)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* Indicates whether a pattern matches a path
|
||||
*/
|
||||
export enum MatchResult {
|
||||
export enum MatchKind {
|
||||
/** Not matched */
|
||||
None = 0,
|
||||
|
|
@ -76,6 +76,7 @@ export class Path {
|
|||
!segment.includes(path.sep),
|
||||
`Parameter 'itemPath' contains unexpected path separators`
|
||||
)
|
||||
this.segments.push(segment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as pathHelper from './internal-path-helper'
|
||||
import {IGlobOptions} from './internal-glob-options'
|
||||
import {MatchResult} from './internal-match-result'
|
||||
import {MatchKind} from './internal-match-kind'
|
||||
import {Pattern} from './internal-pattern'
|
||||
|
||||
const IS_WINDOWS = process.platform === 'win32'
|
||||
|
@ -60,8 +60,8 @@ export function getSearchPaths(patterns: Pattern[]): string[] {
|
|||
/**
|
||||
* Matches the patterns against the path
|
||||
*/
|
||||
export function match(patterns: Pattern[], itemPath: string): MatchResult {
|
||||
let result: MatchResult = MatchResult.None
|
||||
export function match(patterns: Pattern[], itemPath: string): MatchKind {
|
||||
let result: MatchKind = MatchKind.None
|
||||
|
||||
for (const pattern of patterns) {
|
||||
if (pattern.comment) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as assert from 'assert'
|
|||
import * as path from 'path'
|
||||
import * as pathHelper from './internal-path-helper'
|
||||
import {Minimatch, IMinimatch, IOptions as IMinimatchOptions} from 'minimatch'
|
||||
import {MatchResult} from './internal-match-result'
|
||||
import {MatchKind} from './internal-match-kind'
|
||||
import {Path} from './internal-path'
|
||||
|
||||
const IS_WINDOWS = process.platform === 'win32'
|
||||
|
@ -64,16 +64,16 @@ export class Pattern {
|
|||
/**
|
||||
* Matches the pattern against the specified path
|
||||
*/
|
||||
match(itemPath: string): MatchResult {
|
||||
match(itemPath: string): MatchKind {
|
||||
if (this.comment) {
|
||||
return MatchResult.None
|
||||
return MatchKind.None
|
||||
}
|
||||
|
||||
if (this.minimatch.match(itemPath)) {
|
||||
return this.trailingSlash ? MatchResult.Directory : MatchResult.All
|
||||
return this.trailingSlash ? MatchKind.Directory : MatchKind.All
|
||||
}
|
||||
|
||||
return MatchResult.None
|
||||
return MatchKind.None
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,11 +146,11 @@ export class Pattern {
|
|||
private initializePaths(pattern: string): void {
|
||||
// Build the search path
|
||||
const searchSegments: string[] = []
|
||||
for (const literalSegment of this.getLiterals(pattern)) {
|
||||
if (!literalSegment) {
|
||||
for (const literal of this.getLiterals(pattern)) {
|
||||
if (!literal) {
|
||||
break
|
||||
}
|
||||
searchSegments.push(literalSegment)
|
||||
searchSegments.push(literal)
|
||||
}
|
||||
this.searchPath = new Path(searchSegments).toString()
|
||||
|
||||
|
|
Loading…
Reference in New Issue