Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lk/eperm stuff #1

Closed
wants to merge 50 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
a5f6405
benchmark: get cjs benchmarks to run correctly
lukekarrys Oct 4, 2024
3109214
benchmark: convert to esm
lukekarrys Oct 4, 2024
efeafd6
benchmark: add options to filter and compare benchmarks
lukekarrys Oct 4, 2024
9cbab08
wip
lukekarrys Oct 4, 2024
b028752
fix paths
lukekarrys Oct 4, 2024
8644b65
promise all
lukekarrys Oct 5, 2024
82034be
dont sort
lukekarrys Oct 5, 2024
25d26c6
randomize array order before rimraf
lukekarrys Oct 5, 2024
7457f3c
dont use tmpdir
lukekarrys Oct 5, 2024
4d78f55
test readdir contents in each loop
lukekarrys Oct 5, 2024
a233db8
sort fns
lukekarrys Oct 5, 2024
603e569
move readdir back out
lukekarrys Oct 5, 2024
2fec611
faster testing for now
lukekarrys Oct 5, 2024
7af67b3
try again
lukekarrys Oct 5, 2024
bbefba8
more
lukekarrys Oct 5, 2024
080cb36
pr only
lukekarrys Oct 5, 2024
85babe4
just one file
lukekarrys Oct 5, 2024
8ca13b6
fallback to move remove on eperm
lukekarrys Oct 5, 2024
699df22
trace
lukekarrys Oct 5, 2024
b9be53d
trace 2
lukekarrys Oct 5, 2024
ad8249e
log error
lukekarrys Oct 5, 2024
91ae56e
log in rimrafWindows
lukekarrys Oct 5, 2024
b3828a0
log entries
lukekarrys Oct 5, 2024
2183ea9
ci
lukekarrys Oct 5, 2024
363332d
ci
lukekarrys Oct 5, 2024
ee0c42b
return true on eperm
lukekarrys Oct 5, 2024
fff8031
trace in windowsRemoveDir only
lukekarrys Oct 5, 2024
c8e8657
log stack
lukekarrys Oct 5, 2024
979b863
log catches
lukekarrys Oct 5, 2024
756238f
make sure this still fails
lukekarrys Oct 5, 2024
ee57e13
only one ci many times
lukekarrys Oct 5, 2024
fd7327d
use fs.promises #134
lukekarrys Oct 5, 2024
39a0509
trace entries
lukekarrys Oct 5, 2024
7465ac4
fallback to move remove on eperm when getting dir entries
lukekarrys Oct 5, 2024
405ac98
fallback to move remove on eperm in fallback
lukekarrys Oct 5, 2024
ec01c6a
moar
lukekarrys Oct 5, 2024
52e99cb
timeout
lukekarrys Oct 6, 2024
e459db4
timeout again
lukekarrys Oct 6, 2024
4099838
refactor eperm integration test
lukekarrys Oct 6, 2024
5b5370a
better errors in failing iterations
lukekarrys Oct 6, 2024
97dd8b1
only log leftover entries to error cause
lukekarrys Oct 6, 2024
84c4e45
individual rimraf.windows errors
lukekarrys Oct 6, 2024
19dd96a
await eperm and return true
lukekarrys Oct 6, 2024
84793c2
try without fs.promises
lukekarrys Oct 6, 2024
b4acd32
add same behavior for windows sync
lukekarrys Oct 6, 2024
6ca0829
end test properly
lukekarrys Oct 6, 2024
03fb0ec
trace on file eperm
lukekarrys Oct 6, 2024
62709a0
fix
lukekarrys Oct 6, 2024
1c03a98
log things inside fix-eperm
lukekarrys Oct 6, 2024
a822322
log less things
lukekarrys Oct 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,4 @@ jobs:
run: npm install

- name: benchmark
run: node benchmark/index.js
env:
RIMRAF_TEST_START_CHAR: a
RIMRAF_TEST_END_CHAR: f
RIMRAF_TEST_DEPTH: 5
run: node benchmark/index.js --start-char=a --end-char=f --depth=5
39 changes: 26 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
name: CI

