use crate::{
config::{ApplicationConfig, TririgaConfig, TririgaOMObject},
repo::Repo,
tririga::api::{Api, Credentials, PackageStatus},
tririga::deploy::Deployer,
};
use std::env::current_dir;
use std::error::Error;
use std::fs::OpenOptions;
use std::fs::{read_to_string, File};
use std::io::prelude::*;
use std::io::BufReader;
use std::path::Path;
use std::str;
use std::{thread, time};
const APP_CONFIG_PATH: &str = "./config.yaml";
const TRIRIGA_CONFIG_PATH: &str = "./tririga.yaml";
const DELAY: time::Duration = time::Duration::from_secs(3);
pub async fn pull() -> Result<(), Box<dyn Error>> {
let current_directory = current_dir()?.to_str().unwrap().to_owned();
let repo = Repo::new(¤t_directory);
let (repo_ahead, repo_behind) = repo.is_ahead_behind_remote();
if repo_ahead {
println!("✋ Repo is ahead of remote. Please push changes first");
}
if repo_behind {
repo.pull()?;
deploy_from_directory(&repo.last_commit_id()?[..7], ¤t_directory).await?;
} else {
println!("🤷 No update")
}
Ok(())
}
pub async fn deploy() -> Result<(), Box<dyn Error>> {
let current_directory = current_dir()?.to_str().unwrap().to_owned();
let repo = Repo::new(¤t_directory);
deploy_from_directory(&repo.last_commit_id()?[..7], ¤t_directory).await?;
Ok(())
}
async fn deploy_from_directory(
repo_last_commit_id: &str,
current_directory: &str,
) -> Result<(), Box<dyn Error>> {
let app_config = ApplicationConfig::from_yaml(APP_CONFIG_PATH)?;
let tririga_config = TririgaConfig::from_yaml(TRIRIGA_CONFIG_PATH)?;
let api = Api::new(
&tririga_config.url,
Credentials {
user: tririga_config.user.clone(),
password: tririga_config.password.clone(),
},
);
api.login().await?;
let tririga_deployed_package_name =
format!("{}-{}", repo_last_commit_id, &app_config.package_name);
let os_deployed_package_name = format!("{}.zip", &tririga_deployed_package_name);
deploy_package(
&api,
&tririga_config.om_path,
&app_config.package_name,
current_directory,
&os_deployed_package_name,
&tririga_deployed_package_name,
)
.await?;
Ok(())
}
pub async fn push(message: &str) -> Result<(), Box<dyn Error>> {
let current_directory = current_dir()?.to_str().unwrap().to_owned();
let app_config = ApplicationConfig::from_yaml(APP_CONFIG_PATH)?;
let tririga_config = TririgaConfig::from_yaml(TRIRIGA_CONFIG_PATH)?;
let repo = Repo::new(¤t_directory);
let (_, repo_behind) = repo.is_ahead_behind_remote();
if repo_behind {
println!("✋ Repo is behind remote. Please pull changes first");
} else {
let api = Api::new(
&tririga_config.url,
Credentials {
user: tririga_config.user.clone(),
password: tririga_config.password.clone(),
},
);
api.login().await?;
let current_time_millis = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backward")
.as_millis();
let package_name =
format!("{} - {}", &app_config.package_name, current_time_millis);
let package_description = format!(
"{} - {}. {}",
current_time_millis, message, &app_config.package_description
);
let package_id = api
.create_new_package(&package_name, &package_description)
.await?;
println!("🌀 Adding objects to package");
for object in app_config.objects {
api.add_object_to_package_by_id(
&package_id.to_string(),
&object.object_type,
&object.object_name,
&object.module_name,
&object.bo_name.clone().unwrap_or("".to_string()),
)
.await?;
println!(
"\t✔ {} {} added to package",
&object.object_type, &object.object_name
);
}
api.export_package_by_id(&package_id.to_string()).await?;
loop {
let package_status = api
.get_package_status_by_id(&package_id.to_string())
.await?;
match package_status {
PackageStatus::Exported => {
println!("📦 Package Exported");
break;
}
PackageStatus::ExportFailed => {
println!("❌ Package Export Failed. Consider inspecting log files from TRIRIGA");
break;
}
PackageStatus::New => {
println!("🛑 There is a problem exporting. Package is declared as 'New'. Take a look at the TRIRIGA OM Logs and Console");
}
PackageStatus::ExportPending => {
continue;
}
_ => {
println!(
"🛑 The package status is {:?}, which is impossible since we are trying to export it",
&package_status
)
}
}
thread::sleep(DELAY);
}
println!("📥 Saving package as zip file");
let zip_file_path = format!(
"{}.{}",
Path::new(¤t_directory)
.join(Path::new(&app_config.package_name))
.to_str()
.unwrap(),
"zip"
);
api.download_package_as_zip(&package_name, &Path::new(&zip_file_path))
.await?;
let index = repo.add_all()?;
repo.commit(index, message)?;
repo.push()?;
println!("🚀 All changes commited and pushed");
}
Ok(())
}
pub async fn init() -> Result<(), Box<dyn Error>> {
ApplicationConfig::init(APP_CONFIG_PATH)?;
let tririga_config = TririgaConfig::init(TRIRIGA_CONFIG_PATH)?;
match tririga_config {
Some(_) => {
println!("✅ Initialization successful");
add_config_to_git_ignore()?;
Ok(())
}
None => {
println!("❌ Initialization abandoned");
Ok(())
}
}
}
pub fn add_tririga_object_to_config() -> Result<(), Box<dyn Error>> {
let current_directory = current_dir()?.to_str().unwrap().to_owned();
let repo = Repo::new(¤t_directory);
let (_, is_behind) = repo.is_ahead_behind_remote();
if is_behind {
println!("🛑 Repository is behind remote. Perform a 'pull' first");
return Ok(());
}
let object = TririgaOMObject::from_dialog()?;
println!("⏳ Modifying config file");
let mut app_config = ApplicationConfig::from_yaml(APP_CONFIG_PATH)?;
app_config.objects.push(object.clone());
ApplicationConfig::to_yaml(&app_config, APP_CONFIG_PATH)?;
println!("📝 Config file saved locally");
println!("📩 Pushing change to remote");
let index = repo.add_all()?;
let commit_message = format!("OM Object list update - {:#?}", object);
repo.commit(index, &commit_message)?;
repo.push()?;
println!("🚀 Config file updated and pushed");
Ok(())
}
pub fn delete_tririga_object_from_config() -> Result<(), Box<dyn Error>> {
let current_directory = current_dir()?.to_str().unwrap().to_owned();
let repo = Repo::new(¤t_directory);
let (_, is_behind) = repo.is_ahead_behind_remote();
if is_behind {
println!("🛑 Repository is behind remote. Perform a 'pull' first");
return Ok(());
}
let mut app_config = ApplicationConfig::from_yaml(APP_CONFIG_PATH)?;
let deleted_objects = app_config.delete_tririga_om_objects_dialog()?;
println!("⏳ Modifying config file");
ApplicationConfig::to_yaml(&app_config, APP_CONFIG_PATH)?;
println!("📝 Config file saved locally");
println!("📩 Pushing change to remote");
let index = repo.add_all()?;
let commit_message = format!("OM object list deletion - {:#?}", &deleted_objects);
repo.commit(index, &commit_message)?;
repo.push()?;
println!("🚀 Config file updated and pushed");
Ok(())
}
fn add_config_to_git_ignore() -> Result<(), Box<dyn Error>> {
let file_path = ".gitignore";
let tririga_yaml_file_name = "tririga.yaml";
if Path::new(file_path).exists() {
let file = std::fs::File::open(file_path)?;
let reader = BufReader::new(&file);
for line in reader.lines() {
match line {
Ok(line) => {
if line.contains(tririga_yaml_file_name) {
return Ok(());
}
}
Err(e) => println!("ERROR: {}", e),
}
}
let mut file = OpenOptions::new()
.write(true)
.append(true)
.open(&file_path)
.unwrap();
if read_to_string(tririga_yaml_file_name)?.len() > 0 {
println!("There is something in the .gitignore file. Skipping a line to write");
if let Err(e) = writeln!(file) {
eprintln!("Couldn't write to file: {}", e);
}
}
if let Err(e) = write!(file, "{}", tririga_yaml_file_name) {
eprintln!("Couldn't write to file: {}", e);
}
return Ok(());
}
let mut git_ignore = File::create(Path::new(file_path))?;
if let Err(e) = write!(git_ignore, "{}", tririga_yaml_file_name) {
eprintln!("Couldn't write to file: {}", e);
}
Ok(())
}
async fn deploy_package(
api: &Api,
om_path: &str,
package_name: &str,
current_directory: &str,
os_deployed_package_name: &str,
tririga_deployed_package_name: &str,
) -> Result<(), Box<dyn Error>> {
let deployer = Deployer::new(om_path, package_name)?;
println!("🎬 Begin deploying package");
deployer.execute(current_directory, os_deployed_package_name)?;
println!("📡 Package will be picked up automatically by OM Agent");
while Path::new(om_path)
.join(Path::new(&os_deployed_package_name))
.exists()
{
let cooling_duration = std::time::Duration::from_secs(2);
std::thread::sleep(cooling_duration);
}
println!("🍒 Package deployed. Waiting for status update from API...");
loop {
let package_status = api
.get_package_status_by_name(tririga_deployed_package_name)
.await?;
match package_status {
PackageStatus::Imported => {
println!("✅ Package Deployed (Imported)");
return Ok(());
}
PackageStatus::ImportFailed => {
panic!("❌ Package Import Failed. Consider inspecting log files from TRIRIGA");
}
PackageStatus::New => {
panic!("⚠️️ There is a problem deploying. Package is declared as 'New'. Take a look at the TRIRIGA OM Logs and Console");
}
PackageStatus::ImportPending => {
continue;
}
_ => {
println!(
"🛑 The package status is {:?}, which is impossible since we are trying to export it",
&package_status
)
}
}
thread::sleep(DELAY);
}
}