Skip to content

Commit 223a1e4

Browse files
committed
Rewrite embed_migrations! to be a real proc macro
Remove the proc-macro-hack for `embed_migrations!` as it is not required anymore. This enables importing the macro via use. Also migrates `migrations_macros` to the 2018 edition.
1 parent fe87242 commit 223a1e4

7 files changed

Lines changed: 107 additions & 135 deletions

File tree

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ script:
7171
(cd "examples/$BACKEND" && ./test_all) &&
7272
(cd diesel_cli && cargo test --no-default-features --features "$BACKEND") &&
7373
(cd diesel_migrations/migrations_internals && cargo test ) &&
74-
(cd diesel_migrations/migrations_macros && cargo test ) &&
74+
(cd diesel_migrations/migrations_macros && cargo test --features "$BACKEND diesel/$BACKEND" ) &&
7575
(cd diesel_migrations/ && cargo test --features "$BACKEND diesel/$BACKEND" ) &&
7676
if [[ "$TRAVIS_RUST_VERSION" == nightly* ]]; then
7777
(cd diesel_tests && cargo test --no-default-features --features "unstable $BACKEND")

_build/azure-pipelines-template.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
rust_version: $(RUSTUP_TOOLCHAIN)
6161
bash: |
6262
(cd diesel_migrations/migrations_internals && cargo test ) &&
63-
(cd diesel_migrations/migrations_macros && cargo test ) &&
63+
(cd diesel_migrations/migrations_macros && cargo test --features "$BACKEND diesel/$BACKEND" ) &&
6464
(cd diesel_migrations/ && cargo test --features "$BACKEND diesel/$BACKEND" )
6565
displayName: Test diesel-migrations
6666
- template: failable_step.yml

diesel_migrations/migrations_macros/Cargo.toml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0"
66
description = "Codegeneration macros for diesels embedded migrations"
77
documentation = "https://docs.diesel.rs"
88
homepage = "https://diesel.rs"
9+
edition = "2018"
910

1011
[dependencies]
11-
syn = { version = "1", features = ["extra-traits"] }
1212
quote = "1"
1313
proc-macro2 = "1"
1414

@@ -18,9 +18,24 @@ path = "../migrations_internals"
1818

1919
[dev-dependencies]
2020
tempfile = "3.0.0"
21+
dotenv = ">=0.8, <0.11"
22+
cfg-if = "0.1.0"
23+
24+
[dev-dependencies.diesel]
25+
version = "~2.0.0"
26+
path = "../../diesel"
27+
default-features = false
28+
29+
[dev-dependencies.diesel_migrations]
30+
version = "~1.4.0"
31+
path = "../"
32+
default-features = false
2133

2234
[lib]
2335
proc-macro = true
2436

2537
[features]
2638
default = []
39+
sqlite = []
40+
postgresql = []
41+
mysql = []

diesel_migrations/migrations_macros/src/embed_migrations.rs

Lines changed: 42 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,17 @@
1-
use proc_macro2;
2-
use syn;
3-
4-
use migrations::migration_directory_from_given_path;
1+
use crate::migrations::migration_directory_from_given_path;
52
use migrations_internals::{migration_paths_in_directory, version_from_path};
3+
use quote::quote;
64
use std::error::Error;
75
use std::fs::DirEntry;
86
use std::path::Path;
97

