Skip to content

Commit

Permalink
new: Only load project package.json and tsconfig.json once. (#163)
Browse files Browse the repository at this point in the history
* Start.

* Move other calls.

* Convert tsconfig.

* Enable moon workflow.

* Enable when rust changes.

* Only use once cell.

* Add track caller.
  • Loading branch information
milesj committed Jun 27, 2022
1 parent 215033b commit be0d7a3
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 58 deletions.
19 changes: 0 additions & 19 deletions .github/workflows/moon-stub.yml

This file was deleted.

4 changes: 4 additions & 0 deletions .github/workflows/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ on:
- master
pull_request:
paths:
- .github/workflows/moon.yml
- .moon/workspace.yml
- .moon/project.yml
- crates/**
- packages/**
- website/**
- package.json
Expand Down
1 change: 1 addition & 0 deletions crates/project/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ petgraph = "0.6.0"
serde = { version = "1.0.137", features = ["derive"] }
serde_json = { version = "1.0.81", features = ["preserve_order"] }
thiserror = "1.0.31"
tokio = { version = "1.18.2", features = ["full"] }

[dev-dependencies]
insta = "1.14.0"
Expand Down
109 changes: 84 additions & 25 deletions crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use moon_utils::path;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use tokio::sync::OnceCell;

pub type FileGroupsMap = HashMap<String, FileGroup>;

Expand Down Expand Up @@ -222,7 +223,7 @@ fn create_tasks_from_config(
Ok(tasks)
}

#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Project {
/// Project configuration loaded from "project.yml", if it exists.
Expand All @@ -238,6 +239,10 @@ pub struct Project {
#[serde(skip)]
pub log_target: String,

// The `package.json` in the project root.
#[serde(skip)]
pub package_json: OnceCell<PackageJson>,

/// Absolute path to the project's root folder.
pub root: PathBuf,

Expand All @@ -246,6 +251,37 @@ pub struct Project {

/// Tasks specific to the project. Inherits all tasks from the global config.
pub tasks: TasksMap,

// The `tsconfig.json` in the project root.
#[serde(skip)]
pub tsconfig_json: OnceCell<TsConfigJson>,
}

impl Default for Project {
fn default() -> Self {
Project {
config: None,
file_groups: HashMap::new(),
id: String::new(),
log_target: String::new(),
package_json: OnceCell::new(),
root: PathBuf::new(),
source: String::new(),
tasks: HashMap::new(),
tsconfig_json: OnceCell::new(),
}
}
}

impl PartialEq for Project {
fn eq(&self, other: &Self) -> bool {
self.config == other.config
&& self.file_groups == other.file_groups
&& self.id == other.id
&& self.root == other.root
&& self.source == other.source
&& self.tasks == other.tasks
}
}

impl Logable for Project {
Expand Down Expand Up @@ -293,9 +329,11 @@ impl Project {
file_groups,
id: String::from(id),
log_target,
package_json: OnceCell::new(),
root,
source: String::from(source),
tasks,
tsconfig_json: OnceCell::new(),
})
}

Expand All @@ -314,7 +352,9 @@ impl Project {

/// Return the "package.json" name, if the file exists.
pub async fn get_package_name(&self) -> Result<Option<String>, ProjectError> {
if let Some(json) = self.load_package_json().await? {
self.load_package_json().await?;

if let Some(json) = self.package_json.get() {
if let Some(name) = &json.name {
return Ok(Some(name.clone()));
}
Expand All @@ -335,48 +375,67 @@ impl Project {
}

/// Load and parse the package's `package.json` if it exists.
pub async fn load_package_json(&self) -> Result<Option<PackageJson>, ProjectError> {
let package_path = self.root.join("package.json");
#[track_caller]
pub async fn load_package_json(&self) -> Result<bool, ProjectError> {
if self.package_json.initialized() {
return Ok(true);
}

trace!(
target: self.get_log_target(),
"Attempting to find {} in {}",
color::file("package.json"),
color::path(&self.root),
);
let package_path = self.root.join("package.json");

if package_path.exists() {
trace!(
target: self.get_log_target(),
"Loading {} in {}",
color::file("package.json"),
color::path(&self.root),
);

return match PackageJson::load(&package_path).await {
Ok(cfg) => Ok(Some(cfg)),
Ok(json) => {
self.package_json
.set(json)
.expect("Failed to load package.json");

Ok(true)
}
Err(error) => Err(ProjectError::Moon(error)),
};
}

Ok(None)
Ok(false)
}

/// Load and parse the package's `tsconfig.json` if it exists.
pub async fn load_tsconfig_json(
&self,
tsconfig_name: &str,
) -> Result<Option<TsConfigJson>, ProjectError> {
let tsconfig_path = self.root.join(tsconfig_name);
#[track_caller]
pub async fn load_tsconfig_json(&self, tsconfig_name: &str) -> Result<bool, ProjectError> {
if self.tsconfig_json.initialized() {
return Ok(true);
}

trace!(
target: self.get_log_target(),
"Attempting to find {} in {}",
color::file(tsconfig_name),
color::path(&self.root),
);
let tsconfig_path = self.root.join(tsconfig_name);

if tsconfig_path.exists() {
trace!(
target: self.get_log_target(),
"Loading {} in {}",
color::file(tsconfig_name),
color::path(&self.root),
);

return match TsConfigJson::load(&tsconfig_path).await {
Ok(cfg) => Ok(Some(cfg)),
Ok(json) => {
self.tsconfig_json
.set(json)
.expect("Failed to load tsconfig.json");

Ok(true)
}
Err(error) => Err(ProjectError::Moon(error)),
};
}

Ok(None)
Ok(false)
}

/// Return the project as a JSON string.
Expand Down
4 changes: 3 additions & 1 deletion crates/project/tests/project_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,10 @@ async fn has_package_json() {
)
.unwrap();

project.load_package_json().await.unwrap();

assert_eq!(
project.load_package_json().await.unwrap().unwrap(),
*project.package_json.get().unwrap(),
PackageJson {
path: workspace_root.join("projects/package-json/package.json"),
name: Some(String::from("npm-example")),
Expand Down
16 changes: 9 additions & 7 deletions crates/workspace/src/actions/hashing/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,17 @@ pub async fn create_target_hasher(
}

// Hash project configs second so they can override
if let Some(package) = project.load_package_json().await? {
hasher.hash_package_json(&package);
project.load_package_json().await?;
project
.load_tsconfig_json(&workspace.config.typescript.project_config_file_name)
.await?;

if let Some(package) = project.package_json.get() {
hasher.hash_package_json(package);
}

if let Some(tsconfig) = project
.load_tsconfig_json(&workspace.config.typescript.project_config_file_name)
.await?
{
hasher.hash_tsconfig_json(&tsconfig);
if let Some(tsconfig) = project.tsconfig_json.get() {
hasher.hash_tsconfig_json(tsconfig);
}

// For input files, hash them with the vcs layer first
Expand Down
13 changes: 7 additions & 6 deletions crates/workspace/src/actions/sync_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,26 @@ pub async fn sync_project(
// Read only
{
let workspace = workspace.read().await;
let project = workspace.projects.load(project_id)?;
let mut project = workspace.projects.load(project_id)?;
let node_config = &workspace.config.node;

// Copy values outside of this block
typescript_config = workspace.config.typescript.clone();

// Sync each dependency to `tsconfig.json` and `package.json`
let package_manager = workspace.toolchain.get_node().get_package_manager();
let mut project_package_json = project.load_package_json().await?;
let mut project_tsconfig_json = project
project.load_package_json().await?;
project
.load_tsconfig_json(&typescript_config.project_config_file_name)
.await?;

let package_manager = workspace.toolchain.get_node().get_package_manager();

for dep_id in project.get_dependencies() {
let dep_project = workspace.projects.load(&dep_id)?;

// Update `dependencies` within this project's `package.json`
if node_config.sync_project_workspace_dependencies {
if let Some(package_json) = &mut project_package_json {
if let Some(package_json) = project.package_json.get_mut() {
let dep_package_name =
dep_project.get_package_name().await?.unwrap_or_default();

Expand Down Expand Up @@ -93,7 +94,7 @@ pub async fn sync_project(

// Update `references` within this project's `tsconfig.json`
if typescript_config.sync_project_references {
if let Some(tsconfig_json) = &mut project_tsconfig_json {
if let Some(tsconfig_json) = project.tsconfig_json.get_mut() {
let tsconfig_branch_name = &typescript_config.project_config_file_name;
let dep_ref_path = String::from(
diff_paths(&dep_project.root, &project.root)
Expand Down

0 comments on commit be0d7a3

Please sign in to comment.