Beispiel #1
0
        public static BuildResultCode Build(BuilderOptions options)
        {
            BuildResultCode result;

            if (options.IsValidForSlave())
            {
                // Sleeps one second so that debugger can attach
                //Thread.Sleep(1000);

                result = BuildSlave(options);
            }
            else if (options.IsValidForMaster())
            {
                result = BuildLocal(options);

                if (!string.IsNullOrWhiteSpace(options.OutputDirectory) && options.BuilderMode == Builder.Mode.Build)
                {
                    CopyBuildToOutput(options);
                }
            }
            else
            {
                throw new OptionException("Insufficient parameters, no action taken", "build-path");
            }

            return(result);
        }
Beispiel #2
0
        public static BuildResultCode BuildLocal(BuilderOptions options)
        {
            string inputFile = options.InputFiles[0];
            string sdkDir    = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../..");

            BuildScript buildScript = BuildScript.LoadFromFile(sdkDir, inputFile);

            buildScript.Compile(options.Plugins);

            if (buildScript.GetWarnings().FirstOrDefault() != null)
            {
                foreach (string warning in buildScript.GetWarnings())
                {
                    options.Logger.Warning(warning);
                }
            }

            if (buildScript.HasErrors)
            {
                foreach (string error in buildScript.GetErrors())
                {
                    options.Logger.Error(error);
                }
                throw new InvalidOperationException("Can't compile the provided build script.");
            }

            string inputDir = Path.GetDirectoryName(inputFile) ?? Environment.CurrentDirectory;

            options.SourceBaseDirectory       = options.SourceBaseDirectory ?? Path.Combine(inputDir, buildScript.SourceBaseDirectory ?? "");
            options.BuildDirectory            = options.BuildDirectory ?? Path.Combine(inputDir, buildScript.BuildDirectory ?? "");
            options.OutputDirectory           = options.OutputDirectory ?? (buildScript.OutputDirectory != null ? Path.Combine(inputDir, buildScript.OutputDirectory) : "");
            options.MetadataDatabaseDirectory = options.MetadataDatabaseDirectory ?? (buildScript.MetadataDatabaseDirectory != null ? Path.Combine(inputDir, buildScript.MetadataDatabaseDirectory) : "");
            if (!string.IsNullOrWhiteSpace(options.SourceBaseDirectory))
            {
                if (!Directory.Exists(options.SourceBaseDirectory))
                {
                    string error = string.Format("Source base directory \"{0}\" does not exists.", options.SourceBaseDirectory);
                    options.Logger.Error(error);
                    throw new OptionException(error, "sourcebase");
                }
                Environment.CurrentDirectory = options.SourceBaseDirectory;
            }

            if (string.IsNullOrWhiteSpace(options.BuildDirectory))
            {
                throw new OptionException("This tool requires a build path.", "build-path");
            }

            // Mount build path
            ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(options.BuildDirectory);

            options.ValidateOptionsForMaster();

            // assets is always added by default
            //options.Databases.Add(new DatabaseMountInfo("/assets"));
            PrepareDatabases(options);

            try
            {
                VirtualFileSystem.CreateDirectory("/data/");
                VirtualFileSystem.CreateDirectory("/data/db/");
            }
            catch (Exception)
            {
                throw new OptionException("Invalid Build database path", "database");
            }

            // Create builder
            LogMessageType logLevel = options.Debug ? LogMessageType.Debug : (options.Verbose ? LogMessageType.Verbose : LogMessageType.Info);
            var            logger   = Logger.GetLogger("builder");

            logger.ActivateLog(logLevel);
            var builder = new Builder("builder", options.BuildDirectory, options.BuilderMode, logger)
            {
                ThreadCount = options.ThreadCount
            };

            builder.MonitorPipeNames.AddRange(options.MonitorPipeNames);
            builder.ActivateConfiguration(options.Configuration);
            foreach (var sourceFolder in buildScript.SourceFolders)
            {
                builder.InitialVariables.Add(("SourceFolder:" + sourceFolder.Key).ToUpperInvariant(), sourceFolder.Value);
            }
            Console.CancelKeyPress += (sender, e) => Cancel(builder, e);

            buildScript.Execute(builder);

            // Run builder
            return(builder.Run(options.Append == false));
        }