on: [push, pull_request]
on: [pull_request]

jobs:
build:
strategy:
matrix:
node-version: [20.x, 22.x]
node-version: [22.x]
platform:
- os: ubuntu-latest
shell: bash
- os: macos-latest
shell: bash
# - os: ubuntu-latest
# shell: bash
# - os: macos-latest
# shell: bash
- os: windows-latest
shell: bash
- os: windows-latest
shell: powershell
# - os: windows-latest
# shell: powershell
fail-fast: false

runs-on: ${{ matrix.platform.os }}
Expand All @@ -36,8 +36,21 @@ jobs:
run: npm install

- name: Run Tests
run: npm test -- -t0 -c
env:
RIMRAF_TEST_START_CHAR: a
RIMRAF_TEST_END_CHAR: f
RIMRAF_TEST_DEPTH: 5
run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
- run: npm test -- test/integration/eperm.ts --disable-coverage --grep=. --grep=async
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
!/typedoc.json
!/tsconfig-*.json
!/.prettierignore
/benchmark-*.json
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
/tap-snapshots
/.nyc_output
/coverage
/benchmark
/benchmark/old-rimraf
21 changes: 11 additions & 10 deletions benchmark/create-fixture.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
const { writeFile: writeFile_ } = require('fs')
const writeFile = async (path, data) => new Promise((res, rej) =>
writeFile_(path, data, er => er ? rej(er) : res()))
const { mkdirp } = require('mkdirp')
const { resolve } = require('path')
import { writeFile as writeFile_ } from 'fs'
const writeFile = async (path, data) =>
new Promise((res, rej) =>
writeFile_(path, data, er => (er ? rej(er) : res())),
)
import { mkdirp } from 'mkdirp'
import { resolve } from 'path'

const create = async (path, start, end, maxDepth, depth = 0) => {
await mkdirp(path)
const promises = []
for (let i = start; i <= end; i++) {
const c = String.fromCharCode(i)
if (depth < maxDepth && (i-start >= depth))
if (depth < maxDepth && i - start >= depth)
await create(resolve(path, c), start, end, maxDepth, depth + 1)
else
promises.push(writeFile(resolve(path, c), c))
else promises.push(writeFile(resolve(path, c), c))
}
await Promise.all(promises)
return path
}

