internal static void GenerateModels(string modelsDirectory, string binPath)
        {
            if (!Directory.Exists(modelsDirectory))
            {
                Directory.CreateDirectory(modelsDirectory);
            }

            foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs"))
            {
                File.Delete(file);
            }

            var umbraco    = Application.GetApplication();
            var typeModels = umbraco.GetAllTypes();

            var ourFiles    = Directory.GetFiles(modelsDirectory, "*.cs").ToDictionary(x => x, File.ReadAllText);
            var parseResult = new CodeParser().ParseWithReferencedAssemblies(ourFiles);
            var builder     = new TextBuilder(typeModels, parseResult, UmbracoConfig.For.ModelsBuilder().ModelsNamespace);

            foreach (var typeModel in builder.GetModelsToGenerate())
            {
                var sb = new StringBuilder();
                builder.Generate(sb, typeModel);
                var filename = Path.Combine(modelsDirectory, typeModel.ClrName + ".generated.cs");
                File.WriteAllText(filename, sb.ToString());
            }

            // the idea was to calculate the current hash and to add it as an extra file to the compilation,
            // in order to be able to detect whether a DLL is consistent with an environment - however the
            // environment *might not* contain the local partial files, and thus it could be impossible to
            // calculate the hash. So... maybe that's not a good idea after all?

            /*
             * var currentHash = HashHelper.Hash(ourFiles, typeModels);
             * ourFiles["models.hash.cs"] = $@"using Umbraco.ModelsBuilder;
             * [assembly:ModelsBuilderAssembly(SourceHash = ""{currentHash}"")]
             * ";
             */

            if (binPath != null)
            {
                //When bin directory is changed by config
                if (!Directory.Exists(binPath))
                {
                    Directory.CreateDirectory(binPath);
                }

                foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs"))
                {
                    ourFiles[file] = File.ReadAllText(file);
                }
                var compiler = new Compiler();
                compiler.Compile(builder.GetModelsNamespace(), ourFiles, binPath);
            }

            OutOfDateModelsStatus.Clear();
        }
Example #2
0
        internal static void GenerateModels(string appData, string bin)
        {
            var modelsDirectory = Path.Combine(appData, "Models");

            if (!Directory.Exists(modelsDirectory))
            {
                Directory.CreateDirectory(modelsDirectory);
            }

            foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs"))
            {
                File.Delete(file);
            }

            var umbraco    = Application.GetApplication();
            var typeModels = umbraco.GetAllTypes();

            var ourFiles    = Directory.GetFiles(modelsDirectory, "*.cs").ToDictionary(x => x, File.ReadAllText);
            var parseResult = new CodeParser().ParseWithReferencedAssemblies(ourFiles);
            var builder     = new TextBuilder(typeModels, parseResult, UmbracoConfig.For.ModelsBuilder().ModelsNamespace);

            foreach (var typeModel in builder.GetModelsToGenerate())
            {
                var sb = new StringBuilder();
                builder.Generate(sb, typeModel);
                var filename = Path.Combine(modelsDirectory, typeModel.ClrName + ".generated.cs");
                File.WriteAllText(filename, sb.ToString());
            }

            if (bin != null)
            {
                foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs"))
                {
                    ourFiles[file] = File.ReadAllText(file);
                }
                var compiler = new Compiler();
                compiler.Compile(builder.GetModelsNamespace(), ourFiles, bin);
            }

            OutOfDateModelsStatus.Clear();
        }
