Skip to content

Commit

Permalink
refactor/replace_pyxdg
Browse files Browse the repository at this point in the history
  • Loading branch information
JarbasAl committed Feb 15, 2022
1 parent 10f71bd commit 2585c18
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 19 deletions.
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
recursive-include ovos_utils/res *
recursive-include ovos_utils/requirements *
recursive-include requirements *
2 changes: 1 addition & 1 deletion ovos_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import re
import datetime
import kthread
from ovos_utils.network_utils import *
from ovos_utils.network_utils import get_ip, get_external_ip, is_connected_dns, is_connected_http, is_connected
from ovos_utils.file_utils import resolve_ovos_resource_file, resolve_resource_file


Expand Down
51 changes: 41 additions & 10 deletions ovos_utils/configuration.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,43 @@
from importlib.util import find_spec
from os.path import isfile, join
from os.path import isfile, join, isdir

import xdg.BaseDirectory
from json_database import JsonStorage
from xdg import BaseDirectory as XDG

from ovos_utils.json_helper import load_commented_json, merge_dict
from ovos_utils.log import LOG
from ovos_utils.system import search_mycroft_core_location
from ovos_utils.xdg_utils import (
xdg_config_home,
xdg_config_dirs,
xdg_data_home,
xdg_data_dirs,
xdg_cache_home
)


def get_xdg_config_dirs(folder=None):
folder = folder or get_xdg_base()
return [join(path, folder) for path in xdg_config_dirs() if isdir(join(path, folder))]


def get_xdg_data_dirs(folder=None):
folder = folder or get_xdg_base()
return [join(path, folder) for path in xdg_data_dirs() if isdir(join(path, folder))]


def get_xdg_config_save_path(folder=None):
folder = folder or get_xdg_base()
return join(xdg_config_home(), folder)


def get_xdg_data_save_path(folder=None):
folder = folder or get_xdg_base()
return join(xdg_data_home(), folder)


def get_xdg_cache_save_path(folder=None):
folder = folder or get_xdg_base()
return join(xdg_cache_home(), folder)


def get_ovos_config():
Expand All @@ -30,7 +60,7 @@ def get_ovos_config():

# This includes both the user config and
# /etc/xdg/OpenVoiceOS/ovos.conf
for p in xdg.BaseDirectory.load_config_paths("OpenVoiceOS"):
for p in get_xdg_config_dirs("OpenVoiceOS"):
if isfile(join(p, "ovos.conf")):
try:
xdg_cfg = load_commented_json(join(p, "ovos.conf"))
Expand Down Expand Up @@ -67,7 +97,7 @@ def get_xdg_base():