Beispiel #3
0
 private static void PrepareDatabases(BuilderOptions options)
 {
     AssetManager.GetDatabaseFileProvider = () => IndexFileCommand.DatabaseFileProvider.Value;
 }
Beispiel #4
0
 public static void CopyBuildToOutput(BuilderOptions options)
 {
     throw new InvalidOperationException();
 }
Beispiel #5
0
        public static BuildResultCode BuildSlave(BuilderOptions options)
        {
            // Mount build path
            ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(options.BuildDirectory);

            PrepareDatabases(options);

            try
            {
                VirtualFileSystem.CreateDirectory("/data/");
                VirtualFileSystem.CreateDirectory("/data/db/");
            }
            catch (Exception)
            {
                throw new OptionException("Invalid Build database path", "database");
            }

            // Open WCF channel with master builder
            var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
            {
                SendTimeout = TimeSpan.FromSeconds(300.0)
            };
            var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(options.SlavePipe));

            try
            {
                RegisterRemoteLogger(processBuilderRemote);

                // Create scheduler
                var scheduler = new Scheduler();

                var status = ResultStatus.NotProcessed;

                // Schedule command
                string      buildPath   = options.BuildDirectory;
                Logger      logger      = options.Logger;
                MicroThread microthread = scheduler.Add(async() =>
                {
                    // Deserialize command and parameters
                    Command command = processBuilderRemote.GetCommandToExecute();
                    BuildParameterCollection parameters = processBuilderRemote.GetBuildParameters();

                    // Run command
                    var inputHashes    = new DictionaryStore <InputVersionKey, ObjectId>(VirtualFileSystem.OpenStream("/data/db/InputHashes", VirtualFileMode.OpenOrCreate, VirtualFileAccess.ReadWrite, VirtualFileShare.ReadWrite));
                    var builderContext = new BuilderContext(buildPath, inputHashes, parameters, 0, null);

                    var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger);
                    command.PreCommand(commandContext);
                    status = await command.DoCommand(commandContext);
                    command.PostCommand(commandContext, status);

                    // Returns result to master builder
                    processBuilderRemote.RegisterResult(commandContext.ResultEntry);
                });

                while (true)
                {
                    scheduler.Run();

                    // Exit loop if no more micro threads
                    lock (scheduler.MicroThreads)
                    {
                        if (!scheduler.MicroThreads.Any())
                        {
                            break;
                        }
                    }

                    Thread.Sleep(0);
                }

                // Rethrow any exception that happened in microthread
                if (microthread.Exception != null)
                {
                    options.Logger.Fatal(microthread.Exception.ToString());
                    return(BuildResultCode.BuildError);
                }

                if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful)
                {
                    return(BuildResultCode.Successful);
                }

                return(BuildResultCode.BuildError);
            }
            finally
            {
                // Close WCF channel
                // ReSharper disable SuspiciousTypeConversion.Global
                ((IClientChannel)processBuilderRemote).Close();
                // ReSharper restore SuspiciousTypeConversion.Global
            }
        }
