Overview
Implement the CLI presentation layer for the create command, handling Figment integration for configuration file parsing, argument processing, and user interaction.
Parent EPIC: #34 - Implement Create Environment Command
Depends On: #36 (Application Layer CreateCommand)
Related: Full Specification
Key Points
- Add
--working-dir flag to main CLI for production use (not just tests)
- Figment stays in presentation layer as delivery mechanism
- All errors use tiered help system with
.help() methods
Goals
Module Structure
src/presentation/console/subcommands/create/
├── mod.rs # Module exports
├── subcommand.rs # CreateSubcommand implementation
├── args.rs # CLI argument definitions
├── config_loader.rs # Figment integration
├── errors.rs # Presentation error types with .help()
└── tests/
├── mod.rs
├── integration.rs # CLI integration tests
└── fixtures.rs # Test fixtures
CLI Arguments
#[derive(Debug, Args)]
pub struct CreateArgs {
#[command(subcommand)]
pub action: CreateAction,
}
#[derive(Debug, Subcommand)]
pub enum CreateAction {
Environment {
/// Path to the environment configuration file
#[arg(long, short = 'f', value_name = "FILE")]
env_file: PathBuf,
},
// Future: Template generation
}
Configuration Loader (Figment)
pub struct ConfigLoader;
impl ConfigLoader {
pub fn load_from_file(
&self,
config_path: &Path
) -> Result<EnvironmentCreationConfig, CreateSubcommandError> {
// Verify file exists
if !config_path.exists() {
return Err(CreateSubcommandError::ConfigFileNotFound {
path: config_path.to_path_buf(),
});
}
// Load with Figment
let config = Figment::new()
.merge(Serialized::defaults(EnvironmentCreationConfig::default()))
.merge(Json::file(config_path))
.extract()
.map_err(|source| CreateSubcommandError::ConfigParsingFailed {
path: config_path.to_path_buf(),
format: ConfigFormat::Json,
source: Box::new(source),
})?;
// Validate using domain rules
config.validate()
.map_err(CreateSubcommandError::ConfigValidationFailed)?;
Ok(config)
}
}
Error Types with .help()
#[derive(Debug, Error)]
pub enum CreateSubcommandError {
#[error("Configuration file not found: {path}")]
ConfigFileNotFound { path: PathBuf },
#[error("Failed to parse configuration file: {path}")]
ConfigParsingFailed {
path: PathBuf,
format: ConfigFormat,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Configuration validation failed")]
ConfigValidationFailed(#[source] ConfigValidationError),
#[error("Command execution failed")]
CommandFailed(#[source] CreateCommandError),
}
impl CreateSubcommandError {
pub fn help(&self) -> &'static str {
// Detailed troubleshooting guidance
}
}
Usage Examples
# Create environment from configuration file
torrust-tracker-deployer create environment --env-file ./config/environment.json
# With custom working directory
torrust-tracker-deployer --working-dir /path/to/workspace create environment --env-file ./config/env.json
# Show help
torrust-tracker-deployer create --help
torrust-tracker-deployer create environment --help
Acceptance Criteria
Estimated Time
3-4 hours
Notes
- Figment integration stays in presentation layer (DDD boundary)
- Support
--working-dir at main CLI level for production use
- All errors must be user-friendly with
.help() guidance
- TOML support will be added in future separate issue
Overview
Implement the CLI presentation layer for the create command, handling Figment integration for configuration file parsing, argument processing, and user interaction.
Parent EPIC: #34 - Implement Create Environment Command
Depends On: #36 (Application Layer CreateCommand)
Related: Full Specification
Key Points
--working-dirflag to main CLI for production use (not just tests).help()methodsGoals
Create
createsubcommand in presentation layer--env-file,--working-dir)Add explicit presentation error enums
CreateSubcommandErrorfor CLI-specific errors.help()methodsCommand help documentation
Tests
Module Structure
CLI Arguments
Configuration Loader (Figment)
Error Types with .help()
Usage Examples
Acceptance Criteria
create environment --env-fileloads and parses JSON configuration--working-dirflag works in production (main CLI args).help()methods)Estimated Time
3-4 hours
Notes
--working-dirat main CLI level for production use.help()guidance