diff --git a/.gitpod.yml b/.gitpod.yml index 21c613b6..5ed5cf03 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,7 +1,6 @@ tasks: - command: | ./lila-docker start - ./lila-docker gitpod-welcome ports: - port: 8080 diff --git a/command/Cargo.lock b/command/Cargo.lock index 07386997..7bb3268a 100644 --- a/command/Cargo.lock +++ b/command/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "cfg-if" version = "1.0.0" @@ -21,11 +27,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "command" version = "0.1.0" dependencies = [ "cliclack", + "colored", + "serde", "strum", ] @@ -39,7 +58,7 @@ dependencies = [ "lazy_static", "libc", "unicode-width", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -48,12 +67,28 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "errno" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + [[package]] name = "indicatif" version = "0.17.7" @@ -76,6 +111,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -88,6 +134,12 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + [[package]] name = "number_prefix" version = "0.4.0" @@ -124,12 +176,45 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rustix" +version = "0.38.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustversion" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "smawk" version = "0.3.2" @@ -160,9 +245,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -204,7 +289,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -213,13 +307,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 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", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -228,47 +337,89 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] diff --git a/command/Cargo.toml b/command/Cargo.toml index e7c64d50..c4afd435 100644 --- a/command/Cargo.toml +++ b/command/Cargo.toml @@ -7,4 +7,6 @@ edition = "2021" [dependencies] cliclack = "0.1.6" +colored = "2.0.4" +serde = { version = "1.0", features = ["derive"] } strum = { version = "0.25.0", features = ["derive", "strum_macros"] } diff --git a/command/src/main.rs b/command/src/main.rs index fc7750a9..73a18f9a 100644 --- a/command/src/main.rs +++ b/command/src/main.rs @@ -1,6 +1,7 @@ -use std::io::Error; - -use cliclack::{confirm, input, intro, multiselect}; +use cliclack::{confirm, input, intro, log, multiselect, spinner}; +use colored::Colorize; +use serde::{Deserialize, Serialize}; +use std::{io::Error, path::Path}; use strum::{EnumIter, EnumString, IntoEnumIterator}; const BANNER: &str = r" @@ -12,7 +13,26 @@ const BANNER: &str = r" |___/ "; -const ENV_PATH: &str = "/.env"; +#[derive(Debug, Serialize, Deserialize)] +struct Config { + profiles: Vec, + setup_database: bool, + su_password: String, + password: String, +} + +impl Config { + fn to_env(&self) -> String { + let mut env = String::new(); + + env.push_str(&format!("COMPOSE_PROFILES={}\n", self.profiles.join(","))); + env.push_str(&format!("SETUP_DATABASE={}\n", self.setup_database)); + env.push_str(&format!("SU_PASSWORD={}\n", self.su_password)); + env.push_str(&format!("PASSWORD={}\n", self.password)); + + env + } +} #[derive(Default, Clone, Eq, PartialEq, Debug)] struct OptionalService { @@ -37,25 +57,69 @@ enum ComposeProfile { #[derive(Debug, Clone, PartialEq, EnumString, strum::Display, Eq, EnumIter)] #[strum(serialize_all = "kebab-case")] enum Repository { + #[strum(serialize = "lichess-org/lila")] Lila, + #[strum(serialize = "lichess-org/lila-ws")] LilaWs, + #[strum(serialize = "lichess-org/lila-db-seed")] LilaDbSeed, + #[strum(serialize = "lichess-org/lifat")] Lifat, + #[strum(serialize = "lichess-org/lila-fishnet")] LilaFishnet, + #[strum(serialize = "lichess-org/lila-engine")] LilaEngine, + #[strum(serialize = "lichess-org/lila-search")] LilaSearch, + #[strum(serialize = "lichess-org/lila-gif")] LilaGif, + #[strum(serialize = "lichess-org/api")] Api, + #[strum(serialize = "lichess-org/chessground")] Chessground, + #[strum(serialize = "lichess-org/pgn-viewer")] PgnViewer, + #[strum(serialize = "lichess-org/scalachess")] Scalachess, + #[strum(serialize = "lichess-org/dartchess")] Dartchess, + #[strum(serialize = "lichess-org/berserk")] Berserk, #[strum(serialize = "cyanfish/bbpPairings")] BbpPairings, } fn main() -> std::io::Result<()> { + let args: Vec = std::env::args().collect(); + + assert!(args.len() > 1, "Missing command"); + + match args[1].as_str() { + "setup" => setup(), + "gitpod-welcome" => gitpod_welcome(), + _ => panic!("Unknown command"), + } +} + +fn gitpod_welcome() -> std::io::Result<()> { + println!("{}", "################".green()); + println!( + "{}", + "Your Lichess development environment is starting!".green() + ); + println!( + "{}", + "Monitor the progress in the 'lila' container with the command:".green() + ); + println!("{}", " docker compose logs lila --follow".green().bold()); + println!( + "{}", + "For full documentation, see: https://lichess-org.github.io/lila-gitpod/".green() + ); + Ok(()) +} + +fn setup() -> std::io::Result<()> { intro(BANNER)?; let services = prompt_for_optional_services()?; @@ -82,57 +146,80 @@ fn main() -> std::io::Result<()> { (String::new(), String::new()) }; - let env_contents = [ - format!( - "DIRS={}", - Repository::iter() - .map(|repo| repo.to_string()) - .collect::>() - .join(",") - ), - format!( - "REPOS={}", - [ - vec![ - Repository::Lila, - Repository::LilaWs, - Repository::LilaDbSeed, - Repository::Lifat, - ], - services - .iter() - .filter_map(|service| service.repositories.clone()) - .flatten() - .collect::>(), - ] - .concat() + let config = Config { + profiles: services .iter() - .map(std::string::ToString::to_string) - .collect::>() - .join(",") - ), - format!( - "COMPOSE_PROFILES={}", - services - .iter() - .filter_map(|service| service.compose_profile.clone()) - .collect::>() - .iter() - .map(std::string::ToString::to_string) - .collect::>() - .join(",") - ), - format!("SETUP_DB={setup_database}"), - format!("SU_PASSWORD={su_password}"), - format!("PASSWORD={password}"), - ] - .join("\n"); - - match std::fs::metadata(ENV_PATH) { - Ok(_) => std::fs::write(ENV_PATH, env_contents)?, - Err(_) => println!(".env contents:\n{env_contents}"), + .filter_map(|service| service.compose_profile.clone()) + .map(|profile| profile.to_string()) + .collect(), + setup_database, + su_password, + password, + }; + + // Create a placeholder directory for each of the repos + // otherwise the directories will be created by Docker + // when the volumes are mounted and they may be owned by root + Repository::iter() + .map(|repo| repo.to_string()) + .for_each(|repo| { + let folder = Path::new(&repo).file_name().unwrap(); + let clone_path = Path::new("repos").join(folder); + std::fs::create_dir_all(clone_path).unwrap(); + }); + + let default_repos: Vec = vec![ + Repository::Lila.to_string(), + Repository::LilaWs.to_string(), + Repository::LilaDbSeed.to_string(), + Repository::Lifat.to_string(), + ]; + let optional_repos = services + .iter() + .filter_map(|service| service.repositories.clone()) + .flatten() + .map(|repo| repo.to_string()) + .collect::>(); + let repos_to_clone = default_repos + .iter() + .chain(optional_repos.iter()) + .collect::>(); + + for repo in repos_to_clone { + let repo_url = format!("https://github.com/{repo}.git"); + let mut progress = spinner(); + progress.start(&format!("Cloning {repo}")); + let folder = Path::new(&repo).file_name().unwrap(); + let clone_path = Path::new("repos").join(folder); + + if clone_path.read_dir()?.next().is_some() { + progress.stop(format!("Clone {repo} ✓")); + continue; + } + + let mut cmd = std::process::Command::new("git"); + cmd.arg("clone") + .arg("--origin") + .arg("upstream") + .arg("--depth") + .arg("1") + .arg("--recurse-submodules") + .arg(&repo_url) + .arg(&clone_path); + + let output = cmd.output().unwrap(); + assert!( + output.status.success(), + "Failed to clone {repo} - {output:?}" + ); + + progress.stop(format!("Clone {repo} ✓")); } + let env_content = config.to_env(); + std::fs::write(".env", env_content)?; + log::success("Wrote .env")?; + Ok(()) } diff --git a/docker-compose.yml b/docker-compose.yml index 3c76b982..677549b9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -139,10 +139,8 @@ services: lila_docker_rs: image: rust:1.74.0-slim-bookworm volumes: - - .env:/.env - ./command:/mnt - environment: - - CARGO_HOME=/mnt/.cargo + working_dir: /mnt profiles: - utils diff --git a/lila-docker b/lila-docker index 25641ee1..bba025c2 100755 --- a/lila-docker +++ b/lila-docker @@ -1,37 +1,17 @@ #!/bin/bash -e if [ ! -z "$GITPOD_WORKSPACE_ID" ]; then + export IS_GITPOD=true export SCHEME=https export LILA_DOMAIN=$(gp url 8080 | cut -c9-) export PICFIT_DOMAIN=$(gp url 3001 | cut -c9-) fi run_setup() { - touch .env - docker compose run --rm -it lila_docker_rs bash -c "cargo run --manifest-path /mnt/Cargo.toml" - export $(cat .env | xargs) - - # create a placeholder directory for each of the repos - # otherwise the directories will be created by Docker - # when the volumes are mounted and they may be owned by root - dirs=($(echo $DIRS | tr ',' ' ')) - for dir in "${dirs[@]}"; do - mkdir -p repos/$(basename $dir) - done - - repos=($(echo $REPOS | tr ',' ' ')) - echo "Cloning repos ${repos[@]}..." - for repo in "${repos[@]}"; do - if [[ $repo == */* ]]; then - org="${repo%%/*}" - else - org="lichess-org" - fi - repo=$(basename $repo) - [ ! -d repos/$repo/.git ] && git clone --depth 1 --origin upstream https://github.com/$org/$repo repos/$repo - done + docker compose run --rm lila_docker_rs cargo build + ./command/target/debug/command setup - git -C repos/lila submodule update --init + export $(cat .env | xargs) docker compose build # separate build specifically for utils profile otherwise its Dockerfile changes won't be detected @@ -45,6 +25,10 @@ run_setup() { if [ "$SETUP_DB" = "true" ]; then setup_database fi + + if [ "$IS_GITPOD" = "true" ]; then + ./command/target/debug/command gitpod-welcome + fi } run_start() { @@ -105,20 +89,6 @@ run_formatter() { docker compose run --rm --entrypoint "sbt scalafmtAll" lila } -run_gitpod_welcome() { - GREEN="\e[32m" - BOLDGREEN="\e[1;32m" - ENDCOLOR="\e[0m" - - echo -e "${GREEN}################${ENDCOLOR}" - echo -e "${GREEN}Your Lichess development environment is starting!${ENDCOLOR}" - echo -e "${GREEN}When it's ready, you can access it at:${ENDCOLOR}" - echo -e "${BOLDGREEN} $(gp url 8080)${ENDCOLOR}" - echo -e "${GREEN}Monitor the progress in the 'lila' container with the command:${ENDCOLOR}" - echo -e "${BOLDGREEN} docker compose logs lila --follow${ENDCOLOR}" - echo -e "${GREEN}For full documentation, see: https://lichess-org.github.io/lila-gitpod/${ENDCOLOR}" -} - show_help() { echo "Usage: $0 [start|stop|restart|down|build|format]" } @@ -146,9 +116,6 @@ case $1 in format) run_formatter ;; - gitpod-welcome) - run_gitpod_welcome - ;; *) show_help exit 1