diff --git a/.gitignore b/.gitignore
index 53649aa..38f07a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,5 +11,5 @@ Cargo.lock
.idea
*.tar.gz
-.vscode
-ctr-bundle
\ No newline at end of file
+.vscode/
+/build/
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..1695232
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,379 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "3.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c167e37342afc5f33fd87bbc870cedd020d2a6dffa05d45ccd9241fbdd146db"
+dependencies = [
+ "atty",
+ "bitflags",
+ "clap_derive",
+ "clap_lex",
+ "indexmap",
+ "lazy_static",
+ "strsim",
+ "termcolor",
+ "textwrap",
+]
+
+[[package]]
+name = "clap_derive"
+version = "3.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "filetime"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "winapi",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
+dependencies = [
+ "cfg-if",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.124"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "os_str_bytes"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quark"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "flate2",
+ "serde",
+ "serde_json",
+ "subprocess",
+ "tar",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
+
+[[package]]
+name = "serde"
+version = "1.0.136"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.136"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "subprocess"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "055cf3ebc2981ad8f0a5a17ef6652f652d87831f79fddcba2ac57bcb9a0aa407"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tar"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
+dependencies = [
+ "filetime",
+ "libc",
+ "xattr",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "xattr"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"
+dependencies = [
+ "libc",
+]
diff --git a/Cargo.toml b/Cargo.toml
index eee4325..44b7dc2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,4 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-clap = { version = "3.0.5", features = ["derive"] }
\ No newline at end of file
+clap = { version = "3.0.5", features = ["derive"] }
+flate2 = "1.0.23"
+tar = "0.4.38"
+subprocess = "0.2.8"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
\ No newline at end of file
diff --git a/README.md b/README.md
index 8f9a918..016c45c 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,40 @@
-# Lumper
+# Quark
+
+## Getting started
+
+### Building phase
+
+To run as an example; you can do this :
+
+```sh
+git clone git@github.com:virt-do/quark.git
+cd quark
+./hack/mk_all.sh
+cargo build
+sudo ./target/debug/quark -o -q hello.qrk
+```
+#### Test building phase without quark run
+
+If we have a file like `hello.qrk`, we can test it like this
+
+```sh
+tar xzf hello.qrk
+sudo ./build/lumper/target/debug/lumper --kernel tmp/quark/tar/linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin -i tmp/quark/tar/initramfs.img
+```
+
+
+## Troubleshooting
+
+### Kaps, build target x86_64-unknown-linux-musl
+
+#### error: failed to run custom build command for `openssl-sys v0.9.72`
+
+If this happened during `./hack/mk_all.sh`, you need to go in `build/kaps/Cargo.toml` and add this in dependencies
+
+```cargo
+openssl = { version = "0.10", features = ["vendored"] }
+```
+
+Relaunch `./hack/mk_all.sh` after this
diff --git a/hack/mk_all.sh b/hack/mk_all.sh
new file mode 100755
index 0000000..dadca90
--- /dev/null
+++ b/hack/mk_all.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+set -e
+
+mkdir -p build
+cd build
+
+# kaps
+if [[ ! -d "kaps" ]]; then
+ git clone https://github.com/virt-do/kaps.git
+else
+ echo "kaps already cloned"
+fi
+
+echo "Building kaps"
+cd kaps/hack
+if [[ ! -d "ctr-bundle" ]]; then
+ ./mkbundle.sh
+else
+ echo "kaps bundle already exists"
+fi
+cd ..
+cargo build --release --target=x86_64-unknown-linux-musl
+cd ..
+echo "kaps done"
+
+# lumper
+if [[ ! -d "lumper" ]]; then
+ git clone https://github.com/virt-do/lumper.git
+else
+ echo "lumper already exists"
+fi
+
+echo "Building lumper"
+cd lumper/kernel
+if [[ ! -d "linux-cloud-hypervisor" ]]; then
+ sudo ./mkkernel.sh
+else
+ echo "kernel already built"
+fi
+cd ../rootfs
+if [[ ! -d "alpine-minirootfs" ]]; then
+ sudo ./mkrootfs.sh
+else
+ echo "rootfs already built"
+fi
+cd ..
+cargo build --release
+cd ..
+echo "lumper done"
diff --git a/src/cli/build.rs b/src/cli/build.rs
index 84f6e7a..cb13786 100644
--- a/src/cli/build.rs
+++ b/src/cli/build.rs
@@ -1,6 +1,20 @@
use clap::Args;
use super::{Handler, Result};
+use serde::{Deserialize, Serialize};
+use std::io::Write;
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct JsonConfig {
+ kernel: String,
+ initrd: String,
+ container_url: String,
+}
+
+// pub enum Result {
+// Ok(Success),
+// Err(Error),
+// }
/// Arguments for `BuildCommand`
///
@@ -16,14 +30,201 @@ pub struct BuildCommand {
#[clap(short, long)]
offline: bool,
- /// Overrides the default kernel command line
+ /// Overrides the default kernel image
+ #[clap(
+ short,
+ long,
+ default_value = "./build/lumper/kernel/linux-cloud-hypervisor"
+ )]
+ kernel: String,
+
+ /// Overrides the default rootfs
+ #[clap(short, long, default_value = "./build/lumper/rootfs/alpine-minirootfs")]
+ rootfs: String,
+
+ /// Path for kaps
+ #[clap(
+ short = 'K',
+ long,
+ default_value = "./build/kaps/target/x86_64-unknown-linux-musl/release/kaps"
+ )]
+ kaps: String,
+
+ /// Overrides the default bundle
#[clap(short, long)]
- kernel_cmd: Option,
+ bundle: String,
+}
+
+fn copy_dir(src: &str, workdir: &str) -> Result<()> {
+ println!("Copying directory {} to {}", src, workdir);
+ std::process::Command::new("cp")
+ .arg("-r")
+ .arg(src)
+ .arg(workdir)
+ .status()
+ .unwrap();
+
+ Ok(())
}
/// Method that will be called when the command is executed.
impl Handler for BuildCommand {
fn handler(&self) -> Result<()> {
+ // If offline is not set, display error message
+ let workdir = "/tmp/quark/";
+
+ if !self.offline {
+ println!("Online mode is not supported yet.");
+ return Ok(());
+ }
+
+ // If workdir exists, remove it
+ if std::path::Path::new(workdir).exists() {
+ println!("Removing existing workdir {}", workdir);
+ std::fs::remove_dir_all(workdir).unwrap();
+ }
+
+ // Create the workdir
+ println!("Creating workdir {}", workdir);
+ std::fs::create_dir_all(&workdir)?;
+
+ // If the kernel is a directory, copy it into the workdir
+ if std::fs::metadata(&self.kernel).is_ok() {
+ copy_dir(&self.kernel, workdir)?;
+ } else {
+ // If the kernel doesn't exist, display error message
+ println!("Kernel doesn't exist.");
+ return Ok(());
+ }
+
+ // If the rootfs is a directory, copy it into the workdir
+ if std::fs::metadata(&self.rootfs).is_ok() {
+ copy_dir(&self.rootfs, workdir)?;
+ } else {
+ // If the rootfs doesn't exist, display error message
+ println!("Rootfs doesn't exist.");
+ return Ok(());
+ }
+
+ // Get the rootfs filename
+ let rootfs_path = std::path::Path::new(&self.rootfs);
+ let rootfs_filename = rootfs_path.file_name().unwrap().to_str().unwrap();
+
+ // If kaps exists, copy it into the workdir rootfs
+ if std::fs::metadata(&self.kaps).is_ok() {
+ println!(
+ "Copying kaps to workdir rootfs {}{}",
+ workdir, rootfs_filename
+ );
+
+ std::fs::copy(&self.kaps, &format!("{}/{}/kaps", workdir, rootfs_filename))?;
+ } else {
+ // If kaps doesn't exist, display error message
+ println!("Kaps doesn't exist.");
+ return Ok(());
+ }
+
+ // If bundle exists, copy the directory into the workdir rootfs
+ if std::fs::metadata(&self.bundle).is_ok() {
+ copy_dir(&self.bundle, &format!("{}{}", workdir, rootfs_filename))?;
+ } else if self.bundle.contains("http") {
+ // If bundle is a url, download it
+ /* TODO: implement */
+ // display error message
+ println!("Bundle is a url, not implemented yet.");
+ return Ok(());
+ } else {
+ // If bundle doesn't exist, display error message
+ println!("Bundle doesn't exist.");
+ return Ok(());
+ }
+
+ // Configure rootfs
+ println!("Configuring rootfs");
+
+ // Change the init script to use the kaps bundle
+ println!("Changing init script to use the kaps bundle");
+ let init_script = format!("{}/{}/init", workdir, rootfs_filename);
+ // Remove the old init script
+ std::fs::remove_file(init_script.clone()).unwrap();
+
+ // Write the new init script
+ let mut init_script_file = std::fs::File::create(init_script.clone())?;
+ println!("Writing new init script");
+ let kaps_name = self.kaps.split('/').last().unwrap();
+ let bundle_name = self.bundle.split('/').last().unwrap();
+ let init_script_content = format!(
+ "mount -t devtmpfs dev /dev\nmount -t proc proc /proc\nmount -t sysfs sys /sys\nip link set lo up\necho running kaps\n/{} run --bundle {}\n",
+ kaps_name, bundle_name
+ );
+ write!(&mut init_script_file, "{}", init_script_content)?;
+
+ // Make init script executable
+ println!("Making init script executable");
+ std::process::Command::new("chmod")
+ .arg("+x")
+ .arg(init_script)
+ .status()
+ .unwrap();
+
+ // Create initramfs
+ println!("Creating initramfs");
+ let rootfs_workdir = format!("{}/{}", workdir, rootfs_filename);
+ (subprocess::Exec::shell(format!("find {} -print0", rootfs_workdir))
+ | subprocess::Exec::shell("cpio --null --create --owner root:root --format=newc")
+ | subprocess::Exec::shell(format!("xz -9 --format=lzma > {}initramfs.img", workdir)))
+ .join()
+ .unwrap();
+ println!("Initramfs created");
+
+ // Generate the quark.json file
+ println!("Generating quark.json");
+ let json_data = JsonConfig {
+ kernel: self.kernel.clone().split('/').last().unwrap().to_string(),
+ initrd: "initramfs.img".to_string(),
+ container_url: bundle_name.to_string(),
+ };
+ let serialized = serde_json::to_string(&json_data).unwrap();
+ // Write the quark.json file
+ let quark_json = format!("{}quark.json", workdir);
+ let mut quark_json_file = std::fs::File::create(quark_json.clone())?;
+ write!(&mut quark_json_file, "{}", serialized)?;
+ println!("Quark.json generated");
+
+ // Create the quardle file
+ let quark_name = if self.quardle.ends_with(".qrk") {
+ self.quardle.clone()
+ } else {
+ format!("{}.qrk", self.quardle)
+ };
+ println!("Creating {}tar directory", workdir,);
+ // Create the directory for the quardle file
+ std::fs::create_dir_all(format!("{}tar", workdir))?;
+ // Copy kernel directory into the quark directory
+ copy_dir(&self.kernel, &format!("{}tar", workdir))?;
+ // Copy initramfs into the quark directory
+ println!("Copying initramfs to tar directory");
+ std::fs::copy(
+ &format!("{}initramfs.img", workdir),
+ &format!("{}tar/initramfs.img", workdir),
+ )?;
+ // Copy quark.json into the quark directory
+ println!("Copying quark.json to tar directory");
+ std::fs::copy(&quark_json, &format!("{}tar/quark.json", workdir))?;
+
+ // Create the quardle file
+ println!("Creating {} file", quark_name);
+
+ // Create the tar file
+ std::process::Command::new("tar")
+ .arg("-czf")
+ .arg(quark_name.clone())
+ .arg(format!("{}tar", workdir))
+ .status()
+ .unwrap();
+
+ println!("{} file created", quark_name);
+
Ok(())
}
}