Skip to content

Commit

Permalink
internal: Use Cow when appropriate. (#1217)
Browse files Browse the repository at this point in the history
* Update query.

* Update tokens.

* Update process.

* Polish.
  • Loading branch information
milesj authored Dec 7, 2023
1 parent e4a237f commit 1c7ce97
Show file tree
Hide file tree
Showing 13 changed files with 281 additions and 147 deletions.
6 changes: 3 additions & 3 deletions nextgen/action-graph/src/action_graph_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct RunRequirements<'app> {
}

pub struct ActionGraphBuilder<'app> {
all_query: Option<Criteria>,
all_query: Option<Criteria<'app>>,
graph: DiGraph<ActionNode, ()>,
indices: FxHashMap<ActionNode, NodeIndex>,
platform_manager: &'app PlatformManager,
Expand Down Expand Up @@ -77,7 +77,7 @@ impl<'app> ActionGraphBuilder<'app> {
Runtime::system()
}

pub fn set_query(&mut self, input: &str) -> miette::Result<()> {
pub fn set_query(&mut self, input: &'app str) -> miette::Result<()> {
self.all_query = Some(build_query(input)?);

Ok(())
Expand Down Expand Up @@ -318,7 +318,7 @@ impl<'app> ActionGraphBuilder<'app> {
TargetScope::Tag(tag) => {
let projects = self
.project_graph
.query(build_query(format!("tag={}", tag))?)?;
.query(build_query(format!("tag={}", tag).as_str())?)?;

for project in projects {
// Don't error if the task does not exist
Expand Down
49 changes: 47 additions & 2 deletions nextgen/args/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use miette::Diagnostic;
use std::ffi::{OsStr, OsString};
use thiserror::Error;

#[derive(Error, Debug, Diagnostic)]
Expand Down Expand Up @@ -44,7 +45,7 @@ where
let arg = arg.as_ref();

match arg {
"&" | "&&" | "|&" | "|" | "||" | ";" | "!" | ">" | ">>" | "<" | "-" | "--" => {
"&" | "&&" | "|&" | "|" | "||" | ";" | "!" | ">" | ">>" | "<" | "<<" | "-" | "--" => {
line.push_str(arg);
line.push(' ');
}
Expand All @@ -63,6 +64,50 @@ where
line
});

line.pop();
line.pop(); // Trailing space
line
}

pub fn join_args_os<I, S>(args: I) -> OsString
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let single_chars = [b"&", b"|", b";", b"!", b">", b"<", b"-"];
let multi_chars = [b"&&", b"|&", b"||", b">>", b"<<", b"--"];

args.into_iter().fold(OsString::new(), |mut line, arg| {
let arg = arg.as_ref();
let bytes = arg.as_encoded_bytes();
let bytes_len = bytes.len();

// Better way to do this?
let has_special_chars =
// Multi chars
bytes
.windows(bytes_len)
.any(|window| multi_chars.iter().any(|c| *c == window))
||
// Single chars
single_chars.iter().any(|c| bytes.contains(&c[0]));

if has_special_chars {
line.push(arg);
line.push(OsStr::new(" "));
} else {
if bytes.starts_with(&[b'$'])
|| bytes.starts_with(&[b'\''])
|| bytes.starts_with(&[b'"'])
{
line.push(arg);
} else {
let quoted = shell_words::quote(arg.to_str().unwrap()); // Handle conversion?
line.push(OsStr::new(quoted.as_ref()));
}

line.push(OsStr::new(" "))
}

line
})
}
2 changes: 1 addition & 1 deletion nextgen/process/src/async_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl<'cmd> AsyncCommand<'cmd> {
}

async fn write_input_to_child(&self, child: &mut Child) -> miette::Result<()> {
let input = &self.inspector.get_command_line().input;
let input = self.inspector.get_command_line().input.to_string_lossy();

let mut stdin = child.stdin.take().unwrap_or_else(|| {
panic!("Unable to write stdin: {input}");
Expand Down
65 changes: 39 additions & 26 deletions nextgen/process/src/command_inspector.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
use crate::command::Command;
use moon_args::join_args;
use moon_args::join_args_os;
use moon_common::color;
use once_cell::sync::OnceCell;
use rustc_hash::FxHashMap;
use std::borrow::Cow;
use std::env;
use std::ffi::OsStr;
use std::fmt::{self, Display};
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use tracing::{debug, enabled};

type LineValue<'l> = Cow<'l, OsStr>;

#[derive(Debug)]
pub struct CommandLine {
pub command: Vec<String>,
pub input: String,
pub main_command: String,
pub struct CommandLine<'l> {
pub command: Vec<LineValue<'l>>,
pub input: LineValue<'l>,
pub main_command: LineValue<'l>,
}

impl CommandLine {
impl<'l> CommandLine<'l> {
pub fn new(command: &Command) -> CommandLine {
let mut command_line: Vec<String> = vec![];
let mut input_line: Vec<String> = vec![];
let mut main_line: Vec<String> = vec![];
let mut command_line: Vec<LineValue> = vec![];
let mut input_line: Vec<LineValue> = vec![];
let mut main_line: Vec<LineValue> = vec![];
// let mut join_input = false;

let push_to_line = |line: &mut Vec<String>| {
line.push(command.bin.to_string_lossy().to_string());
let push_to_line = |line: &mut Vec<LineValue>| {
line.push(Cow::Owned(command.bin.to_owned()));

for arg in &command.args {
line.push(arg.to_string_lossy().to_string());
line.push(Cow::Owned(arg.to_owned()));
}
};

Expand All @@ -36,8 +40,8 @@ impl CommandLine {
// If wrapped in a shell, the shell binary and arguments
// must be placed at the start of the line.
if let Some(shell) = &command.shell {
command_line.push(shell.bin.clone());
command_line.extend(shell.args.clone());
command_line.push(Cow::Borrowed(OsStr::new(shell.bin.as_str())));
command_line.extend(shell.args.iter().map(|arg| Cow::Borrowed(OsStr::new(arg))));

// If the main command should be passed via stdin,
// then append the input line instead of the command line.
Expand All @@ -48,10 +52,10 @@ impl CommandLine {
// Otherwise append as a *single* argument. This typically
// appears after a "-" argument (should come from shell).
} else {
let mut sub_line: Vec<String> = vec![];
let mut sub_line: Vec<LineValue> = vec![];
push_to_line(&mut sub_line);

command_line.push(join_args(sub_line));
command_line.push(Cow::Owned(join_args_os(sub_line)));
}

// Otherwise we have a normal command and arguments.
Expand All @@ -61,7 +65,7 @@ impl CommandLine {
// That also may have input.
if !command.input.is_empty() {
for input in &command.input {
input_line.push(input.to_string_lossy().to_string());
input_line.push(Cow::Borrowed(input));
}
}
}
Expand All @@ -73,17 +77,18 @@ impl CommandLine {
// } else {
// input_line.join("")
// },
input: input_line.join(" "),
main_command: join_args(main_line),
input: Cow::Owned(input_line.join(OsStr::new(" "))),
main_command: Cow::Owned(join_args_os(main_line)),
}
}
}

impl Display for CommandLine {
impl<'l> Display for CommandLine<'l> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let command = join_args(&self.command);
let command = join_args_os(&self.command);
let command = command.to_string_lossy();

write!(f, "{}", &command)?;
write!(f, "{}", command)?;

if !self.input.is_empty() {
let debug_input = env::var("MOON_DEBUG_PROCESS_INPUT").is_ok();
Expand All @@ -99,7 +104,7 @@ impl Display for CommandLine {
if input.len() > 200 && !debug_input {
"(truncated)".into()
} else {
input.replace('\n', " ")
input.to_string_lossy().replace('\n', " ")
}
)?;
}
Expand All @@ -110,7 +115,7 @@ impl Display for CommandLine {

pub struct CommandInspector<'cmd> {
command: &'cmd Command,
line_cache: OnceCell<CommandLine>,
line_cache: OnceCell<CommandLine<'cmd>>,
}

impl<'cmd> CommandInspector<'cmd> {
Expand All @@ -124,7 +129,11 @@ impl<'cmd> CommandInspector<'cmd> {
pub fn get_cache_key(&self) -> String {
let line = self.get_command_line();

format!("{}{}", line.command.join(" "), line.input)
format!(
"{}{}",
line.command.join(OsStr::new(" ")).to_string_lossy(),
line.input.to_string_lossy()
)
}

pub fn get_command_line(&self) -> &CommandLine {
Expand Down Expand Up @@ -189,7 +198,11 @@ impl<'cmd> CommandInspector<'cmd> {
if self.command.print_command {
println!(
"{}",
self.format_command(&command_line.main_command, &workspace_root, None)
self.format_command(
command_line.main_command.to_str().unwrap(),
&workspace_root,
None
)
);
}

Expand Down
56 changes: 32 additions & 24 deletions nextgen/project-expander/src/token_expander.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use moon_task::Task;
use moon_time::{now_millis, now_timestamp};
use pathdiff::diff_paths;
use rustc_hash::FxHashMap;
use std::borrow::Cow;
use tracing::warn;

pub type ExpandedPaths = (Vec<WorkspaceRelativePathBuf>, Vec<WorkspaceRelativePathBuf>);
Expand Down Expand Up @@ -181,7 +182,7 @@ impl<'graph, 'query> TokenExpander<'graph, 'query> {
self.context
.project
.source
.join(self.replace_variable(task, var)?),
.join(self.replace_variable(task, Cow::Borrowed(var))?.as_ref()),
);
}
InputPath::ProjectFile(_) | InputPath::WorkspaceFile(_) => {
Expand Down Expand Up @@ -374,18 +375,22 @@ impl<'graph, 'query> TokenExpander<'graph, 'query> {
}

pub fn replace_variables(&self, task: &Task, value: &str) -> miette::Result<String> {
let mut value = value.to_owned();
let mut value = Cow::Borrowed(value);

while self.has_token_variable(&value) {
value = self.replace_variable(task, &value)?;
value = self.replace_variable(task, value)?;
}

Ok(value)
Ok(value.to_string())
}

pub fn replace_variable(&self, task: &Task, value: &str) -> miette::Result<String> {
let Some(matches) = patterns::TOKEN_VAR.captures(value) else {
return Ok(value.to_owned());
pub fn replace_variable<'l>(
&self,
task: &Task,
value: Cow<'l, str>,
) -> miette::Result<Cow<'l, str>> {
let Some(matches) = patterns::TOKEN_VAR.captures(&value) else {
return Ok(value);
};

let token = matches.get(0).unwrap().as_str(); // $var
Expand All @@ -404,30 +409,33 @@ impl<'graph, 'query> TokenExpander<'graph, 'query> {
)?;

let replaced_value = match variable {
"workspaceRoot" => path::to_string(self.context.workspace_root)?,
"workspaceRoot" => Cow::Owned(path::to_string(self.context.workspace_root)?),
// Project
"language" => project.language.to_string(),
"project" => project.id.to_string(),
"projectAlias" => project.alias.clone().unwrap_or_default(),
"projectRoot" => path::to_string(&project.root)?,
"projectSource" => project.source.to_string(),
"projectType" => project.type_of.to_string(),
"language" => Cow::Owned(project.language.to_string()),
"project" => Cow::Borrowed(project.id.as_str()),
"projectAlias" => match project.alias.as_ref() {
Some(alias) => Cow::Borrowed(alias.as_str()),
None => Cow::Owned(String::new()),
},
"projectRoot" => Cow::Owned(path::to_string(&project.root)?),
"projectSource" => Cow::Borrowed(project.source.as_str()),
"projectType" => Cow::Owned(project.type_of.to_string()),
// Task
"target" => task.target.to_string(),
"task" => task.id.to_string(),
"taskPlatform" => task.platform.to_string(),
"taskType" => task.type_of.to_string(),
"target" => Cow::Borrowed(task.target.as_str()),
"task" => Cow::Borrowed(task.id.as_str()),
"taskPlatform" => Cow::Owned(task.platform.to_string()),
"taskType" => Cow::Owned(task.type_of.to_string()),
// Datetime
"date" => now_timestamp().format("%F").to_string(),
"datetime" => now_timestamp().format("%F_%T").to_string(),
"time" => now_timestamp().format("%T").to_string(),
"timestamp" => (now_millis() / 1000).to_string(),
"date" => Cow::Owned(now_timestamp().format("%F").to_string()),
"datetime" => Cow::Owned(now_timestamp().format("%F_%T").to_string()),
"time" => Cow::Owned(now_timestamp().format("%T").to_string()),
"timestamp" => Cow::Owned((now_millis() / 1000).to_string()),
_ => {
return Ok(value.to_owned());
return Ok(value);
}
};

Ok(value.replace(token, &replaced_value))
Ok(value.replace(token, &replaced_value).into())
}

fn check_scope(&self, token: &str, allowed: &[TokenScope]) -> miette::Result<()> {
Expand Down
Loading

0 comments on commit 1c7ce97

Please sign in to comment.