build(hololake): add verified Windows x64 distribution path

This commit is contained in:
冰朔 2026-08-17 14:01:01 +08:00
commit 39fc36f35b
13 changed files with 275 additions and 33 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
use std::cmp::Reverse;
use std::fs::{self, OpenOptions};
use std::io::Write;
#[cfg(unix)]
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::path::{Component, Path, PathBuf};
use std::process::Command;
@ -13,6 +14,18 @@ use tauri_plugin_dialog::DialogExt;
use url::Url;
use uuid::Uuid;
#[cfg(windows)]
trait OpenOptionsModeExt {
fn mode(&mut self, mode: u32) -> &mut Self;
}
#[cfg(windows)]
impl OpenOptionsModeExt for OpenOptions {
fn mode(&mut self, _mode: u32) -> &mut Self {
self
}
}
const SNAPSHOT_SCHEMA: &str = "hololake.code-channel/v1";
const REGISTRY_SCHEMA: &str = "hololake.code-channel-registry/v1";
const ALLOWED_HOSTS: &[&str] = &["guanghulab.com", "guanghubingshuo.com", "guanghu.chat"];
@ -207,6 +220,7 @@ pub(crate) fn register_managed_repository(
fn ensure_root(root: &Path) -> Result<(), String> {
fs::create_dir_all(root.join("repositories"))
.map_err(|error| format!("HOLOLAKE_CODE_CHANNEL_STORAGE_UNAVAILABLE: {error}"))?;
#[cfg(unix)]
fs::set_permissions(root, fs::Permissions::from_mode(0o700))
.map_err(|error| format!("HOLOLAKE_CODE_CHANNEL_PERMISSION_FAILED: {error}"))?;
Ok(())
@ -526,11 +540,15 @@ fn clone_at(root: &Path, input: CloneCodeChannelInput) -> Result<CodeChannelSnap
if destination.exists() {
return Err("HOLOLAKE_CODE_CHANNEL_DESTINATION_EXISTS".into());
}
let output = Command::new("/usr/bin/git")
let mut command = Command::new(git_executable());
command
.env("GIT_TERMINAL_PROMPT", "0")
.env("GIT_CONFIG_NOSYSTEM", "1");
#[cfg(unix)]
command
.env("GIT_ASKPASS", "/usr/bin/false")
.env("SSH_ASKPASS", "/usr/bin/false")
.env("GIT_CONFIG_NOSYSTEM", "1")
.env("SSH_ASKPASS", "/usr/bin/false");
let output = command
.args([
"-c",
"credential.helper=",
@ -761,7 +779,7 @@ fn write_registry(root: &Path, registry: &CodeChannelRegistry) -> Result<(), Str
}
fn git(root: &Path, args: &[&str], operation: &str) -> Result<String, String> {
let output = Command::new("/usr/bin/git")
let output = Command::new(git_executable())
.current_dir(root)
.env("GIT_TERMINAL_PROMPT", "0")
.args(args)
@ -778,7 +796,7 @@ fn git(root: &Path, args: &[&str], operation: &str) -> Result<String, String> {
}
fn git_optional(root: &Path, args: &[&str]) -> Option<String> {
let output = Command::new("/usr/bin/git")
let output = Command::new(git_executable())
.current_dir(root)
.env("GIT_TERMINAL_PROMPT", "0")
.args(args)
@ -790,6 +808,14 @@ fn git_optional(root: &Path, args: &[&str]) -> Option<String> {
.then(|| String::from_utf8_lossy(&output.stdout).into_owned())
}
fn git_executable() -> &'static str {
if cfg!(windows) {
"git"
} else {
"/usr/bin/git"
}
}
fn now_unix_ms() -> Result<u128, String> {
SystemTime::now()
.duration_since(UNIX_EPOCH)

View file

@ -14,6 +14,7 @@
use serde::{Deserialize, Serialize};
use std::fs;
#[cfg(target_os = "macos")]
use std::process::Command;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tauri::{AppHandle, Manager, State};

View file

@ -0,0 +1,57 @@
use serde::Serialize;
use tauri::AppHandle;
const DISCOVERY_SCHEMA: &str = "hololake.nearby-ai-discovery/v1";
/// Windows currently has no Unix-domain socket transport. Keep the public app
/// launchable while reporting the connector boundary as closed, rather than
/// silently opening a TCP listener with weaker local-user isolation.
#[derive(Default)]
pub struct DirectLocalBrokerState;
impl DirectLocalBrokerState {
pub fn ensure_started(&self, _app: &AppHandle) -> Result<bool, String> {
Ok(false)
}
pub fn active_connection_count(&self) -> usize {
0
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NearbyAiDiscoverySnapshot {
pub schema: &'static str,
pub state: &'static str,
pub service_name: &'static str,
pub transport: &'static str,
pub language_protocol: &'static str,
pub automatic_same_device_discovery: bool,
pub large_invitation_copy_required: bool,
pub generic_ai_visitor: &'static str,
pub guanghu_persona: &'static str,
pub local_network_discovery: &'static str,
pub authority: &'static str,
}
#[tauri::command]
pub fn get_nearby_ai_discovery() -> NearbyAiDiscoverySnapshot {
NearbyAiDiscoverySnapshot {
schema: DISCOVERY_SCHEMA,
state: "WINDOWS_TRANSPORT_NOT_YET_IMPLEMENTED",
service_name: "HoloLake",
transport: "CLOSED_NO_TCP_FALLBACK",
language_protocol: "GLP/1.0",
automatic_same_device_discovery: false,
large_invitation_copy_required: false,
generic_ai_visitor: "DEFERRED",
guanghu_persona: "BINDING_EVIDENCE_REQUIRED",
local_network_discovery: "DEFERRED_UNTIL_ENCRYPTED_TRANSPORT_AND_APPROVAL",
authority: "UNAVAILABLE_IS_NOT_AUTHORIZATION",
}
}
pub fn run_connector() -> Result<(), String> {
Err("HOLOLAKE_WINDOWS_DIRECT_LOCAL_CONNECTOR_NOT_IMPLEMENTED".into())
}

View file

@ -1195,7 +1195,8 @@ fn modified_unix_ms(metadata: &fs::Metadata) -> u128 {
}
fn git(root: &Path, args: &[&str], operation: &str) -> Result<String, String> {
let output = Command::new("/usr/bin/git")
let executable = if cfg!(windows) { "git" } else { "/usr/bin/git" };
let output = Command::new(executable)
.current_dir(root)
.env("GIT_TERMINAL_PROMPT", "0")
.args(args)

View file

@ -1,7 +1,11 @@
mod circular_lake_membrane;
mod authenticated_storage;
mod circular_lake_membrane;
mod code_channel;
mod code_repo_login;
#[cfg(unix)]
mod direct_local_broker;
#[cfg(windows)]
#[path = "direct_local_broker_windows.rs"]
mod direct_local_broker;
mod direct_local_session;
mod dynamic_capability_routing;

View file

@ -688,12 +688,23 @@ fn remove_exact_cache(root: &Path, cache: &Path) -> Result<(), String> {
}
fn trusted_git() -> Command {
let mut command = Command::new("/usr/bin/git");
let executable = if cfg!(windows) { "git" } else { "/usr/bin/git" };
let mut command = Command::new(executable);
command.env_clear();
#[cfg(unix)]
command.env("PATH", "/usr/bin:/bin");
#[cfg(windows)]
for key in ["PATH", "SystemRoot", "WINDIR", "TEMP", "TMP"] {
if let Some(value) = std::env::var_os(key) {
command.env(key, value);
}
}
command
.env_clear()
.env("PATH", "/usr/bin:/bin")
.env("GIT_CONFIG_NOSYSTEM", "1")
.env("GIT_CONFIG_GLOBAL", "/dev/null")
.env(
"GIT_CONFIG_GLOBAL",
if cfg!(windows) { "NUL" } else { "/dev/null" },
)
.env("GIT_TERMINAL_PROMPT", "0")
.env("GCM_INTERACTIVE", "Never")
.args(["-c", "protocol.file.allow=never"]);

View file

@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;
use std::fs::{self, OpenOptions};
use std::io::Write;
#[cfg(unix)]
use std::os::unix::fs::OpenOptionsExt;
use std::path::{Component, Path, PathBuf};
use std::process::{Command, Output};
@ -16,6 +17,18 @@ use tauri::AppHandle;
use tauri_plugin_dialog::DialogExt;
use uuid::Uuid;
#[cfg(windows)]
trait OpenOptionsModeExt {
fn mode(&mut self, mode: u32) -> &mut Self;
}
#[cfg(windows)]
impl OpenOptionsModeExt for OpenOptions {
fn mode(&mut self, _mode: u32) -> &mut Self {
self
}
}
const MANIFEST_PATH: &str = ".hololake/persona/manifest.json";
const MANIFEST_SCHEMA: &str = "hololake.persona/v1";
const MAX_MANIFEST_BYTES: usize = 512 * 1024;
@ -765,12 +778,23 @@ fn now_unix_ms() -> Result<u128, String> {
}
fn trusted_git() -> Command {
let mut command = Command::new("/usr/bin/git");
let executable = if cfg!(windows) { "git" } else { "/usr/bin/git" };
let mut command = Command::new(executable);
command.env_clear();
#[cfg(unix)]
command.env("PATH", "/usr/bin:/bin");
#[cfg(windows)]
for key in ["PATH", "SystemRoot", "WINDIR", "TEMP", "TMP"] {
if let Some(value) = std::env::var_os(key) {
command.env(key, value);
}
}
command
.env_clear()
.env("PATH", "/usr/bin:/bin")
.env("GIT_CONFIG_NOSYSTEM", "1")
.env("GIT_CONFIG_GLOBAL", "/dev/null")
.env(
"GIT_CONFIG_GLOBAL",
if cfg!(windows) { "NUL" } else { "/dev/null" },
)
.env("GIT_TERMINAL_PROMPT", "0");
command
}

View file

@ -120,7 +120,8 @@ fn parse_projection(bytes: &[u8]) -> Result<ServerPnccProjection, String> {
#[tauri::command]
pub async fn query_jd_pncc_server_projection() -> Result<ServerPnccProjection, String> {
tauri::async_runtime::spawn_blocking(|| {
let output = Command::new("/usr/bin/ssh")
let executable = if cfg!(windows) { "ssh" } else { "/usr/bin/ssh" };
let output = Command::new(executable)
.args([
"-o",
"BatchMode=yes",

View file

@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::fs::{self, OpenOptions};
use std::io::Write;
#[cfg(unix)]
use std::os::unix::fs::OpenOptionsExt;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
@ -15,6 +16,18 @@ use tauri::{AppHandle, Manager};
use tauri_plugin_updater::{Update, UpdaterExt};
use uuid::Uuid;
#[cfg(windows)]
trait OpenOptionsModeExt {
fn mode(&mut self, mode: u32) -> &mut Self;
}
#[cfg(windows)]
impl OpenOptionsModeExt for OpenOptions {
fn mode(&mut self, _mode: u32) -> &mut Self {
self
}
}
const CANDIDATE_SCHEMA: &str = "hololake.release-candidate/v1";
const RECEIPT_SCHEMA: &str = "hololake.release-install-receipt/v1";
const RECOVERY_SCHEMA: &str = "hololake.release-recovery/v1";
@ -257,18 +270,17 @@ pub async fn confirm_hololake_update_install(
{
return Err("HOLOLAKE_RELEASE_PACKAGE_DIGEST_OR_SIZE_MISMATCH".into());
}
let current_bundle = current_app_bundle_path()?;
let backup = prepare_last_known_good_at(&root, &current_bundle)?;
let platform_recovery = prepare_platform_recovery_at(&root)?;
let mut recovery = ReleaseRecoveryRecord {
schema: RECOVERY_SCHEMA.into(),
state: "LAST_KNOWN_GOOD_VERIFIED_INSTALLING".into(),
state: platform_recovery.installing_state.into(),
release_id: snapshot.envelope.release_id.clone(),
previous_version: snapshot.current_version.clone(),
installed_version: snapshot.envelope.version.clone(),
backup_bundle_path: backup.0.to_string_lossy().into_owned(),
backup_identifier: backup.1.identifier,
backup_team_identifier: backup.1.team_identifier,
backup_cdhash: backup.1.cdhash,
backup_bundle_path: platform_recovery.backup_bundle_path,
backup_identifier: platform_recovery.backup_identifier,
backup_team_identifier: platform_recovery.backup_team_identifier,
backup_cdhash: platform_recovery.backup_cdhash,
failed_bundle_path: None,
observed_at_unix_ms: now_unix_ms()?,
receipt_id: sha256_hex(
@ -293,7 +305,8 @@ pub async fn confirm_hololake_update_install(
package_size: snapshot.package_size,
automatic_restart: false,
health_receipt_required: snapshot.envelope.hololake.rollback.health_receipt_required,
rollback_declared_by_broadcast: snapshot.envelope.hololake.rollback.supported,
rollback_declared_by_broadcast: snapshot.envelope.hololake.rollback.supported
&& platform_recovery.local_rollback_available,
receipt_id: sha256_hex(
format!(
"{}\n{}\n{}\n{}",
@ -311,13 +324,13 @@ pub async fn confirm_hololake_update_install(
"RECEIPT",
)?;
if let Err(error) = mark_candidate_installing_at(&root, &record.candidate_id) {
recovery.state = "INSTALL_FAILED_BACKUP_RETAINED".into();
recovery.state = platform_install_failed_state().into();
recovery.observed_at_unix_ms = now_unix_ms()?;
write_json_atomic(&recovery_path(&root), &recovery, "RECOVERY")?;
return Err(error);
}
if let Err(error) = update.install(&bytes) {
recovery.state = "INSTALL_FAILED_BACKUP_RETAINED".into();
recovery.state = platform_install_failed_state().into();
recovery.observed_at_unix_ms = now_unix_ms()?;
write_json_atomic(&recovery_path(&root), &recovery, "RECOVERY")?;
return Err(format!("HOLOLAKE_RELEASE_INSTALL_FAILED: {error}"));
@ -347,6 +360,8 @@ pub fn confirm_hololake_release_health(app: AppHandle) -> Result<ReleaseRecovery
| "ROLLED_BACK_AWAITING_HUMAN_ACKNOWLEDGEMENT"
| "INSTALL_FAILED_BACKUP_RETAINED"
| "INSTALL_INTERRUPTED_BACKUP_RETAINED"
| "INSTALL_FAILED_NO_LOCAL_BACKUP"
| "INSTALL_INTERRUPTED_NO_LOCAL_BACKUP"
) {
return Err("HOLOLAKE_RELEASE_HEALTH_CONFIRMATION_NOT_AVAILABLE".into());
}
@ -359,13 +374,14 @@ pub fn confirm_hololake_release_health(app: AppHandle) -> Result<ReleaseRecovery
if &running_version != expected {
return Err("HOLOLAKE_RELEASE_RUNNING_VERSION_MISMATCH".into());
}
remove_owned_bundle_path(&root, Path::new(&record.backup_bundle_path))?;
if let Some(failed) = record.failed_bundle_path.as_deref() {
remove_owned_failed_bundle(Path::new(failed), &current_app_parent()?)?;
}
finalize_platform_recovery_artifacts(&root, &record)?;
record.state = match record.state.as_str() {
"AWAITING_HUMAN_HEALTH_CONFIRMATION" if record.backup_bundle_path.is_empty() => {
"HEALTH_CONFIRMED_NO_LOCAL_BACKUP"
}
"AWAITING_HUMAN_HEALTH_CONFIRMATION" => "HEALTH_CONFIRMED_BACKUP_REMOVED",
"ROLLED_BACK_AWAITING_HUMAN_ACKNOWLEDGEMENT" => "ROLLBACK_CONFIRMED_BACKUP_REMOVED",
_ if record.backup_bundle_path.is_empty() => "INSTALL_FAILURE_ACKNOWLEDGED_NO_LOCAL_BACKUP",
_ => "INSTALL_FAILURE_ACKNOWLEDGED_BACKUP_REMOVED",
}
.into();
@ -374,6 +390,7 @@ pub fn confirm_hololake_release_health(app: AppHandle) -> Result<ReleaseRecovery
Ok(recovery_receipt(&record))
}
#[cfg(not(windows))]
#[tauri::command]
pub fn rollback_hololake_update(app: AppHandle) -> Result<ReleaseRecoveryReceipt, String> {
let root = release_update_root(&app)?;
@ -396,6 +413,12 @@ pub fn rollback_hololake_update(app: AppHandle) -> Result<ReleaseRecoveryReceipt
Ok(recovery_receipt(&record))
}
#[cfg(windows)]
#[tauri::command]
pub fn rollback_hololake_update(_app: AppHandle) -> Result<ReleaseRecoveryReceipt, String> {
Err("HOLOLAKE_RELEASE_WINDOWS_LOCAL_ROLLBACK_NOT_AVAILABLE".into())
}
pub(crate) fn observe_release_startup(app: &AppHandle) -> Result<(), String> {
let root = release_update_root(app)?;
let path = recovery_path(&root);
@ -422,6 +445,16 @@ pub(crate) fn observe_release_startup(app: &AppHandle) -> Result<(), String> {
"LAST_KNOWN_GOOD_VERIFIED_INSTALLING" if version == record.installed_version => {
Some("AWAITING_HUMAN_HEALTH_CONFIRMATION")
}
"SIGNED_PACKAGE_VERIFIED_INSTALLING_NO_LOCAL_ROLLBACK"
if version == record.previous_version =>
{
Some("INSTALL_INTERRUPTED_NO_LOCAL_BACKUP")
}
"SIGNED_PACKAGE_VERIFIED_INSTALLING_NO_LOCAL_ROLLBACK"
if version == record.installed_version =>
{
Some("AWAITING_HUMAN_HEALTH_CONFIRMATION")
}
"AWAITING_HUMAN_HEALTH_CONFIRMATION" if version == record.previous_version => {
Some("ROLLED_BACK_AWAITING_HUMAN_ACKNOWLEDGEMENT")
}
@ -615,8 +648,10 @@ fn ensure_no_unresolved_recovery_at(root: &Path) -> Result<(), String> {
if matches!(
record.state.as_str(),
"HEALTH_CONFIRMED_BACKUP_REMOVED"
| "HEALTH_CONFIRMED_NO_LOCAL_BACKUP"
| "ROLLBACK_CONFIRMED_BACKUP_REMOVED"
| "INSTALL_FAILURE_ACKNOWLEDGED_BACKUP_REMOVED"
| "INSTALL_FAILURE_ACKNOWLEDGED_NO_LOCAL_BACKUP"
) {
Ok(())
} else {
@ -643,8 +678,11 @@ fn release_recovery_status_at(root: &Path) -> Result<ReleaseRecoveryStatus, Stri
| "ROLLED_BACK_AWAITING_HUMAN_ACKNOWLEDGEMENT"
| "INSTALL_FAILED_BACKUP_RETAINED"
| "INSTALL_INTERRUPTED_BACKUP_RETAINED"
| "INSTALL_FAILED_NO_LOCAL_BACKUP"
| "INSTALL_INTERRUPTED_NO_LOCAL_BACKUP"
);
let backup_ready = Path::new(&record.backup_bundle_path).exists();
let backup_ready =
!record.backup_bundle_path.is_empty() && Path::new(&record.backup_bundle_path).exists();
Ok(ReleaseRecoveryStatus {
schema: RECOVERY_SCHEMA,
state: record.state,
@ -672,6 +710,74 @@ fn recovery_receipt(record: &ReleaseRecoveryRecord) -> ReleaseRecoveryReceipt {
}
}
struct PlatformRecoveryPreparation {
installing_state: &'static str,
backup_bundle_path: String,
backup_identifier: String,
backup_team_identifier: String,
backup_cdhash: String,
local_rollback_available: bool,
}
#[cfg(not(windows))]
fn prepare_platform_recovery_at(root: &Path) -> Result<PlatformRecoveryPreparation, String> {
let current_bundle = current_app_bundle_path()?;
let (backup, evidence) = prepare_last_known_good_at(root, &current_bundle)?;
Ok(PlatformRecoveryPreparation {
installing_state: "LAST_KNOWN_GOOD_VERIFIED_INSTALLING",
backup_bundle_path: backup.to_string_lossy().into_owned(),
backup_identifier: evidence.identifier,
backup_team_identifier: evidence.team_identifier,
backup_cdhash: evidence.cdhash,
local_rollback_available: true,
})
}
#[cfg(windows)]
fn prepare_platform_recovery_at(_root: &Path) -> Result<PlatformRecoveryPreparation, String> {
Ok(PlatformRecoveryPreparation {
installing_state: "SIGNED_PACKAGE_VERIFIED_INSTALLING_NO_LOCAL_ROLLBACK",
backup_bundle_path: String::new(),
backup_identifier: String::new(),
backup_team_identifier: String::new(),
backup_cdhash: String::new(),
local_rollback_available: false,
})
}
#[cfg(not(windows))]
fn platform_install_failed_state() -> &'static str {
"INSTALL_FAILED_BACKUP_RETAINED"
}
#[cfg(windows)]
fn platform_install_failed_state() -> &'static str {
"INSTALL_FAILED_NO_LOCAL_BACKUP"
}
#[cfg(not(windows))]
fn finalize_platform_recovery_artifacts(
root: &Path,
record: &ReleaseRecoveryRecord,
) -> Result<(), String> {
remove_owned_bundle_path(root, Path::new(&record.backup_bundle_path))?;
if let Some(failed) = record.failed_bundle_path.as_deref() {
remove_owned_failed_bundle(Path::new(failed), &current_app_parent()?)?;
}
Ok(())
}
#[cfg(windows)]
fn finalize_platform_recovery_artifacts(
_root: &Path,
record: &ReleaseRecoveryRecord,
) -> Result<(), String> {
if !record.backup_bundle_path.is_empty() || record.failed_bundle_path.is_some() {
return Err("HOLOLAKE_RELEASE_WINDOWS_RECOVERY_BOUNDARY_INVALID".into());
}
Ok(())
}
fn prepare_last_known_good_at(
root: &Path,
current_bundle: &Path,

View file

@ -402,7 +402,8 @@ fn write_json_atomic(path: &Path, value: &UserPnccBindingRecord) -> Result<(), S
}
fn run_git(root: &Path, args: &[&str], operation: &str) -> Result<String, String> {
let output = Command::new("/usr/bin/git")
let executable = if cfg!(windows) { "git" } else { "/usr/bin/git" };
let output = Command::new(executable)
.current_dir(root)
.env("GIT_TERMINAL_PROMPT", "0")
.env("GIT_CONFIG_NOSYSTEM", "1")

View file

@ -37,7 +37,8 @@
"targets": "all",
"icon": [
"icons/icon.icns",
"icons/icon.png"
"icons/icon.png",
"icons/icon.ico"
],
"createUpdaterArtifacts": true,
"category": "Productivity",