Replace glob with custom fs-utils
- On windows the glob library wouldn't work, let's create our own file discovery mechanism using readdir - This fixes #395
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import { getFilesRecursive, filterReadable } from '../src/fs-utils.js'
|
||||
|
||||
describe('fs-utils', () => {
|
||||
const tmpRoot = path.join(os.tmpdir(), `cuda-toolkit-test-${Date.now()}`)
|
||||
|
||||
beforeAll(async () => {
|
||||
await fs.promises.mkdir(tmpRoot, { recursive: true })
|
||||
// create files and nested directories
|
||||
await fs.promises.mkdir(path.join(tmpRoot, 'subdir'))
|
||||
await fs.promises.writeFile(path.join(tmpRoot, 'a.txt'), 'a')
|
||||
await fs.promises.writeFile(path.join(tmpRoot, 'subdir', 'b.txt'), 'b')
|
||||
|
||||
// create a non-readable file (if platform supports chmod)
|
||||
try {
|
||||
const p = path.join(tmpRoot, 'noaccess.txt')
|
||||
await fs.promises.writeFile(p, 'x')
|
||||
await fs.promises.chmod(p, 0o000)
|
||||
} catch {
|
||||
// ignore chmod failures on platforms that don't support it
|
||||
}
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
try {
|
||||
const p = path.join(tmpRoot, 'noaccess.txt')
|
||||
await fs.promises.chmod(p, 0o644)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
await fs.promises.rm(tmpRoot, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('getFilesRecursive returns all files under directory', async () => {
|
||||
const files = await getFilesRecursive(tmpRoot)
|
||||
|
||||
const normalizedNames = files.map((f) => path.relative(tmpRoot, f)).sort()
|
||||
|
||||
expect(normalizedNames).toEqual(
|
||||
['a.txt', 'noaccess.txt', path.join('subdir', 'b.txt')].sort()
|
||||
)
|
||||
})
|
||||
|
||||
test('filterReadable filters out non-readable or missing files', async () => {
|
||||
const a = path.join(tmpRoot, 'a.txt')
|
||||
const nosuch = path.join(tmpRoot, 'does-not-exist.txt')
|
||||
const noaccess = path.join(tmpRoot, 'noaccess.txt')
|
||||
|
||||
const result = await filterReadable([a, nosuch, noaccess])
|
||||
|
||||
expect(result).toContain(a)
|
||||
expect(result).not.toContain(nosuch)
|
||||
})
|
||||
})
|
||||
+1
-1
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="116" height="20" role="img" aria-label="Coverage: 18.44%"><title>Coverage: 18.44%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="116" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="53" height="20" fill="#e05d44"/><rect width="116" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="885" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">18.44%</text><text x="885" y="140" transform="scale(.1)" fill="#fff" textLength="430">18.44%</text></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="116" height="20" role="img" aria-label="Coverage: 22.86%"><title>Coverage: 22.86%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="116" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="53" height="20" fill="#e05d44"/><rect width="116" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="885" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">22.86%</text><text x="885" y="140" transform="scale(.1)" fill="#fff" textLength="430">22.86%</text></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
+354
-1562
File diff suppressed because it is too large
Load Diff
+1
-1
File diff suppressed because one or more lines are too long
Generated
+20
@@ -483,6 +483,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz",
|
||||
"integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
@@ -1613,6 +1614,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.1.tgz",
|
||||
"integrity": "sha512-dKYCMuPO1bmrpuogcjQ8z7ICCH3FP6WmxpwC03yjzGfZhj9fTJg6+bS1+UAplekbN2C+M61UNllGOOoAfGCrdQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.1.0",
|
||||
@@ -1741,6 +1743,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.5.tgz",
|
||||
"integrity": "sha512-vvmsN0r7rguA+FySiCsbaTTobSftpIDIpPW81trAmsv9TGxg3YCujAxRYp/Uy8xmDgYCzzgulG62H7KYUFmeIg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^5.0.0",
|
||||
"@octokit/graphql": "^8.2.2",
|
||||
@@ -2711,6 +2714,7 @@
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
|
||||
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
@@ -2874,6 +2878,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.5.tgz",
|
||||
"integrity": "sha512-vvmsN0r7rguA+FySiCsbaTTobSftpIDIpPW81trAmsv9TGxg3YCujAxRYp/Uy8xmDgYCzzgulG62H7KYUFmeIg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^5.0.0",
|
||||
"@octokit/graphql": "^8.2.2",
|
||||
@@ -3165,6 +3170,7 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -3723,6 +3729,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.0.tgz",
|
||||
"integrity": "sha512-CACyQuqSHt7ma3Ns601xykeBK/rDeZa3w6IS6UtMQbixO5DWy+8TilKkviGDH6jtWCo8FGRKEK5cLLkPvEammQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.33.0",
|
||||
@@ -3752,6 +3759,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.0.tgz",
|
||||
"integrity": "sha512-JaehZvf6m0yqYp34+RVnihBAChkqeH+tqqhS0GuX1qgPpwLvmTPheKEs6OeCK6hVJgXZHJ2vbjnC9j119auStQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.33.0",
|
||||
"@typescript-eslint/types": "8.33.0",
|
||||
@@ -4232,6 +4240,7 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -4744,6 +4753,7 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001718",
|
||||
"electron-to-chromium": "^1.5.160",
|
||||
@@ -5697,6 +5707,7 @@
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
|
||||
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -5757,6 +5768,7 @@
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz",
|
||||
"integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
@@ -5876,6 +5888,7 @@
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
|
||||
"integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.8",
|
||||
@@ -7551,6 +7564,7 @@
|
||||
"resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
|
||||
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jest/core": "^29.7.0",
|
||||
"@jest/types": "^29.6.3",
|
||||
@@ -9071,6 +9085,7 @@
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -9305,6 +9320,7 @@
|
||||
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -9830,6 +9846,7 @@
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz",
|
||||
"integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.7"
|
||||
},
|
||||
@@ -10574,6 +10591,7 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -10870,6 +10888,7 @@
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -10924,6 +10943,7 @@
|
||||
"integrity": "sha512-2zsXwyOXmCX9nGz4vhtZRYhe30V78heAv+KDc21A/KMdovGHbZcixeD5JHEF0DrFXzdytwuzYclcPbvp8A3Jlw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"napi-postinstall": "^0.2.2"
|
||||
},
|
||||
|
||||
+12
-5
@@ -1,6 +1,5 @@
|
||||
import * as cache from '@actions/cache'
|
||||
import * as core from '@actions/core'
|
||||
import * as glob from '@actions/glob'
|
||||
import * as tc from '@actions/tool-cache'
|
||||
import * as io from '@actions/io'
|
||||
import { OSType, getOs, getRelease } from './platform.js'
|
||||
@@ -11,6 +10,7 @@ import { WindowsLinks } from './links/windows-links.js'
|
||||
import fs from 'fs'
|
||||
import { getLinks } from './links/get-links.js'
|
||||
import { getArch } from './arch.js'
|
||||
import { getFilesRecursive } from './fs-utils.js'
|
||||
|
||||
// Download helper which returns the installer executable and caches it for next runs
|
||||
export async function download(
|
||||
@@ -88,6 +88,15 @@ export async function download(
|
||||
core.debug(`Copying ${destFilePath} to ${cacheDirectory}`)
|
||||
await io.mkdirP(cacheDirectory)
|
||||
await io.mv(destFilePath, cacheDirectory)
|
||||
// Log full path and files in cache directory
|
||||
const filesInCacheDir = await getFilesRecursive(cacheDirectory)
|
||||
core.debug(`Files in GitHub cache directory ${cacheDirectory}:`)
|
||||
for (const f of filesInCacheDir) {
|
||||
core.debug(f)
|
||||
}
|
||||
// Log absolute path
|
||||
const absoluteCacheDir = await fs.promises.realpath(cacheDirectory)
|
||||
core.debug(`Absolute path of cache directory: ${absoluteCacheDir}`)
|
||||
// Save cache directory to GitHub cache
|
||||
const cacheId = await cache.saveCache([cacheDirectory], cacheKey)
|
||||
if (cacheId !== -1) {
|
||||
@@ -105,10 +114,8 @@ export async function download(
|
||||
core.debug(`Executable path ${executableDirectory}`)
|
||||
// String with full executable path
|
||||
let fullExecutablePath: string
|
||||
// Get list of files in tool cache
|
||||
const filesInCache = await (
|
||||
await glob.create(`${executableDirectory}/**.*`)
|
||||
).glob()
|
||||
// Get list of files in tool cache using readdir recursive helper
|
||||
const filesInCache = await getFilesRecursive(executableDirectory)
|
||||
core.debug(`Files in tool cache:`)
|
||||
for (const f of filesInCache) {
|
||||
core.debug(f)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import * as core from '@actions/core'
|
||||
|
||||
export async function getFilesRecursive(dir: string): Promise<string[]> {
|
||||
const results: string[] = []
|
||||
async function walk(current: string) {
|
||||
const entries = await fs.promises.readdir(current, { withFileTypes: true })
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(current, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
await walk(fullPath)
|
||||
} else if (entry.isFile()) {
|
||||
results.push(fullPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
await walk(dir)
|
||||
} catch (e) {
|
||||
core.debug(`Error reading files from ${dir}: ${e}`)
|
||||
return []
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
export async function filterReadable(paths: string[]): Promise<string[]> {
|
||||
const readable: string[] = []
|
||||
for (const path of paths) {
|
||||
try {
|
||||
await fs.promises.access(path, fs.constants.R_OK)
|
||||
readable.push(path)
|
||||
} catch (e) {
|
||||
core.debug(`Path not readable: ${path} - ${e}`)
|
||||
}
|
||||
}
|
||||
return readable
|
||||
}
|
||||
+3
-4
@@ -1,6 +1,6 @@
|
||||
import { DefaultArtifactClient } from '@actions/artifact'
|
||||
import * as core from '@actions/core'
|
||||
import * as glob from '@actions/glob'
|
||||
import { filterReadable } from './fs-utils.js'
|
||||
import { OSType, getOs, getRelease } from './platform.js'
|
||||
import { SemVer } from 'semver'
|
||||
import { exec } from '@actions/exec'
|
||||
@@ -76,9 +76,8 @@ export async function install(
|
||||
const osRelease = await getRelease()
|
||||
if (osType === OSType.linux) {
|
||||
const artifactName = `cuda-install-${osType}-${osRelease}-${method}-${logFileSuffix}`
|
||||
const patterns = ['/var/log/cuda-installer.log']
|
||||
const globber = await glob.create(patterns.join('\n'))
|
||||
const files = await globber.glob()
|
||||
const candidates = ['/var/log/cuda-installer.log']
|
||||
const files = await filterReadable(candidates)
|
||||
const username = os.userInfo().username
|
||||
if (files.length > 0) {
|
||||
// If any of the files is not readable without root permissions, the upload will fail, so we need to
|
||||
|
||||
Reference in New Issue
Block a user