private List <LogInfo> LoadLinks(BackgroundWorker worker) { List <LogInfo> logs = new List <LogInfo>(32); List <int> removeIdxs = new List <int>(); // Doing this will consume memory, but also greatly increase performance. DB_ScriptCache[] cacheDB = null; if (scriptCache != null) { cacheDB = scriptCache.Table <DB_ScriptCache>().Where(x => true).ToArray(); } var links = allProjectScripts.Where(x => x.Type == ScriptType.Link); Debug.Assert(links.Count(x => x.IsDirLink) == 0); Task[] tasks = links.Select(p => { return(Task.Run(() => { Script link = null; bool valid = false; int cached = 2; try { do { string linkPath = p.Sections["Main"].IniDict["Link"]; string linkFullPath = Path.Combine(baseDir, linkPath); if (File.Exists(linkFullPath) == false) // Invalid link { break; } // Load .link's linked scripts with cache if (scriptCache != null) { // Case of ScriptCache enabled FileInfo f = new FileInfo(linkFullPath); DB_ScriptCache pCache = cacheDB.FirstOrDefault(x => x.Hash == linkPath.GetHashCode()); if (pCache != null && pCache.Path.Equals(linkPath, StringComparison.Ordinal) && DateTime.Equals(pCache.LastWriteTimeUtc, f.LastWriteTimeUtc) && pCache.FileSize == f.Length) { try { using (MemoryStream memStream = new MemoryStream(pCache.Serialized)) { BinaryFormatter formatter = new BinaryFormatter(); link = (Script)formatter.Deserialize(memStream); } link.Project = p.Project; link.IsDirLink = false; cached = 3; } catch { } } } if (link == null) { // TODO : Lazy loading of link, takes too much time at start string ext = Path.GetExtension(linkFullPath); ScriptType type = ScriptType.Script; if (ext.Equals(".link", StringComparison.OrdinalIgnoreCase)) { type = ScriptType.Link; } link = new Script(type, Path.Combine(baseDir, linkFullPath), p.Project, projectRoot, null, false, false, false); Debug.Assert(p != null); } // Check Script Link's validity // Also, convert nested link to one-depth link if (link == null) { break; } if (link.Type == ScriptType.Script) { valid = true; break; } link = link.Link; }while (link.Type != ScriptType.Script); } catch (Exception e) { // Parser Error logs.Add(new LogInfo(LogState.Error, Logger.LogExceptionMessage(e))); } if (valid) { p.LinkLoaded = true; p.Link = link; if (worker != null) { worker.ReportProgress(cached, Path.GetDirectoryName(p.ShortPath)); } } else // Error { int idx = allProjectScripts.IndexOf(p); removeIdxs.Add(idx); if (worker != null) { worker.ReportProgress(cached); } } })); }).ToArray(); Task.WaitAll(tasks); // Remove malformed link var idxs = removeIdxs.OrderByDescending(x => x); foreach (int idx in idxs) { allProjectScripts.RemoveAt(idx); } return(logs); }
/// <summary> /// Launch after Application.Current is loaded /// </summary> public static void Init() { string baseDir = Environment.CurrentDirectory; for (int i = 0; i < Args.Length; i++) { if (Args[i].Equals("/basedir", StringComparison.OrdinalIgnoreCase)) { if (i + 1 < Args.Length) { baseDir = Path.GetFullPath(Args[i + 1]); if (!Directory.Exists(baseDir)) { MessageBox.Show($"Directory [{baseDir}] does not exist", "Invalid BaseDir", MessageBoxButton.OK, MessageBoxImage.Error); Environment.Exit(1); // Force Shutdown } Environment.CurrentDirectory = baseDir; } else { // ReSharper disable once LocalizableElement Console.WriteLine("\'/basedir\' must be used with path\r\n"); } } else if (Args[i].Equals("/?", StringComparison.OrdinalIgnoreCase) || Args[i].Equals("/help", StringComparison.OrdinalIgnoreCase) || Args[i].Equals("/h", StringComparison.OrdinalIgnoreCase)) { // ReSharper disable once LocalizableElement Console.WriteLine("Sorry, help message not implemented\r\n"); } } BaseDir = baseDir; // Database directory string dbDir = Path.Combine(BaseDir, "Database"); if (!Directory.Exists(dbDir)) { Directory.CreateDirectory(dbDir); } // Log Database string logDbFile = Path.Combine(dbDir, "PEBakeryLog.db"); try { Logger = new Logger(logDbFile); Logger.SystemWrite(new LogInfo(LogState.Info, "PEBakery launched")); } catch (SQLiteException e) { // Update failure string msg = $"SQLite Error : {e.Message}\r\n\r\nLog database is corrupted.\r\nPlease delete PEBakeryLog.db and restart."; MessageBox.Show(msg, "SQLite Error!", MessageBoxButton.OK, MessageBoxImage.Error); if (Application.Current != null) { Application.Current.Shutdown(1); } else { Environment.Exit(1); } } // Init ProjectCollection Projects = new ProjectCollection(BaseDir); // Setting File string settingFile = Path.Combine(BaseDir, "PEBakery.ini"); Setting = new Setting(settingFile); Setting.ApplySetting(); // Custom Title if (Setting.Interface.UseCustomTitle) { MainViewModel.TitleBar = Setting.Interface.CustomTitle; } // Load script cache if (Setting.Script.EnableCache) { string cacheDbFile = Path.Combine(dbDir, "PEBakeryCache.db"); try { ScriptCache = new ScriptCache(cacheDbFile); Logger.SystemWrite(new LogInfo(LogState.Info, $"ScriptCache enabled, {ScriptCache.Table<CacheModel.ScriptCache>().Count()} cached scripts found")); } catch (SQLiteException e) { // Load failure string msg = $"SQLite Error : {e.Message}\r\n\r\nCache database is corrupted.\r\nPlease delete PEBakeryCache.db and restart."; MessageBox.Show(msg, "SQLite Error!", MessageBoxButton.OK, MessageBoxImage.Error); if (Application.Current != null) { Application.Current.Shutdown(1); } else { Environment.Exit(1); } } } else { Logger.SystemWrite(new LogInfo(LogState.Info, "ScriptCache disabled")); } }
/// <summary> /// Launch after Application.Current is loaded /// </summary> public static void Init() { // Set fallback BaseDir string baseDir = BaseDir = Environment.CurrentDirectory; // Setup unhandled exception handler (requires BaseDir to be set) AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException; // Run ArgumentParser ArgumentParser argParser = new ArgumentParser(); PEBakeryOptions opts = argParser.Parse(Args); if (opts == null) // Arguments parse fail { Environment.Exit(1); // Force Shutdown } // Setup BaseDir if (opts.BaseDir != null) { baseDir = Path.GetFullPath(opts.BaseDir); if (Directory.Exists(baseDir) == false) { MessageBox.Show($"Directory [{baseDir}] does not exist.\r\nRun [PEBkaery --help] for commnad line help message.", "PEBakery CommandLine Error", MessageBoxButton.OK, MessageBoxImage.Error); Environment.Exit(1); // Force Shutdown } Environment.CurrentDirectory = BaseDir = baseDir; } // Database directory string dbDir = Path.Combine(BaseDir, "Database"); if (!Directory.Exists(dbDir)) { Directory.CreateDirectory(dbDir); } // Log Database string logDbFile = Path.Combine(dbDir, "PEBakeryLog.db"); try { Logger = new Logger(logDbFile); Logger.SystemWrite(new LogInfo(LogState.Info, "PEBakery launched")); } catch (SQLiteException) { // Update failure -> retry with clearing existing log db File.Delete(logDbFile); try { Logger = new Logger(logDbFile); Logger.SystemWrite(new LogInfo(LogState.Info, "PEBakery launched, log cleared due to an error")); } catch (SQLiteException e) { // Unable to continue -> raise an error message string msg = $"SQLite Error : {e.Message}\r\n\r\nThe Log database is corrupted and was not able to be repaired.\r\nPlease delete {dbDir}\\PEBakeryLog.db and restart."; MessageBox.Show(msg, "SQLite Error!", MessageBoxButton.OK, MessageBoxImage.Error); if (Application.Current != null) { Application.Current.Shutdown(1); } else { Environment.Exit(1); } } } // Init ProjectCollection Projects = new ProjectCollection(BaseDir); // Setting File string settingFile = Path.Combine(BaseDir, "PEBakery.ini"); Setting = new Setting(settingFile); Setting.ApplySetting(); // Custom Title if (Setting.Interface.UseCustomTitle) { MainViewModel.TitleBar = Setting.Interface.CustomTitle; } // Init script cache DB, regardless of Setting.Script.EnableCache string cacheDbFile = Path.Combine(dbDir, "PEBakeryCache.db"); try { ScriptCache = new ScriptCache(cacheDbFile); int cachedScriptCount = ScriptCache.Table <CacheModel.ScriptCache>().Count(); if (Setting.Script.EnableCache) { Logger.SystemWrite(new LogInfo(LogState.Info, $"ScriptCache enabled, {cachedScriptCount} cached scripts found")); } else { Logger.SystemWrite(new LogInfo(LogState.Info, "ScriptCache disabled")); } } catch (SQLiteException) { // Load failure -> Fallback, delete and remake database File.Delete(cacheDbFile); try { ScriptCache = new ScriptCache(cacheDbFile); Logger.SystemWrite(new LogInfo(LogState.Info, $"ScriptCache enabled, cache cleared due to an error")); } catch (SQLiteException e) { // Unable to continue -> raise an error message string msg = $"SQLite Error : {e.Message}\r\n\r\nThe Cache database is corrupted and was not able to be repaired.\r\nPlease delete {dbDir}\\PEBakeryCache.db and restart."; MessageBox.Show(msg, "SQLite Error!", MessageBoxButton.OK, MessageBoxImage.Error); if (Application.Current != null) { Application.Current.Shutdown(1); } else { Environment.Exit(1); } } } }