Compare commits

...
Author SHA1 Message Date
adminandClaude Opus 4.5 b8e5346209 Fix sysroot .so plugins and registry auth
- Exclude GCC plugin .so files from sysroot (Bazel can't handle them)
- Only copy GCC headers and static libs needed for cross-compilation
- Add tarball structure verification to build script
- Fix DO registry auth by setting DOCKER_CONFIG env var for Bazel

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 08:50:44 -08:00
adminandClaude Opus 4.5 c128531662 Update sysroot sha256 for v2 with GCC directories
The v2 sysroot includes GCC installation directories that clang needs
to find libstdc++ headers for cross-compilation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 08:34:47 -08:00
ee6189a9d7 Fix AWS CLI and use correct bucket for sysroot upload (#4780)
- Skip AWS CLI install if already present
- Use eagle0-windows bucket (same as other workflows, credentials have access)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 08:30:55 -08:00
e0304125b8 Add ledFactionName field to Hero for faction renaming (#4781)
Add a new field to the Hero proto and Scala models to store the name of the
faction that a hero would lead, if they became a faction leader. This is
populated from the "faction_name" column in the heroes TSV for "great person"
heroes, and is empty (or None in Scala) for other heroes.

This will be used in the future to rename factions when a great person
becomes the leader of a different faction.

Changes:
- Add led_faction_name (string) to Hero proto
- Add ledFactionName: Option[String] to HeroT trait and HeroC case class
- Add ledFactionName to LoadedHero intermediate type
- Update HeroConverter, LoadedHeroConversion, and FixedHeroes to handle the new field
- Update FixedHeroesTest to include the new field

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 08:23:04 -08:00
11eac42e30 Fix sysroot workflow secret names (#4779)
Use existing ACCESS_KEY_ID and SECRET_KEY secrets instead of
non-existent DO_SPACES_KEY and DO_SPACES_SECRET.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 08:12:19 -08:00
13 changed files with 73 additions and 28 deletions
+12 -9
View File
@@ -30,34 +30,37 @@ jobs:
- name: Install AWS CLI
run: |
sudo apt-get update
sudo apt-get install -y awscli
if ! command -v aws &> /dev/null; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip -q awscliv2.zip
sudo ./aws/install
fi
- name: Upload to DigitalOcean Spaces
env:
AWS_ACCESS_KEY_ID: ${{ secrets.DO_SPACES_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.DO_SPACES_SECRET }}
AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_KEY }}
run: |
# Upload sysroot tarball to DO Spaces
# Upload sysroot tarball to DO Spaces (using eagle0-windows bucket, same as other workflows)
aws s3 cp tools/sysroot/output/ubuntu_noble_amd64_sysroot.tar.xz \
s3://eagle0/sysroot/${{ inputs.version }}/ubuntu_noble_amd64_sysroot.tar.xz \
s3://eagle0-windows/sysroot/${{ inputs.version }}/ubuntu_noble_amd64_sysroot.tar.xz \
--endpoint-url https://sfo3.digitaloceanspaces.com \
--acl public-read
# Upload sha256 file
aws s3 cp tools/sysroot/output/ubuntu_noble_amd64_sysroot.sha256 \
s3://eagle0/sysroot/${{ inputs.version }}/ubuntu_noble_amd64_sysroot.sha256 \
s3://eagle0-windows/sysroot/${{ inputs.version }}/ubuntu_noble_amd64_sysroot.sha256 \
--endpoint-url https://sfo3.digitaloceanspaces.com \
--acl public-read
echo ""
echo "=== Sysroot uploaded ==="
echo "URL: https://eagle0.sfo3.digitaloceanspaces.com/sysroot/${{ inputs.version }}/ubuntu_noble_amd64_sysroot.tar.xz"
echo "URL: https://eagle0-windows.sfo3.digitaloceanspaces.com/sysroot/${{ inputs.version }}/ubuntu_noble_amd64_sysroot.tar.xz"
echo "SHA256: $(cat tools/sysroot/output/ubuntu_noble_amd64_sysroot.sha256)"
echo ""
echo "Update MODULE.bazel with:"
echo "sysroot("
echo " name = \"linux_sysroot\","
echo " sha256 = \"$(cat tools/sysroot/output/ubuntu_noble_amd64_sysroot.sha256)\","
echo " urls = [\"https://eagle0.sfo3.digitaloceanspaces.com/sysroot/${{ inputs.version }}/ubuntu_noble_amd64_sysroot.tar.xz\"],"
echo " urls = [\"https://eagle0-windows.sfo3.digitaloceanspaces.com/sysroot/${{ inputs.version }}/ubuntu_noble_amd64_sysroot.tar.xz\"],"
echo ")"
+10
View File
@@ -42,9 +42,14 @@ jobs:
mkdir -p ~/.docker
AUTH=$(echo -n "${DO_TOKEN}:${DO_TOKEN}" | base64)
echo "{\"auths\":{\"registry.digitalocean.com\":{\"auth\":\"${AUTH}\"}}}" > ~/.docker/config.json
# Also set for current directory in case Bazel uses different home
mkdir -p .docker
cp ~/.docker/config.json .docker/
- name: Push Eagle image to DO registry
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_images == 'true')
env:
DOCKER_CONFIG: ${{ github.workspace }}/.docker
run: bazel run //ci:eagle_server_push
build-shardok:
@@ -66,7 +71,12 @@ jobs:
mkdir -p ~/.docker
AUTH=$(echo -n "${DO_TOKEN}:${DO_TOKEN}" | base64)
echo "{\"auths\":{\"registry.digitalocean.com\":{\"auth\":\"${AUTH}\"}}}" > ~/.docker/config.json
# Also set for current directory in case Bazel uses different home
mkdir -p .docker
cp ~/.docker/config.json .docker/
- name: Push Shardok image to DO registry
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_images == 'true')
env:
DOCKER_CONFIG: ${{ github.workspace }}/.docker
run: bazel run --platforms=//:linux_x86_64 //ci:shardok_server_push
+2 -3
View File
@@ -72,9 +72,8 @@ use_repo(llvm, "llvm_toolchain", "llvm_toolchain_linux")
sysroot = use_repo_rule("@toolchains_llvm//toolchain:sysroot.bzl", "sysroot")
sysroot(
name = "linux_sysroot",
# TODO: Update sha256 after running sysroot build workflow with version v2
sha256 = "PLACEHOLDER_RUN_SYSROOT_WORKFLOW_FIRST",
urls = ["https://eagle0.sfo3.digitaloceanspaces.com/sysroot/v2/ubuntu_noble_amd64_sysroot.tar.xz"],
sha256 = "aadb60a2e2c776ac000bb2e29f3039fd81b5b031500cf4a1651b365712819d1f",
urls = ["https://eagle0-windows.sfo3.digitaloceanspaces.com/sysroot/v2/ubuntu_noble_amd64_sysroot.tar.xz"],
)
#
@@ -58,4 +58,8 @@ message Hero {
repeated EventForHeroBackstory new_backstory_events = 29;
.net.eagle0.eagle.common.Gender pronoun_gender = 27;
// The name of the faction this hero would lead, if they led one.
// Populated for "great person" heroes from the heroes TSV; empty for others.
string led_faction_name = 30;
}
@@ -36,7 +36,8 @@ object HeroConverter {
imagePath: String,
personalityWords: Vector[String],
backstoryVersions: Vector[BackstoryVersion],
backstoryEvents: Vector[EventForHeroBackstoryT]
backstoryEvents: Vector[EventForHeroBackstoryT],
ledFactionName: Option[String]
) =>
HeroProto(
id = id,
@@ -67,7 +68,8 @@ object HeroConverter {
case BackstoryVersion(textId, date) =>
BackstoryVersionProto(textId, Some(DateConverter.toProto(date)))
},
newBackstoryEvents = backstoryEvents.map(EventForHeroBackstoryConverter.toProto)
newBackstoryEvents = backstoryEvents.map(EventForHeroBackstoryConverter.toProto),
ledFactionName = ledFactionName.getOrElse("")
)
}
@@ -99,6 +101,7 @@ object HeroConverter {
backstoryVersions,
newBackstoryEvents,
pronounGender,
ledFactionName,
_ /* unknownFields */
) =>
HeroC(
@@ -132,7 +135,8 @@ object HeroConverter {
}.toVector,
backstoryEvents = newBackstoryEvents
.map(EventForHeroBackstoryConverter.fromProto)
.toVector
.toVector,
ledFactionName = Option(ledFactionName).filter(_.nonEmpty)
)
}
}
@@ -40,4 +40,10 @@ trait HeroT {
final def backstoryTextId: ClientTextId = backstoryVersions.last.textId
def backstoryEvents: Vector[EventForHeroBackstoryT]
/**
* The name of the faction this hero would lead, if they led one. Populated for "great person" heroes from the heroes
* TSV; None for others.
*/
def ledFactionName: Option[String]
}
@@ -30,7 +30,8 @@ case class HeroC(
imagePath: String = "",
personalityWords: Vector[String] = Vector(),
backstoryVersions: Vector[BackstoryVersion] = Vector(),
backstoryEvents: Vector[EventForHeroBackstoryT] = Vector()
backstoryEvents: Vector[EventForHeroBackstoryT] = Vector(),
ledFactionName: Option[String] = None
) extends HeroT {
def withProfession(profession: Profession): HeroC =
copy(profession = profession)
@@ -59,7 +59,8 @@ object FixedHeroes {
private def personalityWords(commaDelimited: String): Vector[String] =
commaDelimited.split(", ").toVector
private def heroFromMap(map: Map[String, String]): LoadedHero =
private def heroFromMap(map: Map[String, String]): LoadedHero = {
val factionName = map.getOrElse("faction_name", "").trim
LoadedHero(
id = -1, // Placeholder ID, will be set later
backstory = map.getOrElse("backstory", ""),
@@ -90,6 +91,8 @@ object FixedHeroes {
case "other" => Gender.Other
case _ => throw new EagleInternalException("unspecified gender")
},
personalityWords = personalityWords(map.getOrElse("personality", ""))
personalityWords = personalityWords(map.getOrElse("personality", "")),
ledFactionName = Option(factionName).filter(_.nonEmpty)
)
}
}
@@ -38,7 +38,8 @@ object LoadedHeroConversion {
profession: Profession,
imagePath: String,
pronounGender: Gender,
personalityWords: Vector[String]
personalityWords: Vector[String],
ledFactionName: Option[String]
) =>
HeroC(
nameTextId = loadedHero.nameTextId,
@@ -63,7 +64,8 @@ object LoadedHeroConversion {
profession = profession,
imagePath = imagePath,
pronounGender = pronounGender,
personalityWords = personalityWords
personalityWords = personalityWords,
ledFactionName = ledFactionName
)
}
@@ -86,7 +88,8 @@ object LoadedHeroConversion {
profession: Profession,
imagePath: String,
pronounGender: Gender,
personalityWords: Vector[String]
personalityWords: Vector[String],
ledFactionName: Option[String]
) =>
Hero(
nameTextId = loadedHero.nameTextId,
@@ -111,7 +114,8 @@ object LoadedHeroConversion {
profession = ProfessionConverter.toProto(profession),
imagePath = imagePath,
pronounGender = GenderConverter.toProto(pronounGender),
personalityWords = personalityWords
personalityWords = personalityWords,
ledFactionName = ledFactionName.getOrElse("")
)
}
}
@@ -28,7 +28,8 @@ case class LoadedHero(
profession: Profession = Profession.NoProfession,
imagePath: String = "",
pronounGender: Gender = Gender.Other,
personalityWords: Vector[String] = Vector.empty
personalityWords: Vector[String] = Vector.empty,
ledFactionName: Option[String] = None
) {
def withId(newId: HeroId): LoadedHero = copy(id = newId)
def withFactionId(newFactionId: FactionId): LoadedHero =
@@ -70,7 +70,8 @@ class FixedHeroesTest extends AnyFlatSpec with Matchers {
imagePath = "fixed/eagle.png",
pronounGender = Gender.Male,
personalityWords = Vector("one", "two", "three"),
backstory = "The Eagle's backstory"
backstory = "The Eagle's backstory",
ledFactionName = Some("The Eagle's Faction")
)
)
fh.greatPeople.head.greatPerson.factionName shouldBe "The Eagle's Faction"
+6 -2
View File
@@ -36,5 +36,9 @@ RUN cp -a /usr/include /sysroot/ && \
mkdir -p /sysroot/lib && \
cp -a /lib/x86_64-linux-gnu /sysroot/lib/ && \
# Copy GCC installation directory - Clang uses this to find libstdc++ headers
mkdir -p /sysroot/usr/lib/gcc && \
cp -a /usr/lib/gcc/x86_64-linux-gnu /sysroot/usr/lib/gcc/
# Only copy headers and static libs, exclude plugins (.so files) that Bazel can't handle
mkdir -p /sysroot/usr/lib/gcc/x86_64-linux-gnu/13 && \
cp -a /usr/lib/gcc/x86_64-linux-gnu/13/include /sysroot/usr/lib/gcc/x86_64-linux-gnu/13/ && \
cp -a /usr/lib/gcc/x86_64-linux-gnu/13/include-fixed /sysroot/usr/lib/gcc/x86_64-linux-gnu/13/ 2>/dev/null || true && \
cp /usr/lib/gcc/x86_64-linux-gnu/13/*.a /sysroot/usr/lib/gcc/x86_64-linux-gnu/13/ 2>/dev/null || true && \
cp /usr/lib/gcc/x86_64-linux-gnu/13/*.o /sysroot/usr/lib/gcc/x86_64-linux-gnu/13/ 2>/dev/null || true
+7 -2
View File
@@ -30,6 +30,7 @@ echo "Extracting sysroot..."
CONTAINER_ID=$(docker create sysroot-builder)
# Create the sysroot structure expected by toolchains_llvm
# The tarball should extract to create a 'sysroot' directory at the root
TEMP_DIR=$(mktemp -d)
SYSROOT_DIR="${TEMP_DIR}/sysroot"
mkdir -p "${SYSROOT_DIR}/usr/lib" "${SYSROOT_DIR}/lib"
@@ -40,17 +41,21 @@ docker cp "${CONTAINER_ID}:/sysroot/usr_lib" "${SYSROOT_DIR}/usr/lib/x86_64-linu
docker cp "${CONTAINER_ID}:/sysroot/lib/x86_64-linux-gnu" "${SYSROOT_DIR}/lib/"
# Copy GCC installation directory - Clang uses this to find libstdc++ headers
# The path /usr/lib/gcc/x86_64-linux-gnu/13 is where clang looks for GCC
# Only copy what the Dockerfile prepared (headers and static libs, no .so plugins)
docker cp "${CONTAINER_ID}:/sysroot/usr/lib/gcc" "${SYSROOT_DIR}/usr/lib/"
# Also need lib64 symlink for some builds
ln -sf lib "${SYSROOT_DIR}/lib64"
# Create the tarball
# Create the tarball - use strip-components-friendly structure
# The tarball extracts directly, MODULE.bazel label points to //sysroot
echo "Creating tarball..."
cd "${TEMP_DIR}"
tar -cJf "${OUTPUT_DIR}/${SYSROOT_NAME}.tar.xz" sysroot
echo "Verifying tarball structure..."
tar -tf "${OUTPUT_DIR}/${SYSROOT_NAME}.tar.xz" | head -20
# Compute SHA256
echo "Computing SHA256..."
SHA256=$(shasum -a 256 "${OUTPUT_DIR}/${SYSROOT_NAME}.tar.xz" | cut -d' ' -f1)