[INFO] fetching crate yok 0.1.9...
[INFO] testing yok-0.1.9 against master#1871252fc8bb672d40787e67404e6eaae7059369 for pr-125151
[INFO] extracting crate yok 0.1.9 into /workspace/builds/worker-3-tc1/source
[INFO] validating manifest of crates.io crate yok 0.1.9 on toolchain 1871252fc8bb672d40787e67404e6eaae7059369
[INFO] running `Command { std: CARGO_HOME="/workspace/cargo-home" RUSTUP_HOME="/workspace/rustup-home" "/workspace/cargo-home/bin/cargo" "+1871252fc8bb672d40787e67404e6eaae7059369" "metadata" "--manifest-path" "Cargo.toml" "--no-deps", kill_on_drop: false }`
[INFO] started tweaking crates.io crate yok 0.1.9
[INFO] finished tweaking crates.io crate yok 0.1.9
[INFO] tweaked toml for crates.io crate yok 0.1.9 written to /workspace/builds/worker-3-tc1/source/Cargo.toml
[INFO] crate crates.io crate yok 0.1.9 already has a lockfile, it will not be regenerated
[INFO] running `Command { std: CARGO_HOME="/workspace/cargo-home" RUSTUP_HOME="/workspace/rustup-home" "/workspace/cargo-home/bin/cargo" "+1871252fc8bb672d40787e67404e6eaae7059369" "fetch" "--manifest-path" "Cargo.toml", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc1/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc1/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--user" "0:0" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:59a85a07ab18ca8720692f8e61effa1c651d9e2ca591e072c2b212bb91a6b8b5" "/opt/rustwide/cargo-home/bin/cargo" "+1871252fc8bb672d40787e67404e6eaae7059369" "metadata" "--no-deps" "--format-version=1", kill_on_drop: false }`
[INFO] [stdout] 38133137b66aced515437121c3cd4d0e4bab9a10f4c68e8e9470054cd88cffa2
[INFO] running `Command { std: "docker" "start" "-a" "38133137b66aced515437121c3cd4d0e4bab9a10f4c68e8e9470054cd88cffa2", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "inspect" "38133137b66aced515437121c3cd4d0e4bab9a10f4c68e8e9470054cd88cffa2", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "38133137b66aced515437121c3cd4d0e4bab9a10f4c68e8e9470054cd88cffa2", kill_on_drop: false }`
[INFO] [stdout] 38133137b66aced515437121c3cd4d0e4bab9a10f4c68e8e9470054cd88cffa2
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc1/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc1/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=forbid" "-e" "RUSTDOCFLAGS=--cap-lints=forbid" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--user" "0:0" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:59a85a07ab18ca8720692f8e61effa1c651d9e2ca591e072c2b212bb91a6b8b5" "/opt/rustwide/cargo-home/bin/cargo" "+1871252fc8bb672d40787e67404e6eaae7059369" "build" "--frozen" "--message-format=json", kill_on_drop: false }`
[INFO] [stdout] e07c0a8294ad96caf317ad8a876215257689d0debfcdff83e0238d94e9a9f251
[INFO] running `Command { std: "docker" "start" "-a" "e07c0a8294ad96caf317ad8a876215257689d0debfcdff83e0238d94e9a9f251", kill_on_drop: false }`
[INFO] [stderr]    Compiling yok v0.1.9 (/opt/rustwide/workdir)
[INFO] [stderr]     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.78s
[INFO] running `Command { std: "docker" "inspect" "e07c0a8294ad96caf317ad8a876215257689d0debfcdff83e0238d94e9a9f251", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "e07c0a8294ad96caf317ad8a876215257689d0debfcdff83e0238d94e9a9f251", kill_on_drop: false }`
[INFO] [stdout] e07c0a8294ad96caf317ad8a876215257689d0debfcdff83e0238d94e9a9f251
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc1/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc1/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=forbid" "-e" "RUSTDOCFLAGS=--cap-lints=forbid" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--user" "0:0" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:59a85a07ab18ca8720692f8e61effa1c651d9e2ca591e072c2b212bb91a6b8b5" "/opt/rustwide/cargo-home/bin/cargo" "+1871252fc8bb672d40787e67404e6eaae7059369" "test" "--frozen" "--no-run" "--message-format=json", kill_on_drop: false }`
[INFO] [stdout] c3004cbd70b1e3fba49641e8bf98e1abceffc011be0237f4a40648a95de8c5f1
[INFO] running `Command { std: "docker" "start" "-a" "c3004cbd70b1e3fba49641e8bf98e1abceffc011be0237f4a40648a95de8c5f1", kill_on_drop: false }`
[INFO] [stderr]    Compiling yok v0.1.9 (/opt/rustwide/workdir)
[INFO] [stderr]     Finished `test` profile [unoptimized + debuginfo] target(s) in 0.52s
[INFO] running `Command { std: "docker" "inspect" "c3004cbd70b1e3fba49641e8bf98e1abceffc011be0237f4a40648a95de8c5f1", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "c3004cbd70b1e3fba49641e8bf98e1abceffc011be0237f4a40648a95de8c5f1", kill_on_drop: false }`
[INFO] [stdout] c3004cbd70b1e3fba49641e8bf98e1abceffc011be0237f4a40648a95de8c5f1
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc1/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc1/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=forbid" "-e" "RUSTDOCFLAGS=--cap-lints=forbid" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--user" "0:0" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:59a85a07ab18ca8720692f8e61effa1c651d9e2ca591e072c2b212bb91a6b8b5" "/opt/rustwide/cargo-home/bin/cargo" "+1871252fc8bb672d40787e67404e6eaae7059369" "test" "--frozen", kill_on_drop: false }`
[INFO] [stdout] 2210901f4c2e473373cb7078b0bd87cd96224f830c2945e87480e72963aab834
[INFO] running `Command { std: "docker" "start" "-a" "2210901f4c2e473373cb7078b0bd87cd96224f830c2945e87480e72963aab834", kill_on_drop: false }`
[INFO] [stderr]    Compiling yok v0.1.9 (/opt/rustwide/workdir)
[INFO] [stderr]     Finished `test` profile [unoptimized + debuginfo] target(s) in 0.44s
[INFO] [stderr]      Running unittests src/lib.rs (/opt/rustwide/target/debug/deps/yok-52d48ae7f605bbb8)
[INFO] [stdout] 
[INFO] [stdout] running 0 tests
[INFO] [stdout] 
[INFO] [stderr]      Running unittests src/main.rs (/opt/rustwide/target/debug/deps/yok-221974d0057d098f)
[INFO] [stdout] test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] running 0 tests
[INFO] [stdout] 
[INFO] [stdout] test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
[INFO] [stdout] 
[INFO] [stderr]    Doc-tests yok
[INFO] [stdout] 
[INFO] [stdout] running 3 tests
[INFO] [stdout] test src/lib.rs - Dir::extract (line 218) ... FAILED
[INFO] [stdout] test src/lib.rs - include_dir (line 282) ... FAILED
[INFO] [stdout] test src/lib.rs - DirEntry (line 10) ... FAILED
[INFO] [stdout] 
[INFO] [stdout] failures:
[INFO] [stdout] 
[INFO] [stdout] ---- src/lib.rs - Dir::extract (line 218) stdout ----
[INFO] [stdout] Test executable failed (exit status: 101).
[INFO] [stdout] 
[INFO] [stdout] stdout:
[INFO] [stdout] use std::{
[INFO] [stdout]     fs, io,
[INFO] [stdout]     path::{Path, PathBuf},
[INFO] [stdout] };
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     use std::mem;
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct DirEntry {
[INFO] [stdout]         path: String,
[INFO] [stdout]         is_dir: bool,
[INFO] [stdout]         is_file: bool,
[INFO] [stdout]         content: Vec<u8>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct Dir {
[INFO] [stdout]         data: Vec<DirEntry>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement as_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]             // Calculate the total size of the serialized data
[INFO] [stdout]             let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]                 size += entry.path.as_bytes().len();
[INFO] [stdout]                 size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]                 size += entry.content.len();
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]             // Write the length prefix
[INFO] [stdout]             bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 // Write the size prefix for this entry
[INFO] [stdout]                 bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]                 // Write the entry data
[INFO] [stdout]                 bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]                 bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]                 bytes.extend((entry.content.len() as u32).to_le_bytes().iter());
[INFO] [stdout]                 bytes.extend(entry.content.iter());
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             bytes
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement from_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         #[allow(warnings)]
[INFO] [stdout]         pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]             let mut cursor = 0;
[INFO] [stdout]             let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let len = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]             for _ in 0..len {
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let entry_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < end_pos {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]                 cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + 2 {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let is_dir = bytes[cursor] != 0;
[INFO] [stdout]                 let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]                 cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + content_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]                 cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]                 data.push(DirEntry {
[INFO] [stdout]                     path,
[INFO] [stdout]                     is_dir,
[INFO] [stdout]                     is_file,
[INFO] [stdout]                     content,
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             Some(Dir { data })
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     pub fn walk_dir(path: impl ToString) -> io::Result<Vec<PathBuf>> {
[INFO] [stdout]         let path = path.to_string();
[INFO] [stdout]         let dir = Path::new(&path);
[INFO] [stdout]         let mut files = Vec::new();
[INFO] [stdout]         for entry in fs::read_dir(dir)? {
[INFO] [stdout]             let entry = entry?;
[INFO] [stdout]             let newpath = entry.path();
[INFO] [stdout] 
[INFO] [stdout]             if newpath.is_dir() {
[INFO] [stdout]                 files.extend(walk_dir(&newpath.display())?);
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             } else {
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(files)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     use std::env;
[INFO] [stdout]     let yok_path = match env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     println!("cargo:rerun-if-env-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed=main.rs");
[INFO] [stdout]     println!("cargo:rerun-if-changed=lib.rs");
[INFO] [stdout]     let yok_path = std::path::Path::new(&yok_path);
[INFO] [stdout]     if yok_path.is_dir() {
[INFO] [stdout]         let mut res_dir: Vec<DirEntry> = vec![];
[INFO] [stdout]         let dir_list = walk_dir(yok_path.display()).expect("walk dir error");
[INFO] [stdout]         for dir in dir_list {
[INFO] [stdout]             if dir.is_file() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: false,
[INFO] [stdout]                     is_file: true,
[INFO] [stdout]                     content: std::fs::read(dir).expect("read dir error"),
[INFO] [stdout]                 });
[INFO] [stdout]             } else if dir.is_dir() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: true,
[INFO] [stdout]                     is_file: false,
[INFO] [stdout]                     content: vec![],
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         let all_dir: Dir = Dir { data: res_dir };
[INFO] [stdout]         let all_dir_bytes = all_dir.as_bytes();
[INFO] [stdout]         if let Ok(_) = std::fs::write(format!("../.yok"), all_dir_bytes){}
[INFO] [stdout]     } else {
[INFO] [stdout]         eprintln!("Environment variable 'YOK_PATH' not dir");
[INFO] [stdout]         return;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] keywords = ["include","dir","compile-time"]
[INFO] [stdout] categories = ["development-tools","game-engines","web-programming"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] categories = ["development-tools", "game-engines", "web-programming"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] keywords = ["include", "dir", "compile-time"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] name = "yok"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] # yok
[INFO] [stdout] 
[INFO] [stdout] [![Crates.io](https://img.shields.io/crates/v/yok.svg)](https://crates.io/crates/yok)
[INFO] [stdout] [![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://gitlab.com/andrew_ryan/yok)
[INFO] [stdout] [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitlab.com/andrew_ryan/yok/-/raw/master/LICENSE)
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] A crate for Embed the contents of a directory in your binary at compile time.
[INFO] [stdout] 
[INFO] [stdout] ## Getting Started
[INFO] [stdout] ```sh
[INFO] [stdout] cargo add yok
[INFO] [stdout] ```
[INFO] [stdout] ```rust
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::{Dir, Bytes,include_dir};
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] }
[INFO] [stdout] ```
[INFO] [stdout] ## Set YOK_PATH env and run or default path is cuttent dir
[INFO] [stdout] ```sh
[INFO] [stdout] # linux,macos
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] # windows cmd
[INFO] [stdout] set YOK_PATH="C:\path\to\your\directory"
[INFO] [stdout] # windows powershell
[INFO] [stdout] $env:YOK_PATH = "C:\path\to\your\directory"
[INFO] [stdout] 
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] ```
[INFO] [stdout] rm -rf path
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] # This file is automatically @generated by Cargo.
[INFO] [stdout] # It is not intended for manual editing.
[INFO] [stdout] version = 3
[INFO] [stdout] 
[INFO] [stdout] [[package]]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] 
[INFO] [stdout] image: rustlang/rust:nightly
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] push:cargo:
[INFO] [stdout]   script:
[INFO] [stdout]     - rustc --version && cargo --version  
[INFO] [stdout]     - cargo publish --allow-dirty --token cioHYTp8cpgbRbBqcJvqGF7rUIjJQSlBvH3
[INFO] [stdout] 
[INFO] [stdout] use std::{mem, path::PathBuf, str::FromStr};
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct DirEntry {
[INFO] [stdout]     pub path: String,
[INFO] [stdout]     pub is_dir: bool,
[INFO] [stdout]     pub is_file: bool,
[INFO] [stdout]     pub contents: Vec<u8>,
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct Dir {
[INFO] [stdout]     pub data: Vec<DirEntry>,
[INFO] [stdout] }
[INFO] [stdout] pub trait Bytes {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn from_bytes(&self) -> Dir;
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn into_dir(&self) -> Dir;
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for [u8] {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for Dir {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement as_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         // Calculate the total size of the serialized data
[INFO] [stdout]         let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]             size += entry.path.as_bytes().len();
[INFO] [stdout]             size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]             size += entry.contents.len();
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]         // Write the length prefix
[INFO] [stdout]         bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             // Write the size prefix for this entry
[INFO] [stdout]             bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             // Write the entry data
[INFO] [stdout]             bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]             bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]             bytes.extend((entry.contents.len() as u32).to_le_bytes().iter());
[INFO] [stdout]             bytes.extend(entry.contents.iter());
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         bytes
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement from_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]         let mut cursor = 0;
[INFO] [stdout]         let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]         if bytes.len() < len_prefix_size {
[INFO] [stdout]             return None;
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let len = u32::from_le_bytes([
[INFO] [stdout]             bytes[cursor],
[INFO] [stdout]             bytes[cursor + 1],
[INFO] [stdout]             bytes[cursor + 2],
[INFO] [stdout]             bytes[cursor + 3],
[INFO] [stdout]         ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]         cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]         let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]         for _ in 0..len {
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let entry_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < end_pos {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]             cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + 2 {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let is_dir = bytes[cursor] != 0;
[INFO] [stdout]             let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]             cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let content_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + content_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let contents = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]             cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]             data.push(DirEntry {
[INFO] [stdout]                 path,
[INFO] [stdout]                 is_dir,
[INFO] [stdout]                 is_file,
[INFO] [stdout]                 contents,
[INFO] [stdout]             });
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         Some(Dir { data })
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] fn get_new_path(path: &str) -> String {
[INFO] [stdout]     let yok_path = match std::env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     let path = path.to_string().replace("\\", "/").to_string();
[INFO] [stdout]     if yok_path != "."{
[INFO] [stdout]         return path;
[INFO] [stdout]     }else {
[INFO] [stdout]         return path;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] 
[INFO] [stdout] impl Dir {
[INFO] [stdout]     /// include dir at compile time
[INFO] [stdout]     /// in default die path is current dir
[INFO] [stdout]     ///
[INFO] [stdout]     /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout]     ///
[INFO] [stdout]     /// you can also set YOK_PATH env before cargo run
[INFO] [stdout]     ///
[INFO] [stdout]     /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout]     /// ```rust
[INFO] [stdout]     ///   use yok::include_dir;
[INFO] [stdout]     ///   use yok::Dir;
[INFO] [stdout]     ///   use yok::DirEntry;
[INFO] [stdout]     ///   use yok::Bytes;
[INFO] [stdout]     ///   const DATA:&[u8] = include_dir();
[INFO] [stdout]     ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout]     ///   for entry in &dir.data{
[INFO] [stdout]     ///       if entry.is_file{
[INFO] [stdout]     ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]     ///       }else if entry.is_dir {
[INFO] [stdout]     ///           println!("{}",entry.path);
[INFO] [stdout]     ///       }
[INFO] [stdout]     ///   }
[INFO] [stdout]     ///   dir.extract("./demo");
[INFO] [stdout]     /// ```
[INFO] [stdout]     ///
[INFO] [stdout]     pub fn extract(&self, base_dir: impl ToString) ->std::io::Result<()>{
[INFO] [stdout]         std::fs::create_dir_all(base_dir.to_string()).expect("create to dir error");
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_dir {
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 std::fs::create_dir_all(path.clone()).expect("create to dir error");
[INFO] [stdout]                 if cfg!(target_os = "windows") {
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }else{
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_file {
[INFO] [stdout]                 use std::fs::{self, File, OpenOptions};
[INFO] [stdout]                 use std::io::prelude::*;
[INFO] [stdout]                 use std::os::unix::fs::OpenOptionsExt;
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 if !path.exists(){
[INFO] [stdout]                     let mut open_options = OpenOptions::new();
[INFO] [stdout]                     open_options.mode(0o777); // Set read/write permission for owner, read-only for others
[INFO] [stdout]                     let file = open_options.create(true).write(true).open(path).unwrap();
[INFO] [stdout]                     let mut file_writer = std::io::BufWriter::new(file);
[INFO] [stdout]                     file_writer.write_all(&entry.contents).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(())
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] pub const fn include_dir() -> &'static [u8] {
[INFO] [stdout]     include_bytes!("../../.yok")
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::include_dir;
[INFO] [stdout]     use yok::Bytes;
[INFO] [stdout]     use yok::Dir;
[INFO] [stdout]     use yok::DirEntry;
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             // println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             // println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] 
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] src
[INFO] [stdout] /target
[INFO] [stdout] Cargo.lock
[INFO] [stdout] .DS_Store
[INFO] [stdout] MIT License
[INFO] [stdout] 
[INFO] [stdout] Copyright (c) [year] [fullname]
[INFO] [stdout] 
[INFO] [stdout] Permission is hereby granted, free of charge, to any person obtaining a copy
[INFO] [stdout] of this software and associated documentation files (the "Software"), to deal
[INFO] [stdout] in the Software without restriction, including without limitation the rights
[INFO] [stdout] to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
[INFO] [stdout] copies of the Software, and to permit persons to whom the Software is
[INFO] [stdout] furnished to do so, subject to the following conditions:
[INFO] [stdout] 
[INFO] [stdout] The above copyright notice and this permission notice shall be included in all
[INFO] [stdout] copies or substantial portions of the Software.
[INFO] [stdout] 
[INFO] [stdout] THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
[INFO] [stdout] IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
[INFO] [stdout] FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
[INFO] [stdout] AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
[INFO] [stdout] LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
[INFO] [stdout] OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
[INFO] [stdout] SOFTWARE.
[INFO] [stdout] use std::fs::File;
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] use std::io::{BufWriter, Write};
[INFO] [stdout] use std::path::Path;
[INFO] [stdout] use zip::write::FileOptions;
[INFO] [stdout] use zip::ZipWriter;
[INFO] [stdout] use std::io::Read;
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     // Path to the directory to compress
[INFO] [stdout]     let dir_path = Path::new(".");
[INFO] [stdout] 
[INFO] [stdout]     // Path to the output ZIP file
[INFO] [stdout]     let zip_path = Path::new("app.zip");
[INFO] [stdout] 
[INFO] [stdout]     // Create a new ZIP file
[INFO] [stdout]     let file = File::create(&zip_path).unwrap();
[INFO] [stdout]     let writer = BufWriter::new(file);
[INFO] [stdout]     let mut zip = ZipWriter::new(writer);
[INFO] [stdout] 
[INFO] [stdout]     // Recursively add all files and directories in the input directory to the ZIP file
[INFO] [stdout]     add_directory_to_zip(&mut zip, dir_path, "").unwrap();
[INFO] [stdout] 
[INFO] [stdout]     // Finalize the ZIP file
[INFO] [stdout]     zip.finish().unwrap();
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Recursively adds a directory (and all its contents) to a ZipWriter
[INFO] [stdout] fn add_directory_to_zip(zip: &mut ZipWriter<BufWriter<File>>, dir_path: &Path, base_path: &str) -> zip::result::ZipResult<()> {
[INFO] [stdout]     for entry in dir_path.read_dir()? {
[INFO] [stdout]         let path = entry?.path();
[INFO] [stdout] 
[INFO] [stdout]         if path.is_dir() {
[INFO] [stdout]             // Recursively add the subdirectory
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let new_base_path = format!("{}/{}", base_path, name);
[INFO] [stdout]             add_directory_to_zip(zip, &path, &new_base_path)?;
[INFO] [stdout]         } else {
[INFO] [stdout]             // Add the file to the ZIP archive
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let options = FileOptions::default()
[INFO] [stdout]                 .compression_method(zip::CompressionMethod::Deflated)
[INFO] [stdout]                 .unix_permissions(0o755); // Set appropriate permissions for the file
[INFO] [stdout]             zip.start_file(format!("{}/{}", base_path, name), options)?;
[INFO] [stdout]             let mut file = File::open(&path)?;
[INFO] [stdout]             let mut buffer = Vec::new();
[INFO] [stdout]             file.read_to_end(&mut buffer)?;
[INFO] [stdout]             zip.write_all(&buffer)?;
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     Ok(())
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] stderr:
[INFO] [stdout] thread 'main' panicked at /opt/rustwide/workdir/src/lib.rs:236:55:
[INFO] [stdout] create to dir error: Os { code: 30, kind: ReadOnlyFilesystem, message: "Read-only file system" }
[INFO] [stdout] stack backtrace:
[INFO] [stdout]    0:     0x560c00c44395 - std::backtrace_rs::backtrace::libunwind::trace::h59d96bdb08384354
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5
[INFO] [stdout]    1:     0x560c00c44395 - std::backtrace_rs::backtrace::trace_unsynchronized::h9cf5becacfc93fba
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
[INFO] [stdout]    2:     0x560c00c44395 - std::sys_common::backtrace::_print_fmt::h10b76d10405dbd48
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:68:5
[INFO] [stdout]    3:     0x560c00c44395 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h6ed9e62a156d84e4
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:44:22
[INFO] [stdout]    4:     0x560c00c617fb - core::fmt::rt::Argument::fmt::h645c680983f03c9f
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/fmt/rt.rs:165:63
[INFO] [stdout]    5:     0x560c00c617fb - core::fmt::write::h8bcd80919a02be29
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/fmt/mod.rs:1169:21
[INFO] [stdout]    6:     0x560c00c423df - std::io::Write::write_fmt::hed769ca6c29434ec
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/io/mod.rs:1835:15
[INFO] [stdout]    7:     0x560c00c4416e - std::sys_common::backtrace::_print::h6306f131a28d62b0
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:47:5
[INFO] [stdout]    8:     0x560c00c4416e - std::sys_common::backtrace::print::h7079288e0a26dfcc
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:34:9
[INFO] [stdout]    9:     0x560c00c454d9 - std::panicking::default_hook::{{closure}}::hb063ecec81a736ba
[INFO] [stdout]   10:     0x560c00c4521d - std::panicking::default_hook::hd56ee406bf547b5c
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:298:9
[INFO] [stdout]   11:     0x560c00c45973 - std::panicking::rust_panic_with_hook::h624aa3ca42ebb8f2
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:795:13
[INFO] [stdout]   12:     0x560c00c45854 - std::panicking::begin_panic_handler::{{closure}}::hbc4e76194a5e287c
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:664:13
[INFO] [stdout]   13:     0x560c00c44859 - std::sys_common::backtrace::__rust_end_short_backtrace::h847fedc9d1ff7b6d
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:171:18
[INFO] [stdout]   14:     0x560c00c45587 - rust_begin_unwind
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:652:5
[INFO] [stdout]   15:     0x560c00c1cfb3 - core::panicking::panic_fmt::hec11a924b87ce965
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/panicking.rs:72:14
[INFO] [stdout]   16:     0x560c00c1d3c6 - core::result::unwrap_failed::h382691b96ca8c13a
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/result.rs:1654:5
[INFO] [stdout]   17:     0x560c00c20c73 - core::result::Result<T,E>::expect::h89ef1fc9f1ac74e1
[INFO] [stdout]   18:     0x560c00c1ef08 - yok::Dir::extract::hbe01f85fb3c0ddd8
[INFO] [stdout]   19:     0x560c00c21918 - rust_out::main::_doctest_main_src_lib_rs_218_0::hc38c165be7d75405
[INFO] [stdout]   20:     0x560c00c21846 - rust_out::main::h696a342f0ae7cd72
[INFO] [stdout]   21:     0x560c00c20243 - core::ops::function::FnOnce::call_once::hacff659aa20c7b40
[INFO] [stdout]   22:     0x560c00c1da26 - std::sys_common::backtrace::__rust_begin_short_backtrace::hcc6b8bea3112e884
[INFO] [stdout]   23:     0x560c00c1ec69 - std::rt::lang_start::{{closure}}::h4db0ca8543e29a47
[INFO] [stdout]   24:     0x560c00c3f1ad - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h239f0051f1e18680
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/ops/function.rs:284:13
[INFO] [stdout]   25:     0x560c00c3f1ad - std::panicking::try::do_call::hf7072797cbfea7fa
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:559:40
[INFO] [stdout]   26:     0x560c00c3f1ad - std::panicking::try::h3a37e38691a5244b
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:523:19
[INFO] [stdout]   27:     0x560c00c3f1ad - std::panic::catch_unwind::hc7cc1460e4236209
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panic.rs:149:14
[INFO] [stdout]   28:     0x560c00c3f1ad - std::rt::lang_start_internal::{{closure}}::hce632608b277cffc
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/rt.rs:141:48
[INFO] [stdout]   29:     0x560c00c3f1ad - std::panicking::try::do_call::hafc0f13e6abd9d79
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:559:40
[INFO] [stdout]   30:     0x560c00c3f1ad - std::panicking::try::h67b8f1800ef15799
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:523:19
[INFO] [stdout]   31:     0x560c00c3f1ad - std::panic::catch_unwind::he5b260dc522c68be
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panic.rs:149:14
[INFO] [stdout]   32:     0x560c00c3f1ad - std::rt::lang_start_internal::hf119eb75d1ffe221
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/rt.rs:141:20
[INFO] [stdout]   33:     0x560c00c1ec47 - std::rt::lang_start::ha9360cc92730957e
[INFO] [stdout]   34:     0x560c00c21b25 - main
[INFO] [stdout]   35:     0x7f7a43abed90 - <unknown>
[INFO] [stdout]   36:     0x7f7a43abee40 - __libc_start_main
[INFO] [stdout]   37:     0x560c00c1d5e5 - _start
[INFO] [stdout]   38:                0x0 - <unknown>
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] ---- src/lib.rs - include_dir (line 282) stdout ----
[INFO] [stdout] Test executable failed (exit status: 101).
[INFO] [stdout] 
[INFO] [stdout] stdout:
[INFO] [stdout] use std::{
[INFO] [stdout]     fs, io,
[INFO] [stdout]     path::{Path, PathBuf},
[INFO] [stdout] };
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     use std::mem;
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct DirEntry {
[INFO] [stdout]         path: String,
[INFO] [stdout]         is_dir: bool,
[INFO] [stdout]         is_file: bool,
[INFO] [stdout]         content: Vec<u8>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct Dir {
[INFO] [stdout]         data: Vec<DirEntry>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement as_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]             // Calculate the total size of the serialized data
[INFO] [stdout]             let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]                 size += entry.path.as_bytes().len();
[INFO] [stdout]                 size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]                 size += entry.content.len();
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]             // Write the length prefix
[INFO] [stdout]             bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 // Write the size prefix for this entry
[INFO] [stdout]                 bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]                 // Write the entry data
[INFO] [stdout]                 bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]                 bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]                 bytes.extend((entry.content.len() as u32).to_le_bytes().iter());
[INFO] [stdout]                 bytes.extend(entry.content.iter());
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             bytes
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement from_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         #[allow(warnings)]
[INFO] [stdout]         pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]             let mut cursor = 0;
[INFO] [stdout]             let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let len = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]             for _ in 0..len {
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let entry_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < end_pos {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]                 cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + 2 {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let is_dir = bytes[cursor] != 0;
[INFO] [stdout]                 let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]                 cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + content_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]                 cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]                 data.push(DirEntry {
[INFO] [stdout]                     path,
[INFO] [stdout]                     is_dir,
[INFO] [stdout]                     is_file,
[INFO] [stdout]                     content,
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             Some(Dir { data })
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     pub fn walk_dir(path: impl ToString) -> io::Result<Vec<PathBuf>> {
[INFO] [stdout]         let path = path.to_string();
[INFO] [stdout]         let dir = Path::new(&path);
[INFO] [stdout]         let mut files = Vec::new();
[INFO] [stdout]         for entry in fs::read_dir(dir)? {
[INFO] [stdout]             let entry = entry?;
[INFO] [stdout]             let newpath = entry.path();
[INFO] [stdout] 
[INFO] [stdout]             if newpath.is_dir() {
[INFO] [stdout]                 files.extend(walk_dir(&newpath.display())?);
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             } else {
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(files)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     use std::env;
[INFO] [stdout]     let yok_path = match env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     println!("cargo:rerun-if-env-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed=main.rs");
[INFO] [stdout]     println!("cargo:rerun-if-changed=lib.rs");
[INFO] [stdout]     let yok_path = std::path::Path::new(&yok_path);
[INFO] [stdout]     if yok_path.is_dir() {
[INFO] [stdout]         let mut res_dir: Vec<DirEntry> = vec![];
[INFO] [stdout]         let dir_list = walk_dir(yok_path.display()).expect("walk dir error");
[INFO] [stdout]         for dir in dir_list {
[INFO] [stdout]             if dir.is_file() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: false,
[INFO] [stdout]                     is_file: true,
[INFO] [stdout]                     content: std::fs::read(dir).expect("read dir error"),
[INFO] [stdout]                 });
[INFO] [stdout]             } else if dir.is_dir() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: true,
[INFO] [stdout]                     is_file: false,
[INFO] [stdout]                     content: vec![],
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         let all_dir: Dir = Dir { data: res_dir };
[INFO] [stdout]         let all_dir_bytes = all_dir.as_bytes();
[INFO] [stdout]         if let Ok(_) = std::fs::write(format!("../.yok"), all_dir_bytes){}
[INFO] [stdout]     } else {
[INFO] [stdout]         eprintln!("Environment variable 'YOK_PATH' not dir");
[INFO] [stdout]         return;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] keywords = ["include","dir","compile-time"]
[INFO] [stdout] categories = ["development-tools","game-engines","web-programming"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] categories = ["development-tools", "game-engines", "web-programming"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] keywords = ["include", "dir", "compile-time"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] name = "yok"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] # yok
[INFO] [stdout] 
[INFO] [stdout] [![Crates.io](https://img.shields.io/crates/v/yok.svg)](https://crates.io/crates/yok)
[INFO] [stdout] [![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://gitlab.com/andrew_ryan/yok)
[INFO] [stdout] [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitlab.com/andrew_ryan/yok/-/raw/master/LICENSE)
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] A crate for Embed the contents of a directory in your binary at compile time.
[INFO] [stdout] 
[INFO] [stdout] ## Getting Started
[INFO] [stdout] ```sh
[INFO] [stdout] cargo add yok
[INFO] [stdout] ```
[INFO] [stdout] ```rust
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::{Dir, Bytes,include_dir};
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] }
[INFO] [stdout] ```
[INFO] [stdout] ## Set YOK_PATH env and run or default path is cuttent dir
[INFO] [stdout] ```sh
[INFO] [stdout] # linux,macos
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] # windows cmd
[INFO] [stdout] set YOK_PATH="C:\path\to\your\directory"
[INFO] [stdout] # windows powershell
[INFO] [stdout] $env:YOK_PATH = "C:\path\to\your\directory"
[INFO] [stdout] 
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] ```
[INFO] [stdout] rm -rf path
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] # This file is automatically @generated by Cargo.
[INFO] [stdout] # It is not intended for manual editing.
[INFO] [stdout] version = 3
[INFO] [stdout] 
[INFO] [stdout] [[package]]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] 
[INFO] [stdout] image: rustlang/rust:nightly
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] push:cargo:
[INFO] [stdout]   script:
[INFO] [stdout]     - rustc --version && cargo --version  
[INFO] [stdout]     - cargo publish --allow-dirty --token cioHYTp8cpgbRbBqcJvqGF7rUIjJQSlBvH3
[INFO] [stdout] 
[INFO] [stdout] use std::{mem, path::PathBuf, str::FromStr};
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct DirEntry {
[INFO] [stdout]     pub path: String,
[INFO] [stdout]     pub is_dir: bool,
[INFO] [stdout]     pub is_file: bool,
[INFO] [stdout]     pub contents: Vec<u8>,
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct Dir {
[INFO] [stdout]     pub data: Vec<DirEntry>,
[INFO] [stdout] }
[INFO] [stdout] pub trait Bytes {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn from_bytes(&self) -> Dir;
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn into_dir(&self) -> Dir;
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for [u8] {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for Dir {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement as_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         // Calculate the total size of the serialized data
[INFO] [stdout]         let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]             size += entry.path.as_bytes().len();
[INFO] [stdout]             size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]             size += entry.contents.len();
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]         // Write the length prefix
[INFO] [stdout]         bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             // Write the size prefix for this entry
[INFO] [stdout]             bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             // Write the entry data
[INFO] [stdout]             bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]             bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]             bytes.extend((entry.contents.len() as u32).to_le_bytes().iter());
[INFO] [stdout]             bytes.extend(entry.contents.iter());
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         bytes
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement from_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]         let mut cursor = 0;
[INFO] [stdout]         let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]         if bytes.len() < len_prefix_size {
[INFO] [stdout]             return None;
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let len = u32::from_le_bytes([
[INFO] [stdout]             bytes[cursor],
[INFO] [stdout]             bytes[cursor + 1],
[INFO] [stdout]             bytes[cursor + 2],
[INFO] [stdout]             bytes[cursor + 3],
[INFO] [stdout]         ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]         cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]         let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]         for _ in 0..len {
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let entry_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < end_pos {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]             cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + 2 {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let is_dir = bytes[cursor] != 0;
[INFO] [stdout]             let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]             cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let content_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + content_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let contents = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]             cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]             data.push(DirEntry {
[INFO] [stdout]                 path,
[INFO] [stdout]                 is_dir,
[INFO] [stdout]                 is_file,
[INFO] [stdout]                 contents,
[INFO] [stdout]             });
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         Some(Dir { data })
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] fn get_new_path(path: &str) -> String {
[INFO] [stdout]     let yok_path = match std::env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     let path = path.to_string().replace("\\", "/").to_string();
[INFO] [stdout]     if yok_path != "."{
[INFO] [stdout]         return path;
[INFO] [stdout]     }else {
[INFO] [stdout]         return path;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] 
[INFO] [stdout] impl Dir {
[INFO] [stdout]     /// include dir at compile time
[INFO] [stdout]     /// in default die path is current dir
[INFO] [stdout]     ///
[INFO] [stdout]     /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout]     ///
[INFO] [stdout]     /// you can also set YOK_PATH env before cargo run
[INFO] [stdout]     ///
[INFO] [stdout]     /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout]     /// ```rust
[INFO] [stdout]     ///   use yok::include_dir;
[INFO] [stdout]     ///   use yok::Dir;
[INFO] [stdout]     ///   use yok::DirEntry;
[INFO] [stdout]     ///   use yok::Bytes;
[INFO] [stdout]     ///   const DATA:&[u8] = include_dir();
[INFO] [stdout]     ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout]     ///   for entry in &dir.data{
[INFO] [stdout]     ///       if entry.is_file{
[INFO] [stdout]     ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]     ///       }else if entry.is_dir {
[INFO] [stdout]     ///           println!("{}",entry.path);
[INFO] [stdout]     ///       }
[INFO] [stdout]     ///   }
[INFO] [stdout]     ///   dir.extract("./demo");
[INFO] [stdout]     /// ```
[INFO] [stdout]     ///
[INFO] [stdout]     pub fn extract(&self, base_dir: impl ToString) ->std::io::Result<()>{
[INFO] [stdout]         std::fs::create_dir_all(base_dir.to_string()).expect("create to dir error");
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_dir {
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 std::fs::create_dir_all(path.clone()).expect("create to dir error");
[INFO] [stdout]                 if cfg!(target_os = "windows") {
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }else{
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_file {
[INFO] [stdout]                 use std::fs::{self, File, OpenOptions};
[INFO] [stdout]                 use std::io::prelude::*;
[INFO] [stdout]                 use std::os::unix::fs::OpenOptionsExt;
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 if !path.exists(){
[INFO] [stdout]                     let mut open_options = OpenOptions::new();
[INFO] [stdout]                     open_options.mode(0o777); // Set read/write permission for owner, read-only for others
[INFO] [stdout]                     let file = open_options.create(true).write(true).open(path).unwrap();
[INFO] [stdout]                     let mut file_writer = std::io::BufWriter::new(file);
[INFO] [stdout]                     file_writer.write_all(&entry.contents).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(())
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] pub const fn include_dir() -> &'static [u8] {
[INFO] [stdout]     include_bytes!("../../.yok")
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::include_dir;
[INFO] [stdout]     use yok::Bytes;
[INFO] [stdout]     use yok::Dir;
[INFO] [stdout]     use yok::DirEntry;
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             // println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             // println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] 
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] src
[INFO] [stdout] /target
[INFO] [stdout] Cargo.lock
[INFO] [stdout] .DS_Store
[INFO] [stdout] MIT License
[INFO] [stdout] 
[INFO] [stdout] Copyright (c) [year] [fullname]
[INFO] [stdout] 
[INFO] [stdout] Permission is hereby granted, free of charge, to any person obtaining a copy
[INFO] [stdout] of this software and associated documentation files (the "Software"), to deal
[INFO] [stdout] in the Software without restriction, including without limitation the rights
[INFO] [stdout] to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
[INFO] [stdout] copies of the Software, and to permit persons to whom the Software is
[INFO] [stdout] furnished to do so, subject to the following conditions:
[INFO] [stdout] 
[INFO] [stdout] The above copyright notice and this permission notice shall be included in all
[INFO] [stdout] copies or substantial portions of the Software.
[INFO] [stdout] 
[INFO] [stdout] THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
[INFO] [stdout] IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
[INFO] [stdout] FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
[INFO] [stdout] AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
[INFO] [stdout] LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
[INFO] [stdout] OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
[INFO] [stdout] SOFTWARE.
[INFO] [stdout] use std::fs::File;
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] use std::io::{BufWriter, Write};
[INFO] [stdout] use std::path::Path;
[INFO] [stdout] use zip::write::FileOptions;
[INFO] [stdout] use zip::ZipWriter;
[INFO] [stdout] use std::io::Read;
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     // Path to the directory to compress
[INFO] [stdout]     let dir_path = Path::new(".");
[INFO] [stdout] 
[INFO] [stdout]     // Path to the output ZIP file
[INFO] [stdout]     let zip_path = Path::new("app.zip");
[INFO] [stdout] 
[INFO] [stdout]     // Create a new ZIP file
[INFO] [stdout]     let file = File::create(&zip_path).unwrap();
[INFO] [stdout]     let writer = BufWriter::new(file);
[INFO] [stdout]     let mut zip = ZipWriter::new(writer);
[INFO] [stdout] 
[INFO] [stdout]     // Recursively add all files and directories in the input directory to the ZIP file
[INFO] [stdout]     add_directory_to_zip(&mut zip, dir_path, "").unwrap();
[INFO] [stdout] 
[INFO] [stdout]     // Finalize the ZIP file
[INFO] [stdout]     zip.finish().unwrap();
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Recursively adds a directory (and all its contents) to a ZipWriter
[INFO] [stdout] fn add_directory_to_zip(zip: &mut ZipWriter<BufWriter<File>>, dir_path: &Path, base_path: &str) -> zip::result::ZipResult<()> {
[INFO] [stdout]     for entry in dir_path.read_dir()? {
[INFO] [stdout]         let path = entry?.path();
[INFO] [stdout] 
[INFO] [stdout]         if path.is_dir() {
[INFO] [stdout]             // Recursively add the subdirectory
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let new_base_path = format!("{}/{}", base_path, name);
[INFO] [stdout]             add_directory_to_zip(zip, &path, &new_base_path)?;
[INFO] [stdout]         } else {
[INFO] [stdout]             // Add the file to the ZIP archive
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let options = FileOptions::default()
[INFO] [stdout]                 .compression_method(zip::CompressionMethod::Deflated)
[INFO] [stdout]                 .unix_permissions(0o755); // Set appropriate permissions for the file
[INFO] [stdout]             zip.start_file(format!("{}/{}", base_path, name), options)?;
[INFO] [stdout]             let mut file = File::open(&path)?;
[INFO] [stdout]             let mut buffer = Vec::new();
[INFO] [stdout]             file.read_to_end(&mut buffer)?;
[INFO] [stdout]             zip.write_all(&buffer)?;
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     Ok(())
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] stderr:
[INFO] [stdout] thread 'main' panicked at /opt/rustwide/workdir/src/lib.rs:236:55:
[INFO] [stdout] create to dir error: Os { code: 30, kind: ReadOnlyFilesystem, message: "Read-only file system" }
[INFO] [stdout] stack backtrace:
[INFO] [stdout]    0:     0x55dd49387395 - std::backtrace_rs::backtrace::libunwind::trace::h59d96bdb08384354
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5
[INFO] [stdout]    1:     0x55dd49387395 - std::backtrace_rs::backtrace::trace_unsynchronized::h9cf5becacfc93fba
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
[INFO] [stdout]    2:     0x55dd49387395 - std::sys_common::backtrace::_print_fmt::h10b76d10405dbd48
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:68:5
[INFO] [stdout]    3:     0x55dd49387395 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h6ed9e62a156d84e4
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:44:22
[INFO] [stdout]    4:     0x55dd493a47fb - core::fmt::rt::Argument::fmt::h645c680983f03c9f
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/fmt/rt.rs:165:63
[INFO] [stdout]    5:     0x55dd493a47fb - core::fmt::write::h8bcd80919a02be29
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/fmt/mod.rs:1169:21
[INFO] [stdout]    6:     0x55dd493853df - std::io::Write::write_fmt::hed769ca6c29434ec
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/io/mod.rs:1835:15
[INFO] [stdout]    7:     0x55dd4938716e - std::sys_common::backtrace::_print::h6306f131a28d62b0
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:47:5
[INFO] [stdout]    8:     0x55dd4938716e - std::sys_common::backtrace::print::h7079288e0a26dfcc
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:34:9
[INFO] [stdout]    9:     0x55dd493884d9 - std::panicking::default_hook::{{closure}}::hb063ecec81a736ba
[INFO] [stderr] error: doctest failed, to rerun pass `--doc`
[INFO] [stdout]   10:     0x55dd4938821d - std::panicking::default_hook::hd56ee406bf547b5c
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:298:9
[INFO] [stdout]   11:     0x55dd49388973 - std::panicking::rust_panic_with_hook::h624aa3ca42ebb8f2
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:795:13
[INFO] [stdout]   12:     0x55dd49388854 - std::panicking::begin_panic_handler::{{closure}}::hbc4e76194a5e287c
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:664:13
[INFO] [stdout]   13:     0x55dd49387859 - std::sys_common::backtrace::__rust_end_short_backtrace::h847fedc9d1ff7b6d
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:171:18
[INFO] [stdout]   14:     0x55dd49388587 - rust_begin_unwind
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:652:5
[INFO] [stdout]   15:     0x55dd4935ffb3 - core::panicking::panic_fmt::hec11a924b87ce965
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/panicking.rs:72:14
[INFO] [stdout]   16:     0x55dd493603c6 - core::result::unwrap_failed::h382691b96ca8c13a
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/result.rs:1654:5
[INFO] [stdout]   17:     0x55dd49363c73 - core::result::Result<T,E>::expect::h89ef1fc9f1ac74e1
[INFO] [stdout]   18:     0x55dd49361f08 - yok::Dir::extract::hbe01f85fb3c0ddd8
[INFO] [stdout]   19:     0x55dd49364918 - rust_out::main::_doctest_main_src_lib_rs_282_0::hdd8940a51c9b0e6f
[INFO] [stdout]   20:     0x55dd49364846 - rust_out::main::h696a342f0ae7cd72
[INFO] [stdout]   21:     0x55dd49363243 - core::ops::function::FnOnce::call_once::hacff659aa20c7b40
[INFO] [stdout]   22:     0x55dd49360a26 - std::sys_common::backtrace::__rust_begin_short_backtrace::hcc6b8bea3112e884
[INFO] [stdout]   23:     0x55dd49361c69 - std::rt::lang_start::{{closure}}::h4db0ca8543e29a47
[INFO] [stdout]   24:     0x55dd493821ad - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h239f0051f1e18680
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/ops/function.rs:284:13
[INFO] [stdout]   25:     0x55dd493821ad - std::panicking::try::do_call::hf7072797cbfea7fa
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:559:40
[INFO] [stdout]   26:     0x55dd493821ad - std::panicking::try::h3a37e38691a5244b
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:523:19
[INFO] [stdout]   27:     0x55dd493821ad - std::panic::catch_unwind::hc7cc1460e4236209
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panic.rs:149:14
[INFO] [stdout]   28:     0x55dd493821ad - std::rt::lang_start_internal::{{closure}}::hce632608b277cffc
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/rt.rs:141:48
[INFO] [stdout]   29:     0x55dd493821ad - std::panicking::try::do_call::hafc0f13e6abd9d79
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:559:40
[INFO] [stdout]   30:     0x55dd493821ad - std::panicking::try::h67b8f1800ef15799
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:523:19
[INFO] [stdout]   31:     0x55dd493821ad - std::panic::catch_unwind::he5b260dc522c68be
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panic.rs:149:14
[INFO] [stdout]   32:     0x55dd493821ad - std::rt::lang_start_internal::hf119eb75d1ffe221
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/rt.rs:141:20
[INFO] [stdout]   33:     0x55dd49361c47 - std::rt::lang_start::ha9360cc92730957e
[INFO] [stdout]   34:     0x55dd49364b25 - main
[INFO] [stdout]   35:     0x7f4815a9ed90 - <unknown>
[INFO] [stdout]   36:     0x7f4815a9ee40 - __libc_start_main
[INFO] [stdout]   37:     0x55dd493605e5 - _start
[INFO] [stdout]   38:                0x0 - <unknown>
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] ---- src/lib.rs - DirEntry (line 10) stdout ----
[INFO] [stdout] Test executable failed (exit status: 101).
[INFO] [stdout] 
[INFO] [stdout] stdout:
[INFO] [stdout] use std::{
[INFO] [stdout]     fs, io,
[INFO] [stdout]     path::{Path, PathBuf},
[INFO] [stdout] };
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     use std::mem;
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct DirEntry {
[INFO] [stdout]         path: String,
[INFO] [stdout]         is_dir: bool,
[INFO] [stdout]         is_file: bool,
[INFO] [stdout]         content: Vec<u8>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct Dir {
[INFO] [stdout]         data: Vec<DirEntry>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement as_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]             // Calculate the total size of the serialized data
[INFO] [stdout]             let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]                 size += entry.path.as_bytes().len();
[INFO] [stdout]                 size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]                 size += entry.content.len();
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]             // Write the length prefix
[INFO] [stdout]             bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 // Write the size prefix for this entry
[INFO] [stdout]                 bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]                 // Write the entry data
[INFO] [stdout]                 bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]                 bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]                 bytes.extend((entry.content.len() as u32).to_le_bytes().iter());
[INFO] [stdout]                 bytes.extend(entry.content.iter());
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             bytes
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement from_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         #[allow(warnings)]
[INFO] [stdout]         pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]             let mut cursor = 0;
[INFO] [stdout]             let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let len = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]             for _ in 0..len {
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let entry_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < end_pos {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]                 cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + 2 {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let is_dir = bytes[cursor] != 0;
[INFO] [stdout]                 let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]                 cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + content_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]                 cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]                 data.push(DirEntry {
[INFO] [stdout]                     path,
[INFO] [stdout]                     is_dir,
[INFO] [stdout]                     is_file,
[INFO] [stdout]                     content,
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             Some(Dir { data })
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     pub fn walk_dir(path: impl ToString) -> io::Result<Vec<PathBuf>> {
[INFO] [stdout]         let path = path.to_string();
[INFO] [stdout]         let dir = Path::new(&path);
[INFO] [stdout]         let mut files = Vec::new();
[INFO] [stdout]         for entry in fs::read_dir(dir)? {
[INFO] [stdout]             let entry = entry?;
[INFO] [stdout]             let newpath = entry.path();
[INFO] [stdout] 
[INFO] [stdout]             if newpath.is_dir() {
[INFO] [stdout]                 files.extend(walk_dir(&newpath.display())?);
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             } else {
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(files)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     use std::env;
[INFO] [stdout]     let yok_path = match env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     println!("cargo:rerun-if-env-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed=main.rs");
[INFO] [stdout]     println!("cargo:rerun-if-changed=lib.rs");
[INFO] [stdout]     let yok_path = std::path::Path::new(&yok_path);
[INFO] [stdout]     if yok_path.is_dir() {
[INFO] [stdout]         let mut res_dir: Vec<DirEntry> = vec![];
[INFO] [stdout]         let dir_list = walk_dir(yok_path.display()).expect("walk dir error");
[INFO] [stdout]         for dir in dir_list {
[INFO] [stdout]             if dir.is_file() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: false,
[INFO] [stdout]                     is_file: true,
[INFO] [stdout]                     content: std::fs::read(dir).expect("read dir error"),
[INFO] [stdout]                 });
[INFO] [stdout]             } else if dir.is_dir() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: true,
[INFO] [stdout]                     is_file: false,
[INFO] [stdout]                     content: vec![],
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         let all_dir: Dir = Dir { data: res_dir };
[INFO] [stdout]         let all_dir_bytes = all_dir.as_bytes();
[INFO] [stdout]         if let Ok(_) = std::fs::write(format!("../.yok"), all_dir_bytes){}
[INFO] [stdout]     } else {
[INFO] [stdout]         eprintln!("Environment variable 'YOK_PATH' not dir");
[INFO] [stdout]         return;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] keywords = ["include","dir","compile-time"]
[INFO] [stdout] categories = ["development-tools","game-engines","web-programming"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] categories = ["development-tools", "game-engines", "web-programming"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] keywords = ["include", "dir", "compile-time"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] name = "yok"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] # yok
[INFO] [stdout] 
[INFO] [stdout] [![Crates.io](https://img.shields.io/crates/v/yok.svg)](https://crates.io/crates/yok)
[INFO] [stdout] [![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://gitlab.com/andrew_ryan/yok)
[INFO] [stdout] [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitlab.com/andrew_ryan/yok/-/raw/master/LICENSE)
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] A crate for Embed the contents of a directory in your binary at compile time.
[INFO] [stdout] 
[INFO] [stdout] ## Getting Started
[INFO] [stdout] ```sh
[INFO] [stdout] cargo add yok
[INFO] [stdout] ```
[INFO] [stdout] ```rust
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::{Dir, Bytes,include_dir};
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] }
[INFO] [stdout] ```
[INFO] [stdout] ## Set YOK_PATH env and run or default path is cuttent dir
[INFO] [stdout] ```sh
[INFO] [stdout] # linux,macos
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] # windows cmd
[INFO] [stdout] set YOK_PATH="C:\path\to\your\directory"
[INFO] [stdout] # windows powershell
[INFO] [stdout] $env:YOK_PATH = "C:\path\to\your\directory"
[INFO] [stdout] 
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] ```
[INFO] [stdout] rm -rf path
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] # This file is automatically @generated by Cargo.
[INFO] [stdout] # It is not intended for manual editing.
[INFO] [stdout] version = 3
[INFO] [stdout] 
[INFO] [stdout] [[package]]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] 
[INFO] [stdout] image: rustlang/rust:nightly
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] push:cargo:
[INFO] [stdout]   script:
[INFO] [stdout]     - rustc --version && cargo --version  
[INFO] [stdout]     - cargo publish --allow-dirty --token cioHYTp8cpgbRbBqcJvqGF7rUIjJQSlBvH3
[INFO] [stdout] 
[INFO] [stdout] use std::{mem, path::PathBuf, str::FromStr};
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct DirEntry {
[INFO] [stdout]     pub path: String,
[INFO] [stdout]     pub is_dir: bool,
[INFO] [stdout]     pub is_file: bool,
[INFO] [stdout]     pub contents: Vec<u8>,
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct Dir {
[INFO] [stdout]     pub data: Vec<DirEntry>,
[INFO] [stdout] }
[INFO] [stdout] pub trait Bytes {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn from_bytes(&self) -> Dir;
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn into_dir(&self) -> Dir;
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for [u8] {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for Dir {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement as_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         // Calculate the total size of the serialized data
[INFO] [stdout]         let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]             size += entry.path.as_bytes().len();
[INFO] [stdout]             size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]             size += entry.contents.len();
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]         // Write the length prefix
[INFO] [stdout]         bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             // Write the size prefix for this entry
[INFO] [stdout]             bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             // Write the entry data
[INFO] [stdout]             bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]             bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]             bytes.extend((entry.contents.len() as u32).to_le_bytes().iter());
[INFO] [stdout]             bytes.extend(entry.contents.iter());
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         bytes
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement from_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]         let mut cursor = 0;
[INFO] [stdout]         let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]         if bytes.len() < len_prefix_size {
[INFO] [stdout]             return None;
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let len = u32::from_le_bytes([
[INFO] [stdout]             bytes[cursor],
[INFO] [stdout]             bytes[cursor + 1],
[INFO] [stdout]             bytes[cursor + 2],
[INFO] [stdout]             bytes[cursor + 3],
[INFO] [stdout]         ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]         cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]         let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]         for _ in 0..len {
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let entry_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < end_pos {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]             cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + 2 {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let is_dir = bytes[cursor] != 0;
[INFO] [stdout]             let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]             cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let content_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + content_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let contents = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]             cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]             data.push(DirEntry {
[INFO] [stdout]                 path,
[INFO] [stdout]                 is_dir,
[INFO] [stdout]                 is_file,
[INFO] [stdout]                 contents,
[INFO] [stdout]             });
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         Some(Dir { data })
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] fn get_new_path(path: &str) -> String {
[INFO] [stdout]     let yok_path = match std::env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     let path = path.to_string().replace("\\", "/").to_string();
[INFO] [stdout]     if yok_path != "."{
[INFO] [stdout]         return path;
[INFO] [stdout]     }else {
[INFO] [stdout]         return path;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] 
[INFO] [stdout] impl Dir {
[INFO] [stdout]     /// include dir at compile time
[INFO] [stdout]     /// in default die path is current dir
[INFO] [stdout]     ///
[INFO] [stdout]     /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout]     ///
[INFO] [stdout]     /// you can also set YOK_PATH env before cargo run
[INFO] [stdout]     ///
[INFO] [stdout]     /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout]     /// ```rust
[INFO] [stdout]     ///   use yok::include_dir;
[INFO] [stdout]     ///   use yok::Dir;
[INFO] [stdout]     ///   use yok::DirEntry;
[INFO] [stdout]     ///   use yok::Bytes;
[INFO] [stdout]     ///   const DATA:&[u8] = include_dir();
[INFO] [stdout]     ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout]     ///   for entry in &dir.data{
[INFO] [stdout]     ///       if entry.is_file{
[INFO] [stdout]     ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]     ///       }else if entry.is_dir {
[INFO] [stdout]     ///           println!("{}",entry.path);
[INFO] [stdout]     ///       }
[INFO] [stdout]     ///   }
[INFO] [stdout]     ///   dir.extract("./demo");
[INFO] [stdout]     /// ```
[INFO] [stdout]     ///
[INFO] [stdout]     pub fn extract(&self, base_dir: impl ToString) ->std::io::Result<()>{
[INFO] [stdout]         std::fs::create_dir_all(base_dir.to_string()).expect("create to dir error");
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_dir {
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 std::fs::create_dir_all(path.clone()).expect("create to dir error");
[INFO] [stdout]                 if cfg!(target_os = "windows") {
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }else{
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_file {
[INFO] [stdout]                 use std::fs::{self, File, OpenOptions};
[INFO] [stdout]                 use std::io::prelude::*;
[INFO] [stdout]                 use std::os::unix::fs::OpenOptionsExt;
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 if !path.exists(){
[INFO] [stdout]                     let mut open_options = OpenOptions::new();
[INFO] [stdout]                     open_options.mode(0o777); // Set read/write permission for owner, read-only for others
[INFO] [stdout]                     let file = open_options.create(true).write(true).open(path).unwrap();
[INFO] [stdout]                     let mut file_writer = std::io::BufWriter::new(file);
[INFO] [stdout]                     file_writer.write_all(&entry.contents).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(())
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] pub const fn include_dir() -> &'static [u8] {
[INFO] [stdout]     include_bytes!("../../.yok")
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::include_dir;
[INFO] [stdout]     use yok::Bytes;
[INFO] [stdout]     use yok::Dir;
[INFO] [stdout]     use yok::DirEntry;
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             // println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             // println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] 
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] src
[INFO] [stdout] /target
[INFO] [stdout] Cargo.lock
[INFO] [stdout] .DS_Store
[INFO] [stdout] MIT License
[INFO] [stdout] 
[INFO] [stdout] Copyright (c) [year] [fullname]
[INFO] [stdout] 
[INFO] [stdout] Permission is hereby granted, free of charge, to any person obtaining a copy
[INFO] [stdout] of this software and associated documentation files (the "Software"), to deal
[INFO] [stdout] in the Software without restriction, including without limitation the rights
[INFO] [stdout] to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
[INFO] [stdout] copies of the Software, and to permit persons to whom the Software is
[INFO] [stdout] furnished to do so, subject to the following conditions:
[INFO] [stdout] 
[INFO] [stdout] The above copyright notice and this permission notice shall be included in all
[INFO] [stdout] copies or substantial portions of the Software.
[INFO] [stdout] 
[INFO] [stdout] THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
[INFO] [stdout] IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
[INFO] [stdout] FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
[INFO] [stdout] AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
[INFO] [stdout] LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
[INFO] [stdout] OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
[INFO] [stdout] SOFTWARE.
[INFO] [stdout] use std::fs::File;
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] use std::io::{BufWriter, Write};
[INFO] [stdout] use std::path::Path;
[INFO] [stdout] use zip::write::FileOptions;
[INFO] [stdout] use zip::ZipWriter;
[INFO] [stdout] use std::io::Read;
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     // Path to the directory to compress
[INFO] [stdout]     let dir_path = Path::new(".");
[INFO] [stdout] 
[INFO] [stdout]     // Path to the output ZIP file
[INFO] [stdout]     let zip_path = Path::new("app.zip");
[INFO] [stdout] 
[INFO] [stdout]     // Create a new ZIP file
[INFO] [stdout]     let file = File::create(&zip_path).unwrap();
[INFO] [stdout]     let writer = BufWriter::new(file);
[INFO] [stdout]     let mut zip = ZipWriter::new(writer);
[INFO] [stdout] 
[INFO] [stdout]     // Recursively add all files and directories in the input directory to the ZIP file
[INFO] [stdout]     add_directory_to_zip(&mut zip, dir_path, "").unwrap();
[INFO] [stdout] 
[INFO] [stdout]     // Finalize the ZIP file
[INFO] [stdout]     zip.finish().unwrap();
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Recursively adds a directory (and all its contents) to a ZipWriter
[INFO] [stdout] fn add_directory_to_zip(zip: &mut ZipWriter<BufWriter<File>>, dir_path: &Path, base_path: &str) -> zip::result::ZipResult<()> {
[INFO] [stdout]     for entry in dir_path.read_dir()? {
[INFO] [stdout]         let path = entry?.path();
[INFO] [stdout] 
[INFO] [stdout]         if path.is_dir() {
[INFO] [stdout]             // Recursively add the subdirectory
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let new_base_path = format!("{}/{}", base_path, name);
[INFO] [stdout]             add_directory_to_zip(zip, &path, &new_base_path)?;
[INFO] [stdout]         } else {
[INFO] [stdout]             // Add the file to the ZIP archive
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let options = FileOptions::default()
[INFO] [stdout]                 .compression_method(zip::CompressionMethod::Deflated)
[INFO] [stdout]                 .unix_permissions(0o755); // Set appropriate permissions for the file
[INFO] [stdout]             zip.start_file(format!("{}/{}", base_path, name), options)?;
[INFO] [stdout]             let mut file = File::open(&path)?;
[INFO] [stdout]             let mut buffer = Vec::new();
[INFO] [stdout]             file.read_to_end(&mut buffer)?;
[INFO] [stdout]             zip.write_all(&buffer)?;
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     Ok(())
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] stderr:
[INFO] [stdout] thread 'main' panicked at /opt/rustwide/workdir/src/lib.rs:236:55:
[INFO] [stdout] create to dir error: Os { code: 30, kind: ReadOnlyFilesystem, message: "Read-only file system" }
[INFO] [stdout] stack backtrace:
[INFO] [stdout]    0:     0x55e8e9d1e395 - std::backtrace_rs::backtrace::libunwind::trace::h59d96bdb08384354
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5
[INFO] [stdout]    1:     0x55e8e9d1e395 - std::backtrace_rs::backtrace::trace_unsynchronized::h9cf5becacfc93fba
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
[INFO] [stdout]    2:     0x55e8e9d1e395 - std::sys_common::backtrace::_print_fmt::h10b76d10405dbd48
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:68:5
[INFO] [stdout]    3:     0x55e8e9d1e395 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h6ed9e62a156d84e4
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:44:22
[INFO] [stdout]    4:     0x55e8e9d3b7fb - core::fmt::rt::Argument::fmt::h645c680983f03c9f
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/fmt/rt.rs:165:63
[INFO] [stdout]    5:     0x55e8e9d3b7fb - core::fmt::write::h8bcd80919a02be29
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/fmt/mod.rs:1169:21
[INFO] [stdout]    6:     0x55e8e9d1c3df - std::io::Write::write_fmt::hed769ca6c29434ec
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/io/mod.rs:1835:15
[INFO] [stdout]    7:     0x55e8e9d1e16e - std::sys_common::backtrace::_print::h6306f131a28d62b0
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:47:5
[INFO] [stdout]    8:     0x55e8e9d1e16e - std::sys_common::backtrace::print::h7079288e0a26dfcc
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:34:9
[INFO] [stdout]    9:     0x55e8e9d1f4d9 - std::panicking::default_hook::{{closure}}::hb063ecec81a736ba
[INFO] [stdout]   10:     0x55e8e9d1f21d - std::panicking::default_hook::hd56ee406bf547b5c
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:298:9
[INFO] [stdout]   11:     0x55e8e9d1f973 - std::panicking::rust_panic_with_hook::h624aa3ca42ebb8f2
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:795:13
[INFO] [stdout]   12:     0x55e8e9d1f854 - std::panicking::begin_panic_handler::{{closure}}::hbc4e76194a5e287c
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:664:13
[INFO] [stdout]   13:     0x55e8e9d1e859 - std::sys_common::backtrace::__rust_end_short_backtrace::h847fedc9d1ff7b6d
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/sys_common/backtrace.rs:171:18
[INFO] [stdout]   14:     0x55e8e9d1f587 - rust_begin_unwind
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:652:5
[INFO] [stdout]   15:     0x55e8e9cf6fb3 - core::panicking::panic_fmt::hec11a924b87ce965
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/panicking.rs:72:14
[INFO] [stdout]   16:     0x55e8e9cf73c6 - core::result::unwrap_failed::h382691b96ca8c13a
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/result.rs:1654:5
[INFO] [stdout]   17:     0x55e8e9cfac73 - core::result::Result<T,E>::expect::h89ef1fc9f1ac74e1
[INFO] [stdout]   18:     0x55e8e9cf8f08 - yok::Dir::extract::hbe01f85fb3c0ddd8
[INFO] [stdout]   19:     0x55e8e9cfb918 - rust_out::main::_doctest_main_src_lib_rs_10_0::h347af604ac52de5d
[INFO] [stdout]   20:     0x55e8e9cfb846 - rust_out::main::h696a342f0ae7cd72
[INFO] [stdout]   21:     0x55e8e9cfa243 - core::ops::function::FnOnce::call_once::hacff659aa20c7b40
[INFO] [stdout]   22:     0x55e8e9cf7a26 - std::sys_common::backtrace::__rust_begin_short_backtrace::hcc6b8bea3112e884
[INFO] [stdout]   23:     0x55e8e9cf8c69 - std::rt::lang_start::{{closure}}::h4db0ca8543e29a47
[INFO] [stdout]   24:     0x55e8e9d191ad - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h239f0051f1e18680
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/core/src/ops/function.rs:284:13
[INFO] [stdout]   25:     0x55e8e9d191ad - std::panicking::try::do_call::hf7072797cbfea7fa
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:559:40
[INFO] [stdout]   26:     0x55e8e9d191ad - std::panicking::try::h3a37e38691a5244b
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:523:19
[INFO] [stdout]   27:     0x55e8e9d191ad - std::panic::catch_unwind::hc7cc1460e4236209
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panic.rs:149:14
[INFO] [stdout]   28:     0x55e8e9d191ad - std::rt::lang_start_internal::{{closure}}::hce632608b277cffc
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/rt.rs:141:48
[INFO] [stdout]   29:     0x55e8e9d191ad - std::panicking::try::do_call::hafc0f13e6abd9d79
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:559:40
[INFO] [stdout]   30:     0x55e8e9d191ad - std::panicking::try::h67b8f1800ef15799
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panicking.rs:523:19
[INFO] [stdout]   31:     0x55e8e9d191ad - std::panic::catch_unwind::he5b260dc522c68be
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/panic.rs:149:14
[INFO] [stdout]   32:     0x55e8e9d191ad - std::rt::lang_start_internal::hf119eb75d1ffe221
[INFO] [stdout]                                at /rustc/1871252fc8bb672d40787e67404e6eaae7059369/library/std/src/rt.rs:141:20
[INFO] [stdout]   33:     0x55e8e9cf8c47 - std::rt::lang_start::ha9360cc92730957e
[INFO] [stdout]   34:     0x55e8e9cfbb25 - main
[INFO] [stdout]   35:     0x7f37d7d6bd90 - <unknown>
[INFO] [stdout]   36:     0x7f37d7d6be40 - __libc_start_main
[INFO] [stdout]   37:     0x55e8e9cf75e5 - _start
[INFO] [stdout]   38:                0x0 - <unknown>
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] failures:
[INFO] [stdout]     src/lib.rs - Dir::extract (line 218)
[INFO] [stdout]     src/lib.rs - DirEntry (line 10)
[INFO] [stdout]     src/lib.rs - include_dir (line 282)
[INFO] [stdout] 
[INFO] [stdout] test result: FAILED. 0 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.39s
[INFO] [stdout] 
[INFO] running `Command { std: "docker" "inspect" "2210901f4c2e473373cb7078b0bd87cd96224f830c2945e87480e72963aab834", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "2210901f4c2e473373cb7078b0bd87cd96224f830c2945e87480e72963aab834", kill_on_drop: false }`
[INFO] [stdout] 2210901f4c2e473373cb7078b0bd87cd96224f830c2945e87480e72963aab834
[INFO] testing yok-0.1.9 against try#b642703cf9526da1e72c0b6755753b939a9c6b6d for pr-125151
[INFO] extracting crate yok 0.1.9 into /workspace/builds/worker-3-tc2/source
[INFO] validating manifest of crates.io crate yok 0.1.9 on toolchain b642703cf9526da1e72c0b6755753b939a9c6b6d
[INFO] running `Command { std: CARGO_HOME="/workspace/cargo-home" RUSTUP_HOME="/workspace/rustup-home" "/workspace/cargo-home/bin/cargo" "+b642703cf9526da1e72c0b6755753b939a9c6b6d" "metadata" "--manifest-path" "Cargo.toml" "--no-deps", kill_on_drop: false }`
[INFO] started tweaking crates.io crate yok 0.1.9
[INFO] finished tweaking crates.io crate yok 0.1.9
[INFO] tweaked toml for crates.io crate yok 0.1.9 written to /workspace/builds/worker-3-tc2/source/Cargo.toml
[INFO] crate crates.io crate yok 0.1.9 already has a lockfile, it will not be regenerated
[INFO] running `Command { std: CARGO_HOME="/workspace/cargo-home" RUSTUP_HOME="/workspace/rustup-home" "/workspace/cargo-home/bin/cargo" "+b642703cf9526da1e72c0b6755753b939a9c6b6d" "fetch" "--manifest-path" "Cargo.toml", kill_on_drop: false }`
[INFO] [stderr]     Blocking waiting for file lock on package cache
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc2/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc2/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--user" "0:0" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:59a85a07ab18ca8720692f8e61effa1c651d9e2ca591e072c2b212bb91a6b8b5" "/opt/rustwide/cargo-home/bin/cargo" "+b642703cf9526da1e72c0b6755753b939a9c6b6d" "metadata" "--no-deps" "--format-version=1", kill_on_drop: false }`
[INFO] [stdout] 198c53b4caa4161ad563236fad32643c11095f798c33588310dbfbe8ba4eb680
[INFO] running `Command { std: "docker" "start" "-a" "198c53b4caa4161ad563236fad32643c11095f798c33588310dbfbe8ba4eb680", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "inspect" "198c53b4caa4161ad563236fad32643c11095f798c33588310dbfbe8ba4eb680", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "198c53b4caa4161ad563236fad32643c11095f798c33588310dbfbe8ba4eb680", kill_on_drop: false }`
[INFO] [stdout] 198c53b4caa4161ad563236fad32643c11095f798c33588310dbfbe8ba4eb680
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc2/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc2/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=forbid" "-e" "RUSTDOCFLAGS=--cap-lints=forbid" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--user" "0:0" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:59a85a07ab18ca8720692f8e61effa1c651d9e2ca591e072c2b212bb91a6b8b5" "/opt/rustwide/cargo-home/bin/cargo" "+b642703cf9526da1e72c0b6755753b939a9c6b6d" "build" "--frozen" "--message-format=json", kill_on_drop: false }`
[INFO] [stdout] 27e61de7f7f97ba72fff39f1ae59f52d840319ad1e0ba9849259130c55dc37cd
[INFO] running `Command { std: "docker" "start" "-a" "27e61de7f7f97ba72fff39f1ae59f52d840319ad1e0ba9849259130c55dc37cd", kill_on_drop: false }`
[INFO] [stderr]    Compiling yok v0.1.9 (/opt/rustwide/workdir)
[INFO] [stderr]     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.73s
[INFO] running `Command { std: "docker" "inspect" "27e61de7f7f97ba72fff39f1ae59f52d840319ad1e0ba9849259130c55dc37cd", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "27e61de7f7f97ba72fff39f1ae59f52d840319ad1e0ba9849259130c55dc37cd", kill_on_drop: false }`
[INFO] [stdout] 27e61de7f7f97ba72fff39f1ae59f52d840319ad1e0ba9849259130c55dc37cd
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc2/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc2/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=forbid" "-e" "RUSTDOCFLAGS=--cap-lints=forbid" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--user" "0:0" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:59a85a07ab18ca8720692f8e61effa1c651d9e2ca591e072c2b212bb91a6b8b5" "/opt/rustwide/cargo-home/bin/cargo" "+b642703cf9526da1e72c0b6755753b939a9c6b6d" "test" "--frozen" "--no-run" "--message-format=json", kill_on_drop: false }`
[INFO] [stdout] d2db2b8c0b28d4000f61d8cdd943557c68c44bad09f30f428f3ef5a7796ce2e1
[INFO] running `Command { std: "docker" "start" "-a" "d2db2b8c0b28d4000f61d8cdd943557c68c44bad09f30f428f3ef5a7796ce2e1", kill_on_drop: false }`
[INFO] [stderr]    Compiling yok v0.1.9 (/opt/rustwide/workdir)
[INFO] [stderr]     Finished `test` profile [unoptimized + debuginfo] target(s) in 0.57s
[INFO] running `Command { std: "docker" "inspect" "d2db2b8c0b28d4000f61d8cdd943557c68c44bad09f30f428f3ef5a7796ce2e1", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "d2db2b8c0b28d4000f61d8cdd943557c68c44bad09f30f428f3ef5a7796ce2e1", kill_on_drop: false }`
[INFO] [stdout] d2db2b8c0b28d4000f61d8cdd943557c68c44bad09f30f428f3ef5a7796ce2e1
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc2/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-3-tc2/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=forbid" "-e" "RUSTDOCFLAGS=--cap-lints=forbid" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--user" "0:0" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:59a85a07ab18ca8720692f8e61effa1c651d9e2ca591e072c2b212bb91a6b8b5" "/opt/rustwide/cargo-home/bin/cargo" "+b642703cf9526da1e72c0b6755753b939a9c6b6d" "test" "--frozen", kill_on_drop: false }`
[INFO] [stdout] e76c937cc21701deaabf5b46b1346000c16fa080e14f4f3a7cb3ae9c9e194891
[INFO] running `Command { std: "docker" "start" "-a" "e76c937cc21701deaabf5b46b1346000c16fa080e14f4f3a7cb3ae9c9e194891", kill_on_drop: false }`
[INFO] [stderr]    Compiling yok v0.1.9 (/opt/rustwide/workdir)
[INFO] [stderr]     Finished `test` profile [unoptimized + debuginfo] target(s) in 0.55s
[INFO] [stdout] 
[INFO] [stderr]      Running unittests src/lib.rs (/opt/rustwide/target/debug/deps/yok-52d48ae7f605bbb8)
[INFO] [stdout] running 0 tests
[INFO] [stderr]      Running unittests src/main.rs (/opt/rustwide/target/debug/deps/yok-221974d0057d098f)
[INFO] [stdout] 
[INFO] [stdout] test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] running 0 tests
[INFO] [stdout] 
[INFO] [stdout] test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
[INFO] [stdout] 
[INFO] [stderr]    Doc-tests yok
[INFO] [stdout] 
[INFO] [stdout] running 3 tests
[INFO] [stdout] test src/lib.rs - DirEntry (line 10) ... FAILED
[INFO] [stdout] test src/lib.rs - include_dir (line 282) ... FAILED
[INFO] [stderr] error: doctest failed, to rerun pass `--doc`
[INFO] [stdout] test src/lib.rs - Dir::extract (line 218) ... FAILED
[INFO] [stdout] 
[INFO] [stdout] failures:
[INFO] [stdout] 
[INFO] [stdout] ---- src/lib.rs - DirEntry (line 10) stdout ----
[INFO] [stdout] Test executable failed (exit status: 101).
[INFO] [stdout] 
[INFO] [stdout] stdout:
[INFO] [stdout] use std::{
[INFO] [stdout]     fs, io,
[INFO] [stdout]     path::{Path, PathBuf},
[INFO] [stdout] };
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     use std::mem;
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct DirEntry {
[INFO] [stdout]         path: String,
[INFO] [stdout]         is_dir: bool,
[INFO] [stdout]         is_file: bool,
[INFO] [stdout]         content: Vec<u8>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct Dir {
[INFO] [stdout]         data: Vec<DirEntry>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement as_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]             // Calculate the total size of the serialized data
[INFO] [stdout]             let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]                 size += entry.path.as_bytes().len();
[INFO] [stdout]                 size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]                 size += entry.content.len();
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]             // Write the length prefix
[INFO] [stdout]             bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 // Write the size prefix for this entry
[INFO] [stdout]                 bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]                 // Write the entry data
[INFO] [stdout]                 bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]                 bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]                 bytes.extend((entry.content.len() as u32).to_le_bytes().iter());
[INFO] [stdout]                 bytes.extend(entry.content.iter());
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             bytes
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement from_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         #[allow(warnings)]
[INFO] [stdout]         pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]             let mut cursor = 0;
[INFO] [stdout]             let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let len = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]             for _ in 0..len {
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let entry_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < end_pos {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]                 cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + 2 {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let is_dir = bytes[cursor] != 0;
[INFO] [stdout]                 let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]                 cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + content_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]                 cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]                 data.push(DirEntry {
[INFO] [stdout]                     path,
[INFO] [stdout]                     is_dir,
[INFO] [stdout]                     is_file,
[INFO] [stdout]                     content,
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             Some(Dir { data })
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     pub fn walk_dir(path: impl ToString) -> io::Result<Vec<PathBuf>> {
[INFO] [stdout]         let path = path.to_string();
[INFO] [stdout]         let dir = Path::new(&path);
[INFO] [stdout]         let mut files = Vec::new();
[INFO] [stdout]         for entry in fs::read_dir(dir)? {
[INFO] [stdout]             let entry = entry?;
[INFO] [stdout]             let newpath = entry.path();
[INFO] [stdout] 
[INFO] [stdout]             if newpath.is_dir() {
[INFO] [stdout]                 files.extend(walk_dir(&newpath.display())?);
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             } else {
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(files)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     use std::env;
[INFO] [stdout]     let yok_path = match env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     println!("cargo:rerun-if-env-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed=main.rs");
[INFO] [stdout]     println!("cargo:rerun-if-changed=lib.rs");
[INFO] [stdout]     let yok_path = std::path::Path::new(&yok_path);
[INFO] [stdout]     if yok_path.is_dir() {
[INFO] [stdout]         let mut res_dir: Vec<DirEntry> = vec![];
[INFO] [stdout]         let dir_list = walk_dir(yok_path.display()).expect("walk dir error");
[INFO] [stdout]         for dir in dir_list {
[INFO] [stdout]             if dir.is_file() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: false,
[INFO] [stdout]                     is_file: true,
[INFO] [stdout]                     content: std::fs::read(dir).expect("read dir error"),
[INFO] [stdout]                 });
[INFO] [stdout]             } else if dir.is_dir() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: true,
[INFO] [stdout]                     is_file: false,
[INFO] [stdout]                     content: vec![],
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         let all_dir: Dir = Dir { data: res_dir };
[INFO] [stdout]         let all_dir_bytes = all_dir.as_bytes();
[INFO] [stdout]         if let Ok(_) = std::fs::write(format!("../.yok"), all_dir_bytes){}
[INFO] [stdout]     } else {
[INFO] [stdout]         eprintln!("Environment variable 'YOK_PATH' not dir");
[INFO] [stdout]         return;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] keywords = ["include","dir","compile-time"]
[INFO] [stdout] categories = ["development-tools","game-engines","web-programming"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] categories = ["development-tools", "game-engines", "web-programming"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] keywords = ["include", "dir", "compile-time"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] name = "yok"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] # yok
[INFO] [stdout] 
[INFO] [stdout] [![Crates.io](https://img.shields.io/crates/v/yok.svg)](https://crates.io/crates/yok)
[INFO] [stdout] [![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://gitlab.com/andrew_ryan/yok)
[INFO] [stdout] [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitlab.com/andrew_ryan/yok/-/raw/master/LICENSE)
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] A crate for Embed the contents of a directory in your binary at compile time.
[INFO] [stdout] 
[INFO] [stdout] ## Getting Started
[INFO] [stdout] ```sh
[INFO] [stdout] cargo add yok
[INFO] [stdout] ```
[INFO] [stdout] ```rust
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::{Dir, Bytes,include_dir};
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] }
[INFO] [stdout] ```
[INFO] [stdout] ## Set YOK_PATH env and run or default path is cuttent dir
[INFO] [stdout] ```sh
[INFO] [stdout] # linux,macos
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] # windows cmd
[INFO] [stdout] set YOK_PATH="C:\path\to\your\directory"
[INFO] [stdout] # windows powershell
[INFO] [stdout] $env:YOK_PATH = "C:\path\to\your\directory"
[INFO] [stdout] 
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] ```
[INFO] [stdout] rm -rf path
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] # This file is automatically @generated by Cargo.
[INFO] [stdout] # It is not intended for manual editing.
[INFO] [stdout] version = 3
[INFO] [stdout] 
[INFO] [stdout] [[package]]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] 
[INFO] [stdout] image: rustlang/rust:nightly
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] push:cargo:
[INFO] [stdout]   script:
[INFO] [stdout]     - rustc --version && cargo --version  
[INFO] [stdout]     - cargo publish --allow-dirty --token cioHYTp8cpgbRbBqcJvqGF7rUIjJQSlBvH3
[INFO] [stdout] 
[INFO] [stdout] use std::{mem, path::PathBuf, str::FromStr};
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct DirEntry {
[INFO] [stdout]     pub path: String,
[INFO] [stdout]     pub is_dir: bool,
[INFO] [stdout]     pub is_file: bool,
[INFO] [stdout]     pub contents: Vec<u8>,
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct Dir {
[INFO] [stdout]     pub data: Vec<DirEntry>,
[INFO] [stdout] }
[INFO] [stdout] pub trait Bytes {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn from_bytes(&self) -> Dir;
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn into_dir(&self) -> Dir;
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for [u8] {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for Dir {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement as_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         // Calculate the total size of the serialized data
[INFO] [stdout]         let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]             size += entry.path.as_bytes().len();
[INFO] [stdout]             size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]             size += entry.contents.len();
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]         // Write the length prefix
[INFO] [stdout]         bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             // Write the size prefix for this entry
[INFO] [stdout]             bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             // Write the entry data
[INFO] [stdout]             bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]             bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]             bytes.extend((entry.contents.len() as u32).to_le_bytes().iter());
[INFO] [stdout]             bytes.extend(entry.contents.iter());
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         bytes
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement from_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]         let mut cursor = 0;
[INFO] [stdout]         let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]         if bytes.len() < len_prefix_size {
[INFO] [stdout]             return None;
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let len = u32::from_le_bytes([
[INFO] [stdout]             bytes[cursor],
[INFO] [stdout]             bytes[cursor + 1],
[INFO] [stdout]             bytes[cursor + 2],
[INFO] [stdout]             bytes[cursor + 3],
[INFO] [stdout]         ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]         cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]         let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]         for _ in 0..len {
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let entry_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < end_pos {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]             cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + 2 {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let is_dir = bytes[cursor] != 0;
[INFO] [stdout]             let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]             cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let content_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + content_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let contents = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]             cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]             data.push(DirEntry {
[INFO] [stdout]                 path,
[INFO] [stdout]                 is_dir,
[INFO] [stdout]                 is_file,
[INFO] [stdout]                 contents,
[INFO] [stdout]             });
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         Some(Dir { data })
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] fn get_new_path(path: &str) -> String {
[INFO] [stdout]     let yok_path = match std::env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     let path = path.to_string().replace("\\", "/").to_string();
[INFO] [stdout]     if yok_path != "."{
[INFO] [stdout]         return path;
[INFO] [stdout]     }else {
[INFO] [stdout]         return path;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] 
[INFO] [stdout] impl Dir {
[INFO] [stdout]     /// include dir at compile time
[INFO] [stdout]     /// in default die path is current dir
[INFO] [stdout]     ///
[INFO] [stdout]     /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout]     ///
[INFO] [stdout]     /// you can also set YOK_PATH env before cargo run
[INFO] [stdout]     ///
[INFO] [stdout]     /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout]     /// ```rust
[INFO] [stdout]     ///   use yok::include_dir;
[INFO] [stdout]     ///   use yok::Dir;
[INFO] [stdout]     ///   use yok::DirEntry;
[INFO] [stdout]     ///   use yok::Bytes;
[INFO] [stdout]     ///   const DATA:&[u8] = include_dir();
[INFO] [stdout]     ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout]     ///   for entry in &dir.data{
[INFO] [stdout]     ///       if entry.is_file{
[INFO] [stdout]     ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]     ///       }else if entry.is_dir {
[INFO] [stdout]     ///           println!("{}",entry.path);
[INFO] [stdout]     ///       }
[INFO] [stdout]     ///   }
[INFO] [stdout]     ///   dir.extract("./demo");
[INFO] [stdout]     /// ```
[INFO] [stdout]     ///
[INFO] [stdout]     pub fn extract(&self, base_dir: impl ToString) ->std::io::Result<()>{
[INFO] [stdout]         std::fs::create_dir_all(base_dir.to_string()).expect("create to dir error");
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_dir {
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 std::fs::create_dir_all(path.clone()).expect("create to dir error");
[INFO] [stdout]                 if cfg!(target_os = "windows") {
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }else{
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_file {
[INFO] [stdout]                 use std::fs::{self, File, OpenOptions};
[INFO] [stdout]                 use std::io::prelude::*;
[INFO] [stdout]                 use std::os::unix::fs::OpenOptionsExt;
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 if !path.exists(){
[INFO] [stdout]                     let mut open_options = OpenOptions::new();
[INFO] [stdout]                     open_options.mode(0o777); // Set read/write permission for owner, read-only for others
[INFO] [stdout]                     let file = open_options.create(true).write(true).open(path).unwrap();
[INFO] [stdout]                     let mut file_writer = std::io::BufWriter::new(file);
[INFO] [stdout]                     file_writer.write_all(&entry.contents).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(())
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] pub const fn include_dir() -> &'static [u8] {
[INFO] [stdout]     include_bytes!("../../.yok")
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::include_dir;
[INFO] [stdout]     use yok::Bytes;
[INFO] [stdout]     use yok::Dir;
[INFO] [stdout]     use yok::DirEntry;
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             // println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             // println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] 
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] src
[INFO] [stdout] /target
[INFO] [stdout] Cargo.lock
[INFO] [stdout] .DS_Store
[INFO] [stdout] MIT License
[INFO] [stdout] 
[INFO] [stdout] Copyright (c) [year] [fullname]
[INFO] [stdout] 
[INFO] [stdout] Permission is hereby granted, free of charge, to any person obtaining a copy
[INFO] [stdout] of this software and associated documentation files (the "Software"), to deal
[INFO] [stdout] in the Software without restriction, including without limitation the rights
[INFO] [stdout] to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
[INFO] [stdout] copies of the Software, and to permit persons to whom the Software is
[INFO] [stdout] furnished to do so, subject to the following conditions:
[INFO] [stdout] 
[INFO] [stdout] The above copyright notice and this permission notice shall be included in all
[INFO] [stdout] copies or substantial portions of the Software.
[INFO] [stdout] 
[INFO] [stdout] THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
[INFO] [stdout] IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
[INFO] [stdout] FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
[INFO] [stdout] AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
[INFO] [stdout] LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
[INFO] [stdout] OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
[INFO] [stdout] SOFTWARE.
[INFO] [stdout] use std::fs::File;
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] use std::io::{BufWriter, Write};
[INFO] [stdout] use std::path::Path;
[INFO] [stdout] use zip::write::FileOptions;
[INFO] [stdout] use zip::ZipWriter;
[INFO] [stdout] use std::io::Read;
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     // Path to the directory to compress
[INFO] [stdout]     let dir_path = Path::new(".");
[INFO] [stdout] 
[INFO] [stdout]     // Path to the output ZIP file
[INFO] [stdout]     let zip_path = Path::new("app.zip");
[INFO] [stdout] 
[INFO] [stdout]     // Create a new ZIP file
[INFO] [stdout]     let file = File::create(&zip_path).unwrap();
[INFO] [stdout]     let writer = BufWriter::new(file);
[INFO] [stdout]     let mut zip = ZipWriter::new(writer);
[INFO] [stdout] 
[INFO] [stdout]     // Recursively add all files and directories in the input directory to the ZIP file
[INFO] [stdout]     add_directory_to_zip(&mut zip, dir_path, "").unwrap();
[INFO] [stdout] 
[INFO] [stdout]     // Finalize the ZIP file
[INFO] [stdout]     zip.finish().unwrap();
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Recursively adds a directory (and all its contents) to a ZipWriter
[INFO] [stdout] fn add_directory_to_zip(zip: &mut ZipWriter<BufWriter<File>>, dir_path: &Path, base_path: &str) -> zip::result::ZipResult<()> {
[INFO] [stdout]     for entry in dir_path.read_dir()? {
[INFO] [stdout]         let path = entry?.path();
[INFO] [stdout] 
[INFO] [stdout]         if path.is_dir() {
[INFO] [stdout]             // Recursively add the subdirectory
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let new_base_path = format!("{}/{}", base_path, name);
[INFO] [stdout]             add_directory_to_zip(zip, &path, &new_base_path)?;
[INFO] [stdout]         } else {
[INFO] [stdout]             // Add the file to the ZIP archive
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let options = FileOptions::default()
[INFO] [stdout]                 .compression_method(zip::CompressionMethod::Deflated)
[INFO] [stdout]                 .unix_permissions(0o755); // Set appropriate permissions for the file
[INFO] [stdout]             zip.start_file(format!("{}/{}", base_path, name), options)?;
[INFO] [stdout]             let mut file = File::open(&path)?;
[INFO] [stdout]             let mut buffer = Vec::new();
[INFO] [stdout]             file.read_to_end(&mut buffer)?;
[INFO] [stdout]             zip.write_all(&buffer)?;
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     Ok(())
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] stderr:
[INFO] [stdout] thread 'main' panicked at /opt/rustwide/workdir/src/lib.rs:236:55:
[INFO] [stdout] create to dir error: Os { code: 30, kind: ReadOnlyFilesystem, message: "Read-only file system" }
[INFO] [stdout] stack backtrace:
[INFO] [stdout]    0:     0x562e6801a485 - std::backtrace_rs::backtrace::libunwind::trace::he49dc9a9e3164223
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5
[INFO] [stdout]    1:     0x562e6801a485 - std::backtrace_rs::backtrace::trace_unsynchronized::h3a3e77c68030aa6b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
[INFO] [stdout]    2:     0x562e6801a485 - std::sys_common::backtrace::_print_fmt::h9479ad2f99afd5d4
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:68:5
[INFO] [stdout]    3:     0x562e6801a485 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hfb01aa1fa3fb1821
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:44:22
[INFO] [stdout]    4:     0x562e6803789b - core::fmt::rt::Argument::fmt::h125e56152abbc1c3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/fmt/rt.rs:165:63
[INFO] [stdout]    5:     0x562e6803789b - core::fmt::write::hb0ab4ff05ccfe741
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/fmt/mod.rs:1169:21
[INFO] [stdout]    6:     0x562e6801841f - std::io::Write::write_fmt::h456b7988df61daf3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/io/mod.rs:1835:15
[INFO] [stdout]    7:     0x562e6801a25e - std::sys_common::backtrace::_print::h79ca548f3a2adf4b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:47:5
[INFO] [stdout]    8:     0x562e6801a25e - std::sys_common::backtrace::print::h9aebf997b2fea2d3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:34:9
[INFO] [stdout]    9:     0x562e6801b509 - std::panicking::default_hook::{{closure}}::h68a0954af2694526
[INFO] [stdout]   10:     0x562e6801b2d8 - std::panicking::default_hook::h5be50cc6849ffb00
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:298:9
[INFO] [stdout]   11:     0x562e6801b9a3 - std::panicking::rust_panic_with_hook::h3c0df6036729334c
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:795:13
[INFO] [stdout]   12:     0x562e6801b884 - std::panicking::begin_panic_handler::{{closure}}::ha3a21e93c4cfd807
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:664:13
[INFO] [stdout]   13:     0x562e6801a949 - std::sys_common::backtrace::__rust_end_short_backtrace::h19508a8f8ae71dc9
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:171:18
[INFO] [stdout]   14:     0x562e6801b5b7 - rust_begin_unwind
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:652:5
[INFO] [stdout]   15:     0x562e67ff2f93 - core::panicking::panic_fmt::h2ba8af99174d83ea
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/panicking.rs:72:14
[INFO] [stdout]   16:     0x562e67ff33a6 - core::result::unwrap_failed::h52f3bbb78b59f71d
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/result.rs:1654:5
[INFO] [stdout]   17:     0x562e67ff6b93 - core::result::Result<T,E>::expect::h2c0d42f454820c3e
[INFO] [stdout]   18:     0x562e67ff4ee8 - yok::Dir::extract::h06b970ca2cb27101
[INFO] [stdout]   19:     0x562e67ff78f8 - rust_out::main::_doctest_main_src_lib_rs_10_0::h0f0eff085b7aa42e
[INFO] [stdout]   20:     0x562e67ff7826 - rust_out::main::h90fc46ea9798ded1
[INFO] [stdout]   21:     0x562e67ff61e3 - core::ops::function::FnOnce::call_once::h48eb9b1eb2de063c
[INFO] [stdout]   22:     0x562e67ff3a06 - std::sys_common::backtrace::__rust_begin_short_backtrace::h747a6d1e1b11dda9
[INFO] [stdout]   23:     0x562e67ff4c49 - std::rt::lang_start::{{closure}}::hc32502aff423e72f
[INFO] [stdout]   24:     0x562e6801529d - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hac8b4a62b6f52371
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/ops/function.rs:284:13
[INFO] [stdout]   25:     0x562e6801529d - std::panicking::try::do_call::h6fc24bc97db29d34
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:559:40
[INFO] [stdout]   26:     0x562e6801529d - std::panicking::try::hc544b64aa2eea933
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:523:19
[INFO] [stdout]   27:     0x562e6801529d - std::panic::catch_unwind::hefb17e81fb559b9c
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panic.rs:149:14
[INFO] [stdout]   28:     0x562e6801529d - std::rt::lang_start_internal::{{closure}}::h834103e2d23d958b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/rt.rs:141:48
[INFO] [stdout]   29:     0x562e6801529d - std::panicking::try::do_call::he39c25d597788515
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:559:40
[INFO] [stdout]   30:     0x562e6801529d - std::panicking::try::hf4ef8dd97697f2c7
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:523:19
[INFO] [stdout]   31:     0x562e6801529d - std::panic::catch_unwind::haa22d191a5c8abfb
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panic.rs:149:14
[INFO] [stdout]   32:     0x562e6801529d - std::rt::lang_start_internal::h8104aca277c551bf
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/rt.rs:141:20
[INFO] [stdout]   33:     0x562e67ff4c27 - std::rt::lang_start::h363611def46ee6df
[INFO] [stdout]   34:     0x562e67ff7b05 - main
[INFO] [stdout]   35:     0x7feb0df87d90 - <unknown>
[INFO] [stdout]   36:     0x7feb0df87e40 - __libc_start_main
[INFO] [stdout]   37:     0x562e67ff35c5 - _start
[INFO] [stdout]   38:                0x0 - <unknown>
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] ---- src/lib.rs - include_dir (line 282) stdout ----
[INFO] [stdout] Test executable failed (exit status: 101).
[INFO] [stdout] 
[INFO] [stdout] stdout:
[INFO] [stdout] use std::{
[INFO] [stdout]     fs, io,
[INFO] [stdout]     path::{Path, PathBuf},
[INFO] [stdout] };
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     use std::mem;
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct DirEntry {
[INFO] [stdout]         path: String,
[INFO] [stdout]         is_dir: bool,
[INFO] [stdout]         is_file: bool,
[INFO] [stdout]         content: Vec<u8>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct Dir {
[INFO] [stdout]         data: Vec<DirEntry>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement as_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]             // Calculate the total size of the serialized data
[INFO] [stdout]             let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]                 size += entry.path.as_bytes().len();
[INFO] [stdout]                 size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]                 size += entry.content.len();
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]             // Write the length prefix
[INFO] [stdout]             bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 // Write the size prefix for this entry
[INFO] [stdout]                 bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]                 // Write the entry data
[INFO] [stdout]                 bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]                 bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]                 bytes.extend((entry.content.len() as u32).to_le_bytes().iter());
[INFO] [stdout]                 bytes.extend(entry.content.iter());
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             bytes
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement from_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         #[allow(warnings)]
[INFO] [stdout]         pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]             let mut cursor = 0;
[INFO] [stdout]             let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let len = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]             for _ in 0..len {
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let entry_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < end_pos {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]                 cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + 2 {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let is_dir = bytes[cursor] != 0;
[INFO] [stdout]                 let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]                 cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + content_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]                 cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]                 data.push(DirEntry {
[INFO] [stdout]                     path,
[INFO] [stdout]                     is_dir,
[INFO] [stdout]                     is_file,
[INFO] [stdout]                     content,
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             Some(Dir { data })
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     pub fn walk_dir(path: impl ToString) -> io::Result<Vec<PathBuf>> {
[INFO] [stdout]         let path = path.to_string();
[INFO] [stdout]         let dir = Path::new(&path);
[INFO] [stdout]         let mut files = Vec::new();
[INFO] [stdout]         for entry in fs::read_dir(dir)? {
[INFO] [stdout]             let entry = entry?;
[INFO] [stdout]             let newpath = entry.path();
[INFO] [stdout] 
[INFO] [stdout]             if newpath.is_dir() {
[INFO] [stdout]                 files.extend(walk_dir(&newpath.display())?);
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             } else {
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(files)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     use std::env;
[INFO] [stdout]     let yok_path = match env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     println!("cargo:rerun-if-env-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed=main.rs");
[INFO] [stdout]     println!("cargo:rerun-if-changed=lib.rs");
[INFO] [stdout]     let yok_path = std::path::Path::new(&yok_path);
[INFO] [stdout]     if yok_path.is_dir() {
[INFO] [stdout]         let mut res_dir: Vec<DirEntry> = vec![];
[INFO] [stdout]         let dir_list = walk_dir(yok_path.display()).expect("walk dir error");
[INFO] [stdout]         for dir in dir_list {
[INFO] [stdout]             if dir.is_file() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: false,
[INFO] [stdout]                     is_file: true,
[INFO] [stdout]                     content: std::fs::read(dir).expect("read dir error"),
[INFO] [stdout]                 });
[INFO] [stdout]             } else if dir.is_dir() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: true,
[INFO] [stdout]                     is_file: false,
[INFO] [stdout]                     content: vec![],
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         let all_dir: Dir = Dir { data: res_dir };
[INFO] [stdout]         let all_dir_bytes = all_dir.as_bytes();
[INFO] [stdout]         if let Ok(_) = std::fs::write(format!("../.yok"), all_dir_bytes){}
[INFO] [stdout]     } else {
[INFO] [stdout]         eprintln!("Environment variable 'YOK_PATH' not dir");
[INFO] [stdout]         return;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] keywords = ["include","dir","compile-time"]
[INFO] [stdout] categories = ["development-tools","game-engines","web-programming"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] categories = ["development-tools", "game-engines", "web-programming"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] keywords = ["include", "dir", "compile-time"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] name = "yok"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] # yok
[INFO] [stdout] 
[INFO] [stdout] [![Crates.io](https://img.shields.io/crates/v/yok.svg)](https://crates.io/crates/yok)
[INFO] [stdout] [![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://gitlab.com/andrew_ryan/yok)
[INFO] [stdout] [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitlab.com/andrew_ryan/yok/-/raw/master/LICENSE)
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] A crate for Embed the contents of a directory in your binary at compile time.
[INFO] [stdout] 
[INFO] [stdout] ## Getting Started
[INFO] [stdout] ```sh
[INFO] [stdout] cargo add yok
[INFO] [stdout] ```
[INFO] [stdout] ```rust
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::{Dir, Bytes,include_dir};
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] }
[INFO] [stdout] ```
[INFO] [stdout] ## Set YOK_PATH env and run or default path is cuttent dir
[INFO] [stdout] ```sh
[INFO] [stdout] # linux,macos
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] # windows cmd
[INFO] [stdout] set YOK_PATH="C:\path\to\your\directory"
[INFO] [stdout] # windows powershell
[INFO] [stdout] $env:YOK_PATH = "C:\path\to\your\directory"
[INFO] [stdout] 
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] ```
[INFO] [stdout] rm -rf path
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] # This file is automatically @generated by Cargo.
[INFO] [stdout] # It is not intended for manual editing.
[INFO] [stdout] version = 3
[INFO] [stdout] 
[INFO] [stdout] [[package]]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] 
[INFO] [stdout] image: rustlang/rust:nightly
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] push:cargo:
[INFO] [stdout]   script:
[INFO] [stdout]     - rustc --version && cargo --version  
[INFO] [stdout]     - cargo publish --allow-dirty --token cioHYTp8cpgbRbBqcJvqGF7rUIjJQSlBvH3
[INFO] [stdout] 
[INFO] [stdout] use std::{mem, path::PathBuf, str::FromStr};
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct DirEntry {
[INFO] [stdout]     pub path: String,
[INFO] [stdout]     pub is_dir: bool,
[INFO] [stdout]     pub is_file: bool,
[INFO] [stdout]     pub contents: Vec<u8>,
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct Dir {
[INFO] [stdout]     pub data: Vec<DirEntry>,
[INFO] [stdout] }
[INFO] [stdout] pub trait Bytes {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn from_bytes(&self) -> Dir;
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn into_dir(&self) -> Dir;
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for [u8] {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for Dir {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement as_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         // Calculate the total size of the serialized data
[INFO] [stdout]         let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]             size += entry.path.as_bytes().len();
[INFO] [stdout]             size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]             size += entry.contents.len();
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]         // Write the length prefix
[INFO] [stdout]         bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             // Write the size prefix for this entry
[INFO] [stdout]             bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             // Write the entry data
[INFO] [stdout]             bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]             bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]             bytes.extend((entry.contents.len() as u32).to_le_bytes().iter());
[INFO] [stdout]             bytes.extend(entry.contents.iter());
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         bytes
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement from_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]         let mut cursor = 0;
[INFO] [stdout]         let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]         if bytes.len() < len_prefix_size {
[INFO] [stdout]             return None;
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let len = u32::from_le_bytes([
[INFO] [stdout]             bytes[cursor],
[INFO] [stdout]             bytes[cursor + 1],
[INFO] [stdout]             bytes[cursor + 2],
[INFO] [stdout]             bytes[cursor + 3],
[INFO] [stdout]         ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]         cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]         let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]         for _ in 0..len {
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let entry_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < end_pos {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]             cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + 2 {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let is_dir = bytes[cursor] != 0;
[INFO] [stdout]             let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]             cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let content_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + content_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let contents = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]             cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]             data.push(DirEntry {
[INFO] [stdout]                 path,
[INFO] [stdout]                 is_dir,
[INFO] [stdout]                 is_file,
[INFO] [stdout]                 contents,
[INFO] [stdout]             });
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         Some(Dir { data })
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] fn get_new_path(path: &str) -> String {
[INFO] [stdout]     let yok_path = match std::env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     let path = path.to_string().replace("\\", "/").to_string();
[INFO] [stdout]     if yok_path != "."{
[INFO] [stdout]         return path;
[INFO] [stdout]     }else {
[INFO] [stdout]         return path;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] 
[INFO] [stdout] impl Dir {
[INFO] [stdout]     /// include dir at compile time
[INFO] [stdout]     /// in default die path is current dir
[INFO] [stdout]     ///
[INFO] [stdout]     /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout]     ///
[INFO] [stdout]     /// you can also set YOK_PATH env before cargo run
[INFO] [stdout]     ///
[INFO] [stdout]     /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout]     /// ```rust
[INFO] [stdout]     ///   use yok::include_dir;
[INFO] [stdout]     ///   use yok::Dir;
[INFO] [stdout]     ///   use yok::DirEntry;
[INFO] [stdout]     ///   use yok::Bytes;
[INFO] [stdout]     ///   const DATA:&[u8] = include_dir();
[INFO] [stdout]     ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout]     ///   for entry in &dir.data{
[INFO] [stdout]     ///       if entry.is_file{
[INFO] [stdout]     ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]     ///       }else if entry.is_dir {
[INFO] [stdout]     ///           println!("{}",entry.path);
[INFO] [stdout]     ///       }
[INFO] [stdout]     ///   }
[INFO] [stdout]     ///   dir.extract("./demo");
[INFO] [stdout]     /// ```
[INFO] [stdout]     ///
[INFO] [stdout]     pub fn extract(&self, base_dir: impl ToString) ->std::io::Result<()>{
[INFO] [stdout]         std::fs::create_dir_all(base_dir.to_string()).expect("create to dir error");
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_dir {
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 std::fs::create_dir_all(path.clone()).expect("create to dir error");
[INFO] [stdout]                 if cfg!(target_os = "windows") {
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }else{
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_file {
[INFO] [stdout]                 use std::fs::{self, File, OpenOptions};
[INFO] [stdout]                 use std::io::prelude::*;
[INFO] [stdout]                 use std::os::unix::fs::OpenOptionsExt;
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 if !path.exists(){
[INFO] [stdout]                     let mut open_options = OpenOptions::new();
[INFO] [stdout]                     open_options.mode(0o777); // Set read/write permission for owner, read-only for others
[INFO] [stdout]                     let file = open_options.create(true).write(true).open(path).unwrap();
[INFO] [stdout]                     let mut file_writer = std::io::BufWriter::new(file);
[INFO] [stdout]                     file_writer.write_all(&entry.contents).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(())
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] pub const fn include_dir() -> &'static [u8] {
[INFO] [stdout]     include_bytes!("../../.yok")
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::include_dir;
[INFO] [stdout]     use yok::Bytes;
[INFO] [stdout]     use yok::Dir;
[INFO] [stdout]     use yok::DirEntry;
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             // println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             // println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] 
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] src
[INFO] [stdout] /target
[INFO] [stdout] Cargo.lock
[INFO] [stdout] .DS_Store
[INFO] [stdout] MIT License
[INFO] [stdout] 
[INFO] [stdout] Copyright (c) [year] [fullname]
[INFO] [stdout] 
[INFO] [stdout] Permission is hereby granted, free of charge, to any person obtaining a copy
[INFO] [stdout] of this software and associated documentation files (the "Software"), to deal
[INFO] [stdout] in the Software without restriction, including without limitation the rights
[INFO] [stdout] to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
[INFO] [stdout] copies of the Software, and to permit persons to whom the Software is
[INFO] [stdout] furnished to do so, subject to the following conditions:
[INFO] [stdout] 
[INFO] [stdout] The above copyright notice and this permission notice shall be included in all
[INFO] [stdout] copies or substantial portions of the Software.
[INFO] [stdout] 
[INFO] [stdout] THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
[INFO] [stdout] IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
[INFO] [stdout] FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
[INFO] [stdout] AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
[INFO] [stdout] LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
[INFO] [stdout] OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
[INFO] [stdout] SOFTWARE.
[INFO] [stdout] use std::fs::File;
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] use std::io::{BufWriter, Write};
[INFO] [stdout] use std::path::Path;
[INFO] [stdout] use zip::write::FileOptions;
[INFO] [stdout] use zip::ZipWriter;
[INFO] [stdout] use std::io::Read;
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     // Path to the directory to compress
[INFO] [stdout]     let dir_path = Path::new(".");
[INFO] [stdout] 
[INFO] [stdout]     // Path to the output ZIP file
[INFO] [stdout]     let zip_path = Path::new("app.zip");
[INFO] [stdout] 
[INFO] [stdout]     // Create a new ZIP file
[INFO] [stdout]     let file = File::create(&zip_path).unwrap();
[INFO] [stdout]     let writer = BufWriter::new(file);
[INFO] [stdout]     let mut zip = ZipWriter::new(writer);
[INFO] [stdout] 
[INFO] [stdout]     // Recursively add all files and directories in the input directory to the ZIP file
[INFO] [stdout]     add_directory_to_zip(&mut zip, dir_path, "").unwrap();
[INFO] [stdout] 
[INFO] [stdout]     // Finalize the ZIP file
[INFO] [stdout]     zip.finish().unwrap();
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Recursively adds a directory (and all its contents) to a ZipWriter
[INFO] [stdout] fn add_directory_to_zip(zip: &mut ZipWriter<BufWriter<File>>, dir_path: &Path, base_path: &str) -> zip::result::ZipResult<()> {
[INFO] [stdout]     for entry in dir_path.read_dir()? {
[INFO] [stdout]         let path = entry?.path();
[INFO] [stdout] 
[INFO] [stdout]         if path.is_dir() {
[INFO] [stdout]             // Recursively add the subdirectory
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let new_base_path = format!("{}/{}", base_path, name);
[INFO] [stdout]             add_directory_to_zip(zip, &path, &new_base_path)?;
[INFO] [stdout]         } else {
[INFO] [stdout]             // Add the file to the ZIP archive
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let options = FileOptions::default()
[INFO] [stdout]                 .compression_method(zip::CompressionMethod::Deflated)
[INFO] [stdout]                 .unix_permissions(0o755); // Set appropriate permissions for the file
[INFO] [stdout]             zip.start_file(format!("{}/{}", base_path, name), options)?;
[INFO] [stdout]             let mut file = File::open(&path)?;
[INFO] [stdout]             let mut buffer = Vec::new();
[INFO] [stdout]             file.read_to_end(&mut buffer)?;
[INFO] [stdout]             zip.write_all(&buffer)?;
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     Ok(())
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] stderr:
[INFO] [stdout] thread 'main' panicked at /opt/rustwide/workdir/src/lib.rs:236:55:
[INFO] [stdout] create to dir error: Os { code: 30, kind: ReadOnlyFilesystem, message: "Read-only file system" }
[INFO] [stdout] stack backtrace:
[INFO] [stdout]    0:     0x5576201b8485 - std::backtrace_rs::backtrace::libunwind::trace::he49dc9a9e3164223
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5
[INFO] [stdout]    1:     0x5576201b8485 - std::backtrace_rs::backtrace::trace_unsynchronized::h3a3e77c68030aa6b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
[INFO] [stdout]    2:     0x5576201b8485 - std::sys_common::backtrace::_print_fmt::h9479ad2f99afd5d4
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:68:5
[INFO] [stdout]    3:     0x5576201b8485 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hfb01aa1fa3fb1821
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:44:22
[INFO] [stdout]    4:     0x5576201d589b - core::fmt::rt::Argument::fmt::h125e56152abbc1c3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/fmt/rt.rs:165:63
[INFO] [stdout]    5:     0x5576201d589b - core::fmt::write::hb0ab4ff05ccfe741
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/fmt/mod.rs:1169:21
[INFO] [stdout]    6:     0x5576201b641f - std::io::Write::write_fmt::h456b7988df61daf3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/io/mod.rs:1835:15
[INFO] [stdout]    7:     0x5576201b825e - std::sys_common::backtrace::_print::h79ca548f3a2adf4b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:47:5
[INFO] [stdout]    8:     0x5576201b825e - std::sys_common::backtrace::print::h9aebf997b2fea2d3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:34:9
[INFO] [stdout]    9:     0x5576201b9509 - std::panicking::default_hook::{{closure}}::h68a0954af2694526
[INFO] [stdout]   10:     0x5576201b92d8 - std::panicking::default_hook::h5be50cc6849ffb00
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:298:9
[INFO] [stdout]   11:     0x5576201b99a3 - std::panicking::rust_panic_with_hook::h3c0df6036729334c
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:795:13
[INFO] [stdout]   12:     0x5576201b9884 - std::panicking::begin_panic_handler::{{closure}}::ha3a21e93c4cfd807
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:664:13
[INFO] [stdout]   13:     0x5576201b8949 - std::sys_common::backtrace::__rust_end_short_backtrace::h19508a8f8ae71dc9
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:171:18
[INFO] [stdout]   14:     0x5576201b95b7 - rust_begin_unwind
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:652:5
[INFO] [stdout]   15:     0x557620190f93 - core::panicking::panic_fmt::h2ba8af99174d83ea
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/panicking.rs:72:14
[INFO] [stdout]   16:     0x5576201913a6 - core::result::unwrap_failed::h52f3bbb78b59f71d
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/result.rs:1654:5
[INFO] [stdout]   17:     0x557620194b93 - core::result::Result<T,E>::expect::h2c0d42f454820c3e
[INFO] [stdout]   18:     0x557620192ee8 - yok::Dir::extract::h06b970ca2cb27101
[INFO] [stdout]   19:     0x5576201958f8 - rust_out::main::_doctest_main_src_lib_rs_282_0::h24505fe32c14de40
[INFO] [stdout]   20:     0x557620195826 - rust_out::main::h90fc46ea9798ded1
[INFO] [stdout]   21:     0x5576201941e3 - core::ops::function::FnOnce::call_once::h48eb9b1eb2de063c
[INFO] [stdout]   22:     0x557620191a06 - std::sys_common::backtrace::__rust_begin_short_backtrace::h747a6d1e1b11dda9
[INFO] [stdout]   23:     0x557620192c49 - std::rt::lang_start::{{closure}}::hc32502aff423e72f
[INFO] [stdout]   24:     0x5576201b329d - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hac8b4a62b6f52371
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/ops/function.rs:284:13
[INFO] [stdout]   25:     0x5576201b329d - std::panicking::try::do_call::h6fc24bc97db29d34
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:559:40
[INFO] [stdout]   26:     0x5576201b329d - std::panicking::try::hc544b64aa2eea933
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:523:19
[INFO] [stdout]   27:     0x5576201b329d - std::panic::catch_unwind::hefb17e81fb559b9c
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panic.rs:149:14
[INFO] [stdout]   28:     0x5576201b329d - std::rt::lang_start_internal::{{closure}}::h834103e2d23d958b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/rt.rs:141:48
[INFO] [stdout]   29:     0x5576201b329d - std::panicking::try::do_call::he39c25d597788515
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:559:40
[INFO] [stdout]   30:     0x5576201b329d - std::panicking::try::hf4ef8dd97697f2c7
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:523:19
[INFO] [stdout]   31:     0x5576201b329d - std::panic::catch_unwind::haa22d191a5c8abfb
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panic.rs:149:14
[INFO] [stdout]   32:     0x5576201b329d - std::rt::lang_start_internal::h8104aca277c551bf
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/rt.rs:141:20
[INFO] [stdout]   33:     0x557620192c27 - std::rt::lang_start::h363611def46ee6df
[INFO] [stdout]   34:     0x557620195b05 - main
[INFO] [stdout]   35:     0x7f8dfb960d90 - <unknown>
[INFO] [stdout]   36:     0x7f8dfb960e40 - __libc_start_main
[INFO] [stdout]   37:     0x5576201915c5 - _start
[INFO] [stdout]   38:                0x0 - <unknown>
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] ---- src/lib.rs - Dir::extract (line 218) stdout ----
[INFO] [stdout] Test executable failed (exit status: 101).
[INFO] [stdout] 
[INFO] [stdout] stdout:
[INFO] [stdout] use std::{
[INFO] [stdout]     fs, io,
[INFO] [stdout]     path::{Path, PathBuf},
[INFO] [stdout] };
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     use std::mem;
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct DirEntry {
[INFO] [stdout]         path: String,
[INFO] [stdout]         is_dir: bool,
[INFO] [stdout]         is_file: bool,
[INFO] [stdout]         content: Vec<u8>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout]     pub struct Dir {
[INFO] [stdout]         data: Vec<DirEntry>,
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement as_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]             // Calculate the total size of the serialized data
[INFO] [stdout]             let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]                 size += entry.path.as_bytes().len();
[INFO] [stdout]                 size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]                 size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]                 size += entry.content.len();
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]             // Write the length prefix
[INFO] [stdout]             bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             for entry in &self.data {
[INFO] [stdout]                 // Write the size prefix for this entry
[INFO] [stdout]                 bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]                 // Write the entry data
[INFO] [stdout]                 bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]                 bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]                 bytes.extend((entry.content.len() as u32).to_le_bytes().iter());
[INFO] [stdout]                 bytes.extend(entry.content.iter());
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             bytes
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     // Implement from_bytes() for Dir
[INFO] [stdout]     impl Dir {
[INFO] [stdout]         #[allow(warnings)]
[INFO] [stdout]         pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]             let mut cursor = 0;
[INFO] [stdout]             let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let len = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]             for _ in 0..len {
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let entry_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < end_pos {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]                 cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + 2 {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let is_dir = bytes[cursor] != 0;
[INFO] [stdout]                 let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]                 cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content_size = u32::from_le_bytes([
[INFO] [stdout]                     bytes[cursor],
[INFO] [stdout]                     bytes[cursor + 1],
[INFO] [stdout]                     bytes[cursor + 2],
[INFO] [stdout]                     bytes[cursor + 3],
[INFO] [stdout]                 ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]                 cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]                 if bytes.len() < cursor + content_size {
[INFO] [stdout]                     return None;
[INFO] [stdout]                 }
[INFO] [stdout] 
[INFO] [stdout]                 let content = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]                 cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]                 data.push(DirEntry {
[INFO] [stdout]                     path,
[INFO] [stdout]                     is_dir,
[INFO] [stdout]                     is_file,
[INFO] [stdout]                     content,
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             Some(Dir { data })
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     pub fn walk_dir(path: impl ToString) -> io::Result<Vec<PathBuf>> {
[INFO] [stdout]         let path = path.to_string();
[INFO] [stdout]         let dir = Path::new(&path);
[INFO] [stdout]         let mut files = Vec::new();
[INFO] [stdout]         for entry in fs::read_dir(dir)? {
[INFO] [stdout]             let entry = entry?;
[INFO] [stdout]             let newpath = entry.path();
[INFO] [stdout] 
[INFO] [stdout]             if newpath.is_dir() {
[INFO] [stdout]                 files.extend(walk_dir(&newpath.display())?);
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             } else {
[INFO] [stdout]                 files.push(newpath);
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(files)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     use std::env;
[INFO] [stdout]     let yok_path = match env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     println!("cargo:rerun-if-env-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed={}", yok_path);
[INFO] [stdout]     println!("cargo:rerun-if-changed=main.rs");
[INFO] [stdout]     println!("cargo:rerun-if-changed=lib.rs");
[INFO] [stdout]     let yok_path = std::path::Path::new(&yok_path);
[INFO] [stdout]     if yok_path.is_dir() {
[INFO] [stdout]         let mut res_dir: Vec<DirEntry> = vec![];
[INFO] [stdout]         let dir_list = walk_dir(yok_path.display()).expect("walk dir error");
[INFO] [stdout]         for dir in dir_list {
[INFO] [stdout]             if dir.is_file() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: false,
[INFO] [stdout]                     is_file: true,
[INFO] [stdout]                     content: std::fs::read(dir).expect("read dir error"),
[INFO] [stdout]                 });
[INFO] [stdout]             } else if dir.is_dir() {
[INFO] [stdout]                 res_dir.push(DirEntry {
[INFO] [stdout]                     path: dir.strip_prefix(yok_path).unwrap().display().to_string(),
[INFO] [stdout]                     is_dir: true,
[INFO] [stdout]                     is_file: false,
[INFO] [stdout]                     content: vec![],
[INFO] [stdout]                 });
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         let all_dir: Dir = Dir { data: res_dir };
[INFO] [stdout]         let all_dir_bytes = all_dir.as_bytes();
[INFO] [stdout]         if let Ok(_) = std::fs::write(format!("../.yok"), all_dir_bytes){}
[INFO] [stdout]     } else {
[INFO] [stdout]         eprintln!("Environment variable 'YOK_PATH' not dir");
[INFO] [stdout]         return;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] keywords = ["include","dir","compile-time"]
[INFO] [stdout] categories = ["development-tools","game-engines","web-programming"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] [build-dependencies]
[INFO] [stdout] 
[INFO] [stdout] [dependencies]
[INFO] [stdout] 
[INFO] [stdout] [package]
[INFO] [stdout] authors = ["Anonymous <dnrops@outlook.com>"]
[INFO] [stdout] build = "build.rs"
[INFO] [stdout] categories = ["development-tools", "game-engines", "web-programming"]
[INFO] [stdout] description = "Embed the contents of a directory in your binary"
[INFO] [stdout] documentation = "https://docs.rs/yok"
[INFO] [stdout] edition = "2021"
[INFO] [stdout] homepage = "https://dnrops.gitee.io"
[INFO] [stdout] keywords = ["include", "dir", "compile-time"]
[INFO] [stdout] license = "MIT"
[INFO] [stdout] name = "yok"
[INFO] [stdout] readme = "README.md"
[INFO] [stdout] repository = "https://gitlab.com/andrew_ryan/yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] [package.metadata.docs.rs]
[INFO] [stdout] rustc-args = ["--cfg", "docsrs"]
[INFO] [stdout] 
[INFO] [stdout] # yok
[INFO] [stdout] 
[INFO] [stdout] [![Crates.io](https://img.shields.io/crates/v/yok.svg)](https://crates.io/crates/yok)
[INFO] [stdout] [![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://gitlab.com/andrew_ryan/yok)
[INFO] [stdout] [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitlab.com/andrew_ryan/yok/-/raw/master/LICENSE)
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] A crate for Embed the contents of a directory in your binary at compile time.
[INFO] [stdout] 
[INFO] [stdout] ## Getting Started
[INFO] [stdout] ```sh
[INFO] [stdout] cargo add yok
[INFO] [stdout] ```
[INFO] [stdout] ```rust
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::{Dir, Bytes,include_dir};
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] }
[INFO] [stdout] ```
[INFO] [stdout] ## Set YOK_PATH env and run or default path is cuttent dir
[INFO] [stdout] ```sh
[INFO] [stdout] # linux,macos
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] # windows cmd
[INFO] [stdout] set YOK_PATH="C:\path\to\your\directory"
[INFO] [stdout] # windows powershell
[INFO] [stdout] $env:YOK_PATH = "C:\path\to\your\directory"
[INFO] [stdout] 
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] ```
[INFO] [stdout] rm -rf path
[INFO] [stdout] export YOK_PATH="/home/andrew/code/gitlab/test_code/"
[INFO] [stdout] cargo clean
[INFO] [stdout] cargo r
[INFO] [stdout] # This file is automatically @generated by Cargo.
[INFO] [stdout] # It is not intended for manual editing.
[INFO] [stdout] version = 3
[INFO] [stdout] 
[INFO] [stdout] [[package]]
[INFO] [stdout] name = "yok"
[INFO] [stdout] version = "0.1.9"
[INFO] [stdout] 
[INFO] [stdout] image: rustlang/rust:nightly
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] push:cargo:
[INFO] [stdout]   script:
[INFO] [stdout]     - rustc --version && cargo --version  
[INFO] [stdout]     - cargo publish --allow-dirty --token cioHYTp8cpgbRbBqcJvqGF7rUIjJQSlBvH3
[INFO] [stdout] 
[INFO] [stdout] use std::{mem, path::PathBuf, str::FromStr};
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct DirEntry {
[INFO] [stdout]     pub path: String,
[INFO] [stdout]     pub is_dir: bool,
[INFO] [stdout]     pub is_file: bool,
[INFO] [stdout]     pub contents: Vec<u8>,
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[derive(Debug, Clone, PartialEq, Eq)]
[INFO] [stdout] pub struct Dir {
[INFO] [stdout]     pub data: Vec<DirEntry>,
[INFO] [stdout] }
[INFO] [stdout] pub trait Bytes {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn from_bytes(&self) -> Dir;
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8>;
[INFO] [stdout]     fn into_dir(&self) -> Dir;
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for [u8] {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         self.to_vec()
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         Dir::from_bytes(self).expect("from bytes error")
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] impl Bytes for Dir {
[INFO] [stdout]     fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout]     fn into_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         Dir::as_bytes(&self)
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     fn from_bytes(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout]     fn into_dir(&self) -> Dir {
[INFO] [stdout]         self.clone()
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement as_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn as_bytes(&self) -> Vec<u8> {
[INFO] [stdout]         // Calculate the total size of the serialized data
[INFO] [stdout]         let mut size = mem::size_of::<u32>(); // Size of the length prefix
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of the entry size prefix
[INFO] [stdout]             size += entry.path.as_bytes().len();
[INFO] [stdout]             size += mem::size_of::<bool>() * 2; // Sizes of is_dir and is_file fields
[INFO] [stdout]             size += mem::size_of::<u32>(); // Size of content size prefix
[INFO] [stdout]             size += entry.contents.len();
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let mut bytes = Vec::with_capacity(size);
[INFO] [stdout] 
[INFO] [stdout]         // Write the length prefix
[INFO] [stdout]         bytes.extend((self.data.len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]         for entry in &self.data {
[INFO] [stdout]             // Write the size prefix for this entry
[INFO] [stdout]             bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
[INFO] [stdout] 
[INFO] [stdout]             // Write the entry data
[INFO] [stdout]             bytes.extend(entry.path.as_bytes().iter());
[INFO] [stdout]             bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]);
[INFO] [stdout]             bytes.extend((entry.contents.len() as u32).to_le_bytes().iter());
[INFO] [stdout]             bytes.extend(entry.contents.iter());
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         bytes
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Implement from_bytes() for Dir
[INFO] [stdout] impl Dir {
[INFO] [stdout]     pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
[INFO] [stdout]         let mut cursor = 0;
[INFO] [stdout]         let len_prefix_size = mem::size_of::<u32>();
[INFO] [stdout] 
[INFO] [stdout]         if bytes.len() < len_prefix_size {
[INFO] [stdout]             return None;
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         let len = u32::from_le_bytes([
[INFO] [stdout]             bytes[cursor],
[INFO] [stdout]             bytes[cursor + 1],
[INFO] [stdout]             bytes[cursor + 2],
[INFO] [stdout]             bytes[cursor + 3],
[INFO] [stdout]         ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]         cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]         let mut data = Vec::with_capacity(len);
[INFO] [stdout] 
[INFO] [stdout]         for _ in 0..len {
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let entry_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             let end_pos = cursor + entry_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < end_pos {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?;
[INFO] [stdout]             cursor = end_pos;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + 2 {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let is_dir = bytes[cursor] != 0;
[INFO] [stdout]             let is_file = bytes[cursor + 1] != 0;
[INFO] [stdout]             cursor += 2;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + len_prefix_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let content_size = u32::from_le_bytes([
[INFO] [stdout]                 bytes[cursor],
[INFO] [stdout]                 bytes[cursor + 1],
[INFO] [stdout]                 bytes[cursor + 2],
[INFO] [stdout]                 bytes[cursor + 3],
[INFO] [stdout]             ]) as usize;
[INFO] [stdout] 
[INFO] [stdout]             cursor += len_prefix_size;
[INFO] [stdout] 
[INFO] [stdout]             if bytes.len() < cursor + content_size {
[INFO] [stdout]                 return None;
[INFO] [stdout]             }
[INFO] [stdout] 
[INFO] [stdout]             let contents = bytes[cursor..cursor + content_size].to_vec();
[INFO] [stdout]             cursor += content_size;
[INFO] [stdout] 
[INFO] [stdout]             data.push(DirEntry {
[INFO] [stdout]                 path,
[INFO] [stdout]                 is_dir,
[INFO] [stdout]                 is_file,
[INFO] [stdout]                 contents,
[INFO] [stdout]             });
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         Some(Dir { data })
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] fn get_new_path(path: &str) -> String {
[INFO] [stdout]     let yok_path = match std::env::var("YOK_PATH") {
[INFO] [stdout]         Ok(value) => value,
[INFO] [stdout]         Err(_) => ".".to_string(),
[INFO] [stdout]     };
[INFO] [stdout]     let path = path.to_string().replace("\\", "/").to_string();
[INFO] [stdout]     if yok_path != "."{
[INFO] [stdout]         return path;
[INFO] [stdout]     }else {
[INFO] [stdout]         return path;
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] 
[INFO] [stdout] impl Dir {
[INFO] [stdout]     /// include dir at compile time
[INFO] [stdout]     /// in default die path is current dir
[INFO] [stdout]     ///
[INFO] [stdout]     /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout]     ///
[INFO] [stdout]     /// you can also set YOK_PATH env before cargo run
[INFO] [stdout]     ///
[INFO] [stdout]     /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout]     /// ```rust
[INFO] [stdout]     ///   use yok::include_dir;
[INFO] [stdout]     ///   use yok::Dir;
[INFO] [stdout]     ///   use yok::DirEntry;
[INFO] [stdout]     ///   use yok::Bytes;
[INFO] [stdout]     ///   const DATA:&[u8] = include_dir();
[INFO] [stdout]     ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout]     ///   for entry in &dir.data{
[INFO] [stdout]     ///       if entry.is_file{
[INFO] [stdout]     ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]     ///       }else if entry.is_dir {
[INFO] [stdout]     ///           println!("{}",entry.path);
[INFO] [stdout]     ///       }
[INFO] [stdout]     ///   }
[INFO] [stdout]     ///   dir.extract("./demo");
[INFO] [stdout]     /// ```
[INFO] [stdout]     ///
[INFO] [stdout]     pub fn extract(&self, base_dir: impl ToString) ->std::io::Result<()>{
[INFO] [stdout]         std::fs::create_dir_all(base_dir.to_string()).expect("create to dir error");
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_dir {
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 std::fs::create_dir_all(path.clone()).expect("create to dir error");
[INFO] [stdout]                 if cfg!(target_os = "windows") {
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }else{
[INFO] [stdout]                     use std::os::unix::fs::PermissionsExt;
[INFO] [stdout]                     let permissions = std::fs::Permissions::from_mode(0o777);
[INFO] [stdout]                     std::fs::set_permissions(path.clone(), permissions).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout] 
[INFO] [stdout]         for entry in self.data.clone().into_iter() {
[INFO] [stdout]             if entry.is_file {
[INFO] [stdout]                 use std::fs::{self, File, OpenOptions};
[INFO] [stdout]                 use std::io::prelude::*;
[INFO] [stdout]                 use std::os::unix::fs::OpenOptionsExt;
[INFO] [stdout]                 let path = PathBuf::from_str(&base_dir.to_string()).expect("parse to to PathBuf error");
[INFO] [stdout]                 let path = path.join(get_new_path(&entry.path.to_string()));
[INFO] [stdout]                 if !path.exists(){
[INFO] [stdout]                     let mut open_options = OpenOptions::new();
[INFO] [stdout]                     open_options.mode(0o777); // Set read/write permission for owner, read-only for others
[INFO] [stdout]                     let file = open_options.create(true).write(true).open(path).unwrap();
[INFO] [stdout]                     let mut file_writer = std::io::BufWriter::new(file);
[INFO] [stdout]                     file_writer.write_all(&entry.contents).unwrap();
[INFO] [stdout]                 }
[INFO] [stdout]             }
[INFO] [stdout]         }
[INFO] [stdout]         Ok(())
[INFO] [stdout]     }
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] /// include dir at compile time
[INFO] [stdout] /// in default die path is current dir
[INFO] [stdout] ///
[INFO] [stdout] /// `export YOK_PATH="/home/andrew/code/gitlab/test_code/"`
[INFO] [stdout] ///
[INFO] [stdout] /// you can also set YOK_PATH env before cargo run
[INFO] [stdout] ///
[INFO] [stdout] /// If the dir path is not the path you set, run `cargo clean` before `cargo run`
[INFO] [stdout] /// ```rust
[INFO] [stdout] ///   use yok::include_dir;
[INFO] [stdout] ///   use yok::Dir;
[INFO] [stdout] ///   use yok::DirEntry;
[INFO] [stdout] ///   use yok::Bytes;
[INFO] [stdout] ///   const DATA:&[u8] = include_dir();
[INFO] [stdout] ///   let dir:Dir = DATA.into_dir();
[INFO] [stdout] ///   for entry in &dir.data{
[INFO] [stdout] ///       if entry.is_file{
[INFO] [stdout] ///           println!("{}",String::from_utf8_lossy(&entry.contents));
[INFO] [stdout] ///       }else if entry.is_dir {
[INFO] [stdout] ///           println!("{}",entry.path);
[INFO] [stdout] ///       }
[INFO] [stdout] ///   }
[INFO] [stdout] ///   dir.extract("./demo");
[INFO] [stdout] /// ```
[INFO] [stdout] ///
[INFO] [stdout] pub const fn include_dir() -> &'static [u8] {
[INFO] [stdout]     include_bytes!("../../.yok")
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] fn main() {
[INFO] [stdout]     use yok::include_dir;
[INFO] [stdout]     use yok::Bytes;
[INFO] [stdout]     use yok::Dir;
[INFO] [stdout]     use yok::DirEntry;
[INFO] [stdout]     const DATA: &[u8] = include_dir();
[INFO] [stdout]     let dir: Dir = DATA.into_dir();
[INFO] [stdout]     for entry in &dir.data {
[INFO] [stdout]         if entry.is_file {
[INFO] [stdout]             // println!("{}", String::from_utf8_lossy(&entry.contents));
[INFO] [stdout]         } else if entry.is_dir {
[INFO] [stdout]             // println!("{}", entry.path);
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout]     dir.extract("./path");
[INFO] [stdout] 
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] src
[INFO] [stdout] /target
[INFO] [stdout] Cargo.lock
[INFO] [stdout] .DS_Store
[INFO] [stdout] MIT License
[INFO] [stdout] 
[INFO] [stdout] Copyright (c) [year] [fullname]
[INFO] [stdout] 
[INFO] [stdout] Permission is hereby granted, free of charge, to any person obtaining a copy
[INFO] [stdout] of this software and associated documentation files (the "Software"), to deal
[INFO] [stdout] in the Software without restriction, including without limitation the rights
[INFO] [stdout] to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
[INFO] [stdout] copies of the Software, and to permit persons to whom the Software is
[INFO] [stdout] furnished to do so, subject to the following conditions:
[INFO] [stdout] 
[INFO] [stdout] The above copyright notice and this permission notice shall be included in all
[INFO] [stdout] copies or substantial portions of the Software.
[INFO] [stdout] 
[INFO] [stdout] THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
[INFO] [stdout] IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
[INFO] [stdout] FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
[INFO] [stdout] AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
[INFO] [stdout] LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
[INFO] [stdout] OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
[INFO] [stdout] SOFTWARE.
[INFO] [stdout] use std::fs::File;
[INFO] [stdout] #[allow(warnings)]
[INFO] [stdout] use std::io::{BufWriter, Write};
[INFO] [stdout] use std::path::Path;
[INFO] [stdout] use zip::write::FileOptions;
[INFO] [stdout] use zip::ZipWriter;
[INFO] [stdout] use std::io::Read;
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] fn main() {
[INFO] [stdout]     // Path to the directory to compress
[INFO] [stdout]     let dir_path = Path::new(".");
[INFO] [stdout] 
[INFO] [stdout]     // Path to the output ZIP file
[INFO] [stdout]     let zip_path = Path::new("app.zip");
[INFO] [stdout] 
[INFO] [stdout]     // Create a new ZIP file
[INFO] [stdout]     let file = File::create(&zip_path).unwrap();
[INFO] [stdout]     let writer = BufWriter::new(file);
[INFO] [stdout]     let mut zip = ZipWriter::new(writer);
[INFO] [stdout] 
[INFO] [stdout]     // Recursively add all files and directories in the input directory to the ZIP file
[INFO] [stdout]     add_directory_to_zip(&mut zip, dir_path, "").unwrap();
[INFO] [stdout] 
[INFO] [stdout]     // Finalize the ZIP file
[INFO] [stdout]     zip.finish().unwrap();
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] // Recursively adds a directory (and all its contents) to a ZipWriter
[INFO] [stdout] fn add_directory_to_zip(zip: &mut ZipWriter<BufWriter<File>>, dir_path: &Path, base_path: &str) -> zip::result::ZipResult<()> {
[INFO] [stdout]     for entry in dir_path.read_dir()? {
[INFO] [stdout]         let path = entry?.path();
[INFO] [stdout] 
[INFO] [stdout]         if path.is_dir() {
[INFO] [stdout]             // Recursively add the subdirectory
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let new_base_path = format!("{}/{}", base_path, name);
[INFO] [stdout]             add_directory_to_zip(zip, &path, &new_base_path)?;
[INFO] [stdout]         } else {
[INFO] [stdout]             // Add the file to the ZIP archive
[INFO] [stdout]             let name = path.file_name().unwrap().to_str().unwrap();
[INFO] [stdout]             let options = FileOptions::default()
[INFO] [stdout]                 .compression_method(zip::CompressionMethod::Deflated)
[INFO] [stdout]                 .unix_permissions(0o755); // Set appropriate permissions for the file
[INFO] [stdout]             zip.start_file(format!("{}/{}", base_path, name), options)?;
[INFO] [stdout]             let mut file = File::open(&path)?;
[INFO] [stdout]             let mut buffer = Vec::new();
[INFO] [stdout]             file.read_to_end(&mut buffer)?;
[INFO] [stdout]             zip.write_all(&buffer)?;
[INFO] [stdout]         }
[INFO] [stdout]     }
[INFO] [stdout] 
[INFO] [stdout]     Ok(())
[INFO] [stdout] }
[INFO] [stdout] 
[INFO] [stdout] stderr:
[INFO] [stdout] thread 'main' panicked at /opt/rustwide/workdir/src/lib.rs:236:55:
[INFO] [stdout] create to dir error: Os { code: 30, kind: ReadOnlyFilesystem, message: "Read-only file system" }
[INFO] [stdout] stack backtrace:
[INFO] [stdout]    0:     0x55f68113b485 - std::backtrace_rs::backtrace::libunwind::trace::he49dc9a9e3164223
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5
[INFO] [stdout]    1:     0x55f68113b485 - std::backtrace_rs::backtrace::trace_unsynchronized::h3a3e77c68030aa6b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
[INFO] [stdout]    2:     0x55f68113b485 - std::sys_common::backtrace::_print_fmt::h9479ad2f99afd5d4
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:68:5
[INFO] [stdout]    3:     0x55f68113b485 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hfb01aa1fa3fb1821
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:44:22
[INFO] [stdout]    4:     0x55f68115889b - core::fmt::rt::Argument::fmt::h125e56152abbc1c3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/fmt/rt.rs:165:63
[INFO] [stdout]    5:     0x55f68115889b - core::fmt::write::hb0ab4ff05ccfe741
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/fmt/mod.rs:1169:21
[INFO] [stdout]    6:     0x55f68113941f - std::io::Write::write_fmt::h456b7988df61daf3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/io/mod.rs:1835:15
[INFO] [stdout]    7:     0x55f68113b25e - std::sys_common::backtrace::_print::h79ca548f3a2adf4b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:47:5
[INFO] [stdout]    8:     0x55f68113b25e - std::sys_common::backtrace::print::h9aebf997b2fea2d3
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:34:9
[INFO] [stdout]    9:     0x55f68113c509 - std::panicking::default_hook::{{closure}}::h68a0954af2694526
[INFO] [stdout]   10:     0x55f68113c2d8 - std::panicking::default_hook::h5be50cc6849ffb00
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:298:9
[INFO] [stdout]   11:     0x55f68113c9a3 - std::panicking::rust_panic_with_hook::h3c0df6036729334c
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:795:13
[INFO] [stdout]   12:     0x55f68113c884 - std::panicking::begin_panic_handler::{{closure}}::ha3a21e93c4cfd807
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:664:13
[INFO] [stdout]   13:     0x55f68113b949 - std::sys_common::backtrace::__rust_end_short_backtrace::h19508a8f8ae71dc9
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/sys_common/backtrace.rs:171:18
[INFO] [stdout]   14:     0x55f68113c5b7 - rust_begin_unwind
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:652:5
[INFO] [stdout]   15:     0x55f681113f93 - core::panicking::panic_fmt::h2ba8af99174d83ea
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/panicking.rs:72:14
[INFO] [stdout]   16:     0x55f6811143a6 - core::result::unwrap_failed::h52f3bbb78b59f71d
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/result.rs:1654:5
[INFO] [stdout]   17:     0x55f681117b93 - core::result::Result<T,E>::expect::h2c0d42f454820c3e
[INFO] [stdout]   18:     0x55f681115ee8 - yok::Dir::extract::h06b970ca2cb27101
[INFO] [stdout]   19:     0x55f6811188f8 - rust_out::main::_doctest_main_src_lib_rs_218_0::h6bc729fd80acef8f
[INFO] [stdout]   20:     0x55f681118826 - rust_out::main::h90fc46ea9798ded1
[INFO] [stdout]   21:     0x55f6811171e3 - core::ops::function::FnOnce::call_once::h48eb9b1eb2de063c
[INFO] [stdout]   22:     0x55f681114a06 - std::sys_common::backtrace::__rust_begin_short_backtrace::h747a6d1e1b11dda9
[INFO] [stdout]   23:     0x55f681115c49 - std::rt::lang_start::{{closure}}::hc32502aff423e72f
[INFO] [stdout]   24:     0x55f68113629d - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hac8b4a62b6f52371
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/core/src/ops/function.rs:284:13
[INFO] [stdout]   25:     0x55f68113629d - std::panicking::try::do_call::h6fc24bc97db29d34
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:559:40
[INFO] [stdout]   26:     0x55f68113629d - std::panicking::try::hc544b64aa2eea933
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:523:19
[INFO] [stdout]   27:     0x55f68113629d - std::panic::catch_unwind::hefb17e81fb559b9c
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panic.rs:149:14
[INFO] [stdout]   28:     0x55f68113629d - std::rt::lang_start_internal::{{closure}}::h834103e2d23d958b
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/rt.rs:141:48
[INFO] [stdout]   29:     0x55f68113629d - std::panicking::try::do_call::he39c25d597788515
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:559:40
[INFO] [stdout]   30:     0x55f68113629d - std::panicking::try::hf4ef8dd97697f2c7
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panicking.rs:523:19
[INFO] [stdout]   31:     0x55f68113629d - std::panic::catch_unwind::haa22d191a5c8abfb
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/panic.rs:149:14
[INFO] [stdout]   32:     0x55f68113629d - std::rt::lang_start_internal::h8104aca277c551bf
[INFO] [stdout]                                at /rustc/b642703cf9526da1e72c0b6755753b939a9c6b6d/library/std/src/rt.rs:141:20
[INFO] [stdout]   33:     0x55f681115c27 - std::rt::lang_start::h363611def46ee6df
[INFO] [stdout]   34:     0x55f681118b05 - main
[INFO] [stdout]   35:     0x7fe6846b5d90 - <unknown>
[INFO] [stdout]   36:     0x7fe6846b5e40 - __libc_start_main
[INFO] [stdout]   37:     0x55f6811145c5 - _start
[INFO] [stdout]   38:                0x0 - <unknown>
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] failures:
[INFO] [stdout]     src/lib.rs - Dir::extract (line 218)
[INFO] [stdout]     src/lib.rs - DirEntry (line 10)
[INFO] [stdout]     src/lib.rs - include_dir (line 282)
[INFO] [stdout] 
[INFO] [stdout] test result: FAILED. 0 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.38s
[INFO] [stdout] 
[INFO] running `Command { std: "docker" "inspect" "e76c937cc21701deaabf5b46b1346000c16fa080e14f4f3a7cb3ae9c9e194891", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "e76c937cc21701deaabf5b46b1346000c16fa080e14f4f3a7cb3ae9c9e194891", kill_on_drop: false }`
[INFO] [stdout] e76c937cc21701deaabf5b46b1346000c16fa080e14f4f3a7cb3ae9c9e194891
