1- import json
2- import os
3- from os import makedirs
4- from os .path import isfile , exists , expanduser , join , dirname , isdir
1+ from importlib .util import find_spec
2+ from os .path import isfile , join
53
4+ import xdg .BaseDirectory
5+ from json_database import JsonStorage
66from xdg import BaseDirectory as XDG
77
8- from ovos_utils .fingerprinting import core_supports_xdg
9- from ovos_utils .json_helper import merge_dict , load_commented_json
8+ from ovos_utils .json_helper import load_commented_json , merge_dict
109from ovos_utils .log import LOG
1110from ovos_utils .system import search_mycroft_core_location
1211
13- # for downstream support, all XDG paths should respect this
14- _BASE_FOLDER = "mycroft"
15- _CONFIG_FILE_NAME = "mycroft.conf"
1612
17- _DEFAULT_CONFIG = None
18- _SYSTEM_CONFIG = os .environ .get ('MYCROFT_SYSTEM_CONFIG' ,
19- f'/etc/{ _BASE_FOLDER } /{ _CONFIG_FILE_NAME } ' )
20- # Make sure we support the old location until mycroft moves to XDG
21- _OLD_USER_CONFIG = join (expanduser ('~' ), '.' + _BASE_FOLDER , _CONFIG_FILE_NAME )
22- _USER_CONFIG = join (XDG .xdg_config_home , _BASE_FOLDER , _CONFIG_FILE_NAME )
23- _WEB_CONFIG_CACHE = join (XDG .xdg_config_home , _BASE_FOLDER , 'web_cache.json' )
13+ def get_ovos_config ():
14+ config = {"xdg" : True ,
15+ "base_folder" : "mycroft" ,
16+ "config_filename" : "mycroft.conf" ,
17+ "default_config_path" : find_default_config ()}
18+
19+ try :
20+ if isfile ("/etc/OpenVoiceOS/ovos.conf" ):
21+ config = merge_dict (config ,
22+ load_commented_json (
23+ "/etc/OpenVoiceOS/ovos.conf" ))
24+ elif isfile ("/etc/mycroft/ovos.conf" ):
25+ config = merge_dict (config ,
26+ load_commented_json ("/etc/mycroft/ovos.conf" ))
27+ except :
28+ # tolerate bad json TODO proper exception (?)
29+ pass
30+
31+ # This includes both the user config and
32+ # /etc/xdg/OpenVoiceOS/ovos.conf
33+ for p in xdg .BaseDirectory .load_config_paths ("OpenVoiceOS" ):
34+ if isfile (join (p , "ovos.conf" )):
35+ try :
36+ xdg_cfg = load_commented_json (join (p , "ovos.conf" ))
37+ config = merge_dict (config , xdg_cfg )
38+ except :
39+ # tolerate bad json TODO proper exception (?)
40+ pass
41+
42+ # let's check for derivatives specific configs
43+ # the assumption is that these cores are exclusive to each other,
44+ # this will never find more than one override
45+ # TODO this works if using dedicated .venvs what about system installs?
46+ cores = config .get ("module_overrides" ) or {}
47+ for k in cores :
48+ if find_spec (k ):
49+ config = merge_dict (config , cores [k ])
50+ break
51+ else :
52+ subcores = config .get ("submodule_mappings" ) or {}
53+ for k in subcores :
54+ if find_spec (k ):
55+ config = merge_dict (config , cores [subcores [k ]])
56+ break
57+
58+ return config
59+
60+
61+ def is_using_xdg ():
62+ return get_ovos_config ().get ("xdg" , True )
2463
2564
2665def get_xdg_base ():
27- global _BASE_FOLDER
28- return _BASE_FOLDER
66+ return get_ovos_config ().get ("base_folder" ) or "mycroft"
67+
68+
69+ def save_ovos_core_config (new_config ):
70+ OVOS_CONFIG = join (xdg .BaseDirectory .save_config_path ("OpenVoiceOS" ),
71+ "ovos.conf" )
72+ cfg = JsonStorage (OVOS_CONFIG )
73+ cfg .update (new_config )
74+ cfg .store ()
75+ return cfg
2976
3077
3178def set_xdg_base (folder_name ):
32- global _BASE_FOLDER , _WEB_CONFIG_CACHE
3379 LOG .info (f"XDG base folder set to: '{ folder_name } '" )
34- _BASE_FOLDER = folder_name
35- _WEB_CONFIG_CACHE = join (XDG .xdg_config_home , _BASE_FOLDER ,
36- 'web_cache.json' )
80+ save_ovos_core_config ({"base_folder" : folder_name })
3781
3882
3983def set_config_filename (file_name , core_folder = None ):
40- global _CONFIG_FILE_NAME , _SYSTEM_CONFIG , _OLD_USER_CONFIG , _USER_CONFIG , \
41- _BASE_FOLDER
4284 if core_folder :
43- _BASE_FOLDER = core_folder
4485 set_xdg_base (core_folder )
4586 LOG .info (f"config filename set to: '{ file_name } '" )
46- _CONFIG_FILE_NAME = file_name
47- _SYSTEM_CONFIG = os .environ .get ('MYCROFT_SYSTEM_CONFIG' ,
48- f'/etc/{ _BASE_FOLDER } /{ _CONFIG_FILE_NAME } ' )
49- # Make sure we support the old location still
50- # Deprecated and will be removed eventually
51- _OLD_USER_CONFIG = join (expanduser ('~' ), '.' + _BASE_FOLDER ,
52- _CONFIG_FILE_NAME )
53- _USER_CONFIG = join (XDG .xdg_config_home , _BASE_FOLDER , _CONFIG_FILE_NAME )
87+ save_ovos_core_config ({"config_filename" : file_name })
5488
5589
5690def set_default_config (file_path = None ):
57- global _DEFAULT_CONFIG
58- _DEFAULT_CONFIG = file_path or find_default_config ()
91+ file_path = file_path or find_default_config ()
5992 LOG .info (f"default config file changed to: { file_path } " )
93+ save_ovos_core_config ({"default_config_path" : file_path })
6094
6195
6296def find_default_config ():
63- if _DEFAULT_CONFIG :
64- # previously set, otherwise None
65- return _DEFAULT_CONFIG
6697 mycroft_root = search_mycroft_core_location ()
6798 if not mycroft_root :
6899 raise FileNotFoundError ("Couldn't find mycroft core root folder." )
69- return join (mycroft_root , _BASE_FOLDER , "configuration" , _CONFIG_FILE_NAME )
100+ return join (mycroft_root , "mycroft" , "configuration" , "mycroft.conf" )
70101
71102
72103def find_user_config ():
73- # ideally it will have been set by downstream using util methods
104+ if is_using_xdg ():
105+ path = join (XDG .xdg_config_home , get_xdg_base (), get_config_filename ())
106+ if isfile (path ):
107+ return path
74108 old , path = get_config_locations (default = False , web_cache = False ,
75109 system = False , old_user = True ,
76110 user = True )
77111 if isfile (path ):
78112 return path
79-
80- if core_supports_xdg ():
81- path = join (XDG .xdg_config_home , _BASE_FOLDER , _CONFIG_FILE_NAME )
82- else :
83- path = old
84- # mark1 runs as a different user
85- sysconfig = MycroftSystemConfig ()
86- platform_str = sysconfig .get ("enclosure" , {}).get ("platform" , "" )
87- if platform_str == "mycroft_mark_1" :
88- path = "/home/mycroft/.mycroft/mycroft.conf"
89-
90- if not isfile (path ) and isfile (old ):
91- # xdg might be disabled in HolmesV compatibility mode
92- # or migration might be in progress
93- # (user action required when updated from a no xdg install)
94- path = old
95-
113+ if isfile (old ):
114+ return old
115+ # mark1 runs as a different user
116+ sysconfig = MycroftSystemConfig ()
117+ platform_str = sysconfig .get ("enclosure" , {}).get ("platform" , "" )
118+ if platform_str == "mycroft_mark_1" :
119+ path = "/home/mycroft/.mycroft/mycroft.conf"
96120 return path
97121
98122
99123def get_config_locations (default = True , web_cache = True , system = True ,
100124 old_user = True , user = True ):
101125 locs = []
126+ ovos_cfg = get_ovos_config ()
102127 if default :
103- locs .append (_DEFAULT_CONFIG )
128+ locs .append (ovos_cfg [ "default_config_path" ] )
104129 if system :
105- locs .append (_SYSTEM_CONFIG )
130+ locs .append (f"/etc/ { ovos_cfg [ 'base_folder' ] } / { ovos_cfg [ 'config_filename' ] } " )
106131 if web_cache :
107- locs .append (_WEB_CONFIG_CACHE )
132+ locs .append (f" { XDG . xdg_config_home } / { ovos_cfg [ 'base_folder' ] } /web_cache.json" )
108133 if old_user :
109- locs .append (_OLD_USER_CONFIG )
134+ locs .append (f"~/. { ovos_cfg [ 'base_folder' ] } / { ovos_cfg [ 'config_filename' ] } " )
110135 if user :
111- locs .append (_USER_CONFIG )
112-
136+ if is_using_xdg ():
137+ locs .append (f"{ XDG .xdg_config_home } /{ ovos_cfg ['base_folder' ]} /{ ovos_cfg ['config_filename' ]} " )
138+ else :
139+ locs .append (f"~/.{ ovos_cfg ['base_folder' ]} /{ ovos_cfg ['config_filename' ]} " )
113140 return locs
114141
115142
116143def get_webcache_location ():
117- return join (XDG .xdg_config_home , _BASE_FOLDER , _CONFIG_FILE_NAME )
144+ return join (XDG .xdg_config_home , get_xdg_base (), 'web_cache.json' )
118145
119146
120147def get_xdg_config_locations ():
@@ -128,7 +155,7 @@ def get_xdg_config_locations():
128155
129156
130157def get_config_filename ():
131- return _CONFIG_FILE_NAME
158+ return get_ovos_config (). get ( "config_filename" ) or "mycroft.conf"
132159
133160
134161def set_config_name (name , core_folder = None ):
@@ -138,7 +165,7 @@ def set_config_name(name, core_folder=None):
138165
139166
140167def read_mycroft_config ():
141- conf = LocalConf (None )
168+ conf = LocalConf ("tmp/dummy.conf" )
142169 conf .merge (MycroftDefaultConfig ())
143170 conf .merge (MycroftSystemConfig ())
144171 conf .merge (MycroftUserConfig ())
@@ -155,60 +182,13 @@ def update_mycroft_config(config, path=None):
155182 return conf
156183
157184
158- class LocalConf (dict ):
185+ class LocalConf (JsonStorage ):
159186 """
160187 Config dict from file.
161188 """
162189 allow_overwrite = True
163-
164- def __init__ (self , path ):
165- super (LocalConf , self ).__init__ ()
166- self .path = path
167- if self .path :
168- self .load_local (self .path )
169-
170- def load_local (self , path ):
171- """
172- Load local json file into self.
173-
174- Args:
175- path (str): file to load
176- """
177- path = expanduser (path )
178- if exists (path ) and isfile (path ):
179- try :
180- config = load_commented_json (path )
181- for key in config :
182- self .__setitem__ (key , config [key ])
183- #LOG.debug("Configuration {} loaded".format(path))
184- except Exception as e :
185- LOG .error ("Error loading configuration '{}'" .format (path ))
186- LOG .error (repr (e ))
187- else :
188- pass
189- #LOG.debug("Configuration '{}' not defined, skipping".format(path))
190-
191- def reload (self ):
192- self .load_local (self .path )
193-
194- def store (self , path = None ):
195- """
196- store the configuration locally.
197- """
198- path = path or self .path
199- if not path :
200- LOG .warning ("config path not set, updating user config!!" )
201- update_mycroft_config (self )
202- return
203- path = expanduser (path )
204- if not isdir (dirname (path )):
205- makedirs (dirname (path ))
206- with open (path , 'w' , encoding = "utf-8" ) as f :
207- json .dump (self , f , indent = 4 , ensure_ascii = False )
208-
209- def merge (self , conf ):
210- merge_dict (self , conf )
211- return self
190+ def __init__ (self , path = None ):
191+ super (LocalConf , self ).__init__ (path )
212192
213193
214194class ReadOnlyConfig (LocalConf ):
@@ -234,10 +214,10 @@ def __setattr__(self, key, value):
234214 raise PermissionError
235215 super ().__setattr__ (key , value )
236216
237- def merge (self , conf ):
217+ def merge (self , * args , ** kwargs ):
238218 if not self .allow_overwrite :
239219 raise PermissionError
240- super ().merge (conf )
220+ super ().merge (* args , ** kwargs )
241221
242222 def store (self , path = None ):
243223 if not self .allow_overwrite :
@@ -253,7 +233,7 @@ def __init__(self):
253233
254234class MycroftDefaultConfig (ReadOnlyConfig ):
255235 def __init__ (self ):
256- path = find_default_config ()
236+ path = get_ovos_config ()[ "default_config_path" ]
257237 super ().__init__ (path )
258238 if not self .path or not isfile (self .path ):
259239 LOG .debug (f"mycroft root path not found, could not load default .conf: { self .path } " )
0 commit comments