Skip to content

Commit

Permalink
[JavaToolInstallerV0] add Maven Toolchains declaration (microsoft#16492)
Browse files Browse the repository at this point in the history
Add Maven Toolchains declaration generation based on the JDK input parameters
  • Loading branch information
Okeanos committed Jun 25, 2022
1 parent 68c1642 commit b878223
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 1 deletion.
Expand Up @@ -26,6 +26,8 @@
"loc.input.help.cleanDestinationDirectory": "Select this option to clean the destination directory before JDK is extracted into it.",
"loc.input.label.createExtractDirectory": "Create directory for extracting",
"loc.input.help.createExtractDirectory": "By default, task is creating a directory similar to this JAVA_HOME_8_X64_OpenJDK_zip for extracting JDK. This option allows to disable creation of this folder, in this case, JDK will be located in the root of jdkDestinationDirectory",
"loc.input.label.createMavenToolchains": "Create Maven Toolchains declaration",
"loc.input.help.createMavenToolchains": "Create a Maven Toolchains declaration in the official default location describing the JDK that was installed with this task. Existing Maven Toolchains are modified accordingly.",
"loc.messages.DownloadFromAzureBlobStorage": "Downloading artifacts from Azure blob storage, Container Name: %s",
"loc.messages.SuccessFullyFetchedItemList": "Successfully fetched list of items",
"loc.messages.StorageAccountDoesNotExist": "Failed to get azure storage account with name %s.",
Expand Down
11 changes: 11 additions & 0 deletions Tasks/JavaToolInstallerV0/Tests/L0.ts
Expand Up @@ -51,4 +51,15 @@ describe('JavaToolInstaller L0 Suite', function () {

assert(testRunner.failed, 'task should have failed');
});

it('should run successfully when creating a Maven Toolchains Declaration', function () {
this.timeout(20000);

const testPath: string = path.join(__dirname, 'L0MavenToolchains.js');
const testRunner: ttm.MockTestRunner = new ttm.MockTestRunner(testPath);

testRunner.run();

assert(testRunner.succeeded, 'task should have succeeded.');
});
});
106 changes: 106 additions & 0 deletions Tasks/JavaToolInstallerV0/Tests/L0MavenToolchains.ts
@@ -0,0 +1,106 @@
import mockanswer = require('azure-pipelines-task-lib/mock-answer');
import tmrm = require('azure-pipelines-task-lib/mock-run');
import msRestAzure = require('azure-pipelines-tasks-azure-arm-rest-v2/azure-arm-common');
import path = require('path');
import os = require('os');
import mockTask = require('azure-pipelines-task-lib/mock-task');

const taskPath = path.join(__dirname, '..', 'javatoolinstaller.js');
const tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);

const destDir = path.join(os.homedir(), '.m2');
const destFile = path.join(destDir, 'toolchains.xml');

tr.setInput("versionSpec", "8.1");
tr.setInput("jdkSource", "Azure Storage")
tr.setInput("artifactProvider", "azureStorage");
tr.setInput("azureResourceManagerEndpoint", "ARM1");
tr.setInput("azureStorageAccountName", "storage1");
tr.setInput("azureContainerName", "container1");
tr.setInput("azureCommonVirtualPath", "");
tr.setInput("fileType", ".tar.gz");
tr.setInput("destinationFolder", "javaJDK");
tr.setInput("cleanDestinationFolder", "false");
tr.setInput("createMavenToolchains", "true");

// provide answers for task mock
const a: mockanswer.TaskLibAnswers = <mockanswer.TaskLibAnswers>{
exist: {[destDir]: true, [destFile]: true},
find: {[destDir]: [destDir], [destFile]: [destFile]},
rmRF: { },
stats: {[destDir]: {'isDirectory':'true'}, [destFile]: {'isFile':'true'}},
};
tr.setAnswers(a);

tr.registerMock("azure-pipelines-tasks-azure-arm-rest-v2/azure-arm-storage", {
StorageManagementClient: function (A, B) {
return {
storageAccounts: {
get: function (A) {
return {
properties: {
primaryEndpoints: {
blob: "primaryBlobUrl"
}
},
id: "StorageAccountUrl"
}
},
listkeys: function (A, B, C) {
return ["accesskey1", "accessKey2"];
}
}
}
},
StorageAccounts: {
getResourceGroupNameFromUri: function (A) {
return "storageAccountResouceGroupName";
}
}
});

