use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use tempfile::tempdir;
pub fn fixture_path(name: &str) -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("..")
.join("fixtures")
.join(name)
}
pub fn python_path() -> String {
std::env::var("ALEMBIC_DJANGO_PYTHON").unwrap_or_else(|_| "python3".to_string())
}
pub fn bin_path() -> PathBuf {
let env_keys = ["CARGO_BIN_EXE_alembic"];
for key in env_keys {
if let Ok(value) = std::env::var(key) {
return PathBuf::from(value);
}
}
let target_dir = std::env::var("CARGO_TARGET_DIR")
.ok()
.map(PathBuf::from)
.unwrap_or_else(|| {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("..")
.join("target")
});
target_dir.join("debug").join("alembic")
}
pub fn run_command(mut command: Command, context: &str) {
let output = command.output().unwrap_or_else(|err| {
panic!("{context}: failed to start command: {err}");
});
if !output.status.success() {
panic!(
"{context}: command failed\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
}
pub fn django_available(python: &str) -> bool {
let output = Command::new(python)
.args(["-c", "import django, rest_framework"])
.output();
let available = match output {
Ok(result) => result.status.success(),
Err(_) => false,
};
if !available && std::env::var_os("ALEMBIC_DJANGO_PYTHON").is_some() {
panic!("ALEMBIC_DJANGO_PYTHON is set to '{python}', but django + djangorestframework are not importable there");
}
available
}
pub fn walkthrough_path(name: &str) -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("..")
.join("examples")
.join("walkthroughs")
.join(name)
}
pub fn write_django_config(dir: &Path, output: &Path) -> PathBuf {
let path = dir.join("django.yaml");
let data = format!(
r"backend: django
output: {}
project: alembic_project
app: alembic_app
python: python3
no_migrate: false
no_admin: false",
output.to_str().unwrap(),
);
fs::write(&path, data).expect("write django config to temp dir");
path
}
pub fn run_apply_django(fixture: &str) {
let python = python_path();
if !django_available(&python) {
eprintln!("skipping django e2e; django + djangorestframework not available for {python}");
return;
}
let out = tempdir().expect("create temp dir");
let config_file_path = write_django_config(out.path(), out.path());
let mut cmd = Command::new(bin_path());
cmd.env("ALEMBIC_STATE_PATH", out.path().join("state.json"));
cmd.args([
"apply",
"--backend-config",
config_file_path.to_str().unwrap(),
"--plan",
fixture_path(fixture).to_str().unwrap(),
]);
run_command(cmd, &format!("apply django ({fixture})"));
}