private static IEnumerable <T> GetInterfaceInstances <T>() where T : class { var interfaceType = typeof(T); var types = GetReflectionAssemblies().SelectMany(p => p.GetTypes().Where(t => interfaceType.IsAssignableFrom(t) && !t.IsAbstract)); foreach (var type in types) { TSLog.Log(LogCategory.Trace, string.Format("Creating Data Source: {0}", type.FullName)); T dataSource = null; try { dataSource = (T)Activator.CreateInstance(type); } catch (Exception e) { TSLog.LogError(LogCategory.Info, string.Format("Error creating instance ({0})", type.FullName)); TSLog.LogError(LogCategory.Info, e.ToString()); } if (dataSource == null) { TSLog.LogError(LogCategory.Info, string.Format("Error creating instance ({0})", type.FullName)); continue; } yield return(dataSource); } }
private void OnEditorUpdate() { TypeSafeUtil.ReportCodeRefreshCompleted(); Settings settings = Settings.Instance; if (settings == null) { return; } if (!WelcomeWindow.HasOpenedBefore() || !settings.HasShownWelcome) { TSLog.Log(LogCategory.Trace, string.Format("Opening welcome window (HasOpenedBefore={0}, HasShownWelcome={1})", WelcomeWindow.HasOpenedBefore(), settings.HasShownWelcome)); WelcomeWindow.Open(); } else if (WelcomeWindow.GetPreviousOpenedVersion() != Strings.Version) { TSLog.Log(LogCategory.Trace, string.Format("Opening changelog window (previousVersion={0}, currentVersion={1})", WelcomeWindow.GetPreviousOpenedVersion(), Strings.Version)); WelcomeWindow.Open(true); TSLog.Log(LogCategory.Trace, "Clearing AssetTypeCache (new TypeSafe version detected)"); AssetTypeCache.ClearCache(); } Step(); }
private static Texture2D ReadTexture(string path) { string assetPath = Path.Combine(Path.Combine(PathUtility.GetTypeSafeEditorPath(), "UI"), path); TSLog.Log(LogCategory.Trace, string.Format("Loading Embedded Texture: {0} from {1}", path, assetPath)); return(AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath)); }
public static void ReportCodeRefreshCompleted() { if (_codeRefreshCompleted) { return; } TSLog.Log(LogCategory.Trace, "Code Refresh Completed"); _codeRefreshCompleted = true; }
/// <summary> /// Queue a scan. /// </summary> public void Queue(bool userInitiated = false) { if (_state != States.Idle) { TSLog.LogWarning(LogCategory.Trace, "Cannot queue scan - state is not idle"); return; } TSLog.Log(LogCategory.Trace, string.Format("Scan Queued (userInitiated={0})", userInitiated)); _userInitiated = userInitiated; _state = States.ScanQueued; }
private void AbortScan() { if (_state != States.Scanning) { throw new InvalidOperationException(); } TSLog.Log(LogCategory.Trace, "Aborting Scan"); _scanController = null; _state = States.Idle; TSLog.EndBuffer(LogCategory.Compile, false); }
private static void UpgradeFromOldVersion(string settingsPath) { // Check file to see if it's an older version. string[] fileContents = File.ReadAllLines(settingsPath); for (var i = 0; i < fileContents.Length; i++) { if (fileContents[i].Equals(PatchOldVersion)) { TSLog.Log(LogCategory.Info, "Upgrading settings file from old version."); fileContents[i] = PatchNewVersion; string backupPath = null; try { string backupDirectory = PathUtility.GetBackupDirectory(); if (!Directory.Exists(backupDirectory)) { Directory.CreateDirectory(backupDirectory); } // Backup existing settings backupPath = Path.Combine(backupDirectory, "Settings.asset.backup"); File.WriteAllLines(backupPath, fileContents); // Delete old settings AssetDatabase.DeleteAsset(settingsPath); AssetDatabase.SaveAssets(); // Write new settings File.WriteAllLines(settingsPath, fileContents); AssetDatabase.Refresh(ImportAssetOptions.Default); TSLog.Log(LogCategory.Info, "Upgrade complete."); // Delete backup File.Delete(backupPath); } catch (Exception e) { TSLog.LogError(LogCategory.Info, "Error when trying to upgrade from old settings file: " + e); if (backupPath != null) { TSLog.LogError(LogCategory.Info, "Backup was written to " + backupPath); } } break; } } }
private void OnEnable() { TSLog.Log(LogCategory.Trace, string.Format("TypeSafeController.OnEnable (Version={0}, ", Strings.Version) + string.Format("UnityVersion={0}, ", Application.unityVersion) + string.Format("TypeSafePath={0}, ", PathUtility.GetTypeSafePath()) + string.Format("TypeSafeEditorPath={0})", PathUtility.GetTypeSafeEditorPath())); _instance = this; TypeSafeUtil.EnsureCorrectUnityVersion(); EditorApplication.update += OnEditorUpdate; }
private void OnDisable() { TSLog.Log(LogCategory.Trace, "TypeSafeController.OnDisable"); TypeSafeUtil.ReportCodeRefreshStarted(); if (State != States.Idle) { Cancel(); Queue(); } TSLog.CloseLog(); }
public void Begin() { if (_scanProgressEnumerator != null) { throw new InvalidOperationException("Scan already in progress"); } TSLog.Log(LogCategory.Scanner, "ScanController.Begin"); IsDone = false; WasSuccessful = false; _scanProgressEnumerator = ScanProcess().GetEnumerator(); }
private static TypeCache GetInstance(bool autoCreate) { if (!TypeSafeUtil.IsEnabled()) { throw new InvalidOperationException( "Attempted to create settings instance while TypeSafe is disabled. Something should be checking TypeSafeUtil.IsEnabled() before running."); } var cachePath = PathUtility.GetTypeCachePath(); TSLog.Log(LogCategory.Trace, string.Format("Checking for TypeCache asset at {0}", cachePath)); var fileExists = File.Exists(cachePath); var instance = AssetDatabase.LoadAssetAtPath <TypeCache>(cachePath); if (instance == null && fileExists) { TSLog.Log(LogCategory.Trace, "TypeCache asset exists, but AssetDatabase doesn't know it. Likely project reimport in progress."); return(null); } if (instance == null) { TSLog.Log(LogCategory.Trace, string.Format("TypeCache asset not found at {0} (fileExists={1}, instance=null)", cachePath, fileExists)); if (!autoCreate) { return(null); } // Create instance instance = CreateInstance <TypeCache>(); TSLog.Log(LogCategory.Info, string.Format("Creating TypeCache asset at {0}", cachePath)); try { AssetDatabase.CreateAsset(instance, cachePath); } catch (Exception e) { TSLog.LogError(LogCategory.Info, "Error creating TypeCache asset."); TSLog.LogError(LogCategory.Info, e.ToString()); } } return(instance); }
private void BeginCompile() { if (_scanResult == null) { throw new InvalidOperationException(); } TSLog.Log(LogCategory.Trace, "BeginCompile"); _state = States.Compiling; _compileController = new CompileController(); _compileController.ResourceDatabase = _scanResult.ResourceDatabase; _compileController.DataUnits = _scanResult.DataUnits; _compileController.Compile(); }
private void BeginScan() { if (_state != States.Idle && _state != States.ScanQueued) { throw new InvalidOperationException(); } TSLog.BeginBuffer(LogCategory.Compile); TSLog.Log(LogCategory.Trace, "BeginScan"); TypeSafeUtil.CheckForRemovedAssets(); _stopwatch.Reset(); _stopwatch.Start(); _scanController = new ScanController(); _scanController.Begin(); _state = States.Scanning; }
/// <summary> /// Remove all generated files from the Unity project directory /// </summary> public static void Clean() { TSLog.Log(LogCategory.Trace, "Cleaning Deploy Directory"); var directory = PathUtility.GetDeployDirectory(); TSLog.Log(LogCategory.Trace, "Deploy Directory: " + directory); foreach (var file in Directory.GetFiles(directory, "*.Generated.*")) { if (file.EndsWith(".meta")) { continue; } var path = PathUtility.PathRelativeTo(file, Environment.CurrentDirectory); TSLog.Log(LogCategory.Trace, string.Format("Deleting {0}", file)); try { if (!FileContains(path, Strings.TypeSafeInternalTagFieldName)) { TSLog.LogWarning(LogCategory.Trace, "File does not contain TypeSafe tag, skipped deletion."); continue; } if (!AssetDatabase.DeleteAsset(path)) { TSLog.LogError(LogCategory.Info, string.Format("Error deleting {0} with AssetDatabase. Attempting File.Delete", path)); File.Delete(path); } } catch (Exception e) { TSLog.LogError(LogCategory.Info, string.Format("Error deleting {0}", path)); TSLog.LogError(LogCategory.Info, e.ToString()); } } }
public static bool IsEnabled() { if (_isEnabled.HasValue) { return(_isEnabled.Value); } _isEnabled = !Environment.GetCommandLineArgs().Contains(Strings.DisableCommandLineParam); if (!_isEnabled.Value) { TSLog.Log(LogCategory.Trace, "TypeSafe is disabled via command line."); return(false); } // Force TypeSafe to be disabled if the assembly is missing (likely the user has deleted TypeSafe) if (!File.Exists(typeof(TypeSafeUtil).Assembly.Location)) { TSLog.Log(LogCategory.Trace, "TypeSafe assembly is missing, IsEnabled() = false"); _isEnabled = false; } return(_isEnabled.Value); }
public static void ReportCodeRefreshStarted() { TSLog.Log(LogCategory.Trace, "Code Refresh Started"); _codeRefreshCompleted = false; }
private void Step() { switch (State) { case States.Idle: break; case States.ScanQueued: if (!TypeSafeUtil.ShouldBeOperating()) { break; } BeginScan(); break; case States.Scanning: if (_scanController == null) { TSLog.LogError(LogCategory.Trace, "ScanController = null, but State = Scanning"); _state = States.Idle; break; } if (!TypeSafeUtil.ShouldBeOperating()) { TSLog.Log(LogCategory.Trace, "Aborting scan due to script reload in progress."); Cancel(); Queue(); break; } _scanController.Update(); ItemsCompleted = _scanController.ItemsCompleted; TotalItems = _scanController.TotalItems; if (_scanController.IsDone) { TSLog.Log(LogCategory.Trace, string.Format("Scan complete (took {0}s).", _stopwatch.Elapsed.TotalSeconds)); if (_scanController.WasSuccessful) { _scanResult = _scanController.Result; _scanController = null; BeginCompile(); } else { TSLog.LogError(LogCategory.Info, "Error occured while scanning. Aborting process."); _state = States.Idle; } } break; case States.Compiling: case States.Waiting: if (_compileController == null) { TSLog.LogError(LogCategory.Trace, "CompileController = null, but State = Compiling"); _state = States.Idle; break; } if (!TypeSafeUtil.ShouldBeOperating()) { TSLog.Log(LogCategory.Trace, "Aborting compile."); Cancel(); Queue(); break; } if (_compileController.IsDone) { if (_state != States.Waiting) { // Perform a dry run of the deploy step to see if there were any changes since the last compile int changeCount; TypeSafeUtil.DeployBuildArtifacts(_compileController.Output, out changeCount, true); // Delay for minimum build time if not user initiated and there were changes if (Settings.Instance.EnableWaiting && changeCount > 0 && !_userInitiated && _stopwatch.Elapsed.TotalSeconds < Settings.Instance.MinimumBuildTime) { _state = States.Waiting; break; } } else { // Wait for wait stage to elapse if (!_abortWait && _stopwatch.Elapsed.TotalSeconds < Settings.Instance.MinimumBuildTime) { break; } } _abortWait = false; TSLog.Log(LogCategory.Trace, string.Format("Compile Complete (WasSuccessful={0})", _compileController.WasSuccessful)); if (_compileController.WasSuccessful) { int updatedFileCount; var deployResult = TypeSafeUtil.DeployBuildArtifacts(_compileController.Output, out updatedFileCount); TSLog.Log(LogCategory.Trace, string.Format("Deploy Complete (WasSuccessful={0}, updatedFileCount={1})", deployResult, updatedFileCount)); var shouldReport = _userInitiated || updatedFileCount > 0; TSLog.EndBuffer(LogCategory.Compile, shouldReport); if (!deployResult) { TSLog.LogError(LogCategory.Info, "Compile failed."); } else if (shouldReport) { if (updatedFileCount == 0) { TSLog.Log(LogCategory.Info, "Compile complete, no changes."); } else { TSLog.Log(LogCategory.Info, string.Format("Compile completed. (Took {0}s)", _stopwatch.Elapsed.Seconds)); } } } _compileController = null; _state = States.Idle; } break; } }
/// <summary> /// Copy a collection of file paths to the deploy path and refresh the Unity asset database for the target files. /// This will check for file changes before copying to reduce unnecessary recompiles. /// </summary> /// <param name="paths">Collection of paths to deploy.</param> /// <param name="fileCount">Number of files that have been updated.</param> /// <param name="dryRun">If true, skip the actual copying of the file, just check for differences</param> /// <returns>True if successfully deployed.</returns> public static bool DeployBuildArtifacts(ICollection <string> paths, out int fileCount, bool dryRun = false) { TSLog.Log(LogCategory.Trace, "Deploying Build Artifacts"); fileCount = 0; var error = false; var deployDirectory = PathUtility.GetDeployDirectory(); TSLog.Log(LogCategory.Trace, "Deploy Directory: " + deployDirectory); if (!Directory.Exists(deployDirectory) && !dryRun) { try { TSLog.Log(LogCategory.Trace, string.Format("Creating deploy directory @ {0}", deployDirectory)); Directory.CreateDirectory(deployDirectory); } catch (Exception e) { TSLog.LogError(LogCategory.Info, string.Format("Error creating deploy directory @ {0}", deployDirectory)); TSLog.LogError(LogCategory.Info, e.ToString()); return(false); } } try { AssetDatabase.StartAssetEditing(); foreach (var s in paths) { var destPath = deployDirectory + "/" + Path.GetFileName(s); if (File.Exists(destPath) && PathUtility.GetFileHash(destPath) == PathUtility.GetFileHash(s)) { if (!dryRun) { TSLog.Log(LogCategory.Trace, string.Format("Ignoring File {0} -> {1} (no changes)", s, destPath)); } continue; } ++fileCount; if (dryRun) { continue; } TSLog.Log(LogCategory.Trace, string.Format("Copying File {0} -> {1}", s, destPath)); try { File.Copy(s, destPath, true); AssetDatabase.ImportAsset(PathUtility.PathRelativeTo(destPath, Environment.CurrentDirectory)); } catch (Exception exception) { TSLog.LogError(LogCategory.Info, string.Format("Error copying file {0} -> {1}", s, destPath)); TSLog.LogError(LogCategory.Info, exception.ToString()); error = true; } } } finally { AssetDatabase.StopAssetEditing(); } return(!error); }
/// <summary> /// If a TypeSafe scan is currently in progress, cancel it. /// </summary> public static void Cancel() { TSLog.Log(LogCategory.Trace, "TypeSafeApi.Cancel"); TypeSafeController.Instance.Cancel(); }
/// <summary> /// Queue a new scan/compile process. Will do nothing and print a warning if <c>IsBusy</c> is true. /// </summary> public static void QueueRefresh() { TSLog.Log(LogCategory.Trace, "TypeSafeApi.QueueRefresh"); TypeSafeController.Instance.Queue(true); }
private static bool CompileToSourceFiles(CodeDomProvider provider, IEnumerable <CodeCompileUnit> compileUnits, CompileParameters p, out IList <string> paths) { TSLog.Log(LogCategory.Trace, "Compiling to Source Files"); PathUtility.EnsureDirectoryExists(PathUtility.GetBuildTempDirectory()); var codeGeneratorOptions = new CodeGeneratorOptions(); codeGeneratorOptions.VerbatimOrder = true; var outputPath = PathUtility.GetBuildTempDirectory(); var outputPaths = new List <string>(); foreach (var c in compileUnits) { var found = false; foreach (var key in c.UserData.Keys) { var s = key as string; if (s != null && s == Strings.CompileUnitUserDataKey) { found = true; break; } } if (!found) { TSLog.LogError(LogCategory.Compile, "Compile unit does not contain name user data key"); continue; } var name = (string)c.UserData[Strings.CompileUnitUserDataKey]; var fileName = string.Format(Strings.SourceFileNameFormat, name); var o = Path.Combine(outputPath, fileName); using (var fs = File.Open(o, FileMode.Create, FileAccess.Write)) { using (var tw = new StreamWriter(fs)) { provider.GenerateCodeFromCompileUnit(c, tw, codeGeneratorOptions); } } // Read the newly generated file var file = File.ReadAllLines(o); // It's not worth the bother to do this. sealed and private constructor achieve the same effect. /*// Replace sealed classes with static ones. (CodeDOM doesn't have a way of creating static classes by default) * for (var i = 0; i < file.Length; i++) { * * var s = file[i]; * * if (s.Contains("public sealed ")) { * file[i] = s.Replace("public sealed ", "public static "); * break; * } * * }*/ // Write with default header removed File.WriteAllLines(o, file.Skip(10).ToArray()); outputPaths.Add(o); } paths = outputPaths; return(true); }
private static bool CompileToDll(CodeDomProvider provider, IEnumerable <CodeCompileUnit> compileUnits, CompileParameters p, out string path) { TSLog.Log(LogCategory.Trace, "Compiling to DLL"); var compilerParameters = new CompilerParameters(); compilerParameters.ReferencedAssemblies.Add(typeof(int).Assembly.Location); compilerParameters.ReferencedAssemblies.Add(typeof(Object).Assembly.Location); compilerParameters.ReferencedAssemblies.Add("TypeSafe.dll"); if (p.ResourceDatabase != null) { // Include references to assemblies used in resources var list = GetReferencedAssemblies(p.ResourceDatabase); foreach (var s in list) { if (!compilerParameters.ReferencedAssemblies.Contains(s)) { compilerParameters.ReferencedAssemblies.Add(s); } } } for (var i = 0; i < compilerParameters.ReferencedAssemblies.Count; i++) { TSLog.Log(LogCategory.Trace, string.Format("Referencing Assembly: {0}", compilerParameters.ReferencedAssemblies[i])); } PathUtility.EnsureDirectoryExists(PathUtility.GetBuildTempDirectory()); compilerParameters.OutputAssembly = PathUtility.GetBuildTempDirectory() + "/" + Strings.DllName; //compilerParameters.TempFiles.KeepFiles = true; TSLog.Log(LogCategory.Trace, "Compile starting..."); var result = provider.CompileAssemblyFromDom(compilerParameters, compileUnits.ToArray()); if (p.LogErrors) { for (var i = 0; i < result.Errors.Count; i++) { var error = result.Errors[i]; if (error.IsWarning) { TSLog.LogWarning(LogCategory.Compile, error.ToString()); } else { TSLog.LogError(LogCategory.Compile, error.ToString()); } } } path = result.PathToAssembly; return(result.NativeCompilerReturnValue == 0); }
private IEnumerable ScanProcess() { TSLog.Log(LogCategory.Scanner, "ScanController.ScanProcess start"); ResourceDatabase db; var sw = new Stopwatch(); sw.Start(); using (var scanIterator = ResourceScanProcess().GetEnumerator()) { while (scanIterator.MoveNext()) { if (sw.Elapsed.TotalSeconds > MaxUpdateProcessingTime) { TSLog.Log(LogCategory.Scanner, "ScanProcess Suspending"); Resources.UnloadUnusedAssets(); sw.Stop(); sw.Reset(); yield return(null); sw.Start(); } } db = scanIterator.Current; } var dataUnits = new List <TypeSafeDataUnit>(); TSLog.Log(LogCategory.Scanner, "Beginning ITypeSafeDataSource hooks"); foreach (var dataSource in TypeSafeUtil.GetCustomDataSources()) { if (Settings.Instance.DisabledDataSources.Contains(dataSource.GetType().AssemblyQualifiedName)) { TSLog.Log(LogCategory.Scanner, string.Format("Skipping {0}", dataSource.GetType().FullName)); continue; } TSLog.Log(LogCategory.Scanner, string.Format("Processing {0}", dataSource.GetType().FullName)); try { var data = dataSource.GetTypeSafeDataUnit(); if (ValidateDataUnit(data)) { dataUnits.Add(data); } } catch (Exception e) { TSLog.LogError(LogCategory.Info, string.Format("Exception occured inside data source ({0})", dataSource.GetType().FullName)); TSLog.LogError(LogCategory.Info, e.ToString()); } } TSLog.Log(LogCategory.Scanner, "Done running ITypeSafeDataSource hooks"); Result = new ScanResult(db, dataUnits); TSLog.Log(LogCategory.Scanner, "ScanProcess Done"); IsDone = true; WasSuccessful = true; }