11import atexit
2- import io
32import logging
43import os
54import re
@@ -91,8 +90,10 @@ def jm_single() -> AttributeDict:
9190 'POLICY' : ['absurd_fee_per_kb' , 'taker_utxo_retries' ,
9291 'taker_utxo_age' , 'taker_utxo_amtpercent' ]}
9392
94- _DEFAULT_INTEREST_RATE = "0.015"
93+ _ENV_VAR_PREFIX = "JM_"
94+ _SECTIONS_WITH_SUBSECTIONS = {"MESSAGING" }
9595
96+ _DEFAULT_INTEREST_RATE = "0.015"
9697_DEFAULT_BONDLESS_MAKERS_ALLOWANCE = "0.125"
9798
9899defaultconfig = \
@@ -673,9 +674,8 @@ def _remove_unwanted_default_settings(config: ConfigParser) -> None:
673674 if section .startswith ('MESSAGING:' ):
674675 config .remove_section (section )
675676
676- def load_program_config (config_path : str = "" , bs : Optional [str ] = None ,
677- plugin_services : List [JMPluginService ] = []) -> None :
678- global_singleton .config .read_file (io .StringIO (defaultconfig ))
677+
678+ def set_paths (config_path : str = "" ) -> None :
679679 if not config_path :
680680 config_path = lookup_appdata_folder (global_singleton .APPNAME )
681681 # we set the global home directory, but keep the config_path variable
@@ -692,29 +692,70 @@ def load_program_config(config_path: str = "", bs: Optional[str] = None,
692692 if not os .path .exists (os .path .join (global_singleton .datadir , "cmtdata" )):
693693 os .makedirs (os .path .join (global_singleton .datadir , "cmtdata" ))
694694 global_singleton .config_location = os .path .join (
695- global_singleton .datadir , global_singleton .config_location )
695+ global_singleton .datadir , global_singleton .config_location
696+ )
696697
697- _remove_unwanted_default_settings (global_singleton .config )
698+
699+ def read_config_file () -> bool :
698700 try :
699- loadedFiles = global_singleton .config .read (
700- [global_singleton .config_location ])
701+ loaded = global_singleton .config .read ([global_singleton .config_location ])
701702 except UnicodeDecodeError :
702- jmprint ("Error loading `joinmarket.cfg`, invalid file format." ,
703- "info" )
703+ jmprint ("Error loading `joinmarket.cfg`, invalid file format." , "info" )
704704 sys .exit (EXIT_FAILURE )
705+ return len (loaded ) == 1
706+
705707
708+ def write_config_file (config : str = defaultconfig ) -> bool :
709+ with open (global_singleton .config_location , "w" ) as configfile :
710+ configfile .write (config )
711+ jmprint (
712+ "Created a new `joinmarket.cfg`. Please review and adopt the "
713+ "settings and restart joinmarket." ,
714+ "info" ,
715+ )
716+ sys .exit (EXIT_FAILURE )
717+
718+
719+ def override (config : ConfigParser , bs : Optional [str ] = None ) -> None :
720+ _remove_unwanted_default_settings (config )
706721 # Hack required for bitcoin-rpc-no-history and probably others
707722 # (historicaly electrum); must be able to enforce a different blockchain
708723 # interface even in default/new load.
709724 if bs :
710- global_singleton .config .set ("BLOCKCHAIN" , "blockchain_source" , bs )
711- # Create default config file if not found
712- if len (loadedFiles ) != 1 :
713- with open (global_singleton .config_location , "w" ) as configfile :
714- configfile .write (defaultconfig )
715- jmprint ("Created a new `joinmarket.cfg`. Please review and adopt the "
716- "settings and restart joinmarket." , "info" )
717- sys .exit (EXIT_FAILURE )
725+ config .set ("BLOCKCHAIN" , "blockchain_source" , bs )
726+
727+
728+ def override_from_environment (config : ConfigParser ) -> ConfigParser :
729+ for key , value in os .environ .items ():
730+ if key .startswith (_ENV_VAR_PREFIX ):
731+ key = key .removeprefix (_ENV_VAR_PREFIX )
732+ section , key = key .split ("_" , 1 )
733+ if section in _SECTIONS_WITH_SUBSECTIONS :
734+ sub , key = key .split ("_" , 1 )
735+ section = f"{ section } :{ sub .lower ()} "
736+ key = key .lower ()
737+ if not config .has_section (section ):
738+ config .add_section (section )
739+ log .info (f"Overriding [{ section } ] { key } ={ value } " )
740+ config .set (section , key , value )
741+ return config
742+
743+
744+ def load_program_config (
745+ config_path : str = "" ,
746+ bs : Optional [str ] = None ,
747+ plugin_services : List [JMPluginService ] = [],
748+ from_environment : bool = False ,
749+ ) -> None :
750+ set_paths (config_path )
751+ global_singleton .config .read_string (defaultconfig )
752+ if from_environment :
753+ override_from_environment (global_singleton .config )
754+ else :
755+ override (global_singleton .config , bs )
756+ # Create default config file if not found
757+ if not read_config_file ():
758+ write_config_file ()
718759
719760 loglevel = global_singleton .config .get ("LOGGING" , "console_log_level" )
720761 try :
0 commit comments