Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tools] Fix transforming binary files #19251

Merged
merged 1 commit into from
Sep 27, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 31 additions & 21 deletions tools/src/Transforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,30 +41,29 @@ export function transformString(

async function getTransformedFileContentAsync(
filePath: string,
transforms: FileTransform[],
options?: {
// File path to match the `transforms.paths` pattern, e.g. use relative path here
transformMatchPath?: string;
}
transforms: FileTransform[]
): Promise<string> {
// Filter out transforms that don't match paths patterns.
const sourceFile = options?.transformMatchPath ?? filePath;
const filteredContentTransforms = transforms.filter(
({ paths }) =>
!paths ||
arrayize(paths).some((pattern) => minimatch(sourceFile, pattern, { matchBase: true }))
);

// Transform source content.
let result = await fs.readFile(filePath, 'utf8');
for (const transform of filteredContentTransforms) {
for (const transform of transforms) {
const beforeTransformation = result;
result = applySingleTransform(result, transform);
await maybePrintDebugInfoAsync(beforeTransformation, result, filePath, transform);
}
return result;
}

/**
* Filters file contents transformations to only these that match path patterns.
* `filePath` param should be a relative path.
*/
function getFilteredContentTransforms(transforms: FileTransform[], filePath: string) {
return transforms.filter(
({ paths }) =>
!paths || arrayize(paths).some((pattern) => minimatch(filePath, pattern, { matchBase: true }))
);
}

async function maybePrintDebugInfoAsync(
contentBefore: string,
contentAfter: string,
Expand Down Expand Up @@ -119,8 +118,10 @@ export async function transformFileAsync(
*/
export async function transformFilesAsync(files: string[], transforms: FileTransform[]) {
for (const file of files) {
const filteredContentTransforms = getFilteredContentTransforms(transforms ?? [], file);

// Transform source content.
const content = await getTransformedFileContentAsync(file, transforms);
const content = await getTransformedFileContentAsync(file, filteredContentTransforms);

// Save transformed content
await fs.outputFile(file, content);
Expand All @@ -140,13 +141,22 @@ export async function copyFileWithTransformsAsync(
const targetFile = transformString(sourceFile, transforms.path);
const targetPath = path.join(targetDirectory, targetFile);

// Transform source content.
const content = await getTransformedFileContentAsync(sourcePath, transforms.content ?? [], {
transformMatchPath: sourceFile,
});
const filteredContentTransforms = getFilteredContentTransforms(
transforms.content ?? [],
sourceFile
);

// Save transformed source file at renamed target path.
await fs.outputFile(targetPath, content);
// Transform source content.
const content = await getTransformedFileContentAsync(sourcePath, filteredContentTransforms);

if (filteredContentTransforms.length > 0) {
// Save transformed source file at renamed target path.
await fs.outputFile(targetPath, content);
} else {
// When there are no transforms, it's safer to just copy the file.
// Only then binary files will be copied properly since the `content` is utf8-encoded.
await fs.copy(sourcePath, targetPath, { overwrite: true });
}

// Keep original file mode if needed.
if (options.keepFileMode) {
Expand Down