Skip to content
Merged
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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ env:
RUST_BACKTRACE: 1
EMULEBB_BUILD_REF: 995d13f350c8342437fdb3122d2a271696ac6e29
EMULEBB_ANDROID_BUILD_REF: 995d13f350c8342437fdb3122d2a271696ac6e29
EMULEBB_BUILD_TESTS_REF: 20a007f34d88b99c40d456cfe1dce3d0537ba00d
EMULEBB_TOOLING_REF: 856e0499d12e281697618cc81a0b09805e96f59e
EMULEBB_BUILD_TESTS_REF: d2a48d8920ef4225e86fbe918045240ab2452e67
EMULEBB_TOOLING_REF: 3b045ab4dea7554dceb13d3022a21727046d06e5
# Pin the native NAT sources linked by the sys crates.
MINIUPNP_REF: 4e7a10948004ca2085ac8103e14fc77edb898b4c
PCPNATPMP_REF: a6e787f837e507336a8774522c33b54264ef4a4b
Expand Down Expand Up @@ -440,15 +440,15 @@ jobs:
with:
persist-credentials: false
repository: emulebb/emulebb-build-tests
ref: fd4c6d21e079fab2b84704294c7c7000b893a81e
ref: d2a48d8920ef4225e86fbe918045240ab2452e67
path: repos/emulebb-build-tests

- name: Checkout pinned Rust OpenAPI contract
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
repository: emulebb/emulebb-tooling
ref: 630d1a3492ae65acad0a8dfd1575d671ff7b492c
ref: 3b045ab4dea7554dceb13d3022a21727046d06e5
path: repos/emulebb-tooling

- name: Download tested Linux daemon
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/optional-platforms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ env:
RUST_BACKTRACE: 1
EMULEBB_BUILD_REF: 995d13f350c8342437fdb3122d2a271696ac6e29
EMULEBB_ANDROID_BUILD_REF: 995d13f350c8342437fdb3122d2a271696ac6e29
EMULEBB_BUILD_TESTS_REF: 20a007f34d88b99c40d456cfe1dce3d0537ba00d
EMULEBB_TOOLING_REF: 856e0499d12e281697618cc81a0b09805e96f59e
EMULEBB_BUILD_TESTS_REF: d2a48d8920ef4225e86fbe918045240ab2452e67
EMULEBB_TOOLING_REF: 3b045ab4dea7554dceb13d3022a21727046d06e5
# Pin the native NAT sources linked by the sys crates.
MINIUPNP_REF: 4e7a10948004ca2085ac8103e14fc77edb898b4c
PCPNATPMP_REF: a6e787f837e507336a8774522c33b54264ef4a4b
Expand Down
28 changes: 22 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ permissions:
env:
RELEASE_PLATFORM_PROFILE: ${{ inputs.platform_profile || 'full' }}
RELEASE_CHANNEL: ${{ inputs.channel || (startsWith(github.ref, 'refs/tags/rust-v') && 'beta') || 'candidate' }}
EMULEBB_BUILD_REF: 995d13f350c8342437fdb3122d2a271696ac6e29
EMULEBB_BUILD_TESTS_REF: 20a007f34d88b99c40d456cfe1dce3d0537ba00d
EMULEBB_TOOLING_REF: c9aa7c7b5c0a298a6ba3b0485f29d9f4c86b5d05
EMULEBB_BUILD_REF: a508474e81f641e2a1ba1a6f7c8535e8ab358ddf
EMULEBB_BUILD_TESTS_REF: 86e32b1d547ca68c294350ad45d70d79b987d2bb
EMULEBB_TOOLING_REF: d406cfd8e6f3e3b6f04e377ac469c413293f81d9
MINIUPNP_REF: 4e7a10948004ca2085ac8103e14fc77edb898b4c
PCPNATPMP_REF: a6e787f837e507336a8774522c33b54264ef4a4b

Expand Down Expand Up @@ -219,7 +219,13 @@ jobs:

