Tons of Solutions Engineering work done today for the rest of the CS team! Headway, Howard Hanna, Engels, Brighton, etc. Also completed Datasnippers auth flow and worked on Anthology's script. Cloned Anthology's courses (900..) and will clone Full Story on Monday.
This commit is contained in:
370
Scripts/node_modules/tar-fs/index.js
generated
vendored
Normal file
370
Scripts/node_modules/tar-fs/index.js
generated
vendored
Normal file
@ -0,0 +1,370 @@
|
||||
const tar = require('tar-stream')
|
||||
const pump = require('pump')
|
||||
const mkdirp = require('mkdirp-classic')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const win32 = process.platform === 'win32'
|
||||
|
||||
exports.pack = function pack (cwd, opts) {
|
||||
if (!cwd) cwd = '.'
|
||||
if (!opts) opts = {}
|
||||
|
||||
const xfs = opts.fs || fs
|
||||
const ignore = opts.ignore || opts.filter || noop
|
||||
const mapStream = opts.mapStream || echo
|
||||
const statNext = statAll(xfs, opts.dereference ? xfs.stat : xfs.lstat, cwd, ignore, opts.entries, opts.sort)
|
||||
const strict = opts.strict !== false
|
||||
const umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask()
|
||||
const pack = opts.pack || tar.pack()
|
||||
const finish = opts.finish || noop
|
||||
|
||||
let map = opts.map || noop
|
||||
let dmode = typeof opts.dmode === 'number' ? opts.dmode : 0
|
||||
let fmode = typeof opts.fmode === 'number' ? opts.fmode : 0
|
||||
|
||||
if (opts.strip) map = strip(map, opts.strip)
|
||||
|
||||
if (opts.readable) {
|
||||
dmode |= parseInt(555, 8)
|
||||
fmode |= parseInt(444, 8)
|
||||
}
|
||||
if (opts.writable) {
|
||||
dmode |= parseInt(333, 8)
|
||||
fmode |= parseInt(222, 8)
|
||||
}
|
||||
|
||||
onnextentry()
|
||||
|
||||
function onsymlink (filename, header) {
|
||||
xfs.readlink(path.join(cwd, filename), function (err, linkname) {
|
||||
if (err) return pack.destroy(err)
|
||||
header.linkname = normalize(linkname)
|
||||
pack.entry(header, onnextentry)
|
||||
})
|
||||
}
|
||||
|
||||
function onstat (err, filename, stat) {
|
||||
if (err) return pack.destroy(err)
|
||||
if (!filename) {
|
||||
if (opts.finalize !== false) pack.finalize()
|
||||
return finish(pack)
|
||||
}
|
||||
|
||||
if (stat.isSocket()) return onnextentry() // tar does not support sockets...
|
||||
|
||||
let header = {
|
||||
name: normalize(filename),
|
||||
mode: (stat.mode | (stat.isDirectory() ? dmode : fmode)) & umask,
|
||||
mtime: stat.mtime,
|
||||
size: stat.size,
|
||||
type: 'file',
|
||||
uid: stat.uid,
|
||||
gid: stat.gid
|
||||
}
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
header.size = 0
|
||||
header.type = 'directory'
|
||||
header = map(header) || header
|
||||
return pack.entry(header, onnextentry)
|
||||
}
|
||||
|
||||
if (stat.isSymbolicLink()) {
|
||||
header.size = 0
|
||||
header.type = 'symlink'
|
||||
header = map(header) || header
|
||||
return onsymlink(filename, header)
|
||||
}
|
||||
|
||||
// TODO: add fifo etc...
|
||||
|
||||
header = map(header) || header
|
||||
|
||||
if (!stat.isFile()) {
|
||||
if (strict) return pack.destroy(new Error('unsupported type for ' + filename))
|
||||
return onnextentry()
|
||||
}
|
||||
|
||||
const entry = pack.entry(header, onnextentry)
|
||||
const rs = mapStream(xfs.createReadStream(path.join(cwd, filename), { start: 0, end: header.size > 0 ? header.size - 1 : header.size }), header)
|
||||
|
||||
rs.on('error', function (err) { // always forward errors on destroy
|
||||
entry.destroy(err)
|
||||
})
|
||||
|
||||
pump(rs, entry)
|
||||
}
|
||||
|
||||
function onnextentry (err) {
|
||||
if (err) return pack.destroy(err)
|
||||
statNext(onstat)
|
||||
}
|
||||
|
||||
return pack
|
||||
}
|
||||
|
||||
function head (list) {
|
||||
return list.length ? list[list.length - 1] : null
|
||||
}
|
||||
|
||||
function processGetuid () {
|
||||
return process.getuid ? process.getuid() : -1
|
||||
}
|
||||
|
||||
function processUmask () {
|
||||
return process.umask ? process.umask() : 0
|
||||
}
|
||||
|
||||
exports.extract = function extract (cwd, opts) {
|
||||
if (!cwd) cwd = '.'
|
||||
if (!opts) opts = {}
|
||||
|
||||
const xfs = opts.fs || fs
|
||||
const ignore = opts.ignore || opts.filter || noop
|
||||
const mapStream = opts.mapStream || echo
|
||||
const own = opts.chown !== false && !win32 && processGetuid() === 0
|
||||
const extract = opts.extract || tar.extract()
|
||||
const stack = []
|
||||
const now = new Date()
|
||||
const umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask()
|
||||
const strict = opts.strict !== false
|
||||
|
||||
let map = opts.map || noop
|
||||
let dmode = typeof opts.dmode === 'number' ? opts.dmode : 0
|
||||
let fmode = typeof opts.fmode === 'number' ? opts.fmode : 0
|
||||
|
||||
if (opts.strip) map = strip(map, opts.strip)
|
||||
|
||||
if (opts.readable) {
|
||||
dmode |= parseInt(555, 8)
|
||||
fmode |= parseInt(444, 8)
|
||||
}
|
||||
if (opts.writable) {
|
||||
dmode |= parseInt(333, 8)
|
||||
fmode |= parseInt(222, 8)
|
||||
}
|
||||
|
||||
extract.on('entry', onentry)
|
||||
|
||||
if (opts.finish) extract.on('finish', opts.finish)
|
||||
|
||||
return extract
|
||||
|
||||
function onentry (header, stream, next) {
|
||||
header = map(header) || header
|
||||
header.name = normalize(header.name)
|
||||
|
||||
const name = path.join(cwd, path.join('/', header.name))
|
||||
|
||||
if (ignore(name, header)) {
|
||||
stream.resume()
|
||||
return next()
|
||||
}
|
||||
|
||||
if (header.type === 'directory') {
|
||||
stack.push([name, header.mtime])
|
||||
return mkdirfix(name, {
|
||||
fs: xfs,
|
||||
own,
|
||||
uid: header.uid,
|
||||
gid: header.gid,
|
||||
mode: header.mode
|
||||
}, stat)
|
||||
}
|
||||
|
||||
const dir = path.dirname(name)
|
||||
|
||||
validate(xfs, dir, path.join(cwd, '.'), function (err, valid) {
|
||||
if (err) return next(err)
|
||||
if (!valid) return next(new Error(dir + ' is not a valid path'))
|
||||
|
||||
mkdirfix(dir, {
|
||||
fs: xfs,
|
||||
own,
|
||||
uid: header.uid,
|
||||
gid: header.gid,
|
||||
// normally, the folders with rights and owner should be part of the TAR file
|
||||
// if this is not the case, create folder for same user as file and with
|
||||
// standard permissions of 0o755 (rwxr-xr-x)
|
||||
mode: 0o755
|
||||
}, function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
switch (header.type) {
|
||||
case 'file': return onfile()
|
||||
case 'link': return onlink()
|
||||
case 'symlink': return onsymlink()
|
||||
}
|
||||
|
||||
if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')'))
|
||||
|
||||
stream.resume()
|
||||
next()
|
||||
})
|
||||
})
|
||||
|
||||
function stat (err) {
|
||||
if (err) return next(err)
|
||||
utimes(name, header, function (err) {
|
||||
if (err) return next(err)
|
||||
if (win32) return next()
|
||||
chperm(name, header, next)
|
||||
})
|
||||
}
|
||||
|
||||
function onsymlink () {
|
||||
if (win32) return next() // skip symlinks on win for now before it can be tested
|
||||
xfs.unlink(name, function () {
|
||||
xfs.symlink(header.linkname, name, stat)
|
||||
})
|
||||
}
|
||||
|
||||
function onlink () {
|
||||
if (win32) return next() // skip links on win for now before it can be tested
|
||||
xfs.unlink(name, function () {
|
||||
const srcpath = path.join(cwd, path.join('/', header.linkname))
|
||||
|
||||
xfs.link(srcpath, name, function (err) {
|
||||
if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) {
|
||||
stream = xfs.createReadStream(srcpath)
|
||||
return onfile()
|
||||
}
|
||||
|
||||
stat(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function onfile () {
|
||||
const ws = xfs.createWriteStream(name)
|
||||
const rs = mapStream(stream, header)
|
||||
|
||||
ws.on('error', function (err) { // always forward errors on destroy
|
||||
rs.destroy(err)
|
||||
})
|
||||
|
||||
pump(rs, ws, function (err) {
|
||||
if (err) return next(err)
|
||||
ws.on('close', stat)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function utimesParent (name, cb) { // we just set the mtime on the parent dir again everytime we write an entry
|
||||
let top
|
||||
while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop()
|
||||
if (!top) return cb()
|
||||
xfs.utimes(top[0], now, top[1], cb)
|
||||
}
|
||||
|
||||
function utimes (name, header, cb) {
|
||||
if (opts.utimes === false) return cb()
|
||||
|
||||
if (header.type === 'directory') return xfs.utimes(name, now, header.mtime, cb)
|
||||
if (header.type === 'symlink') return utimesParent(name, cb) // TODO: how to set mtime on link?
|
||||
|
||||
xfs.utimes(name, now, header.mtime, function (err) {
|
||||
if (err) return cb(err)
|
||||
utimesParent(name, cb)
|
||||
})
|
||||
}
|
||||
|
||||
function chperm (name, header, cb) {
|
||||
const link = header.type === 'symlink'
|
||||
|
||||
/* eslint-disable n/no-deprecated-api */
|
||||
const chmod = link ? xfs.lchmod : xfs.chmod
|
||||
const chown = link ? xfs.lchown : xfs.chown
|
||||
/* eslint-enable n/no-deprecated-api */
|
||||
|
||||
if (!chmod) return cb()
|
||||
|
||||
const mode = (header.mode | (header.type === 'directory' ? dmode : fmode)) & umask
|
||||
|
||||
if (chown && own) chown.call(xfs, name, header.uid, header.gid, onchown)
|
||||
else onchown(null)
|
||||
|
||||
function onchown (err) {
|
||||
if (err) return cb(err)
|
||||
if (!chmod) return cb()
|
||||
chmod.call(xfs, name, mode, cb)
|
||||
}
|
||||
}
|
||||
|
||||
function mkdirfix (name, opts, cb) {
|
||||
// when mkdir is called on an existing directory, the permissions
|
||||
// will be overwritten (?), to avoid this we check for its existance first
|
||||
xfs.stat(name, function (err) {
|
||||
if (!err) return cb(null)
|
||||
if (err.code !== 'ENOENT') return cb(err)
|
||||
mkdirp(name, { fs: opts.fs, mode: opts.mode }, function (err, made) {
|
||||
if (err) return cb(err)
|
||||
chperm(name, opts, cb)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function validate (fs, name, root, cb) {
|
||||
if (name === root) return cb(null, true)
|
||||
fs.lstat(name, function (err, st) {
|
||||
if (err && err.code === 'ENOENT') return validate(fs, path.join(name, '..'), root, cb)
|
||||
else if (err) return cb(err)
|
||||
cb(null, st.isDirectory())
|
||||
})
|
||||
}
|
||||
|
||||
function noop () {}
|
||||
|
||||
function echo (name) {
|
||||
return name
|
||||
}
|
||||
|
||||
function normalize (name) {
|
||||
return win32 ? name.replace(/\\/g, '/').replace(/[:?<>|]/g, '_') : name
|
||||
}
|
||||
|
||||
function statAll (fs, stat, cwd, ignore, entries, sort) {
|
||||
if (!entries) entries = ['.']
|
||||
const queue = entries.slice(0)
|
||||
|
||||
return function loop (callback) {
|
||||
if (!queue.length) return callback(null)
|
||||
|
||||
const next = queue.shift()
|
||||
const nextAbs = path.join(cwd, next)
|
||||
|
||||
stat.call(fs, nextAbs, function (err, stat) {
|
||||
// ignore errors if the files were deleted while buffering
|
||||
if (err) return callback(entries.indexOf(next) === -1 && err.code === 'ENOENT' ? null : err)
|
||||
|
||||
if (!stat.isDirectory()) return callback(null, next, stat)
|
||||
|
||||
fs.readdir(nextAbs, function (err, files) {
|
||||
if (err) return callback(err)
|
||||
|
||||
if (sort) files.sort()
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (!ignore(path.join(cwd, next, files[i]))) queue.push(path.join(next, files[i]))
|
||||
}
|
||||
|
||||
callback(null, next, stat)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function strip (map, level) {
|
||||
return function (header) {
|
||||
header.name = header.name.split('/').slice(level).join('/')
|
||||
|
||||
const linkname = header.linkname
|
||||
if (linkname && (header.type === 'link' || path.isAbsolute(linkname))) {
|
||||
header.linkname = linkname.split('/').slice(level).join('/')
|
||||
}
|
||||
|
||||
return map(header)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user