Example #3
0
        private Assembly GetModelsAssembly(bool forceRebuild)
        {
            var modelsDirectory = UmbracoConfig.For.ModelsBuilder().ModelsDirectory;

            if (!Directory.Exists(modelsDirectory))
            {
                Directory.CreateDirectory(modelsDirectory);
            }

            // must filter out *.generated.cs because we haven't deleted them yet!
            var ourFiles = Directory.Exists(modelsDirectory)
                ? Directory.GetFiles(modelsDirectory, "*.cs")
                           .Where(x => !x.EndsWith(".generated.cs"))
                           .ToDictionary(x => x, File.ReadAllText)
                : new Dictionary <string, string>();

            var umbraco        = Application.GetApplication();
            var typeModels     = umbraco.GetAllTypes();
            var currentHash    = HashHelper.Hash(ourFiles, typeModels);
            var modelsHashFile = Path.Combine(modelsDirectory, "models.hash");
            var modelsSrcFile  = Path.Combine(modelsDirectory, "models.generated.cs");
            var projFile       = Path.Combine(modelsDirectory, "all.generated.cs");
            var dllPathFile    = Path.Combine(modelsDirectory, "all.dll.path");

            // caching the generated models speeds up booting
            // currentHash hashes both the types & the user's partials

            if (!forceRebuild)
            {
                _logger.Logger.Debug <PureLiveModelFactory>("Looking for cached models.");
                if (File.Exists(modelsHashFile) && File.Exists(projFile))
                {
                    var cachedHash = File.ReadAllText(modelsHashFile);
                    if (currentHash != cachedHash)
                    {
                        _logger.Logger.Debug <PureLiveModelFactory>("Found obsolete cached models.");
                        forceRebuild = true;
                    }
                }
                else
                {
                    _logger.Logger.Debug <PureLiveModelFactory>("Could not find cached models.");
                    forceRebuild = true;
                }
            }

            Assembly assembly;

            if (forceRebuild == false)
            {
                // try to load the dll directly (avoid rebuilding)
                if (File.Exists(dllPathFile))
                {
                    var dllPath = File.ReadAllText(dllPathFile);
                    if (File.Exists(dllPath))
                    {
                        assembly = Assembly.LoadFile(dllPath);
                        var attr = assembly.GetCustomAttribute <ModelsBuilderAssemblyAttribute>();
                        if (attr != null && attr.PureLive && attr.SourceHash == currentHash)
                        {
                            // if we were to resume at that revision, then _ver would keep increasing
                            // and that is probably a bad idea - so, we'll always rebuild starting at
                            // ver 1, but we remember we want to skip that one - so we never end up
                            // with the "same but different" version of the assembly in memory
                            _skipver = assembly.GetName().Version.Revision;

                            _logger.Logger.Debug <PureLiveModelFactory>("Loading cached models (dll).");
                            return(assembly);
                        }
                    }
                }

                // mmust reset the version in the file else it would keep growing
                // loading cached modules only happens when the app restarts
                var text  = File.ReadAllText(projFile);
                var match = AssemblyVersionRegex.Match(text);
                if (match.Success)
                {
                    text = text.Replace(match.Value, "AssemblyVersion(\"0.0.0." + _ver + "\")");
                    File.WriteAllText(projFile, text);
                }

                // generate a marker file that will be a dependency
                // see note in RazorBuildProvider_CodeGenerationStarted
                // NO: using all.generated.cs as a dependency
                //File.WriteAllText(Path.Combine(modelsDirectory, "models.dep"), "VER:" + _ver);

                _ver++;
                assembly = BuildManager.GetCompiledAssembly(ProjVirt);
                File.WriteAllText(dllPathFile, assembly.Location);

                _logger.Logger.Debug <PureLiveModelFactory>("Loading cached models (source).");
                return(assembly);
            }

            // need to rebuild
            _logger.Logger.Debug <PureLiveModelFactory>("Rebuilding models.");

            // generate code, save
            var code = GenerateModelsCode(ourFiles, typeModels);
            // add extra attributes,
            //  PureLiveAssembly helps identifying Assemblies that contain PureLive models
            //  AssemblyVersion is so that we have a different version for each rebuild
            var ver = _ver == _skipver ? ++_ver : _ver;

            _ver++;
            code = code.Replace("//ASSATTR", $@"[assembly: PureLiveAssembly]
[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = ""{currentHash}"")]
[assembly:System.Reflection.AssemblyVersion(""0.0.0.{ver}"")]");
            File.WriteAllText(modelsSrcFile, code);

            // generate proj, save
            ourFiles["models.generated.cs"] = code;
            var proj = GenerateModelsProj(ourFiles);

            File.WriteAllText(projFile, proj);

            // compile and register
            assembly = BuildManager.GetCompiledAssembly(ProjVirt);
            File.WriteAllText(dllPathFile, assembly.Location);

            // assuming we can write and it's not going to cause exceptions...
            File.WriteAllText(modelsHashFile, currentHash);

            _logger.Logger.Debug <PureLiveModelFactory>("Done rebuilding.");
            return(assembly);
        }
