Added some logging capability in project using env_logger
Signed-off-by: Louis Vallat <louis@louis-vallat.xyz>
This commit is contained in:
parent
2447a01145
commit
9e82b3102c
@ -1,18 +1,17 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use log::{trace, warn};
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
const CONFIG_FILENAME: &str = "./config.json";
|
||||
|
||||
// TODO REMOVE PUB AND REPLACE BY FN
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
pub host: String,
|
||||
pub token: String,
|
||||
pub projects: Vec<Project>
|
||||
}
|
||||
|
||||
// TODO REMOVE PUB AND REPLACE BY FN
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Project {
|
||||
pub name: String,
|
||||
@ -22,15 +21,21 @@ pub struct Project {
|
||||
}
|
||||
|
||||
pub fn get_config() -> Option<Config> {
|
||||
trace!("Trying to read config file at location '{}'.", CONFIG_FILENAME);
|
||||
if Path::exists(Path::new(CONFIG_FILENAME)) {
|
||||
return serde_json::from_str(
|
||||
std::fs::read_to_string(CONFIG_FILENAME).unwrap().as_str())
|
||||
.unwrap();
|
||||
std::fs::read_to_string(CONFIG_FILENAME)
|
||||
.expect("Cannot read configuration file.").as_str())
|
||||
.expect("Cannot deserialize configuration file.");
|
||||
}
|
||||
warn!("Configuration file doesn't exist at location '{}'.", CONFIG_FILENAME);
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn save_config(config: &Config) {
|
||||
trace!("Saving configuration file with content {:?}.", config);
|
||||
std::fs::write(Path::new(CONFIG_FILENAME),
|
||||
serde_json::to_string_pretty(config).unwrap()).unwrap();
|
||||
serde_json::to_string_pretty(config)
|
||||
.expect("Could not serialize the configuration class to JSON."))
|
||||
.expect("Could not write serialized configuration file.");
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::{thread::{sleep, self, JoinHandle}, time::Duration};
|
||||
|
||||
use launchy::{launchpad_mini::{Button, Color, Output, DoubleBufferingBehavior}, OutputDevice};
|
||||
use serde::Deserialize;
|
||||
use log::info;
|
||||
use log::{warn, trace, debug, error};
|
||||
use gitlab::{Gitlab, api::{projects::pipelines::{Pipelines, PipelineOrderBy}, Query}};
|
||||
|
||||
use crate::config_manager::{Config, Project};
|
||||
@ -15,6 +15,7 @@ pub struct Pipeline {
|
||||
status: String
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum PipelineStatus {
|
||||
Created,
|
||||
WaitingForResource,
|
||||
@ -31,6 +32,7 @@ enum PipelineStatus {
|
||||
|
||||
impl PipelineStatus {
|
||||
fn from(s: &str) -> Option<PipelineStatus> {
|
||||
trace!("Trying to convert '{}' to PipelineStatus.", s);
|
||||
return match s {
|
||||
"created" => Some(PipelineStatus::Created),
|
||||
"waiting_for_resource" => Some(PipelineStatus::WaitingForResource),
|
||||
@ -43,29 +45,36 @@ impl PipelineStatus {
|
||||
"skipped" => Some(PipelineStatus::Skipped),
|
||||
"manual" => Some(PipelineStatus::Manual),
|
||||
"scheduled" => Some(PipelineStatus::Scheduled),
|
||||
_ => None
|
||||
_ => { warn!("Could not find correspondance for status '{}'.", s); None }
|
||||
}
|
||||
}
|
||||
|
||||
fn get_color(&self) -> (Color, bool) {
|
||||
trace!("Getting color for PipelineStatus '{:?}'.", self);
|
||||
return match self {
|
||||
PipelineStatus::Pending => (Color::YELLOW, false),
|
||||
PipelineStatus::Running => (Color::AMBER, true),
|
||||
PipelineStatus::Success => (Color::GREEN, false),
|
||||
PipelineStatus::Failed => (Color::RED, false),
|
||||
_ => (Color::OFF, false)
|
||||
_ => { warn!("Unknown color for pipeline status {:?}.", self);
|
||||
(Color::OFF, false) }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn refresh_on_timer(client: Gitlab, project: Project) {
|
||||
trace!("Starting a refresh on timer task for project {:?}.", project);
|
||||
let mut output = Output::guess().unwrap();
|
||||
loop {
|
||||
let pipeline = get_latest_pipelines(&client, &project);
|
||||
if pipeline.is_none() { return; }
|
||||
if pipeline.is_none() {
|
||||
error!("Project {:?} has no existing pipeline. Ignoring.", project);
|
||||
return;
|
||||
}
|
||||
let c = PipelineStatus::from(pipeline.unwrap().status.as_str())
|
||||
.unwrap();
|
||||
debug!("Project {:?} has a pipeline status of {:?}, updating.", project, c);
|
||||
output.set_button(Button::GridButton { x: project.abs_x, y: project.abs_y },
|
||||
c.get_color().0,
|
||||
if c.get_color().1 { DoubleBufferingBehavior::Clear }
|
||||
@ -75,42 +84,61 @@ pub fn refresh_on_timer(client: Gitlab, project: Project) {
|
||||
}
|
||||
|
||||
pub fn load_from_config(config: Config) -> Vec<JoinHandle<()>> {
|
||||
info!("Loading gitlab manager from configuration.");
|
||||
trace!("Loading gitlab manager from configuration.");
|
||||
let mut threads = vec![];
|
||||
for p in config.projects.iter() {
|
||||
let client = Gitlab::new(config.host.as_str(), config.token.as_str()).unwrap();
|
||||
let project = p.clone();
|
||||
debug!("Spawning refresh thread for project {:?}.", project);
|
||||
threads.push(thread::spawn(move|| refresh_on_timer(client, project)));
|
||||
}
|
||||
debug!("Spawned {} threads for the refreshes.", threads.len());
|
||||
return threads;
|
||||
}
|
||||
|
||||
pub fn get_latest_pipelines(client: &Gitlab, project: &Project) -> Option<Pipeline> {
|
||||
trace!("Getting latest pipeline for project {:?}.", project);
|
||||
let endpoint = Pipelines::builder()
|
||||
.project(project.name.as_str()).ref_(project.ref_.as_str())
|
||||
.order_by(PipelineOrderBy::UpdatedAt).build().unwrap();
|
||||
let pipelines: Vec<Pipeline> = endpoint.query(client).unwrap_or(vec![]);
|
||||
return if pipelines.is_empty() { None } else {
|
||||
Some(pipelines.first().unwrap().to_owned()) };
|
||||
if pipelines.is_empty() {
|
||||
warn!("No pipeline found for project {:?}.", project);
|
||||
return None;
|
||||
} else {
|
||||
let pipeline = pipelines.first().unwrap().to_owned();
|
||||
debug!("Found pipeline {:?} as latest pipeline for project {:?}.",
|
||||
pipeline, project);
|
||||
return Some(pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn retry_pipeline(host: &str, token: &str, project: &Project) {
|
||||
trace!("Retrying pipeline for project {:?}.", project);
|
||||
let client = Gitlab::new(host, token).unwrap();
|
||||
let pipeline = get_latest_pipelines(&client, &project);
|
||||
if pipeline.is_none() { return; }
|
||||
let _res: Pipeline;
|
||||
if pipeline.is_none() {
|
||||
warn!("{:?} has no pipeline, ignoring.", project);
|
||||
return;
|
||||
}
|
||||
let res: Pipeline;
|
||||
if pipeline.clone().unwrap().status == "success" {
|
||||
debug!("Latest pipeline for {:?} has a 'success' status, creating another one.",
|
||||
project);
|
||||
let endpoint = gitlab::api::projects::pipelines::CreatePipeline::builder()
|
||||
.project(project.name.clone())
|
||||
.ref_(project.ref_.clone())
|
||||
.build().unwrap();
|
||||
_res = endpoint.query(&client).unwrap();
|
||||
res = endpoint.query(&client).unwrap();
|
||||
} else {
|
||||
debug!("Latest pipeline status for {:?} wasn't a success, retrying.",
|
||||
project);
|
||||
let endpoint = gitlab::api::projects::pipelines::RetryPipeline::builder()
|
||||
.project(project.name.clone())
|
||||
.pipeline(pipeline.unwrap().id)
|
||||
.build().unwrap();
|
||||
_res = endpoint.query(&client).unwrap();
|
||||
res = endpoint.query(&client).unwrap();
|
||||
}
|
||||
debug!("API answer was {:?}.", res);
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,30 @@
|
||||
use launchy::{OutputDevice, InputDevice, launchpad_mini::{Output, Input, Buffer, Button, Color, DoubleBuffering, DoubleBufferingBehavior, Message}, MsgPollingWrapper};
|
||||
use log::{trace, debug, warn};
|
||||
|
||||
use crate::{config_manager::Config, gitlab_controller::retry_pipeline};
|
||||
|
||||
const RESTART_BUTTON: Button = Button::GridButton { x: 8, y: 0 };
|
||||
const RESTART_BUTTON: Button = Button::GridButton { x: 8, y: 0 }; // A BUTTON
|
||||
|
||||
fn engage_restart(output: &mut Output) {
|
||||
trace!("Engaging restart mode.");
|
||||
output.set_button(RESTART_BUTTON, Color::DIM_GREEN, DoubleBufferingBehavior::Copy).unwrap();
|
||||
}
|
||||
|
||||
fn disengage_restart(output: &mut Output) {
|
||||
trace!("Disengaging restart mode.");
|
||||
output.set_button(RESTART_BUTTON, Color::OFF, DoubleBufferingBehavior::Copy).unwrap();
|
||||
}
|
||||
|
||||
fn running_thread(config: Config) {
|
||||
trace!("Starting a thread dedicated to the Launchpad input.");
|
||||
let mut output = Output::guess().unwrap();
|
||||
let input = Input::guess_polling().unwrap();
|
||||
let mut restart = false;
|
||||
for msg in input.iter() {
|
||||
debug!("Got message from Launchpad: {:?}.", msg);
|
||||
if let Message::Release { button } = msg {
|
||||
if button == RESTART_BUTTON {
|
||||
debug!("Restart button has been pressed.");
|
||||
if !restart {
|
||||
restart = true;
|
||||
engage_restart(&mut output);
|
||||
@ -27,16 +33,26 @@ fn running_thread(config: Config) {
|
||||
disengage_restart(&mut output);
|
||||
}
|
||||
} else if button.abs_x() != 8 {
|
||||
debug!("A project tile has been pressed.");
|
||||
let project = config.projects.iter()
|
||||
.find(|p| p.abs_x == button.abs_x() && p.abs_y + 1 == button.abs_y());
|
||||
if project.is_none() { continue; }
|
||||
if project.is_none() {
|
||||
warn!("The tile {:?} has no project associated. Ignoring.", button);
|
||||
continue;
|
||||
}
|
||||
let project = project.unwrap();
|
||||
debug!("Tile {:?} has an associated project {:?}.", button, project);
|
||||
if restart {
|
||||
debug!("Restart mode is engaged, attempting to restart pipeline for project {:?}.",
|
||||
project);
|
||||
restart = false;
|
||||
retry_pipeline(config.host.as_str(), config.token.as_str(), project);
|
||||
disengage_restart(&mut output);
|
||||
} else {
|
||||
open::that_in_background(format!("https://{}/{}", config.host, project.name));
|
||||
let url = format!("https://{}/{}", config.host, project.name);
|
||||
debug!("Restart mode isn't engaged. Trying to open project {:?} in browser with URL {}.",
|
||||
project, url);
|
||||
open::that_in_background(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,13 +60,17 @@ fn running_thread(config: Config) {
|
||||
}
|
||||
|
||||
pub fn init(config: Config) {
|
||||
trace!("Initializing launchpad.");
|
||||
let mut output = launchy::launchpad_mini::Output::guess().unwrap();
|
||||
debug!("Resetting launchpad state.");
|
||||
output.reset().unwrap();
|
||||
debug!("Setting up the double buffering behavior for the launchpad.");
|
||||
output.control_double_buffering(DoubleBuffering {
|
||||
copy: false,
|
||||
flash: true,
|
||||
edited_buffer: Buffer::A,
|
||||
displayed_buffer: Buffer::A
|
||||
}).unwrap();
|
||||
debug!("Spawning a thread for handling to launchpad I/O.");
|
||||
std::thread::spawn(move || running_thread(config));
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use log::error;
|
||||
use log::{info, error, trace};
|
||||
|
||||
use crate::config_manager::Config;
|
||||
use crate::config_manager::Project;
|
||||
@ -9,8 +9,10 @@ mod gitlab_controller;
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
trace!("Starting main application.");
|
||||
let conf = config_manager::get_config();
|
||||
if conf.is_none() {
|
||||
info!("Configuration file cannot be loaded, saving a default one.");
|
||||
config_manager::save_config(&Config {
|
||||
host: "gitlab-host".to_string(),
|
||||
token: "your-gitlab-key".to_string(),
|
||||
@ -27,6 +29,7 @@ fn main() {
|
||||
let conf = conf.unwrap();
|
||||
launchpad_controller::init(conf.clone());
|
||||
let threads = gitlab_controller::load_from_config(conf);
|
||||
trace!("Joining timer threads.");
|
||||
for t in threads {
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user