mirror of
https://github.com/tealdeer-rs/tealdeer.git
synced 2026-08-09 09:49:10 +02:00
Make network support optional
This commit is contained in:
parent
89a2595495
commit
584885c78d
8 changed files with 576 additions and 321 deletions
|
|
@ -18,9 +18,11 @@ jobs:
|
||||||
# Build
|
# Build
|
||||||
- run: cargo build
|
- run: cargo build
|
||||||
- run: cargo build --features logging
|
- run: cargo build --features logging
|
||||||
|
- run: cargo build --no-default-features
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
- run: cargo test
|
- run: cargo test
|
||||||
|
- run: cargo test --no-default-features
|
||||||
|
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: v1-cargo-cache-{{ arch }}-{{ .Branch }}
|
key: v1-cargo-cache-{{ arch }}-{{ .Branch }}
|
||||||
|
|
|
||||||
651
Cargo.lock
generated
651
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -28,17 +28,19 @@ time = "0.1.38"
|
||||||
toml = "0.4.6"
|
toml = "0.4.6"
|
||||||
walkdir = "2.0.1"
|
walkdir = "2.0.1"
|
||||||
xdg = "2.1.0"
|
xdg = "2.1.0"
|
||||||
reqwest = "0.9.5"
|
reqwest = { version = "0.9.5", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "0.10"
|
assert_cmd = "0.10"
|
||||||
escargot = "0.3"
|
escargot = "0.4"
|
||||||
predicates = "1.0"
|
predicates = "1.0"
|
||||||
tempdir = "^0.3"
|
tempdir = "^0.3"
|
||||||
utime = "0.2.0"
|
utime = "0.2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = ["networking"]
|
||||||
logging = ["env_logger"]
|
logging = ["env_logger"]
|
||||||
|
networking = ["reqwest"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|
|
||||||
14
README.md
14
README.md
|
|
@ -132,6 +132,7 @@ To enable the log output, set the `RUST_LOG` env variable:
|
||||||
$ export RUST_LOG=tldr=debug
|
$ export RUST_LOG=tldr=debug
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
The tldr command can be customized with a config file called `config.toml`.
|
The tldr command can be customized with a config file called `config.toml`.
|
||||||
|
|
@ -189,12 +190,25 @@ To run tests:
|
||||||
|
|
||||||
$ cargo test
|
$ cargo test
|
||||||
|
|
||||||
|
(Note that integration tests are a bit slow, since they invoke `cargo build` in different configurations.)
|
||||||
|
|
||||||
To run lints:
|
To run lints:
|
||||||
|
|
||||||
$ rustup component add clippy
|
$ rustup component add clippy
|
||||||
$ cargo clean && cargo clippy
|
$ cargo clean && cargo clippy
|
||||||
|
|
||||||
|
|
||||||
|
## Build Flags
|
||||||
|
|
||||||
|
tealdeer knows the following feature flags:
|
||||||
|
|
||||||
|
- `logging`: This enables logging support through [env_logger](https://docs.rs/env_logger/*/env_logger/)
|
||||||
|
- `networking`: This enables support for updating the cache from the internet
|
||||||
|
|
||||||
|
By default, only the `networking` feature is enabled. To build tealdeer without
|
||||||
|
networking support, use the `--no-default-features` Cargo flag.
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Licensed under either of
|
Licensed under either of
|
||||||
|
|
|
||||||
75
src/cache.rs
75
src/cache.rs
|
|
@ -1,15 +1,19 @@
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, feature = "networking"))]
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
use reqwest::{Client, Proxy};
|
use reqwest::{Client, Proxy};
|
||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use tar::Archive;
|
use tar::Archive;
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
use time;
|
use time;
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
|
|
@ -17,19 +21,36 @@ use xdg::BaseDirectories;
|
||||||
use crate::error::TealdeerError::{self, CacheError, UpdateError};
|
use crate::error::TealdeerError::{self, CacheError, UpdateError};
|
||||||
use crate::types::OsType;
|
use crate::types::OsType;
|
||||||
|
|
||||||
|
/// A cache update source.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Source {
|
||||||
|
/// Load the archive from the file system.
|
||||||
|
File(PathBuf),
|
||||||
|
|
||||||
|
/// Load the archive from the network.
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
|
Url(Cow<'static, str>),
|
||||||
|
|
||||||
|
/// No source is defined.
|
||||||
|
#[cfg(not(feature = "networking"))]
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Cache {
|
pub struct Cache {
|
||||||
url: String,
|
/// The cache source. Either an URL or a file path.
|
||||||
|
source: Source,
|
||||||
|
/// The target OS type.
|
||||||
os: OsType,
|
os: OsType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cache {
|
impl Cache {
|
||||||
pub fn new<S>(url: S, os: OsType) -> Self
|
pub fn new<S>(source: S, os: OsType) -> Self
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<Source>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
url: url.into(),
|
source: source.into(),
|
||||||
os,
|
os,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -60,8 +81,20 @@ impl Cache {
|
||||||
Ok(xdg_dirs.get_cache_home())
|
Ok(xdg_dirs.get_cache_home())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Download the archive
|
/// Load the archive from the file system.
|
||||||
fn download(&self) -> Result<Vec<u8>, TealdeerError> {
|
fn load_from_file(path: &Path) -> Result<Vec<u8>, TealdeerError> {
|
||||||
|
let mut f = fs::File::open(path)
|
||||||
|
.map_err(|e| UpdateError(format!("Could not open file: {}", e)))?;
|
||||||
|
let mut buf: Vec<u8> = vec![];
|
||||||
|
let bytes_read = f.read_to_end(&mut buf)
|
||||||
|
.map_err(|e| UpdateError(format!("Could not read file: {}", e)))?;
|
||||||
|
debug!("{} bytes loaded from filesystem", bytes_read);
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load the archive from the network.
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
|
fn load_from_network(url: &str) -> Result<Vec<u8>, TealdeerError> {
|
||||||
let mut builder = Client::builder();
|
let mut builder = Client::builder();
|
||||||
if let Ok(ref host) = env::var("HTTP_PROXY") {
|
if let Ok(ref host) = env::var("HTTP_PROXY") {
|
||||||
if let Ok(proxy) = Proxy::http(host) {
|
if let Ok(proxy) = Proxy::http(host) {
|
||||||
|
|
@ -74,13 +107,31 @@ impl Cache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let client = builder.build().unwrap_or_else(|_| Client::new());
|
let client = builder.build().unwrap_or_else(|_| Client::new());
|
||||||
let mut resp = client.get(&self.url).send()?;
|
let mut resp = client.get(url).send()?;
|
||||||
let mut buf: Vec<u8> = vec![];
|
let mut buf: Vec<u8> = vec![];
|
||||||
let bytes_downloaded = resp.copy_to(&mut buf)?;
|
let bytes_downloaded = resp.copy_to(&mut buf)?;
|
||||||
debug!("{} bytes downloaded", bytes_downloaded);
|
debug!("{} bytes downloaded", bytes_downloaded);
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Download the archive from the network or load it from a file.
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
|
fn load(&self) -> Result<Vec<u8>, TealdeerError> {
|
||||||
|
match self.source {
|
||||||
|
Source::File(ref path) => Self::load_from_file(path),
|
||||||
|
Source::Url(ref url) => Self::load_from_network(url),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load the archive from the file system.
|
||||||
|
#[cfg(not(feature = "networking"))]
|
||||||
|
fn load(&self) -> Result<Vec<u8>, TealdeerError> {
|
||||||
|
match self.source {
|
||||||
|
Source::File(ref path) => Self::load_from_file(path),
|
||||||
|
Source::None => Err(TealdeerError::UpdateError("No update source defined".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Decompress and open the archive
|
/// Decompress and open the archive
|
||||||
fn decompress<R: Read>(&self, reader: R) -> Archive<GzDecoder<R>> {
|
fn decompress<R: Read>(&self, reader: R) -> Archive<GzDecoder<R>> {
|
||||||
Archive::new(GzDecoder::new(reader))
|
Archive::new(GzDecoder::new(reader))
|
||||||
|
|
@ -88,8 +139,8 @@ impl Cache {
|
||||||
|
|
||||||
/// Update the pages cache.
|
/// Update the pages cache.
|
||||||
pub fn update(&self) -> Result<(), TealdeerError> {
|
pub fn update(&self) -> Result<(), TealdeerError> {
|
||||||
// First, download the compressed data
|
// First, load the compressed data
|
||||||
let bytes: Vec<u8> = self.download()?;
|
let bytes: Vec<u8> = self.load()?;
|
||||||
|
|
||||||
// Decompress the response body into an `Archive`
|
// Decompress the response body into an `Archive`
|
||||||
let mut archive = self.decompress(&bytes[..]);
|
let mut archive = self.decompress(&bytes[..]);
|
||||||
|
|
@ -118,7 +169,7 @@ impl Cache {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, feature = "networking"))]
|
||||||
/// Return the number of seconds since the cache directory was last modified.
|
/// Return the number of seconds since the cache directory was last modified.
|
||||||
pub fn last_update(&self) -> Option<i64> {
|
pub fn last_update(&self) -> Option<i64> {
|
||||||
if let Ok(cache_dir) = self.get_cache_dir() {
|
if let Ok(cache_dir) = self.get_cache_dir() {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
use reqwest::Error as ReqwestError;
|
use reqwest::Error as ReqwestError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -9,6 +11,7 @@ pub enum TealdeerError {
|
||||||
UpdateError(String),
|
UpdateError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
impl From<ReqwestError> for TealdeerError {
|
impl From<ReqwestError> for TealdeerError {
|
||||||
fn from(err: ReqwestError) -> Self {
|
fn from(err: ReqwestError) -> Self {
|
||||||
TealdeerError::UpdateError(format!("HTTP error: {}", err.to_string()))
|
TealdeerError::UpdateError(format!("HTTP error: {}", err.to_string()))
|
||||||
|
|
|
||||||
79
src/main.rs
79
src/main.rs
|
|
@ -16,11 +16,14 @@
|
||||||
#[cfg(feature = "logging")]
|
#[cfg(feature = "logging")]
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
@ -32,7 +35,7 @@ mod formatter;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use crate::cache::Cache;
|
use crate::cache::{Cache, Source};
|
||||||
use crate::config::{get_config_path, make_default_config, Config};
|
use crate::config::{get_config_path, make_default_config, Config};
|
||||||
use crate::error::TealdeerError::{CacheError, ConfigError, UpdateError};
|
use crate::error::TealdeerError::{CacheError, ConfigError, UpdateError};
|
||||||
use crate::formatter::print_lines;
|
use crate::formatter::print_lines;
|
||||||
|
|
@ -42,6 +45,8 @@ use crate::types::OsType;
|
||||||
const NAME: &str = "tealdeer";
|
const NAME: &str = "tealdeer";
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
const USAGE: &str = "
|
const USAGE: &str = "
|
||||||
|
tealdeer, a fast tldr implementation written in Rust.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
tldr [options] <command>
|
tldr [options] <command>
|
||||||
|
|
@ -49,16 +54,17 @@ Usage:
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
-h --help Show this screen
|
-h --help Show this screen
|
||||||
-v --version Show version information
|
-v --version Show version information
|
||||||
-l --list List all commands in the cache
|
-l --list List all commands in the cache
|
||||||
-f --render <file> Render a specific markdown file
|
-f --render <file> Render a specific markdown file
|
||||||
-o --os <type> Override the operating system [linux, osx, sunos]
|
-o --os <type> Override the operating system [linux, osx, sunos]
|
||||||
-u --update Update the local cache
|
-u --update Update the local cache from the network
|
||||||
-c --clear-cache Clear the local cache
|
-U --update-from <src> Update the local cache from the specified URL or path
|
||||||
-q --quiet Suppress informational messages
|
-c --clear-cache Clear the local cache
|
||||||
--config-path Show config file path
|
-q --quiet Suppress informational messages
|
||||||
--seed-config Create a basic config
|
--config-path Show config file path
|
||||||
|
--seed-config Create a basic config
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
|
@ -70,11 +76,19 @@ To control the cache:
|
||||||
$ tldr --update
|
$ tldr --update
|
||||||
$ tldr --clear-cache
|
$ tldr --clear-cache
|
||||||
|
|
||||||
|
You can also manually specify the archive to be used for updating the cache:
|
||||||
|
|
||||||
|
$ tldr --update-from https://github.com/tldr-pages/tldr/archive/master.tar.gz
|
||||||
|
$ tldr --update-from master.tar.gz
|
||||||
|
|
||||||
To render a local file (for testing):
|
To render a local file (for testing):
|
||||||
|
|
||||||
$ tldr --render /path/to/file.md
|
$ tldr --render /path/to/file.md
|
||||||
";
|
";
|
||||||
|
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
const ARCHIVE_URL: &str = "https://github.com/tldr-pages/tldr/archive/master.tar.gz";
|
const ARCHIVE_URL: &str = "https://github.com/tldr-pages/tldr/archive/master.tar.gz";
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
const MAX_CACHE_AGE: i64 = 2_592_000; // 30 days
|
const MAX_CACHE_AGE: i64 = 2_592_000; // 30 days
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
|
@ -86,6 +100,7 @@ struct Args {
|
||||||
flag_render: Option<String>,
|
flag_render: Option<String>,
|
||||||
flag_os: Option<OsType>,
|
flag_os: Option<OsType>,
|
||||||
flag_update: bool,
|
flag_update: bool,
|
||||||
|
flag_update_from: Option<String>,
|
||||||
flag_clear_cache: bool,
|
flag_clear_cache: bool,
|
||||||
flag_quiet: bool,
|
flag_quiet: bool,
|
||||||
flag_config_path: bool,
|
flag_config_path: bool,
|
||||||
|
|
@ -119,6 +134,7 @@ fn print_page(path: &Path) -> Result<(), String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the cache for freshness
|
/// Check the cache for freshness
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
fn check_cache(args: &Args, cache: &Cache) {
|
fn check_cache(args: &Args, cache: &Cache) {
|
||||||
if !args.flag_update {
|
if !args.flag_update {
|
||||||
match cache.last_update() {
|
match cache.last_update() {
|
||||||
|
|
@ -144,6 +160,14 @@ fn check_cache(args: &Args, cache: &Cache) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check the cache for freshness
|
||||||
|
///
|
||||||
|
/// No-op when networking support is disabled.
|
||||||
|
#[cfg(not(feature = "networking"))]
|
||||||
|
fn check_cache(_args: &Args, _cache: &Cache) {
|
||||||
|
// No-op when no networking support is enabled.
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "logging")]
|
#[cfg(feature = "logging")]
|
||||||
fn init_log() {
|
fn init_log() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
@ -176,6 +200,28 @@ fn get_os() -> OsType {
|
||||||
OsType::Other
|
OsType::Other
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
|
fn get_url_source(source: &str) -> Source {
|
||||||
|
Source::Url(Cow::Owned(source.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "networking"))]
|
||||||
|
fn get_url_source(_source: &str) -> Source {
|
||||||
|
eprintln!("tealdeer has been compiled without networking support,");
|
||||||
|
eprintln!("cannot update the cache from a network URL.");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "networking")]
|
||||||
|
fn get_default_source() -> Source {
|
||||||
|
Source::Url(Cow::Borrowed(ARCHIVE_URL))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "networking"))]
|
||||||
|
fn get_default_source() -> Source {
|
||||||
|
Source::None
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Initialize logger
|
// Initialize logger
|
||||||
init_log();
|
init_log();
|
||||||
|
|
@ -198,8 +244,15 @@ fn main() {
|
||||||
None => get_os(),
|
None => get_os(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Validate cache source
|
||||||
|
let cache_source: Source = match args.flag_update_from {
|
||||||
|
Some(ref src) if src.starts_with("http") => get_url_source(src),
|
||||||
|
Some(ref src) => Source::File(PathBuf::from(src)),
|
||||||
|
None => get_default_source(),
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize cache
|
// Initialize cache
|
||||||
let cache = Cache::new(ARCHIVE_URL, os);
|
let cache = Cache::new(cache_source, os);
|
||||||
|
|
||||||
// Clear cache, pass through
|
// Clear cache, pass through
|
||||||
if args.flag_clear_cache {
|
if args.flag_clear_cache {
|
||||||
|
|
@ -217,7 +270,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update cache, pass through
|
// Update cache, pass through
|
||||||
if args.flag_update {
|
if args.flag_update || args.flag_update_from.is_some() {
|
||||||
cache.update().unwrap_or_else(|e| {
|
cache.update().unwrap_or_else(|e| {
|
||||||
match e {
|
match e {
|
||||||
CacheError(msg) | ConfigError(msg) | UpdateError(msg) => {
|
CacheError(msg) | ConfigError(msg) | UpdateError(msg) => {
|
||||||
|
|
|
||||||
75
tests/lib.rs
75
tests/lib.rs
|
|
@ -1,11 +1,5 @@
|
||||||
//! Integration tests.
|
//! Integration tests.
|
||||||
|
|
||||||
extern crate assert_cmd;
|
|
||||||
extern crate escargot;
|
|
||||||
extern crate predicates;
|
|
||||||
extern crate tempdir;
|
|
||||||
extern crate utime;
|
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
@ -20,7 +14,6 @@ struct TestEnv {
|
||||||
pub config_dir: TempDir,
|
pub config_dir: TempDir,
|
||||||
pub input_dir: TempDir,
|
pub input_dir: TempDir,
|
||||||
pub default_features: bool,
|
pub default_features: bool,
|
||||||
pub features: Vec<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestEnv {
|
impl TestEnv {
|
||||||
|
|
@ -30,7 +23,6 @@ impl TestEnv {
|
||||||
config_dir: TempDir::new(".tldr.test.config").unwrap(),
|
config_dir: TempDir::new(".tldr.test.config").unwrap(),
|
||||||
input_dir: TempDir::new(".tldr.test.input").unwrap(),
|
input_dir: TempDir::new(".tldr.test.input").unwrap(),
|
||||||
default_features: true,
|
default_features: true,
|
||||||
features: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,12 +32,6 @@ impl TestEnv {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add the specified feature.
|
|
||||||
fn with_feature<S: Into<String>>(mut self, feature: S) -> Self {
|
|
||||||
self.features.push(feature.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a new `Command` with env vars set.
|
/// Return a new `Command` with env vars set.
|
||||||
fn command(&self) -> Command {
|
fn command(&self) -> Command {
|
||||||
let mut build = escargot::CargoBuild::new()
|
let mut build = escargot::CargoBuild::new()
|
||||||
|
|
@ -53,10 +39,9 @@ impl TestEnv {
|
||||||
.current_release()
|
.current_release()
|
||||||
.current_target();
|
.current_target();
|
||||||
if !self.default_features {
|
if !self.default_features {
|
||||||
build = build.arg("--no-default-features");
|
build = build
|
||||||
}
|
.arg("--no-default-features")
|
||||||
if !self.features.is_empty() {
|
.target_dir("target/no-default-features");
|
||||||
build = build.arg(&format!("--feature {}", self.features.join(",")));
|
|
||||||
}
|
}
|
||||||
let run = build.run().unwrap();
|
let run = build.run().unwrap();
|
||||||
let mut cmd = run.command();
|
let mut cmd = run.command();
|
||||||
|
|
@ -257,3 +242,57 @@ fn test_correct_rendering_with_config() {
|
||||||
.success()
|
.success()
|
||||||
.stdout(similar(expected));
|
.stdout(similar(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updating from a network URL should not be possible when networking support
|
||||||
|
/// is not enabled.
|
||||||
|
#[test]
|
||||||
|
fn test_update_from_no_networking() {
|
||||||
|
let testenv = TestEnv::new();
|
||||||
|
testenv
|
||||||
|
.no_default_features() // Disable networking
|
||||||
|
.command()
|
||||||
|
.args(&["--update-from", "https://github.com/tldr-pages/tldr/archive/master.tar.gz"])
|
||||||
|
.assert()
|
||||||
|
.failure()
|
||||||
|
.stderr(contains("compiled without networking support"))
|
||||||
|
.stderr(contains("cannot update the cache from a network URL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updating from an invalid URL should result in an error message.
|
||||||
|
#[test]
|
||||||
|
fn test_update_from_invalid_url() {
|
||||||
|
let testenv = TestEnv::new();
|
||||||
|
testenv
|
||||||
|
.command()
|
||||||
|
.args(&["--update-from", "httpsss:github.com/tldr-pages/tldr/archive/master.tar.gz"])
|
||||||
|
.assert()
|
||||||
|
.failure()
|
||||||
|
.stderr(contains("Could not update cache: HTTP error"))
|
||||||
|
.stderr(contains("URL scheme is not allowed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updating from the wrong (non-gzip-archive) URL should result in an error.
|
||||||
|
#[test]
|
||||||
|
fn test_update_from_wrong_url() {
|
||||||
|
let testenv = TestEnv::new();
|
||||||
|
testenv
|
||||||
|
.command()
|
||||||
|
.args(&["--update-from", "https://tldr.sh/"])
|
||||||
|
.assert()
|
||||||
|
.failure()
|
||||||
|
.stderr(contains("Could not update cache: Could not unpack compressed data"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When a path is specified that does not exist, an error message should be shown.
|
||||||
|
#[test]
|
||||||
|
fn test_update_from_missing_path() {
|
||||||
|
let testenv = TestEnv::new();
|
||||||
|
testenv
|
||||||
|
.no_default_features()
|
||||||
|
.command()
|
||||||
|
.args(&["--update-from", "ajsdfasjdkfljasdf"]) // Invalid path
|
||||||
|
.assert()
|
||||||
|
.failure()
|
||||||
|
.stderr(contains("Could not update cache: Could not open file:"))
|
||||||
|
.stderr(contains("No such file or directory"));
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue