mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-11-27 18:11:20 +00:00
Add CLI support for running script and zip files
Launcher now accepts a --file argument to run .js or .zip files directly from the command line. MainForm and Program.cs were refactored to support this, including new registry entries in setup.iss for file associations with WelsonJS Script extensions.
This commit is contained in:
parent
ba7b3e3685
commit
c677c6907a
|
|
@ -20,6 +20,7 @@ namespace WelsonJS.Launcher
|
||||||
private readonly string _dateTimeFormat;
|
private readonly string _dateTimeFormat;
|
||||||
private readonly ICompatibleLogger _logger;
|
private readonly ICompatibleLogger _logger;
|
||||||
|
|
||||||
|
private string _filePath;
|
||||||
private string _workingDirectory;
|
private string _workingDirectory;
|
||||||
private string _instanceId;
|
private string _instanceId;
|
||||||
private string _scriptName;
|
private string _scriptName;
|
||||||
|
|
@ -122,6 +123,16 @@ namespace WelsonJS.Launcher
|
||||||
|
|
||||||
private void btnRunFromZipFile_Click(object sender, EventArgs e)
|
private void btnRunFromZipFile_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!String.IsNullOrEmpty(_filePath))
|
||||||
|
{
|
||||||
|
string fileExtension = Path.GetExtension(_filePath);
|
||||||
|
if (fileExtension != null && fileExtension.Equals(".zip", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
DisableUI();
|
||||||
|
Task.Run(() => RunAppPackageFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using (var openFileDialog = new OpenFileDialog())
|
using (var openFileDialog = new OpenFileDialog())
|
||||||
{
|
{
|
||||||
openFileDialog.Filter = "zip files (*.zip)|*.zip|All files (*.*)|*.*";
|
openFileDialog.Filter = "zip files (*.zip)|*.zip|All files (*.*)|*.*";
|
||||||
|
|
@ -130,15 +141,15 @@ namespace WelsonJS.Launcher
|
||||||
|
|
||||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||||
{
|
{
|
||||||
string filePath = openFileDialog.FileName;
|
_filePath = openFileDialog.FileName;
|
||||||
|
|
||||||
DisableUI();
|
DisableUI();
|
||||||
Task.Run(() => RunAppPackageFile(filePath));
|
Task.Run(() => RunAppPackageFile());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunAppPackageFile(string filePath)
|
private void RunAppPackageFile()
|
||||||
{
|
{
|
||||||
_instanceId = Guid.NewGuid().ToString();
|
_instanceId = Guid.NewGuid().ToString();
|
||||||
_workingDirectory = Program.GetWorkingDirectory(_instanceId);
|
_workingDirectory = Program.GetWorkingDirectory(_instanceId);
|
||||||
|
|
@ -153,7 +164,7 @@ namespace WelsonJS.Launcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to extract ZIP file
|
// try to extract ZIP file
|
||||||
ZipFile.ExtractToDirectory(filePath, _workingDirectory);
|
ZipFile.ExtractToDirectory(_filePath, _workingDirectory);
|
||||||
|
|
||||||
// record the first deploy time
|
// record the first deploy time
|
||||||
RecordFirstDeployTime(_workingDirectory, _instanceId);
|
RecordFirstDeployTime(_workingDirectory, _instanceId);
|
||||||
|
|
@ -339,5 +350,11 @@ namespace WelsonJS.Launcher
|
||||||
{
|
{
|
||||||
Program.OpenWebBrowser(Program.GetAppConfig("RepositoryUrl"));
|
Program.OpenWebBrowser(Program.GetAppConfig("RepositoryUrl"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RunFromZipFile(string filePath)
|
||||||
|
{
|
||||||
|
_filePath = filePath;
|
||||||
|
btnRunFromZipFile.PerformClick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,22 @@ namespace WelsonJS.Launcher
|
||||||
}
|
}
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
// if set the target file path
|
||||||
|
string targetFilePath = GetTargetFilePath(args);
|
||||||
|
if (!string.IsNullOrEmpty(targetFilePath))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
HandleTargetFilePath(targetFilePath);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error($"Initialization failed: {e}");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// create the mutex
|
// create the mutex
|
||||||
_mutex = new Mutex(true, "WelsonJS.Launcher", out bool createdNew);
|
_mutex = new Mutex(true, "WelsonJS.Launcher", out bool createdNew);
|
||||||
if (!createdNew)
|
if (!createdNew)
|
||||||
|
|
@ -56,14 +70,165 @@ namespace WelsonJS.Launcher
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
Application.Run(new MainForm(_logger));
|
Application.Run(new MainForm(_logger));
|
||||||
|
|
||||||
// destory the mutex
|
// release the mutex
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
_mutex.ReleaseMutex();
|
_mutex.ReleaseMutex();
|
||||||
} catch { /* ignore if not owned */ }
|
}
|
||||||
|
catch { /* ignore if not owned */ }
|
||||||
_mutex.Dispose();
|
_mutex.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RunCommandPrompt(string workingDirectory, string entryFileName, string scriptName, bool isConsoleApplication = false, bool isInteractiveServiceAapplication = false)
|
private static string GetTargetFilePath(string[] args)
|
||||||
|
{
|
||||||
|
if (args == null || args.Length == 0) return null;
|
||||||
|
|
||||||
|
for (int i = 0; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
string token = args[i];
|
||||||
|
if (string.Equals(token, "--file", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(token, "/file", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (i + 1 < args.Length)
|
||||||
|
{
|
||||||
|
return args[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.StartsWith("--file=", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return token.Substring("--file=".Length).Trim('"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleTargetFilePath(string filePath)
|
||||||
|
{
|
||||||
|
string fileExtension = Path.GetExtension(filePath);
|
||||||
|
|
||||||
|
if (String.IsNullOrEmpty(fileExtension))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The file extension is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileExtension.Equals(".zip", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var mainForm = new MainForm(_logger);
|
||||||
|
mainForm.Show();
|
||||||
|
mainForm.RunFromZipFile(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileExtension.Equals(".js", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string workingDirectory = CreateInstanceDirectory();
|
||||||
|
|
||||||
|
string appRoot = GetAppRootDirectory();
|
||||||
|
string appBaseSource = Path.Combine(appRoot, "app.js");
|
||||||
|
if (!File.Exists(appBaseSource))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException("app.js not found in application root.", appBaseSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
string appBaseDestination = Path.Combine(workingDirectory, "app.js");
|
||||||
|
File.Copy(appBaseSource, appBaseDestination, overwrite: true);
|
||||||
|
|
||||||
|
string assetsSource = Path.Combine(appRoot, "app", "assets", "js");
|
||||||
|
string assetsDestination = Path.Combine(workingDirectory, "app", "assets", "js");
|
||||||
|
CopyDirectoryRecursive(assetsSource, assetsDestination);
|
||||||
|
|
||||||
|
string entrypointDestination = Path.Combine(workingDirectory, "bootstrap.js");
|
||||||
|
File.Copy(filePath, entrypointDestination, overwrite: true);
|
||||||
|
|
||||||
|
RunCommandPrompt(
|
||||||
|
workingDirectory: workingDirectory,
|
||||||
|
entryFileName: "app.js",
|
||||||
|
scriptName: "bootstrap",
|
||||||
|
isConsoleApplication: true,
|
||||||
|
isInteractiveServiceApplication: false
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException($"Unsupported file type: {fileExtension}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetAppRootDirectory()
|
||||||
|
{
|
||||||
|
string[] candidates = new[]
|
||||||
|
{
|
||||||
|
GetAppConfig("AppRootDirectory"),
|
||||||
|
AppDomain.CurrentDomain.BaseDirectory,
|
||||||
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "WelsonJS"),
|
||||||
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WelsonJS"),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (string dir in candidates)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(dir))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string appJs = Path.Combine(dir, "app.js");
|
||||||
|
if (File.Exists(appJs))
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileNotFoundException("Could not locate app.js in any known application root directory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string CreateInstanceDirectory()
|
||||||
|
{
|
||||||
|
string instanceId = Guid.NewGuid().ToString();
|
||||||
|
string workingDirectory = GetWorkingDirectory(instanceId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// check if the working directory exists
|
||||||
|
if (Directory.Exists(workingDirectory))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("GUID validation failed. Directory already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory.CreateDirectory(workingDirectory);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw new Exception("Instance Initialization failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return workingDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyDirectoryRecursive(string sourceDir, string destDir)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(sourceDir))
|
||||||
|
{
|
||||||
|
throw new DirectoryNotFoundException("Source directory not found: " + sourceDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory.CreateDirectory(destDir);
|
||||||
|
|
||||||
|
foreach (var file in Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
string relativePath = file.Substring(sourceDir.Length).TrimStart(
|
||||||
|
Path.DirectorySeparatorChar,
|
||||||
|
Path.AltDirectorySeparatorChar
|
||||||
|
);
|
||||||
|
|
||||||
|
string targetPath = Path.Combine(destDir, relativePath);
|
||||||
|
string targetDir = Path.GetDirectoryName(targetPath);
|
||||||
|
if (!Directory.Exists(targetDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(targetDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.Copy(file, targetPath, overwrite: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RunCommandPrompt(string workingDirectory, string entryFileName, string scriptName, bool isConsoleApplication = false, bool isInteractiveServiceApplication = false)
|
||||||
{
|
{
|
||||||
if (!isConsoleApplication)
|
if (!isConsoleApplication)
|
||||||
{
|
{
|
||||||
|
|
@ -93,33 +258,37 @@ namespace WelsonJS.Launcher
|
||||||
};
|
};
|
||||||
process.Start();
|
process.Start();
|
||||||
|
|
||||||
process.StandardInput.WriteLine("pushd " + workingDirectory);
|
StreamWriter input = process.StandardInput;
|
||||||
process.StandardInput.WriteLine();
|
StreamReader output = process.StandardOutput;
|
||||||
process.StandardInput.Flush();
|
|
||||||
process.StandardOutput.ReadLine();
|
|
||||||
|
|
||||||
if (isInteractiveServiceAapplication)
|
input.WriteLine("pushd " + workingDirectory);
|
||||||
|
input.WriteLine();
|
||||||
|
input.Flush();
|
||||||
|
output.ReadLine();
|
||||||
|
|
||||||
|
if (isInteractiveServiceApplication)
|
||||||
{
|
{
|
||||||
process.StandardInput.WriteLine($"start cmd /c startInteractiveService.bat");
|
input.WriteLine($"start cmd /c startInteractiveService.bat");
|
||||||
process.StandardInput.WriteLine();
|
input.WriteLine();
|
||||||
process.StandardInput.Flush();
|
input.Flush();
|
||||||
process.StandardOutput.ReadLine();
|
output.ReadLine();
|
||||||
}
|
}
|
||||||
else if (!isConsoleApplication)
|
else if (!isConsoleApplication)
|
||||||
{
|
{
|
||||||
process.StandardInput.WriteLine(entryFileName);
|
input.WriteLine(entryFileName);
|
||||||
process.StandardInput.WriteLine();
|
input.WriteLine();
|
||||||
process.StandardInput.Flush();
|
input.Flush();
|
||||||
process.StandardOutput.ReadLine();
|
output.ReadLine();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
process.StandardInput.WriteLine($"start cmd /c cscript app.js {scriptName}");
|
input.WriteLine($"start cmd /c cscript app.js {scriptName}");
|
||||||
process.StandardInput.WriteLine();
|
input.WriteLine();
|
||||||
process.StandardInput.Flush();
|
input.Flush();
|
||||||
process.StandardOutput.ReadLine();
|
output.ReadLine();
|
||||||
}
|
}
|
||||||
process.StandardInput.Close();
|
input.Close();
|
||||||
|
|
||||||
process.WaitForExit();
|
process.WaitForExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
12
setup.iss
12
setup.iss
|
|
@ -25,12 +25,24 @@ DisableWelcomePage=yes
|
||||||
DisableDirPage=yes
|
DisableDirPage=yes
|
||||||
DisableProgramGroupPage=yes
|
DisableProgramGroupPage=yes
|
||||||
LicenseFile=SECURITY.MD
|
LicenseFile=SECURITY.MD
|
||||||
|
ChangesAssociations=yes
|
||||||
|
|
||||||
; [Registry]
|
; [Registry]
|
||||||
; Root: HKCR; Subkey: "welsonjs"; ValueType: "string"; ValueData: "URL:{cm:AppName}"; Flags: uninsdeletekey
|
; Root: HKCR; Subkey: "welsonjs"; ValueType: "string"; ValueData: "URL:{cm:AppName}"; Flags: uninsdeletekey
|
||||||
; Root: HKCR; Subkey: "welsonjs"; ValueType: "string"; ValueName: "URL Protocol"; ValueData: ""
|
; Root: HKCR; Subkey: "welsonjs"; ValueType: "string"; ValueName: "URL Protocol"; ValueData: ""
|
||||||
; Root: HKCR; Subkey: "welsonjs\DefaultIcon"; ValueType: "string"; ValueData: "{app}\app\favicon.ico,0"
|
; Root: HKCR; Subkey: "welsonjs\DefaultIcon"; ValueType: "string"; ValueData: "{app}\app\favicon.ico,0"
|
||||||
; Root: HKCR; Subkey: "welsonjs\shell\open\command"; ValueType: "string"; ValueData: "cscript ""{app}\app.js"" uriloader ""%1"""
|
; Root: HKCR; Subkey: "welsonjs\shell\open\command"; ValueType: "string"; ValueData: "cscript ""{app}\app.js"" uriloader ""%1"""
|
||||||
|
Root: HKCR; Subkey: "WelsonJS.Script"; ValueType: string; ValueData: "WelsonJS Script"; Flags: uninsdeletekey
|
||||||
|
Root: HKCR; Subkey: "WelsonJS.Script\DefaultIcon"; ValueType: string; ValueData: "{app}\app\favicon.ico,0"; Flags: uninsdeletekey
|
||||||
|
Root: HKCR; Subkey: "WelsonJS.Script\shell"; ValueType: string; ValueData: "open"; Flags: uninsdeletevalue
|
||||||
|
Root: HKCR; Subkey: "WelsonJS.Script\shell\open"; ValueType: string; ValueData: "Run with WelsonJS"; Flags: uninsdeletevalue
|
||||||
|
Root: HKCR; Subkey: "WelsonJS.Script\shell\open\command"; ValueType: string; ValueData: """{app}\bin\x86\WelsonJS.Launcher.exe"" --file ""%1"""; Flags: uninsdeletevalue
|
||||||
|
Root: HKCR; Subkey: ".js"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||||
|
Root: HKCR; Subkey: ".ts"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||||
|
Root: HKCR; Subkey: ".re"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||||
|
Root: HKCR; Subkey: ".res"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||||
|
Root: HKCR; Subkey: ".ls"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||||
|
Root: HKCR; Subkey: ".coffee"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
Source: "app.js"; DestDir: "{app}";
|
Source: "app.js"; DestDir: "{app}";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user