예제 #1
0
        private static string GetRuntimeConfigPath(RemoteInvokeOptions options, out IEnumerable <IDisposable> toDispose)
        {
            if (options.RuntimeConfigurationOptions?.Any() != true)
            {
                toDispose = null;
                return(RuntimeConfigPath);
            }

            // to support RuntimeConfigurationOptions, copy the runtimeconfig.json file to
            // a temp file and add the options to the runtimeconfig.dev.json file.

            // NOTE: using the dev.json file so we don't need to parse and edit the runtimeconfig.json
            // which would require a reference to System.Text.Json.

            string tempFile      = System.IO.Path.GetTempFileName();
            string configFile    = tempFile + ".runtimeconfig.json";
            string devConfigFile = System.IO.Path.ChangeExtension(configFile, "dev.json");

            File.Copy(RuntimeConfigPath, configFile);

            string configProperties = string.Join(
                "," + Environment.NewLine,
                options.RuntimeConfigurationOptions.Select(kvp => $"\"{kvp.Key}\": {ToJsonString(kvp.Value)}"));

            string devConfigFileContents =
                @"
{
  ""runtimeOptions"": {
    ""configProperties"": {
"
                + configProperties +
                @"
    }
  }
}";

            File.WriteAllText(devConfigFile, devConfigFileContents);

            toDispose = new IDisposable[] { new FileDeleter(tempFile, configFile, devConfigFile) };
            return(configFile);
        }
예제 #2
0
        private static string GetConsoleAppArgs(RemoteInvokeOptions options, out IEnumerable <IDisposable> toDispose)
        {
            bool isNetCore = IsNetCore();

            if (options.RuntimeConfigurationOptions?.Any() == true && !isNetCore)
            {
                throw new InvalidOperationException("RuntimeConfigurationOptions are only supported on .NET Core");
            }

            if (!isNetCore)
            {
                toDispose = null;
                return(string.Empty);
            }

            string args = "exec";

            string runtimeConfigPath = GetRuntimeConfigPath(options, out toDispose);

            if (runtimeConfigPath != null)
            {
                args += $" --runtimeconfig \"{runtimeConfigPath}\"";
            }

            if (DepsJsonPath != null)
            {
                args += $" --depsfile \"{DepsJsonPath}\"";
            }

            if (!string.IsNullOrEmpty(options.RollForward))
            {
                args += $" --roll-forward {options.RollForward}";
            }

            args += $" \"{Path}\"";
            return(args);
        }
예제 #3
0
 /// <summary>Invokes the method from this assembly in another process using the specified arguments without performing any modifications to the arguments.</summary>
 /// <param name="method">The method to invoke.</param>
 /// <param name="unparsedArg">The arguments to pass to the method.</param>
 /// <param name="options">Options to use for the invocation.</param>
 public static RemoteInvokeHandle InvokeRaw(Delegate method, string unparsedArg,
                                            RemoteInvokeOptions options = null)
 {
     return(Invoke(GetMethodInfo(method), new[] { unparsedArg }, options, pasteArguments: false));
 }
예제 #4
0
 /// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
 /// <param name="method">The method to invoke.</param>
 /// <param name="arg1">The first argument to pass to the method.</param>
 /// <param name="arg2">The second argument to pass to the method.</param>
 /// <param name="arg3">The third argument to pass to the method.</param>
 /// <param name="arg4">The fourth argument to pass to the method.</param>
 /// <param name="arg5">The fifth argument to pass to the method.</param>
 /// <param name="options">Options to use for the invocation.</param>
 public static RemoteInvokeHandle Invoke(Func <string, string, string, string, string, int> method,
                                         string arg1, string arg2, string arg3, string arg4, string arg5, RemoteInvokeOptions options = null)
 {
     return(Invoke(GetMethodInfo(method), new[] { arg1, arg2, arg3, arg4, arg5 }, options));
 }
예제 #5
0
 /// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
 /// <param name="method">The method to invoke.</param>
 /// <param name="arg1">The first argument to pass to the method.</param>
 /// <param name="arg2">The second argument to pass to the method.</param>
 /// <param name="options">Options to use for the invocation.</param>
 public static RemoteInvokeHandle Invoke(Func <string, string, Task <int> > method, string arg1, string arg2,
                                         RemoteInvokeOptions options = null)
 {
     return(Invoke(GetMethodInfo(method), new[] { arg1, arg2 }, options));
 }
