@jnxplus/nx-maven
Version:
[](https://badge.fury.io/js/@jnxplus%2Fnx-maven)
377 lines • 16.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getWorkspaceData = getWorkspaceData;
exports.getNormalizedOptions = getNormalizedOptions;
exports.getCachePath = getCachePath;
exports.readWorkspaceDataCache = readWorkspaceDataCache;
exports.writeWorkspaceDataToCache = writeWorkspaceDataToCache;
exports.addProjects = addProjects;
exports.getEffectiveVersion = getEffectiveVersion;
exports.validateTargetInputs = validateTargetInputs;
exports.getOutputDirLocalRepo = getOutputDirLocalRepo;
exports.getTask = getTask;
exports.ifOutputDirLocalRepoNotPresent = ifOutputDirLocalRepoNotPresent;
const tslib_1 = require("tslib");
const common_1 = require("@jnxplus/common");
const xml_1 = require("@jnxplus/xml");
const devkit_1 = require("@nx/devkit");
const fs_1 = require("fs");
const cache_directory_1 = require("nx/src/utils/cache-directory");
const path_1 = require("path");
const utils_1 = require("../utils");
const file_hasher_1 = require("nx/src/hasher/file-hasher");
const workspace_context_1 = require("nx/src/utils/workspace-context");
let NORMALIZED_OPTIONS_CACHE = undefined;
const WORKSPACE_DATA_PROMISE_CACHE = new Map();
function getWorkspaceData(opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const normalizedOpts = getNormalizedOptions(opts);
const cachePath = yield getCachePath(normalizedOpts);
// Check if we already have a promise for this cache path
if (WORKSPACE_DATA_PROMISE_CACHE.has(cachePath)) {
const cachedPromise = WORKSPACE_DATA_PROMISE_CACHE.get(cachePath);
if (cachedPromise) {
return cachedPromise;
}
}
// Create and cache the promise
const workspaceDataPromise = computeWorkspaceData(normalizedOpts, cachePath);
WORKSPACE_DATA_PROMISE_CACHE.set(cachePath, workspaceDataPromise);
try {
return yield workspaceDataPromise;
}
catch (error) {
// Remove failed promise from cache so it can be retried
WORKSPACE_DATA_PROMISE_CACHE.delete(cachePath);
throw error;
}
});
}
function computeWorkspaceData(normalizedOpts, cachePath) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
// Check file system cache first
let data = readWorkspaceDataCache(cachePath);
if (data) {
return data;
}
const mavenRootDirAbsolutePath = (0, path_1.join)(devkit_1.workspaceRoot, normalizedOpts.mavenRootDirectory);
data = {
mavenRootDirAbsolutePath,
targetDefaults: getTargetDefaults(),
localRepo: normalizedOpts.localRepoRelativePath,
projects: {},
};
addProjects(data, normalizedOpts, normalizedOpts.mavenRootDirectory);
// Store data in cache for future use
writeWorkspaceDataToCache(cachePath, data);
return data;
});
}
function getNormalizedOptions(opts) {
if (!NORMALIZED_OPTIONS_CACHE) {
const plugin = (0, utils_1.getPlugin)();
const mavenRootDirectory = (0, utils_1.getMavenRootDirectory)(plugin);
NORMALIZED_OPTIONS_CACHE = {
buildTargetName: (0, common_1.getBuildTargetName)(plugin),
testTargetName: (0, common_1.getTestTargetName)(plugin),
serveTargetName: (0, common_1.getServeTargetName)(plugin),
integrationTestTargetName: (0, common_1.getIntegrationTestTargetName)(plugin),
buildImageTargetName: (0, common_1.getBuildImageTargetName)(plugin),
mavenRootDirectory,
localRepoRelativePath: (0, utils_1.getLocalRepositoryPath)(opts, (0, path_1.join)(devkit_1.workspaceRoot, mavenRootDirectory)),
graphOptions: {
skipAggregatorProjectLinking: (0, utils_1.getSkipAggregatorProjectLinkingOption)(plugin),
skipProjectWithoutProjectJson: (0, utils_1.getSkipProjectWithoutProjectJsonOption)(plugin),
},
};
}
return NORMALIZED_OPTIONS_CACHE;
}
/**
* Generate an hash filename matching all pom.xml content
* If one pom.xml change, hash is invalidated
*
* @param normalizedOptions
*/
function getCachePath(normalizedOptions) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const hash = (0, devkit_1.hashArray)([
yield (0, workspace_context_1.hashWithWorkspaceContext)(devkit_1.workspaceRoot, ['pom.xml', '**/pom.xml']),
(0, file_hasher_1.hashObject)(normalizedOptions),
]);
return (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `maven-workspace-data-${hash}.hash`);
});
}
function readWorkspaceDataCache(cachePath) {
return process.env['NX_CACHE_PROJECT_GRAPH'] !== 'false' &&
(0, fs_1.existsSync)(cachePath)
? (0, devkit_1.readJsonFile)(cachePath)
: null;
}
function writeWorkspaceDataToCache(cachePath, results) {
(0, devkit_1.writeJsonFile)(cachePath, results);
}
function addProjects(data, normalizedOpts, projectRelativePath, aggregatorProjectArtifactId) {
var _a;
const projectAbsolutePath = (0, path_1.join)(devkit_1.workspaceRoot, projectRelativePath);
const pomXmlPath = (0, path_1.join)(projectAbsolutePath, 'pom.xml');
const pomXmlContent = (0, xml_1.readXml)(pomXmlPath);
const artifactId = (0, utils_1.getArtifactId)(pomXmlContent);
const projectJsonPath = (0, path_1.join)(projectAbsolutePath, 'project.json');
data.projects[artifactId] = {
artifactId,
groupId: (0, utils_1.getGroupId)(artifactId, pomXmlContent),
version: (0, utils_1.getVersion)(artifactId, pomXmlContent),
isRootProject: !aggregatorProjectArtifactId,
isPomPackaging: isPomPackagingFunction(pomXmlContent),
projectRoot: getProjectRoot(projectAbsolutePath),
projectAbsolutePath,
dependencies: getDependencyArtifactIds(pomXmlContent),
profileDependencies: getProfileDependencyArtifactIds(pomXmlContent),
pluginDependencies: getPluginDependencyArtifactIds(pomXmlContent),
parentProjectArtifactId: getParentProjectName(pomXmlContent),
aggregatorProjectArtifactId: aggregatorProjectArtifactId,
properties: getProperties(pomXmlContent),
skipProject: normalizedOpts.graphOptions.skipProjectWithoutProjectJson &&
!(0, fs_1.existsSync)(projectJsonPath),
};
const moduleXmlElementArray = (_a = pomXmlContent === null || pomXmlContent === void 0 ? void 0 : pomXmlContent.childNamed('modules')) === null || _a === void 0 ? void 0 : _a.childrenNamed('module');
if (moduleXmlElementArray === undefined) {
return;
}
for (const moduleXmlElement of moduleXmlElementArray) {
const moduleRelativePath = (0, devkit_1.joinPathFragments)(projectRelativePath, moduleXmlElement.val.trim());
addProjects(data, normalizedOpts, moduleRelativePath, artifactId);
}
}
function getProjectRoot(projectAbsolutePath) {
let projectRoot = (0, devkit_1.normalizePath)((0, path_1.relative)(devkit_1.workspaceRoot, projectAbsolutePath));
// projectRoot should not be an empty string
if (!projectRoot) {
projectRoot = '.';
}
return projectRoot;
}
function getParentProjectName(pomXmlContent) {
var _a, _b;
const parentXmlElement = pomXmlContent.childNamed('parent');
if (parentXmlElement === undefined) {
return undefined;
}
const relativePath = (_a = parentXmlElement.childNamed('relativePath')) === null || _a === void 0 ? void 0 : _a.val;
if (!relativePath) {
return undefined;
}
return (_b = parentXmlElement.childNamed('artifactId')) === null || _b === void 0 ? void 0 : _b.val;
}
function getDependencyArtifactIds(pomXml) {
const dependenciesXml = pomXml.childNamed('dependencies');
if (dependenciesXml === undefined) {
return [];
}
return dependenciesXml
.childrenNamed('dependency')
.filter((dependencyXmlElement) => {
var _a;
const groupId = (_a = dependencyXmlElement.childNamed('groupId')) === null || _a === void 0 ? void 0 : _a.val;
return (groupId !== 'org.springframework.boot' &&
groupId !== 'io.quarkus' &&
groupId !== 'io.micronaut');
})
.map((dependencyXmlElement) => {
var _a;
return (_a = dependencyXmlElement.childNamed('artifactId')) === null || _a === void 0 ? void 0 : _a.val;
});
}
function isPomPackagingFunction(pomXmlContent) {
const packagingXml = pomXmlContent.childNamed('packaging');
if (packagingXml === undefined) {
return false;
}
return packagingXml.val === 'pom';
}
function getEffectiveVersion(project, workspaceData) {
let newVersion = project.version;
//1 if version is constant return it
if (isConstantVersion(newVersion)) {
return newVersion;
}
//2 try to calculate version from project properties
newVersion = getVersionFromProperties(newVersion, project.properties);
if (isConstantVersion(newVersion)) {
return newVersion;
}
//3 try to calculate version from parent project
// we just calculate the part we didn't calculate in step 2
newVersion = getVersionFromParentProject(newVersion, project.parentProjectArtifactId, workspaceData.projects);
if (isConstantVersion(newVersion)) {
return newVersion;
}
//4 Can't calculate version, maybe contains something like ${project.parent.version}
// call help:evaluate to get version and add warning because help:evaluate took a lot of time
devkit_1.logger.warn(`Can't calculate version ${newVersion} of project ${project.artifactId} without using mvn help:evaluate that take a lot of time. Please Open an issue to address this case.`);
return (0, utils_1.getExpressionValue)('project.version', workspaceData.mavenRootDirAbsolutePath, project.artifactId);
}
function getVersionFromParentProject(newVersion, parentProjectArtifactId, projects) {
if (!parentProjectArtifactId) {
return newVersion;
}
const parentProject = projects[parentProjectArtifactId];
newVersion = getVersionFromProperties(newVersion, parentProject.properties);
if (isConstantVersion(newVersion)) {
return newVersion;
}
return getVersionFromParentProject(newVersion, parentProject.parentProjectArtifactId, projects);
}
function validateTargetInputs(targetName, file, inputs) {
if ((inputs !== null && inputs !== void 0 ? inputs : []).some((element) => typeof element === 'string' &&
element === '{options.outputDirLocalRepo}')) {
throw new Error(`"{options.outputDirLocalRepo}" is not allowed in target inputs. To make it works, remove it from "${targetName}" target in "${file}" file. If you have a valid use case, please open an issue.`);
}
}
function getTargetDefaults() {
var _a;
const targetDefaults = [];
const nxJsonPath = (0, path_1.join)(devkit_1.workspaceRoot, 'nx.json');
const nxJson = (0, devkit_1.readJsonFile)(nxJsonPath);
if (nxJson.targetDefaults) {
for (const [targetName, target] of Object.entries(nxJson.targetDefaults)) {
validateTargetInputs(targetName, 'nx.json', target.inputs);
if (((_a = target.outputs) !== null && _a !== void 0 ? _a : []).some((element) => element === '{options.outputDirLocalRepo}')) {
targetDefaults.push(targetName);
}
}
}
return targetDefaults;
}
function isConstantVersion(version) {
const index = version.indexOf('${');
if (index >= 0) {
return false;
}
return true;
}
function getProperties(pomXmlContent) {
//properties
const propertiesXml = pomXmlContent.childNamed('properties');
const properties = [];
if (propertiesXml === undefined) {
return properties;
}
propertiesXml.eachChild((propertyXml) => {
properties.push({ key: propertyXml.name, value: propertyXml.val });
});
return properties;
}
function getVersionFromProperties(version, properties) {
if (properties.length === 0) {
return version;
}
const versionExpressions = extractExpressions(version);
if (versionExpressions.length === 0) {
throw new Error(`Version ${version} is a constant`);
}
const commonProperties = properties.filter((p) => versionExpressions.includes(p.key));
if (commonProperties.length === 0) {
return version;
}
let parsedVersion = version;
for (const property of commonProperties) {
parsedVersion = parsedVersion.replace('${' + property.key + '}', property.value);
}
if (version === parsedVersion) {
throw new Error(`Code not working properly: version ${version} and parsedVersion ${parsedVersion} should not be the same`);
}
return parsedVersion;
}
function extractExpressions(version) {
const expressionRegex = /\${([^${}]*)}/g;
const expressions = [];
let match;
while ((match = expressionRegex.exec(version)) !== null) {
expressions.push(match[1]);
}
const containsAnExpression = expressions.some((p) => p.indexOf('$') >= 0);
if (containsAnExpression) {
throw new Error(`Version ${version} not correctly parsed with regex ${expressionRegex}`);
}
return expressions;
}
function getProfileDependencyArtifactIds(pomXml) {
let results = [];
const profilesXml = pomXml.childNamed('profiles');
if (profilesXml === undefined) {
return [];
}
const profileXmlArray = profilesXml.childrenNamed('profile');
for (const profileXml of profileXmlArray) {
const dependenciesXml = profileXml.childNamed('dependencies');
if (dependenciesXml === undefined) {
continue;
}
const profileDependencyArtifactIds = dependenciesXml
.childrenNamed('dependency')
.map((dependencyXmlElement) => {
var _a;
return (_a = dependencyXmlElement.childNamed('artifactId')) === null || _a === void 0 ? void 0 : _a.val;
});
results = results.concat(profileDependencyArtifactIds);
}
return results;
}
function getPluginDependencyArtifactIds(pomXml) {
let results = [];
const buildXml = pomXml.childNamed('build');
if (buildXml === undefined) {
return [];
}
results = results.concat(getPluginDependencyArtifactIdsFromPluginsTag(buildXml));
const pluginManagementXml = buildXml.childNamed('pluginManagement');
if (pluginManagementXml === undefined) {
return results;
}
results = results.concat(getPluginDependencyArtifactIdsFromPluginsTag(pluginManagementXml));
return results;
}
function getPluginDependencyArtifactIdsFromPluginsTag(xmlElement) {
let results = [];
const pluginsXml = xmlElement.childNamed('plugins');
if (pluginsXml === undefined) {
return [];
}
const pluginXmlArray = pluginsXml.childrenNamed('plugin');
for (const profileXml of pluginXmlArray) {
const dependenciesXml = profileXml.childNamed('dependencies');
if (dependenciesXml === undefined) {
continue;
}
const pluginDependencyArtifactIds = dependenciesXml
.childrenNamed('dependency')
.map((dependencyXmlElement) => {
var _a;
return (_a = dependencyXmlElement.childNamed('artifactId')) === null || _a === void 0 ? void 0 : _a.val;
});
results = results.concat(pluginDependencyArtifactIds);
}
return results;
}
function getOutputDirLocalRepo(localRepositoryPath, groupId, artifactId, projectVersion) {
return (0, path_1.join)(localRepositoryPath, `${groupId.replace(new RegExp(/\./, 'g'), '/')}/${artifactId}/${projectVersion}`);
}
function getTask(isRootProject) {
if (isRootProject) {
return 'install -N';
}
return 'install';
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function ifOutputDirLocalRepoNotPresent(options) {
if (!options) {
return true;
}
if ('outputDirLocalRepo' in options) {
return false;
}
return true;
}
//# sourceMappingURL=graph-utils.js.map