Example #4
0
        private Assembly GetModelsAssembly(bool forceRebuild)
        {
            var appData = HostingEnvironment.MapPath("~/App_Data");

            if (appData == null)
            {
                throw new Exception("Panic: appData is null.");
            }

            var modelsDirectory = Path.Combine(appData, "Models");

            if (!Directory.Exists(modelsDirectory))
            {
                Directory.CreateDirectory(modelsDirectory);
            }

            // must filter out *.generated.cs because we haven't deleted them yet!
            var ourFiles = Directory.Exists(modelsDirectory)
                ? Directory.GetFiles(modelsDirectory, "*.cs")
                           .Where(x => !x.EndsWith(".generated.cs"))
                           .ToDictionary(x => x, File.ReadAllText)
                : new Dictionary <string, string>();

            var umbraco        = Application.GetApplication();
            var typeModels     = umbraco.GetAllTypes();
            var currentHash    = Hash(ourFiles, typeModels);
            var modelsHashFile = Path.Combine(modelsDirectory, "models.hash");
            var modelsSrcFile  = Path.Combine(modelsDirectory, "models.generated.cs");
            var projFile       = Path.Combine(modelsDirectory, "all.generated.cs");
            var projVirt       = "~/App_Data/Models/all.generated.cs";

            // caching the generated models speeds up booting
            // if you change your own partials, delete the .generated.cs file to force a rebuild

            if (!forceRebuild)
            {
                _logger.Logger.Debug <PureLiveModelFactory>("Looking for cached models.");
                if (File.Exists(modelsHashFile) && File.Exists(projFile))
                {
                    var cachedHash = File.ReadAllText(modelsHashFile);
                    if (currentHash != cachedHash)
                    {
                        _logger.Logger.Debug <PureLiveModelFactory>("Found obsolete cached models.");
                        forceRebuild = true;
                    }
                }
                else
                {
                    _logger.Logger.Debug <PureLiveModelFactory>("Could not find cached models.");
                    forceRebuild = true;
                }
            }

            if (forceRebuild == false)
            {
                _logger.Logger.Debug <PureLiveModelFactory>("Loading cached models.");

                // mmust reset the version in the file else it would keep growing
                // loading cached modules only happens when the app restarts
                var text  = File.ReadAllText(projFile);
                var match = AssemblyVersionRegex.Match(text);
                if (match.Success)
                {
                    text = text.Replace(match.Value, "AssemblyVersion(\"0.0.0." + _ver++ + "\")");
                    File.WriteAllText(projFile, text);
                }

                return(BuildManager.GetCompiledAssembly(projVirt));
            }

            // need to rebuild
            _logger.Logger.Debug <PureLiveModelFactory>("Rebuilding models.");

            // generate code, save
            var code = GenerateModelsCode(ourFiles, typeModels);

            // add extra attributes,
            //  PureLiveAssembly helps identifying Assemblies that contain PureLive models
            //  AssemblyVersion is so that we have a different version for each rebuild
            code = code.Replace("//ASSATTR", "[assembly: PureLiveAssembly, System.Reflection.AssemblyVersion(\"0.0.0." + _ver++ + "\")]");
            File.WriteAllText(modelsSrcFile, code);

            // generate proj, save
            ourFiles["models.generated.cs"] = code;
            var proj = GenerateModelsProj(ourFiles);

            File.WriteAllText(projFile, proj);

            // compile and register
            var assembly = BuildManager.GetCompiledAssembly(projVirt);

            // assuming we can write and it's not going to cause exceptions...
            File.WriteAllText(modelsHashFile, currentHash);

            _logger.Logger.Debug <PureLiveModelFactory>("Done rebuilding.");
            return(assembly);
        }
