( files: string[], map = new Map<string | undefined, DeploymentFile>() )
| 67 | * @return Map of hash digest to file object |
| 68 | */ |
| 69 | export async function hashes( |
| 70 | files: string[], |
| 71 | map = new Map<string | undefined, DeploymentFile>() |
| 72 | ): Promise<FilesMap> { |
| 73 | const semaphore = new Sema(100); |
| 74 | |
| 75 | await Promise.all( |
| 76 | files.map(async (name: string): Promise<void> => { |
| 77 | await semaphore.acquire(); |
| 78 | |
| 79 | const stat = await fs.lstat(name); |
| 80 | const mode = stat.mode; |
| 81 | |
| 82 | let data: Buffer | undefined; |
| 83 | let size: number | undefined; |
| 84 | const isDirectory = stat.isDirectory(); |
| 85 | |
| 86 | let h: string | undefined; |
| 87 | |
| 88 | if (!isDirectory) { |
| 89 | if (stat.isSymbolicLink()) { |
| 90 | const link = await fs.readlink(name); |
| 91 | data = Buffer.from(link, 'utf8'); |
| 92 | size = data.length; |
| 93 | h = hash(data); |
| 94 | } else if (stat.size > MAX_BUFFER_FILE_SIZE) { |
| 95 | // Too large to read into a single Buffer; hash by streaming and leave |
| 96 | // `data` undefined so the upload streams it from disk as well. |
| 97 | size = stat.size; |
| 98 | h = await hashFile(name); |
| 99 | } else { |
| 100 | data = await fs.readFile(name); |
| 101 | size = data.length; |
| 102 | h = hash(data); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | const entry = map.get(h); |
| 107 | |
| 108 | if (entry) { |
| 109 | const names = new Set(entry.names); |
| 110 | names.add(name); |
| 111 | entry.names = [...names]; |
| 112 | } else { |
| 113 | map.set(h, { names: [name], data, mode, size }); |
| 114 | } |
| 115 | |
| 116 | semaphore.release(); |
| 117 | }) |
| 118 | ); |
| 119 | return map; |
| 120 | } |
no test coverage detected