New: Multi target net framework 4.6.2 and net core 3.0

pull/1689/head
ta264 5 years ago committed by Qstick
parent d881b26261
commit 8fe924fdcd

6
.gitignore vendored

@ -127,6 +127,12 @@ coverage*.json
setup/Output/ setup/Output/
*.~is *.~is
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
#VS outout folders #VS outout folders
bin bin
obj obj

@ -11,11 +11,6 @@ variables:
minorVersion: $[counter('minorVersion', 1076)] minorVersion: $[counter('minorVersion', 1076)]
lidarrVersion: '$(majorVersion).$(minorVersion)' lidarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(lidarrVersion)' buildName: '$(Build.SourceBranchName).$(lidarrVersion)'
windowsInstaller: 'Lidarr.$(buildName).windows-installer.exe'
windowsZip: 'Lidarr.$(buildName).windows.zip'
macOsApp: 'Lidarr.$(buildName).osx-app.zip'
macOsTar: 'Lidarr.$(buildName).osx.tar.gz'
linuxTar: 'Lidarr.$(buildName).linux.tar.gz'
sentryOrg: 'lidarr' sentryOrg: 'lidarr'
dotnetVersion: '3.0.100' dotnetVersion: '3.0.100'
@ -44,7 +39,7 @@ stages:
imageName: 'macos-10.14' imageName: 'macos-10.14'
Windows: Windows:
osName: 'Windows' osName: 'Windows'
imageName: 'vs2017-win2016' imageName: 'windows-2019'
pool: pool:
vmImage: $(imageName) vmImage: $(imageName)
@ -59,6 +54,7 @@ stages:
displayName: 'Install .net core 3.0' displayName: 'Install .net core 3.0'
inputs: inputs:
version: $(dotnetVersion) version: $(dotnetVersion)
condition: ne(variables['osName'], 'Windows')
- bash: ./build.sh --backend - bash: ./build.sh --backend
displayName: Build Lidarr Backend displayName: Build Lidarr Backend
- bash: | - bash: |
@ -66,22 +62,25 @@ stages:
find ${OUTPUTFOLDER} -depth -empty -type d -exec rm -r "{}" \; find ${OUTPUTFOLDER} -depth -empty -type d -exec rm -r "{}" \;
find ${TESTSFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \; find ${TESTSFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \;
find ${TESTSFOLDER} -depth -empty -type d -exec rm -r "{}" \; find ${TESTSFOLDER} -depth -empty -type d -exec rm -r "{}" \;
ls -lR
displayName: Clean up intermediate output displayName: Clean up intermediate output
- publish: $(outputFolder) - publish: $(outputFolder)
artifact: '$(osName)Backend' artifact: '$(osName)Backend'
displayName: Publish Backend displayName: Publish Backend
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net462/win-x64/publish' - publish: '$(testsFolder)/netcoreapp3.0/win-x64/publish'
artifact: WindowsTests artifact: WindowsCoreTests
displayName: Publish Windows Test Package displayName: Publish Windows Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net462/linux-x64/publish' - publish: '$(testsFolder)/net462/linux-x64/publish'
artifact: LinuxTests artifact: LinuxTests
displayName: Publish Linux Test Package displayName: Publish Linux Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net462/osx-x64/publish' - publish: '$(testsFolder)/netcoreapp3.0/linux-x64/publish'
artifact: MacTests artifact: LinuxCoreTests
displayName: Publish Linux Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/netcoreapp3.0/osx-x64/publish'
artifact: MacCoreTests
displayName: Publish MacOS Test Package displayName: Publish MacOS Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
@ -101,7 +100,7 @@ stages:
imageName: 'macos-10.14' imageName: 'macos-10.14'
Windows: Windows:
osName: 'Windows' osName: 'Windows'
imageName: 'vs2017-win2016' imageName: 'windows-2019'
pool: pool:
vmImage: $(imageName) vmImage: $(imageName)
steps: steps:
@ -129,7 +128,7 @@ stages:
- job: Windows_Installer - job: Windows_Installer
displayName: Create Installer displayName: Create Installer
pool: pool:
vmImage: 'vs2017-win2016' vmImage: 'windows-2019'
steps: steps:
- checkout: self - checkout: self
fetchDepth: 1 fetchDepth: 1
@ -148,9 +147,9 @@ stages:
- bash: ./build.sh --packages - bash: ./build.sh --packages
displayName: Create Packages displayName: Create Packages
- bash: | - bash: |
./setup/inno/ISCC.exe "./setup/lidarr.iss" setup/inno/ISCC.exe setup/lidarr.iss //DFramework=netcoreapp3.0
cp ./setup/output/Lidarr.*windows.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/${WINDOWSINSTALLER} cp setup/output/Lidarr.*windows.netcoreapp3.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Lidarr.${BUILDNAME}.windows-core-x64-installer.exe
displayName: Create Windows installer displayName: Create .NET Core Windows installer
- publish: $(Build.ArtifactStagingDirectory) - publish: $(Build.ArtifactStagingDirectory)
artifact: 'WindowsInstaller' artifact: 'WindowsInstaller'
displayName: Publish Installer displayName: Publish Installer
@ -184,37 +183,62 @@ stages:
- bash: | - bash: |
find . -name "fpcalc" -exec chmod a+x {} \; find . -name "fpcalc" -exec chmod a+x {} \;
find . -name "Lidarr" -exec chmod a+x {} \; find . -name "Lidarr" -exec chmod a+x {} \;
displayName: Set Mac executable bits find . -name "Lidarr.Update" -exec chmod a+x {} \;
displayName: Set executable bits
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create Windows zip displayName: Create Windows Core zip
inputs: inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/$(windowsZip)' archiveFile: '$(Build.ArtifactStagingDirectory)/Lidarr.$(buildName).windows-core-x64.zip'
archiveType: 'zip' archiveType: 'zip'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/windows/net462 rootFolderOrFile: $(artifactsFolder)/windows/netcoreapp3.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create MacOS app displayName: Create MacOS Core app
inputs: inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/$(macOsApp)' archiveFile: '$(Build.ArtifactStagingDirectory)/Lidarr.$(buildName).osx-app-core-x64.zip'
archiveType: 'zip' archiveType: 'zip'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/macos-app/net462 rootFolderOrFile: $(artifactsFolder)/macos-app/netcoreapp3.0
- task: ArchiveFiles@2
displayName: Create MacOS Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Lidarr.$(buildName).osx-core-x64.tar.gz'
archiveType: 'tar'
tarCompression: 'gz'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/macos/netcoreapp3.0
- task: ArchiveFiles@2
displayName: Create Linux Mono tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Lidarr.$(buildName).linux.tar.gz'
archiveType: 'tar'
tarCompression: 'gz'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-x64/net462
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create MacOS tar displayName: Create Linux Core tar
inputs: inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/$(macOsTar)' archiveFile: '$(Build.ArtifactStagingDirectory)/Lidarr.$(buildName).linux-core-x64.tar.gz'
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/macos/net462 rootFolderOrFile: $(artifactsFolder)/linux-x64/netcoreapp3.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create Linux tar displayName: Create ARM32 Core tar
inputs: inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/$(linuxTar)' archiveFile: '$(Build.ArtifactStagingDirectory)/Lidarr.$(buildName).linux-core-arm.tar.gz'
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux/net462 rootFolderOrFile: $(artifactsFolder)/linux-arm/netcoreapp3.0
- task: ArchiveFiles@2
displayName: Create Linux Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Lidarr.$(buildName).linux-core-arm64.tar.gz'
archiveType: 'tar'
tarCompression: 'gz'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-arm64/netcoreapp3.0
- publish: $(Build.ArtifactStagingDirectory) - publish: $(Build.ArtifactStagingDirectory)
artifact: 'Packages' artifact: 'Packages'
displayName: Publish Packages displayName: Publish Packages
@ -250,9 +274,19 @@ stages:
displayName: Unit Native displayName: Unit Native
strategy: strategy:
matrix: matrix:
Windows: MacCore:
osName: 'Mac'
testName: 'MacCore'
imageName: 'macos-10.13'
WindowsCore:
osName: 'Windows' osName: 'Windows'
imageName: 'vs2017-win2016' testName: 'WindowsCore'
imageName: 'windows-2019'
LinuxCore:
osName: 'Linux'
testName: 'LinuxCore'
imageName: 'ubuntu-16.04'
pattern: 'Lidarr.**.linux-core-x64.tar.gz'
pool: pool:
vmImage: $(imageName) vmImage: $(imageName)
@ -263,15 +297,21 @@ stages:
displayName: 'Install .net core 3.0' displayName: 'Install .net core 3.0'
inputs: inputs:
version: $(dotnetVersion) version: $(dotnetVersion)
condition: ne(variables['osName'], 'Windows')
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Test Artifact displayName: Download Test Artifact
inputs: inputs:
buildType: 'current' buildType: 'current'
artifactName: '$(osName)Tests' artifactName: '$(testName)Tests'
targetPath: $(testsFolder) targetPath: $(testsFolder)
- powershell: Set-Service SCardSvr -StartupType Manual - powershell: Set-Service SCardSvr -StartupType Manual
displayName: Enable Windows Test Service displayName: Enable Windows Test Service
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- bash: |
wget https://github.com/acoustid/chromaprint/releases/download/v1.4.3/chromaprint-fpcalc-1.4.3-linux-x86_64.tar.gz
sudo tar xf chromaprint-fpcalc-1.4.3-linux-x86_64.tar.gz --strip-components=1 --directory /usr/bin
displayName: Install fpcalc
condition: and(succeeded(), eq(variables['osName'], 'Linux'))
- bash: | - bash: |
SYMLINK=5_18_1 SYMLINK=5_18_1
MONOPREFIX=/Library/Frameworks/Mono.framework/Versions/$SYMLINK MONOPREFIX=/Library/Frameworks/Mono.framework/Versions/$SYMLINK
@ -296,7 +336,7 @@ stages:
inputs: inputs:
testResultsFormat: 'NUnit' testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(osName) Unit Tests' testRunTitle: '$(testName) Unit Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
- job: Unit_Docker - job: Unit_Docker
@ -314,7 +354,10 @@ stages:
containerImage: servarr/testimages:mono-6.10 containerImage: servarr/testimages:mono-6.10
mono604: mono604:
testName: 'Mono 6.4' testName: 'Mono 6.4'
containerImage: servarr/testimages:mono-6.12 containerImage: lidarr/testimages:mono-6.4
mono606:
testName: 'Mono 6.6'
containerImage: lidarr/testimages:mono-6.6
pool: pool:
vmImage: 'ubuntu-16.04' vmImage: 'ubuntu-16.04'
@ -326,12 +369,17 @@ stages:
steps: steps:
- bash: mono --version - bash: mono --version
displayName: Check Mono version displayName: Check Mono version
- task: UseDotNet@2
displayName: 'Install .net core 3.0'
inputs:
version: $(dotnetVersion)
condition: ne(variables['osName'], 'Windows')
- checkout: none - checkout: none
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Test Artifact displayName: Download Test Artifact
inputs: inputs:
buildType: 'current' buildType: 'current'
artifactName: WindowsTests artifactName: LinuxTests
targetPath: $(testsFolder) targetPath: $(testsFolder)
- task: Bash@3 - task: Bash@3
displayName: Run Tests displayName: Run Tests
@ -356,10 +404,21 @@ stages:
displayName: Integration Native displayName: Integration Native
strategy: strategy:
matrix: matrix:
Windows: MacCore:
osName: 'Mac'
testName: 'MacCore'
imageName: 'macos-10.13'
pattern: 'Lidarr.**.osx-core-x64.tar.gz'
WindowsCore:
osName: 'Windows' osName: 'Windows'
imageName: 'vs2017-win2016' testName: 'WindowsCore'
pattern: 'Lidarr.**.windows.zip' imageName: 'windows-2019'
pattern: 'Lidarr.**.windows-core-x64.zip'
LinuxCore:
osName: 'Linux'
testName: 'LinuxCore'
imageName: 'ubuntu-16.04'
pattern: 'Lidarr.**.linux-core-x64.tar.gz'
pool: pool:
vmImage: $(imageName) vmImage: $(imageName)
@ -377,12 +436,13 @@ stages:
displayName: 'Install .net core 3.0' displayName: 'Install .net core 3.0'
inputs: inputs:
version: $(dotnetVersion) version: $(dotnetVersion)
condition: ne(variables['osName'], 'Windows')
- checkout: none - checkout: none
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Test Artifact displayName: Download Test Artifact
inputs: inputs:
buildType: 'current' buildType: 'current'
artifactName: '$(osName)Tests' artifactName: '$(testName)Tests'
targetPath: $(testsFolder) targetPath: $(testsFolder)
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Build Artifact displayName: Download Build Artifact
@ -410,7 +470,7 @@ stages:
inputs: inputs:
testResultsFormat: 'NUnit' testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(osName) Integration Tests' testRunTitle: '$(testName) Integration Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
displayName: Publish Test Results displayName: Publish Test Results
@ -429,7 +489,10 @@ stages:
containerImage: servarr/testimages:mono-6.10 containerImage: servarr/testimages:mono-6.10
mono604: mono604:
testName: 'Mono 6.4' testName: 'Mono 6.4'
containerImage: servarr/testimages:mono-6.12 containerImage: lidarr/testimages:mono-6.4
mono606:
testName: 'Mono 6.6'
containerImage: lidarr/testimages:mono-6.6
variables: variables:
pattern: 'Lidarr.**.linux.tar.gz' pattern: 'Lidarr.**.linux.tar.gz'
@ -444,12 +507,17 @@ stages:
steps: steps:
- bash: mono --version - bash: mono --version
displayName: Check Mono version displayName: Check Mono version
- task: UseDotNet@2
displayName: 'Install .net core 3.0'
inputs:
version: $(dotnetVersion)
condition: ne(variables['osName'], 'Windows')
- checkout: none - checkout: none
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Test Artifact displayName: Download Test Artifact
inputs: inputs:
buildType: 'current' buildType: 'current'
artifactName: WindowsTests artifactName: LinuxTests
targetPath: $(testsFolder) targetPath: $(testsFolder)
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Build Artifact displayName: Download Build Artifact
@ -466,7 +534,6 @@ stages:
- bash: | - bash: |
mkdir -p ./bin/ mkdir -p ./bin/
cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Lidarr/. ./bin/ cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Lidarr/. ./bin/
ls -lR
displayName: Move Package Contents displayName: Move Package Contents
- task: Bash@3 - task: Bash@3
displayName: Run Integration Tests displayName: Run Integration Tests
@ -493,17 +560,17 @@ stages:
Linux: Linux:
osName: 'Linux' osName: 'Linux'
imageName: 'ubuntu-16.04' imageName: 'ubuntu-16.04'
pattern: 'Lidarr.**.linux.tar.gz' pattern: 'Lidarr.**.linux-core-x64.tar.gz'
failBuild: true failBuild: true
Mac: Mac:
osName: 'Mac' osName: 'Mac'
imageName: 'macos-10.14' # Fails due to firefox not being installed on image imageName: 'macos-10.13' # Fails due to firefox not being installed on image
pattern: 'Lidarr.**.osx.tar.gz' pattern: 'Lidarr.**.osx-core-x64.tar.gz'
failBuild: false failBuild: false
Windows: Windows:
osName: 'Windows' osName: 'Windows'
imageName: 'vs2017-win2016' imageName: 'windows-2019'
pattern: 'Lidarr.**.windows.zip' pattern: 'Lidarr.**.windows-core-x64.zip'
failBuild: true failBuild: true
pool: pool:
@ -514,12 +581,13 @@ stages:
displayName: 'Install .net core 3.0' displayName: 'Install .net core 3.0'
inputs: inputs:
version: $(dotnetVersion) version: $(dotnetVersion)
condition: ne(variables['osName'], 'Windows')
- checkout: none - checkout: none
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Test Artifact displayName: Download Test Artifact
inputs: inputs:
buildType: 'current' buildType: 'current'
artifactName: '$(osName)Tests' artifactName: '$(osName)CoreTests'
targetPath: $(testsFolder) targetPath: $(testsFolder)
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Build Artifact displayName: Download Build Artifact
@ -551,7 +619,6 @@ stages:
mv geckodriver _tests mv geckodriver _tests
displayName: Install Gecko Driver displayName: Install Gecko Driver
condition: and(succeeded(), ne(variables['osName'], 'Windows')) condition: and(succeeded(), ne(variables['osName'], 'Windows'))
- bash: ls -lR
- task: Bash@3 - task: Bash@3
displayName: Run Automation Tests displayName: Run Automation Tests
inputs: inputs:
@ -581,7 +648,7 @@ stages:
imageName: 'ubuntu-16.04' imageName: 'ubuntu-16.04'
Windows: Windows:
osName: 'Windows' osName: 'Windows'
imageName: 'vs2017-win2016' imageName: 'windows-2019'
pool: pool:
vmImage: $(imageName) vmImage: $(imageName)
steps: steps:
@ -600,7 +667,7 @@ stages:
- job: Analyze_Frontend - job: Analyze_Frontend
displayName: Frontend displayName: Frontend
pool: pool:
vmImage: vs2017-win2016 vmImage: windows-2019
steps: steps:
- checkout: self # Need history for Sonar analysis - checkout: self # Need history for Sonar analysis
- task: SonarCloudPrepare@1 - task: SonarCloudPrepare@1
@ -620,10 +687,14 @@ stages:
- job: Analyze_Backend - job: Analyze_Backend
displayName: Backend displayName: Backend
pool: pool:
vmImage: vs2017-win2016 vmImage: windows-2019
variables:
disable.coverage.autogenerate: 'true'
steps: steps:
- checkout: self # Need history for Sonar analysis - checkout: self # Need history for Sonar analysis
submodules: true submodules: true
- powershell: Set-Service SCardSvr -StartupType Manual
displayName: Enable Windows Test Service
- task: SonarCloudPrepare@1 - task: SonarCloudPrepare@1
inputs: inputs:
SonarCloud: 'SonarCloud' SonarCloud: 'SonarCloud'
@ -635,22 +706,23 @@ stages:
extraProperties: | extraProperties: |
sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,**/ExternalModules/**,./src/Libraries/** sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,**/ExternalModules/**,./src/Libraries/**
sonar.coverage.exclusions=**/Lidarr.Api.V1/**/*,**/MonoTorrent/**/*,**/Marr.Data/**/* sonar.coverage.exclusions=**/Lidarr.Api.V1/**/*,**/MonoTorrent/**/*,**/Marr.Data/**/*
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/_tests/CoverageResults/coverage.opencover.xml sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
- task: DotNetCoreCLI@2 - bash: |
displayName: Build backend ./build.sh --backend -f netcoreapp3.0 -r win-x64
inputs: TEST_DIR=_tests/netcoreapp3.0/win-x64/publish/ ./test.sh Windows Unit Coverage
command: 'build'
projects: 'src/Lidarr.Windows.sln'
- task: Bash@3
displayName: Coverage Unit Tests displayName: Coverage Unit Tests
- task: SonarCloudAnalyze@1
displayName: Publish SonarCloud Results
- task: reportgenerator@4
displayName: Generate Coverage Report
inputs: inputs:
targetType: 'filePath' reports: '$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml'
filePath: ./test.sh targetdir: '$(Build.SourcesDirectory)/CoverageResults/combined'
arguments: Windows Unit Coverage reporttypes: 'HtmlInline_AzurePipelines;Cobertura;Badges'
- task: PublishCodeCoverageResults@1 - task: PublishCodeCoverageResults@1
displayName: Publish Coverage Results displayName: Publish Coverage Report
inputs: inputs:
codeCoverageTool: 'cobertura' codeCoverageTool: 'cobertura'
summaryFileLocation: './_tests/CoverageResults/coverage.cobertura.xml' summaryFileLocation: './CoverageResults/combined/Cobertura.xml'
- task: SonarCloudAnalyze@1 reportDirectory: './CoverageResults/combined/'

@ -1,23 +1,11 @@
#! /bin/bash #! /bin/bash
outputFolder='./_output' set -e
testPackageFolder='./_tests/'
sourceFolder='./src'
#Artifact variables outputFolder='_output'
artifactsFolder="./_artifacts"; testPackageFolder='_tests'
nuget='tools/nuget/nuget.exe';
CheckExitCode() #Artifact variables
{ artifactsFolder="_artifacts";
"$@"
local status=$?
if [ $status -ne 0 ]; then
echo "error with $1" >&2
exit 1
fi
return $status
}
ProgressStart() ProgressStart()
{ {
@ -33,9 +21,9 @@ UpdateVersionNumber()
{ {
if [ "$LIDARRVERSION" != "" ]; then if [ "$LIDARRVERSION" != "" ]; then
echo "Updating Version Info" echo "Updating Version Info"
sed -i "s/<AssemblyVersion>[0-9.*]\+<\/AssemblyVersion>/<AssemblyVersion>$LIDARRVERSION<\/AssemblyVersion>/g" ./src/Directory.Build.props sed -i'' -e "s/<AssemblyVersion>[0-9.*]\+<\/AssemblyVersion>/<AssemblyVersion>$LIDARRVERSION<\/AssemblyVersion>/g" src/Directory.Build.props
sed -i "s/<AssemblyConfiguration>[\$()A-Za-z-]\+<\/AssemblyConfiguration>/<AssemblyConfiguration>${BUILD_SOURCEBRANCHNAME}<\/AssemblyConfiguration>/g" ./src/Directory.Build.props sed -i'' -e "s/<AssemblyConfiguration>[\$()A-Za-z-]\+<\/AssemblyConfiguration>/<AssemblyConfiguration>${BUILD_SOURCEBRANCHNAME}<\/AssemblyConfiguration>/g" src/Directory.Build.props
sed -i "s/<string>10.0.0.0<\/string>/<string>$LIDARRVERSION<\/string>/g" ./macOS/Lidarr.app/Contents/Info.plist sed -i'' -e "s/<string>10.0.0.0<\/string>/<string>$LIDARRVERSION<\/string>/g" macOS/Lidarr.app/Contents/Info.plist
fi fi
} }
@ -59,14 +47,14 @@ CleanFolder()
LintUI() LintUI()
{ {
ProgressStart 'ESLint' ProgressStart 'ESLint'
CheckExitCode yarn lint yarn lint
ProgressEnd 'ESLint' ProgressEnd 'ESLint'
ProgressStart 'Stylelint' ProgressStart 'Stylelint'
if [ "$os" = "windows" ]; then if [ "$os" = "windows" ]; then
CheckExitCode yarn stylelint-windows yarn stylelint-windows
else else
CheckExitCode yarn stylelint-linux yarn stylelint-linux
fi fi
ProgressEnd 'Stylelint' ProgressEnd 'Stylelint'
} }
@ -79,14 +67,20 @@ Build()
rm -rf $testPackageFolder rm -rf $testPackageFolder
if [ $os = "windows" ]; then if [ $os = "windows" ]; then
slnFile=$sourceFolder/Lidarr.Windows.sln slnFile=src/Lidarr.Windows.sln
else else
slnFile=$sourceFolder/Lidarr.Posix.sln slnFile=src/Lidarr.Posix.sln
fi fi
CheckExitCode dotnet clean $slnFile -c Debug dotnet clean $slnFile -c Debug
CheckExitCode dotnet clean $slnFile -c Release dotnet clean $slnFile -c Release
CheckExitCode dotnet msbuild -restore $slnFile -p:Configuration=Release -t:PublishAllRids
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
dotnet msbuild -restore $slnFile -p:Configuration=Release -t:PublishAllRids
else
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:RuntimeIdentifiers=$RID -t:PublishAllRids
fi
ProgressEnd 'Build' ProgressEnd 'Build'
} }
@ -95,14 +89,13 @@ YarnInstall()
{ {
ProgressStart 'yarn install' ProgressStart 'yarn install'
yarn install yarn install
#npm-cache install npm || CheckExitCode npm install --no-optional --no-bin-links
ProgressEnd 'yarn install' ProgressEnd 'yarn install'
} }
RunGulp() RunGulp()
{ {
ProgressStart 'Running gulp' ProgressStart 'Running gulp'
CheckExitCode yarn run build --production yarn run build --production
ProgressEnd 'Running gulp' ProgressEnd 'Running gulp'
} }
@ -127,12 +120,13 @@ PackageFiles()
PackageLinux() PackageLinux()
{ {
local framework="$1" local framework="$1"
local runtime="$2"
ProgressStart "Creating Linux Package for $framework" ProgressStart "Creating $runtime Package for $framework"
local folder=$artifactsFolder/linux/$framework/Lidarr local folder=$artifactsFolder/$runtime/$framework/Lidarr
PackageFiles "$folder" $framework $runtime "linux-x64" PackageFiles "$folder" "$framework" "$runtime"
echo "Removing Service helpers" echo "Removing Service helpers"
rm -f $folder/ServiceUninstall.* rm -f $folder/ServiceUninstall.*
@ -143,8 +137,12 @@ PackageLinux()
echo "Adding Lidarr.Mono to UpdatePackage" echo "Adding Lidarr.Mono to UpdatePackage"
cp $folder/Lidarr.Mono.* $folder/Lidarr.Update cp $folder/Lidarr.Mono.* $folder/Lidarr.Update
if [ "$framework" = "netcoreapp3.0" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Lidarr.Update
cp $folder/libMonoPosixHelper.* $folder/Lidarr.Update
fi
ProgressEnd "Creating Linux Package for $framework" ProgressEnd "Creating $runtime Package for $framework"
} }
PackageMacOS() PackageMacOS()
@ -157,8 +155,10 @@ PackageMacOS()
PackageFiles "$folder" "$framework" "osx-x64" PackageFiles "$folder" "$framework" "osx-x64"
echo "Adding Startup script" if [ "$framework" = "net462" ]; then
cp ./macOS/Lidarr $folder echo "Adding Startup script"
cp macOS/Lidarr $folder
fi
echo "Removing Service helpers" echo "Removing Service helpers"
rm -f $folder/ServiceUninstall.* rm -f $folder/ServiceUninstall.*
@ -169,6 +169,10 @@ PackageMacOS()
echo "Adding Lidarr.Mono to UpdatePackage" echo "Adding Lidarr.Mono to UpdatePackage"
cp $folder/Lidarr.Mono.* $folder/Lidarr.Update cp $folder/Lidarr.Mono.* $folder/Lidarr.Update
if [ "$framework" = "netcoreapp3.0" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Lidarr.Update
cp $folder/libMonoPosixHelper.* $folder/Lidarr.Update
fi
ProgressEnd 'Creating MacOS Package' ProgressEnd 'Creating MacOS Package'
} }
@ -183,7 +187,7 @@ PackageMacOSApp()
rm -rf $folder rm -rf $folder
mkdir -p $folder mkdir -p $folder
cp -r ./macOS/Lidarr.app $folder cp -r macOS/Lidarr.app $folder
mkdir -p $folder/Lidarr.app/Contents/MacOS mkdir -p $folder/Lidarr.app/Contents/MacOS
echo "Copying Binaries" echo "Copying Binaries"
@ -195,36 +199,6 @@ PackageMacOSApp()
ProgressEnd 'Creating macOS App Package' ProgressEnd 'Creating macOS App Package'
} }
PackageTests()
{
ProgressStart 'Creating Test Package'
cp ./test.sh $testPackageFolder/net462/win-x64/publish
cp ./test.sh $testPackageFolder/net462/linux-x64/publish
cp ./test.sh $testPackageFolder/net462/osx-x64/publish
if [ $os = "windows" ] ; then
$nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolder/net462/win-x64/publish
$nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolder/net462/linux-x64/publish
$nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolder/net462/osx-x64/publish
else
mono $nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolder/net462/win-x64/publish
mono $nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolder/net462/linux-x64/publish
mono $nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolder/net462/osx-x64/publish
fi
rm -f $testPackageFolder/*.log.config
# geckodriver.exe isn't copied by dotnet publish
curl -Lo gecko.zip "https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-win64.zip"
unzip -o gecko.zip
cp geckodriver.exe $testPackageFolder/net462/win-x64/publish
CleanFolder $testPackageFolder
ProgressEnd 'Creating Test Package'
}
PackageWindows() PackageWindows()
{ {
local framework="$1" local framework="$1"
@ -237,6 +211,8 @@ PackageWindows()
echo "Removing Lidarr.Mono" echo "Removing Lidarr.Mono"
rm -f $folder/Lidarr.Mono.* rm -f $folder/Lidarr.Mono.*
rm -f $folder/Mono.Posix.NETStandard.*
rm -f $folder/libMonoPosixHelper.*
echo "Adding Lidarr.Windows to UpdatePackage" echo "Adding Lidarr.Windows to UpdatePackage"
cp $folder/Lidarr.Windows.* $folder/Lidarr.Update cp $folder/Lidarr.Windows.* $folder/Lidarr.Update
@ -244,6 +220,50 @@ PackageWindows()
ProgressEnd 'Creating Windows Package' ProgressEnd 'Creating Windows Package'
} }
Package()
{
local framework="$1"
local runtime="$2"
local SPLIT
IFS='-' read -ra SPLIT <<< "$runtime"
case "${SPLIT[0]}" in
linux)
PackageLinux "$framework" "$runtime"
;;
win)
PackageWindows "$framework"
;;
osx)
PackageMacOS "$framework"
PackageMacOSApp "$framework"
;;
esac
}
PackageTests()
{
local framework="$1"
local runtime="$2"
cp test.sh "$testPackageFolder/$framework/$runtime/publish"
rm -f $testPackageFolder/$framework/$runtime/*.log.config
# geckodriver.exe isn't copied by dotnet publish
if [ "$runtime" = "win-x64" ];
then
curl -Lso gecko.zip "https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-win64.zip"
unzip -o gecko.zip
cp geckodriver.exe "$testPackageFolder/$framework/win-x64/publish"
fi
CleanFolder "$testPackageFolder/$framework/$runtime"
ProgressEnd 'Creating Test Package'
}
# Use mono or .net depending on OS # Use mono or .net depending on OS
case "$(uname -s)" in case "$(uname -s)" in
CYGWIN*|MINGW32*|MINGW64*|MSYS*) CYGWIN*|MINGW32*|MINGW64*|MSYS*)
@ -275,6 +295,16 @@ case $key in
BACKEND=YES BACKEND=YES
shift # past argument shift # past argument
;; ;;
-r|--runtime)
RID="$2"
shift # past argument
shift # past value
;;
-f|--framework)
FRAMEWORK="$2"
shift # past argument
shift # past value
;;
--frontend) --frontend)
FRONTEND=YES FRONTEND=YES
shift # past argument shift # past argument
@ -306,7 +336,15 @@ if [ "$BACKEND" = "YES" ];
then then
UpdateVersionNumber UpdateVersionNumber
Build Build
PackageTests if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
PackageTests "netcoreapp3.0" "win-x64"
PackageTests "netcoreapp3.0" "linux-x64"
PackageTests "netcoreapp3.0" "osx-x64"
PackageTests "net462" "linux-x64"
else
PackageTests "$FRAMEWORK" "$RID"
fi
fi fi
if [ "$FRONTEND" = "YES" ]; if [ "$FRONTEND" = "YES" ];
@ -328,8 +366,16 @@ fi
if [ "$PACKAGES" = "YES" ]; if [ "$PACKAGES" = "YES" ];
then then
UpdateVersionNumber UpdateVersionNumber
PackageWindows "net462"
PackageLinux "net462" if [[ -z "$RID" || -z "$FRAMEWORK" ]];
PackageMacOS "net462" then
PackageMacOSApp "net462" Package "netcoreapp3.0" "win-x64"
Package "netcoreapp3.0" "linux-x64"
Package "netcoreapp3.0" "linux-arm64"
Package "netcoreapp3.0" "linux-arm"
Package "netcoreapp3.0" "osx-x64"
Package "net462" "linux-x64"
else
Package "$FRAMEWORK" "$RID"
fi
fi fi

@ -1,4 +1,4 @@
import * as signalR from '@aspnet/signalr/dist/browser/signalr.js'; import * as signalR from '@microsoft/signalr/dist/browser/signalr.js';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Component } from 'react'; import { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
@ -54,6 +54,37 @@ const mapDispatchToProps = {
dispatchFetchTagDetails: fetchTagDetails dispatchFetchTagDetails: fetchTagDetails
}; };
function Logger(minimumLogLevel) {
this.minimumLogLevel = minimumLogLevel;
}
Logger.prototype.cleanse = function(message) {
const apikey = new RegExp(`access_token=${window.Lidarr.apiKey}`, 'g');
return message.replace(apikey, 'access_token=(removed)');
};
Logger.prototype.log = function(logLevel, message) {
// see https://github.com/aspnet/AspNetCore/blob/21c9e2cc954c10719878839cd3f766aca5f57b34/src/SignalR/clients/ts/signalr/src/Utils.ts#L147
if (logLevel >= this.minimumLogLevel) {
switch (logLevel) {
case signalR.LogLevel.Critical:
case signalR.LogLevel.Error:
console.error(`[signalR] ${signalR.LogLevel[logLevel]}: ${this.cleanse(message)}`);
break;
case signalR.LogLevel.Warning:
console.warn(`[signalR] ${signalR.LogLevel[logLevel]}: ${this.cleanse(message)}`);
break;
case signalR.LogLevel.Information:
console.info(`[signalR] ${signalR.LogLevel[logLevel]}: ${this.cleanse(message)}`);
break;
default:
// console.debug only goes to attached debuggers in Node, so we use console.log for Trace and Debug
console.log(`[signalR] ${signalR.LogLevel[logLevel]}: ${this.cleanse(message)}`);
break;
}
}
};
class SignalRConnector extends Component { class SignalRConnector extends Component {
// //
@ -71,6 +102,7 @@ class SignalRConnector extends Component {
const url = `${window.Lidarr.urlBase}/signalr/messages`; const url = `${window.Lidarr.urlBase}/signalr/messages`;
this.connection = new signalR.HubConnectionBuilder() this.connection = new signalR.HubConnectionBuilder()
.configureLogging(new Logger(signalR.LogLevel.Information))
.withUrl(`${url}?access_token=${window.Lidarr.apiKey}`) .withUrl(`${url}?access_token=${window.Lidarr.apiKey}`)
.withAutomaticReconnect({ .withAutomaticReconnect({
nextRetryDelayInMilliseconds: (retryContext) => { nextRetryDelayInMilliseconds: (retryContext) => {

@ -97,7 +97,6 @@ class GeneralSettings extends Component {
settings, settings,
hasSettings, hasSettings,
isResettingApiKey, isResettingApiKey,
isMono,
isWindows, isWindows,
isWindowsService, isWindowsService,
isDocker, isDocker,
@ -163,7 +162,7 @@ class GeneralSettings extends Component {
<UpdateSettings <UpdateSettings
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
settings={settings} settings={settings}
isMono={isMono} isWindows={isWindows}
isDocker={isDocker} isDocker={isDocker}
onInputChange={onInputChange} onInputChange={onInputChange}
/> />
@ -205,7 +204,6 @@ GeneralSettings.propTypes = {
settings: PropTypes.object.isRequired, settings: PropTypes.object.isRequired,
isResettingApiKey: PropTypes.bool.isRequired, isResettingApiKey: PropTypes.bool.isRequired,
hasSettings: PropTypes.bool.isRequired, hasSettings: PropTypes.bool.isRequired,
isMono: PropTypes.bool.isRequired,
isWindows: PropTypes.bool.isRequired, isWindows: PropTypes.bool.isRequired,
isWindowsService: PropTypes.bool.isRequired, isWindowsService: PropTypes.bool.isRequired,
isDocker: PropTypes.bool.isRequired, isDocker: PropTypes.bool.isRequired,

@ -24,7 +24,6 @@ function createMapStateToProps() {
return { return {
advancedSettings, advancedSettings,
isResettingApiKey, isResettingApiKey,
isMono: systemStatus.isMono,
isWindows: systemStatus.isWindows, isWindows: systemStatus.isWindows,
isWindowsService: systemStatus.isWindows && systemStatus.mode === 'service', isWindowsService: systemStatus.isWindows && systemStatus.mode === 'service',
isDocker: systemStatus.isDocker, isDocker: systemStatus.isDocker,

@ -88,7 +88,7 @@ function HostSettings(props) {
</FormGroup> </FormGroup>
{ {
enableSsl.value && enableSsl.value ?
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
@ -104,11 +104,12 @@ function HostSettings(props) {
onChange={onInputChange} onChange={onInputChange}
{...sslPort} {...sslPort}
/> />
</FormGroup> </FormGroup> :
null
} }
{ {
enableSsl.value && enableSsl.value ?
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
@ -123,11 +124,12 @@ function HostSettings(props) {
onChange={onInputChange} onChange={onInputChange}
{...sslCertPath} {...sslCertPath}
/> />
</FormGroup> </FormGroup> :
null
} }
{ {
enableSsl.value && enableSsl.value ?
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
@ -142,7 +144,8 @@ function HostSettings(props) {
onChange={onInputChange} onChange={onInputChange}
{...sslCertPassword} {...sslCertPassword}
/> />
</FormGroup> </FormGroup> :
null
} }
{ {

@ -15,7 +15,7 @@ function UpdateSettings(props) {
const { const {
advancedSettings, advancedSettings,
settings, settings,
isMono, isWindows,
isDocker, isDocker,
onInputChange onInputChange
} = props; } = props;
@ -64,7 +64,7 @@ function UpdateSettings(props) {
</FormGroup> </FormGroup>
{ {
isMono && !isWindows &&
<div> <div>
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
@ -125,7 +125,7 @@ function UpdateSettings(props) {
UpdateSettings.propTypes = { UpdateSettings.propTypes = {
advancedSettings: PropTypes.bool.isRequired, advancedSettings: PropTypes.bool.isRequired,
settings: PropTypes.object.isRequired, settings: PropTypes.object.isRequired,
isMono: PropTypes.bool.isRequired, isWindows: PropTypes.bool.isRequired,
isDocker: PropTypes.bool.isRequired, isDocker: PropTypes.bool.isRequired,
onInputChange: PropTypes.func.isRequired onInputChange: PropTypes.func.isRequired
}; };

@ -49,7 +49,7 @@ class MediaManagement extends Component {
error, error,
settings, settings,
hasSettings, hasSettings,
isMono, isWindows,
onInputChange, onInputChange,
onSavePress, onSavePress,
...otherProps ...otherProps
@ -129,7 +129,7 @@ class MediaManagement extends Component {
legend="Importing" legend="Importing"
> >
{ {
isMono && !isWindows &&
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
@ -340,7 +340,7 @@ class MediaManagement extends Component {
</FieldSet> </FieldSet>
{ {
advancedSettings && isMono && advancedSettings && !isWindows &&
<FieldSet <FieldSet
legend="Permissions" legend="Permissions"
> >
@ -445,7 +445,7 @@ MediaManagement.propTypes = {
error: PropTypes.object, error: PropTypes.object,
settings: PropTypes.object.isRequired, settings: PropTypes.object.isRequired,
hasSettings: PropTypes.bool.isRequired, hasSettings: PropTypes.bool.isRequired,
isMono: PropTypes.bool.isRequired, isWindows: PropTypes.bool.isRequired,
onSavePress: PropTypes.func.isRequired, onSavePress: PropTypes.func.isRequired,
onInputChange: PropTypes.func.isRequired onInputChange: PropTypes.func.isRequired
}; };

@ -22,7 +22,7 @@ function createMapStateToProps() {
advancedSettings, advancedSettings,
...sectionSettings, ...sectionSettings,
hasPendingChanges: !_.isEmpty(namingSettings.pendingChanges) || sectionSettings.hasPendingChanges, hasPendingChanges: !_.isEmpty(namingSettings.pendingChanges) || sectionSettings.hasPendingChanges,
isMono: systemStatus.isMono isWindows: systemStatus.isWindows
}; };
} }
); );

@ -15,7 +15,8 @@ class About extends Component {
render() { render() {
const { const {
version, version,
isMonoRuntime, isNetCore,
isMono,
isDocker, isDocker,
runtimeVersion, runtimeVersion,
migrationVersion, migrationVersion,
@ -36,18 +37,26 @@ class About extends Component {
/> />
{ {
isMonoRuntime && isMono &&
<DescriptionListItem <DescriptionListItem
title="Mono Version" title="Mono Version"
data={runtimeVersion} data={runtimeVersion}
/> />
} }
{
isNetCore &&
<DescriptionListItem
title=".NET Core"
data={'Yes'}
/>
}
{ {
isDocker && isDocker &&
<DescriptionListItem <DescriptionListItem
title="Docker" title="Docker"
data={'True'} data={'Yes'}
/> />
} }
@ -90,7 +99,8 @@ class About extends Component {
About.propTypes = { About.propTypes = {
version: PropTypes.string.isRequired, version: PropTypes.string.isRequired,
isMonoRuntime: PropTypes.bool.isRequired, isNetCore: PropTypes.bool.isRequired,
isMono: PropTypes.bool.isRequired,
runtimeVersion: PropTypes.string.isRequired, runtimeVersion: PropTypes.string.isRequired,
isDocker: PropTypes.bool.isRequired, isDocker: PropTypes.bool.isRequired,
migrationVersion: PropTypes.number.isRequired, migrationVersion: PropTypes.number.isRequired,

@ -20,7 +20,6 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"readmeFilename": "readme.md", "readmeFilename": "readme.md",
"dependencies": { "dependencies": {
"@aspnet/signalr": "1.1.4",
"@babel/core": "7.5.5", "@babel/core": "7.5.5",
"@babel/plugin-proposal-class-properties": "7.5.5", "@babel/plugin-proposal-class-properties": "7.5.5",
"@babel/plugin-proposal-decorators": "7.4.4", "@babel/plugin-proposal-decorators": "7.4.4",
@ -39,6 +38,7 @@
"@fortawesome/free-regular-svg-icons": "5.10.2", "@fortawesome/free-regular-svg-icons": "5.10.2",
"@fortawesome/free-solid-svg-icons": "5.10.2", "@fortawesome/free-solid-svg-icons": "5.10.2",
"@fortawesome/react-fontawesome": "0.1.4", "@fortawesome/react-fontawesome": "0.1.4",
"@microsoft/signalr": "3.0.0",
"@sentry/browser": "5.6.3", "@sentry/browser": "5.6.3",
"@sentry/integrations": "5.6.1", "@sentry/integrations": "5.6.1",
"ansi-colors": "4.1.1", "ansi-colors": "4.1.1",

@ -26,7 +26,7 @@ DefaultDirName={commonappdata}\Lidarr\bin
DisableDirPage=yes DisableDirPage=yes
DefaultGroupName={#AppName} DefaultGroupName={#AppName}
DisableProgramGroupPage=yes DisableProgramGroupPage=yes
OutputBaseFilename=Lidarr.{#BranchName}.{#BuildVersion}.windows OutputBaseFilename=Lidarr.{#BranchName}.{#BuildVersion}.windows.{#Framework}
SolidCompression=yes SolidCompression=yes
AppCopyright=Creative Commons 3.0 License AppCopyright=Creative Commons 3.0 License
AllowUNCPath=False AllowUNCPath=False
@ -48,8 +48,8 @@ Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts
Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
[Files] [Files]
Source: "..\_artifacts\windows\net462\Lidarr\Lidarr.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "..\_artifacts\windows\{#Framework}\Lidarr\Lidarr.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\_artifacts\windows\net462\Lidarr\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "..\_artifacts\windows\{#Framework}\Lidarr\*"; Excludes: "Lidarr.Update"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons] [Icons]

@ -5,7 +5,8 @@
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch> <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers> <RuntimeIdentifiers>win-x64;osx-x64;linux-x64;linux-arm;linux-arm64</RuntimeIdentifiers>
<ExcludedRuntimeFrameworkPairs>win-x64:net462;osx-x64:net462;linux-arm:net462;linux-arm64:net462</ExcludedRuntimeFrameworkPairs>
<LidarrRootDir>$(MSBuildThisFileDirectory)..\</LidarrRootDir> <LidarrRootDir>$(MSBuildThisFileDirectory)..\</LidarrRootDir>

Binary file not shown.

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Marr.Data\Marr.Data.csproj" /> <ProjectReference Include="..\Marr.Data\Marr.Data.csproj" />
@ -17,6 +17,6 @@
<PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" /> <PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />
<PackageReference Include="System.IO.Abstractions" Version="4.0.11" /> <PackageReference Include="System.IO.Abstractions" Version="6.0.38" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -59,7 +59,7 @@ namespace Lidarr.Api.V1.System
AppData = _appFolderInfo.GetAppDataPath(), AppData = _appFolderInfo.GetAppDataPath(),
OsName = _osInfo.Name, OsName = _osInfo.Name,
OsVersion = _osInfo.Version, OsVersion = _osInfo.Version,
IsMonoRuntime = PlatformInfo.IsMono, IsNetCore = PlatformInfo.IsNetCore,
IsMono = PlatformInfo.IsMono, IsMono = PlatformInfo.IsMono,
IsLinux = OsInfo.IsLinux, IsLinux = OsInfo.IsLinux,
IsOsx = OsInfo.IsOsx, IsOsx = OsInfo.IsOsx,

@ -6,7 +6,6 @@ using Nancy;
using Nancy.Bootstrapper; using Nancy.Bootstrapper;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
namespace Lidarr.Http.Extensions.Pipelines namespace Lidarr.Http.Extensions.Pipelines
{ {
@ -81,7 +80,7 @@ namespace Lidarr.Http.Extensions.Pipelines
private static bool ContentLengthIsTooSmall(Response response) private static bool ContentLengthIsTooSmall(Response response)
{ {
var contentLength = response.Headers.GetValueOrDefault("Content-Length"); var contentLength = response.Headers.TryGetValue("Content-Length", out var value) ? value : null;
if (contentLength != null && long.Parse(contentLength) < 1024) if (contentLength != null && long.Parse(contentLength) < 1024)
{ {
@ -93,7 +92,7 @@ namespace Lidarr.Http.Extensions.Pipelines
private static bool AlreadyGzipEncoded(Response response) private static bool AlreadyGzipEncoded(Response response)
{ {
var contentEncoding = response.Headers.GetValueOrDefault("Content-Encoding"); var contentEncoding = response.Headers.TryGetValue("Content-Encoding", out var value) ? value : null;
if (contentEncoding == "gzip") if (contentEncoding == "gzip")
{ {

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="8.4.0" /> <PackageReference Include="FluentValidation" Version="8.4.0" />

@ -38,15 +38,6 @@ namespace Marr.Data
private DbCommand _command; private DbCommand _command;
/// <summary>
/// Initializes a DataMapper for the given provider type and connection string.
/// </summary>
/// <param name="providerName">Ex: </param>
/// <param name="connectionString">The database connection string.</param>
public DataMapper(string providerName, string connectionString)
: this(DbProviderFactories.GetFactory(providerName), connectionString)
{ }
/// <summary> /// <summary>
/// A database provider agnostic initialization. /// A database provider agnostic initialization.
/// </summary> /// </summary>

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>netstandard2.0</TargetFrameworks>
<AssemblyVersion>3.17.0.0</AssemblyVersion> <AssemblyVersion>3.17.0.0</AssemblyVersion>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute> <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>

@ -1,68 +0,0 @@
/* Copyright (C) 2008 - 2011 Jordan Marr
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
using System;
using System.Data;
using System.Data.OleDb;
namespace Marr.Data.Parameters
{
public class OleDbTypeBuilder : IDbTypeBuilder
{
public Enum GetDbType(Type type)
{
if (type == typeof(String))
return OleDbType.VarChar;
if (type == typeof(Int32))
return OleDbType.Integer;
if (type == typeof(Decimal))
return OleDbType.Decimal;
if (type == typeof(DateTime))
return OleDbType.DBTimeStamp;
if (type == typeof(Boolean))
return OleDbType.Boolean;
if (type == typeof(Int16))
return OleDbType.SmallInt;
if (type == typeof(Int64))
return OleDbType.BigInt;
if (type == typeof(Double))
return OleDbType.Double;
if (type == typeof(Byte))
return OleDbType.Binary;
if (type == typeof(Byte[]))
return OleDbType.VarBinary;
if (type == typeof(Guid))
return OleDbType.Guid;
return OleDbType.Variant;
}
public void SetDbType(IDbDataParameter param, Enum dbType)
{
var oleDbParam = (OleDbParameter)param;
oleDbParam.OleDbType = (OleDbType)dbType;
}
}
}

@ -1,71 +0,0 @@
/* Copyright (C) 2008 - 2011 Jordan Marr
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
using System;
using System.Data;
using System.Data.SqlClient;
namespace Marr.Data.Parameters
{
public class SqlDbTypeBuilder : IDbTypeBuilder
{
public Enum GetDbType(Type type)
{
if (type == typeof(String))
return SqlDbType.VarChar;
if (type == typeof(Int32))
return SqlDbType.Int;
if (type == typeof(Decimal))
return SqlDbType.Decimal;
if (type == typeof(DateTime))
return SqlDbType.DateTime;
if (type == typeof(Boolean))
return SqlDbType.Bit;
if (type == typeof(Int16))
return SqlDbType.SmallInt;
if (type == typeof(Int64))
return SqlDbType.BigInt;
if (type == typeof(Double))
return SqlDbType.Float;
if (type == typeof(Char))
return SqlDbType.Char;
if (type == typeof(Byte))
return SqlDbType.Binary;
if (type == typeof(Byte[]))
return SqlDbType.VarBinary;
if (type == typeof(Guid))
return SqlDbType.UniqueIdentifier;
return SqlDbType.Variant;
}
public void SetDbType(IDbDataParameter param, Enum dbType)
{
var sqlDbParam = (SqlParameter)param;
sqlDbParam.SqlDbType = (SqlDbType)dbType;
}
}
}

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>netstandard2.0</TargetFrameworks>
<Version>9.0.21022</Version> <Version>9.0.21022</Version>
</PropertyGroup> </PropertyGroup>

@ -1,10 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
<PackageReference Include="NBuilder" Version="6.0.1" /> <PackageReference Include="NBuilder" Version="6.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" /> <ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" />
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />

@ -1,8 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
<PackageReference Include="Selenium.Firefox.WebDriver" Version="0.24.0" /> <PackageReference Include="Selenium.Firefox.WebDriver" Version="0.24.0" />
<PackageReference Include="Selenium.Support" Version="3.141.0" /> <PackageReference Include="Selenium.Support" Version="3.141.0" />
</ItemGroup> </ItemGroup>

@ -170,7 +170,7 @@ namespace NzbDrone.Common.Test.Http
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
response.Resource.Headers["Accept-Encoding"].ToString().Should().Be(compression); response.Resource.Headers["Accept-Encoding"].ToString().Should().Be(compression);
response.Headers.ContentLength.Should().BeLessOrEqualTo(response.Content.Length); response.Resource.Gzipped.Should().BeTrue();
} }
[TestCase(HttpStatusCode.Unauthorized)] [TestCase(HttpStatusCode.Unauthorized)]
@ -723,6 +723,7 @@ namespace NzbDrone.Common.Test.Http
public string Origin { get; set; } public string Origin { get; set; }
public string Url { get; set; } public string Url { get; set; }
public string Data { get; set; } public string Data { get; set; }
public bool Gzipped { get; set; }
} }
public class HttpCookieResource public class HttpCookieResource

@ -1,13 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" /> <ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" />
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
<ProjectReference Include="..\NzbDrone.Test.Dummy\Lidarr.Test.Dummy.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Dummy\Lidarr.Test.Dummy.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<Reference Include="System.ServiceProcess" /> <Reference Include="System.ServiceProcess" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -224,7 +224,7 @@ namespace NzbDrone.Common.Test
public void get_actual_casing_should_return_actual_casing_for_local_dir_in_windows() public void get_actual_casing_should_return_actual_casing_for_local_dir_in_windows()
{ {
WindowsOnly(); WindowsOnly();
var path = Directory.GetCurrentDirectory().Replace("c:\\","C:\\").Replace("system32", "System32"); var path = Directory.GetCurrentDirectory().Replace("c:\\","C:\\").Replace("d:\\","D:\\").Replace("system32", "System32");
path.ToUpper().GetActualCasing().Should().Be(path); path.ToUpper().GetActualCasing().Should().Be(path);
path.ToLower().GetActualCasing().Should().Be(path); path.ToLower().GetActualCasing().Should().Be(path);
@ -281,7 +281,7 @@ namespace NzbDrone.Common.Test
[Test] [Test]
public void GetUpdateClientExePath() public void GetUpdateClientExePath()
{ {
GetIAppDirectoryInfo().GetUpdateClientExePath(new Version("0.7.1.1381")).Should().BeEquivalentTo(@"C:\Temp\lidarr_update\Lidarr.Update.exe".AsOsAgnostic()); GetIAppDirectoryInfo().GetUpdateClientExePath(PlatformType.DotNet).Should().BeEquivalentTo(@"C:\Temp\lidarr_update\Lidarr.Update.exe".AsOsAgnostic());
} }
[Test] [Test]

@ -6,6 +6,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Model; using NzbDrone.Common.Model;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
@ -123,7 +124,17 @@ namespace NzbDrone.Common.Test
{ {
var processStarted = new ManualResetEventSlim(); var processStarted = new ManualResetEventSlim();
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, DummyApp.DUMMY_PROCCESS_NAME + ".exe"); string suffix;
if (OsInfo.IsWindows || PlatformInfo.IsMono)
{
suffix = ".exe";
}
else
{
suffix = "";
}
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, DummyApp.DUMMY_PROCCESS_NAME + suffix);
var process = Subject.Start(path, onOutputDataReceived: (string data) => { var process = Subject.Start(path, onOutputDataReceived: (string data) => {
if (data.StartsWith("Dummy process. ID:")) if (data.StartsWith("Dummy process. ID:"))
{ {

@ -4,13 +4,13 @@ using System.ServiceProcess;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Processes;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
using NzbDrone.Test.Common.Categories; using NzbDrone.Test.Common.Categories;
namespace NzbDrone.Common.Test namespace NzbDrone.Common.Test
{ {
[TestFixture] [TestFixture]
[Timeout(15000)]
public class ServiceProviderFixture : TestBase<ServiceProvider> public class ServiceProviderFixture : TestBase<ServiceProvider>
{ {
private const string ALWAYS_INSTALLED_SERVICE = "SCardSvr"; //Smart Card private const string ALWAYS_INSTALLED_SERVICE = "SCardSvr"; //Smart Card
@ -20,6 +20,9 @@ namespace NzbDrone.Common.Test
public void Setup() public void Setup()
{ {
WindowsOnly(); WindowsOnly();
Mocker.SetConstant<IProcessProvider>(Mocker.Resolve<ProcessProvider>());
CleanupService(); CleanupService();
} }

@ -6,6 +6,12 @@ using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Messaging; using NzbDrone.Common.Messaging;
using TinyIoC; using TinyIoC;
#if NETCOREAPP3_0
using System.IO;
using System.Runtime.Loader;
using System.Runtime.InteropServices;
#endif
namespace NzbDrone.Common.Composition namespace NzbDrone.Common.Composition
{ {
public abstract class ContainerBuilderBase public abstract class ContainerBuilderBase
@ -21,15 +27,67 @@ namespace NzbDrone.Common.Composition
assemblies.Add(OsInfo.IsWindows ? "Lidarr.Windows" : "Lidarr.Mono"); assemblies.Add(OsInfo.IsWindows ? "Lidarr.Windows" : "Lidarr.Mono");
assemblies.Add("Lidarr.Common"); assemblies.Add("Lidarr.Common");
#if !NETCOREAPP3_0
foreach (var assembly in assemblies) foreach (var assembly in assemblies)
{ {
_loadedTypes.AddRange(Assembly.Load(assembly).GetTypes()); _loadedTypes.AddRange(Assembly.Load(assembly).GetTypes());
} }
#else
var _startupPath = AppDomain.CurrentDomain.BaseDirectory;
foreach (var assemblyName in assemblies)
{
_loadedTypes.AddRange(AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(_startupPath, $"{assemblyName}.dll")).GetTypes());
}
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ContainerResolveEventHandler);
RegisterSQLiteResolver();
#endif
Container = new Container(new TinyIoCContainer(), _loadedTypes); Container = new Container(new TinyIoCContainer(), _loadedTypes);
AutoRegisterInterfaces(); AutoRegisterInterfaces();
Container.Register(args); Container.Register(args);
} }
#if NETCOREAPP3_0
private static Assembly ContainerResolveEventHandler(object sender, ResolveEventArgs args)
{
var _resolver = new AssemblyDependencyResolver(args.RequestingAssembly.Location);
var assemblyPath = _resolver.ResolveAssemblyToPath(new AssemblyName(args.Name));
if (assemblyPath == null)
{
return null;
}
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
}
public static void RegisterSQLiteResolver()
{
// This ensures we look for sqlite3 using libsqlite3.so.0 on Linux and not libsqlite3.so which
// is less likely to exist.
var sqliteAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "System.Data.SQLite.dll")
);
try
{
NativeLibrary.SetDllImportResolver(sqliteAssembly, LoadSqliteNativeLib);
}
catch (InvalidOperationException)
{
// This can only be set once per assembly
// Catch required for NzbDrone.Host tests
}
}
private static IntPtr LoadSqliteNativeLib(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath)
{
var mappedName = OsInfo.IsLinux && libraryName == "sqlite3" ? "libsqlite3.so.0" : libraryName;
return NativeLibrary.Load(mappedName, assembly, dllImportSearchPath);
}
#endif
private void AutoRegisterInterfaces() private void AutoRegisterInterfaces()
{ {

@ -74,21 +74,26 @@ namespace NzbDrone.Common.EnvironmentInfo
try try
{ {
var configHome = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); // It seems that DoNotVerify is the mono behaviour even though .net docs specify a blank string
if (configHome == "/.config" || // should be returned if the data doesn't exist. For compatibility with .net core, explicitly
// set DoNotVerify (which makes sense given we're explicitly checking that the folder exists)
var configHome = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.DoNotVerify);
if (configHome.IsNullOrWhiteSpace() ||
configHome == "/.config" ||
configHome.EndsWith("/.config") && !_diskProvider.FolderExists(configHome.GetParentPath()) || configHome.EndsWith("/.config") && !_diskProvider.FolderExists(configHome.GetParentPath()) ||
!_diskProvider.FolderExists(configHome)) !_diskProvider.FolderExists(configHome))
{ {
// Tell mono to use appData/.config as ApplicationData folder. // Tell mono/netcore to use appData/.config as ApplicationData folder.
Environment.SetEnvironmentVariable("XDG_CONFIG_HOME", Path.Combine(_appFolderInfo.AppDataFolder, ".config")); Environment.SetEnvironmentVariable("XDG_CONFIG_HOME", Path.Combine(_appFolderInfo.AppDataFolder, ".config"));
} }
var dataHome = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var dataHome = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.DoNotVerify);
if (dataHome == "/.local/share" || if (dataHome.IsNullOrWhiteSpace() ||
dataHome == "/.local/share" ||
dataHome.EndsWith("/.local/share") && !_diskProvider.FolderExists(dataHome.GetParentPath().GetParentPath()) || dataHome.EndsWith("/.local/share") && !_diskProvider.FolderExists(dataHome.GetParentPath().GetParentPath()) ||
!_diskProvider.FolderExists(dataHome)) !_diskProvider.FolderExists(dataHome))
{ {
// Tell mono to use appData/.config/share as LocalApplicationData folder. // Tell mono/netcore to use appData/.config/share as LocalApplicationData folder.
Environment.SetEnvironmentVariable("XDG_DATA_HOME", Path.Combine(_appFolderInfo.AppDataFolder, ".config/share")); Environment.SetEnvironmentVariable("XDG_DATA_HOME", Path.Combine(_appFolderInfo.AppDataFolder, ".config/share"));
} }
} }

@ -34,7 +34,7 @@ namespace NzbDrone.Common.EnvironmentInfo
} }
else else
{ {
AppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.None), "Lidarr"); AppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.DoNotVerify), "Lidarr");
} }
StartUpFolder = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName; StartUpFolder = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
@ -47,4 +47,4 @@ namespace NzbDrone.Common.EnvironmentInfo
public string TempFolder { get; } public string TempFolder { get; }
} }
} }

@ -9,7 +9,8 @@ namespace NzbDrone.Common.EnvironmentInfo
public enum PlatformType public enum PlatformType
{ {
DotNet = 0, DotNet = 0,
Mono = 1 Mono = 1,
NetCore = 2
} }
public interface IPlatformInfo public interface IPlatformInfo
@ -26,6 +27,10 @@ namespace NzbDrone.Common.EnvironmentInfo
static PlatformInfo() static PlatformInfo()
{ {
#if NETCOREAPP3_0
_platform = PlatformType.NetCore;
_version = new Version("3.0");
#else
if (Type.GetType("Mono.Runtime") != null) if (Type.GetType("Mono.Runtime") != null)
{ {
_platform = PlatformType.Mono; _platform = PlatformType.Mono;
@ -36,11 +41,13 @@ namespace NzbDrone.Common.EnvironmentInfo
_platform = PlatformType.DotNet; _platform = PlatformType.DotNet;
_version = GetDotNetVersion(); _version = GetDotNetVersion();
} }
#endif
} }
public static PlatformType Platform => _platform; public static PlatformType Platform => _platform;
public static bool IsMono => Platform == PlatformType.Mono; public static bool IsMono => Platform == PlatformType.Mono;
public static bool IsDotNet => Platform == PlatformType.DotNet; public static bool IsDotNet => Platform == PlatformType.DotNet;
public static bool IsNetCore => Platform == PlatformType.NetCore;
public static string PlatformName public static string PlatformName
{ {
@ -50,8 +57,14 @@ namespace NzbDrone.Common.EnvironmentInfo
{ {
return ".NET"; return ".NET";
} }
else if (IsMono)
return "Mono"; {
return "Mono";
}
else
{
return ".NET Core";
}
} }
} }

@ -7,6 +7,10 @@ using System.ServiceProcess;
using NLog; using NLog;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
#if NETCOREAPP3_0
using Microsoft.Extensions.Hosting.WindowsServices;
#endif
namespace NzbDrone.Common.EnvironmentInfo namespace NzbDrone.Common.EnvironmentInfo
{ {
public class RuntimeInfo : IRuntimeInfo public class RuntimeInfo : IRuntimeInfo
@ -57,7 +61,12 @@ namespace NzbDrone.Common.EnvironmentInfo
} }
} }
#if !NETCOREAPP3_0
public static bool IsUserInteractive => Environment.UserInteractive; public static bool IsUserInteractive => Environment.UserInteractive;
#else
// Note that Environment.UserInteractive is always true on net core: https://stackoverflow.com/a/57325783
public static bool IsUserInteractive => OsInfo.IsWindows && !WindowsServiceHelpers.IsWindowsService();
#endif
bool IRuntimeInfo.IsUserInteractive => IsUserInteractive; bool IRuntimeInfo.IsUserInteractive => IsUserInteractive;
@ -65,6 +74,11 @@ namespace NzbDrone.Common.EnvironmentInfo
{ {
get get
{ {
if (OsInfo.IsNotWindows)
{
return false;
}
try try
{ {
var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent()); var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());

@ -0,0 +1,29 @@
using System;
namespace NzbDrone.Common.Exceptions
{
public class ServiceProviderException : NzbDroneException
{
public ServiceProviderException(string message, params object[] args)
: base(string.Format(message, args))
{
}
public ServiceProviderException(string message)
: base(message)
{
}
public ServiceProviderException(Exception innerException, string message, params object[] args)
: base(string.Format(message, args), innerException)
{
}
public ServiceProviderException(Exception innerException, string message)
: base(message, innerException)
{
}
}
}

@ -6,11 +6,13 @@ namespace NzbDrone.Common.Extensions
{ {
public static class DictionaryExtensions public static class DictionaryExtensions
{ {
public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue = default(TValue)) #if !NETCOREAPP3_0
public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue = default(TValue))
{ {
TValue value; TValue value;
return dictionary.TryGetValue(key, out value) ? value : defaultValue; return dictionary.TryGetValue(key, out value) ? value : defaultValue;
} }
#endif
public static Dictionary<T1, T2> Merge<T1, T2>(this Dictionary<T1, T2> first, Dictionary<T1, T2> second) public static Dictionary<T1, T2> Merge<T1, T2>(this Dictionary<T1, T2> first, Dictionary<T1, T2> second)
{ {

@ -0,0 +1,30 @@
using System.IO;
using System.IO.Compression;
namespace NzbDrone.Common.Extensions
{
public static class GzipExtensions
{
public static byte[] Decompress(this byte[] data)
{
using (var compressedStream = new MemoryStream(data))
using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var decompressedStream = new MemoryStream())
{
gzip.CopyTo(decompressedStream);
return decompressedStream.ToArray();
}
}
public static byte[] Compress(this byte[] data)
{
using (var compressedStream = new MemoryStream())
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress))
{
zipStream.Write(data, 0, data.Length);
zipStream.Close();
return compressedStream.ToArray();
}
}
}
}

@ -217,12 +217,9 @@ namespace NzbDrone.Common.Extensions
return null; return null;
} }
public static string ProcessNameToExe(this string processName, Version version) public static string ProcessNameToExe(this string processName, PlatformType runtime)
{ {
// Windows always has exe (but is shunted to net core) if (OsInfo.IsWindows || runtime != PlatformType.NetCore)
// Linux is kept on mono pending manual upgrade to net core so has .exe
// macOS is shunted to net core and does not have .exe
if (OsInfo.IsWindows || OsInfo.IsLinux || (version.Major == 0 && version.Minor == 7))
{ {
processName += ".exe"; processName += ".exe";
} }
@ -230,6 +227,11 @@ namespace NzbDrone.Common.Extensions
return processName; return processName;
} }
public static string ProcessNameToExe(this string processName)
{
return processName.ProcessNameToExe(PlatformInfo.Platform);
}
public static string GetAppDataPath(this IAppFolderInfo appFolderInfo) public static string GetAppDataPath(this IAppFolderInfo appFolderInfo)
{ {
return appFolderInfo.AppDataFolder; return appFolderInfo.AppDataFolder;
@ -290,9 +292,9 @@ namespace NzbDrone.Common.Extensions
return Path.Combine(GetUpdatePackageFolder(appFolderInfo), UPDATE_CLIENT_FOLDER_NAME); return Path.Combine(GetUpdatePackageFolder(appFolderInfo), UPDATE_CLIENT_FOLDER_NAME);
} }
public static string GetUpdateClientExePath(this IAppFolderInfo appFolderInfo, Version version) public static string GetUpdateClientExePath(this IAppFolderInfo appFolderInfo, PlatformType runtime)
{ {
return Path.Combine(GetUpdateSandboxFolder(appFolderInfo), UPDATE_CLIENT_EXE_NAME).ProcessNameToExe(version); return Path.Combine(GetUpdateSandboxFolder(appFolderInfo), UPDATE_CLIENT_EXE_NAME).ProcessNameToExe(runtime);
} }
public static string GetDatabase(this IAppFolderInfo appFolderInfo) public static string GetDatabase(this IAppFolderInfo appFolderInfo)

@ -1,6 +1,5 @@
using System; using System;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using NLog; using NLog;
@ -125,14 +124,7 @@ namespace NzbDrone.Common.Http.Dispatchers
if (PlatformInfo.IsMono && httpWebResponse.ContentEncoding == "gzip") if (PlatformInfo.IsMono && httpWebResponse.ContentEncoding == "gzip")
{ {
using (var compressedStream = new MemoryStream(data)) data = data.Decompress();
using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var decompressedStream = new MemoryStream())
{
gzip.CopyTo(decompressedStream);
data = decompressedStream.ToArray();
}
httpWebResponse.Headers.Remove("Content-Encoding"); httpWebResponse.Headers.Remove("Content-Encoding");
} }
} }

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" /> <PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" />
@ -8,12 +8,18 @@
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />
<PackageReference Include="Sentry" Version="1.2.0" /> <PackageReference Include="Sentry" Version="1.2.0" />
<PackageReference Include="SharpZipLib" Version="1.2.0" /> <PackageReference Include="SharpZipLib" Version="1.2.0" />
<PackageReference Include="System.IO.Abstractions" Version="4.0.11" /> <PackageReference Include="System.IO.Abstractions" Version="6.0.38" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Data.SQLite.Core.Lidarr" Version="1.0.111.0-5" /> <PackageReference Include="System.Data.SQLite.Core.Lidarr" Version="1.0.111.0-5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Reference Include="System.Configuration.Install" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.6.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.6.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="3.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.6.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<Reference Include="System.ServiceProcess" /> <Reference Include="System.ServiceProcess" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -1,10 +1,9 @@
using System; using System;
using System.Collections.Specialized;
using System.Configuration.Install;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.ServiceProcess; using System.ServiceProcess;
using NLog; using NLog;
using NzbDrone.Common.Exceptions;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
@ -62,30 +61,36 @@ namespace NzbDrone.Common
public virtual void Install(string serviceName) public virtual void Install(string serviceName)
{ {
_logger.Info("Installing service '{0}'", serviceName);
_logger.Info("Installing service '{0}'", serviceName);
var installer = new ServiceProcessInstaller var args = $"create {serviceName} " +
{ $"DisplayName= \"{serviceName}\" " +
Account = ServiceAccount.LocalService $"binpath= \"{Process.GetCurrentProcess().MainModule.FileName}\" " +
}; "start= auto " +
"depend= EventLog/Tcpip/http " +
"obj= \"NT AUTHORITY\\LocalService\"";
var serviceInstaller = new ServiceInstaller(); _logger.Info(args);
var installOutput = _processProvider.StartAndCapture("sc.exe", args);
string[] cmdline = { @"/assemblypath=" + Process.GetCurrentProcess().MainModule.FileName }; if (installOutput.ExitCode != 0)
{
_logger.Error($"Failed to install service: {installOutput.Lines.Select(x => x.Content).ConcatToString("\n")}");
throw new ServiceProviderException("Failed to install service");
}
var context = new InstallContext("service_install.log", cmdline); _logger.Info(installOutput.Lines.Select(x => x.Content).ConcatToString("\n"));
serviceInstaller.Context = context;
serviceInstaller.DisplayName = serviceName;
serviceInstaller.ServiceName = serviceName;
serviceInstaller.Description = "Lidarr Application Server";
serviceInstaller.StartType = ServiceStartMode.Automatic;
serviceInstaller.ServicesDependedOn = new[] { "EventLog", "Tcpip", "http" };
serviceInstaller.Parent = installer; var descOutput = _processProvider.StartAndCapture("sc.exe", $"description {serviceName} \"Lidarr Application Server\"");
if (descOutput.ExitCode != 0)
{
_logger.Error($"Failed to install service: {descOutput.Lines.Select(x => x.Content).ConcatToString("\n")}");
throw new ServiceProviderException("Failed to install service");
}
serviceInstaller.Install(new ListDictionary()); _logger.Info(descOutput.Lines.Select(x => x.Content).ConcatToString("\n"));
_logger.Info("Service Has installed successfully."); _logger.Info("Service Has installed successfully.");
} }
@ -96,12 +101,8 @@ namespace NzbDrone.Common
Stop(serviceName); Stop(serviceName);
var serviceInstaller = new ServiceInstaller(); var output = _processProvider.StartAndCapture("sc.exe", $"delete {serviceName}");
_logger.Info(output.Lines.Select(x => x.Content).ConcatToString("\n"));
var context = new InstallContext("service_uninstall.log", null);
serviceInstaller.Context = context;
serviceInstaller.ServiceName = serviceName;
serviceInstaller.Uninstall(null);
_logger.Info("{0} successfully uninstalled", serviceName); _logger.Info("{0} successfully uninstalled", serviceName);
} }

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
<ApplicationIcon>..\NzbDrone.Host\NzbDrone.ico</ApplicationIcon> <ApplicationIcon>..\NzbDrone.Host\NzbDrone.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>

@ -163,7 +163,7 @@ namespace NzbDrone.Core.Test.Download
Mocker.GetMock<IIndexerStatusService>() Mocker.GetMock<IIndexerStatusService>()
.Verify(v => v.RecordFailure(It.IsAny<int>(), .Verify(v => v.RecordFailure(It.IsAny<int>(),
It.IsInRange<TimeSpan>(TimeSpan.FromMinutes(4.9), TimeSpan.FromMinutes(5.1), Range.Inclusive)), Times.Once()); It.IsInRange<TimeSpan>(TimeSpan.FromMinutes(4.9), TimeSpan.FromMinutes(5.1), Moq.Range.Inclusive)), Times.Once());
} }
[Test] [Test]

File diff suppressed because one or more lines are too long

@ -1,69 +0,0 @@
using System;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
[TestFixture]
public class DotnetVersionCheckFixture : CoreTest<DotnetVersionCheck>
{
private void GivenOutput(string version)
{
WindowsOnly();
Mocker.GetMock<IPlatformInfo>()
.SetupGet(s => s.Version)
.Returns(new Version(version));
}
[TestCase("4.7.2")]
[TestCase("4.8")]
public void should_return_ok(string version)
{
GivenOutput(version);
Subject.Check().ShouldBeOk();
}
[TestCase("4.6.2")]
[TestCase("4.7")]
[TestCase("4.7.1")]
public void should_return_notice(string version)
{
GivenOutput(version);
Subject.Check().ShouldBeNotice();
}
public void should_return_warning(string version)
{
GivenOutput(version);
Subject.Check().ShouldBeWarning();
}
[TestCase("4.5")]
[TestCase("4.5.2")]
[TestCase("4.6.1")]
public void should_return_error(string version)
{
GivenOutput(version);
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_ok_for_net462_on_Win1511()
{
Mocker.GetMock<IOsInfo>()
.SetupGet(v => v.Version)
.Returns("10.0.14392");
GivenOutput("4.6.2");
Subject.Check().ShouldBeOk();
}
}
}

@ -1,12 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
<PackageReference Include="System.Buffers" Version="4.5.0" />
<PackageReference Include="NBuilder" Version="6.0.1" /> <PackageReference Include="NBuilder" Version="6.0.1" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="4.0.11" /> <PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="6.0.38" />
<PackageReference Include="AutoFixture" Version="4.11.0" /> <PackageReference Include="AutoFixture" Version="4.11.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
<ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" /> <ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" />

@ -3,11 +3,12 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using Newtonsoft.Json; using Newtonsoft.Json;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -22,7 +23,7 @@ namespace NzbDrone.Core.Test.ParserTests
{ {
public class FingerPrintTest public class FingerPrintTest
{ {
public string RequestContent { get; set; } public string Request { get; set; }
public string Response { get; set; } public string Response { get; set; }
} }
@ -30,7 +31,7 @@ namespace NzbDrone.Core.Test.ParserTests
public void UseAcoustidResponses() public void UseAcoustidResponses()
{ {
// responses were generated by editing HttpClient to write out the content bytes as a string // responses were generated by editing HttpClient to write out the content bytes as a string
// using BitConverter.ToString(request.ContentData) // using System.Text.Encoding.UTF8.GetString(request.ContentData.Decompress());
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Fingerprinting", "AcoustidResponses.json"); var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Fingerprinting", "AcoustidResponses.json");
var responses = JsonConvert.DeserializeObject<List<FingerPrintTest>>(File.ReadAllText(path)); var responses = JsonConvert.DeserializeObject<List<FingerPrintTest>>(File.ReadAllText(path));
@ -38,16 +39,13 @@ namespace NzbDrone.Core.Test.ParserTests
{ {
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(o => o.Post<LookupResponse>( .Setup(o => o.Post<LookupResponse>(
It.Is<HttpRequest>(v => It.Is<HttpRequest>(v =>
v.Url.Equals(new HttpUri("https://api.acoustid.org/v2/lookup")) && v.Url.Equals(new HttpUri("https://api.acoustid.org/v2/lookup")) &&
v.Headers.Contains(new KeyValuePair<string, string>("Content-Encoding", "gzip")) && v.Headers.Contains(new KeyValuePair<string, string>("Content-Encoding", "gzip")) &&
v.Headers.ContentType == "application/x-www-form-urlencoded" && v.Headers.ContentType == "application/x-www-form-urlencoded" &&
// Skip past the first bit of gzip header which varies by OS: Encoding.UTF8.GetString(v.ContentData.Decompress()) == response.Request
// http://www.onicos.com/staff/iz/formats/gzip.html )))
BitConverter.ToString(v.ContentData).Substring(31) == response.RequestContent.Substring(31)
)))
.Returns<HttpRequest>(r => new HttpResponse<LookupResponse>(new HttpResponse(r, new HttpHeader(), response.Response))); .Returns<HttpRequest>(r => new HttpResponse<LookupResponse>(new HttpResponse(r, new HttpHeader(), response.Response)));
} }
} }

@ -25,6 +25,7 @@ namespace NzbDrone.Core.Test.UpdateTests
} }
[Test] [Test]
[Platform(Exclude="NetCore")]
public void finds_update_when_version_lower() public void finds_update_when_version_lower()
{ {
UseRealHttp(); UseRealHttp();

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;

@ -3,7 +3,6 @@ using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.MediaFiles.TorrentInfo; using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@ -12,6 +11,7 @@ using NLog;
using FluentValidation.Results; using FluentValidation.Results;
using System.Net; using System.Net;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Core.Download.Clients.Deluge namespace NzbDrone.Core.Download.Clients.Deluge
{ {

@ -12,7 +12,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
{ {
HadoukenSystemInfo GetSystemInfo(HadoukenSettings settings); HadoukenSystemInfo GetSystemInfo(HadoukenSettings settings);
HadoukenTorrent[] GetTorrents(HadoukenSettings settings); HadoukenTorrent[] GetTorrents(HadoukenSettings settings);
IDictionary<string, object> GetConfig(HadoukenSettings settings); IReadOnlyDictionary<string, object> GetConfig(HadoukenSettings settings);
string AddTorrentFile(HadoukenSettings settings, byte[] fileContent); string AddTorrentFile(HadoukenSettings settings, byte[] fileContent);
void AddTorrentUri(HadoukenSettings settings, string torrentUrl); void AddTorrentUri(HadoukenSettings settings, string torrentUrl);
void RemoveTorrent(HadoukenSettings settings, string downloadId); void RemoveTorrent(HadoukenSettings settings, string downloadId);
@ -42,9 +42,9 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
return GetTorrents(result.Torrents); return GetTorrents(result.Torrents);
} }
public IDictionary<string, object> GetConfig(HadoukenSettings settings) public IReadOnlyDictionary<string, object> GetConfig(HadoukenSettings settings)
{ {
return ProcessRequest<IDictionary<string, object>>(settings, "webui.getSettings"); return ProcessRequest<IReadOnlyDictionary<string, object>>(settings, "webui.getSettings");
} }
public string AddTorrentFile(HadoukenSettings settings, byte[] fileContent) public string AddTorrentFile(HadoukenSettings settings, byte[] fileContent)

@ -1,16 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.3" /> <PackageReference Include="System.Memory" Version="4.5.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
<PackageReference Include="FluentMigrator.Runner" Version="4.0.0-alpha.268" /> <PackageReference Include="FluentMigrator.Runner" Version="4.0.0-alpha.268" />
<PackageReference Include="FluentMigrator.Runner.SQLite" Version="4.0.0-alpha.268" /> <PackageReference Include="FluentMigrator.Runner.SQLite" Version="4.0.0-alpha.268" />
<PackageReference Include="FluentValidation" Version="8.4.0" /> <PackageReference Include="FluentValidation" Version="8.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />
<PackageReference Include="RestSharp" Version="106.6.10" /> <PackageReference Include="RestSharp" Version="106.6.10" />
<PackageReference Include="System.IO.Abstractions" Version="4.0.11" /> <PackageReference Include="System.IO.Abstractions" Version="6.0.38" />
<PackageReference Include="TagLibSharp-Lidarr" Version="2.2.0.19" /> <PackageReference Include="TagLibSharp-Lidarr" Version="2.2.0.19" />
<PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" />
<PackageReference Include="SpotifyAPI.Web" Version="4.2.0" /> <PackageReference Include="SpotifyAPI.Web" Version="4.2.0" />
@ -22,7 +24,7 @@
<ProjectReference Include="..\MonoTorrent\MonoTorrent.csproj" /> <ProjectReference Include="..\MonoTorrent\MonoTorrent.csproj" />
<ProjectReference Include="..\NzbDrone.Common\Lidarr.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Common\Lidarr.Common.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<Reference Include="System.Web" /> <Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" /> <Reference Include="System.Web.Extensions" />
</ItemGroup> </ItemGroup>

@ -6,8 +6,8 @@ using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NLog; using NLog;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Profiles.Releases; using NzbDrone.Core.Profiles.Releases;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -318,17 +317,6 @@ namespace NzbDrone.Core.Parser
return null; return null;
} }
private static byte[] Compress(byte[] data)
{
using (var compressedStream = new MemoryStream())
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress))
{
zipStream.Write(data, 0, data.Length);
zipStream.Close();
return compressedStream.ToArray();
}
}
public void Lookup(List<LocalTrack> tracks, double threshold) public void Lookup(List<LocalTrack> tracks, double threshold)
{ {
if (!IsSetup()) if (!IsSetup())
@ -365,7 +353,7 @@ namespace NzbDrone.Core.Parser
} }
// they prefer a gzipped body // they prefer a gzipped body
httpRequest.SetContent(Compress(Encoding.UTF8.GetBytes(sb.ToString()))); httpRequest.SetContent(Encoding.UTF8.GetBytes(sb.ToString()).Compress());
httpRequest.Headers.Add("Content-Encoding", "gzip"); httpRequest.Headers.Add("Content-Encoding", "gzip");
httpRequest.Headers.ContentType = "application/x-www-form-urlencoded"; httpRequest.Headers.ContentType = "application/x-www-form-urlencoded";
httpRequest.SuppressHttpError = true; httpRequest.SuppressHttpError = true;

@ -132,6 +132,7 @@ namespace NzbDrone.Core.Update
_diskTransferService.TransferFolder(_appFolderInfo.GetUpdateClientFolder(), updateSandboxFolder, TransferMode.Move, false); _diskTransferService.TransferFolder(_appFolderInfo.GetUpdateClientFolder(), updateSandboxFolder, TransferMode.Move, false);
// Set executable flag on update app // Set executable flag on update app
<<<<<<< HEAD
if (OsInfo.IsOsx) if (OsInfo.IsOsx)
{ {
_diskProvider.SetPermissions(_appFolderInfo.GetUpdateClientExePath(updatePackage.Version), "0755", null, null); _diskProvider.SetPermissions(_appFolderInfo.GetUpdateClientExePath(updatePackage.Version), "0755", null, null);
@ -141,6 +142,17 @@ namespace NzbDrone.Core.Update
_logger.ProgressInfo("Lidarr will restart shortly."); _logger.ProgressInfo("Lidarr will restart shortly.");
_processProvider.Start(_appFolderInfo.GetUpdateClientExePath(updatePackage.Version), GetUpdaterArgs(updateSandboxFolder)); _processProvider.Start(_appFolderInfo.GetUpdateClientExePath(updatePackage.Version), GetUpdaterArgs(updateSandboxFolder));
=======
if (OsInfo.IsOsx || (OsInfo.IsLinux && PlatformInfo.IsNetCore))
{
_diskProvider.SetPermissions(_appFolderInfo.GetUpdateClientExePath(updatePackage.Runtime), "0755", null, null);
}
_logger.Info("Starting update client {0}", _appFolderInfo.GetUpdateClientExePath(updatePackage.Runtime));
_logger.ProgressInfo("Lidarr will restart shortly.");
_processProvider.Start(_appFolderInfo.GetUpdateClientExePath(updatePackage.Runtime), GetUpdaterArgs(updateSandboxFolder));
>>>>>>> 4346c76d4... New: Multi target net framework 4.6.2 and net core 3.0
} }
private void EnsureValidBranch(UpdatePackage package) private void EnsureValidBranch(UpdatePackage package)

@ -1,5 +1,5 @@
using System; using System;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Core.Update namespace NzbDrone.Core.Update
{ {
@ -12,5 +12,6 @@ namespace NzbDrone.Core.Update
public UpdateChanges Changes { get; set; } public UpdateChanges Changes { get; set; }
public string Hash { get; set; } public string Hash { get; set; }
public string Branch { get; set; } public string Branch { get; set; }
public PlatformType Runtime { get; set; }
} }
} }

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices;
using NzbDrone.Common.Cloud; using NzbDrone.Common.Cloud;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
@ -34,6 +35,8 @@ namespace NzbDrone.Core.Update
.Resource("/update/{branch}") .Resource("/update/{branch}")
.AddQueryParam("version", currentVersion) .AddQueryParam("version", currentVersion)
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("arch", RuntimeInformation.OSArchitecture)
.AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant())
.AddQueryParam("runtimeVer", _platformInfo.Version) .AddQueryParam("runtimeVer", _platformInfo.Version)
.SetSegment("branch", branch); .SetSegment("branch", branch);
@ -70,4 +73,4 @@ namespace NzbDrone.Core.Update
return updates.Resource; return updates.Resource;
} }
} }
} }

@ -1,12 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" /> <ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" />
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<Reference Include="System.ServiceProcess" /> <Reference Include="System.ServiceProcess" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -1,13 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
<OutputType>Library</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="System.Security.Cryptography.Cng" Version="4.6.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" /> <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Owin" Version="2.2.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="3.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="3.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NLog.Extensions.Logging" Version="1.5.3" /> <PackageReference Include="NLog.Extensions.Logging" Version="1.5.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -15,6 +15,7 @@ namespace NzbDrone.Host.Middleware
private readonly IContainer _container; private readonly IContainer _container;
private readonly Logger _logger; private readonly Logger _logger;
private static string API_KEY; private static string API_KEY;
private static string URL_BASE;
public int Order => 1; public int Order => 1;
public SignalRMiddleware(IContainer container, public SignalRMiddleware(IContainer container,
@ -24,6 +25,7 @@ namespace NzbDrone.Host.Middleware
_container = container; _container = container;
_logger = logger; _logger = logger;
API_KEY = configFileProvider.ApiKey; API_KEY = configFileProvider.ApiKey;
URL_BASE = configFileProvider.UrlBase;
} }
public void Attach(IApplicationBuilder appBuilder) public void Attach(IApplicationBuilder appBuilder)
@ -53,11 +55,17 @@ namespace NzbDrone.Host.Middleware
} }
}); });
appBuilder.UseSignalR(routes => #if NETCOREAPP3_0
appBuilder.UseEndpoints(x =>
{ {
routes.MapHub<MessageHub>("/signalr/messages"); x.MapHub<MessageHub>(URL_BASE + "/signalr/messages");
}); });
#else
appBuilder.UseSignalR(x =>
{
x.MapHub<MessageHub>("/signalr/messages");
});
#endif
// This is a side effect of haing multiple IoC containers, TinyIoC and whatever // This is a side effect of haing multiple IoC containers, TinyIoC and whatever
// Kestrel/SignalR is using. Ideally we'd have one IoC container, but that's non-trivial with TinyIoC // Kestrel/SignalR is using. Ideally we'd have one IoC container, but that's non-trivial with TinyIoC
// TODO: Use a single IoC container if supported for TinyIoC or if we switch to another system (ie Autofac). // TODO: Use a single IoC container if supported for TinyIoC or if we switch to another system (ie Autofac).

@ -5,7 +5,6 @@ using System.Linq;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NLog; using NLog;
@ -77,6 +76,10 @@ namespace NzbDrone.Host
}); });
} }
}) })
.ConfigureKestrel(serverOptions =>
{
serverOptions.AllowSynchronousIO = true;
})
.ConfigureLogging(logging => .ConfigureLogging(logging =>
{ {
logging.AddProvider(new NLogLoggerProvider()); logging.AddProvider(new NLogLoggerProvider());
@ -86,15 +89,23 @@ namespace NzbDrone.Host
{ {
services services
.AddSignalR() .AddSignalR()
.AddJsonProtocol(options => #if !NETCOREAPP3_0
.AddJsonProtocol(
#else
.AddNewtonsoftJsonProtocol(
#endif
options =>
{ {
options.PayloadSerializerSettings = Json.GetSerializerSettings(); options.PayloadSerializerSettings = Json.GetSerializerSettings();
}); });
}) })
.Configure(app => .Configure(app =>
{ {
app.UsePathBase(_configFileProvider.UrlBase); #if NETCOREAPP3_0
app.UseRouting();
#endif
app.Properties["host.AppName"] = BuildInfo.AppName; app.Properties["host.AppName"] = BuildInfo.AppName;
app.UsePathBase(_configFileProvider.UrlBase);
foreach (var middleWare in _middlewares.OrderBy(c => c.Order)) foreach (var middleWare in _middlewares.OrderBy(c => c.Order))
{ {

@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using System.Reflection; using System.Reflection;
using System.IO; using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Common;
namespace NzbDrone.Integration.Test.ApiTests namespace NzbDrone.Integration.Test.ApiTests
{ {
@ -61,7 +62,7 @@ namespace NzbDrone.Integration.Test.ApiTests
result.Directories.Should().NotBeNullOrEmpty(); result.Directories.Should().NotBeNullOrEmpty();
result.Files.Should().NotBeNullOrEmpty(); result.Files.Should().NotBeNullOrEmpty();
result.Files.Should().Contain(v => v.Path == _file && v.Type == FileSystemEntityType.File); result.Files.Should().Contain(v => PathEqualityComparer.Instance.Equals(v.Path, _file) && v.Type == FileSystemEntityType.File);
} }
[Test] [Test]

@ -15,6 +15,7 @@ namespace NzbDrone.Integration.Test.ApiTests
} }
[Test] [Test]
[Ignore("SignalR on CI seems unstable")]
public void should_add_and_delete_root_folders() public void should_add_and_delete_root_folders()
{ {
ConnectSignalR().Wait(); ConnectSignalR().Wait();

@ -1,10 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
<OutputType>Library</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="1.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.0.0" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Lidarr.Api.V1\Lidarr.Api.V1.csproj" /> <ProjectReference Include="..\Lidarr.Api.V1\Lidarr.Api.V1.csproj" />
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />

@ -1,7 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
</ItemGroup> </ItemGroup>

@ -1,17 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Mono.Posix-4.5" Version="4.5.0" PrivateAssets="all"/>
</ItemGroup>
<!--
The netstandard veresion here doesn't work in net framework
See https://github.com/xamarin/XamarinComponents/issues/282
-->
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Common.Test\Lidarr.Common.Test.csproj" /> <ProjectReference Include="..\NzbDrone.Common.Test\Lidarr.Common.Test.csproj" />
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
<ProjectReference Include="..\NzbDrone.Mono\Lidarr.Mono.csproj" /> <ProjectReference Include="..\NzbDrone.Mono\Lidarr.Mono.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="Mono.Posix">
<HintPath>..\Libraries\Mono.Posix.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="Files\**\*.*"> <None Update="Files\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

@ -1,17 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />
<PackageReference Include="System.IO.Abstractions" Version="4.0.11" /> <PackageReference Include="System.IO.Abstractions" Version="6.0.38" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<ProjectReference Include="..\NzbDrone.Common\Lidarr.Common.csproj" /> <PackageReference Include="Mono.Posix-4.5" Version="4.5.0" PrivateAssets="all"/>
</ItemGroup>
<!--
The netstandard veresion here doesn't work in net framework
See https://github.com/xamarin/XamarinComponents/issues/282
-->
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Mono.Posix"> <ProjectReference Include="..\NzbDrone.Common\Lidarr.Common.csproj" />
<HintPath>..\Libraries\Mono.Posix.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
<OutputType>Library</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
</ItemGroup> </ItemGroup>

@ -9,6 +9,7 @@ using System.Runtime.CompilerServices;
using Unity; using Unity;
using Moq; using Moq;
using Moq.Language.Flow; using Moq.Language.Flow;
using NzbDrone.Common.Composition;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Test.Common.AutoMoq.Unity; using NzbDrone.Test.Common.AutoMoq.Unity;
@ -150,6 +151,10 @@ namespace NzbDrone.Test.Common.AutoMoq
RegisterPlatformLibrary(container); RegisterPlatformLibrary(container);
AddTheAutoMockingContainerExtensionToTheContainer(container); AddTheAutoMockingContainerExtensionToTheContainer(container);
#if NETCOREAPP3_0
ContainerBuilderBase.RegisterSQLiteResolver();
#endif
} }
private static void AddTheAutoMockingContainerExtensionToTheContainer(IUnityContainer container) private static void AddTheAutoMockingContainerExtensionToTheContainer(IUnityContainer container)

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.9.0" /> <PackageReference Include="FluentAssertions" Version="5.9.0" />
@ -10,7 +10,7 @@
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="RestSharp" Version="106.6.10" /> <PackageReference Include="RestSharp" Version="106.6.10" />
<PackageReference Include="System.IO.Abstractions" Version="4.0.11" /> <PackageReference Include="System.IO.Abstractions" Version="6.0.38" />
<PackageReference Include="Unity" Version="5.11.1" /> <PackageReference Include="Unity" Version="5.11.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -33,17 +33,29 @@ namespace NzbDrone.Test.Common
Directory.CreateDirectory(AppData); Directory.CreateDirectory(AppData);
GenerateConfigFile(); GenerateConfigFile();
var lidarrConsoleExe = OsInfo.IsWindows ? "Lidarr.Console.exe" : "Lidarr.exe"; string lidarrConsoleExe;
var frameworkFolder = "net462"; if (OsInfo.IsWindows)
{
lidarrConsoleExe = "Lidarr.Console.exe";
}
else if (PlatformInfo.IsMono)
{
lidarrConsoleExe = "Lidarr.exe";
}
else
{
lidarrConsoleExe = "Lidarr";
}
if (BuildInfo.IsDebug) if (BuildInfo.IsDebug)
{ {
var frameworkFolder = PlatformInfo.IsNetCore ? "netcoreapp3.0" : "net462";
Start(Path.Combine(TestContext.CurrentContext.TestDirectory, "..", "..", "_output", frameworkFolder, lidarrConsoleExe)); Start(Path.Combine(TestContext.CurrentContext.TestDirectory, "..", "..", "_output", frameworkFolder, lidarrConsoleExe));
} }
else else
{ {
Start(Path.Combine("bin", lidarrConsoleExe)); Start(Path.Combine(TestContext.CurrentContext.TestDirectory, "..", "bin", lidarrConsoleExe));
} }
while (true) while (true)

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

@ -1,7 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
<ProjectReference Include="..\NzbDrone.Update\Lidarr.Update.csproj" /> <ProjectReference Include="..\NzbDrone.Update\Lidarr.Update.csproj" />

@ -3,6 +3,7 @@ using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
using NzbDrone.Update.UpdateEngine; using NzbDrone.Update.UpdateEngine;
@ -27,7 +28,7 @@ namespace NzbDrone.Update.Test
public void should_start_console_if_app_type_was_service_but_start_failed_because_of_permissions() public void should_start_console_if_app_type_was_service_but_start_failed_because_of_permissions()
{ {
string targetFolder = "c:\\Lidarr\\".AsOsAgnostic(); string targetFolder = "c:\\Lidarr\\".AsOsAgnostic();
string targetProcess = "c:\\Lidarr\\Lidarr.Console.exe".AsOsAgnostic(); string targetProcess = "c:\\Lidarr\\Lidarr.Console".AsOsAgnostic().ProcessNameToExe();
Mocker.GetMock<IServiceProvider>().Setup(c => c.Start(ServiceProvider.SERVICE_NAME)).Throws(new InvalidOperationException()); Mocker.GetMock<IServiceProvider>().Setup(c => c.Start(ServiceProvider.SERVICE_NAME)).Throws(new InvalidOperationException());

@ -1,241 +0,0 @@
/*
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Common.Model;
using NzbDrone.Test.Common;
using NzbDrone.Update.UpdateEngine;
namespace NzbDrone.Update.Test
{
[TestFixture]
public class UpdateProviderStartFixture : TestBase
{
private const string UPDATE_FOLDER = @"C:\Temp\nzbdrone_update\nzbdrone\";
private const string BACKUP_FOLDER = @"C:\Temp\nzbdrone_update\nzbdrone_backup\";
private const string TARGET_FOLDER = @"C:\NzbDrone\";
Mock<IIAppDirectoryInfo> _IAppDirectoryInfo;
[SetUp]
public void Setup()
{
_IAppDirectoryInfo = Mocker.GetMock<IIAppDirectoryInfo>();
_IAppDirectoryInfo.SetupGet(c => c.SystemTemp).Returns(@"C:\Temp\");
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderExists(UPDATE_FOLDER))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderExists(TARGET_FOLDER))
.Returns(true);
}
private void WithInstalledService()
{
Mocker.GetMock<IServiceProvider>()
.Setup(c => c.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME))
.Returns(true);
}
private void WithServiceRunning(bool state)
{
Mocker.GetMock<IServiceProvider>()
.Setup(c => c.IsServiceRunning(ServiceProvider.NZBDRONE_SERVICE_NAME)).Returns(state);
}
[Test]
public void should_stop_nzbdrone_service_if_installed_and_running()
{
WithInstalledService();
WithServiceRunning(true);
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
Mocker.GetMock<IServiceProvider>().Verify(c => c.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME), Times.Once());
}
[Test]
public void should_not_stop_nzbdrone_service_if_installed_but_not_running()
{
WithInstalledService();
WithServiceRunning(false);
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
Mocker.GetMock<IServiceProvider>().Verify(c => c.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME), Times.Never());
}
[Test]
public void should_not_stop_nzbdrone_service_if_service_isnt_installed()
{
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
Mocker.GetMock<IServiceProvider>().Verify(c => c.Stop(It.IsAny<string>()), Times.Never());
}
[Test]
public void should_kill_nzbdrone_process_if_running()
{
var proccesses = Builder<ProcessInfo>.CreateListOfSize(2).Build().ToList();
Mocker.GetMock<IProcessProvider>()
.Setup(c => c.GetProcessByName(ProcessProvider.NzbDroneProcessName))
.Returns(proccesses);
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
Mocker.GetMock<IProcessProvider>().Verify(c => c.KillAll(ProcessProvider.NzbDroneProcessName), Times.Once());
}
[Test]
public void should_not_kill_nzbdrone_process_not_running()
{
Mocker.GetMock<IProcessProvider>()
.Setup(c => c.GetProcessByName(ProcessProvider.NzbDroneProcessName))
.Returns(new List<ProcessInfo>());
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
Mocker.GetMock<IProcessProvider>().Verify(c => c.Kill(It.IsAny<int>()), Times.Never());
}
[Test]
public void should_create_backup_of_current_installation()
{
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.CopyDirectory(TARGET_FOLDER, BACKUP_FOLDER));
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
}
[Test]
public void should_copy_update_package_to_target()
{
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.CopyDirectory(UPDATE_FOLDER, TARGET_FOLDER));
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.DeleteFolder(UPDATE_FOLDER, true));
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
}
[Test]
public void should_restore_if_update_fails()
{
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.CopyDirectory(UPDATE_FOLDER, TARGET_FOLDER))
.Throws(new IOException());
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
Mocker.GetMock<IDiskProvider>()
.Verify(c => c.CopyDirectory(BACKUP_FOLDER, TARGET_FOLDER), Times.Once());
ExceptionVerification.ExpectedFatals(1);
}
[Test]
public void should_restart_service_if_service_was_running()
{
WithInstalledService();
WithServiceRunning(true);
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
VerifyServiceRestart();
}
[Test]
public void should_restart_process_if_service_was_not_running()
{
WithInstalledService();
WithServiceRunning(false);
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
VerifyProcessRestart();
}
[Test]
public void should_restart_service_if_service_was_running_and_update_fails()
{
WithInstalledService();
WithServiceRunning(true);
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.CopyDirectory(UPDATE_FOLDER, TARGET_FOLDER))
.Throws(new IOException());
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
VerifyServiceRestart();
ExceptionVerification.ExpectedFatals(1);
}
[Test]
public void should_restart_process_if_service_was_not_running_and_update_fails()
{
WithInstalledService();
WithServiceRunning(false);
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.CopyDirectory(UPDATE_FOLDER, TARGET_FOLDER))
.Throws(new IOException());
Mocker.Resolve<InstallUpdateService>().Start(TARGET_FOLDER);
VerifyProcessRestart();
ExceptionVerification.ExpectedFatals(1);
}
private void VerifyServiceRestart()
{
Mocker.GetMock<IServiceProvider>()
.Verify(c => c.Start(ServiceProvider.NZBDRONE_SERVICE_NAME), Times.Once());
Mocker.GetMock<IProcessProvider>()
.Verify(c => c.Start(It.IsAny<string>()), Times.Never());
}
private void VerifyProcessRestart()
{
Mocker.GetMock<IServiceProvider>()
.Verify(c => c.Start(It.IsAny<string>()), Times.Never());
Mocker.GetMock<IProcessProvider>()
.Verify(c => c.Start(TARGET_FOLDER + "NzbDrone.exe"), Times.Once());
}
}
}
*/

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />

@ -114,7 +114,7 @@ namespace NzbDrone.Update.UpdateEngine
_diskTransferService.MirrorFolder(_appFolderInfo.GetUpdatePackageFolder(), installationFolder); _diskTransferService.MirrorFolder(_appFolderInfo.GetUpdatePackageFolder(), installationFolder);
// Set executable flag on Lidarr app // Set executable flag on Lidarr app
if (OsInfo.IsOsx) if (OsInfo.IsOsx || (OsInfo.IsLinux && PlatformInfo.IsNetCore))
{ {
_diskProvider.SetPermissions(Path.Combine(installationFolder, "Lidarr"), "0755", null, null); _diskProvider.SetPermissions(Path.Combine(installationFolder, "Lidarr"), "0755", null, null);
} }

@ -3,6 +3,7 @@ using System.IO;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
using IServiceProvider = NzbDrone.Common.IServiceProvider; using IServiceProvider = NzbDrone.Common.IServiceProvider;
@ -62,12 +63,12 @@ namespace NzbDrone.Update.UpdateEngine
private void StartWinform(string installationFolder) private void StartWinform(string installationFolder)
{ {
Start(installationFolder, "Lidarr.exe"); Start(installationFolder, "Lidarr".ProcessNameToExe());
} }
private void StartConsole(string installationFolder) private void StartConsole(string installationFolder)
{ {
Start(installationFolder, "Lidarr.Console.exe"); Start(installationFolder, "Lidarr.Console".ProcessNameToExe());
} }
private void Start(string installationFolder, string fileName) private void Start(string installationFolder, string fileName)
@ -83,4 +84,4 @@ namespace NzbDrone.Update.UpdateEngine
_processProvider.SpawnNewProcess(path, _startupContext.PreservedArguments); _processProvider.SpawnNewProcess(path, _startupContext.PreservedArguments);
} }
} }
} }

