diff --git a/.releaseindex.json b/.releaseindex.json index 39e83f40..c8d02388 100644 --- a/.releaseindex.json +++ b/.releaseindex.json @@ -2,7 +2,7 @@ "WindowsClassic": "Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-classic\\.zip", "WindowsAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-chardonnay\\.zip", "LinuxAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-amd64\\.deb", - "MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-x64\\.tgz" + "MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-x64\\.tgz", "LinuxAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-arm64\\.deb", "MacOSAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-arm64\\.tgz" } diff --git a/Scripts/Bundle_Linux.sh b/Scripts/Bundle_Linux.sh index de1995ed..33d71afb 100644 --- a/Scripts/Bundle_Linux.sh +++ b/Scripts/Bundle_Linux.sh @@ -53,7 +53,7 @@ if [ $? -ne 0 ] fi -delfiles=('libmp3lame.x64.dylib' 'libmp3lame.arm64.dylib' 'ffmpegaac.x64.dylib' 'ffmpegaac.arm64.dylib' 'libmp3lame.x64.dll' 'ffmpegaac.x64.dll' 'libmp3lame.x86.dll' 'ffmpegaac.x86.dll' 'LinuxConfigApp' 'LinuxConfigApp.runtimeconfig.json' 'LinuxConfigApp.deps.json') +delfiles=('libmp3lame.arm64.dylib' 'libmp3lame.x64.dylib' 'libmp3lame.x64.dll' 'libmp3lame.x86.dll' 'ffmpegaac.arm64.dylib' 'ffmpegaac.x64.dylib' 'ffmpegaac.x64.dll' 'ffmpegaac.x86.dll' 'LinuxConfigApp' 'LinuxConfigApp.deps.json' 'LinuxConfigApp.runtimeconfig.json') if [[ "$ARCH" == "arm64" ]] then delfiles+=('libmp3lame.x64.so' 'ffmpegaac.x64.so') diff --git a/Scripts/Bundle_MacOS.sh b/Scripts/Bundle_MacOS.sh index bc3bb738..7465cc13 100644 --- a/Scripts/Bundle_MacOS.sh +++ b/Scripts/Bundle_MacOS.sh @@ -79,7 +79,7 @@ echo "Set CFBundleVersion to $VERSION" sed -i -e "s/VERSION_STRING/$VERSION/" $BUNDLE_CONTENTS/Info.plist -delfiles=('libmp3lame.x64.so' 'ffmpegaac.x64.so' 'libmp3lame.arm64.so' 'ffmpegaac.arm64.so' 'libmp3lame.x64.dll' 'ffmpegaac.x64.dll' 'libmp3lame.x86.dll' 'ffmpegaac.x86.dll' 'ffmpegaac.x86.dll' 'MacOSConfigApp' 'MacOSConfigApp.runtimeconfig.json' 'MacOSConfigApp.deps.json') +delfiles=( 'libmp3lame.arm64.so' 'libmp3lame.x64.so' 'libmp3lame.x64.dll' 'libmp3lame.x86.dll' 'ffmpegaac.arm64.so' 'ffmpegaac.x64.so' 'ffmpegaac.x64.dll' 'ffmpegaac.x86.dll' 'MacOSConfigApp' 'MacOSConfigApp.deps.json' 'MacOSConfigApp.runtimeconfig.json') if [[ "$ARCH" == "arm64" ]] then delfiles+=('libmp3lame.x64.dylib' 'ffmpegaac.x64.dylib') diff --git a/Source/AppScaffolding/OSConfigBase.cs b/Source/AppScaffolding/OSConfigBase.cs deleted file mode 100644 index d07eb639..00000000 --- a/Source/AppScaffolding/OSConfigBase.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace AppScaffolding -{ - public abstract class OSConfigBase - { - public abstract Type InteropFunctionsType { get; } - public virtual Type[] ReferencedTypes { get; } = new Type[0]; - - public void Run() - { - //Each of these types belongs to a different windows-only assembly that's needed by - //the WinInterop methods. By referencing these types in main we force the runtime to - //load their assemblies before execution reaches inside main. This allows the calling - //process to find these assemblies in its module list. - _ = ReferencedTypes; - _ = InteropFunctionsType; - - //Wait for the calling process to be ready to read the WriteLine() - Console.ReadLine(); - - // Signal the calling process that execution has reached inside main, and that all referenced assemblies have been loaded. - Console.WriteLine(); - - // Wait for the calling process to finish reading the process module list, then exit. - Console.ReadLine(); - } - } -} diff --git a/Source/LibationAvalonia/Program.cs b/Source/LibationAvalonia/Program.cs index 88b9e786..8953cb67 100644 --- a/Source/LibationAvalonia/Program.cs +++ b/Source/LibationAvalonia/Program.cs @@ -24,18 +24,15 @@ namespace LibationAvalonia //We can do this because we're already executing inside the sandbox. //Any process created in the sandbox executes in the same sandbox. //Unfortunately, all sandbox files are read/execute, so no writing! - - Assembly asm = Assembly.GetExecutingAssembly(); - string path = Path.GetDirectoryName(asm.Location); - Process.Start("Hangover" + (Configuration.IsWindows ? ".exe" : "")); + Process.Start("Hangover"); return; } if (Configuration.IsMacOs && args?.Length > 0 && args[0] == "cli") { //Open a new Terminal in the sandbox - Assembly asm2 = Assembly.GetExecutingAssembly(); - string libationProgramFiles = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - Process.Start("/System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", $"\"{libationProgramFiles}\""); + Process.Start( + "/System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", + $"\"{Configuration.ProcessDirectory}\""); return; } diff --git a/Source/LibationFileManager/Configuration.KnownDirectories.cs b/Source/LibationFileManager/Configuration.KnownDirectories.cs index 5ad6a75e..d989b616 100644 --- a/Source/LibationFileManager/Configuration.KnownDirectories.cs +++ b/Source/LibationFileManager/Configuration.KnownDirectories.cs @@ -9,8 +9,9 @@ namespace LibationFileManager { public partial class Configuration { - public static string AppDir_Relative => $@".{Path.PathSeparator}{LIBATION_FILES_KEY}"; - public static string AppDir_Absolute => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Exe.FileLocationOnDisk), LIBATION_FILES_KEY)); + public static string ProcessDirectory { get; } = Path.GetDirectoryName(Exe.FileLocationOnDisk); + public static string AppDir_Relative => $@".{Path.PathSeparator}{LIBATION_FILES_KEY}"; + public static string AppDir_Absolute => Path.GetFullPath(Path.Combine(ProcessDirectory, LIBATION_FILES_KEY)); public static string MyDocs => Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Libation")); public static string WinTemp => Path.GetFullPath(Path.Combine(Path.GetTempPath(), "Libation")); public static string UserProfile => Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Libation")); diff --git a/Source/LibationFileManager/Configuration.LibationFiles.cs b/Source/LibationFileManager/Configuration.LibationFiles.cs index 7608f6c8..553c6a5f 100644 --- a/Source/LibationFileManager/Configuration.LibationFiles.cs +++ b/Source/LibationFileManager/Configuration.LibationFiles.cs @@ -76,7 +76,7 @@ namespace LibationFileManager //Possible appsettings.json locations, in order of preference. string[] possibleAppsettingsFiles = new[] { - Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), appsettings_filename), + Path.Combine(ProcessDirectory, appsettings_filename), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation", appsettings_filename), Path.Combine(UserProfile, appsettings_filename), Path.Combine(Path.GetTempPath(), "Libation", appsettings_filename) diff --git a/Source/LibationFileManager/InteropFactory.cs b/Source/LibationFileManager/InteropFactory.cs index ac2928a9..8d6deaa1 100644 --- a/Source/LibationFileManager/InteropFactory.cs +++ b/Source/LibationFileManager/InteropFactory.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; -using System.Threading; using Dinah.Core; namespace LibationFileManager @@ -25,21 +23,29 @@ namespace LibationFileManager instance ??= InteropFunctionsType is null ? new NullInteropFunctions() - //: values is null || values.Length == 0 ? Activator.CreateInstance(InteropFunctionsType) as IInteropFunctions : Activator.CreateInstance(InteropFunctionsType, values) as IInteropFunctions; return instance; } - #region load types + #region load types - public static Func MatchesOS { get; } + private const string CONFIG_APP_ENDING = "ConfigApp.dll"; + + public static Func MatchesOS { get; } = Configuration.IsWindows ? a => Path.GetFileName(a).StartsWithInsensitive("win") : Configuration.IsLinux ? a => Path.GetFileName(a).StartsWithInsensitive("linux") : Configuration.IsMacOs ? a => Path.GetFileName(a).StartsWithInsensitive("mac") || Path.GetFileName(a).StartsWithInsensitive("osx") : _ => false; - private const string CONFIG_APP_ENDING = "ConfigApp.dll"; - private static List ModuleList { get; } = new(); + private static readonly EnumerationOptions enumerationOptions = new() + { + MatchType = MatchType.Simple, + MatchCasing = MatchCasing.CaseInsensitive, + IgnoreInaccessible = true, + RecurseSubdirectories = false, + ReturnSpecialDirectories = false + }; + static InteropFactory() { // searches file names for potential matches; doesn't run anything @@ -52,94 +58,36 @@ namespace LibationFileManager return; } - /* - * Commented code used to locate assemblies from the *ConfigApp.exe's module list. - * Use this method to locate dependencies when they are not in Libation's program files directory. -#if DEBUG - - // runs the exe and gets the exe's loaded modules - ModuleList = LoadModuleList(Path.GetFileNameWithoutExtension(configApp)) - .OrderBy(x => x.ModuleName) - .ToList(); -#endif - */ - AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; var configAppAssembly = Assembly.LoadFrom(configApp); var type = typeof(IInteropFunctions); InteropFunctionsType = configAppAssembly .GetTypes() - .FirstOrDefault(t => type.IsAssignableFrom(t)); + .FirstOrDefault(type.IsAssignableFrom); } private static string getOSConfigApp() { - var here = Path.GetDirectoryName(Environment.ProcessPath); - // find '*ConfigApp.dll' files var appName = - Directory.EnumerateFiles(here, $"*{CONFIG_APP_ENDING}", SearchOption.TopDirectoryOnly) - // sanity check. shouldn't ever be true - .Except(new[] { Environment.ProcessPath }) + Directory.EnumerateFiles(Configuration.ProcessDirectory, $"*{CONFIG_APP_ENDING}", enumerationOptions) .FirstOrDefault(exe => MatchesOS(exe)); return appName; } - /* - * Use this method to locate dependencies when they are not in Libation's program files directory. - * - private static List LoadModuleList(string exeName) - { - var proc = new Process - { - StartInfo = new() - { - FileName = exeName, - RedirectStandardInput = true, - RedirectStandardOutput = true, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - UseShellExecute = false - } - }; - - var waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); - - proc.OutputDataReceived += (_, _) => waitHandle.Set(); - proc.Start(); - proc.BeginOutputReadLine(); - - //Let the win process know we're ready to receive its standard output - proc.StandardInput.WriteLine(); - - if (!waitHandle.WaitOne(2000)) - throw new Exception("Failed to start program"); - - //The win process has finished loading and is now waiting inside Main(). - //Copy it process module list. - var modules = proc.Modules.Cast().ToList(); - - //Let the win process know we're done reading its module list - proc.StandardInput.WriteLine(); - - return modules; - } - */ - private static Dictionary lowEffortCache { get; } = new(); private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { - // e.g. "System.Windows.Forms, Version=6.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" - var asmName = args.Name.Split(',')[0] + ".dll"; - var here = Path.GetDirectoryName(Environment.ProcessPath); + var asmName = new AssemblyName(args.Name); + var here = Configuration.ProcessDirectory; var key = $"{asmName}|{here}"; if (lowEffortCache.TryGetValue(key, out var value)) return value; - var assembly = CurrentDomain_AssemblyResolve_internal(asmName: asmName, here: here); + var assembly = CurrentDomain_AssemblyResolve_internal(asmName, here: here); lowEffortCache[key] = assembly; //Let the runtime handle any dll not found exceptions. @@ -149,27 +97,14 @@ namespace LibationFileManager return assembly; } - private static Assembly CurrentDomain_AssemblyResolve_internal(string asmName, string here) + private static Assembly CurrentDomain_AssemblyResolve_internal(AssemblyName asmName, string here) { - /* - * Commented code used to locate assemblies from the *ConfigApp.exe's module list. - * Use this method to locate dependencies when they are not in Libation's program files directory. - #if DEBUG - - var modulePath = ModuleList.SingleOrDefault(m => m.ModuleName.EqualsInsensitive(asmName))?.FileName; - #else - */ - // find the requested assembly in the program files directory var modulePath = - Directory.EnumerateFiles(here, asmName, SearchOption.TopDirectoryOnly) + Directory.EnumerateFiles(here, $"{asmName.Name}.dll", enumerationOptions) .SingleOrDefault(); -//#endif - if (modulePath is null) - return null; - - return Assembly.LoadFrom(modulePath); + return modulePath is null ? null : Assembly.LoadFrom(modulePath); } #endregion diff --git a/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs b/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs index 3ff64786..bd6458b0 100644 --- a/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs +++ b/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs @@ -1,6 +1,5 @@ using LibationFileManager; using System.Diagnostics; -using System.Reflection; namespace LinuxConfigApp { @@ -39,8 +38,6 @@ namespace LinuxConfigApp //prompt across multiple distributions and desktop environments. const string runasroot = "runasroot.sh"; - var asmDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - string command = $"{exe ?? ""} {args ?? ""}".Trim(); foreach (var console in consoleCommands) @@ -55,7 +52,7 @@ namespace LinuxConfigApp $"Running '{exe}' as root", // console title console[2], "/bin/sh", - Path.Combine(asmDir, runasroot), //script file + Path.Combine(Configuration.ProcessDirectory, runasroot), //script file "Installing libation.deb", //command title command, // command to execute vis /bin/sh $"Please run '{command}' manually" // error message to display in the terminal diff --git a/Source/LoadByOS/LinuxConfigApp/Program.cs b/Source/LoadByOS/LinuxConfigApp/Program.cs index e98c8ff9..81d89b03 100644 --- a/Source/LoadByOS/LinuxConfigApp/Program.cs +++ b/Source/LoadByOS/LinuxConfigApp/Program.cs @@ -1,11 +1,7 @@ -using AppScaffolding; - -namespace LinuxConfigApp +namespace LinuxConfigApp { - class Program : OSConfigBase + class Program { - public override Type InteropFunctionsType => typeof(LinuxInterop); - - static void Main() => new Program().Run(); + static void Main() { } } } diff --git a/Source/LoadByOS/MacOSConfigApp/Program.cs b/Source/LoadByOS/MacOSConfigApp/Program.cs index bab9d875..dcc8ffbc 100644 --- a/Source/LoadByOS/MacOSConfigApp/Program.cs +++ b/Source/LoadByOS/MacOSConfigApp/Program.cs @@ -1,11 +1,7 @@ -using AppScaffolding; - -namespace MacOSConfigApp +namespace MacOSConfigApp { - class Program : OSConfigBase + class Program { - public override Type InteropFunctionsType => typeof(MacOSInterop); - - static void Main() => new Program().Run(); + static void Main() { } } } diff --git a/Source/LoadByOS/WindowsConfigApp/Program.cs b/Source/LoadByOS/WindowsConfigApp/Program.cs index 1786ce7b..72473a31 100644 --- a/Source/LoadByOS/WindowsConfigApp/Program.cs +++ b/Source/LoadByOS/WindowsConfigApp/Program.cs @@ -1,18 +1,7 @@ -using AppScaffolding; - namespace WindowsConfigApp { - class Program : OSConfigBase + class Program { - public override Type InteropFunctionsType => typeof(WinInterop); - public override Type[] ReferencedTypes => new Type[] - { - typeof(Bitmap), - typeof(Dinah.Core.WindowsDesktop.GitClient), - typeof(Accessibility.IAccIdentity), - typeof(Microsoft.Win32.SystemEvents) - }; - - static void Main() => new Program().Run(); + static void Main() { } } } \ No newline at end of file