예제 #6
0
 /// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
 /// <param name="method">The method to invoke.</param>
 /// <param name="options">Options to use for the invocation.</param>
 public static RemoteInvokeHandle Invoke(Func <Task <int> > method, RemoteInvokeOptions options = null)
 {
     return(Invoke(GetMethodInfo(method), Array.Empty <string>(), options));
 }
예제 #7
0
        /// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
        /// <param name="method">The method to invoke.</param>
        /// <param name="options">Options to use for the invocation.</param>
        public static RemoteInvokeHandle Invoke(Action <string, string, string, string> method, string arg1,
                                                string arg2, string arg3, string arg4, RemoteInvokeOptions options = null)
        {
            // There's no exit code to check
            options = options ?? new RemoteInvokeOptions();
            options.CheckExitCode = false;

            return(Invoke(GetMethodInfo(method), new[] { arg1, arg2, arg3, arg4 }, options));
        }
예제 #8
0
        /// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
        /// <param name="method">The method to invoke.</param>
        /// <param name="args">The arguments to pass to the method.</param>
        /// <param name="options">Options to use for the invocation.</param>
        /// <param name="pasteArguments">true if this function should paste the arguments (e.g. surrounding with quotes); false if that responsibility is left up to the caller.</param>
        private static RemoteInvokeHandle Invoke(MethodInfo method, string[] args,
                                                 RemoteInvokeOptions options, bool pasteArguments = true)
        {
            options = options ?? new RemoteInvokeOptions();

            // For platforms that do not support RemoteExecutor
            if (!IsSupported)
            {
                throw new PlatformNotSupportedException("RemoteExecutor is not supported on this platform.");
            }

            // Verify the specified method returns an int (the exit code) or nothing,
            // and that if it accepts any arguments, they're all strings.
            Assert.True(method.ReturnType == typeof(void) ||
                        method.ReturnType == typeof(int) ||
                        method.ReturnType == typeof(Task) ||
                        method.ReturnType == typeof(Task <int>));
            Assert.All(method.GetParameters(), pi => Assert.Equal(typeof(string), pi.ParameterType));

            // And make sure it's in this assembly.  This isn't critical, but it helps with deployment to know
            // that the method to invoke is available because we're already running in this assembly.
            Type     t = method.DeclaringType;
            Assembly a = t.GetTypeInfo().Assembly;

            // Start the other process and return a wrapper for it to handle its lifetime and exit checking.
            ProcessStartInfo psi = options.StartInfo;

            psi.UseShellExecute = false;

            if (!options.EnableProfiling)
            {
                // Profilers / code coverage tools doing coverage of the test process set environment
                // variables to tell the targeted process what profiler to load.  We don't want the child process
                // to be profiled / have code coverage, so we remove these environment variables for that process
                // before it's started.
                psi.Environment.Remove("Cor_Profiler");
                psi.Environment.Remove("Cor_Enable_Profiling");
                psi.Environment.Remove("CoreClr_Profiler");
                psi.Environment.Remove("CoreClr_Enable_Profiling");
            }

            // If we need the host (if it exists), use it, otherwise target the console app directly.
            string metadataArgs       = PasteArguments.Paste(new string[] { a.FullName, t.FullName, method.Name, options.ExceptionFile }, pasteFirstArgumentUsingArgV0Rules: false);
            string passedArgs         = pasteArguments ? PasteArguments.Paste(args, pasteFirstArgumentUsingArgV0Rules: false) : string.Join(" ", args);
            string testConsoleAppArgs = s_extraParameter.Value + " " + metadataArgs + " " + passedArgs;

            if (options.RunAsSudo)
            {
                psi.FileName  = "sudo";
                psi.Arguments = HostRunner + " " + testConsoleAppArgs;

                // Create exception file up front so there are no permission issue when RemoteInvokeHandle tries to delete it.
                File.WriteAllText(options.ExceptionFile, "");
            }
            else
            {
                psi.FileName  = HostRunner;
                psi.Arguments = testConsoleAppArgs;
            }

            // Return the handle to the process, which may or not be started
            return(new RemoteInvokeHandle(options.Start ? Process.Start(psi) : new Process()
            {
                StartInfo = psi
            },
                                          options, a.FullName, t.FullName, method.Name));
        }