module.exports = async ({ start, end, depth, name }) => {
const path = resolve(__dirname, 'fixtures', name, 'test')
export default async ({ start, end, depth, name }) => {
const path = resolve(import.meta.dirname, 'fixtures', name, 'test')
return await create(path, start.charCodeAt(0), end.charCodeAt(0), depth)
}
136 changes: 125 additions & 11 deletions benchmark/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,132 @@
const cases = require('./rimrafs.js')
const runTest = require('./run-test.js')
const print = require('./print-results.js')
import rimrafs, { names as rimrafNames } from './rimrafs.js'
import runTest, { names as runTestNames } from './run-test.js'
import parse from './parse-results.js'
import { sync as rimrafSync } from '../dist/esm/index.js'
import { parseArgs } from 'util'
import assert from 'assert'
import { readFileSync, writeFileSync } from 'fs'

const parseOptions = () => {
const { values } = parseArgs({
options: {
cases: {
type: 'string',
short: 'c',
multiple: true,
},
'omit-cases': {
type: 'string',
short: 'o',
multiple: true,
},
'start-char': {
type: 'string',
default: 'a',
},
'end-char': {
type: 'string',
default: 'f',
},
depth: {
type: 'string',
default: '5',
},
iterations: {
type: 'string',
default: '7',
},
compare: {
type: 'string',
},
save: {
type: 'boolean',
},
},
})

if (values.compare) {
const { results, options } = JSON.parse(
readFileSync(values.compare, 'utf8'),
)
return {
...options,
save: false,
compare: results,
}
}

const allNames = new Set([...rimrafNames, ...runTestNames])
const partition = (name, defaults = [new Set(), new Set()]) => {
const options = values[name] ?? []
assert(
options.every(c => allNames.has(c)),
new TypeError(`invalid ${name}`, {
cause: {
found: options,
wanted: [...allNames],
},
}),
)
const found = options.reduce(
(acc, k) => {
acc[rimrafNames.has(k) ? 0 : 1].add(k)
return acc
},
[new Set(), new Set()],
)
return [
found[0].size ? found[0] : defaults[0],
found[1].size ? found[1] : defaults[1],
]
}

const cases = partition('cases', [rimrafNames, runTestNames])
for (const [i, omitCase] of Object.entries(partition('omit-cases'))) {
for (const o of omitCase) {
cases[i].delete(o)
}
}

return {
rimraf: [...cases[0]],
runTest: [...cases[1]],
start: values['start-char'],
end: values['end-char'],
depth: +values.depth,
iterations: +values.iterations,
save: values.save,
compare: null,
}
}

const rimraf = require('../')
const main = async () => {
// cleanup first. since the windows impl works on all platforms,
// use that. it's only relevant if the folder exists anyway.
rimraf.sync(__dirname + '/fixtures')
const results = {}
for (const name of Object.keys(cases)) {
results[name] = await runTest(name)
rimrafSync(import.meta.dirname + '/fixtures')
const data = {}
const { save, compare, ...options } = parseOptions()
for (const [name, rimraf] of Object.entries(rimrafs)) {
if (options.rimraf.includes(name)) {
data[name] = await runTest(name, rimraf, options)
}
}
rimrafSync(import.meta.dirname + '/fixtures')
const { results, entries } = parse(data, compare)
if (save) {
const f = `benchmark-${Date.now()}.json`
writeFileSync(f, JSON.stringify({ options, results }, 0, 2))
console.log(`results saved to ${f}`)
} else {
console.log(JSON.stringify(results, null, 2))
}
rimraf.sync(__dirname + '/fixtures')
return results
console.table(
entries
.sort(([, { mean: a }], [, { mean: b }]) => a - b)
.reduce((set, [key, val]) => {
set[key] = val
return set
}, {}),
)
}

main().then(print)
main()
64 changes: 64 additions & 0 deletions benchmark/parse-results.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const sum = list => list.reduce((a, b) => a + b)
const mean = list => sum(list) / list.length
const median = list => list.sort()[Math.floor(list.length / 2)]
const max = list => list.sort()[list.length - 1]
const min = list => list.sort()[0]
const sqrt = n => Math.pow(n, 0.5)
const variance = list => {
const m = mean(list)
return mean(list.map(n => Math.pow(n - m, 2)))
}
const stddev = list => {
const v = variance(list)
if (isNaN(v)) {
throw new Error('wat?', { cause: { list, v } })
}
return sqrt(variance(list))
}
const comp = (v1, v2) => {
if (v1 === undefined) {
return {}
}
return {
'old mean': v1.mean,
'% +/-': round(((v2.mean - v1.mean) / v1.mean) * 100),
}
}

const round = n => Math.round(n * 1e3) / 1e3

const nums = list => ({
mean: round(mean(list)),
median: round(median(list)),
stddev: round(stddev(list)),
max: round(max(list)),
min: round(min(list)),
})

const printEr = er => `${er.code ? er.code + ': ' : ''}${er.message}`

const parseResults = (data, compare) => {
const results = {}
const table = {}

for (const [rimrafName, rimrafData] of Object.entries(data)) {
results[rimrafName] = {}
for (const [runTestName, { times, fails }] of Object.entries(rimrafData)) {
const result = nums(times)
const failures = fails.map(printEr)
results[rimrafName][runTestName] = { ...result, times, failures }
table[`${rimrafName} ${runTestName}`] = {
...result,
...comp(compare?.[rimrafName]?.[runTestName], result),
...(failures.length ? { failures: failures.join('\n') } : {}),
}
}
}

return {
results,
entries: Object.entries(table),
}
}

export default parseResults
65 changes: 0 additions & 65 deletions benchmark/print-results.js

This file was deleted.

Loading
Loading