Codebasis als Dateien ins Arbeitsrepo statt als Gitlink

QuellCode/CentronERP war nur als Gitlink (Submodul-Referenz auf 79c1142)
getrackt, ohne .gitmodules und ohne erreichbares Remote. Der
Untersuchungsgegenstand der Versuchsreihe war damit nicht reproduzierbar
gesichert: Ein Klon haette ein leeres Verzeichnis erhalten, und die Belege
der 3.287 Anforderungen waeren nicht ueberpruefbar gewesen.

Umstellung:
- Historie nach c:\DEV\CentronERP_git_snapshot_79c1142 ausgelagert
  (vollstaendig lesbar, enthaelt 79c1142 und Vorgaenger 89ccfd6)
- Gitlink aus dem Index entfernt
- Dateiinhalt aufgenommen: 24.557 Dateien, rund 333 MB

Die verschachtelte .gitignore der Codebasis gilt weiter, Build-Artefakte
bleiben ausgeschlossen. Details in Versuche/Versuch_01/_Codebasis-Nachweis.md
This commit is contained in:
Christoph Schwörer
2026-08-26 07:43:51 +02:00
parent 18edae75b6
commit f045b99a25
24664 changed files with 5846716 additions and 1 deletions
@@ -0,0 +1,191 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Xml.Linq;
using static Centron.Scripts.RunHelper;
using static Centron.Scripts.CentronPaths;
namespace Centron.Scripts;
public static class DependencyGraph
{
public record Dependency(string Name, string Version, string ProjectUrl, string License);
public static List<Dependency> ReadDependencyGraphs(params string[] projectFilePaths)
{
return projectFilePaths.SelectMany(ReadDependencyGraph).Distinct().ToList();
}
public static List<Dependency> ReadDependencyGraph(string projectFilePath)
{
var projectAssetsJsonFilePath = Path.Combine(Path.GetDirectoryName(projectFilePath), "obj", "project.assets.json");
var projectAssetsJsonContent = File.ReadAllText(projectAssetsJsonFilePath);
var filter = new Func<Dependency, bool>[]
{
IsMicrosoftPackage,
IsCentronPackage,
IsRiverbirdPackage,
IsRuntimePackage,
IsLanguagePackage,
IsNetStandardLibraryPackage,
};
var dependencies = JsonDocument.Parse(projectAssetsJsonContent)
.RootElement.GetProperty("targets")
.EnumerateObject()
.SelectMany(f => f.Value.EnumerateObject()
.Select(f => f.Name.Split('/'))
.Select(f => new Dependency(f[0], f[1], null, null)))
.Where(f => filter.All(d => d(f) is false))
.Select(f => LoadAdditionalInfo(f))
.Distinct() // We might have duplicates if multiple targets are found in the project.assets.json file, so remove them
.ToList();
return dependencies;
}
private static readonly HttpClient _httpClient = new();
private static Dependency LoadAdditionalInfo(Dependency dependency)
{
if (dependency.Name.StartsWith("DevExpress"))
return dependency with { ProjectUrl = "https://www.devexpress.com/", License = "DevExpress" };
if (dependency.Name.StartsWith("FastReport"))
return dependency with { ProjectUrl = "https://www.fast-report.com/", License = "FastReport" };
try
{
// See: https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-manifest-nuspec
using var request = new HttpRequestMessage(HttpMethod.Get, $"https://api.nuget.org/v3-flatcontainer/{dependency.Name.ToLower()}/{dependency.Version}/{dependency.Name.ToLower()}.nuspec");
using var response = _httpClient.Send(request);
using var responseStream = response.Content.ReadAsStream();
using var reader = new StreamReader(responseStream);
var nuspecXml = reader.ReadToEnd();
var xmlDocument = XDocument.Parse(nuspecXml);
var xmlNamespace = "{" + xmlDocument.Root.GetDefaultNamespace() + "}";
var metadataElement = xmlDocument.Root.Element($"{xmlNamespace}metadata");
var license = metadataElement.Element($"{xmlNamespace}license")?.Value;
var licenseUrl = metadataElement.Element($"{xmlNamespace}licenseUrl")?.Value;
license = TryGuessLicense(dependency, license, licenseUrl) ?? license;
var projectUrl = metadataElement.Element($"{xmlNamespace}projectUrl")?.Value;
var sourceCodeUrl = metadataElement.Element($"{xmlNamespace}repository")?.Attribute("url")?.Value;
var url = string.IsNullOrWhiteSpace(projectUrl) is false ? projectUrl : sourceCodeUrl;
return dependency with { ProjectUrl = url, License = license };
}
catch
{
// Something went wrong, but we don't want the build to fail because of that
return dependency;
}
}
private static string TryGuessLicense(Dependency dependency, string license, string licenseUrl)
{
if (dependency is { Name: "Antlr3.Runtime", Version: "3.5.1" } &&
licenseUrl is "https://raw.githubusercontent.com/antlr/antlrcs/master/LICENSE.txt")
return "BSD-3-Clause";
if (dependency is { Name: "AutoMapper", Version: "8.1.1" } &&
licenseUrl is "https://github.com/AutoMapper/AutoMapper/blob/master/LICENSE.txt")
return "MIT";
if (dependency is { Name: "Castle.Core", Version: "4.4.1" } &&
licenseUrl is "http://www.apache.org/licenses/LICENSE-2.0.html")
return "Apache-2.0";
if (dependency is { Name: "FluentNHibernate", Version: "3.2.1" } &&
licenseUrl is "https://aka.ms/deprecateLicenseUrl")
return "BSD-3-Clause";
if (dependency is { Name: "Iesi.Collections", Version: "4.0.4" } &&
licenseUrl is null)
return "Public Domain";
if (dependency is { Name: "libfintx", Version: "1.1.0" } &&
licenseUrl is "https://opensource.org/license/LGPL-3.0")
return "LGPL-3.0";
if (dependency is { Name: "Remotion.Linq", Version: "2.2.0" } &&
licenseUrl is "http://opensource.org/licenses/Apache-2.0")
return "Apache-2.0";
if (dependency is { Name: "Remotion.Linq.EagerFetching", Version: "2.2.0" } &&
licenseUrl is "http://opensource.org/licenses/LGPL-2.1")
return "LGPL-2.1";
if (dependency is { Name: "SSH.NET", Version: "2020.0.2" } &&
licenseUrl is "https://github.com/sshnet/SSH.NET/blob/master/LICENSE")
return "MIT";
if (dependency is { Name: "SshNet.Security.Cryptography", Version: "1.3.0" } &&
licenseUrl is "https://github.com/sshnet/Cryptography/blob/master/LICENSE")
return "MIT";
if (dependency is { Name: "Castle.Windsor", Version: "5.0.1" } &&
licenseUrl is "http://www.apache.org/licenses/LICENSE-2.0.html")
return "Apache-2.0";
if (dependency is { Name: "OpenMcdf", Version: "2.3.0" } &&
licenseUrl is "https://opensource.org/licenses/MPL-2.0")
return "MPL-2.0";
if (dependency is { Name: "RtfPipe", Version: "2.0.7677.4303" } &&
licenseUrl is null)
return "MIT";
if (dependency is { Name: "Simple-MAPI.NET", Version: "1.2.1" } &&
licenseUrl is "https://aka.ms/deprecateLicenseUrl")
return "MIT";
return null;
}
private static bool IsMicrosoftPackage(Dependency package)
{
return package.Name.StartsWith("Microsoft") ||
package.Name.StartsWith("System");
}
private static bool IsCentronPackage(Dependency package)
{
return package.Name.StartsWith("Centron");
}
private static bool IsRiverbirdPackage(Dependency package)
{
return package.Name.StartsWith("Riverbird");
}
private static bool IsRuntimePackage(Dependency package)
{
return package.Name.StartsWith("runtime");
}
private static bool IsLanguagePackage(Dependency package)
{
return package.Name.EndsWith(".de");
}
private static bool IsNetStandardLibraryPackage(Dependency package)
{
return package.Name == "NETStandard.Library";
}
public static void Write(List<Dependency> dependencies, string filePath)
{
var content = new StringBuilder();
content.AppendLine($"{"Dependency",-50}{"Versionsnummer",-15}{"Lizenz",-15}{"URL",-100}");
foreach (var dependency in dependencies.OrderBy(f => f.Name).ThenBy(f => f.License))
{
content.AppendLine($"{dependency.Name,-50}{dependency.Version,-15}{dependency.License,-15}{dependency.ProjectUrl,-100}");
}
if (!Directory.Exists(Path.GetDirectoryName(filePath)))
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
File.WriteAllText(filePath, content.ToString());
}
}