- name: Install Linux build dependencies
if: matrix.os == 'linux'
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y dpkg-dev libfontconfig1-dev
timeout-minutes: 6
working-directory: .ci/emulebb-build
run: >-
python -B -m emule_workspace provision-ubuntu-dependencies-ci
--profile rust-native-release --deadline-seconds 300
--network-timeout-seconds 20 --attempts 3
--report "$RUNNER_TEMP/emulebb-rust-out/reports/native-linux-provisioning.json"
- name: Install verified AppImage builder
if: matrix.os == 'linux'
shell: bash
Expand Down Expand Up @@ -263,7 +269,9 @@ jobs:
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: emulebb-rust-build-logs-${{ matrix.os }}-${{ matrix.arch }}
path: ${{ runner.temp }}/emulebb-rust-out/logs/builds/**/*.log
path: |
${{ runner.temp }}/emulebb-rust-out/logs/builds/**/*.log
${{ runner.temp }}/emulebb-rust-out/reports/native-linux-provisioning.json
if-no-files-found: warn
retention-days: 30
- name: Retain package and provenance
Expand Down Expand Up @@ -324,7 +332,10 @@ jobs:
name: ${{ env.NATIVE_PAYLOAD_PREFIX }}-${{ matrix.slug }}
path: ${{ runner.temp }}/emulebb-rust-out/release/rust-v${{ env.RELEASE_VERSION }}
- name: Prove packaged lifecycle, local transfer, and embedded WebUI
run: python .ci/emulebb-build-tests/scripts/smoke-rust-release-package.py --release-dir "${{ runner.temp }}/emulebb-rust-out/release/rust-v${{ env.RELEASE_VERSION }}" --release-version ${{ env.RELEASE_VERSION }} --rust-repo .ci/candidate --expected-source-sha "${{ needs.prepare.outputs.source_sha }}" --report-path "${{ runner.temp }}/emulebb-rust-out/evidence/emulebb-rust-v${{ env.RELEASE_VERSION }}-package-smoke-${{ matrix.slug }}.json" --target-os ${{ matrix.os }} --platform ${{ matrix.arch }} ${{ matrix.os == 'windows' && matrix.arch == 'x64' && '--render-webui' || '' }}
env:
EMULEBB_WORKSPACE_ROOT: ${{ github.workspace }}
EMULEBB_WORKSPACE_OUTPUT_ROOT: ${{ runner.temp }}/emulebb-rust-out
run: python .ci/emulebb-build-tests/scripts/smoke-rust-release-package.py --release-dir "${{ runner.temp }}/emulebb-rust-out/release/rust-v${{ env.RELEASE_VERSION }}" --release-version ${{ env.RELEASE_VERSION }} --rust-repo .ci/candidate --expected-source-sha "${{ needs.prepare.outputs.source_sha }}" --expected-channel "${{ env.RELEASE_CHANNEL }}" --report-path "${{ runner.temp }}/emulebb-rust-out/evidence/emulebb-rust-v${{ env.RELEASE_VERSION }}-package-smoke-${{ matrix.slug }}.json" --target-os ${{ matrix.os }} --platform ${{ matrix.arch }} ${{ matrix.os != 'macos' && '--verify-profile-ownership' || '' }} ${{ matrix.os == 'windows' && matrix.arch == 'x64' && '--render-webui' || '' }}
- name: Retain package lifecycle evidence
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
Expand Down Expand Up @@ -468,10 +479,15 @@ jobs:
uses: docker/setup-docker-action@7ec28a010822b4626af4874f9448a4b05ac6f3e5 # v5.6.0
with:
version: v29.6.1
- name: Prepare inherited host Cargo target for the source-cache fence
env:
CARGO_TARGET_DIR: ${{ runner.temp }}/emulebb-rust-out/builds/rust/target
run: python -c "from pathlib import Path; import os; Path(os.environ['CARGO_TARGET_DIR']).mkdir(parents=True, exist_ok=True)"
- name: Build, test and smoke static musl with the local recipe
working-directory: .ci/emulebb-build
env:
EMULEBB_WORKSPACE_OUTPUT_ROOT: ${{ runner.temp }}/emulebb-rust-out
CARGO_TARGET_DIR: ${{ runner.temp }}/emulebb-rust-out/builds/rust/target
run: >-
python -B -m emule_workspace package-emulebb-rust-linux-ci
--libc musl --architecture ${{ matrix.architecture }} --release-version "$RELEASE_VERSION"
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ data-encoding = "2"
embed-manifest = "1.5"
encoding_rs = "0.8"
file-id = "0.2"
find-msvc-tools = "0.1.15"
flate2 = "1"
fs4 = "1.1"
futures-util = "0.3"
Expand Down
51 changes: 51 additions & 0 deletions crates/emulebb-core/src/build_identity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//! Compile-time distribution identity shared by the daemon and REST views.

use std::sync::LazyLock;

