Skip to content

Commit

Permalink
feat: apply remote pattern name (#361)
Browse files Browse the repository at this point in the history
  • Loading branch information
seren5240 authored May 28, 2024
1 parent cce7a9b commit 3b39014
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 45 deletions.
81 changes: 51 additions & 30 deletions crates/cli/src/commands/apply_pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use marzano_core::api::{AllDone, AllDoneReason, AnalysisLog, MatchResult};
use marzano_core::pattern_compiler::CompilationResult;
use marzano_gritmodule::fetcher::KeepFetcherKind;
use marzano_gritmodule::markdown::get_body_from_md_content;
use marzano_gritmodule::searcher::find_grit_modules_dir;
use marzano_gritmodule::utils::is_pattern_name;
use marzano_gritmodule::searcher::{find_global_grit_dir, find_grit_modules_dir};
use marzano_gritmodule::utils::{is_pattern_name, parse_remote_name};
use marzano_language::target_language::PatternLanguage;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
Expand All @@ -41,11 +41,13 @@ use marzano_messenger::{
output_mode::OutputMode,
};

use crate::resolver::{get_grit_files_from_flags_or_cwd, GritModuleResolver};
use crate::resolver::{
get_grit_files_from_flags_or_cwd, get_grit_files_from_known_grit_dir, GritModuleResolver,
};
use crate::utils::has_uncommitted_changes;

use super::filters::SharedFilterArgs;
use super::init::init_config_from_cwd;
use super::init::{init_config_from_cwd, init_global_grit_modules};

/// Apply a pattern to a set of paths on disk which will be rewritten in place
#[derive(Deserialize)]
Expand Down Expand Up @@ -319,17 +321,25 @@ pub(crate) async fn run_apply_pattern(
.unwrap_or_else(|| &cwd)
.to_path_buf();
let mod_dir = find_grit_modules_dir(target_grit_dir.clone()).await;
let target_remote = parse_remote_name(&pattern);
let is_remote_name = target_remote.is_some();

if !env::var("GRIT_DOWNLOADS_DISABLED")
.unwrap_or_else(|_| "false".to_owned())
.parse::<bool>()
.unwrap_or(false)
&& mod_dir.is_err()
&& target_remote.is_none()
{
flushable_unwrap!(
emitter,
init_config_from_cwd::<KeepFetcherKind>(target_grit_dir, false).await
);
} else if let Some(target) = &target_remote {
flushable_unwrap!(
emitter,
init_global_grit_modules::<KeepFetcherKind>(Some(target)).await
);
}

#[cfg(feature = "grit_tracing")]
Expand All @@ -356,10 +366,18 @@ pub(crate) async fn run_apply_pattern(
#[cfg(feature = "grit_tracing")]
let grit_file_discovery = span!(tracing::Level::INFO, "grit_file_discovery",).entered();

let pattern_libs = flushable_unwrap!(
emitter,
get_grit_files_from_flags_or_cwd(format_flags).await
);
let pattern_libs = if let Some(target) = target_remote {
let global = find_global_grit_dir().await?;
flushable_unwrap!(
emitter,
get_grit_files_from_known_grit_dir(&global, vec![target]).await
)
} else {
flushable_unwrap!(
emitter,
get_grit_files_from_flags_or_cwd(format_flags).await
)
};

let (mut lang, pattern_body) = if pattern.ends_with(".grit") || pattern.ends_with(".md") {
match fs::read_to_string(pattern.clone()).await {
Expand Down Expand Up @@ -396,29 +414,32 @@ pub(crate) async fn run_apply_pattern(
}
}
}
} else if is_pattern_name(&pattern) {
let raw_name = pattern.trim_end_matches("()");
details.named_pattern = Some(raw_name.to_string());
let presumptive_grit_file = pattern_libs.get(format!("{}.grit", raw_name).as_str());
let lang = match presumptive_grit_file {
Some(g) => PatternLanguage::get_language(g),
None => PatternLanguage::get_language(&pattern),
};
let body = if pattern.ends_with(')') {
pattern.clone()
} else {
format!("{}()", pattern)
};
(lang, body)
} else if is_remote_name {
let raw_name = pattern.split('#').last().unwrap_or(&pattern);
let presumptive_grit_file = pattern_libs.get(format!("{}.grit", raw_name).as_str());
let lang = match presumptive_grit_file {
Some(g) => PatternLanguage::get_language(g),
None => PatternLanguage::get_language(raw_name),
};
let body = format!("{}()", raw_name);
(lang, body)
} else {
match is_pattern_name(&pattern) {
true => {
let raw_name = pattern.trim_end_matches("()");
details.named_pattern = Some(raw_name.to_string());
let presumptive_grit_file =
pattern_libs.get(format!("{}.grit", raw_name).as_str());
let lang = match presumptive_grit_file {
Some(g) => PatternLanguage::get_language(g),
None => PatternLanguage::get_language(&pattern),
};
let body = if pattern.ends_with(')') {
pattern.clone()
} else {
format!("{}()", pattern)
};
(lang, body)
}
false => {
let lang = PatternLanguage::get_language(&pattern);
(lang, pattern.clone())
}
}
let lang = PatternLanguage::get_language(&pattern);
(lang, pattern.clone())
};
if let Some(lang_option) = &default_lang {
if let Some(lang) = lang {
Expand Down
44 changes: 36 additions & 8 deletions crates/cli/src/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{env, fmt, io::ErrorKind, path::PathBuf, str::FromStr};

use tracing::instrument;

use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use clap::Args;
use colored::Colorize;
use log::info;
Expand All @@ -28,7 +28,7 @@ pub struct InitArgs {

pub(crate) async fn run_init(arg: InitArgs) -> Result<()> {
if arg.global {
init_global_grit_modules::<CleanFetcherKind>().await?;
init_global_grit_modules::<CleanFetcherKind>(None).await?;
} else {
let cwd = std::env::current_dir()?;
init_config_from_cwd::<CleanFetcherKind>(cwd, true).await?;
Expand Down Expand Up @@ -62,12 +62,12 @@ pub async fn init_config_from_cwd<T: FetcherType>(
Some(config) => PathBuf::from_str(&config).unwrap(),
None => {
if !create_local {
return init_global_grit_modules::<T>().await;
return init_global_grit_modules::<T>(None).await;
}
let git_dir = match find_git_dir_from(cwd).await {
Some(dir) => dir,
None => {
return init_global_grit_modules::<T>().await;
return init_global_grit_modules::<T>(None).await;
}
};
let git_path = PathBuf::from_str(&git_dir).unwrap();
Expand Down Expand Up @@ -112,17 +112,45 @@ patterns:
))?);
let parent_str = &grit_parent.to_string_lossy().to_string();
let repo = ModuleRepo::from_dir(&config_path).await;
fetch_modules::<T>(&repo, parent_str).await?;
fetch_modules::<T>(&repo, parent_str, None).await?;
Ok(ConfigSource::Local(config_path))
}

pub async fn init_global_grit_modules<T: FetcherType>() -> Result<ConfigSource> {
pub async fn init_global_grit_modules<T: FetcherType>(
from_module: Option<&ModuleRepo>,
) -> Result<ConfigSource> {
let global_grit_modules_dir = find_global_grit_modules_dir().await?;

let token = env::var("GRIT_PROVIDER_TOKEN").ok();
let fetcher = T::make_fetcher(global_grit_modules_dir, token);
fetcher.prep_grit_modules()?;
install_default_stdlib(&fetcher, None).await?;

if let Some(module) = from_module {
let location = match fetcher.fetch_grit_module(module) {
Ok(loc) => loc,
Err(err) => {
bail!(
"Failed to fetch remote grit module {}: {}",
module.full_name,
err.to_string()
)
}
};
fetch_modules::<T>(
module,
&location,
Some(
fetcher
.clone_dir()
.parent()
.context("Unable to find global grit dir")?
.to_path_buf(),
),
)
.await?;
} else {
fetcher.prep_grit_modules()?;
install_default_stdlib(&fetcher, None).await?;
}

Ok(ConfigSource::Global(find_global_grit_dir().await?))
}
2 changes: 1 addition & 1 deletion crates/cli/src/commands/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ pub(crate) async fn run_plumbing(
if input.paths.is_empty() {
return Ok(());
}
init_global_grit_modules::<KeepFetcherKind>().await?;
init_global_grit_modules::<KeepFetcherKind>(None).await?;
let combined_args = CheckArg {
paths: input.paths,
..args
Expand Down
12 changes: 8 additions & 4 deletions crates/cli/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ impl<'b> fmt::Display for RichPattern<'b> {
}
}

async fn from_known_grit_dir(config_path: &Path) -> Result<PatternsDirectory> {
let stdlib_modules = get_stdlib_modules();
pub async fn get_grit_files_from_known_grit_dir(
config_path: &Path,
must_process: Vec<ModuleRepo>,
) -> Result<PatternsDirectory> {
let mut stdlib_modules = get_stdlib_modules();
stdlib_modules.extend(must_process);

let grit_parent = PathBuf::from(config_path.parent().context(format!(
"Unable to find parent of .grit directory at {}",
Expand All @@ -84,7 +88,7 @@ pub async fn get_grit_files_from(cwd: Option<PathBuf>) -> Result<PatternsDirecto
};

match existing_config {
Some(config) => from_known_grit_dir(&PathBuf::from(config)).await,
Some(config) => get_grit_files_from_known_grit_dir(&PathBuf::from(config), vec![]).await,
None => {
let stdlib_modules = get_stdlib_modules();

Expand All @@ -108,7 +112,7 @@ pub async fn get_grit_files_from_flags_or_cwd(
flags: &GlobalFormatFlags,
) -> Result<PatternsDirectory> {
if let Some(grit_dir) = &flags.grit_dir {
from_known_grit_dir(grit_dir).await
get_grit_files_from_known_grit_dir(grit_dir, vec![]).await
} else {
let cwd = std::env::current_dir()?;
get_grit_files_from(Some(cwd)).await
Expand Down
7 changes: 7 additions & 0 deletions crates/cli_bin/fixtures/valibot/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const Schema1 = v.string([v.email("Email required")]);
const Schema2 = v.string([v.email(), v.endsWith("@example.com")]);
const Schema3 = v.string([
v.email(),
v.endsWith("@example.com"),
v.maxLength(30),
]);
21 changes: 21 additions & 0 deletions crates/cli_bin/tests/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2806,3 +2806,24 @@ def cool(name):

Ok(())
}

#[test]
fn apply_remote_pattern() -> Result<()> {
let (_temp_dir, dir) = get_fixture("valibot", false)?;

let mut cmd = get_test_cmd()?;

cmd.arg("apply")
.arg("github.com/fabian-hiller/valibot#migrate_to_v0_31_0")
.current_dir(dir.clone());

let output = cmd.output()?;

assert!(output.status.success(), "Command should have succeeded");

let test_file = dir.join("test.js");
let content: String = fs_err::read_to_string(&test_file)?;
assert_snapshot!(content);

Ok(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: crates/cli_bin/tests/apply.rs
expression: content
---
const Schema1 = v.pipe(v.string(), v.email("Email required"));
const Schema2 = v.pipe(v.string(), v.email(), v.endsWith("@example.com"));
const Schema3 = v.pipe(v.string(), v.email(),
v.endsWith("@example.com"),
v.maxLength(30),);
9 changes: 9 additions & 0 deletions crates/gritmodule/src/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ fn clone_repo<'a>(
}

pub trait GritModuleFetcher: Send + Sync {
fn clone_dir(&self) -> &PathBuf;
fn fetch_grit_module(&self, repo: &ModuleRepo) -> Result<String>;
fn prep_grit_modules(&self) -> Result<()>;
}
Expand Down Expand Up @@ -319,6 +320,10 @@ impl CleanFetcher {
}

impl GritModuleFetcher for CleanFetcher {
fn clone_dir(&self) -> &PathBuf {
&self.clone_dir
}

fn fetch_grit_module(&self, repo: &ModuleRepo) -> Result<String> {
let target_dir = self.get_grit_module_dir(repo);
self.clone_repo(repo, &target_dir)?;
Expand Down Expand Up @@ -362,6 +367,10 @@ impl KeepFetcher {
}

impl GritModuleFetcher for KeepFetcher {
fn clone_dir(&self) -> &PathBuf {
&self.clone_dir
}

fn fetch_grit_module(&self, repo: &ModuleRepo) -> Result<String> {
let target_dir = self.get_grit_module_dir(repo);
self.clone_repo(repo, &target_dir)?;
Expand Down
3 changes: 2 additions & 1 deletion crates/gritmodule/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ pub async fn find_user_patterns() -> Result<Vec<ResolvedGritDefinition>> {
pub async fn fetch_modules<T: FetcherType>(
module: &ModuleRepo,
grit_parent_dir: &str,
override_grit_dir: Option<PathBuf>,
) -> Result<()> {
let as_path = PathBuf::from_str(grit_parent_dir).unwrap();
let grit_dir = as_path.join(REPO_CONFIG_DIR_NAME);
let grit_dir = override_grit_dir.unwrap_or_else(|| as_path.join(REPO_CONFIG_DIR_NAME));

// Since git cloning is slow, two processes can try to clone at the same time and cause issues because they are overwriting each other
// To avoid this, we create a random dir name and move it to the actual gritmodules dir after cloning is complete
Expand Down
17 changes: 17 additions & 0 deletions crates/gritmodule/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use anyhow::{bail, Result};
use marzano_core::api::MatchResult;
use regex::Regex;

use crate::fetcher::ModuleRepo;

/// Extracts the *rewritten* (after applying a pattern) path from a `MatchResult`.
pub fn extract_path(result: &MatchResult) -> Option<&String> {
match result {
Expand Down Expand Up @@ -31,3 +33,18 @@ pub fn is_pattern_name(pattern: &str) -> bool {
let regex = Regex::new(r"^[a-zA-Z_][a-zA-Z0-9_]*(\(\))?$").unwrap();
regex.is_match(pattern)
}

pub fn parse_remote_name(pattern: &str) -> Option<ModuleRepo> {
let hash_index = pattern.find('#');
let hash_index = match hash_index {
Some(index) => index,
None => return None,
};
let repo_str = &pattern[..hash_index];
let pattern_name = &pattern[hash_index + 1..];
if is_pattern_name(pattern_name) {
ModuleRepo::from_repo_str(repo_str).ok()
} else {
None
}
}
2 changes: 1 addition & 1 deletion crates/lsp/src/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub async fn prep_grit_modules(
let grit_dir = grit_parent.join(REPO_CONFIG_DIR_NAME);
let repo = ModuleRepo::from_dir(&grit_dir).await;
if fetch {
let _ = fetch_modules::<KeepFetcherKind>(&repo, &grit_parent.to_string_lossy()).await;
let _ = fetch_modules::<KeepFetcherKind>(&repo, &grit_parent.to_string_lossy(), None).await;
}
let parent_str = grit_parent.to_string_lossy().to_string();
Ok((repo, parent_str, Some(stdlib_modules)))
Expand Down

0 comments on commit 3b39014

Please sign in to comment.