use std::fs;
use unilang::data::{ ErrorCode, ErrorData, OutputData };
use unilang::interpreter::ExecutionContext;
use unilang::semantic::VerifiedCommand;
use unilang::types::Value;
use crate::templates::{ Ecosystem, dockerfile, runbox_yml, wrapper_script };
fn opt_str( cmd : &VerifiedCommand, name : &str ) -> Option< String >
{
match cmd.arguments.get( name )
{
Some( Value::String( s ) ) => Some( s.clone() ),
_ => None,
}
}
fn require_str( cmd : &VerifiedCommand, name : &str ) -> Result< String, ErrorData >
{
let missing = || ErrorData::new(
ErrorCode::ArgumentMissing,
format!( "missing required argument: {name}::" ),
);
match opt_str( cmd, name )
{
Some( s ) if !s.is_empty() => Ok( s ),
_ => Err( missing() ),
}
}
#[ allow( clippy::needless_pass_by_value ) ]
#[ inline ]
pub fn init_routine( cmd : VerifiedCommand, _ctx : ExecutionContext ) -> Result< OutputData, ErrorData >
{
let image = require_str( &cmd, "image" )?;
let eco_raw = opt_str( &cmd, "ecosystem" ).unwrap_or_default();
let eco = if eco_raw.is_empty()
{
Ecosystem::None
}
else
{
Ecosystem::from_name( &eco_raw ).ok_or_else( || ErrorData::new(
ErrorCode::ArgumentTypeMismatch,
format!( "unknown ecosystem: {eco_raw}" ),
) )?
};
let test_script = opt_str( &cmd, "test_script" )
.filter( |s| !s.is_empty() )
.unwrap_or_else( || "verb/test.d/l1".to_string() );
let cwd = std::env::current_dir().map_err( |e| ErrorData::new(
ErrorCode::InternalError,
format!( "cannot determine current directory: {e}" ),
) )?;
let runbox_dir = cwd.join( "runbox" );
if runbox_dir.exists()
{
return Err( ErrorData::new(
ErrorCode::ArgumentTypeMismatch,
"runbox/ already exists".to_string(),
) );
}
fs::create_dir( &runbox_dir ).map_err( |e| ErrorData::new(
ErrorCode::InternalError,
format!( "failed to create runbox/: {e}" ),
) )?;
let wrapper_path = runbox_dir.join( "runbox" );
fs::write( &wrapper_path, wrapper_script() ).map_err( |e| ErrorData::new(
ErrorCode::InternalError,
format!( "failed to write runbox/runbox: {e}" ),
) )?;
#[ cfg( unix ) ]
{
use std::os::unix::fs::PermissionsExt as _;
let mut perms = fs::metadata( &wrapper_path ).map_err( |e| ErrorData::new(
ErrorCode::InternalError,
format!( "failed to read runbox/runbox metadata: {e}" ),
) )?.permissions();
perms.set_mode( 0o755 );
fs::set_permissions( &wrapper_path, perms ).map_err( |e| ErrorData::new(
ErrorCode::InternalError,
format!( "failed to set permissions on runbox/runbox: {e}" ),
) )?;
}
fs::write( runbox_dir.join( "runbox.yml" ), runbox_yml( &image, &eco, &test_script ) )
.map_err( |e| ErrorData::new(
ErrorCode::InternalError,
format!( "failed to write runbox/runbox.yml: {e}" ),
) )?;
fs::write( runbox_dir.join( "runbox.dockerfile" ), dockerfile( &eco ) )
.map_err( |e| ErrorData::new(
ErrorCode::InternalError,
format!( "failed to write runbox/runbox.dockerfile: {e}" ),
) )?;
let msg = format!(
"Initialized runbox/ for image '{image}' (ecosystem: {})\n runbox/runbox\n runbox/runbox.yml\n runbox/runbox.dockerfile\n",
eco.as_str(),
);
Ok( OutputData::new( msg, "text" ) )
}