feat: add improved interactivity, config customizability, disable DRUF

This commit is contained in:
rzmk 2025-09-03 13:17:07 -04:00
parent 572cfab8ca
commit 3ab06a07ec
4 changed files with 349 additions and 190 deletions

View file

@ -5,12 +5,8 @@
- [DataStore extension](https://docs.ckan.org/en/2.11/maintaining/datastore.html) - [DataStore extension](https://docs.ckan.org/en/2.11/maintaining/datastore.html)
- [ckanext-scheming extension](https://github.com/ckan/ckanext-scheming) - [ckanext-scheming extension](https://github.com/ckan/ckanext-scheming)
- [DataPusher+ extension](https://github.com/dathere/datapusher-plus) - [DataPusher+ extension](https://github.com/dathere/datapusher-plus)
- [DRUF mode](https://github.com/dathere/datapusher-plus?tab=readme-ov-file#druf-dataset-resource-upload-first-workflow)
The [`datatablesview-plus` extension](https://github.com/dathere/ckanext-datatables-plus) is planned to be included in a future release. [DRUF mode](https://github.com/dathere/datapusher-plus?tab=readme-ov-file#druf-dataset-resource-upload-first-workflow) is available but disabled by default. The [`datatablesview-plus` extension](https://github.com/dathere/ckanext-datatables-plus) is planned to be included in a future release.
> [!NOTE]
> We plan on including customizability for enabling/disabling features in a future release.
## Quick start ## Quick start

View file

@ -1,6 +1,11 @@
mod questions;
mod steps;
mod styles; mod styles;
use crate::styles::{highlighted_text, important_text, step_text, success_text}; use crate::{
questions::{question_ckan_version, question_ssh, question_sysadmin},
styles::{highlighted_text, important_text, step_text, success_text},
};
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use human_panic::{metadata, setup_panic}; use human_panic::{metadata, setup_panic};
@ -19,6 +24,22 @@ struct Args {
default: bool, default: bool,
} }
struct Sysadmin {
username: String,
password: String,
email: String,
}
struct Config {
ssh: bool,
ckan_version: String,
sysadmin: Sysadmin,
extension_datastore: bool,
extension_ckanext_scheming: bool,
extension_datapusher_plus: bool,
druf_mode: bool,
}
fn main() -> Result<()> { fn main() -> Result<()> {
setup_panic!(metadata!() setup_panic!(metadata!()
.homepage("https://dathere.com") .homepage("https://dathere.com")
@ -26,33 +47,85 @@ fn main() -> Result<()> {
let args = Args::parse(); let args = Args::parse();
println!("Welcome to the ckan-devstaller!"); // Set up default config
println!( let sh = Shell::new()?;
"ckan-devstaller is provided by datHere - {}\n", let username = cmd!(sh, "whoami").read()?;
highlighted_text("https://datHere.com"), steps::step_intro();
);
println!(
"This installer should assist in setting up {} from a source installation along with ckan-compose (https://github.com/tino097/ckan-compose). If you have any issues, please report them at https://github.com/dathere/ckan-devstaller/issues.",
highlighted_text("CKAN 2.11.3")
);
println!(
"{}",
important_text(
"This installer is only intended for a brand new installation of Ubuntu 22.04."
)
);
let ans = if args.default { let default_config_text = r#"
true The default configuration for ckan-devstaller does the following:
- Install openssh-server to enable SSH access
- Install ckan-compose (https://github.com/tino097/ckan-compose) which sets up the CKAN backend (PostgreSQL, SOLR, Redis)
- Install CKAN v2.11.3
- Install the DataStore extension
- Install the ckanext-scheming extension
- Install the DataPusher+ extension
- Disable DRUF mode for DataPusher+
"#;
println!("{default_config_text}");
let answer_customize = if args.default {
false
} else { } else {
Confirm::new("Would you like to begin the installation?") Confirm::new(
.with_default(false) "Would you like to customize any of these features for your CKAN installation?",
.prompt()? )
.prompt()?
};
let default_sysadmin = Sysadmin {
username: username.clone(),
password: "password".to_string(),
email: format!("{username}@localhost"),
};
let config = if answer_customize {
let answer_ssh = question_ssh()?;
let answer_ckan_version = question_ckan_version()?;
let answer_sysadmin = question_sysadmin(username.clone())?;
// let answer_extension_datastore = Confirm::new("Would you like to install the DataStore extension?")
// .with_default(true)
// .prompt()?;
// let answer_extension_ckanext_scheming = Confirm::new("Would you like to install the ckanext-scheming extension?")
// .with_default(true)
// .prompt()?;
let answer_extension_datapusher_plus =
Confirm::new("Would you like to install the DataPusher+ extension?")
.with_default(true)
.prompt()?;
let answer_druf_mode = if answer_extension_datapusher_plus {
Confirm::new("Would you like to enable DRUF mode for DataPusher+?")
.with_default(false)
.prompt()?
} else {
false
};
Config {
ssh: answer_ssh,
ckan_version: answer_ckan_version,
sysadmin: answer_sysadmin,
extension_datastore: true,
extension_ckanext_scheming: true,
extension_datapusher_plus: answer_extension_datapusher_plus,
druf_mode: answer_druf_mode,
}
} else {
Config {
ssh: true,
ckan_version: "2.11.3".to_string(),
sysadmin: default_sysadmin,
extension_datastore: true,
extension_ckanext_scheming: true,
extension_datapusher_plus: true,
druf_mode: false,
}
}; };
if ans { let begin_installation = if args.default {
let sh = Shell::new()?; true
let username = cmd!(sh, "whoami").read()?; } else {
Confirm::new("Would you like to begin the installation?").prompt()?
};
if begin_installation {
println!("{}", important_text("Starting installation..."));
println!( println!(
"\n{} Running {} and {}...", "\n{} Running {} and {}...",
step_text("1."), step_text("1."),
@ -71,11 +144,20 @@ fn main() -> Result<()> {
success_text("✅ 1. Successfully ran update and upgrade commands.") success_text("✅ 1. Successfully ran update and upgrade commands.")
); );
println!("\n{} Installing curl and enabling SSH...", step_text("2.")); println!(
cmd!(sh, "sudo apt install curl openssh-server -y").run()?; "\n{} Installing {}...",
step_text("2."),
highlighted_text("curl")
);
cmd!(sh, "sudo apt install curl -y").run()?;
println!("{}", success_text("✅ 2.1. Successfully installed curl."));
if config.ssh {
println!("\n{} Installing openssh-server...", step_text("2."));
cmd!(sh, "sudo apt install openssh-server -y").run()?;
}
println!( println!(
"{}", "{}",
success_text("✅ 2. Successfully installed curl and enabled SSH.") success_text("✅ 2.2. Successfully installed openssh-server.")
); );
let dpkg_l_output = cmd!(sh, "dpkg -l").read()?; let dpkg_l_output = cmd!(sh, "dpkg -l").read()?;
@ -129,7 +211,11 @@ POSTGRES_PASSWORD=pass";
cmd!(sh, "sudo ../ahoy up").run()?; cmd!(sh, "sudo ../ahoy up").run()?;
println!("{}", success_text("✅ 5. Successfully ran ckan-compose.")); println!("{}", success_text("✅ 5. Successfully ran ckan-compose."));
println!("\n{} Installing CKAN 2.11.3...", step_text("6."),); println!(
"\n{} Installing CKAN {}...",
step_text("6."),
config.ckan_version
);
cmd!(sh, "sudo apt install python3-dev libpq-dev python3-pip python3-venv git-core redis-server -y").run()?; cmd!(sh, "sudo apt install python3-dev libpq-dev python3-pip python3-venv git-core redis-server -y").run()?;
cmd!(sh, "sudo mkdir -p /usr/lib/ckan/default").run()?; cmd!(sh, "sudo mkdir -p /usr/lib/ckan/default").run()?;
cmd!(sh, "sudo chown {username} /usr/lib/ckan/default").run()?; cmd!(sh, "sudo chown {username} /usr/lib/ckan/default").run()?;
@ -137,7 +223,11 @@ POSTGRES_PASSWORD=pass";
let venv = VirtualEnv::with_path(&sh, &venv_path)?; let venv = VirtualEnv::with_path(&sh, &venv_path)?;
venv.pip_upgrade("pip")?; venv.pip_upgrade("pip")?;
venv.pip_install( venv.pip_install(
"git+https://github.com/ckan/ckan.git@ckan-2.11.3#egg=ckan[requirements]", format!(
"git+https://github.com/ckan/ckan.git@ckan-{}#egg=ckan[requirements]",
config.ckan_version
)
.as_str(),
)?; )?;
cmd!(sh, "sudo mkdir -p /etc/ckan/default").run()?; cmd!(sh, "sudo mkdir -p /etc/ckan/default").run()?;
cmd!(sh, "sudo chown -R {username} /etc/ckan/").run()?; cmd!(sh, "sudo chown -R {username} /etc/ckan/").run()?;
@ -159,118 +249,124 @@ POSTGRES_PASSWORD=pass";
cmd!(sh, "sudo mkdir -p ckan/default").run()?; cmd!(sh, "sudo mkdir -p ckan/default").run()?;
cmd!(sh, "sudo chown {username}.{username} ckan/default").run()?; cmd!(sh, "sudo chown {username}.{username} ckan/default").run()?;
cmd!(sh, "ckan -c /etc/ckan/default/ckan.ini db init").run()?; cmd!(sh, "ckan -c /etc/ckan/default/ckan.ini db init").run()?;
cmd!(sh, "ckan -c /etc/ckan/default/ckan.ini user add {username} password=password email={username}@localhost").run()?; let sysadmin_username = config.sysadmin.username;
let sysadmin_password = config.sysadmin.password;
let sysadmin_email = config.sysadmin.email;
cmd!(sh, "ckan -c /etc/ckan/default/ckan.ini user add {sysadmin_username} password={sysadmin_password} email={sysadmin_email}").run()?;
cmd!( cmd!(
sh, sh,
"ckan -c /etc/ckan/default/ckan.ini sysadmin add {username}" "ckan -c /etc/ckan/default/ckan.ini sysadmin add {sysadmin_username}"
) )
.run()?; .run()?;
println!("{}", success_text("✅ 6. Installed CKAN 2.11.3."));
println!(
"\n{} Enabling DataStore plugin, adding config URLs in /etc/ckan/default/ckan.ini and updating permissions...",
step_text("7."),
);
// TODO: use the ckan config-tool command instead of rust-ini
let mut conf = ini::Ini::load_from_file("/etc/ckan/default/ckan.ini")?;
let app_main_section = conf.section_mut(Some("app:main")).unwrap();
let mut ckan_plugins = app_main_section.get("ckan.plugins").unwrap().to_string();
ckan_plugins.push_str(" datastore");
app_main_section.insert("ckan.plugins", ckan_plugins);
app_main_section.insert(
"ckan.datastore.write_url",
"postgresql://ckan_default:pass@localhost/datastore_default",
);
app_main_section.insert(
"ckan.datastore.read_url",
"postgresql://datastore_default:pass@localhost/datastore_default",
);
app_main_section.insert("ckan.datastore.sqlsearch.enabled", "true");
conf.write_to_file("/etc/ckan/default/ckan.ini")?;
let postgres_container_id = cmd!(
sh,
"sudo docker ps -aqf name=^ckan-devstaller-project-postgres$"
)
.read()?;
let set_permissions_output = cmd!(
sh,
"ckan -c /etc/ckan/default/ckan.ini datastore set-permissions"
)
.read()?;
std::fs::write("permissions.sql", set_permissions_output)?;
loop {
std::thread::sleep(std::time::Duration::from_secs(2));
if std::fs::exists("permissions.sql")? {
break;
}
}
sh.change_dir(format!("/home/{username}"));
cmd!(
sh,
"sudo docker cp permissions.sql {postgres_container_id}:/permissions.sql"
)
.run()?;
cmd!(sh, "sudo docker exec {postgres_container_id} psql -U ckan_default --set ON_ERROR_STOP=1 -f permissions.sql").run()?;
println!( println!(
"{}", "{}",
success_text( success_text(format!("✅ 6. Installed CKAN {}.", config.ckan_version).as_str())
"✅ 7. Enabled DataStore plugin, set DataStore URLs in /etc/ckan/default/ckan.ini, and updated permissions." );
if config.extension_datapusher_plus {
println!(
"\n{} Enabling DataStore plugin, adding config URLs in /etc/ckan/default/ckan.ini and updating permissions...",
step_text("7."),
);
let mut conf = ini::Ini::load_from_file("/etc/ckan/default/ckan.ini")?;
let app_main_section = conf.section_mut(Some("app:main")).unwrap();
let mut ckan_plugins = app_main_section.get("ckan.plugins").unwrap().to_string();
ckan_plugins.push_str(" datastore");
app_main_section.insert("ckan.plugins", ckan_plugins);
app_main_section.insert(
"ckan.datastore.write_url",
"postgresql://ckan_default:pass@localhost/datastore_default",
);
app_main_section.insert(
"ckan.datastore.read_url",
"postgresql://datastore_default:pass@localhost/datastore_default",
);
app_main_section.insert("ckan.datastore.sqlsearch.enabled", "true");
conf.write_to_file("/etc/ckan/default/ckan.ini")?;
let postgres_container_id = cmd!(
sh,
"sudo docker ps -aqf name=^ckan-devstaller-project-postgres$"
) )
); .read()?;
let set_permissions_output = cmd!(
sh,
"ckan -c /etc/ckan/default/ckan.ini datastore set-permissions"
)
.read()?;
std::fs::write("permissions.sql", set_permissions_output)?;
loop {
std::thread::sleep(std::time::Duration::from_secs(2));
if std::fs::exists("permissions.sql")? {
break;
}
}
sh.change_dir(format!("/home/{username}"));
cmd!(
sh,
"sudo docker cp permissions.sql {postgres_container_id}:/permissions.sql"
)
.run()?;
cmd!(sh, "sudo docker exec {postgres_container_id} psql -U ckan_default --set ON_ERROR_STOP=1 -f permissions.sql").run()?;
println!(
"{}",
success_text(
"✅ 7. Enabled DataStore plugin, set DataStore URLs in /etc/ckan/default/ckan.ini, and updated permissions."
)
);
println!( println!(
"{}", "{}",
step_text("\n{} Installing ckanext-scheming and DataPusher+ extensions..."), step_text("\n{} Installing ckanext-scheming and DataPusher+ extensions..."),
); );
cmd!( cmd!(
sh, sh,
"pip install -e git+https://github.com/ckan/ckanext-scheming.git#egg=ckanext-scheming" "pip install -e git+https://github.com/ckan/ckanext-scheming.git#egg=ckanext-scheming"
) )
.run()?; .run()?;
let mut conf = ini::Ini::load_from_file("/etc/ckan/default/ckan.ini")?; let mut conf = ini::Ini::load_from_file("/etc/ckan/default/ckan.ini")?;
let app_main_section = conf.section_mut(Some("app:main")).unwrap(); let app_main_section = conf.section_mut(Some("app:main")).unwrap();
let mut ckan_plugins = app_main_section.get("ckan.plugins").unwrap().to_string(); let mut ckan_plugins = app_main_section.get("ckan.plugins").unwrap().to_string();
ckan_plugins.push_str(" scheming_datasets"); ckan_plugins.push_str(" scheming_datasets");
cmd!( cmd!(
sh, sh,
"ckan config-tool /etc/ckan/default/ckan.ini -s app:main ckan.plugins={ckan_plugins}" "ckan config-tool /etc/ckan/default/ckan.ini -s app:main ckan.plugins={ckan_plugins}"
) )
.run()?; .run()?;
cmd!(sh, "ckan config-tool /etc/ckan/default/ckan.ini -s app:main scheming.presets=ckanext.scheming:presets.json").run()?; cmd!(sh, "ckan config-tool /etc/ckan/default/ckan.ini -s app:main scheming.presets=ckanext.scheming:presets.json").run()?;
cmd!(sh, "ckan config-tool /etc/ckan/default/ckan.ini -s app:main scheming.dataset_fallback=false").run()?; cmd!(sh, "ckan config-tool /etc/ckan/default/ckan.ini -s app:main scheming.dataset_fallback=false").run()?;
// app_main_section.insert("ckan.plugins", ckan_plugins); // app_main_section.insert("ckan.plugins", ckan_plugins);
// app_main_section.insert("scheming.presets", "ckanext.scheming:presets.json"); // app_main_section.insert("scheming.presets", "ckanext.scheming:presets.json");
// app_main_section.insert("scheming.dataset_fallback", "false"); // app_main_section.insert("scheming.dataset_fallback", "false");
// conf.write_to_file("/etc/ckan/default/ckan.ini")?; // conf.write_to_file("/etc/ckan/default/ckan.ini")?;
// Install DataPusher+ // Install DataPusher+
cmd!(sh, "sudo apt install python3-virtualenv python3-dev python3-pip python3-wheel build-essential libxslt1-dev libxml2-dev zlib1g-dev git libffi-dev libpq-dev uchardet -y").run()?; cmd!(sh, "sudo apt install python3-virtualenv python3-dev python3-pip python3-wheel build-essential libxslt1-dev libxml2-dev zlib1g-dev git libffi-dev libpq-dev uchardet -y").run()?;
sh.change_dir("/usr/lib/ckan/default/src"); sh.change_dir("/usr/lib/ckan/default/src");
cmd!(sh, "pip install -e git+https://github.com/dathere/datapusher-plus.git@main#egg=datapusher-plus").run()?; cmd!(sh, "pip install -e git+https://github.com/dathere/datapusher-plus.git@main#egg=datapusher-plus").run()?;
sh.change_dir("/usr/lib/ckan/default/src/datapusher-plus"); sh.change_dir("/usr/lib/ckan/default/src/datapusher-plus");
cmd!(sh, "pip install -r requirements.txt").run()?; cmd!(sh, "pip install -r requirements.txt").run()?;
sh.change_dir(format!("/home/{username}")); sh.change_dir(format!("/home/{username}"));
cmd!(sh, "wget https://github.com/dathere/qsv/releases/download/4.0.0/qsv-4.0.0-x86_64-unknown-linux-gnu.zip").run()?; cmd!(sh, "wget https://github.com/dathere/qsv/releases/download/4.0.0/qsv-4.0.0-x86_64-unknown-linux-gnu.zip").run()?;
cmd!(sh, "sudo apt install unzip -y").run()?; cmd!(sh, "sudo apt install unzip -y").run()?;
cmd!(sh, "unzip qsv-4.0.0-x86_64-unknown-linux-gnu.zip").run()?; cmd!(sh, "unzip qsv-4.0.0-x86_64-unknown-linux-gnu.zip").run()?;
cmd!(sh, "sudo rm -rf qsv-4.0.0-x86_64-unknown-linux-gnu.zip").run()?; cmd!(sh, "sudo rm -rf qsv-4.0.0-x86_64-unknown-linux-gnu.zip").run()?;
cmd!(sh, "sudo mv ./qsvdp_glibc-2.31 /usr/local/bin/qsvdp").run()?; cmd!(sh, "sudo mv ./qsvdp_glibc-2.31 /usr/local/bin/qsvdp").run()?;
let mut conf = ini::Ini::load_from_file("/etc/ckan/default/ckan.ini")?; let mut conf = ini::Ini::load_from_file("/etc/ckan/default/ckan.ini")?;
let app_main_section = conf.section_mut(Some("app:main")).unwrap(); let app_main_section = conf.section_mut(Some("app:main")).unwrap();
let mut ckan_plugins = app_main_section.get("ckan.plugins").unwrap().to_string(); let mut ckan_plugins = app_main_section.get("ckan.plugins").unwrap().to_string();
ckan_plugins.push_str(" datapusher_plus"); ckan_plugins.push_str(" datapusher_plus");
cmd!( cmd!(
sh, sh,
"ckan config-tool /etc/ckan/default/ckan.ini -s app:main ckan.plugins={ckan_plugins}" "ckan config-tool /etc/ckan/default/ckan.ini -s app:main ckan.plugins={ckan_plugins}"
) )
.run()?; .run()?;
cmd!(sh, "ckan config-tool /etc/ckan/default/ckan.ini -s app:main scheming.dataset_schemas=ckanext.datapusher_plus:dataset-druf.yaml").run()?; cmd!(sh, "ckan config-tool /etc/ckan/default/ckan.ini -s app:main scheming.dataset_schemas=ckanext.datapusher_plus:dataset-druf.yaml").run()?;
// app_main_section.insert("ckan.plugins", ckan_plugins); // app_main_section.insert("ckan.plugins", ckan_plugins);
// app_main_section.insert( // app_main_section.insert(
// "scheming.dataset_schemas", // "scheming.dataset_schemas",
// "ckanext.datapusher_plus:dataset-druf.yaml", // "ckanext.datapusher_plus:dataset-druf.yaml",
// ); // );
// conf.write_to_file("/etc/ckan/default/ckan.ini")?; // conf.write_to_file("/etc/ckan/default/ckan.ini")?;
let dpp_default_config = r#" let dpp_default_config = r#"
ckanext.datapusher_plus.use_proxy = false ckanext.datapusher_plus.use_proxy = false
ckanext.datapusher_plus.download_proxy = ckanext.datapusher_plus.download_proxy =
ckanext.datapusher_plus.ssl_verify = false ckanext.datapusher_plus.ssl_verify = false
@ -316,75 +412,59 @@ ckanext.datapusher_plus.auto_unzip_one_file = true
ckanext.datapusher_plus.api_token = <CKAN service account token for CKAN user with sysadmin privileges> ckanext.datapusher_plus.api_token = <CKAN service account token for CKAN user with sysadmin privileges>
ckanext.datapusher_plus.describeGPT_api_key = <Token for OpenAI API compatible service> ckanext.datapusher_plus.describeGPT_api_key = <Token for OpenAI API compatible service>
ckanext.datapusher_plus.file_bin = /usr/bin/file ckanext.datapusher_plus.file_bin = /usr/bin/file
ckanext.datapusher_plus.enable_druf = true ckanext.datapusher_plus.enable_druf = false
ckanext.datapusher_plus.enable_form_redirect = true ckanext.datapusher_plus.enable_form_redirect = true
"#; "#;
std::fs::write("dpp_default_config.ini", dpp_default_config)?; std::fs::write("dpp_default_config.ini", dpp_default_config)?;
cmd!( cmd!(
sh, sh,
"ckan config-tool /etc/ckan/default/ckan.ini -f dpp_default_config.ini" "ckan config-tool /etc/ckan/default/ckan.ini -f dpp_default_config.ini"
) )
.run()?; .run()?;
let resource_formats_str = let resource_formats_str = std::fs::read_to_string(
std::fs::read_to_string("/usr/lib/ckan/default/src/ckan/config/resource_formats.json")?; "/usr/lib/ckan/default/src/ckan/config/resource_formats.json",
let mut resource_formats_val: serde_json::Value = )?;
serde_json::from_str(&resource_formats_str)?; let mut resource_formats_val: serde_json::Value =
let all_resource_formats = resource_formats_val serde_json::from_str(&resource_formats_str)?;
.get_mut(0) let all_resource_formats = resource_formats_val
.unwrap() .get_mut(0)
.as_array_mut() .unwrap()
.unwrap(); .as_array_mut()
all_resource_formats.push(json!([ .unwrap();
"TAB", all_resource_formats.push(json!([
"Tab Separated Values File", "TAB",
"text/tab-separated-values", "Tab Separated Values File",
[] "text/tab-separated-values",
])); []
std::fs::write( ]));
"/usr/lib/ckan/default/src/ckan/config/resource_formats.json", std::fs::write(
serde_json::to_string(&resource_formats_val)?, "/usr/lib/ckan/default/src/ckan/config/resource_formats.json",
)?; serde_json::to_string(&resource_formats_val)?,
cmd!(sh, "sudo locale-gen en_US.UTF-8").run()?; )?;
cmd!(sh, "sudo update-locale").run()?; cmd!(sh, "sudo locale-gen en_US.UTF-8").run()?;
let token_command_output = cmd!( cmd!(sh, "sudo update-locale").run()?;
sh, let token_command_output = cmd!(
"ckan -c /etc/ckan/default/ckan.ini user token add {username} dpplus" sh,
) "ckan -c /etc/ckan/default/ckan.ini user token add {sysadmin_username} dpplus"
.read()?; )
let tail_output = cmd!(sh, "tail -n 1").stdin(token_command_output).read()?; .read()?;
let dpp_api_token = cmd!(sh, "tr -d '\t'").stdin(tail_output).read()?; let tail_output = cmd!(sh, "tail -n 1").stdin(token_command_output).read()?;
cmd!(sh, "ckan config-tool /etc/ckan/default/ckan.ini ckanext.datapusher_plus.api_token={dpp_api_token}").env("LC_ALL", "en_US.UTF-8").run()?; let dpp_api_token = cmd!(sh, "tr -d '\t'").stdin(tail_output).read()?;
cmd!( cmd!(sh, "ckan config-tool /etc/ckan/default/ckan.ini ckanext.datapusher_plus.api_token={dpp_api_token}").env("LC_ALL", "en_US.UTF-8").run()?;
sh, cmd!(
"ckan -c /etc/ckan/default/ckan.ini db upgrade -p datapusher_plus" sh,
) "ckan -c /etc/ckan/default/ckan.ini db upgrade -p datapusher_plus"
.run()?; )
println!( .run()?;
"{}", println!(
success_text("✅ 8. Installed ckanext-scheming and DataPusher+ extensions.") "{}",
); success_text("✅ 8. Installed ckanext-scheming and DataPusher+ extensions.")
);
}
println!("\n{}", success_text("✅ 9. Running CKAN instance...")); println!("\n{}", success_text(" Running CKAN instance..."));
cmd!(sh, "ckan -c /etc/ckan/default/ckan.ini run").run()?; cmd!(sh, "ckan -c /etc/ckan/default/ckan.ini run").run()?;
} }
Ok(()) Ok(())
} }
struct Config {
ssh: bool,
}
fn get_config_from_prompts() -> Result<Config> {
let ssh = Confirm::new("Would you like to enable SSH? (optional)")
.with_default(false)
.with_help_message(
format!(
"This step would install {}",
highlighted_text("openssh-server")
)
.as_str(),
)
.prompt()?;
Ok(Config { ssh })
}

64
src/questions.rs Normal file
View file

@ -0,0 +1,64 @@
use crate::{Sysadmin, styles::highlighted_text};
use anyhow::Result;
use inquire::{Confirm, Select, Text};
pub fn question_ssh() -> Result<bool> {
Ok(Confirm::new("Would you like to enable SSH? (optional)")
.with_default(false)
.with_help_message(
format!(
"This step would install {}",
highlighted_text("openssh-server")
)
.as_str(),
)
.prompt()?)
}
pub fn question_ckan_version() -> Result<String> {
let ckan_version_options: Vec<&str> = vec!["2.11.3", "2.10.8", "Other"];
let answer_ckan_version = Select::new(
"What CKAN version would you like to install? (optional)",
ckan_version_options,
)
.with_help_message("We recommend using the latest compatible version of CKAN. Please do not choose 'Other' option unless for testing purposes as the CKAN version may not be supported and may cause a broken installation.")
.prompt()?;
if answer_ckan_version == "Other" {
Ok(
Text::new("What CKAN version would you like to install? (optional)")
.with_default("2.11.3")
.prompt()?,
)
} else {
Ok(answer_ckan_version.to_string())
}
}
pub fn question_sysadmin(username: String) -> Result<Sysadmin> {
let configure_sysadmin = Confirm::new("Would you like to configure the sysadmin account for your CKAN instance?")
.with_help_message(format!("The following values are set as defaults for the sysadmin account:\n\n- Username: {username}\n- Password: password\n- Email: {username}@localhost\n").as_str())
.prompt()?;
if configure_sysadmin {
let username = Text::new("What should your sysadmin username be set to?")
.with_default(username.clone().as_str())
.prompt()?;
let password = Text::new("What should your sysadmin password be set to?")
.with_default("password")
.with_help_message("The password must be at least 8 characters long")
.prompt()?;
let email = Text::new("What should your sysadmin email be set to?")
.with_default(format!("{username}@localhost").as_str())
.prompt()?;
Ok(Sysadmin {
username,
password,
email,
})
} else {
Ok(Sysadmin {
username: username.clone(),
password: "password".to_string(),
email: format!("{username}@localhost"),
})
}
}

19
src/steps.rs Normal file
View file

@ -0,0 +1,19 @@
use crate::styles::{highlighted_text, important_text};
pub fn step_intro() {
println!("Welcome to the ckan-devstaller!");
println!(
"ckan-devstaller is provided by datHere - {}\n",
highlighted_text("https://datHere.com"),
);
println!(
"This installer should assist in setting up {} from a source installation along with ckan-compose. If you have any issues, please report them at https://support.dathere.com or https://github.com/dathere/ckan-devstaller/issues.",
highlighted_text("CKAN 2.11.3")
);
println!(
"{}",
important_text(
"This installer is only intended for a brand new installation of Ubuntu 22.04."
)
);
}