Example #5
0
        private Assembly GetModelsAssembly(bool forceRebuild)
        {
            var modelsDirectory = UmbracoConfig.For.ModelsBuilder().ModelsDirectory;

            if (!Directory.Exists(modelsDirectory))
            {
                Directory.CreateDirectory(modelsDirectory);
            }

            // must filter out *.generated.cs because we haven't deleted them yet!
            var ourFiles = Directory.Exists(modelsDirectory)
                ? Directory.GetFiles(modelsDirectory, "*.cs")
                           .Where(x => !x.EndsWith(".generated.cs"))
                           .ToDictionary(x => x, File.ReadAllText)
                : new Dictionary <string, string>();

            var umbraco        = Application.GetApplication();
            var typeModels     = umbraco.GetAllTypes();
            var currentHash    = HashHelper.Hash(ourFiles, typeModels);
            var modelsHashFile = Path.Combine(modelsDirectory, "models.hash");
            var modelsSrcFile  = Path.Combine(modelsDirectory, "models.generated.cs");
            var projFile       = Path.Combine(modelsDirectory, "all.generated.cs");

            // caching the generated models speeds up booting
            // if you change your own partials, delete the .generated.cs file to force a rebuild

            if (!forceRebuild)
            {
                _logger.Logger.Debug <PureLiveModelFactory>("Looking for cached models.");
                if (File.Exists(modelsHashFile) && File.Exists(projFile))
                {
                    var cachedHash = File.ReadAllText(modelsHashFile);
                    if (currentHash != cachedHash)
                    {
                        _logger.Logger.Debug <PureLiveModelFactory>("Found obsolete cached models.");
                        forceRebuild = true;
                    }
                }
                else
                {
                    _logger.Logger.Debug <PureLiveModelFactory>("Could not find cached models.");
                    forceRebuild = true;
                }
            }

            if (forceRebuild == false)
            {
                _logger.Logger.Debug <PureLiveModelFactory>("Loading cached models.");

                // mmust reset the version in the file else it would keep growing
                // loading cached modules only happens when the app restarts
                var text  = File.ReadAllText(projFile);
                var match = AssemblyVersionRegex.Match(text);
                if (match.Success)
                {
                    text = text.Replace(match.Value, "AssemblyVersion(\"0.0.0." + _ver + "\")");
                    File.WriteAllText(projFile, text);
                }

                // generate a marker file that will be a dependency
                // see note in RazorBuildProvider_CodeGenerationStarted
                // NO: using all.generated.cs as a dependency
                //File.WriteAllText(Path.Combine(modelsDirectory, "models.dep"), "VER:" + _ver);

                _ver++;
                return(BuildManager.GetCompiledAssembly(ProjVirt));
            }

            // need to rebuild
            _logger.Logger.Debug <PureLiveModelFactory>("Rebuilding models.");

            // generate code, save
            var code = GenerateModelsCode(ourFiles, typeModels);

            // add extra attributes,
            //  PureLiveAssembly helps identifying Assemblies that contain PureLive models
            //  AssemblyVersion is so that we have a different version for each rebuild
            code = code.Replace("//ASSATTR", $@"[assembly: PureLiveAssembly]
[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = ""{currentHash}"")]
[assembly:System.Reflection.AssemblyVersion(""0.0.0.{_ver++}"")]");
            File.WriteAllText(modelsSrcFile, code);

            // generate proj, save
            ourFiles["models.generated.cs"] = code;
            var proj = GenerateModelsProj(ourFiles);

            File.WriteAllText(projFile, proj);

            // compile and register
            var assembly = BuildManager.GetCompiledAssembly(ProjVirt);

            // assuming we can write and it's not going to cause exceptions...
            File.WriteAllText(modelsHashFile, currentHash);

            _logger.Logger.Debug <PureLiveModelFactory>("Done rebuilding.");
            return(assembly);
        }
        private Assembly GetModelsAssembly(bool forceRebuild)
        {
            var modelsDirectory = UmbracoConfig.For.ModelsBuilder().ModelsDirectory;

            if (!Directory.Exists(modelsDirectory))
            {
                Directory.CreateDirectory(modelsDirectory);
            }

            // must filter out *.generated.cs because we haven't deleted them yet!
            var ourFiles = Directory.Exists(modelsDirectory)
                ? Directory.GetFiles(modelsDirectory, "*.cs")
                           .Where(x => !x.EndsWith(".generated.cs"))
                           .ToDictionary(x => x, File.ReadAllText)
                : new Dictionary <string, string>();

            var umbraco        = Application.GetApplication();
            var typeModels     = umbraco.GetAllTypes();
            var currentHash    = HashHelper.Hash(ourFiles, typeModels);
            var modelsHashFile = Path.Combine(modelsDirectory, "models.hash");
            var modelsSrcFile  = Path.Combine(modelsDirectory, "models.generated.cs");
            var projFile       = Path.Combine(modelsDirectory, "all.generated.cs");
            var dllPathFile    = Path.Combine(modelsDirectory, "all.dll.path");

            // caching the generated models speeds up booting
            // currentHash hashes both the types & the user's partials

            if (!forceRebuild)
            {
                _logger.Logger.Debug <PureLiveModelFactory>("Looking for cached models.");
                if (File.Exists(modelsHashFile) && File.Exists(projFile))
                {
                    var cachedHash = File.ReadAllText(modelsHashFile);
                    if (currentHash != cachedHash)
                    {
                        _logger.Logger.Debug <PureLiveModelFactory>("Found obsolete cached models.");
                        forceRebuild = true;
                    }

                    // else cachedHash matches currentHash, we can try to load an existing dll
                }
                else
                {
                    _logger.Logger.Debug <PureLiveModelFactory>("Could not find cached models.");
                    forceRebuild = true;
                }
            }

            Assembly assembly;

            if (!forceRebuild)
            {
                // try to load the dll directly (avoid rebuilding)
                //
                // ensure that the .dll file does not have a corresponding .dll.delete file
                // as that would mean the the .dll file is going to be deleted and should not
                // be re-used - that should not happen in theory, but better be safe
                //
                // ensure that the .dll file is in the curreng codegen directory - when IIS
                // or Express does a full restart, it can switch to an entirely new codegen
                // directory, and then we end up referencing a dll which is *not* in that
                // directory, and BuildManager fails to instanciate views ("the view found
                // at ... was not created").
                //
                if (File.Exists(dllPathFile))
                {
                    var dllPath = File.ReadAllText(dllPathFile);
                    var codegen = HttpRuntime.CodegenDir;

                    _logger.Logger.Debug <PureLiveModelFactory>($"Cached models dll at {dllPath}.");

                    if (File.Exists(dllPath) && !File.Exists(dllPath + ".delete") && dllPath.StartsWith(codegen))
                    {
                        assembly = Assembly.LoadFile(dllPath);
                        var attr = assembly.GetCustomAttribute <ModelsBuilderAssemblyAttribute>();
                        if (attr != null && attr.PureLive && attr.SourceHash == currentHash)
                        {
                            // if we were to resume at that revision, then _ver would keep increasing
                            // and that is probably a bad idea - so, we'll always rebuild starting at
                            // ver 1, but we remember we want to skip that one - so we never end up
                            // with the "same but different" version of the assembly in memory
                            _skipver = assembly.GetName().Version.Revision;

                            _logger.Logger.Debug <PureLiveModelFactory>("Loading cached models (dll).");
                            return(assembly);
                        }

                        _logger.Logger.Debug <PureLiveModelFactory>("Cached models dll cannot be loaded (invalid assembly).");
                    }
                    else if (!File.Exists(dllPath))
                    {
                        _logger.Logger.Debug <PureLiveModelFactory>("Cached models dll does not exist.");
                    }
                    else if (File.Exists(dllPath + ".delete"))
                    {
                        _logger.Logger.Debug <PureLiveModelFactory>("Cached models dll is marked for deletion.");
                    }
                    else if (!dllPath.StartsWith(codegen))
                    {
                        _logger.Logger.Debug <PureLiveModelFactory>("Cached models dll is in a different codegen directory.");
                    }
                    else
                    {
                        _logger.Logger.Debug <PureLiveModelFactory>("Cached models dll cannot be loaded (why?).");
                    }
                }

                // must reset the version in the file else it would keep growing
                // loading cached modules only happens when the app restarts
                var text  = File.ReadAllText(projFile);
                var match = AssemblyVersionRegex.Match(text);
                if (match.Success)
                {
                    text = text.Replace(match.Value, "AssemblyVersion(\"0.0.0." + _ver + "\")");
                    File.WriteAllText(projFile, text);
                }

                // generate a marker file that will be a dependency
                // see note in RazorBuildProvider_CodeGenerationStarted
                // NO: using all.generated.cs as a dependency
                //File.WriteAllText(Path.Combine(modelsDirectory, "models.dep"), "VER:" + _ver);

                _ver++;
                try
                {
                    assembly = BuildManager.GetCompiledAssembly(ProjVirt);
                    File.WriteAllText(dllPathFile, assembly.Location);
                }
                catch
                {
                    _logger.Logger.Debug <PureLiveModelFactory>("Failed to compile.");

                    // the dll file reference still points to the previous dll, which is obsolete
                    // now and will be deleted by ASP.NET eventually, so better clear that reference.
                    // also touch the proj file to force views to recompile - don't delete as it's
                    // useful to have the source around for debuggin.
                    try
                    {
                        if (File.Exists(dllPathFile))
                        {
                            File.Delete(dllPathFile);
                        }
                        if (File.Exists(modelsHashFile))
                        {
                            File.Delete(modelsHashFile);
                        }
                        if (File.Exists(projFile))
                        {
                            File.SetLastWriteTime(projFile, DateTime.Now);
                        }
                    }
                    catch { /* enough */ }
                    throw;
                }

                _logger.Logger.Debug <PureLiveModelFactory>("Loading cached models (source).");
                return(assembly);
            }

            // need to rebuild
            _logger.Logger.Debug <PureLiveModelFactory>("Rebuilding models.");

            // generate code, save
            var code = GenerateModelsCode(ourFiles, typeModels);
            // add extra attributes,
            //  PureLiveAssembly helps identifying Assemblies that contain PureLive models
            //  AssemblyVersion is so that we have a different version for each rebuild
            var ver = _ver == _skipver ? ++_ver : _ver;

            _ver++;
            code = code.Replace("//ASSATTR", $@"[assembly: PureLiveAssembly]
[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = ""{currentHash}"")]
[assembly:System.Reflection.AssemblyVersion(""0.0.0.{ver}"")]");
            File.WriteAllText(modelsSrcFile, code);

            // generate proj, save
            ourFiles["models.generated.cs"] = code;
            var proj = GenerateModelsProj(ourFiles);

            File.WriteAllText(projFile, proj);

            // compile and register
            try
            {
                assembly = BuildManager.GetCompiledAssembly(ProjVirt);
                File.WriteAllText(dllPathFile, assembly.Location);
                File.WriteAllText(modelsHashFile, currentHash);
            }
            catch
            {
                _logger.Logger.Debug <PureLiveModelFactory>("Failed to compile.");

                // the dll file reference still points to the previous dll, which is obsolete
                // now and will be deleted by ASP.NET eventually, so better clear that reference.
                // also touch the proj file to force views to recompile - don't delete as it's
                // useful to have the source around for debuggin.
                try
                {
                    if (File.Exists(dllPathFile))
                    {
                        File.Delete(dllPathFile);
                    }
                    if (File.Exists(modelsHashFile))
                    {
                        File.Delete(modelsHashFile);
                    }
                    if (File.Exists(projFile))
                    {
                        File.SetLastWriteTime(projFile, DateTime.Now);
                    }
                }
                catch { /* enough */ }
                throw;
            }

            _logger.Logger.Debug <PureLiveModelFactory>("Done rebuilding.");
            return(assembly);
        }