tr.registerMock("azure-pipelines-tasks-azure-arm-rest-v2/azure-arm-common", {
ApplicationTokenCredentials: function(A,B,C,D,E,F,G) {
return {};
}
});

tr.registerMock('./AzureStorageArtifacts/AzureStorageArtifactDownloader',{
AzureStorageArtifactDownloader: function(A,B,C) {
return {
downloadArtifacts: function(A,B) {
return "pathFromDownloader";
}
}
}
})

const mtl = require("azure-pipelines-tool-lib/tool")
const mtlClone = Object.assign({}, mtl);

mtlClone.prependPath = function(variable1: string, variable2: string) {
return {};
};

tr.registerMock("azure-pipelines-tool-lib/tool", mtlClone);

const mfs = require('fs')
const mfsClone = Object.assign({}, mfs);

mfsClone.lstatSync = function(variable: string) {
return {
isDirectory: function() {
return true;
}
};
};

mfsClone.existsSync = function (variable: string) {
if (variable === "DestinationDirectory\\econdlevelJDK2" || variable === "DestinationDirectory/econdlevelJDK2") {
return false;
} else return true;
}

tr.registerMock('fs', mfsClone);

tr.run();
5 changes: 5 additions & 0 deletions Tasks/JavaToolInstallerV0/javatoolinstaller.ts
Expand Up @@ -8,6 +8,7 @@ import * as telemetry from 'azure-pipelines-tasks-utility-common/telemetry';
import { AzureStorageArtifactDownloader } from './AzureStorageArtifacts/AzureStorageArtifactDownloader';
import { JavaFilesExtractor, BIN_FOLDER } from './FileExtractor/JavaFilesExtractor';
import taskutils = require('./taskutils');
import {configureToolchains} from "./toolchains";

const VOLUMES_FOLDER: string = '/Volumes';
const JDK_FOLDER: string = '/Library/Java/JavaVirtualMachines';
Expand All @@ -32,6 +33,7 @@ async function getJava(versionSpec: string, jdkArchitectureOption: string): Prom
const fromAzure: boolean = ('AzureStorage' == taskLib.getInput('jdkSourceOption', true));
const extractLocation: string = taskLib.getPathInput('jdkDestinationDirectory', true);
const cleanDestinationDirectory: boolean = taskLib.getBoolInput('cleanDestinationDirectory', false);
const createMavenToolchains = taskLib.getBoolInput('createMavenToolchains', false);
let compressedFileExtension: string;
let jdkDirectory: string;
const extendedJavaHome: string = `JAVA_HOME_${versionSpec}_${jdkArchitectureOption}`.toUpperCase();
Expand Down Expand Up @@ -76,6 +78,9 @@ async function getJava(versionSpec: string, jdkArchitectureOption: string): Prom
console.log(taskLib.loc('SetExtendedJavaHome', extendedJavaHome, jdkDirectory));
taskLib.setVariable(extendedJavaHome, jdkDirectory);
toolLib.prependPath(path.join(jdkDirectory, BIN_FOLDER));
if (createMavenToolchains) {
await configureToolchains(version, 'unknown', jdkDirectory);
}
}

