Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ jobs:
# https://github.com/rust-lang/rustup/issues/2441
#
# for more information.
rustup toolchain install 1.85.0 --no-self-update # [ref:rust_1.85.0]
rustup default 1.85.0 # [ref:rust_1.85.0]
rustup toolchain install 1.87.0 --no-self-update # [ref:rust_1.87.0]
rustup default 1.87.0 # [ref:rust_1.87.0]

# Add the targets.
rustup target add x86_64-pc-windows-msvc
Expand Down Expand Up @@ -124,8 +124,8 @@ jobs:
set -euxo pipefail

# Install the appropriate version of Rust.
rustup toolchain install 1.85.0 # [ref:rust_1.85.0]
rustup default 1.85.0 # [ref:rust_1.85.0]
rustup toolchain install 1.87.0 # [ref:rust_1.87.0]
rustup default 1.87.0 # [ref:rust_1.87.0]

# Add the targets.
rustup target add x86_64-apple-darwin
Expand Down Expand Up @@ -200,8 +200,8 @@ jobs:
set -euxo pipefail

# Install the appropriate version of Rust.
rustup toolchain install 1.85.0 # [ref:rust_1.85.0]
rustup default 1.85.0 # [ref:rust_1.85.0]
rustup toolchain install 1.87.0 # [ref:rust_1.87.0]
rustup default 1.87.0 # [ref:rust_1.87.0]

