public async static Task <Stetic.CodeGenerationResult> GenerateSteticCode(ProgressMonitor monitor, DotNetProject project, ConfigurationSelector configuration)
        {
            if (generating || !GtkDesignInfo.HasDesignedObjects(project))
            {
                return(null);
            }

            using (var timer = Counters.SteticFileGeneratedTimer.BeginTiming()) {
                timer.Trace("Checking references");
                GtkDesignInfo info = GtkDesignInfo.FromProject(project);

                DateTime last_gen_time = File.Exists(info.SteticGeneratedFile) ? File.GetLastWriteTime(info.SteticGeneratedFile) : DateTime.MinValue;

                bool ref_changed = false;

                // Disabled check for changes in referenced assemblies, since it cause too much
                // regeneration of code. If a component has changed in a referenced project, this
                // project may not build, but this can be solved by editing some file in the
                // designer and saving.

/*				foreach (ProjectReference pref in project.References) {
 *                                      if (!pref.IsValid)
 *                                              continue;
 *                                      foreach (string filename in pref.GetReferencedFileNames (configuration)) {
 *                                              if (File.GetLastWriteTime (filename) > last_gen_time) {
 *                                                      ref_changed = true;
 *                                                      break;
 *                                              }
 *                                      }
 *                                      if (ref_changed)
 *                                              break;
 *                              }*/

                // Check if generated code is already up to date.
                if (!ref_changed && last_gen_time >= File.GetLastWriteTime(info.SteticFile))
                {
                    return(null);
                }

                if (info.GuiBuilderProject.HasError)
                {
                    var error = GettextCatalog.GetString("GUI code generation failed for project '{0}'. The file '{1}' could not be loaded.", project.Name, info.SteticFile);
                    monitor.ReportError(error, null);
                    throw new UserException(error);
                }

                if (info.GuiBuilderProject.IsEmpty)
                {
                    return(null);
                }

                monitor.Log.WriteLine(GettextCatalog.GetString("Generating GUI code for project '{0}'...", project.Name));

                timer.Trace("Copy support files");

                // Make sure the referenced assemblies are up to date. It is necessary to do
                // it now since they may contain widget libraries.
                project.CopySupportFiles(monitor, configuration);

                timer.Trace("Update libraries");

                info.GuiBuilderProject.UpdateLibraries();

                ArrayList projects = new ArrayList();
                projects.Add(info.GuiBuilderProject.File);

                generating = true;
                Stetic.CodeGenerationResult generationResult = null;
                Exception generatedException = null;

                bool canGenerateInProcess = IsolationMode != Stetic.IsolationMode.None || info.GuiBuilderProject.SteticProject.CanGenerateCode;

                if (!canGenerateInProcess)
                {
                    timer.Trace("Generating out of process");

                    await Task.Run(delegate {
                        try {
                            // Generate the code in another process if stetic is not isolated
                            CodeGeneratorProcess cob = (CodeGeneratorProcess)Runtime.ProcessService.CreateExternalProcessObject(typeof(CodeGeneratorProcess), false);
                            using (cob) {
                                generationResult = cob.GenerateCode(projects, info.GenerateGettext, info.GettextClass, info.ImageResourceLoaderClass, project.UsePartialTypes);
                            }
                        } catch (Exception ex) {
                            generatedException = ex;
                        } finally {
                            generating = false;
                        }
                    });
                }
                else
                {
                    timer.Trace("Generating in-process");
                    // No need to create another process, since stetic has its own backend process
                    // or the widget libraries have no custom wrappers
                    try {
                        Stetic.GenerationOptions options = new Stetic.GenerationOptions();
                        options.UseGettext               = info.GenerateGettext;
                        options.GettextClass             = info.GettextClass;
                        options.ImageResourceLoaderClass = info.ImageResourceLoaderClass;
                        options.UsePartialClasses        = project.UsePartialTypes;
                        options.GenerateSingleFile       = false;
                        options.GenerateModifiedOnly     = true;
                        generationResult = SteticApp.GenerateProjectCode(options, info.GuiBuilderProject.SteticProject);
                        info.GuiBuilderProject.SteticProject.ResetModifiedWidgetFlags();
                    } catch (Exception ex) {
                        generatedException = ex;
                    }
                    generating = false;
                }
                timer.Trace("Writing code units");

                if (generatedException != null)
                {
                    LoggingService.LogError("GUI code generation failed", generatedException);
                    throw new UserException("GUI code generation failed: " + generatedException.Message);
                }

                if (generationResult == null)
                {
                    return(null);
                }

                CodeDomProvider provider = project.LanguageBinding.GetCodeDomProvider();
                if (provider == null)
                {
                    throw new UserException("Code generation not supported for language: " + project.LanguageName);
                }

                string basePath = Path.GetDirectoryName(info.SteticGeneratedFile);
                string ext      = Path.GetExtension(info.SteticGeneratedFile);

                var pol = project.Policies.Get <TextStylePolicy> ();
                var codeGeneratorOptions = new CodeGeneratorOptions()
                {
                    IndentString             = pol.TabsToSpaces? new string (' ', pol.TabWidth) : "\t",
                    BlankLinesBetweenMembers = true
                };

                foreach (Stetic.SteticCompilationUnit unit in generationResult.Units)
                {
                    string fname;
                    if (unit.Name.Length == 0)
                    {
                        fname = info.SteticGeneratedFile;
                    }
                    else
                    {
                        fname = Path.Combine(basePath, unit.Name) + ext;
                    }
                    StringWriter sw = new StringWriter();
                    try {
                        foreach (CodeNamespace ns in unit.Namespaces)
                        {
                            ns.Comments.Add(new CodeCommentStatement("This file has been generated by the GUI designer. Do not modify."));
                        }
                        timer.Trace("Generating code for " + unit.Name);
                        provider.GenerateCodeFromCompileUnit(unit, sw, codeGeneratorOptions);
                        string content = sw.ToString();

                        timer.Trace("Formatting code");
                        content = FormatGeneratedFile(fname, content, project, provider);
                        timer.Trace("Writing code");
                        File.WriteAllText(fname, content);
                    } finally {
                        timer.Trace("Notifying changes");
                        FileService.NotifyFileChanged(fname);
                    }
                }

                timer.Trace("Updating GTK folder");

                // Make sure the generated files are added to the project
                if (info.UpdateGtkFolder())
                {
                    Gtk.Application.Invoke(delegate {
                        IdeApp.ProjectOperations.SaveAsync(project);
                    });
                }

                return(generationResult);
            }
        }
