Skip to content

Commit

Permalink
Support for setting default backend, cosmocc, uncrustify
Browse files Browse the repository at this point in the history
Resolves #13
Resolves #8

* Support for uncrustify as an alternate formatter
* Support for cosmocc (it is mostly gcc compatible)
* Support for providing default backend (this is the backend that cpkg will look for first.) for compiler, formatter and docgen.
* Bump version to 0.11.0
  • Loading branch information
DvvCz committed May 18, 2024
1 parent f35c200 commit ec115eb
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 65 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "cpkg"
description = "A dead simple C package manager."
version = "0.10.0"
version = "0.11.0"
edition = "2021"

authors = ["David Cruz <codebycruz@gmail.com>"]
Expand Down
2 changes: 1 addition & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub enum Commands {

/// Adds the dependency, as a local file path to symlink.
#[arg(long)]
path: Option<String>,
path: Option<std::path::PathBuf>,
},

#[command(about = "Removes a dependency from cpkg.toml and deletes it.\x1b[36m")]
Expand Down
65 changes: 57 additions & 8 deletions src/components/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ impl Compiler for Gcc {

if !e.status.success() {
let msg = String::from_utf8_lossy(&e.stderr);
if msg.find("multiple definition of `main").is_some() { /* todo: should be backend agnostic, moved upward */
if msg.find("multiple definition of `main").is_some() {
/* todo: should be backend agnostic, moved upward */
anyhow::bail!("{msg}\n(cpkg: did you mean to run with --bin?)");
} else {
anyhow::bail!("{msg}");
Expand All @@ -61,14 +62,62 @@ impl Compiler for Gcc {
}
}

const SUPPORTED: &[(&'static str, fn() -> Box<dyn Compiler>)] = &[
("gcc", || Box::new(Gcc { bin: "gcc" })),
("clang", || Box::new(Gcc { bin: "clang" })),
("cosmocc", || Box::new(Gcc { bin: "cosmocc" })),
];

/// Tries to find an available C compiler backend.
/// Currently only supports gcc -> clang.
pub fn try_locate() -> anyhow::Result<Box<dyn Compiler>> {
match which::which("gcc") {
Ok(_) => Ok(Box::new(Gcc { bin: "gcc" })),
Err(_) => match which::which("clang") {
Ok(_) => Ok(Box::new(Gcc { bin: "clang" })), // Should be api compatible.
Err(_) => Err(anyhow::anyhow!("Couldn't find gcc or clang.")),
},
pub fn try_locate(proj: Option<&crate::Project>) -> anyhow::Result<Box<dyn Compiler>> {
let default = proj
.map(|p| {
p.config()
.compiler
.as_ref()
.map(|f| f.default.as_ref())
.flatten()
})
.flatten();

let backends = if let Some(d) = default {
match d.as_ref() {
"clang" | "gcc" | "cosmocc" => {
let mut c = SUPPORTED.to_vec();
let target = c.iter().position(|e| e.0 == d).unwrap();
c.swap(0, target);
std::borrow::Cow::Owned(c)
}

_ => {
anyhow::bail!("Unrecognized default compiler: {d}");
}
}
} else {
std::borrow::Cow::Borrowed(SUPPORTED)
};

for (bin, make) in backends.as_ref() {
if which::which(bin).is_ok() {
return Ok(make());
}
}

/* todo: cleaner impl when const for / const iterators exist */
const SUPPORTED_NAMES: &[&str] = &const {
let mut i = 0;
let mut arr = [""; SUPPORTED.len()];
while i < SUPPORTED.len() {
arr[i] = SUPPORTED[i].0;
i += 1;
}

arr
};

Err(anyhow::anyhow!(
"Couldn't find {}",
SUPPORTED_NAMES.join(" or ")
))
}
57 changes: 50 additions & 7 deletions src/components/docgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,57 @@ fn start_program(p: &std::path::Path) -> anyhow::Result<()> {
Ok(())
}

const SUPPORTED: &[(&'static str, fn() -> Box<dyn Docgen>)] = &[
("doxygen", || Box::new(Doxygen)),
("cldoc", || Box::new(Cldoc)),
];

/// Tries to find an available C compiler backend.
/// Currently only supports gcc -> clang.
pub fn try_locate() -> anyhow::Result<Box<dyn Docgen>> {
match which::which("doxygen") {
Ok(_) => Ok(Box::new(Doxygen)),
Err(_) => match which::which("cldoc") {
Ok(_) => Ok(Box::new(Cldoc)),
Err(_) => Err(anyhow::anyhow!("Couldn't find doxygen or cldoc.")),
},
pub fn try_locate(proj: &crate::Project) -> anyhow::Result<Box<dyn Docgen>> {
let default = proj.config()
.docgen
.as_ref()
.map(|f| f.default.as_ref())
.flatten();

let backends = if let Some(d) = default {
match d.as_ref() {
"doxygen" | "cldoc" => {
let mut c = SUPPORTED.to_vec();
let target = c.iter().position(|e| e.0 == d).unwrap();
c.swap(0, target);
std::borrow::Cow::Owned(c)
},

_ => {
anyhow::bail!("Unrecognized default doc generator: {d}");
}
}
} else {
std::borrow::Cow::Borrowed(SUPPORTED)
};

for (bin, make) in backends.as_ref() {
if which::which(bin).is_ok() {
return Ok(make());
}
}

/* todo: cleaner impl when const for / const iterators exist */
const SUPPORTED_NAMES: &[&str] = &const {
let mut i = 0;
let mut arr = [""; SUPPORTED.len()];
while i < SUPPORTED.len() {
arr[i] = SUPPORTED[i].0;
i += 1;
}

arr
};

Err(anyhow::anyhow!(
"Couldn't find {}",
SUPPORTED_NAMES.join(" or ")
))
}
102 changes: 86 additions & 16 deletions src/components/format.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
pub trait Format {
fn format(&self, src: &std::path::Path) -> anyhow::Result<()>;
fn format(&self, proj: &crate::Project) -> anyhow::Result<()>;
}

pub struct ClangFormat;

impl Format for ClangFormat {
fn format(&self, src: &std::path::Path) -> anyhow::Result<()> {
let paths = walkdir::WalkDir::new(src)
.into_iter()
.flat_map(std::convert::identity) // Filter out walkdir failures
.filter(|e| {
e.path()
.extension()
.filter(|ext| *ext == "c" || *ext == "h")
.is_some()
}) // Only formatting .c and .h files
.map(|e| e.path().to_owned()); // Retrieving paths of files
fn format(&self, proj: &crate::Project) -> anyhow::Result<()> {
let paths = proj.src_files()
.collect::<Vec<_>>();

let cmd = std::process::Command::new("clang-format")
.args(paths)
Expand All @@ -33,11 +25,89 @@ impl Format for ClangFormat {
}
}

pub struct Uncrustify;

impl Format for Uncrustify {
fn format(&self, proj: &crate::Project) -> anyhow::Result<()> {
let paths = proj.src_files()
.collect::<Vec<_>>();

let mut cmd = std::process::Command::new("uncrustify");

if let Some(ref f) = proj.config().formatter {
if let Some(ref u) = f.uncrustify {
cmd
.arg("-c")
.arg(&u.config);
}
}

let cmd = cmd
.args(paths)
.arg("--no-backup")
.output()?;

if cmd.status.success() {
Ok(())
} else {
Err(anyhow::anyhow!(
"Failed to format files. {}",
String::from_utf8_lossy(&cmd.stderr)
))
}
}
}

const SUPPORTED: &[(&'static str, fn() -> Box<dyn Format>)] = &[
( "clang-format", || Box::new(ClangFormat) ),
( "uncrustify", || Box::new(Uncrustify) )
];

/* todo: cleaner impl when const for / const iterators exist */
const SUPPORTED_NAMES: &[&str] = &const {
let mut i = 0;
let mut arr = [""; SUPPORTED.len()];
while i < SUPPORTED.len() {
arr[i] = SUPPORTED[i].0;
i += 1;
}

arr
};

/// Tries to find an available C formatter
/// Currently only supports clang-format.
pub fn try_locate() -> anyhow::Result<Box<dyn Format>> {
match which::which("clang-format") {
Ok(_) => Ok(Box::new(ClangFormat)),
Err(_) => Err(anyhow::anyhow!("Couldn't find clang-format.")),
pub fn try_locate(proj: &crate::Project) -> anyhow::Result<Box<dyn Format>> {
let default = proj.config().formatter
.as_ref()
.map(|f| f.default.as_ref())
.flatten();

let backends = if let Some(d) = default {
match d.as_ref() {
"clang-format" | "uncrustify" => {
let mut c = SUPPORTED.to_vec();
let target = c.iter().position(|e| e.0 == d).unwrap();
c.swap(0, target);
std::borrow::Cow::Owned(c)
},

_ => {
anyhow::bail!("Unrecognized default formatter: {d}");
}
}
} else {
std::borrow::Cow::Borrowed(SUPPORTED)
};

for (bin, make) in backends.as_ref() {
if which::which(bin).is_ok() {
return Ok(make());
}
}

Err(anyhow::anyhow!(
"Couldn't find {}",
SUPPORTED_NAMES.join(" or ")
))
}
21 changes: 15 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ nestify::nest! {
pub package: pub struct ConfigPackage {
pub name: String,
/// Optional location to output the target binary
pub bin: Option<String>
pub bin: Option<std::path::PathBuf>
},

#[serde(default)]
pub dependencies: HashMap<String, #[serde(untagged)] pub enum ConfigDependency {
Path {
path: String,
path: std::path::PathBuf,
},
Git {
git: String
Expand All @@ -36,13 +36,22 @@ nestify::nest! {
}>,

pub formatter: Option<pub struct ConfigFormatter {
pub clang_format: toml::Table,
pub default: Option<String>,

pub clang_format: Option<pub struct ConfigClangFormat {
/* nada */
}>,
pub uncrustify: Option<pub struct ConfigUncrustify {
pub config: std::path::PathBuf
}>
}>,

pub docgen: Option<pub struct ConfigDocgen {
pub doxygen: pub struct ConfigDoxygen {
pub doxyfile: String
},
pub default: Option<String>,

pub doxygen: Option<pub struct ConfigDoxygen {
pub doxyfile: std::path::PathBuf
}>,
}>
}
}
Loading

0 comments on commit ec115eb

Please sign in to comment.