Beispiel #6
0
        private static int Main(string[] args)
        {
            var exeName  = Path.GetFileName(Assembly.GetExecutingAssembly().Location);
            var showHelp = false;
            var options  = new BuilderOptions(Logger.GetLogger("BuildEngine"));

            var p = new OptionSet
            {
                "Copyright (c) Stride contributors (https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) All Rights Reserved",
                "Stride Build Tool - Version: "
                +
                String.Format(
                    "{0}.{1}.{2}",
                    typeof(Program).Assembly.GetName().Version.Major,
                    typeof(Program).Assembly.GetName().Version.Minor,
                    typeof(Program).Assembly.GetName().Version.Build) + string.Empty,
                string.Format("Usage: {0} [options]* inputfile -o outputfile", exeName),
                string.Empty,
                "=== Options ===",
                string.Empty,
                { "h|help", "Show this message and exit", v => showHelp = v != null },
                { "v|verbose", "Show more verbose progress logs", v => options.Verbose = v != null },
                { "d|debug", "Show debug logs (imply verbose)", v => options.Debug = v != null },
                { "c|clean", "Clean the command cache, forcing to rebuild everything at the next build.", v => options.BuilderMode = Builder.Mode.Clean },
                { "cd|clean-delete", "Clean the command cache and delete output objects", v => options.BuilderMode = Builder.Mode.CleanAndDelete },
                { "b|build-path=", "Build path", v => options.BuildDirectory = v },
                { "mdb|metadata-database=", "Optional ; indicate the directory containing the Metadata database, if used.", v => { if (!string.IsNullOrEmpty(v))
                                                                                                                                   {
                                                                                                                                       options.MetadataDatabaseDirectory = v;
                                                                                                                                   }
                  } },
                { "o|output-path=", "Optional ; indicate an output path to copy the built assets in.", v => options.OutputDirectory = v },
                { "cfg|config=", "Configuration name", v => options.Configuration = v },
                { "log", "Enable file logging", v => options.EnableFileLogging = v != null },
                { "log-file=", "Log build in a custom file.", v =>
                  {
                      options.EnableFileLogging = v != null;
                      options.CustomLogFileName = v;
                  } },
                { "monitor-pipe=", "Monitor pipe.", v =>
                  {
                      if (!string.IsNullOrEmpty(v))
                      {
                          options.MonitorPipeNames.Add(v);
                      }
                  } },
                { "slave=", "Slave pipe", v => options.SlavePipe = v },     // Benlitz: I don't think this should be documented
                { "s|sourcebase=", "Optional ; Set the base directory for the source files. Not required if all source paths are absolute", v => options.SourceBaseDirectory = v },
                { "a|append", "If set, the existing asset mappings won't be deleted.", v => options.Append = v != null },
                { "t|threads=", "Number of threads to create. Default value is the number of hardware threads available.", v => options.ThreadCount = int.Parse(v) },
                { "p|plugin=", "Add plugin directory.", v =>
                  {
                      if (!string.IsNullOrEmpty(v))
                      {
                          options.Plugins.AddPluginFolder(v);
                      }
                  } },
                { "test=", "Run a test session.", v => options.TestName = v }
            };

            TextWriterLogListener fileLogListener = null;

            // Output logs to the console with colored messages
            if (options.SlavePipe == null)
            {
                var consoleLogListener = new ConsoleLogListener {
                    TextFormatter = FormatLog
                };
                GlobalLogger.MessageLogged += consoleLogListener;
            }

            // Setting up plugin manager
            options.Plugins.AddPluginFolder(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) ?? "", "BuildPlugins"));
            options.Plugins.Register();

            BuildResultCode exitCode;

            try
            {
                options.InputFiles = p.Parse(args);

                // Also write logs from master process into a file
                if (options.SlavePipe == null)
                {
                    if (options.EnableFileLogging)
                    {
                        string logFileName = options.CustomLogFileName;
                        if (string.IsNullOrEmpty(logFileName))
                        {
                            string inputName = "NoInput";
                            if (options.InputFiles.Count > 0)
                            {
                                inputName = Path.GetFileNameWithoutExtension(options.InputFiles[0]);
                            }

                            logFileName = "Logs/Build-" + inputName + "-" + DateTime.Now.ToString("yy-MM-dd-HH-mm") + ".txt";
                        }

                        string dirName = Path.GetDirectoryName(logFileName);
                        if (dirName != null)
                        {
                            Directory.CreateDirectory(dirName);
                        }

                        fileLogListener = new TextWriterLogListener(new FileStream(logFileName, FileMode.Create))
                        {
                            TextFormatter = FormatLog
                        };
                        GlobalLogger.MessageLogged += fileLogListener;
                    }
                    options.Logger.Info("BuildEngine arguments: " + string.Join(" ", args));
                    options.Logger.Info("Starting builder.");
                }

                if (showHelp)
                {
                    p.WriteOptionDescriptions(Console.Out);
                    exitCode = BuildResultCode.Successful;
                }
                else if (!string.IsNullOrEmpty(options.TestName))
                {
                    var test = new TestSession();
                    test.RunTest(options.TestName, options.Logger);
                    exitCode = BuildResultCode.Successful;
                }
                else
                {
                    exitCode = BuildEngineCommands.Build(options);
                }
            }
            catch (OptionException e)
            {
                options.Logger.Error("{0}", e);
                exitCode = BuildResultCode.CommandLineError;
            }
            catch (Exception e)
            {
                options.Logger.Error("{0}", e);
                exitCode = BuildResultCode.BuildError;
            }
            finally
            {
                if (fileLogListener != null)
                {
                    fileLogListener.LogWriter.Close();
                }
            }
            return((int)exitCode);
        }