10-
use util::{get_option, get_options_from_input};
11-
12-
pub fn derive_embed_migrations(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
13-
fn bug() -> ! {
14-
panic!(
15-
"This is a bug. Please open a Github issue \
16-
with your invocation of `embed_migrations!"
17-
);
18-
}
19-
20-
let options =
21-
get_options_from_input(&parse_quote!(embed_migrations_options), &input.attrs, bug);
22-
let migrations_path_opt = options
23-
.as_ref()
24-
.map(|o| get_option(o, "migrations_path", bug));
8+
pub fn expand(path: String) -> proc_macro2::TokenStream {
9+
dbg!(&path);
10+
let migrations_path_opt = if path.is_empty() {
11+
None
12+
} else {
13+
Some(path.replace("\"", ""))
14+
};
2515
let migrations_expr =
2616
migration_directory_from_given_path(migrations_path_opt.as_ref().map(String::as_str))
2717
.and_then(|path| migration_literals_from_path(&path));
@@ -30,54 +20,48 @@ pub fn derive_embed_migrations(input: &syn::DeriveInput) -> proc_macro2::TokenSt
3020
Err(e) => panic!("Error reading migrations: {}", e),
3121
};
3222

33-
// These are split into multiple `quote!` calls to avoid recursion limit
34-
let embedded_migration_def = quote!(
35-
struct EmbeddedMigration {
36-
version: &'static str,
37-
up_sql: &'static str,
38-
}
23+
quote! {
24+
#[allow(dead_code)]
25+
mod embedded_migrations {
26+
extern crate diesel;
27+
extern crate diesel_migrations;
3928

40-
impl Migration for EmbeddedMigration {
41-
fn version(&self) -> &str {
42-
self.version
43-
}
29+
use self::diesel_migrations::*;
30+
use self::diesel::connection::SimpleConnection;
31+
use std::io;
4432

45-
fn run(&self, conn: &SimpleConnection) -> Result<(), RunMigrationsError> {
46-
conn.batch_execute(self.up_sql).map_err(Into::into)
47-
}
33+
const ALL_MIGRATIONS: &[&Migration] = &[#(#migrations_expr),*];
4834

49-
fn revert(&self, _conn: &SimpleConnection) -> Result<(), RunMigrationsError> {
50-
unreachable!()
35+
struct EmbeddedMigration {
36+
version: &'static str,
37+
up_sql: &'static str,
5138
}
52-
}
53-
);
5439

55-
let run_fns = quote!(
56-
pub fn run<C: MigrationConnection>(conn: &C) -> Result<(), RunMigrationsError> {
57-
run_with_output(conn, &mut io::sink())
58-
}
59-
60-
pub fn run_with_output<C: MigrationConnection>(
61-
conn: &C,
62-
out: &mut io::Write,
63-
) -> Result<(), RunMigrationsError> {
64-
run_migrations(conn, ALL_MIGRATIONS.iter().map(|v| *v), out)
65-
}
66-
);
67-
68-
quote! {
69-
extern crate diesel;
70-
extern crate diesel_migrations;
40+
impl Migration for EmbeddedMigration {
41+
fn version(&self) -> &str {
42+
self.version
43+
}
7144

72-
use self::diesel_migrations::*;
73-
use self::diesel::connection::SimpleConnection;
74-
use std::io;
45+
fn run(&self, conn: &SimpleConnection) -> Result<(), RunMigrationsError> {
46+
conn.batch_execute(self.up_sql).map_err(Into::into)
47+
}
7548

76-
const ALL_MIGRATIONS: &[&Migration] = &[#(#migrations_expr),*];
49+
fn revert(&self, _conn: &SimpleConnection) -> Result<(), RunMigrationsError> {
50+
unreachable!()
51+
}
52+
}
7753

78-
#embedded_migration_def
54+
pub fn run<C: MigrationConnection>(conn: &C) -> Result<(), RunMigrationsError> {
55+
run_with_output(conn, &mut io::sink())
56+
}
7957

80-
#run_fns
58+
pub fn run_with_output<C: MigrationConnection>(
59+
conn: &C,
60+
out: &mut io::Write,
61+
) -> Result<(), RunMigrationsError> {
62+
run_migrations(conn, ALL_MIGRATIONS.iter().map(|v| *v), out)
63+
}
64+
}
8165
}
8266
}
8367

diesel_migrations/migrations_macros/src/lib.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,57 @@
2121
clippy::used_underscore_binding
2222
)]
2323
#![cfg_attr(test, allow(clippy::option_unwrap_used, clippy::result_unwrap_used))]
24-
extern crate migrations_internals;
2524
extern crate proc_macro;
26-
extern crate proc_macro2;
27-
#[macro_use]
28-
extern crate quote;
29-
#[macro_use]
30-
extern crate syn;
3125

3226
mod embed_migrations;
3327
mod migrations;
34-
mod util;
3528

3629
use proc_macro::TokenStream;
37-
use syn::DeriveInput;
3830

39-
#[proc_macro_derive(EmbedMigrations, attributes(embed_migrations_options))]
40-
pub fn derive_embed_migrations(input: TokenStream) -> TokenStream {
41-
let item = parse_macro_input!(input as DeriveInput);
42-
embed_migrations::derive_embed_migrations(&item)
31+
/// This macro will read your migrations at compile time, and embed a module you can use to execute
32+
/// them at runtime without the migration files being present on the file system. This is useful if
33+
/// you would like to use Diesel's migration infrastructure, but want to ship a single executable
34+
/// file (such as for embedded applications). It can also be used to apply migrations to an in
35+
/// memory database (Diesel does this for its own test suite).
36+
///
37+
/// You can optionally pass the path to the migrations directory to this macro. When left
38+
/// unspecified, Diesel Codegen will search for the migrations directory in the same way that
39+
/// Diesel CLI does. If specified, the path should be relative to the directory where `Cargo.toml`
40+
/// resides.
41+
///
42+
/// # Examples
43+
///
44+
/// ```rust
45+
/// # use diesel_migrations::embed_migrations;
46+
/// # include!("../../../diesel/src/doctest_setup.rs");
47+
/// # table! {
48+
/// # users {
49+
/// # id -> Integer,
50+
/// # name -> VarChar,
51+
/// # }
52+
/// # }
53+
/// #
54+
/// # #[cfg(feature = "postgres")]
55+
/// # embed_migrations!("../../migrations/postgresql");
56+
/// # #[cfg(all(feature = "mysql", not(feature = "postgres")))]
57+
/// # embed_migrations!("../../migrations/mysql");
58+
/// # #[cfg(all(feature = "sqlite", not(any(feature = "postgres", feature = "mysql"))))]
59+
/// embed_migrations!("../../migrations/sqlite");
60+
///
61+
/// fn main() {
62+
/// let connection = establish_connection();
63+
///
64+
/// // This will run the necessary migrations.
65+
/// embedded_migrations::run(&connection);
66+
///
67+
/// // By default the output is thrown out. If you want to redirect it to stdout, you
68+
/// // should call embedded_migrations::run_with_output.
69+
/// embedded_migrations::run_with_output(&connection, &mut std::io::stdout());
70+
/// }
71+
/// ```
72+
#[proc_macro]
73+
pub fn embed_migrations(input: TokenStream) -> TokenStream {
74+
embed_migrations::expand(input.to_string())
4375
.to_string()
4476
.parse()
4577
.unwrap()

diesel_migrations/migrations_macros/src/migrations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn resolve_migrations_directory(
3232

3333
#[cfg(test)]
3434
mod tests {
35-
extern crate tempfile;
35+
use tempfile;
3636

3737
use self::tempfile::Builder;
3838
use super::resolve_migrations_directory;

diesel_migrations/src/lib.rs

Lines changed: 2 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -130,64 +130,5 @@ pub mod connection {
130130
pub use migrations_internals::connection::MigrationConnection;
131131
}
132132

133-
#[macro_export]
134-
/// This macro will read your migrations at compile time, and embed a module you can use to execute
135-
/// them at runtime without the migration files being present on the file system. This is useful if
136-
/// you would like to use Diesel's migration infrastructure, but want to ship a single executable
137-
/// file (such as for embedded applications). It can also be used to apply migrations to an in
138-
/// memory database (Diesel does this for its own test suite).
139-
///
140-
/// You can optionally pass the path to the migrations directory to this macro. When left
141-
/// unspecified, Diesel Codegen will search for the migrations directory in the same way that
142-
/// Diesel CLI does. If specified, the path should be relative to the directory where `Cargo.toml`
143-
/// resides.
144-
///
145-
/// # Examples
146-
///
147-
/// ```rust
148-
/// # #[macro_use] extern crate diesel;
149-
/// # #[macro_use] extern crate diesel_migrations;
150-
/// # include!("../../diesel/src/doctest_setup.rs");
151-
/// # table! {
152-
/// # users {
153-
/// # id -> Integer,
154-
/// # name -> VarChar,
155-
/// # }
156-
/// # }
157-
/// #
158-
/// # #[cfg(feature = "postgres")]
159-
/// # embed_migrations!("../migrations/postgresql");
160-
/// # #[cfg(all(feature = "mysql", not(feature = "postgres")))]
161-
/// # embed_migrations!("../migrations/mysql");
162-
/// # #[cfg(all(feature = "sqlite", not(any(feature = "postgres", feature = "mysql"))))]
163-
/// embed_migrations!("../migrations/sqlite");
164-
///
165-
/// fn main() {
166-
/// let connection = establish_connection();
167-
///
168-
/// // This will run the necessary migrations.
169-
/// embedded_migrations::run(&connection);
170-
///
171-
/// // By default the output is thrown out. If you want to redirect it to stdout, you
172-
/// // should call embedded_migrations::run_with_output.
173-
/// embedded_migrations::run_with_output(&connection, &mut std::io::stdout());
174-
/// }
175-
/// ```
176-
macro_rules! embed_migrations {
177-
() => {
178-
#[allow(dead_code)]
179-
mod embedded_migrations {
180-
#[derive(EmbedMigrations)]
181-
struct _Dummy;
182-
}
183-
};
184-
185-
($migrations_path:expr) => {
186-
#[allow(dead_code)]
187-
mod embedded_migrations {
188-
#[derive(EmbedMigrations)]
189-
#[embed_migrations_options(migrations_path=$migrations_path)]
190-
struct _Dummy;
191-
}
192-
};
193-
}
133+
#[doc(inline)]
134+
pub use migrations_macros::embed_migrations;

0 commit comments

Comments
 (0)