ReactOS Sin Custom Revision Action (Revision ISO Creator)
authorCasper Hornstrup <chorns@users.sourceforge.net>
Wed, 23 Nov 2005 17:31:28 +0000 (17:31 +0000)
committerCasper Hornstrup <chorns@users.sourceforge.net>
Wed, 23 Nov 2005 17:31:28 +0000 (17:31 +0000)
svn path=/trunk/; revision=19491

cis/ReactOS.CustomRevisionAction/App.config [new file with mode: 0644]
cis/ReactOS.CustomRevisionAction/AssemblyInfo.cs [new file with mode: 0644]
cis/ReactOS.CustomRevisionAction/Default.build [new file with mode: 0644]
cis/ReactOS.CustomRevisionAction/Main.cs [new file with mode: 0644]
cis/ReactOS.CustomRevisionAction/RedirectableProcess.cs [new file with mode: 0644]

diff --git a/cis/ReactOS.CustomRevisionAction/App.config b/cis/ReactOS.CustomRevisionAction/App.config
new file mode 100644 (file)
index 0000000..b697b94
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" ?> \r
+<configuration>\r
+       <appSettings>\r
+               <add key="publishPath" value="c:\iso" />\r
+               <add key="smtpServer" value="localhost" />\r
+               <add key="errorEmail" value="mailbox@somewhere-on-the-net" />\r
+               <add key="makeParameters" value="" />\r
+               <add key="fastDisk" value="" />\r
+       </appSettings>\r
+</configuration>\r
diff --git a/cis/ReactOS.CustomRevisionAction/AssemblyInfo.cs b/cis/ReactOS.CustomRevisionAction/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..fa009e2
--- /dev/null
@@ -0,0 +1,14 @@
+using System.Reflection;\r
+using System.Runtime.CompilerServices;\r
+\r
+[assembly: AssemblyTitle("ReactOS Sin Custom Revision Action")]\r
+[assembly: AssemblyDescription("ReactOS Sin Custom Revision Action")]\r
+[assembly: AssemblyConfiguration("")]\r
+[assembly: AssemblyCompany("ReactOS Project")]\r
+[assembly: AssemblyProduct("React Operating System")]\r
+[assembly: AssemblyCopyright("Copyright 2005 ReactOS Project")]\r
+[assembly: AssemblyTrademark("")]\r
+[assembly: AssemblyCulture("")]\r
+[assembly: AssemblyVersion("1.0.*")]\r
+[assembly: AssemblyDelaySign(false)]\r
+[assembly: AssemblyKeyFile("")]\r
diff --git a/cis/ReactOS.CustomRevisionAction/Default.build b/cis/ReactOS.CustomRevisionAction/Default.build
new file mode 100644 (file)
index 0000000..8bbc2ef
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>\r
+<project name="ReactOS.CustomRevisionAction" default="build">\r
+\r
+       <property name="output.dir" value="bin" />\r
+\r
+       <target name="build" description="Build component">\r
+               <mkdir dir="${output.dir}" />\r
+               <csc target="exe"\r
+                       output="${output.dir}\ReactOS.CustomRevisionAction.exe"\r
+                       optimize="true"\r
+                       debug="true"\r
+                       doc="${output.dir}\ReactOS.CustomRevisionAction.xml"\r
+                       warninglevel="0">\r
+                       <sources>\r
+                               <include name="*.cs" />\r
+                       </sources>\r
+               </csc>\r
+       </target>\r
+\r
+</project>\r
diff --git a/cis/ReactOS.CustomRevisionAction/Main.cs b/cis/ReactOS.CustomRevisionAction/Main.cs
new file mode 100644 (file)
index 0000000..3535671
--- /dev/null
@@ -0,0 +1,254 @@
+using System;\r
+using System.IO;\r
+using System.Diagnostics;\r
+using System.Configuration;\r
+using System.Web.Mail;\r
+\r
+namespace ReactOS.CustomRevisionAction\r
+{\r
+       public class MainClass\r
+       {\r
+               /// <summary>\r
+               /// Path to store published binaries at.\r
+               /// </summary>\r
+               private static string publishPath;\r
+\r
+               /// <summary>\r
+               /// Run the application.\r
+               /// </summary>\r
+               /// <param name="script">Script to run.</param>\r
+               /// <param name="args">Arguments to pass to script.</param>\r
+               /// <param name="workingDirectory">Working directory.</param>\r
+               /// <param name="standardOutput">Receives standard output.</param>\r
+               /// <param name="standardError">Receives standard error.</param>\r
+               /// <returns>\r
+               /// Exit code.\r
+               /// </returns>\r
+               private static int RunScript(string script,\r
+                                            string args,\r
+                                            string workingDirectory,\r
+                                            out string standardOutput,\r
+                                            out string standardError)\r
+               {\r
+                       ProcessStartInfo scriptProcessStartInfo = new ProcessStartInfo(script,\r
+                                                                                      args);\r
+                       scriptProcessStartInfo.CreateNoWindow = true;\r
+                       /*\r
+                        * All standard streams must be redirected.\r
+                        * Otherwise DuplicateHandle() will fail.\r
+                        */\r
+                       scriptProcessStartInfo.RedirectStandardInput = true;\r
+                       scriptProcessStartInfo.RedirectStandardError = true;\r
+                       scriptProcessStartInfo.RedirectStandardOutput = true;\r
+                       scriptProcessStartInfo.UseShellExecute = false;\r
+                       scriptProcessStartInfo.WorkingDirectory = workingDirectory;\r
+                       RedirectableProcess redirectableProcess = new RedirectableProcess(scriptProcessStartInfo);\r
+                       standardOutput = redirectableProcess.ProcessOutput;\r
+                       standardError = redirectableProcess.ProcessError;\r
+                       return redirectableProcess.ExitCode;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Retrieve value of configuration from configuration file.\r
+               /// </summary>\r
+               /// <param name="name">Name of configuration option.</param>\r
+               /// <param name="defaultValue">\r
+               /// Default value to be returned if the option does not exist.\r
+               /// </param>\r
+               /// <returns>\r
+               /// Value of configuration option or null if the option does not\r
+               /// exist and no default value is provided.\r
+               /// </returns>\r
+               private static string GetConfigurationOption(string name,\r
+                                                            string defaultValue)\r
+               {\r
+                       if (ConfigurationSettings.AppSettings[name] != null)\r
+                               return ConfigurationSettings.AppSettings[name];\r
+                       else\r
+                               return defaultValue;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Send an email.\r
+               /// </summary>\r
+               /// <param name="subject">Subject of the email.</param>\r
+               /// <param name="body">Content of the email.</param>\r
+               private static void SendErrorMail(string subject, string body)\r
+               {\r
+                       try\r
+                       {\r
+                               string smtpServer = GetConfigurationOption("smtpServer", "localhost");\r
+                               string toEmail = GetConfigurationOption("errorEmail", null);\r
+                               if (toEmail == null)\r
+                                       return;\r
+                               string fromEmail = GetConfigurationOption("fromEmail", null);\r
+                               if (fromEmail == null)\r
+                                       fromEmail = toEmail;\r
+                               MailMessage mm = new MailMessage();\r
+                               mm.Priority = MailPriority.Normal;\r
+                               mm.From = toEmail;\r
+                               mm.To = toEmail;\r
+                               mm.Subject = subject;\r
+                               mm.Body += body;\r
+                               mm.Body += "<br>";\r
+                               mm.BodyFormat = MailFormat.Html;\r
+                               SmtpMail.SmtpServer = smtpServer;\r
+                               SmtpMail.Send(mm);\r
+                       }\r
+                       catch (Exception ex)\r
+                       {\r
+                               Console.Error.WriteLine(ex.Message);\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Fail with an error message.\r
+               /// </summary>\r
+               /// <param name="revision">Repository revision.</param>\r
+               /// <param name="text">Error message.</param>\r
+               private static void Fail(int revision,\r
+                                        string text)\r
+               {\r
+                       Console.WriteLine(text);\r
+                       Console.Error.WriteLine(text);\r
+                       SendErrorMail(String.Format("[{0}] ReactOS Publish Error", revision), text);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Fail with an error message.\r
+               /// </summary>\r
+               /// <param name="text">Error message.</param>\r
+               private static void Fail(string text)\r
+               {\r
+                       Console.WriteLine(text);\r
+                       Console.Error.WriteLine(text);\r
+                       SendErrorMail("ReactOS Publish Error", text);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Generate filename of distribution.\r
+               /// </summary>\r
+               /// <param name="branch">Branch.</param>\r
+               /// <param name="revision">Revision.</param>\r
+               private static string GetDistributionFilename(string branch,\r
+                                                             int revision)\r
+               {\r
+                       return String.Format("ReactOS-{0}-r{1}.iso",\r
+                                            branch,\r
+                                            revision);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Copy ISO to the destination.\r
+               /// </summary>\r
+               /// <param name="sourceFilename">Name of source ISO file to copy.</param>\r
+               /// <param name="branch">Branch.</param>\r
+               /// <param name="revision">Revision.</param>\r
+               /// <remarks>\r
+               /// Structure is <branch>\ReactOS-<branch>-r<revision>.iso.\r
+               /// </remarks>\r
+               private static void CopyISOToDestination(string sourceFilename,\r
+                                                        string branch,\r
+                                                        int revision)\r
+               {\r
+                       string distributionFilename = GetDistributionFilename(branch,\r
+                                                                             revision);\r
+                       string destinationDirectory = Path.Combine(publishPath,\r
+                                                                  branch);\r
+                       string destinationFilename = Path.Combine(destinationDirectory,\r
+                                                                 distributionFilename);\r
+                       if (!Directory.Exists(destinationDirectory))\r
+                               Directory.CreateDirectory(destinationDirectory);\r
+                       File.Copy(sourceFilename,\r
+                                 destinationFilename);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Publish a revision of ReactOS.\r
+               /// </summary>\r
+               /// <param name="text">Error message.</param>\r
+               private static int Publish(string branch,\r
+                                          int revision,\r
+                                          string workingDirectory)\r
+               {\r
+                       string make = "mingw32-make";\r
+                       string makeParameters = GetConfigurationOption("makeParameters", "");\r
+                       string reactosDirectory = Path.Combine(workingDirectory,\r
+                                                              "reactos");\r
+                       Console.WriteLine(String.Format("ReactOS directory is {0}",\r
+                                                       reactosDirectory));\r
+                       string standardOutput;\r
+                       string standardError;\r
+                       int exitCode = RunScript(make,\r
+                                                makeParameters + " bootcd",\r
+                                                reactosDirectory,\r
+                                                out standardOutput,\r
+                                                out standardError);\r
+                       if (exitCode != 0)\r
+                       {\r
+                               Fail(revision,\r
+                                    String.Format("make bootcd failed: (error: {0}) {1}",\r
+                                                  standardError,\r
+                                                  standardOutput));\r
+                               return exitCode;\r
+                       }\r
+\r
+                       string sourceFilename = Path.Combine(reactosDirectory,\r
+                                                            "ReactOS.iso");\r
+                       if (File.Exists(sourceFilename))\r
+                               CopyISOToDestination(sourceFilename,\r
+                                                    branch,\r
+                                                    revision);\r
+                       else\r
+                       {\r
+                               Fail(revision,\r
+                                    "make bootcd produced no ReactOS.iso");\r
+                               return exitCode;\r
+                       }\r
+\r
+                       return exitCode;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Program entry point.\r
+               /// </summary>\r
+               /// <param name="args">Arguments from command line.</param>\r
+               /// <remarks>\r
+               /// If exit code is 0, then the commit was processed successfully.\r
+               /// If exit code is 1, then the commit was not processed successfully.\r
+               /// </remarks>\r
+               public static void Main(string[] args)\r
+               {\r
+                       try\r
+                       {\r
+                               System.Environment.ExitCode = 1;\r
+\r
+                               publishPath = ConfigurationSettings.AppSettings["publishPath"];\r
+                               if (publishPath == null)\r
+                               {\r
+                                       Fail("PublishPath option not set.");\r
+                                       return;\r
+                               }\r
+\r
+                               if (args.Length < 3)\r
+                               {\r
+                                       Fail("Usage: ReactOS.CustomRevisionAction action branch revision");\r
+                                       return;\r
+                               }\r
+\r
+                               string action = args[0]; /* bootcd */\r
+                               string branch = args[1];\r
+                               int revision = Int32.Parse(args[2]);\r
+                               \r
+                               System.Environment.ExitCode = Publish(branch,\r
+                                                                     revision,\r
+                                                                     System.Environment.CurrentDirectory);\r
+                       }\r
+                       catch (Exception ex)\r
+                       {\r
+                               Fail(String.Format("Exception: {0}", ex));\r
+                               System.Environment.ExitCode = 1;\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/cis/ReactOS.CustomRevisionAction/RedirectableProcess.cs b/cis/ReactOS.CustomRevisionAction/RedirectableProcess.cs
new file mode 100644 (file)
index 0000000..e0acb7f
--- /dev/null
@@ -0,0 +1,145 @@
+/*\r
+ * When using the ProcessStartInfo.RedirectStandardXxx properties there is a chance of\r
+ * the parent and child process blocking due to a race condition. This class handles the\r
+ * problem.\r
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdiagnosticsprocessstartinfoclassredirectstandardoutputtopic.asp\r
+ */\r
+using System;\r
+using System.IO;\r
+using System.Threading;\r
+using System.Diagnostics;\r
+\r
+namespace ReactOS.CustomRevisionAction\r
+{\r
+       /// <summary>\r
+       /// Process that redirects standard output and standard error streams.\r
+       /// </summary>\r
+       public class RedirectableProcess\r
+       {\r
+               /// <summary>\r
+               /// Process.\r
+               /// </summary>\r
+               private Process process;\r
+\r
+               /// <summary>\r
+               /// Redirected standard error stream.\r
+               /// </summary>\r
+               private string processError;\r
+\r
+               /// <summary>\r
+               /// Redirected standard output stream.\r
+               /// </summary>\r
+               private string processOutput;\r
+\r
+               /// <summary>\r
+               /// Exit code.\r
+               /// </summary>\r
+               private int exitCode;\r
+\r
+               /// <summary>\r
+               /// Redirected standard error stream.\r
+               /// </summary>\r
+               public string ProcessError\r
+               {\r
+                       get\r
+                       {\r
+                               return processError;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Redirected standard output stream.\r
+               /// </summary>\r
+               public string ProcessOutput\r
+               {\r
+                       get\r
+                       {\r
+                               return processOutput;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Exit code.\r
+               /// </summary>\r
+               public int ExitCode\r
+               {\r
+                       get\r
+                       {\r
+                               return exitCode;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Run an excutable and redirect standard error and/or standard output safely.\r
+               /// </summary>\r
+               public RedirectableProcess(ProcessStartInfo processStartInfo)\r
+               {\r
+                       Run(processStartInfo, null);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Run an excutable and redirect standard error and/or standard output safely.\r
+               /// </summary>\r
+               public RedirectableProcess(ProcessStartInfo processStartInfo, string input)\r
+               {\r
+                       Run(processStartInfo, input);\r
+               }\r
+               \r
+               private void Run(ProcessStartInfo processStartInfo, string input)\r
+               {\r
+                       process = new Process();\r
+                       process.StartInfo = processStartInfo;\r
+                       process.Start();\r
+                       if (processStartInfo.RedirectStandardInput && input != null)\r
+                       {\r
+                               process.StandardInput.AutoFlush = true;\r
+                               process.StandardInput.WriteLine(input);\r
+                       }\r
+                       Thread readStandardError = null;\r
+                       if (processStartInfo.RedirectStandardError)\r
+                       {\r
+                               readStandardError = new Thread(new ThreadStart(ReadStandardError));\r
+                               readStandardError.Start();\r
+                       }\r
+                       Thread readStandardOutput = null;\r
+                       if (processStartInfo.RedirectStandardOutput)\r
+                       {\r
+                               readStandardOutput = new Thread(new ThreadStart(ReadStandardOutput));\r
+                               readStandardOutput.Start();\r
+                       }\r
+                       if (processStartInfo.RedirectStandardError)\r
+                       {\r
+                               readStandardError.Join();\r
+                       }\r
+                       if (processStartInfo.RedirectStandardOutput)\r
+                       {\r
+                               readStandardOutput.Join();\r
+                       }\r
+                       process.WaitForExit();\r
+                       exitCode = process.ExitCode;\r
+                       process = null;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Read standard error thread entry-point.\r
+               /// </summary>          \r
+               private void ReadStandardError()\r
+               {\r
+                       if (process != null)\r
+                       {\r
+                               processError = process.StandardError.ReadToEnd();\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Read standard output thread entry-point.\r
+               /// </summary>          \r
+               private void ReadStandardOutput()\r
+               {\r
+                       if (process != null)\r
+                       {\r
+                               processOutput = process.StandardOutput.ReadToEnd();\r
+                       }\r
+               }\r
+       }\r
+}\r