Skip to content

Commit

Permalink
add geode config setup for setting up config.json without installer +
Browse files Browse the repository at this point in the history
automatic old config migration
  • Loading branch information
HJfod committed Oct 8, 2022
1 parent a2ed32e commit 4ff023d
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 22 deletions.
98 changes: 95 additions & 3 deletions src/info.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::cell::RefCell;
use std::io::BufRead;
/**
* geode info
*/
use std::path::{PathBuf};
use crate::config::Config;
use crate::{fail, done};
use crate::util::config::Profile;
use crate::{fail, done, info};
use crate::NiceUnwrap;
use colored::Colorize;
use clap::Subcommand;
Expand All @@ -30,7 +33,10 @@ pub enum Info {
},

/// List possible values
List
List,

/// Setup config (if you have manually installed Geode)
Setup {},
}

const CONFIGURABLES: [&str; 3] = [
Expand Down Expand Up @@ -102,6 +108,92 @@ pub fn subcommand(config: &mut Config, cmd: Info) {
for i in CONFIGURABLES {
println!("{}", i);
}
}
},

Info::Setup {} => {
if config.profiles.is_empty() {
info!("Please enter the path to the Geometry Dash folder:");

let path = loop {
let mut buf = String::new();
match std::io::stdin().lock().read_line(&mut buf) {
Ok(_) => {},
Err(e) => {
fail!("Unable to read input: {}", e);
continue;
}
};

// Verify path is valid
let path = PathBuf::from(buf.trim());
if !path.is_dir() {
fail!(
"The path must point to the Geometry Dash \
folder, not the executable"
);
continue;
}
if path.read_dir().map(|mut files| files.next().is_none()).unwrap_or(false) {
fail!("Given path appears to be empty");
continue;
}
// todo: maybe do some checksum verification
// to make sure GD 2.113 is in the folder
break path;
};

info!("Please enter a name for the profile:");
let name = loop {
let mut buf = String::new();
match std::io::stdin().lock().read_line(&mut buf) {
Ok(_) => break buf,
Err(e) => fail!("Unable to read input: {}", e)
};
};

config.profiles.push(RefCell::new(
Profile::new(name.trim().into(), path)
));
config.current_profile = Some(name.trim().into());
done!("Profile added");
}

if config.sdk_path.is_none() {
info!(
"Please enter the path to the Geode repository folder \
(https://github.com/geode-sdk/geode):"
);
config.sdk_path = Some(loop {
let mut buf = String::new();
match std::io::stdin().lock().read_line(&mut buf) {
Ok(_) => {},
Err(e) => {
fail!("Unable to read input: {}", e);
continue;
}
};

// Verify path is valid
let path = PathBuf::from(buf.trim());
if !path.is_dir() {
fail!("The path must point to a folder");
continue;
}
if !path.join("README.md").exists() {
fail!(
"Given path doesn't seem to be the Geode repo, \
make sure to enter the path to the root (where \
README.md is)"
);
continue;
}
break path;
});
config.sdk_nightly = config.sdk_path.as_ref().unwrap().join("bin/nightly").exists();
done!("SDK path added");
}

done!("Config setup finished");
},
}
}
11 changes: 5 additions & 6 deletions src/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,30 +69,29 @@ pub fn subcommand(config: &mut Config, cmd: Profile) {
},

