Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions Metadata/metadata.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Metadata>
<Tags>
<!-- 预留标记 -->
<Commit>${ENV:CF_PAGES_COMMIT_SHA}</Commit>
</Tags>
<Includes>
<!-- 子模块 -->
<Include Source="mods/mods.xml" Type="public" />
<Include Source="apps/apps.xml" Type="public" />
</Includes>
<Tags>
<!-- 预留标记 -->
<Commit>${ENV:CF_PAGES_COMMIT_SHA}</Commit>
</Tags>
<Includes>
<!-- 子模块 -->
<Include Source="mods/mods.xml" Type="public" />
<Include Source="apps/apps.xml" Type="public" />
</Includes>
</Metadata>
46 changes: 34 additions & 12 deletions Ra3.BattleNet.Metadata/Metadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ public Metadata()
{
foreach (System.Collections.DictionaryEntry env in Environment.GetEnvironmentVariables())
{
_envVars[env.Key.ToString()] = env.Value.ToString();
var key = env.Key?.ToString();
var value = env.Value?.ToString();
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
{
_envVars[key] = value;
}
}
}

Expand Down Expand Up @@ -141,7 +146,7 @@ public void ReplaceVariablesInFile(string filePath)
var root = doc.Root ?? throw new InvalidOperationException("无效的XML结构: 缺少根节点");

// 验证所有Include/Module资源
ValidateResources(root, Path.GetDirectoryName(filePath));
ValidateResources(root, Path.GetDirectoryName(filePath) ?? string.Empty);

// 替换变量
ReplaceVariables(root);
Expand All @@ -155,14 +160,16 @@ public void ReplaceVariablesInFile(string filePath)
}
}

private void ValidateResources(XElement element, string basePath)
private void ValidateResources(XElement element, string? basePath)
{
if (string.IsNullOrEmpty(basePath)) return;

foreach (var include in element.Elements("Include").Concat(element.Elements("Module")))
{
var path = include.Attribute("Path")?.Value ?? include.Attribute("Source")?.Value;
if (string.IsNullOrEmpty(path)) continue;

var fullPath = Path.Combine(basePath, path.Replace('/', '\\'));
var fullPath = Path.Combine(basePath, path.Replace('/', Path.DirectorySeparatorChar));
if (!File.Exists(fullPath))
{
throw new FileNotFoundException($"引用的资源文件不存在: {fullPath} (来自元素: {include.Name.LocalName})");
Expand Down Expand Up @@ -207,7 +214,7 @@ private void ParseElement(XElement? element, string currentFilePath)
var includePath = child.Attribute("Path")?.Value ?? child.Attribute("Source")?.Value;
if (!string.IsNullOrEmpty(includePath))
{
string normalizedPath = includePath.Replace('/', '\\');
string normalizedPath = includePath.Replace('/', Path.DirectorySeparatorChar);
var dir = Path.GetDirectoryName(currentFilePath);
if (string.IsNullOrEmpty(dir))
{
Expand Down Expand Up @@ -255,7 +262,7 @@ private void ProcessIncludes(XElement element)
{
throw new InvalidOperationException($"无法确定文件目录: {_currentFilePath}");
}
var fullPath = Path.Combine(dir, source.Replace('/', '\\'));
var fullPath = Path.Combine(dir, source.Replace('/', Path.DirectorySeparatorChar));
if (!File.Exists(fullPath)) continue;

var includedDoc = XDocument.Load(fullPath);
Expand All @@ -279,7 +286,7 @@ private void ReplaceVariables(XElement element)
{
try
{
attr.Value = ResolveVariables(attr.Value, element);
attr.Value = ResolveVariables(attr.Value, element, attr);
}
catch (Exception ex)
{
Expand All @@ -291,7 +298,7 @@ private void ReplaceVariables(XElement element)
{
try
{
element.Value = ResolveVariables(element.Value, element);
element.Value = ResolveVariables(element.Value, element, null);
}
catch (Exception ex)
{
Expand All @@ -310,7 +317,7 @@ private void ReplaceVariables(XElement element)
}
}

private string ResolveVariables(string input, XElement context)
private string ResolveVariables(string input, XElement context, XAttribute? currentAttr)
{
return System.Text.RegularExpressions.Regex.Replace(input, @"\$\{(.*?)\}", match =>
{
Expand All @@ -328,7 +335,22 @@ private string ResolveVariables(string input, XElement context)
var fileToHash = parts.Length > 1 ? parts[1] : "";
if (string.IsNullOrEmpty(fileToHash))
{
return ComputeFileHash(_currentFilePath);
// ${MD5::} - When used in a Hash attribute, compute hash of file in Source attribute
// Example: <Markdown Source="file.md" Hash="${MD5::}"/>
// This will compute the MD5 hash of "file.md"
if (currentAttr != null && currentAttr.Name.LocalName == "Hash")
{
var sourceAttr = context.Attribute("Source");
if (sourceAttr != null && !string.IsNullOrEmpty(sourceAttr.Value))
{
fileToHash = sourceAttr.Value;
}
}

if (string.IsNullOrEmpty(fileToHash))
{
return ComputeFileHash(_currentFilePath);
}
}
var dir = Path.GetDirectoryName(_currentFilePath);
if (string.IsNullOrEmpty(dir))
Expand Down Expand Up @@ -443,10 +465,10 @@ private string ComputeFileHash(string filePath)
if (parts.Length == 0)
return null;

Metadata current = this;
Metadata? current = this;
foreach (var part in parts)
{
current = current._children.FirstOrDefault(c => c.Name == part);
current = current?._children.FirstOrDefault(c => c.Name == part);
if (current == null)
return null;
}
Expand Down