diff --git a/.gitattributes b/.gitattributes index 873ddfb587..666eddc88d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ +* text=auto eol=lf + *.ml linguist-language=OCaml *.mli linguist-language=OCaml *.res linguist-language=ReScript diff --git a/CHANGELOG.md b/CHANGELOG.md index bd9695b714..0b52d12ecf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ # 12.0.0-alpha.15 (Unreleased) +#### :boom: Breaking Change + +- The legacy rescript cli can be called through rewatch via `rewatch legacy`. Arguments to rewatch need to be passed after the subcommand. Argument `--compiler-args` is now a subcommand `compiler-args`. https://github.com/rescript-lang/rescript/pull/7551 + #### :bug: Bug fix - Ignore inferred arity in functions inside `%raw` functions, leaving to `%ffi` the responsibility to check the arity since it gives an error in case of mismatch. https://github.com/rescript-lang/rescript/pull/7542 diff --git a/cli/rewatch.js b/cli/rewatch.js index 7eae74aed1..d7e65e077e 100755 --- a/cli/rewatch.js +++ b/cli/rewatch.js @@ -7,10 +7,37 @@ import { rewatch_exe, bsc_exe } from "./common/bins.js"; const args = process.argv.slice(2); +const firstPositionalArgIndex = args.findIndex((arg) => !arg.startsWith("-")); + try { - child_process.execFileSync(rewatch_exe, [...args, "--bsc-path", bsc_exe], { - stdio: "inherit", - }); + if (firstPositionalArgIndex !== -1) { + const subcommand = args[firstPositionalArgIndex]; + const subcommandWithArgs = args.slice(firstPositionalArgIndex); + + if ( + subcommand === "build" || + subcommand === "watch" || + subcommand === "clean" || + subcommand === "compiler-args" + ) { + child_process.execFileSync( + rewatch_exe, + [...subcommandWithArgs, "--bsc-path", bsc_exe], + { + stdio: "inherit", + } + ); + } else { + child_process.execFileSync(rewatch_exe, [...args], { + stdio: "inherit", + }); + } + } else { + // no subcommand means build subcommand + child_process.execFileSync(rewatch_exe, [...args, "--bsc-path", bsc_exe], { + stdio: "inherit", + }); + } } catch (err) { if (err.status !== undefined) { process.exit(err.status); // Pass through the exit code diff --git a/rewatch/src/build.rs b/rewatch/src/build.rs index c76120064e..7562872f02 100644 --- a/rewatch/src/build.rs +++ b/rewatch/src/build.rs @@ -18,10 +18,12 @@ use console::style; use indicatif::{ProgressBar, ProgressStyle}; use log::log_enabled; use serde::Serialize; +use std::ffi::OsString; use std::fmt; use std::fs::File; use std::io::{stdout, Write}; use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::time::{Duration, Instant}; use self::compile::compiler_args; @@ -57,7 +59,7 @@ pub struct CompilerArgs { pub fn get_compiler_args( path: &Path, rescript_version: Option, - bsc_path: &Option, + bsc_path: Option, build_dev_deps: bool, ) -> Result { let filename = &helpers::get_abs_path(path); @@ -499,7 +501,7 @@ pub fn build( show_progress: bool, no_timing: bool, create_sourcedirs: bool, - bsc_path: &Option, + bsc_path: Option, build_dev_deps: bool, snapshot_output: bool, ) -> Result { @@ -514,7 +516,7 @@ pub fn build( filter, show_progress, path, - bsc_path, + &bsc_path, build_dev_deps, snapshot_output, ) @@ -551,3 +553,25 @@ pub fn build( } } } + +pub fn pass_through_legacy(mut args: Vec) -> i32 { + let project_root = helpers::get_abs_path(Path::new(".")); + let workspace_root = helpers::get_workspace_root(&project_root); + + let rescript_legacy_path = helpers::get_rescript_legacy(&project_root, workspace_root); + + args.insert(0, rescript_legacy_path.into()); + let status = std::process::Command::new("node") + .args(args) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .status(); + + match status { + Ok(s) => s.code().unwrap_or(0), + Err(err) => { + eprintln!("Error running the legacy build system: {err}"); + 1 + } + } +} diff --git a/rewatch/src/build/clean.rs b/rewatch/src/build/clean.rs index 5624e6ac33..8a09bef035 100644 --- a/rewatch/src/build/clean.rs +++ b/rewatch/src/build/clean.rs @@ -334,8 +334,7 @@ pub fn cleanup_after_build(build_state: &BuildState) { pub fn clean( path: &Path, show_progress: bool, - bsc_path: &Option, - build_dev_deps: bool, + bsc_path: Option, snapshot_output: bool, ) -> Result<()> { let project_root = helpers::get_abs_path(path); @@ -345,8 +344,9 @@ pub fn clean( &project_root, &workspace_root, show_progress, - // Always clean dev dependencies - build_dev_deps, + // Build the package tree with dev dependencies. + // They should always be cleaned if they are there. + true, )?; let root_config_name = packages::read_package_name(&project_root)?; let bsc_path = match bsc_path { diff --git a/rewatch/src/cli.rs b/rewatch/src/cli.rs new file mode 100644 index 0000000000..d9a088d8ae --- /dev/null +++ b/rewatch/src/cli.rs @@ -0,0 +1,257 @@ +use std::{ffi::OsString, ops::Deref}; + +use clap::{Args, Parser, Subcommand}; +use clap_verbosity_flag::InfoLevel; + +/// Rewatch is an alternative build system for the Rescript Compiler bsb (which uses Ninja internally). It strives +/// to deliver consistent and faster builds in monorepo setups with multiple packages, where the +/// default build system fails to pick up changed interfaces across multiple packages. +#[derive(Parser, Debug)] +#[command(version)] +#[command(args_conflicts_with_subcommands = true)] +pub struct Cli { + /// Verbosity: + /// -v -> Debug + /// -vv -> Trace + /// -q -> Warn + /// -qq -> Error + /// -qqq -> Off. + /// Default (/ no argument given): 'info' + #[command(flatten)] + pub verbose: clap_verbosity_flag::Verbosity, + + /// The command to run. If not provided it will default to build. + #[command(subcommand)] + pub command: Option, + + #[command(flatten)] + pub build_args: BuildArgs, +} + +#[derive(Args, Debug, Clone)] +pub struct FolderArg { + /// The relative path to where the main rescript.json resides. IE - the root of your project. + #[arg(default_value = ".")] + pub folder: String, +} + +#[derive(Args, Debug, Clone)] +pub struct FilterArg { + /// Filter files by regex + /// + /// Filter allows for a regex to be supplied which will filter the files to be compiled. For + /// instance, to filter out test files for compilation while doing feature work. + #[arg(short, long)] + pub filter: Option, +} + +#[derive(Args, Debug, Clone)] +pub struct AfterBuildArg { + /// Action after build + /// + /// This allows one to pass an additional command to the watcher, which allows it to run when + /// finished. For instance, to play a sound when done compiling, or to run a test suite. + /// NOTE - You may need to add '--color=always' to your subcommand in case you want to output + /// color as well + #[arg(short, long)] + pub after_build: Option, +} + +#[derive(Args, Debug, Clone, Copy)] +pub struct CreateSourceDirsArg { + /// Create source_dirs.json + /// + /// This creates a source_dirs.json file at the root of the monorepo, which is needed when you + /// want to use Reanalyze + #[arg(short, long, default_value_t = false, num_args = 0..=1)] + pub create_sourcedirs: bool, +} + +#[derive(Args, Debug, Clone, Copy)] +pub struct DevArg { + /// Build development dependencies + /// + /// This is the flag to also compile development dependencies + /// It's important to know that we currently do not discern between project src, and + /// dependencies. So enabling this flag will enable building _all_ development dependencies of + /// _all_ packages + #[arg(long, default_value_t = false, num_args = 0..=1)] + pub dev: bool, +} + +#[derive(Args, Debug, Clone)] +pub struct BscPathArg { + /// Custom path to bsc + #[arg(long)] + pub bsc_path: Option, +} + +#[derive(Args, Debug, Clone, Copy)] +pub struct SnapshotOutputArg { + /// simple output for snapshot testing + #[arg(short, long, default_value = "false", num_args = 0..=1)] + pub snapshot_output: bool, +} + +#[derive(Args, Debug, Clone)] +pub struct BuildArgs { + #[command(flatten)] + pub folder: FolderArg, + + #[command(flatten)] + pub filter: FilterArg, + + #[command(flatten)] + pub after_build: AfterBuildArg, + + #[command(flatten)] + pub create_sourcedirs: CreateSourceDirsArg, + + #[command(flatten)] + pub dev: DevArg, + + /// Disable timing on the output + #[arg(short, long, default_value_t = false, num_args = 0..=1)] + pub no_timing: bool, + + #[command(flatten)] + pub snapshot_output: SnapshotOutputArg, + + #[command(flatten)] + pub bsc_path: BscPathArg, +} + +#[derive(Args, Clone, Debug)] +pub struct WatchArgs { + #[command(flatten)] + pub folder: FolderArg, + + #[command(flatten)] + pub filter: FilterArg, + + #[command(flatten)] + pub after_build: AfterBuildArg, + + #[command(flatten)] + pub create_sourcedirs: CreateSourceDirsArg, + + #[command(flatten)] + pub dev: DevArg, + + #[command(flatten)] + pub snapshot_output: SnapshotOutputArg, + + #[command(flatten)] + pub bsc_path: BscPathArg, +} + +#[derive(Subcommand, Clone, Debug)] +pub enum Command { + /// Build using Rewatch + Build(BuildArgs), + /// Build, then start a watcher + Watch(WatchArgs), + /// Clean the build artifacts + Clean { + #[command(flatten)] + folder: FolderArg, + + #[command(flatten)] + bsc_path: BscPathArg, + + #[command(flatten)] + snapshot_output: SnapshotOutputArg, + }, + /// Alias to `legacy format`. + #[command(disable_help_flag = true)] + Format { + #[arg(allow_hyphen_values = true, num_args = 0..)] + format_args: Vec, + }, + /// Alias to `legacy dump`. + #[command(disable_help_flag = true)] + Dump { + #[arg(allow_hyphen_values = true, num_args = 0..)] + dump_args: Vec, + }, + /// This prints the compiler arguments. It expects the path to a rescript.json file. + CompilerArgs { + /// Path to a rescript.json file + #[command()] + path: String, + + #[command(flatten)] + dev: DevArg, + + /// To be used in conjunction with compiler_args + #[arg(long)] + rescript_version: Option, + + #[command(flatten)] + bsc_path: BscPathArg, + }, + /// Use the legacy build system. + /// + /// After this command is encountered, the rest of the arguments are passed to the legacy build system. + #[command(disable_help_flag = true, external_subcommand = true)] + Legacy { + #[arg(allow_hyphen_values = true, num_args = 0..)] + legacy_args: Vec, + }, +} + +impl Deref for FolderArg { + type Target = str; + + fn deref(&self) -> &Self::Target { + &self.folder + } +} + +impl Deref for FilterArg { + type Target = Option; + + fn deref(&self) -> &Self::Target { + &self.filter + } +} + +impl Deref for AfterBuildArg { + type Target = Option; + + fn deref(&self) -> &Self::Target { + &self.after_build + } +} + +impl Deref for CreateSourceDirsArg { + type Target = bool; + + fn deref(&self) -> &Self::Target { + &self.create_sourcedirs + } +} + +impl Deref for DevArg { + type Target = bool; + + fn deref(&self) -> &Self::Target { + &self.dev + } +} + +impl Deref for BscPathArg { + type Target = Option; + + fn deref(&self) -> &Self::Target { + &self.bsc_path + } +} + +impl Deref for SnapshotOutputArg { + type Target = bool; + + fn deref(&self) -> &Self::Target { + &self.snapshot_output + } +} diff --git a/rewatch/src/helpers.rs b/rewatch/src/helpers.rs index a91dee77f5..9b6661c2e4 100644 --- a/rewatch/src/helpers.rs +++ b/rewatch/src/helpers.rs @@ -181,32 +181,35 @@ pub fn create_path_for_path(path: &Path) { fs::DirBuilder::new().recursive(true).create(path).unwrap(); } -pub fn get_bsc(root_path: &Path, workspace_root: &Option) -> PathBuf { +fn get_bin_dir() -> PathBuf { let subfolder = match (std::env::consts::OS, std::env::consts::ARCH) { ("macos", "aarch64") => "darwin-arm64", ("macos", _) => "darwin-x64", ("linux", "aarch64") => "linux-arm64", ("linux", _) => "linux-x64", ("windows", "aarch64") => "win-arm64", - ("windows", _) => "win-x64", + ("windows", _) => "win32-x64", _ => panic!("Unsupported architecture"), }; + Path::new("node_modules") + .join("@rescript") + .join(subfolder) + .join("bin") +} + +pub fn get_bsc(root_path: &Path, workspace_root: &Option) -> PathBuf { + let bin_dir = get_bin_dir(); + match ( root_path - .join("node_modules") - .join("@rescript") - .join(subfolder) - .join("bin") + .join(&bin_dir) .join("bsc.exe") .canonicalize() .map(StrippedVerbatimPath::to_stripped_verbatim_path), workspace_root.as_ref().map(|workspace_root| { workspace_root - .join("node_modules") - .join("@rescript") - .join(subfolder) - .join("bin") + .join(&bin_dir) .join("bsc.exe") .canonicalize() .map(StrippedVerbatimPath::to_stripped_verbatim_path) @@ -218,6 +221,29 @@ pub fn get_bsc(root_path: &Path, workspace_root: &Option) -> PathBuf { } } +pub fn get_rescript_legacy(root_path: &Path, workspace_root: Option) -> PathBuf { + let bin_dir = Path::new("node_modules").join("rescript").join("cli"); + + match ( + root_path + .join(&bin_dir) + .join("rescript.js") + .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path), + workspace_root.map(|workspace_root| { + workspace_root + .join(&bin_dir) + .join("rescript.js") + .canonicalize() + .map(StrippedVerbatimPath::to_stripped_verbatim_path) + }), + ) { + (Ok(path), _) => path, + (_, Some(Ok(path))) => path, + _ => panic!("Could not find rescript.exe"), + } +} + pub fn string_ends_with_any(s: &Path, suffixes: &[&str]) -> bool { suffixes .iter() diff --git a/rewatch/src/lib.rs b/rewatch/src/lib.rs index 9dc6f5591c..2df92a48f3 100644 --- a/rewatch/src/lib.rs +++ b/rewatch/src/lib.rs @@ -1,4 +1,5 @@ pub mod build; +pub mod cli; pub mod cmd; pub mod config; pub mod helpers; diff --git a/rewatch/src/main.rs b/rewatch/src/main.rs index 5c27a4d02b..3cd1c5d084 100644 --- a/rewatch/src/main.rs +++ b/rewatch/src/main.rs @@ -1,93 +1,17 @@ use anyhow::Result; -use clap::{Parser, ValueEnum}; -use clap_verbosity_flag::InfoLevel; +use clap::Parser; use log::LevelFilter; use regex::Regex; -use std::io::Write; -use std::path::{Path, PathBuf}; +use std::{ + io::Write, + path::{Path, PathBuf}, +}; -use rewatch::{build, cmd, lock, watcher}; - -#[derive(Debug, Clone, ValueEnum)] -enum Command { - /// Build using Rewatch - Build, - /// Build, then start a watcher - Watch, - /// Clean the build artifacts - Clean, -} - -/// Rewatch is an alternative build system for the Rescript Compiler bsb (which uses Ninja internally). It strives -/// to deliver consistent and faster builds in monorepo setups with multiple packages, where the -/// default build system fails to pick up changed interfaces across multiple packages. -#[derive(Parser, Debug)] -#[command(version)] -struct Args { - #[arg(value_enum)] - command: Option, - - /// The relative path to where the main rescript.json resides. IE - the root of your project. - folder: Option, - - /// Filter allows for a regex to be supplied which will filter the files to be compiled. For - /// instance, to filter out test files for compilation while doing feature work. - #[arg(short, long)] - filter: Option, - - /// This allows one to pass an additional command to the watcher, which allows it to run when - /// finished. For instance, to play a sound when done compiling, or to run a test suite. - /// NOTE - You may need to add '--color=always' to your subcommand in case you want to output - /// colour as well - #[arg(short, long)] - after_build: Option, - - // Disable timing on the output - #[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 - /// -q -> Warn - /// -qq -> Error - /// -qqq -> Off. - /// Default (/ no argument given): 'info' - #[command(flatten)] - verbose: clap_verbosity_flag::Verbosity, - - /// This creates a source_dirs.json file at the root of the monorepo, which is needed when you - /// want to use Reanalyze - #[arg(short, long, default_value_t = false, num_args = 0..=1)] - create_sourcedirs: bool, - - /// This prints the compiler arguments. It expects the path to a rescript.json file. - /// This also requires --bsc-path and --rescript-version to be present - #[arg(long)] - compiler_args: Option, - - /// This is the flag to also compile development dependencies - /// It's important to know that we currently do not discern between project src, and - /// dependencies. So enabling this flag will enable building _all_ development dependencies of - /// _all_ packages - #[arg(long, default_value_t = false, num_args = 0..=1)] - dev: bool, - - /// To be used in conjunction with compiler_args - #[arg(long)] - rescript_version: Option, - - /// A custom path to bsc - #[arg(long)] - bsc_path: Option, -} +use rewatch::{build, cli, cmd, lock, watcher}; fn main() -> Result<()> { - let args = Args::parse(); + let args = cli::Cli::parse(); + let log_level_filter = args.verbose.log_level_filter(); env_logger::Builder::new() @@ -96,82 +20,117 @@ fn main() -> Result<()> { .target(env_logger::fmt::Target::Stdout) .init(); - let command = args.command.unwrap_or(Command::Build); - let folder = args.folder.unwrap_or(".".to_string()); - let filter = args - .filter - .map(|filter| Regex::new(filter.as_ref()).expect("Could not parse regex")); + let command = args.command.unwrap_or(cli::Command::Build(args.build_args)); + + // The 'normal run' mode will show the 'pretty' formatted progress. But if we turn off the log + // level, we should never show that. + let show_progress = log_level_filter == LevelFilter::Info; - match args.compiler_args { - None => (), - Some(path) => { + match command.clone() { + cli::Command::CompilerArgs { + path, + dev, + rescript_version, + bsc_path, + } => { println!( "{}", build::get_compiler_args( Path::new(&path), - args.rescript_version, - &args.bsc_path.map(PathBuf::from), - args.dev + rescript_version, + bsc_path.as_ref().map(PathBuf::from), + *dev )? ); std::process::exit(0); } - } + cli::Command::Build(build_args) => { + let _lock = get_lock(&build_args.folder); - // The 'normal run' mode will show the 'pretty' formatted progress. But if we turn off the log - // level, we should never show that. - let show_progress = log_level_filter == LevelFilter::Info; + let filter = build_args + .filter + .as_ref() + .map(|filter| Regex::new(&filter).expect("Could not parse regex")); - match lock::get(&folder) { - lock::Lock::Error(ref e) => { - println!("Could not start Rewatch: {e}"); - std::process::exit(1) - } - lock::Lock::Aquired(_) => match command { - Command::Clean => build::clean::clean( - Path::new(&folder), + match build::build( + &filter, + Path::new(&build_args.folder as &str), show_progress, - &args.bsc_path.map(PathBuf::from), - args.dev, - args.snapshot_output, - ), - Command::Build => { - match build::build( - &filter, - Path::new(&folder), - show_progress, - args.no_timing, - args.create_sourcedirs, - &args.bsc_path.map(PathBuf::from), - args.dev, - args.snapshot_output, - ) { - Err(e) => { - println!("{e}"); - std::process::exit(1) + build_args.no_timing, + *build_args.create_sourcedirs, + build_args.bsc_path.as_ref().map(PathBuf::from), + *build_args.dev, + *build_args.snapshot_output, + ) { + Err(e) => { + println!("{e}"); + std::process::exit(1) + } + Ok(_) => { + if let Some(args_after_build) = (*build_args.after_build).clone() { + cmd::run(args_after_build) } - Ok(_) => { - if let Some(args_after_build) = args.after_build { - cmd::run(args_after_build) - } - std::process::exit(0) - } - }; - } - Command::Watch => { - watcher::start( - &filter, - show_progress, - &folder, - args.after_build, - args.create_sourcedirs, - args.dev, - args.bsc_path, - args.snapshot_output, - ); + std::process::exit(0) + } + }; + } + cli::Command::Watch(watch_args) => { + let _lock = get_lock(&watch_args.folder); + + let filter = watch_args + .filter + .as_ref() + .map(|filter| Regex::new(&filter).expect("Could not parse regex")); + watcher::start( + &filter, + show_progress, + &watch_args.folder, + (*watch_args.after_build).clone(), + *watch_args.create_sourcedirs, + *watch_args.dev, + (*watch_args.bsc_path).clone(), + *watch_args.snapshot_output, + ); - Ok(()) - } - }, + Ok(()) + } + cli::Command::Clean { + folder, + bsc_path, + snapshot_output, + } => { + let _lock = get_lock(&folder); + + build::clean::clean( + Path::new(&folder as &str), + show_progress, + bsc_path.as_ref().map(PathBuf::from), + *snapshot_output, + ) + } + cli::Command::Legacy { legacy_args } => { + let code = build::pass_through_legacy(legacy_args); + std::process::exit(code); + } + cli::Command::Format { mut format_args } => { + format_args.insert(0, "format".into()); + let code = build::pass_through_legacy(format_args); + std::process::exit(code); + } + cli::Command::Dump { mut dump_args } => { + dump_args.insert(0, "dump".into()); + let code = build::pass_through_legacy(dump_args); + std::process::exit(code); + } + } +} + +fn get_lock(folder: &str) -> lock::Lock { + match lock::get(folder) { + lock::Lock::Error(error) => { + println!("Could not start Rewatch: {error}"); + std::process::exit(1); + } + acquired_lock => acquired_lock, } } diff --git a/rewatch/testrepo/bsconfig.json b/rewatch/testrepo/bsconfig.json index 706ee9066a..95e49a9f45 100644 --- a/rewatch/testrepo/bsconfig.json +++ b/rewatch/testrepo/bsconfig.json @@ -20,7 +20,8 @@ "@testrepo/dep02", "@testrepo/new-namespace", "@testrepo/namespace-casing", - "@testrepo/with-dev-deps" + "@testrepo/with-dev-deps", + "@testrepo/compiled-by-legacy" ], "bs-dependencies": [ "@testrepo/main", @@ -28,7 +29,8 @@ "@testrepo/dep02", "@testrepo/new-namespace", "@testrepo/namespace-casing", - "@testrepo/with-dev-deps" + "@testrepo/with-dev-deps", + "@testrepo/compiled-by-legacy" ], "reason": { "react-jsx": 3 diff --git a/rewatch/testrepo/package.json b/rewatch/testrepo/package.json index 3436184038..2ed3978be5 100644 --- a/rewatch/testrepo/package.json +++ b/rewatch/testrepo/package.json @@ -8,7 +8,8 @@ "packages/dep02", "packages/new-namespace", "packages/namespace-casing", - "packages/with-dev-deps" + "packages/with-dev-deps", + "packages/compiled-by-legacy" ] }, "dependencies": { diff --git a/rewatch/testrepo/packages/compiled-by-legacy/package.json b/rewatch/testrepo/packages/compiled-by-legacy/package.json new file mode 100644 index 0000000000..34d940f905 --- /dev/null +++ b/rewatch/testrepo/packages/compiled-by-legacy/package.json @@ -0,0 +1,9 @@ +{ + "name": "@testrepo/compiled-by-legacy", + "version": "0.0.1", + "keywords": [ + "rescript" + ], + "author": "", + "license": "MIT" +} diff --git a/rewatch/testrepo/packages/compiled-by-legacy/rescript.json b/rewatch/testrepo/packages/compiled-by-legacy/rescript.json new file mode 100644 index 0000000000..3722c661d5 --- /dev/null +++ b/rewatch/testrepo/packages/compiled-by-legacy/rescript.json @@ -0,0 +1,13 @@ +{ + "name": "@testrepo/compiled-by-legacy", + "namespace": true, + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": { + "module": "esmodule", + "in-source": true + }, + "suffix": ".res.js" +} diff --git a/rewatch/testrepo/packages/compiled-by-legacy/src/Main.mjs b/rewatch/testrepo/packages/compiled-by-legacy/src/Main.mjs new file mode 100644 index 0000000000..618d7a44e8 --- /dev/null +++ b/rewatch/testrepo/packages/compiled-by-legacy/src/Main.mjs @@ -0,0 +1,9 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +let x = 1; + +export { + x, +} +/* No side effect */ diff --git a/rewatch/testrepo/packages/compiled-by-legacy/src/Main.res b/rewatch/testrepo/packages/compiled-by-legacy/src/Main.res new file mode 100644 index 0000000000..3b0c82647f --- /dev/null +++ b/rewatch/testrepo/packages/compiled-by-legacy/src/Main.res @@ -0,0 +1 @@ +let x = 1 \ No newline at end of file diff --git a/rewatch/testrepo/packages/compiled-by-legacy/src/Main.res.js b/rewatch/testrepo/packages/compiled-by-legacy/src/Main.res.js new file mode 100644 index 0000000000..618d7a44e8 --- /dev/null +++ b/rewatch/testrepo/packages/compiled-by-legacy/src/Main.res.js @@ -0,0 +1,9 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +let x = 1; + +export { + x, +} +/* No side effect */ diff --git a/rewatch/testrepo/packages/main/package.json b/rewatch/testrepo/packages/main/package.json index 10954e0797..1813de299d 100644 --- a/rewatch/testrepo/packages/main/package.json +++ b/rewatch/testrepo/packages/main/package.json @@ -12,6 +12,7 @@ "author": "", "license": "MIT", "dependencies": { + "@testrepo/compiled-by-legacy": "*", "@testrepo/dep01": "*" } } diff --git a/rewatch/testrepo/yarn.lock b/rewatch/testrepo/yarn.lock index ac41b3d2c1..beb6bf912d 100644 --- a/rewatch/testrepo/yarn.lock +++ b/rewatch/testrepo/yarn.lock @@ -40,6 +40,12 @@ __metadata: languageName: node linkType: hard +"@testrepo/compiled-by-legacy@npm:*, @testrepo/compiled-by-legacy@workspace:packages/compiled-by-legacy": + version: 0.0.0-use.local + resolution: "@testrepo/compiled-by-legacy@workspace:packages/compiled-by-legacy" + languageName: unknown + linkType: soft + "@testrepo/dep01@npm:*, @testrepo/dep01@workspace:packages/dep01": version: 0.0.0-use.local resolution: "@testrepo/dep01@workspace:packages/dep01" @@ -58,6 +64,7 @@ __metadata: version: 0.0.0-use.local resolution: "@testrepo/main@workspace:packages/main" dependencies: + "@testrepo/compiled-by-legacy": "npm:*" "@testrepo/dep01": "npm:*" languageName: unknown linkType: soft diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index fd035bf902..a465933c9e 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -33,32 +33,32 @@ fi node ./packages/main/src/Main.mjs > ./packages/main/src/output.txt mv ./packages/main/src/Main.res ./packages/main/src/Main2.res -rewatch build &> ../tests/snapshots/rename-file.txt +rewatch build --snapshot-output &> ../tests/snapshots/rename-file.txt 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 +rewatch build --snapshot-output &> ../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 +rewatch build --snapshot-output &> ../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 +rewatch build --snapshot-output &> ../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 +rewatch build --snapshot-output &> ../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 @@ -66,7 +66,7 @@ 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 +rewatch build --snapshot-output &> ../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 @@ -74,7 +74,7 @@ rewatch build &> /dev/null # it should show an error when we have a dependency cycle echo 'Dep01.log()' >> packages/new-namespace/src/NS_alias.res -rewatch build &> ../tests/snapshots/dependency-cycle.txt +rewatch build --snapshot-output &> ../tests/snapshots/dependency-cycle.txt git checkout -- packages/new-namespace/src/NS_alias.res # it should compile dev dependencies with the --dev flag @@ -87,21 +87,23 @@ then fi file_count=$(find ./packages/with-dev-deps/test -name *.mjs | wc -l) -if [ "$file_count" -eq 1 ]; +expected_file_count=1 +if [ "$file_count" -eq $expected_file_count ]; then success "Compiled dev dependencies successfully" else - error "Expected 2 files to be compiled with the --dev flag, found $file_count" + error "Expected $expected_file_count files to be compiled with the --dev flag, found $file_count" exit 1 fi -rewatch clean --dev &> /dev/null +error_output=$(rewatch clean 2>&1 >/dev/null) file_count=$(find ./packages/with-dev-deps -name *.mjs | wc -l) if [ "$file_count" -eq 0 ]; then success "Cleaned dev dependencies successfully" else error "Expected 0 files remaining after cleaning, found $file_count" + printf "%s\n" "$error_output" >&2 exit 1 fi diff --git a/rewatch/tests/legacy-utils.sh b/rewatch/tests/legacy-utils.sh new file mode 100644 index 0000000000..3899df52c8 --- /dev/null +++ b/rewatch/tests/legacy-utils.sh @@ -0,0 +1,3 @@ +source "utils.sh" + +rewatch_legacy() { RUST_BACKTRACE=1 "../../$REWATCH_EXECUTABLE" legacy $@; } \ No newline at end of file diff --git a/rewatch/tests/legacy.sh b/rewatch/tests/legacy.sh new file mode 100755 index 0000000000..3a350c2a3a --- /dev/null +++ b/rewatch/tests/legacy.sh @@ -0,0 +1,52 @@ +source "./legacy-utils.sh" +cd ../testrepo/packages/compiled-by-legacy + +bold "Test: It should use the legacy build system" + +error_output=$(rewatch_legacy 2>&1 >/dev/null) +if [ $? -ne 0 ]; +then + error "Error running rewatch legacy" + echo $error_output + exit 1 +fi + +error_output=$(rewatch_legacy clean 2>&1 >/dev/null) +file_count=$(find . -name "*.res.js" | wc -l) +if [ $? -eq 0 ] && [ $file_count -eq 0 ]; +then + success "Test package cleaned" +else + error "Error cleaning test package. File count was $file_count." + echo $error_output + exit 1 +fi + +error_output=$(rewatch_legacy build 2>&1 >/dev/null) +if [ $? -eq 0 ]; +then + success "Test package built" +else + error "Error building test package" + echo $error_output + exit 1 +fi + +if git diff --exit-code ./; +then + success "Test package has no changes" +else + error "Build has changed" + exit 1 +fi + +error_output=$(rewatch_legacy format -all 2>&1 >/dev/null) +git_diff_file_count=$(git diff --name-only ./ | wc -l) +if [ $? -eq 0 ] && [ $git_diff_file_count -eq 1 ]; +then + success "Test package formatted. Got $git_diff_file_count changed files." +else + error "Error formatting test package" + echo $error_output + exit 1 +fi \ No newline at end of file diff --git a/rewatch/tests/snapshots/dependency-cycle.txt b/rewatch/tests/snapshots/dependency-cycle.txt index c949d4005c..c6d7f793e8 100644 --- a/rewatch/tests/snapshots/dependency-cycle.txt +++ b/rewatch/tests/snapshots/dependency-cycle.txt @@ -1,4 +1,4 @@ -Cleaned 0/14 +Cleaned 0/15 Parsed 1 source files Compiled 0 modules diff --git a/rewatch/tests/snapshots/remove-file.txt b/rewatch/tests/snapshots/remove-file.txt index 921f9d4246..8d68cdd418 100644 --- a/rewatch/tests/snapshots/remove-file.txt +++ b/rewatch/tests/snapshots/remove-file.txt @@ -1,4 +1,4 @@ -Cleaned 1/14 +Cleaned 1/15 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 1950bad9e3..3263c0fe88 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 @@ -Cleaned 2/14 +Cleaned 2/15 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 f81a6dece4..829a187871 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep.txt @@ -1,4 +1,4 @@ -Cleaned 2/14 +Cleaned 2/15 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 257fba3570..e784d71b9e 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 -Cleaned 2/14 +Cleaned 2/15 Parsed 1 source files Compiled 2 modules diff --git a/rewatch/tests/snapshots/rename-file.txt b/rewatch/tests/snapshots/rename-file.txt index 5b20d86fd7..5458530d74 100644 --- a/rewatch/tests/snapshots/rename-file.txt +++ b/rewatch/tests/snapshots/rename-file.txt @@ -1,3 +1,3 @@ -Cleaned 1/14 +Cleaned 1/15 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 e2d7fd9752..26d7ffe3e6 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 -Cleaned 1/14 +Cleaned 1/15 Parsed 1 source files Compiled 2 modules diff --git a/rewatch/tests/suffix.sh b/rewatch/tests/suffix.sh index 3768005297..d644a34e99 100755 --- a/rewatch/tests/suffix.sh +++ b/rewatch/tests/suffix.sh @@ -27,7 +27,7 @@ fi # Count files with new extension file_count=$(find ./packages -name *.res.js | wc -l) -if [ "$file_count" -eq 24 ]; +if [ "$file_count" -eq 26 ]; then success "Found files with correct suffix" else diff --git a/rewatch/tests/suite-ci.sh b/rewatch/tests/suite-ci.sh index d36319b988..fd5f11544b 100755 --- a/rewatch/tests/suite-ci.sh +++ b/rewatch/tests/suite-ci.sh @@ -8,10 +8,13 @@ cd $(dirname $0) # Get rewatch executable location from the first argument or use default if [ -n "$1" ]; then REWATCH_EXECUTABLE="$1" + BSC_PATH="" else - REWATCH_EXECUTABLE="../target/release/rewatch --bsc-path ../../_build/install/default/bin/bsc" + REWATCH_EXECUTABLE="../target/release/rewatch" + BSC_PATH="--bsc-path ../../_build/install/default/bin/bsc" fi export REWATCH_EXECUTABLE +export BSC_PATH source ./utils.sh @@ -37,4 +40,4 @@ else exit 1 fi -./compile.sh && ./watch.sh && ./lock.sh && ./suffix.sh +./compile.sh && ./watch.sh && ./lock.sh && ./suffix.sh && ./legacy.sh diff --git a/rewatch/tests/utils.sh b/rewatch/tests/utils.sh index 1dffbe8a8d..44a22ba0e3 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 --snapshot-output=true $@; } -rewatch_bg() { RUST_BACKTRACE=1 nohup $REWATCH_EXECUTABLE --no-timing=true --snapshot-output=true $@; } +rewatch() { RUST_BACKTRACE=1 $REWATCH_EXECUTABLE $@ $BSC_PATH; } +rewatch_bg() { RUST_BACKTRACE=1 nohup $REWATCH_EXECUTABLE $@ $BSC_PATH; } # Detect if running on Windows is_windows() {