Profile::Switch { profile } => {
if config.get_profile(&profile).is_none() {
if config.get_profile(&Some(profile.to_owned())).is_none() {
fail!("Profile '{}' does not exist", profile);
} else if config.current_profile == profile {
} else if config.current_profile == Some(profile.to_owned()) {
fail!("'{}' is already the current profile", profile);
} else {
done!("'{}' is now the current profile", &profile);
config.current_profile = profile;
config.current_profile = Some(profile);
}
},

Profile::Add { name, location } => {
if config.get_profile(&name).is_some() {
if config.get_profile(&Some(name.to_owned())).is_some() {
fail!("A profile named '{}' already exists", name);
} else if !is_valid_geode_dir(&location) {
fail!("The specified path does not point to a valid Geode installation");
} else {
done!("A new profile named '{}' has been created", &name);
config.profiles.push(RefCell::new(CfgProfile::new(name, location)));
}

},

Profile::Remove { name } => {
if config.get_profile(&name).is_none() {
if config.get_profile(&Some(name.to_owned())).is_none() {
fail!("Profile '{}' does not exist", name);
} else {
config.profiles.retain(|x| x.borrow().name != name);
Expand Down
85 changes: 72 additions & 13 deletions src/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::path::PathBuf;

use crate::{fail, warn, done, info};
use crate::{fail, warn, done, info, fatal};
use crate::NiceUnwrap;

#[derive(Serialize, Deserialize, Clone)]
Expand All @@ -21,7 +21,7 @@ pub struct Profile {
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct Config {
pub current_profile: String,
pub current_profile: Option<String>,
pub profiles: Vec<RefCell<Profile>>,
pub default_developer: Option<String>,
pub sdk_path: Option<PathBuf>,
Expand All @@ -30,6 +30,49 @@ pub struct Config {
other: HashMap<String, Value>,
}

// old config.json structures for migration

#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct OldConfigInstallation {
pub path: PathBuf,
pub executable: String,
}

#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct OldConfig {
pub default_installation: usize,
pub working_installation: Option<usize>,
pub installations: Option<Vec<OldConfigInstallation>>,
pub default_developer: Option<String>,
}

impl OldConfig {
pub fn migrate(&self) -> Config {
let profiles = self.installations.as_ref().map(|insts| {
insts.iter().map(|inst| RefCell::from(Profile {
name: inst.executable
.strip_suffix(".exe")
.unwrap_or(&inst.executable)
.into(),
gd_path: inst.path.clone(),
other: HashMap::new()
})).collect::<Vec<_>>()
}).unwrap_or(Vec::new());
Config {
current_profile: profiles.get(
self.working_installation.unwrap_or(self.default_installation)
).map(|i| i.borrow().name.clone()),
profiles,
default_developer: self.default_developer.to_owned(),
sdk_path: None,
sdk_nightly: false,
other: HashMap::new()
}
}
}

pub fn geode_root() -> PathBuf {
// get data dir per-platform
let data_dir: PathBuf;
Expand Down Expand Up @@ -57,8 +100,12 @@ impl Profile {
}

impl Config {
pub fn get_profile(&self, name: &str) -> Option<&RefCell<Profile>> {
self.profiles.iter().filter(|x| x.borrow().name == name).next()
pub fn get_profile(&self, name: &Option<String>) -> Option<&RefCell<Profile>> {
if let Some(name) = name {
self.profiles.iter().filter(|x| x.borrow().name == name.to_owned()).next()
} else {
None
}
}

pub fn new() -> Config {
Expand All @@ -68,7 +115,7 @@ impl Config {
info!("At {}", "https://github.com/geode-sdk/installer/releases/latest".bright_cyan());

return Config {
current_profile: String::new(),
current_profile: None,
profiles: Vec::new(),
default_developer: None,
sdk_path: None,
Expand All @@ -82,26 +129,38 @@ impl Config {
let mut output: Config = if !config_json.exists() {
// Create new config
Config {
current_profile: String::new(),
current_profile: None,
profiles: Vec::new(),
default_developer: None,
sdk_path: None,
sdk_nightly: false,
other: HashMap::<String, Value>::new()
}
} else {
serde_json::from_str(&std::fs::read_to_string(&config_json).unwrap())
.nice_unwrap("Unable to parse config.json")
// Parse config
let config_json_str = &std::fs::read_to_string(&config_json)
.nice_unwrap("Unable to read config.json");
match serde_json::from_str(config_json_str) {
Ok(json) => json,
Err(e) => {
// Try migrating old config
if let Ok(json) = serde_json::from_str::<OldConfig>(config_json_str) {
info!("Migrating old config.json");
json.migrate()
} else {
fatal!("Unable to parse config.json: {}", e);
}
}
}
};

output.save();

if output.profiles.is_empty() {
warn!("No Geode profiles found! Some operations will be unavailable.");
info!("Install Geode using the official installer (https://github.com/geode-sdk/installer/releases/latest)");

} else if output.get_profile(&output.current_profile.clone()).is_none() {
output.current_profile = output.profiles[0].borrow().name.clone();
} else if output.get_profile(&output.current_profile).is_none() {
output.current_profile = Some(output.profiles[0].borrow().name.clone());
}

output
Expand All @@ -115,10 +174,10 @@ impl Config {
}

pub fn rename_profile(&mut self, old: &str, new: String) {
let profile = self.get_profile(old)
let profile = self.get_profile(&Some(String::from(old)))
.nice_unwrap(format!("Profile named '{}' does not exist", old));

if self.get_profile(&new).is_some() {
if self.get_profile(&Some(new.to_owned())).is_some() {
fail!("The name '{}' is already taken!", new);
} else {
done!("Successfully renamed '{}' to '{}'", old, &new);
Expand Down

0 comments on commit 4ff023d

Please sign in to comment.