using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using HtmlAgilityPack; namespace ReleaseBot { class Program { private const string V = "1.34"; // <--- numpy.net version! private const string PythonNetVersion = "3.0.1"; private const string PythonVersion = "3.11"; // relevant only for Numpy with included binaries private const string NumpyVersion = "1.23.5"; private const string ProjectPath = "../../../Numpy"; private const string ProjectName = "Numpy.csproj"; private const string ProjectPath2 = "../../../Numpy.Bare"; private const string ProjectName2 = "Numpy.Bare.csproj"; private const string Description = "C# bindings for NumPy on {0} - a fundamental library for scientific computing, machine learning and AI. Does require Python {1} with NumPy {2} installed!"; private const string Tags = "Data science, Machine Learning, ML, AI, Scientific Computing, NumPy, Linear Algebra, FFT, SVD, BLAS, Vector, Matrix, Python"; static void Main(string[] args) { // ==> Numpy ProcessNumpy(); // ==> Numpy Bare // TODO: release numpy bare for the new Pythonnet 3.0.0 //// first delete old packages as to not upload them again //foreach (var nuget in Directory.GetFiles(Path.Combine(ProjectPath2, "bin", "Release"), "*.nupkg")) //{ // File.Delete(nuget); //} //var specs = new ReleaseSpec[] //{ // // linux // new ReleaseSpec() { CPythonVersion = "2.7", Platform="Linux", }, // new ReleaseSpec() { CPythonVersion = "3.5", Platform="Linux", }, // new ReleaseSpec() { CPythonVersion = "3.6", Platform="Linux", }, // new ReleaseSpec() { CPythonVersion = "3.8", Platform="Linux", }, // new ReleaseSpec() { CPythonVersion = "3.7", Platform="Linux", }, // // mac // new ReleaseSpec() { CPythonVersion = "2.7", Platform="OSX", }, // new ReleaseSpec() { CPythonVersion = "3.5", Platform="OSX", }, // new ReleaseSpec() { CPythonVersion = "3.6", Platform="OSX", }, // new ReleaseSpec() { CPythonVersion = "3.8", Platform="OSX", }, // new ReleaseSpec() { CPythonVersion = "3.7", Platform="OSX", }, // // win // new ReleaseSpec() { CPythonVersion = "2.7", Platform="Win64", }, // new ReleaseSpec() { CPythonVersion = "3.5", Platform="Win64", }, // new ReleaseSpec() { CPythonVersion = "3.6", Platform="Win64", }, // new ReleaseSpec() { CPythonVersion = "3.8", Platform="Win64", }, // new ReleaseSpec() { CPythonVersion = "3.7", Platform="Win64", }, //}; //foreach (var spec in specs) //{ // spec.Version = $"{spec.CPythonVersion}.{V}"; // spec.PythonNetVersion = $"{PythonNetVersion}"; // spec.NumpyVersion = NumpyVersion; // spec.Description = string.Format(Description, spec.Platform, spec.CPythonVersion, spec.NumpyVersion); // spec.PackageTags = Tags; // spec.RelativeProjectPath = ProjectPath2; // spec.ProjectName = ProjectName2; // var py = spec.CPythonVersion.Replace(".", ""); // switch (spec.Platform) // { // case "Linux": // spec.PackageId = "Numpy.Bare.Mono"; // spec.PythonNet = $"pythonnet_netstandard_py{py}_linux"; // break; // case "OSX": // spec.PackageId = "Numpy.Bare.OSX"; // spec.PythonNet = $"pythonnet_netstandard_py{py}_osx"; // break; // case "Win64": // spec.PackageId = "Numpy.Bare"; // spec.PythonNet = $"pythonnet_netstandard_py{py}_win"; // break; // } // spec.Process(); //} var key = File.ReadAllText("../../nuget.key").Trim(); foreach (var nuget in Directory.GetFiles(Path.Combine(ProjectPath2, "bin", "Release"), "*.nupkg")) { Console.WriteLine("Push " + nuget); var arg = $"push -Source https://api.nuget.org/v3/index.json -ApiKey {key} {nuget}"; var p = new Process() { StartInfo = new ProcessStartInfo("nuget.exe", arg) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false } }; p.OutputDataReceived += (x, data) => Console.WriteLine(data.Data); p.ErrorDataReceived += (x, data) => Console.WriteLine("Error: " + data.Data); p.Start(); p.WaitForExit(); Console.WriteLine("... pushed"); } Thread.Sleep(3000); } private static void ProcessNumpy() { // first delete old packages as to not upload them again foreach (var nuget in Directory.GetFiles(Path.Combine(ProjectPath, "bin", "Release"), "*.nupkg")) { File.Delete(nuget); } var spec = new ReleaseSpec() { Version = $"{PythonVersion}.{V}", ProjectName = ProjectName, RelativeProjectPath = ProjectPath, PackageId = "Numpy", Description = @"C# bindings for NumPy - a fundamental library for scientific computing, machine learning and AI. Does not require a local Python installation!", PackageTags = "Data science, Machine Learning, ML, AI, Scientific Computing, NumPy, Linear Algebra, FFT, SVD, Matrix, Python", UsePythonIncluded = true, }; spec.Process(); // nuget var key = File.ReadAllText("../../nuget.key").Trim(); foreach (var nuget in Directory.GetFiles(Path.Combine(ProjectPath, "bin", "Release"), "*.nupkg")) { Console.WriteLine("Push " + nuget); var arg = $"push -Source https://api.nuget.org/v3/index.json -ApiKey {key} {nuget}"; var p = new Process() { StartInfo = new ProcessStartInfo("nuget.exe", arg) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false } }; p.OutputDataReceived += (x, data) => Console.WriteLine(data.Data); p.ErrorDataReceived += (x, data) => Console.WriteLine("Error: " + data.Data); p.Start(); p.WaitForExit(); Console.WriteLine("... pushed"); } } } public class ReleaseSpec { /// /// The assembly / nuget package version /// public string Version; public string CPythonVersion; public string Platform; /// /// Project description /// public string Description; /// /// Project description /// public string PackageTags; /// /// Nuget package id /// public string PackageId; /// /// PythonNet package name /// public string PythonNet; /// /// PythonNet Version /// public string PythonNetVersion; /// /// Name of the csproj file /// public string ProjectName; /// /// Path to the csproj file, relative to the execution directory of ReleaseBot /// public string RelativeProjectPath; public string FullProjectPath => Path.Combine(RelativeProjectPath, ProjectName); /// /// Uses Python.Included /// public bool UsePythonIncluded { get; set; } // Numpy Version public string NumpyVersion { get; set; } public void Process() { if (!File.Exists(FullProjectPath)) throw new InvalidOperationException("Project not found at: " + FullProjectPath); // modify csproj var doc = new HtmlDocument() { OptionOutputOriginalCase = true, OptionWriteEmptyNodes = true }; doc.Load(FullProjectPath); var group0 = doc.DocumentNode.Descendants("propertygroup").FirstOrDefault(); SetInnerText(group0.Element("version"), Version); Console.WriteLine("Version: " + group0.Element("version").InnerText); SetInnerText(group0.Element("description"), Description); Console.WriteLine("Description: " + group0.Element("description").InnerText); if (!UsePythonIncluded) { SetInnerText(group0.Element("packageid"), PackageId); var group1 = doc.DocumentNode.Descendants("itemgroup").FirstOrDefault(g => g.Element("packagereference") != null); var reference = group1.Descendants("packagereference").ToArray()[1]; reference.Attributes["Include"].Value = PythonNet; reference.Attributes["Version"].Value = PythonNetVersion; } doc.Save(FullProjectPath); // now build in release mode RestoreNugetDependencies(); Build(); } private void RestoreNugetDependencies() { Console.WriteLine("Fetch Nugets " + Description); var p = new Process() { StartInfo = new ProcessStartInfo("dotnet", "restore") { WorkingDirectory = Path.GetFullPath(RelativeProjectPath) } }; p.Start(); p.WaitForExit(); } private void Build() { Console.WriteLine("Build " + Description); var p = new Process() { StartInfo = new ProcessStartInfo("dotnet", "build -c Release") { WorkingDirectory = Path.GetFullPath(RelativeProjectPath) } }; p.Start(); p.WaitForExit(); } private void SetInnerText(HtmlNode node, string text) { node.ReplaceChild(HtmlTextNode.CreateNode(text), node.FirstChild); } } }