1'use strict'; 2 3const fs = require('fs'); 4const path = require('path'); 5const { pathToFileURL } = require('url'); 6const { isMainThread } = require('worker_threads'); 7 8function rmSync(pathname) { 9 fs.rmSync(pathname, { maxRetries: 3, recursive: true, force: true }); 10} 11 12const testRoot = process.env.NODE_TEST_DIR ? 13 fs.realpathSync(process.env.NODE_TEST_DIR) : path.resolve(__dirname, '..'); 14 15// Using a `.` prefixed name, which is the convention for "hidden" on POSIX, 16// gets tools to ignore it by default or by simple rules, especially eslint. 17const tmpdirName = '.tmp.' + 18 (process.env.TEST_SERIAL_ID || process.env.TEST_THREAD_ID || '0'); 19const tmpPath = path.join(testRoot, tmpdirName); 20 21let firstRefresh = true; 22function refresh() { 23 rmSync(tmpPath); 24 fs.mkdirSync(tmpPath); 25 26 if (firstRefresh) { 27 firstRefresh = false; 28 // Clean only when a test uses refresh. This allows for child processes to 29 // use the tmpdir and only the parent will clean on exit. 30 process.on('exit', onexit); 31 } 32} 33 34function onexit() { 35 // Change directory to avoid possible EBUSY 36 if (isMainThread) 37 process.chdir(testRoot); 38 39 try { 40 rmSync(tmpPath); 41 } catch (e) { 42 console.error('Can\'t clean tmpdir:', tmpPath); 43 44 const files = fs.readdirSync(tmpPath); 45 console.error('Files blocking:', files); 46 47 if (files.some((f) => f.startsWith('.nfs'))) { 48 // Warn about NFS "silly rename" 49 console.error('Note: ".nfs*" might be files that were open and ' + 50 'unlinked but not closed.'); 51 console.error('See http://nfs.sourceforge.net/#faq_d2 for details.'); 52 } 53 54 console.error(); 55 throw e; 56 } 57} 58 59function resolve(...paths) { 60 return path.resolve(tmpPath, ...paths); 61} 62 63function hasEnoughSpace(size) { 64 const { bavail, bsize } = fs.statfsSync(tmpPath); 65 return bavail >= Math.ceil(size / bsize); 66} 67 68function fileURL(...paths) { 69 // When called without arguments, add explicit trailing slash 70 const fullPath = path.resolve(tmpPath + path.sep, ...paths); 71 72 return pathToFileURL(fullPath); 73} 74 75module.exports = { 76 fileURL, 77 hasEnoughSpace, 78 path: tmpPath, 79 refresh, 80 resolve, 81}; 82