host_mode_t detect_operating_mode(const host_startup_info_t& host_info)
{
- if (coreclr_exists_in_dir(host_info.dotnet_root) || pal::file_exists(host_info.app_path))
+ if (coreclr_exists_in_dir(host_info.dotnet_root))
{
- pal::string_t own_deps_json = host_info.dotnet_root;
- pal::string_t own_deps_filename = host_info.get_app_name() + _X(".deps.json");
- pal::string_t own_config_filename = host_info.get_app_name() + _X(".runtimeconfig.json");
- append_path(&own_deps_json, own_deps_filename.c_str());
- if (trace::is_enabled())
- {
- trace::info(_X("Detecting mode... CoreCLR present in dotnet root [%s] and checking if [%s] file present=[%d]"),
- host_info.dotnet_root.c_str(), own_deps_filename.c_str(), pal::file_exists(own_deps_json));
- }
- return ((pal::file_exists(own_deps_json) || !pal::file_exists(own_config_filename)) && pal::file_exists(host_info.app_path)) ? host_mode_t::apphost : host_mode_t::split_fx;
+ // Detect between standalone apphost or legacy split mode (specifying --depsfile and --runtimeconfig)
+
+ pal::string_t deps_in_dotnet_root = host_info.dotnet_root;
+ pal::string_t deps_filename = host_info.get_app_name() + _X(".deps.json");
+ append_path(&deps_in_dotnet_root, deps_filename.c_str());
+ bool deps_exists = pal::file_exists(deps_in_dotnet_root);
+
+ trace::info(_X("Detecting mode... CoreCLR present in dotnet root [%d] and checking if [%s] file present=[%d]"),
+ host_info.dotnet_root.c_str(), deps_filename.c_str(), deps_exists);
+
+ // Name of runtimeconfig file; since no path is included here the check is in the current working directory
+ pal::string_t config_in_cwd = host_info.get_app_name() + _X(".runtimeconfig.json");
+
+ return (deps_exists || !pal::file_exists(config_in_cwd)) && pal::file_exists(host_info.app_path) ? host_mode_t::apphost : host_mode_t::split_fx;
}
- else
+
+ if (pal::file_exists(host_info.app_path))
{
- return host_mode_t::muxer;
+ // Framework-dependent apphost
+ return host_mode_t::apphost;
}
+
+ return host_mode_t::muxer;
}
void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str)
// 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 FluentAssertions;
+using Microsoft.DotNet.Cli.Build.Framework;
+using Microsoft.DotNet.CoreSetup.Test;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Text;
using System.Text.RegularExpressions;
using Xunit;
-using FluentAssertions;
-using Microsoft.DotNet.CoreSetup.Test;
namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.PortableApp
{
.Fail();
}
+ [Fact]
+ public void Framework_Dependent_AppHost_Succeeds()
+ {
+ var fixture = PreviouslyPublishedAndRestoredPortableTestProjectFixture
+ .Copy();
+
+ // Since SDK doesn't support building framework dependent apphost yet, emulate that behavior
+ // by creating the executable from apphost.exe
+ var appExe = fixture.TestProject.AppExe;
+ var appDllName = Path.GetFileName(fixture.TestProject.AppDll);
+
+ string hostExeName = $"apphost{Constants.ExeSuffix}";
+ string builtAppHost = Path.Combine(RepoDirectories.HostArtifacts, hostExeName);
+ string appDir = Path.GetDirectoryName(appExe);
+ string appDirHostExe = Path.Combine(appDir, hostExeName);
+
+ // Make a copy of apphost first, replace hash and overwrite app.exe, rather than
+ // overwrite app.exe and edit in place, because the file is opened as "write" for
+ // the replacement -- the test fails with ETXTBSY (exit code: 26) in Linux when
+ // executing a file opened in "write" mode.
+ File.Copy(builtAppHost, appDirHostExe, true);
+ using (var sha256 = SHA256.Create())
+ {
+ // Replace the hash with the managed DLL name.
+ var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes("foobar"));
+ var hashStr = BitConverter.ToString(hash).Replace("-", "").ToLower();
+ AppHostExtensions.SearchAndReplace(appDirHostExe, Encoding.UTF8.GetBytes(hashStr), Encoding.UTF8.GetBytes(appDllName), true);
+ }
+ File.Copy(appDirHostExe, appExe, true);
+
+ // Get the framework location that was built
+ string builtDotnet = fixture.BuiltDotnet.BinPath;
+
+ // Verify running with the default working directory
+ Command.Create(appExe)
+ .CaptureStdErr()
+ .CaptureStdOut()
+ .EnvironmentVariable("DOTNET_ROOT", builtDotnet)
+ .EnvironmentVariable("DOTNET_ROOT(x86)", builtDotnet)
+ .Execute()
+ .Should()
+ .Pass()
+ .And
+ .HaveStdOutContaining("Hello World");
+
+ // Verify running from within the working directory
+ Command.Create(appExe)
+ .WorkingDirectory(fixture.TestProject.OutputDirectory)
+ .EnvironmentVariable("DOTNET_ROOT", builtDotnet)
+ .EnvironmentVariable("DOTNET_ROOT(x86)", builtDotnet)
+ .CaptureStdErr()
+ .CaptureStdOut()
+ .Execute()
+ .Should()
+ .Pass()
+ .And
+ .HaveStdOutContaining("Hello World");
+ }
+
private void MoveDepsJsonToSubdirectory(TestProjectFixture testProjectFixture)
{
var subdirectory = Path.Combine(testProjectFixture.TestProject.ProjectDirectory, "d");
testProjectFixture.TestProject.RuntimeConfigJson = destRuntimeConfig;
}
- private string CreateAStore(TestProjectFixture testProjectFixture)
+ private string CreateAStore(TestProjectFixture testProjectFixture)
{
var storeoutputDirectory = Path.Combine(testProjectFixture.TestProject.ProjectDirectory, "store");
if (!Directory.Exists(storeoutputDirectory))