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();
        }
Beispiel #11
0
        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);
        }
Beispiel #19
0
 /// <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();
 }
Beispiel #20
0
 /// <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;
        }