def save_ovos_core_config(new_config):
OVOS_CONFIG = join(xdg.BaseDirectory.save_config_path("OpenVoiceOS"),
OVOS_CONFIG = join(get_xdg_config_save_path("OpenVoiceOS"),
"ovos.conf")
cfg = JsonStorage(OVOS_CONFIG)
cfg.update(new_config)
Expand Down Expand Up @@ -102,7 +132,7 @@ def find_default_config():

def find_user_config():
if is_using_xdg():
path = join(XDG.xdg_config_home, get_xdg_base(), get_config_filename())
path = join(get_xdg_config_save_path(), get_config_filename())
if isfile(path):
return path
old, path = get_config_locations(default=False, web_cache=False,
Expand All @@ -129,27 +159,27 @@ def get_config_locations(default=True, web_cache=True, system=True,
if system:
locs.append(f"/etc/{ovos_cfg['base_folder']}/{ovos_cfg['config_filename']}")
if web_cache:
locs.append(f"{XDG.xdg_config_home}/{ovos_cfg['base_folder']}/web_cache.json")
locs.append(get_webcache_location())
if old_user:
locs.append(f"~/.{ovos_cfg['base_folder']}/{ovos_cfg['config_filename']}")
if user:
if is_using_xdg():
locs.append(f"{XDG.xdg_config_home}/{ovos_cfg['base_folder']}/{ovos_cfg['config_filename']}")
locs.append(f"{get_xdg_config_save_path()}/{ovos_cfg['config_filename']}")
else:
locs.append(f"~/.{ovos_cfg['base_folder']}/{ovos_cfg['config_filename']}")
return locs


def get_webcache_location():
return join(XDG.xdg_config_home, get_xdg_base(), 'web_cache.json')
return join(get_xdg_config_save_path(), 'web_cache.json')


def get_xdg_config_locations():
# This includes both the user config and
# /etc/xdg/mycroft/mycroft.conf
xdg_paths = list(reversed(
[join(p, get_config_filename())
for p in XDG.load_config_paths(get_xdg_base())]
for p in get_xdg_config_dirs()]
))
return xdg_paths

Expand Down Expand Up @@ -187,6 +217,7 @@ class LocalConf(JsonStorage):
Config dict from file.
"""
allow_overwrite = True

def __init__(self, path=None):
super(LocalConf, self).__init__(path)

Expand Down
6 changes: 2 additions & 4 deletions ovos_utils/skills/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from ovos_utils.configuration import read_mycroft_config, \
update_mycroft_config, get_xdg_base
from ovos_utils.configuration import read_mycroft_config, update_mycroft_config, get_xdg_data_save_path
from ovos_utils.messagebus import wait_for_reply
from os.path import join, isdir, isfile
from os import listdir
from xdg import BaseDirectory as XDG


def skills_loaded(bus=None):
Expand Down Expand Up @@ -67,7 +65,7 @@ def get_skills_folder(config=None):
# once XDG PR is merged skills folder will no longer be configurable,
# skills are moved automatically to new locations
# this is already live in mycroft-lib
xdg_skills = join(XDG.xdg_data_home, get_xdg_base(), 'skills')
xdg_skills = join(get_xdg_data_save_path(), 'skills')
if isdir(xdg_skills):
return xdg_skills

Expand Down
174 changes: 174 additions & 0 deletions ovos_utils/xdg_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Copyright © 2016-2021 Scott Stevenson <scott@stevenson.io>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.

"""XDG Base Directory Specification variables.
xdg_cache_home(), xdg_config_home(), xdg_data_home(), and xdg_state_home()
return pathlib.Path objects containing the value of the environment variable
named XDG_CACHE_HOME, XDG_CONFIG_HOME, XDG_DATA_HOME, and XDG_STATE_HOME
respectively, or the default defined in the specification if the environment
variable is unset, empty, or contains a relative path rather than absolute
path.
xdg_config_dirs() and xdg_data_dirs() return a list of pathlib.Path
objects containing the value, split on colons, of the environment
variable named XDG_CONFIG_DIRS and XDG_DATA_DIRS respectively, or the
default defined in the specification if the environment variable is
unset or empty. Relative paths are ignored, as per the specification.
xdg_runtime_dir() returns a pathlib.Path object containing the value of
the XDG_RUNTIME_DIR environment variable, or None if the environment
variable is not set, or contains a relative path rather than absolute path.
"""

# pylint: disable=fixme

import os
from pathlib import Path
from typing import List, Optional

__all__ = [
"xdg_cache_home",
"xdg_config_dirs",
"xdg_config_home",
"xdg_data_dirs",
"xdg_data_home",
"xdg_runtime_dir",
"xdg_state_home",
"XDG_CACHE_HOME",
"XDG_CONFIG_DIRS",
"XDG_CONFIG_HOME",
"XDG_DATA_DIRS",
"XDG_DATA_HOME",
"XDG_RUNTIME_DIR",
]


def _path_from_env(variable: str, default: Path) -> Path:
"""Read an environment variable as a path.
The environment variable with the specified name is read, and its
value returned as a path. If the environment variable is not set, is
set to the empty string, or is set to a relative rather than
absolute path, the default value is returned.
Parameters
----------
variable : str
Name of the environment variable.
default : Path
Default value.
Returns
-------
Path
Value from environment or default.
"""
# TODO(srstevenson): Use assignment expression in Python 3.8.
value = os.environ.get(variable)
if value and os.path.isabs(value):
return Path(value)
return default


def _paths_from_env(variable: str, default: List[Path]) -> List[Path]:
"""Read an environment variable as a list of paths.
The environment variable with the specified name is read, and its
value split on colons and returned as a list of paths. If the
environment variable is not set, or set to the empty string, the
default value is returned. Relative paths are ignored, as per the
specification.
Parameters
----------
variable : str
Name of the environment variable.
default : List[Path]
Default value.
Returns
-------
List[Path]
Value from environment or default.
"""
# TODO(srstevenson): Use assignment expression in Python 3.8.
value = os.environ.get(variable)
if value:
paths = [
Path(path) for path in value.split(":") if os.path.isabs(path)
]
if paths:
return paths
return default


def xdg_cache_home() -> Path:
"""Return a Path corresponding to XDG_CACHE_HOME."""
return _path_from_env("XDG_CACHE_HOME", Path.home() / ".cache")


def xdg_config_dirs() -> List[Path]:
"""Return a list of Paths corresponding to XDG_CONFIG_DIRS."""
return _paths_from_env("XDG_CONFIG_DIRS", [Path("/etc/xdg")])


def xdg_config_home() -> Path:
"""Return a Path corresponding to XDG_CONFIG_HOME."""
return _path_from_env("XDG_CONFIG_HOME", Path.home() / ".config")


def xdg_data_dirs() -> List[Path]:
"""Return a list of Paths corresponding to XDG_DATA_DIRS."""
return _paths_from_env(
"XDG_DATA_DIRS",
[Path(path) for path in "/usr/local/share/:/usr/share/".split(":")],
)


def xdg_data_home() -> Path:
"""Return a Path corresponding to XDG_DATA_HOME."""
return _path_from_env("XDG_DATA_HOME", Path.home() / ".local" / "share")


def xdg_runtime_dir() -> Optional[Path]:
"""Return a Path corresponding to XDG_RUNTIME_DIR.
If the XDG_RUNTIME_DIR environment variable is not set, None will be
returned as per the specification.
"""
value = os.getenv("XDG_RUNTIME_DIR")
if value and os.path.isabs(value):
return Path(value)
return None


def xdg_state_home() -> Path:
"""Return a Path corresponding to XDG_STATE_HOME."""
return _path_from_env("XDG_STATE_HOME", Path.home() / ".local" / "state")


# The following variables are deprecated, but remain for backward compatibility.
XDG_CACHE_HOME = xdg_cache_home()
XDG_CONFIG_DIRS = xdg_config_dirs()
XDG_CONFIG_HOME = xdg_config_home()
XDG_DATA_DIRS = xdg_data_dirs()
XDG_DATA_HOME = xdg_data_home()
XDG_RUNTIME_DIR = xdg_runtime_dir()
3 changes: 1 addition & 2 deletions requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
mycroft-messagebus-client~=0.9.1,!=0.9.2,!=0.9.3
pexpect~=4.8
requests~=2.26
json_database~=0.5
json_database~=0.7
kthread~=0.2
pyxdg~=0.26
PyYAML~=5.4
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def required(requirements_file):

setup(
name='ovos_utils',
version='0.0.14a5',
version='0.0.14a7',
packages=['ovos_utils',
'ovos_utils.intents',
'ovos_utils.sound',
Expand Down

0 comments on commit 2585c18

Please sign in to comment.