Exemple #2
0
        public static Stetic.CodeGenerationResult GenerateSteticCode(IProgressMonitor monitor, DotNetProject project, ConfigurationSelector configuration)
        {
            if (generating || !GtkDesignInfo.HasDesignedObjects(project))
            {
                return(null);
            }

            GtkDesignInfo info = GtkDesignInfo.FromProject(project);

            info.CheckGtkFolder();

            DateTime last_gen_time = File.Exists(info.SteticGeneratedFile) ? File.GetLastWriteTime(info.SteticGeneratedFile) : DateTime.MinValue;

            bool ref_changed = false;

            foreach (ProjectReference pref in project.References)
            {
                if (!pref.IsValid)
                {
                    continue;
                }
                foreach (string filename in pref.GetReferencedFileNames(configuration))
                {
                    if (File.GetLastWriteTime(filename) > last_gen_time)
                    {
                        ref_changed = true;
                        break;
                    }
                }
                if (ref_changed)
                {
                    break;
                }
            }

            // Check if generated code is already up to date.
//			if (!ref_changed && last_gen_time >= File.GetLastWriteTime (info.SteticFile))
//				return null;

            if (info.GuiBuilderProject.HasError)
            {
                monitor.ReportError(GettextCatalog.GetString("GUI code generation failed for project '{0}'. The file '{1}' could not be loaded.", project.Name, info.SteticFile), null);
                monitor.AsyncOperation.Cancel();
                return(null);
            }

            if (info.GuiBuilderProject.IsEmpty)
            {
                return(null);
            }

            monitor.Log.WriteLine(GettextCatalog.GetString("Generating GUI code for project '{0}'...", project.Name));

            // Make sure the referenced assemblies are up to date. It is necessary to do
            // it now since they may contain widget libraries.
            project.CopySupportFiles(monitor, configuration);

            info.GuiBuilderProject.UpdateLibraries();

            ArrayList projectFolders = new ArrayList();

            projectFolders.Add(info.SteticFolder.FullPath);

            generating = true;
            Stetic.CodeGenerationResult generationResult = null;
            Exception generatedException = null;

            bool canGenerateInProcess = IsolationMode != Stetic.IsolationMode.None || info.GuiBuilderProject.SteticProject.CanGenerateCode;

            if (!canGenerateInProcess)
            {
                // Run the generation in another thread to avoid freezing the GUI
                System.Threading.ThreadPool.QueueUserWorkItem(delegate {
                    try {
                        // Generate the code in another process if stetic is not isolated
                        CodeGeneratorProcess cob = (CodeGeneratorProcess)Runtime.ProcessService.CreateExternalProcessObject(typeof(CodeGeneratorProcess), false);
                        using (cob) {
                            generationResult = cob.GenerateCode(projectFolders, info.GenerateGettext, info.GettextClass, project.UsePartialTypes, info);
                        }
                    } catch (Exception ex) {
                        generatedException = ex;
                    } finally {
                        generating = false;
                    }
                });

                while (generating)
                {
                    DispatchService.RunPendingEvents();
                    System.Threading.Thread.Sleep(100);
                }
            }
            else
            {
                // No need to create another process, since stetic has its own backend process
                // or the widget libraries have no custom wrappers
                try {
                    Stetic.GenerationOptions options = new Stetic.GenerationOptions();
                    options.UseGettext   = info.GenerateGettext;
                    options.GettextClass = info.GettextClass;
                    generationResult     = SteticApp.GenerateProjectCode(options, info.GuiBuilderProject.SteticProject);
                } catch (Exception ex) {
                    generatedException = ex;
                }
                generating = false;
            }

            if (generatedException != null)
            {
                string msg = string.Empty;

                if (generatedException.InnerException != null)
                {
                    msg = string.Format("{0}\n{1}\nInner Exception {2}\n{3}",
                                        generatedException.Message,
                                        generatedException.StackTrace,
                                        generatedException.InnerException.Message,
                                        generatedException.InnerException.StackTrace);
                }
                else
                {
                    msg = string.Format("{0}\n{1}",
                                        generatedException.Message,
                                        generatedException.StackTrace);
                }

//				LoggingService.LogError ("GUI code generation failed", generatedException);
                LoggingService.LogError("GUI code generation failed: " + msg);
                throw new UserException("GUI code generation failed: " + msg);
            }

            if (generationResult == null)
            {
                return(null);
            }

            CodeDomProvider provider = project.LanguageBinding.GetCodeDomProvider();

            if (provider == null)
            {
                throw new UserException("Code generation not supported for language: " + project.LanguageName);
            }

            foreach (Stetic.SteticCompilationUnit unit in generationResult.Units)
            {
                string fname;
                if (unit.Name.Length == 0)
                {
                    fname = info.SteticGeneratedFile;
                }
                else
                {
                    fname = GetBuildCodeFileName(project,
                                                 unit.Name,
                                                 (unit.Namespace != null) ? unit.Namespace.Name : string.Empty);
                }

                StringWriter sw = new StringWriter();
                try {
                    foreach (CodeNamespace ns in unit.Namespaces)
                    {
                        ns.Comments.Add(new CodeCommentStatement("This file has been generated by the GUI designer. Do not modify."));
                    }
                    provider.GenerateCodeFromCompileUnit(unit, sw, new CodeGeneratorOptions());
                    string content = sw.ToString();
                    content = FormatGeneratedFile(fname, content, provider);
                    File.WriteAllText(fname, content);
                } finally {
                    FileService.NotifyFileChanged(fname);
                }
            }

            // Make sure the generated files are added to the project
            if (info.UpdateGtkFolder())
            {
                Gtk.Application.Invoke(delegate {
                    IdeApp.ProjectOperations.Save(project);
                });
            }

            return(generationResult);
        }