From 65d7f78f0d0c527db2c370216ac87327d2908473 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Fri, 23 May 2025 21:37:08 +0200 Subject: [PATCH 01/39] add rescript 12 as dep --- rewatch/testrepo/package.json | 2 +- rewatch/testrepo/yarn.lock | 69 ++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/rewatch/testrepo/package.json b/rewatch/testrepo/package.json index 7f50287c62..3436184038 100644 --- a/rewatch/testrepo/package.json +++ b/rewatch/testrepo/package.json @@ -12,7 +12,7 @@ ] }, "dependencies": { - "rescript": "11.1.4" + "rescript": "12.0.0-alpha.13" }, "scripts": { "build": "../target/release/rewatch build .", diff --git a/rewatch/testrepo/yarn.lock b/rewatch/testrepo/yarn.lock index 01d1a28761..051f89cf65 100644 --- a/rewatch/testrepo/yarn.lock +++ b/rewatch/testrepo/yarn.lock @@ -14,6 +14,41 @@ __metadata: languageName: node linkType: hard +"@rescript/darwin-arm64@npm:12.0.0-alpha.13": + version: 12.0.0-alpha.13 + resolution: "@rescript/darwin-arm64@npm:12.0.0-alpha.13" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rescript/darwin-x64@npm:12.0.0-alpha.13": + version: 12.0.0-alpha.13 + resolution: "@rescript/darwin-x64@npm:12.0.0-alpha.13" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rescript/linux-arm64@npm:12.0.0-alpha.13": + version: 12.0.0-alpha.13 + resolution: "@rescript/linux-arm64@npm:12.0.0-alpha.13" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@rescript/linux-x64@npm:12.0.0-alpha.13": + version: 12.0.0-alpha.13 + resolution: "@rescript/linux-x64@npm:12.0.0-alpha.13" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@rescript/win32-x64@npm:12.0.0-alpha.13": + version: 12.0.0-alpha.13 + resolution: "@rescript/win32-x64@npm:12.0.0-alpha.13" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@testrepo/dep01@npm:*, @testrepo/dep01@workspace:packages/dep01": version: 0.0.0-use.local resolution: "@testrepo/dep01@workspace:packages/dep01" @@ -58,7 +93,7 @@ __metadata: languageName: unknown linkType: soft -"rescript@npm:*, rescript@npm:11.1.4": +"rescript@npm:*": version: 11.1.4 resolution: "rescript@npm:11.1.4" bin: @@ -69,10 +104,40 @@ __metadata: languageName: node linkType: hard +"rescript@npm:12.0.0-alpha.13": + version: 12.0.0-alpha.13 + resolution: "rescript@npm:12.0.0-alpha.13" + dependencies: + "@rescript/darwin-arm64": "npm:12.0.0-alpha.13" + "@rescript/darwin-x64": "npm:12.0.0-alpha.13" + "@rescript/linux-arm64": "npm:12.0.0-alpha.13" + "@rescript/linux-x64": "npm:12.0.0-alpha.13" + "@rescript/win32-x64": "npm:12.0.0-alpha.13" + dependenciesMeta: + "@rescript/darwin-arm64": + optional: true + "@rescript/darwin-x64": + optional: true + "@rescript/linux-arm64": + optional: true + "@rescript/linux-x64": + optional: true + "@rescript/win32-x64": + optional: true + bin: + bsc: cli/bsc.js + bstracing: cli/bstracing.js + rescript: cli/rescript.js + rescript-tools: cli/rescript-tools.js + rewatch: cli/rewatch.js + checksum: 10c0/97ad8615b1a1cbace61e050b65a10bbe280c77b4fe693b99aee7d3c6bb0b2ebd284db16a7aec3d65179267dc610a9737fdf74197f6322b1281113fd588fe1b32 + languageName: node + linkType: hard + "testrepo@workspace:.": version: 0.0.0-use.local resolution: "testrepo@workspace:." dependencies: - rescript: "npm:11.1.4" + rescript: "npm:12.0.0-alpha.13" languageName: unknown linkType: soft From 8ce238d95bd850773cf6e9f0a0b8ae0c40e70768 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Fri, 16 May 2025 23:20:49 +0200 Subject: [PATCH 02/39] paths wip - windows support fix Fix some issues Fix issue --- rewatch/src/build.rs | 35 +++-- rewatch/src/build/build_types.rs | 26 ++-- rewatch/src/build/clean.rs | 36 ++--- rewatch/src/build/compile.rs | 62 +++++---- rewatch/src/build/deps.rs | 6 +- rewatch/src/build/logs.rs | 10 +- rewatch/src/build/namespaces.rs | 13 +- rewatch/src/build/packages.rs | 169 ++++++++++++------------ rewatch/src/build/parse.rs | 51 +++---- rewatch/src/build/read_compile_state.rs | 46 +++---- rewatch/src/config.rs | 27 ++-- rewatch/src/helpers.rs | 98 ++++++-------- rewatch/src/main.rs | 19 ++- rewatch/src/sourcedirs.rs | 26 ++-- rewatch/src/watcher.rs | 43 +++--- 15 files changed, 328 insertions(+), 339 deletions(-) diff --git a/rewatch/src/build.rs b/rewatch/src/build.rs index 15f02de8b9..03dbaff9d9 100644 --- a/rewatch/src/build.rs +++ b/rewatch/src/build.rs @@ -21,7 +21,7 @@ use serde::Serialize; use std::fmt; use std::fs::File; use std::io::{stdout, Write}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::time::{Duration, Instant}; use self::compile::compiler_args; @@ -55,15 +55,14 @@ pub struct CompilerArgs { } pub fn get_compiler_args( - path: &str, + path: &Path, rescript_version: Option, - bsc_path: Option, + bsc_path: &Option, build_dev_deps: bool, ) -> Result { let filename = &helpers::get_abs_path(path); - let package_root = helpers::get_abs_path( - &helpers::get_nearest_config(&std::path::PathBuf::from(path)).expect("Couldn't find package root"), - ); + let package_root = + helpers::get_abs_path(&helpers::get_nearest_config(&path).expect("Couldn't find package root")); let workspace_root = get_workspace_root(&package_root).map(|p| helpers::get_abs_path(&p)); let root_rescript_config = packages::read_config(&workspace_root.to_owned().unwrap_or(package_root.to_owned()))?; @@ -73,17 +72,13 @@ pub fn get_compiler_args( } else { let bsc_path = match bsc_path { Some(bsc_path) => helpers::get_abs_path(&bsc_path), - None => helpers::get_bsc(&package_root, workspace_root.to_owned()), + None => helpers::get_bsc(&package_root, &workspace_root), }; helpers::get_rescript_version(&bsc_path) }; // make PathBuf from package root and get the relative path for filename - let relative_filename = PathBuf::from(&filename) - .strip_prefix(PathBuf::from(&package_root)) - .unwrap() - .to_string_lossy() - .to_string(); + let relative_filename = filename.strip_prefix(PathBuf::from(&package_root)).unwrap(); let file_path = PathBuf::from(&package_root).join(filename); let contents = helpers::read_file(&file_path).expect("Error reading file"); @@ -97,18 +92,18 @@ pub fn get_compiler_args( workspace_root.as_ref().unwrap_or(&package_root), &contents, ); - let is_interface = filename.ends_with('i'); + let is_interface = filename.to_string_lossy().ends_with('i'); let has_interface = if is_interface { true } else { - let mut interface_filename = filename.to_string(); + let mut interface_filename = filename.to_string_lossy().to_string(); interface_filename.push('i'); PathBuf::from(&interface_filename).exists() }; let compiler_args = compiler_args( &rescript_config, &root_rescript_config, - &ast_path.to_string_lossy(), + &ast_path, &rescript_version, &relative_filename, is_interface, @@ -131,15 +126,15 @@ pub fn initialize_build( default_timing: Option, filter: &Option, show_progress: bool, - path: &str, - bsc_path: Option, + path: &Path, + bsc_path: &Option, build_dev_deps: bool, ) -> Result { let project_root = helpers::get_abs_path(path); let workspace_root = helpers::get_workspace_root(&project_root); let bsc_path = match bsc_path { Some(bsc_path) => helpers::get_abs_path(&bsc_path), - None => helpers::get_bsc(&project_root, workspace_root.to_owned()), + None => helpers::get_bsc(&project_root, &workspace_root), }; let root_config_name = packages::read_package_name(&project_root)?; let rescript_version = helpers::get_rescript_version(&bsc_path); @@ -453,11 +448,11 @@ pub fn write_build_ninja(build_state: &BuildState) { pub fn build( filter: &Option, - path: &str, + path: &Path, show_progress: bool, no_timing: bool, create_sourcedirs: bool, - bsc_path: Option, + bsc_path: &Option, build_dev_deps: bool, ) -> Result { let default_timing: Option = if no_timing { diff --git a/rewatch/src/build/build_types.rs b/rewatch/src/build/build_types.rs index 51700e7d7c..15bf3eb712 100644 --- a/rewatch/src/build/build_types.rs +++ b/rewatch/src/build/build_types.rs @@ -1,6 +1,6 @@ use crate::build::packages::{Namespace, Package}; use ahash::{AHashMap, AHashSet}; -use std::{fmt::Display, time::SystemTime}; +use std::{fmt::Display, path::PathBuf, time::SystemTime}; #[derive(Debug, Clone, PartialEq)] pub enum ParseState { @@ -19,7 +19,7 @@ pub enum CompileState { } #[derive(Debug, Clone, PartialEq)] pub struct Interface { - pub path: String, + pub path: PathBuf, pub parse_state: ParseState, pub compile_state: CompileState, pub last_modified: SystemTime, @@ -28,7 +28,7 @@ pub struct Interface { #[derive(Debug, Clone, PartialEq)] pub struct Implementation { - pub path: String, + pub path: PathBuf, pub parse_state: ParseState, pub compile_state: CompileState, pub last_modified: SystemTime, @@ -91,12 +91,12 @@ pub struct BuildState { pub modules: AHashMap, pub packages: AHashMap, pub module_names: AHashSet, - pub project_root: String, + pub project_root: PathBuf, pub root_config_name: String, pub deleted_modules: AHashSet, pub rescript_version: String, - pub bsc_path: String, - pub workspace_root: Option, + pub bsc_path: PathBuf, + pub workspace_root: Option, pub deps_initialized: bool, } @@ -109,12 +109,12 @@ impl BuildState { self.modules.get(module_name) } pub fn new( - project_root: String, + project_root: PathBuf, root_config_name: String, packages: AHashMap, - workspace_root: Option, + workspace_root: Option, rescript_version: String, - bsc_path: String, + bsc_path: PathBuf, ) -> Self { Self { module_names: AHashSet::new(), @@ -141,15 +141,15 @@ pub struct AstModule { pub package_name: String, pub namespace: Namespace, pub last_modified: SystemTime, - pub ast_file_path: String, + pub ast_file_path: PathBuf, pub is_root: bool, pub suffix: String, } pub struct CompileAssetsState { - pub ast_modules: AHashMap, + pub ast_modules: AHashMap, pub cmi_modules: AHashMap, pub cmt_modules: AHashMap, - pub ast_rescript_file_locations: AHashSet, - pub rescript_file_locations: AHashSet, + pub ast_rescript_file_locations: AHashSet, + pub rescript_file_locations: AHashSet, } diff --git a/rewatch/src/build/clean.rs b/rewatch/src/build/clean.rs index ba53e4ff5e..d0ec07d142 100644 --- a/rewatch/src/build/clean.rs +++ b/rewatch/src/build/clean.rs @@ -7,9 +7,10 @@ use anyhow::Result; use console::style; use rayon::prelude::*; use std::io::Write; +use std::path::{Path, PathBuf}; use std::time::Instant; -fn remove_ast(package: &packages::Package, source_file: &str) { +fn remove_ast(package: &packages::Package, source_file: &Path) { let _ = std::fs::remove_file(helpers::get_compiler_asset( package, &packages::Namespace::NoNamespace, @@ -18,7 +19,7 @@ fn remove_ast(package: &packages::Package, source_file: &str) { )); } -fn remove_iast(package: &packages::Package, source_file: &str) { +fn remove_iast(package: &packages::Package, source_file: &Path) { let _ = std::fs::remove_file(helpers::get_compiler_asset( package, &packages::Namespace::NoNamespace, @@ -27,15 +28,14 @@ fn remove_iast(package: &packages::Package, source_file: &str) { )); } -fn remove_mjs_file(source_file: &str, suffix: &String) { - let _ = std::fs::remove_file(helpers::change_extension( - source_file, +fn remove_mjs_file(source_file: &Path, suffix: &String) { + let _ = std::fs::remove_file(source_file.with_extension( // suffix.to_string includes the ., so we need to remove it &suffix.to_string()[1..], )); } -fn remove_compile_asset(package: &packages::Package, source_file: &str, extension: &str) { +fn remove_compile_asset(package: &packages::Package, source_file: &Path, extension: &str) { let _ = std::fs::remove_file(helpers::get_compiler_asset( package, &package.namespace, @@ -50,7 +50,7 @@ fn remove_compile_asset(package: &packages::Package, source_file: &str, extensio )); } -pub fn remove_compile_assets(package: &packages::Package, source_file: &str) { +pub fn remove_compile_assets(package: &packages::Package, source_file: &Path) { // optimization // only issue cmti if there is an interfacce file for extension in &["cmj", "cmi", "cmt", "cmti"] { @@ -79,23 +79,20 @@ pub fn clean_mjs_files(build_state: &BuildState) { .filter_map(|spec| { if spec.in_source { Some(( - std::path::PathBuf::from(package.path.to_string()) - .join(&source_file.implementation.path) - .to_string_lossy() - .to_string(), + package.path.join(&source_file.implementation.path), root_package.config.get_suffix(spec), )) } else { None } }) - .collect::>(), + .collect::>(), ) } _ => None, }) .flatten() - .collect::>(); + .collect::>(); rescript_file_locations .par_iter() @@ -118,7 +115,7 @@ pub fn cleanup_previous_build( let diff = compile_assets_state .ast_rescript_file_locations .difference(&compile_assets_state.rescript_file_locations) - .collect::>(); + .collect::>(); let diff_len = diff.len(); @@ -133,7 +130,7 @@ pub fn cleanup_previous_build( .. } = compile_assets_state .ast_modules - .get(&res_file_location.to_string()) + .get(*res_file_location) .expect("Could not find module name for ast file"); let package = build_state @@ -338,7 +335,12 @@ pub fn cleanup_after_build(build_state: &BuildState) { }); } -pub fn clean(path: &str, show_progress: bool, bsc_path: Option, build_dev_deps: bool) -> Result<()> { +pub fn clean( + path: &Path, + show_progress: bool, + bsc_path: &Option, + build_dev_deps: bool, +) -> Result<()> { let project_root = helpers::get_abs_path(path); let workspace_root = helpers::get_workspace_root(&project_root); let packages = packages::make( @@ -352,7 +354,7 @@ pub fn clean(path: &str, show_progress: bool, bsc_path: Option, build_de let root_config_name = packages::read_package_name(&project_root)?; let bsc_path = match bsc_path { Some(bsc_path) => helpers::get_abs_path(&bsc_path), - None => helpers::get_bsc(&project_root, workspace_root.to_owned()), + None => helpers::get_bsc(&project_root, &workspace_root), }; let rescript_version = helpers::get_rescript_version(&bsc_path); diff --git a/rewatch/src/build/compile.rs b/rewatch/src/build/compile.rs index 73260ec6a9..6b8b8922c4 100644 --- a/rewatch/src/build/compile.rs +++ b/rewatch/src/build/compile.rs @@ -12,7 +12,7 @@ use anyhow::anyhow; use console::style; use log::{debug, trace}; use rayon::prelude::*; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::Command; use std::time::SystemTime; @@ -162,7 +162,7 @@ pub fn compile( let result = compile_file( package, root_package, - &helpers::get_ast_path(&path).to_string_lossy(), + &helpers::get_ast_path(&path), module, &build_state.rescript_version, true, @@ -179,7 +179,7 @@ pub fn compile( let result = compile_file( package, root_package, - &helpers::get_ast_path(&source_file.implementation.path).to_string_lossy(), + &helpers::get_ast_path(&source_file.implementation.path), module, &build_state.rescript_version, false, @@ -352,13 +352,13 @@ pub fn compile( pub fn compiler_args( config: &config::Config, root_config: &config::Config, - ast_path: &str, + ast_path: &Path, version: &str, - file_path: &str, + file_path: &Path, is_interface: bool, has_interface: bool, - project_root: &str, - workspace_root: &Option, + project_root: &Path, + workspace_root: &Option, // if packages are known, we pass a reference here // this saves us a scan to find their paths packages: &Option<&AHashMap>, @@ -494,7 +494,7 @@ pub fn compiler_args( // abs_node_modules_path.to_string() + "/rescript/ocaml", // ], vec!["-bs-v".to_string(), format!("{}", version)], - vec![ast_path.to_string()], + vec![ast_path.to_string_lossy().to_string()], ] .concat() } @@ -523,8 +523,8 @@ impl DependentPackage { fn get_dependency_paths( config: &config::Config, - project_root: &str, - workspace_root: &Option, + project_root: &Path, + workspace_root: &Option, packages: &Option<&AHashMap>, build_dev_deps: bool, ) -> Vec> { @@ -553,14 +553,19 @@ fn get_dependency_paths( .filter_map(|dependent_package| { let package_name = dependent_package.name(); let dependency_path = if let Some(packages) = packages { - packages.get(package_name).map(|package| package.path.to_string()) + packages + .get(package_name) + .as_ref() + .map(|package| package.path.clone()) } else { packages::read_dependency(package_name, project_root, project_root, workspace_root).ok() } .map(|canonicalized_path| { vec![ "-I".to_string(), - packages::get_ocaml_build_path(&canonicalized_path), + packages::get_ocaml_build_path(&canonicalized_path) + .to_string_lossy() + .to_string(), ] }); @@ -579,14 +584,14 @@ fn get_dependency_paths( fn compile_file( package: &packages::Package, root_package: &packages::Package, - ast_path: &str, + ast_path: &Path, module: &Module, version: &str, is_interface: bool, - bsc_path: &str, + bsc_path: &Path, packages: &AHashMap, - project_root: &str, - workspace_root: &Option, + project_root: &Path, + workspace_root: &Option, build_dev_deps: bool, ) -> Result, String> { let ocaml_build_path_abs = package.get_ocaml_build_path(); @@ -595,7 +600,8 @@ fn compile_file( SourceType::SourceFile(ref source_file) => Ok(&source_file.implementation.path), sourcetype => Err(format!( "Tried to compile a file that is not a source file ({}). Path to AST: {}. ", - sourcetype, ast_path + sourcetype, + ast_path.to_string_lossy() )), }?; let module_name = helpers::file_path_to_module_name(implementation_file_path, &package.namespace); @@ -615,7 +621,7 @@ fn compile_file( ); let to_mjs = Command::new(bsc_path) - .current_dir(helpers::canonicalize_string_path(&build_path_abs.to_owned()).unwrap()) + .current_dir(build_path_abs.canonicalize().ok().unwrap()) .args(to_mjs_args) .output(); @@ -644,14 +650,14 @@ fn compile_file( // because editor tooling doesn't support namespace entries yet // we just remove the @ for now. This makes sure the editor support // doesn't break - .join(module_name.to_owned() + ".cmi"), - ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmi", + .join(module_name.to_string() + ".cmi"), + ocaml_build_path_abs.join(module_name.to_string() + ".cmi"), ); let _ = std::fs::copy( std::path::Path::new(&package.get_build_path()) .join(dir) - .join(module_name.to_owned() + ".cmj"), - ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmj", + .join(module_name.to_string() + ".cmj"), + ocaml_build_path_abs.join(module_name.to_string() + ".cmj"), ); let _ = std::fs::copy( std::path::Path::new(&package.get_build_path()) @@ -659,21 +665,21 @@ fn compile_file( // because editor tooling doesn't support namespace entries yet // we just remove the @ for now. This makes sure the editor support // doesn't break - .join(module_name.to_owned() + ".cmt"), - ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmt", + .join(module_name.to_string() + ".cmt"), + ocaml_build_path_abs.join(module_name.to_string() + ".cmt"), ); } else { let _ = std::fs::copy( std::path::Path::new(&package.get_build_path()) .join(dir) - .join(module_name.to_owned() + ".cmti"), - ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmti", + .join(module_name.to_string() + ".cmti"), + ocaml_build_path_abs.join(module_name.to_string() + ".cmti"), ); let _ = std::fs::copy( std::path::Path::new(&package.get_build_path()) .join(dir) - .join(module_name.to_owned() + ".cmi"), - ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmi", + .join(module_name.to_string() + ".cmi"), + ocaml_build_path_abs.join(module_name.to_string() + ".cmi"), ); } diff --git a/rewatch/src/build/deps.rs b/rewatch/src/build/deps.rs index 59ddd3c2a7..373f449d4a 100644 --- a/rewatch/src/build/deps.rs +++ b/rewatch/src/build/deps.rs @@ -12,8 +12,8 @@ fn get_dep_modules( package: &packages::Package, ) -> AHashSet { let mut deps = AHashSet::new(); - let ast_file = package.get_build_path() + "/" + ast_file; - if let Ok(lines) = helpers::read_lines(ast_file.to_string()) { + let ast_file = package.get_build_path().join(ast_file); + if let Ok(lines) = helpers::read_lines(&ast_file) { // we skip the first line with is some null characters // the following lines in the AST are the dependency modules // we stop when we hit a line that starts with a "/", this is the path of the file. @@ -27,7 +27,7 @@ fn get_dep_modules( } } } else { - panic!("Could not read file {}", ast_file); + panic!("Could not read file {}", ast_file.to_string_lossy()); } return deps diff --git a/rewatch/src/build/logs.rs b/rewatch/src/build/logs.rs index 5f3b8b4026..0f92896ac3 100644 --- a/rewatch/src/build/logs.rs +++ b/rewatch/src/build/logs.rs @@ -6,6 +6,7 @@ use rayon::prelude::*; use regex::Regex; use std::fs::File; use std::io::prelude::*; +use std::path::PathBuf; use super::packages; @@ -14,13 +15,13 @@ enum Location { Ocaml, } -fn get_log_file_path(package: &packages::Package, subfolder: Location) -> String { +fn get_log_file_path(package: &packages::Package, subfolder: Location) -> PathBuf { let build_folder = match subfolder { Location::Bs => package.get_build_path(), Location::Ocaml => package.get_ocaml_build_path(), }; - build_folder.to_owned() + "/.compiler.log" + build_folder.join(".compiler.log") } fn escape_colours(str: &str) -> String { @@ -59,7 +60,10 @@ pub fn append(package: &packages::Package, str: &str) { .append(true) .open(get_log_file_path(package, Location::Bs)) .map(|file| write_to_log_file(file, &package.name, str)) - .expect(&("Cannot write compilerlog: ".to_owned() + &get_log_file_path(package, Location::Bs))); + .expect( + &("Cannot write compilerlog: ".to_owned() + + &get_log_file_path(package, Location::Bs).to_string_lossy()), + ); } pub fn finalize(packages: &AHashMap) { diff --git a/rewatch/src/build/namespaces.rs b/rewatch/src/build/namespaces.rs index 39b943d848..88e1ffd51d 100644 --- a/rewatch/src/build/namespaces.rs +++ b/rewatch/src/build/namespaces.rs @@ -1,8 +1,9 @@ use crate::build::packages; -use crate::helpers; use ahash::AHashSet; use std::fs::File; use std::io::Write; +use std::path::Path; +use std::path::PathBuf; use std::process::Command; // Namespaces work like the following: The build system will generate a file @@ -23,13 +24,13 @@ pub fn gen_mlmap( package: &packages::Package, namespace: &str, depending_modules: &AHashSet, -) -> String { +) -> PathBuf { let build_path_abs = package.get_build_path(); // we don't really need to create a digest, because we track if we need to // recompile in a different way but we need to put it in the file for it to // be readable. - let path = build_path_abs.to_string() + "/" + namespace + ".mlmap"; + let path = build_path_abs.join(namespace.to_string() + ".mlmap"); let mut file = File::create(&path).expect("Unable to create mlmap"); file.write_all(b"randjbuildsystem\n") @@ -46,16 +47,16 @@ pub fn gen_mlmap( file.write_all(b"\n").unwrap(); } - path.to_string() + path } -pub fn compile_mlmap(package: &packages::Package, namespace: &str, bsc_path: &str) { +pub fn compile_mlmap(package: &packages::Package, namespace: &str, bsc_path: &Path) { let build_path_abs = package.get_build_path(); let mlmap_name = format!("{}.mlmap", namespace); let args = vec!["-w", "-49", "-color", "always", "-no-alias-deps", &mlmap_name]; let _ = Command::new(bsc_path) - .current_dir(helpers::canonicalize_string_path(&build_path_abs).unwrap()) + .current_dir(build_path_abs.canonicalize().ok().unwrap()) .args(args) .output() .expect("err"); diff --git a/rewatch/src/build/packages.rs b/rewatch/src/build/packages.rs index d85f93f754..553d9e8774 100644 --- a/rewatch/src/build/packages.rs +++ b/rewatch/src/build/packages.rs @@ -41,7 +41,7 @@ impl Namespace { struct Dependency { name: String, config: config::Config, - path: String, + path: PathBuf, is_pinned: bool, dependencies: Vec, } @@ -52,68 +52,66 @@ pub struct Package { pub config: config::Config, pub source_folders: AHashSet, // these are the relative file paths (relative to the package root) - pub source_files: Option>, + pub source_files: Option>, pub namespace: Namespace, pub modules: Option>, // canonicalized dir of the package - pub path: String, + pub path: PathBuf, pub dirs: Option>, pub is_pinned_dep: bool, pub is_local_dep: bool, pub is_root: bool, } -pub fn get_build_path(canonical_path: &str) -> String { - format!("{}/lib/bs", canonical_path) +pub fn get_build_path(canonical_path: &Path) -> PathBuf { + canonical_path.join("lib").join("bs") } -pub fn get_js_path(canonical_path: &str) -> String { - format!("{}/lib/js", canonical_path) +pub fn get_js_path(canonical_path: &Path) -> PathBuf { + canonical_path.join("lib").join("js") } -pub fn get_es6_path(canonical_path: &str) -> String { - format!("{}/lib/es6", canonical_path) +pub fn get_es6_path(canonical_path: &Path) -> PathBuf { + canonical_path.join("lib").join("es6") } -pub fn get_ocaml_build_path(canonical_path: &str) -> String { - format!("{}/lib/ocaml", canonical_path) +pub fn get_ocaml_build_path(canonical_path: &Path) -> PathBuf { + canonical_path.join("lib").join("ocaml") } impl Package { - pub fn get_ocaml_build_path(&self) -> String { + pub fn get_ocaml_build_path(&self) -> PathBuf { get_ocaml_build_path(&self.path) } - pub fn get_build_path(&self) -> String { + pub fn get_build_path(&self) -> PathBuf { get_build_path(&self.path) } - pub fn get_js_path(&self) -> String { + pub fn get_js_path(&self) -> PathBuf { get_js_path(&self.path) } - pub fn get_es6_path(&self) -> String { + pub fn get_es6_path(&self) -> PathBuf { get_es6_path(&self.path) } - pub fn get_mlmap_path(&self) -> String { - self.get_build_path() - + "/" - + &self - .namespace + pub fn get_mlmap_path(&self) -> PathBuf { + self.get_build_path().join( + self.namespace .to_suffix() .expect("namespace should be set for mlmap module") - + ".mlmap" + + ".mlmap", + ) } - pub fn get_mlmap_compile_path(&self) -> String { - self.get_build_path() - + "/" - + &self - .namespace + pub fn get_mlmap_compile_path(&self) -> PathBuf { + self.get_build_path().join( + self.namespace .to_suffix() .expect("namespace should be set for mlmap module") - + ".cmi" + + ".cmi", + ) } } @@ -141,8 +139,8 @@ pub fn read_folders( package_dir: &Path, path: &Path, recurse: bool, -) -> Result, Box> { - let mut map: AHashMap = AHashMap::new(); +) -> Result, Box> { + let mut map: AHashMap = AHashMap::new(); let path_buf = PathBuf::from(path); let meta = fs::metadata(package_dir.join(path)); let path_with_meta = meta.map(|meta| { @@ -174,7 +172,7 @@ pub fn read_folders( let mut path = path.to_owned(); path.push(&name); map.insert( - path.to_string_lossy().to_string(), + path, SourceFileMeta { modified: metadata.modified().unwrap(), }, @@ -230,29 +228,23 @@ fn get_source_dirs(source: config::Source, sub_path: Option) -> AHashSe source_folders } -pub fn read_config(package_dir: &str) -> Result { - let prefix = if package_dir.is_empty() { - "".to_string() - } else { - package_dir.to_string() + "/" - }; - - let rescript_json_path = prefix.to_string() + "rescript.json"; - let bsconfig_json_path = prefix.to_string() + "bsconfig.json"; +pub fn read_config(package_dir: &Path) -> Result { + let rescript_json_path = package_dir.join("rescript.json"); + let bsconfig_json_path = package_dir.join("bsconfig.json"); if Path::new(&rescript_json_path).exists() { - config::read(rescript_json_path) + config::read(&rescript_json_path) } else { - config::read(bsconfig_json_path) + config::read(&bsconfig_json_path) } } pub fn read_dependency( package_name: &str, - parent_path: &str, - project_root: &str, - workspace_root: &Option, -) -> Result { + parent_path: &Path, + project_root: &Path, + workspace_root: &Option, +) -> Result { let path_from_parent = PathBuf::from(helpers::package_path(parent_path, package_name)); let path_from_project_root = PathBuf::from(helpers::package_path(project_root, package_name)); let maybe_path_from_workspace_root = workspace_root @@ -276,7 +268,7 @@ pub fn read_dependency( }?; let canonical_path = match path.canonicalize() { - Ok(canonical_path) => Ok(canonical_path.to_string_lossy().to_string()), + Ok(canonical_path) => Ok(canonical_path), Err(e) => { Err(format!( "Failed canonicalizing the package \"{}\" path \"{}\" (are node_modules up-to-date?)...\nMore details: {}", @@ -301,9 +293,9 @@ pub fn read_dependency( fn read_dependencies( registered_dependencies_set: &mut AHashSet, parent_config: &config::Config, - parent_path: &str, - project_root: &str, - workspace_root: Option, + parent_path: &Path, + project_root: &Path, + workspace_root: &Option, show_progress: bool, ) -> Vec { return parent_config @@ -335,8 +327,9 @@ fn read_dependencies( ); } + let parent_path_str = parent_path.to_string_lossy(); log::error!( - "We could not build package tree reading depencency '{package_name}', at path '{parent_path}'. Error: {error}", + "We could not build package tree reading depencency '{package_name}', at path '{parent_path_str}'. Error: {error}", ); std::process::exit(2) @@ -345,8 +338,9 @@ fn read_dependencies( match read_config(&canonical_path) { Ok(config) => (config, canonical_path), Err(error) => { + let parent_path_str = parent_path.to_string_lossy(); log::error!( - "We could not build package tree '{package_name}', at path '{parent_path}', Error: {error}", + "We could not build package tree '{package_name}', at path '{parent_path_str}'. Error: {error}", ); std::process::exit(2) } @@ -365,7 +359,7 @@ fn read_dependencies( &config, &canonical_path, project_root, - workspace_root.to_owned(), + workspace_root, show_progress ); @@ -390,12 +384,8 @@ fn flatten_dependencies(dependencies: Vec) -> Vec { flattened } -pub fn read_package_name(package_dir: &str) -> Result { - let package_json_path = if package_dir.is_empty() { - "package.json".to_string() - } else { - format!("{}/package.json", package_dir) - }; +pub fn read_package_name(package_dir: &Path) -> Result { + let package_json_path = package_dir.join("package.json"); let package_json_contents = fs::read_to_string(&package_json_path).map_err(|e| anyhow!("Could not read package.json: {}", e))?; @@ -409,7 +399,7 @@ pub fn read_package_name(package_dir: &str) -> Result { .ok_or_else(|| anyhow!("No name field found in package.json")) } -fn make_package(config: config::Config, package_path: &str, is_pinned_dep: bool, is_root: bool) -> Package { +fn make_package(config: config::Config, package_path: &Path, is_pinned_dep: bool, is_root: bool) -> Package { let source_folders = match config.sources.to_owned() { Some(config::OneOrMore::Single(source)) => get_source_dirs(source, None), Some(config::OneOrMore::Multiple(sources)) => { @@ -424,7 +414,8 @@ fn make_package(config: config::Config, package_path: &str, is_pinned_dep: bool, } None => { if !is_root { - log::warn!("Package '{}' has not defined any sources, but is not the root package. This is likely a mistake. It is located: {}", config.name, package_path); + let package_path_str = package_path.to_string_lossy(); + log::warn!("Package '{}' has not defined any sources, but is not the root package. This is likely a mistake. It is located: {}", config.name, package_path_str); } AHashSet::new() @@ -440,21 +431,17 @@ fn make_package(config: config::Config, package_path: &str, is_pinned_dep: bool, namespace: config.get_namespace(), modules: None, // we canonicalize the path name so it's always the same - path: PathBuf::from(package_path) - .canonicalize() - .expect("Could not canonicalize") - .to_string_lossy() - .to_string(), + path: package_path.canonicalize().expect("Could not canonicalize"), dirs: None, is_pinned_dep, - is_local_dep: !package_path.contains("node_modules"), + is_local_dep: !package_path.components().any(|c| c.as_os_str() == "node_modules"), is_root, } } fn read_packages( - project_root: &str, - workspace_root: Option, + project_root: &Path, + workspace_root: &Option, show_progress: bool, ) -> Result> { let root_config = read_config(project_root)?; @@ -497,8 +484,8 @@ pub fn get_source_files( filter: &Option, source: &config::PackageSource, build_dev_deps: bool, -) -> AHashMap { - let mut map: AHashMap = AHashMap::new(); +) -> AHashMap { + let mut map: AHashMap = AHashMap::new(); let (recurse, type_) = match source { config::PackageSource { @@ -535,7 +522,7 @@ fn extend_with_children( build_dev_deps: bool, ) -> AHashMap { for (_key, package) in build.iter_mut() { - let mut map: AHashMap = AHashMap::new(); + let mut map: AHashMap = AHashMap::new(); package .source_folders .par_iter() @@ -548,7 +535,7 @@ fn extend_with_children( build_dev_deps, ) }) - .collect::>>() + .collect::>>() .into_iter() .for_each(|source| map.extend(source)); @@ -586,12 +573,12 @@ fn extend_with_children( /// The two step process is there to reduce IO overhead pub fn make( filter: &Option, - root_folder: &str, - workspace_root: &Option, + root_folder: &Path, + workspace_root: &Option, show_progress: bool, build_dev_deps: bool, ) -> Result> { - let map = read_packages(root_folder, workspace_root.to_owned(), show_progress)?; + let map = read_packages(root_folder, workspace_root, show_progress)?; /* Once we have the deduplicated packages, we can add the source files for each - to minimize * the IO */ @@ -661,7 +648,7 @@ pub fn parse_packages(build_state: &mut BuildState) { Some(source_files) => source_files .keys() .map(|key| key.to_owned()) - .collect::>(), + .collect::>(), None => unreachable!(), }; let entry = match &package.namespace { @@ -725,9 +712,8 @@ pub fn parse_packages(build_state: &mut BuildState) { Some(source_files) => source_files.iter().for_each(|(file, metadata)| { let namespace = package.namespace.to_owned(); - let file_buf = PathBuf::from(file); - let extension = file_buf.extension().unwrap().to_str().unwrap(); - let module_name = helpers::file_path_to_module_name(&file.to_owned(), &namespace); + let extension = file.extension().unwrap().to_str().unwrap(); + let module_name = helpers::file_path_to_module_name(&file, &namespace); if helpers::is_implementation_file(extension) { build_state @@ -737,8 +723,11 @@ pub fn parse_packages(build_state: &mut BuildState) { if let SourceType::SourceFile(ref mut source_file) = module.source_type { if &source_file.implementation.path != file { error!("Duplicate files found for module: {}", &module_name); - error!("file 1: {}", &source_file.implementation.path); - error!("file 2: {}", &file); + error!( + "file 1: {}", + source_file.implementation.path.to_string_lossy() + ); + error!("file 2: {}", file.to_string_lossy()); panic!("Unable to continue... See log output above..."); } @@ -769,13 +758,19 @@ pub fn parse_packages(build_state: &mut BuildState) { } else { // remove last character of string: resi -> res, rei -> re, mli -> ml let mut implementation_filename = file.to_owned(); - implementation_filename.pop(); + let extension = implementation_filename.extension().unwrap().to_str().unwrap(); + implementation_filename = match extension { + "resi" => implementation_filename.with_extension("res"), + "rei" => implementation_filename.with_extension("re"), + "mli" => implementation_filename.with_extension("ml"), + _ => implementation_filename, + }; match source_files.get(&implementation_filename) { None => { log::warn!( "{} No implementation file found for interface file (skipping): {}", LINE_CLEAR, - file + file.to_string_lossy() ) } Some(_) => { @@ -800,7 +795,7 @@ pub fn parse_packages(build_state: &mut BuildState) { source_type: SourceType::SourceFile(SourceFile { // this will be overwritten later implementation: Implementation { - path: implementation_filename.to_string(), + path: implementation_filename, parse_state: ParseState::Pending, compile_state: CompileState::Pending, last_modified: metadata.modified, @@ -943,10 +938,10 @@ pub fn validate_packages_dependencies(packages: &AHashMap) -> b #[cfg(test)] mod test { + use super::{Namespace, Package}; use crate::config::Source; use ahash::{AHashMap, AHashSet}; - - use super::{Namespace, Package}; + use std::path::PathBuf; fn create_package( name: String, @@ -982,7 +977,7 @@ mod test { source_files: None, namespace: Namespace::Namespace(String::from("Package1")), modules: None, - path: String::from("./something"), + path: PathBuf::from("./something"), dirs: None, is_pinned_dep: false, is_root: false, diff --git a/rewatch/src/build/parse.rs b/rewatch/src/build/parse.rs index b4fddd72f2..7bc52149c4 100644 --- a/rewatch/src/build/parse.rs +++ b/rewatch/src/build/parse.rs @@ -213,23 +213,23 @@ pub fn generate_asts( .namespace .to_suffix() .expect("namespace should be set for mlmap module"); - let base_build_path = package.get_build_path() + "/" + &suffix; - let base_ocaml_build_path = package.get_ocaml_build_path() + "/" + &suffix; + let base_build_path = package.get_build_path().join(&suffix); + let base_ocaml_build_path = package.get_ocaml_build_path().join(&suffix); let _ = std::fs::copy( - base_build_path.to_string() + ".cmi", - base_ocaml_build_path.to_string() + ".cmi", + base_build_path.with_extension(".cmi"), + base_ocaml_build_path.with_extension(".cmi"), ); let _ = std::fs::copy( - base_build_path.to_string() + ".cmt", - base_ocaml_build_path.to_string() + ".cmt", + base_build_path.with_extension("cmt"), + base_ocaml_build_path.with_extension("cmt"), ); let _ = std::fs::copy( - base_build_path.to_string() + ".cmj", - base_ocaml_build_path.to_string() + ".cmj", + base_build_path.with_extension("cmj"), + base_ocaml_build_path.with_extension("cmj"), ); let _ = std::fs::copy( - base_build_path.to_string() + ".mlmap", - base_ocaml_build_path.to_string() + ".mlmap", + base_build_path.with_extension("mlmap"), + base_ocaml_build_path.with_extension("mlmap"), ); match (mlmap_hash, mlmap_hash_after) { (Some(digest), Some(digest_after)) => !digest.eq(&digest_after), @@ -256,19 +256,19 @@ pub fn generate_asts( pub fn parser_args( config: &config::Config, root_config: &config::Config, - filename: &str, + filename: &Path, version: &str, - workspace_root: &Option, - root_path: &str, + workspace_root: &Option, + root_path: &Path, contents: &str, ) -> (PathBuf, Vec) { - let file = &filename.to_string(); + let file = &filename; let ast_path = helpers::get_ast_path(file); let ppx_flags = config::flatten_ppx_flags( &if let Some(workspace_root) = workspace_root { - format!("{}/node_modules", &workspace_root) + workspace_root.join("node_modules") } else { - format!("{}/node_modules", &root_path) + root_path.join("node_modules") }, &filter_ppx_flags(&config.ppx_flags, contents), &config.name, @@ -279,7 +279,8 @@ pub fn parser_args( let uncurried_args = root_config.get_uncurried_args(version); let bsc_flags = config::flatten_flags(&config.bsc_flags); - let file = "../../".to_string() + file; + let file = PathBuf::from("..").join("..").join(file); + ( ast_path.to_owned(), [ @@ -295,7 +296,7 @@ pub fn parser_args( "-bs-ast".to_string(), "-o".to_string(), ast_path.to_string_lossy().to_string(), - file, + file.to_string_lossy().to_string(), ], ] .concat(), @@ -305,10 +306,10 @@ pub fn parser_args( fn generate_ast( package: packages::Package, root_package: packages::Package, - filename: &str, + filename: &Path, version: &str, - bsc_path: &str, - workspace_root: &Option, + bsc_path: &PathBuf, + workspace_root: &Option, ) -> Result<(PathBuf, Option), String> { let file_path = PathBuf::from(&package.path).join(filename); let contents = helpers::read_file(&file_path).expect("Error reading file"); @@ -325,7 +326,8 @@ fn generate_ast( ); // generate the dir of the ast_path (it mirrors the source file dir) - helpers::create_path(&(package.get_build_path() + "/" + &ast_path.parent().unwrap().to_string_lossy())); + let ast_parent_path = package.get_build_path().join(ast_path.parent().unwrap()); + helpers::create_path(&ast_parent_path); /* Create .ast */ let result = if let Some(res_to_ast) = Some( @@ -346,11 +348,12 @@ fn generate_ast( Ok((ast_path, None)) } } else { - log::info!("Parsing file {}...", filename); + log::info!("Parsing file {}...", filename.display()); Err(format!( "Could not find canonicalize_string_path for file {} in package {}", - filename, package.name + filename.display(), + package.name )) }; if let Ok((ast_path, _)) = &result { diff --git a/rewatch/src/build/read_compile_state.rs b/rewatch/src/build/read_compile_state.rs index 4bfc3e29fc..d9dc1bbddf 100644 --- a/rewatch/src/build/read_compile_state.rs +++ b/rewatch/src/build/read_compile_state.rs @@ -4,11 +4,11 @@ use crate::helpers; use ahash::{AHashMap, AHashSet}; use rayon::prelude::*; use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::time::SystemTime; pub fn read(build_state: &mut BuildState) -> CompileAssetsState { - let mut ast_modules: AHashMap = AHashMap::new(); + let mut ast_modules: AHashMap = AHashMap::new(); let mut cmi_modules: AHashMap = AHashMap::new(); let mut cmt_modules: AHashMap = AHashMap::new(); let mut ast_rescript_file_locations = AHashSet::new(); @@ -20,16 +20,11 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { SourceType::SourceFile(source_file) => { let package = build_state.packages.get(&module.package_name).unwrap(); - Some( - PathBuf::from(&package.path) - .join(&source_file.implementation.path) - .to_string_lossy() - .to_string(), - ) + Some(PathBuf::from(&package.path).join(&source_file.implementation.path)) } _ => None, }) - .collect::>(); + .collect::>(); rescript_file_locations.extend( build_state @@ -37,14 +32,12 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { .values() .filter_map(|module| { let package = build_state.packages.get(&module.package_name).unwrap(); - module.get_interface().as_ref().map(|interface| { - PathBuf::from(&package.path) - .join(&interface.path) - .to_string_lossy() - .to_string() - }) + module + .get_interface() + .as_ref() + .map(|interface| package.path.join(&interface.path)) }) - .collect::>(), + .collect::>(), ); // scan all ast files in all packages @@ -84,36 +77,35 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { |(path, last_modified, extension, package_name, package_namespace, package_is_root)| { match extension.as_str() { "iast" | "ast" => { - let module_name = - helpers::file_path_to_module_name(path.to_str().unwrap(), package_namespace); + let module_name = helpers::file_path_to_module_name(path, package_namespace); - let ast_file_path = path.to_str().unwrap().to_owned(); - let res_file_path = get_res_path_from_ast(&ast_file_path); + let res_file_path = get_res_path_from_ast(&path); let root_package = build_state .packages .get(&build_state.root_config_name) .expect("Could not find root package"); if let Some(res_file_path) = res_file_path { + let res_file_path_buf = PathBuf::from(res_file_path); let _ = ast_modules.insert( - res_file_path.to_owned(), + res_file_path_buf.clone(), AstModule { module_name, package_name: package_name.to_owned(), namespace: package_namespace.to_owned(), last_modified: last_modified.to_owned(), - ast_file_path, + ast_file_path: path.to_path_buf(), is_root: *package_is_root, suffix: root_package .config .get_suffix(root_package.config.get_package_specs().first().unwrap()), }, ); - let _ = ast_rescript_file_locations.insert(res_file_path); + let _ = ast_rescript_file_locations.insert(res_file_path_buf); } } "cmi" => { let module_name = helpers::file_path_to_module_name( - path.to_str().unwrap(), + path, // we don't want to include a namespace here because the CMI file // already includes a namespace &packages::Namespace::NoNamespace, @@ -122,7 +114,7 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { } "cmt" => { let module_name = helpers::file_path_to_module_name( - path.to_str().unwrap(), + path, // we don't want to include a namespace here because the CMI file // already includes a namespace &packages::Namespace::NoNamespace, @@ -145,8 +137,8 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { } } -fn get_res_path_from_ast(ast_file: &str) -> Option { - if let Ok(lines) = helpers::read_lines(ast_file.to_string()) { +fn get_res_path_from_ast(ast_file: &Path) -> Option { + if let Ok(lines) = helpers::read_lines(ast_file) { // we skip the first line with is some null characters // the following lines in the AST are the dependency modules // we stop when we hit a line that starts with a "/", this is the path of the file. diff --git a/rewatch/src/config.rs b/rewatch/src/config.rs index 7bcbda2e51..d9706086ad 100644 --- a/rewatch/src/config.rs +++ b/rewatch/src/config.rs @@ -246,13 +246,13 @@ pub fn flatten_flags(flags: &Option>>) -> Vec { /// Since ppx-flags could be one or more, and could be nested potentiall, this function takes the /// flags and flattens them outright. pub fn flatten_ppx_flags( - node_modules_dir: &String, + node_modules_dir: &Path, flags: &Option>>, package_name: &String, ) -> Vec { match flags { None => vec![], - Some(xs) => xs + Some(flags) => flags .iter() .flat_map(|x| match x { OneOrMore::Single(y) => { @@ -261,18 +261,29 @@ pub fn flatten_ppx_flags( Some('.') => { vec![ "-ppx".to_string(), - node_modules_dir.to_owned() + "/" + package_name + "/" + y, + node_modules_dir + .join(package_name) + .join(y) + .to_string_lossy() + .to_string(), ] } - _ => vec!["-ppx".to_string(), node_modules_dir.to_owned() + "/" + y], + _ => vec![ + "-ppx".to_string(), + node_modules_dir.join(y).to_string_lossy().to_string(), + ], } } OneOrMore::Multiple(ys) if ys.is_empty() => vec![], OneOrMore::Multiple(ys) => { let first_character = ys[0].chars().next(); let ppx = match first_character { - Some('.') => node_modules_dir.to_owned() + "/" + package_name + "/" + &ys[0], - _ => node_modules_dir.to_owned() + "/" + &ys[0], + Some('.') => node_modules_dir + .join(package_name) + .join(&ys[0]) + .to_string_lossy() + .to_string(), + _ => node_modules_dir.join(&ys[0]).to_string_lossy().to_string(), }; vec![ "-ppx".to_string(), @@ -289,8 +300,8 @@ pub fn flatten_ppx_flags( } /// Try to convert a bsconfig from a certain path to a bsconfig struct -pub fn read(path: String) -> Result { - let read = fs::read_to_string(path.clone())?; +pub fn read(path: &Path) -> Result { + let read = fs::read_to_string(path)?; let parse = serde_json::from_str::(&read)?; Ok(parse) diff --git a/rewatch/src/helpers.rs b/rewatch/src/helpers.rs index 58fb734154..53bd3b7881 100644 --- a/rewatch/src/helpers.rs +++ b/rewatch/src/helpers.rs @@ -60,24 +60,20 @@ impl LexicalAbsolute for Path { } } -pub fn package_path(root: &str, package_name: &str) -> String { - format!("{}/node_modules/{}", root, package_name) +pub fn package_path(root: &Path, package_name: &str) -> PathBuf { + root.join("node_modules").join(package_name) } -pub fn get_abs_path(path: &str) -> String { +pub fn get_abs_path(path: &Path) -> PathBuf { let abs_path_buf = PathBuf::from(path); return abs_path_buf .to_lexical_absolute() - .expect("Could not canonicalize") - .to_str() - .expect("Could not canonicalize") - .to_string(); + .expect("Could not canonicalize"); } -pub fn get_basename(path: &str) -> String { - let path_buf = PathBuf::from(path); - return path_buf +pub fn get_basename(path: &Path) -> String { + return path .file_stem() .expect("Could not get basename") .to_str() @@ -85,15 +81,6 @@ pub fn get_basename(path: &str) -> String { .to_string(); } -pub fn change_extension(path: &str, new_extension: &str) -> String { - let path_buf = PathBuf::from(path); - return path_buf - .with_extension(new_extension) - .to_str() - .expect("Could not change extension") - .to_string(); -} - /// Capitalizes the first character in s. fn capitalize(s: &str) -> String { let mut c = s.chars(); @@ -121,12 +108,12 @@ pub fn module_name_with_namespace(module_name: &str, namespace: &packages::Names // this doesn't capitalize the module name! if the rescript name of the file is "foo.res" the // compiler assets are foo-Namespace.cmt and foo-Namespace.cmj, but the module name is Foo -pub fn file_path_to_compiler_asset_basename(path: &str, namespace: &packages::Namespace) -> String { +pub fn file_path_to_compiler_asset_basename(path: &Path, namespace: &packages::Namespace) -> String { let base = get_basename(path); add_suffix(&base, namespace) } -pub fn file_path_to_module_name(path: &str, namespace: &packages::Namespace) -> String { +pub fn file_path_to_module_name(path: &Path, namespace: &packages::Namespace) -> String { capitalize(&file_path_to_compiler_asset_basename(path, namespace)) } @@ -139,18 +126,15 @@ pub fn contains_ascii_characters(str: &str) -> bool { false } -pub fn create_path(path: &str) { - fs::DirBuilder::new() - .recursive(true) - .create(PathBuf::from(path.to_string())) - .unwrap(); +pub fn create_path(path: &Path) { + fs::DirBuilder::new().recursive(true).create(path).unwrap(); } pub fn create_path_for_path(path: &Path) { fs::DirBuilder::new().recursive(true).create(path).unwrap(); } -pub fn get_bsc(root_path: &str, workspace_root: Option) -> String { +pub fn get_bsc(root_path: &Path, workspace_root: &Option) -> PathBuf { let subfolder = match (std::env::consts::OS, std::env::consts::ARCH) { ("macos", "aarch64") => "darwin-arm64", ("macos", _) => "darwin-x64", @@ -162,25 +146,27 @@ pub fn get_bsc(root_path: &str, workspace_root: Option) -> String { }; match ( - PathBuf::from(format!( - "{}/node_modules/@rescript/{}/bin/bsc.exe", - root_path, subfolder - )) - .canonicalize(), - workspace_root.map(|workspace_root| { - PathBuf::from(format!( - "{}/node_modules/rescript/{}/bsc.exe", - workspace_root, subfolder - )) - .canonicalize() + root_path + .join("node_modules") + .join("@rescript") + .join(subfolder) + .join("bin") + .join("bsc.exe") + .canonicalize(), + workspace_root.as_ref().map(|workspace_root| { + workspace_root + .join("node_modules") + .join("@rescript") + .join(subfolder) + .join("bin") + .join("bsc.exe") + .canonicalize() }), ) { (Ok(path), _) => path, (_, Some(Ok(path))) => path, _ => panic!("Could not find bsc.exe"), } - .to_string_lossy() - .to_string() } pub fn string_ends_with_any(s: &Path, suffixes: &[&str]) -> bool { @@ -198,8 +184,8 @@ fn path_to_ast_extension(path: &Path) -> &str { } } -pub fn get_ast_path(source_file: &str) -> PathBuf { - let source_path = Path::new(source_file); +pub fn get_ast_path(source_file: &Path) -> PathBuf { + let source_path = source_file; source_path.parent().unwrap().join( file_path_to_compiler_asset_basename(source_file, &packages::Namespace::NoNamespace) @@ -210,18 +196,16 @@ pub fn get_ast_path(source_file: &str) -> PathBuf { pub fn get_compiler_asset( package: &packages::Package, namespace: &packages::Namespace, - source_file: &str, + source_file: &Path, extension: &str, -) -> String { +) -> PathBuf { let namespace = match extension { "ast" | "iast" => &packages::Namespace::NoNamespace, _ => namespace, }; - package.get_ocaml_build_path() - + "/" - + &file_path_to_compiler_asset_basename(source_file, namespace) - + "." - + extension + package + .get_ocaml_build_path() + .join(file_path_to_compiler_asset_basename(source_file, namespace) + "." + extension) } pub fn canonicalize_string_path(path: &str) -> Option { @@ -231,7 +215,7 @@ pub fn canonicalize_string_path(path: &str) -> Option { pub fn get_bs_compiler_asset( package: &packages::Package, namespace: &packages::Namespace, - source_file: &str, + source_file: &Path, extension: &str, ) -> String { let namespace = match extension { @@ -255,11 +239,11 @@ pub fn get_namespace_from_module_name(module_name: &str) -> Option { split.next().map(|s| s.to_string()) } -pub fn is_interface_ast_file(file: &str) -> bool { +pub fn is_interface_ast_file(file: &Path) -> bool { file.ends_with(".iast") } -pub fn read_lines(filename: String) -> io::Result>> { +pub fn read_lines(filename: &Path) -> io::Result>> { let file = fs::File::open(filename)?; Ok(io::BufReader::new(file).lines()) } @@ -290,7 +274,7 @@ pub fn is_non_exotic_module_name(module_name: &str) -> bool { false } -pub fn get_extension(path: &str) -> String { +pub fn get_extension(path: &Path) -> String { let path_buf = PathBuf::from(path); return path_buf .extension() @@ -324,18 +308,18 @@ fn has_rescript_config(path: &Path) -> bool { path.join("bsconfig.json").exists() || path.join("rescript.json").exists() } -pub fn get_workspace_root(package_root: &str) -> Option { +pub fn get_workspace_root(package_root: &Path) -> Option { std::path::PathBuf::from(&package_root) .parent() .and_then(get_nearest_config) } // traverse up the directory tree until we find a config.json, if not return None -pub fn get_nearest_config(path_buf: &Path) -> Option { +pub fn get_nearest_config(path_buf: &Path) -> Option { let mut current_dir = path_buf.to_owned(); loop { if has_rescript_config(¤t_dir) { - return Some(current_dir.to_string_lossy().to_string()); + return Some(current_dir); } match current_dir.parent() { None => return None, @@ -344,7 +328,7 @@ pub fn get_nearest_config(path_buf: &Path) -> Option { } } -pub fn get_rescript_version(bsc_path: &str) -> String { +pub fn get_rescript_version(bsc_path: &Path) -> String { let version_cmd = Command::new(bsc_path) .args(["-v"]) .output() diff --git a/rewatch/src/main.rs b/rewatch/src/main.rs index 3ff476875e..15b0f5880d 100644 --- a/rewatch/src/main.rs +++ b/rewatch/src/main.rs @@ -4,6 +4,7 @@ use clap_verbosity_flag::InfoLevel; use log::LevelFilter; use regex::Regex; use std::io::Write; +use std::path::{Path, PathBuf}; use rewatch::{build, cmd, lock, watcher}; @@ -102,7 +103,12 @@ fn main() -> Result<()> { Some(path) => { println!( "{}", - build::get_compiler_args(&path, args.rescript_version, args.bsc_path, args.dev)? + build::get_compiler_args( + Path::new(&path), + args.rescript_version, + &args.bsc_path.map(PathBuf::from), + args.dev + )? ); std::process::exit(0); } @@ -118,15 +124,20 @@ fn main() -> Result<()> { std::process::exit(1) } lock::Lock::Aquired(_) => match command { - Command::Clean => build::clean::clean(&folder, show_progress, args.bsc_path, args.dev), + Command::Clean => build::clean::clean( + Path::new(&folder), + show_progress, + &args.bsc_path.map(PathBuf::from), + args.dev, + ), Command::Build => { match build::build( &filter, - &folder, + Path::new(&folder), show_progress, args.no_timing, args.create_sourcedirs, - args.bsc_path, + &args.bsc_path.map(PathBuf::from), args.dev, ) { Err(e) => { diff --git a/rewatch/src/sourcedirs.rs b/rewatch/src/sourcedirs.rs index ed704aa7e9..46325b3842 100644 --- a/rewatch/src/sourcedirs.rs +++ b/rewatch/src/sourcedirs.rs @@ -6,11 +6,11 @@ use serde::Serialize; use serde_json::json; use std::fs::File; use std::io::prelude::*; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; -type Dir = String; +type Dir = PathBuf; type PackageName = String; -type AbsolutePath = String; +type AbsolutePath = PathBuf; type Pkg = (PackageName, AbsolutePath); #[derive(Serialize, Debug, Clone, PartialEq, Hash)] @@ -20,20 +20,16 @@ pub struct SourceDirs<'a> { pub generated: &'a Vec, } -fn package_to_dirs(package: &Package, root_package_path: &String) -> AHashSet { - let relative_path = PathBuf::from(&package.path) - .strip_prefix(PathBuf::from(&root_package_path)) - .unwrap() - .to_string_lossy() - .to_string(); +fn package_to_dirs(package: &Package, root_package_path: &Path) -> AHashSet { + let relative_path = package.path.strip_prefix(&root_package_path).unwrap(); package .dirs .as_ref() .unwrap_or(&AHashSet::new()) .iter() - .filter_map(|path| path.to_str().map(|path| format!("{relative_path}/{path}"))) - .collect::>() + .map(|path| relative_path.join(path)) + .collect::>() } fn deps_to_pkgs<'a>( @@ -52,8 +48,8 @@ fn deps_to_pkgs<'a>( .collect::>() } -fn write_sourcedirs_files(path: String, source_dirs: &SourceDirs) -> Result { - let mut source_dirs_json = File::create(path + "/.sourcedirs.json")?; +fn write_sourcedirs_files(path: &Path, source_dirs: &SourceDirs) -> Result { + let mut source_dirs_json = File::create(path.join(".sourcedirs.json"))?; source_dirs_json.write(json!(source_dirs).to_string().as_bytes()) } @@ -85,7 +81,7 @@ pub fn print(buildstate: &BuildState) { // Write sourcedirs.json write_sourcedirs_files( - package.get_build_path(), + &package.get_build_path(), &SourceDirs { dirs: &dirs.clone().into_iter().collect::>(), pkgs: &pkgs.clone().flatten().collect::>(), @@ -109,7 +105,7 @@ pub fn print(buildstate: &BuildState) { // Write sourcedirs.json write_sourcedirs_files( - root_package.get_build_path(), + &root_package.get_build_path(), &SourceDirs { dirs: &merged_dirs.into_iter().collect::>(), pkgs: &merged_pkgs.into_iter().collect::>(), diff --git a/rewatch/src/watcher.rs b/rewatch/src/watcher.rs index 6b99db75bc..d55339ea79 100644 --- a/rewatch/src/watcher.rs +++ b/rewatch/src/watcher.rs @@ -9,7 +9,7 @@ use crate::queue::*; use futures_timer::Delay; use notify::event::ModifyKind; use notify::{Config, Error, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; use std::sync::Mutex; use std::time::{Duration, Instant}; @@ -48,23 +48,17 @@ fn matches_filter(path_buf: &Path, filter: &Option) -> bool { async fn async_watch( q: Arc>>, - path: &str, + path: &Path, show_progress: bool, filter: &Option, after_build: Option, create_sourcedirs: bool, build_dev_deps: bool, - bsc_path: Option, + bsc_path: Option, ) -> notify::Result<()> { - let mut build_state = build::initialize_build( - None, - filter, - show_progress, - path, - bsc_path.clone(), - build_dev_deps, - ) - .expect("Can't initialize build"); + let mut build_state = + build::initialize_build(None, filter, show_progress, path, &bsc_path, build_dev_deps) + .expect("Can't initialize build"); let mut needs_compile_type = CompileType::Incremental; // create a mutex to capture if ctrl-c was pressed let ctrlc_pressed = Arc::new(Mutex::new(false)); @@ -153,8 +147,7 @@ async fn async_watch( .get(&module.package_name) .expect("Package not found"); let canonicalized_implementation_file = - std::path::PathBuf::from(package.path.to_string()) - .join(&source_file.implementation.path); + package.path.join(&source_file.implementation.path); if canonicalized_path_buf == canonicalized_implementation_file { if let Ok(modified) = canonicalized_path_buf.metadata().and_then(|x| x.modified()) @@ -168,8 +161,7 @@ async fn async_watch( // mark the interface file dirty if let Some(ref mut interface) = source_file.interface { let canonicalized_interface_file = - std::path::PathBuf::from(package.path.to_string()) - .join(&interface.path); + package.path.join(&interface.path); if canonicalized_path_buf == canonicalized_interface_file { if let Ok(modified) = canonicalized_path_buf .metadata() @@ -236,15 +228,9 @@ async fn async_watch( } CompileType::Full => { let timing_total = Instant::now(); - build_state = build::initialize_build( - None, - filter, - show_progress, - path, - bsc_path.clone(), - build_dev_deps, - ) - .expect("Can't initialize build"); + build_state = + build::initialize_build(None, filter, show_progress, path, &bsc_path, build_dev_deps) + .expect("Can't initialize build"); let _ = build::incremental_build( &mut build_state, None, @@ -301,15 +287,18 @@ pub fn start( .watch(folder.as_ref(), RecursiveMode::Recursive) .expect("Could not start watcher"); + let path = Path::new(folder); + let bsc_path_buf = bsc_path.map(PathBuf::from); + if let Err(e) = async_watch( consumer, - folder, + path, show_progress, filter, after_build, create_sourcedirs, build_dev_deps, - bsc_path, + bsc_path_buf, ) .await { From 44b6605bec215478401bbd8bd93ab44a93c15e78 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 26 May 2025 09:14:48 +0200 Subject: [PATCH 03/39] log error --- rewatch/tests/compile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index dd39bf5b96..33c2024475 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -13,7 +13,7 @@ else exit 1 fi -if rewatch &> /dev/null; +if rewatch ; then success "Repo Built" else From 1f957a196c0812e15bbee0947c43b9f898e34c53 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 26 May 2025 10:46:29 +0200 Subject: [PATCH 04/39] fix bug --- rewatch/src/build/parse.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rewatch/src/build/parse.rs b/rewatch/src/build/parse.rs index 7bc52149c4..ca92fd5a5f 100644 --- a/rewatch/src/build/parse.rs +++ b/rewatch/src/build/parse.rs @@ -216,8 +216,8 @@ pub fn generate_asts( let base_build_path = package.get_build_path().join(&suffix); let base_ocaml_build_path = package.get_ocaml_build_path().join(&suffix); let _ = std::fs::copy( - base_build_path.with_extension(".cmi"), - base_ocaml_build_path.with_extension(".cmi"), + base_build_path.with_extension("cmi"), + base_ocaml_build_path.with_extension("cmi"), ); let _ = std::fs::copy( base_build_path.with_extension("cmt"), From 36aae3daa7d75a55d574b7d5c834c27587993835 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 26 May 2025 15:53:14 +0200 Subject: [PATCH 05/39] fix bug --- rewatch/src/build/clean.rs | 12 ++++-------- rewatch/src/helpers.rs | 7 ++++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/rewatch/src/build/clean.rs b/rewatch/src/build/clean.rs index d0ec07d142..e04745e644 100644 --- a/rewatch/src/build/clean.rs +++ b/rewatch/src/build/clean.rs @@ -170,18 +170,14 @@ pub fn cleanup_previous_build( .get_mut(module_name) .expect("Could not find module for ast file"); - let compile_dirty = compile_assets_state.cmt_modules.get(module_name); + let cmt_last_modified = compile_assets_state.cmt_modules.get(module_name); // if there is a new AST but it has not been compiled yet, we mark the module as compile dirty // we do this by checking if the cmt file is newer than the AST file. We always compile the // interface AND implementation. For some reason the CMI file is not always rewritten if it // doesn't have any changes, that's why we just look at the CMT file. - if let Some(compile_dirty) = compile_dirty { - let last_modified = Some(ast_last_modified); - - if let Some(last_modified) = last_modified { - if compile_dirty > last_modified && !deleted_interfaces.contains(module_name) { - module.compile_dirty = false; - } + if let Some(cmt_last_modified) = cmt_last_modified { + if cmt_last_modified > ast_last_modified && !deleted_interfaces.contains(module_name) { + module.compile_dirty = false; } } diff --git a/rewatch/src/helpers.rs b/rewatch/src/helpers.rs index 53bd3b7881..10397d6fad 100644 --- a/rewatch/src/helpers.rs +++ b/rewatch/src/helpers.rs @@ -240,7 +240,9 @@ pub fn get_namespace_from_module_name(module_name: &str) -> Option { } pub fn is_interface_ast_file(file: &Path) -> bool { - file.ends_with(".iast") + file.extension() + .map(|extension| extension.eq_ignore_ascii_case("iast")) + .unwrap_or(false) } pub fn read_lines(filename: &Path) -> io::Result>> { @@ -275,8 +277,7 @@ pub fn is_non_exotic_module_name(module_name: &str) -> bool { } pub fn get_extension(path: &Path) -> String { - let path_buf = PathBuf::from(path); - return path_buf + return path .extension() .expect("Could not get extension") .to_str() From d7b23111c631cc5096906213ba381828cf3bd707 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Fri, 16 May 2025 23:20:49 +0200 Subject: [PATCH 06/39] paths wip - windows support fix merge issue From 959caa4d6c02ff53c4253d4a00aa695fcbdfb735 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Fri, 23 May 2025 21:07:32 +0200 Subject: [PATCH 07/39] wip --- rewatch/src/build.rs | 3 +- rewatch/src/build/compile.rs | 68 ++++++++++++++----------- rewatch/src/build/namespaces.rs | 2 +- rewatch/src/build/packages.rs | 22 ++++---- rewatch/src/build/parse.rs | 12 ++--- rewatch/src/build/read_compile_state.rs | 2 +- rewatch/src/helpers.rs | 21 +++++--- rewatch/src/lock.rs | 17 ++++--- 8 files changed, 78 insertions(+), 69 deletions(-) diff --git a/rewatch/src/build.rs b/rewatch/src/build.rs index 03dbaff9d9..4e178f6450 100644 --- a/rewatch/src/build.rs +++ b/rewatch/src/build.rs @@ -440,8 +440,7 @@ pub fn incremental_build( pub fn write_build_ninja(build_state: &BuildState) { for package in build_state.packages.values() { // write empty file: - let mut f = File::create(std::path::Path::new(&package.get_build_path()).join("build.ninja")) - .expect("Unable to write file"); + let mut f = File::create(package.get_build_path().join("build.ninja")).expect("Unable to write file"); f.write_all(b"").expect("unable to write to ninja file"); } } diff --git a/rewatch/src/build/compile.rs b/rewatch/src/build/compile.rs index 6b8b8922c4..4aa880e094 100644 --- a/rewatch/src/build/compile.rs +++ b/rewatch/src/build/compile.rs @@ -455,15 +455,14 @@ pub fn compiler_args( .unwrap() .to_string() } else { - format!( - "lib/{}", - Path::join( + Path::new("lib") + .join(Path::join( Path::new(&spec.get_out_of_source_dir()), - Path::new(file_path).parent().unwrap() - ) + Path::new(file_path).parent().unwrap(), + )) .to_str() .unwrap() - ) + .to_string() }, root_config.get_suffix(spec), ), @@ -645,41 +644,46 @@ fn compile_file( // perhaps we can do this copying somewhere else if !is_interface { let _ = std::fs::copy( - std::path::Path::new(&package.get_build_path()) + package + .get_build_path() .join(dir) // because editor tooling doesn't support namespace entries yet // we just remove the @ for now. This makes sure the editor support // doesn't break - .join(module_name.to_string() + ".cmi"), - ocaml_build_path_abs.join(module_name.to_string() + ".cmi"), + .join(format!("{}.cmi", module_name)), + ocaml_build_path_abs.join(format!("{}.cmi", module_name)), ); let _ = std::fs::copy( - std::path::Path::new(&package.get_build_path()) + package + .get_build_path() .join(dir) - .join(module_name.to_string() + ".cmj"), - ocaml_build_path_abs.join(module_name.to_string() + ".cmj"), + .join(format!("{}.cmj", module_name)), + ocaml_build_path_abs.join(format!("{}.cmj", module_name)), ); let _ = std::fs::copy( - std::path::Path::new(&package.get_build_path()) + package + .get_build_path() .join(dir) // because editor tooling doesn't support namespace entries yet // we just remove the @ for now. This makes sure the editor support // doesn't break - .join(module_name.to_string() + ".cmt"), - ocaml_build_path_abs.join(module_name.to_string() + ".cmt"), + .join(format!("{}.cmt", module_name)), + ocaml_build_path_abs.join(format!("{}.cmt", module_name)), ); } else { let _ = std::fs::copy( - std::path::Path::new(&package.get_build_path()) + package + .get_build_path() .join(dir) - .join(module_name.to_string() + ".cmti"), - ocaml_build_path_abs.join(module_name.to_string() + ".cmti"), + .join(format!("{}.cmti", module_name)), + ocaml_build_path_abs.join(format!("{}.cmti", module_name)), ); let _ = std::fs::copy( - std::path::Path::new(&package.get_build_path()) + package + .get_build_path() .join(dir) - .join(module_name.to_string() + ".cmi"), - ocaml_build_path_abs.join(module_name.to_string() + ".cmi"), + .join(format!("{}.cmi", module_name)), + ocaml_build_path_abs.join(format!("{}.cmi", module_name)), ); } @@ -692,14 +696,15 @@ fn compile_file( // editor tools expects the source file in lib/bs for finding the current package // and in lib/ocaml when referencing modules in other packages let _ = std::fs::copy( - std::path::Path::new(&package.path).join(path), - std::path::Path::new(&package.get_build_path()).join(path), + Path::new(&package.path).join(path), + package.get_build_path().join(path), ) .expect("copying source file failed"); let _ = std::fs::copy( - std::path::Path::new(&package.path).join(path), - std::path::Path::new(&package.get_ocaml_build_path()) + Path::new(&package.path).join(path), + package + .get_ocaml_build_path() .join(std::path::Path::new(path).file_name().unwrap()), ) .expect("copying source file failed"); @@ -715,14 +720,15 @@ fn compile_file( // editor tools expects the source file in lib/bs for finding the current package // and in lib/ocaml when referencing modules in other packages let _ = std::fs::copy( - std::path::Path::new(&package.path).join(path), - std::path::Path::new(&package.get_build_path()).join(path), + Path::new(&package.path).join(path), + package.get_build_path().join(path), ) .expect("copying source file failed"); let _ = std::fs::copy( - std::path::Path::new(&package.path).join(path), - std::path::Path::new(&package.get_ocaml_build_path()) + Path::new(&package.path).join(path), + package + .get_ocaml_build_path() .join(std::path::Path::new(path).file_name().unwrap()), ) .expect("copying source file failed"); @@ -739,11 +745,11 @@ fn compile_file( .. }) => { let source = helpers::get_source_file_from_rescript_file( - &std::path::Path::new(&package.path).join(path), + &Path::new(&package.path).join(path), &root_package.config.get_suffix(spec), ); let destination = helpers::get_source_file_from_rescript_file( - &std::path::Path::new(&package.get_build_path()).join(path), + &package.get_build_path().join(path), &root_package.config.get_suffix(spec), ); diff --git a/rewatch/src/build/namespaces.rs b/rewatch/src/build/namespaces.rs index 88e1ffd51d..9ecd5377fd 100644 --- a/rewatch/src/build/namespaces.rs +++ b/rewatch/src/build/namespaces.rs @@ -30,7 +30,7 @@ pub fn gen_mlmap( // recompile in a different way but we need to put it in the file for it to // be readable. - let path = build_path_abs.join(namespace.to_string() + ".mlmap"); + let path = build_path_abs.join(format!("{}.mlmap", namespace)); let mut file = File::create(&path).expect("Unable to create mlmap"); file.write_all(b"randjbuildsystem\n") diff --git a/rewatch/src/build/packages.rs b/rewatch/src/build/packages.rs index 553d9e8774..ee901ffc91 100644 --- a/rewatch/src/build/packages.rs +++ b/rewatch/src/build/packages.rs @@ -97,21 +97,19 @@ impl Package { } pub fn get_mlmap_path(&self) -> PathBuf { - self.get_build_path().join( - self.namespace - .to_suffix() - .expect("namespace should be set for mlmap module") - + ".mlmap", - ) + let suffix = self + .namespace + .to_suffix() + .expect("namespace should be set for mlmap module"); + self.get_build_path().join(format!("{}.mlmap", suffix)) } pub fn get_mlmap_compile_path(&self) -> PathBuf { - self.get_build_path().join( - self.namespace - .to_suffix() - .expect("namespace should be set for mlmap module") - + ".cmi", - ) + let suffix = self + .namespace + .to_suffix() + .expect("namespace should be set for mlmap module"); + self.get_build_path().join(format!("{}.cmi", suffix)) } } diff --git a/rewatch/src/build/parse.rs b/rewatch/src/build/parse.rs index ca92fd5a5f..f4f49a28c3 100644 --- a/rewatch/src/build/parse.rs +++ b/rewatch/src/build/parse.rs @@ -74,17 +74,13 @@ pub fn generate_asts( } else { ( Ok(( - Path::new( - &(helpers::get_basename(&source_file.implementation.path).to_string() - + ".ast"), - ) - .to_path_buf(), + PathBuf::from(helpers::get_basename(&source_file.implementation.path)) + .with_extension("ast"), None, )), Ok(source_file.interface.as_ref().map(|i| { ( - Path::new(&(helpers::get_basename(&i.path).to_string() + ".iast")) - .to_path_buf(), + PathBuf::from(helpers::get_basename(&i.path)).with_extension("iast"), None, ) })), @@ -359,7 +355,7 @@ fn generate_ast( if let Ok((ast_path, _)) = &result { let _ = std::fs::copy( Path::new(&build_path_abs).join(&ast_path), - std::path::Path::new(&package.get_ocaml_build_path()).join(ast_path.file_name().unwrap()), + package.get_ocaml_build_path().join(ast_path.file_name().unwrap()), ); } result diff --git a/rewatch/src/build/read_compile_state.rs b/rewatch/src/build/read_compile_state.rs index d9dc1bbddf..dffdd9a4c9 100644 --- a/rewatch/src/build/read_compile_state.rs +++ b/rewatch/src/build/read_compile_state.rs @@ -45,7 +45,7 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { .packages .par_iter() .map(|(_, package)| { - let read_dir = fs::read_dir(std::path::Path::new(&package.get_ocaml_build_path())).unwrap(); + let read_dir = fs::read_dir(&package.get_ocaml_build_path()).unwrap(); read_dir .filter_map(|entry| match entry { Ok(entry) => { diff --git a/rewatch/src/helpers.rs b/rewatch/src/helpers.rs index 10397d6fad..de99ca7449 100644 --- a/rewatch/src/helpers.rs +++ b/rewatch/src/helpers.rs @@ -186,11 +186,13 @@ fn path_to_ast_extension(path: &Path) -> &str { pub fn get_ast_path(source_file: &Path) -> PathBuf { let source_path = source_file; + let basename = file_path_to_compiler_asset_basename(source_file, &packages::Namespace::NoNamespace); + let extension = path_to_ast_extension(source_path); - source_path.parent().unwrap().join( - file_path_to_compiler_asset_basename(source_file, &packages::Namespace::NoNamespace) - + path_to_ast_extension(source_path), - ) + source_path + .parent() + .unwrap() + .join(format!("{}{}", basename, extension)) } pub fn get_compiler_asset( @@ -203,9 +205,10 @@ pub fn get_compiler_asset( "ast" | "iast" => &packages::Namespace::NoNamespace, _ => namespace, }; + let basename = file_path_to_compiler_asset_basename(source_file, namespace); package .get_ocaml_build_path() - .join(file_path_to_compiler_asset_basename(source_file, namespace) + "." + extension) + .join(format!("{}.{}", basename, extension)) } pub fn canonicalize_string_path(path: &str) -> Option { @@ -223,11 +226,13 @@ pub fn get_bs_compiler_asset( _ => namespace, }; - let dir = std::path::Path::new(&source_file).parent().unwrap(); + let dir = source_file.parent().unwrap(); + let basename = file_path_to_compiler_asset_basename(source_file, namespace); - std::path::Path::new(&package.get_build_path()) + package + .get_build_path() .join(dir) - .join(file_path_to_compiler_asset_basename(source_file, namespace) + extension) + .join(format!("{}{}", basename, extension)) .to_str() .unwrap() .to_owned() diff --git a/rewatch/src/lock.rs b/rewatch/src/lock.rs index dfadcfbb4e..9eca7ed604 100644 --- a/rewatch/src/lock.rs +++ b/rewatch/src/lock.rs @@ -22,8 +22,14 @@ impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let msg = match self { Error::Locked(pid) => format!("Rewatch is already running. The process ID (PID) is {}", pid), - Error::ParsingLockfile(e) => format!("Could not parse lockfile: \n {} \n (try removing it and running the command again)", e), - Error::ReadingLockfile(e) => format!("Could not read lockfile: \n {} \n (try removing it and running the command again)", e), + Error::ParsingLockfile(e) => format!( + "Could not parse lockfile: \n {} \n (try removing it and running the command again)", + e + ), + Error::ReadingLockfile(e) => format!( + "Could not read lockfile: \n {} \n (try removing it and running the command again)", + e + ), Error::WritingLockfile(e) => format!("Could not write lockfile: \n {}", e), }; write!(f, "{}", msg) @@ -54,15 +60,14 @@ fn create(lockfile_location: &Path, pid: u32) -> Lock { } pub fn get(folder: &str) -> Lock { - let location = format!("{}/lib/{}", folder, LOCKFILE); - let path = Path::new(&location); + let location = Path::new(folder).join("lib").join(LOCKFILE); let pid = process::id(); match fs::read_to_string(&location) { - Err(e) if (e.kind() == std::io::ErrorKind::NotFound) => create(path, pid), + Err(e) if (e.kind() == std::io::ErrorKind::NotFound) => create(&location, pid), Err(e) => Lock::Error(Error::ReadingLockfile(e)), Ok(s) => match s.parse::() { - Ok(parsed_pid) if !exists(parsed_pid) => create(path, pid), + Ok(parsed_pid) if !exists(parsed_pid) => create(&location, pid), Ok(parsed_pid) => Lock::Error(Error::Locked(parsed_pid)), Err(e) => Lock::Error(Error::ParsingLockfile(e)), }, From 0094a311664c09e33f896cd0e7b9efb1511b8cf6 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Fri, 23 May 2025 21:26:51 +0200 Subject: [PATCH 08/39] fix another path issue --- rewatch/src/watcher.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/rewatch/src/watcher.rs b/rewatch/src/watcher.rs index d55339ea79..f67883fbd7 100644 --- a/rewatch/src/watcher.rs +++ b/rewatch/src/watcher.rs @@ -32,10 +32,17 @@ fn is_rescript_file(path_buf: &Path) -> bool { } fn is_in_build_path(path_buf: &Path) -> bool { - path_buf - .to_str() - .map(|x| x.contains("/lib/bs/") || x.contains("/lib/ocaml/")) - .unwrap_or(false) + let mut prev_component: Option<&std::ffi::OsStr> = None; + for component in path_buf.components() { + let comp_os = component.as_os_str(); + if let Some(prev) = prev_component { + if prev == "lib" && (comp_os == "bs" || comp_os == "ocaml") { + return true; + } + } + prev_component = Some(comp_os); + } + false } fn matches_filter(path_buf: &Path, filter: &Option) -> bool { From 69580cc9b0db0649e24ddd448c3acad1d8412806 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 26 May 2025 17:07:58 +0200 Subject: [PATCH 09/39] remove logging --- rewatch/tests/compile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index 33c2024475..dd39bf5b96 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -13,7 +13,7 @@ else exit 1 fi -if rewatch ; +if rewatch &> /dev/null; then success "Repo Built" else From 0526247b85ce1126494c137aef591a9258006d17 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 26 May 2025 17:18:30 +0200 Subject: [PATCH 10/39] remove dep on rescript core for v12 --- rewatch/testrepo/packages/with-dev-deps/package.json | 5 +---- rewatch/testrepo/packages/with-dev-deps/rescript.json | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/rewatch/testrepo/packages/with-dev-deps/package.json b/rewatch/testrepo/packages/with-dev-deps/package.json index 68aad6fe20..007ab59b9a 100644 --- a/rewatch/testrepo/packages/with-dev-deps/package.json +++ b/rewatch/testrepo/packages/with-dev-deps/package.json @@ -5,8 +5,5 @@ "rescript" ], "author": "", - "license": "MIT", - "dependencies": { - "@rescript/core": "*" - } + "license": "MIT" } diff --git a/rewatch/testrepo/packages/with-dev-deps/rescript.json b/rewatch/testrepo/packages/with-dev-deps/rescript.json index 6d67d606cc..8cae5b6dcc 100644 --- a/rewatch/testrepo/packages/with-dev-deps/rescript.json +++ b/rewatch/testrepo/packages/with-dev-deps/rescript.json @@ -13,6 +13,5 @@ "module": "es6", "in-source": true }, - "bs-dependencies": ["@rescript/core"], "suffix": ".res.js" } From a819a6259611a657b5b3d7eea8c7989ae09c083d Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 26 May 2025 22:33:23 +0200 Subject: [PATCH 11/39] remove core - snapshots --- rewatch/tests/snapshots/dependency-cycle.txt | 2 +- rewatch/tests/snapshots/remove-file.txt | 2 +- rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt | 2 +- rewatch/tests/snapshots/rename-file-internal-dep.txt | 2 +- rewatch/tests/snapshots/rename-file-with-interface.txt | 2 +- rewatch/tests/snapshots/rename-file.txt | 2 +- rewatch/tests/snapshots/rename-interface-file.txt | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rewatch/tests/snapshots/dependency-cycle.txt b/rewatch/tests/snapshots/dependency-cycle.txt index 6c5236a57d..e8b6db1b43 100644 --- a/rewatch/tests/snapshots/dependency-cycle.txt +++ b/rewatch/tests/snapshots/dependency-cycle.txt @@ -1,7 +1,7 @@ [1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s [2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s [3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 0/94 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 0/14 0.00s  [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s  [6/7] ๐ŸŒด Collected deps in 0.00s  [7/7] โŒ Compiled 0 modules in 0.00s diff --git a/rewatch/tests/snapshots/remove-file.txt b/rewatch/tests/snapshots/remove-file.txt index 7fdacf29a3..98c0a992ab 100644 --- a/rewatch/tests/snapshots/remove-file.txt +++ b/rewatch/tests/snapshots/remove-file.txt @@ -1,7 +1,7 @@ [1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s [2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s [3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/94 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/14 0.00s  [5/7] ๐Ÿงฑ Parsed 0 source files in 0.00s  [6/7] ๐ŸŒด Collected deps in 0.00s  [7/7] โŒ Compiled 1 modules in 0.00s diff --git a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt index a5836f99fa..0b3b2dbc51 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt @@ -1,7 +1,7 @@ [1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s [2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s [3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/94 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/14 0.00s  [5/7] ๐Ÿงฑ Parsed 2 source files in 0.00s  [6/7] ๐ŸŒด Collected deps in 0.00s  [7/7] โŒ Compiled 3 modules in 0.00s diff --git a/rewatch/tests/snapshots/rename-file-internal-dep.txt b/rewatch/tests/snapshots/rename-file-internal-dep.txt index 9dc7b4a390..986c4d7cf7 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep.txt @@ -1,7 +1,7 @@ [1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s [2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s [3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/94 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/14 0.00s  [5/7] ๐Ÿงฑ Parsed 2 source files in 0.00s  [6/7] ๐ŸŒด Collected deps in 0.00s  [7/7] โŒ Compiled 2 modules in 0.00s diff --git a/rewatch/tests/snapshots/rename-file-with-interface.txt b/rewatch/tests/snapshots/rename-file-with-interface.txt index 45d05ea95f..7f25c66484 100644 --- a/rewatch/tests/snapshots/rename-file-with-interface.txt +++ b/rewatch/tests/snapshots/rename-file-with-interface.txt @@ -3,7 +3,7 @@  No implementation file found for interface file (skipping): src/ModuleWithInterface.resi  [2/7] ๐Ÿ‘€ Found source files in 0.00s [3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/94 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/14 0.00s  [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s  [6/7] ๐ŸŒด Collected deps in 0.00s  [7/7] ๐Ÿคบ Compiled 2 modules in 0.00s diff --git a/rewatch/tests/snapshots/rename-file.txt b/rewatch/tests/snapshots/rename-file.txt index 7965bd423b..cf5109cfdb 100644 --- a/rewatch/tests/snapshots/rename-file.txt +++ b/rewatch/tests/snapshots/rename-file.txt @@ -1,7 +1,7 @@ [1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s [2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s [3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/94 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/14 0.00s  [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s  [6/7] ๐ŸŒด Collected deps in 0.00s  [7/7] ๐Ÿคบ Compiled 1 modules in 0.00s diff --git a/rewatch/tests/snapshots/rename-interface-file.txt b/rewatch/tests/snapshots/rename-interface-file.txt index be2cd61a21..67475cbde4 100644 --- a/rewatch/tests/snapshots/rename-interface-file.txt +++ b/rewatch/tests/snapshots/rename-interface-file.txt @@ -3,7 +3,7 @@  No implementation file found for interface file (skipping): src/ModuleWithInterface2.resi  [2/7] ๐Ÿ‘€ Found source files in 0.00s [3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/94 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/14 0.00s  [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s  [6/7] ๐ŸŒด Collected deps in 0.00s  [7/7] ๐Ÿคบ Compiled 2 modules in 0.00s From 04b6714a5512f896863a6a375ff247f48b801441 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 26 May 2025 22:35:09 +0200 Subject: [PATCH 12/39] See if it works on CI --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5deaeef1c0..41fa0da9d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -516,7 +516,6 @@ jobs: - name: Run rewatch integration tests # Currently failing on Windows and intermittently on macOS - if: runner.os == 'Linux' run: make test-rewatch-ci publish: From 2f6528495967136c5df48c4c9dee60cdfbc9f2b7 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 08:06:20 +0200 Subject: [PATCH 13/39] don't skip install --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41fa0da9d5..405f7b0e90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -507,7 +507,6 @@ jobs: working-directory: ${{ steps.tmp-dir.outputs.path }} - name: Install ReScript package in rewatch/testrepo - if: runner.os == 'Linux' run: | COMMIT_SHA="${{ github.event.pull_request.head.sha || github.sha }}" yarn add "rescript@https://pkg.pr.new/rescript-lang/rescript@${COMMIT_SHA::7}" From ec5de6f1c22a57deb54ce0f3d2461115c6e0a67b Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 15:18:06 +0200 Subject: [PATCH 14/39] default the bsc path to the one in the repo --- rewatch/tests/suite-ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewatch/tests/suite-ci.sh b/rewatch/tests/suite-ci.sh index 60970745e1..87fd645cb5 100755 --- a/rewatch/tests/suite-ci.sh +++ b/rewatch/tests/suite-ci.sh @@ -6,7 +6,7 @@ cd $(dirname $0) if [ -n "$1" ]; then REWATCH_EXECUTABLE="$1" else - REWATCH_EXECUTABLE="../target/release/rewatch" + REWATCH_EXECUTABLE="../target/release/rewatch --bsc-path ../../_build/install/default/bin/bsc" fi export REWATCH_EXECUTABLE From 90aeb9c671f1a1ebb5f5ecc87d0a0dac5946dd4f Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 15:18:26 +0200 Subject: [PATCH 15/39] copy stdlib build artifacts to the test repo after building the runtime --- scripts/buildRuntimeRewatch.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/buildRuntimeRewatch.sh b/scripts/buildRuntimeRewatch.sh index bb8d97fc56..b74825c7f9 100755 --- a/scripts/buildRuntimeRewatch.sh +++ b/scripts/buildRuntimeRewatch.sh @@ -11,3 +11,5 @@ cp runtime/lib/es6/*.js lib/es6 cp runtime/lib/js/*.js lib/js cp runtime/lib/bs/*.@(cmi|cmj|cmt|cmti) lib/ocaml/ cp runtime/*.@(res|resi) lib/ocaml/ +# copy the stdlib build artifacts to the testrepo +cp -rf lib/ocaml rewatch/testrepo/node_modules/rescript/lib/ocaml \ No newline at end of file From 43a627547c7a865c004c59bc1b1edec6c5f19f56 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 15:24:10 +0200 Subject: [PATCH 16/39] also run non-integration tests --- .github/workflows/ci.yml | 5 ++++- Makefile | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 405f7b0e90..0589bfbb10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -354,6 +354,9 @@ jobs: if: runner.os != 'Windows' run: make -C tests/gentype_tests/typescript-react-example clean test + - name: Run rewatch tests + run: make test-rewatch + - name: Run syntax benchmarks if: matrix.benchmarks run: ./_build/install/default/bin/syntax_benchmarks | tee tests/benchmark-output.json @@ -515,7 +518,7 @@ jobs: - name: Run rewatch integration tests # Currently failing on Windows and intermittently on macOS - run: make test-rewatch-ci + run: make test-rewatch-integration publish: needs: diff --git a/Makefile b/Makefile index 96a166ce9e..dcc4fc7550 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ test-gentype: test-rewatch: bash ./rewatch/tests/suite-ci.sh -test-rewatch-ci: +test-rewatch-integration: bash ./rewatch/tests/suite-ci.sh node_modules/.bin/rewatch test-all: test test-gentype test-analysis test-tools test-rewatch From f33e1d5d8cef5df4356b3f0bb8f0b7e95fe958f8 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 15:26:40 +0200 Subject: [PATCH 17/39] make it work when no node-modules are installed --- scripts/buildRuntimeRewatch.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/buildRuntimeRewatch.sh b/scripts/buildRuntimeRewatch.sh index b74825c7f9..bfd89a1bc3 100755 --- a/scripts/buildRuntimeRewatch.sh +++ b/scripts/buildRuntimeRewatch.sh @@ -12,4 +12,5 @@ cp runtime/lib/js/*.js lib/js cp runtime/lib/bs/*.@(cmi|cmj|cmt|cmti) lib/ocaml/ cp runtime/*.@(res|resi) lib/ocaml/ # copy the stdlib build artifacts to the testrepo +mkdir -p rewatch/testrepo/node_modules/rescript/lib/ocaml cp -rf lib/ocaml rewatch/testrepo/node_modules/rescript/lib/ocaml \ No newline at end of file From b249165c24d01495424ce7266a78c55decbf0932 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 15:34:50 +0200 Subject: [PATCH 18/39] fix? --- .github/workflows/ci.yml | 3 +++ scripts/buildRuntimeRewatch.sh | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0589bfbb10..dfe39f3fc3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,6 +98,9 @@ jobs: - name: Install npm packages run: yarn install + - name: Install testrepo deps + run: cd rewatch/testrepo && yarn install + - name: Install dependencies (Linux) if: runner.os == 'Linux' uses: awalsh128/cache-apt-pkgs-action@v1.4.3 diff --git a/scripts/buildRuntimeRewatch.sh b/scripts/buildRuntimeRewatch.sh index bfd89a1bc3..2d2bd014af 100755 --- a/scripts/buildRuntimeRewatch.sh +++ b/scripts/buildRuntimeRewatch.sh @@ -11,6 +11,6 @@ cp runtime/lib/es6/*.js lib/es6 cp runtime/lib/js/*.js lib/js cp runtime/lib/bs/*.@(cmi|cmj|cmt|cmti) lib/ocaml/ cp runtime/*.@(res|resi) lib/ocaml/ -# copy the stdlib build artifacts to the testrepo +# overwrite the stdlib build artifacts to the testrepo mkdir -p rewatch/testrepo/node_modules/rescript/lib/ocaml cp -rf lib/ocaml rewatch/testrepo/node_modules/rescript/lib/ocaml \ No newline at end of file From aaf1719bc74bf5b490fc03dc1b78c9bbf9cac947 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 15:38:11 +0200 Subject: [PATCH 19/39] fix lockfile --- .../packages/namespace-casing/package.json | 5 +--- rewatch/testrepo/yarn.lock | 24 ------------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/rewatch/testrepo/packages/namespace-casing/package.json b/rewatch/testrepo/packages/namespace-casing/package.json index 65b2411476..a666649db8 100644 --- a/rewatch/testrepo/packages/namespace-casing/package.json +++ b/rewatch/testrepo/packages/namespace-casing/package.json @@ -5,8 +5,5 @@ "rescript" ], "author": "", - "license": "MIT", - "dependencies": { - "rescript": "*" - } + "license": "MIT" } diff --git a/rewatch/testrepo/yarn.lock b/rewatch/testrepo/yarn.lock index 051f89cf65..ac41b3d2c1 100644 --- a/rewatch/testrepo/yarn.lock +++ b/rewatch/testrepo/yarn.lock @@ -5,15 +5,6 @@ __metadata: version: 8 cacheKey: 10c0 -"@rescript/core@npm:*": - version: 1.6.1 - resolution: "@rescript/core@npm:1.6.1" - peerDependencies: - rescript: ">=11.1.0" - checksum: 10c0/04e7fc14dc050de0a9da8eb0642fb0800bc80c8978ef79aada1823bc2080b47a4d40c1168c63b53642009935342a4feb833fc190a71aa45e83af5d896269b95d - languageName: node - linkType: hard - "@rescript/darwin-arm64@npm:12.0.0-alpha.13": version: 12.0.0-alpha.13 resolution: "@rescript/darwin-arm64@npm:12.0.0-alpha.13" @@ -74,8 +65,6 @@ __metadata: "@testrepo/namespace-casing@workspace:packages/namespace-casing": version: 0.0.0-use.local resolution: "@testrepo/namespace-casing@workspace:packages/namespace-casing" - dependencies: - rescript: "npm:*" languageName: unknown linkType: soft @@ -88,22 +77,9 @@ __metadata: "@testrepo/with-dev-deps@workspace:packages/with-dev-deps": version: 0.0.0-use.local resolution: "@testrepo/with-dev-deps@workspace:packages/with-dev-deps" - dependencies: - "@rescript/core": "npm:*" languageName: unknown linkType: soft -"rescript@npm:*": - version: 11.1.4 - resolution: "rescript@npm:11.1.4" - bin: - bsc: bsc - bstracing: lib/bstracing - rescript: rescript - checksum: 10c0/7f12186a84209f586457a60e65755fcdfbcbb503ac805c60ab5132ce4c927bc264c3b851419ed5498ba7dc4066723377bb7453f893f482a0ccd424986d02beba - languageName: node - linkType: hard - "rescript@npm:12.0.0-alpha.13": version: 12.0.0-alpha.13 resolution: "rescript@npm:12.0.0-alpha.13" From 2c23b7652ef05f0c3d3f1d528d6c919b1388e0fa Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 15:40:55 +0200 Subject: [PATCH 20/39] see error --- rewatch/tests/compile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index dd39bf5b96..1dcb6f61b4 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -5,7 +5,7 @@ cd ../testrepo bold "Test: It should compile" -if rewatch clean &> /dev/null; +if rewatch clean ; then success "Repo Cleaned" else From ccc7b535d74ce06f99385170bf1752a630871ab5 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 15:47:14 +0200 Subject: [PATCH 21/39] fix? --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dfe39f3fc3..f164054571 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,6 +126,8 @@ jobs: - name: Build rewatch if: steps.rewatch-build-cache.outputs.cache-hit != 'true' run: | + cargo build --manifest-path rewatch/Cargo.toml --release + # build specific target cargo build --manifest-path rewatch/Cargo.toml --target ${{ matrix.rust-target }} --release - name: Run rewatch unit tests From 1b83ac31ac7c03e980463c716e46f9c6393448d3 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 16:36:06 +0200 Subject: [PATCH 22/39] fix? --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f164054571..611ad0e66f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,8 +126,6 @@ jobs: - name: Build rewatch if: steps.rewatch-build-cache.outputs.cache-hit != 'true' run: | - cargo build --manifest-path rewatch/Cargo.toml --release - # build specific target cargo build --manifest-path rewatch/Cargo.toml --target ${{ matrix.rust-target }} --release - name: Run rewatch unit tests @@ -138,6 +136,8 @@ jobs: - name: Copy rewatch binary run: | cp rewatch/target/${{ matrix.rust-target }}/release/rewatch${{ runner.os == 'Windows' && '.exe' || '' }} rewatch + mkdir -p rewatch/target/release + cp rewatch/target/${{ matrix.rust-target }}/release/rewatch${{ runner.os == 'Windows' && '.exe' || '' }} rewatch/target/release ./scripts/copyExes.js --rewatch shell: bash From 03448b435349f61e76871b95d99805b54b350bc1 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 16:41:23 +0200 Subject: [PATCH 23/39] Revert "see error" This reverts commit 2c23b7652ef05f0c3d3f1d528d6c919b1388e0fa. --- rewatch/tests/compile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index 1dcb6f61b4..dd39bf5b96 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -5,7 +5,7 @@ cd ../testrepo bold "Test: It should compile" -if rewatch clean ; +if rewatch clean &> /dev/null; then success "Repo Cleaned" else From 45d6c512f21940e31a848b8d4c2bac7e95efc4d3 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 27 May 2025 18:08:46 +0200 Subject: [PATCH 24/39] fix path --- rewatch/src/build/compile.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rewatch/src/build/compile.rs b/rewatch/src/build/compile.rs index 4aa880e094..0c446bf483 100644 --- a/rewatch/src/build/compile.rs +++ b/rewatch/src/build/compile.rs @@ -475,7 +475,10 @@ pub fn compiler_args( vec![ namespace_args, read_cmi_args, - vec!["-I".to_string(), "../ocaml".to_string()], + vec![ + "-I".to_string(), + Path::new("..").join("ocaml").to_string_lossy().to_string(), + ], dependency_paths.concat(), uncurried_args, bsc_flags.to_owned(), From 40f0387dd269e9c88f254a36c0655cf99955a3d2 Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Tue, 27 May 2025 22:03:52 +0200 Subject: [PATCH 25/39] fix: verbatim windows paths --- rewatch/src/build/compile.rs | 18 ++++++----- rewatch/src/build/namespaces.rs | 9 +++++- rewatch/src/build/packages.rs | 8 +++-- rewatch/src/helpers.rs | 56 +++++++++++++++++++++++++++++++-- rewatch/src/watcher.rs | 6 +++- 5 files changed, 83 insertions(+), 14 deletions(-) diff --git a/rewatch/src/build/compile.rs b/rewatch/src/build/compile.rs index 0c446bf483..dac7cac8a8 100644 --- a/rewatch/src/build/compile.rs +++ b/rewatch/src/build/compile.rs @@ -7,6 +7,7 @@ use super::logs; use super::packages; use crate::config; use crate::helpers; +use crate::helpers::StrippedVerbatimPath; use ahash::{AHashMap, AHashSet}; use anyhow::anyhow; use console::style; @@ -448,17 +449,12 @@ pub fn compiler_args( "{}:{}:{}", spec.module, if spec.in_source { - Path::new(file_path) - .parent() - .unwrap() - .to_str() - .unwrap() - .to_string() + file_path.parent().unwrap().to_str().unwrap().to_string() } else { Path::new("lib") .join(Path::join( Path::new(&spec.get_out_of_source_dir()), - Path::new(file_path).parent().unwrap(), + file_path.parent().unwrap(), )) .to_str() .unwrap() @@ -623,7 +619,13 @@ fn compile_file( ); let to_mjs = Command::new(bsc_path) - .current_dir(build_path_abs.canonicalize().ok().unwrap()) + .current_dir( + build_path_abs + .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path) + .ok() + .unwrap(), + ) .args(to_mjs_args) .output(); diff --git a/rewatch/src/build/namespaces.rs b/rewatch/src/build/namespaces.rs index 9ecd5377fd..c5d8355e28 100644 --- a/rewatch/src/build/namespaces.rs +++ b/rewatch/src/build/namespaces.rs @@ -1,4 +1,5 @@ use crate::build::packages; +use crate::helpers::StrippedVerbatimPath; use ahash::AHashSet; use std::fs::File; use std::io::Write; @@ -56,7 +57,13 @@ pub fn compile_mlmap(package: &packages::Package, namespace: &str, bsc_path: &Pa let args = vec!["-w", "-49", "-color", "always", "-no-alias-deps", &mlmap_name]; let _ = Command::new(bsc_path) - .current_dir(build_path_abs.canonicalize().ok().unwrap()) + .current_dir( + build_path_abs + .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path) + .ok() + .unwrap(), + ) .args(args) .output() .expect("err"); diff --git a/rewatch/src/build/packages.rs b/rewatch/src/build/packages.rs index ee901ffc91..b6c9ab168c 100644 --- a/rewatch/src/build/packages.rs +++ b/rewatch/src/build/packages.rs @@ -4,6 +4,7 @@ use super::packages; use crate::config; use crate::helpers; use crate::helpers::emojis::*; +use crate::helpers::StrippedVerbatimPath; use ahash::{AHashMap, AHashSet}; use anyhow::{anyhow, Result}; use console::style; @@ -265,7 +266,7 @@ pub fn read_dependency( )), }?; - let canonical_path = match path.canonicalize() { + let canonical_path = match path.canonicalize().map(StrippedVerbatimPath::to_stripped_verbatim_path) { Ok(canonical_path) => Ok(canonical_path), Err(e) => { Err(format!( @@ -429,7 +430,10 @@ fn make_package(config: config::Config, package_path: &Path, is_pinned_dep: bool namespace: config.get_namespace(), modules: None, // we canonicalize the path name so it's always the same - path: package_path.canonicalize().expect("Could not canonicalize"), + path: package_path + .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path) + .expect("Could not canonicalize"), dirs: None, is_pinned_dep, is_local_dep: !package_path.components().any(|c| c.as_os_str() == "node_modules"), diff --git a/rewatch/src/helpers.rs b/rewatch/src/helpers.rs index de99ca7449..c8b56a72c8 100644 --- a/rewatch/src/helpers.rs +++ b/rewatch/src/helpers.rs @@ -36,6 +36,53 @@ pub mod emojis { pub static LINE_CLEAR: &str = "\x1b[2K\r"; } +/// This trait is used to strip the verbatim prefix from a Windows path. +/// On non-Windows systems, it simply returns the original path. +/// This is needed until the rescript compiler can handle such paths. +pub trait StrippedVerbatimPath { + fn to_stripped_verbatim_path(self) -> PathBuf; +} + +impl StrippedVerbatimPath for PathBuf { + fn to_stripped_verbatim_path(self) -> PathBuf { + if cfg!(not(target_os = "windows")) { + return self; + } + + let mut stripped = PathBuf::new(); + for component in self.components() { + match component { + Component::Prefix(prefix_component) => { + if prefix_component.kind().is_verbatim() { + stripped.push( + prefix_component + .as_os_str() + .to_string_lossy() + .strip_prefix("\\\\?\\") + .unwrap(), + ); + } else { + stripped.push(prefix_component.as_os_str()); + } + } + Component::RootDir => { + stripped.push(Component::RootDir); + } + Component::CurDir => { + stripped.push(Component::CurDir); + } + Component::ParentDir => { + stripped.push(Component::ParentDir); + } + Component::Normal(os_str) => { + stripped.push(os_str); + } + } + } + stripped + } +} + pub trait LexicalAbsolute { fn to_lexical_absolute(&self) -> std::io::Result; } @@ -152,7 +199,8 @@ pub fn get_bsc(root_path: &Path, workspace_root: &Option) -> PathBuf { .join(subfolder) .join("bin") .join("bsc.exe") - .canonicalize(), + .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path), workspace_root.as_ref().map(|workspace_root| { workspace_root .join("node_modules") @@ -161,6 +209,7 @@ pub fn get_bsc(root_path: &Path, workspace_root: &Option) -> PathBuf { .join("bin") .join("bsc.exe") .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path) }), ) { (Ok(path), _) => path, @@ -212,7 +261,10 @@ pub fn get_compiler_asset( } pub fn canonicalize_string_path(path: &str) -> Option { - return Path::new(path).canonicalize().ok(); + return Path::new(path) + .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path) + .ok(); } pub fn get_bs_compiler_asset( diff --git a/rewatch/src/watcher.rs b/rewatch/src/watcher.rs index f67883fbd7..52bc915090 100644 --- a/rewatch/src/watcher.rs +++ b/rewatch/src/watcher.rs @@ -4,6 +4,7 @@ use crate::build::clean; use crate::cmd; use crate::helpers; use crate::helpers::emojis::*; +use crate::helpers::StrippedVerbatimPath; use crate::queue::FifoQueue; use crate::queue::*; use futures_timer::Delay; @@ -144,7 +145,10 @@ async fn async_watch( ) => { // if we are going to compile incrementally, we need to mark the exact files // dirty - if let Ok(canonicalized_path_buf) = path_buf.canonicalize() { + if let Ok(canonicalized_path_buf) = path_buf + .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path) + { for module in build_state.modules.values_mut() { match module.source_type { SourceType::SourceFile(ref mut source_file) => { From 44696a56503c11b03115c14a6913b0305411f763 Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Wed, 28 May 2025 12:11:14 +0200 Subject: [PATCH 26/39] fix: incremental build on windows `get_res_path_from_ast` --- rewatch/src/build/build_types.rs | 2 ++ rewatch/src/build/read_compile_state.rs | 10 ++++------ rewatch/src/helpers.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rewatch/src/build/build_types.rs b/rewatch/src/build/build_types.rs index 15bf3eb712..956cc5e159 100644 --- a/rewatch/src/build/build_types.rs +++ b/rewatch/src/build/build_types.rs @@ -136,6 +136,7 @@ impl BuildState { } } +#[derive(Debug)] pub struct AstModule { pub module_name: String, pub package_name: String, @@ -146,6 +147,7 @@ pub struct AstModule { pub suffix: String, } +#[derive(Debug)] pub struct CompileAssetsState { pub ast_modules: AHashMap, pub cmi_modules: AHashMap, diff --git a/rewatch/src/build/read_compile_state.rs b/rewatch/src/build/read_compile_state.rs index dffdd9a4c9..c6a05e445d 100644 --- a/rewatch/src/build/read_compile_state.rs +++ b/rewatch/src/build/read_compile_state.rs @@ -79,13 +79,11 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { "iast" | "ast" => { let module_name = helpers::file_path_to_module_name(path, package_namespace); - let res_file_path = get_res_path_from_ast(&path); let root_package = build_state .packages .get(&build_state.root_config_name) .expect("Could not find root package"); - if let Some(res_file_path) = res_file_path { - let res_file_path_buf = PathBuf::from(res_file_path); + if let Some(res_file_path_buf) = get_res_path_from_ast(&path) { let _ = ast_modules.insert( res_file_path_buf.clone(), AstModule { @@ -137,15 +135,15 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { } } -fn get_res_path_from_ast(ast_file: &Path) -> Option { +fn get_res_path_from_ast(ast_file: &Path) -> Option { if let Ok(lines) = helpers::read_lines(ast_file) { // we skip the first line with is some null characters // the following lines in the AST are the dependency modules - // we stop when we hit a line that starts with a "/", this is the path of the file. + // we stop when we hit a line that is an absolute path, this is the path of the file. // this is the point where the dependencies end and the actual AST starts for line in lines.skip(1) { match line { - Ok(line) if line.trim_start().starts_with('/') => return Some(line), + Ok(line) if Path::new(&line).is_absolute() => return Some(PathBuf::from(line)), _ => (), } } diff --git a/rewatch/src/helpers.rs b/rewatch/src/helpers.rs index c8b56a72c8..a91dee77f5 100644 --- a/rewatch/src/helpers.rs +++ b/rewatch/src/helpers.rs @@ -75,7 +75,7 @@ impl StrippedVerbatimPath for PathBuf { stripped.push(Component::ParentDir); } Component::Normal(os_str) => { - stripped.push(os_str); + stripped.push(Component::Normal(os_str)); } } } From ae18ec02a052095b149c263ce06cf59d2d013830 Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Thu, 29 May 2025 23:07:37 +0200 Subject: [PATCH 27/39] fix: file paths in snapshots by normalizing on windows --- rewatch/tests/compile.sh | 16 ++++++++++------ rewatch/tests/utils.sh | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index dd39bf5b96..fd035bf902 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -39,32 +39,36 @@ mv ./packages/main/src/Main2.res ./packages/main/src/Main.res # Rename a file with a dependent - this should trigger an error mv ./packages/main/src/InternalDep.res ./packages/main/src/InternalDep2.res rewatch build &> ../tests/snapshots/rename-file-internal-dep.txt -# replace the absolute path so the snapshot is the same on all machines -replace "s/$(pwd | sed "s/\//\\\\\//g")//g" ../tests/snapshots/rename-file-internal-dep.txt +# normalize paths so the snapshot is the same on all machines +normalize_paths ../tests/snapshots/rename-file-internal-dep.txt mv ./packages/main/src/InternalDep2.res ./packages/main/src/InternalDep.res # Rename a file with a dependent in a namespaced package - this should trigger an error (regression) mv ./packages/new-namespace/src/Other_module.res ./packages/new-namespace/src/Other_module2.res rewatch build &> ../tests/snapshots/rename-file-internal-dep-namespace.txt -# replace the absolute path so the snapshot is the same on all machines -replace "s/$(pwd | sed "s/\//\\\\\//g")//g" ../tests/snapshots/rename-file-internal-dep-namespace.txt +# normalize paths so the snapshot is the same on all machines +normalize_paths ../tests/snapshots/rename-file-internal-dep-namespace.txt mv ./packages/new-namespace/src/Other_module2.res ./packages/new-namespace/src/Other_module.res rewatch build &> /dev/null mv ./packages/main/src/ModuleWithInterface.resi ./packages/main/src/ModuleWithInterface2.resi rewatch build &> ../tests/snapshots/rename-interface-file.txt +# normalize paths so the snapshot is the same on all machines +normalize_paths ../tests/snapshots/rename-interface-file.txt mv ./packages/main/src/ModuleWithInterface2.resi ./packages/main/src/ModuleWithInterface.resi rewatch build &> /dev/null mv ./packages/main/src/ModuleWithInterface.res ./packages/main/src/ModuleWithInterface2.res rewatch build &> ../tests/snapshots/rename-file-with-interface.txt +# normalize paths so the snapshot is the same on all machines +normalize_paths ../tests/snapshots/rename-file-with-interface.txt mv ./packages/main/src/ModuleWithInterface2.res ./packages/main/src/ModuleWithInterface.res rewatch build &> /dev/null # when deleting a file that other files depend on, the compile should fail rm packages/dep02/src/Dep02.res rewatch build &> ../tests/snapshots/remove-file.txt -# replace the absolute path so the snapshot is the same on all machines -replace "s/$(pwd | sed "s/\//\\\\\//g")//g" ../tests/snapshots/remove-file.txt +# normalize paths so the snapshot is the same on all machines +normalize_paths ../tests/snapshots/remove-file.txt git checkout -- packages/dep02/src/Dep02.res rewatch build &> /dev/null diff --git a/rewatch/tests/utils.sh b/rewatch/tests/utils.sh index f2ee211ddd..471732c886 100644 --- a/rewatch/tests/utils.sh +++ b/rewatch/tests/utils.sh @@ -6,6 +6,42 @@ bold() { echo -e "\033[1m$1\033[0m"; } rewatch() { RUST_BACKTRACE=1 $REWATCH_EXECUTABLE --no-timing=true $@; } rewatch_bg() { RUST_BACKTRACE=1 nohup $REWATCH_EXECUTABLE --no-timing=true $@; } +# Detect if running on Windows +is_windows() { + [[ $OSTYPE == 'msys'* || $OSTYPE == 'cygwin'* || $OSTYPE == 'win'* ]]; +} + +# get pwd with forward slashes +pwd_prefix() { + if is_windows; then + # On Windows, escape backslashes for sed and convert to forward slashes for consistent snapshots + # This ensures paths like C:\a\b are replaced correctly + # First get the Windows-style path with backslashes + local win_path=$(pwd -W | sed "s#/#\\\\#g") + # Then escape the backslashes for sed replacement + echo $win_path | sed 's#\\#\\\\#g' + else + # On Unix-like systems, escape forward slashes for sed + echo $(pwd | sed "s#/#\\/#g") + fi +} + +# replace the absolute path so the snapshot is the same on all machines +# then normalize the path separators +normalize_paths() { + if [[ $OSTYPE == 'darwin'* ]]; + then + sed -i '' "s#$(pwd_prefix)##g" $1; + else + if is_windows; then + sed -i "s#$(pwd_prefix)##g" $1 + sed -i "s#\\\\#/#g" $1 + else + sed -i "s#$(pwd_prefix)##g" $1; + fi + fi +} + replace() { if [[ $OSTYPE == 'darwin'* ]]; then From 5d935a93a1f1d5274ff28d82ca4e1a677a254a25 Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Fri, 30 May 2025 10:57:00 +0200 Subject: [PATCH 28/39] debug: print bash version --- rewatch/tests/compile.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index fd035bf902..b85f170ebf 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -3,6 +3,8 @@ cd $(dirname $0) source "./utils.sh" cd ../testrepo +bash --version + bold "Test: It should compile" if rewatch clean &> /dev/null; From 2ac6f3a5bac1b59cde8fc406be5103bbf5b5fc56 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Thu, 29 May 2025 14:19:21 +0200 Subject: [PATCH 29/39] fix CI output --- rewatch/src/build.rs | 112 ++++++++++++++++++++-------------- rewatch/src/build/clean.rs | 29 +++++---- rewatch/src/build/packages.rs | 2 +- rewatch/src/main.rs | 7 +++ rewatch/src/watcher.rs | 52 +++++++++++----- rewatch/tests/utils.sh | 4 +- 6 files changed, 132 insertions(+), 74 deletions(-) diff --git a/rewatch/src/build.rs b/rewatch/src/build.rs index 4e178f6450..18fd5425e6 100644 --- a/rewatch/src/build.rs +++ b/rewatch/src/build.rs @@ -129,6 +129,7 @@ pub fn initialize_build( path: &Path, bsc_path: &Option, build_dev_deps: bool, + snapshot_output: bool, ) -> Result { let project_root = helpers::get_abs_path(path); let workspace_root = helpers::get_workspace_root(&project_root); @@ -139,7 +140,7 @@ pub fn initialize_build( let root_config_name = packages::read_package_name(&project_root)?; let rescript_version = helpers::get_rescript_version(&bsc_path); - if show_progress { + if !snapshot_output && show_progress { print!("{} {}Building package tree...", style("[1/7]").bold().dim(), TREE); let _ = stdout().flush(); } @@ -154,7 +155,7 @@ pub fn initialize_build( )?; let timing_package_tree_elapsed = timing_package_tree.elapsed(); - if show_progress { + if !snapshot_output && show_progress { println!( "{}{} {}Built package tree in {:.2}s", LINE_CLEAR, @@ -172,7 +173,7 @@ pub fn initialize_build( let timing_source_files = Instant::now(); - if show_progress { + if !snapshot_output && show_progress { print!( "{} {}Finding source files...", style("[2/7]").bold().dim(), @@ -192,7 +193,7 @@ pub fn initialize_build( packages::parse_packages(&mut build_state); let timing_source_files_elapsed = timing_source_files.elapsed(); - if show_progress { + if !snapshot_output && show_progress { println!( "{}{} {}Found source files in {:.2}s", LINE_CLEAR, @@ -214,7 +215,7 @@ pub fn initialize_build( let compile_assets_state = read_compile_state::read(&mut build_state); let timing_compile_state_elapsed = timing_compile_state.elapsed(); - if show_progress { + if !snapshot_output && show_progress { println!( "{}{} {}Read compile state {:.2}s", LINE_CLEAR, @@ -236,15 +237,19 @@ pub fn initialize_build( let timing_cleanup_elapsed = timing_cleanup.elapsed(); if show_progress { - println!( - "{}{} {}Cleaned {}/{} {:.2}s", - LINE_CLEAR, - style("[4/7]").bold().dim(), - SWEEP, - diff_cleanup, - total_cleanup, - default_timing.unwrap_or(timing_cleanup_elapsed).as_secs_f64() - ); + if snapshot_output { + println!("Cleant {}/{}", diff_cleanup, total_cleanup) + } else { + println!( + "{}{} {}Cleant {}/{} {:.2}s", + LINE_CLEAR, + style("[4/7]").bold().dim(), + SWEEP, + diff_cleanup, + total_cleanup, + default_timing.unwrap_or(timing_cleanup_elapsed).as_secs_f64() + ); + } } Ok(build_state) @@ -282,10 +287,11 @@ pub fn incremental_build( only_incremental: bool, create_sourcedirs: bool, build_dev_deps: bool, + snapshot_output: bool, ) -> Result<(), IncrementalBuildError> { logs::initialize(&build_state.packages); let num_dirty_modules = build_state.modules.values().filter(|m| is_dirty(m)).count() as u64; - let pb = if show_progress { + let pb = if !snapshot_output && show_progress { ProgressBar::new(num_dirty_modules) } else { ProgressBar::hidden() @@ -308,20 +314,25 @@ pub fn incremental_build( match result_asts { Ok(_ast) => { if show_progress { - println!( - "{}{} {}Parsed {} source files in {:.2}s", - LINE_CLEAR, - format_step(current_step, total_steps), - CODE, - num_dirty_modules, - default_timing.unwrap_or(timing_ast_elapsed).as_secs_f64() - ); - pb.finish(); + if snapshot_output { + println!("Parsed {} source files", num_dirty_modules) + } else { + println!( + "{}{} {}Parsed {} source files in {:.2}s", + LINE_CLEAR, + format_step(current_step, total_steps), + CODE, + num_dirty_modules, + default_timing.unwrap_or(timing_ast_elapsed).as_secs_f64() + ); + pb.finish(); + } } } Err(err) => { logs::finalize(&build_state.packages); - if show_progress { + + if !snapshot_output && show_progress { println!( "{}{} {}Error parsing source files in {:.2}s", LINE_CLEAR, @@ -332,7 +343,7 @@ pub fn incremental_build( pb.finish(); } - println!("Could not parse source files: {}", &err); + println!("{}", &err); return Err(IncrementalBuildError::SourceFileParseError); } } @@ -341,7 +352,7 @@ pub fn incremental_build( let timing_deps_elapsed = timing_deps.elapsed(); current_step += 1; - if show_progress { + if !snapshot_output && show_progress { println!( "{}{} {}Collected deps in {:.2}s", LINE_CLEAR, @@ -365,7 +376,7 @@ pub fn incremental_build( }; let start_compiling = Instant::now(); - let pb = if show_progress { + let pb = if !snapshot_output && show_progress { ProgressBar::new(build_state.modules.len().try_into().unwrap()) } else { ProgressBar::hidden() @@ -397,14 +408,18 @@ pub fn incremental_build( pb.finish(); if !compile_errors.is_empty() { if show_progress { - println!( - "{}{} {}Compiled {} modules in {:.2}s", - LINE_CLEAR, - format_step(current_step, total_steps), - CROSS, - num_compiled_modules, - default_timing.unwrap_or(compile_duration).as_secs_f64() - ); + if snapshot_output { + println!("Compiled {} modules", num_compiled_modules) + } else { + println!( + "{}{} {}Compiled {} modules in {:.2}s", + LINE_CLEAR, + format_step(current_step, total_steps), + CROSS, + num_compiled_modules, + default_timing.unwrap_or(compile_duration).as_secs_f64() + ); + } } if helpers::contains_ascii_characters(&compile_warnings) { println!("{}", &compile_warnings); @@ -415,14 +430,18 @@ pub fn incremental_build( Err(IncrementalBuildError::CompileError(None)) } else { if show_progress { - println!( - "{}{} {}Compiled {} modules in {:.2}s", - LINE_CLEAR, - format_step(current_step, total_steps), - SWORDS, - num_compiled_modules, - default_timing.unwrap_or(compile_duration).as_secs_f64() - ); + if snapshot_output { + println!("Compiled {} modules", num_compiled_modules) + } else { + println!( + "{}{} {}Compiled {} modules in {:.2}s", + LINE_CLEAR, + format_step(current_step, total_steps), + SWORDS, + num_compiled_modules, + default_timing.unwrap_or(compile_duration).as_secs_f64() + ); + } } if helpers::contains_ascii_characters(&compile_warnings) { @@ -453,6 +472,7 @@ pub fn build( create_sourcedirs: bool, bsc_path: &Option, build_dev_deps: bool, + snapshot_output: bool, ) -> Result { let default_timing: Option = if no_timing { Some(std::time::Duration::new(0.0 as u64, 0.0 as u32)) @@ -467,6 +487,7 @@ pub fn build( path, bsc_path, build_dev_deps, + snapshot_output, ) .map_err(|e| anyhow!("Could not initialize build. Error: {e}"))?; @@ -478,9 +499,10 @@ pub fn build( false, create_sourcedirs, build_dev_deps, + snapshot_output, ) { Ok(_) => { - if show_progress { + if !snapshot_output && show_progress { let timing_total_elapsed = timing_total.elapsed(); println!( "\n{}{}Finished Compilation in {:.2}s", diff --git a/rewatch/src/build/clean.rs b/rewatch/src/build/clean.rs index e04745e644..9b9d09553a 100644 --- a/rewatch/src/build/clean.rs +++ b/rewatch/src/build/clean.rs @@ -336,6 +336,7 @@ pub fn clean( show_progress: bool, bsc_path: &Option, build_dev_deps: bool, + snapshot_output: bool, ) -> Result<()> { let project_root = helpers::get_abs_path(path); let workspace_root = helpers::get_workspace_root(&project_root); @@ -356,7 +357,7 @@ pub fn clean( let rescript_version = helpers::get_rescript_version(&bsc_path); let timing_clean_compiler_assets = Instant::now(); - if show_progress { + if !snapshot_output && show_progress { print!( "{} {}Cleaning compiler assets...", style("[1/2]").bold().dim(), @@ -366,13 +367,17 @@ pub fn clean( }; packages.iter().for_each(|(_, package)| { if show_progress { - print!( - "{}{} {}Cleaning {}...", - LINE_CLEAR, - style("[1/2]").bold().dim(), - SWEEP, - package.name - ); + if snapshot_output { + println!("Cleaning {}", package.name) + } else { + print!( + "{}{} {}Cleaning {}...", + LINE_CLEAR, + style("[1/2]").bold().dim(), + SWEEP, + package.name + ); + } let _ = std::io::stdout().flush(); } @@ -386,9 +391,9 @@ pub fn clean( }); let timing_clean_compiler_assets_elapsed = timing_clean_compiler_assets.elapsed(); - if show_progress { + if !snapshot_output && show_progress { println!( - "{}{} {}Cleaned compiler assets in {:.2}s", + "{}{} {}Cleant compiler assets in {:.2}s", LINE_CLEAR, style("[1/2]").bold().dim(), SWEEP, @@ -398,7 +403,7 @@ pub fn clean( } let timing_clean_mjs = Instant::now(); - if show_progress { + if !snapshot_output && show_progress { println!("{} {}Cleaning mjs files...", style("[2/2]").bold().dim(), SWEEP); let _ = std::io::stdout().flush(); } @@ -414,7 +419,7 @@ pub fn clean( clean_mjs_files(&build_state); let timing_clean_mjs_elapsed = timing_clean_mjs.elapsed(); - if show_progress { + if !snapshot_output && show_progress { println!( "{}{} {}Cleaned mjs files in {:.2}s", LINE_CLEAR, diff --git a/rewatch/src/build/packages.rs b/rewatch/src/build/packages.rs index b6c9ab168c..f3a5871b1f 100644 --- a/rewatch/src/build/packages.rs +++ b/rewatch/src/build/packages.rs @@ -769,7 +769,7 @@ pub fn parse_packages(build_state: &mut BuildState) { }; match source_files.get(&implementation_filename) { None => { - log::warn!( + println!( "{} No implementation file found for interface file (skipping): {}", LINE_CLEAR, file.to_string_lossy() diff --git a/rewatch/src/main.rs b/rewatch/src/main.rs index 15b0f5880d..5c27a4d02b 100644 --- a/rewatch/src/main.rs +++ b/rewatch/src/main.rs @@ -46,6 +46,10 @@ struct Args { #[arg(short, long, default_value = "false", num_args = 0..=1)] no_timing: bool, + // simple output for snapshot testing + #[arg(short, long, default_value = "false", num_args = 0..=1)] + snapshot_output: bool, + /// Verbosity: /// -v -> Debug /// -vv -> Trace @@ -129,6 +133,7 @@ fn main() -> Result<()> { show_progress, &args.bsc_path.map(PathBuf::from), args.dev, + args.snapshot_output, ), Command::Build => { match build::build( @@ -139,6 +144,7 @@ fn main() -> Result<()> { args.create_sourcedirs, &args.bsc_path.map(PathBuf::from), args.dev, + args.snapshot_output, ) { Err(e) => { println!("{e}"); @@ -161,6 +167,7 @@ fn main() -> Result<()> { args.create_sourcedirs, args.dev, args.bsc_path, + args.snapshot_output, ); Ok(()) diff --git a/rewatch/src/watcher.rs b/rewatch/src/watcher.rs index 52bc915090..9151028937 100644 --- a/rewatch/src/watcher.rs +++ b/rewatch/src/watcher.rs @@ -63,10 +63,18 @@ async fn async_watch( create_sourcedirs: bool, build_dev_deps: bool, bsc_path: Option, + snapshot_output: bool, ) -> notify::Result<()> { - let mut build_state = - build::initialize_build(None, filter, show_progress, path, &bsc_path, build_dev_deps) - .expect("Can't initialize build"); + let mut build_state = build::initialize_build( + None, + filter, + show_progress, + path, + &bsc_path, + build_dev_deps, + snapshot_output, + ) + .expect("Can't initialize build"); let mut needs_compile_type = CompileType::Incremental; // create a mutex to capture if ctrl-c was pressed let ctrlc_pressed = Arc::new(Mutex::new(false)); @@ -217,6 +225,7 @@ async fn async_watch( !initial_build, create_sourcedirs, build_dev_deps, + snapshot_output, ) .is_ok() { @@ -225,13 +234,18 @@ async fn async_watch( } let timing_total_elapsed = timing_total.elapsed(); if show_progress { - println!( - "\n{}{}Finished {} compilation in {:.2}s\n", - LINE_CLEAR, - SPARKLES, - if initial_build { "initial" } else { "incremental" }, - timing_total_elapsed.as_secs_f64() - ); + let compilation_type = if initial_build { "initial" } else { "incremental" }; + if snapshot_output { + println!("Finished {} compilation", compilation_type) + } else { + println!( + "\n{}{}Finished {} compilation in {:.2}s\n", + LINE_CLEAR, + SPARKLES, + compilation_type, + timing_total_elapsed.as_secs_f64() + ); + } } } needs_compile_type = CompileType::None; @@ -239,9 +253,16 @@ async fn async_watch( } CompileType::Full => { let timing_total = Instant::now(); - build_state = - build::initialize_build(None, filter, show_progress, path, &bsc_path, build_dev_deps) - .expect("Can't initialize build"); + build_state = build::initialize_build( + None, + filter, + show_progress, + path, + &bsc_path, + build_dev_deps, + snapshot_output, + ) + .expect("Can't initialize build"); let _ = build::incremental_build( &mut build_state, None, @@ -250,6 +271,7 @@ async fn async_watch( false, create_sourcedirs, build_dev_deps, + snapshot_output, ); if let Some(a) = after_build.clone() { cmd::run(a) @@ -258,7 +280,7 @@ async fn async_watch( build::write_build_ninja(&build_state); let timing_total_elapsed = timing_total.elapsed(); - if show_progress { + if !snapshot_output && show_progress { println!( "\n{}{}Finished compilation in {:.2}s\n", LINE_CLEAR, @@ -286,6 +308,7 @@ pub fn start( create_sourcedirs: bool, build_dev_deps: bool, bsc_path: Option, + snapshot_output: bool, ) { futures::executor::block_on(async { let queue = Arc::new(FifoQueue::>::new()); @@ -310,6 +333,7 @@ pub fn start( create_sourcedirs, build_dev_deps, bsc_path_buf, + snapshot_output, ) .await { diff --git a/rewatch/tests/utils.sh b/rewatch/tests/utils.sh index 471732c886..1dffbe8a8d 100644 --- a/rewatch/tests/utils.sh +++ b/rewatch/tests/utils.sh @@ -3,8 +3,8 @@ overwrite() { echo -e "\r\033[1A\033[0K$@"; } success() { echo -e "- โœ… \033[32m$1\033[0m"; } error() { echo -e "- ๐Ÿ›‘ \033[31m$1\033[0m"; } bold() { echo -e "\033[1m$1\033[0m"; } -rewatch() { RUST_BACKTRACE=1 $REWATCH_EXECUTABLE --no-timing=true $@; } -rewatch_bg() { RUST_BACKTRACE=1 nohup $REWATCH_EXECUTABLE --no-timing=true $@; } +rewatch() { RUST_BACKTRACE=1 $REWATCH_EXECUTABLE --no-timing=true --snapshot-output=true $@; } +rewatch_bg() { RUST_BACKTRACE=1 nohup $REWATCH_EXECUTABLE --no-timing=true --snapshot-output=true $@; } # Detect if running on Windows is_windows() { From d659af65371aabee2580a57cf6bd7aa3636c2283 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Thu, 29 May 2025 14:20:42 +0200 Subject: [PATCH 30/39] improve CI output --- rewatch/tests/snapshots/dependency-cycle.txt | 10 +++------- rewatch/tests/snapshots/remove-file.txt | 10 +++------- .../rename-file-internal-dep-namespace.txt | 10 +++------- .../tests/snapshots/rename-file-internal-dep.txt | 10 +++------- .../tests/snapshots/rename-file-with-interface.txt | 13 +++---------- rewatch/tests/snapshots/rename-file.txt | 12 +++--------- rewatch/tests/snapshots/rename-interface-file.txt | 13 +++---------- 7 files changed, 21 insertions(+), 57 deletions(-) diff --git a/rewatch/tests/snapshots/dependency-cycle.txt b/rewatch/tests/snapshots/dependency-cycle.txt index e8b6db1b43..f7bf8e6035 100644 --- a/rewatch/tests/snapshots/dependency-cycle.txt +++ b/rewatch/tests/snapshots/dependency-cycle.txt @@ -1,10 +1,6 @@ -[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 0/14 0.00s - [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s - [6/7] ๐ŸŒด Collected deps in 0.00s - [7/7] โŒ Compiled 0 modules in 0.00s +Cleant 0/14 +Parsed 1 source files +Compiled 0 modules Can't continue... Found a circular dependency in your code: Dep01 diff --git a/rewatch/tests/snapshots/remove-file.txt b/rewatch/tests/snapshots/remove-file.txt index 98c0a992ab..6e8d58c461 100644 --- a/rewatch/tests/snapshots/remove-file.txt +++ b/rewatch/tests/snapshots/remove-file.txt @@ -1,10 +1,6 @@ -[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/14 0.00s - [5/7] ๐Ÿงฑ Parsed 0 source files in 0.00s - [6/7] ๐ŸŒด Collected deps in 0.00s - [7/7] โŒ Compiled 1 modules in 0.00s +Cleant 1/14 +Parsed 0 source files +Compiled 1 modules We've found a bug for you! /packages/dep01/src/Dep01.res:3:9-17 diff --git a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt index 0b3b2dbc51..934f98d760 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt @@ -1,10 +1,6 @@ -[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/14 0.00s - [5/7] ๐Ÿงฑ Parsed 2 source files in 0.00s - [6/7] ๐ŸŒด Collected deps in 0.00s - [7/7] โŒ Compiled 3 modules in 0.00s +Cleant 2/14 +Parsed 2 source files +Compiled 3 modules We've found a bug for you! /packages/new-namespace/src/NS_alias.res:2:1-16 diff --git a/rewatch/tests/snapshots/rename-file-internal-dep.txt b/rewatch/tests/snapshots/rename-file-internal-dep.txt index 986c4d7cf7..e194961cd3 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep.txt @@ -1,10 +1,6 @@ -[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/14 0.00s - [5/7] ๐Ÿงฑ Parsed 2 source files in 0.00s - [6/7] ๐ŸŒด Collected deps in 0.00s - [7/7] โŒ Compiled 2 modules in 0.00s +Cleant 2/14 +Parsed 2 source files +Compiled 2 modules We've found a bug for you! /packages/main/src/Main.res:4:8-24 diff --git a/rewatch/tests/snapshots/rename-file-with-interface.txt b/rewatch/tests/snapshots/rename-file-with-interface.txt index 7f25c66484..3f8ae93fb6 100644 --- a/rewatch/tests/snapshots/rename-file-with-interface.txt +++ b/rewatch/tests/snapshots/rename-file-with-interface.txt @@ -1,11 +1,4 @@ -[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ‘€ Finding source files...WARN:  No implementation file found for interface file (skipping): src/ModuleWithInterface.resi - [2/7] ๐Ÿ‘€ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/14 0.00s - [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s - [6/7] ๐ŸŒด Collected deps in 0.00s - [7/7] ๐Ÿคบ Compiled 2 modules in 0.00s - - โœจ Finished Compilation in 0.00s +Cleant 2/14 +Parsed 1 source files +Compiled 2 modules diff --git a/rewatch/tests/snapshots/rename-file.txt b/rewatch/tests/snapshots/rename-file.txt index cf5109cfdb..b933486cae 100644 --- a/rewatch/tests/snapshots/rename-file.txt +++ b/rewatch/tests/snapshots/rename-file.txt @@ -1,9 +1,3 @@ -[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/14 0.00s - [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s - [6/7] ๐ŸŒด Collected deps in 0.00s - [7/7] ๐Ÿคบ Compiled 1 modules in 0.00s - - โœจ Finished Compilation in 0.00s +Cleant 1/14 +Parsed 1 source files +Compiled 1 modules diff --git a/rewatch/tests/snapshots/rename-interface-file.txt b/rewatch/tests/snapshots/rename-interface-file.txt index 67475cbde4..4d71d014e1 100644 --- a/rewatch/tests/snapshots/rename-interface-file.txt +++ b/rewatch/tests/snapshots/rename-interface-file.txt @@ -1,11 +1,4 @@ -[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ‘€ Finding source files...WARN:  No implementation file found for interface file (skipping): src/ModuleWithInterface2.resi - [2/7] ๐Ÿ‘€ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/14 0.00s - [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s - [6/7] ๐ŸŒด Collected deps in 0.00s - [7/7] ๐Ÿคบ Compiled 2 modules in 0.00s - - โœจ Finished Compilation in 0.00s +Cleant 1/14 +Parsed 1 source files +Compiled 2 modules From 7ce8778c25de2bf66a755c9212eaad2a587ab7d4 Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Fri, 30 May 2025 12:17:45 +0200 Subject: [PATCH 31/39] Revert "debug: print bash version" This reverts commit 5d935a93a1f1d5274ff28d82ca4e1a677a254a25. --- rewatch/tests/compile.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index b85f170ebf..fd035bf902 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -3,8 +3,6 @@ cd $(dirname $0) source "./utils.sh" cd ../testrepo -bash --version - bold "Test: It should compile" if rewatch clean &> /dev/null; From 97a89bc849b1df6847d4d88141f44bd2d459cae5 Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Fri, 30 May 2025 12:38:29 +0200 Subject: [PATCH 32/39] feat: add snapshot_output to IncrementalBuildError --- rewatch/src/build.rs | 49 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/rewatch/src/build.rs b/rewatch/src/build.rs index 18fd5425e6..d70751ac7b 100644 --- a/rewatch/src/build.rs +++ b/rewatch/src/build.rs @@ -260,20 +260,40 @@ fn format_step(current: usize, total: usize) -> console::StyledObject { } #[derive(Debug, Clone)] -pub enum IncrementalBuildError { +pub enum IncrementalBuildErrorKind { SourceFileParseError, CompileError(Option), } +#[derive(Debug, Clone)] +pub struct IncrementalBuildError { + pub snapshot_output: bool, + pub kind: IncrementalBuildErrorKind, +} + impl fmt::Display for IncrementalBuildError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::SourceFileParseError => write!(f, "{} {}Could not parse Source Files", LINE_CLEAR, CROSS,), - Self::CompileError(Some(e)) => { - write!(f, "{} {}Failed to Compile. Error: {e}", LINE_CLEAR, CROSS,) + match &self.kind { + IncrementalBuildErrorKind::SourceFileParseError => { + if self.snapshot_output { + write!(f, "{} Could not parse Source Files", LINE_CLEAR,) + } else { + write!(f, "{} {}Could not parse Source Files", LINE_CLEAR, CROSS,) + } + } + IncrementalBuildErrorKind::CompileError(Some(e)) => { + if self.snapshot_output { + write!(f, "{} Failed to Compile. Error: {e}", LINE_CLEAR,) + } else { + write!(f, "{} {}Failed to Compile. Error: {e}", LINE_CLEAR, CROSS,) + } } - Self::CompileError(None) => { - write!(f, "{} {}Failed to Compile. See Errors Above", LINE_CLEAR, CROSS,) + IncrementalBuildErrorKind::CompileError(None) => { + if self.snapshot_output { + write!(f, "{} Failed to Compile. See Errors Above", LINE_CLEAR,) + } else { + write!(f, "{} {}Failed to Compile. See Errors Above", LINE_CLEAR, CROSS,) + } } } } @@ -344,7 +364,10 @@ pub fn incremental_build( } println!("{}", &err); - return Err(IncrementalBuildError::SourceFileParseError); + return Err(IncrementalBuildError { + kind: IncrementalBuildErrorKind::SourceFileParseError, + snapshot_output, + }); } } let timing_deps = Instant::now(); @@ -397,7 +420,10 @@ pub fn incremental_build( |size| pb.set_length(size), build_dev_deps, ) - .map_err(|e| IncrementalBuildError::CompileError(Some(e.to_string())))?; + .map_err(|e| IncrementalBuildError { + kind: IncrementalBuildErrorKind::CompileError(Some(e.to_string())), + snapshot_output, + })?; let compile_duration = start_compiling.elapsed(); @@ -427,7 +453,10 @@ pub fn incremental_build( if helpers::contains_ascii_characters(&compile_errors) { println!("{}", &compile_errors); } - Err(IncrementalBuildError::CompileError(None)) + Err(IncrementalBuildError { + kind: IncrementalBuildErrorKind::CompileError(None), + snapshot_output, + }) } else { if show_progress { if snapshot_output { From a57f118a2db904ad9090de3b535e64ecc727d087 Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Fri, 30 May 2025 12:38:49 +0200 Subject: [PATCH 33/39] test: update snapshots --- rewatch/tests/snapshots/dependency-cycle.txt | 2 +- rewatch/tests/snapshots/remove-file.txt | 2 +- rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt | 2 +- rewatch/tests/snapshots/rename-file-internal-dep.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rewatch/tests/snapshots/dependency-cycle.txt b/rewatch/tests/snapshots/dependency-cycle.txt index f7bf8e6035..f35c1d9c93 100644 --- a/rewatch/tests/snapshots/dependency-cycle.txt +++ b/rewatch/tests/snapshots/dependency-cycle.txt @@ -9,4 +9,4 @@ Dep01 โ†’ NewNamespace.NS_alias โ†’ Dep01 -Incremental build failed. Error:  โŒ Failed to Compile. See Errors Above +Incremental build failed. Error:  Failed to Compile. See Errors Above diff --git a/rewatch/tests/snapshots/remove-file.txt b/rewatch/tests/snapshots/remove-file.txt index 6e8d58c461..ca5887786c 100644 --- a/rewatch/tests/snapshots/remove-file.txt +++ b/rewatch/tests/snapshots/remove-file.txt @@ -18,4 +18,4 @@ Compiled 1 modules -Incremental build failed. Error:  โŒ Failed to Compile. See Errors Above +Incremental build failed. Error:  Failed to Compile. See Errors Above diff --git a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt index 934f98d760..ec67dea3bb 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt @@ -18,4 +18,4 @@ Compiled 3 modules Hint: Did you mean Other_module2? -Incremental build failed. Error:  โŒ Failed to Compile. See Errors Above +Incremental build failed. Error:  Failed to Compile. See Errors Above diff --git a/rewatch/tests/snapshots/rename-file-internal-dep.txt b/rewatch/tests/snapshots/rename-file-internal-dep.txt index e194961cd3..34250bbc05 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep.txt @@ -18,4 +18,4 @@ Compiled 2 modules -Incremental build failed. Error:  โŒ Failed to Compile. See Errors Above +Incremental build failed. Error:  Failed to Compile. See Errors Above From 4cf3b1a160ccbb5368ec199d30988308c8903cba Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Fri, 30 May 2025 14:42:56 +0200 Subject: [PATCH 34/39] test: `build` to check for lock --- rewatch/tests/lock.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rewatch/tests/lock.sh b/rewatch/tests/lock.sh index 4522a7a037..4bb474ab5a 100755 --- a/rewatch/tests/lock.sh +++ b/rewatch/tests/lock.sh @@ -19,10 +19,11 @@ exit_watcher() { } rewatch_bg watch > /dev/null 2>&1 & +success "Watcher Started" sleep 1 -if rewatch watch | grep 'Could not start Rewatch:' &> /dev/null; +if rewatch build | grep 'Could not start Rewatch:' &> /dev/null; then # rm output.txt success "Lock is correctly set" From f6bec1961cad0d8ae07b43c72a0d4bbba68ead32 Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Fri, 30 May 2025 15:49:05 +0200 Subject: [PATCH 35/39] debug: check output after watch --- rewatch/tests/lock.sh | 5 ++--- rewatch/tests/watch.sh | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rewatch/tests/lock.sh b/rewatch/tests/lock.sh index 4bb474ab5a..40f534400c 100755 --- a/rewatch/tests/lock.sh +++ b/rewatch/tests/lock.sh @@ -14,22 +14,21 @@ else fi exit_watcher() { - # Try to find child process, if not found just kill the process directly + # kill watcher by removing lock file rm lib/rewatch.lock } rewatch_bg watch > /dev/null 2>&1 & success "Watcher Started" +ps sleep 1 if rewatch build | grep 'Could not start Rewatch:' &> /dev/null; then - # rm output.txt success "Lock is correctly set" exit_watcher else - # rm output.txt error "Not setting lock correctly" exit_watcher exit 1 diff --git a/rewatch/tests/watch.sh b/rewatch/tests/watch.sh index e3a24c0997..047a343488 100755 --- a/rewatch/tests/watch.sh +++ b/rewatch/tests/watch.sh @@ -12,7 +12,7 @@ else fi exit_watcher() { - # we need to kill the parent process (rewatch) + # kill watcher by removing lock file rm lib/rewatch.lock } From b4d39dfcdfb06a9f2712da03e56bfdc8be48a96c Mon Sep 17 00:00:00 2001 From: Paul Buschmann Date: Fri, 30 May 2025 16:04:20 +0200 Subject: [PATCH 36/39] test: sleep longer --- rewatch/tests/lock.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rewatch/tests/lock.sh b/rewatch/tests/lock.sh index 40f534400c..f96d68db3e 100755 --- a/rewatch/tests/lock.sh +++ b/rewatch/tests/lock.sh @@ -20,9 +20,8 @@ exit_watcher() { rewatch_bg watch > /dev/null 2>&1 & success "Watcher Started" -ps -sleep 1 +sleep 2 if rewatch build | grep 'Could not start Rewatch:' &> /dev/null; then @@ -40,7 +39,7 @@ touch tmp.txt rewatch_bg watch > tmp.txt 2>&1 & success "Watcher Started" -sleep 1 +sleep 2 if cat tmp.txt | grep 'Could not start Rewatch:' &> /dev/null; then From caed520d322bd0aa9364e6f479fb6c72e7404470 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Fri, 30 May 2025 17:37:42 +0200 Subject: [PATCH 37/39] sleep longer for mac os --- rewatch/tests/watch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewatch/tests/watch.sh b/rewatch/tests/watch.sh index 047a343488..83cee30f1b 100755 --- a/rewatch/tests/watch.sh +++ b/rewatch/tests/watch.sh @@ -21,7 +21,7 @@ success "Watcher Started" echo 'Js.log("added-by-test")' >> ./packages/main/src/Main.res -sleep 1 +sleep 2 if node ./packages/main/src/Main.mjs | grep 'added-by-test' &> /dev/null; then From 3c9de5bff0d5acb99ea19749a7438991d4b3c308 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Wed, 4 Jun 2025 08:58:02 +0200 Subject: [PATCH 38/39] fix typo --- rewatch/src/build.rs | 4 ++-- rewatch/src/build/clean.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rewatch/src/build.rs b/rewatch/src/build.rs index d70751ac7b..c76120064e 100644 --- a/rewatch/src/build.rs +++ b/rewatch/src/build.rs @@ -238,10 +238,10 @@ pub fn initialize_build( if show_progress { if snapshot_output { - println!("Cleant {}/{}", diff_cleanup, total_cleanup) + println!("Cleaned {}/{}", diff_cleanup, total_cleanup) } else { println!( - "{}{} {}Cleant {}/{} {:.2}s", + "{}{} {}Cleaned {}/{} {:.2}s", LINE_CLEAR, style("[4/7]").bold().dim(), SWEEP, diff --git a/rewatch/src/build/clean.rs b/rewatch/src/build/clean.rs index 9b9d09553a..5624e6ac33 100644 --- a/rewatch/src/build/clean.rs +++ b/rewatch/src/build/clean.rs @@ -393,7 +393,7 @@ pub fn clean( if !snapshot_output && show_progress { println!( - "{}{} {}Cleant compiler assets in {:.2}s", + "{}{} {}Cleaned compiler assets in {:.2}s", LINE_CLEAR, style("[1/2]").bold().dim(), SWEEP, From 097d6e66d4792afaab64f3229daab6e21db26537 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Wed, 4 Jun 2025 08:58:24 +0200 Subject: [PATCH 39/39] fix typo in snapshots --- rewatch/tests/snapshots/dependency-cycle.txt | 2 +- rewatch/tests/snapshots/remove-file.txt | 2 +- rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt | 2 +- rewatch/tests/snapshots/rename-file-internal-dep.txt | 2 +- rewatch/tests/snapshots/rename-file-with-interface.txt | 2 +- rewatch/tests/snapshots/rename-file.txt | 2 +- rewatch/tests/snapshots/rename-interface-file.txt | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rewatch/tests/snapshots/dependency-cycle.txt b/rewatch/tests/snapshots/dependency-cycle.txt index f35c1d9c93..c949d4005c 100644 --- a/rewatch/tests/snapshots/dependency-cycle.txt +++ b/rewatch/tests/snapshots/dependency-cycle.txt @@ -1,4 +1,4 @@ -Cleant 0/14 +Cleaned 0/14 Parsed 1 source files Compiled 0 modules diff --git a/rewatch/tests/snapshots/remove-file.txt b/rewatch/tests/snapshots/remove-file.txt index ca5887786c..921f9d4246 100644 --- a/rewatch/tests/snapshots/remove-file.txt +++ b/rewatch/tests/snapshots/remove-file.txt @@ -1,4 +1,4 @@ -Cleant 1/14 +Cleaned 1/14 Parsed 0 source files Compiled 1 modules diff --git a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt index ec67dea3bb..1950bad9e3 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt @@ -1,4 +1,4 @@ -Cleant 2/14 +Cleaned 2/14 Parsed 2 source files Compiled 3 modules diff --git a/rewatch/tests/snapshots/rename-file-internal-dep.txt b/rewatch/tests/snapshots/rename-file-internal-dep.txt index 34250bbc05..f81a6dece4 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep.txt @@ -1,4 +1,4 @@ -Cleant 2/14 +Cleaned 2/14 Parsed 2 source files Compiled 2 modules diff --git a/rewatch/tests/snapshots/rename-file-with-interface.txt b/rewatch/tests/snapshots/rename-file-with-interface.txt index 3f8ae93fb6..257fba3570 100644 --- a/rewatch/tests/snapshots/rename-file-with-interface.txt +++ b/rewatch/tests/snapshots/rename-file-with-interface.txt @@ -1,4 +1,4 @@  No implementation file found for interface file (skipping): src/ModuleWithInterface.resi -Cleant 2/14 +Cleaned 2/14 Parsed 1 source files Compiled 2 modules diff --git a/rewatch/tests/snapshots/rename-file.txt b/rewatch/tests/snapshots/rename-file.txt index b933486cae..5b20d86fd7 100644 --- a/rewatch/tests/snapshots/rename-file.txt +++ b/rewatch/tests/snapshots/rename-file.txt @@ -1,3 +1,3 @@ -Cleant 1/14 +Cleaned 1/14 Parsed 1 source files Compiled 1 modules diff --git a/rewatch/tests/snapshots/rename-interface-file.txt b/rewatch/tests/snapshots/rename-interface-file.txt index 4d71d014e1..e2d7fd9752 100644 --- a/rewatch/tests/snapshots/rename-interface-file.txt +++ b/rewatch/tests/snapshots/rename-interface-file.txt @@ -1,4 +1,4 @@  No implementation file found for interface file (skipping): src/ModuleWithInterface2.resi -Cleant 1/14 +Cleaned 1/14 Parsed 1 source files Compiled 2 modules