# Fetch the program version.
VERSION="$(cargo pkgid | cut -d# -f2 | cut -d: -f2)"
Expand Down
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "toast"
version = "0.47.7"
authors = ["Stephan Boyer <stephan@stephanboyer.com>"]
edition = "2021"
edition = "2024"
description = "Containerize your development and continuous integration environments."
license = "MIT"
documentation = "https://github.com/stepchowfun/toast"
Expand All @@ -24,7 +24,6 @@ dirs = "3"
env_logger = "0.8"
hex = "0.4"
indicatif = "0.16"
lazy_static = "1.4"
log = "0.4"
scopeguard = "1"
serde_yaml = "0.8"
Expand Down
6 changes: 3 additions & 3 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{
failure,
failure::Failure,
toastfile::{command, location, user, Task, Toastfile},
toastfile::{Task, Toastfile, command, location, user},
},
sha2::{Digest, Sha256},
std::{
Expand Down Expand Up @@ -159,8 +159,8 @@ pub fn image_name(
mod tests {
use {
crate::{
cache::{combine, hash_read, image_name, CryptoHash},
toastfile::{Task, Toastfile, DEFAULT_LOCATION, DEFAULT_USER},
cache::{CryptoHash, combine, hash_read, image_name},
toastfile::{DEFAULT_LOCATION, DEFAULT_USER, Task, Toastfile},
},
std::{collections::HashMap, path::Path},
typed_path::UnixPath,
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub fn parse(config: &str) -> Result<Config, Failure> {

#[cfg(test)]
mod tests {
use crate::config::{parse, Config, DOCKER_CLI_DEFAULT, EMPTY_CONFIG};
use crate::config::{Config, DOCKER_CLI_DEFAULT, EMPTY_CONFIG, parse};

#[test]
fn parse_empty() {
Expand Down
4 changes: 2 additions & 2 deletions src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use {
std::{
collections::HashMap,
env::current_dir,
fs::{copy, create_dir_all, rename, symlink_metadata, Metadata},
fs::{Metadata, copy, create_dir_all, rename, symlink_metadata},
io,
io::Read,
path::Path,
process::{ChildStdin, Command, Stdio},
string::ToString,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
atomic::{AtomicBool, Ordering},
},
},
tempfile::tempdir,
Expand Down
4 changes: 2 additions & 2 deletions src/format.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use colored::{control::SHOULD_COLORIZE, ColoredString, Colorize};
use colored::{ColoredString, Colorize, control::SHOULD_COLORIZE};

// This trait has a function for formatting "code-like" text, such as a file path. The reason it's
// implemented as a trait and not just a function is so we can use it with method syntax, as in
Expand Down Expand Up @@ -46,7 +46,7 @@ pub fn series(items: &[String]) -> String {

#[cfg(test)]
mod tests {
use crate::format::{number, series, CodeStr};
use crate::format::{CodeStr, number, series};

#[test]
fn code_str_display() {
Expand Down
13 changes: 5 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use {
crate::{failure::Failure, format::CodeStr},
atty::Stream,
clap::{App, AppSettings, Arg},
env_logger::{fmt::Color, Builder},
env_logger::{Builder, fmt::Color},
log::{Level, LevelFilter},
std::{
collections::{HashMap, HashSet},
Expand All @@ -22,24 +22,21 @@ use {
env,
env::current_dir,
fs,
io::{stdout, Write},
io::{Write, stdout},
mem::drop,
path::Path,
path::PathBuf,
process::exit,
str::FromStr,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
atomic::{AtomicBool, Ordering},
},
},
toastfile::{default_task_mount_readonly, location, user, DEFAULT_USER},
toastfile::{DEFAULT_USER, default_task_mount_readonly, location, user},
typed_path::UnixPath,
};

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate log;

Expand Down Expand Up @@ -723,7 +720,7 @@ fn entry() -> Result<(), Failure> {
// There was an error not caused by a regular task failure. Quit now.
return result;
}
};
}

// Drop the user into a shell if requested.
if settings.spawn_shell {
Expand Down
8 changes: 4 additions & 4 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use {
cache, docker, failure,
failure::Failure,
tar,
toastfile::{command, location, user, Task, Toastfile},
toastfile::{Task, Toastfile, command, location, user},
},
std::{
collections::{HashMap, HashSet},
io::{Seek, SeekFrom},
path::PathBuf,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
atomic::{AtomicBool, Ordering},
},
},
tempfile::tempfile,
Expand Down Expand Up @@ -72,7 +72,7 @@ pub fn run(
return (
Err(failure::system("Unable to create temporary file.")(e)),
Some(context),
)
);
}
};

Expand All @@ -96,7 +96,7 @@ pub fn run(
Err(failure::system("Unable to seek temporary file.")(e)),
Some(context),
);
};
}

// Compute the name of the image that this task produces.
let image = cache::image_name(
Expand Down
2 changes: 1 addition & 1 deletion src/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ mod tests {
use {
crate::{
schedule::compute,
toastfile::{Task, Toastfile, DEFAULT_LOCATION, DEFAULT_USER},
toastfile::{DEFAULT_LOCATION, DEFAULT_USER, Task, Toastfile},
},
std::collections::HashMap,
typed_path::UnixPath,
Expand Down
92 changes: 47 additions & 45 deletions src/spinner.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use {
atty::Stream,
crossbeam::channel::{bounded, Sender},
crossbeam::channel::{Sender, bounded},
indicatif::{ProgressBar, ProgressStyle},
scopeguard::guard,
std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
atomic::{AtomicBool, Ordering},
},
thread,
thread::sleep,
Expand All @@ -18,57 +18,59 @@ use {
pub fn spin(message: &str) -> impl Drop {
// Start a thread for our spinner-as-a-service. This thread will only be created once and will
// live for the duration of the whole program.
lazy_static! {
static ref SPINNER_SERVICE: Sender<(String, Arc<AtomicBool>, Sender<()>)> = {
// Create a channel for requests to start spinning.
let (request_sender, request_receiver) =
bounded::<(String, Arc<AtomicBool>, Sender<()>)>(0);
#[allow(clippy::type_complexity)]
static SPINNER_SERVICE: std::sync::LazyLock<Sender<(String, Arc<AtomicBool>, Sender<()>)>> =
std::sync::LazyLock::new(|| {
// Create a channel for requests to start spinning.
let (request_sender, request_receiver) =
bounded::<(String, Arc<AtomicBool>, Sender<()>)>(0);

// Start a thread to handle spinner requests.
thread::spawn(move || loop {
// Wait for a request. The `unwrap` is safe since we never hang up the channel.
let (message, spinning, response_sender) =
request_receiver.recv().unwrap();
// Start a thread to handle spinner requests.
thread::spawn(move || {
loop {
// Wait for a request. The `unwrap` is safe since we never hang up the channel.
let (message, spinning, response_sender) = request_receiver.recv().unwrap();

// If STDERR is not a TTY, the spinner will be hidden. In that case, just print
// the message to STDERR.
if !atty::is(Stream::Stderr) {
info!("{}", message);
}
// If STDERR is not a TTY, the spinner will be hidden. In that case, just print
// the message to STDERR.
if !atty::is(Stream::Stderr) {
info!("{}", message);
}

// Create the spinner!
let spinner = ProgressBar::new(1);
spinner.set_style(ProgressStyle::default_spinner());
spinner.set_message(message.clone());
// Create the spinner!
let spinner = ProgressBar::new(1);
spinner.set_style(ProgressStyle::default_spinner());
spinner.set_message(message.clone());

// Animate the spinner for as long as necessary.
let now = Instant::now();
while spinning.load(Ordering::SeqCst) {
// Render the next frame of the spinner.
spinner.tick();
// Animate the spinner for as long as necessary.
let now = Instant::now();
while spinning.load(Ordering::SeqCst) {
// Render the next frame of the spinner.
spinner.tick();

// For the first 100ms, we animate on a shorter time interval so we can stop faster if
// the work finishes instantly. If the work takes longer than that, we slow the
// animation down out of courtesy for the CPU.
if now.elapsed() < Duration::from_millis(100) {
sleep(Duration::from_millis(16));
} else {
sleep(Duration::from_millis(100));
}
}
// For the first 100ms, we animate on a shorter time interval so we can
// stop faster if the work finishes instantly. If the work takes longer
// than that, we slow the animation down out of courtesy for the CPU.
if now.elapsed() < Duration::from_millis(100) {
sleep(Duration::from_millis(16));
} else {
sleep(Duration::from_millis(100));
}
}

// Clean up the spinner.
spinner.finish_and_clear();
// Clean up the spinner.
spinner.finish_and_clear();

// Inform the caller that the spinner has been cleaned up. The `unwrap` is safe since we
// never hang up the channel.
response_sender.send(()).unwrap();
});
// Inform the caller that the spinner has been cleaned up. The `unwrap` is safe
// since we never hang up the channel.
response_sender.send(()).unwrap();
}
});

// The sender half of the request channel is the API for this spinner service. Return it.
request_sender
};
}
// The sender half of the request channel is the API for this spinner service. Return
// it.
request_sender
});

// Create a channel for waiting on the spinner.
let (response_sender, response_receiver) = bounded::<()>(0);
Expand Down
6 changes: 3 additions & 3 deletions src/tar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use {
crate::{cache, cache::CryptoHash, failure, failure::Failure, format::CodeStr, spinner::spin},
std::{
collections::HashSet,
fs::{read_link, symlink_metadata, File, Metadata},
io::{empty, Read, Seek, SeekFrom, Write},
fs::{File, Metadata, read_link, symlink_metadata},
io::{Read, Seek, SeekFrom, Write, empty},
path::Path,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
atomic::{AtomicBool, Ordering},
},
},
tar::{Builder, EntryType, Header},
Expand Down
18 changes: 12 additions & 6 deletions src/toastfile.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{failure::Failure, format, format::CodeStr},
serde::{de::Error, Deserialize, Deserializer},
serde::{Deserialize, Deserializer, de::Error},
std::{
collections::{HashMap, HashSet},
env,
Expand Down Expand Up @@ -641,8 +641,8 @@ fn check_task(name: &str, task: &Task) -> Result<(), Failure> {
mod tests {
use {
crate::toastfile::{
check_dependencies, check_task, command, environment, location, parse, user,
MappingPath, Task, Toastfile, DEFAULT_LOCATION, DEFAULT_USER,
DEFAULT_LOCATION, DEFAULT_USER, MappingPath, Task, Toastfile, check_dependencies,
check_task, command, environment, location, parse, user,
},
std::{collections::HashMap, env, path::Path},
typed_path::UnixPath,
Expand Down Expand Up @@ -1750,7 +1750,9 @@ tasks:
let mut expected = HashMap::new();
expected.insert("foo1".to_owned(), "baz".to_owned());

env::set_var("foo1", "baz");
unsafe {
env::set_var("foo1", "baz");
}
assert_eq!(env::var("foo1"), Ok("baz".to_owned()));
assert_eq!(environment(&task), Ok(expected));
}
Expand Down Expand Up @@ -1784,7 +1786,9 @@ tasks:
let mut expected = HashMap::new();
expected.insert("foo2".to_owned(), "bar".to_owned());

env::remove_var("foo2");
unsafe {
env::remove_var("foo2");
}
assert!(env::var("foo2").is_err());
assert_eq!(environment(&task), Ok(expected));
}
Expand Down Expand Up @@ -1815,7 +1819,9 @@ tasks:
extra_docker_arguments: vec![],
};

env::remove_var("foo3");
unsafe {
env::remove_var("foo3");
}
assert!(env::var("foo3").is_err());
let result = environment(&task);
assert!(result.is_err());
Expand Down
Loading