/**
Expand Down
55 changes: 55 additions & 0 deletions Tasks/JavaToolInstallerV0/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Tasks/JavaToolInstallerV0/package.json
Expand Up @@ -30,7 +30,8 @@
"azure-pipelines-task-lib": "^3.1.2",
"azure-pipelines-tasks-azure-arm-rest-v2": "2.0.4",
"azure-pipelines-tasks-utility-common": "^3.0.3",
"azure-pipelines-tool-lib": "^1.0.2"
"azure-pipelines-tool-lib": "^1.0.2",
"xmlbuilder2": "^2.4.1"
},
"devDependencies": {
"typescript": "4.0.2"
Expand Down
8 changes: 8 additions & 0 deletions Tasks/JavaToolInstallerV0/task.json
Expand Up @@ -134,6 +134,14 @@
"defaultValue": true,
"visibleRule": "jdkSourceOption != PreInstalled",
"helpMarkDown": "By default, task is creating a directory similar to this JAVA_HOME_8_X64_OpenJDK_zip for extracting JDK. This option allows to disable creation of this folder, in this case, JDK will be located in the root of jdkDestinationDirectory"
},
{
"name": "createMavenToolchains",
"type": "boolean",
"label": "Create Maven Toolchains declaration",
"required": false,
"defaultValue": false,
"helpMarkDown": "Create a Maven Toolchains declaration in the official default location describing the JDK that was installed with this task. Existing Maven Toolchains are modified accordingly."
}
],
"dataSourceBindings": [
Expand Down
8 changes: 8 additions & 0 deletions Tasks/JavaToolInstallerV0/task.loc.json
Expand Up @@ -134,6 +134,14 @@
"defaultValue": true,
"visibleRule": "jdkSourceOption != PreInstalled",
"helpMarkDown": "ms-resource:loc.input.help.createExtractDirectory"
},
{
"name": "createMavenToolchains",
"type": "boolean",
"label": "ms-resource:loc.input.label.createMavenToolchains",
"required": false,
"defaultValue": false,
"helpMarkDown": "ms-resource:loc.input.help.createMavenToolchains"
}
],
"dataSourceBindings": [
Expand Down
121 changes: 121 additions & 0 deletions Tasks/JavaToolInstallerV0/toolchains.ts
@@ -0,0 +1,121 @@
import fs = require('fs');
import os = require('os');
import path = require('path');
import taskLib = require('azure-pipelines-task-lib/task');
import toolLib = require('azure-pipelines-tool-lib/tool');
import { create as xmlCreate } from 'xmlbuilder2';

const M2_DIR = '.m2';
const MVN_TOOLCHAINS_FILE: string = 'toolchains.xml';

export async function configureToolchains(version: string, vendor: string, jdkHome: string) {
const id = `${vendor}_${version}`;
const settingsDirectory = path.join(os.homedir(), M2_DIR);

await createToolchainsSettings(
version,
vendor,
id,
jdkHome,
settingsDirectory,
);
}

async function createToolchainsSettings(
version: string,
vendor: string,
id: string,
jdkHome: string,
settingsDirectory: string,
) {
toolLib.debug(`Creating ${MVN_TOOLCHAINS_FILE} for JDK version ${version} from ${vendor}`);
await taskLib.mkdirP(settingsDirectory);
const originalToolchains = await readExisting(settingsDirectory);
const updatedToolchains = generate(originalToolchains, version, vendor, id, jdkHome);
await write(settingsDirectory, updatedToolchains, true);
}

function generate(
original: string,
version: string,
vendor: string,
id: string,
jdkHome: string
) {
let xmlObj;
if (original && original.length > 0) {
xmlObj = xmlCreate(original)
.root()
.ele({
type: 'jdk',
provides: {
version: `${version}`,
vendor: `${vendor}`,
id: `${id}`
},
configuration: {
jdkHome: `${jdkHome}`
}
});
} else
xmlObj = xmlCreate({
toolchains: {
'@xmlns': 'https://maven.apache.org/TOOLCHAINS/1.1.0',
'@xmlns:xsi': 'https://www.w3.org/2001/XMLSchema-instance',
'@xsi:schemaLocation':
'https://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd',
toolchain: [
{
type: 'jdk',
provides: {
version: `${version}`,
vendor: `${vendor}`,
id: `${id}`
},
configuration: {
jdkHome: `${jdkHome}`
}
}
]
}
});

return xmlObj.end({
format: 'xml',
wellFormed: false,
headless: false,
prettyPrint: true,
width: 80
});
}

async function readExisting(directory: string) {
const location = path.join(directory, MVN_TOOLCHAINS_FILE);
if (fs.existsSync(location)) {
return fs.readFileSync(location, {
encoding: 'utf-8',
flag: 'r'
});
}
return '';
}

async function write(directory: string, settings: string, overwriteSettings: boolean) {
const location = path.join(directory, MVN_TOOLCHAINS_FILE);
const settingsExists = fs.existsSync(location);
if (settingsExists && overwriteSettings) {
toolLib.debug(`Overwriting existing file ${location}`);
} else if (!settingsExists) {
toolLib.debug(`Writing to ${location}`);
} else {
toolLib.debug(
`Skipping generation ${location} because file already exists and overwriting is not required`
);
return;
}

return fs.writeFileSync(location, settings, {
encoding: 'utf-8',
flag: 'w'
});
}

0 comments on commit b878223

Please sign in to comment.