diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1d085ca --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +** diff --git a/.gitignore b/.gitignore index 1733ca8..c03ca78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /target dist -docs +/docs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 46d9fd5..4ddfdb0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,7 @@ workflow: - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"' default: - image: 'rust:slim' + image: 'quirinecker/rust-openssl' build: script: diff --git a/Cargo.lock b/Cargo.lock index 158cf5d..2c50c96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,5 +3,1156 @@ version = 3 [[package]] -name = "docki-cli" +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "docki" +version = "0.2.0" +dependencies = [ + "bytes", + "colored", + "home", + "regex", + "reqwest", + "text_io", + "zip-extract", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" + +[[package]] +name = "futures-io" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" + +[[package]] +name = "futures-sink" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" + +[[package]] +name = "futures-task" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" + +[[package]] +name = "futures-util" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "h2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "home" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408" +dependencies = [ + "winapi", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[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.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + +[[package]] +name = "openssl" +version = "0.10.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "proc-macro2" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "text_io" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f0c8eb2ad70c12a6a69508f499b3051c924f4b1cfeae85bfad96e6bc5bba46" + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "unicode-bidi" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "bzip2", + "crc32fast", + "flate2", + "thiserror", + "time", +] + +[[package]] +name = "zip-extract" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c5cc0309f6e81ab96c2b43d5e935025f8732c886690be8f78f68e06bad1d274" +dependencies = [ + "log", + "thiserror", + "zip", +] diff --git a/Cargo.toml b/Cargo.toml index 335bd77..2fe412d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "docki" -version = "0.1.1" +version = "0.3.0" edition = "2021" description = "cli for building and publishing documentation using asciidoctor" license-file = "LICENSE.txt" @@ -8,3 +8,10 @@ license-file = "LICENSE.txt" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bytes = "1.4.0" +colored = "2.0.0" +home = "0.5.4" +regex = "1.7.1" +reqwest = { version = "0.11.14", features = ["blocking"] } +text_io = "0.1.12" +zip-extract = "0.1.1" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d506f3d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM rust:slim + +WORKDIR /opt/rust + +RUN apt update \ + && apt-get -y upgrade \ + && apt-get -y install libssl-dev pkg-config diff --git a/res/test/docs/core/functions.adoc b/res/test/docs/core/functions.adoc new file mode 100644 index 0000000..e69de29 diff --git a/res/test/docs/core/index.adoc b/res/test/docs/core/index.adoc new file mode 100644 index 0000000..e69de29 diff --git a/res/test/docs/fail.txt b/res/test/docs/fail.txt new file mode 100644 index 0000000..e69de29 diff --git a/res/test/docs/functions.adoc b/res/test/docs/functions.adoc new file mode 100644 index 0000000..e69de29 diff --git a/res/test/docs/index.adoc b/res/test/docs/index.adoc new file mode 100644 index 0000000..e69de29 diff --git a/sh/asciidoctor-revealjs-sh b/sh/asciidoctor-revealjs-sh new file mode 100755 index 0000000..eb87d1d --- /dev/null +++ b/sh/asciidoctor-revealjs-sh @@ -0,0 +1 @@ +asciidoctor-revealjs $1 -a revealjsdir=$2 --out-file=$3 diff --git a/src/app/builder/asciidoctor.rs b/src/app/builder/asciidoctor.rs index 13b48b9..e18b680 100644 --- a/src/app/builder/asciidoctor.rs +++ b/src/app/builder/asciidoctor.rs @@ -1,29 +1,108 @@ use std::process; +use regex::Regex; + use super::Builder; -pub struct AsciiDoctorBuilder; +fn exec_command(command: &mut process::Command) -> Result<(), String> { + let result = command.output(); -impl Builder for AsciiDoctorBuilder { - fn build(&self, in_path: &str, out_path: &str) -> Result<(), String> { - let result = process::Command::new("asciidoctor") - .arg(format!("{in_path}")) - .arg(format!("--out-file={out_path}")) - .output(); - - if let Ok(success) = result { - if success.stderr.len() == 0 { - return Ok(()); - } else { - return Err(AsciiDoctorBuilder::from_utf8(success.stderr)); - } + if let Ok(success) = result { + if success.stderr.len() == 0 { + return Ok(()); } else { - return Err("command failed to execute".to_string()); + return Err(AsciiDoctorDocsBuilder::from_utf8(success.stderr)); } + } else { + println!("{}", result.unwrap_err()); + return Err("asciidoctor not installed. For more information run docki health!".to_string()); } } -impl AsciiDoctorBuilder { +fn asciidoctor_docs(in_path: &str, out_path: &str) -> process::Command { + let mut command = process::Command::new(format!("asciidoctor")); + + command + .arg(format!("--out-file={out_path}")) + .arg(format!("{in_path}")); + + return command; +} + +fn asciidoctor_slides(in_path: &str, out_path: &str) -> process::Command { + let mut command = process::Command::new(format!("asciidoctor-revealjs")); + let out_dir = parent_path(out_path); + let revealjs_path = path_between(out_dir.to_string(), "./dist/slides/revealjs".to_string()); + + command + .arg(format!("{in_path}")) + .arg(format!("-a")) + .arg(format!("revealjsdir={revealjs_path}")) + .arg(format!("--out-file={out_path}")); + + return command; +} + +fn parent_path(child_path: &str) -> String { + let split: Vec<&str> = child_path.split("/").collect(); + let slice = &split[..split.len() - 1]; + return slice.join("/"); +} + +pub fn path_between(from: String, to: String) -> String { + let from_segments = transform_input_to_clone_split(&from); + let to_segments = transform_input_to_clone_split(&to); + let last_matching_index = matching_from_start(&from_segments, &to_segments); + let number_of_backs = from_segments.len() - last_matching_index; + let mut path_between = path_back(number_of_backs); + let path_to_to_path = &to_segments[last_matching_index..]; + path_between.push_str(&path_to_to_path.join("/")); + return path_between; +} + +fn transform_input_to_clone_split(input: &String) -> Vec { + let regex = Regex::new(r"/$").unwrap(); + let first_transformation = input.clone().replace("./", ""); + return regex.replace_all(&first_transformation, "") + .to_string().split("/") + .collect::>() + .iter().map(|s| s.to_string()).collect() +} + +fn path_back(count: usize) -> String { + let mut path = "".to_string(); + + for _ in 0..count { + path.push_str("../"); + } + + return path; +} + +pub fn matching_from_start(from_segments: &Vec, to_segments: &Vec) -> usize { + for (index, from_segment) in from_segments.iter().enumerate() { + if let Some(to_segment) = to_segments.get(index){ + if from_segment != to_segment { + return index; + } + } else { + return index; + } + } + + return from_segments.len(); +} + +pub struct AsciiDoctorDocsBuilder; + +impl Builder for AsciiDoctorDocsBuilder { + fn build(&self, in_path: &str, out_path: &str) -> Result<(), String> { + let mut command = asciidoctor_docs(in_path, out_path); + return exec_command(&mut command); + } +} + +impl AsciiDoctorDocsBuilder { fn from_utf8(input: Vec) -> String { return match String::from_utf8(input) { Ok(m) => m, @@ -31,3 +110,12 @@ impl AsciiDoctorBuilder { }; } } + +pub struct AsciiDoctorSlideBuilder; + +impl Builder for AsciiDoctorSlideBuilder { + fn build(&self, in_path: &str, out_path: &str) -> Result<(), String> { + let mut command = asciidoctor_slides(in_path, out_path); + return exec_command(&mut command); + } +} diff --git a/src/app/commands/build.rs b/src/app/commands/build.rs index b7ce21e..f1515d9 100644 --- a/src/app/commands/build.rs +++ b/src/app/commands/build.rs @@ -1,99 +1,19 @@ -use std::{collections::HashMap, fs, path::Path}; +use std::collections::HashMap; -use crate::app::builder::{asciidoctor::AsciiDoctorBuilder, Builder}; +use super::{executions::build_execution::BuildExecution, traits::Command}; -use super::traits::Command; - -pub struct Build { - builder: Box, -} - -impl Build { - fn build_dir(&self, path: &str) -> Vec> { - let mut results = vec![]; - let Ok(dirs) = fs::read_dir(path) else { - return vec![Err(format!("direcotry {path} was not found. The filesystem was maybe updated while build"))] - }; - - for result in dirs { - let Ok(entry) = result else { - return vec![Err("could not read entry".to_string())]; - }; - - let path = entry - .path() - .to_str() - .expect("could not get text path") - .to_string() - .clone(); - - if entry.path().is_dir() { - results = [results, self.build_dir(&path)].concat() - } else { - results.push(self.build_file(&path)); - } - } - - return results; - } - - fn build_file(&self, path: &str) -> Result<(), String> { - let out_path = path - .clone() - .replace("docs", "dist") - .replace(".adoc", ".html"); - - return self.builder.build(&path, &out_path); - } - - fn docs_directory_exists(&self, path: &String) -> bool { - Path::new(path).is_dir() - } -} +pub struct Build; impl Command for Build { fn execute(&self, _args: &HashMap) -> Result<(), String> { - // let Ok(project_cwd_object) = env::current_dir() else { - // return Err("current dirctory does not seem to exist".to_string()) - // }; - // - // let Some(project_cwd) = project_cwd_object.to_str() else { - // return Err("invalid path".to_string()); - // }; - - let path = format!("./docs/"); - let mut error_count = 0; - - if !self.docs_directory_exists(&path) { - error_count += 1; - println!( - "docs directory does not exist. Either create it or clone the template from gitlab" - ) - } else { - for result in self.build_dir(&path) { - match result { - Err(e) => { - error_count += 1; - println!("{e}"); - } - Ok(()) => println!("success"), - }; - } - } - - if error_count > 0 { - return Err(format!("failed with {} errors", error_count)); - } - - return Ok(()); + let mut build_execution = BuildExecution::new(); + return build_execution.execute(); } fn new() -> Self where Self: Sized, { - return Build { - builder: Box::new(AsciiDoctorBuilder {}), - }; + return Build {} } } diff --git a/src/app/commands/executions/build_execution.rs b/src/app/commands/executions/build_execution.rs new file mode 100644 index 0000000..dd466f9 --- /dev/null +++ b/src/app/commands/executions/build_execution.rs @@ -0,0 +1,163 @@ +use std::{fs, path::{Path, PathBuf}, io::Cursor}; + +use crate::app::{ + builder::{ + asciidoctor::{AsciiDoctorDocsBuilder, AsciiDoctorSlideBuilder}, + Builder, + }, + fs_util, +}; + +pub struct BuildExecution { + progress: usize, + goal: usize, + doc_builder: Box, + slide_builder: Box, +} + +impl BuildExecution { + pub fn new() -> Self { + return BuildExecution { + progress: 0, + goal: 0, + slide_builder: Box::new(AsciiDoctorSlideBuilder {}), + doc_builder: Box::new(AsciiDoctorDocsBuilder {}), + }; + } + + pub fn execute(&mut self) -> Result<(), String> { + let path = "./docs/".to_string(); + + if !Self::directory_exists(&path) { + return Err("docs directory does not exist it. Create it or use the template".to_string()) + } + + if let Err(error) = Self::prepare() { + return Err(error); + } + + return self.build_dir(&path); + } + + fn build_file( + &self, + builder: &Box, + in_path: &str, + out_path: &str, + ) -> Result<(), String> { + return builder.build(&in_path, &out_path); + } + + fn build_file_and_status( + &self, + builder: &Box, + in_path: &str, + out_path: &str, + conversion_type: &str, + ) { + let result = self.build_file(builder, in_path, out_path); + if result.is_ok() { + self.display_status(in_path, out_path, conversion_type) + } else { + self.display_status(in_path, out_path, "error"); + let error = result.unwrap_err(); + println!("{error}"); + } + } + + fn copy(&self, in_path: &str, out_path: &str) { + let segments: &Vec<&str> = &out_path.split("/").collect(); + let parent_dir = &segments[0..segments.len() - 1].join("/"); + Self::create_dir_recursive(parent_dir); + let result = fs::copy(in_path, out_path); + if result.is_ok() { + self.display_status(in_path, out_path, "copy"); + } else { + self.display_status(in_path, out_path, "error"); + let error = result.unwrap_err(); + println!("{error}"); + } + } + + fn create_dir_recursive(path: &str) { + let mut validated_path = "./".to_string(); + for segment in path.split("/") { + validated_path.push_str(format!("{segment}/").as_str()); + if !Self::directory_exists(&validated_path) { + fs::create_dir(&validated_path).unwrap() + } + } + } + + fn display_status(&self, in_path: &str, out_path: &str, conversion_type: &str) -> () { + println!( + "({} / {}) [{}] {} -> {}", + self.progress, self.goal, conversion_type, in_path, out_path + ); + } + + fn build_doc(&self, in_path: &str, out_path: &str) { + self.build_file_and_status(&self.doc_builder, in_path, out_path, "doc"); + } + + fn prepare() -> Result<(), String> { + let reveal_version = "3.9.2"; + let target = format!("https://github.com/hakimel/reveal.js/archive/{reveal_version}.zip"); + + let Ok(response) = reqwest::blocking::get(target) else { + return Err("could not downlaod revealjs".to_string()) + }; + + let Ok(bytes) = response.bytes() else { + return Err("could not extract bytes".to_string()) + }; + + let out = PathBuf::from("./docs/slides/revealjs"); + + if zip_extract::extract(Cursor::new(bytes), &out, true).is_err() { + return Err("could not write extracted archive to disk".to_string()); + } + + return Ok(()) + } + + fn build_slide(&self, in_path: &str, out_path: &str) { + self.build_file_and_status(&self.slide_builder, in_path, out_path, "slide"); + } + + fn directory_exists(path: &String) -> bool { + Path::new(path).is_dir() + } + + fn build_dir(&mut self, path: &str) -> Result<(), String> { + let result = fs_util::fetch_paths_recursive(&path); + + let Ok(paths) = result else { + return Err(result.unwrap_err()) + }; + + for (index, path) in paths.iter().enumerate() { + self.progress = index + 1; + self.goal = paths.len(); + + if path.ends_with(".adoc") && path.starts_with("./docs/slides") { + let out_path = path + .clone() + .replace("adoc", "html") + .replace("/docs/", "/dist/"); + self.build_slide(&path, &out_path) + } else if path.ends_with(".adoc") { + let out_path = path + .clone() + .replace("adoc", "html") + .replace("/docs/", "/dist/"); + self.build_doc(&path, &out_path) + } else { + let out_path = path.clone().replace("/docs/", "/dist/"); + self.copy(&path, &out_path) + } + } + + return Ok(()); + } +} diff --git a/src/app/commands/executions/mod.rs b/src/app/commands/executions/mod.rs new file mode 100644 index 0000000..ea118d9 --- /dev/null +++ b/src/app/commands/executions/mod.rs @@ -0,0 +1 @@ +pub mod build_execution; diff --git a/src/app/commands/health.rs b/src/app/commands/health.rs new file mode 100644 index 0000000..4cbca6c --- /dev/null +++ b/src/app/commands/health.rs @@ -0,0 +1,91 @@ +use std::{collections::HashMap, process, io::ErrorKind}; + +use colored::Colorize; + +use super::traits::Command; + +pub struct Health; + +const INFO_ASCIIDOC: &str = " +Install the binary with your package manager! + +sudo apt install asciidoctor +brew install asciidoctor +gem install asciidoctor +sudo pacman -Syu asciidoctor +yay -Syu asciidoctor +"; + +const INFO_REVEAL: &str = " +There are two options to install it: + +Option 1: +- run `docki install-reveal + +Option 2: +- Install the binary from Github https://github.com/asciidoctor/asciidoctor-reveal.js/releases +- Move the downloaded binary in a folder included in the path +- Make sure the binary is called asciidoctor-revealjs and not asciidoctor-revealjs-linux or similar +"; + +impl Command for Health { + fn execute(&self, _args: &HashMap) -> Result<(), String> { + Self::health(); + return Ok(()) + } + + fn new() -> Self where Self: Sized { + return Self {} + } +} + + +impl Health { + fn health() { + Self::check_asciidoc(); + Self::check_reveal(); + } + + fn check_reveal() -> () { + if Self::reveal_is_installed() { + Self::print_health_ok("asciidoctor-revealjs") + } else { + Self::print_health_not_ok("asciidoctor-revealjs", INFO_REVEAL) + } + } + + fn reveal_is_installed() -> bool { + return Self::check_command("asciidoctor-revealjs") + } + + fn check_asciidoc() -> () { + if Self::asciidoc_is_installed() { + Self::print_health_ok("asciidoctor") + } else { + Self::print_health_not_ok("asciidoctor", INFO_ASCIIDOC) + } + } + + fn asciidoc_is_installed() -> bool { + return Self::check_command("asciidoctor") + } + + fn check_command(command: &str) -> bool { + return match process::Command::new(command) + .output() { + Ok(_) => true, + Err(e) => ErrorKind::NotFound != e.kind() + } + } + + fn print_health_ok(name: &str) { + println!("- ✔️ {}", name.bright_green()); + } + + fn print_health_not_ok(name: &str, info: &str) { + println!("- ❗{}", name.bright_red()); + println!("{}", info.bright_black()) + } + +} + diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index d7f1263..fc7951d 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -2,10 +2,13 @@ use std::collections::HashMap; use traits::Command; -use self::build::Build; +use self::{build::Build, health::Health, reveal::Reveal}; pub mod traits; +pub mod executions; mod build; +mod health; +mod reveal; pub struct CommandRegistry { commands: HashMap> @@ -15,7 +18,10 @@ impl CommandRegistry { pub fn register_all(&mut self) { let registry = self; - registry.register("/build".to_string(), Box::new(Build::new()), true) + registry.register("/build".to_string(), Box::new(Build::new()), true); + registry.register("/health".to_string(), Box::new(Health::new()), true); + registry.register("/install-reveal".to_string(), Box::new(Reveal::new()), true); + } pub fn register(&mut self, path: String, command: Box, enabled: bool) { diff --git a/src/app/commands/reveal.rs b/src/app/commands/reveal.rs new file mode 100644 index 0000000..21ea9d3 --- /dev/null +++ b/src/app/commands/reveal.rs @@ -0,0 +1,43 @@ +use std::{fs::File, io::Write}; + +use crate::app::fs_util; + +use super::traits::Command; + +pub struct Reveal; + +const ASCIIDOC_REVEAL_VERSION: &str= "v4.1.0-rc.5"; + +fn url() -> String { + return format!("https://github.com/asciidoctor/asciidoctor-reveal.js/releases/download/{}/asciidoctor-revealjs-linux", ASCIIDOC_REVEAL_VERSION); +} + +impl Command for Reveal { + fn execute(&self, _args: &std::collections::HashMap) -> Result<(), String> { + Self::install_asciidocto_revealjs(); + return Ok(()) + } + + fn new() -> Self where Self: Sized { + return Self {} + } +} + +impl Reveal { + fn install_asciidocto_revealjs() -> () { + let result = reqwest::blocking::get(url()) + .expect("Could not download reveal. Make sure you are connected to the internet"); + + let binary = result.bytes().expect("could not get binary"); + + let home_path = home::home_dir().expect("could not find home dir"); + let save_path = format!("{}/.docki/asciidoctor-revealjs", home_path.display()); + let save_dir = format!("{}/.docki", home_path.display()); + + fs_util::create_dir_recursive(save_dir.as_str()); + + let mut file = File::create(save_path).expect("could not save binary"); + file.write_all(&binary).expect("could not save binary"); + } + +} diff --git a/src/app/fs_util/mod.rs b/src/app/fs_util/mod.rs new file mode 100644 index 0000000..e01d58e --- /dev/null +++ b/src/app/fs_util/mod.rs @@ -0,0 +1,84 @@ +use std::{env, fs, path::Path}; + +struct RecursivePathFetch { + paths: Vec, + path: String, +} + +impl RecursivePathFetch { + pub fn new_with_extension_filter(path: String) -> Self { + return Self { + paths: vec![], + path, + }; + } + + pub fn fetch(&mut self) -> Result, String> { + if let Err(error) = self.read_dir(self.path.clone()) { + return Err(error); + } else { + return Ok(self.paths.clone()); + } + } + + fn read_dir(&mut self, path: String) -> Result<(), String> { + let Ok(entries) = fs::read_dir(path) else { + return self.dir_not_found(); + }; + + for result in entries { + let entry = result.unwrap(); + let path = entry.path(); + let str_path = path.to_str().unwrap(); + + if path.is_file() { + self.paths.push(str_path.to_string()) + } else if path.is_dir() { + let read_result = self.read_dir(str_path.to_string()); + if read_result.is_err() { + return read_result; + } + } + } + + return Ok(()); + } + + fn dir_not_found(&self) -> Result<(), String> { + return Err(format!( + "directory {} was not found or was changed while building", + self.path + )); + } +} + +pub fn fetch_paths_recursive(path: &str) -> Result, String> { + let mut path_fetch = RecursivePathFetch::new_with_extension_filter(path.to_string()); + + return path_fetch.fetch(); +} + +pub fn create_dir_recursive(path: &str) { + let mut validated_path = "".to_string(); + for segment in path.split("/") { + validated_path.push_str(format!("{segment}/").as_str()); + if !directory_exists(&validated_path) { + fs::create_dir(&validated_path).unwrap() + } + } +} + +pub fn directory_exists(path: &String) -> bool { + Path::new(path).is_dir() +} + +pub fn expand_path(path: String) -> String { + let home_dir = env::var("HOME").expect("could not find home dir"); + + return path.replace("~", &home_dir); +} + +pub fn docki_path_env() -> String { + let current = env::var("PATH").unwrap_or("".to_string()); + return expand_path(format!("{}:~/.docki/", current)); +} diff --git a/src/app/mod.rs b/src/app/mod.rs index c8212e7..ff73392 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,7 +1,9 @@ mod commands; pub mod builder; +pub mod fs_util; use std::collections::HashMap; +use std::env; use commands::traits::Command; use commands::CommandRegistry; @@ -17,7 +19,8 @@ impl App { } } - pub fn start(&self, args: Vec) { + pub fn start(self, args: Vec) { + Self::preapare_env_path(); let command_args = &args[1..]; let mut path = String::from(""); let mut argument_map = HashMap::new(); @@ -44,7 +47,11 @@ impl App { self.execute_path(&path, &argument_map); } - fn execute_path(&self, path: &String, args: &HashMap) { + fn preapare_env_path() { + env::set_var("PATH", fs_util::docki_path_env()); + } + + fn execute_path(self, path: &String, args: &HashMap) { let command = self.command_regisrty.command_by(path); if let Some(c) = command { @@ -59,7 +66,7 @@ impl App { match result { Ok(_) => println!("successfully executed"), - Err(message) => println!("{message}"), + Err(message) => println!("{message}") } } } diff --git a/src/main.rs b/src/main.rs index 11311b0..a5101bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,8 @@ mod app; +#[cfg(test)] +mod test; + use std::env; use app::App; diff --git a/src/test/builder/asciidoctor.rs b/src/test/builder/asciidoctor.rs new file mode 100644 index 0000000..883152e --- /dev/null +++ b/src/test/builder/asciidoctor.rs @@ -0,0 +1,37 @@ +use crate::app::builder::asciidoctor; + +#[test] +fn last_matching_index_0() { + let vec1 = vec!["dings", "dings", "dingens"].iter().map(|s| s.to_string()).collect(); + let vec2 = vec!["dings", "dings", "dings"].iter().map(|s| s.to_string()).collect(); + + let last_maching = asciidoctor::matching_from_start(&vec1, &vec2); + assert_eq!(last_maching, 2); +} + +#[test] +fn last_matching_index_1() { + let vec1 = vec!["dings", "dings", "dingens", "dings", "dingens"].iter().map(|s| s.to_string()).collect(); + let vec2 = vec!["dings", "dings", "dingens", "dings"].iter().map(|s| s.to_string()).collect(); + + let last_maching = asciidoctor::matching_from_start(&vec1, &vec2); + assert_eq!(last_maching, 4); +} + +#[test] +fn path_between_0() { + let path1 = "./docs/dings"; + let path2 = "./dist/dings"; + + let path_between = asciidoctor::path_between(path1.to_string(), path2.to_string()); + assert_eq!(path_between, "../../dist/dings"); +} + +#[test] +fn path_between_1() { + let path1 = "./dist/slides/core/"; + let path2 = "./dist/slides/revealjs"; + + let path_between = asciidoctor::path_between(path1.to_string(), path2.to_string()); + assert_eq!(path_between, "../revealjs") +} diff --git a/src/test/builder/mod.rs b/src/test/builder/mod.rs new file mode 100644 index 0000000..118a2e8 --- /dev/null +++ b/src/test/builder/mod.rs @@ -0,0 +1 @@ +pub mod asciidoctor; diff --git a/src/test/fs_util.rs b/src/test/fs_util.rs new file mode 100644 index 0000000..6cd4a88 --- /dev/null +++ b/src/test/fs_util.rs @@ -0,0 +1,11 @@ +use std::{fs, path::Path}; + +use crate::app::fs_util; + +#[test] +fn test_fetch_asciidoctor_paths_recursive() { + let paths = fs_util::fetch_paths_recursive("res/test/docs").unwrap(); + let len = paths.len(); + dbg!(paths); + assert_eq!(len, 5); +} diff --git a/src/test/mod.rs b/src/test/mod.rs new file mode 100644 index 0000000..f39763a --- /dev/null +++ b/src/test/mod.rs @@ -0,0 +1,2 @@ +mod fs_util; +mod builder;