diff --git a/Tasks/DotNetCoreInstallerV0/Strings/resources.resjson/en-US/resources.resjson b/Tasks/DotNetCoreInstallerV0/Strings/resources.resjson/en-US/resources.resjson index 95e966847425..7b24abe4fd1a 100644 --- a/Tasks/DotNetCoreInstallerV0/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/DotNetCoreInstallerV0/Strings/resources.resjson/en-US/resources.resjson @@ -6,22 +6,24 @@ "loc.input.label.packageType": "Package to install", "loc.input.help.packageType": "Please select whether to install only runtime or full SDK.", "loc.input.label.version": "Version", - "loc.input.help.version": "Specify exact version of .NET Core SDK or runtime to install.

Examples:
1. To install 1.0.4 SDK, use 1.0.4
2. To install 1.1.2 runtime, use 1.1.2
2. To install 2.0 preview 2 runtime, use 2.0.0-preview2-25407-01

For getting more details about exact version, refer [here](https://github.com/dotnet/core/blob/master/release-notes/releases.csv)", + "loc.input.help.version": "Specify exact version of .NET Core SDK or runtime to install.
Find the value of `version-sdk` for installing SDK, or `version-runtime` for installing Runtime from any releases [here](https://github.com/dotnet/core/blob/master/release-notes/releases.json)", "loc.messages.ToolFailed": "Tool install failed: %s", "loc.messages.ImplicitVersionNotSupported": "Version should be a valid and explicit version: %s", - "loc.messages.PrimaryUrlDownloadFailed": "Failed to download .NET Core package using primary URL. Error: %s.", - "loc.messages.LegacyUrlDownloadFailed": "Failed to download .NET Core package using legacy URL as well. Error: %s.", - "loc.messages.DownloadFailed": "Failed to download .NET Core package. Please ensure that .NET Core %s of version %s exists. Check out: https://github.com/dotnet/core/blob/master/release-notes/releases.csv", - "loc.messages.getDownloadUrlsFailed": "Failed to get download urls. Error: %s.", + "loc.messages.getMachinePlatformFailed": "Failed to get machine platform details. Error: %s.", "loc.messages.UsingCachedTool": "Cached copy of .NET Core exists. No need to install afresh. Cached tool location: %s.", "loc.messages.CheckingToolCache": "Checking if a cached copy exists for this version...", "loc.messages.InstallingAfresh": "Cache does not contains this particular .NET Core. Will be downloaded and installed.", - "loc.messages.GettingDownloadUrls": "Getting URLs to download .NET Core %s version: %s.", - "loc.messages.NullDownloadUrls": "Could not construct download Urls. Please ensure that specified version is valid.", - "loc.messages.DownloadingPrimaryUrl": "Downloading .NET Core package from primary URL: %s", - "loc.messages.DownloadingSecondaryUrl": "Downloading .NET Core package from legacy URL: %s", + "loc.messages.GettingDownloadUrl": "Getting URL to download .NET Core %s version: %s.", + "loc.messages.CouldNotDetectPlatform": "Could not detect the machine's OS", + "loc.messages.NullDownloadUrls": "Could not construct download Url. Please ensure that specified version %s is valid.", + "loc.messages.DownloadingUrl": "Downloading .NET Core package from URL: %s", "loc.messages.ExtractingPackage": "Extracting downloaded package %s.", "loc.messages.CachingTool": "Caching this installed tool.", "loc.messages.SuccessfullyInstalled": "Successfully installed .NET Core %s version %s.", - "loc.messages.ToolToInstall": "Tool to install: .NET Core %s version %s." + "loc.messages.ToolToInstall": "Tool to install: .NET Core %s version %s.", + "loc.messages.PrimaryPlatform": "Detected platform (Primary): %s", + "loc.messages.LegacyPlatform": "Detected platform (Legacy): %s", + "loc.messages.VersionNotFound": "Could not fetch download information for version %s. Please check if the version specified is correct. You can refer https://github.com/dotnet/core/blob/master/release-notes/releases.json", + "loc.messages.CouldNotDownload": "Could not download installation package from this URL: %s Error: %s", + "loc.messages.FailedToDownloadPackage": "Failed to download package for installation" } \ No newline at end of file diff --git a/Tasks/DotNetCoreInstallerV0/Tests/InstallNix.ts b/Tasks/DotNetCoreInstallerV0/Tests/InstallNix.ts index f334175007bb..cf6c8ea310e2 100644 --- a/Tasks/DotNetCoreInstallerV0/Tests/InstallNix.ts +++ b/Tasks/DotNetCoreInstallerV0/Tests/InstallNix.ts @@ -14,33 +14,27 @@ process.env["AGENT_TEMPDIRECTORY"] = "/agent/_temp"; let a: ma.TaskLibAnswers = { "exec": { - "/somedir/currdir/externals/install-dotnet.sh --version 1.0.4 --dry-run": { - "code": process.env["__get_dlurls_failed__"] === "true" ? -1 : 0, - "stdout": process.env["__get_dlurls_failed__"] === "true" ? "" : "dotnet-install: Payload URLs:" + os.EOL + "dotnet-install: Payload URL: https://primary-url" + os.EOL + "dotnet-install: Legacy payload URL: https://legacy-url" + os.EOL + "dotnet-install: Repeatable invocation:", - "stderr": process.env["__get_dlurls_failed__"] === "true" ? "install-script failed to get donwload urls" : "" - }, - "/somedir/currdir/externals/install-dotnet.sh --version 1.0.4 --dry-run --shared-runtime": { + "/somedir/currdir/externals/get-os-distro.sh": { "code": 0, - "stdout": "dotnet-install: Payload URLs:" + os.EOL + "dotnet-install: Payload URL: https://primary-runtime-url" + os.EOL + "dotnet-install: Legacy payload URL: https://legacy-runtime-url" + os.EOL + "dotnet-install: Repeatable invocation:" + "stdout": "Primary: linux" + os.EOL, } }, "osType": { "osType": "Linux" }, "which": { - "/somedir/currdir/externals/install-dotnet.sh": "/somedir/currdir/externals/install-dotnet.sh" + "/somedir/currdir/externals/get-os-distro.sh": "/somedir/currdir/externals/get-os-distro.sh" }, "checkPath": { - "/somedir/currdir/externals/install-dotnet.sh": true + "/somedir/currdir/externals/get-os-distro.sh": true } }; -var ut = require('../utilities'); tr.registerMock('./utilities', { - getCurrentDir : function() { + getCurrentDir: function () { return "/somedir/currdir"; }, - setFileAttribute: function(file, mode) { + setFileAttribute: function (file, mode) { console.log("Changing attribute for file " + file + " to " + mode); } }); @@ -50,4 +44,5 @@ tr.setAnswers(a); tr.registerMock('vsts-task-lib/toolrunner', require('vsts-task-lib/mock-toolrunner')); tr.registerMock('vsts-task-tool-lib/tool', require('./mock_node_modules/tool')); +tr.registerMock('./releasesfetcher', require("./mock_node_modules/releasesfetcher")); tr.run(); \ No newline at end of file diff --git a/Tasks/DotNetCoreInstallerV0/Tests/InstallWindows.ts b/Tasks/DotNetCoreInstallerV0/Tests/InstallWindows.ts index 80171fbc428f..0873feb6cf69 100644 --- a/Tasks/DotNetCoreInstallerV0/Tests/InstallWindows.ts +++ b/Tasks/DotNetCoreInstallerV0/Tests/InstallWindows.ts @@ -48,4 +48,5 @@ tr.setAnswers(a); tr.registerMock('vsts-task-lib/toolrunner', require('vsts-task-lib/mock-toolrunner')); tr.registerMock('vsts-task-tool-lib/tool', require('./mock_node_modules/tool')); +tr.registerMock('./releasesfetcher', require("./mock_node_modules/releasesfetcher")); tr.run(); \ No newline at end of file diff --git a/Tasks/DotNetCoreInstallerV0/Tests/L0.ts b/Tasks/DotNetCoreInstallerV0/Tests/L0.ts index 9109eec428c7..3536d14823bb 100644 --- a/Tasks/DotNetCoreInstallerV0/Tests/L0.ts +++ b/Tasks/DotNetCoreInstallerV0/Tests/L0.ts @@ -40,7 +40,7 @@ describe('DotNetCoreInstaller', function() { assert(tr.stdout.indexOf("Checking local tool for dncs and version 1.0.4") > -1, "should check for local cached tool"); assert(tr.stdout.indexOf("loc_mock_InstallingAfresh") > -1, "should install fresh if cache miss"); assert(tr.stdout.indexOf("Downloading tool from https://primary-url") > -1, "should download from correct url"); - assert(tr.stdout.indexOf("Extracting zip archieve from C:\\agent\\_temp\\someArchieve") > -1, "Should extract downloaded archieve corectly"); + assert(tr.stdout.indexOf("Extracting zip archive from C:\\agent\\_temp\\someArchive.zip") > -1, "Should extract downloaded archive corectly"); assert(tr.stdout.indexOf("Caching dir C:\\agent\\_temp\\someDir for tool dncs version 1.0.4") > -1, "should cache correctly"); assert(tr.stdout.indexOf("loc_mock_SuccessfullyInstalled sdk 1.0.4") > -1, "should print installed tool info"); assert(tr.stdout.indexOf("prepending path: C:\\agent\\_tools\\cacheDir") > -1, "should pre-prend to PATH"); @@ -60,7 +60,7 @@ describe('DotNetCoreInstaller', function() { assert(tr.stdout.indexOf("Checking local tool for dncr and version 1.0.4") > -1, "should check for local cached tool"); assert(tr.stdout.indexOf("loc_mock_InstallingAfresh") > -1, "should install fresh if cache miss"); assert(tr.stdout.indexOf("Downloading tool from https://primary-runtime-url") > -1, "should download from correct url"); - assert(tr.stdout.indexOf("Extracting zip archieve from C:\\agent\\_temp\\someArchieve") > -1, "Should extract downloaded archieve corectly"); + assert(tr.stdout.indexOf("Extracting zip archive from C:\\agent\\_temp\\someArchive.zip") > -1, "Should extract downloaded archive corectly"); assert(tr.stdout.indexOf("Caching dir C:\\agent\\_temp\\someDir for tool dncr version 1.0.4") > -1, "should cache correctly"); assert(tr.stdout.indexOf("loc_mock_SuccessfullyInstalled runtime 1.0.4") > -1, "should print installed tool info"); assert(tr.stdout.indexOf("prepending path: C:\\agent\\_tools\\cacheDir") > -1, "should pre-prend to PATH"); @@ -96,7 +96,7 @@ describe('DotNetCoreInstaller', function() { runValidations(() => { assert(tr.succeeded, "Should have succeeded"); - assert(tr.stdout.indexOf("loc_mock_PrimaryUrlDownloadFailed 404 not found https://primary-url") >= -1, "should print primary url failure error") + assert(tr.stdout.indexOf("404 not found https://primary-url") > -1, "should print primary url failure error") assert(tr.stdout.indexOf("Downloading tool from https://legacy-url") > -1, "should download from legacy url"); }, tr, done); }); @@ -137,9 +137,9 @@ describe('DotNetCoreInstaller', function() { assert(tr.stdout.indexOf("loc_mock_ToolToInstall sdk 1.0.4") > -1, "should print to-be-installed info"); assert(tr.stdout.indexOf("Checking local tool for dncs and version 1.0.4") > -1, "should check for local cached tool"); assert(tr.stdout.indexOf("loc_mock_InstallingAfresh") > -1, "should install fresh if cache miss"); - assert(tr.stdout.indexOf("Changing attribute for file /somedir/currdir/externals/install-dotnet.sh to 777") > -1, "should iset executable attribute for install script"); + assert(tr.stdout.indexOf("Changing attribute for file /somedir/currdir/externals/get-os-distro.sh to 777") > -1, "should iset executable attribute for install script"); assert(tr.stdout.indexOf("Downloading tool from https://primary-url") > -1, "should download from correct url"); - assert(tr.stdout.indexOf("Extracting tar archieve from /agent/_temp/someArchieve") > -1, "Should extract downloaded archieve corectly"); + assert(tr.stdout.indexOf("Extracting tar archive from /agent/_temp/someArchive.tar") > -1, "Should extract downloaded archive corectly"); assert(tr.stdout.indexOf("Caching dir /agent/_temp/someDir for tool dncs version 1.0.4") > -1, "should cache correctly"); assert(tr.stdout.indexOf("loc_mock_SuccessfullyInstalled sdk 1.0.4") > -1, "should print installed tool info"); assert(tr.stdout.indexOf("prepending path: /agent/_tools/cacheDir") > -1, "should pre-prend to PATH"); @@ -159,7 +159,7 @@ describe('DotNetCoreInstaller', function() { assert(tr.stdout.indexOf("Checking local tool for dncr and version 1.0.4") > -1, "should check for local cached tool"); assert(tr.stdout.indexOf("loc_mock_InstallingAfresh") > -1, "should install fresh if cache miss"); assert(tr.stdout.indexOf("Downloading tool from https://primary-runtime-url") > -1, "should download from correct url"); - assert(tr.stdout.indexOf("Extracting tar archieve from /agent/_temp/someArchieve") > -1, "Should extract downloaded archieve corectly"); + assert(tr.stdout.indexOf("Extracting tar archive from /agent/_temp/someArchive.tar") > -1, "Should extract downloaded archive corectly"); assert(tr.stdout.indexOf("Caching dir /agent/_temp/someDir for tool dncr version 1.0.4") > -1, "should cache correctly"); assert(tr.stdout.indexOf("loc_mock_SuccessfullyInstalled runtime 1.0.4") > -1, "should print installed tool info"); assert(tr.stdout.indexOf("prepending path: /agent/_tools/cacheDir") > -1, "should pre-prend to PATH"); @@ -184,5 +184,19 @@ describe('DotNetCoreInstaller', function() { assert(tr.stdout.indexOf("prepending path: /agent/_tools/oldCacheDir") > -1, "should pre-prend to PATH"); }, tr, done); }); + + it("[nix]Should download using DLC url if primary url does not work", (done) => { + process.env["__primary_url_failed__"] = "true"; + let tp = path.join(__dirname, "InstallNix.js"); + let tr = new ttm.MockTestRunner(tp); + tr.run(); + delete process.env["__primary_url_failed__"]; + + runValidations(() => { + assert(tr.succeeded, "Should have succeeded"); + assert(tr.stdout.indexOf("404 not found https://primary-url") > -1, "should print primary url failure error") + assert(tr.stdout.indexOf("Downloading tool from https://legacy-url") > -1, "should download from legacy url"); + }, tr, done); + }); } }); diff --git a/Tasks/DotNetCoreInstallerV0/Tests/mock_node_modules/releasesfetcher.ts b/Tasks/DotNetCoreInstallerV0/Tests/mock_node_modules/releasesfetcher.ts new file mode 100644 index 000000000000..8306a103f2fd --- /dev/null +++ b/Tasks/DotNetCoreInstallerV0/Tests/mock_node_modules/releasesfetcher.ts @@ -0,0 +1,18 @@ +export class DotNetCoreReleaseFetcher { + + public static async getDownloadUrls(osSuffixes: string[], version: string, type: string) { + if (process.env["__get_dlurls_failed__"] == "true") { + throw "loc_mock_getDownloadUrlsFailed install-script failed to get donwload urls"; + } + if (process.env["__primary_url_failed__"] == "true") { + return ["https://primary-url", "https://legacy-url"]; + } + + if (type == "sdk" && version == "1.0.4") { + return ["https://primary-url"]; + } + if (type == "runtime") { + return ["https://primary-runtime-url"]; + } + } +} \ No newline at end of file diff --git a/Tasks/DotNetCoreInstallerV0/Tests/mock_node_modules/tool.js b/Tasks/DotNetCoreInstallerV0/Tests/mock_node_modules/tool.js index 73ec3a955e47..2d3d418a97bd 100644 --- a/Tasks/DotNetCoreInstallerV0/Tests/mock_node_modules/tool.js +++ b/Tasks/DotNetCoreInstallerV0/Tests/mock_node_modules/tool.js @@ -1,8 +1,9 @@ var tl = require('vsts-task-lib/task'); var path = require('path'); +var os = require('os'); function isExplicitVersion(versionSpec) { - if(process.env["__implicit_version__"] === "true") { + if (process.env["__implicit_version__"] === "true") { return false; } @@ -17,7 +18,7 @@ exports.prependPath = prependPath; function findLocalTool(toolName, versionSpec, arch) { console.log("Checking local tool for " + toolName + " and version " + versionSpec); - if(process.env["__cache_hit__"] === "true") { + if (process.env["__cache_hit__"] === "true") { return path.join(tl.getVariable('Agent.ToolsDirectory'), "oldCacheDir"); } return null; @@ -25,27 +26,27 @@ function findLocalTool(toolName, versionSpec, arch) { exports.findLocalTool = findLocalTool; function downloadTool(url, fileName) { - if( process.env["__primary_url_failed__"] === "true" && url === "https://primary-url") { + if (process.env["__primary_url_failed__"] === "true" && url === "https://primary-url") { throw "404 not found " + url; } console.log("Downloading tool from " + url); - return path.join(tl.getVariable('Agent.TempDirectory'), "someArchieve"); + return path.join(tl.getVariable('Agent.TempDirectory'), "someArchive" + (os.type().match(/^Win/) ? ".zip" : ".tar")); } exports.downloadTool = downloadTool; function extractZip(file) { - if( process.env["__extract_failed__"] === "true") { + if (process.env["__extract_failed__"] === "true") { throw "unzip failed with some error"; } - console.log("Extracting zip archieve from " + file); + console.log("Extracting zip archive from " + file); return path.join(tl.getVariable('Agent.TempDirectory'), "someDir"); } exports.extractZip = extractZip; function extractTar(file) { - console.log("Extracting tar archieve from " + file); + console.log("Extracting tar archive from " + file); return path.join(tl.getVariable('Agent.TempDirectory'), "someDir"); } exports.extractTar = extractTar; diff --git a/Tasks/DotNetCoreInstallerV0/dotnetcoreinstaller.ts b/Tasks/DotNetCoreInstallerV0/dotnetcoreinstaller.ts index 34bb110e577e..e5c1fd4677a9 100644 --- a/Tasks/DotNetCoreInstallerV0/dotnetcoreinstaller.ts +++ b/Tasks/DotNetCoreInstallerV0/dotnetcoreinstaller.ts @@ -1,171 +1,136 @@ -import * as taskLib from 'vsts-task-lib/task'; +import * as tl from 'vsts-task-lib/task'; import * as toolLib from 'vsts-task-tool-lib/tool'; import * as trm from 'vsts-task-lib/toolrunner'; -import * as utils from "./utilities"; +import { DotNetCoreReleaseFetcher } from "./releasesfetcher"; +import * as utilities from "./utilities"; import * as os from 'os'; import * as path from 'path'; -async function run() { - let packageType = taskLib.getInput('packageType', true); - let version = taskLib.getInput('version', true).trim(); - console.log(taskLib.loc("ToolToInstall", packageType, version)); - await getDotnetCore(packageType, version); -} - -async function getDotnetCore(packageType: string, version: string): Promise { - if (!toolLib.isExplicitVersion(version)) { - throw taskLib.loc("ImplicitVersionNotSupported", version); +class DotnetCoreInstaller { + constructor(packageType, version) { + this.packageType = packageType; + if (!toolLib.isExplicitVersion(version)) { + throw tl.loc("ImplicitVersionNotSupported", version); + } + this.version = version; + this.cachedToolName = this.packageType === 'runtime' ? 'dncr' : 'dncs';; } - // check cache - let toolPath: string; - toolPath = getLocalTool(packageType, version); + public async install() { + // Check cache + let toolPath: string; + toolPath = this.getLocalTool(); + + if (!toolPath) { + // download, extract, cache + console.log(tl.loc("InstallingAfresh")); + let osSuffixes = this.detectMachineOS(); + console.log(tl.loc("GettingDownloadUrl", this.packageType, this.version)); + let downloadUrls = await DotNetCoreReleaseFetcher.getDownloadUrls(osSuffixes, this.version, this.packageType); + toolPath = await this.downloadAndInstall(downloadUrls); + } else { + console.log(tl.loc("UsingCachedTool", toolPath)); + } + + // Prepend the tools path. instructs the agent to prepend for future tasks + toolLib.prependPath(toolPath); - if (!toolPath) { - // download, extract, cache - console.log(taskLib.loc("InstallingAfresh")); - toolPath = await acquireDotNetCore(packageType, version); - } else { - console.log(taskLib.loc("UsingCachedTool", toolPath)); + // Set DOTNET_ROOT for dotnet core Apphost to find runtime since it is installed to a non well-known location. + tl.setVariable('DOTNET_ROOT', toolPath); } - // prepend the tools path. instructs the agent to prepend for future tasks - toolLib.prependPath(toolPath); - // set DOTNET_ROOT for dotnet core Apphost to find runtime since it is installed to a non well-known location. - taskLib.setVariable('DOTNET_ROOT', toolPath); -} + private getLocalTool(): string { + console.log(tl.loc("CheckingToolCache")); + return toolLib.findLocalTool(this.cachedToolName, this.version); + } -function getCachedToolName(packageType: string): string { - // use short names to not unnecessarily run into path limit issues - return packageType === 'runtime' ? 'dncr' : 'dncs'; -} + private detectMachineOS(): string[] { + let osSuffix = []; -function getLocalTool(packageType: string, version:string): string { - console.log(taskLib.loc("CheckingToolCache")); - let cachedToolName = getCachedToolName(packageType); - return toolLib.findLocalTool(cachedToolName, version); -} + if (tl.osType().match(/^Win/)) { + let primary = "win-" + os.arch(); + osSuffix.push(primary); + console.log(tl.loc("PrimaryPlatform", primary)); + } + else { + let scriptPath = path.join(utilities.getCurrentDir(), 'externals', 'get-os-distro.sh'); + utilities.setFileAttribute(scriptPath, "777"); -async function acquireDotNetCore(packageType: string, version: string): Promise { - let downloadUrls = getDownloadUrls(packageType, version); - let downloadPath: string; + let scriptRunner: trm.ToolRunner = tl.tool(tl.which(scriptPath, true)); + let result: trm.IExecSyncResult = scriptRunner.execSync(); - try { - // try primary url - if (!!downloadUrls[0]) { - console.log(taskLib.loc("DownloadingPrimaryUrl", downloadUrls[0])); - downloadPath = await toolLib.downloadTool(downloadUrls[0]); - } - } catch (error1) { - console.log(taskLib.loc("PrimaryUrlDownloadFailed", error1)); - try { - // try secondary url - if (!!downloadUrls[1]) { - console.log(taskLib.loc("DownloadingSecondaryUrl", downloadUrls[1])); - downloadPath = await toolLib.downloadTool(downloadUrls[1]); + if (result.code != 0) { + throw tl.loc("getMachinePlatformFailed", result.error ? result.error.message : result.stderr); } - } catch (error2) { - console.log(taskLib.loc("LegacyUrlDownloadFailed", error2)); - throw taskLib.loc("DownloadFailed", packageType, version); - } - } - // extract - let extPath: string; - console.log(taskLib.loc("ExtractingPackage", downloadPath)); - if (taskLib.osType().match(/^Win/)) { - extPath = await toolLib.extractZip(downloadPath); - } - else { - extPath = await toolLib.extractTar(downloadPath); - } + let output: string = result.stdout; - // cache tool - let cachedToolName = getCachedToolName(packageType); - console.log(taskLib.loc("CachingTool")); - let cachedDir = await toolLib.cacheDir(extPath, cachedToolName, version); - console.log(taskLib.loc("SuccessfullyInstalled", packageType, version)); - return cachedDir; -} + let index; + if ((index = output.indexOf("Primary:")) >= 0) { + let primary = output.substr(index + "Primary:".length).split(os.EOL)[0]; + osSuffix.push(primary); + console.log(tl.loc("PrimaryPlatform", primary)); + } -function getDownloadUrls(packageType: string, version: string): string[] { - let scriptRunner: trm.ToolRunner; - let primaryUrlSearchString: string; - let legacyUrlSearchString: string; - - console.log(taskLib.loc("GettingDownloadUrls", packageType, version)); - if(taskLib.osType().match(/^Win/)) { - let escapedScript = path.join(utils.getCurrentDir(), 'externals', 'install-dotnet.ps1').replace(/'/g, "''"); - let command = `& '${escapedScript}' -Version ${version} -DryRun` - if(packageType === 'runtime') { - command = command.concat(" -SharedRuntime"); - } + if (index = output.indexOf("Legacy:") >= 0) { + let legacy = output.substr(index + "Legacy:".length).split(os.EOL)[0]; + osSuffix.push(legacy); + console.log(tl.loc("LegacyPlatform", legacy)); + } - let powershellPath = taskLib.which('powershell', true); - scriptRunner = taskLib.tool(powershellPath) - .line('-NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command') - .arg(command); - - primaryUrlSearchString = "dotnet-install: Primary - "; - legacyUrlSearchString = "dotnet-install: Legacy - "; - } else { - let escapedScript = path.join(utils.getCurrentDir(), 'externals', 'install-dotnet.sh').replace(/'/g, "''"); - utils.setFileAttribute(escapedScript, "777"); - scriptRunner = taskLib.tool(taskLib.which(escapedScript, true)); - scriptRunner.arg('--version'); - scriptRunner.arg(version); - scriptRunner.arg('--dry-run'); - if(packageType === 'runtime') { - scriptRunner.arg('--shared-runtime'); + if (osSuffix.length == 0) { + throw tl.loc("CouldNotDetectPlatform"); + } } - primaryUrlSearchString = "dotnet-install: Payload URL: "; - legacyUrlSearchString = "dotnet-install: Legacy payload URL: "; + return osSuffix; } - let result: trm.IExecSyncResult = scriptRunner.execSync(); - if(result.code != 0) { - throw taskLib.loc("getDownloadUrlsFailed", result.error ? result.error.message : result.stderr); - } + private async downloadAndInstall(downloadUrls: string[]) { + let downloaded = false; + let downloadPath = ""; + for (var i = 0; i < downloadUrls.length; i++) { + try { + downloadPath = await toolLib.downloadTool(downloadUrls[i]); + downloaded = true; + break; + } catch (error) { + tl.warning(tl.loc("CouldNotDownload", downloadUrls[i], JSON.stringify(error))); + } + } - let output: string = result.stdout; - - let primaryUrl: string = null; - let legacyUrl: string = null; - if(!!output && output.length > 0) { - let lines: string[] = output.split(os.EOL); - if(!!lines && lines.length > 0) { - lines.forEach((line: string) => { - if(!line) { return; } - var primarySearchStringIndex = line.indexOf(primaryUrlSearchString); - if(primarySearchStringIndex > -1) { - primaryUrl = line.substring(primarySearchStringIndex + primaryUrlSearchString.length); - return; - } - - var legacySearchStringIndex = line.indexOf(legacyUrlSearchString); - if(legacySearchStringIndex > -1) { - legacyUrl = line.substring(legacySearchStringIndex + legacyUrlSearchString.length); - return; - } - }); + if (!downloaded) { + throw tl.loc("FailedToDownloadPackage"); } - } - if(!primaryUrl && !legacyUrl) { - throw taskLib.loc("NullDownloadUrls"); + // extract + console.log(tl.loc("ExtractingPackage", downloadPath)); + let extPath: string = downloadPath.endsWith(".zip") ? await toolLib.extractZip(downloadPath) : await toolLib.extractTar(downloadPath); + + // cache tool + console.log(tl.loc("CachingTool")); + let cachedDir = await toolLib.cacheDir(extPath, this.cachedToolName, this.version); + console.log(tl.loc("SuccessfullyInstalled", this.packageType, this.version)); + return cachedDir; } - return [primaryUrl, legacyUrl]; + private packageType: string; + private version: string; + private cachedToolName: string; +} + +async function run() { + let packageType = tl.getInput('packageType', true); + let version = tl.getInput('version', true).trim(); + console.log(tl.loc("ToolToInstall", packageType, version)); + await new DotnetCoreInstaller(packageType, version).install(); } var taskManifestPath = path.join(__dirname, "task.json"); -taskLib.debug("Setting resource path to " + taskManifestPath); -taskLib.setResourcePath(taskManifestPath); - -run().then((result) => - taskLib.setResult(taskLib.TaskResult.Succeeded, "") -).catch((error) => - taskLib.setResult(taskLib.TaskResult.Failed, !!error.message ? error.message : error) -); +tl.debug("Setting resource path to " + taskManifestPath); +tl.setResourcePath(taskManifestPath); + +run() + .then(() => tl.setResult(tl.TaskResult.Succeeded, "")) + .catch((error) => tl.setResult(tl.TaskResult.Failed, !!error.message ? error.message : error)); \ No newline at end of file diff --git a/Tasks/DotNetCoreInstallerV0/externals/get-os-distro.sh b/Tasks/DotNetCoreInstallerV0/externals/get-os-distro.sh new file mode 100644 index 000000000000..af2a48025bce --- /dev/null +++ b/Tasks/DotNetCoreInstallerV0/externals/get-os-distro.sh @@ -0,0 +1,167 @@ +#!/usr/bin/env bash +# Copyright (c) .NET Foundation and contributors. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. +# + +# Stop script on NZEC +set -e +# Stop script if unbound variable found (use ${var:-} if intentional) +set -u +# By default cmd1 | cmd2 returns exit code of cmd2 regardless of cmd1 success +# This is causing it to fail +set -o pipefail + +# Use in the the functions: eval $invocation +invocation='say_verbose "Calling: ${yellow:-}${FUNCNAME[0]} ${green:-}$*${normal:-}"' + +# standard output may be used as a return value in the functions +# we need a way to write text on the screen in the functions so that +# it won't interfere with the return value. +# Exposing stream 3 as a pipe to standard output of the script itself +exec 3>&1 + +say_err() { + printf "%b\n" "get-os-distro: Error: $1" >&2 +} + +# This platform list is finite - if the SDK/Runtime has supported Linux distribution-specific assets, +# then and only then should the Linux distribution appear in this list. +# Adding a Linux distribution to this list does not imply distribution-specific support. +get_legacy_os_name_from_platform() { + + platform="$1" + case "$platform" in + "centos.7") + echo "centos" + return 0 + ;; + "debian.8") + echo "debian" + return 0 + ;; + "fedora.23") + echo "fedora.23" + return 0 + ;; + "fedora.27") + echo "fedora.27" + return 0 + ;; + "fedora.24") + echo "fedora.24" + return 0 + ;; + "opensuse.13.2") + echo "opensuse.13.2" + return 0 + ;; + "opensuse.42.1") + echo "opensuse.42.1" + return 0 + ;; + "opensuse.42.3") + echo "opensuse.42.3" + return 0 + ;; + "rhel.7"*) + echo "rhel" + return 0 + ;; + "ubuntu.14.04") + echo "ubuntu" + return 0 + ;; + "ubuntu.16.04") + echo "ubuntu.16.04" + return 0 + ;; + "ubuntu.16.10") + echo "ubuntu.16.10" + return 0 + ;; + "ubuntu.18.04") + echo "ubuntu.18.04" + return 0 + ;; + "alpine.3.4.3") + echo "alpine" + return 0 + ;; + esac + return 1 +} + +get_linux_platform_name() { + + if [ -e /etc/os-release ]; then + . /etc/os-release + echo "$ID.$VERSION_ID" + return 0 + elif [ -e /etc/redhat-release ]; then + local redhatRelease=$(&1 - -# Setup some colors to use. These need to work in fairly limited shells, like the Ubuntu Docker container where there are only 8 colors. -# See if stdout is a terminal -if [ -t 1 ]; then - # see if it supports colors - ncolors=$(tput colors) - if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then - bold="$(tput bold || echo)" - normal="$(tput sgr0 || echo)" - black="$(tput setaf 0 || echo)" - red="$(tput setaf 1 || echo)" - green="$(tput setaf 2 || echo)" - yellow="$(tput setaf 3 || echo)" - blue="$(tput setaf 4 || echo)" - magenta="$(tput setaf 5 || echo)" - cyan="$(tput setaf 6 || echo)" - white="$(tput setaf 7 || echo)" - fi -fi - -say_err() { - printf "%b\n" "${red:-}dotnet_install: Error: $1${normal:-}" >&2 -} - -say() { - # using stream 3 (defined in the beginning) to not interfere with stdout of functions - # which may be used as return value - printf "%b\n" "${cyan:-}dotnet-install:${normal:-} $1" >&3 -} - -say_verbose() { - if [ "$verbose" = true ]; then - say "$1" - fi -} - -get_os_download_name_from_platform() { - eval $invocation - - platform="$1" - case "$platform" in - "centos.7") - echo "centos" - return 0 - ;; - "debian.8") - echo "debian" - return 0 - ;; - "fedora.23") - echo "fedora.23" - return 0 - ;; - "fedora.24") - echo "fedora.24" - return 0 - ;; - "opensuse.13.2") - echo "opensuse.13.2" - return 0 - ;; - "opensuse.42.1") - echo "opensuse.42.1" - return 0 - ;; - "rhel.7"*) - echo "rhel" - return 0 - ;; - "ubuntu.14.04") - echo "ubuntu" - return 0 - ;; - "ubuntu.16.04") - echo "ubuntu.16.04" - return 0 - ;; - "ubuntu.16.10") - echo "ubuntu.16.10" - return 0 - ;; - "alpine.3.4.3") - echo "alpine" - return 0 - ;; - esac - return 1 -} - -get_current_os_name() { - eval $invocation - - local uname=$(uname) - if [ "$uname" = "Darwin" ]; then - echo "osx" - return 0 - else - if [ "$uname" = "Linux" ]; then - echo "linux" - return 0 - fi - fi - - say_err "OS name could not be detected: $ID.$VERSION_ID" - return 1 -} - -get_distro_specific_os_name() { - eval $invocation - - local uname=$(uname) - if [ "$uname" = "Darwin" ]; then - echo "osx" - return 0 - elif [ -n "$runtime_id" ]; then - echo $(get_os_download_name_from_platform "${runtime_id%-*}" || echo "${runtime_id%-*}") - return 0 - else - if [ -e /etc/os-release ]; then - . /etc/os-release - os=$(get_os_download_name_from_platform "$ID.$VERSION_ID" || echo "") - if [ -n "$os" ]; then - echo "$os" - return 0 - fi - fi - fi - - say_verbose "Distribution specific OS name and version could not be detected: $ID.$VERSION_ID" - return 1 -} - -machine_has() { - eval $invocation - - hash "$1" > /dev/null 2>&1 - return $? -} - - -check_min_reqs() { - local hasMinimum=false - if machine_has "curl"; then - hasMinimum=true - elif machine_has "wget"; then - hasMinimum=true - fi - - if [ "$hasMinimum" = "false" ]; then - say_err "curl (recommended) or wget are required to download dotnet. Install missing prerequisite to proceed." - return 1 - fi - return 0 -} - -check_pre_reqs() { - eval $invocation - - local failing=false; - - if [ "${DOTNET_INSTALL_SKIP_PREREQS:-}" = "1" ]; then - return 0 - fi - - if [ "$(uname)" = "Linux" ]; then - if ! [ -x "$(command -v ldconfig)" ]; then - echo "ldconfig is not in PATH, trying /sbin/ldconfig." - LDCONFIG_COMMAND="/sbin/ldconfig" - else - LDCONFIG_COMMAND="ldconfig" - fi - - [ -z "$($LDCONFIG_COMMAND -p | grep libunwind)" ] && say_err "Unable to locate libunwind. Install libunwind to continue" && failing=true - [ -z "$($LDCONFIG_COMMAND -p | grep libssl)" ] && say_err "Unable to locate libssl. Install libssl to continue" && failing=true - [ -z "$($LDCONFIG_COMMAND -p | grep libicu)" ] && say_err "Unable to locate libicu. Install libicu to continue" && failing=true - fi - - if [ "$failing" = true ]; then - return 1 - fi - - return 0 -} - -# args: -# input - $1 -to_lowercase() { - #eval $invocation - - echo "$1" | tr '[:upper:]' '[:lower:]' - return 0 -} - -# args: -# input - $1 -remove_trailing_slash() { - #eval $invocation - - local input=${1:-} - echo "${input%/}" - return 0 -} - -# args: -# input - $1 -remove_beginning_slash() { - #eval $invocation - - local input=${1:-} - echo "${input#/}" - return 0 -} - -# args: -# root_path - $1 -# child_path - $2 - this parameter can be empty -combine_paths() { - eval $invocation - - # TODO: Consider making it work with any number of paths. For now: - if [ ! -z "${3:-}" ]; then - say_err "combine_paths: Function takes two parameters." - return 1 - fi - - local root_path=$(remove_trailing_slash $1) - local child_path=$(remove_beginning_slash ${2:-}) - say_verbose "combine_paths: root_path=$root_path" - say_verbose "combine_paths: child_path=$child_path" - echo "$root_path/$child_path" - return 0 -} - -get_machine_architecture() { - eval $invocation - - # Currently the only one supported - echo "x64" - return 0 -} - -# args: -# architecture - $1 -get_normalized_architecture_from_architecture() { - eval $invocation - - local architecture=$(to_lowercase $1) - case $architecture in - \) - echo "$(get_normalized_architecture_from_architecture $(get_machine_architecture))" - return 0 - ;; - amd64|x64) - echo "x64" - return 0 - ;; - x86) - say_err "Architecture \`x86\` currently not supported" - return 1 - ;; - esac - - say_err "Architecture \`$architecture\` not supported. If you think this is a bug, please report it at https://github.com/dotnet/cli/issues" - return 1 -} - -# version_info is a conceptual two line string representing commit hash and 4-part version -# format: -# Line 1: # commit_hash -# Line 2: # 4-part version - -# args: -# version_text - stdin -get_version_from_version_info() { - eval $invocation - - cat | tail -n 1 - return 0 -} - -# args: -# version_text - stdin -get_commit_hash_from_version_info() { - eval $invocation - - cat | head -n 1 - return 0 -} - -# args: -# install_root - $1 -# relative_path_to_package - $2 -# specific_version - $3 -is_dotnet_package_installed() { - eval $invocation - - local install_root=$1 - local relative_path_to_package=$2 - local specific_version=${3//[$'\t\r\n']} - - local dotnet_package_path=$(combine_paths $(combine_paths $install_root $relative_path_to_package) $specific_version) - say_verbose "is_dotnet_package_installed: dotnet_package_path=$dotnet_package_path" - - if [ -d "$dotnet_package_path" ]; then - return 0 - else - return 1 - fi -} - -# args: -# azure_feed - $1 -# channel - $2 -# normalized_architecture - $3 -get_latest_version_info() { - eval $invocation - - local azure_feed=$1 - local channel=$2 - local normalized_architecture=$3 - local coherent=$4 - - local version_file_url=null - if [ "$shared_runtime" = true ]; then - version_file_url="$uncached_feed/Runtime/$channel/latest.version" - else - if [ "$coherent" = true ]; then - version_file_url="$uncached_feed/Sdk/$channel/latest.coherent.version" - else - version_file_url="$uncached_feed/Sdk/$channel/latest.version" - fi - fi - say_verbose "get_latest_version_info: latest url: $version_file_url" - - download $version_file_url - return $? -} - -# args: -# azure_feed - $1 -# channel - $2 -# normalized_architecture - $3 -# version - $4 -get_specific_version_from_version() { - eval $invocation - - local azure_feed=$1 - local channel=$2 - local normalized_architecture=$3 - local version=$(to_lowercase $4) - - case $version in - latest) - local version_info - version_info="$(get_latest_version_info $azure_feed $channel $normalized_architecture false)" || return 1 - say_verbose "get_specific_version_from_version: version_info=$version_info" - echo "$version_info" | get_version_from_version_info - return 0 - ;; - coherent) - local version_info - version_info="$(get_latest_version_info $azure_feed $channel $normalized_architecture true)" || return 1 - say_verbose "get_specific_version_from_version: version_info=$version_info" - echo "$version_info" | get_version_from_version_info - return 0 - ;; - *) - echo $version - return 0 - ;; - esac -} - -# args: -# azure_feed - $1 -# channel - $2 -# normalized_architecture - $3 -# specific_version - $4 -construct_download_link() { - eval $invocation - - local azure_feed=$1 - local channel=$2 - local normalized_architecture=$3 - local specific_version=${4//[$'\t\r\n']} - - local osname - osname=$(get_current_os_name) || return 1 - - local download_link=null - if [ "$shared_runtime" = true ]; then - download_link="$azure_feed/Runtime/$specific_version/dotnet-runtime-$specific_version-$osname-$normalized_architecture.tar.gz" - else - download_link="$azure_feed/Sdk/$specific_version/dotnet-sdk-$specific_version-$osname-$normalized_architecture.tar.gz" - fi - - echo "$download_link" - return 0 -} - -# args: -# azure_feed - $1 -# channel - $2 -# normalized_architecture - $3 -# specific_version - $4 -construct_legacy_download_link() { - eval $invocation - - local azure_feed=$1 - local channel=$2 - local normalized_architecture=$3 - local specific_version=${4//[$'\t\r\n']} - - local distro_specific_osname - distro_specific_osname=$(get_distro_specific_os_name) || return 1 - - local legacy_download_link=null - if [ "$shared_runtime" = true ]; then - legacy_download_link="$azure_feed/Runtime/$specific_version/dotnet-$distro_specific_osname-$normalized_architecture.$specific_version.tar.gz" - else - legacy_download_link="$azure_feed/Sdk/$specific_version/dotnet-dev-$distro_specific_osname-$normalized_architecture.$specific_version.tar.gz" - fi - - echo "$legacy_download_link" - return 0 -} - -get_user_install_path() { - eval $invocation - - if [ ! -z "${DOTNET_INSTALL_DIR:-}" ]; then - echo $DOTNET_INSTALL_DIR - else - echo "$HOME/.dotnet" - fi - return 0 -} - -# args: -# install_dir - $1 -resolve_installation_path() { - eval $invocation - - local install_dir=$1 - if [ "$install_dir" = "" ]; then - local user_install_path=$(get_user_install_path) - say_verbose "resolve_installation_path: user_install_path=$user_install_path" - echo "$user_install_path" - return 0 - fi - - echo "$install_dir" - return 0 -} - -# args: -# install_root - $1 -get_installed_version_info() { - eval $invocation - - local install_root=$1 - local version_file=$(combine_paths "$install_root" "$local_version_file_relative_path") - say_verbose "Local version file: $version_file" - if [ ! -z "$version_file" ] | [ -r "$version_file" ]; then - local version_info="$(cat $version_file)" - echo "$version_info" - return 0 - fi - - say_verbose "Local version file not found." - return 0 -} - -# args: -# relative_or_absolute_path - $1 -get_absolute_path() { - eval $invocation - - local relative_or_absolute_path=$1 - echo $(cd $(dirname "$1") && pwd -P)/$(basename "$1") - return 0 -} - -# args: -# input_files - stdin -# root_path - $1 -# out_path - $2 -# override - $3 -copy_files_or_dirs_from_list() { - eval $invocation - - local root_path=$(remove_trailing_slash $1) - local out_path=$(remove_trailing_slash $2) - local override=$3 - local override_switch=$(if [ "$override" = false ]; then printf -- "-n"; fi) - - cat | uniq | while read -r file_path; do - local path=$(remove_beginning_slash ${file_path#$root_path}) - local target=$out_path/$path - if [ "$override" = true ] || (! ([ -d "$target" ] || [ -e "$target" ])); then - mkdir -p $out_path/$(dirname $path) - cp -R $override_switch $root_path/$path $target - fi - done -} - -# args: -# zip_path - $1 -# out_path - $2 -extract_dotnet_package() { - eval $invocation - - local zip_path=$1 - local out_path=$2 - - local temp_out_path=$(mktemp -d $temporary_file_template) - - local failed=false - tar -xzf "$zip_path" -C "$temp_out_path" > /dev/null || failed=true - - local folders_with_version_regex='^.*/[0-9]+\.[0-9]+[^/]+/' - find $temp_out_path -type f | grep -Eo $folders_with_version_regex | copy_files_or_dirs_from_list $temp_out_path $out_path false - find $temp_out_path -type f | grep -Ev $folders_with_version_regex | copy_files_or_dirs_from_list $temp_out_path $out_path true - - rm -rf $temp_out_path - - if [ "$failed" = true ]; then - say_err "Extraction failed" - return 1 - fi -} - -# args: -# remote_path - $1 -# [out_path] - $2 - stdout if not provided -download() { - eval $invocation - - local remote_path=$1 - local out_path=${2:-} - - local failed=false - if machine_has "curl"; then - downloadcurl $remote_path $out_path || failed=true - elif machine_has "wget"; then - downloadwget $remote_path $out_path || failed=true - else - failed=true - fi - if [ "$failed" = true ]; then - say_verbose "Download failed: $remote_path" - return 1 - fi - return 0 -} - -downloadcurl() { - eval $invocation - local remote_path=$1 - local out_path=${2:-} - - local failed=false - if [ -z "$out_path" ]; then - curl --retry 10 -sSL -f --create-dirs $remote_path || failed=true - else - curl --retry 10 -sSL -f --create-dirs -o $out_path $remote_path || failed=true - fi - if [ "$failed" = true ]; then - say_verbose "Curl download failed" - return 1 - fi - return 0 -} - -downloadwget() { - eval $invocation - local remote_path=$1 - local out_path=${2:-} - - local failed=false - if [ -z "$out_path" ]; then - wget -q --tries 10 $remote_path || failed=true - else - wget -v --tries 10 -O $out_path $remote_path || failed=true - fi - if [ "$failed" = true ]; then - say_verbose "Wget download failed" - return 1 - fi - return 0 -} - -calculate_vars() { - eval $invocation - valid_legacy_download_link=true - - normalized_architecture=$(get_normalized_architecture_from_architecture "$architecture") - say_verbose "normalized_architecture=$normalized_architecture" - - specific_version=$(get_specific_version_from_version $azure_feed $channel $normalized_architecture $version) - say_verbose "specific_version=$specific_version" - if [ -z "$specific_version" ]; then - say_err "Could not get version information." - return 1 - fi - - download_link=$(construct_download_link $azure_feed $channel $normalized_architecture $specific_version) - say_verbose "download_link=$download_link" - - legacy_download_link=$(construct_legacy_download_link $azure_feed $channel $normalized_architecture $specific_version) || valid_legacy_download_link=false - - if [ "$valid_legacy_download_link" = true ]; then - say_verbose "legacy_download_link=$legacy_download_link" - else - say_verbose "Cound not construct a legacy_download_link; omitting..." - fi - - install_root=$(resolve_installation_path $install_dir) - say_verbose "install_root=$install_root" -} - -install_dotnet() { - eval $invocation - local download_failed=false - - if is_dotnet_package_installed $install_root "sdk" $specific_version; then - say ".NET SDK version $specific_version is already installed." - return 0 - fi - - mkdir -p $install_root - zip_path=$(mktemp $temporary_file_template) - say_verbose "Zip path: $zip_path" - - say "Downloading link: $download_link" - download "$download_link" $zip_path || download_failed=true - - # if the download fails, download the legacy_download_link - if [ "$download_failed" = true ] && [ "$valid_legacy_download_link" = true ]; then - say "Cannot download: $download_link" - download_link=$legacy_download_link - zip_path=$(mktemp $temporary_file_template) - say_verbose "Legacy zip path: $zip_path" - say "Downloading legacy link: $download_link" - download "$download_link" $zip_path - fi - - say "Extracting zip from $download_link" - extract_dotnet_package $zip_path $install_root - - return 0 -} - -local_version_file_relative_path="/.version" -bin_folder_relative_path="" -temporary_file_template="${TMPDIR:-/tmp}/dotnet.XXXXXXXXX" - -channel="LTS" -version="Latest" -install_dir="" -architecture="" -dry_run=false -no_path=false -azure_feed="https://dotnetcli.azureedge.net/dotnet" -uncached_feed="https://dotnetcli.blob.core.windows.net/dotnet" -verbose=false -shared_runtime=false -runtime_id="" - -while [ $# -ne 0 ] -do - name=$1 - case $name in - -c|--channel|-[Cc]hannel) - shift - channel=$1 - ;; - -v|--version|-[Vv]ersion) - shift - version="$1" - ;; - -i|--install-dir|-[Ii]nstall[Dd]ir) - shift - install_dir="$1" - ;; - --arch|--architecture|-[Aa]rch|-[Aa]rchitecture) - shift - architecture="$1" - ;; - --shared-runtime|-[Ss]hared[Rr]untime) - shared_runtime=true - ;; - --dry-run|-[Dd]ry[Rr]un) - dry_run=true - ;; - --no-path|-[Nn]o[Pp]ath) - no_path=true - ;; - --verbose|-[Vv]erbose) - verbose=true - ;; - --azure-feed|-[Aa]zure[Ff]eed) - shift - azure_feed="$1" - ;; - --uncached-feed|-[Uu]ncached[Ff]eed) - shift - uncached_feed="$1" - ;; - --runtime-id|-[Rr]untime[Ii]d) - shift - runtime_id="$1" - ;; - -?|--?|-h|--help|-[Hh]elp) - script_name="$(basename $0)" - echo ".NET Tools Installer" - echo "Usage: $script_name [-c|--channel ] [-v|--version ] [-p|--prefix ]" - echo " $script_name -h|-?|--help" - echo "" - echo "$script_name is a simple command line interface for obtaining dotnet cli." - echo "" - echo "Options:" - echo " -c,--channel Download from the CHANNEL specified, Defaults to \`$channel\`." - echo " -Channel" - echo " Possible values:" - echo " - Current - most current release" - echo " - LTS - most current supported release" - echo " - 2-part version in a format A.B - represents a specific release" - echo " examples: 2.0; 1.0" - echo " - Branch name" - echo " examples: release/2.0.0; Master" - echo " -v,--version Use specific VERSION, Defaults to \`$version\`." - echo " -Version" - echo " Possible values:" - echo " - latest - most latest build on specific channel" - echo " - coherent - most latest coherent build on specific channel" - echo " coherent applies only to SDK downloads" - echo " - 3-part version in a format A.B.C - represents specific version of build" - echo " examples: 2.0.0-preview2-006120; 1.1.0" - echo " -i,--install-dir Install under specified location (see Install Location below)" - echo " -InstallDir" - echo " --architecture Architecture of .NET Tools. Currently only x64 is supported." - echo " --arch,-Architecture,-Arch" - echo " --shared-runtime Installs just the shared runtime bits, not the entire SDK." - echo " -SharedRuntime" - echo " --dry-run,-DryRun Do not perform installation. Display download link." - echo " --no-path, -NoPath Do not set PATH for the current process." - echo " --verbose,-Verbose Display diagnostics information." - echo " --azure-feed,-AzureFeed Azure feed location. Defaults to $azure_feed, This parameter typically is not changed by the user." - echo " --uncached-feed,-UncachedFeed Uncached feed location. This parameter typically is not changed by the user." - echo " --runtime-id Installs the .NET Tools for the given platform (use linux-x64 for portable linux)." - echo " -RuntimeId" - echo " -?,--?,-h,--help,-Help Shows this help message" - echo "" - echo "Install Location:" - echo " Location is chosen in following order:" - echo " - --install-dir option" - echo " - Environmental variable DOTNET_INSTALL_DIR" - echo " - $HOME/.dotnet" - exit 0 - ;; - *) - say_err "Unknown argument \`$name\`" - exit 1 - ;; - esac - - shift -done - -check_min_reqs -calculate_vars - -if [ "$dry_run" = true ]; then - say "Payload URL: $download_link" - if [ "$valid_legacy_download_link" = true ]; then - say "Legacy payload URL: $legacy_download_link" - fi - say "Repeatable invocation: ./$(basename $0) --version $specific_version --channel $channel --install-dir $install_dir" - exit 0 -fi - -check_pre_reqs -install_dotnet - -bin_path=$(get_absolute_path $(combine_paths $install_root $bin_folder_relative_path)) -if [ "$no_path" = false ]; then - say "Adding to current process PATH: \`$bin_path\`. Note: This change will be visible only when sourcing script." - export PATH=$bin_path:$PATH -else - say "Binaries of dotnet can be found in $bin_path" -fi - -say "Installation finished successfully." \ No newline at end of file diff --git a/Tasks/DotNetCoreInstallerV0/package.json b/Tasks/DotNetCoreInstallerV0/package.json index 5f07104cd850..9e2da38d84cb 100644 --- a/Tasks/DotNetCoreInstallerV0/package.json +++ b/Tasks/DotNetCoreInstallerV0/package.json @@ -23,6 +23,7 @@ "homepage": "https://github.com/microsoft/vsts-tasks#readme", "dependencies": { "vsts-task-lib": "2.0.6", - "vsts-task-tool-lib": "0.4.1" + "vsts-task-tool-lib": "0.4.1", + "typed-rest-client": "0.11.0" } } diff --git a/Tasks/DotNetCoreInstallerV0/releasesfetcher.ts b/Tasks/DotNetCoreInstallerV0/releasesfetcher.ts new file mode 100644 index 000000000000..40d927b28b55 --- /dev/null +++ b/Tasks/DotNetCoreInstallerV0/releasesfetcher.ts @@ -0,0 +1,64 @@ +import * as util from 'util'; +import * as taskLib from 'vsts-task-lib/task'; + +import httpClient = require("typed-rest-client/HttpClient"); +import httpInterfaces = require("typed-rest-client/Interfaces"); +import { HttpClientResponse } from 'typed-rest-client/HttpClient'; + +export class DotNetCoreReleaseFetcher { + + // OsSuffixes - The suffix which is a part of the file name ex- linux-x64, windows-x86 + // Type - SDK / Runtime + // Version - Version of the SDK/Runtime + public static async getDownloadUrls(osSuffixes: string[], version: string, type: string): Promise { + let downloadUrls = []; + let releasesJSON = await this.getReleasesJson(); + + let releasesInfo = JSON.parse(await releasesJSON.readBody()); + releasesInfo = releasesInfo.filter(releaseInfo => { + return releaseInfo['version-' + type] === version || releaseInfo['version-' + type + '-display'] === version; + }); + + if (releasesInfo.length == 0) { + throw taskLib.loc("VersionNotFound", version); + } + + let release = releasesInfo[0]; + let blobUrl: string = release['blob-' + type]; + let dlcUrl: string = release['dlc-' + type]; + let fileName: string = release[type + '-' + osSuffixes[0]] ? release[type + '-' + osSuffixes[0]] : release[type + '-' + osSuffixes[1]]; + + if (!!fileName) { + if (!!blobUrl) { + downloadUrls.push(util.format("%s%s", blobUrl.trim(), fileName.trim())); + } + + if (!!dlcUrl) { + downloadUrls.push(util.format("%s%s", dlcUrl.trim(), fileName.trim())); + } + } + + if (downloadUrls.length == 0) { + throw taskLib.loc("NullDownloadUrls", version); + } + + return downloadUrls; + } + + private static getReleasesJson(): Promise { + let proxyUrl: string = taskLib.getVariable("agent.proxyurl"); + var requestOptions: httpInterfaces.IRequestOptions = proxyUrl ? { + proxy: { + proxyUrl: proxyUrl, + proxyUsername: taskLib.getVariable("agent.proxyusername"), + proxyPassword: taskLib.getVariable("agent.proxypassword"), + proxyBypassHosts: taskLib.getVariable("agent.proxybypasslist") ? JSON.parse(taskLib.getVariable("agent.proxybypasslist")) : null + } + } : {}; + + var httpCallbackClient = new httpClient.HttpClient(taskLib.getVariable("AZURE_HTTP_USER_AGENT"), null, requestOptions); + return httpCallbackClient.get(DotNetCoreReleasesUrl); + } +} + +const DotNetCoreReleasesUrl: string = "https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json"; \ No newline at end of file diff --git a/Tasks/DotNetCoreInstallerV0/task.json b/Tasks/DotNetCoreInstallerV0/task.json index d2076762d2bf..4cd14daff3c7 100644 --- a/Tasks/DotNetCoreInstallerV0/task.json +++ b/Tasks/DotNetCoreInstallerV0/task.json @@ -13,12 +13,15 @@ "version": { "Major": 0, "Minor": 1, - "Patch": 8 + "Patch": 9 }, - "satisfies": ["DotNetCore"], + "satisfies": [ + "DotNetCore" + ], "demands": [], "instanceNameFormat": "Use .NET Core $(packageType) $(version)", - "inputs": [{ + "inputs": [ + { "name": "packageType", "type": "pickList", "label": "Package to install", @@ -36,7 +39,7 @@ "label": "Version", "defaultValue": "1.0.4", "required": true, - "helpMarkDown": "Specify exact version of .NET Core SDK or runtime to install.

Examples:
1. To install 1.0.4 SDK, use 1.0.4
2. To install 1.1.2 runtime, use 1.1.2
2. To install 2.0 preview 2 runtime, use 2.0.0-preview2-25407-01

For getting more details about exact version, refer [here](https://github.com/dotnet/core/blob/master/release-notes/releases.csv)" + "helpMarkDown": "Specify exact version of .NET Core SDK or runtime to install.
Find the value of `version-sdk` for installing SDK, or `version-runtime` for installing Runtime from any releases [here](https://github.com/dotnet/core/blob/master/release-notes/releases.json)" } ], "execution": { @@ -47,20 +50,22 @@ "messages": { "ToolFailed": "Tool install failed: %s", "ImplicitVersionNotSupported": "Version should be a valid and explicit version: %s", - "PrimaryUrlDownloadFailed": "Failed to download .NET Core package using primary URL. Error: %s.", - "LegacyUrlDownloadFailed": "Failed to download .NET Core package using legacy URL as well. Error: %s.", - "DownloadFailed": "Failed to download .NET Core package. Please ensure that .NET Core %s of version %s exists. Check out: https://github.com/dotnet/core/blob/master/release-notes/releases.csv", - "getDownloadUrlsFailed": "Failed to get download urls. Error: %s.", + "getMachinePlatformFailed": "Failed to get machine platform details. Error: %s.", "UsingCachedTool": "Cached copy of .NET Core exists. No need to install afresh. Cached tool location: %s.", "CheckingToolCache": "Checking if a cached copy exists for this version...", "InstallingAfresh": "Cache does not contains this particular .NET Core. Will be downloaded and installed.", - "GettingDownloadUrls": "Getting URLs to download .NET Core %s version: %s.", - "NullDownloadUrls": "Could not construct download Urls. Please ensure that specified version is valid.", - "DownloadingPrimaryUrl": "Downloading .NET Core package from primary URL: %s", - "DownloadingSecondaryUrl": "Downloading .NET Core package from legacy URL: %s", + "GettingDownloadUrl": "Getting URL to download .NET Core %s version: %s.", + "CouldNotDetectPlatform": "Could not detect the machine's OS", + "NullDownloadUrls": "Could not construct download Url. Please ensure that specified version %s is valid.", + "DownloadingUrl": "Downloading .NET Core package from URL: %s", "ExtractingPackage": "Extracting downloaded package %s.", "CachingTool": "Caching this installed tool.", "SuccessfullyInstalled": "Successfully installed .NET Core %s version %s.", - "ToolToInstall": "Tool to install: .NET Core %s version %s." + "ToolToInstall": "Tool to install: .NET Core %s version %s.", + "PrimaryPlatform": "Detected platform (Primary): %s", + "LegacyPlatform": "Detected platform (Legacy): %s", + "VersionNotFound": "Could not fetch download information for version %s. Please check if the version specified is correct. You can refer https://github.com/dotnet/core/blob/master/release-notes/releases.json", + "CouldNotDownload": "Could not download installation package from this URL: %s Error: %s", + "FailedToDownloadPackage": "Failed to download package for installation" } } \ No newline at end of file diff --git a/Tasks/DotNetCoreInstallerV0/task.loc.json b/Tasks/DotNetCoreInstallerV0/task.loc.json index d250f13a7201..8fec155a4a83 100644 --- a/Tasks/DotNetCoreInstallerV0/task.loc.json +++ b/Tasks/DotNetCoreInstallerV0/task.loc.json @@ -13,7 +13,7 @@ "version": { "Major": 0, "Minor": 1, - "Patch": 8 + "Patch": 9 }, "satisfies": [ "DotNetCore" @@ -50,20 +50,22 @@ "messages": { "ToolFailed": "ms-resource:loc.messages.ToolFailed", "ImplicitVersionNotSupported": "ms-resource:loc.messages.ImplicitVersionNotSupported", - "PrimaryUrlDownloadFailed": "ms-resource:loc.messages.PrimaryUrlDownloadFailed", - "LegacyUrlDownloadFailed": "ms-resource:loc.messages.LegacyUrlDownloadFailed", - "DownloadFailed": "ms-resource:loc.messages.DownloadFailed", - "getDownloadUrlsFailed": "ms-resource:loc.messages.getDownloadUrlsFailed", + "getMachinePlatformFailed": "ms-resource:loc.messages.getMachinePlatformFailed", "UsingCachedTool": "ms-resource:loc.messages.UsingCachedTool", "CheckingToolCache": "ms-resource:loc.messages.CheckingToolCache", "InstallingAfresh": "ms-resource:loc.messages.InstallingAfresh", - "GettingDownloadUrls": "ms-resource:loc.messages.GettingDownloadUrls", + "GettingDownloadUrl": "ms-resource:loc.messages.GettingDownloadUrl", + "CouldNotDetectPlatform": "ms-resource:loc.messages.CouldNotDetectPlatform", "NullDownloadUrls": "ms-resource:loc.messages.NullDownloadUrls", - "DownloadingPrimaryUrl": "ms-resource:loc.messages.DownloadingPrimaryUrl", - "DownloadingSecondaryUrl": "ms-resource:loc.messages.DownloadingSecondaryUrl", + "DownloadingUrl": "ms-resource:loc.messages.DownloadingUrl", "ExtractingPackage": "ms-resource:loc.messages.ExtractingPackage", "CachingTool": "ms-resource:loc.messages.CachingTool", "SuccessfullyInstalled": "ms-resource:loc.messages.SuccessfullyInstalled", - "ToolToInstall": "ms-resource:loc.messages.ToolToInstall" + "ToolToInstall": "ms-resource:loc.messages.ToolToInstall", + "PrimaryPlatform": "ms-resource:loc.messages.PrimaryPlatform", + "LegacyPlatform": "ms-resource:loc.messages.LegacyPlatform", + "VersionNotFound": "ms-resource:loc.messages.VersionNotFound", + "CouldNotDownload": "ms-resource:loc.messages.CouldNotDownload", + "FailedToDownloadPackage": "ms-resource:loc.messages.FailedToDownloadPackage" } } \ No newline at end of file