Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
* text=auto eol=lf

*.ml linguist-language=OCaml
*.mli linguist-language=OCaml
*.res linguist-language=ReScript
Expand Down
33 changes: 30 additions & 3 deletions cli/rewatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -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], {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need this branch? can we not just pass --bsc-path in both cases?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bsc-path is not a root level arg anymore

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be an option to use an env var BSC_PATH instead to avoid this problem?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea. Either that, or we promote --bsc-path to a root level argument again. If we decide for the env var would this be in addition to the arg?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking was that it would replace the arg. What's your opinion @jfrolich?

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
Expand Down
30 changes: 27 additions & 3 deletions rewatch/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -57,7 +59,7 @@ pub struct CompilerArgs {
pub fn get_compiler_args(
path: &Path,
rescript_version: Option<String>,
bsc_path: &Option<PathBuf>,
bsc_path: Option<PathBuf>,
build_dev_deps: bool,
) -> Result<String> {
let filename = &helpers::get_abs_path(path);
Expand Down Expand Up @@ -499,7 +501,7 @@ pub fn build(
show_progress: bool,
no_timing: bool,
create_sourcedirs: bool,
bsc_path: &Option<PathBuf>,
bsc_path: Option<PathBuf>,
build_dev_deps: bool,
snapshot_output: bool,
) -> Result<BuildState> {
Expand All @@ -514,7 +516,7 @@ pub fn build(
filter,
show_progress,
path,
bsc_path,
&bsc_path,
build_dev_deps,
snapshot_output,
)
Expand Down Expand Up @@ -551,3 +553,25 @@ pub fn build(
}
}
}

pub fn pass_through_legacy(mut args: Vec<OsString>) -> 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
}
}
}
8 changes: 4 additions & 4 deletions rewatch/src/build/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,7 @@ pub fn cleanup_after_build(build_state: &BuildState) {
pub fn clean(
path: &Path,
show_progress: bool,
bsc_path: &Option<PathBuf>,
build_dev_deps: bool,
bsc_path: Option<PathBuf>,
snapshot_output: bool,
) -> Result<()> {
let project_root = helpers::get_abs_path(path);
Expand All @@ -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 {
Expand Down
257 changes: 257 additions & 0 deletions rewatch/src/cli.rs
Original file line number Diff line number Diff line change
@@ -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<InfoLevel>,

/// The command to run. If not provided it will default to build.
#[command(subcommand)]
pub command: Option<Command>,

#[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<String>,
}

#[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<String>,
}

#[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<String>,
}

#[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<OsString>,
},
/// Alias to `legacy dump`.
#[command(disable_help_flag = true)]
Dump {
#[arg(allow_hyphen_values = true, num_args = 0..)]
dump_args: Vec<OsString>,
},
/// 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<String>,

#[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<OsString>,
},
}

impl Deref for FolderArg {
type Target = str;

fn deref(&self) -> &Self::Target {
&self.folder
}
}

impl Deref for FilterArg {
type Target = Option<String>;

fn deref(&self) -> &Self::Target {
&self.filter
}
}

impl Deref for AfterBuildArg {
type Target = Option<String>;

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<String>;

fn deref(&self) -> &Self::Target {
&self.bsc_path
}
}

impl Deref for SnapshotOutputArg {
type Target = bool;

fn deref(&self) -> &Self::Target {
&self.snapshot_output
}
}
Loading