Skip to content

Commit

Permalink
feat: add tman create command (#507)
Browse files Browse the repository at this point in the history
  • Loading branch information
halajohn authored Jan 5, 2025
1 parent d304517 commit 1361454
Show file tree
Hide file tree
Showing 16 changed files with 357 additions and 88 deletions.
7 changes: 3 additions & 4 deletions build/ten_runtime/feature/install_pkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,11 @@ def process_possible_published_results(file_paths: list[str]) -> list[str]:
args.src_pkg += f"@{versions[0]}"

cmd += [
"install",
"create",
args.pkg_type,
generated_app_name,
"--template",
args.src_pkg,
"--template-mode",
"--template-data",
f"package_name={generated_app_name}",
]

if args.build_type is not None:
Expand Down
28 changes: 0 additions & 28 deletions build/ten_runtime/feature/test.gni
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,6 @@ template("ten_package_test_prepare_app") {
rebase_path(install_app_dummy_output_file),
]

args += [ "--build-type" ]
if (is_debug) {
args += [ "debug" ]
} else {
args += [ "release" ]
}

args += [
"--config-file",
rebase_path("${root_out_dir}/tests/local_registry/config.json"),
Expand Down Expand Up @@ -196,13 +189,6 @@ template("ten_package_test_prepare_app") {
rebase_path(install_all_dummy_output_file),
]

args += [ "--build-type" ]
if (is_debug) {
args += [ "debug" ]
} else {
args += [ "release" ]
}

args += [
"--assume-yes",
"True",
Expand Down Expand Up @@ -625,13 +611,6 @@ template("ten_package_standalone_pkg") {
invoker.pkg_template,
]

args += [ "--build-type" ]
if (is_debug) {
args += [ "debug" ]
} else {
args += [ "release" ]
}

args += [
"--config-file",
rebase_path("${root_out_dir}/tests/local_registry/config.json"),
Expand Down Expand Up @@ -706,13 +685,6 @@ template("ten_package_standalone_pkg") {
rebase_path(install_all_dummy_output_file),
]

args += [ "--build-type" ]
if (is_debug) {
args += [ "debug" ]
} else {
args += [ "release" ]
}

args += [
"--assume-yes",
"True",
Expand Down
179 changes: 179 additions & 0 deletions core/src/ten_manager/src/cmd/cmd_create.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//
// Copyright © 2025 Agora
// This file is part of TEN Framework, an open source project.
// Licensed under the Apache License, Version 2.0, with certain conditions.
// Refer to the "LICENSE" file in the root directory for more information.
//
use std::{collections::HashMap, time::Instant};

use anyhow::{anyhow, Context, Result};
use clap::{Arg, ArgAction, ArgMatches, Command};
use console::Emoji;
use indicatif::HumanDuration;
use semver::VersionReq;

use ten_rust::pkg_info::{
pkg_type::PkgType,
supports::{Arch, Os, PkgSupport},
};

use crate::{
config::TmanConfig, create::create_pkg_in_path,
version_utils::parse_pkg_name_version_req,
};

#[derive(Debug)]
pub struct CreateCommand {
pub pkg_type: PkgType,
pub pkg_name: String,
pub support: PkgSupport,
pub template_name: String,
pub template_version_req: VersionReq,
pub template_data: HashMap<String, String>,
}

pub fn create_sub_cmd(args_cfg: &crate::cmd_line::ArgsCfg) -> Command {
Command::new("create")
.about("Create a package")
.arg(
Arg::new("PACKAGE_TYPE")
.help("The type of the package")
.value_parser(args_cfg.pkg_type.possible_values.clone())
.required(true),
)
.arg(
Arg::new("PACKAGE_NAME")
.help("The name of the package")
.required(true),
)
.arg(
Arg::new("OS")
.long("os")
.help("The operating system")
.value_parser(args_cfg.os.possible_values.clone())
.required(false),
)
.arg(
Arg::new("ARCH")
.long("arch")
.help("The CPU architecture")
.value_parser(args_cfg.arch.possible_values.clone())
.required(false),
)
.arg(
Arg::new("TEMPLATE")
.long("template")
.help("The template package to create from")
.required(true),
)
.arg(
Arg::new("TEMPLATE_DATA")
.long("template-data")
.help("The placeholders used within the template and their corresponding values. The format is key-value pairs, e.g., `--template-data key=value`")
.value_name("KEY=VALUE")
.action(ArgAction::Append),
)
}

pub fn parse_sub_cmd(sub_cmd_args: &ArgMatches) -> Result<CreateCommand> {
let pkg_type_str = sub_cmd_args
.get_one::<String>("PACKAGE_TYPE")
.cloned()
.ok_or_else(|| anyhow!("Missing required argument: PACKAGE_TYPE"))?;
let pkg_type = pkg_type_str
.parse::<PkgType>()
.context("Invalid PACKAGE_TYPE format")?;

let pkg_name = sub_cmd_args
.get_one::<String>("PACKAGE_NAME")
.cloned()
.ok_or_else(|| anyhow!("Missing required argument: PACKAGE_NAME"))?;

let support = PkgSupport {
os: sub_cmd_args
.get_one::<String>("OS")
.and_then(|s| s.parse::<Os>().ok()),
arch: sub_cmd_args
.get_one::<String>("ARCH")
.and_then(|s| s.parse::<Arch>().ok()),
};

let mut cmd = CreateCommand {
pkg_type,
pkg_name,
support,
template_name: String::new(),
template_version_req: VersionReq::default(),
template_data: HashMap::new(),
};

let _ = cmd.support.set_defaults();

if let Some(kv_pairs) = sub_cmd_args.get_many::<String>("TEMPLATE_DATA") {
for pair in kv_pairs {
let mut split = pair.splitn(2, '=');
if let (Some(key), Some(value)) = (split.next(), split.next()) {
cmd.template_data.insert(key.to_string(), value.to_string());
}
}
}

if cmd.template_data.contains_key("package_name") {
return Err(anyhow!(
"The 'package_name' is set via the command line as '{}', and cannot be modified through '--template-data'.",
cmd.pkg_name
));
}

cmd.template_data
.insert("package_name".to_string(), cmd.pkg_name.clone());

let template = sub_cmd_args
.get_one::<String>("TEMPLATE")
.cloned()
.ok_or_else(|| anyhow!("Missing required argument: TEMPLATE"))?;

let (parsed_name, parsed_version_req) =
parse_pkg_name_version_req(&template).with_context(|| {
format!("Failed to parse template '{}'", template)
})?;

cmd.template_name = parsed_name;
cmd.template_version_req = parsed_version_req;

Ok(cmd)
}

pub async fn execute_cmd(
tman_config: &TmanConfig,
command_data: CreateCommand,
) -> Result<()> {
let started = Instant::now();

// Retrieve the current working directory.
let cwd = std::env::current_dir()
.context("Failed to get current working directory")?;

create_pkg_in_path(
tman_config,
&cwd,
&command_data.pkg_type,
&command_data.pkg_name,
&command_data.template_name,
&command_data.template_version_req,
Some(&command_data.template_data),
)
.await
.context("Failed to create the package")?;

println!(
"{} Package '{}:{}' created successfully in '{}' in {}.",
Emoji("🏆", ":-)"),
command_data.pkg_type,
command_data.pkg_name,
cwd.display(),
HumanDuration(started.elapsed())
);

Ok(())
}
22 changes: 2 additions & 20 deletions core/src/ten_manager/src/cmd/cmd_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use clap::{Arg, ArgAction, ArgMatches, Command};
use console::Emoji;
use indicatif::HumanDuration;
use inquire::Confirm;
use semver::VersionReq;

use ten_rust::pkg_info::{
dependencies::PkgDependency,
Expand Down Expand Up @@ -57,6 +56,7 @@ use crate::{
install_solver_results_in_standalone_mode,
},
},
version_utils::parse_pkg_name_version_req,
};

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -118,13 +118,6 @@ pub fn create_sub_cmd(args_cfg: &crate::cmd_line::ArgsCfg) -> Command {
.value_parser(args_cfg.arch.possible_values.clone())
.required(false),
)
.arg(
Arg::new("BUILD_TYPE")
.long("build-type")
.help("The build type")
.value_parser(args_cfg.build_type.possible_values.clone())
.required(false),
)
.arg(
Arg::new("TEMPLATE_MODE")
.long("template-mode")
Expand Down Expand Up @@ -393,17 +386,6 @@ fn write_pkgs_into_lock(pkgs: &Vec<&PkgInfo>, app_dir: &Path) -> Result<()> {
Ok(())
}

fn parse_pkg_name_version(
pkg_name_version: &str,
) -> Result<(String, VersionReq)> {
let parts: Vec<&str> = pkg_name_version.split('@').collect();
if parts.len() == 2 {
Ok((parts[0].to_string(), VersionReq::parse(parts[1])?))
} else {
Ok((pkg_name_version.to_string(), VersionReq::STAR))
}
}

fn filter_compatible_pkgs_to_candidates(
tman_config: &TmanConfig,
all_existing_local_pkgs: &Vec<PkgInfo>,
Expand Down Expand Up @@ -636,7 +618,7 @@ pub async fn execute_cmd(

let desired_pkg_type_: PkgType = package_type_str.parse()?;
let (desired_pkg_src_name_, desired_pkg_src_version_) =
parse_pkg_name_version(
parse_pkg_name_version_req(
command_data.package_name.as_ref().unwrap(),
)?;

Expand Down
5 changes: 5 additions & 0 deletions core/src/ten_manager/src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Refer to the "LICENSE" file in the root directory for more information.
//
pub mod cmd_check;
pub mod cmd_create;
pub mod cmd_delete;
pub mod cmd_designer;
pub mod cmd_install;
Expand All @@ -19,6 +20,7 @@ use anyhow::Result;
use super::config::TmanConfig;

pub enum CommandData {
Create(self::cmd_create::CreateCommand),
Install(self::cmd_install::InstallCommand),
Uninstall(self::cmd_uninstall::UninstallCommand),
Package(self::cmd_package::PackageCommand),
Expand All @@ -35,6 +37,9 @@ pub async fn execute_cmd(
command_data: CommandData,
) -> Result<()> {
match command_data {
CommandData::Create(cmd) => {
crate::cmd::cmd_create::execute_cmd(tman_config, cmd).await
}
CommandData::Install(cmd) => {
crate::cmd::cmd_install::execute_cmd(tman_config, cmd).await
}
Expand Down
4 changes: 4 additions & 0 deletions core/src/ten_manager/src/cmd_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ fn create_cmd() -> clap::ArgMatches {
.action(clap::ArgAction::SetTrue)
.hide(true),
)
.subcommand(crate::cmd::cmd_create::create_sub_cmd(&args_cfg))
.subcommand(crate::cmd::cmd_install::create_sub_cmd(&args_cfg))
.subcommand(crate::cmd::cmd_uninstall::create_sub_cmd(&args_cfg))
.subcommand(crate::cmd::cmd_package::create_sub_cmd(&args_cfg))
Expand All @@ -121,6 +122,9 @@ pub fn parse_cmd(
tman_config.mi_mode = matches.get_flag("MI");

let command_data = match matches.subcommand() {
Some(("create", sub_cmd_args)) => crate::cmd::CommandData::Create(
crate::cmd::cmd_create::parse_sub_cmd(sub_cmd_args)?,
),
Some(("install", sub_cmd_args)) => crate::cmd::CommandData::Install(
crate::cmd::cmd_install::parse_sub_cmd(sub_cmd_args)?,
),
Expand Down
Loading

0 comments on commit 1361454

Please sign in to comment.