Skip to content

Commit

Permalink
feat: forc command to init/new workspace (FuelLabs#3418)
Browse files Browse the repository at this point in the history
  • Loading branch information
kayagokalp authored Nov 30, 2022
1 parent 7bd2c63 commit 01f2a71
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 22 deletions.
2 changes: 2 additions & 0 deletions docs/src/forc/workspaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Workspace manifests are declared within `Forc.toml` files and support the follow

* [`members`](#the-members-field) - Packages to include in the workspace.

An empty workspace can be created with `forc new --workspace` or `forc init --workspace`.

## The `members` field

The `members` field defines which packages are members of the workspace:
Expand Down
4 changes: 4 additions & 0 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2444,6 +2444,10 @@ pub fn build_with_options(build_options: BuildOpts) -> Result<Built> {

let manifest_file = ManifestFile::from_dir(&this_dir)?;
let member_manifests = manifest_file.member_manifests()?;
// Check if we have members to build so that we are not trying to build an empty workspace.
if member_manifests.is_empty() {
bail!("No member found to build")
}
let lock_path = manifest_file.lock_path()?;
let build_plan = BuildPlan::from_lock_and_manifests(
&lock_path,
Expand Down
3 changes: 3 additions & 0 deletions forc/src/cli/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub struct Command {
/// Create a package with a library target (src/lib.sw).
#[clap(long)]
pub library: bool,
/// Adding this flag creates an empty workspace.
#[clap(long)]
pub workspace: bool,
/// Set the package name. Defaults to the directory name
#[clap(long)]
pub name: Option<String>,
Expand Down
5 changes: 5 additions & 0 deletions forc/src/cli/commands/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub struct Command {
/// Adding this flag creates an empty library program.
#[clap(long)]
pub library: bool,
/// Adding this flag creates an empty workspace.
#[clap(long)]
pub workspace: bool,
/// Set the package name. Defaults to the directory name
#[clap(long)]
pub name: Option<String>,
Expand All @@ -35,6 +38,7 @@ pub(crate) fn exec(command: Command) -> Result<()> {
script,
predicate,
library,
workspace,
name,
path,
} = command;
Expand All @@ -57,6 +61,7 @@ pub(crate) fn exec(command: Command) -> Result<()> {
script,
predicate,
library,
workspace,
name,
};

Expand Down
55 changes: 36 additions & 19 deletions forc/src/ops/forc_init.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::cli::InitCommand;
use crate::utils::{defaults, program_type::ProgramType::*};
use crate::utils::{defaults, program_type::ProgramType};
use anyhow::{Context, Result};
use forc_util::validate_name;
use std::fs;
Expand All @@ -8,6 +8,12 @@ use std::path::{Path, PathBuf};
use sway_utils::constants;
use tracing::{debug, info};

#[derive(Debug)]
enum InitType {
Package(ProgramType),
Workspace,
}

fn print_welcome_message() {
let read_the_docs = format!(
"Read the Docs:\n- {}\n- {}\n- {}",
Expand Down Expand Up @@ -70,62 +76,73 @@ pub fn init(command: InitCommand) -> Result<()> {

validate_name(&project_name, "project name")?;

let program_type = match (
let init_type = match (
command.contract,
command.script,
command.predicate,
command.library,
command.workspace,
) {
(_, false, false, false) => Contract,
(false, true, false, false) => Script,
(false, false, true, false) => Predicate,
(false, false, false, true) => Library,
(_, false, false, false, false) => InitType::Package(ProgramType::Contract),
(false, true, false, false, false) => InitType::Package(ProgramType::Script),
(false, false, true, false, false) => InitType::Package(ProgramType::Predicate),
(false, false, false, true, false) => InitType::Package(ProgramType::Library),
(false, false, false, false, true) => InitType::Workspace,
_ => anyhow::bail!(
"Multiple types detected, please specify only one program type: \
\n Possible Types:\n - contract\n - script\n - predicate\n - library"
"Multiple types detected, please specify only one initialization type: \
\n Possible Types:\n - contract\n - script\n - predicate\n - library\n - workspace"
),
};

// Make a new directory for the project
fs::create_dir_all(Path::new(&project_dir).join("src"))?;
let dir_to_create = match init_type {
InitType::Package(_) => project_dir.join("src"),
InitType::Workspace => project_dir.clone(),
};
fs::create_dir_all(dir_to_create)?;

// Insert default manifest file
match program_type {
Library => fs::write(
match init_type {
InitType::Workspace => fs::write(
Path::new(&project_dir).join(constants::MANIFEST_FILE_NAME),
defaults::default_workspace_manifest(),
)?,
InitType::Package(ProgramType::Library) => fs::write(
Path::new(&project_dir).join(constants::MANIFEST_FILE_NAME),
defaults::default_manifest(&project_name, constants::LIB_ENTRY),
defaults::default_pkg_manifest(&project_name, constants::LIB_ENTRY),
)?,
_ => fs::write(
Path::new(&project_dir).join(constants::MANIFEST_FILE_NAME),
defaults::default_manifest(&project_name, constants::MAIN_ENTRY),
defaults::default_pkg_manifest(&project_name, constants::MAIN_ENTRY),
)?,
}

match program_type {
Contract => fs::write(
match init_type {
InitType::Package(ProgramType::Contract) => fs::write(
Path::new(&project_dir)
.join("src")
.join(constants::MAIN_ENTRY),
defaults::default_contract(),
)?,
Script => fs::write(
InitType::Package(ProgramType::Script) => fs::write(
Path::new(&project_dir)
.join("src")
.join(constants::MAIN_ENTRY),
defaults::default_script(),
)?,
Library => fs::write(
InitType::Package(ProgramType::Library) => fs::write(
Path::new(&project_dir)
.join("src")
.join(constants::LIB_ENTRY),
defaults::default_library(&project_name),
)?,
Predicate => fs::write(
InitType::Package(ProgramType::Predicate) => fs::write(
Path::new(&project_dir)
.join("src")
.join(constants::MAIN_ENTRY),
defaults::default_predicate(),
)?,
_ => {}
}

// Ignore default `out` and `target` directories created by forc and cargo.
Expand All @@ -143,7 +160,7 @@ pub fn init(command: InitCommand) -> Result<()> {
gitignore_path.canonicalize()?.display()
);

debug!("\nSuccessfully created {program_type}: {project_name}",);
debug!("\nSuccessfully created {init_type:?}: {project_name}",);

print_welcome_message();

Expand Down
19 changes: 16 additions & 3 deletions forc/src/utils/defaults.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// We intentionally don't construct this using [serde]'s default deserialization so we get
/// the chance to insert some helpful comments and nicer formatting.
pub(crate) fn default_manifest(project_name: &str, entry_type: &str) -> String {
pub(crate) fn default_pkg_manifest(project_name: &str, entry_type: &str) -> String {
let author = get_author();

format!(
Expand All @@ -15,6 +15,12 @@ name = "{project_name}"
)
}

pub(crate) fn default_workspace_manifest() -> String {
r#"[workspace]
members = []"#
.to_string()
}

pub(crate) fn default_contract() -> String {
r#"contract;
Expand Down Expand Up @@ -72,11 +78,18 @@ fn get_author() -> String {
}

#[test]
fn parse_default_manifest() {
fn parse_default_pkg_manifest() {
use sway_utils::constants::MAIN_ENTRY;
tracing::info!(
"{:#?}",
toml::from_str::<forc_pkg::PackageManifest>(&default_manifest("test_proj", MAIN_ENTRY))
toml::from_str::<forc_pkg::PackageManifest>(&default_pkg_manifest("test_proj", MAIN_ENTRY))
.unwrap()
)
}
#[test]
fn parse_default_workspace_manifest() {
tracing::info!(
"{:#?}",
toml::from_str::<forc_pkg::PackageManifest>(&default_workspace_manifest()).unwrap()
)
}

0 comments on commit 01f2a71

Please sign in to comment.