UNPKG

sfdx-git-delta

Version:

Generate the sfdx content in source format and destructive change from two git commits

147 lines 5.58 kB
import { join } from 'node:path/posix'; import { simpleGit } from 'simple-git'; import { TAB } from '../constant/cliConstants.js'; import { PATH_SEP, UTF8_ENCODING } from '../constant/fsConstants.js'; import { ADDITION, BLOB_TYPE, DELETION, HEAD, IGNORE_WHITESPACE_PARAMS, MODIFICATION, NUM_STAT_CHANGE_INFORMATION, TREE_TYPE, } from '../constant/gitConstants.js'; import { treatPathSep } from '../utils/fsUtils.js'; import { getLFSObjectContentPath, isLFS } from '../utils/gitLfsHelper.js'; import { readFile } from 'node:fs/promises'; const EOL = new RegExp(/\r?\n/); const revPath = (pathDef) => `${pathDef.oid}:${pathDef.path}`; export default class GitAdapter { config; static instances = new Map(); static getInstance(config) { if (!GitAdapter.instances.has(config)) { const instance = new GitAdapter(config); GitAdapter.instances.set(config, instance); } return GitAdapter.instances.get(config); } simpleGit; getFilesPathCache; pathExistsCache; constructor(config) { this.config = config; this.simpleGit = simpleGit({ baseDir: config.repo, trimmed: true }); this.getFilesPathCache = new Map(); this.pathExistsCache = new Map(); } async configureRepository() { await this.simpleGit.addConfig('core.longpaths', 'true'); await this.simpleGit.addConfig('core.quotepath', 'off'); } async parseRev(ref) { return await this.simpleGit.revparse(['--verify', ref]); } async pathExistsImpl(path) { let doesPathExists = false; try { const type = await this.simpleGit.catFile([ '-t', revPath({ path, oid: this.config.to }), ]); doesPathExists = [TREE_TYPE, BLOB_TYPE].includes(type.trimEnd()); } catch { doesPathExists = false; } return doesPathExists; } async pathExists(path) { if (this.pathExistsCache.has(path)) { return this.pathExistsCache.get(path); } const doesPathExists = await this.pathExistsImpl(path); this.pathExistsCache.set(path, doesPathExists); return doesPathExists; } async getFirstCommitRef() { return await this.simpleGit.raw(['rev-list', '--max-parents=0', HEAD]); } async getBufferContent(forRef) { let content = await this.simpleGit.showBuffer(revPath(forRef)); if (isLFS(content)) { const lsfPath = getLFSObjectContentPath(content); content = await readFile(join(this.config.repo, lsfPath)); } return content; } async getStringContent(forRef) { const content = await this.getBufferContent(forRef); return content.toString(UTF8_ENCODING); } async getFilesPathImpl(path) { return (await this.simpleGit.raw([ 'ls-tree', '--name-only', '-r', this.config.to, path || '.', ])) .split(EOL) .filter(line => line) .map(line => treatPathSep(line)); } async getFilesPath(path) { if (this.getFilesPathCache.has(path)) { return Array.from(this.getFilesPathCache.get(path)); } const filesPath = await this.getFilesPathImpl(path); const pathSegmentsLength = path.split(PATH_SEP).length; // Start iterating over each filePath for (const filePath of filesPath) { const relevantSegments = filePath .split(PATH_SEP) .slice(pathSegmentsLength); // Only cache the sub-paths for relevant files starting from the given path const subPathSegments = [path]; for (const segment of relevantSegments) { subPathSegments.push(segment); const currentPath = subPathSegments.join(PATH_SEP); if (!this.getFilesPathCache.has(currentPath)) { this.getFilesPathCache.set(currentPath, new Set()); } this.getFilesPathCache.get(currentPath).add(filePath); } } // Store the full set of file paths for the given path in cache this.getFilesPathCache.set(path, new Set(filesPath)); return filesPath; } async *getFilesFrom(path) { const filesPath = await this.getFilesPath(path); for (const filePath of filesPath) { const fileContent = await this.getBufferContent({ path: filePath, oid: this.config.to, }); yield { path: filePath, content: fileContent, }; } } async getDiffLines() { let lines = []; for (const changeType of [ADDITION, MODIFICATION, DELETION]) { const linesOfType = await this.getDiffForType(changeType); lines = lines.concat(linesOfType.map(line => line.replace(NUM_STAT_CHANGE_INFORMATION, `${changeType}${TAB}`))); } return lines.map(treatPathSep); } async getDiffForType(changeType) { return (await this.simpleGit.raw([ 'diff', '--numstat', '--no-renames', ...(this.config.ignoreWhitespace ? IGNORE_WHITESPACE_PARAMS : []), `--diff-filter=${changeType}`, this.config.from, this.config.to, '--', this.config.source, ])).split(EOL); } } //# sourceMappingURL=GitAdapter.js.map