introduce rustfmt (#919)

* introduce rustfmt

* Cargofmt on all sea-orm crates & examples

* Revert testing script

* cargo fmt --manifest-path sea-orm-rocket/Cargo.toml --all

* add a script for formatting

* add nightly component for formatting

* set timeout and manual nightly install  in github action

* add flag for manifest-path

Co-authored-by: Billy Chan <ccw.billy.123@gmail.com>
This commit is contained in:
kyoto7250 2022-08-01 19:30:43 +09:00 committed by GitHub
parent a2fbbc7a57
commit dd545441d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 190 additions and 96 deletions

View File

@ -140,6 +140,58 @@ jobs:
-- --
-D warnings -D warnings
rustfmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
components: rustfmt
override: true
- name: Run rustfmt on `sea-orm` workspace
uses: actions-rs/cargo@v1
with:
command: fmt
args: >
--all
--
--check
- name: Run rustfmt on `sea-orm-cli`
uses: actions-rs/cargo@v1
with:
command: fmt
args: >
--manifest-path sea-orm-cli/Cargo.toml
--all
--
--check
- name: Run rustfmt on `sea-orm-migration`
uses: actions-rs/cargo@v1
with:
command: fmt
args: >
--manifest-path sea-orm-migration/Cargo.toml
--all
--
--check
- name: Run rustfmt on `sea-orm-rocket`
uses: actions-rs/cargo@v1
with:
command: fmt
args: >
--manifest-path sea-orm-rocket/Cargo.toml
--all
--
--check
compile-sqlite: compile-sqlite:
name: Compile SQLite name: Compile SQLite
needs: init needs: init
@ -326,6 +378,7 @@ jobs:
name: Examples name: Examples
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: examples-matrix needs: examples-matrix
timeout-minutes: 15
strategy: strategy:
fail-fast: false fail-fast: false
max-parallel: 12 max-parallel: 12
@ -352,6 +405,12 @@ jobs:
args: > args: >
--manifest-path ${{ matrix.path }} --manifest-path ${{ matrix.path }}
- name: check rustfmt
run: |
rustup override set nightly
rustup component add rustfmt
cargo +nightly fmt --manifest-path ${{ matrix.path }} --all -- --check
issues-matrix: issues-matrix:
name: Issues Matrix name: Issues Matrix
needs: init needs: init

24
build-tools/rustfmt.sh Normal file
View File

@ -0,0 +1,24 @@
#!/bin/bash
set -e
if [ -d ./build-tools ]; then
targets=(
"sea-orm-cli/Cargo.toml"
"sea-orm-codegen/Cargo.toml"
"sea-orm-macros/Cargo.toml"
"sea-orm-migration/Cargo.toml"
"sea-orm-rocket/Cargo.toml"
)
for target in "${targets[@]}"; do
echo "cargo +nightly fmt --manifest-path ${target} --all"
cargo +nightly fmt --manifest-path "${target}" --all
done
examples=(`find examples -type f -name 'Cargo.toml'`)
for example in "${examples[@]}"; do
echo "cargo +nightly fmt --manifest-path ${example} --all"
cargo +nightly fmt --manifest-path "${example}" --all
done
else
echo "Please execute this script from the repository root."
fi

View File

@ -163,7 +163,8 @@ async fn not_found(data: web::Data<AppState>, request: HttpRequest) -> Result<Ht
ctx.insert("uri", request.uri().path()); ctx.insert("uri", request.uri().path());
let template = &data.templates; let template = &data.templates;
let body = template.render("error/404.html.tera", &ctx) let body = template
.render("error/404.html.tera", &ctx)
.map_err(|_| error::ErrorInternalServerError("Template error"))?; .map_err(|_| error::ErrorInternalServerError("Template error"))?;
Ok(HttpResponse::Ok().content_type("text/html").body(body)) Ok(HttpResponse::Ok().content_type("text/html").body(body))

View File

@ -1,8 +1,8 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use devise::{DeriveGenerator, FromMeta, MapperBuild, Support, ValidatorBuild};
use devise::proc_macro2_diagnostics::SpanDiagnosticExt; use devise::proc_macro2_diagnostics::SpanDiagnosticExt;
use devise::syn::{self, spanned::Spanned}; use devise::syn::{self, spanned::Spanned};
use devise::{DeriveGenerator, FromMeta, MapperBuild, Support, ValidatorBuild};
const ONE_DATABASE_ATTR: &str = "missing `#[database(\"name\")]` attribute"; const ONE_DATABASE_ATTR: &str = "missing `#[database(\"name\")]` attribute";
const ONE_UNNAMED_FIELD: &str = "struct must have exactly one unnamed field"; const ONE_UNNAMED_FIELD: &str = "struct must have exactly one unnamed field";
@ -16,95 +16,89 @@ struct DatabaseAttribute {
pub fn derive_database(input: TokenStream) -> TokenStream { pub fn derive_database(input: TokenStream) -> TokenStream {
DeriveGenerator::build_for(input, quote!(impl sea_orm_rocket::Database)) DeriveGenerator::build_for(input, quote!(impl sea_orm_rocket::Database))
.support(Support::TupleStruct) .support(Support::TupleStruct)
.validator(ValidatorBuild::new() .validator(ValidatorBuild::new().struct_validate(|_, s| {
.struct_validate(|_, s| { if s.fields.len() == 1 {
if s.fields.len() == 1 { Ok(())
Ok(()) } else {
} else { Err(s.span().error(ONE_UNNAMED_FIELD))
Err(s.span().error(ONE_UNNAMED_FIELD)) }
}))
.outer_mapper(MapperBuild::new().struct_map(|_, s| {
let pool_type = match &s.fields {
syn::Fields::Unnamed(f) => &f.unnamed[0].ty,
_ => unreachable!("Support::TupleStruct"),
};
let decorated_type = &s.ident;
let db_ty = quote_spanned!(decorated_type.span() =>
<#decorated_type as sea_orm_rocket::Database>
);
quote_spanned! { decorated_type.span() =>
impl From<#pool_type> for #decorated_type {
fn from(pool: #pool_type) -> Self {
Self(pool)
}
} }
})
)
.outer_mapper(MapperBuild::new()
.struct_map(|_, s| {
let pool_type = match &s.fields {
syn::Fields::Unnamed(f) => &f.unnamed[0].ty,
_ => unreachable!("Support::TupleStruct"),
};
let decorated_type = &s.ident; impl std::ops::Deref for #decorated_type {
let db_ty = quote_spanned!(decorated_type.span() => type Target = #pool_type;
<#decorated_type as sea_orm_rocket::Database>
);
quote_spanned! { decorated_type.span() => fn deref(&self) -> &Self::Target {
impl From<#pool_type> for #decorated_type { &self.0
fn from(pool: #pool_type) -> Self {
Self(pool)
}
} }
}
impl std::ops::Deref for #decorated_type { impl std::ops::DerefMut for #decorated_type {
type Target = #pool_type; fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
fn deref(&self) -> &Self::Target {
&self.0
}
} }
}
impl std::ops::DerefMut for #decorated_type { #[rocket::async_trait]
fn deref_mut(&mut self) -> &mut Self::Target { impl<'r> rocket::request::FromRequest<'r> for &'r #decorated_type {
&mut self.0 type Error = ();
}
}
#[rocket::async_trait] async fn from_request(
impl<'r> rocket::request::FromRequest<'r> for &'r #decorated_type { req: &'r rocket::request::Request<'_>
type Error = (); ) -> rocket::request::Outcome<Self, Self::Error> {
match #db_ty::fetch(req.rocket()) {
async fn from_request( Some(db) => rocket::outcome::Outcome::Success(db),
req: &'r rocket::request::Request<'_> None => rocket::outcome::Outcome::Failure((
) -> rocket::request::Outcome<Self, Self::Error> { rocket::http::Status::InternalServerError, ()))
match #db_ty::fetch(req.rocket()) {
Some(db) => rocket::outcome::Outcome::Success(db),
None => rocket::outcome::Outcome::Failure((
rocket::http::Status::InternalServerError, ()))
}
}
}
impl rocket::Sentinel for &#decorated_type {
fn abort(rocket: &rocket::Rocket<rocket::Ignite>) -> bool {
#db_ty::fetch(rocket).is_none()
} }
} }
} }
})
) impl rocket::Sentinel for &#decorated_type {
fn abort(rocket: &rocket::Rocket<rocket::Ignite>) -> bool {
#db_ty::fetch(rocket).is_none()
}
}
}
}))
.outer_mapper(quote!(#[rocket::async_trait])) .outer_mapper(quote!(#[rocket::async_trait]))
.inner_mapper(MapperBuild::new() .inner_mapper(MapperBuild::new().try_struct_map(|_, s| {
.try_struct_map(|_, s| { let db_name = DatabaseAttribute::one_from_attrs("database", &s.attrs)?
let db_name = DatabaseAttribute::one_from_attrs("database", &s.attrs)? .map(|attr| attr.name)
.map(|attr| attr.name) .ok_or_else(|| s.span().error(ONE_DATABASE_ATTR))?;
.ok_or_else(|| s.span().error(ONE_DATABASE_ATTR))?;
let fairing_name = format!("'{}' Database Pool", db_name); let fairing_name = format!("'{}' Database Pool", db_name);
let pool_type = match &s.fields { let pool_type = match &s.fields {
syn::Fields::Unnamed(f) => &f.unnamed[0].ty, syn::Fields::Unnamed(f) => &f.unnamed[0].ty,
_ => unreachable!("Support::TupleStruct"), _ => unreachable!("Support::TupleStruct"),
}; };
Ok(quote_spanned! { pool_type.span() => Ok(quote_spanned! { pool_type.span() =>
type Pool = #pool_type; type Pool = #pool_type;
const NAME: &'static str = #db_name; const NAME: &'static str = #db_name;
fn init() -> sea_orm_rocket::Initializer<Self> { fn init() -> sea_orm_rocket::Initializer<Self> {
sea_orm_rocket::Initializer::with_name(#fairing_name) sea_orm_rocket::Initializer::with_name(#fairing_name)
} }
})
}) })
) }))
.to_tokens() .to_tokens()
} }

View File

@ -1,4 +1,4 @@
#![recursion_limit="256"] #![recursion_limit = "256"]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
//! # `sea_orm_rocket` - Code Generation //! # `sea_orm_rocket` - Code Generation
@ -7,7 +7,8 @@
//! is an implementation detail. This create should never be depended on //! is an implementation detail. This create should never be depended on
//! directly. //! directly.
#[macro_use] extern crate quote; #[macro_use]
extern crate quote;
mod database; mod database;

View File

@ -29,14 +29,16 @@ use rocket::serde::{Deserialize, Serialize};
/// # use rocket::launch; /// # use rocket::launch;
/// #[launch] /// #[launch]
/// fn rocket() -> _ { /// fn rocket() -> _ {
/// let figment = rocket::Config::figment() /// let figment = rocket::Config::figment().merge((
/// .merge(("databases.name", sea_orm_rocket::Config { /// "databases.name",
/// sea_orm_rocket::Config {
/// url: "db:specific@config&url".into(), /// url: "db:specific@config&url".into(),
/// min_connections: None, /// min_connections: None,
/// max_connections: 1024, /// max_connections: 1024,
/// connect_timeout: 3, /// connect_timeout: 3,
/// idle_timeout: None, /// idle_timeout: None,
/// })); /// },
/// ));
/// ///
/// rocket::custom(figment) /// rocket::custom(figment)
/// } /// }

View File

@ -1,13 +1,13 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{DerefMut}; use std::ops::DerefMut;
use rocket::{error, info_, Build, Ignite, Phase, Rocket, Sentinel};
use rocket::fairing::{self, Fairing, Info, Kind}; use rocket::fairing::{self, Fairing, Info, Kind};
use rocket::request::{FromRequest, Outcome, Request};
use rocket::http::Status; use rocket::http::Status;
use rocket::request::{FromRequest, Outcome, Request};
use rocket::{error, info_, Build, Ignite, Phase, Rocket, Sentinel};
use rocket::yansi::Paint;
use rocket::figment::providers::Serialized; use rocket::figment::providers::Serialized;
use rocket::yansi::Paint;
use crate::Pool; use crate::Pool;
@ -31,7 +31,9 @@ use crate::Pool;
/// ``` /// ```
/// ///
/// See the [`Database` derive](derive@crate::Database) for details. /// See the [`Database` derive](derive@crate::Database) for details.
pub trait Database: From<Self::Pool> + DerefMut<Target = Self::Pool> + Send + Sync + 'static { pub trait Database:
From<Self::Pool> + DerefMut<Target = Self::Pool> + Send + Sync + 'static
{
/// The [`Pool`] type of connections to this database. /// The [`Pool`] type of connections to this database.
/// ///
/// When `Database` is derived, this takes the value of the `Inner` type in /// When `Database` is derived, this takes the value of the `Inner` type in
@ -51,7 +53,7 @@ pub trait Database: From<Self::Pool> + DerefMut<Target = Self::Pool> + Send + Sy
/// ```rust /// ```rust
/// # mod _inner { /// # mod _inner {
/// # use rocket::launch; /// # use rocket::launch;
/// use sea_orm_rocket::{Database}; /// use sea_orm_rocket::Database;
/// # use sea_orm_rocket::MockPool as SeaOrmPool; /// # use sea_orm_rocket::MockPool as SeaOrmPool;
/// ///
/// #[derive(Database)] /// #[derive(Database)]
@ -90,10 +92,10 @@ pub trait Database: From<Self::Pool> + DerefMut<Target = Self::Pool> + Send + Sy
/// ```rust /// ```rust
/// # mod _inner { /// # mod _inner {
/// # use rocket::launch; /// # use rocket::launch;
/// use rocket::{Rocket, Build};
/// use rocket::fairing::{self, AdHoc}; /// use rocket::fairing::{self, AdHoc};
/// use rocket::{Build, Rocket};
/// ///
/// use sea_orm_rocket::{Database}; /// use sea_orm_rocket::Database;
/// # use sea_orm_rocket::MockPool as SeaOrmPool; /// # use sea_orm_rocket::MockPool as SeaOrmPool;
/// ///
/// #[derive(Database)] /// #[derive(Database)]
@ -124,8 +126,14 @@ pub trait Database: From<Self::Pool> + DerefMut<Target = Self::Pool> + Send + Sy
let dbtype = std::any::type_name::<Self>(); let dbtype = std::any::type_name::<Self>();
let fairing = Paint::default(format!("{}::init()", dbtype)).bold(); let fairing = Paint::default(format!("{}::init()", dbtype)).bold();
error!("Attempted to fetch unattached database `{}`.", Paint::default(dbtype).bold()); error!(
info_!("`{}` fairing must be attached prior to using this database.", fairing); "Attempted to fetch unattached database `{}`.",
Paint::default(dbtype).bold()
);
info_!(
"`{}` fairing must be attached prior to using this database.",
fairing
);
None None
} }
} }
@ -168,7 +176,6 @@ pub struct Initializer<D: Database>(Option<&'static str>, PhantomData<fn() -> D>
/// * If a connection is not available within `connect_timeout` seconds or /// * If a connection is not available within `connect_timeout` seconds or
/// another error occurs, the gaurd _fails_ with status `ServiceUnavailable` /// another error occurs, the gaurd _fails_ with status `ServiceUnavailable`
/// and the error is returned in `Some`. /// and the error is returned in `Some`.
///
pub struct Connection<'a, D: Database>(&'a <D::Pool as Pool>::Connection); pub struct Connection<'a, D: Database>(&'a <D::Pool as Pool>::Connection);
impl<D: Database> Initializer<D> { impl<D: Database> Initializer<D> {
@ -208,11 +215,13 @@ impl<D: Database> Fairing for Initializer<D> {
} }
async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result { async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
let workers: usize = rocket.figment() let workers: usize = rocket
.figment()
.extract_inner(rocket::Config::WORKERS) .extract_inner(rocket::Config::WORKERS)
.unwrap_or_else(|_| rocket::Config::default().workers); .unwrap_or_else(|_| rocket::Config::default().workers);
let figment = rocket.figment() let figment = rocket
.figment()
.focus(&format!("databases.{}", D::NAME)) .focus(&format!("databases.{}", D::NAME))
.merge(Serialized::default("max_connections", workers * 4)) .merge(Serialized::default("max_connections", workers * 4))
.merge(Serialized::default("connect_timeout", 5)); .merge(Serialized::default("connect_timeout", 5));

View File

@ -26,7 +26,11 @@ impl<A: fmt::Display, B: fmt::Display> fmt::Display for Error<A, B> {
} }
impl<A, B> std::error::Error for Error<A, B> impl<A, B> std::error::Error for Error<A, B>
where A: fmt::Debug + fmt::Display, B: fmt::Debug + fmt::Display {} where
A: fmt::Debug + fmt::Display,
B: fmt::Debug + fmt::Display,
{
}
impl<A, B> From<crate::figment::Error> for Error<A, B> { impl<A, B> From<crate::figment::Error> for Error<A, B> {
fn from(e: crate::figment::Error) -> Self { fn from(e: crate::figment::Error) -> Self {

View File

@ -7,14 +7,14 @@ pub use rocket::figment;
pub use rocket; pub use rocket;
mod config;
mod database; mod database;
mod error; mod error;
mod pool; mod pool;
mod config;
pub use self::config::Config;
pub use self::database::{Connection, Database, Initializer}; pub use self::database::{Connection, Database, Initializer};
pub use self::error::Error; pub use self::error::Error;
pub use self::pool::{Pool, MockPool}; pub use self::pool::{MockPool, Pool};
pub use self::config::Config;
pub use sea_orm_rocket_codegen::*; pub use sea_orm_rocket_codegen::*;