Added unit test for extracting runtime.

This commit is contained in:
Paul Knopf 2019-04-12 17:11:16 -04:00
parent 89d0bc3bee
commit 4bd92651ef
9 changed files with 282 additions and 4 deletions

View file

@ -1,6 +1,6 @@
image: Visual Studio 2017
before_build:
- ps: Invoke-WebRequest -Uri https://github.com/qmlnet/qt-runtimes/releases/download/releases/qt-5.12.2-de3f7b1-win-x64-dev.tar.gz -OutFile C:\qmlnet-qt.tar.gz
- ps: Invoke-WebRequest -Uri https://github.com/qmlnet/qt-runtimes/releases/download/releases/qt-5.12.2-877b810-win-x64-dev.tar.gz -OutFile C:\qmlnet-qt.tar.gz
- cmd: 7z x C:\qmlnet-qt.tar.gz -oC:\
- cmd: 7z x C:\qmlnet-qt.tar -oC:\qmlnet-qt
- cmd: rm -r C:\Tools\GitVersion\

View file

@ -6,7 +6,7 @@ QT_DIR=$SCRIPT_DIR/Qt
sudo apt-get install -y libgl1-mesa-dev
mkdir -p $QT_DIR
wget -O- -q https://github.com/qmlnet/qt-runtimes/releases/download/releases/qt-5.12.2-de3f7b1-linux-x64-dev.tar.gz | tar xpz -C $QT_DIR
wget -O- -q https://github.com/qmlnet/qt-runtimes/releases/download/releases/qt-5.12.2-877b810-linux-x64-dev.tar.gz | tar xpz -C $QT_DIR
export PATH=$QT_DIR/qt/bin:$PATH
export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/src/native/output:$QT_DIR/qt/lib

View file

@ -5,7 +5,7 @@ SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
QT_DIR=$SCRIPT_DIR/Qt
mkdir -p $QT_DIR
wget -O- -q https://github.com/qmlnet/qt-runtimes/releases/download/releases/qt-5.12.2-de3f7b1-osx-x64-dev.tar.gz | tar xpz -C $QT_DIR
wget -O- -q https://github.com/qmlnet/qt-runtimes/releases/download/releases/qt-5.12.2-877b810-osx-x64-dev.tar.gz | tar xpz -C $QT_DIR
export PATH=$QT_DIR/qt/bin:$PATH
export DYLD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/src/native/output:$QT_DIR/qt/lib

View file

@ -6,7 +6,9 @@
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="Moq" Version="4.10.1" />
<PackageReference Include="SharpCompress" Version="0.23.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />

View file

@ -0,0 +1,70 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using FluentAssertions;
using Qml.Net.Runtimes;
using SharpCompress.Common;
using SharpCompress.Readers;
using Xunit;
namespace Qml.Net.Tests
{
public class RuntimeManagerTests : IDisposable
{
private readonly string _tempDirectory;
public RuntimeManagerTests()
{
_tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString().Replace("-", ""));
Directory.CreateDirectory(_tempDirectory);
RuntimeManager.ExtractTarGZStream = (stream, directory) =>
{
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
reader.WriteEntryToDirectory(directory, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true,
WriteSymbolicLink = (sourcePath, targetPath) =>
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
throw new Exception("File links aren't supported.");
}
var link = new Mono.Unix.UnixSymbolicLinkInfo(sourcePath);
if (File.Exists(sourcePath))
{
link.Delete(); // equivalent to ln -s -f
}
link.CreateSymbolicLinkTo(targetPath);
}
});
}
}
}
};
}
[Fact]
public void Can_download_runtime()
{
RuntimeManager.DownloadRuntimeToDirectory(QmlNetConfig.QtBuildVersion, RuntimeTarget.Windows64, _tempDirectory);
File.ReadAllText(Path.Combine(_tempDirectory, "version.txt")).Should().Be($"{QmlNetConfig.QtBuildVersion}-win-x64");
}
public void Dispose()
{
if (Directory.Exists(_tempDirectory))
{
Directory.Delete(_tempDirectory, true);
}
}
}
}

View file

