Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ cargo install --git https://github.com/uqbar-dao/uqdev
## Usage

```bash
# Create a new package template (default Rust):
# Create a Rust package template (default no UI):
uqdev new my_package

# Build the package ("--ui" is optional):
uqdev build my_package --ui
# Build the package:
uqdev build my_package

# Start a fake node, by default, on port 8080:
uqdev boot-fake-node
Expand All @@ -38,16 +38,22 @@ uqdev start-package my_package --url http://localhost:8080

# Or build, start a node, and start a package from inside the project...
cd my_package
uqdev build --ui
uqdev build
uqdev boot-fake-node
uqdev start-package -u http://localhost:8080

# Create a Python package template (it `build`s & `start-package`s just like a Rust package!):
# Bonus: create a Python package template (it `build`s & `start-package`s just like a Rust package!):
uqdev new my_py_package -l python
cd my_py_package
uqdev build
uqdev start-package -u http://localhost:8080

# Bonus: create a Rust package template with UI (it `build`s & `start-package`s just like a Rust package!):
uqdev new my_package_with_ui --ui
cd my_package_with_ui
uqdev build
uqdev start-package -u http://localhost:8080

# Print usage

uqdev --help
Expand Down
127 changes: 72 additions & 55 deletions src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,61 +46,6 @@ pub async fn download_file(url: &str, path: &Path) -> anyhow::Result<()> {
Ok(())
}

pub fn compile_and_copy_ui(package_dir: &Path, verbose: bool) -> anyhow::Result<()> {
let ui_path = package_dir.join("ui");
println!("Building UI in {:?}...", ui_path);

if ui_path.exists() && ui_path.is_dir() && ui_path.join("package.json").exists() {
println!("UI directory found, running npm install...");

// Set the current directory to 'ui_path' for the command
run_command(Command::new("npm")
.arg("install")
.current_dir(&ui_path) // Set the working directory
.stdout(if verbose { Stdio::inherit() } else { Stdio::null() })
.stderr(if verbose { Stdio::inherit() } else { Stdio::null() })
)?;

println!("Running npm run build:copy...");

// Similarly for 'npm run build:copy'
run_command(Command::new("npm")
.args(["run", "build:copy"])
.current_dir(&ui_path) // Set the working directory
.stdout(if verbose { Stdio::inherit() } else { Stdio::null() })
.stderr(if verbose { Stdio::inherit() } else { Stdio::null() })
)?;
} else {
println!("'ui' directory not found or 'ui/package.json' does not exist");
}

Ok(())
}

pub async fn compile_package_and_ui(package_dir: &Path, verbose: bool) -> anyhow::Result<()> {
compile_package(package_dir, verbose).await?;
compile_and_copy_ui(package_dir, verbose)?;
Ok(())
}

pub async fn compile_package(package_dir: &Path, verbose: bool) -> anyhow::Result<()> {
let rust_src_path = "src/lib.rs";
let python_src_path = "src/lib.py";
for entry in package_dir.read_dir()? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
if path.join(&rust_src_path).exists() {
compile_rust_wasm_process(&path, verbose).await?;
} else if path.join(&python_src_path).exists() {
compile_python_wasm_process(&path, verbose).await?;
}
}
}

Ok(())
}

async fn compile_python_wasm_process(
process_dir: &Path,
verbose: bool,
Expand Down Expand Up @@ -249,3 +194,75 @@ async fn compile_rust_wasm_process(
println!("Done compiling Rust Uqbar process in {:?}.", process_dir);
Ok(())
}

fn compile_and_copy_ui(package_dir: &Path, verbose: bool) -> anyhow::Result<()> {
let ui_path = package_dir.join("ui");
println!("Building UI in {:?}...", ui_path);

if ui_path.exists() && ui_path.is_dir() && ui_path.join("package.json").exists() {
println!("UI directory found, running npm install...");

// Set the current directory to 'ui_path' for the command
run_command(Command::new("npm")
.arg("install")
.current_dir(&ui_path) // Set the working directory
.stdout(if verbose { Stdio::inherit() } else { Stdio::null() })
.stderr(if verbose { Stdio::inherit() } else { Stdio::null() })
)?;

println!("Running npm run build:copy...");

// Similarly for 'npm run build:copy'
run_command(Command::new("npm")
.args(["run", "build:copy"])
.current_dir(&ui_path) // Set the working directory
.stdout(if verbose { Stdio::inherit() } else { Stdio::null() })
.stderr(if verbose { Stdio::inherit() } else { Stdio::null() })
)?;
} else {
println!("'ui' directory not found or 'ui/package.json' does not exist");
}

Ok(())
}

async fn compile_package_and_ui(package_dir: &Path, verbose: bool) -> anyhow::Result<()> {
compile_package(package_dir, verbose).await?;
compile_and_copy_ui(package_dir, verbose)?;
Ok(())
}

async fn compile_package(package_dir: &Path, verbose: bool) -> anyhow::Result<()> {
let rust_src_path = "src/lib.rs";
let python_src_path = "src/lib.py";
for entry in package_dir.read_dir()? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
if path.join(&rust_src_path).exists() {
compile_rust_wasm_process(&path, verbose).await?;
} else if path.join(&python_src_path).exists() {
compile_python_wasm_process(&path, verbose).await?;
}
}
}

Ok(())
}

pub async fn execute(package_dir: &Path, ui_only: bool, verbose: bool) -> anyhow::Result<()> {
let ui_dir = package_dir.join("ui");
if !ui_dir.exists() {
if ui_only {
return Err(anyhow::anyhow!("uqdev build: can't build UI: no ui directory exists"));
} else {
compile_package(package_dir, verbose).await
}
} else {
if ui_only {
compile_and_copy_ui(package_dir, verbose)
} else {
compile_package_and_ui(package_dir, verbose).await
}
}
}
23 changes: 9 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,10 @@ async fn execute(
},
Some(("build", build_matches)) => {
let package_dir = PathBuf::from(build_matches.get_one::<String>("DIR").unwrap());
let ui = build_matches.get_one::<bool>("UI").unwrap_or(&false);
let ui_only = build_matches.get_one::<bool>("UI_ONLY").unwrap_or(&false);
let verbose = !build_matches.get_one::<bool>("QUIET").unwrap();

if *ui_only {
build::compile_and_copy_ui(&package_dir, verbose)
} else if *ui {
build::compile_package_and_ui(&package_dir, verbose).await
} else {
build::compile_package(&package_dir, verbose).await
}
build::execute(&package_dir, *ui_only, verbose).await
},
Some(("inject-message", inject_message_matches)) => {
let url: &String = inject_message_matches.get_one("URL").unwrap();
Expand All @@ -75,13 +68,15 @@ async fn execute(
let publisher = new_matches.get_one::<String>("PUBLISHER").unwrap();
let language: new::Language = new_matches.get_one::<String>("LANGUAGE").unwrap().into();
let template: new::Template = new_matches.get_one::<String>("TEMPLATE").unwrap().into();
let ui = new_matches.get_one::<bool>("UI").unwrap_or(&false);

new::execute(
new_dir,
package_name.to_string(),
publisher.clone(),
language.clone(),
template.clone(),
*ui,
)
},
Some(("run-tests", run_tests_matches)) => {
Expand Down Expand Up @@ -203,12 +198,6 @@ async fn main() -> anyhow::Result<()> {
.help("The package directory to build")
.default_value(&current_dir)
)
.arg(Arg::new("UI")
.action(ArgAction::SetTrue)
.long("ui")
.help("If set, build the web UI for the process")
.required(false)
)
.arg(Arg::new("UI_ONLY")
.action(ArgAction::SetTrue)
.long("ui-only")
Expand Down Expand Up @@ -297,6 +286,12 @@ async fn main() -> anyhow::Result<()> {
.value_parser(["chat"])
.default_value("chat")
)
.arg(Arg::new("UI")
.action(ArgAction::SetTrue)
.long("ui")
.help("If set, use the template with UI")
.required(false)
)
)
.subcommand(Command::new("run-tests")
.about("Run Uqbar tests")
Expand Down
23 changes: 22 additions & 1 deletion src/new/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub fn execute(
publisher: String,
language: Language,
template: Template,
ui: bool,
) -> anyhow::Result<()> {
// Check if the directory already exists
if new_dir.exists() {
Expand All @@ -66,12 +67,24 @@ pub fn execute(
return Err(anyhow::anyhow!(error));
}

let template_prefix = format!("{}/{}/", language.to_string(), template.to_string());
let ui_infix = if ui { "ui".to_string() } else { "no-ui".to_string() };
let template_prefix = format!(
"{}/{}/{}/",
language.to_string(),
ui_infix,
template.to_string(),
);
let ui_prefix = format!(
"{}/{}/",
ui_infix,
template.to_string(),
);
let path_to_content: HashMap<String, String> = PATH_TO_CONTENT
.iter()
.filter_map(|(k, v)| {
k
.strip_prefix(&template_prefix)
.or_else(|| k.strip_prefix(&ui_prefix))
.and_then(|stripped| {
let key = stripped
.replace("{package_name}", &package_name)
Expand All @@ -84,6 +97,14 @@ pub fn execute(
})
})
.collect();
if ui && path_to_content.keys().filter(|p| !p.starts_with("ui")).count() == 0 {
// Only `ui/` exists
return Err(anyhow::anyhow!(
"uqdev new: cannot use `--ui` for {} {}; template does not exist",
language.to_string(),
template.to_string(),
));
}

// Create the template directory and subdirectories
path_to_content
Expand Down
23 changes: 23 additions & 0 deletions src/new/templates/rust/no-ui/chat/{package_name}/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "{package_name}"
version = "0.1.0"
edition = "2021"

[profile.release]
panic = "abort"
opt-level = "s"
lto = true

[dependencies]
anyhow = "1.0"
bincode = "1.3.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "e75fec6" }
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }

[lib]
crate-type = ["cdylib"]

[package.metadata.component]
package = "uqbar:process"
Loading