From b8317831f807bf005219c666be02968f24d3e6c0 Mon Sep 17 00:00:00 2001 From: Conor Sloan Date: Tue, 6 Feb 2024 13:05:06 +0000 Subject: [PATCH 1/7] kick off action using custom npm script and prefix arg this accepts a prefix path which should be platform-agnostic. --- action.yml | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 99dd0b3..368ca44 100644 --- a/action.yml +++ b/action.yml @@ -21,7 +21,7 @@ runs: using: 'composite' steps: - name: Publish Action Package - run: 'node ${{github.action_path}}/dist/index.js' + run: 'npm --prefix ${{github.action_path}} start' shell: bash id: publish env: diff --git a/package.json b/package.json index 7fe0e9e..3479f39 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "package": "ncc build src/index.ts --license licenses.txt", "package:watch": "npm run package -- --watch", "test": "jest", + "start": "node dist/index.js", "all": "npm run format:write && npm run lint && npm run test && npm run coverage && npm run package" }, "license": "MIT", From 3f76c4d47cd3e2c53197df3fd9b5d994e53cdb4b Mon Sep 17 00:00:00 2001 From: Conor Sloan Date: Tue, 6 Feb 2024 15:48:26 +0000 Subject: [PATCH 2/7] use GITHUB_WORKSPACE as target dir to package up --- __tests__/main.test.ts | 25 ++ action.yml | 1 + dist/index.js | 903 +++++++++++++++++++++++------------------ src/main.ts | 8 +- 4 files changed, 530 insertions(+), 407 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 7e7883c..7d65e65 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -64,8 +64,22 @@ describe('run', () => { .mockImplementation() }) + it('fails if no action workspace found', async () => { + // Mock the environment + process.env.GITHUB_WORKSPACE = '' + + // Run the action + await main.run() + + // Check the results + expect(setFailedMock).toHaveBeenCalledWith( + 'Could not find GITHUB_WORKSPACE.' + ) + }) + it('fails if no repository found', async () => { // Mock the environment + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = '' // Run the action @@ -77,6 +91,7 @@ describe('run', () => { it('fails if no token found', async () => { // Mock the environment + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' process.env.TOKEN = '' @@ -89,6 +104,7 @@ describe('run', () => { it('fails if no source commit found', async () => { // Mock the environment + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' process.env.TOKEN = 'test' process.env.GITHUB_SHA = '' @@ -101,6 +117,7 @@ describe('run', () => { }) it('fails if trigger is not release or tag push', async () => { + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' process.env.GITHUB_SHA = 'test-sha' process.env.TOKEN = 'token' @@ -117,6 +134,7 @@ describe('run', () => { }) it('fails if the trigger is a push, but not a tag push', async () => { + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' process.env.GITHUB_SHA = 'test-sha' process.env.TOKEN = 'token' @@ -131,6 +149,7 @@ describe('run', () => { }) it('fails if the value of the tag input is not a valid semver', async () => { + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' process.env.GITHUB_SHA = 'test-sha' process.env.TOKEN = 'token' @@ -155,6 +174,7 @@ describe('run', () => { it('fails if staging files fails', async () => { // Mock the environment + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' github.context.eventName = 'release' process.env.GITHUB_SHA = 'test-sha' @@ -179,6 +199,7 @@ describe('run', () => { it('fails if creating temp directory fails', async () => { // Mock the environment + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' github.context.eventName = 'release' process.env.GITHUB_SHA = 'test-sha' @@ -203,6 +224,7 @@ describe('run', () => { it('fails if creating archives fails', async () => { // Mock the environment + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' github.context.eventName = 'release' process.env.GITHUB_SHA = 'test-sha' @@ -226,6 +248,7 @@ describe('run', () => { }) it('fails if getting container registry URL fails', async () => { + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' github.context.eventName = 'release' process.env.GITHUB_SHA = 'test-sha' @@ -268,6 +291,7 @@ describe('run', () => { }) it('fails if publishing OCI artifact fails', async () => { + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' github.context.eventName = 'release' process.env.GITHUB_SHA = 'test-sha' @@ -314,6 +338,7 @@ describe('run', () => { }) it('uploads the artifact, returns package metadata from GHCR, and cleans up tmp dirs', async () => { + process.env.GITHUB_WORKSPACE = '.' process.env.GITHUB_REPOSITORY = 'test-org/test-repo' github.context.eventName = 'release' process.env.GITHUB_SHA = 'test-sha' diff --git a/action.yml b/action.yml index 368ca44..81efe68 100644 --- a/action.yml +++ b/action.yml @@ -29,6 +29,7 @@ runs: GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_REF: ${{ github.ref }} GITHUB_SHA: ${{ github.sha }} + GITHUB_WORKSPACE: ${{ github.workspace }} - name: Output variables shell: bash run: | diff --git a/dist/index.js b/dist/index.js index 0b7d415..1581e35 100644 --- a/dist/index.js +++ b/dist/index.js @@ -23452,18 +23452,24 @@ module.exports = copySync "use strict"; -const fs = __nccwpck_require__(61176) +const fs = __nccwpck_require__(77758) const path = __nccwpck_require__(71017) -const { mkdirs } = __nccwpck_require__(98605) -const { pathExists } = __nccwpck_require__(43835) -const { utimesMillis } = __nccwpck_require__(52548) +const mkdirs = (__nccwpck_require__(98605).mkdirs) +const pathExists = (__nccwpck_require__(43835).pathExists) +const utimesMillis = (__nccwpck_require__(52548).utimesMillis) const stat = __nccwpck_require__(73901) -async function copy (src, dest, opts = {}) { - if (typeof opts === 'function') { +function copy (src, dest, opts, cb) { + if (typeof opts === 'function' && !cb) { + cb = opts + opts = {} + } else if (typeof opts === 'function') { opts = { filter: opts } } + cb = cb || function () {} + opts = opts || {} + opts.clobber = 'clobber' in opts ? !!opts.clobber : true // default to true for now opts.overwrite = 'overwrite' in opts ? !!opts.overwrite : opts.clobber // overwrite falls back to clobber @@ -23476,154 +23482,209 @@ async function copy (src, dest, opts = {}) { ) } - const { srcStat, destStat } = await stat.checkPaths(src, dest, 'copy', opts) + stat.checkPaths(src, dest, 'copy', opts, (err, stats) => { + if (err) return cb(err) + const { srcStat, destStat } = stats + stat.checkParentPaths(src, srcStat, dest, 'copy', err => { + if (err) return cb(err) + runFilter(src, dest, opts, (err, include) => { + if (err) return cb(err) + if (!include) return cb() - await stat.checkParentPaths(src, srcStat, dest, 'copy') + checkParentDir(destStat, src, dest, opts, cb) + }) + }) + }) +} - const include = await runFilter(src, dest, opts) - - if (!include) return - - // check if the parent of dest exists, and create it if it doesn't exist +function checkParentDir (destStat, src, dest, opts, cb) { const destParent = path.dirname(dest) - const dirExists = await pathExists(destParent) - if (!dirExists) { - await mkdirs(destParent) - } - - await getStatsAndPerformCopy(destStat, src, dest, opts) + pathExists(destParent, (err, dirExists) => { + if (err) return cb(err) + if (dirExists) return getStats(destStat, src, dest, opts, cb) + mkdirs(destParent, err => { + if (err) return cb(err) + return getStats(destStat, src, dest, opts, cb) + }) + }) } -async function runFilter (src, dest, opts) { - if (!opts.filter) return true - return opts.filter(src, dest) +function runFilter (src, dest, opts, cb) { + if (!opts.filter) return cb(null, true) + Promise.resolve(opts.filter(src, dest)) + .then(include => cb(null, include), error => cb(error)) } -async function getStatsAndPerformCopy (destStat, src, dest, opts) { - const statFn = opts.dereference ? fs.stat : fs.lstat - const srcStat = await statFn(src) +function getStats (destStat, src, dest, opts, cb) { + const stat = opts.dereference ? fs.stat : fs.lstat + stat(src, (err, srcStat) => { + if (err) return cb(err) - if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts) - - if ( - srcStat.isFile() || - srcStat.isCharacterDevice() || - srcStat.isBlockDevice() - ) return onFile(srcStat, destStat, src, dest, opts) - - if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts) - if (srcStat.isSocket()) throw new Error(`Cannot copy a socket file: ${src}`) - if (srcStat.isFIFO()) throw new Error(`Cannot copy a FIFO pipe: ${src}`) - throw new Error(`Unknown file: ${src}`) + if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts, cb) + else if (srcStat.isFile() || + srcStat.isCharacterDevice() || + srcStat.isBlockDevice()) return onFile(srcStat, destStat, src, dest, opts, cb) + else if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts, cb) + else if (srcStat.isSocket()) return cb(new Error(`Cannot copy a socket file: ${src}`)) + else if (srcStat.isFIFO()) return cb(new Error(`Cannot copy a FIFO pipe: ${src}`)) + return cb(new Error(`Unknown file: ${src}`)) + }) } -async function onFile (srcStat, destStat, src, dest, opts) { - if (!destStat) return copyFile(srcStat, src, dest, opts) +function onFile (srcStat, destStat, src, dest, opts, cb) { + if (!destStat) return copyFile(srcStat, src, dest, opts, cb) + return mayCopyFile(srcStat, src, dest, opts, cb) +} +function mayCopyFile (srcStat, src, dest, opts, cb) { if (opts.overwrite) { - await fs.unlink(dest) - return copyFile(srcStat, src, dest, opts) - } - if (opts.errorOnExist) { - throw new Error(`'${dest}' already exists`) - } + fs.unlink(dest, err => { + if (err) return cb(err) + return copyFile(srcStat, src, dest, opts, cb) + }) + } else if (opts.errorOnExist) { + return cb(new Error(`'${dest}' already exists`)) + } else return cb() } -async function copyFile (srcStat, src, dest, opts) { - await fs.copyFile(src, dest) - if (opts.preserveTimestamps) { - // Make sure the file is writable before setting the timestamp - // otherwise open fails with EPERM when invoked with 'r+' - // (through utimes call) - if (fileIsNotWritable(srcStat.mode)) { - await makeFileWritable(dest, srcStat.mode) - } +function copyFile (srcStat, src, dest, opts, cb) { + fs.copyFile(src, dest, err => { + if (err) return cb(err) + if (opts.preserveTimestamps) return handleTimestampsAndMode(srcStat.mode, src, dest, cb) + return setDestMode(dest, srcStat.mode, cb) + }) +} - // Set timestamps and mode correspondingly - - // Note that The initial srcStat.atime cannot be trusted - // because it is modified by the read(2) system call - // (See https://nodejs.org/api/fs.html#fs_stat_time_values) - const updatedSrcStat = await fs.stat(src) - await utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime) +function handleTimestampsAndMode (srcMode, src, dest, cb) { + // Make sure the file is writable before setting the timestamp + // otherwise open fails with EPERM when invoked with 'r+' + // (through utimes call) + if (fileIsNotWritable(srcMode)) { + return makeFileWritable(dest, srcMode, err => { + if (err) return cb(err) + return setDestTimestampsAndMode(srcMode, src, dest, cb) + }) } - - return fs.chmod(dest, srcStat.mode) + return setDestTimestampsAndMode(srcMode, src, dest, cb) } function fileIsNotWritable (srcMode) { return (srcMode & 0o200) === 0 } -function makeFileWritable (dest, srcMode) { - return fs.chmod(dest, srcMode | 0o200) +function makeFileWritable (dest, srcMode, cb) { + return setDestMode(dest, srcMode | 0o200, cb) } -async function onDir (srcStat, destStat, src, dest, opts) { - // the dest directory might not exist, create it - if (!destStat) { - await fs.mkdir(dest) - } - - const items = await fs.readdir(src) - - // loop through the files in the current directory to copy everything - await Promise.all(items.map(async item => { - const srcItem = path.join(src, item) - const destItem = path.join(dest, item) - - // skip the item if it is matches by the filter function - const include = await runFilter(srcItem, destItem, opts) - if (!include) return - - const { destStat } = await stat.checkPaths(srcItem, destItem, 'copy', opts) - - // If the item is a copyable file, `getStatsAndPerformCopy` will copy it - // If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively - return getStatsAndPerformCopy(destStat, srcItem, destItem, opts) - })) - - if (!destStat) { - await fs.chmod(dest, srcStat.mode) - } +function setDestTimestampsAndMode (srcMode, src, dest, cb) { + setDestTimestamps(src, dest, err => { + if (err) return cb(err) + return setDestMode(dest, srcMode, cb) + }) } -async function onLink (destStat, src, dest, opts) { - let resolvedSrc = await fs.readlink(src) - if (opts.dereference) { - resolvedSrc = path.resolve(process.cwd(), resolvedSrc) - } - if (!destStat) { - return fs.symlink(resolvedSrc, dest) - } +function setDestMode (dest, srcMode, cb) { + return fs.chmod(dest, srcMode, cb) +} - let resolvedDest = null - try { - resolvedDest = await fs.readlink(dest) - } catch (e) { - // dest exists and is a regular file or directory, - // Windows may throw UNKNOWN error. If dest already exists, - // fs throws error anyway, so no need to guard against it here. - if (e.code === 'EINVAL' || e.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest) - throw e - } - if (opts.dereference) { - resolvedDest = path.resolve(process.cwd(), resolvedDest) - } - if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) { - throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`) - } +function setDestTimestamps (src, dest, cb) { + // The initial srcStat.atime cannot be trusted + // because it is modified by the read(2) system call + // (See https://nodejs.org/api/fs.html#fs_stat_time_values) + fs.stat(src, (err, updatedSrcStat) => { + if (err) return cb(err) + return utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime, cb) + }) +} - // do not copy if src is a subdir of dest since unlinking - // dest in this case would result in removing src contents - // and therefore a broken symlink would be created. - if (stat.isSrcSubdir(resolvedDest, resolvedSrc)) { - throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`) - } +function onDir (srcStat, destStat, src, dest, opts, cb) { + if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts, cb) + return copyDir(src, dest, opts, cb) +} - // copy the link - await fs.unlink(dest) - return fs.symlink(resolvedSrc, dest) +function mkDirAndCopy (srcMode, src, dest, opts, cb) { + fs.mkdir(dest, err => { + if (err) return cb(err) + copyDir(src, dest, opts, err => { + if (err) return cb(err) + return setDestMode(dest, srcMode, cb) + }) + }) +} + +function copyDir (src, dest, opts, cb) { + fs.readdir(src, (err, items) => { + if (err) return cb(err) + return copyDirItems(items, src, dest, opts, cb) + }) +} + +function copyDirItems (items, src, dest, opts, cb) { + const item = items.pop() + if (!item) return cb() + return copyDirItem(items, item, src, dest, opts, cb) +} + +function copyDirItem (items, item, src, dest, opts, cb) { + const srcItem = path.join(src, item) + const destItem = path.join(dest, item) + runFilter(srcItem, destItem, opts, (err, include) => { + if (err) return cb(err) + if (!include) return copyDirItems(items, src, dest, opts, cb) + + stat.checkPaths(srcItem, destItem, 'copy', opts, (err, stats) => { + if (err) return cb(err) + const { destStat } = stats + getStats(destStat, srcItem, destItem, opts, err => { + if (err) return cb(err) + return copyDirItems(items, src, dest, opts, cb) + }) + }) + }) +} + +function onLink (destStat, src, dest, opts, cb) { + fs.readlink(src, (err, resolvedSrc) => { + if (err) return cb(err) + if (opts.dereference) { + resolvedSrc = path.resolve(process.cwd(), resolvedSrc) + } + + if (!destStat) { + return fs.symlink(resolvedSrc, dest, cb) + } else { + fs.readlink(dest, (err, resolvedDest) => { + if (err) { + // dest exists and is a regular file or directory, + // Windows may throw UNKNOWN error. If dest already exists, + // fs throws error anyway, so no need to guard against it here. + if (err.code === 'EINVAL' || err.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest, cb) + return cb(err) + } + if (opts.dereference) { + resolvedDest = path.resolve(process.cwd(), resolvedDest) + } + if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) { + return cb(new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`)) + } + + // do not copy if src is a subdir of dest since unlinking + // dest in this case would result in removing src contents + // and therefore a broken symlink would be created. + if (stat.isSrcSubdir(resolvedDest, resolvedSrc)) { + return cb(new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`)) + } + return copyLink(resolvedSrc, dest, cb) + }) + } + }) +} + +function copyLink (resolvedSrc, dest, cb) { + fs.unlink(dest, err => { + if (err) return cb(err) + return fs.symlink(resolvedSrc, dest, cb) + }) } module.exports = copy @@ -23637,7 +23698,7 @@ module.exports = copy "use strict"; -const u = (__nccwpck_require__(9046).fromPromise) +const u = (__nccwpck_require__(9046).fromCallback) module.exports = { copy: u(__nccwpck_require__(38834)), copySync: __nccwpck_require__(89618) @@ -23699,48 +23760,51 @@ module.exports = { "use strict"; -const u = (__nccwpck_require__(9046).fromPromise) +const u = (__nccwpck_require__(9046).fromCallback) const path = __nccwpck_require__(71017) -const fs = __nccwpck_require__(61176) +const fs = __nccwpck_require__(77758) const mkdir = __nccwpck_require__(98605) -async function createFile (file) { - let stats - try { - stats = await fs.stat(file) - } catch { } - if (stats && stats.isFile()) return - - const dir = path.dirname(file) - - let dirStats = null - try { - dirStats = await fs.stat(dir) - } catch (err) { - // if the directory doesn't exist, make it - if (err.code === 'ENOENT') { - await mkdir.mkdirs(dir) - await fs.writeFile(file, '') - return - } else { - throw err - } +function createFile (file, callback) { + function makeFile () { + fs.writeFile(file, '', err => { + if (err) return callback(err) + callback() + }) } - if (dirStats.isDirectory()) { - await fs.writeFile(file, '') - } else { - // parent is not a directory - // This is just to cause an internal ENOTDIR error to be thrown - await fs.readdir(dir) - } + fs.stat(file, (err, stats) => { // eslint-disable-line handle-callback-err + if (!err && stats.isFile()) return callback() + const dir = path.dirname(file) + fs.stat(dir, (err, stats) => { + if (err) { + // if the directory doesn't exist, make it + if (err.code === 'ENOENT') { + return mkdir.mkdirs(dir, err => { + if (err) return callback(err) + makeFile() + }) + } + return callback(err) + } + + if (stats.isDirectory()) makeFile() + else { + // parent is not a directory + // This is just to cause an internal ENOTDIR error to be thrown + fs.readdir(dir, err => { + if (err) return callback(err) + }) + } + }) + }) } function createFileSync (file) { let stats try { stats = fs.statSync(file) - } catch { } + } catch {} if (stats && stats.isFile()) return const dir = path.dirname(file) @@ -23804,40 +23868,40 @@ module.exports = { "use strict"; -const u = (__nccwpck_require__(9046).fromPromise) +const u = (__nccwpck_require__(9046).fromCallback) const path = __nccwpck_require__(71017) -const fs = __nccwpck_require__(61176) +const fs = __nccwpck_require__(77758) const mkdir = __nccwpck_require__(98605) -const { pathExists } = __nccwpck_require__(43835) +const pathExists = (__nccwpck_require__(43835).pathExists) const { areIdentical } = __nccwpck_require__(73901) -async function createLink (srcpath, dstpath) { - let dstStat - try { - dstStat = await fs.lstat(dstpath) - } catch { - // ignore error +function createLink (srcpath, dstpath, callback) { + function makeLink (srcpath, dstpath) { + fs.link(srcpath, dstpath, err => { + if (err) return callback(err) + callback(null) + }) } - let srcStat - try { - srcStat = await fs.lstat(srcpath) - } catch (err) { - err.message = err.message.replace('lstat', 'ensureLink') - throw err - } + fs.lstat(dstpath, (_, dstStat) => { + fs.lstat(srcpath, (err, srcStat) => { + if (err) { + err.message = err.message.replace('lstat', 'ensureLink') + return callback(err) + } + if (dstStat && areIdentical(srcStat, dstStat)) return callback(null) - if (dstStat && areIdentical(srcStat, dstStat)) return - - const dir = path.dirname(dstpath) - - const dirExists = await pathExists(dir) - - if (!dirExists) { - await mkdir.mkdirs(dir) - } - - await fs.link(srcpath, dstpath) + const dir = path.dirname(dstpath) + pathExists(dir, (err, dirExists) => { + if (err) return callback(err) + if (dirExists) return makeLink(srcpath, dstpath) + mkdir.mkdirs(dir, err => { + if (err) return callback(err) + makeLink(srcpath, dstpath) + }) + }) + }) + }) } function createLinkSync (srcpath, dstpath) { @@ -23877,10 +23941,8 @@ module.exports = { const path = __nccwpck_require__(71017) -const fs = __nccwpck_require__(61176) -const { pathExists } = __nccwpck_require__(43835) - -const u = (__nccwpck_require__(9046).fromPromise) +const fs = __nccwpck_require__(77758) +const pathExists = (__nccwpck_require__(43835).pathExists) /** * Function that returns two types of paths, one relative to symlink, and one @@ -23904,75 +23966,75 @@ const u = (__nccwpck_require__(9046).fromPromise) * the ability to pass in `relative to current working direcotry` paths. */ -async function symlinkPaths (srcpath, dstpath) { +function symlinkPaths (srcpath, dstpath, callback) { if (path.isAbsolute(srcpath)) { - try { - await fs.lstat(srcpath) - } catch (err) { - err.message = err.message.replace('lstat', 'ensureSymlink') - throw err - } - - return { - toCwd: srcpath, - toDst: srcpath - } - } - - const dstdir = path.dirname(dstpath) - const relativeToDst = path.join(dstdir, srcpath) - - const exists = await pathExists(relativeToDst) - if (exists) { - return { - toCwd: relativeToDst, - toDst: srcpath - } - } - - try { - await fs.lstat(srcpath) - } catch (err) { - err.message = err.message.replace('lstat', 'ensureSymlink') - throw err - } - - return { - toCwd: srcpath, - toDst: path.relative(dstdir, srcpath) + return fs.lstat(srcpath, (err) => { + if (err) { + err.message = err.message.replace('lstat', 'ensureSymlink') + return callback(err) + } + return callback(null, { + toCwd: srcpath, + toDst: srcpath + }) + }) + } else { + const dstdir = path.dirname(dstpath) + const relativeToDst = path.join(dstdir, srcpath) + return pathExists(relativeToDst, (err, exists) => { + if (err) return callback(err) + if (exists) { + return callback(null, { + toCwd: relativeToDst, + toDst: srcpath + }) + } else { + return fs.lstat(srcpath, (err) => { + if (err) { + err.message = err.message.replace('lstat', 'ensureSymlink') + return callback(err) + } + return callback(null, { + toCwd: srcpath, + toDst: path.relative(dstdir, srcpath) + }) + }) + } + }) } } function symlinkPathsSync (srcpath, dstpath) { + let exists if (path.isAbsolute(srcpath)) { - const exists = fs.existsSync(srcpath) + exists = fs.existsSync(srcpath) if (!exists) throw new Error('absolute srcpath does not exist') return { toCwd: srcpath, toDst: srcpath } - } - - const dstdir = path.dirname(dstpath) - const relativeToDst = path.join(dstdir, srcpath) - const exists = fs.existsSync(relativeToDst) - if (exists) { - return { - toCwd: relativeToDst, - toDst: srcpath + } else { + const dstdir = path.dirname(dstpath) + const relativeToDst = path.join(dstdir, srcpath) + exists = fs.existsSync(relativeToDst) + if (exists) { + return { + toCwd: relativeToDst, + toDst: srcpath + } + } else { + exists = fs.existsSync(srcpath) + if (!exists) throw new Error('relative srcpath does not exist') + return { + toCwd: srcpath, + toDst: path.relative(dstdir, srcpath) + } } } - - const srcExists = fs.existsSync(srcpath) - if (!srcExists) throw new Error('relative srcpath does not exist') - return { - toCwd: srcpath, - toDst: path.relative(dstdir, srcpath) - } } module.exports = { - symlinkPaths: u(symlinkPaths), + symlinkPaths, symlinkPathsSync } @@ -23985,26 +24047,23 @@ module.exports = { "use strict"; -const fs = __nccwpck_require__(61176) -const u = (__nccwpck_require__(9046).fromPromise) +const fs = __nccwpck_require__(77758) -async function symlinkType (srcpath, type) { - if (type) return type - - let stats - try { - stats = await fs.lstat(srcpath) - } catch { - return 'file' - } - - return (stats && stats.isDirectory()) ? 'dir' : 'file' +function symlinkType (srcpath, type, callback) { + callback = (typeof type === 'function') ? type : callback + type = (typeof type === 'function') ? false : type + if (type) return callback(null, type) + fs.lstat(srcpath, (err, stats) => { + if (err) return callback(null, 'file') + type = (stats && stats.isDirectory()) ? 'dir' : 'file' + callback(null, type) + }) } function symlinkTypeSync (srcpath, type) { - if (type) return type - let stats + + if (type) return type try { stats = fs.lstatSync(srcpath) } catch { @@ -24014,7 +24073,7 @@ function symlinkTypeSync (srcpath, type) { } module.exports = { - symlinkType: u(symlinkType), + symlinkType, symlinkTypeSync } @@ -24027,51 +24086,66 @@ module.exports = { "use strict"; -const u = (__nccwpck_require__(9046).fromPromise) +const u = (__nccwpck_require__(9046).fromCallback) const path = __nccwpck_require__(71017) const fs = __nccwpck_require__(61176) +const _mkdirs = __nccwpck_require__(98605) +const mkdirs = _mkdirs.mkdirs +const mkdirsSync = _mkdirs.mkdirsSync -const { mkdirs, mkdirsSync } = __nccwpck_require__(98605) +const _symlinkPaths = __nccwpck_require__(53727) +const symlinkPaths = _symlinkPaths.symlinkPaths +const symlinkPathsSync = _symlinkPaths.symlinkPathsSync -const { symlinkPaths, symlinkPathsSync } = __nccwpck_require__(53727) -const { symlinkType, symlinkTypeSync } = __nccwpck_require__(18254) +const _symlinkType = __nccwpck_require__(18254) +const symlinkType = _symlinkType.symlinkType +const symlinkTypeSync = _symlinkType.symlinkTypeSync -const { pathExists } = __nccwpck_require__(43835) +const pathExists = (__nccwpck_require__(43835).pathExists) const { areIdentical } = __nccwpck_require__(73901) -async function createSymlink (srcpath, dstpath, type) { - let stats - try { - stats = await fs.lstat(dstpath) - } catch { } +function createSymlink (srcpath, dstpath, type, callback) { + callback = (typeof type === 'function') ? type : callback + type = (typeof type === 'function') ? false : type - if (stats && stats.isSymbolicLink()) { - const [srcStat, dstStat] = await Promise.all([ - fs.stat(srcpath), - fs.stat(dstpath) - ]) + fs.lstat(dstpath, (err, stats) => { + if (!err && stats.isSymbolicLink()) { + Promise.all([ + fs.stat(srcpath), + fs.stat(dstpath) + ]).then(([srcStat, dstStat]) => { + if (areIdentical(srcStat, dstStat)) return callback(null) + _createSymlink(srcpath, dstpath, type, callback) + }) + } else _createSymlink(srcpath, dstpath, type, callback) + }) +} - if (areIdentical(srcStat, dstStat)) return - } - - const relative = await symlinkPaths(srcpath, dstpath) - srcpath = relative.toDst - const toType = await symlinkType(relative.toCwd, type) - const dir = path.dirname(dstpath) - - if (!(await pathExists(dir))) { - await mkdirs(dir) - } - - return fs.symlink(srcpath, dstpath, toType) +function _createSymlink (srcpath, dstpath, type, callback) { + symlinkPaths(srcpath, dstpath, (err, relative) => { + if (err) return callback(err) + srcpath = relative.toDst + symlinkType(relative.toCwd, type, (err, type) => { + if (err) return callback(err) + const dir = path.dirname(dstpath) + pathExists(dir, (err, dirExists) => { + if (err) return callback(err) + if (dirExists) return fs.symlink(srcpath, dstpath, type, callback) + mkdirs(dir, err => { + if (err) return callback(err) + fs.symlink(srcpath, dstpath, type, callback) + }) + }) + }) + }) } function createSymlinkSync (srcpath, dstpath, type) { let stats try { stats = fs.lstatSync(dstpath) - } catch { } + } catch {} if (stats && stats.isSymbolicLink()) { const srcStat = fs.statSync(srcpath) const dstStat = fs.statSync(dstpath) @@ -24443,7 +24517,7 @@ module.exports.checkPath = function checkPath (pth) { "use strict"; -const u = (__nccwpck_require__(9046).fromPromise) +const u = (__nccwpck_require__(9046).fromCallback) module.exports = { move: u(__nccwpck_require__(72231)), moveSync: __nccwpck_require__(42047) @@ -24521,60 +24595,77 @@ module.exports = moveSync "use strict"; -const fs = __nccwpck_require__(61176) +const fs = __nccwpck_require__(77758) const path = __nccwpck_require__(71017) -const { copy } = __nccwpck_require__(61335) -const { remove } = __nccwpck_require__(47357) -const { mkdirp } = __nccwpck_require__(98605) -const { pathExists } = __nccwpck_require__(43835) +const copy = (__nccwpck_require__(61335).copy) +const remove = (__nccwpck_require__(47357).remove) +const mkdirp = (__nccwpck_require__(98605).mkdirp) +const pathExists = (__nccwpck_require__(43835).pathExists) const stat = __nccwpck_require__(73901) -async function move (src, dest, opts = {}) { +function move (src, dest, opts, cb) { + if (typeof opts === 'function') { + cb = opts + opts = {} + } + + opts = opts || {} + const overwrite = opts.overwrite || opts.clobber || false - const { srcStat, isChangingCase = false } = await stat.checkPaths(src, dest, 'move', opts) - - await stat.checkParentPaths(src, srcStat, dest, 'move') - - // If the parent of dest is not root, make sure it exists before proceeding - const destParent = path.dirname(dest) - const parsedParentPath = path.parse(destParent) - if (parsedParentPath.root !== destParent) { - await mkdirp(destParent) - } - - return doRename(src, dest, overwrite, isChangingCase) + stat.checkPaths(src, dest, 'move', opts, (err, stats) => { + if (err) return cb(err) + const { srcStat, isChangingCase = false } = stats + stat.checkParentPaths(src, srcStat, dest, 'move', err => { + if (err) return cb(err) + if (isParentRoot(dest)) return doRename(src, dest, overwrite, isChangingCase, cb) + mkdirp(path.dirname(dest), err => { + if (err) return cb(err) + return doRename(src, dest, overwrite, isChangingCase, cb) + }) + }) + }) } -async function doRename (src, dest, overwrite, isChangingCase) { - if (!isChangingCase) { - if (overwrite) { - await remove(dest) - } else if (await pathExists(dest)) { - throw new Error('dest already exists.') - } - } - - try { - // Try w/ rename first, and try copy + remove if EXDEV - await fs.rename(src, dest) - } catch (err) { - if (err.code !== 'EXDEV') { - throw err - } - await moveAcrossDevice(src, dest, overwrite) - } +function isParentRoot (dest) { + const parent = path.dirname(dest) + const parsedPath = path.parse(parent) + return parsedPath.root === parent } -async function moveAcrossDevice (src, dest, overwrite) { +function doRename (src, dest, overwrite, isChangingCase, cb) { + if (isChangingCase) return rename(src, dest, overwrite, cb) + if (overwrite) { + return remove(dest, err => { + if (err) return cb(err) + return rename(src, dest, overwrite, cb) + }) + } + pathExists(dest, (err, destExists) => { + if (err) return cb(err) + if (destExists) return cb(new Error('dest already exists.')) + return rename(src, dest, overwrite, cb) + }) +} + +function rename (src, dest, overwrite, cb) { + fs.rename(src, dest, err => { + if (!err) return cb() + if (err.code !== 'EXDEV') return cb(err) + return moveAcrossDevice(src, dest, overwrite, cb) + }) +} + +function moveAcrossDevice (src, dest, overwrite, cb) { const opts = { overwrite, errorOnExist: true, preserveTimestamps: true } - - await copy(src, dest, opts) - return remove(src) + copy(src, dest, opts, err => { + if (err) return cb(err) + return remove(src, cb) + }) } module.exports = move @@ -24588,28 +24679,37 @@ module.exports = move "use strict"; -const u = (__nccwpck_require__(9046).fromPromise) -const fs = __nccwpck_require__(61176) +const u = (__nccwpck_require__(9046).fromCallback) +const fs = __nccwpck_require__(77758) const path = __nccwpck_require__(71017) const mkdir = __nccwpck_require__(98605) const pathExists = (__nccwpck_require__(43835).pathExists) -async function outputFile (file, data, encoding = 'utf-8') { - const dir = path.dirname(file) - - if (!(await pathExists(dir))) { - await mkdir.mkdirs(dir) +function outputFile (file, data, encoding, callback) { + if (typeof encoding === 'function') { + callback = encoding + encoding = 'utf8' } - return fs.writeFile(file, data, encoding) + const dir = path.dirname(file) + pathExists(dir, (err, itDoes) => { + if (err) return callback(err) + if (itDoes) return fs.writeFile(file, data, encoding, callback) + + mkdir.mkdirs(dir, err => { + if (err) return callback(err) + + fs.writeFile(file, data, encoding, callback) + }) + }) } function outputFileSync (file, ...args) { const dir = path.dirname(file) - if (!fs.existsSync(dir)) { - mkdir.mkdirsSync(dir) + if (fs.existsSync(dir)) { + return fs.writeFileSync(file, ...args) } - + mkdir.mkdirsSync(dir) fs.writeFileSync(file, ...args) } @@ -24674,7 +24774,7 @@ module.exports = { const fs = __nccwpck_require__(61176) const path = __nccwpck_require__(71017) -const u = (__nccwpck_require__(9046).fromPromise) +const util = __nccwpck_require__(73837) function getStats (src, dest, opts) { const statFunc = opts.dereference @@ -24704,32 +24804,35 @@ function getStatsSync (src, dest, opts) { return { srcStat, destStat } } -async function checkPaths (src, dest, funcName, opts) { - const { srcStat, destStat } = await getStats(src, dest, opts) - if (destStat) { - if (areIdentical(srcStat, destStat)) { - const srcBaseName = path.basename(src) - const destBaseName = path.basename(dest) - if (funcName === 'move' && - srcBaseName !== destBaseName && - srcBaseName.toLowerCase() === destBaseName.toLowerCase()) { - return { srcStat, destStat, isChangingCase: true } +function checkPaths (src, dest, funcName, opts, cb) { + util.callbackify(getStats)(src, dest, opts, (err, stats) => { + if (err) return cb(err) + const { srcStat, destStat } = stats + + if (destStat) { + if (areIdentical(srcStat, destStat)) { + const srcBaseName = path.basename(src) + const destBaseName = path.basename(dest) + if (funcName === 'move' && + srcBaseName !== destBaseName && + srcBaseName.toLowerCase() === destBaseName.toLowerCase()) { + return cb(null, { srcStat, destStat, isChangingCase: true }) + } + return cb(new Error('Source and destination must not be the same.')) + } + if (srcStat.isDirectory() && !destStat.isDirectory()) { + return cb(new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`)) + } + if (!srcStat.isDirectory() && destStat.isDirectory()) { + return cb(new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`)) } - throw new Error('Source and destination must not be the same.') } - if (srcStat.isDirectory() && !destStat.isDirectory()) { - throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`) - } - if (!srcStat.isDirectory() && destStat.isDirectory()) { - throw new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`) - } - } - if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { - throw new Error(errMsg(src, dest, funcName)) - } - - return { srcStat, destStat } + if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { + return cb(new Error(errMsg(src, dest, funcName))) + } + return cb(null, { srcStat, destStat }) + }) } function checkPathsSync (src, dest, funcName, opts) { @@ -24764,24 +24867,20 @@ function checkPathsSync (src, dest, funcName, opts) { // It works for all file types including symlinks since it // checks the src and dest inodes. It starts from the deepest // parent and stops once it reaches the src parent or the root path. -async function checkParentPaths (src, srcStat, dest, funcName) { +function checkParentPaths (src, srcStat, dest, funcName, cb) { const srcParent = path.resolve(path.dirname(src)) const destParent = path.resolve(path.dirname(dest)) - if (destParent === srcParent || destParent === path.parse(destParent).root) return - - let destStat - try { - destStat = await fs.stat(destParent, { bigint: true }) - } catch (err) { - if (err.code === 'ENOENT') return - throw err - } - - if (areIdentical(srcStat, destStat)) { - throw new Error(errMsg(src, dest, funcName)) - } - - return checkParentPaths(src, srcStat, destParent, funcName) + if (destParent === srcParent || destParent === path.parse(destParent).root) return cb() + fs.stat(destParent, { bigint: true }, (err, destStat) => { + if (err) { + if (err.code === 'ENOENT') return cb() + return cb(err) + } + if (areIdentical(srcStat, destStat)) { + return cb(new Error(errMsg(src, dest, funcName))) + } + return checkParentPaths(src, srcStat, destParent, funcName, cb) + }) } function checkParentPathsSync (src, srcStat, dest, funcName) { @@ -24810,7 +24909,7 @@ function areIdentical (srcStat, destStat) { function isSrcSubdir (src, dest) { const srcArr = path.resolve(src).split(path.sep).filter(i => i) const destArr = path.resolve(dest).split(path.sep).filter(i => i) - return srcArr.every((cur, i) => destArr[i] === cur) + return srcArr.reduce((acc, cur, i) => acc && destArr[i] === cur, true) } function errMsg (src, dest, funcName) { @@ -24818,13 +24917,10 @@ function errMsg (src, dest, funcName) { } module.exports = { - // checkPaths - checkPaths: u(checkPaths), + checkPaths, checkPathsSync, - // checkParent - checkParentPaths: u(checkParentPaths), + checkParentPaths, checkParentPathsSync, - // Misc isSrcSubdir, areIdentical } @@ -24838,28 +24934,18 @@ module.exports = { "use strict"; -const fs = __nccwpck_require__(61176) -const u = (__nccwpck_require__(9046).fromPromise) +const fs = __nccwpck_require__(77758) -async function utimesMillis (path, atime, mtime) { +function utimesMillis (path, atime, mtime, callback) { // if (!HAS_MILLIS_RES) return fs.utimes(path, atime, mtime, callback) - const fd = await fs.open(path, 'r+') - - let closeErr = null - - try { - await fs.futimes(fd, atime, mtime) - } finally { - try { - await fs.close(fd) - } catch (e) { - closeErr = e - } - } - - if (closeErr) { - throw closeErr - } + fs.open(path, 'r+', (err, fd) => { + if (err) return callback(err) + fs.futimes(fd, atime, mtime, futimesErr => { + fs.close(fd, closeErr => { + if (callback) callback(futimesErr || closeErr) + }) + }) + }) } function utimesMillisSync (path, atime, mtime) { @@ -24869,7 +24955,7 @@ function utimesMillisSync (path, atime, mtime) { } module.exports = { - utimesMillis: u(utimesMillis), + utimesMillis, utimesMillisSync } @@ -74703,6 +74789,11 @@ const semver_1 = __importDefault(__nccwpck_require__(11383)); */ async function run() { try { + const workspace = process.env.GITHUB_WORKSPACE || ''; + if (workspace === '') { + core.setFailed(`Could not find GITHUB_WORKSPACE.`); + return; + } const repository = process.env.GITHUB_REPOSITORY || ''; if (repository === '') { core.setFailed(`Could not find Repository.`); @@ -74721,7 +74812,7 @@ async function run() { const semanticVersion = parseSourceSemanticVersion(); // Create a temporary directory to stage files for packaging in archives const stagedActionFilesDir = fsHelper.createTempDir('staging'); - fsHelper.stageActionFiles('.', stagedActionFilesDir); + fsHelper.stageActionFiles(workspace, stagedActionFilesDir); // Create a temporary directory to store the archives const archiveDir = fsHelper.createTempDir('archive'); const archives = await fsHelper.createArchives(stagedActionFilesDir, archiveDir); diff --git a/src/main.ts b/src/main.ts index 0d29c18..be35c96 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,6 +12,12 @@ import semver from 'semver' */ export async function run(): Promise { try { + const workspace: string = process.env.GITHUB_WORKSPACE || '' + if (workspace === '') { + core.setFailed(`Could not find GITHUB_WORKSPACE.`) + return + } + const repository: string = process.env.GITHUB_REPOSITORY || '' if (repository === '') { core.setFailed(`Could not find Repository.`) @@ -33,7 +39,7 @@ export async function run(): Promise { // Create a temporary directory to stage files for packaging in archives const stagedActionFilesDir = fsHelper.createTempDir('staging') - fsHelper.stageActionFiles('.', stagedActionFilesDir) + fsHelper.stageActionFiles(workspace, stagedActionFilesDir) // Create a temporary directory to store the archives const archiveDir = fsHelper.createTempDir('archive') From a07f7523c00a3d1e978ce27a2621e53e5833eda3 Mon Sep 17 00:00:00 2001 From: Conor Sloan Date: Tue, 6 Feb 2024 16:16:25 +0000 Subject: [PATCH 3/7] quote the path when calling npm to avoid backslash issues --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 81efe68..872bb70 100644 --- a/action.yml +++ b/action.yml @@ -21,7 +21,7 @@ runs: using: 'composite' steps: - name: Publish Action Package - run: 'npm --prefix ${{github.action_path}} start' + run: 'npm --prefix "${{github.action_path}}" start' shell: bash id: publish env: From 646d55a0895f8e793f2dcae4f950be6b4a1c39d1 Mon Sep 17 00:00:00 2001 From: Conor Sloan Date: Tue, 6 Feb 2024 16:22:07 +0000 Subject: [PATCH 4/7] properly quote the output variables --- action.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/action.yml b/action.yml index 872bb70..4a26ff1 100644 --- a/action.yml +++ b/action.yml @@ -33,10 +33,10 @@ runs: - name: Output variables shell: bash run: | - echo "package manifest": ${{steps.publish.outputs.package-manifest}} - echo "package manifest sha": ${{steps.publish.outputs.package-manifest-sha}} - echo "package url": ${{steps.publish.outputs.package-url}} - echo "subject name": ${{github.repository}}_${{github.ref}} + echo "package manifest: ${{steps.publish.outputs.package-manifest}}" + echo "package manifest sha: ${{steps.publish.outputs.package-manifest-sha}}" + echo "package url: ${{steps.publish.outputs.package-url}}" + echo "subject name: ${{github.repository}}_${{github.ref}}" - name: Generate Provenance Attestation uses: github-early-access/generate-build-provenance@main id: build-provenance From 1b0ee34e3411c04521088d29eff1f68156060274 Mon Sep 17 00:00:00 2001 From: Conor Sloan Date: Tue, 6 Feb 2024 16:25:28 +0000 Subject: [PATCH 5/7] remove manifest from action output printing --- action.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/action.yml b/action.yml index 4a26ff1..527c2a0 100644 --- a/action.yml +++ b/action.yml @@ -33,7 +33,6 @@ runs: - name: Output variables shell: bash run: | - echo "package manifest: ${{steps.publish.outputs.package-manifest}}" echo "package manifest sha: ${{steps.publish.outputs.package-manifest-sha}}" echo "package url: ${{steps.publish.outputs.package-url}}" echo "subject name: ${{github.repository}}_${{github.ref}}" From 1105b75f9599a9f1c4e737f76b05dbd9252b423c Mon Sep 17 00:00:00 2001 From: Conor Sloan Date: Tue, 6 Feb 2024 16:39:53 +0000 Subject: [PATCH 6/7] update coverage --- badges/coverage.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/badges/coverage.svg b/badges/coverage.svg index 8225784..56c2350 100644 --- a/badges/coverage.svg +++ b/badges/coverage.svg @@ -1 +1 @@ -Coverage: 93.96%Coverage93.96% \ No newline at end of file +Coverage: 94.08%Coverage94.08% \ No newline at end of file From f2fb01cf175f20d3dbe037f2b56638fa5b0eecca Mon Sep 17 00:00:00 2001 From: Conor Sloan Date: Tue, 6 Feb 2024 16:42:15 +0000 Subject: [PATCH 7/7] run bundle --- dist/index.js | 914 +++++++++++++++++++++++--------------------------- 1 file changed, 414 insertions(+), 500 deletions(-) diff --git a/dist/index.js b/dist/index.js index 1581e35..5f23d50 100644 --- a/dist/index.js +++ b/dist/index.js @@ -23452,24 +23452,18 @@ module.exports = copySync "use strict"; -const fs = __nccwpck_require__(77758) +const fs = __nccwpck_require__(61176) const path = __nccwpck_require__(71017) -const mkdirs = (__nccwpck_require__(98605).mkdirs) -const pathExists = (__nccwpck_require__(43835).pathExists) -const utimesMillis = (__nccwpck_require__(52548).utimesMillis) +const { mkdirs } = __nccwpck_require__(98605) +const { pathExists } = __nccwpck_require__(43835) +const { utimesMillis } = __nccwpck_require__(52548) const stat = __nccwpck_require__(73901) -function copy (src, dest, opts, cb) { - if (typeof opts === 'function' && !cb) { - cb = opts - opts = {} - } else if (typeof opts === 'function') { +async function copy (src, dest, opts = {}) { + if (typeof opts === 'function') { opts = { filter: opts } } - cb = cb || function () {} - opts = opts || {} - opts.clobber = 'clobber' in opts ? !!opts.clobber : true // default to true for now opts.overwrite = 'overwrite' in opts ? !!opts.overwrite : opts.clobber // overwrite falls back to clobber @@ -23482,209 +23476,154 @@ function copy (src, dest, opts, cb) { ) } - stat.checkPaths(src, dest, 'copy', opts, (err, stats) => { - if (err) return cb(err) - const { srcStat, destStat } = stats - stat.checkParentPaths(src, srcStat, dest, 'copy', err => { - if (err) return cb(err) - runFilter(src, dest, opts, (err, include) => { - if (err) return cb(err) - if (!include) return cb() + const { srcStat, destStat } = await stat.checkPaths(src, dest, 'copy', opts) - checkParentDir(destStat, src, dest, opts, cb) - }) - }) - }) -} + await stat.checkParentPaths(src, srcStat, dest, 'copy') -function checkParentDir (destStat, src, dest, opts, cb) { + const include = await runFilter(src, dest, opts) + + if (!include) return + + // check if the parent of dest exists, and create it if it doesn't exist const destParent = path.dirname(dest) - pathExists(destParent, (err, dirExists) => { - if (err) return cb(err) - if (dirExists) return getStats(destStat, src, dest, opts, cb) - mkdirs(destParent, err => { - if (err) return cb(err) - return getStats(destStat, src, dest, opts, cb) - }) - }) -} - -function runFilter (src, dest, opts, cb) { - if (!opts.filter) return cb(null, true) - Promise.resolve(opts.filter(src, dest)) - .then(include => cb(null, include), error => cb(error)) -} - -function getStats (destStat, src, dest, opts, cb) { - const stat = opts.dereference ? fs.stat : fs.lstat - stat(src, (err, srcStat) => { - if (err) return cb(err) - - if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts, cb) - else if (srcStat.isFile() || - srcStat.isCharacterDevice() || - srcStat.isBlockDevice()) return onFile(srcStat, destStat, src, dest, opts, cb) - else if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts, cb) - else if (srcStat.isSocket()) return cb(new Error(`Cannot copy a socket file: ${src}`)) - else if (srcStat.isFIFO()) return cb(new Error(`Cannot copy a FIFO pipe: ${src}`)) - return cb(new Error(`Unknown file: ${src}`)) - }) -} - -function onFile (srcStat, destStat, src, dest, opts, cb) { - if (!destStat) return copyFile(srcStat, src, dest, opts, cb) - return mayCopyFile(srcStat, src, dest, opts, cb) -} - -function mayCopyFile (srcStat, src, dest, opts, cb) { - if (opts.overwrite) { - fs.unlink(dest, err => { - if (err) return cb(err) - return copyFile(srcStat, src, dest, opts, cb) - }) - } else if (opts.errorOnExist) { - return cb(new Error(`'${dest}' already exists`)) - } else return cb() -} - -function copyFile (srcStat, src, dest, opts, cb) { - fs.copyFile(src, dest, err => { - if (err) return cb(err) - if (opts.preserveTimestamps) return handleTimestampsAndMode(srcStat.mode, src, dest, cb) - return setDestMode(dest, srcStat.mode, cb) - }) -} - -function handleTimestampsAndMode (srcMode, src, dest, cb) { - // Make sure the file is writable before setting the timestamp - // otherwise open fails with EPERM when invoked with 'r+' - // (through utimes call) - if (fileIsNotWritable(srcMode)) { - return makeFileWritable(dest, srcMode, err => { - if (err) return cb(err) - return setDestTimestampsAndMode(srcMode, src, dest, cb) - }) + const dirExists = await pathExists(destParent) + if (!dirExists) { + await mkdirs(destParent) } - return setDestTimestampsAndMode(srcMode, src, dest, cb) + + await getStatsAndPerformCopy(destStat, src, dest, opts) +} + +async function runFilter (src, dest, opts) { + if (!opts.filter) return true + return opts.filter(src, dest) +} + +async function getStatsAndPerformCopy (destStat, src, dest, opts) { + const statFn = opts.dereference ? fs.stat : fs.lstat + const srcStat = await statFn(src) + + if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts) + + if ( + srcStat.isFile() || + srcStat.isCharacterDevice() || + srcStat.isBlockDevice() + ) return onFile(srcStat, destStat, src, dest, opts) + + if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts) + if (srcStat.isSocket()) throw new Error(`Cannot copy a socket file: ${src}`) + if (srcStat.isFIFO()) throw new Error(`Cannot copy a FIFO pipe: ${src}`) + throw new Error(`Unknown file: ${src}`) +} + +async function onFile (srcStat, destStat, src, dest, opts) { + if (!destStat) return copyFile(srcStat, src, dest, opts) + + if (opts.overwrite) { + await fs.unlink(dest) + return copyFile(srcStat, src, dest, opts) + } + if (opts.errorOnExist) { + throw new Error(`'${dest}' already exists`) + } +} + +async function copyFile (srcStat, src, dest, opts) { + await fs.copyFile(src, dest) + if (opts.preserveTimestamps) { + // Make sure the file is writable before setting the timestamp + // otherwise open fails with EPERM when invoked with 'r+' + // (through utimes call) + if (fileIsNotWritable(srcStat.mode)) { + await makeFileWritable(dest, srcStat.mode) + } + + // Set timestamps and mode correspondingly + + // Note that The initial srcStat.atime cannot be trusted + // because it is modified by the read(2) system call + // (See https://nodejs.org/api/fs.html#fs_stat_time_values) + const updatedSrcStat = await fs.stat(src) + await utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime) + } + + return fs.chmod(dest, srcStat.mode) } function fileIsNotWritable (srcMode) { return (srcMode & 0o200) === 0 } -function makeFileWritable (dest, srcMode, cb) { - return setDestMode(dest, srcMode | 0o200, cb) +function makeFileWritable (dest, srcMode) { + return fs.chmod(dest, srcMode | 0o200) } -function setDestTimestampsAndMode (srcMode, src, dest, cb) { - setDestTimestamps(src, dest, err => { - if (err) return cb(err) - return setDestMode(dest, srcMode, cb) - }) +async function onDir (srcStat, destStat, src, dest, opts) { + // the dest directory might not exist, create it + if (!destStat) { + await fs.mkdir(dest) + } + + const items = await fs.readdir(src) + + // loop through the files in the current directory to copy everything + await Promise.all(items.map(async item => { + const srcItem = path.join(src, item) + const destItem = path.join(dest, item) + + // skip the item if it is matches by the filter function + const include = await runFilter(srcItem, destItem, opts) + if (!include) return + + const { destStat } = await stat.checkPaths(srcItem, destItem, 'copy', opts) + + // If the item is a copyable file, `getStatsAndPerformCopy` will copy it + // If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively + return getStatsAndPerformCopy(destStat, srcItem, destItem, opts) + })) + + if (!destStat) { + await fs.chmod(dest, srcStat.mode) + } } -function setDestMode (dest, srcMode, cb) { - return fs.chmod(dest, srcMode, cb) -} +async function onLink (destStat, src, dest, opts) { + let resolvedSrc = await fs.readlink(src) + if (opts.dereference) { + resolvedSrc = path.resolve(process.cwd(), resolvedSrc) + } + if (!destStat) { + return fs.symlink(resolvedSrc, dest) + } -function setDestTimestamps (src, dest, cb) { - // The initial srcStat.atime cannot be trusted - // because it is modified by the read(2) system call - // (See https://nodejs.org/api/fs.html#fs_stat_time_values) - fs.stat(src, (err, updatedSrcStat) => { - if (err) return cb(err) - return utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime, cb) - }) -} + let resolvedDest = null + try { + resolvedDest = await fs.readlink(dest) + } catch (e) { + // dest exists and is a regular file or directory, + // Windows may throw UNKNOWN error. If dest already exists, + // fs throws error anyway, so no need to guard against it here. + if (e.code === 'EINVAL' || e.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest) + throw e + } + if (opts.dereference) { + resolvedDest = path.resolve(process.cwd(), resolvedDest) + } + if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) { + throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`) + } -function onDir (srcStat, destStat, src, dest, opts, cb) { - if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts, cb) - return copyDir(src, dest, opts, cb) -} + // do not copy if src is a subdir of dest since unlinking + // dest in this case would result in removing src contents + // and therefore a broken symlink would be created. + if (stat.isSrcSubdir(resolvedDest, resolvedSrc)) { + throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`) + } -function mkDirAndCopy (srcMode, src, dest, opts, cb) { - fs.mkdir(dest, err => { - if (err) return cb(err) - copyDir(src, dest, opts, err => { - if (err) return cb(err) - return setDestMode(dest, srcMode, cb) - }) - }) -} - -function copyDir (src, dest, opts, cb) { - fs.readdir(src, (err, items) => { - if (err) return cb(err) - return copyDirItems(items, src, dest, opts, cb) - }) -} - -function copyDirItems (items, src, dest, opts, cb) { - const item = items.pop() - if (!item) return cb() - return copyDirItem(items, item, src, dest, opts, cb) -} - -function copyDirItem (items, item, src, dest, opts, cb) { - const srcItem = path.join(src, item) - const destItem = path.join(dest, item) - runFilter(srcItem, destItem, opts, (err, include) => { - if (err) return cb(err) - if (!include) return copyDirItems(items, src, dest, opts, cb) - - stat.checkPaths(srcItem, destItem, 'copy', opts, (err, stats) => { - if (err) return cb(err) - const { destStat } = stats - getStats(destStat, srcItem, destItem, opts, err => { - if (err) return cb(err) - return copyDirItems(items, src, dest, opts, cb) - }) - }) - }) -} - -function onLink (destStat, src, dest, opts, cb) { - fs.readlink(src, (err, resolvedSrc) => { - if (err) return cb(err) - if (opts.dereference) { - resolvedSrc = path.resolve(process.cwd(), resolvedSrc) - } - - if (!destStat) { - return fs.symlink(resolvedSrc, dest, cb) - } else { - fs.readlink(dest, (err, resolvedDest) => { - if (err) { - // dest exists and is a regular file or directory, - // Windows may throw UNKNOWN error. If dest already exists, - // fs throws error anyway, so no need to guard against it here. - if (err.code === 'EINVAL' || err.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest, cb) - return cb(err) - } - if (opts.dereference) { - resolvedDest = path.resolve(process.cwd(), resolvedDest) - } - if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) { - return cb(new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`)) - } - - // do not copy if src is a subdir of dest since unlinking - // dest in this case would result in removing src contents - // and therefore a broken symlink would be created. - if (stat.isSrcSubdir(resolvedDest, resolvedSrc)) { - return cb(new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`)) - } - return copyLink(resolvedSrc, dest, cb) - }) - } - }) -} - -function copyLink (resolvedSrc, dest, cb) { - fs.unlink(dest, err => { - if (err) return cb(err) - return fs.symlink(resolvedSrc, dest, cb) - }) + // copy the link + await fs.unlink(dest) + return fs.symlink(resolvedSrc, dest) } module.exports = copy @@ -23698,7 +23637,7 @@ module.exports = copy "use strict"; -const u = (__nccwpck_require__(9046).fromCallback) +const u = (__nccwpck_require__(9046).fromPromise) module.exports = { copy: u(__nccwpck_require__(38834)), copySync: __nccwpck_require__(89618) @@ -23760,51 +23699,48 @@ module.exports = { "use strict"; -const u = (__nccwpck_require__(9046).fromCallback) +const u = (__nccwpck_require__(9046).fromPromise) const path = __nccwpck_require__(71017) -const fs = __nccwpck_require__(77758) +const fs = __nccwpck_require__(61176) const mkdir = __nccwpck_require__(98605) -function createFile (file, callback) { - function makeFile () { - fs.writeFile(file, '', err => { - if (err) return callback(err) - callback() - }) +async function createFile (file) { + let stats + try { + stats = await fs.stat(file) + } catch { } + if (stats && stats.isFile()) return + + const dir = path.dirname(file) + + let dirStats = null + try { + dirStats = await fs.stat(dir) + } catch (err) { + // if the directory doesn't exist, make it + if (err.code === 'ENOENT') { + await mkdir.mkdirs(dir) + await fs.writeFile(file, '') + return + } else { + throw err + } } - fs.stat(file, (err, stats) => { // eslint-disable-line handle-callback-err - if (!err && stats.isFile()) return callback() - const dir = path.dirname(file) - fs.stat(dir, (err, stats) => { - if (err) { - // if the directory doesn't exist, make it - if (err.code === 'ENOENT') { - return mkdir.mkdirs(dir, err => { - if (err) return callback(err) - makeFile() - }) - } - return callback(err) - } - - if (stats.isDirectory()) makeFile() - else { - // parent is not a directory - // This is just to cause an internal ENOTDIR error to be thrown - fs.readdir(dir, err => { - if (err) return callback(err) - }) - } - }) - }) + if (dirStats.isDirectory()) { + await fs.writeFile(file, '') + } else { + // parent is not a directory + // This is just to cause an internal ENOTDIR error to be thrown + await fs.readdir(dir) + } } function createFileSync (file) { let stats try { stats = fs.statSync(file) - } catch {} + } catch { } if (stats && stats.isFile()) return const dir = path.dirname(file) @@ -23868,40 +23804,40 @@ module.exports = { "use strict"; -const u = (__nccwpck_require__(9046).fromCallback) +const u = (__nccwpck_require__(9046).fromPromise) const path = __nccwpck_require__(71017) -const fs = __nccwpck_require__(77758) +const fs = __nccwpck_require__(61176) const mkdir = __nccwpck_require__(98605) -const pathExists = (__nccwpck_require__(43835).pathExists) +const { pathExists } = __nccwpck_require__(43835) const { areIdentical } = __nccwpck_require__(73901) -function createLink (srcpath, dstpath, callback) { - function makeLink (srcpath, dstpath) { - fs.link(srcpath, dstpath, err => { - if (err) return callback(err) - callback(null) - }) +async function createLink (srcpath, dstpath) { + let dstStat + try { + dstStat = await fs.lstat(dstpath) + } catch { + // ignore error } - fs.lstat(dstpath, (_, dstStat) => { - fs.lstat(srcpath, (err, srcStat) => { - if (err) { - err.message = err.message.replace('lstat', 'ensureLink') - return callback(err) - } - if (dstStat && areIdentical(srcStat, dstStat)) return callback(null) + let srcStat + try { + srcStat = await fs.lstat(srcpath) + } catch (err) { + err.message = err.message.replace('lstat', 'ensureLink') + throw err + } - const dir = path.dirname(dstpath) - pathExists(dir, (err, dirExists) => { - if (err) return callback(err) - if (dirExists) return makeLink(srcpath, dstpath) - mkdir.mkdirs(dir, err => { - if (err) return callback(err) - makeLink(srcpath, dstpath) - }) - }) - }) - }) + if (dstStat && areIdentical(srcStat, dstStat)) return + + const dir = path.dirname(dstpath) + + const dirExists = await pathExists(dir) + + if (!dirExists) { + await mkdir.mkdirs(dir) + } + + await fs.link(srcpath, dstpath) } function createLinkSync (srcpath, dstpath) { @@ -23941,8 +23877,10 @@ module.exports = { const path = __nccwpck_require__(71017) -const fs = __nccwpck_require__(77758) -const pathExists = (__nccwpck_require__(43835).pathExists) +const fs = __nccwpck_require__(61176) +const { pathExists } = __nccwpck_require__(43835) + +const u = (__nccwpck_require__(9046).fromPromise) /** * Function that returns two types of paths, one relative to symlink, and one @@ -23966,75 +23904,75 @@ const pathExists = (__nccwpck_require__(43835).pathExists) * the ability to pass in `relative to current working direcotry` paths. */ -function symlinkPaths (srcpath, dstpath, callback) { +async function symlinkPaths (srcpath, dstpath) { if (path.isAbsolute(srcpath)) { - return fs.lstat(srcpath, (err) => { - if (err) { - err.message = err.message.replace('lstat', 'ensureSymlink') - return callback(err) - } - return callback(null, { - toCwd: srcpath, - toDst: srcpath - }) - }) - } else { - const dstdir = path.dirname(dstpath) - const relativeToDst = path.join(dstdir, srcpath) - return pathExists(relativeToDst, (err, exists) => { - if (err) return callback(err) - if (exists) { - return callback(null, { - toCwd: relativeToDst, - toDst: srcpath - }) - } else { - return fs.lstat(srcpath, (err) => { - if (err) { - err.message = err.message.replace('lstat', 'ensureSymlink') - return callback(err) - } - return callback(null, { - toCwd: srcpath, - toDst: path.relative(dstdir, srcpath) - }) - }) - } - }) + try { + await fs.lstat(srcpath) + } catch (err) { + err.message = err.message.replace('lstat', 'ensureSymlink') + throw err + } + + return { + toCwd: srcpath, + toDst: srcpath + } + } + + const dstdir = path.dirname(dstpath) + const relativeToDst = path.join(dstdir, srcpath) + + const exists = await pathExists(relativeToDst) + if (exists) { + return { + toCwd: relativeToDst, + toDst: srcpath + } + } + + try { + await fs.lstat(srcpath) + } catch (err) { + err.message = err.message.replace('lstat', 'ensureSymlink') + throw err + } + + return { + toCwd: srcpath, + toDst: path.relative(dstdir, srcpath) } } function symlinkPathsSync (srcpath, dstpath) { - let exists if (path.isAbsolute(srcpath)) { - exists = fs.existsSync(srcpath) + const exists = fs.existsSync(srcpath) if (!exists) throw new Error('absolute srcpath does not exist') return { toCwd: srcpath, toDst: srcpath } - } else { - const dstdir = path.dirname(dstpath) - const relativeToDst = path.join(dstdir, srcpath) - exists = fs.existsSync(relativeToDst) - if (exists) { - return { - toCwd: relativeToDst, - toDst: srcpath - } - } else { - exists = fs.existsSync(srcpath) - if (!exists) throw new Error('relative srcpath does not exist') - return { - toCwd: srcpath, - toDst: path.relative(dstdir, srcpath) - } + } + + const dstdir = path.dirname(dstpath) + const relativeToDst = path.join(dstdir, srcpath) + const exists = fs.existsSync(relativeToDst) + if (exists) { + return { + toCwd: relativeToDst, + toDst: srcpath } } + + const srcExists = fs.existsSync(srcpath) + if (!srcExists) throw new Error('relative srcpath does not exist') + return { + toCwd: srcpath, + toDst: path.relative(dstdir, srcpath) + } } module.exports = { - symlinkPaths, + symlinkPaths: u(symlinkPaths), symlinkPathsSync } @@ -24047,23 +23985,26 @@ module.exports = { "use strict"; -const fs = __nccwpck_require__(77758) +const fs = __nccwpck_require__(61176) +const u = (__nccwpck_require__(9046).fromPromise) -function symlinkType (srcpath, type, callback) { - callback = (typeof type === 'function') ? type : callback - type = (typeof type === 'function') ? false : type - if (type) return callback(null, type) - fs.lstat(srcpath, (err, stats) => { - if (err) return callback(null, 'file') - type = (stats && stats.isDirectory()) ? 'dir' : 'file' - callback(null, type) - }) +async function symlinkType (srcpath, type) { + if (type) return type + + let stats + try { + stats = await fs.lstat(srcpath) + } catch { + return 'file' + } + + return (stats && stats.isDirectory()) ? 'dir' : 'file' } function symlinkTypeSync (srcpath, type) { - let stats - if (type) return type + + let stats try { stats = fs.lstatSync(srcpath) } catch { @@ -24073,7 +24014,7 @@ function symlinkTypeSync (srcpath, type) { } module.exports = { - symlinkType, + symlinkType: u(symlinkType), symlinkTypeSync } @@ -24086,66 +24027,51 @@ module.exports = { "use strict"; -const u = (__nccwpck_require__(9046).fromCallback) +const u = (__nccwpck_require__(9046).fromPromise) const path = __nccwpck_require__(71017) const fs = __nccwpck_require__(61176) -const _mkdirs = __nccwpck_require__(98605) -const mkdirs = _mkdirs.mkdirs -const mkdirsSync = _mkdirs.mkdirsSync -const _symlinkPaths = __nccwpck_require__(53727) -const symlinkPaths = _symlinkPaths.symlinkPaths -const symlinkPathsSync = _symlinkPaths.symlinkPathsSync +const { mkdirs, mkdirsSync } = __nccwpck_require__(98605) -const _symlinkType = __nccwpck_require__(18254) -const symlinkType = _symlinkType.symlinkType -const symlinkTypeSync = _symlinkType.symlinkTypeSync +const { symlinkPaths, symlinkPathsSync } = __nccwpck_require__(53727) +const { symlinkType, symlinkTypeSync } = __nccwpck_require__(18254) -const pathExists = (__nccwpck_require__(43835).pathExists) +const { pathExists } = __nccwpck_require__(43835) const { areIdentical } = __nccwpck_require__(73901) -function createSymlink (srcpath, dstpath, type, callback) { - callback = (typeof type === 'function') ? type : callback - type = (typeof type === 'function') ? false : type +async function createSymlink (srcpath, dstpath, type) { + let stats + try { + stats = await fs.lstat(dstpath) + } catch { } - fs.lstat(dstpath, (err, stats) => { - if (!err && stats.isSymbolicLink()) { - Promise.all([ - fs.stat(srcpath), - fs.stat(dstpath) - ]).then(([srcStat, dstStat]) => { - if (areIdentical(srcStat, dstStat)) return callback(null) - _createSymlink(srcpath, dstpath, type, callback) - }) - } else _createSymlink(srcpath, dstpath, type, callback) - }) -} + if (stats && stats.isSymbolicLink()) { + const [srcStat, dstStat] = await Promise.all([ + fs.stat(srcpath), + fs.stat(dstpath) + ]) -function _createSymlink (srcpath, dstpath, type, callback) { - symlinkPaths(srcpath, dstpath, (err, relative) => { - if (err) return callback(err) - srcpath = relative.toDst - symlinkType(relative.toCwd, type, (err, type) => { - if (err) return callback(err) - const dir = path.dirname(dstpath) - pathExists(dir, (err, dirExists) => { - if (err) return callback(err) - if (dirExists) return fs.symlink(srcpath, dstpath, type, callback) - mkdirs(dir, err => { - if (err) return callback(err) - fs.symlink(srcpath, dstpath, type, callback) - }) - }) - }) - }) + if (areIdentical(srcStat, dstStat)) return + } + + const relative = await symlinkPaths(srcpath, dstpath) + srcpath = relative.toDst + const toType = await symlinkType(relative.toCwd, type) + const dir = path.dirname(dstpath) + + if (!(await pathExists(dir))) { + await mkdirs(dir) + } + + return fs.symlink(srcpath, dstpath, toType) } function createSymlinkSync (srcpath, dstpath, type) { let stats try { stats = fs.lstatSync(dstpath) - } catch {} + } catch { } if (stats && stats.isSymbolicLink()) { const srcStat = fs.statSync(srcpath) const dstStat = fs.statSync(dstpath) @@ -24517,7 +24443,7 @@ module.exports.checkPath = function checkPath (pth) { "use strict"; -const u = (__nccwpck_require__(9046).fromCallback) +const u = (__nccwpck_require__(9046).fromPromise) module.exports = { move: u(__nccwpck_require__(72231)), moveSync: __nccwpck_require__(42047) @@ -24595,77 +24521,60 @@ module.exports = moveSync "use strict"; -const fs = __nccwpck_require__(77758) +const fs = __nccwpck_require__(61176) const path = __nccwpck_require__(71017) -const copy = (__nccwpck_require__(61335).copy) -const remove = (__nccwpck_require__(47357).remove) -const mkdirp = (__nccwpck_require__(98605).mkdirp) -const pathExists = (__nccwpck_require__(43835).pathExists) +const { copy } = __nccwpck_require__(61335) +const { remove } = __nccwpck_require__(47357) +const { mkdirp } = __nccwpck_require__(98605) +const { pathExists } = __nccwpck_require__(43835) const stat = __nccwpck_require__(73901) -function move (src, dest, opts, cb) { - if (typeof opts === 'function') { - cb = opts - opts = {} - } - - opts = opts || {} - +async function move (src, dest, opts = {}) { const overwrite = opts.overwrite || opts.clobber || false - stat.checkPaths(src, dest, 'move', opts, (err, stats) => { - if (err) return cb(err) - const { srcStat, isChangingCase = false } = stats - stat.checkParentPaths(src, srcStat, dest, 'move', err => { - if (err) return cb(err) - if (isParentRoot(dest)) return doRename(src, dest, overwrite, isChangingCase, cb) - mkdirp(path.dirname(dest), err => { - if (err) return cb(err) - return doRename(src, dest, overwrite, isChangingCase, cb) - }) - }) - }) -} + const { srcStat, isChangingCase = false } = await stat.checkPaths(src, dest, 'move', opts) -function isParentRoot (dest) { - const parent = path.dirname(dest) - const parsedPath = path.parse(parent) - return parsedPath.root === parent -} + await stat.checkParentPaths(src, srcStat, dest, 'move') -function doRename (src, dest, overwrite, isChangingCase, cb) { - if (isChangingCase) return rename(src, dest, overwrite, cb) - if (overwrite) { - return remove(dest, err => { - if (err) return cb(err) - return rename(src, dest, overwrite, cb) - }) + // If the parent of dest is not root, make sure it exists before proceeding + const destParent = path.dirname(dest) + const parsedParentPath = path.parse(destParent) + if (parsedParentPath.root !== destParent) { + await mkdirp(destParent) } - pathExists(dest, (err, destExists) => { - if (err) return cb(err) - if (destExists) return cb(new Error('dest already exists.')) - return rename(src, dest, overwrite, cb) - }) + + return doRename(src, dest, overwrite, isChangingCase) } -function rename (src, dest, overwrite, cb) { - fs.rename(src, dest, err => { - if (!err) return cb() - if (err.code !== 'EXDEV') return cb(err) - return moveAcrossDevice(src, dest, overwrite, cb) - }) +async function doRename (src, dest, overwrite, isChangingCase) { + if (!isChangingCase) { + if (overwrite) { + await remove(dest) + } else if (await pathExists(dest)) { + throw new Error('dest already exists.') + } + } + + try { + // Try w/ rename first, and try copy + remove if EXDEV + await fs.rename(src, dest) + } catch (err) { + if (err.code !== 'EXDEV') { + throw err + } + await moveAcrossDevice(src, dest, overwrite) + } } -function moveAcrossDevice (src, dest, overwrite, cb) { +async function moveAcrossDevice (src, dest, overwrite) { const opts = { overwrite, errorOnExist: true, preserveTimestamps: true } - copy(src, dest, opts, err => { - if (err) return cb(err) - return remove(src, cb) - }) + + await copy(src, dest, opts) + return remove(src) } module.exports = move @@ -24679,37 +24588,28 @@ module.exports = move "use strict"; -const u = (__nccwpck_require__(9046).fromCallback) -const fs = __nccwpck_require__(77758) +const u = (__nccwpck_require__(9046).fromPromise) +const fs = __nccwpck_require__(61176) const path = __nccwpck_require__(71017) const mkdir = __nccwpck_require__(98605) const pathExists = (__nccwpck_require__(43835).pathExists) -function outputFile (file, data, encoding, callback) { - if (typeof encoding === 'function') { - callback = encoding - encoding = 'utf8' +async function outputFile (file, data, encoding = 'utf-8') { + const dir = path.dirname(file) + + if (!(await pathExists(dir))) { + await mkdir.mkdirs(dir) } - const dir = path.dirname(file) - pathExists(dir, (err, itDoes) => { - if (err) return callback(err) - if (itDoes) return fs.writeFile(file, data, encoding, callback) - - mkdir.mkdirs(dir, err => { - if (err) return callback(err) - - fs.writeFile(file, data, encoding, callback) - }) - }) + return fs.writeFile(file, data, encoding) } function outputFileSync (file, ...args) { const dir = path.dirname(file) - if (fs.existsSync(dir)) { - return fs.writeFileSync(file, ...args) + if (!fs.existsSync(dir)) { + mkdir.mkdirsSync(dir) } - mkdir.mkdirsSync(dir) + fs.writeFileSync(file, ...args) } @@ -24774,7 +24674,7 @@ module.exports = { const fs = __nccwpck_require__(61176) const path = __nccwpck_require__(71017) -const util = __nccwpck_require__(73837) +const u = (__nccwpck_require__(9046).fromPromise) function getStats (src, dest, opts) { const statFunc = opts.dereference @@ -24804,35 +24704,32 @@ function getStatsSync (src, dest, opts) { return { srcStat, destStat } } -function checkPaths (src, dest, funcName, opts, cb) { - util.callbackify(getStats)(src, dest, opts, (err, stats) => { - if (err) return cb(err) - const { srcStat, destStat } = stats - - if (destStat) { - if (areIdentical(srcStat, destStat)) { - const srcBaseName = path.basename(src) - const destBaseName = path.basename(dest) - if (funcName === 'move' && - srcBaseName !== destBaseName && - srcBaseName.toLowerCase() === destBaseName.toLowerCase()) { - return cb(null, { srcStat, destStat, isChangingCase: true }) - } - return cb(new Error('Source and destination must not be the same.')) - } - if (srcStat.isDirectory() && !destStat.isDirectory()) { - return cb(new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`)) - } - if (!srcStat.isDirectory() && destStat.isDirectory()) { - return cb(new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`)) +async function checkPaths (src, dest, funcName, opts) { + const { srcStat, destStat } = await getStats(src, dest, opts) + if (destStat) { + if (areIdentical(srcStat, destStat)) { + const srcBaseName = path.basename(src) + const destBaseName = path.basename(dest) + if (funcName === 'move' && + srcBaseName !== destBaseName && + srcBaseName.toLowerCase() === destBaseName.toLowerCase()) { + return { srcStat, destStat, isChangingCase: true } } + throw new Error('Source and destination must not be the same.') } - - if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { - return cb(new Error(errMsg(src, dest, funcName))) + if (srcStat.isDirectory() && !destStat.isDirectory()) { + throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`) } - return cb(null, { srcStat, destStat }) - }) + if (!srcStat.isDirectory() && destStat.isDirectory()) { + throw new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`) + } + } + + if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { + throw new Error(errMsg(src, dest, funcName)) + } + + return { srcStat, destStat } } function checkPathsSync (src, dest, funcName, opts) { @@ -24867,20 +24764,24 @@ function checkPathsSync (src, dest, funcName, opts) { // It works for all file types including symlinks since it // checks the src and dest inodes. It starts from the deepest // parent and stops once it reaches the src parent or the root path. -function checkParentPaths (src, srcStat, dest, funcName, cb) { +async function checkParentPaths (src, srcStat, dest, funcName) { const srcParent = path.resolve(path.dirname(src)) const destParent = path.resolve(path.dirname(dest)) - if (destParent === srcParent || destParent === path.parse(destParent).root) return cb() - fs.stat(destParent, { bigint: true }, (err, destStat) => { - if (err) { - if (err.code === 'ENOENT') return cb() - return cb(err) - } - if (areIdentical(srcStat, destStat)) { - return cb(new Error(errMsg(src, dest, funcName))) - } - return checkParentPaths(src, srcStat, destParent, funcName, cb) - }) + if (destParent === srcParent || destParent === path.parse(destParent).root) return + + let destStat + try { + destStat = await fs.stat(destParent, { bigint: true }) + } catch (err) { + if (err.code === 'ENOENT') return + throw err + } + + if (areIdentical(srcStat, destStat)) { + throw new Error(errMsg(src, dest, funcName)) + } + + return checkParentPaths(src, srcStat, destParent, funcName) } function checkParentPathsSync (src, srcStat, dest, funcName) { @@ -24909,7 +24810,7 @@ function areIdentical (srcStat, destStat) { function isSrcSubdir (src, dest) { const srcArr = path.resolve(src).split(path.sep).filter(i => i) const destArr = path.resolve(dest).split(path.sep).filter(i => i) - return srcArr.reduce((acc, cur, i) => acc && destArr[i] === cur, true) + return srcArr.every((cur, i) => destArr[i] === cur) } function errMsg (src, dest, funcName) { @@ -24917,10 +24818,13 @@ function errMsg (src, dest, funcName) { } module.exports = { - checkPaths, + // checkPaths + checkPaths: u(checkPaths), checkPathsSync, - checkParentPaths, + // checkParent + checkParentPaths: u(checkParentPaths), checkParentPathsSync, + // Misc isSrcSubdir, areIdentical } @@ -24934,18 +24838,28 @@ module.exports = { "use strict"; -const fs = __nccwpck_require__(77758) +const fs = __nccwpck_require__(61176) +const u = (__nccwpck_require__(9046).fromPromise) -function utimesMillis (path, atime, mtime, callback) { +async function utimesMillis (path, atime, mtime) { // if (!HAS_MILLIS_RES) return fs.utimes(path, atime, mtime, callback) - fs.open(path, 'r+', (err, fd) => { - if (err) return callback(err) - fs.futimes(fd, atime, mtime, futimesErr => { - fs.close(fd, closeErr => { - if (callback) callback(futimesErr || closeErr) - }) - }) - }) + const fd = await fs.open(path, 'r+') + + let closeErr = null + + try { + await fs.futimes(fd, atime, mtime) + } finally { + try { + await fs.close(fd) + } catch (e) { + closeErr = e + } + } + + if (closeErr) { + throw closeErr + } } function utimesMillisSync (path, atime, mtime) { @@ -24955,7 +24869,7 @@ function utimesMillisSync (path, atime, mtime) { } module.exports = { - utimesMillis, + utimesMillis: u(utimesMillis), utimesMillisSync }