Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/loam-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,12 @@ rust-embed = { version = "8.2.0", features = ["debug-embed"] }
regex = "1.10.5"
toml_edit = "0.22.16"
indexmap = { version = "1.9", features = ["serde"] }
tempfile = "3.8"
fs_extra = "1.3"

[dev-dependencies]
assert_cmd = "2.0.4"
assert_fs = "1.0.7"
fs_extra = "1.3.0"
predicates = "3.1.0"
walkdir = "2.3"

Expand Down
52 changes: 45 additions & 7 deletions crates/loam-cli/src/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use clap::Parser;
use rust_embed::{EmbeddedFile, RustEmbed};
use soroban_cli::commands::contract::init as soroban_init;
use std::{
fs::{self, create_dir_all, metadata, read_to_string, remove_dir_all, write, Metadata},
fs::{self, create_dir_all, metadata, read_to_string, write, Metadata},
io,
path::{Path, PathBuf},
process::Command,
};
use tempfile::TempDir;
use toml_edit::{DocumentMut, TomlError};

const FRONTEND_TEMPLATE: &str = "https://github.com/loambuild/frontend";
Expand Down Expand Up @@ -58,17 +60,20 @@ impl Cmd {
project_path: self.project_path.to_string_lossy().to_string(),
name: self.name.clone(),
with_example: None,
frontend_template: Some(FRONTEND_TEMPLATE.to_string()),
overwrite: true,
frontend_template: None,
}
.run(&soroban_cli::commands::global::Args::default())?;

// remove soroban hello_world default contract
remove_dir_all(self.project_path.join("contracts/hello_world/")).map_err(|e| {
eprintln!("Error removing directory");
e
// Clone frontend template
let fe_template_dir = tempfile::tempdir().map_err(|e| {
eprintln!("Error creating temp dir for frontend template");
Error::IoError(e)
})?;

clone_repo(FRONTEND_TEMPLATE, fe_template_dir.path())?;
copy_frontend_files(&fe_template_dir, &self.project_path)?;

copy_example_contracts(&self.project_path)?;
rename_cargo_toml_remove(&self.project_path, "core")?;
rename_cargo_toml_remove(&self.project_path, "status_message")?;
Expand Down Expand Up @@ -160,7 +165,6 @@ fn copy_file(
Ok(())
}

// TODO: import from stellar-cli init (not currently pub there)
fn file_exists(file_path: &Path) -> bool {
metadata(file_path)
.as_ref()
Expand All @@ -175,3 +179,37 @@ fn rename_cargo_toml_remove(project: &Path, name: &str) -> Result<(), Error> {
fs::rename(from, to)?;
Ok(())
}

fn clone_repo(repo_url: &str, dest: &Path) -> Result<(), Error> {
let status = Command::new("git")
.args(["clone", repo_url, dest.to_str().unwrap()])
.status()
.map_err(|e| {
eprintln!("Error executing git clone");
Error::IoError(e)
})?;

if !status.success() {
return Err(Error::IoError(io::Error::new(
io::ErrorKind::Other,
"Failed to clone repository",
)));
}
Ok(())
}

fn copy_frontend_files(temp_dir: &TempDir, project_path: &Path) -> Result<(), Error> {
fs_extra::dir::copy(
temp_dir.path(),
project_path,
&fs_extra::dir::CopyOptions::new()
.content_only(true)
.overwrite(true),
)
.map_err(|e| {
eprintln!("Error copying frontend files");
Error::IoError(io::Error::new(io::ErrorKind::Other, e.to_string()))
})?;

Ok(())
}
32 changes: 32 additions & 0 deletions crates/loam-cli/tests/it/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,35 @@ soroban_token_contract.client = false
assert!(stderr.contains("🌐 using network at http://localhost:8000/rpc\n"));
});
}

#[test]
fn init_copies_contracts_and_frontend_template() {
let env = TestEnv::new_empty();

// Run loam init with project path
let project_path = env.cwd.join("my-project");
env.loam("init")
.args([project_path.to_str().unwrap()])
.assert()
.success();
// Verify contract files exist
assert!(project_path.join("contracts/core/src/lib.rs").exists());
assert!(project_path
.join("contracts/status_message/src/lib.rs")
.exists());
assert!(project_path.join("contracts/core/Cargo.toml").exists());
assert!(project_path
.join("contracts/status_message/Cargo.toml")
.exists());

// Verify frontend template files exist
assert!(project_path.join("package.json").exists());
assert!(project_path.join("src").exists());
assert!(project_path.join("tsconfig.json").exists());

// Verify Cargo.toml contains loam dependencies
let cargo_toml = std::fs::read_to_string(project_path.join("Cargo.toml"))
.expect("Should be able to read Cargo.toml");
assert!(cargo_toml.contains("loam-sdk"));
assert!(cargo_toml.contains("loam-subcontract-core"));
}
8 changes: 8 additions & 0 deletions crates/loam-cli/tests/it/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ impl TestEnv {
}
}

pub fn new_empty() -> Self {
let temp_dir = TempDir::new().unwrap();
Self {
cwd: temp_dir.path().to_path_buf(),
temp_dir,
}
}

pub fn from<F: FnOnce(&TestEnv)>(template: &str, f: F) {
let test_env = TestEnv::new(template);
f(&test_env);
Expand Down
Loading