From 1ecc48d9f4f55b78877edbd734a8baf48b847c99 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Thu, 31 Aug 2023 09:48:00 -0700 Subject: [PATCH 1/3] Install node and nvm --- pgml-apps/cargo-pgml-components/Cargo.lock | 2 +- pgml-apps/cargo-pgml-components/Cargo.toml | 2 +- .../src/frontend/javascript.rs | 5 +- .../cargo-pgml-components/src/frontend/nvm.sh | 6 ++ .../src/frontend/sass.rs | 5 +- .../src/frontend/tools.rs | 88 +++++++++++++++++-- pgml-apps/cargo-pgml-components/src/main.rs | 6 +- pgml-apps/cargo-pgml-components/src/util.rs | 19 ++-- 8 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 pgml-apps/cargo-pgml-components/src/frontend/nvm.sh diff --git a/pgml-apps/cargo-pgml-components/Cargo.lock b/pgml-apps/cargo-pgml-components/Cargo.lock index fa54e9722..c02281263 100644 --- a/pgml-apps/cargo-pgml-components/Cargo.lock +++ b/pgml-apps/cargo-pgml-components/Cargo.lock @@ -79,7 +79,7 @@ checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "cargo-pgml-components" -version = "0.1.7" +version = "0.1.8" dependencies = [ "anyhow", "clap", diff --git a/pgml-apps/cargo-pgml-components/Cargo.toml b/pgml-apps/cargo-pgml-components/Cargo.toml index 84be9f5b5..ed7e37973 100644 --- a/pgml-apps/cargo-pgml-components/Cargo.toml +++ b/pgml-apps/cargo-pgml-components/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-pgml-components" -version = "0.1.7" +version = "0.1.8" edition = "2021" authors = ["PostgresML "] license = "MIT" diff --git a/pgml-apps/cargo-pgml-components/src/frontend/javascript.rs b/pgml-apps/cargo-pgml-components/src/frontend/javascript.rs index 90b733122..0c9bde514 100644 --- a/pgml-apps/cargo-pgml-components/src/frontend/javascript.rs +++ b/pgml-apps/cargo-pgml-components/src/frontend/javascript.rs @@ -7,7 +7,8 @@ use std::process::Command; use convert_case::{Case, Casing}; -use crate::util::{execute_command, info, unwrap_or_exit, warn}; +use crate::frontend::tools::execute_with_nvm; +use crate::util::{info, unwrap_or_exit, warn}; /// The name of the JS file that imports all other JS files /// created in the modules. @@ -99,7 +100,7 @@ pub fn bundle() { assemble_modules(); // Bundle JavaScript. - unwrap_or_exit!(execute_command( + unwrap_or_exit!(execute_with_nvm( Command::new(JS_COMPILER) .arg(MODULES_FILE) .arg("--file") diff --git a/pgml-apps/cargo-pgml-components/src/frontend/nvm.sh b/pgml-apps/cargo-pgml-components/src/frontend/nvm.sh new file mode 100644 index 000000000..067872416 --- /dev/null +++ b/pgml-apps/cargo-pgml-components/src/frontend/nvm.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion + +${@} diff --git a/pgml-apps/cargo-pgml-components/src/frontend/sass.rs b/pgml-apps/cargo-pgml-components/src/frontend/sass.rs index dc74cd5d2..c12ba643d 100644 --- a/pgml-apps/cargo-pgml-components/src/frontend/sass.rs +++ b/pgml-apps/cargo-pgml-components/src/frontend/sass.rs @@ -5,7 +5,8 @@ use std::fs::{copy, read_to_string, remove_file, File}; use std::io::Write; use std::process::Command; -use crate::util::{execute_command, info, unwrap_or_exit, warn}; +use crate::frontend::tools::execute_with_nvm; +use crate::util::{info, unwrap_or_exit, warn}; /// The name of the SASS file that imports all other SASS files /// created in the modules. @@ -77,7 +78,7 @@ pub fn bundle() { cleanup_old_bundles(); // Build Sass. - unwrap_or_exit!(execute_command( + unwrap_or_exit!(execute_with_nvm( Command::new(SASS_COMPILER).arg(SASS_FILE).arg(CSS_FILE), )); diff --git a/pgml-apps/cargo-pgml-components/src/frontend/tools.rs b/pgml-apps/cargo-pgml-components/src/frontend/tools.rs index b6b2e785c..33a289b59 100644 --- a/pgml-apps/cargo-pgml-components/src/frontend/tools.rs +++ b/pgml-apps/cargo-pgml-components/src/frontend/tools.rs @@ -1,29 +1,99 @@ //! Tools required by us to build stuff. -use crate::util::{error, execute_command, unwrap_or_exit, warn}; +use crate::util::{debug1, error, execute_command, unwrap_or_exit, warn}; +use std::fs::File; +use std::io::Write; use std::process::{exit, Command}; /// Required tools. static TOOLS: &[&str] = &["sass", "rollup"]; +static NVM_EXEC: &'static str = "/tmp/pgml-components-nvm.sh"; +static NVM_SOURCE: &'static str = "https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh"; +static NVM_SOURCE_DOWNLOADED: &'static str = "/tmp/pgml-components-nvm-source.sh"; /// Install any missing tools. pub fn install() { - if let Err(err) = execute_command(Command::new("node").arg("--version")) { - error("Node is not installed. Install it with nvm or your system package manager."); - debug!("{}", err); - exit(1); - } + install_nvm_entrypoint(); + debug!("installed node entrypoint"); + install_node(); + debug!("installed node"); for tool in TOOLS { - match execute_command(Command::new(tool).arg("--version")) { + match execute_with_nvm(Command::new(tool).arg("--version")) { Ok(_) => (), Err(err) => { - debug!("{}", err); + debug1!(err); warn(&format!("installing {}", tool)); - unwrap_or_exit!(execute_command( + unwrap_or_exit!(execute_with_nvm( Command::new("npm").arg("install").arg("-g").arg(tool) )); } } } } + +pub fn execute_with_nvm(command: &mut Command) -> std::io::Result { + let mut cmd = Command::new(NVM_EXEC); + cmd.arg(command.get_program()); + for arg in command.get_args() { + cmd.arg(arg); + } + execute_command(&mut cmd) +} + +fn install_nvm_entrypoint() { + let mut file = unwrap_or_exit!(File::create(NVM_EXEC)); + unwrap_or_exit!(writeln!(&mut file, "{}", include_str!("nvm.sh"))); + drop(file); + + unwrap_or_exit!(execute_command( + Command::new("chmod").arg("+x").arg(NVM_EXEC) + )); +} + +fn install_node() { + debug!("installing node"); + // Node is already installed. + if let Ok(_) = execute_with_nvm(Command::new("node").arg("--version")) { + debug!("node is available"); + return; + } + + warn("installing node using nvm"); + + debug!("node is not available"); + + if let Err(err) = execute_command(Command::new("nvm").arg("--version")) { + debug!("nvm is not available"); + debug1!(err); + // Install Node Version Manager. + if let Err(err) = execute_command( + Command::new("curl") + .arg("-Ls") + .arg(NVM_SOURCE) + .arg("-o") + .arg(NVM_SOURCE_DOWNLOADED), + ) { + debug!("curl is not available"); + error("couldn't not download nvm from Github, please do so manually before proceeding"); + debug1!(err); + exit(1); + } else { + if let Err(err) = execute_command(Command::new("bash").arg(NVM_SOURCE_DOWNLOADED)) { + error("couldn't install nvm, please do so manually before proceeding"); + debug1!(err); + exit(1); + } else { + warn("installed nvm"); + } + } + } + + if let Err(err) = execute_with_nvm(Command::new("nvm").arg("install").arg("stable")) { + error("couldn't install Node, please do so manually before proceeding"); + debug1!(err); + exit(1); + } else { + warn("installed node") + } +} diff --git a/pgml-apps/cargo-pgml-components/src/main.rs b/pgml-apps/cargo-pgml-components/src/main.rs index 6f2a57a6d..c3ae683c7 100644 --- a/pgml-apps/cargo-pgml-components/src/main.rs +++ b/pgml-apps/cargo-pgml-components/src/main.rs @@ -2,7 +2,7 @@ use clap::{Args, Parser, Subcommand}; use std::env::{current_dir, set_current_dir}; -use std::fs::{create_dir_all}; +use std::fs::create_dir_all; use std::path::Path; #[macro_use] @@ -65,7 +65,9 @@ fn main() { CargoSubcommands::PgmlComponents(pgml_commands) => match pgml_commands.command { Commands::Bundle {} => bundle(pgml_commands.project_path), Commands::Add(command) => match command { - AddCommands::Component { name } => crate::frontend::components::add(&name, pgml_commands.overwrite), + AddCommands::Component { name } => { + crate::frontend::components::add(&name, pgml_commands.overwrite) + } }, }, } diff --git a/pgml-apps/cargo-pgml-components/src/util.rs b/pgml-apps/cargo-pgml-components/src/util.rs index 7205c4a9b..ec3d4aa3d 100644 --- a/pgml-apps/cargo-pgml-components/src/util.rs +++ b/pgml-apps/cargo-pgml-components/src/util.rs @@ -1,8 +1,8 @@ use owo_colors::OwoColorize; use std::fs::File; -use std::io::Write; +use std::io::{ErrorKind, Write}; use std::path::Path; -use std::process::{exit, Command}; +use std::process::Command; macro_rules! unwrap_or_exit { ($i:expr) => { @@ -17,6 +17,13 @@ macro_rules! unwrap_or_exit { }; } +macro_rules! debug1 { + ($e:expr) => { + debug!("{}:{}:{} {}", file!(), line!(), column!(), $e); + }; +} + +pub(crate) use debug1; pub(crate) use unwrap_or_exit; pub fn info(value: &str) { @@ -43,12 +50,14 @@ pub fn execute_command(command: &mut Command) -> std::io::Result { let stdout = String::from_utf8_lossy(&output.stderr).to_string(); if !output.status.success() { - error!( + let error = String::from_utf8_lossy(&output.stderr).to_string(); + debug!( "{} failed: {}", command.get_program().to_str().unwrap(), - String::from_utf8_lossy(&output.stderr).to_string(), + error, ); - exit(1); + + return Err(std::io::Error::new(ErrorKind::Other, error)); } if !stderr.is_empty() { From d25826ed225d434c4a76c25a50c175c71940af7f Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Thu, 31 Aug 2023 09:52:38 -0700 Subject: [PATCH 2/3] always validate project path --- pgml-apps/cargo-pgml-components/src/main.rs | 30 +++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/pgml-apps/cargo-pgml-components/src/main.rs b/pgml-apps/cargo-pgml-components/src/main.rs index c3ae683c7..5a47b1caf 100644 --- a/pgml-apps/cargo-pgml-components/src/main.rs +++ b/pgml-apps/cargo-pgml-components/src/main.rs @@ -62,19 +62,23 @@ fn main() { let cli = Cli::parse(); match cli.subcomand { - CargoSubcommands::PgmlComponents(pgml_commands) => match pgml_commands.command { - Commands::Bundle {} => bundle(pgml_commands.project_path), - Commands::Add(command) => match command { - AddCommands::Component { name } => { - crate::frontend::components::add(&name, pgml_commands.overwrite) - } - }, - }, + CargoSubcommands::PgmlComponents(pgml_commands) => { + validate_project(pgml_commands.project_path); + match pgml_commands.command { + Commands::Bundle {} => bundle(), + Commands::Add(command) => match command { + AddCommands::Component { name } => { + crate::frontend::components::add(&name, pgml_commands.overwrite) + } + }, + } + } } } -/// Bundle SASS and JavaScript into neat bundle files. -fn bundle(project_path: Option) { +fn validate_project(project_path: Option) { + debug!("validating project directory"); + // Validate that the required project paths exist. let cwd = if let Some(project_path) = project_path { project_path @@ -94,9 +98,13 @@ fn bundle(project_path: Option) { } unwrap_or_exit!(set_current_dir(path)); +} + +/// Bundle SASS and JavaScript into neat bundle files. +fn bundle() { frontend::sass::bundle(); frontend::javascript::bundle(); frontend::components::update_modules(); - info("Bundle complete"); + info("bundle complete"); } From b64951e4b2bb737e124c147d93545e9d5a3bbabd Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Thu, 31 Aug 2023 09:55:10 -0700 Subject: [PATCH 3/3] Comments --- pgml-apps/cargo-pgml-components/src/frontend/tools.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pgml-apps/cargo-pgml-components/src/frontend/tools.rs b/pgml-apps/cargo-pgml-components/src/frontend/tools.rs index 33a289b59..c3f19f79d 100644 --- a/pgml-apps/cargo-pgml-components/src/frontend/tools.rs +++ b/pgml-apps/cargo-pgml-components/src/frontend/tools.rs @@ -32,6 +32,7 @@ pub fn install() { } } +/// Execute a command making sure that nvm is available. pub fn execute_with_nvm(command: &mut Command) -> std::io::Result { let mut cmd = Command::new(NVM_EXEC); cmd.arg(command.get_program()); @@ -41,6 +42,7 @@ pub fn execute_with_nvm(command: &mut Command) -> std::io::Result { execute_command(&mut cmd) } +/// Install the nvm entrypoint we provide into /tmp fn install_nvm_entrypoint() { let mut file = unwrap_or_exit!(File::create(NVM_EXEC)); unwrap_or_exit!(writeln!(&mut file, "{}", include_str!("nvm.sh"))); @@ -51,6 +53,7 @@ fn install_nvm_entrypoint() { )); } +/// Install node using nvm fn install_node() { debug!("installing node"); // Node is already installed.