Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Management.Automation;
- public class RunspaceSynchronizer
- {
- public static bool SourceActionEnabled = false;
- private static bool TargetActionEnabled = false;
- // 'moduleCache' keeps track of all modules imported in the source Runspace.
- // when there is a `Import-Module -Force`, the new module object would be a
- // different instance with different hashcode, so we can tell if there is a
- // force loading of an already loaded module.
- private static HashSet<PSModuleInfo> moduleCache = new HashSet<PSModuleInfo>();
- // 'variableCache' keeps all global scope variable names and their value type.
- // As long as the value type doesn't change, we don't need to update the variable
- // in the target Runspace, because all tab completion needs is the type information.
- private static Dictionary<string, Type> variableCache = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
- public static List<PSModuleInfo> moduleToImport = new List<PSModuleInfo>();
- public static List<PSVariable> variablesToSet = new List<PSVariable>();
- private static EngineIntrinsics sourceEngineIntrinsics;
- private static EngineIntrinsics targetEngineIntrinsics;
- private static object syncObj = new object();
- private static bool sourceEventSubscribed = false;
- private static bool targetEventSubscribed = false;
- private static void CollectSourceRunspaceState(object sender, PSEventArgs args)
- {
- if (!SourceActionEnabled)
- {
- return;
- }
- try
- {
- // Maybe also track the latest history item id ($h = Get-History -Count 1; $h.Id)
- // to make sure we do the collection only if there was actually any input.
- var newOrChangedModules = new List<PSModuleInfo>();
- var newOrChangedVars = new List<PSVariable>();
- var results = sourceEngineIntrinsics.InvokeCommand.InvokeScript("Get-Module");
- foreach (var res in results)
- {
- var module = (PSModuleInfo) res.BaseObject;
- if (moduleCache.Add(module))
- {
- newOrChangedModules.Add(module);
- }
- }
- // Process variables to get those that need to be updated.
- // - first filter out the built-in variables.
- // - check against the existing variable cache, if the value type of a variable name remains the same,
- // then no need to update the variable.
- // - finally get a dictionary of new/updated variables.
- if (newOrChangedModules.Count == 0 && newOrChangedVars.Count == 0)
- {
- return;
- }
- lock (syncObj)
- {
- moduleToImport.AddRange(newOrChangedModules);
- variablesToSet.AddRange(newOrChangedVars);
- }
- // Enable the action in target Runspace
- TargetActionEnabled = true;
- } catch (Exception ex) {
- Console.WriteLine(ex.Message);
- Console.WriteLine(ex.StackTrace);
- }
- SourceActionEnabled = false;
- }
- private static void UpdateTargetRunspaceState(object sender, PSEventArgs args)
- {
- if (!TargetActionEnabled)
- {
- return;
- }
- List<PSModuleInfo> newOrChangedModules;
- List<PSVariable> newOrChangedVars;
- lock (syncObj)
- {
- newOrChangedModules = new List<PSModuleInfo>(moduleToImport);
- newOrChangedVars = new List<PSVariable>(variablesToSet);
- moduleToImport.Clear();
- variablesToSet.Clear();
- }
- if (newOrChangedModules.Count > 0)
- {
- // Import the modules with -Force
- }
- if (newOrChangedVars.Count > 0)
- {
- // Set or update the variables.
- }
- TargetActionEnabled = false;
- }
- public static PSEventSubscriber SubscribeOnIdleEvent(EngineIntrinsics engineIntrinsics, bool isSourceRunspace)
- {
- PSEventReceivedEventHandler handler = null;
- if (isSourceRunspace)
- {
- if (sourceEventSubscribed)
- {
- throw new InvalidOperationException("OnIdle even already subscribed in source Runspace.");
- }
- // Save the engineIntrinsics from source Runspace for later use.
- handler = (PSEventReceivedEventHandler) CollectSourceRunspaceState;
- sourceEngineIntrinsics = engineIntrinsics;
- sourceEventSubscribed = true;
- }
- else
- {
- if (targetEventSubscribed)
- {
- throw new InvalidOperationException("OnIdle even already subscribed in target Runspace.");
- }
- // Save the engineIntrinsics from target Runspace for later use.
- handler = (PSEventReceivedEventHandler) UpdateTargetRunspaceState;
- targetEngineIntrinsics = engineIntrinsics;
- targetEventSubscribed = true;
- }
- return engineIntrinsics.Events.SubscribeEvent(
- source: null,
- eventName: null,
- sourceIdentifier: PSEngineEvent.OnIdle.ToString(),
- data: null,
- handlerDelegate: handler,
- supportEvent: true,
- forwardEvent: false);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement