Skip to content

Commit bc223a7

Browse files
committed
Allow the migration directory to be overridden
This currently only affects the generator, as we don't have tests for the other commands yet. This is to allow us to use CLI on our own codebase again, as we have a non-standard migration directory structure.
1 parent 4e0f73c commit bc223a7

2 files changed

Lines changed: 90 additions & 26 deletions

File tree

diesel_cli/src/main.rs

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@ fn main() {
3131

3232
let migration_subcommand = SubCommand::with_name("migration")
3333
.setting(AppSettings::VersionlessSubcommands)
34-
.subcommand(
34+
.arg(Arg::with_name("MIGRATION_DIRECTORY")
35+
.long("migration-dir")
36+
.help("The location of your migration directory. By default this \
37+
will look for a directory called `migrations` in the \
38+
current directory and its parents.")
39+
.takes_value(true)
40+
.global(true)
41+
).subcommand(
3542
SubCommand::with_name("run")
3643
.about("Runs all pending migrations")
3744
).subcommand(
@@ -102,11 +109,11 @@ fn run_migration_command(matches: &ArgMatches) {
102109
match matches.subcommand() {
103110
("run", Some(_)) => {
104111
call_with_conn!(database_url, migrations::run_pending_migrations)
105-
.map_err(handle_error).unwrap();
112+
.unwrap_or_else(handle_error);
106113
}
107114
("revert", Some(_)) => {
108115
call_with_conn!(database_url, migrations::revert_latest_migration)
109-
.map_err(handle_error).unwrap();
116+
.unwrap_or_else(handle_error);
110117
}
111118
("redo", Some(_)) => {
112119
call_with_conn!(database_url, redo_latest_migration);
@@ -115,13 +122,12 @@ fn run_migration_command(matches: &ArgMatches) {
115122
let migration_name = args.value_of("MIGRATION_NAME").unwrap();
116123
let version = migration_version(args);
117124
let versioned_name = format!("{}_{}", version, migration_name);
118-
let mut migration_dir = migrations::find_migrations_directory()
119-
.map_err(handle_error).unwrap().join(versioned_name);
125+
let migration_dir = migrations_dir(args).join(versioned_name);
120126
fs::create_dir(&migration_dir).unwrap();
121127

122128
let migration_dir_relative = convert_absolute_path_to_relative(
123-
&mut migration_dir,
124-
&mut env::current_dir().unwrap()
129+
&migration_dir,
130+
&env::current_dir().unwrap()
125131
);
126132

127133
let up_path = migration_dir.join("up.sql");
@@ -141,12 +147,23 @@ fn migration_version<'a>(matches: &'a ArgMatches) -> Box<Display + 'a> {
141147
.unwrap_or_else(|| Box::new(Local::now().format("%Y%m%d%H%M%S")))
142148
}
143149

150+
fn migrations_dir(matches: &ArgMatches) -> PathBuf {
151+
matches.value_of("MIGRATION_DIRECTORY")
152+
.map(PathBuf::from)
153+
.or_else(|| {
154+
env::var("MIGRATION_DIRECTORY").map(PathBuf::from).ok()
155+
}).unwrap_or_else(|| {
156+
migrations::find_migrations_directory()
157+
.unwrap_or_else(handle_error)
158+
})
159+
}
160+
144161
fn run_setup_command(matches: &ArgMatches) {
145162
migrations::find_migrations_directory()
146-
.unwrap_or_else(|_|
147-
create_migrations_directory()
148-
.map_err(handle_error).unwrap()
149-
);
163+
.unwrap_or_else(|_| {
164+
create_migrations_directory()
165+
.unwrap_or_else(handle_error)
166+
});
150167

151168
database::setup_database(matches).unwrap_or_else(handle_error);
152169
}
@@ -204,22 +221,23 @@ fn redo_latest_migration<Conn>(conn: &Conn) where
204221
}).unwrap_or_else(handle_error);
205222
}
206223

207-
fn handle_error<E: Error>(error: E) {
224+
fn handle_error<E: Error, T>(error: E) -> T {
208225
panic!("{}", error);
209226
}
210227

211228
// Converts an absolute path to a relative path, with the restriction that the
212229
// target path must be in the same directory or above the current path.
213-
fn convert_absolute_path_to_relative(target_path: &mut PathBuf, current_path: &mut PathBuf)
230+
fn convert_absolute_path_to_relative(target_path: &Path, mut current_path: &Path)
214231
-> PathBuf
215232
{
216233
let mut result = PathBuf::new();
217-
let target_path = target_path.as_path();
218-
let mut current_path = current_path.as_path();
219234

220235
while !target_path.starts_with(current_path) {
221236
result.push("..");
222-
current_path = current_path.parent().unwrap();
237+
match current_path.parent() {
238+
Some(parent) => current_path = parent,
239+
None => return target_path.into(),
240+
}
223241
}
224242

225243
result.join(strip_prefix(target_path, current_path))
@@ -291,19 +309,19 @@ mod tests {
291309
#[test]
292310
fn convert_absolute_path_to_relative_works() {
293311
assert_eq!(PathBuf::from("migrations/12345_create_user"),
294-
convert_absolute_path_to_relative(&mut PathBuf::from("projects/foo/migrations/12345_create_user"),
295-
&mut PathBuf::from("projects/foo")));
312+
convert_absolute_path_to_relative(&PathBuf::from("projects/foo/migrations/12345_create_user"),
313+
&PathBuf::from("projects/foo")));
296314
assert_eq!(PathBuf::from("../migrations/12345_create_user"),
297-
convert_absolute_path_to_relative(&mut PathBuf::from("projects/foo/migrations/12345_create_user"),
298-
&mut PathBuf::from("projects/foo/src")));
315+
convert_absolute_path_to_relative(&PathBuf::from("projects/foo/migrations/12345_create_user"),
316+
&PathBuf::from("projects/foo/src")));
299317
assert_eq!(PathBuf::from("../../../migrations/12345_create_user"),
300-
convert_absolute_path_to_relative(&mut PathBuf::from("projects/foo/migrations/12345_create_user"),
301-
&mut PathBuf::from("projects/foo/src/controllers/errors")));
318+
convert_absolute_path_to_relative(&PathBuf::from("projects/foo/migrations/12345_create_user"),
319+
&PathBuf::from("projects/foo/src/controllers/errors")));
302320
assert_eq!(PathBuf::from("12345_create_user"),
303-
convert_absolute_path_to_relative(&mut PathBuf::from("projects/foo/migrations/12345_create_user"),
304-
&mut PathBuf::from("projects/foo/migrations")));
321+
convert_absolute_path_to_relative(&PathBuf::from("projects/foo/migrations/12345_create_user"),
322+
&PathBuf::from("projects/foo/migrations")));
305323
assert_eq!(PathBuf::from("../12345_create_user"),
306-
convert_absolute_path_to_relative(&mut PathBuf::from("projects/foo/migrations/12345_create_user"),
307-
&mut PathBuf::from("projects/foo/migrations/67890_create_post")));
324+
convert_absolute_path_to_relative(&PathBuf::from("projects/foo/migrations/12345_create_user"),
325+
&PathBuf::from("projects/foo/migrations/67890_create_post")));
308326
}
309327
}

diesel_cli/tests/migrations.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,49 @@ Creating migrations/1234_hello/down.sql
4949
assert!(p.has_file("migrations/1234_hello/up.sql"));
5050
assert!(p.has_file("migrations/1234_hello/down.sql"));
5151
}
52+
53+
#[test]
54+
fn migration_directory_can_be_specified_for_generate_by_command_line_arg() {
55+
let p = project("migration_name")
56+
.folder("foo")
57+
.build();
58+
let result = p.command("migration")
59+
.arg("generate")
60+
.arg("stuff")
61+
.arg("--version=12345")
62+
.arg("--migration-dir=foo")
63+
.run();
64+
65+
let expected_stdout = "\
66+
Creating foo/12345_stuff/up.sql
67+
Creating foo/12345_stuff/down.sql
68+
";
69+
assert!(result.is_success(), "Command failed: {:?}", result);
70+
assert_eq!(expected_stdout, result.stdout());
71+
72+
assert!(p.has_file("foo/12345_stuff/up.sql"));
73+
assert!(p.has_file("foo/12345_stuff/down.sql"));
74+
}
75+
76+
#[test]
77+
fn migration_directory_can_be_specified_for_generate_by_env_var() {
78+
let p = project("migration_name")
79+
.folder("bar")
80+
.build();
81+
let result = p.command("migration")
82+
.arg("generate")
83+
.arg("stuff")
84+
.arg("--version=12345")
85+
.env("MIGRATION_DIRECTORY", "bar")
86+
.run();
87+
88+
let expected_stdout = "\
89+
Creating bar/12345_stuff/up.sql
90+
Creating bar/12345_stuff/down.sql
91+
";
92+
assert!(result.is_success(), "Command failed: {:?}", result);
93+
assert_eq!(expected_stdout, result.stdout());
94+
95+
assert!(p.has_file("bar/12345_stuff/up.sql"));
96+
assert!(p.has_file("bar/12345_stuff/down.sql"));
97+
}

0 commit comments

Comments
 (0)