mirror of
https://github.com/actions/runner.git
synced 2025-12-19 08:50:41 +00:00
GitHub Actions Runner
This commit is contained in:
650
src/Misc/dotnet-install.ps1
vendored
Normal file
650
src/Misc/dotnet-install.ps1
vendored
Normal file
@@ -0,0 +1,650 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs dotnet cli
|
||||
.DESCRIPTION
|
||||
Installs dotnet cli. If dotnet installation already exists in the given directory
|
||||
it will update it only if the requested version differs from the one already installed.
|
||||
.PARAMETER Channel
|
||||
Default: LTS
|
||||
Download from the Channel specified. Possible values:
|
||||
- Current - most current release
|
||||
- LTS - most current supported release
|
||||
- 2-part version in a format A.B - represents a specific release
|
||||
examples: 2.0, 1.0
|
||||
- Branch name
|
||||
examples: release/2.0.0, Master
|
||||
Note: The version parameter overrides the channel parameter.
|
||||
.PARAMETER Version
|
||||
Default: latest
|
||||
Represents a build version on specific channel. Possible values:
|
||||
- latest - most latest build on specific channel
|
||||
- coherent - most latest coherent build on specific channel
|
||||
coherent applies only to SDK downloads
|
||||
- 3-part version in a format A.B.C - represents specific version of build
|
||||
examples: 2.0.0-preview2-006120, 1.1.0
|
||||
.PARAMETER InstallDir
|
||||
Default: %LocalAppData%\Microsoft\dotnet
|
||||
Path to where to install dotnet. Note that binaries will be placed directly in a given directory.
|
||||
.PARAMETER Architecture
|
||||
Default: <auto> - this value represents currently running OS architecture
|
||||
Architecture of dotnet binaries to be installed.
|
||||
Possible values are: <auto>, amd64, x64, x86, arm64, arm
|
||||
.PARAMETER SharedRuntime
|
||||
This parameter is obsolete and may be removed in a future version of this script.
|
||||
The recommended alternative is '-Runtime dotnet'.
|
||||
|
||||
Default: false
|
||||
Installs just the shared runtime bits, not the entire SDK.
|
||||
This is equivalent to specifying `-Runtime dotnet`.
|
||||
.PARAMETER Runtime
|
||||
Installs just a shared runtime, not the entire SDK.
|
||||
Possible values:
|
||||
- dotnet - the Microsoft.NETCore.App shared runtime
|
||||
- aspnetcore - the Microsoft.AspNetCore.App shared runtime
|
||||
- windowsdesktop - the Microsoft.WindowsDesktop.App shared runtime
|
||||
.PARAMETER DryRun
|
||||
If set it will not perform installation but instead display what command line to use to consistently install
|
||||
currently requested version of dotnet cli. In example if you specify version 'latest' it will display a link
|
||||
with specific version so that this command can be used deterministicly in a build script.
|
||||
It also displays binaries location if you prefer to install or download it yourself.
|
||||
.PARAMETER NoPath
|
||||
By default this script will set environment variable PATH for the current process to the binaries folder inside installation folder.
|
||||
If set it will display binaries location but not set any environment variable.
|
||||
.PARAMETER Verbose
|
||||
Displays diagnostics information.
|
||||
.PARAMETER AzureFeed
|
||||
Default: https://dotnetcli.azureedge.net/dotnet
|
||||
This parameter typically is not changed by the user.
|
||||
It allows changing the URL for the Azure feed used by this installer.
|
||||
.PARAMETER UncachedFeed
|
||||
This parameter typically is not changed by the user.
|
||||
It allows changing the URL for the Uncached feed used by this installer.
|
||||
.PARAMETER FeedCredential
|
||||
Used as a query string to append to the Azure feed.
|
||||
It allows changing the URL to use non-public blob storage accounts.
|
||||
.PARAMETER ProxyAddress
|
||||
If set, the installer will use the proxy when making web requests
|
||||
.PARAMETER ProxyUseDefaultCredentials
|
||||
Default: false
|
||||
Use default credentials, when using proxy address.
|
||||
.PARAMETER SkipNonVersionedFiles
|
||||
Default: false
|
||||
Skips installing non-versioned files if they already exist, such as dotnet.exe.
|
||||
.PARAMETER NoCdn
|
||||
Disable downloading from the Azure CDN, and use the uncached feed directly.
|
||||
#>
|
||||
[cmdletbinding()]
|
||||
param(
|
||||
[string]$Channel="LTS",
|
||||
[string]$Version="Latest",
|
||||
[string]$InstallDir="<auto>",
|
||||
[string]$Architecture="<auto>",
|
||||
[ValidateSet("dotnet", "aspnetcore", "windowsdesktop", IgnoreCase = $false)]
|
||||
[string]$Runtime,
|
||||
[Obsolete("This parameter may be removed in a future version of this script. The recommended alternative is '-Runtime dotnet'.")]
|
||||
[switch]$SharedRuntime,
|
||||
[switch]$DryRun,
|
||||
[switch]$NoPath,
|
||||
[string]$AzureFeed="https://dotnetcli.azureedge.net/dotnet",
|
||||
[string]$UncachedFeed="https://dotnetcli.blob.core.windows.net/dotnet",
|
||||
[string]$FeedCredential,
|
||||
[string]$ProxyAddress,
|
||||
[switch]$ProxyUseDefaultCredentials,
|
||||
[switch]$SkipNonVersionedFiles,
|
||||
[switch]$NoCdn
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference="Stop"
|
||||
$ProgressPreference="SilentlyContinue"
|
||||
|
||||
if ($NoCdn) {
|
||||
$AzureFeed = $UncachedFeed
|
||||
}
|
||||
|
||||
$BinFolderRelativePath=""
|
||||
|
||||
if ($SharedRuntime -and (-not $Runtime)) {
|
||||
$Runtime = "dotnet"
|
||||
}
|
||||
|
||||
# example path with regex: shared/1.0.0-beta-12345/somepath
|
||||
$VersionRegEx="/\d+\.\d+[^/]+/"
|
||||
$OverrideNonVersionedFiles = !$SkipNonVersionedFiles
|
||||
|
||||
function Say($str) {
|
||||
Write-Host "dotnet-install: $str"
|
||||
}
|
||||
|
||||
function Say-Verbose($str) {
|
||||
Write-Verbose "dotnet-install: $str"
|
||||
}
|
||||
|
||||
function Say-Invocation($Invocation) {
|
||||
$command = $Invocation.MyCommand;
|
||||
$args = (($Invocation.BoundParameters.Keys | foreach { "-$_ `"$($Invocation.BoundParameters[$_])`"" }) -join " ")
|
||||
Say-Verbose "$command $args"
|
||||
}
|
||||
|
||||
function Invoke-With-Retry([ScriptBlock]$ScriptBlock, [int]$MaxAttempts = 3, [int]$SecondsBetweenAttempts = 1) {
|
||||
$Attempts = 0
|
||||
|
||||
while ($true) {
|
||||
try {
|
||||
return $ScriptBlock.Invoke()
|
||||
}
|
||||
catch {
|
||||
$Attempts++
|
||||
if ($Attempts -lt $MaxAttempts) {
|
||||
Start-Sleep $SecondsBetweenAttempts
|
||||
}
|
||||
else {
|
||||
throw
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-Machine-Architecture() {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
# possible values: amd64, x64, x86, arm64, arm
|
||||
return $ENV:PROCESSOR_ARCHITECTURE
|
||||
}
|
||||
|
||||
function Get-CLIArchitecture-From-Architecture([string]$Architecture) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
switch ($Architecture.ToLower()) {
|
||||
{ $_ -eq "<auto>" } { return Get-CLIArchitecture-From-Architecture $(Get-Machine-Architecture) }
|
||||
{ ($_ -eq "amd64") -or ($_ -eq "x64") } { return "x64" }
|
||||
{ $_ -eq "x86" } { return "x86" }
|
||||
{ $_ -eq "arm" } { return "arm" }
|
||||
{ $_ -eq "arm64" } { return "arm64" }
|
||||
default { throw "Architecture not supported. If you think this is a bug, report it at https://github.com/dotnet/cli/issues" }
|
||||
}
|
||||
}
|
||||
|
||||
# The version text returned from the feeds is a 1-line or 2-line string:
|
||||
# For the SDK and the dotnet runtime (2 lines):
|
||||
# Line 1: # commit_hash
|
||||
# Line 2: # 4-part version
|
||||
# For the aspnetcore runtime (1 line):
|
||||
# Line 1: # 4-part version
|
||||
function Get-Version-Info-From-Version-Text([string]$VersionText) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
$Data = -split $VersionText
|
||||
|
||||
$VersionInfo = @{
|
||||
CommitHash = $(if ($Data.Count -gt 1) { $Data[0] })
|
||||
Version = $Data[-1] # last line is always the version number.
|
||||
}
|
||||
return $VersionInfo
|
||||
}
|
||||
|
||||
function Load-Assembly([string] $Assembly) {
|
||||
try {
|
||||
Add-Type -Assembly $Assembly | Out-Null
|
||||
}
|
||||
catch {
|
||||
# On Nano Server, Powershell Core Edition is used. Add-Type is unable to resolve base class assemblies because they are not GAC'd.
|
||||
# Loading the base class assemblies is not unnecessary as the types will automatically get resolved.
|
||||
}
|
||||
}
|
||||
|
||||
function GetHTTPResponse([Uri] $Uri)
|
||||
{
|
||||
Invoke-With-Retry(
|
||||
{
|
||||
|
||||
$HttpClient = $null
|
||||
|
||||
try {
|
||||
# HttpClient is used vs Invoke-WebRequest in order to support Nano Server which doesn't support the Invoke-WebRequest cmdlet.
|
||||
Load-Assembly -Assembly System.Net.Http
|
||||
|
||||
if(-not $ProxyAddress) {
|
||||
try {
|
||||
# Despite no proxy being explicitly specified, we may still be behind a default proxy
|
||||
$DefaultProxy = [System.Net.WebRequest]::DefaultWebProxy;
|
||||
if($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))) {
|
||||
$ProxyAddress = $DefaultProxy.GetProxy($Uri).OriginalString
|
||||
$ProxyUseDefaultCredentials = $true
|
||||
}
|
||||
} catch {
|
||||
# Eat the exception and move forward as the above code is an attempt
|
||||
# at resolving the DefaultProxy that may not have been a problem.
|
||||
$ProxyAddress = $null
|
||||
Say-Verbose("Exception ignored: $_.Exception.Message - moving forward...")
|
||||
}
|
||||
}
|
||||
|
||||
if($ProxyAddress) {
|
||||
$HttpClientHandler = New-Object System.Net.Http.HttpClientHandler
|
||||
$HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{Address=$ProxyAddress;UseDefaultCredentials=$ProxyUseDefaultCredentials}
|
||||
$HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler
|
||||
}
|
||||
else {
|
||||
|
||||
$HttpClient = New-Object System.Net.Http.HttpClient
|
||||
}
|
||||
# Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out
|
||||
# 20 minutes allows it to work over much slower connections.
|
||||
$HttpClient.Timeout = New-TimeSpan -Minutes 20
|
||||
$Response = $HttpClient.GetAsync("${Uri}${FeedCredential}").Result
|
||||
if (($Response -eq $null) -or (-not ($Response.IsSuccessStatusCode))) {
|
||||
# The feed credential is potentially sensitive info. Do not log FeedCredential to console output.
|
||||
$ErrorMsg = "Failed to download $Uri."
|
||||
if ($Response -ne $null) {
|
||||
$ErrorMsg += " $Response"
|
||||
}
|
||||
|
||||
throw $ErrorMsg
|
||||
}
|
||||
|
||||
return $Response
|
||||
}
|
||||
finally {
|
||||
if ($HttpClient -ne $null) {
|
||||
$HttpClient.Dispose()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel, [bool]$Coherent) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
$VersionFileUrl = $null
|
||||
if ($Runtime -eq "dotnet") {
|
||||
$VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version"
|
||||
}
|
||||
elseif ($Runtime -eq "aspnetcore") {
|
||||
$VersionFileUrl = "$UncachedFeed/aspnetcore/Runtime/$Channel/latest.version"
|
||||
}
|
||||
# Currently, the WindowsDesktop runtime is manufactured with the .Net core runtime
|
||||
elseif ($Runtime -eq "windowsdesktop") {
|
||||
$VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version"
|
||||
}
|
||||
elseif (-not $Runtime) {
|
||||
if ($Coherent) {
|
||||
$VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.coherent.version"
|
||||
}
|
||||
else {
|
||||
$VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version"
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw "Invalid value for `$Runtime"
|
||||
}
|
||||
try {
|
||||
$Response = GetHTTPResponse -Uri $VersionFileUrl
|
||||
}
|
||||
catch {
|
||||
throw "Could not resolve version information."
|
||||
}
|
||||
$StringContent = $Response.Content.ReadAsStringAsync().Result
|
||||
|
||||
switch ($Response.Content.Headers.ContentType) {
|
||||
{ ($_ -eq "application/octet-stream") } { $VersionText = $StringContent }
|
||||
{ ($_ -eq "text/plain") } { $VersionText = $StringContent }
|
||||
{ ($_ -eq "text/plain; charset=UTF-8") } { $VersionText = $StringContent }
|
||||
default { throw "``$Response.Content.Headers.ContentType`` is an unknown .version file content type." }
|
||||
}
|
||||
|
||||
$VersionInfo = Get-Version-Info-From-Version-Text $VersionText
|
||||
|
||||
return $VersionInfo
|
||||
}
|
||||
|
||||
|
||||
function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$Channel, [string]$Version) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
switch ($Version.ToLower()) {
|
||||
{ $_ -eq "latest" } {
|
||||
$LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $False
|
||||
return $LatestVersionInfo.Version
|
||||
}
|
||||
{ $_ -eq "coherent" } {
|
||||
$LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $True
|
||||
return $LatestVersionInfo.Version
|
||||
}
|
||||
default { return $Version }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
if ($Runtime -eq "dotnet") {
|
||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificVersion-win-$CLIArchitecture.zip"
|
||||
}
|
||||
elseif ($Runtime -eq "aspnetcore") {
|
||||
$PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificVersion-win-$CLIArchitecture.zip"
|
||||
}
|
||||
elseif ($Runtime -eq "windowsdesktop") {
|
||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificVersion-win-$CLIArchitecture.zip"
|
||||
}
|
||||
elseif (-not $Runtime) {
|
||||
$PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificVersion-win-$CLIArchitecture.zip"
|
||||
}
|
||||
else {
|
||||
throw "Invalid value for `$Runtime"
|
||||
}
|
||||
|
||||
Say-Verbose "Constructed primary named payload URL: $PayloadURL"
|
||||
|
||||
return $PayloadURL
|
||||
}
|
||||
|
||||
function Get-LegacyDownload-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
if (-not $Runtime) {
|
||||
$PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-dev-win-$CLIArchitecture.$SpecificVersion.zip"
|
||||
}
|
||||
elseif ($Runtime -eq "dotnet") {
|
||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-win-$CLIArchitecture.$SpecificVersion.zip"
|
||||
}
|
||||
else {
|
||||
return $null
|
||||
}
|
||||
|
||||
Say-Verbose "Constructed legacy named payload URL: $PayloadURL"
|
||||
|
||||
return $PayloadURL
|
||||
}
|
||||
|
||||
function Get-User-Share-Path() {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
$InstallRoot = $env:DOTNET_INSTALL_DIR
|
||||
if (!$InstallRoot) {
|
||||
$InstallRoot = "$env:LocalAppData\Microsoft\dotnet"
|
||||
}
|
||||
return $InstallRoot
|
||||
}
|
||||
|
||||
function Resolve-Installation-Path([string]$InstallDir) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
if ($InstallDir -eq "<auto>") {
|
||||
return Get-User-Share-Path
|
||||
}
|
||||
return $InstallDir
|
||||
}
|
||||
|
||||
function Get-Version-Info-From-Version-File([string]$InstallRoot, [string]$RelativePathToVersionFile) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
$VersionFile = Join-Path -Path $InstallRoot -ChildPath $RelativePathToVersionFile
|
||||
Say-Verbose "Local version file: $VersionFile"
|
||||
|
||||
if (Test-Path $VersionFile) {
|
||||
$VersionText = cat $VersionFile
|
||||
Say-Verbose "Local version file text: $VersionText"
|
||||
return Get-Version-Info-From-Version-Text $VersionText
|
||||
}
|
||||
|
||||
Say-Verbose "Local version file not found."
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
$DotnetPackagePath = Join-Path -Path $InstallRoot -ChildPath $RelativePathToPackage | Join-Path -ChildPath $SpecificVersion
|
||||
Say-Verbose "Is-Dotnet-Package-Installed: Path to a package: $DotnetPackagePath"
|
||||
return Test-Path $DotnetPackagePath -PathType Container
|
||||
}
|
||||
|
||||
function Get-Absolute-Path([string]$RelativeOrAbsolutePath) {
|
||||
# Too much spam
|
||||
# Say-Invocation $MyInvocation
|
||||
|
||||
return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($RelativeOrAbsolutePath)
|
||||
}
|
||||
|
||||
function Get-Path-Prefix-With-Version($path) {
|
||||
$match = [regex]::match($path, $VersionRegEx)
|
||||
if ($match.Success) {
|
||||
return $entry.FullName.Substring(0, $match.Index + $match.Length)
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package([System.IO.Compression.ZipArchive]$Zip, [string]$OutPath) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
$ret = @()
|
||||
foreach ($entry in $Zip.Entries) {
|
||||
$dir = Get-Path-Prefix-With-Version $entry.FullName
|
||||
if ($dir -ne $null) {
|
||||
$path = Get-Absolute-Path $(Join-Path -Path $OutPath -ChildPath $dir)
|
||||
if (-Not (Test-Path $path -PathType Container)) {
|
||||
$ret += $dir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ret = $ret | Sort-Object | Get-Unique
|
||||
|
||||
$values = ($ret | foreach { "$_" }) -join ";"
|
||||
Say-Verbose "Directories to unpack: $values"
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
# Example zip content and extraction algorithm:
|
||||
# Rule: files if extracted are always being extracted to the same relative path locally
|
||||
# .\
|
||||
# a.exe # file does not exist locally, extract
|
||||
# b.dll # file exists locally, override only if $OverrideFiles set
|
||||
# aaa\ # same rules as for files
|
||||
# ...
|
||||
# abc\1.0.0\ # directory contains version and exists locally
|
||||
# ... # do not extract content under versioned part
|
||||
# abc\asd\ # same rules as for files
|
||||
# ...
|
||||
# def\ghi\1.0.1\ # directory contains version and does not exist locally
|
||||
# ... # extract content
|
||||
function Extract-Dotnet-Package([string]$ZipPath, [string]$OutPath) {
|
||||
Say-Invocation $MyInvocation
|
||||
|
||||
Load-Assembly -Assembly System.IO.Compression.FileSystem
|
||||
Set-Variable -Name Zip
|
||||
try {
|
||||
$Zip = [System.IO.Compression.ZipFile]::OpenRead($ZipPath)
|
||||
|
||||
$DirectoriesToUnpack = Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package -Zip $Zip -OutPath $OutPath
|
||||
|
||||
foreach ($entry in $Zip.Entries) {
|
||||
$PathWithVersion = Get-Path-Prefix-With-Version $entry.FullName
|
||||
if (($PathWithVersion -eq $null) -Or ($DirectoriesToUnpack -contains $PathWithVersion)) {
|
||||
$DestinationPath = Get-Absolute-Path $(Join-Path -Path $OutPath -ChildPath $entry.FullName)
|
||||
$DestinationDir = Split-Path -Parent $DestinationPath
|
||||
$OverrideFiles=$OverrideNonVersionedFiles -Or (-Not (Test-Path $DestinationPath))
|
||||
if ((-Not $DestinationPath.EndsWith("\")) -And $OverrideFiles) {
|
||||
New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null
|
||||
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $DestinationPath, $OverrideNonVersionedFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ($Zip -ne $null) {
|
||||
$Zip.Dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function DownloadFile($Source, [string]$OutPath) {
|
||||
if ($Source -notlike "http*") {
|
||||
# Using System.IO.Path.GetFullPath to get the current directory
|
||||
# does not work in this context - $pwd gives the current directory
|
||||
if (![System.IO.Path]::IsPathRooted($Source)) {
|
||||
$Source = $(Join-Path -Path $pwd -ChildPath $Source)
|
||||
}
|
||||
$Source = Get-Absolute-Path $Source
|
||||
Say "Copying file from $Source to $OutPath"
|
||||
Copy-Item $Source $OutPath
|
||||
return
|
||||
}
|
||||
|
||||
$Stream = $null
|
||||
|
||||
try {
|
||||
$Response = GetHTTPResponse -Uri $Source
|
||||
$Stream = $Response.Content.ReadAsStreamAsync().Result
|
||||
$File = [System.IO.File]::Create($OutPath)
|
||||
$Stream.CopyTo($File)
|
||||
$File.Close()
|
||||
}
|
||||
finally {
|
||||
if ($Stream -ne $null) {
|
||||
$Stream.Dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolderRelativePath) {
|
||||
$BinPath = Get-Absolute-Path $(Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath)
|
||||
if (-Not $NoPath) {
|
||||
$SuffixedBinPath = "$BinPath;"
|
||||
if (-Not $env:path.Contains($SuffixedBinPath)) {
|
||||
Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process."
|
||||
$env:path = $SuffixedBinPath + $env:path
|
||||
} else {
|
||||
Say-Verbose "Current process PATH already contains `"$BinPath`""
|
||||
}
|
||||
}
|
||||
else {
|
||||
Say "Binaries of dotnet can be found in $BinPath"
|
||||
}
|
||||
}
|
||||
|
||||
$CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture
|
||||
$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version
|
||||
$DownloadLink = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
|
||||
$LegacyDownloadLink = Get-LegacyDownload-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
|
||||
|
||||
$InstallRoot = Resolve-Installation-Path $InstallDir
|
||||
Say-Verbose "InstallRoot: $InstallRoot"
|
||||
$ScriptName = $MyInvocation.MyCommand.Name
|
||||
|
||||
if ($DryRun) {
|
||||
Say "Payload URLs:"
|
||||
Say "Primary named payload URL: $DownloadLink"
|
||||
if ($LegacyDownloadLink) {
|
||||
Say "Legacy named payload URL: $LegacyDownloadLink"
|
||||
}
|
||||
$RepeatableCommand = ".\$ScriptName -Version `"$SpecificVersion`" -InstallDir `"$InstallRoot`" -Architecture `"$CLIArchitecture`""
|
||||
if ($Runtime -eq "dotnet") {
|
||||
$RepeatableCommand+=" -Runtime `"dotnet`""
|
||||
}
|
||||
elseif ($Runtime -eq "aspnetcore") {
|
||||
$RepeatableCommand+=" -Runtime `"aspnetcore`""
|
||||
}
|
||||
foreach ($key in $MyInvocation.BoundParameters.Keys) {
|
||||
if (-not (@("Architecture","Channel","DryRun","InstallDir","Runtime","SharedRuntime","Version") -contains $key)) {
|
||||
$RepeatableCommand+=" -$key `"$($MyInvocation.BoundParameters[$key])`""
|
||||
}
|
||||
}
|
||||
Say "Repeatable invocation: $RepeatableCommand"
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($Runtime -eq "dotnet") {
|
||||
$assetName = ".NET Core Runtime"
|
||||
$dotnetPackageRelativePath = "shared\Microsoft.NETCore.App"
|
||||
}
|
||||
elseif ($Runtime -eq "aspnetcore") {
|
||||
$assetName = "ASP.NET Core Runtime"
|
||||
$dotnetPackageRelativePath = "shared\Microsoft.AspNetCore.App"
|
||||
}
|
||||
elseif ($Runtime -eq "windowsdesktop") {
|
||||
$assetName = ".NET Core Windows Desktop Runtime"
|
||||
$dotnetPackageRelativePath = "shared\Microsoft.WindowsDesktop.App"
|
||||
}
|
||||
elseif (-not $Runtime) {
|
||||
$assetName = ".NET Core SDK"
|
||||
$dotnetPackageRelativePath = "sdk"
|
||||
}
|
||||
else {
|
||||
throw "Invalid value for `$Runtime"
|
||||
}
|
||||
|
||||
# Check if the SDK version is already installed.
|
||||
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion
|
||||
if ($isAssetInstalled) {
|
||||
Say "$assetName version $SpecificVersion is already installed."
|
||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
|
||||
exit 0
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
|
||||
|
||||
$installDrive = $((Get-Item $InstallRoot).PSDrive.Name);
|
||||
$diskInfo = Get-PSDrive -Name $installDrive
|
||||
if ($diskInfo.Free / 1MB -le 100) {
|
||||
Say "There is not enough disk space on drive ${installDrive}:"
|
||||
exit 0
|
||||
}
|
||||
|
||||
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
|
||||
Say-Verbose "Zip path: $ZipPath"
|
||||
|
||||
$DownloadFailed = $false
|
||||
Say "Downloading link: $DownloadLink"
|
||||
try {
|
||||
DownloadFile -Source $DownloadLink -OutPath $ZipPath
|
||||
}
|
||||
catch {
|
||||
Say "Cannot download: $DownloadLink"
|
||||
if ($LegacyDownloadLink) {
|
||||
$DownloadLink = $LegacyDownloadLink
|
||||
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
|
||||
Say-Verbose "Legacy zip path: $ZipPath"
|
||||
Say "Downloading legacy link: $DownloadLink"
|
||||
try {
|
||||
DownloadFile -Source $DownloadLink -OutPath $ZipPath
|
||||
}
|
||||
catch {
|
||||
Say "Cannot download: $DownloadLink"
|
||||
$DownloadFailed = $true
|
||||
}
|
||||
}
|
||||
else {
|
||||
$DownloadFailed = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($DownloadFailed) {
|
||||
throw "Could not find/download: `"$assetName`" with version = $SpecificVersion`nRefer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support"
|
||||
}
|
||||
|
||||
Say "Extracting zip from $DownloadLink"
|
||||
Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot
|
||||
|
||||
# Check if the SDK version is now installed; if not, fail the installation.
|
||||
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion
|
||||
if (!$isAssetInstalled) {
|
||||
throw "`"$assetName`" with version = $SpecificVersion failed to install with an unknown error."
|
||||
}
|
||||
|
||||
Remove-Item $ZipPath
|
||||
|
||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
|
||||
|
||||
Say "Installation finished"
|
||||
exit 0
|
||||
1025
src/Misc/dotnet-install.sh
vendored
Executable file
1025
src/Misc/dotnet-install.sh
vendored
Executable file
File diff suppressed because it is too large
Load Diff
148
src/Misc/externals.sh
Executable file
148
src/Misc/externals.sh
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
PACKAGERUNTIME=$1
|
||||
PRECACHE=$2
|
||||
|
||||
NODE_URL=https://nodejs.org/dist
|
||||
NODE12_VERSION="12.4.0"
|
||||
|
||||
get_abs_path() {
|
||||
# exploits the fact that pwd will print abs path when no args
|
||||
echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
|
||||
}
|
||||
|
||||
LAYOUT_DIR=$(get_abs_path "$(dirname $0)/../../_layout")
|
||||
DOWNLOAD_DIR="$(get_abs_path "$(dirname $0)/../../_downloads")/netcore2x"
|
||||
|
||||
function failed() {
|
||||
local error=${1:-Undefined error}
|
||||
echo "Failed: $error" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function checkRC() {
|
||||
local rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
failed "${1} failed with return code $rc"
|
||||
fi
|
||||
}
|
||||
|
||||
function acquireExternalTool() {
|
||||
local download_source=$1 # E.g. https://github.com/microsoft/vswhere/releases/download/2.6.7/vswhere.exe
|
||||
local target_dir="$LAYOUT_DIR/externals/$2" # E.g. $LAYOUT_DIR/externals/vswhere
|
||||
local fix_nested_dir=$3 # Flag that indicates whether to move nested contents up one directory.
|
||||
|
||||
# Extract the portion of the URL after the protocol. E.g. github.com/microsoft/vswhere/releases/download/2.6.7/vswhere.exe
|
||||
local relative_url="${download_source#*://}"
|
||||
|
||||
# Check if the download already exists.
|
||||
local download_target="$DOWNLOAD_DIR/$relative_url"
|
||||
local download_basename="$(basename "$download_target")"
|
||||
local download_dir="$(dirname "$download_target")"
|
||||
|
||||
if [[ "$PRECACHE" != "" ]]; then
|
||||
if [ -f "$download_target" ]; then
|
||||
echo "Download exists: $download_basename"
|
||||
else
|
||||
# Delete any previous partial file.
|
||||
local partial_target="$DOWNLOAD_DIR/partial/$download_basename"
|
||||
mkdir -p "$(dirname "$partial_target")" || checkRC 'mkdir'
|
||||
if [ -f "$partial_target" ]; then
|
||||
rm "$partial_target" || checkRC 'rm'
|
||||
fi
|
||||
|
||||
# Download from source to the partial file.
|
||||
echo "Downloading $download_source"
|
||||
mkdir -p "$(dirname "$download_target")" || checkRC 'mkdir'
|
||||
# curl -f Fail silently (no output at all) on HTTP errors (H)
|
||||
# -k Allow connections to SSL sites without certs (H)
|
||||
# -S Show error. With -s, make curl show errors when they occur
|
||||
# -L Follow redirects (H)
|
||||
# -o FILE Write to FILE instead of stdout
|
||||
curl -fkSL -o "$partial_target" "$download_source" 2>"${download_target}_download.log" || checkRC 'curl'
|
||||
|
||||
# Move the partial file to the download target.
|
||||
mv "$partial_target" "$download_target" || checkRC 'mv'
|
||||
|
||||
# Extract to current directory
|
||||
# Ensure we can extract those files
|
||||
# We might use them during dev.sh
|
||||
if [[ "$download_basename" == *.zip ]]; then
|
||||
# Extract the zip.
|
||||
echo "Testing zip"
|
||||
unzip "$download_target" -d "$download_dir" > /dev/null
|
||||
local rc=$?
|
||||
if [[ $rc -ne 0 && $rc -ne 1 ]]; then
|
||||
failed "unzip failed with return code $rc"
|
||||
fi
|
||||
elif [[ "$download_basename" == *.tar.gz ]]; then
|
||||
# Extract the tar gz.
|
||||
echo "Testing tar gz"
|
||||
tar xzf "$download_target" -C "$download_dir" > /dev/null || checkRC 'tar'
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Extract to layout.
|
||||
mkdir -p "$target_dir" || checkRC 'mkdir'
|
||||
local nested_dir=""
|
||||
if [[ "$download_basename" == *.zip ]]; then
|
||||
# Extract the zip.
|
||||
echo "Extracting zip to layout"
|
||||
unzip "$download_target" -d "$target_dir" > /dev/null
|
||||
local rc=$?
|
||||
if [[ $rc -ne 0 && $rc -ne 1 ]]; then
|
||||
failed "unzip failed with return code $rc"
|
||||
fi
|
||||
|
||||
# Capture the nested directory path if the fix_nested_dir flag is set.
|
||||
if [[ "$fix_nested_dir" == "fix_nested_dir" ]]; then
|
||||
nested_dir="${download_basename%.zip}" # Remove the trailing ".zip".
|
||||
fi
|
||||
elif [[ "$download_basename" == *.tar.gz ]]; then
|
||||
# Extract the tar gz.
|
||||
echo "Extracting tar gz to layout"
|
||||
tar xzf "$download_target" -C "$target_dir" > /dev/null || checkRC 'tar'
|
||||
|
||||
# Capture the nested directory path if the fix_nested_dir flag is set.
|
||||
if [[ "$fix_nested_dir" == "fix_nested_dir" ]]; then
|
||||
nested_dir="${download_basename%.tar.gz}" # Remove the trailing ".tar.gz".
|
||||
fi
|
||||
else
|
||||
# Copy the file.
|
||||
echo "Copying to layout"
|
||||
cp "$download_target" "$target_dir/" || checkRC 'cp'
|
||||
fi
|
||||
|
||||
# Fixup the nested directory.
|
||||
if [[ "$nested_dir" != "" ]]; then
|
||||
if [ -d "$target_dir/$nested_dir" ]; then
|
||||
mv "$target_dir/$nested_dir"/* "$target_dir/" || checkRC 'mv'
|
||||
rmdir "$target_dir/$nested_dir" || checkRC 'rmdir'
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Download the external tools only for Windows.
|
||||
if [[ "$PACKAGERUNTIME" == "win-x64" ]]; then
|
||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/win-x64/node.exe" node12/bin
|
||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/win-x64/node.lib" node12/bin
|
||||
if [[ "$PRECACHE" != "" ]]; then
|
||||
acquireExternalTool "https://github.com/microsoft/vswhere/releases/download/2.6.7/vswhere.exe" vswhere
|
||||
fi
|
||||
fi
|
||||
|
||||
# Download the external tools only for OSX.
|
||||
if [[ "$PACKAGERUNTIME" == "osx-x64" ]]; then
|
||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-darwin-x64.tar.gz" node12 fix_nested_dir
|
||||
fi
|
||||
|
||||
# Download the external tools common across Linux PACKAGERUNTIMEs (excluding OSX).
|
||||
if [[ "$PACKAGERUNTIME" == "linux-x64" || "$PACKAGERUNTIME" == "rhel.6-x64" ]]; then
|
||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-x64.tar.gz" node12 fix_nested_dir
|
||||
# TODO: Repath this blob to use a consistent version format (_ vs .)
|
||||
acquireExternalTool "https://vstsagenttools.blob.core.windows.net/tools/nodejs/12_4_0/alpine/node-v${NODE12_VERSION}-alpine.tar.gz" node12_alpine
|
||||
fi
|
||||
|
||||
if [[ "$PACKAGERUNTIME" == "linux-arm" ]]; then
|
||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-armv7l.tar.gz" node12 fix_nested_dir
|
||||
fi
|
||||
91
src/Misc/layoutbin/RunnerService.js
Normal file
91
src/Misc/layoutbin/RunnerService.js
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env node
|
||||
// Copyright (c) GitHub. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
var childProcess = require("child_process");
|
||||
var path = require("path")
|
||||
|
||||
var supported = ['linux', 'darwin']
|
||||
|
||||
if (supported.indexOf(process.platform) == -1) {
|
||||
console.log('Unsupported platform: ' + process.platform);
|
||||
console.log('Supported platforms are: ' + supported.toString());
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var stopping = false;
|
||||
var listener = null;
|
||||
|
||||
var runService = function() {
|
||||
var listenerExePath = path.join(__dirname, '../bin/Runner.Listener');
|
||||
var interactive = process.argv[2] === "interactive";
|
||||
|
||||
if(!stopping) {
|
||||
try {
|
||||
if (interactive) {
|
||||
console.log('Starting Runner listener interactively');
|
||||
listener = childProcess.spawn(listenerExePath, ['run'], { env: process.env });
|
||||
} else {
|
||||
console.log('Starting Runner listener with startup type: service');
|
||||
listener = childProcess.spawn(listenerExePath, ['run', '--startuptype', 'service'], { env: process.env });
|
||||
}
|
||||
|
||||
console.log('Started listener process');
|
||||
|
||||
listener.stdout.on('data', (data) => {
|
||||
process.stdout.write(data.toString('utf8'));
|
||||
});
|
||||
|
||||
listener.stderr.on('data', (data) => {
|
||||
process.stdout.write(data.toString('utf8'));
|
||||
});
|
||||
|
||||
listener.on('close', (code) => {
|
||||
console.log(`Runner listener exited with error code ${code}`);
|
||||
|
||||
if (code === 0) {
|
||||
console.log('Runner listener exit with 0 return code, stop the service, no retry needed.');
|
||||
stopping = true;
|
||||
} else if (code === 1) {
|
||||
console.log('Runner listener exit with terminated error, stop the service, no retry needed.');
|
||||
stopping = true;
|
||||
} else if (code === 2) {
|
||||
console.log('Runner listener exit with retryable error, re-launch runner in 5 seconds.');
|
||||
} else if (code === 3) {
|
||||
console.log('Runner listener exit because of updating, re-launch runner in 5 seconds.');
|
||||
} else {
|
||||
console.log('Runner listener exit with undefined return code, re-launch runner in 5 seconds.');
|
||||
}
|
||||
|
||||
if(!stopping) {
|
||||
setTimeout(runService, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
} catch(ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runService();
|
||||
console.log('Started running service');
|
||||
|
||||
var gracefulShutdown = function(code) {
|
||||
console.log('Shutting down runner listener');
|
||||
stopping = true;
|
||||
if (listener) {
|
||||
console.log('Sending SIGINT to runner listener to stop');
|
||||
listener.kill('SIGINT');
|
||||
|
||||
// TODO wait for 30 seconds and send a SIGKILL
|
||||
}
|
||||
}
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
gracefulShutdown(0);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
gracefulShutdown(0);
|
||||
});
|
||||
27
src/Misc/layoutbin/actions.runner.plist.template
Normal file
27
src/Misc/layoutbin/actions.runner.plist.template
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>{{SvcName}}</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>{{RunnerRoot}}/runsvc.sh</string>
|
||||
</array>
|
||||
<key>UserName</key>
|
||||
<string>{{User}}</string>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>{{RunnerRoot}}</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>{{UserHome}}/Library/Logs/{{SvcName}}/stdout.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>{{UserHome}}/Library/Logs/{{SvcName}}/stderr.log</string>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>ACTIONS_RUNNER_SVC</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
14
src/Misc/layoutbin/actions.runner.service.template
Normal file
14
src/Misc/layoutbin/actions.runner.service.template
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description={{Description}}
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart={{RunnerRoot}}/runsvc.sh
|
||||
User={{User}}
|
||||
WorkingDirectory={{RunnerRoot}}
|
||||
KillMode=process
|
||||
KillSignal=SIGTERM
|
||||
TimeoutStopSec=5min
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
135
src/Misc/layoutbin/darwin.svc.sh.template
Normal file
135
src/Misc/layoutbin/darwin.svc.sh.template
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/bin/bash
|
||||
|
||||
SVC_NAME="{{SvcNameVar}}"
|
||||
SVC_DESCRIPTION="{{SvcDescription}}"
|
||||
|
||||
user_id=`id -u`
|
||||
|
||||
# launchctl should not run as sudo for launch runners
|
||||
if [ $user_id -eq 0 ]; then
|
||||
echo "Must not run with sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SVC_CMD=$1
|
||||
RUNNER_ROOT=`pwd`
|
||||
|
||||
LAUNCH_PATH="${HOME}/Library/LaunchAgents"
|
||||
PLIST_PATH="${LAUNCH_PATH}/${SVC_NAME}.plist"
|
||||
TEMPLATE_PATH=./bin/actions.runner.plist.template
|
||||
TEMP_PATH=./bin/actions.runner.plist.temp
|
||||
CONFIG_PATH=.service
|
||||
|
||||
function failed()
|
||||
{
|
||||
local error=${1:-Undefined error}
|
||||
echo "Failed: $error" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ ! -f "${TEMPLATE_PATH}" ]; then
|
||||
failed "Must run from runner root or install is corrupt"
|
||||
fi
|
||||
|
||||
function install()
|
||||
{
|
||||
echo "Creating launch runner in ${PLIST_PATH}"
|
||||
|
||||
if [ ! -d "${LAUNCH_PATH}" ]; then
|
||||
mkdir ${LAUNCH_PATH}
|
||||
fi
|
||||
|
||||
if [ -f "${PLIST_PATH}" ]; then
|
||||
failed "error: exists ${PLIST_PATH}"
|
||||
fi
|
||||
|
||||
if [ -f "${TEMP_PATH}" ]; then
|
||||
rm "${TEMP_PATH}" || failed "failed to delete ${TEMP_PATH}"
|
||||
fi
|
||||
|
||||
log_path="${HOME}/Library/Logs/${SVC_NAME}"
|
||||
echo "Creating ${log_path}"
|
||||
mkdir -p "${log_path}" || failed "failed to create ${log_path}"
|
||||
|
||||
echo Creating ${PLIST_PATH}
|
||||
sed "s/{{User}}/${SUDO_USER:-$USER}/g; s/{{SvcName}}/$SVC_NAME/g; s@{{RunnerRoot}}@${RUNNER_ROOT}@g; s@{{UserHome}}@$HOME@g;" "${TEMPLATE_PATH}" > "${TEMP_PATH}" || failed "failed to create replacement temp file"
|
||||
mv "${TEMP_PATH}" "${PLIST_PATH}" || failed "failed to copy plist"
|
||||
|
||||
# Since we started with sudo, runsvc.sh will be owned by root. Change this to current login user.
|
||||
echo Creating runsvc.sh
|
||||
cp ./bin/runsvc.sh ./runsvc.sh || failed "failed to copy runsvc.sh"
|
||||
chmod u+x ./runsvc.sh || failed "failed to set permission for runsvc.sh"
|
||||
|
||||
echo Creating ${CONFIG_PATH}
|
||||
echo "${PLIST_PATH}" > ${CONFIG_PATH} || failed "failed to create .Service file"
|
||||
|
||||
echo "svc install complete"
|
||||
}
|
||||
|
||||
function start()
|
||||
{
|
||||
echo "starting ${SVC_NAME}"
|
||||
launchctl load -w "${PLIST_PATH}" || failed "failed to load ${PLIST_PATH}"
|
||||
status
|
||||
}
|
||||
|
||||
function stop()
|
||||
{
|
||||
echo "stopping ${SVC_NAME}"
|
||||
launchctl unload "${PLIST_PATH}" || failed "failed to unload ${PLIST_PATH}"
|
||||
status
|
||||
}
|
||||
|
||||
function uninstall()
|
||||
{
|
||||
echo "uninstalling ${SVC_NAME}"
|
||||
stop
|
||||
rm "${PLIST_PATH}" || failed "failed to delete ${PLIST_PATH}"
|
||||
if [ -f "${CONFIG_PATH}" ]; then
|
||||
rm "${CONFIG_PATH}" || failed "failed to delete ${CONFIG_PATH}"
|
||||
fi
|
||||
}
|
||||
|
||||
function status()
|
||||
{
|
||||
echo "status ${SVC_NAME}:"
|
||||
if [ -f "${PLIST_PATH}" ]; then
|
||||
echo
|
||||
echo "${PLIST_PATH}"
|
||||
else
|
||||
echo
|
||||
echo "not installed"
|
||||
echo
|
||||
return
|
||||
fi
|
||||
|
||||
echo
|
||||
status_out=`launchctl list | grep "${SVC_NAME}"`
|
||||
if [ ! -z "$status_out" ]; then
|
||||
echo Started:
|
||||
echo $status_out
|
||||
echo
|
||||
else
|
||||
echo Stopped
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
function usage()
|
||||
{
|
||||
echo
|
||||
echo Usage:
|
||||
echo "./svc.sh [install, start, stop, status, uninstall]"
|
||||
echo
|
||||
}
|
||||
|
||||
case $SVC_CMD in
|
||||
"install") install;;
|
||||
"status") status;;
|
||||
"uninstall") uninstall;;
|
||||
"start") start;;
|
||||
"stop") stop;;
|
||||
*) usage;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
298
src/Misc/layoutbin/installdependencies.sh
Executable file
298
src/Misc/layoutbin/installdependencies.sh
Executable file
@@ -0,0 +1,298 @@
|
||||
#!/bin/bash
|
||||
|
||||
user_id=`id -u`
|
||||
|
||||
if [ $user_id -ne 0 ]; then
|
||||
echo "Need to run with sudo privilege"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine OS type
|
||||
# Debian based OS (Debian, Ubuntu, Linux Mint) has /etc/debian_version
|
||||
# Fedora based OS (Fedora, Redhat, Centos, Oracle Linux 7) has /etc/redhat-release
|
||||
# SUSE based OS (OpenSUSE, SUSE Enterprise) has ID_LIKE=suse in /etc/os-release
|
||||
|
||||
function print_errormessage()
|
||||
{
|
||||
echo "Can't install dotnet core dependencies."
|
||||
echo "You can manually install all required dependencies based on following documentation"
|
||||
echo "https://docs.microsoft.com/en-us/dotnet/core/linux-prerequisites?tabs=netcore2x"
|
||||
}
|
||||
|
||||
function print_rhel6message()
|
||||
{
|
||||
echo "We did our best effort to install dotnet core dependencies"
|
||||
echo "However, there are some dependencies which require manual installation"
|
||||
echo "You can install all remaining required dependencies based on the following documentation"
|
||||
echo "https://github.com/dotnet/core/blob/master/Documentation/build-and-install-rhel6-prerequisites.md"
|
||||
}
|
||||
|
||||
function print_rhel6errormessage()
|
||||
{
|
||||
echo "We couldn't install dotnet core dependencies"
|
||||
echo "You can manually install all required dependencies based on following documentation"
|
||||
echo "https://docs.microsoft.com/en-us/dotnet/core/linux-prerequisites?tabs=netcore2x"
|
||||
echo "In addition, there are some dependencies which require manual installation. Please follow this documentation"
|
||||
echo "https://github.com/dotnet/core/blob/master/Documentation/build-and-install-rhel6-prerequisites.md"
|
||||
}
|
||||
|
||||
if [ -e /etc/os-release ]
|
||||
then
|
||||
echo "--------OS Information--------"
|
||||
cat /etc/os-release
|
||||
echo "------------------------------"
|
||||
|
||||
if [ -e /etc/debian_version ]
|
||||
then
|
||||
echo "The current OS is Debian based"
|
||||
echo "--------Debian Version--------"
|
||||
cat /etc/debian_version
|
||||
echo "------------------------------"
|
||||
|
||||
# prefer apt over apt-get
|
||||
command -v apt
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
apt update && apt install -y liblttng-ust0 libkrb5-3 zlib1g
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'apt' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ubuntu 18 uses libcurl4
|
||||
# ubuntu 14, 16 and other linux use libcurl3
|
||||
apt install -y libcurl3 || apt install -y libcurl4
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'apt' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# debian 9 use libssl1.0.2
|
||||
# other debian linux use libssl1.0.0
|
||||
apt install -y libssl1.0.0 || apt install -y libssl1.0.2
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'apt' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# libicu version prefer: libicu52 -> libicu55 -> libicu57 -> libicu60
|
||||
apt install -y libicu52 || apt install -y libicu55 || apt install -y libicu57 || apt install -y libicu60
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'apt' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
command -v apt-get
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
apt-get update && apt-get install -y liblttng-ust0 libkrb5-3 zlib1g
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'apt-get' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ubuntu 18 uses libcurl4
|
||||
# ubuntu 14, 16 and other linux use libcurl3
|
||||
apt-get install -y libcurl3 || apt-get install -y libcurl4
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'apt-get' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# debian 9 use libssl1.0.2
|
||||
# other debian linux use libssl1.0.0
|
||||
apt-get install -y libssl1.0.0 || apt install -y libssl1.0.2
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'apt-get' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# libicu version prefer: libicu52 -> libicu55 -> libicu57 -> libicu60
|
||||
apt-get install -y libicu52 || apt install -y libicu55 || apt install -y libicu57 || apt install -y libicu60
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'apt-get' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Can not find 'apt' or 'apt-get'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
elif [ -e /etc/redhat-release ]
|
||||
then
|
||||
echo "The current OS is Fedora based"
|
||||
echo "--------Redhat Version--------"
|
||||
cat /etc/redhat-release
|
||||
echo "------------------------------"
|
||||
|
||||
# use dnf on fedora
|
||||
# use yum on centos and redhat
|
||||
if [ -e /etc/fedora-release ]
|
||||
then
|
||||
command -v dnf
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
useCompatSsl=0
|
||||
grep -i 'fedora release 28' /etc/fedora-release
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
useCompatSsl=1
|
||||
else
|
||||
grep -i 'fedora release 27' /etc/fedora-release
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
useCompatSsl=1
|
||||
else
|
||||
grep -i 'fedora release 26' /etc/fedora-release
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
useCompatSsl=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $useCompatSsl -eq 1 ]
|
||||
then
|
||||
echo "Use compat-openssl10-devel instead of openssl-devel for Fedora 27/28 (dotnet core requires openssl 1.0.x)"
|
||||
dnf install -y compat-openssl10
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'dnf' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
dnf install -y openssl-libs
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'dnf' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
dnf install -y lttng-ust libcurl krb5-libs zlib libicu
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'dnf' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Can not find 'dnf'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
command -v yum
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
yum install -y openssl-libs libcurl krb5-libs zlib libicu
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'yum' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# install lttng-ust separately since it's not part of offical package repository
|
||||
yum install -y wget && wget -P /etc/yum.repos.d/ https://packages.efficios.com/repo.files/EfficiOS-RHEL7-x86-64.repo && rpmkeys --import https://packages.efficios.com/rhel/repo.key && yum updateinfo && yum install -y lttng-ust
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'lttng-ust' installation failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Can not find 'yum'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# we might on OpenSUSE
|
||||
OSTYPE=$(grep ID_LIKE /etc/os-release | cut -f2 -d=)
|
||||
echo $OSTYPE
|
||||
if [ $OSTYPE == '"suse"' ]
|
||||
then
|
||||
echo "The current OS is SUSE based"
|
||||
command -v zypper
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
zypper -n install lttng-ust libopenssl1_0_0 libcurl4 krb5 zlib libicu52_1
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'zypper' failed with exit code '$?'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Can not find 'zypper'"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Can't detect current OS type based on /etc/os-release."
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
elif [ -e /etc/redhat-release ]
|
||||
# RHEL6 doesn't have an os-release file defined, read redhat-release instead
|
||||
then
|
||||
redhatRelease=$(</etc/redhat-release)
|
||||
if [[ $redhatRelease == "CentOS release 6."* || $redhatRelease == "Red Hat Enterprise Linux Server release 6."* ]]
|
||||
then
|
||||
echo "The current OS is Red Hat Enterprise Linux 6 or Centos 6"
|
||||
|
||||
# Install known dependencies, as a best effort.
|
||||
# The remaining dependencies are covered by the GitHub doc that will be shown by `print_rhel6message`
|
||||
command -v yum
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
yum install -y openssl krb5-libs zlib
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "'yum' failed with exit code '$?'"
|
||||
print_rhel6errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Can not find 'yum'"
|
||||
print_rhel6errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_rhel6message
|
||||
exit 1
|
||||
else
|
||||
echo "Unknown RHEL OS version"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Unknown OS version"
|
||||
print_errormessage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "-----------------------------"
|
||||
echo " Finish Install Dependencies"
|
||||
echo "-----------------------------"
|
||||
20
src/Misc/layoutbin/runsvc.sh
Executable file
20
src/Misc/layoutbin/runsvc.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# convert SIGTERM signal to SIGINT
|
||||
# for more info on how to propagate SIGTERM to a child process see: http://veithen.github.io/2014/11/16/sigterm-propagation.html
|
||||
trap 'kill -INT $PID' TERM INT
|
||||
|
||||
if [ -f ".path" ]; then
|
||||
# configure
|
||||
export PATH=`cat .path`
|
||||
echo ".path=${PATH}"
|
||||
fi
|
||||
|
||||
# insert anything to setup env when running as a service
|
||||
|
||||
# run the host process which keep the listener alive
|
||||
./externals/node12/bin/node ./bin/RunnerService.js &
|
||||
PID=$!
|
||||
wait $PID
|
||||
trap - TERM INT
|
||||
wait $PID
|
||||
143
src/Misc/layoutbin/systemd.svc.sh.template
Normal file
143
src/Misc/layoutbin/systemd.svc.sh.template
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/bin/bash
|
||||
|
||||
SVC_NAME="{{SvcNameVar}}"
|
||||
SVC_DESCRIPTION="{{SvcDescription}}"
|
||||
|
||||
SVC_CMD=$1
|
||||
arg_2=${2}
|
||||
|
||||
RUNNER_ROOT=`pwd`
|
||||
|
||||
UNIT_PATH=/etc/systemd/system/${SVC_NAME}
|
||||
TEMPLATE_PATH=./bin/actions.runner.service.template
|
||||
TEMP_PATH=./bin/actions.runner.service.temp
|
||||
CONFIG_PATH=.service
|
||||
|
||||
user_id=`id -u`
|
||||
|
||||
# systemctl must run as sudo
|
||||
# this script is a convenience wrapper around systemctl
|
||||
if [ $user_id -ne 0 ]; then
|
||||
echo "Must run as sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function failed()
|
||||
{
|
||||
local error=${1:-Undefined error}
|
||||
echo "Failed: $error" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ ! -f "${TEMPLATE_PATH}" ]; then
|
||||
failed "Must run from runner root or install is corrupt"
|
||||
fi
|
||||
|
||||
#check if we run as root
|
||||
if [[ $(id -u) != "0" ]]; then
|
||||
echo "Failed: This script requires to run with sudo." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function install()
|
||||
{
|
||||
echo "Creating launch runner in ${UNIT_PATH}"
|
||||
if [ -f "${UNIT_PATH}" ]; then
|
||||
failed "error: exists ${UNIT_PATH}"
|
||||
fi
|
||||
|
||||
if [ -f "${TEMP_PATH}" ]; then
|
||||
rm "${TEMP_PATH}" || failed "failed to delete ${TEMP_PATH}"
|
||||
fi
|
||||
|
||||
# can optionally use username supplied
|
||||
run_as_user=${arg_2:-$SUDO_USER}
|
||||
echo "Run as user: ${run_as_user}"
|
||||
|
||||
run_as_uid=$(id -u ${run_as_user}) || failed "User does not exist"
|
||||
echo "Run as uid: ${run_as_uid}"
|
||||
|
||||
run_as_gid=$(id -g ${run_as_user}) || failed "Group not available"
|
||||
echo "gid: ${run_as_gid}"
|
||||
|
||||
sed "s/{{User}}/${run_as_user}/g; s/{{Description}}/$(echo ${SVC_DESCRIPTION} | sed -e 's/[\/&]/\\&/g')/g; s/{{RunnerRoot}}/$(echo ${RUNNER_ROOT} | sed -e 's/[\/&]/\\&/g')/g;" "${TEMPLATE_PATH}" > "${TEMP_PATH}" || failed "failed to create replacement temp file"
|
||||
mv "${TEMP_PATH}" "${UNIT_PATH}" || failed "failed to copy unit file"
|
||||
|
||||
# unit file should not be executable and world writable
|
||||
chmod 664 ${UNIT_PATH} || failed "failed to set permissions on ${UNIT_PATH}"
|
||||
systemctl daemon-reload || failed "failed to reload daemons"
|
||||
|
||||
# Since we started with sudo, runsvc.sh will be owned by root. Change this to current login user.
|
||||
cp ./bin/runsvc.sh ./runsvc.sh || failed "failed to copy runsvc.sh"
|
||||
chown ${run_as_uid}:${run_as_gid} ./runsvc.sh || failed "failed to set owner for runsvc.sh"
|
||||
chmod 755 ./runsvc.sh || failed "failed to set permission for runsvc.sh"
|
||||
|
||||
systemctl enable ${SVC_NAME} || failed "failed to enable ${SVC_NAME}"
|
||||
|
||||
echo "${SVC_NAME}" > ${CONFIG_PATH} || failed "failed to create .service file"
|
||||
chown ${run_as_uid}:${run_as_gid} ${CONFIG_PATH} || failed "failed to set permission for ${CONFIG_PATH}"
|
||||
}
|
||||
|
||||
function start()
|
||||
{
|
||||
systemctl start ${SVC_NAME} || failed "failed to start ${SVC_NAME}"
|
||||
status
|
||||
}
|
||||
|
||||
function stop()
|
||||
{
|
||||
systemctl stop ${SVC_NAME} || failed "failed to stop ${SVC_NAME}"
|
||||
status
|
||||
}
|
||||
|
||||
function uninstall()
|
||||
{
|
||||
stop
|
||||
systemctl disable ${SVC_NAME} || failed "failed to disable ${SVC_NAME}"
|
||||
rm "${UNIT_PATH}" || failed "failed to delete ${UNIT_PATH}"
|
||||
if [ -f "${CONFIG_PATH}" ]; then
|
||||
rm "${CONFIG_PATH}" || failed "failed to delete ${CONFIG_PATH}"
|
||||
fi
|
||||
systemctl daemon-reload || failed "failed to reload daemons"
|
||||
}
|
||||
|
||||
function status()
|
||||
{
|
||||
if [ -f "${UNIT_PATH}" ]; then
|
||||
echo
|
||||
echo "${UNIT_PATH}"
|
||||
else
|
||||
echo
|
||||
echo "not installed"
|
||||
echo
|
||||
return
|
||||
fi
|
||||
|
||||
systemctl --no-pager status ${SVC_NAME}
|
||||
}
|
||||
|
||||
function usage()
|
||||
{
|
||||
echo
|
||||
echo Usage:
|
||||
echo "./svc.sh [install, start, stop, status, uninstall]"
|
||||
echo "Commands:"
|
||||
echo " install [user]: Install runner service as Root or specified user."
|
||||
echo " start: Manually start the runner service."
|
||||
echo " stop: Manually stop the runner service."
|
||||
echo " status: Display status of runner service."
|
||||
echo " uninstall: Uninstall runner service."
|
||||
echo
|
||||
}
|
||||
|
||||
case $SVC_CMD in
|
||||
"install") install;;
|
||||
"status") status;;
|
||||
"uninstall") uninstall;;
|
||||
"start") start;;
|
||||
"stop") stop;;
|
||||
"status") status;;
|
||||
*) usage;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
143
src/Misc/layoutbin/update.cmd.template
Normal file
143
src/Misc/layoutbin/update.cmd.template
Normal file
@@ -0,0 +1,143 @@
|
||||
@echo off
|
||||
|
||||
rem runner will replace key words in the template and generate a batch script to run.
|
||||
rem Keywords:
|
||||
rem PROCESSID = pid
|
||||
rem RUNNERPROCESSNAME = Runner.Listener[.exe]
|
||||
rem ROOTFOLDER = ./
|
||||
rem EXISTRUNNERVERSION = 2.100.0
|
||||
rem DOWNLOADRUNNERVERSION = 2.101.0
|
||||
rem UPDATELOG = _diag/SelfUpdate-UTC.log
|
||||
rem RESTARTINTERACTIVERUNNER = 0/1
|
||||
|
||||
setlocal
|
||||
set runnerpid=_PROCESS_ID_
|
||||
set runnerprocessname=_RUNNER_PROCESS_NAME_
|
||||
set rootfolder=_ROOT_FOLDER_
|
||||
set existrunnerversion=_EXIST_RUNNER_VERSION_
|
||||
set downloadrunnerversion=_DOWNLOAD_RUNNER_VERSION_
|
||||
set logfile=_UPDATE_LOG_
|
||||
set restartinteractiverunner=_RESTART_INTERACTIVE_RUNNER_
|
||||
|
||||
rem log user who run the script
|
||||
echo [%date% %time%] --------whoami-------- >> "%logfile%" 2>&1
|
||||
whoami >> "%logfile%" 2>&1
|
||||
echo [%date% %time%] --------whoami-------- >> "%logfile%" 2>&1
|
||||
|
||||
rem wait for runner process to exit.
|
||||
echo [%date% %time%] Waiting for %runnerprocessname% (%runnerpid%) to complete >> "%logfile%" 2>&1
|
||||
:loop
|
||||
tasklist /fi "pid eq %runnerpid%" | find /I "%runnerprocessname%" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
goto copy
|
||||
)
|
||||
|
||||
echo [%date% %time%] Process %runnerpid% still running, check again after 1 second. >> "%logfile%" 2>&1
|
||||
ping -n 2 127.0.0.1 >nul
|
||||
goto loop
|
||||
|
||||
rem start re-organize folders
|
||||
:copy
|
||||
echo [%date% %time%] Process %runnerpid% finished running >> "%logfile%" 2>&1
|
||||
echo [%date% %time%] Sleep 1 more second to make sure process exited >> "%logfile%" 2>&1
|
||||
ping -n 2 127.0.0.1 >nul
|
||||
echo [%date% %time%] Re-organize folders >> "%logfile%" 2>&1
|
||||
|
||||
rem the folder structure under runner root will be
|
||||
rem ./bin -> bin.2.100.0 (junction folder)
|
||||
rem ./externals -> externals.2.100.0 (junction folder)
|
||||
rem ./bin.2.100.0
|
||||
rem ./externals.2.100.0
|
||||
rem ./bin.2.99.0
|
||||
rem ./externals.2.99.0
|
||||
rem by using the juction folder we can avoid file in use problem.
|
||||
|
||||
rem if the bin/externals junction point already exist, we just need to delete the juction point then re-create to point to new bin/externals folder.
|
||||
rem if the bin/externals still are real folders, we need to rename the existing folder to bin.version format then create junction point to new bin/externals folder.
|
||||
|
||||
rem check bin folder
|
||||
rem we do findstr /C:" bin" since in migration mode, we create a junction folder from runner to bin.
|
||||
rem as result, dir /AL | findstr "bin" will return the runner folder. output looks like (07/27/2016 05:21 PM <JUNCTION> runner [E:\bin])
|
||||
dir "%rootfolder%" /AL 2>&1 | findstr /C:" bin" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
rem return code 1 means it can't find a bin folder that is a junction folder
|
||||
rem so we need to move the current bin folder to bin.2.99.0 folder.
|
||||
echo [%date% %time%] move "%rootfolder%\bin" "%rootfolder%\bin.%existrunnerversion%" >> "%logfile%" 2>&1
|
||||
move "%rootfolder%\bin" "%rootfolder%\bin.%existrunnerversion%" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo [%date% %time%] Can't move "%rootfolder%\bin" to "%rootfolder%\bin.%existrunnerversion%" >> "%logfile%" 2>&1
|
||||
goto fail
|
||||
)
|
||||
|
||||
) else (
|
||||
rem otherwise it find a bin folder that is a junction folder
|
||||
rem we just need to delete the junction point.
|
||||
echo [%date% %time%] Delete existing junction bin folder >> "%logfile%" 2>&1
|
||||
rmdir "%rootfolder%\bin" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo [%date% %time%] Can't delete existing junction bin folder >> "%logfile%" 2>&1
|
||||
goto fail
|
||||
)
|
||||
)
|
||||
|
||||
rem check externals folder
|
||||
dir "%rootfolder%" /AL 2>&1 | findstr "externals" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
rem return code 1 means it can't find a externals folder that is a junction folder
|
||||
rem so we need to move the current externals folder to externals.2.99.0 folder.
|
||||
echo [%date% %time%] move "%rootfolder%\externals" "%rootfolder%\externals.%existrunnerversion%" >> "%logfile%" 2>&1
|
||||
move "%rootfolder%\externals" "%rootfolder%\externals.%existrunnerversion%" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo [%date% %time%] Can't move "%rootfolder%\externals" to "%rootfolder%\externals.%existrunnerversion%" >> "%logfile%" 2>&1
|
||||
goto fail
|
||||
)
|
||||
) else (
|
||||
rem otherwise it find a externals folder that is a junction folder
|
||||
rem we just need to delete the junction point.
|
||||
echo [%date% %time%] Delete existing junction externals folder >> "%logfile%" 2>&1
|
||||
rmdir "%rootfolder%\externals" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo [%date% %time%] Can't delete existing junction externals folder >> "%logfile%" 2>&1
|
||||
goto fail
|
||||
)
|
||||
)
|
||||
|
||||
rem create junction bin folder
|
||||
echo [%date% %time%] Create junction bin folder >> "%logfile%" 2>&1
|
||||
mklink /J "%rootfolder%\bin" "%rootfolder%\bin.%downloadrunnerversion%" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo [%date% %time%] Can't create junction bin folder >> "%logfile%" 2>&1
|
||||
goto fail
|
||||
)
|
||||
|
||||
rem create junction externals folder
|
||||
echo [%date% %time%] Create junction externals folder >> "%logfile%" 2>&1
|
||||
mklink /J "%rootfolder%\externals" "%rootfolder%\externals.%downloadrunnerversion%" >> "%logfile%" 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo [%date% %time%] Can't create junction externals folder >> "%logfile%" 2>&1
|
||||
goto fail
|
||||
)
|
||||
|
||||
echo [%date% %time%] Update succeed >> "%logfile%" 2>&1
|
||||
|
||||
rem rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
|
||||
rem runner service host can base on the log file name determin the result of the runner update
|
||||
echo [%date% %time%] Rename "%logfile%" to be "%logfile%.succeed" >> "%logfile%" 2>&1
|
||||
move "%logfile%" "%logfile%.succeed" >nul
|
||||
|
||||
rem restart interactive runner if needed
|
||||
if %restartinteractiverunner% equ 1 (
|
||||
echo [%date% %time%] Restart interactive runner >> "%logfile%.succeed" 2>&1
|
||||
endlocal
|
||||
start "Actions Runner" cmd.exe /k "_ROOT_FOLDER_\run.cmd"
|
||||
) else (
|
||||
endlocal
|
||||
)
|
||||
|
||||
goto :eof
|
||||
|
||||
:fail
|
||||
echo [%date% %time%] Rename "%logfile%" to be "%logfile%.failed" >> "%logfile%" 2>&1
|
||||
move "%logfile%" "%logfile%.failed" >nul
|
||||
goto :eof
|
||||
|
||||
133
src/Misc/layoutbin/update.sh.template
Normal file
133
src/Misc/layoutbin/update.sh.template
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
|
||||
# runner will replace key words in the template and generate a batch script to run.
|
||||
# Keywords:
|
||||
# PROCESSID = pid
|
||||
# RUNNERPROCESSNAME = Runner.Listener[.exe]
|
||||
# ROOTFOLDER = ./
|
||||
# EXISTRUNNERVERSION = 2.100.0
|
||||
# DOWNLOADRUNNERVERSION = 2.101.0
|
||||
# UPDATELOG = _diag/SelfUpdate-UTC.log
|
||||
# RESTARTINTERACTIVERUNNER = 0/1
|
||||
|
||||
runnerpid=_PROCESS_ID_
|
||||
runnerprocessname=_RUNNER_PROCESS_NAME_
|
||||
rootfolder="_ROOT_FOLDER_"
|
||||
existrunnerversion=_EXIST_RUNNER_VERSION_
|
||||
downloadrunnerversion=_DOWNLOAD_RUNNER_VERSION_
|
||||
logfile="_UPDATE_LOG_"
|
||||
restartinteractiverunner=_RESTART_INTERACTIVE_RUNNER_
|
||||
|
||||
# log user who run the script
|
||||
date "+[%F %T-%4N] --------whoami--------" >> "$logfile" 2>&1
|
||||
whoami >> "$logfile" 2>&1
|
||||
date "+[%F %T-%4N] --------whoami--------" >> "$logfile" 2>&1
|
||||
|
||||
# wait for runner process to exit.
|
||||
date "+[%F %T-%4N] Waiting for $runnerprocessname ($runnerpid) to complete" >> "$logfile" 2>&1
|
||||
while [ -e /proc/$runnerpid ]
|
||||
do
|
||||
date "+[%F %T-%4N] Process $runnerpid still running" >> "$logfile" 2>&1
|
||||
ping -c 2 127.0.0.1 >nul
|
||||
done
|
||||
date "+[%F %T-%4N] Process $runnerpid finished running" >> "$logfile" 2>&1
|
||||
|
||||
# start re-organize folders
|
||||
date "+[%F %T-%4N] Sleep 1 more second to make sure process exited" >> "$logfile" 2>&1
|
||||
ping -c 2 127.0.0.1 >nul
|
||||
|
||||
# the folder structure under runner root will be
|
||||
# ./bin -> bin.2.100.0 (junction folder)
|
||||
# ./externals -> externals.2.100.0 (junction folder)
|
||||
# ./bin.2.100.0
|
||||
# ./externals.2.100.0
|
||||
# ./bin.2.99.0
|
||||
# ./externals.2.99.0
|
||||
# by using the juction folder we can avoid file in use problem.
|
||||
|
||||
# if the bin/externals junction point already exist, we just need to delete the juction point then re-create to point to new bin/externals folder.
|
||||
# if the bin/externals still are real folders, we need to rename the existing folder to bin.version format then create junction point to new bin/externals folder.
|
||||
|
||||
# check bin folder
|
||||
if [[ -L "$rootfolder/bin" && -d "$rootfolder/bin" ]]
|
||||
then
|
||||
# return code 0 means it find a bin folder that is a junction folder
|
||||
# we just need to delete the junction point.
|
||||
date "+[%F %T-%4N] Delete existing junction bin folder" >> "$logfile"
|
||||
rm "$rootfolder/bin" >> "$logfile"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
date "+[%F %T-%4N] Can't delete existing junction bin folder" >> "$logfile"
|
||||
mv -fv "$logfile" "$logfile.failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# otherwise, we need to move the current bin folder to bin.2.99.0 folder.
|
||||
date "+[%F %T-%4N] move $rootfolder/bin $rootfolder/bin.$existrunnerversion" >> "$logfile" 2>&1
|
||||
mv -fv "$rootfolder/bin" "$rootfolder/bin.$existrunnerversion" >> "$logfile" 2>&1
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
date "+[%F %T-%4N] Can't move $rootfolder/bin to $rootfolder/bin.$existrunnerversion" >> "$logfile" 2>&1
|
||||
mv -fv "$logfile" "$logfile.failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# check externals folder
|
||||
if [[ -L "$rootfolder/externals" && -d "$rootfolder/externals" ]]
|
||||
then
|
||||
# the externals folder is already a junction folder
|
||||
# we just need to delete the junction point.
|
||||
date "+[%F %T-%4N] Delete existing junction externals folder" >> "$logfile"
|
||||
rm "$rootfolder/externals" >> "$logfile"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
date "+[%F %T-%4N] Can't delete existing junction externals folder" >> "$logfile"
|
||||
mv -fv "$logfile" "$logfile.failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# otherwise, we need to move the current externals folder to externals.2.99.0 folder.
|
||||
date "+[%F %T-%4N] move $rootfolder/externals $rootfolder/externals.$existrunnerversion" >> "$logfile" 2>&1
|
||||
mv -fv "$rootfolder/externals" "$rootfolder/externals.$existrunnerversion" >> "$logfile" 2>&1
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
date "+[%F %T-%4N] Can't move $rootfolder/externals to $rootfolder/externals.$existrunnerversion" >> "$logfile" 2>&1
|
||||
mv -fv "$logfile" "$logfile.failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# create junction bin folder
|
||||
date "+[%F %T-%4N] Create junction bin folder" >> "$logfile" 2>&1
|
||||
ln -s "$rootfolder/bin.$downloadrunnerversion" "$rootfolder/bin" >> "$logfile" 2>&1
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
date "+[%F %T-%4N] Can't create junction bin folder" >> "$logfile" 2>&1
|
||||
mv -fv "$logfile" "$logfile.failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# create junction externals folder
|
||||
date "+[%F %T-%4N] Create junction externals folder" >> "$logfile" 2>&1
|
||||
ln -s "$rootfolder/externals.$downloadrunnerversion" "$rootfolder/externals" >> "$logfile" 2>&1
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
date "+[%F %T-%4N] Can't create junction externals folder" >> "$logfile" 2>&1
|
||||
mv -fv "$logfile" "$logfile.failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
date "+[%F %T-%4N] Update succeed" >> "$logfile"
|
||||
|
||||
# rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
|
||||
# runner service host can base on the log file name determin the result of the runner update
|
||||
date "+[%F %T-%4N] Rename $logfile to be $logfile.succeed" >> "$logfile" 2>&1
|
||||
mv -fv "$logfile" "$logfile.succeed" >> "$logfile" 2>&1
|
||||
|
||||
# restart interactive runner if needed
|
||||
if [ $restartinteractiverunner -ne 0 ]
|
||||
then
|
||||
date "+[%F %T-%4N] Restarting interactive runner" >> "$logfile.succeed" 2>&1
|
||||
"$rootfolder/run.sh" &
|
||||
fi
|
||||
26
src/Misc/layoutroot/config.cmd
Normal file
26
src/Misc/layoutroot/config.cmd
Normal file
@@ -0,0 +1,26 @@
|
||||
@echo off
|
||||
|
||||
rem ********************************************************************************
|
||||
rem Unblock specific files.
|
||||
rem ********************************************************************************
|
||||
setlocal
|
||||
if defined VERBOSE_ARG (
|
||||
set VERBOSE_ARG='Continue'
|
||||
) else (
|
||||
set VERBOSE_ARG='SilentlyContinue'
|
||||
)
|
||||
|
||||
rem Unblock files in the root of the layout folder. E.g. .cmd files.
|
||||
powershell.exe -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "$VerbosePreference = %VERBOSE_ARG% ; Get-ChildItem -LiteralPath '%~dp0' | ForEach-Object { Write-Verbose ('Unblock: {0}' -f $_.FullName) ; $_ } | Unblock-File | Out-Null"
|
||||
|
||||
if /i "%~1" equ "remove" (
|
||||
rem ********************************************************************************
|
||||
rem Unconfigure the runner.
|
||||
rem ********************************************************************************
|
||||
"%~dp0bin\Runner.Listener.exe" %*
|
||||
) else (
|
||||
rem ********************************************************************************
|
||||
rem Configure the runner.
|
||||
rem ********************************************************************************
|
||||
"%~dp0bin\Runner.Listener.exe" configure %*
|
||||
)
|
||||
86
src/Misc/layoutroot/config.sh
Executable file
86
src/Misc/layoutroot/config.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
|
||||
user_id=`id -u`
|
||||
|
||||
# we want to snapshot the environment of the config user
|
||||
if [ $user_id -eq 0 -a -z "$AGENT_ALLOW_RUNASROOT" ]; then
|
||||
echo "Must not run with sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check dotnet core 2.1 dependencies for Linux
|
||||
if [[ (`uname` == "Linux") ]]
|
||||
then
|
||||
command -v ldd > /dev/null
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "Can not find 'ldd'. Please install 'ldd' and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ldd ./bin/libcoreclr.so | grep 'not found'
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Dependencies is missing for Dotnet Core 2.1"
|
||||
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 2.1 dependencies."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ldd ./bin/System.Security.Cryptography.Native.OpenSsl.so | grep 'not found'
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Dependencies is missing for Dotnet Core 2.1"
|
||||
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 2.1 dependencies."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ldd ./bin/System.IO.Compression.Native.so | grep 'not found'
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Dependencies is missing for Dotnet Core 2.1"
|
||||
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 2.1 dependencies."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ldd ./bin/System.Net.Http.Native.so | grep 'not found'
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Dependencies is missing for Dotnet Core 2.1"
|
||||
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 2.1 dependencies."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -x "$(command -v ldconfig)" ]; then
|
||||
LDCONFIG_COMMAND="/sbin/ldconfig"
|
||||
if ! [ -x "$LDCONFIG_COMMAND" ]; then
|
||||
echo "Can not find 'ldconfig' in PATH and '/sbin/ldconfig' doesn't exists either. Please install 'ldconfig' and try again."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
LDCONFIG_COMMAND="ldconfig"
|
||||
fi
|
||||
|
||||
libpath=${LD_LIBRARY_PATH:-}
|
||||
$LDCONFIG_COMMAND -NXv ${libpath//:/} 2>&1 | grep libicu >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Libicu's dependencies is missing for Dotnet Core 2.1"
|
||||
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 2.1 dependencies."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Change directory to the script root directory
|
||||
# https://stackoverflow.com/questions/59895/getting-the-source-directory-of-a-bash-script-from-within
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
cd $DIR
|
||||
|
||||
source ./env.sh
|
||||
|
||||
shopt -s nocasematch
|
||||
if [[ "$1" == "remove" ]]; then
|
||||
./bin/Runner.Listener "$@"
|
||||
else
|
||||
./bin/Runner.Listener configure "$@"
|
||||
fi
|
||||
44
src/Misc/layoutroot/env.sh
Executable file
44
src/Misc/layoutroot/env.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
varCheckList=(
|
||||
'LANG'
|
||||
'JAVA_HOME'
|
||||
'ANT_HOME'
|
||||
'M2_HOME'
|
||||
'ANDROID_HOME'
|
||||
'GRADLE_HOME'
|
||||
'NVM_BIN'
|
||||
'NVM_PATH'
|
||||
'VSTS_HTTP_PROXY'
|
||||
'VSTS_HTTP_PROXY_USERNAME'
|
||||
'VSTS_HTTP_PROXY_PASSWORD'
|
||||
'LD_LIBRARY_PATH'
|
||||
'PERL5LIB'
|
||||
)
|
||||
|
||||
envContents=""
|
||||
|
||||
if [ -f ".env" ]; then
|
||||
envContents=`cat .env`
|
||||
else
|
||||
touch .env
|
||||
fi
|
||||
|
||||
function writeVar()
|
||||
{
|
||||
checkVar="$1"
|
||||
checkDelim="${1}="
|
||||
if test "${envContents#*$checkDelim}" = "$envContents"
|
||||
then
|
||||
if [ ! -z "${!checkVar}" ]; then
|
||||
echo "${checkVar}=${!checkVar}">>.env
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
echo $PATH>.path
|
||||
|
||||
for var_name in ${varCheckList[@]}
|
||||
do
|
||||
writeVar "${var_name}"
|
||||
done
|
||||
33
src/Misc/layoutroot/run.cmd
Normal file
33
src/Misc/layoutroot/run.cmd
Normal file
@@ -0,0 +1,33 @@
|
||||
@echo off
|
||||
|
||||
rem ********************************************************************************
|
||||
rem Unblock specific files.
|
||||
rem ********************************************************************************
|
||||
setlocal
|
||||
if defined VERBOSE_ARG (
|
||||
set VERBOSE_ARG='Continue'
|
||||
) else (
|
||||
set VERBOSE_ARG='SilentlyContinue'
|
||||
)
|
||||
|
||||
rem Unblock files in the root of the layout folder. E.g. .cmd files.
|
||||
powershell.exe -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "$VerbosePreference = %VERBOSE_ARG% ; Get-ChildItem -LiteralPath '%~dp0' | ForEach-Object { Write-Verbose ('Unblock: {0}' -f $_.FullName) ; $_ } | Unblock-File | Out-Null"
|
||||
|
||||
if /i "%~1" equ "localRun" (
|
||||
rem ********************************************************************************
|
||||
rem Local run.
|
||||
rem ********************************************************************************
|
||||
"%~dp0bin\Runner.Listener.exe" %*
|
||||
) else (
|
||||
rem ********************************************************************************
|
||||
rem Run.
|
||||
rem ********************************************************************************
|
||||
"%~dp0bin\Runner.Listener.exe" run %*
|
||||
|
||||
rem Return code 4 means the run once runner received an update message.
|
||||
rem Sleep 5 seconds to wait for the update process finish and run the runner again.
|
||||
if ERRORLEVEL 4 (
|
||||
timeout /t 5 /nobreak > NUL
|
||||
"%~dp0bin\Runner.Listener.exe" run %*
|
||||
)
|
||||
)
|
||||
51
src/Misc/layoutroot/run.sh
Executable file
51
src/Misc/layoutroot/run.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Validate not sudo
|
||||
user_id=`id -u`
|
||||
if [ $user_id -eq 0 -a -z "$AGENT_ALLOW_RUNASROOT" ]; then
|
||||
echo "Must not run interactively with sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Change directory to the script root directory
|
||||
# https://stackoverflow.com/questions/59895/getting-the-source-directory-of-a-bash-script-from-within
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
# Do not "cd $DIR". For localRun, the current directory is expected to be the repo location on disk.
|
||||
|
||||
# Run
|
||||
shopt -s nocasematch
|
||||
if [[ "$1" == "localRun" ]]; then
|
||||
"$DIR"/bin/Runner.Listener $*
|
||||
else
|
||||
"$DIR"/bin/Runner.Listener run $*
|
||||
|
||||
# Return code 4 means the run once agent received an update message.
|
||||
# Sleep 5 seconds to wait for the update process finish and run the agent again.
|
||||
returnCode=$?
|
||||
if [[ $returnCode == 4 ]]; then
|
||||
if [ ! -x "$(command -v sleep)" ]; then
|
||||
if [ ! -x "$(command -v ping)" ]; then
|
||||
COUNT="0"
|
||||
while [[ $COUNT != 5000 ]]; do
|
||||
echo "SLEEP" >nul
|
||||
COUNT=$[$COUNT+1]
|
||||
done
|
||||
else
|
||||
ping -n 5 127.0.0.1 >nul
|
||||
fi
|
||||
else
|
||||
sleep 5 >nul
|
||||
fi
|
||||
|
||||
"$DIR"/bin/Runner.Listener run $*
|
||||
else
|
||||
exit $returnCode
|
||||
fi
|
||||
fi
|
||||
Reference in New Issue
Block a user