UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

130 lines (114 loc) 3.38 kB
'use strict' const os = require('os') const path = require('path') const fs = require('fs') const crypto = require('crypto') const cp = require('child_process') const log = require('../../log') const getConfig = require('../../config') let isGitEnabled let gitCacheDir function ensureCacheDir () { if (isGitEnabled === undefined) { const config = getConfig() isGitEnabled = config.DD_EXPERIMENTAL_TEST_OPT_GIT_CACHE_ENABLED // TODO: Move the default to config/index.js applyCalculated // when using the config singleton. gitCacheDir = config.DD_EXPERIMENTAL_TEST_OPT_GIT_CACHE_DIR || path.join(os.tmpdir(), 'dd-trace-git-cache') } if (!isGitEnabled) return false try { if (fs.existsSync(gitCacheDir)) { const stats = fs.statSync(gitCacheDir) if (!stats.isDirectory()) { throw new Error(`Cache directory path exists but is not a directory: ${gitCacheDir}`) } } else { fs.mkdirSync(gitCacheDir, { recursive: true }) } return true } catch (err) { log.error('Failed to create git cache directory, disabling cache', err) isGitEnabled = false return false } } function getCacheKey (cmd, flags) { // Create a hash of the command and flags to use as cache key const commandString = `${cmd} ${flags.join(' ')}` return crypto.createHash('sha256').update(commandString).digest('hex') } function getCacheFilePath (cacheKey) { ensureCacheDir() return path.join(gitCacheDir, `${cacheKey}.cache`) } function getCache (cacheKey) { if (!ensureCacheDir()) return null try { const cacheFilePath = getCacheFilePath(cacheKey) if (!fs.existsSync(cacheFilePath)) { return } return fs.readFileSync(cacheFilePath, 'utf8') } catch (err) { log.error('Failed to read git cache', err) } } function setCache (cacheKey, result) { if (!ensureCacheDir()) return try { const cacheFilePath = getCacheFilePath(cacheKey) fs.writeFileSync(cacheFilePath, result, 'utf8') } catch (err) { log.error('Failed to write git cache', err) } } function cachedExec (cmd, flags, options) { if (options === undefined) { options = { stdio: 'pipe' } } if (!ensureCacheDir()) { return cp.execFileSync(cmd, flags, options) } const cacheKey = getCacheKey(cmd, flags) const cachedResult = getCache(cacheKey) if (cachedResult !== undefined) { if (cachedResult.startsWith('__GIT_COMMAND_FAILED__')) { let error try { const errorData = cachedResult.replace('__GIT_COMMAND_FAILED__', '') const { message, code, status, errno } = JSON.parse(errorData) error = new Error(message) error.code = code error.status = status error.errno = errno } catch { // we couldn't parse the error data, so we'll throw a generic error throw new Error('Git command failed') } throw error } return cachedResult } try { const result = cp.execFileSync(cmd, flags, options) setCache(cacheKey, result) return result } catch (err) { const cacheValue = '__GIT_COMMAND_FAILED__' + JSON.stringify({ code: err.code, status: err.status, errno: err.errno, message: err.message, }) setCache(cacheKey, cacheValue) throw err } } module.exports = { getCacheKey, getCacheFilePath, cachedExec, }