Skip to content

Commit 1ed9864

Browse files
mmahroussfda-odoo
authored andcommitted
[IMP] server: add config file arg
1 parent 86cf98a commit 1ed9864

File tree

7 files changed

+151
-116
lines changed

7 files changed

+151
-116
lines changed

server/src/args.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ pub struct Cli {
5454
//provide a path to the directory that will be used for logs
5555
#[arg(long)]
5656
pub logs_directory: Option<String>,
57+
58+
/// Default config file path
59+
#[arg(long)]
60+
pub config_path: Option<String>,
61+
5762
}
5863

5964
#[derive(ValueEnum, Clone, Debug)]

server/src/core/config.rs

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ fn parse_manifest_version(contents: String) -> Option<String> {
429429
None
430430
}
431431

432-
fn process_version(var: Sourced<String>, ws_folders: &HashMap<String, String>, workspace_name: &String) -> Sourced<String> {
432+
fn process_version(var: Sourced<String>, ws_folders: &HashMap<String, String>, workspace_name: Option<&String>) -> Sourced<String> {
433433
let Some(config_path) = var.sources.iter().next().map(PathBuf::from) else {
434434
unreachable!("Expected at least one source for sourced_path: {:?}", var);
435435
};
@@ -624,7 +624,7 @@ pub fn default_profile_name() -> String {
624624
"default".to_string()
625625
}
626626

627-
fn fill_or_canonicalize<F>(sourced_path: &Sourced<String>, ws_folders: &HashMap<String, String>, workspace_name: &String, predicate: &F, var_map: HashMap<String, String>) -> Option<Sourced<String>>
627+
fn fill_or_canonicalize<F>(sourced_path: &Sourced<String>, ws_folders: &HashMap<String, String>, workspace_name: Option<&String>, predicate: &F, var_map: HashMap<String, String>) -> Option<Sourced<String>>
628628
where
629629
F: Fn(&String) -> bool,
630630
{
@@ -651,7 +651,7 @@ F: Fn(&String) -> bool,
651651
fn process_paths(
652652
entry: &mut ConfigEntryRaw,
653653
ws_folders: &HashMap<String, String>,
654-
workspace_name: &String,
654+
workspace_name: Option<&String>,
655655
){
656656
let var_map: HashMap<String, String> = match entry.version.clone() {
657657
Some(v) => HashMap::from([(S!("version"), v.value().clone())]),
@@ -901,8 +901,23 @@ fn merge_configs(
901901
merged
902902
}
903903

904+
fn load_config_from_file(path: String, ws_folders: &HashMap<String, String>,) -> Result<HashMap<String, ConfigEntryRaw>, String> {
905+
let path = PathBuf::from(path);
906+
if !path.exists() || !path.is_file() {
907+
return Err(S!(format!("Config file not found: {}", path.display())));
908+
}
909+
process_config(
910+
read_config_from_file(path)?,
911+
ws_folders,
912+
None,
913+
)
914+
}
904915

905-
fn load_merged_config_upward(ws_folders: &HashMap<String, String>, workspace_name: &String, workspace_path: &String) -> Result<HashMap<String, ConfigEntryRaw>, String> {
916+
fn load_config_from_workspace(
917+
ws_folders: &HashMap<String, String>,
918+
workspace_name: &String,
919+
workspace_path: &String,
920+
) -> Result<HashMap<String, ConfigEntryRaw>, String> {
906921
let mut current_dir = PathBuf::from(workspace_path);
907922
let mut visited_dirs = HashSet::new();
908923
let mut merged_config: HashMap<String, ConfigEntryRaw> = HashMap::new();
@@ -924,10 +939,29 @@ fn load_merged_config_upward(ws_folders: &HashMap<String, String>, workspace_nam
924939
break;
925940
}
926941
}
927-
apply_extends(&mut merged_config)?;
942+
let mut merged_config = process_config(merged_config, ws_folders, Some(workspace_name))?;
943+
944+
for entry in merged_config.values_mut() {
945+
if entry.abstract_ { continue; }
946+
if (matches!(entry.add_workspace_addon_path.as_ref().map(|a| a.value), Some(true)) || entry.addons_paths.is_none()) && is_addon_path(workspace_path) {
947+
let addon_path = Sourced { value: workspace_path.clone(), sources: HashSet::from([S!(format!("$workspaceFolder:{workspace_name}"))]), ..Default::default()};
948+
match entry.addons_paths {
949+
Some(ref mut paths) => paths.push(addon_path),
950+
None => entry.addons_paths = Some(vec![addon_path]),
951+
}
952+
}
953+
}
954+
Ok(merged_config)
955+
}
956+
957+
fn process_config(
958+
mut config_map: HashMap<String, ConfigEntryRaw>,
959+
ws_folders: &HashMap<String, String>,
960+
workspace_name: Option<&String>,
961+
) -> Result<HashMap<String, ConfigEntryRaw>, String> {
962+
apply_extends(&mut config_map)?;
928963
let mut new_configs = vec![];
929-
for config in merged_config.values_mut() {
930-
// If the config has no odoo_path, try to infer it from workspace folders
964+
for config in config_map.values_mut() {
931965
let Some(version_var) = config.version.clone() else {
932966
continue;
933967
};
@@ -965,42 +999,31 @@ fn load_merged_config_upward(ws_folders: &HashMap<String, String>, workspace_nam
965999
}
9661000
}
9671001
for new_entry in new_configs {
968-
merged_config.insert(new_entry.name.clone(), new_entry);
1002+
config_map.insert(new_entry.name.clone(), new_entry);
9691003
}
9701004

9711005
// Process vars
972-
merged_config.values_mut()
1006+
config_map.values_mut()
9731007
.for_each(|entry| {
9741008
// apply process_var to all vars
9751009
if entry.abstract_ { return; }
9761010
entry.version = entry.version.clone().map(|v| process_version(v, ws_folders, workspace_name));
9771011
});
9781012
// Process paths in the merged config
979-
merged_config.values_mut()
1013+
config_map.values_mut()
9801014
.for_each(|entry| {
9811015
if entry.abstract_ { return; }
9821016
process_paths(entry, ws_folders, workspace_name);
9831017
});
9841018
// Merge sourced paths
985-
merged_config.values_mut()
1019+
config_map.values_mut()
9861020
.for_each(|entry| {
9871021
if entry.abstract_ { return; }
9881022
entry.addons_paths = entry.addons_paths.clone().map(|paths| group_sourced_iters(paths).collect());
9891023
entry.additional_stubs = entry.additional_stubs.clone().map(|stubs| group_sourced_iters(stubs).collect());
9901024
});
9911025

992-
for entry in merged_config.values_mut() {
993-
if entry.abstract_ { continue; }
994-
if (matches!(entry.add_workspace_addon_path.as_ref().map(|a| a.value), Some(true)) || entry.addons_paths.is_none()) && is_addon_path(workspace_path) {
995-
let addon_path = Sourced { value: workspace_path.clone(), sources: HashSet::from([S!(format!("$workspaceFolder:{workspace_name}"))]), ..Default::default()};
996-
match entry.addons_paths {
997-
Some(ref mut paths) => paths.push(addon_path),
998-
None => entry.addons_paths = Some(vec![addon_path]),
999-
}
1000-
}
1001-
}
1002-
1003-
Ok(merged_config)
1026+
Ok(config_map)
10041027
}
10051028

10061029
fn merge_all_workspaces(
@@ -1130,9 +1153,22 @@ fn merge_all_workspaces(
11301153
Ok((final_config, config_file))
11311154
}
11321155

1133-
pub fn get_configuration(ws_folders: &HashMap<String, String>) -> Result<(ConfigNew, ConfigFile), String> {
1134-
let ws_confs: Result<Vec<_>, _> = ws_folders.iter().map(|ws_f| load_merged_config_upward(ws_folders, ws_f.0, ws_f.1)).collect();
1135-
merge_all_workspaces(ws_confs?, ws_folders)
1156+
pub fn get_configuration(ws_folders: &HashMap<String, String>, cli_config_file: &Option<String>) -> Result<(ConfigNew, ConfigFile), String> {
1157+
let mut ws_confs: Vec<HashMap<String, ConfigEntryRaw>> = Vec::new();
1158+
1159+
if let Some(ref path) = cli_config_file {
1160+
let config_from_file = load_config_from_file(path.clone(), ws_folders)?;
1161+
ws_confs.push(config_from_file);
1162+
}
1163+
1164+
let ws_confs_result: Result<Vec<_>, _> = ws_folders
1165+
.iter()
1166+
.map(|ws_f| load_config_from_workspace(ws_folders, ws_f.0, ws_f.1))
1167+
.collect();
1168+
1169+
ws_confs.extend(ws_confs_result?);
1170+
1171+
merge_all_workspaces(ws_confs, ws_folders)
11361172
}
11371173

11381174
/// Check if the old and new configuration entries are different enough to require a restart.

server/src/core/odoo.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub struct SyncOdoo {
5959
pub full_version: String,
6060
pub config: ConfigEntry,
6161
pub config_file: Option<ConfigFile>,
62+
pub config_path: Option<String>,
6263
pub entry_point_mgr: Rc<RefCell<EntryPointMgr>>, //An Rc to be able to clone it and free session easily
6364
pub has_main_entry:bool,
6465
pub has_odoo_main_entry: bool,
@@ -96,6 +97,7 @@ impl SyncOdoo {
9697
full_version: "0.0.0".to_string(),
9798
config: ConfigEntry::new(),
9899
config_file: None,
100+
config_path: None,
99101
entry_point_mgr: Rc::new(RefCell::new(EntryPointMgr::new())),
100102
has_main_entry: false,
101103
has_odoo_main_entry: false,
@@ -969,7 +971,7 @@ impl Odoo {
969971
session.show_message(MessageType::ERROR, String::from("There are repeated workspace folders names, which is not supported by OdooLS. Please remove the repeated folders and restart the server."));
970972
return;
971973
}
972-
let config = get_configuration(session.sync_odoo.get_file_mgr().borrow().get_workspace_folders());
974+
let config = get_configuration(session.sync_odoo.get_file_mgr().borrow().get_workspace_folders(), &session.sync_odoo.config_path);
973975
if let Ok((_, config_file)) = &config {
974976
session.sync_odoo.config_file = Some(config_file.clone());
975977
Odoo::send_all_configurations(session);
@@ -1466,7 +1468,7 @@ impl Odoo {
14661468
fn check_handle_config_file_update(session: &mut SessionInfo, path: &PathBuf) -> bool {
14671469
// Check if the change is affecting a config file
14681470
if Odoo::is_config_workspace_file(session, path) {
1469-
let config_result = config::get_configuration(session.sync_odoo.get_file_mgr().borrow().get_workspace_folders())
1471+
let config_result = config::get_configuration(session.sync_odoo.get_file_mgr().borrow().get_workspace_folders(), &session.sync_odoo.config_path)
14701472
.and_then(|(cfg_map, cfg_file)| {
14711473
let config_name = Odoo::read_selected_configuration(session)?.unwrap_or(default_profile_name());
14721474
cfg_map.get(&config_name)

server/src/main.rs

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -82,34 +82,22 @@ fn main() {
8282
info!("starting server (single parse mode)");
8383
let backend = CliBackend::new(cli);
8484
backend.run();
85-
} else if use_debug {
86-
info!(tag = "test", "starting server (debug mode)");
87-
let mut serv = Server::new_tcp().expect("Unable to start tcp connection");
88-
serv.initialize().expect("Error while initializing server");
89-
let sender_panic = serv.connection.as_ref().unwrap().sender.clone();
90-
std::panic::set_hook(Box::new(move |panic_info| {
91-
let backtrace = std::backtrace::Backtrace::capture();
92-
panic_hook(panic_info);
93-
let _ = sender_panic.send(lsp_server::Message::Notification(Notification{
94-
method: "Odoo/displayCrashNotification".to_string(),
95-
params: json!({
96-
"crashInfo": format!("{panic_info}\n\nTraceback:\n{backtrace}"),
97-
"pid": std::process::id()
98-
})
99-
}));
100-
}));
101-
if !serv.run(cli.clientProcessId) {
102-
info!(">>>>>>>>>>>>>>>>>> End Session <<<<<<<<<<<<<<<<<<");
103-
process::exit(1);
104-
}
10585
} else {
106-
info!("starting server");
107-
let mut serv = Server::new_stdio();
86+
let mut serv = if use_debug {
87+
info!(tag = "test", "starting server (debug mode)");
88+
Server::new_tcp().expect("Unable to start tcp connection")
89+
} else {
90+
info!("starting server");
91+
Server::new_stdio()
92+
};
10893
serv.initialize().expect("Error while initializing server");
94+
cli.config_path.map(|config_path| {
95+
serv.set_config_path(config_path.clone());
96+
});
10997
let sender_panic = serv.connection.as_ref().unwrap().sender.clone();
11098
std::panic::set_hook(Box::new(move |panic_info| {
111-
panic_hook(panic_info);
11299
let backtrace = std::backtrace::Backtrace::capture();
100+
panic_hook(panic_info);
113101
let _ = sender_panic.send(lsp_server::Message::Notification(Notification{
114102
method: "Odoo/displayCrashNotification".to_string(),
115103
params: json!({

server/src/server.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ impl Server {
155155
}
156156
}
157157

158-
159158
pub fn initialize(&mut self) -> Result<(), ServerError> {
160159
info!("Waiting for a connection...");
161160
let (id, params) = self.connection.as_ref().unwrap().initialize_start()?;
@@ -562,4 +561,9 @@ impl Server {
562561
}
563562
})
564563
}
564+
565+
pub fn set_config_path(&mut self, config_path: String) {
566+
let mut sync_odoo = self.sync_odoo.lock().unwrap();
567+
sync_odoo.config_path = Some(config_path);
568+
}
565569
}

server/src/utils.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -273,24 +273,24 @@ pub fn build_pattern_map(ws_folders: &HashMap<String, String>) -> HashMap<String
273273
/// While also checking it with the predicate function.
274274
/// pass `|_| true` to skip the predicate check.
275275
/// Currently, only the workspaceFolder[:workspace_name] and userHome variables are supported.
276-
pub fn fill_validate_path<F, P>(ws_folders: &HashMap<String, String>, workspace_name: &String, template: &str, predicate: F, var_map: HashMap<String, String>, parent_path: P) -> Option<String>
276+
pub fn fill_validate_path<F, P>(ws_folders: &HashMap<String, String>, workspace_name: Option<&String>, template: &str, predicate: F, var_map: HashMap<String, String>, parent_path: P) -> Option<String>
277277
where
278278
F: Fn(&String) -> bool,
279279
P: AsRef<Path>
280280
{
281281
let mut pattern_map: HashMap<String, String> = build_pattern_map(ws_folders).into_iter().chain(var_map.into_iter()).collect();
282-
if let Some(path) = ws_folders.get(workspace_name) {
282+
if let Some(path) = workspace_name.and_then(|name| ws_folders.get(name)) {
283283
pattern_map.insert(S!("workspaceFolder"), path.clone());
284-
if let Some(path) = fill_template(template, &pattern_map) {
285-
if predicate(&path) {
286-
return Some(path);
287-
}
288-
// Attempt to convert the path to an absolute path
289-
if let Ok(abs_path) = std::fs::canonicalize(parent_path.as_ref().join(&path)) {
290-
let abs_path = abs_path.sanitize();
291-
if predicate(&abs_path) {
292-
return Some(abs_path);
293-
}
284+
}
285+
if let Some(path) = fill_template(template, &pattern_map) {
286+
if predicate(&path) {
287+
return Some(path);
288+
}
289+
// Attempt to convert the path to an absolute path
290+
if let Ok(abs_path) = std::fs::canonicalize(parent_path.as_ref().join(&path)) {
291+
let abs_path = abs_path.sanitize();
292+
if predicate(&abs_path) {
293+
return Some(abs_path);
294294
}
295295
}
296296
}

0 commit comments

Comments
 (0)