pub const BUILD_VERSION: &str = match option_env!("EMULEBB_RELEASE_VERSION") {
Some(version) => version,
None => env!("CARGO_PKG_VERSION"),
};
pub const BUILD_CHANNEL: &str = match option_env!("EMULEBB_RELEASE_CHANNEL") {
Some(channel) => channel,
None => "development",
};
pub const BUILD_SOURCE_REVISION: &str = match option_env!("EMULEBB_SOURCE_REVISION") {
Some(revision) => revision,
None => "unknown",
};
pub const BUILD_ARCHITECTURE: &str = if cfg!(target_arch = "aarch64") {
"arm64"
} else if cfg!(target_arch = "x86_64") {
"x64"
} else {
std::env::consts::ARCH
};
pub const BUILD_FLAVOR: &str = if cfg!(debug_assertions) {
"debug"
} else {
"release"
};

/// Describe the same immutable identity in both daemon CLI flavors.
pub fn build_version_description() -> &'static str {
static DESCRIPTION: LazyLock<String> = LazyLock::new(|| {
format!("{BUILD_VERSION} ({BUILD_CHANNEL}; {BUILD_ARCHITECTURE}; {BUILD_SOURCE_REVISION})")
});
DESCRIPTION.as_str()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn cli_description_identifies_the_distribution_without_a_clock() {
let description = build_version_description();
assert!(description.starts_with(BUILD_VERSION));
for identity in [BUILD_CHANNEL, BUILD_ARCHITECTURE, BUILD_SOURCE_REVISION] {
assert!(description.contains(identity));
}
assert_eq!(description, build_version_description());
}
}
5 changes: 5 additions & 0 deletions crates/emulebb-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ use tokio_util::sync::CancellationToken;
use uuid::Uuid;

mod app_api;
mod build_identity;
mod callback_tracker;
mod categories;
mod category_api;
Expand Down Expand Up @@ -285,6 +286,10 @@ use shared_directories::{
mod network_status_defaults;
mod rest_model;
mod rest_model_serde;
pub use build_identity::{
BUILD_ARCHITECTURE, BUILD_CHANNEL, BUILD_FLAVOR, BUILD_SOURCE_REVISION, BUILD_VERSION,
build_version_description,
};
use download_task_supervisor::DownloadTaskSupervisor;
pub use emulebb_ed2k::NatStatusSnapshot;
pub use emulebb_ed2k::normalize_ed2k_file_name;
Expand Down
3 changes: 3 additions & 0 deletions crates/emulebb-daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,8 @@ uuid.workspace = true
[build-dependencies]
embed-manifest.workspace = true

[target.'cfg(windows)'.build-dependencies]
find-msvc-tools.workspace = true

[dev-dependencies]
tempfile.workspace = true
130 changes: 122 additions & 8 deletions crates/emulebb-daemon/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Build script for the `emulebb-rust` daemon binary.
//! Windows manifest and executable resources for the daemon targets.
//!
//! On Windows it embeds an application manifest that declares
//! `<ws2:longPathAware>true</ws2:longPathAware>`. Together with the OS-level
Expand All @@ -13,17 +13,13 @@
//! (shared-directory trees, incoming downloads, category paths) get long-path
//! handling; config/logs/the SQLite DB/internal piece-store dirs stay short.
//!
//! On every non-Windows target this build script is a no-op (the manifest is a
//! Windows-only concept), so it never affects Linux/macOS builds.
//! Non-Windows targets do not embed Windows resources.

fn main() {
// Re-run only when this script itself changes; the embedded manifest has no
// external inputs.
println!("cargo:rerun-if-changed=build.rs");

// `CARGO_CFG_WINDOWS` is set by cargo when the *target* is Windows, which is
// the correct gate for a Windows-only manifest (host-independent, so a cross
// build still embeds it for a Windows target and skips it otherwise).
// The existing manifest integration runs on Windows hosts. Version and
// icon resources use the Windows SDK for the supported MSVC targets.
#[cfg(windows)]
{
use embed_manifest::manifest::Setting;
Expand All @@ -32,6 +28,124 @@ fn main() {
if std::env::var_os("CARGO_CFG_WINDOWS").is_some() {
embed_manifest(new_manifest("EmulebbRust").long_path_aware(Setting::Enabled))
.expect("failed to embed longPathAware Windows manifest");
if std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc") {
embed_windows_resources();
}
}
}
}

#[cfg(windows)]
fn embed_windows_resources() {
use std::{env, fs, path::PathBuf, process::Command};

const ICON: &str = "resources/windows/application.ico";
println!("cargo:rerun-if-changed={ICON}");
println!("cargo:rerun-if-changed=resources/windows/version.rc.in");
println!("cargo:rerun-if-env-changed=EMULEBB_RELEASE_VERSION");
println!("cargo:rerun-if-env-changed=EMULEBB_RELEASE_CHANNEL");
println!("cargo:rerun-if-env-changed=EMULEBB_SOURCE_REVISION");
println!("cargo:rerun-if-env-changed=WindowsSdkDir");
println!("cargo:rerun-if-env-changed=WindowsSDKVersion");

let architecture = env::var("CARGO_CFG_TARGET_ARCH").expect("Cargo target architecture");
let sdk = find_msvc_tools::find_windows_sdk(&architecture)
.expect("install the Windows SDK to compile daemon executable resources");
let compiler = sdk
.path()
.map(|directory| directory.join("rc.exe"))
.find(|path| path.is_absolute() && path.is_file())
.expect("install the Windows SDK resource compiler (rc.exe) for the build host");

// Match BUILD_VERSION and keep the SemVer string safe in the RC literal.
let version = match env::var("EMULEBB_RELEASE_VERSION") {
Ok(version) => version,
Err(env::VarError::NotPresent) => env!("CARGO_PKG_VERSION").to_owned(),
Err(error) => panic!("invalid EMULEBB_RELEASE_VERSION: {error}"),
};
assert!(
!version.is_empty()
&& version
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'-' | b'+')),
"the executable resource version must use ASCII SemVer characters"
);
let [major, minor, patch] = [
env!("CARGO_PKG_VERSION_MAJOR"),
env!("CARGO_PKG_VERSION_MINOR"),
env!("CARGO_PKG_VERSION_PATCH"),
]
.map(|component| {
component
.parse::<u16>()
.expect("Cargo version component exceeds the Windows version-resource range")
});
let fixed_version = format!("{major},{minor},{patch},0");
let channel = env::var("EMULEBB_RELEASE_CHANNEL").unwrap_or_else(|_| "development".to_owned());
assert!(
matches!(
channel.as_str(),
"development" | "candidate" | "beta" | "nightly"
),
"the executable resource channel must use a supported build channel"
);
let source_revision =
env::var("EMULEBB_SOURCE_REVISION").unwrap_or_else(|_| "unknown".to_owned());
assert!(
source_revision == "unknown"
|| (source_revision.len() == 40
&& source_revision
.bytes()
.all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase())),
"the executable resource source must be unknown or a full lowercase commit"
);
let architecture_label = match architecture.as_str() {
"x86_64" => "x64",
"aarch64" => "arm64",
other => other,
};
let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("Cargo build output directory"));
// Give RC a relative ASCII icon name regardless of the checkout path.
fs::copy(ICON, out_dir.join("application.ico")).expect("copy approved application icon");

