From a65cbd606bd221952baeba34bede67de96e590f9 Mon Sep 17 00:00:00 2001 From: Mahmoud-Emad Date: Sun, 12 Oct 2025 13:27:10 +0300 Subject: [PATCH] feat: improve build and serialization logic - Update v fmt exit code handling - Support dynamic organization for symlinks - Add f32 and list f64 serialization/deserialization - Improve JSON decoding for bid requirements/pricing - Add basic tests for Bid and Node creation --- .gitignore | 3 +- doc.vsh | 15 +++++-- install_herolib.vsh | 31 ++++++++------- lib/data/encoder/encoder_decode.v | 17 ++++++++ lib/data/encoder/encoder_encode.v | 17 ++++++++ lib/threefold/models_tfgrid/bid.v | 8 ++-- lib/threefold/models_tfgrid/mod.v | 8 ---- .../models_tfgrid/models_tfgrid_test.v | 39 +++++++++++++++++++ 8 files changed, 108 insertions(+), 30 deletions(-) delete mode 100644 lib/threefold/models_tfgrid/mod.v create mode 100644 lib/threefold/models_tfgrid/models_tfgrid_test.v diff --git a/.gitignore b/.gitignore index 3522a21d..33eabe13 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,5 @@ MCP_HTTP_REST_IMPLEMENTATION_PLAN.md .continue tmux_logger release -install_herolib \ No newline at end of file +install_herolib +doc \ No newline at end of file diff --git a/doc.vsh b/doc.vsh index 0730e955..086a8dc5 100755 --- a/doc.vsh +++ b/doc.vsh @@ -6,15 +6,22 @@ abs_dir_of_script := dir(@FILE) // Format code println('Formatting code...') -if os.system('v fmt -w ${abs_dir_of_script}/examples') != 0 { - eprintln('Warning: Failed to format examples') +// v fmt returns: +// - 0: all files already formatted (no changes) +// - 5: files were formatted (changes made) - this is SUCCESS +// - other: actual errors (syntax errors, file access issues, etc.) +fmt_examples_result := os.system('v fmt -w ${abs_dir_of_script}/examples') +if fmt_examples_result != 0 && fmt_examples_result != 5 { + eprintln('Error: Failed to format examples (exit code: ${fmt_examples_result})') exit(1) } -if os.system('v fmt -w ${abs_dir_of_script}/lib') != 0 { - eprintln('Warning: Failed to format herolib') +fmt_lib_result := os.system('v fmt -w ${abs_dir_of_script}/lib') +if fmt_lib_result != 0 && fmt_lib_result != 5 { + eprintln('Error: Failed to format herolib (exit code: ${fmt_lib_result})') exit(1) } +println('✓ Code formatting completed') // Clean existing docs println('Cleaning existing documentation...') diff --git a/install_herolib.vsh b/install_herolib.vsh index c4ce7d06..2ebc055e 100755 --- a/install_herolib.vsh +++ b/install_herolib.vsh @@ -47,7 +47,7 @@ abs_dir_of_script := dir(@FILE) println('Script directory: ${abs_dir_of_script}') // Determine the organization name from the current path -// This makes the script work with any organization (incubaid, freeflowuniverse, etc.) +// This makes the script work with any organization (incubaid, etc.) path_parts := abs_dir_of_script.split('/') mut org_name := 'incubaid' // default fallback for i, part in path_parts { @@ -60,32 +60,35 @@ for i, part in path_parts { println('Detected organization: ${org_name}') println('Will create symlink: ${os.home_dir()}/.vmodules/${org_name}/herolib -> ${abs_dir_of_script}/lib') -// Reset symlinks for both possible organizations (cleanup) +// Reset symlinks (cleanup) println('Resetting all symlinks...') -os.rm('${os.home_dir()}/.vmodules/freeflowuniverse/herolib') or {} os.rm('${os.home_dir()}/.vmodules/incubaid/herolib') or {} os.rm('${os.home_dir()}/.vmodules/${org_name}/herolib') or {} // Create necessary directories -os.mkdir_all('${os.home_dir()}/.vmodules/freeflowuniverse') or { - panic('Failed to create directory ~/.vmodules/freeflowuniverse: ${err}') +os.mkdir_all('${os.home_dir()}/.vmodules/${org_name}') or { + panic('Failed to create directory ~/.vmodules/${org_name}: ${err}') } // Create new symlinks -os.symlink('${abs_dir_of_script}/lib', '${os.home_dir()}/.vmodules/freeflowuniverse/herolib') or { - panic('Failed to create herolib symlink: ${err}') -} +symlink_target := '${abs_dir_of_script}/lib' +symlink_path := '${os.home_dir()}/.vmodules/${org_name}/herolib' + +os.symlink(symlink_target, symlink_path) or { panic('Failed to create herolib symlink: ${err}') } // Verify the symlink was created -symlink_path := '${os.home_dir()}/.vmodules/${org_name}/herolib' -if os.exists(symlink_path) { +// Note: os.exists() may return false for broken symlinks, so we check if it's a link first +if os.is_link(symlink_path) { println('✓ Symlink created successfully: ${symlink_path}') - // Verify it points to the right location - if os.is_link(symlink_path) { - println('✓ Confirmed: ${symlink_path} is a symbolic link') + println('✓ Points to: ${symlink_target}') + // Verify the target exists + if os.exists(symlink_target) { + println('✓ Target directory exists and is accessible') + } else { + eprintln('⚠ Warning: Symlink target does not exist: ${symlink_target}') } } else { - panic('Failed to verify herolib symlink at ${symlink_path}') + panic('Failed to create herolib symlink at ${symlink_path}') } println('Herolib installation completed successfully!') diff --git a/lib/data/encoder/encoder_decode.v b/lib/data/encoder/encoder_decode.v index 5b0948b0..373c7e0b 100644 --- a/lib/data/encoder/encoder_decode.v +++ b/lib/data/encoder/encoder_decode.v @@ -136,6 +136,14 @@ pub fn (mut d Decoder) get_f64() !f64 { return f } +pub fn (mut d Decoder) get_f32() !f32 { + // Get the u32 bits first and then convert back to f32 + bits := d.get_u32()! + // Use unsafe to convert bits to f32 + f := unsafe { *(&f32(&bits)) } + return f +} + pub fn (mut d Decoder) get_time() !time.Time { secs_ := d.get_u32()! secs := i64(secs_) @@ -229,6 +237,15 @@ pub fn (mut d Decoder) get_list_u64() ![]u64 { return v } +pub fn (mut d Decoder) get_list_f64() ![]f64 { + n := d.get_u16()! + mut v := []f64{len: int(n)} + for i in 0 .. n { + v[i] = d.get_f64()! + } + return v +} + pub fn (mut d Decoder) get_map_string() !map[string]string { n := d.get_u16()! mut v := map[string]string{} diff --git a/lib/data/encoder/encoder_encode.v b/lib/data/encoder/encoder_encode.v index 6d03ac2b..56ee0fce 100644 --- a/lib/data/encoder/encoder_encode.v +++ b/lib/data/encoder/encoder_encode.v @@ -115,6 +115,13 @@ pub fn (mut b Encoder) add_f64(data f64) { b.add_u64(bits) } +// adds a float32 value +pub fn (mut b Encoder) add_f32(data f32) { + // Convert f32 to bits first, then store as u32 + bits := unsafe { *(&u32(&data)) } + b.add_u32(bits) +} + // adds gid as a string pub fn (mut b Encoder) add_gid(data gid.GID) { b.add_string(data.str()) @@ -185,6 +192,16 @@ pub fn (mut b Encoder) add_list_u64(data []u64) { } } +pub fn (mut b Encoder) add_list_f64(data []f64) { + if data.len > 64 * kb { + panic('list cannot have more than 64kb items.') + } + b.add_u16(u16(data.len)) // how many items in list + for item in data { + b.add_f64(item) + } +} + // when complicated hash e.g. map of other object need to serialize each sub object pub fn (mut b Encoder) add_map_string(data map[string]string) { if data.len > 64 * kb { diff --git a/lib/threefold/models_tfgrid/bid.v b/lib/threefold/models_tfgrid/bid.v index e0c675f8..a18e1705 100644 --- a/lib/threefold/models_tfgrid/bid.v +++ b/lib/threefold/models_tfgrid/bid.v @@ -3,7 +3,7 @@ module models_tfgrid import incubaid.herolib.data.encoder import incubaid.herolib.data.ourtime import incubaid.herolib.hero.db -import incubaid.herolib.data.json +import json // Bid - ROOT OBJECT @[heap] @@ -106,8 +106,10 @@ pub fn (self Bid) dump(mut e encoder.Encoder) ! { fn (mut self DBBid) load(mut o Bid, mut e encoder.Decoder) ! { o.customer_id = e.get_u32()! - o.requirements = json.decode[map[string]string](e.get_string()!)! - o.pricing = json.decode[map[string]string](e.get_string()!)! + requirements_str := e.get_string()! + o.requirements = json.decode(map[string]string, requirements_str)! + pricing_str := e.get_string()! + o.pricing = json.decode(map[string]string, pricing_str)! o.status = unsafe { BidStatus(e.get_int()!) } o.obligation = e.get_bool()! o.start_date = e.get_u32()! diff --git a/lib/threefold/models_tfgrid/mod.v b/lib/threefold/models_tfgrid/mod.v deleted file mode 100644 index 49ce04cf..00000000 --- a/lib/threefold/models_tfgrid/mod.v +++ /dev/null @@ -1,8 +0,0 @@ -module models_tfgrid - -// Re-export all the root objects and their supporting structures -pub use node -pub use nodegroup -pub use bid -pub use contract -pub use reputation \ No newline at end of file diff --git a/lib/threefold/models_tfgrid/models_tfgrid_test.v b/lib/threefold/models_tfgrid/models_tfgrid_test.v new file mode 100644 index 00000000..bc37ccc4 --- /dev/null +++ b/lib/threefold/models_tfgrid/models_tfgrid_test.v @@ -0,0 +1,39 @@ +module models_tfgrid + +fn test_bid_creation() { + // Just a simple test to verify the module compiles + bid := Bid{ + customer_id: 123 + requirements: { + 'compute_nodes': '10' + } + pricing: { + 'compute_nodes': '10.2' + } + status: .pending + obligation: true + start_date: 1234567890 + end_date: 1234567890 + signature_user: 'test_signature' + billing_period: .monthly + } + + assert bid.customer_id == 123 + assert bid.status == .pending +} + +fn test_node_creation() { + // Just a simple test to verify the module compiles + node := Node{ + nodegroupid: 456 + country: 'US' + uptime: 99 + pubkey: 'test_pubkey' + signature_node: 'test_sig_node' + signature_farmer: 'test_sig_farmer' + } + + assert node.nodegroupid == 456 + assert node.country == 'US' + assert node.uptime == 99 +}