diff --git a/.gitignore b/.gitignore index fa80870..cf70750 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ +# Cargo target dir /target + +# Custom Submodules /submodules + +# Resulting website +/dist diff --git a/Cargo.lock b/Cargo.lock index e514da9..af28c0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,6 +99,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "gimli" version = "0.28.1" @@ -467,6 +473,9 @@ name = "website" version = "0.1.0" dependencies = [ "color-eyre", + "fs_extra", + "serde", + "serde_derive", "toml", "tracing", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index 98073e9..c0416d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,9 @@ edition = "2021" [dependencies] color-eyre = "0.6.2" +fs_extra = "1.3.0" +serde = { version = "1.0.195", features = ["derive"] } +serde_derive = "1.0.195" toml = "0.8.8" tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..f65dd82 --- /dev/null +++ b/build.rs @@ -0,0 +1,4 @@ +fn main() { + let manifest = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + println!("cargo:rustc-env=ROOT_DIR={manifest}"); +} \ No newline at end of file diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..7969ee3 --- /dev/null +++ b/config.toml @@ -0,0 +1,4 @@ +[slides] +talks = [ + "2024-01-17-how-to-contribute-to-the-rust-project" +] diff --git a/shell.nix b/shell.nix index 6d1eedc..b3cef26 100644 --- a/shell.nix +++ b/shell.nix @@ -1,3 +1,3 @@ -{ pkgs ? import {} }: pkgs.mkShell { - packages = with pkgs; [ rustup ]; +{ pkgs ? import { } }: pkgs.mkShell { + packages = with pkgs; [ rustup hugo ]; } diff --git a/src/build/blog.rs b/src/build/blog.rs new file mode 100644 index 0000000..b3781e1 --- /dev/null +++ b/src/build/blog.rs @@ -0,0 +1,37 @@ +//! Builds my blog, built with hugo. + +use std::{path::Path, process::Command}; + +use color_eyre::{eyre::Context, Result}; + +use crate::utils; + +pub fn build(blog: &Path, dist: &Path) -> Result<()> { + info!("Building blog with hugo"); + + utils::run_process( + Command::new("git") + .args(&["submodule", "init"]) + .current_dir(&blog), + )?; + + utils::run_process( + Command::new("git") + .args(&["submodule", "update"]) + .current_dir(&blog), + )?; + + // Patch config + let config = + std::fs::read_to_string(blog.join("config.toml")).wrap_err("reading blog config")?; + let config = config.replace("baseURL = \"/\"", "baseURL = \"/blog/\""); + std::fs::write(blog.join("config.toml"), config).wrap_err("writing patched config.toml")?; + + utils::run_process( + Command::new("hugo") + .args(&["--minify", "--destination", dist.to_str().unwrap()]) + .current_dir(&blog), + )?; + + Ok(()) +} diff --git a/src/build/mod.rs b/src/build/mod.rs new file mode 100644 index 0000000..b72b567 --- /dev/null +++ b/src/build/mod.rs @@ -0,0 +1,22 @@ +//! This module assembles and builds the website. + +mod blog; +mod slides; + +use std::path::Path; + +use color_eyre::{eyre::Context, Result}; + +use crate::Config; + +pub fn assemble_website(config: &Config, submodules: &Path, dist: &Path) -> Result<()> { + blog::build(&submodules.join("blog"), &dist.join("blog")).wrap_err("building blog")?; + slides::build( + &config.slides, + &submodules.join("slides"), + &dist.join("slides"), + ) + .wrap_err("building slides")?; + + Ok(()) +} diff --git a/src/build/slides.rs b/src/build/slides.rs new file mode 100644 index 0000000..94ddd8c --- /dev/null +++ b/src/build/slides.rs @@ -0,0 +1,26 @@ +//! Moving the slides from the reveal.js repo +//! The setup is currently a bit bad but I'm not sure what the best solution would look like. + +use std::path::Path; + +use color_eyre::{eyre::WrapErr, Result}; + +use crate::{utils, SlidesConfig}; + +pub fn build(config: &SlidesConfig, slides: &Path, dist: &Path) -> Result<()> { + info!("Building slides"); + + debug!("Copying reveal.js dist"); + + utils::cp_r(&slides.join("dist"), &dist.join("dist")).wrap_err("copying reveal.js dist")?; + utils::cp_r(&slides.join("plugin"), &dist.join("plugin")).wrap_err("copying reveal.js dist")?; + + for talk in &config.talks { + let path = slides.join(talk); + let dist = dist.join(talk); + + utils::cp_r(&path, &dist).wrap_err("copying slide data")?; + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index b96d1bf..d84e4d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,51 @@ +mod build; mod submodule; mod utils; #[macro_use] extern crate tracing; +use std::path::Path; + use color_eyre::{eyre::Context, Result}; +use serde::Deserialize; use tracing_subscriber::EnvFilter; -fn main() -> Result<()> { - tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()).init(); +const ROOT_DIR: &str = env!("ROOT_DIR"); - let sub_config = - std::fs::read_to_string("submodules.toml").wrap_err("reading ./submodules.toml")?; +#[derive(Deserialize)] +struct Config { + slides: SlidesConfig, +} + +#[derive(Deserialize)] +struct SlidesConfig { + talks: Vec, +} + +fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .init(); + + let root = Path::new(ROOT_DIR); + + // Set the current dir to nonsense to fail everything that relies on it + let _ = std::env::set_current_dir("/"); + + let config = + std::fs::read_to_string(root.join("config.toml")).wrap_err("reading config.toml")?; + let config = toml::from_str::(&config).wrap_err("parsing config.toml")?; + + let sub_config = std::fs::read_to_string(root.join("submodules.toml")) + .wrap_err("reading submodules.toml")?; let sub_config = submodule::Submodules::parse(&sub_config).wrap_err("invalid submodules.toml")?; - submodule::sync(&sub_config).wrap_err("syncing subtrees")?; + let submodules_path = root.join("submodules"); + submodule::sync(&submodules_path, &sub_config).wrap_err("syncing subtrees")?; - info!("Hello, world!"); + let dist_path = root.join("dist"); + build::assemble_website(&config, &submodules_path, &dist_path)?; Ok(()) } diff --git a/src/submodule.rs b/src/submodule.rs index 7f696ab..5599a6d 100644 --- a/src/submodule.rs +++ b/src/submodule.rs @@ -1,7 +1,7 @@ //! Implements a simplistic form of git submodules. -//! +//! //! The config format is as follows: -//! +//! //! A list of //! ```toml //! [[submodule]] @@ -9,7 +9,7 @@ //! url = "" //! commit = "" //! ``` -//! +//! //! For example, //! ```toml //! [[submodule]] @@ -17,11 +17,11 @@ //! url = "https://github.com/Nilstrieb/nixos.git" //! commit = "c5b2fc10b9266b105d792d958b8f13479866a7bd" //! ``` -//! +//! //! This module will check them out into a directory called `submodules` in the current directory. -//! Make sure to put this directory into `.gitignore`. +//! Make sure to put this directory into `.gitignore`. -use std::{io, path, process}; +use std::{path::Path, process}; use color_eyre::{ eyre::{Context, OptionExt}, @@ -73,16 +73,10 @@ impl Submodules { } } -pub fn sync(config: &Submodules) -> color_eyre::Result<()> { +pub fn sync(path: &Path, config: &Submodules) -> color_eyre::Result<()> { info!("Syncing submodules..."); - let submodules_path = path::Path::new("submodules"); - - match std::fs::create_dir(submodules_path) { - Ok(()) => info!("Created ./submodules"), - Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {} - e => return e.wrap_err("failed to create submodules"), - } + utils::create_dir_if_not_exist(path)?; for sync in &config.configs { let name = &sync.name; @@ -91,12 +85,12 @@ pub fn sync(config: &Submodules) -> color_eyre::Result<()> { let span = info_span!("Syncing submodule", ?name, ?url); let _span = span.enter(); - let sub_path = submodules_path.join(name); + let sub_path = path.join(name); if !sub_path.exists() { info!(?name, ?url, "Cloning"); let mut cmd = process::Command::new("git"); cmd.args(&["clone", url, sub_path.to_str().unwrap()]); - utils::run_process(&mut cmd).wrap_err("running git clone")?; + utils::run_process(&mut cmd)?; } else { debug!(?name, ?url, "Repo already exists"); } @@ -123,16 +117,14 @@ pub fn sync(config: &Submodules) -> color_eyre::Result<()> { "fetch", "origin", sync.commit.as_str(), - ])) - .wrap_err("git fetch")?; + ]))?; } utils::run_process(process::Command::new("git").current_dir(&sub_path).args(&[ "reset", "--hard", sync.commit.as_str(), - ])) - .wrap_err("git reset --hard")?; + ]))?; } } diff --git a/src/utils.rs b/src/utils.rs index 15f6fc9..3dad672 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,20 +2,54 @@ use color_eyre::{ eyre::{bail, Context}, Result, }; -use std::process::Command; +use fs_extra::dir::CopyOptions; +use std::{path::Path, process::Command}; pub fn run_process(cmd: &mut Command) -> Result { - let name = cmd.get_program().to_os_string(); - let output = cmd - .output() - .wrap_err(format!("failed to spawn process {name:?}"))?; + fn run_process_inner(cmd: &mut Command) -> Result { + let name = cmd.get_program().to_os_string(); + let output = cmd + .output() + .wrap_err(format!("failed to spawn process {name:?}"))?; - if !output.status.success() { - bail!( - "command returned error: {}", - String::from_utf8(output.stderr).wrap_err("stderr is not UTF-8")? - ); + if !output.status.success() { + bail!( + "command returned error: {}", + String::from_utf8(output.stderr).wrap_err("stderr is not UTF-8")? + ); + } + + Ok(String::from_utf8(output.stdout).wrap_err("stdout is not UTF-8")?) } - - Ok(String::from_utf8(output.stdout).wrap_err("stdout is not UTF-8")?) + run_process_inner(cmd).wrap_err(format!( + "{} {}", + cmd.get_program().to_str().unwrap(), + cmd.get_args() + .map(|arg| format!("'{}'", arg.to_str().unwrap())) + .collect::>() + .join(" ") + )) +} + +pub fn create_dir_if_not_exist(p: &Path) -> Result<()> { + match std::fs::create_dir(p) { + Ok(()) => debug!(?p, "Created directory"), + Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {} + e => return e.wrap_err("failed to create submodules"), + } + Ok(()) +} + +pub fn cp_r(from: &Path, to: &Path) -> Result<()> { + fs_extra::copy_items( + &[from], + to, + &CopyOptions { + overwrite: true, + copy_inside: true, + ..CopyOptions::default() + }, + ) + .wrap_err(format!("copying to {}", to.display()))?; + Ok(()) } diff --git a/submodules.toml b/submodules.toml index b5cb0a6..42a28c9 100644 --- a/submodules.toml +++ b/submodules.toml @@ -2,3 +2,8 @@ name = "blog" url = "https://github.com/Nilstrieb/nilstrieb.github.io.git" commit = "a48053540e1bc85403c25526de304e82f5371a22" + +[[submodule]] +name = "slides" +url = "https://github.com/Nilstrieb/slides.git" +commit = "0401f35c22b124b69447655f0c537badae9e223c"