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