From 8b9839b9b4f5c4270c9f020a7fc072d7d14c5c55 Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Mon, 7 Aug 2023 23:11:45 +1000 Subject: [PATCH] citnames: create entry point --- source/citnames_rs/Cargo.toml | 17 +++-- source/citnames_rs/src/configuration.rs | 33 ++++++---- source/citnames_rs/src/main.rs | 85 +++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 source/citnames_rs/src/main.rs diff --git a/source/citnames_rs/Cargo.toml b/source/citnames_rs/Cargo.toml index 981ceaba..378ddb42 100644 --- a/source/citnames_rs/Cargo.toml +++ b/source/citnames_rs/Cargo.toml @@ -6,17 +6,20 @@ description = "Rust crate to detect semantic of commands." keywords = ["clang", "clang-tooling", "compilation-database"] repository = "https://github.com/rizsotto/Bear" homepage = "https://github.com/rizsotto/Bear" -documentation = "https://docs.rs/Bear/" license = "GPL-3" edition = "2021" [dependencies] +anyhow = "1.0" thiserror = "1.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +lazy_static = "1.4" +serde = { version = "1.0", default-features = false, features = ["derive"] } +serde_json = { version = "1.0", default-features = false, features = ["std"] } path-absolutize = "3.1" +num_cpus = "1.16" +crossbeam = "0.8" +crossbeam-channel = "0.5" json_compilation_db = "0.3.0" -lazy_static = "1.4" - -[dev-dependencies] -tempfile = "3.2" +log = "0.4" +simple_logger = { version = "4.2", default-features = false, features = ["timestamps"]} +clap = { version = "4.3", default-features = false, features = ["std", "cargo", "help", "usage", "suggestions"] } diff --git a/source/citnames_rs/src/configuration.rs b/source/citnames_rs/src/configuration.rs index 20bc8c86..c99decb5 100644 --- a/source/citnames_rs/src/configuration.rs +++ b/source/citnames_rs/src/configuration.rs @@ -22,15 +22,15 @@ use std::path::PathBuf; use serde::Deserialize; // Represents the application configuration. -#[derive(Debug, Deserialize, PartialEq)] -pub(crate) struct Configuration { +#[derive(Debug, Default, Deserialize, PartialEq)] +pub struct Configuration { pub output: Option, pub compilation: Option, } // Represents compiler related configuration. #[derive(Debug, Deserialize, PartialEq)] -pub(crate) struct Compilation { +pub struct Compilation { #[serde(default)] pub compilers_to_recognize: Vec, #[serde(default)] @@ -43,7 +43,7 @@ pub(crate) struct Compilation { // be a known compiler, and append the additional flags to the output // entry if the compiler is recognized. #[derive(Clone, Debug, Deserialize, PartialEq)] -pub(crate) struct CompilerToRecognize { +pub struct CompilerToRecognize { pub executable: PathBuf, #[serde(default)] pub flags_to_add: Vec, @@ -53,7 +53,7 @@ pub(crate) struct CompilerToRecognize { // Groups together the output related configurations. #[derive(Debug, Deserialize, PartialEq)] -pub(crate) struct Output { +pub struct Output { pub format: Option, pub content: Option, } @@ -65,7 +65,7 @@ pub(crate) struct Output { // of strings or a single string (shell escaping to protect white spaces). // Another format element is if the output field is emitted or not. #[derive(Debug, Deserialize, PartialEq)] -pub(crate) struct Format { +pub struct Format { // will default to true pub command_as_array: Option, // will default to false @@ -78,7 +78,7 @@ pub(crate) struct Format { // These attributes can be read from the configuration file, and can be // overridden by command line arguments. #[derive(Debug, Deserialize, PartialEq)] -pub(crate) struct Content { +pub struct Content { // will default to false pub include_only_existing_source: Option, pub duplicate_filter_fields: Option, @@ -91,7 +91,7 @@ pub(crate) struct Content { /// Represents how the duplicate filtering detects duplicate entries. #[derive(Debug, Deserialize, PartialEq)] #[serde(try_from = "String")] -pub(crate) enum DuplicateFilterFields { +pub enum DuplicateFilterFields { FileOnly, FileAndOutputOnly, All, @@ -114,14 +114,16 @@ impl TryFrom for DuplicateFilterFields { } } -mod io { +pub mod io { + use std::io::stdin; + use thiserror::Error; use super::*; /// This error type encompasses any error that can be returned by this module. #[derive(Error, Debug)] - pub(crate) enum Error { + pub enum Error { #[error("IO error")] IoError(#[from] std::io::Error), #[error("Syntax error")] @@ -129,15 +131,22 @@ mod io { } /// Load the content of the given file and parse it as Configuration. - pub(crate) fn from_file(file: &std::path::Path) -> Result { + pub fn from_file(file: &std::path::Path) -> Result { let reader = std::fs::OpenOptions::new().read(true).open(file)?; let result = from_reader(reader)?; Ok(result) } + pub fn from_stdin() -> Result { + let reader = stdin(); + let result = from_reader(reader)?; + + Ok(result) + } + /// Load the content of the given stream and parse it as Configuration. - pub(crate) fn from_reader(reader: impl std::io::Read) -> Result { + pub fn from_reader(reader: impl std::io::Read) -> Result { serde_json::from_reader(reader) } diff --git a/source/citnames_rs/src/main.rs b/source/citnames_rs/src/main.rs new file mode 100644 index 00000000..12aa905e --- /dev/null +++ b/source/citnames_rs/src/main.rs @@ -0,0 +1,85 @@ +/* Copyright (C) 2012-2023 by László Nagy + This file is part of Bear. + + Bear is a tool to generate compilation database for clang tooling. + + Bear is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bear is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +use std::path::Path; + +use anyhow::Result; +use clap::{arg, ArgAction, command}; +use log::LevelFilter; +use simple_logger::SimpleLogger; + +use crate::configuration::Configuration; +use crate::configuration::io::{from_file, from_stdin}; + +mod configuration; + +fn main() -> Result<()> { + let matches = command!() + .args(&[ + arg!(-i --input "Path of the event file") + .default_value("commands.json") + .hide_default_value(false), + arg!(-o --output "Path of the result file") + .default_value("compile_commands.json") + .hide_default_value(false), + arg!(-c --config "Path of the config file"), + arg!(-a --append "Append result to an existing output file") + .action(ArgAction::SetTrue), + arg!(-v --verbose ... "Sets the level of verbosity") + .action(ArgAction::Count), + ]) + .get_matches(); + + // configure logging + let verbose = matches.get_count("verbose"); + SimpleLogger::new() + .with_level(into_log_level(verbose)) + .init() + .unwrap(); + + // read config + let config = match matches.get_one::("config").map(|s| s.as_ref()) { + Some("-") => + from_stdin()?, + Some(file) => + from_file(Path::new(file))?, + None => + Configuration::default(), + }; + + println!("Hello, world! {:?}", config); + + log::trace!("trace message"); + log::debug!("debug message"); + log::info!("info message"); + log::warn!("warn message"); + log::error!("error message"); + + Ok(()) +} + +fn into_log_level(count: u8) -> LevelFilter { + match count { + 0 => LevelFilter::Error, + 1 => LevelFilter::Warn, + 2 => LevelFilter::Info, + 3 => LevelFilter::Debug, + _ => LevelFilter::Trace, + } +}