2020-06-15 06:59:55 -04:00
|
|
|
import * as crypto from 'crypto'
|
|
|
|
import * as fs from 'fs'
|
|
|
|
import * as path from 'path'
|
|
|
|
import * as stream from 'stream'
|
|
|
|
import * as util from 'util'
|
|
|
|
|
|
|
|
import * as glob from '@actions/glob'
|
|
|
|
|
|
|
|
export async function hashFiles(
|
|
|
|
baseDir: string,
|
|
|
|
globs: string[] = ['**'],
|
|
|
|
followSymbolicLinks = false
|
|
|
|
): Promise<string | null> {
|
|
|
|
let hasMatch = false
|
2020-06-15 08:01:06 -04:00
|
|
|
type FileHashes = Record<string, Buffer>
|
|
|
|
const hashes: FileHashes = {}
|
2020-06-15 06:59:55 -04:00
|
|
|
for await (const globPattern of globs) {
|
2020-06-15 08:01:06 -04:00
|
|
|
const globMatch = `${baseDir}${path.sep}${globPattern}`
|
2020-06-15 06:59:55 -04:00
|
|
|
const globber = await glob.create(globMatch, {followSymbolicLinks})
|
|
|
|
for await (const file of globber.globGenerator()) {
|
|
|
|
// console.log(file)
|
|
|
|
if (!file.startsWith(`${baseDir}${path.sep}`)) {
|
|
|
|
// console.log(`Ignore '${file}' since it is not under '${baseDir}'.`)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if (fs.statSync(file).isDirectory()) {
|
|
|
|
// console.log(`Skip directory '${file}'.`)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
const hash = crypto.createHash('sha256')
|
|
|
|
const pipeline = util.promisify(stream.pipeline)
|
|
|
|
await pipeline(fs.createReadStream(file), hash)
|
2020-06-15 08:01:06 -04:00
|
|
|
hashes[path.relative(baseDir, file)] = hash.digest()
|
|
|
|
hasMatch = true
|
2020-06-15 06:59:55 -04:00
|
|
|
}
|
|
|
|
}
|
2020-06-15 08:01:06 -04:00
|
|
|
if (!hasMatch) return null
|
|
|
|
const result = crypto.createHash('sha256')
|
|
|
|
for (const file of Object.keys(hashes).sort()) {
|
|
|
|
result.update(hashes[file])
|
|
|
|
}
|
2020-06-15 06:59:55 -04:00
|
|
|
result.end()
|
2020-06-15 08:01:06 -04:00
|
|
|
return result.digest('hex')
|
2020-06-15 06:59:55 -04:00
|
|
|
}
|