let mut binaries = vec![("emulebb-rust", "eMuleBB", "eMuleBB Rust daemon")];
if env::var_os("CARGO_FEATURE_PACKET_DIAGNOSTICS").is_some() {
binaries.push((
"emulebb-rust-diagnostics",
"eMuleBB Diagnostics",
"eMuleBB Rust diagnostics daemon",
));
}
for (binary, product, description) in binaries {
let script = format!("{binary}.rc");
let resource = format!("{binary}.res");
let contents = format!(
include_str!("resources/windows/version.rc.in"),
fixed_version = fixed_version,
version = version,
binary = binary,
product = product,
description = description,
channel = channel,
architecture = architecture_label,
source_revision = source_revision,
);
fs::write(out_dir.join(&script), contents).expect("write Windows resource script");
let output = Command::new(&compiler)
.current_dir(&out_dir)
.args(["/nologo", "/fo", &resource, &script])
.output()
.expect("run Windows SDK resource compiler");
assert!(
output.status.success(),
"Windows resource compilation failed for {binary} ({}):\n{}{}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
println!(
"cargo:rustc-link-arg-bin={binary}={}",
out_dir.join(resource).display()
);
}
}
Binary file not shown.
32 changes: 32 additions & 0 deletions crates/emulebb-daemon/resources/windows/version.rc.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
LANGUAGE 0x09, 0x01

1 ICON "application.ico"

1 VERSIONINFO
FILEVERSION {fixed_version}
PRODUCTVERSION {fixed_version}
FILEFLAGSMASK 0x3fL
FILEFLAGS 0
FILEOS 0x00040004L
FILETYPE 0x00000001L
FILESUBTYPE 0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "eMuleBB Project\0"
VALUE "Comments", "{channel}; {architecture}; {source_revision}\0"
VALUE "FileDescription", "{description}\0"
VALUE "FileVersion", "{version}\0"
VALUE "LegalCopyright", "Copyright (C) eMuleBB contributors\0"
VALUE "OriginalFilename", "{binary}.exe\0"
VALUE "ProductName", "{product}\0"
VALUE "ProductVersion", "{version}\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1200
END
END
Loading
Loading