public static void UpdateSubmodules(this IRepository git) { foreach (var submodule in git.Submodules) { var subrepoPath = Path.Combine(git.Info.WorkingDirectory, submodule.Path); if (!Repository.IsValid(subrepoPath)) { Directory.Delete(subrepoPath, true); Repository.Clone(submodule.Url, subrepoPath); } using (var subrepo = new Repository(subrepoPath)) { subrepo.UpdateRepository(submodule.HeadCommitId.Sha); } } }
private static int Main(string[] args) { var monoRun = RunWithMonoConfiguration(args); if (monoRun.Item1) { // The main stuff already ran in a subprocess return monoRun.Item2; } // Parse cmdline arguments var options = new CommandLineOptions(); //args = args.DefaultIfEmpty("--help").ToArray(); if (!Parser.Default.ParseArgumentsStrict(args, options, () => { Environment.Exit(-2); })) { return -2; } if (options.ShowVersion) { var version = Regex.Match( Assembly.GetExecutingAssembly() .GetCustomAttributes(typeof (AssemblyInformationalVersionAttribute), false) .OfType<AssemblyInformationalVersionAttribute>().First().InformationalVersion, @"^(?<major>[0-9]+)\.(?<minor>[0-9]+)\.(?<revision>[0-9]+)(\-(?<prerelease>[A-z0-9\.]+))?(\+(?<meta>.+?))?$"); var meta = new Queue<string>(version.Groups["meta"].Value.Split('.')); while (meta.Any() && meta.First() != "Branch") { meta.Dequeue(); } var metaDict = new Dictionary<string, string>(); while (meta.Any()) { var name = meta.Dequeue(); var value = meta.Dequeue(); if (meta.Any() && char.IsDigit(meta.First().First())) { value += "." + meta.Dequeue(); } metaDict.Add(name, value); } Console.WriteLine("{0}.{1}.{2}{3}{4}", version.Groups["major"].Value, version.Groups["minor"].Value, version.Groups["revision"].Value, version.Groups["prerelease"].Success ? "-" + version.Groups["prerelease"].Value : "", metaDict.Any() ? " (" + metaDict["Sha"].Substring(0, 7) + ")" : ""); return 0; } if (string.IsNullOrEmpty(options.OutputPath)) { Console.Error.WriteLine("ERROR: No output directory given."); Console.Write(options.GetUsage()); return -2; } var sourceDirectory = new DirectoryInfo(options.SourceDir); var dataSourceDirectory = sourceDirectory // Who knows if this directory will somewhen cease to exist... .CreateSubdirectory("CitizenMP.Server") .CreateSubdirectory("data"); var outputDirectory = new DirectoryInfo(options.OutputPath); var binOutputDirectory = new DirectoryInfo(Path.Combine(outputDirectory.FullName, "bin")); // Do we even have a copy or do we need to clone? if (!Repository.IsValid(sourceDirectory.FullName)) { if (sourceDirectory.Exists) { Console.WriteLine("Deleting source code folder..."); sourceDirectory.Delete(true); } Console.WriteLine("Cloning source code repository..."); Repository.Clone("http://tohjo.ez.lv/citidev/citizenmp-server.git", sourceDirectory.FullName); } else { // Update working dir Console.WriteLine("Updating source code..."); using (var git = new Repository(sourceDirectory.FullName)) { //git.Network.Pull(GitSignature, new PullOptions()); git.UpdateRepository("HEAD"); } } // Check if we need to update by parsing AssemblyConfigurationAttribute in server assembly. // Should have a space-separated segment saying "CommitHash=<commit hash here>". if (binOutputDirectory.Exists) { var serverBins = binOutputDirectory .EnumerateFiles("*Server.exe", SearchOption.TopDirectoryOnly) .ToArray(); if (serverBins.Any()) { var serverAssembly = Assembly.LoadFile(serverBins.First().FullName); var configurationAttribs = serverAssembly.GetCustomAttributes(typeof (AssemblyConfigurationAttribute), false); if (configurationAttribs.Any()) { var configurationAttrib = (AssemblyConfigurationAttribute) configurationAttribs.First(); foreach (var commitHash in configurationAttrib.Configuration.Split(' ') .Where(section => section.StartsWith("CommitHash=")) .Select(section => section.Split('=').Last())) { using (var repo = new Repository(sourceDirectory.FullName)) { if (commitHash != repo.Head.Tip.Sha) continue; // Yup, same commit. Console.WriteLine("Server is already up-to-date!"); return 0; } } } } } // Get submodules using (var git = new Repository(sourceDirectory.FullName)) { Console.WriteLine("Downloading dependencies..."); git.UpdateSubmodules(); } // Patch AssemblyInfo.cs to include commit hash in an AssemblyConfigurationAttribute Console.WriteLine("Patching assembly information..."); var assemblyGuidRegex = new Regex( @"^[\s]*\[assembly[\s]*:[\s]*Guid[\s]*\([\s]*(?<verbatimPrefix>[@]?)""(?<oldValue>.*?)""[\s]*\)[\s]*\][\s]*$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline); var assemblyConfigurationRegex = new Regex( @"^[\s]*\[assembly[\s]*:[\s]*AssemblyConfiguration[\s]*\([\s]*(?<verbatimPrefix>[@]?)""(?<oldValue>.*?)""[\s]*\)[\s]*\][\s]*$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline); foreach (var assemblyInfoFile in sourceDirectory .EnumerateFiles("AssemblyInfo.cs", SearchOption.AllDirectories)) { var sourceCode = File.ReadAllText(assemblyInfoFile.FullName); // Parse GUID var guid = assemblyGuidRegex.Match(sourceCode).Groups["oldValue"].Value; if (!guid.Equals("b14ff4c2-a2e5-416b-ae79-4580cda4d9d1", StringComparison.OrdinalIgnoreCase)) { //Console.WriteLine("\tSkipping assembly info for GUID \"{0}\" ({1}).", guid, assemblyInfoFile.Directory); continue; } //Console.WriteLine("\tPatching assembly info for GUID \"{0}\" ({1}).", guid, assemblyInfoFile.Directory); if (!assemblyConfigurationRegex.IsMatch(sourceCode)) { sourceCode += Environment.NewLine; sourceCode += @"// Inserted by CitizenMP Server Updater for version comparison"; sourceCode += @"[assembly: AssemblyConfiguration("""")]"; } using (var git = new Repository(sourceDirectory.FullName)) { sourceCode = assemblyConfigurationRegex.Replace(sourceCode, m => string.Format("[assembly: AssemblyConfiguration({0}\"{1}CommitHash={2}\")]", m.Groups["verbatimPrefix"].Value, m.Groups["oldValue"].Length > 0 ? m.Groups["oldValue"].Value + " " : "", // ReSharper disable once AccessToDisposedClosure git.Head.Tip.Sha)); } File.WriteAllText(assemblyInfoFile.FullName, sourceCode); } // Build project //Console.WriteLine("Building server binaries..."); var slnPath = sourceDirectory.EnumerateFiles("*.sln", SearchOption.TopDirectoryOnly) .First().FullName; outputDirectory.Create(); var logpath = options.WriteLogFile ? Path.Combine(outputDirectory.FullName, "build.log") : null; if (!Build(slnPath, new Dictionary<string, string> { {"Configuration", "Release"}, {"Platform", "Any CPU"}, {"DebugType", Environment.OSVersion.IsWin32() ? "None" : "pdbonly"}, {"DebugSymbols", false.ToString()}, {"OutputPath", binOutputDirectory.FullName}, {"AllowedReferenceRelatedFileExtensions", "\".mdb\"=\"\";\".pdb\"=\"\";\".xml\"=\"\""} }, options.Verbosity, logpath)) { Console.Error.WriteLine("Build failed! Please look at {0} for more information.", logpath); return 1; } // Prepare with default files PrepareDirectory(dataSourceDirectory, outputDirectory); // Write startup scripts switch (Environment.OSVersion.Platform) { case PlatformID.Unix: case PlatformID.MacOSX: { var startScriptPath = Path.Combine(outputDirectory.FullName, "start.sh"); File.WriteAllText( startScriptPath, string.Join( Environment.NewLine, @"#!/bin/bash", @"", @"# switch to the script directory", @"cd ""$( dirname ""${BASH_SOURCE[0]}"" )""", @"", @"# run with mono", @"mono ""bin/" + binOutputDirectory.EnumerateFiles("*.exe").First().Name + @""" $@", @"")); // TODO: Pretty sure there is an easier way to do a programmatical chmod +x Stat stat; FilePermissions perms; if (UnixSyscall.stat(startScriptPath, out stat) != 0) { perms = FilePermissions.S_IRUSR | FilePermissions.S_IRGRP | FilePermissions.S_IROTH | FilePermissions.S_IWUSR | FilePermissions.S_IXUSR; } else { perms = stat.st_mode; } UnixSyscall.chmod(startScriptPath, perms | FilePermissions.S_IXUSR | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH); } break; case PlatformID.Win32NT: case PlatformID.Win32Windows: { var startScriptPath = Path.Combine(outputDirectory.FullName, "start.bat"); File.WriteAllText( startScriptPath, string.Join(Environment.NewLine, "@echo off", @"", @":: switch to the script directory", @"pushd ""%~dp0""", @"", @":: run", @"""bin\" + binOutputDirectory.EnumerateFiles("*.exe").First().Name + @""" %*", @"")); } break; default: Console.Error.WriteLine("WARNING: No startup script created. Platform not supported."); break; } Console.WriteLine("Done."); return 0; }