@ -1,3 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OSX/@EntryIndexedValue">OSX</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OSX/@EntryIndexedValue">OSX</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Runtimes/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -4,6 +4,8 @@ namespace Qml.Net
{
public class QmlNetConfig
{
public static string QtBuildVersion => "qt-5.12.2-877b810";
public static bool ListenForExceptionsWhenInvokingTasks { get; set; }
public static event Action<AggregateException> UnhandledTaskException;

View file

@ -0,0 +1,9 @@
namespace Qml.Net.Runtimes
{
public enum RuntimeTarget
{
LinuxX64,
OSX64,
Windows64
}
}

View file

@ -0,0 +1,194 @@
using System;
using System.IO;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Threading;
namespace Qml.Net.Runtimes
{
public static class RuntimeManager
{
public delegate string BuildRuntimeUrlDelegate(string qtVersion, RuntimeTarget target);
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
public static BuildRuntimeUrlDelegate BuildRuntimeUrl = (qtVersion, target) =>
{
var url = $"https://github.com/qmlnet/qt-runtimes/releases/download/releases/{qtVersion}-{{target}}-runtime.tar.gz";
switch (target)
{
case RuntimeTarget.Windows64:
return url.Replace("{target}", "win-x64");
case RuntimeTarget.LinuxX64:
return url.Replace("{target}", "linux-x64");
case RuntimeTarget.OSX64:
return url.Replace("{target}", "osx-64");
default:
throw new Exception($"Unknown target {target}");
}
};
public delegate void ExtractTarGZStreamDelegate(Stream stream, string destinationDirectory);
public static ExtractTarGZStreamDelegate ExtractTarGZStream;
public static RuntimeTarget GetCurrentRuntimeTarget()
{
if (IntPtr.Size != 8)
{
throw new Exception("Only 64bit supported");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return RuntimeTarget.Windows64;
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return RuntimeTarget.LinuxX64;
}
if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return RuntimeTarget.OSX64;
}
throw new Exception("Unknown OS platform");
}
public static void DownloadRuntimeToDirectory(string qtVersion,
RuntimeTarget runtimeTarget,
string destinationDirectory)
{
var extractTarGZStreamDel = ExtractTarGZStream;
if (extractTarGZStreamDel == null)
{
throw new Exception("You must set RuntimeManager.ExtractTarGZStream to properly extract a tar file.");
}
if (!Directory.Exists(destinationDirectory))
{
throw new Exception($"The directory \"{destinationDirectory}\" doesn't exist.");
}
if (Directory.GetFiles(destinationDirectory).Length > 0)
{
throw new Exception("The directory is not empty");
}
if (Directory.GetDirectories(destinationDirectory).Length > 0)
{
throw new Exception("The directory is not empty");
}
var url = BuildRuntimeUrl(qtVersion, runtimeTarget);
GetUrlStream(url, stream =>
{
extractTarGZStreamDel(stream, destinationDirectory);
});
}
public static void GetUrlStream(string url, Action<Stream> action)
{
var syncContext = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(null);
using (var httpClient = new HttpClient())
{
action(httpClient.GetStreamAsync(url).GetAwaiter().GetResult());
}
}
finally
{
SynchronizationContext.SetSynchronizationContext(syncContext);
}
}
//
// private static string GetRuntimeContainerDirectory()
// {
// var homeDirectory = (Environment.OSVersion.Platform == PlatformID.Unix ||
// Environment.OSVersion.Platform == PlatformID.MacOSX)
// ? Environment.GetEnvironmentVariable("HOME")
// : Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
// var runtimeDirector = Path.Combine(homeDirectory, ".qmlnet-runtimes");
// if (!Directory.Exists(runtimeDirector))
// {
//
// }
// }
//
// public static string GetRuntimeDirectory()
// {
// var runtimePath = Environment.GetEnvironmentVariable("QMLNET_QT_RUNTIME_DIR");
// if (!string.IsNullOrEmpty(runtimePath))
// {
// // There is already one ready for us to start using!
// return runtimePath;
// }
//
// // We must now detect the proper version, download it, and return it's path.
// var url = $"https://github.com/qmlnet/qt-runtimes/releases/download/releases/{QmlNetConfig.QtBuildVersion}-{GetPlatformIdentifier()}-runtime.tar.gz";
// }
public static void ConfigureRuntimeDirectory(string directory)
{
if (string.IsNullOrEmpty(directory))
{
throw new ArgumentNullException(nameof(directory));
}
if (!Directory.Exists(directory))
{
throw new Exception("The directory doesn't exist.");
}
var versionFile = Path.Combine(directory, "version.txt");
if (!File.Exists(versionFile))
{
throw new Exception("The version.txt file doesn't exist in the directory.");
}
var version = File.ReadAllText(versionFile).TrimEnd(Environment.NewLine.ToCharArray());
var expectedVersion = $"{QmlNetConfig.QtBuildVersion}-{GetCurrentRuntimeTarget()}";
if (version != expectedVersion)
{
throw new Exception($"The version of the runtime directory was {versionFile}, but expected {expectedVersion}");
}
var pluginsDirectory = Path.Combine(directory, "plugins");
if (!Directory.Exists(pluginsDirectory))
{
throw new Exception($"Plugins directory didn't exist: {pluginsDirectory}");
}
Environment.SetEnvironmentVariable("QT_PLUGIN_PATH", pluginsDirectory);
var qmlDirectory = Path.Combine(directory, "qml");
if (!Directory.Exists(qmlDirectory))
{
throw new Exception($"QML directory didn't exist: {qmlDirectory}");
}
Environment.SetEnvironmentVariable("QML2_IMPORT_PATH", qmlDirectory);
/*if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (!string.IsNullOrEmpty(libDirectory) && Directory.Exists(libDirectory))
{
// Even though we opened up the native dll correctly, we need to add
// the folder to the path. The reason is because QML plugins aren't
// in the same directory and have trouble finding dependencies
// that are within our lib folder.
Environment.SetEnvironmentVariable(
"PATH",
Environment.GetEnvironmentVariable("PATH") + $";{libDirectory}");
}
}*/
}
}
}