Skip to content

Commit

Permalink
feat: add http cache (#4160)
Browse files Browse the repository at this point in the history
* feat: add http cache

* feat: add some code

* feat: add some code

* [autofix.ci] apply automated fixes

* feat: add some code

* feat: add some code

* [autofix.ci] apply automated fixes

* feat: add some code

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
acesyde and autofix-ci[bot] authored Jan 25, 2025
1 parent a0d181f commit afa89de
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 105 deletions.
2 changes: 2 additions & 0 deletions docs/cli/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ Change how tasks information is output when running tasks
- `quiet` - Don't show extra output
- `silent` - Don't show any output including stdout and stderr from the task except for errors

### `--no-cache`

Examples:

```
Expand Down
2 changes: 2 additions & 0 deletions docs/cli/tasks/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ Change how tasks information is output when running tasks
- `quiet` - Don't show extra output
- `silent` - Don't show any output including stdout and stderr from the task except for errors

### `--no-cache`

Examples:

```
Expand Down
9 changes: 7 additions & 2 deletions docs/tasks/toml-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,13 @@ Task files can be fetched via http:
file = "https://example.com/build.sh"
```

Currently, they're fetched everytime they're executed, but we may add some cache support later.
This could be extended with other protocols like mentioned in [this ticket](https://github.com/jdx/mise/issues/2488) if there were interest.
Each task file is cached in the `MISE_CACHE_DIR` directory. If the file is updated, it will not be re-downloaded unless the cache is cleared.

:::tip
You can reset the cache by running `mise cache clear`.
:::

You can use the `MISE_TASK_REMOTE_NO_CACHE` environment variable to disable caching of remote tasks.

## Arguments

Expand Down
2 changes: 2 additions & 0 deletions mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ cmd run help="Run task(s)" {
long_help "Change how tasks information is output when running tasks\n\n- `prefix` - Print stdout/stderr by line, prefixed with the task's label\n- `interleave` - Print directly to stdout/stderr instead of by line\n- `replacing` - Stdout is replaced each time, stderr is printed as is\n- `timed` - Only show stdout lines if they are displayed for more than 1 second\n- `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n- `quiet` - Don't show extra output\n- `silent` - Don't show any output including stdout and stderr from the task except for errors"
arg <OUTPUT>
}
flag --no-cache
mount run="mise tasks --usage"
}
cmd self-update help="Updates mise itself." {
Expand Down Expand Up @@ -844,6 +845,7 @@ cmd tasks help="Manage tasks" {
long_help "Change how tasks information is output when running tasks\n\n- `prefix` - Print stdout/stderr by line, prefixed with the task's label\n- `interleave` - Print directly to stdout/stderr instead of by line\n- `replacing` - Stdout is replaced each time, stderr is printed as is\n- `timed` - Only show stdout lines if they are displayed for more than 1 second\n- `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n- `quiet` - Don't show extra output\n- `silent` - Don't show any output including stdout and stderr from the task except for errors"
arg <OUTPUT>
}
flag --no-cache
arg "[TASK]" help="Tasks to run\nCan specify multiple tasks by separating with `:::`\ne.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2" required=#false default=default
arg "[ARGS]..." help="Arguments to pass to the tasks. Use \":::\" to separate tasks" required=#false var=#true
arg "[-- ARGS_LAST]..." help="Arguments to pass to the tasks. Use \":::\" to separate tasks" required=#false var=#true hide=#true
Expand Down
4 changes: 4 additions & 0 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,10 @@
"silent"
]
},
"task_remote_no_cache": {
"description": "Mise will always fetch the latest tasks from the remote, by default the cache is used.",
"type": "boolean"
},
"task_run_auto_install": {
"default": true,
"description": "Automatically install missing tools when executing tasks.",
Expand Down
6 changes: 6 additions & 0 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,12 @@ docs = """
Change output style when executing tasks. This controls the output of `mise run`.
"""

[task_remote_no_cache]
env = "MISE_TASK_REMOTE_NO_CACHE"
type = "Bool"
optional = true
description = "Mise will always fetch the latest tasks from the remote, by default the cache is used."

[task_run_auto_install]
env = "MISE_TASK_RUN_AUTO_INSTALL"
type = "Bool"
Expand Down
1 change: 1 addition & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ impl Cli {
keep_order_output: Default::default(),
task_prs: Default::default(),
timed_outputs: Default::default(),
no_cache: Default::default(),
}));
} else if let Some(cmd) = external::COMMANDS.get(&task) {
external::execute(
Expand Down
9 changes: 7 additions & 2 deletions src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::config::{Config, SETTINGS};
use crate::env_diff::EnvMap;
use crate::errors::Error;
use crate::file::display_path;
use crate::task::file_providers::TaskFileProviders;
use crate::task::task_file_providers::TaskFileProviders;
use crate::task::{Deps, GetMatchingExt, Task};
use crate::toolset::{InstallOptions, ToolsetBuilder};
use crate::ui::multi_progress_report::MultiProgressReport;
Expand Down Expand Up @@ -194,6 +194,10 @@ pub struct Run {

#[clap(skip)]
pub timed_outputs: Arc<Mutex<IndexMap<String, (SystemTime, String)>>>,

// Do not use cache on remote tasks
#[clap(long, verbatim_doc_comment, env = "MISE_TASK_REMOTE_NO_CACHE")]
pub no_cache: bool,
}

type KeepOrderOutputs = (Vec<(String, String)>, Vec<(String, String)>);
Expand Down Expand Up @@ -873,7 +877,8 @@ impl Run {
}

fn fetch_tasks(&self, tasks: &mut Vec<Task>) -> Result<()> {
let task_file_providers = TaskFileProviders::new(self.tmpdir.clone());
let no_cache = self.no_cache || SETTINGS.task_remote_no_cache.unwrap_or(false);
let task_file_providers = TaskFileProviders::new(no_cache);

for t in tasks {
if let Some(file) = &t.file {
Expand Down
78 changes: 0 additions & 78 deletions src/task/file_providers/http_file_provider.rs

This file was deleted.

2 changes: 1 addition & 1 deletion src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use std::{ffi, fmt, path};
use xx::regex;

mod deps;
pub mod file_providers;
mod task_dep;
pub mod task_file_providers;
mod task_script_parser;
pub mod task_sources;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::path::{Path, PathBuf};
use super::TaskFileProvider;

#[derive(Debug)]
pub struct LocalTaskFileProvider;
pub struct LocalTask;

impl TaskFileProvider for LocalTaskFileProvider {
impl TaskFileProvider for LocalTask {
fn is_match(&self, file: &str) -> bool {
let path = Path::new(file);

Expand All @@ -24,7 +24,7 @@ mod tests {

#[test]
fn test_is_match() {
let provider = LocalTaskFileProvider;
let provider = LocalTask;
assert!(provider.is_match("filetask.bat"));
assert!(provider.is_match("filetask"));
assert!(provider.is_match("/test.txt"));
Expand All @@ -34,7 +34,7 @@ mod tests {

#[test]
fn test_get_local_path() {
let provider = LocalTaskFileProvider;
let provider = LocalTask;
assert_eq!(
provider.get_local_path("/test.txt").unwrap(),
PathBuf::from("/test.txt")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,65 +1,72 @@
use std::sync::LazyLock as Lazy;
use std::{fmt::Debug, path::PathBuf};

mod http_file_provider;
mod local_file_provider;
mod local_task;
mod remote_task_http;

pub use http_file_provider::HttpTaskFileProvider;
pub use local_file_provider::LocalTaskFileProvider;
pub use local_task::LocalTask;
pub use remote_task_http::RemoteTaskHttp;

use crate::dirs;

static REMOTE_TASK_CACHE_DIR: Lazy<PathBuf> = Lazy::new(|| dirs::CACHE.join("remote-tasks-cache"));

pub trait TaskFileProvider: Debug {
fn is_match(&self, file: &str) -> bool;
fn get_local_path(&self, file: &str) -> Result<PathBuf, Box<dyn std::error::Error>>;
}

pub struct TaskFileProviders {
tmpdir: PathBuf,
no_cache: bool,
}

impl TaskFileProviders {
pub fn new(no_cache: bool) -> Self {
Self { no_cache }
}

fn get_providers(&self) -> Vec<Box<dyn TaskFileProvider>> {
vec![
Box::new(HttpTaskFileProvider::new(self.tmpdir.clone())),
Box::new(LocalTaskFileProvider), // Must be the last provider
Box::new(RemoteTaskHttp::new(
REMOTE_TASK_CACHE_DIR.clone(),
self.no_cache,
)),
Box::new(LocalTask), // Must be the last provider
]
}

pub fn new(tmpdir: PathBuf) -> Self {
Self { tmpdir }
}

pub fn get_provider(&self, file: &str) -> Option<Box<dyn TaskFileProvider>> {
self.get_providers().into_iter().find(|p| p.is_match(file))
}
}

#[cfg(test)]
mod tests {
use std::env;

use super::*;

#[test]
fn test_get_providers() {
let task_file_providers = TaskFileProviders::new(env::temp_dir());
let task_file_providers = TaskFileProviders::new(false);
let providers = task_file_providers.get_providers();
assert_eq!(providers.len(), 2);
}

#[test]
fn test_local_file_match_local_provider() {
let task_file_providers = TaskFileProviders::new(env::temp_dir());
let task_file_providers = TaskFileProviders::new(false);
let cases = vec!["file.txt", "./file.txt", "../file.txt", "/file.txt"];

for file in cases {
let provider = task_file_providers.get_provider(file);
assert!(provider.is_some());
assert!(format!("{:?}", provider.unwrap()).contains("LocalTaskFileProvider"));
assert!(format!("{:?}", provider.unwrap()).contains("LocalTask"));
}
}

#[test]
fn test_http_file_match_http_provider() {
let task_file_providers = TaskFileProviders::new(env::temp_dir());
fn test_http_file_match_http_remote_task_provider() {
let task_file_providers = TaskFileProviders::new(false);
let cases = vec![
"http://example.com/file.txt",
"https://example.com/file.txt",
Expand All @@ -69,7 +76,7 @@ mod tests {
for file in cases {
let provider = task_file_providers.get_provider(file);
assert!(provider.is_some());
assert!(format!("{:?}", provider.unwrap()).contains("HttpTaskFileProvider"));
assert!(format!("{:?}", provider.unwrap()).contains("RemoteTaskHttp"));
}
}
}
Loading

0 comments on commit afa89de

Please sign in to comment.