From 2993d76095b0924bdc815759a8f7c92d088fb6c0 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Sat, 27 Apr 2019 12:22:21 +0200 Subject: [PATCH 1/4] Recompile docs while server is running by pressing ENTER --- Cargo.lock | 2 ++ README.md | 2 ++ src/main.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 72ce64d..3667b6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "ansi_term" version = "0.11.0" diff --git a/README.md b/README.md index 70435d5..a3b63dc 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ This is just the result of me fooling around with what would be the minimal HTTP `cargo docserver -p ` +Additionally you can compile the docs while the server is running by pressing ENTER. You can pass arguments to `cargo doc` with `-r "--some-arg"`. For example `cargo docserver -r "--no-deps -j 2"` + ### sidenote diff --git a/src/main.rs b/src/main.rs index 92c907c..a4a9360 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ use hyper::{Body, Method, Request, Response, Server, StatusCode}; use std::io; use std::path::{Path, PathBuf}; use std::str; +use std::thread; use structopt::StructOpt; use futures::{future, Future}; @@ -23,6 +24,10 @@ enum Cargo { Docserver { #[structopt(short = "p", long = "port", default_value = "4000")] port: u16, + + #[structopt(long, short, allow_hyphen_values = true)] + /// The arguments that will be sent to `cargo doc` when recompiling the docs. + recompile_args: Option, }, } @@ -127,9 +132,51 @@ fn not_found() -> ResponseFuture { )) } +fn setup_recompilation_watcher(recompile_args: Option) { + thread::spawn(move || { + let recompile_args = into_command_args(&recompile_args); + let mut input = String::new(); + + println!("Press ENTER to recompile the docs"); + loop { + match io::stdin().read_line(&mut input) { + Ok(_) => { + compile_docs(&recompile_args); + } + Err(error) => eprintln!("Error reading from stdin: {}", error), + } + } + }); +} + +fn into_command_args(args: &Option) -> Vec<&str> { + match args.as_ref() { + Some(args) => args.split(' ').collect(), + None => Vec::new(), + } +} + +fn compile_docs(recompile_args: &[&str]) { + use std::process::Command; + + println!( + "Compiling docs with `cargo doc {}`", + recompile_args.join(" ") + ); + + Command::new("cargo") + .args(&["doc"]) + .args(recompile_args) + .spawn() + .expect("failed to compile docs"); +} + fn main() { match Cargo::from_args() { - Cargo::Docserver { port } => { + Cargo::Docserver { + port, + recompile_args, + } => { let addr = ([0, 0, 0, 0], port).into(); let svc = || service_fn(serve_docs); let server = Server::bind(&addr) @@ -137,6 +184,7 @@ fn main() { .map_err(|e| eprintln!("server error {}", e)); println!("Listening on http://{}", addr); + setup_recompilation_watcher(recompile_args); hyper::rt::run(server); } } From d08259eb47fde2db5d60bda78985f09795784769 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Sun, 28 Apr 2019 17:25:00 +0200 Subject: [PATCH 2/4] Wait to child process to finish --- src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index a4a9360..dfce59f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -164,11 +164,13 @@ fn compile_docs(recompile_args: &[&str]) { recompile_args.join(" ") ); - Command::new("cargo") + let mut child = Command::new("cargo") .args(&["doc"]) .args(recompile_args) .spawn() .expect("failed to compile docs"); + + child.wait().expect("failed to compile docs"); } fn main() { From c766835ddd2a597619bdd1e1b8a61a6b60d09e1e Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Sat, 19 Oct 2019 14:06:27 +0200 Subject: [PATCH 3/4] Misc changes --- Cargo.toml | 1 + rustfmt.toml | 1 + src/main.rs | 67 ++++++++++++++++++++++++++-------------------------- 3 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 rustfmt.toml diff --git a/Cargo.toml b/Cargo.toml index ea04ea1..644750f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ description = "starts an embedded http server for your cargo doc output" homepage = "https://github.com/qmx/cargo-docserver" repository = "https://github.com/qmx/cargo-docserver" license = "MIT/Apache-2.0" +edition = "2018" [dependencies] structopt = "0.2.15" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..7d2cf54 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +merge_imports = true diff --git a/src/main.rs b/src/main.rs index dfce59f..d30cb65 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,9 @@ -extern crate structopt; - -extern crate cargo_metadata; -extern crate hyper; - -extern crate futures; -extern crate mime_guess; -extern crate tokio_fs; -extern crate tokio_io; -use hyper::service::service_fn; -use hyper::{Body, Method, Request, Response, Server, StatusCode}; -use std::io; -use std::path::{Path, PathBuf}; -use std::str; -use std::thread; +use hyper::{service::service_fn, Body, Method, Request, Response, Server, StatusCode}; +use std::{ + io, + path::{Path, PathBuf}, + str, thread, +}; use structopt::StructOpt; use futures::{future, Future}; @@ -31,7 +22,7 @@ enum Cargo { }, } -type ResponseFuture = Box, Error = io::Error> + Send>; +type ResponseFuture = Box, Error = io::Error> + Send>; #[derive(Debug)] struct CrateInfo { @@ -45,29 +36,18 @@ impl CrateInfo { let package_name = &meta.packages[0].name; let package_name_sanitized = str::replace(&package_name, "-", "_"); let doc_path = Path::new(&meta.target_directory).join("doc"); + CrateInfo { - name: package_name_sanitized.clone(), - doc_path: doc_path.clone(), + name: package_name_sanitized, + doc_path, } } } -#[test] -fn test_make_relative() { - assert_eq!("foo/bar/baz", make_relative("/foo/bar/baz")); - assert_eq!("foo/bar/baz", make_relative("///foo/bar/baz")); -} - -#[test] -fn test_make_root_document() { - assert_eq!("/foo/hello/index.html", make_index("/foo/hello")); - assert_eq!("/foo/hello/index.html", make_index("/foo/hello/")); - assert_eq!("/foo/hello.foo", make_index("/foo/hello.foo")); -} - fn make_index(path: &str) -> String { - let sanitized_path = path.trim_end_matches("/"); - if sanitized_path.contains(".") { + let sanitized_path = path.trim_end_matches('/'); + + if sanitized_path.contains('.') { sanitized_path.to_string() } else { format!("{}/index.html", sanitized_path) @@ -75,7 +55,7 @@ fn make_index(path: &str) -> String { } fn make_relative(path: &str) -> String { - path.trim_start_matches("/").to_string() + path.trim_start_matches('/').to_string() } fn serve_docs(req: Request) -> ResponseFuture { @@ -191,3 +171,22 @@ fn main() { } } } + +#[cfg(test)] +mod test { + #[allow(unused_imports)] + use super::*; + + #[test] + fn test_make_relative() { + assert_eq!("foo/bar/baz", make_relative("/foo/bar/baz")); + assert_eq!("foo/bar/baz", make_relative("///foo/bar/baz")); + } + + #[test] + fn test_make_root_document() { + assert_eq!("/foo/hello/index.html", make_index("/foo/hello")); + assert_eq!("/foo/hello/index.html", make_index("/foo/hello/")); + assert_eq!("/foo/hello.foo", make_index("/foo/hello.foo")); + } +} From 9545b323d2b16b18f005515b57d70cd287898332 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Sat, 19 Oct 2019 14:10:13 +0200 Subject: [PATCH 4/4] Recompile docs when starting up --- src/main.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index d30cb65..b755b1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use hyper::{service::service_fn, Body, Method, Request, Response, Server, Status use std::{ io, path::{Path, PathBuf}, + process::Command, str, thread, }; use structopt::StructOpt; @@ -114,7 +115,6 @@ fn not_found() -> ResponseFuture { fn setup_recompilation_watcher(recompile_args: Option) { thread::spawn(move || { - let recompile_args = into_command_args(&recompile_args); let mut input = String::new(); println!("Press ENTER to recompile the docs"); @@ -129,15 +129,8 @@ fn setup_recompilation_watcher(recompile_args: Option) { }); } -fn into_command_args(args: &Option) -> Vec<&str> { - match args.as_ref() { - Some(args) => args.split(' ').collect(), - None => Vec::new(), - } -} - -fn compile_docs(recompile_args: &[&str]) { - use std::process::Command; +fn compile_docs(recompile_args: &Option) { + let recompile_args = into_command_args(&recompile_args); println!( "Compiling docs with `cargo doc {}`", @@ -153,6 +146,13 @@ fn compile_docs(recompile_args: &[&str]) { child.wait().expect("failed to compile docs"); } +fn into_command_args(args: &Option) -> Vec<&str> { + match args.as_ref() { + Some(args) => args.split(' ').collect(), + None => Vec::new(), + } +} + fn main() { match Cargo::from_args() { Cargo::Docserver { @@ -165,8 +165,10 @@ fn main() { .serve(svc) .map_err(|e| eprintln!("server error {}", e)); - println!("Listening on http://{}", addr); + compile_docs(&recompile_args); setup_recompilation_watcher(recompile_args); + + println!("Listening on http://{}", addr); hyper::rt::run(server); } }