@ -25,15 +25,17 @@ namespace NzbDrone.Windows.Test.DiskProviderTests
if (Directory.Exists(path)) if (Directory.Exists(path))
{ {
var ds = Directory.GetAccessControl(path); var directory = new DirectoryInfo(path);
var ds = directory.GetAccessControl();
ds.SetAccessRule(new FileSystemAccessRule(owner, FileSystemRights.Write, accessControlType)); ds.SetAccessRule(new FileSystemAccessRule(owner, FileSystemRights.Write, accessControlType));
Directory.SetAccessControl(path, ds); directory.SetAccessControl(ds);
} }
else else
{ {
var fs = File.GetAccessControl(path); var file = new FileInfo(path);
var fs = file.GetAccessControl();
fs.SetAccessRule(new FileSystemAccessRule(owner, FileSystemRights.Write, accessControlType)); fs.SetAccessRule(new FileSystemAccessRule(owner, FileSystemRights.Write, accessControlType));
File.SetAccessControl(path, fs); file.SetAccessControl(fs);
} }
} }
} }

@ -6,7 +6,7 @@ using NzbDrone.Test.Common;
namespace NzbDrone.Windows.Test.EnvironmentInfo namespace NzbDrone.Windows.Test.EnvironmentInfo
{ {
[TestFixture] [TestFixture]
[Platform("Win")] [Platform("Net")]
public class DotNetPlatformInfoFixture : TestBase<PlatformInfo> public class DotNetPlatformInfoFixture : TestBase<PlatformInfo>
{ {
[Test] [Test]

@ -1,7 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Common.Test\Lidarr.Common.Test.csproj" /> <ProjectReference Include="..\NzbDrone.Common.Test\Lidarr.Common.Test.csproj" />
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />

@ -2,6 +2,7 @@
using System.IO; using System.IO;
using System.IO.Abstractions; using System.IO.Abstractions;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.AccessControl;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnsureThat; using NzbDrone.Common.EnsureThat;
@ -50,9 +51,10 @@ namespace NzbDrone.Windows.Disk
{ {
Ensure.That(filename, () => filename).IsValidPath(); Ensure.That(filename, () => filename).IsValidPath();
var fs = File.GetAccessControl(filename); var file = _fileSystem.FileInfo.FromFileName(filename);
var fs = file.GetAccessControl();
fs.SetAccessRuleProtection(false, false); fs.SetAccessRuleProtection(false, false);
File.SetAccessControl(filename, fs); file.SetAccessControl(fs);
} }
public override void SetPermissions(string path, string mask, string user, string group) public override void SetPermissions(string path, string mask, string user, string group)

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.6.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Common\Lidarr.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Common\Lidarr.Common.csproj" />

@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers> <RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>..\NzbDrone.Host\NzbDrone.ico</ApplicationIcon> <ApplicationIcon>..\NzbDrone.Host\NzbDrone.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
<GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources> <GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources>
@ -13,7 +14,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" /> <ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -10,21 +10,22 @@
<Target Name="PublishAllRids"> <Target Name="PublishAllRids">
<ItemGroup> <ItemGroup>
<!-- Transform RuntimeIdentifiers property to item -->
<Runtimes Include="$(RuntimeIdentifiers)" />
<Frameworks Include="$(TargetFrameworks)" /> <Frameworks Include="$(TargetFrameworks)" />
<Combined1 Include="@(Runtimes)"> <Combined Include="$(RuntimeIdentifiers)">
<Runtime>%(Runtimes.Identity)</Runtime>
</Combined1>
<Combined2 Include="@(Combined1)">
<Framework>%(Frameworks.Identity)</Framework> <Framework>%(Frameworks.Identity)</Framework>
</Combined2> </Combined>
<Renamed Include="@(Combined->'%(Identity):%(Framework)')">
<Runtime>%(Identity)</Runtime>
<Framework>%(Framework)</Framework>
</Renamed>
<Renamed Remove="$(ExcludedRuntimeFrameworkPairs)" />
<!-- Transform RuntimeIdentifierForPublish items to project items to pass to MSBuild task --> <!-- Transform RuntimeIdentifierForPublish items to project items to pass to MSBuild task -->
<ProjectToPublish Include="@(Combined2->'$(MSBuildProjectFullPath)')"> <ProjectToPublish Include="@(Renamed->'$(MSBuildProjectFullPath)')">
<AdditionalProperties>RuntimeIdentifier=%(Combined2.Runtime);TargetFramework=%(Combined2.Framework)</AdditionalProperties> <AdditionalProperties>RuntimeIdentifier=%(Renamed.Runtime);TargetFramework=%(Renamed.Framework)</AdditionalProperties>
</ProjectToPublish> </ProjectToPublish>
</ItemGroup> </ItemGroup>

@ -1,6 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>WinExe</OutputType>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="System.Security.Principal.Windows" Version="4.6.0" />
</ItemGroup>
</Project> </Project>

@ -1,6 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>WinExe</OutputType>
<TargetFrameworks>net462</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="System.Security.Principal.Windows" Version="4.6.0" />
</ItemGroup>
</Project> </Project>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="XPlat code coverage">
<Configuration>
<Format>opencover</Format>
<Exclude>[Lidarr.*.Test]*,[Lidarr.Test.*]*,[Lidarr.Api.V1]*,[Marr.Data]*,[MonoTorrent]*</Exclude>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
<InProcDataCollectionRunSettings>
<InProcDataCollectors>
<InProcDataCollector assemblyQualifiedName="Coverlet.Collector.DataCollection.CoverletInProcDataCollector, coverlet.collector, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null"
friendlyName="XPlat Code Coverage"
enabled="True"
codebase="coverlet.collector.dll" />
</InProcDataCollectors>
</InProcDataCollectionRunSettings>
</RunSettings>

@ -2,7 +2,7 @@
PLATFORM=$1 PLATFORM=$1
TYPE=$2 TYPE=$2
COVERAGE=$3 COVERAGE=$3
WHERE="cat != ManualTest" WHERE="Category!=ManualTest"
TEST_PATTERN="*Test.dll" TEST_PATTERN="*Test.dll"
ASSEMBLIES="" ASSEMBLIES=""
TEST_LOG_FILE="TestLog.txt" TEST_LOG_FILE="TestLog.txt"
@ -16,16 +16,12 @@ if [ -d "$TEST_DIR/_tests" ]; then
TEST_DIR="$TEST_DIR/_tests" TEST_DIR="$TEST_DIR/_tests"
fi fi
COVERAGE_RESULT_DIRECTORY="$TEST_DIR/CoverageResults/"
rm -f "$TEST_LOG_FILE" rm -f "$TEST_LOG_FILE"
# Uncomment to log test output to a file instead of the console # Uncomment to log test output to a file instead of the console
export LIDARR_TESTS_LOG_OUTPUT="File" export LIDARR_TESTS_LOG_OUTPUT="File"
NUNIT="$TEST_DIR/NUnit.ConsoleRunner.3.10.0/tools/nunit3-console.exe" VSTEST_PARAMS="--Platform:x64 --logger:nunit;LogFilePath=TestResult.xml"
NUNIT_COMMAND="$NUNIT"
NUNIT_PARAMS="--workers=1"
if [ "$PLATFORM" = "Mac" ]; then if [ "$PLATFORM" = "Mac" ]; then
@ -39,22 +35,21 @@ fi
if [ "$PLATFORM" = "Windows" ]; then if [ "$PLATFORM" = "Windows" ]; then
mkdir -p "$ProgramData/Lidarr" mkdir -p "$ProgramData/Lidarr"
WHERE="$WHERE && cat != LINUX" WHERE="$WHERE&Category!=LINUX"
elif [ "$PLATFORM" = "Linux" ] || [ "$PLATFORM" = "Mac" ] ; then elif [ "$PLATFORM" = "Linux" ] || [ "$PLATFORM" = "Mac" ] ; then
mkdir -p ~/.config/Lidarr mkdir -p ~/.config/Lidarr
WHERE="$WHERE && cat != WINDOWS" WHERE="$WHERE&Category!=WINDOWS"
NUNIT_COMMAND="mono --debug --runtime=v4.0 $NUNIT"
else else
echo "Platform must be provided as first arguement: Windows, Linux or Mac" echo "Platform must be provided as first arguement: Windows, Linux or Mac"
exit 1 exit 1
fi fi
if [ "$TYPE" = "Unit" ]; then if [ "$TYPE" = "Unit" ]; then
WHERE="$WHERE && cat != IntegrationTest && cat != AutomationTest" WHERE="$WHERE&Category!=IntegrationTest&Category!=AutomationTest"
elif [ "$TYPE" = "Integration" ] || [ "$TYPE" = "int" ] ; then elif [ "$TYPE" = "Integration" ] || [ "$TYPE" = "int" ] ; then
WHERE="$WHERE && cat == IntegrationTest" WHERE="$WHERE&Category=IntegrationTest"
elif [ "$TYPE" = "Automation" ] ; then elif [ "$TYPE" = "Automation" ] ; then
WHERE="$WHERE && cat == AutomationTest" WHERE="$WHERE&Category=AutomationTest"
else else
echo "Type must be provided as second argument: Unit, Integration or Automation" echo "Type must be provided as second argument: Unit, Integration or Automation"
exit 2 exit 2
@ -64,19 +59,13 @@ for i in `find $TEST_DIR -name "$TEST_PATTERN"`;
do ASSEMBLIES="$ASSEMBLIES $i" do ASSEMBLIES="$ASSEMBLIES $i"
done done
DOTNET_PARAMS="$ASSEMBLIES --TestCaseFilter:$WHERE $VSTEST_PARAMS"
if [ "$COVERAGE" = "Coverage" ]; then if [ "$COVERAGE" = "Coverage" ]; then
if [ "$PLATFORM" = "Windows" ] || [ "$PLATFORM" = "Linux" ]; then dotnet vstest $DOTNET_PARAMS --settings:"src/coverlet.runsettings" --ResultsDirectory:./CoverageResults
dotnet tool install coverlet.console --tool-path="$TEST_DIR/coverlet/" EXIT_CODE=$?
mkdir $COVERAGE_RESULT_DIRECTORY
OPEN_COVER="$TEST_DIR/coverlet/coverlet"
$OPEN_COVER "$TEST_DIR/" --verbosity "detailed" --format "cobertura" --format "opencover" --output "$COVERAGE_RESULT_DIRECTORY" --exclude "[Lidarr.*.Test]*" --exclude "[Lidarr.Test.*]*" --exclude "[Lidarr.Api.V1]*" --exclude "[Marr.Data]*" --exclude "[MonoTorrent]*" --exclude "[CurlSharp]*" --target "$NUNIT" --targetargs "$NUNIT_PARAMS --where=\"$WHERE\" $ASSEMBLIES";
EXIT_CODE=$?
else
echo "Coverage only supported on Windows and Linux"
exit 3
fi
elif [ "$COVERAGE" = "Test" ] ; then elif [ "$COVERAGE" = "Test" ] ; then
$NUNIT_COMMAND --where "$WHERE" $NUNIT_PARAMS $ASSEMBLIES; dotnet vstest $DOTNET_PARAMS
EXIT_CODE=$? EXIT_CODE=$?
else else
echo "Run Type must be provided as third argument: Coverage or Test" echo "Run Type must be provided as third argument: Coverage or Test"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -2,15 +2,6 @@
# yarn lockfile v1 # yarn lockfile v1
"@aspnet/signalr@1.1.4":
version "1.1.4"
resolved "https://registry.yarnpkg.com/@aspnet/signalr/-/signalr-1.1.4.tgz#417cf808f4074a8aec45d27f03c4b8df9d96bb0b"
integrity sha512-Jp9nPc8hmmhbG9OKiHe2fOKskBHfg+3Y9foSKHxjgGtyI743hXjGFv3uFlUg503K9f8Ilu63gQt3fDkLICBRyg==
dependencies:
eventsource "^1.0.7"
request "^2.88.0"
ws "^6.0.0"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5":
version "7.5.5" version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
@ -912,6 +903,15 @@
normalize-path "^2.0.1" normalize-path "^2.0.1"
through2 "^2.0.3" through2 "^2.0.3"
"@microsoft/signalr@3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-3.0.0.tgz#df03564f900957db0a62469cad576eb573368c9d"
integrity sha512-M0KMWvJ62yZuizPxFLZakitJb4aOZkJH6epXTLvp5LednJZdzacRDxWT3La7Cexp1cHxVbldBFtc3jrdfwmtxw==
dependencies:
eventsource "^1.0.7"
request "^2.88.0"
ws "^6.0.0"
"@mrmlnc/readdir-enhanced@^2.2.1": "@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"

Loading…
Cancel
Save