Skip to content

Commit def04e0

Browse files
authored
Merge pull request #2 from Devolutions/fix
fix build script
2 parents 7ecfbec + 7e5f5d5 commit def04e0

3 files changed

Lines changed: 149 additions & 13 deletions

File tree

‎README.fork.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ If no version is specified, it defaults to `11.9.1`. You can also pass a build c
1616

1717
The build produces the following NuGet packages in `forked_nugets/`:
1818

19+
- `Avalonia.<version>.nupkg` (repackaged official meta-package with patched Avalonia.Base.dll)
1920
- `Avalonia.Android.<version>.nupkg`
2021
- `Avalonia.iOS.<version>.nupkg`
2122
- `Avalonia.OpenGL.<version>.nupkg`

‎build-fork-nugets.sh‎

Lines changed: 146 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,135 @@ echo "============================================"
1616
rm -rf "$OUTPUT_DIR"
1717
mkdir -p "$OUTPUT_DIR"
1818

19-
# Pack order: OpenGL/Skia first (no fork-to-fork deps), then Android/iOS
19+
# Step 1: Build Avalonia.Base first (we need the patched DLLs)
20+
echo ">> Building Avalonia.Base ..."
21+
dotnet pack "$SCRIPT_DIR/src/Avalonia.Base/Avalonia.Base.csproj" \
22+
-c "$CONFIGURATION" \
23+
-p:ForkVersion="$FORK_VERSION" \
24+
-o "$OUTPUT_DIR"
25+
echo ""
26+
27+
# Step 2: Repackage the official Avalonia meta-package with our patched Avalonia.Base.dll.
28+
#
29+
# The official Avalonia nupkg bundles Avalonia.Base.dll (via Numerge).
30+
# We replace those DLLs with our patched build and re-version the package
31+
# so consumers get the fix without conflicting copies.
32+
NUGET_CACHE="$HOME/.nuget/packages"
33+
OFFICIAL_NUPKG="$NUGET_CACHE/avalonia/$BASE_VERSION/avalonia.$BASE_VERSION.nupkg"
34+
35+
if [ ! -f "$OFFICIAL_NUPKG" ]; then
36+
echo ">> Official Avalonia $BASE_VERSION not found in NuGet cache. Downloading..."
37+
mkdir -p "$NUGET_CACHE/avalonia/$BASE_VERSION"
38+
curl -sSL -o "$OFFICIAL_NUPKG" \
39+
"https://api.nuget.org/v3-flatcontainer/avalonia/$BASE_VERSION/avalonia.$BASE_VERSION.nupkg"
40+
if [ ! -f "$OFFICIAL_NUPKG" ]; then
41+
echo " ERROR: Failed to download Avalonia $BASE_VERSION from nuget.org"
42+
exit 1
43+
fi
44+
echo " Downloaded to $OFFICIAL_NUPKG"
45+
fi
46+
47+
echo ">> Repackaging official Avalonia $BASE_VERSION with patched Avalonia.Base DLLs..."
48+
49+
# Built DLLs from step 1
50+
BASE_BIN="$SCRIPT_DIR/src/Avalonia.Base/bin/$CONFIGURATION"
51+
52+
python3 - "$OFFICIAL_NUPKG" "$BASE_BIN" "$OUTPUT_DIR" "$BASE_VERSION" "$FORK_VERSION" <<'PYEOF'
53+
import sys, os, zipfile, tempfile, shutil
54+
import xml.etree.ElementTree as ET
55+
56+
official_nupkg = sys.argv[1]
57+
base_bin = sys.argv[2]
58+
output_dir = sys.argv[3]
59+
base_version = sys.argv[4]
60+
fork_version = sys.argv[5]
61+
62+
# Map TFM folders in the nupkg to our build output directories
63+
TFM_MAP = {
64+
"net8.0": "net8.0",
65+
"net6.0": "net6.0",
66+
"netstandard2.0": "netstandard2.0",
67+
}
68+
69+
with tempfile.TemporaryDirectory() as tmpdir:
70+
# Extract official package
71+
with zipfile.ZipFile(official_nupkg, 'r') as z:
72+
z.extractall(tmpdir)
73+
74+
# Replace Avalonia.Base.dll in lib/ and ref/ for each TFM
75+
for nupkg_tfm, build_tfm in TFM_MAP.items():
76+
built_dll = os.path.join(base_bin, build_tfm, "Avalonia.Base.dll")
77+
built_xml = os.path.join(base_bin, build_tfm, "Avalonia.Base.xml")
78+
79+
if not os.path.exists(built_dll):
80+
print(f" WARNING: {built_dll} not found, skipping {nupkg_tfm}")
81+
continue
82+
83+
for prefix in ["lib", "ref"]:
84+
target_dll = os.path.join(tmpdir, prefix, nupkg_tfm, "Avalonia.Base.dll")
85+
target_xml = os.path.join(tmpdir, prefix, nupkg_tfm, "Avalonia.Base.xml")
86+
87+
if os.path.exists(target_dll):
88+
shutil.copy2(built_dll, target_dll)
89+
print(f" Replaced {prefix}/{nupkg_tfm}/Avalonia.Base.dll")
90+
91+
if os.path.exists(target_xml) and os.path.exists(built_xml):
92+
shutil.copy2(built_xml, target_xml)
93+
print(f" Replaced {prefix}/{nupkg_tfm}/Avalonia.Base.xml")
94+
95+
# Update version in nuspec
96+
nuspec_files = [f for f in os.listdir(tmpdir) if f.endswith(".nuspec")]
97+
if nuspec_files:
98+
nuspec_path = os.path.join(tmpdir, nuspec_files[0])
99+
tree = ET.parse(nuspec_path)
100+
root = tree.getroot()
101+
102+
# Find namespace
103+
ns = ""
104+
for uri in [
105+
"http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd",
106+
"http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd",
107+
"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd",
108+
]:
109+
if root.find(f"{{{uri}}}metadata") is not None:
110+
ns = uri
111+
break
112+
113+
if ns:
114+
ET.register_namespace("", ns)
115+
metadata = root.find(f"{{{ns}}}metadata")
116+
version_el = metadata.find(f"{{{ns}}}version")
117+
if version_el is not None:
118+
version_el.text = fork_version
119+
print(f" Version: {base_version} -> {fork_version}")
120+
121+
tree.write(nuspec_path, xml_declaration=True, encoding="utf-8")
122+
123+
# Remove [Content_Types].xml signature files that NuGet will regenerate
124+
for f in [".signature.p7s"]:
125+
p = os.path.join(tmpdir, "package", f)
126+
if os.path.exists(p):
127+
os.remove(p)
128+
129+
# Repackage
130+
out_nupkg = os.path.join(output_dir, f"Avalonia.{fork_version}.nupkg")
131+
with zipfile.ZipFile(out_nupkg, 'w', zipfile.ZIP_DEFLATED) as zout:
132+
for dirpath, dirnames, filenames in os.walk(tmpdir):
133+
for fn in filenames:
134+
full = os.path.join(dirpath, fn)
135+
arcname = os.path.relpath(full, tmpdir)
136+
zout.write(full, arcname)
137+
print(f" Created {os.path.basename(out_nupkg)}")
138+
PYEOF
139+
140+
echo ""
141+
142+
# Remove the standalone Avalonia.Base nupkg — it's now inside the Avalonia meta-package
143+
rm -f "$OUTPUT_DIR"/Avalonia.Base.*.nupkg
144+
echo ">> Removed standalone Avalonia.Base nupkg (now bundled in Avalonia meta-package)"
145+
echo ""
146+
147+
# Step 3: Pack the remaining forked projects
20148
PROJECTS=(
21149
"src/Avalonia.OpenGL/Avalonia.OpenGL.csproj"
22150
"src/Skia/Avalonia.Skia/Avalonia.Skia.csproj"
@@ -37,14 +165,14 @@ done
37165
#
38166
# The official Avalonia build uses Numerge to merge sub-packages into the
39167
# Avalonia meta-package. These sub-packages don't exist on nuget.org:
40-
# Avalonia.Base, Avalonia.Controls, Avalonia.DesignerSupport, Avalonia.OpenGL,
168+
# Avalonia.Controls, Avalonia.DesignerSupport, Avalonia.OpenGL,
41169
# Avalonia.Metal, Avalonia.Vulkan, Avalonia.Dialogs, Avalonia.Markup,
42170
# Avalonia.Markup.Xaml, Avalonia.MicroCom
43171
#
44172
# Our dotnet pack creates deps on these non-existent packages. We fix this by:
45-
# 1. Removing deps on merged/bundled packages
46-
# 2. Ensuring a dep on Avalonia >= base_version exists (it provides those DLLs)
47-
# 3. Pinning Avalonia dep to base_version (not fork_version)
173+
# 1. Removing deps on merged/bundled packages (they're inside the Avalonia meta-package)
174+
# 2. Rewriting Avalonia deps to point to our fork version (since we now ship a forked Avalonia nupkg)
175+
# 3. Removing deps on Avalonia.Base (now bundled in our forked Avalonia meta-package)
48176

49177
echo ">> Post-processing nupkgs..."
50178

@@ -82,6 +210,11 @@ def find_ns(root):
82210
for fname in sorted(os.listdir(output_dir)):
83211
if not fname.endswith(".nupkg"):
84212
continue
213+
# Skip the repackaged Avalonia meta-package — already handled
214+
# Its filename is "Avalonia.<fork_version>.nupkg" (no sub-name like .Android, .Skia, etc.)
215+
pkg_name = fname.rsplit("." + fork_version, 1)[0] if ("." + fork_version) in fname else fname
216+
if pkg_name == "Avalonia":
217+
continue
85218
nupkg_path = os.path.join(output_dir, fname)
86219
87220
with tempfile.TemporaryDirectory() as tmpdir:
@@ -118,11 +251,11 @@ for fname in sorted(os.listdir(output_dir)):
118251
119252
if dep_id == "Avalonia":
120253
has_avalonia_dep = True
121-
# Pin to base version (official meta-package on nuget.org)
122-
if dep_ver == fork_version:
123-
dep.set("version", base_version)
254+
# Point to our forked Avalonia meta-package
255+
if dep_ver != fork_version:
256+
dep.set("version", fork_version)
124257
modified = True
125-
print(f" {pkg_id}: Avalonia dep {fork_version} -> {base_version}")
258+
print(f" {pkg_id}: Avalonia dep {dep_ver} -> {fork_version}")
126259
127260
elif dep_id in MERGED:
128261
# Remove deps on packages bundled in the Avalonia meta-package
@@ -144,10 +277,10 @@ for fname in sorted(os.listdir(output_dir)):
144277
if needs_avalonia_dep and not has_avalonia_dep:
145278
new_dep = ET.SubElement(group, f"{{{ns}}}dependency")
146279
new_dep.set("id", "Avalonia")
147-
new_dep.set("version", base_version)
280+
new_dep.set("version", fork_version)
148281
new_dep.set("exclude", "Build,Analyzers")
149282
modified = True
150-
print(f" {pkg_id}: added dep on Avalonia {base_version}")
283+
print(f" {pkg_id}: added dep on Avalonia {fork_version}")
151284
152285
if modified:
153286
tree.write(nuspec_path, xml_declaration=True, encoding="utf-8")
@@ -169,4 +302,5 @@ ls -1 "$OUTPUT_DIR"/*.nupkg 2>/dev/null
169302
echo ""
170303
echo "Copy to your local feed and clean stale cache:"
171304
echo " cp $OUTPUT_DIR/*.nupkg /opt/dev/local_nugets/"
172-
echo " rm -rf ~/.nuget/packages/avalonia*/11.9.1"
305+
echo " rm -rf ~/.nuget/packages/avalonia/$FORK_VERSION"
306+
echo " rm -rf ~/.nuget/packages/avalonia.*/$FORK_VERSION"

‎build/ForkOverride.targets‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<Project>
22
<!--
33
When ForkVersion is passed (e.g. dotnet pack -p:ForkVersion=11.9.1),
4-
only the 4 forked projects get the custom version.
4+
only the forked projects get the custom version.
55
All other projects keep their original version from SharedVersion.props,
66
so ProjectReference-based dependency entries point to the base version.
77
A post-processing step then fixes deps on packages that don't exist on
88
nuget.org (they're bundled in the Avalonia meta-package by Numerge).
99
-->
1010
<PropertyGroup Condition="'$(ForkVersion)' != ''">
11+
<_IsForkProject Condition="'$(MSBuildProjectName)' == 'Avalonia.Base'">true</_IsForkProject>
1112
<_IsForkProject Condition="'$(MSBuildProjectName)' == 'Avalonia.Skia'">true</_IsForkProject>
1213
<_IsForkProject Condition="'$(MSBuildProjectName)' == 'Avalonia.OpenGL'">true</_IsForkProject>
1314
<_IsForkProject Condition="'$(MSBuildProjectName)' == 'Avalonia.Android'">true</_IsForkProject>

0 commit comments

Comments
 (0)