add script to build windows artifact; fix bugs

This commit is contained in:
hosted-fornet 2024-10-15 12:39:56 -07:00
parent 4727de6f03
commit 1b43493c0e
3 changed files with 155 additions and 18 deletions

View File

@ -6,9 +6,15 @@ use lib::types::core::{
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::Arc};
#[cfg(unix)]
const DEFAULT_MAX_OPEN_FDS: u64 = 180;
const DEFAULT_FDS_AS_FRACTION_OF_ULIMIT_PERCENTAGE: u64 = 90;
#[cfg(target_os = "windows")]
const DEFAULT_MAX_OPEN_FDS: u64 = 7_000;
#[cfg(unix)]
const SYS_RESERVED_FDS: u64 = 30;
const DEFAULT_FDS_AS_FRACTION_OF_ULIMIT_PERCENTAGE: u64 = 90;
const DEFAULT_UPDATE_ULIMIT_SECS: u64 = 3600;
const _DEFAULT_CULL_FRACTION_DENOMINATOR: u64 = 2;
@ -46,6 +52,7 @@ impl State {
}
}
#[cfg(unix)]
fn update_max_fds_from_ulimit(&mut self, ulimit_max_fds: u64) {
let Mode::DynamicMax {
ref max_fds_as_fraction_of_ulimit_percentage,
@ -104,7 +111,18 @@ pub async fn fd_manager(
mut recv_from_loop: MessageReceiver,
static_max_fds: Option<u64>,
) -> anyhow::Result<()> {
// Windows does not allow querying of max fds allowed.
// However, it allows some 16m, will expectation of actual
// max number open nearer to 10k; set to 7k which should be plenty.
// https://techcommunity.microsoft.com/t5/windows-blog-archive/pushing-the-limits-of-windows-handles/ba-p/723848
#[cfg(target_os = "windows")]
let static_max_fds = match static_max_fds {
Some(smf) => Some(smf),
None => Some(DEFAULT_MAX_OPEN_FDS),
};
let mut state = State::new(static_max_fds);
#[cfg(unix)]
let mut interval = {
// in code block to release the reference into state
let Mode::DynamicMax {
@ -117,12 +135,12 @@ pub async fn fd_manager(
tokio::time::interval(tokio::time::Duration::from_secs(*update_ulimit_secs))
};
loop {
#[cfg(unix)]
tokio::select! {
Some(message) = recv_from_loop.recv() => {
match handle_message(
&our_node,
message,
&mut interval,
&mut state,
&send_to_loop,
).await {
@ -151,13 +169,31 @@ pub async fn fd_manager(
}
}
}
#[cfg(target_os = "windows")]
if let Some(message) = recv_from_loop.recv().await {
match handle_message(
&our_node,
message,
&mut state,
&send_to_loop,
).await {
Ok(Some(to_print)) => {
Printout::new(2, to_print).send(&send_to_terminal).await;
}
Err(e) => {
Printout::new(1, &format!("handle_message error: {e:?}"))
.send(&send_to_terminal)
.await;
}
_ => {}
}
}
}
}
async fn handle_message(
our_node: &str,
km: KernelMessage,
_interval: &mut tokio::time::Interval,
state: &mut State,
send_to_loop: &MessageSender,
) -> anyhow::Result<Option<String>> {
@ -282,6 +318,7 @@ async fn handle_message(
Ok(return_value)
}
#[cfg(unix)]
async fn update_max_fds(state: &mut State) -> anyhow::Result<u64> {
let ulimit_max_fds = get_max_fd_limit()
.map_err(|_| anyhow::anyhow!("Couldn't update max fd limit: ulimit failed"))?;
@ -289,6 +326,21 @@ async fn update_max_fds(state: &mut State) -> anyhow::Result<u64> {
Ok(ulimit_max_fds)
}
#[cfg(unix)]
fn get_max_fd_limit() -> anyhow::Result<u64> {
let mut rlim = libc::rlimit {
rlim_cur: 0, // Current limit
rlim_max: 0, // Maximum limit value
};
// RLIMIT_NOFILE is the resource indicating the maximum file descriptor number.
if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) } == 0 {
Ok(rlim.rlim_cur as u64)
} else {
Err(anyhow::anyhow!("Failed to get the resource limit."))
}
}
async fn send_all_fds_limits(our_node: &str, send_to_loop: &MessageSender, state: &State) {
for (process_id, limit) in &state.fds_limits {
KernelMessage::builder()
@ -309,20 +361,6 @@ async fn send_all_fds_limits(our_node: &str, send_to_loop: &MessageSender, state
}
}
fn get_max_fd_limit() -> anyhow::Result<u64> {
let mut rlim = libc::rlimit {
rlim_cur: 0, // Current limit
rlim_max: 0, // Maximum limit value
};
// RLIMIT_NOFILE is the resource indicating the maximum file descriptor number.
if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) } == 0 {
Ok(rlim.rlim_cur as u64)
} else {
Err(anyhow::anyhow!("Failed to get the resource limit."))
}
}
pub async fn send_fd_manager_request_fds_limit(our: &Address, send_to_loop: &MessageSender) {
let message = Message::Request(Request {
inherit: false,

View File

@ -1 +1,3 @@
npm install && npm run build:copy
#!/bin/bash
npm install && npm run build:copy

View File

@ -0,0 +1,97 @@
#!/usr/bin/env python3
import argparse
import os
import subprocess
import sys
import zipfile
def is_excluded(path, excludes, include_files):
path = os.path.abspath(path)
# If the path is in include_files, do not exclude it
if path in include_files:
return False
for exclude in excludes:
if os.path.commonpath([path, exclude]) == exclude:
return True
return False
def parse_args(repo_root):
parser = argparse.ArgumentParser(description='Build Windows artifact.')
parser.add_argument(
'--exclude',
action='append',
default=[],
help='Exclude directories (relative to repo root). Can be used multiple times.'
)
parser.add_argument(
'--output',
default=os.path.join(repo_root, 'target', 'windows-artifact.zip'),
help='Output zip file path.'
)
args = parser.parse_args()
return args
def main():
# Get the directory where the script is located
script_dir = os.path.dirname(os.path.abspath(__file__))
# Assume the repo root is one level up from the script directory
repo_root = os.path.abspath(os.path.join(script_dir, '..'))
args = parse_args(repo_root)
default_excludes = [
'.git',
'kinode/packages',
'target',
'kinode/src/register-ui/node_modules',
]
excludes = default_excludes + args.exclude
# Convert exclude paths to absolute paths
excludes = [os.path.abspath(os.path.join(repo_root, p)) for p in excludes]
# Include 'target/packages.zip' even though 'target' is excluded
include_files = [
os.path.abspath(os.path.join(repo_root, 'target', 'packages.zip'))
]
# Run the build scripts
build_script_dir = os.path.join(repo_root, 'kinode', 'src', 'register-ui')
build_script_name = 'build.sh'
build_script = os.path.join(build_script_dir, build_script_name)
if not os.path.exists(build_script):
print(f'Build script not found at {build_script}')
sys.exit(1)
# Execute the build script
subprocess.check_call([f'./{build_script_name}'], cwd=build_script_dir)
# Run cargo build
subprocess.check_call(['cargo', 'build', '-p', 'build_packages'], cwd=repo_root)
# Create the zip file
output_zip = args.output
output_zip_abs = os.path.abspath(output_zip)
output_dir = os.path.dirname(output_zip_abs)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir)
# Exclude the output zip file itself
excludes.append(output_zip_abs)
with zipfile.ZipFile(output_zip_abs, 'w', zipfile.ZIP_DEFLATED) as zipf:
for root, dirs, files in os.walk(repo_root):
for file in files:
file_path = os.path.join(root, file)
if is_excluded(file_path, excludes, include_files):
continue
rel_path = os.path.relpath(file_path, repo_root)
if ':' in str(rel_path):
# Replace ':' in filenames to make them valid on Windows
rel_path = rel_path.replace(':', '_')
print(f'Unexpected `:` in filename: {rel_path}; replacing with `_` in zip file')
zipf.write(file_path, rel_path)
if __name__ == '__main__':
main()