dotnet-installer/src/dotnet/ShellShim/ShellShimRepository.cs
William Li cbd6434c8b Adapt to no config file Apphost shim
Instead of writing the config file. Embed the relative path, instead of only the file name of app binary, to the AppHost itself.
2018-04-06 12:23:05 -07:00

207 lines
7.3 KiB
C#

// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.PlatformAbstractions;
using Microsoft.DotNet.Tools;
using Microsoft.DotNet.Tools.Common;
using Microsoft.Extensions.EnvironmentAbstractions;
using Newtonsoft.Json;
namespace Microsoft.DotNet.ShellShim
{
internal class ShellShimRepository : IShellShimRepository
{
private const string ApphostNameWithoutExtension = "apphost";
private readonly DirectoryPath _shimsDirectory;
private readonly string _appHostSourceDirectory;
public ShellShimRepository(DirectoryPath shimsDirectory, string appHostSourcePath = null)
{
_shimsDirectory = shimsDirectory;
_appHostSourceDirectory = appHostSourcePath ?? Path.Combine(ApplicationEnvironment.ApplicationBasePath,
"AppHostTemplate");
}
public void CreateShim(FilePath targetExecutablePath, string commandName)
{
if (string.IsNullOrEmpty(targetExecutablePath.Value))
{
throw new ShellShimException(CommonLocalizableStrings.CannotCreateShimForEmptyExecutablePath);
}
if (string.IsNullOrEmpty(commandName))
{
throw new ShellShimException(CommonLocalizableStrings.CannotCreateShimForEmptyCommand);
}
if (ShimExists(commandName))
{
throw new ShellShimException(
string.Format(
CommonLocalizableStrings.ShellShimConflict,
commandName));
}
TransactionalAction.Run(
action: () =>
{
try
{
if (!Directory.Exists(_shimsDirectory.Value))
{
Directory.CreateDirectory(_shimsDirectory.Value);
}
CreateApphostShim(
commandName,
entryPoint: targetExecutablePath);
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
SetUserExecutionPermission(GetShimPath(commandName));
}
}
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
{
throw new ShellShimException(
string.Format(
CommonLocalizableStrings.FailedToCreateShellShim,
commandName,
ex.Message
),
ex);
}
},
rollback: () => {
foreach (var file in GetShimFiles(commandName).Where(f => File.Exists(f.Value)))
{
File.Delete(file.Value);
}
});
}
public void RemoveShim(string commandName)
{
var files = new Dictionary<string, string>();
TransactionalAction.Run(
action: () => {
try
{
foreach (var file in GetShimFiles(commandName).Where(f => File.Exists(f.Value)))
{
var tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
File.Move(file.Value, tempPath);
files[file.Value] = tempPath;
}
}
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
{
throw new ShellShimException(
string.Format(
CommonLocalizableStrings.FailedToRemoveShellShim,
commandName,
ex.Message
),
ex);
}
},
commit: () => {
foreach (var value in files.Values)
{
File.Delete(value);
}
},
rollback: () => {
foreach (var kvp in files)
{
File.Move(kvp.Value, kvp.Key);
}
});
}
private void CreateApphostShim(string commandName, FilePath entryPoint)
{
string appHostSourcePath;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
appHostSourcePath = Path.Combine(_appHostSourceDirectory, ApphostNameWithoutExtension + ".exe");
}
else
{
appHostSourcePath = Path.Combine(_appHostSourceDirectory, ApphostNameWithoutExtension);
}
var appHostDestinationFilePath = GetShimPath(commandName).Value;
var appBinaryFilePath = PathUtility.GetRelativePath(appHostDestinationFilePath, entryPoint.Value);
EmbedAppNameInHost.EmbedAndReturnModifiedAppHostPath(
appHostSourceFilePath: appHostSourcePath,
appHostDestinationFilePath: appHostDestinationFilePath,
appBinaryFilePath: appBinaryFilePath);
}
private class StartupOptions
{
public string appRoot { get; set; }
}
private class RootObject
{
public StartupOptions startupOptions { get; set; }
}
private bool ShimExists(string commandName)
{
return GetShimFiles(commandName).Any(p => File.Exists(p.Value));
}
private IEnumerable<FilePath> GetShimFiles(string commandName)
{
if (string.IsNullOrEmpty(commandName))
{
yield break;
}
yield return GetShimPath(commandName);
}
private FilePath GetShimPath(string commandName)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return new FilePath(_shimsDirectory.WithFile(commandName).Value +".exe");
}
else
{
return _shimsDirectory.WithFile(commandName);
}
}
private static void SetUserExecutionPermission(FilePath path)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}
CommandResult result = new CommandFactory()
.Create("chmod", new[] { "u+x", path.Value })
.CaptureStdOut()
.CaptureStdErr()
.Execute();
if (result.ExitCode != 0)
{
throw new ShellShimException(
string.Format(CommonLocalizableStrings.FailedSettingShimPermissions, result.StdErr));
}
}
}
}