Display a package

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2024-03-27 11:34:09 +01:00
parent 1d9ea5a699
commit 11ecc75393
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
5 changed files with 81 additions and 17 deletions

12
Cargo.lock generated
View File

@ -35,8 +35,10 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bok", "bok",
"bok-macro", "bok-macro",
"prettyplease",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn",
] ]
[[package]] [[package]]
@ -45,6 +47,16 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "prettyplease"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7"
dependencies = [
"proc-macro2",
"syn",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.78" version = "1.0.78"

View File

@ -101,7 +101,7 @@ pub fn derive_repository(input: TokenStream) -> TokenStream {
/// e.g.: /// e.g.:
/// ``` /// ```
/// impl MyPackage { /// impl MyPackage {
/// #[package(::bok_macro::to_code)] /// #[::bok_macro::to_code]
/// fn build() { /// fn build() {
/// ... /// ...
/// } /// }
@ -216,6 +216,7 @@ pub fn package(attrs: TokenStream, input: TokenStream) -> TokenStream {
#[proc_macro_derive(Package)] #[proc_macro_derive(Package)]
pub fn derive_package(input: TokenStream) -> TokenStream { pub fn derive_package(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput); let input = parse_macro_input!(input as DeriveInput);
let input2 = input.clone();
let name = input.ident.clone(); let name = input.ident.clone();
let name_builder = quote::format_ident!("{name}Builder"); let name_builder = quote::format_ident!("{name}Builder");
@ -355,20 +356,76 @@ pub fn derive_package(input: TokenStream) -> TokenStream {
let opt_types2 = opt_types.clone(); let opt_types2 = opt_types.clone();
let non_opt_types2 = non_opt_types.clone(); let non_opt_types2 = non_opt_types.clone();
let expanded = quote! { let impl_base = quote! {
impl ::bok::Pkg for #name { impl ::bok::Pkg for #name {
fn base(&self) -> Option<&impl ::bok::Pkg> { fn base(&self) -> Option<&impl ::bok::Pkg> {
Some(&self.base) Some(&self.base)
} }
} }
// FIXME: proper formatting of all functions };
let pkg_struct = quote! {
#input2
};
let mut pkg_struct_str = String::new();
{
use ::core::fmt::Write;
write!(&mut pkg_struct_str, "{}", pkg_struct)
.expect("can't write package struct into string");
}
let expanded = quote! {
#impl_base
impl ::core::fmt::Display for #name { impl ::core::fmt::Display for #name {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
->::core::fmt::Result ->::core::fmt::Result
{ {
// FIXME: this sounds convoluted.
// first we make everything into a string, then we
// parse the string into tokenstream again to format it
// reason: the `prettyplease` works on `::syn::File`
// and I can't find an easy translation
// `TokenStream2 -> TokenStream`
use ::bok::Pkg; use ::bok::Pkg;
let pkg = self.package_code();
pkg.fmt(f) // don't add a method if it is just the base Trait implementation
fn maybe_add_fn(out: &mut String, name: &str, fn_str: &str) -> ::core::fmt::Result {
let str_base = "self . base () . unwrap () . ".to_owned() + name + " ()";
if fn_str.trim() != str_base {
use ::core::fmt::Write;
write!(out,
"#[::bok_macro::to_code]\n\
fn {}(&self) -> Result<(), ()> {{\n{}\n}}\n",
name, fn_str)
} else {
::core::fmt::Result::Ok(())
}
};
// from the Pkg trait
use ::core::fmt::Write;
let pkg_empty = ::bok::PkgEmpty{};
let mut pkg_string = String::new();
write!(&mut pkg_string, "{}", #pkg_struct_str)?;
write!(&mut pkg_string,
"impl ::bok::Pkg for {} {{\n",
::std::stringify!(#name)
)?;
maybe_add_fn(&mut pkg_string, "prepare", &self.prepare_code().to_string())?;
maybe_add_fn(&mut pkg_string, "configure", &self.configure_code().to_string())?;
maybe_add_fn(&mut pkg_string, "build", &self.build_code().to_string())?;
maybe_add_fn(&mut pkg_string, "check", &self.check_code().to_string())?;
maybe_add_fn(&mut pkg_string, "install", &self.install_code().to_string())?;
write!(&mut pkg_string, "}}\n")?;
let re_parsed = ::syn::parse_file(&pkg_string).unwrap();
let formatted = prettyplease::unparse(&re_parsed);
f.write_str(&formatted)
} }
} }
impl #name { impl #name {

View File

@ -16,3 +16,5 @@ bok = { path = "../bok" }
bok-macro = { path = "../bok-macro" } bok-macro = { path = "../bok-macro" }
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
prettyplease = "0.2"
syn = { version = "2", features = [ "full", "parsing" ] }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com> * Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com>
* *
* Licensed under the Apache License, Version 2.0 with LLVM exception (the "License"); * Licensed under the Apache License, Version 2.0 with LLVM exception (the
* you may not use this file except in compliance with the License. * "License"); you may not use this file except in compliance with the
* You may obtain a copy of the License and of the exception at * License. You may obtain a copy of the License and of the exception at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* https://spdx.org/licenses/LLVM-exception.html * https://spdx.org/licenses/LLVM-exception.html
@ -27,4 +27,6 @@ fn main() {
println!("pkgs2 - 1:{}", pkgs2.one().my_attr); println!("pkgs2 - 1:{}", pkgs2.one().my_attr);
println!("pkgs2 - 2:{}", pkgs2.two().my_attr); println!("pkgs2 - 2:{}", pkgs2.two().my_attr);
println!("pkgs2 - 3:{}", pkgs2.three().my_attr); println!("pkgs2 - 3:{}", pkgs2.three().my_attr);
println!("pkgs1:\n{}", pkgs1.one());
} }

View File

@ -131,15 +131,6 @@ pub trait Pkg: ::std::default::Default + ::core::fmt::Display {
self.check()?; self.check()?;
self.install() self.install()
} }
fn package_code(&self) -> ::proc_macro2::TokenStream {
::quote::quote! {
self.prepare()?;
self.configure()?;
self.build()?;
self.check()?;
self.install()
}
}
} }
#[derive(Default)] #[derive(Default)]