Merge branch 'master' of github.com:/MajorBarnulf/epitls-pi

This commit is contained in:
mb 2022-10-06 18:10:29 +02:00
commit 37cad03cf3
6 changed files with 84 additions and 21 deletions

2
Cargo.lock generated
View file

@ -138,7 +138,7 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]] [[package]]
name = "epitls-pi" name = "epitls-pi"
version = "1.2.1" version = "1.3.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "epitls-pi" name = "epitls-pi"
version = "1.2.1" version = "1.3.1"
edition = "2021" edition = "2021"
license = "GPL-3.0+" license = "GPL-3.0+"
description = "A little helper tool meant to ease the developpment of the C piscine at EPITA/Toulouse." description = "A little helper tool meant to ease the developpment of the C piscine at EPITA/Toulouse."

View file

@ -1,12 +1,13 @@
use std::{ use std::{
env, fs, env, fs,
io::stdin,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use ron::ser::PrettyConfig; use ron::ser::PrettyConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::utils::{log_success, Apply}; use crate::utils::{log_process, log_success, Apply};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Config { pub struct Config {
@ -23,7 +24,7 @@ impl Config {
Self { Self {
identifier, identifier,
main_file: "main.c".into(), main_file: "main.c".into(),
test_file: "test.c".into(), test_file: "test.ctest".into(),
includes: vec![], includes: vec![],
strict_mode: false, strict_mode: false,
} }
@ -33,6 +34,11 @@ impl Config {
path.extend([Self::CONFIG_FILE_NAME]); path.extend([Self::CONFIG_FILE_NAME]);
let content = let content =
ron::ser::to_string_pretty(self, PrettyConfig::default().struct_names(true)).unwrap(); ron::ser::to_string_pretty(self, PrettyConfig::default().struct_names(true)).unwrap();
if path.exists() {
log_process("config already exists, overwrite it?");
let mut buff = String::new();
stdin().read_line(&mut buff).unwrap();
}
fs::write(path, content).unwrap(); fs::write(path, content).unwrap();
} }
@ -47,11 +53,21 @@ impl Config {
.unwrap_or_else(|| Self::new(path.file_name().unwrap().to_str().unwrap().to_string())) .unwrap_or_else(|| Self::new(path.file_name().unwrap().to_str().unwrap().to_string()))
} }
pub fn get_local_path() -> Option<PathBuf> {
let path = env::current_dir().unwrap();
Self::get_path(&path)
}
pub fn get(path: &Path) -> Option<Self> { pub fn get(path: &Path) -> Option<Self> {
let path = path.to_path_buf().canonicalize().unwrap(); let path = path.to_path_buf().canonicalize().unwrap();
Self::try_get(&path).or_else(|| path.parent().and_then(Self::get)) Self::try_get(&path).or_else(|| path.parent().and_then(Self::get))
} }
pub fn get_path(path: &Path) -> Option<PathBuf> {
let path = path.to_path_buf().canonicalize().unwrap();
Self::try_get_path(&path).or_else(|| path.parent().and_then(Self::get_path))
}
pub fn identifier(&self) -> &str { pub fn identifier(&self) -> &str {
&self.identifier &self.identifier
} }
@ -78,6 +94,15 @@ impl Config {
.ok() .ok()
.and_then(|content| ron::from_str(&content).ok()) .and_then(|content| ron::from_str(&content).ok())
} }
fn try_get_path(path: &Path) -> Option<PathBuf> {
let path = path.to_path_buf().apply(|p| p.push(Self::CONFIG_FILE_NAME));
fs::read_to_string(&path)
.ok()
.and_then(|content| ron::from_str::<Self>(&content).ok())
.is_some()
.then_some(path)
}
} }
pub fn create(path: String, identifier: String) { pub fn create(path: String, identifier: String) {
@ -94,3 +119,17 @@ pub fn create(path: String, identifier: String) {
.to_string(); .to_string();
log_success(&format!("created '{path}'")); log_success(&format!("created '{path}'"));
} }
pub fn create_test(mut path: String) {
const DEFAULT_CONTENT: &str = r#"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
void test_it_works() {
assert( (2 + 2) == (4) );
}
"#;
path += "/test.ctest";
fs::write(path, DEFAULT_CONTENT).unwrap();
}

View file

@ -1,3 +1,5 @@
use std::env;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use config::Config; use config::Config;
@ -45,10 +47,9 @@ pub enum Commands {
/// Files to run tests from. /// Files to run tests from.
files: Vec<String>, files: Vec<String>,
// /// Specific tests to run.
/// Specific tests to run. // #[clap(short, long)]
#[clap(short, long)] // tests: Vec<String>,
tests: Vec<String>,
}, },
/// Watches changes to the project included files and runs a command on changes. /// Watches changes to the project included files and runs a command on changes.
@ -61,11 +62,13 @@ pub enum Commands {
/// Initializes a project directory configuration, useful for custom flags, includes and custop push messages. /// Initializes a project directory configuration, useful for custom flags, includes and custop push messages.
init { init {
/// Path to the folder containing the project.
path: String,
/// Identifier for the automated tests. /// Identifier for the automated tests.
identifier: String, prefix: String,
/// Path to the folder containing the project.
path: Option<String>,
/// e
#[clap(short, long)]
tests: bool,
}, },
/// Pushes changes to the git server with a custom tag. /// Pushes changes to the git server with a custom tag.
@ -87,6 +90,7 @@ fn compilation_args() -> Vec<String> {
"-fsanitize=address".to_string(), "-fsanitize=address".to_string(),
"-Wextra".to_string(), "-Wextra".to_string(),
"-std=c99".to_string(), "-std=c99".to_string(),
// "-pedantic".to_string(),
]; ];
if Config::get_local_or_default().strict_mode() { if Config::get_local_or_default().strict_mode() {
args.push("-Werror".to_string()); args.push("-Werror".to_string());
@ -114,15 +118,14 @@ fn main() {
Commands::test { Commands::test {
capture, capture,
mut files, mut files,
tests, // tests,
} => { } => {
if files.is_empty() { if files.is_empty() {
files.push(Config::get_local_or_default().test_file().to_string()); files.push(Config::get_local_or_default().test_file().to_string());
} }
append_includes(&mut files); append_includes(&mut files);
let args = compilation_args(); let args = compilation_args();
let tests = (!tests.is_empty()).then_some(tests); test::main(capture, files, args)
test::main(capture, files, args, tests)
} }
Commands::watch { command, files } => { Commands::watch { command, files } => {
let mut files = files.unwrap_or_default(); let mut files = files.unwrap_or_default();
@ -130,8 +133,18 @@ fn main() {
watch::main(files, command); watch::main(files, command);
} }
Commands::init { path, identifier } => { Commands::init {
config::create(path, identifier); path,
prefix,
tests,
} => {
let path =
path.unwrap_or_else(|| env::current_dir().unwrap().to_str().unwrap().to_string());
let prefix = prefix.trim().trim_end_matches('*');
config::create(path.clone(), prefix.to_string());
if tests {
config::create_test(path);
}
} }
Commands::push { message } => { Commands::push { message } => {

View file

@ -7,15 +7,26 @@ use crate::{
utils::{log_error, log_process, log_success}, utils::{log_error, log_process, log_success},
}; };
pub fn add() {
let path = Config::get_local_path().unwrap();
let path = path.parent().unwrap();
let path = path.to_str().unwrap();
Command::new("git")
.args(["add", path])
.status()
.unwrap()
.success()
.then_some(())
.unwrap_or_else(|| exit(1));
}
pub fn main(message: Option<String>) { pub fn main(message: Option<String>) {
let message = message.unwrap_or_else(|| Utc::now().format("pi - %d/%m/%Y %H:%M").to_string()); let message = message.unwrap_or_else(|| Utc::now().format("pi - %d/%m/%Y %H:%M").to_string());
let timestamp = Utc::now().timestamp(); let timestamp = Utc::now().timestamp();
let suffix = format!("pi{timestamp}"); let suffix = format!("pi{timestamp}");
let tag = Config::get_local() let tag = Config::get_local()
.unwrap_or_else(|| { .unwrap_or_else(|| {
log_error( log_error("no config file found.\nPlease initialize with 'pi init <tag-prefix>'");
"no config file found.\nPlease initialize with 'pi init <path> <identifier>'",
);
exit(1) exit(1)
}) })
.identifier() .identifier()

View file

@ -5,7 +5,7 @@ use crate::{
utils::{log_failure, log_process, log_success}, utils::{log_failure, log_process, log_success},
}; };
pub fn main(_capture: bool, files: Vec<String>, args: Vec<String>, _test: Option<Vec<String>>) { pub fn main(_capture: bool, files: Vec<String>, args: Vec<String>) {
log_process("testing"); log_process("testing");
for path in files { for path in files {
let content = fs::read_to_string(&path).unwrap(); let content = fs::read_to_string(&path).unwrap();