Skip to content

Commit 9ac77d1

Browse files
committed
Simplify migration filtering logic and be explicit about skipping migrations in the logs output.
Drive-by fix for spammy logs output when name validating the directory name of a migrations folder.
1 parent 8e120f6 commit 9ac77d1

File tree

2 files changed

+57
-57
lines changed

2 files changed

+57
-57
lines changed

refinery_core/src/traits/mod.rs

+54-56
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use crate::runner::Type;
77
use crate::{error::Kind, Error, Migration};
88

99
// Verifies applied and to be applied migrations returning Error if:
10-
// - `abort_divergent` is true and there are applied migrations with a different name and checksum but same version as a migration to be applied.
10+
// - `abort_divergent` is true and there are applied migrations with a different name and checksum
11+
// but same version as a migration to be applied.
1112
// - `abort_missing` is true and there are applied migrations that are missing on the file system
1213
// - there are repeated migrations with the same version to be applied
1314
pub(crate) fn verify_migrations(
@@ -18,83 +19,80 @@ pub(crate) fn verify_migrations(
1819
) -> Result<Vec<Migration>, Error> {
1920
migrations.sort();
2021

21-
for app in applied.iter() {
22+
for app in &applied {
2223
// iterate applied migrations on database and assert all migrations
2324
// applied on database exist on the file system and have the same checksum
24-
match migrations.iter().find(|m| m.version() == app.version()) {
25-
None => {
26-
if abort_missing {
27-
return Err(Error::new(Kind::MissingVersion(app.clone()), None));
28-
} else {
29-
log::error!(target: "refinery_core::traits::missing", "migration {} is missing from the filesystem", app);
30-
}
31-
}
32-
Some(migration) => {
33-
if migration != app {
34-
if abort_divergent {
35-
return Err(Error::new(
36-
Kind::DivergentVersion(app.clone(), migration.clone()),
37-
None,
38-
));
39-
} else {
40-
log::error!(
41-
target: "refinery_core::traits::divergent",
42-
"applied migration {} is different than filesystem one {}",
43-
app,
44-
migration
45-
);
46-
}
47-
}
25+
if let Err(_) = migrations.binary_search_by(|m| m.version().cmp(&app.version())) {
26+
if abort_missing {
27+
return Err(Error::new(Kind::MissingVersion(app.clone()), None));
28+
} else {
29+
log::warn!(target: "refinery_core::traits::missing", "migration {} is missing from the filesystem", app);
4830
}
4931
}
5032
}
5133

52-
let current: i32 = match applied.last() {
53-
Some(last) => {
54-
log::info!("current version: {}", last.version());
55-
last.version() as i32
56-
}
57-
None => {
58-
log::info!("schema history table is empty, going to apply all migrations");
59-
// use -1 as versions might start with 0
60-
-1
61-
}
34+
let stale = |migration: &Migration| {
35+
applied
36+
.last()
37+
.map(|latest| latest.version() >= migration.version())
38+
.unwrap_or(false)
6239
};
6340

6441
let mut to_be_applied = Vec::new();
65-
// iterate all migration files found on file system and assert that there are not migrations missing:
66-
// migrations which its version is inferior to the current version on the database, yet were not applied.
67-
// select to be applied all migrations with version greater than current
68-
for migration in migrations.into_iter() {
69-
if !applied
42+
// iterate all migration files found on file system and assert that there are not migrations
43+
// missing: migrations which its version is inferior to the current version on the database, yet
44+
// were not applied. select to be applied all migrations with version greater than current
45+
for migration in migrations {
46+
if let Some(app) = applied
7047
.iter()
71-
.any(|app| app.version() == migration.version())
48+
.find(|app| app.version() == migration.version())
7249
{
73-
if to_be_applied.contains(&migration) {
74-
return Err(Error::new(Kind::RepeatedVersion(migration), None));
75-
} else if migration.prefix() == &Type::Versioned
76-
&& current >= migration.version() as i32
77-
{
78-
if abort_missing {
79-
return Err(Error::new(Kind::MissingVersion(migration), None));
80-
} else {
81-
log::error!(target: "refinery_core::traits::missing", "found migration on file system {} not applied", migration);
82-
}
83-
} else {
84-
to_be_applied.push(migration);
50+
if *app == migration {
51+
continue;
52+
}
53+
54+
if abort_divergent {
55+
return Err(Error::new(
56+
Kind::DivergentVersion(app.clone(), migration.clone()),
57+
None,
58+
));
59+
}
60+
61+
log::warn!(
62+
target: "refinery_core::traits::divergent",
63+
"applied migration {app} is different than filesystem one {migration} => skipping {migration}",
64+
);
65+
continue;
66+
}
67+
68+
if to_be_applied.contains(&migration) {
69+
return Err(Error::new(Kind::RepeatedVersion(migration), None));
70+
}
71+
72+
if migration.prefix() == &Type::Versioned && stale(&migration) {
73+
if abort_missing {
74+
return Err(Error::new(Kind::MissingVersion(migration), None));
8575
}
76+
77+
log::error!(target: "refinery_core::traits::missing", "found strictly versioned, not applied migration on file system => skipping: {migration}");
78+
continue;
8679
}
80+
81+
to_be_applied.push(migration);
8782
}
83+
8884
// with these two iterations we both assert that all migrations found on the database
8985
// exist on the file system and have the same checksum, and all migrations found
90-
// on the file system are either on the database, or greater than the current, and therefore going to be applied
86+
// on the file system are either on the database, or greater than the current, and therefore going
87+
// to be applied
9188
Ok(to_be_applied)
9289
}
9390

9491
pub(crate) fn insert_migration_query(migration: &Migration, migration_table_name: &str) -> String {
9592
format!(
9693
"INSERT INTO {} (version, name, applied_on, checksum) VALUES ({}, '{}', '{}', '{}')",
97-
// safe to call unwrap as we just converted it to applied, and we are sure it can be formatted according to RFC 33339
94+
// safe to call unwrap as we just converted it to applied, and we are sure it can be formatted
95+
// according to RFC 33339
9896
migration_table_name,
9997
migration.version(),
10098
migration.name(),

refinery_core/src/util.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ pub fn parse_migration_name(name: &str) -> Result<(Type, i32, String), Error> {
6363
Ok((prefix, version, name))
6464
}
6565

66-
/// find migrations on file system recursively across directories given a location and [MigrationType]
66+
/// find migrations on file system recursively across directories given a location and
67+
/// [MigrationType]
6768
pub fn find_migration_files(
6869
location: impl AsRef<Path>,
6970
migration_type: MigrationType,
@@ -84,6 +85,7 @@ pub fn find_migration_files(
8485
// filter by migration file regex
8586
.filter(
8687
move |entry| match entry.file_name().and_then(OsStr::to_str) {
88+
Some(_) if entry.is_dir() => false,
8789
Some(file_name) if re.is_match(file_name) => true,
8890
Some(file_name) => {
8991
log::warn!(

0 commit comments

Comments
 (0)