diff --git a/cis/ReactOS.Verify/App.config b/cis/ReactOS.Verify/App.config
new file mode 100644
index 00000000000..45b24c6e7fe
--- /dev/null
+++ b/cis/ReactOS.Verify/App.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/cis/ReactOS.Verify/AssemblyInfo.cs b/cis/ReactOS.Verify/AssemblyInfo.cs
new file mode 100644
index 00000000000..f3000d00415
--- /dev/null
+++ b/cis/ReactOS.Verify/AssemblyInfo.cs
@@ -0,0 +1,14 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("ReactOS Sin Verifier")]
+[assembly: AssemblyDescription("ReactOS Sin Verifier")]
+[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("")]
diff --git a/cis/ReactOS.Verify/Default.build b/cis/ReactOS.Verify/Default.build
new file mode 100644
index 00000000000..da799e116ff
--- /dev/null
+++ b/cis/ReactOS.Verify/Default.build
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cis/ReactOS.Verify/Main.cs b/cis/ReactOS.Verify/Main.cs
new file mode 100644
index 00000000000..f997a8dbcc3
--- /dev/null
+++ b/cis/ReactOS.Verify/Main.cs
@@ -0,0 +1,279 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Configuration;
+using System.Web.Mail;
+using System.Collections;
+using System.Collections.Specialized;
+
+namespace ReactOS.Verify
+{
+ public class MainClass
+ {
+ ///
+ /// Run the application.
+ ///
+ /// Script to run.
+ /// Arguments to pass to script.
+ /// Working directory.
+ /// Receives standard output.
+ /// Receives standard error.
+ ///
+ /// Exit code.
+ ///
+ private static int RunScript(string script,
+ string args,
+ string workingDirectory,
+ StringDictionary environmentVarables,
+ 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;
+ if (environmentVarables != null)
+ {
+ foreach (DictionaryEntry de in environmentVarables)
+ scriptProcessStartInfo.EnvironmentVariables.Add(de.Key as string, de.Value as string);
+ }
+ RedirectableProcess redirectableProcess = new RedirectableProcess(scriptProcessStartInfo);
+ standardOutput = redirectableProcess.ProcessOutput;
+ standardError = redirectableProcess.ProcessError;
+ return redirectableProcess.ExitCode;
+ }
+
+ ///
+ /// Retrieve value of configuration from configuration file.
+ ///
+ /// Name of configuration option.
+ ///
+ /// Default value to be returned if the option does not exist.
+ ///
+ ///
+ /// Value of configuration option or null if the option does not
+ /// exist and no default value is provided.
+ ///
+ private static string GetConfigurationOption(string name,
+ string defaultValue)
+ {
+ if (ConfigurationSettings.AppSettings[name] != null)
+ {
+ string s = ConfigurationSettings.AppSettings[name].Trim();
+ return s.Equals(String.Empty) ? defaultValue : s;
+ }
+ else
+ return defaultValue;
+ }
+
+ ///
+ /// Send an email.
+ ///
+ /// Subject of the email.
+ /// Content of the email.
+ private static void SendErrorMail(string subject, string body)
+ {
+ try
+ {
+ string smtpServer = GetConfigurationOption("smtpServer", "localhost");
+ string email = GetConfigurationOption("errorEmail", null);
+ if (email == null)
+ return;
+ MailMessage mm = new MailMessage();
+ mm.Priority = MailPriority.Normal;
+ mm.From = email;
+ mm.To = email;
+ mm.Subject = subject;
+ mm.Body += body;
+ mm.Body += "
";
+ mm.BodyFormat = MailFormat.Html;
+ SmtpMail.SmtpServer = smtpServer;
+ SmtpMail.Send(mm);
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine(ex.Message);
+ }
+ }
+
+ ///
+ /// Fail with an error message.
+ ///
+ /// Error message.
+ private static void Fail(string text)
+ {
+ Console.WriteLine(text);
+ }
+
+ ///
+ /// Paths to fast disk for temporary files.
+ ///
+ private static string TemporaryFastDisk
+ {
+ get
+ {
+ string temporaryFastDisk = GetConfigurationOption("temporaryFastDisk", null);
+ if (temporaryFastDisk == null || temporaryFastDisk.Trim().Equals(String.Empty))
+ return null;
+ return temporaryFastDisk.Trim();
+ }
+ }
+
+ ///
+ /// Paths to fast disk for intermediate files.
+ ///
+ private static string IntermediateFastDisk
+ {
+ get
+ {
+ string intermediateFastDisk = GetConfigurationOption("intermediateFastDisk", null);
+ if (intermediateFastDisk == null || intermediateFastDisk.Trim().Equals(String.Empty))
+ return null;
+ return intermediateFastDisk.Trim();
+ }
+ }
+
+ ///
+ /// Paths to fast disk for output files.
+ ///
+ private static string OutputFastDisk
+ {
+ get
+ {
+ string outputFastDisk = GetConfigurationOption("outputFastDisk", null);
+ if (outputFastDisk == null || outputFastDisk.Trim().Equals(String.Empty))
+ return null;
+ return outputFastDisk.Trim();
+ }
+ }
+
+ ///
+ /// Return collection of environment variables.
+ ///
+ /// Collection of environment variables or null if there is none.
+ private static StringDictionary GetEnvironmentVarables()
+ {
+ StringDictionary environmentVarables = new StringDictionary();
+ if (TemporaryFastDisk != null)
+ environmentVarables.Add("ROS_TEMPORARY", TemporaryFastDisk);
+ if (IntermediateFastDisk != null)
+ environmentVarables.Add("ROS_INTERMEDIATE", IntermediateFastDisk);
+ if (OutputFastDisk != null)
+ environmentVarables.Add("ROS_OUTPUT", OutputFastDisk);
+ return environmentVarables;
+ }
+
+ ///
+ /// Run make.
+ ///
+ /// Arguments.
+ /// Receives standard output.
+ /// Receives standard error.
+ /// Make exit code.
+ private static int RunMake(string arguments,
+ out string standardOutput,
+ out string standardError)
+ {
+ string make = "mingw32-make";
+ string makeParameters = GetConfigurationOption("makeParameters", "");
+ string reactosDirectory = Path.Combine(System.Environment.CurrentDirectory,
+ "reactos");
+ return RunScript(make,
+ makeParameters + " " + arguments,
+ reactosDirectory,
+ GetEnvironmentVarables(),
+ out standardOutput,
+ out standardError);
+ }
+
+ ///
+ /// Verify a revision of ReactOS by building it all.
+ ///
+ private static int VerifyFull()
+ {
+ string standardOutput;
+ string standardError;
+ int exitCode = RunMake("bootcd",
+ out standardOutput,
+ out standardError);
+ if (exitCode != 0)
+ {
+ Fail(String.Format("make bootcd failed: (error: {0}) {1}",
+ standardError,
+ standardOutput));
+ return exitCode;
+ }
+
+ string reactosDirectory = Path.Combine(System.Environment.CurrentDirectory,
+ "reactos");
+ string isoFilename = Path.Combine(reactosDirectory,
+ "ReactOS.iso");
+ if (!File.Exists(isoFilename))
+ Fail("make bootcd produced no ReactOS.iso");
+
+ return exitCode;
+ }
+
+ ///
+ /// Verify a revision of ReactOS by building parts.
+ ///
+ /// Comma separated list of components to build.
+ private static int VerifyPartial(string components)
+ {
+ string standardOutput;
+ string standardError;
+ string componentParameters = "\"" + components.Replace(",", "\" \"") + "\"";
+ int exitCode = RunMake(componentParameters,
+ out standardOutput,
+ out standardError);
+ if (exitCode != 0)
+ Fail(String.Format("make failed for targets {0}: (error: {1}) {2}",
+ componentParameters,
+ standardError,
+ standardOutput));
+ return exitCode;
+ }
+
+ ///
+ /// Verify a revision of ReactOS.
+ ///
+ /// Arguments from command line.
+ private static int Verify(string[] args)
+ {
+ if (args.Length > 0)
+ return VerifyPartial(args[0]);
+ else
+ return VerifyFull();
+ }
+
+ ///
+ /// Program entry point.
+ ///
+ /// Arguments from command line.
+ ///
+ /// If exit code is 0, then the commit was processed successfully.
+ /// If exit code is 1, then the commit was not processed successfully.
+ ///
+ public static void Main(string[] args)
+ {
+ try
+ {
+ System.Environment.ExitCode = Verify(args);
+ }
+ catch (Exception ex)
+ {
+ string text = String.Format("Exception: {0}", ex);
+ SendErrorMail("ReactOS Verify Error", text);
+ System.Environment.ExitCode = 1;
+ }
+ }
+ }
+}
diff --git a/cis/ReactOS.Verify/RedirectableProcess.cs b/cis/ReactOS.Verify/RedirectableProcess.cs
new file mode 100644
index 00000000000..6bdfe94895c
--- /dev/null
+++ b/cis/ReactOS.Verify/RedirectableProcess.cs
@@ -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/html/frlrfsystemdiagnosticsprocessstartinfoclassredirectstandardoutputtopic.asp
+ */
+using System;
+using System.IO;
+using System.Threading;
+using System.Diagnostics;
+
+namespace ReactOS.Verify
+{
+ ///
+ /// Process that redirects standard output and standard error streams.
+ ///
+ public class RedirectableProcess
+ {
+ ///
+ /// Process.
+ ///
+ private Process process;
+
+ ///
+ /// Redirected standard error stream.
+ ///
+ private string processError;
+
+ ///
+ /// Redirected standard output stream.
+ ///
+ private string processOutput;
+
+ ///
+ /// Exit code.
+ ///
+ private int exitCode;
+
+ ///
+ /// Redirected standard error stream.
+ ///
+ public string ProcessError
+ {
+ get
+ {
+ return processError;
+ }
+ }
+
+ ///
+ /// Redirected standard output stream.
+ ///
+ public string ProcessOutput
+ {
+ get
+ {
+ return processOutput;
+ }
+ }
+
+ ///
+ /// Exit code.
+ ///
+ public int ExitCode
+ {
+ get
+ {
+ return exitCode;
+ }
+ }
+
+ ///
+ /// Run an excutable and redirect standard error and/or standard output safely.
+ ///
+ public RedirectableProcess(ProcessStartInfo processStartInfo)
+ {
+ Run(processStartInfo, null);
+ }
+
+ ///
+ /// Run an excutable and redirect standard error and/or standard output safely.
+ ///
+ 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;
+ }
+
+ ///
+ /// Read standard error thread entry-point.
+ ///
+ private void ReadStandardError()
+ {
+ if (process != null)
+ {
+ processError = process.StandardError.ReadToEnd();
+ }
+ }
+
+ ///
+ /// Read standard output thread entry-point.
+ ///
+ private void ReadStandardOutput()
+ {
+ if (process != null)
+ {
+ processOutput = process.StandardOutput.ReadToEnd();
+ }
+ }
+ }
+}