nx/packages/gradle/src/utils/get-gradle-report.ts

207 lines
6.6 KiB
TypeScript

import { existsSync, readFileSync } from 'node:fs';
import { join, relative } from 'node:path';
import { normalizePath, workspaceRoot } from '@nx/devkit';
import { execGradle } from './exec-gradle';
export const fileSeparator = process.platform.startsWith('win')
? 'file:///'
: 'file://';
const newLineSeparator = process.platform.startsWith('win') ? '\r\n' : '\n';
export interface GradleReport {
gradleFileToGradleProjectMap: Map<string, string>;
buildFileToDepsMap: Map<string, string>;
gradleFileToOutputDirsMap: Map<string, Map<string, string>>;
gradleProjectToTasksTypeMap: Map<string, Map<string, string>>;
gradleProjectToProjectName: Map<string, string>;
}
let gradleReportCache: GradleReport;
export function invalidateGradleReportCache() {
gradleReportCache = undefined;
}
export function getGradleReport(): GradleReport {
if (gradleReportCache) {
return gradleReportCache;
}
const gradleProjectReportStart = performance.mark(
'gradleProjectReport:start'
);
const projectReportLines = execGradle(['projectReport'], {
cwd: workspaceRoot,
})
.toString()
.split(newLineSeparator);
const gradleProjectReportEnd = performance.mark('gradleProjectReport:end');
performance.measure(
'gradleProjectReport',
gradleProjectReportStart.name,
gradleProjectReportEnd.name
);
gradleReportCache = processProjectReports(projectReportLines);
return gradleReportCache;
}
export function processProjectReports(
projectReportLines: string[]
): GradleReport {
/**
* Map of Gradle File path to Gradle Project Name
*/
const gradleFileToGradleProjectMap = new Map<string, string>();
/**
* Map of Gradle Project Name to Gradle File
*/
const gradleProjectToGradleFileMap = new Map<string, string>();
const dependenciesMap = new Map<string, string>();
/**
* Map of Gradle Build File to tasks type map
*/
const gradleProjectToTasksTypeMap = new Map<string, Map<string, string>>();
const gradleProjectToProjectName = new Map<string, string>();
/**
* Map of buildFile to dependencies report path
*/
const buildFileToDepsMap = new Map<string, string>();
/**
* Map fo possible output files of each gradle file
* e.g. {build.gradle.kts: { projectReportDir: '' testReportDir: '' }}
*/
const gradleFileToOutputDirsMap = new Map<string, Map<string, string>>();
let index = 0;
while (index < projectReportLines.length) {
const line = projectReportLines[index].trim();
if (line.startsWith('> Task ')) {
if (line.endsWith(':dependencyReport')) {
const gradleProject = line.substring(
'> Task '.length,
line.length - ':dependencyReport'.length
);
while (
index < projectReportLines.length &&
!projectReportLines[index].includes(fileSeparator)
) {
index++;
}
const [_, file] = projectReportLines[index].split(fileSeparator);
dependenciesMap.set(gradleProject, file);
}
if (line.endsWith('propertyReport')) {
const gradleProject = line.substring(
'> Task '.length,
line.length - ':propertyReport'.length
);
while (
index < projectReportLines.length &&
!projectReportLines[index].includes(fileSeparator)
) {
index++;
}
const [_, file] = projectReportLines[index].split(fileSeparator);
const propertyReportLines = existsSync(file)
? readFileSync(file).toString().split(newLineSeparator)
: [];
let projectName: string,
absBuildFilePath: string,
absBuildDirPath: string;
const outputDirMap = new Map<string, string>();
for (const line of propertyReportLines) {
if (line.startsWith('name: ')) {
projectName = line.substring('name: '.length);
}
if (line.startsWith('buildFile: ')) {
absBuildFilePath = line.substring('buildFile: '.length);
}
if (line.startsWith('buildDir: ')) {
absBuildDirPath = line.substring('buildDir: '.length);
}
if (line.includes('Dir: ')) {
const [dirName, dirPath] = line.split(': ');
const taskName = dirName.replace('Dir', '');
outputDirMap.set(
taskName,
`{workspaceRoot}/${relative(workspaceRoot, dirPath)}`
);
}
}
if (!projectName || !absBuildFilePath || !absBuildDirPath) {
continue;
}
const buildFile = normalizePath(
relative(workspaceRoot, absBuildFilePath)
);
const buildDir = relative(workspaceRoot, absBuildDirPath);
buildFileToDepsMap.set(
buildFile,
dependenciesMap.get(gradleProject) as string
);
outputDirMap.set('build', `{workspaceRoot}/${buildDir}`);
outputDirMap.set(
'classes',
`{workspaceRoot}/${join(buildDir, 'classes')}`
);
gradleFileToOutputDirsMap.set(buildFile, outputDirMap);
gradleFileToGradleProjectMap.set(buildFile, gradleProject);
gradleProjectToGradleFileMap.set(gradleProject, buildFile);
gradleProjectToProjectName.set(gradleProject, projectName);
}
if (line.endsWith('taskReport')) {
const gradleProject = line.substring(
'> Task '.length,
line.length - ':taskReport'.length
);
while (
index < projectReportLines.length &&
!projectReportLines[index].includes(fileSeparator)
) {
index++;
}
const [_, file] = projectReportLines[index].split(fileSeparator);
const taskTypeMap = new Map<string, string>();
const tasksFileLines = existsSync(file)
? readFileSync(file).toString().split(newLineSeparator)
: [];
let i = 0;
while (i < tasksFileLines.length) {
const line = tasksFileLines[i];
if (line.endsWith('tasks')) {
const dashes = new Array(line.length + 1).join('-');
if (tasksFileLines[i + 1] === dashes) {
const type = line.substring(0, line.length - ' tasks'.length);
i++;
while (tasksFileLines[++i] !== '') {
const [taskName] = tasksFileLines[i].split(' - ');
taskTypeMap.set(taskName, type);
}
}
}
i++;
}
gradleProjectToTasksTypeMap.set(gradleProject, taskTypeMap);
}
}
index++;
}
return {
gradleFileToGradleProjectMap,
buildFileToDepsMap,
gradleFileToOutputDirsMap,
gradleProjectToTasksTypeMap,
gradleProjectToProjectName,
};
}