public static List <LogInfo> SystemCmd(EngineState s, CodeCommand cmd) { List <LogInfo> logs = new List <LogInfo>(1); CodeInfo_System info = cmd.Info.Cast <CodeInfo_System>(); SystemType type = info.Type; switch (type) { case SystemType.Cursor: { SystemInfo_Cursor subInfo = info.SubInfo.Cast <SystemInfo_Cursor>(); string iconStr = StringEscaper.Preprocess(s, subInfo.State); if (iconStr.Equals("WAIT", StringComparison.OrdinalIgnoreCase)) { Application.Current?.Dispatcher?.Invoke(() => { System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait; }); s.CursorWait = true; logs.Add(new LogInfo(LogState.Success, "Mouse cursor icon set to [Wait]")); } else if (iconStr.Equals("NORMAL", StringComparison.OrdinalIgnoreCase)) { Application.Current?.Dispatcher?.Invoke(() => { System.Windows.Input.Mouse.OverrideCursor = null; }); s.CursorWait = false; logs.Add(new LogInfo(LogState.Success, "Mouse cursor icon set to [Normal]")); } else { logs.Add(new LogInfo(LogState.Error, $"[{iconStr}] is not a valid mouse cursor icon")); } } break; case SystemType.ErrorOff: { SystemInfo_ErrorOff subInfo = info.SubInfo.Cast <SystemInfo_ErrorOff>(); string linesStr = StringEscaper.Preprocess(s, subInfo.Lines); if (!NumberHelper.ParseInt32(linesStr, out int lines)) { return(LogInfo.LogErrorMessage(logs, $"[{linesStr}] is not a positive integer")); } if (lines <= 0) { return(LogInfo.LogErrorMessage(logs, $"[{linesStr}] is not a positive integer")); } if (s.ErrorOff == null) { // Enable s.ErrorOff // Write to s.ErrorOffWaitingRegister instead of s.ErrorOff, to prevent muting error of [System,ErrorOff] itself. EngineLocalState ls = s.PeekLocalState(); if (s.ErrorOffDepthMinusOne) { ls = ls.UpdateDepth(ls.Depth - 1); } ErrorOffState newState = new ErrorOffState { LocalState = ls, StartLineIdx = cmd.LineIdx, LineCount = lines, }; s.ErrorOffWaitingRegister = newState; s.ErrorOffDepthMinusOne = false; logs.Add(new LogInfo(LogState.Success, $"Error and warning logs will be muted for [{lines}] lines")); } else { // If s.ErrorOff is already enabled, do nothing. Ex) Nested ErrorOff logs.Add(new LogInfo(LogState.Ignore, "ErrorOff is already enabled")); } } break; case SystemType.GetEnv: { SystemInfo_GetEnv subInfo = info.SubInfo.Cast <SystemInfo_GetEnv>(); string envVarName = StringEscaper.Preprocess(s, subInfo.EnvVar); string envVarValue = Environment.GetEnvironmentVariable(envVarName); if (envVarValue == null) // Failure { logs.Add(new LogInfo(LogState.Ignore, $"Cannot get environment variable [%{envVarName}%]'s value")); envVarValue = string.Empty; } logs.Add(new LogInfo(LogState.Success, $"Environment variable [{envVarName}]'s value is [{envVarValue}]")); List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, envVarValue); logs.AddRange(varLogs); } break; case SystemType.GetFreeDrive: { SystemInfo_GetFreeDrive subInfo = info.SubInfo.Cast <SystemInfo_GetFreeDrive>(); DriveInfo[] drives = DriveInfo.GetDrives(); // ReSharper disable once StringLiteralTypo const string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char lastFreeLetter = letters.Except(drives.Select(d => d.Name[0])).LastOrDefault(); if (lastFreeLetter != '\0') // Success { logs.Add(new LogInfo(LogState.Success, $"Last free drive letter is [{lastFreeLetter}]")); List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, lastFreeLetter.ToString(CultureInfo.InvariantCulture)); logs.AddRange(varLogs); } else // No Free Drives { // TODO: Is it correct WB082 behavior? logs.Add(new LogInfo(LogState.Ignore, "No free drive letter")); List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, string.Empty); logs.AddRange(varLogs); } } break; case SystemType.GetFreeSpace: { SystemInfo_GetFreeSpace subInfo = info.SubInfo.Cast <SystemInfo_GetFreeSpace>(); string path = StringEscaper.Preprocess(s, subInfo.Path); FileInfo f = new FileInfo(path); if (f.Directory == null) { return(LogInfo.LogErrorMessage(logs, $"Unable to get drive information for [{path}]")); } DriveInfo drive = new DriveInfo(f.Directory.Root.FullName); long freeSpaceMegaByte = drive.TotalFreeSpace / (1024 * 1024); // B to MB List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, freeSpaceMegaByte.ToString(CultureInfo.InvariantCulture)); logs.AddRange(varLogs); } break; case SystemType.IsAdmin: { SystemInfo_IsAdmin subInfo = info.SubInfo.Cast <SystemInfo_IsAdmin>(); bool isAdmin; using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) { WindowsPrincipal principal = new WindowsPrincipal(identity); isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator); } if (isAdmin) { logs.Add(new LogInfo(LogState.Success, "PEBakery is running as Administrator")); } else { logs.Add(new LogInfo(LogState.Success, "PEBakery is not running as Administrator")); } List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, isAdmin.ToString(CultureInfo.InvariantCulture)); logs.AddRange(varLogs); } break; case SystemType.OnBuildExit: { SystemInfo_OnBuildExit subInfo = info.SubInfo.Cast <SystemInfo_OnBuildExit>(); s.OnBuildExit = subInfo.Cmd; logs.Add(new LogInfo(LogState.Success, "OnBuildExit callback registered")); } break; case SystemType.OnScriptExit: { SystemInfo_OnScriptExit subInfo = info.SubInfo.Cast <SystemInfo_OnScriptExit>(); s.OnScriptExit = subInfo.Cmd; logs.Add(new LogInfo(LogState.Success, "OnScriptExit callback registered")); } break; case SystemType.RefreshInterface: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo), "Invalid CodeInfo"); s.MainViewModel.StartRefreshScript().Wait(); logs.Add(new LogInfo(LogState.Success, $"Re-rendered script [{cmd.Section.Script.Title}]")); } break; case SystemType.RescanScripts: case SystemType.RefreshAllScripts: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo), "Invalid CodeInfo"); // Refresh Project s.MainViewModel.StartLoadingProjects(true, true).Wait(); logs.Add(new LogInfo(LogState.Success, $"Reload project [{cmd.Section.Script.Project.ProjectName}]")); } break; case SystemType.LoadNewScript: { SystemInfo_LoadNewScript subInfo = info.SubInfo.Cast <SystemInfo_LoadNewScript>(); string srcFilePath = StringEscaper.Preprocess(s, subInfo.SrcFilePath); string destTreeDir = StringEscaper.Preprocess(s, subInfo.DestTreeDir); SearchOption searchOption = SearchOption.AllDirectories; if (subInfo.NoRecFlag) { searchOption = SearchOption.TopDirectoryOnly; } Debug.Assert(srcFilePath != null, "Internal Logic Error at CommandSystem.LoadNewScript"); // Check wildcard string wildcard = Path.GetFileName(srcFilePath); bool containsWildcard = wildcard.IndexOfAny(new[] { '*', '?' }) != -1; string[] files; if (containsWildcard) { // With wildcard files = FileHelper.GetFilesEx(FileHelper.GetDirNameEx(srcFilePath), wildcard, searchOption); if (files.Length == 0) { return(LogInfo.LogErrorMessage(logs, $"Script [{srcFilePath}] does not exist")); } } else { // No wildcard if (!File.Exists(srcFilePath)) { return(LogInfo.LogErrorMessage(logs, $"Script [{srcFilePath}] does not exist")); } files = new string[] { srcFilePath }; } List <Script> newScripts = new List <Script>(files.Length); string srcDirPath = Path.GetDirectoryName(srcFilePath); Debug.Assert(srcDirPath != null, $"{nameof(srcDirPath)} is null (CommandSystem.LoadNewScript)"); (string realPath, string treePath)[] fileTuples = files
public static List <LogInfo> SystemCmd(EngineState s, CodeCommand cmd) { List <LogInfo> logs = new List <LogInfo>(); Debug.Assert(cmd.Info.GetType() == typeof(CodeInfo_System)); CodeInfo_System info = cmd.Info as CodeInfo_System; SystemType type = info.Type; switch (type) { case SystemType.Cursor: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_Cursor)); SystemInfo_Cursor subInfo = info.SubInfo as SystemInfo_Cursor; string iconStr = StringEscaper.Preprocess(s, subInfo.IconKind); if (iconStr.Equals("WAIT", StringComparison.OrdinalIgnoreCase)) { Application.Current?.Dispatcher.Invoke(() => { System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait; }); logs.Add(new LogInfo(LogState.Success, "Mouse cursor icon set to [Wait]")); } else if (iconStr.Equals("NORMAL", StringComparison.OrdinalIgnoreCase)) { Application.Current?.Dispatcher.Invoke(() => { System.Windows.Input.Mouse.OverrideCursor = null; }); logs.Add(new LogInfo(LogState.Success, "Mouse cursor icon set to [Normal]")); } else { logs.Add(new LogInfo(LogState.Error, $"Wrong mouse cursor icon [{iconStr}]")); } } break; case SystemType.ErrorOff: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_ErrorOff)); SystemInfo_ErrorOff subInfo = info.SubInfo as SystemInfo_ErrorOff; string linesStr = StringEscaper.Preprocess(s, subInfo.Lines); if (!NumberHelper.ParseInt32(linesStr, out int lines)) { throw new ExecuteException($"[{linesStr}] is not a valid integer"); } if (lines <= 0) { throw new ExecuteException($"[{linesStr}] must be a positive integer"); } // +1 to not count ErrorOff itself s.ErrorOffSection = cmd.Addr.Section; s.ErrorOffStartLineIdx = cmd.LineIdx + 1; s.ErrorOffLineCount = lines; logs.Add(new LogInfo(LogState.Success, $"Error is off for [{lines}] lines")); } break; case SystemType.GetEnv: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_GetEnv)); SystemInfo_GetEnv subInfo = info.SubInfo as SystemInfo_GetEnv; string envVarName = StringEscaper.Preprocess(s, subInfo.EnvVarName); string envVarValue = Environment.GetEnvironmentVariable(envVarName); if (envVarValue == null) // Failure { logs.Add(new LogInfo(LogState.Ignore, $"Cannot get environment variable [%{envVarName}%]'s value")); envVarValue = string.Empty; } logs.Add(new LogInfo(LogState.Success, $"Environment variable [{envVarName}]'s value is [{envVarValue}]")); List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, envVarValue); logs.AddRange(varLogs); } break; case SystemType.GetFreeDrive: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_GetFreeDrive)); SystemInfo_GetFreeDrive subInfo = info.SubInfo as SystemInfo_GetFreeDrive; DriveInfo[] drives = DriveInfo.GetDrives(); string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char lastFreeLetter = letters.Except(drives.Select(d => d.Name[0])).LastOrDefault(); if (lastFreeLetter != '\0') // Success { logs.Add(new LogInfo(LogState.Success, $"Last free drive letter is [{lastFreeLetter}]")); List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, lastFreeLetter.ToString()); logs.AddRange(varLogs); } else // No Free Drives { // TODO: Is it correct WB082 behavior? logs.Add(new LogInfo(LogState.Ignore, "No free drive letter")); List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, string.Empty); logs.AddRange(varLogs); } } break; case SystemType.GetFreeSpace: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_GetFreeSpace)); SystemInfo_GetFreeSpace subInfo = info.SubInfo as SystemInfo_GetFreeSpace; string path = StringEscaper.Preprocess(s, subInfo.Path); FileInfo f = new FileInfo(path); DriveInfo drive = new DriveInfo(f.Directory.Root.FullName); long freeSpaceMB = drive.TotalFreeSpace / (1024 * 1024); // B to MB List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, freeSpaceMB.ToString()); logs.AddRange(varLogs); } break; case SystemType.IsAdmin: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_IsAdmin)); SystemInfo_IsAdmin subInfo = info.SubInfo as SystemInfo_IsAdmin; bool isAdmin; using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) { WindowsPrincipal principal = new WindowsPrincipal(identity); isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator); } if (isAdmin) { logs.Add(new LogInfo(LogState.Success, "PEBakery is running as Administrator")); } else { logs.Add(new LogInfo(LogState.Success, "PEBakery is not running as Administrator")); } List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, isAdmin.ToString()); logs.AddRange(varLogs); } break; case SystemType.OnBuildExit: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_OnBuildExit)); SystemInfo_OnBuildExit subInfo = info.SubInfo as SystemInfo_OnBuildExit; s.OnBuildExit = subInfo.Cmd; logs.Add(new LogInfo(LogState.Success, "OnBuildExit callback registered")); } break; case SystemType.OnScriptExit: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_OnScriptExit)); SystemInfo_OnScriptExit subInfo = info.SubInfo as SystemInfo_OnScriptExit; s.OnScriptExit = subInfo.Cmd; logs.Add(new LogInfo(LogState.Success, "OnScriptExit callback registered")); } break; case SystemType.RefreshInterface: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_RefreshInterface)); SystemInfo_RefreshInterface subInfo = info.SubInfo as SystemInfo_RefreshInterface; AutoResetEvent resetEvent = null; Application.Current?.Dispatcher.Invoke(() => { MainWindow w = (Application.Current.MainWindow as MainWindow); resetEvent = w.StartReloadScriptWorker(); }); if (resetEvent != null) { resetEvent.WaitOne(); } logs.Add(new LogInfo(LogState.Success, $"Rerendered script [{cmd.Addr.Script.Title}]")); } break; case SystemType.RescanScripts: case SystemType.LoadAll: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_LoadAll)); SystemInfo_LoadAll subInfo = info.SubInfo as SystemInfo_LoadAll; // Reload Project AutoResetEvent resetEvent = null; Application.Current?.Dispatcher.Invoke(() => { MainWindow w = (Application.Current.MainWindow as MainWindow); resetEvent = w.StartLoadWorker(true); }); if (resetEvent != null) { resetEvent.WaitOne(); } logs.Add(new LogInfo(LogState.Success, $"Reload project [{cmd.Addr.Script.Project.ProjectName}]")); } break; case SystemType.Load: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_Load)); SystemInfo_Load subInfo = info.SubInfo as SystemInfo_Load; string filePath = StringEscaper.Preprocess(s, subInfo.FilePath); SearchOption searchOption = SearchOption.AllDirectories; if (subInfo.NoRec) { searchOption = SearchOption.TopDirectoryOnly; } // Check wildcard string wildcard = Path.GetFileName(filePath); bool containsWildcard = (wildcard.IndexOfAny(new char[] { '*', '?' }) != -1); string[] files; if (containsWildcard) { // With wildcard files = FileHelper.GetFilesEx(FileHelper.GetDirNameEx(filePath), wildcard, searchOption); if (files.Length == 0) { logs.Add(new LogInfo(LogState.Error, $"Script [{filePath}] does not exist")); return(logs); } } else { // No wildcard if (!File.Exists(filePath)) { logs.Add(new LogInfo(LogState.Error, $"Script [{filePath}] does not exist")); return(logs); } files = new string[1] { filePath }; } int successCount = 0; foreach (string f in files) { string pFullPath = Path.GetFullPath(f); // Does this file already exists in project.AllScripts? Project project = cmd.Addr.Project; if (project.ContainsScriptByFullPath(pFullPath)) { // Project Tree conatins this script, so just refresh it // RefreshScript -> Update Project.AllScripts // TODO: Update EngineState.Scripts? Script p = Engine.GetScriptInstance(s, cmd, cmd.Addr.Script.FullPath, pFullPath, out bool inCurrentScript); p = s.Project.RefreshScript(p); if (p == null) { logs.Add(new LogInfo(LogState.Error, $"Unable to refresh script [{pFullPath}]")); continue; } // Update MainWindow and redraw Script Application.Current?.Dispatcher.Invoke(() => { MainWindow w = (Application.Current.MainWindow as MainWindow); w.UpdateScriptTree(project, false); if (p.Equals(w.CurMainTree.Script)) { w.CurMainTree.Script = p; w.DrawScript(w.CurMainTree.Script); } }); logs.Add(new LogInfo(LogState.Success, $"Refreshed script [{f}]")); successCount += 1; } else { // Add scripts into Project.AllScripts Script p = cmd.Addr.Project.LoadScriptMonkeyPatch(pFullPath, true, false); if (p == null) { logs.Add(new LogInfo(LogState.Error, $"Unable to load script [{pFullPath}]")); continue; } // Update MainWindow.MainTree and redraw Script Application.Current?.Dispatcher.Invoke(() => { MainWindow w = (Application.Current.MainWindow as MainWindow); w.UpdateScriptTree(project, false); if (p.Equals(w.CurMainTree.Script)) { w.CurMainTree.Script = p; w.DrawScript(w.CurMainTree.Script); } }); logs.Add(new LogInfo(LogState.Success, $"Loaded script [{f}], added to script tree")); successCount += 1; } } if (1 < files.Length) { logs.Add(new LogInfo(LogState.Success, $"Refresh or loaded [{successCount}] scripts")); } } break; case SystemType.SaveLog: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_SaveLog)); SystemInfo_SaveLog subInfo = info.SubInfo as SystemInfo_SaveLog; string destPath = StringEscaper.Preprocess(s, subInfo.DestPath); string logFormatStr = StringEscaper.Preprocess(s, subInfo.LogFormat); LogExportType logFormat = Logger.ParseLogExportType(logFormatStr); if (s.DisableLogger == false) { // When logger is disabled, s.BuildId is invalid. s.Logger.Build_Write(s, new LogInfo(LogState.Success, $"Exported Build Logs to [{destPath}]", cmd, s.CurDepth)); s.Logger.ExportBuildLog(logFormat, destPath, s.BuildId); } } break; case SystemType.SetLocal: { // SetLocal // No SystemInfo Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo)); Engine.EnableSetLocal(s, cmd.Addr.Section); logs.Add(new LogInfo(LogState.Success, "Local variables are isolated")); } break; case SystemType.EndLocal: { // EndLocal // No CodeInfo Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo)); Engine.DisableSetLocal(s, cmd.Addr.Section); logs.Add(new LogInfo(LogState.Success, "Local variables are no longer isolated")); } break; // WB082 Compatibility Shim case SystemType.HasUAC: { Debug.Assert(info.SubInfo.GetType() == typeof(SystemInfo_HasUAC)); SystemInfo_HasUAC subInfo = info.SubInfo as SystemInfo_HasUAC; logs.Add(new LogInfo(LogState.Warning, $"[System,HasUAC] is deprecated")); // Deprecated, WB082 Compability Shim List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, "True"); logs.AddRange(varLogs); } break; case SystemType.FileRedirect: // Do nothing logs.Add(new LogInfo(LogState.Ignore, $"[System,FileRedirect] is not necessary in PEBakery")); break; case SystemType.RegRedirect: // Do nothing logs.Add(new LogInfo(LogState.Ignore, $"[System,RegRedirect] is not necessary in PEBakery")); break; case SystemType.RebuildVars: { // Reset Variables to clean state s.Variables.ResetVariables(VarsType.Fixed); s.Variables.ResetVariables(VarsType.Global); s.Variables.ResetVariables(VarsType.Local); // Load Global Variables List <LogInfo> varLogs; varLogs = s.Variables.LoadDefaultGlobalVariables(); logs.AddRange(LogInfo.AddDepth(varLogs, s.CurDepth + 1)); // Load Per-Script Variables varLogs = s.Variables.LoadDefaultScriptVariables(cmd.Addr.Script); logs.AddRange(LogInfo.AddDepth(varLogs, s.CurDepth + 1)); // Load Per-Script Macro s.Macro.ResetLocalMacros(); varLogs = s.Macro.LoadLocalMacroDict(cmd.Addr.Script, false); logs.AddRange(LogInfo.AddDepth(varLogs, s.CurDepth + 1)); logs.Add(new LogInfo(LogState.Success, $"Variables are reset to their default state")); } break; default: // Error throw new InvalidCodeCommandException($"Wrong SystemType [{type}]"); } return(logs); }