From 5dcccad90bd7757c016721497e9be95181a64c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Sun, 21 Aug 2022 22:54:52 +0200 Subject: [PATCH] roezio: migrate poezio/xdg.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maxime “pep” Buquet --- Cargo.toml | 1 + poezio/config.py | 6 ++-- poezio/connection.py | 4 +-- poezio/core/completions.py | 4 +-- poezio/core/core.py | 5 +-- poezio/libpoezio.pyi | 6 ++++ poezio/plugin_manager.py | 7 ++-- poezio/theming.py | 4 +-- poezio/xdg.py | 41 ---------------------- src/lib.rs | 2 ++ src/xdg.rs | 69 ++++++++++++++++++++++++++++++++++++++ 11 files changed, 94 insertions(+), 55 deletions(-) delete mode 100644 poezio/xdg.py create mode 100644 src/xdg.rs diff --git a/Cargo.toml b/Cargo.toml index bd86bf6b..6c28926d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ ncurses = "5" lazy_static = "1" enum-set = "0.0" clap = { version = "3.2.17", features = ["derive"] } +directories = "4.0.1" [lib] crate-type = ["cdylib"] diff --git a/poezio/config.py b/poezio/config.py index 4eb43cad..0a86ac8a 100644 --- a/poezio/config.py +++ b/poezio/config.py @@ -19,7 +19,7 @@ from configparser import RawConfigParser, NoOptionError, NoSectionError from pathlib import Path from typing import Dict, List, Optional, Union, Tuple, cast, Any -from poezio import xdg +from poezio.libpoezio import XDG from slixmpp import JID, InvalidJID log = logging.getLogger(__name__) # type: logging.Logger @@ -603,7 +603,7 @@ def get_image_cache() -> Optional[Path]: tmp_dir = config.getstr('tmp_image_dir') if tmp_dir: return Path(tmp_dir) - return xdg.CACHE_HOME / 'images' + return XDG.cache_dir / 'images' def check_config(): @@ -656,7 +656,7 @@ def setup_logging(debug_file=''): "Change the logging config according to the cmdline options and config" global LOG_DIR LOG_DIR = config.get('log_dir') - LOG_DIR = Path(LOG_DIR).expanduser() if LOG_DIR else xdg.DATA_HOME / 'logs' + LOG_DIR = Path(LOG_DIR).expanduser() if LOG_DIR else XDG.data_dir / 'logs' from copy import deepcopy logging_config = deepcopy(LOGGING_CONFIG) if config.get('log_errors'): diff --git a/poezio/connection.py b/poezio/connection.py index 503d9169..b0c6fb45 100644 --- a/poezio/connection.py +++ b/poezio/connection.py @@ -27,7 +27,7 @@ from slixmpp.util import FileSystemCache from poezio import common from poezio import fixes -from poezio import xdg +from poezio.libpoezio import XDG from poezio.config import config @@ -136,7 +136,7 @@ class Connection(slixmpp.ClientXMPP): 'https://poez.io', 'cache': FileSystemCache( - str(xdg.CACHE_HOME), + str(XDG.cache_dir), 'caps', encode=str, decode=lambda x: DiscoInfo(ET.fromstring(x))), diff --git a/poezio/core/completions.py b/poezio/core/completions.py index 084910a2..1cb934c0 100644 --- a/poezio/core/completions.py +++ b/poezio/core/completions.py @@ -11,7 +11,7 @@ from slixmpp import JID, InvalidJID from poezio import common from poezio import tabs -from poezio import xdg +from poezio.libpoezio import XDG from poezio.config import config from poezio.roster import roster @@ -82,7 +82,7 @@ class CompletionCore: """ Completion for /theme""" themes_dir = config.getstr('themes_dir') themes_dir = Path(themes_dir).expanduser( - ) if themes_dir else xdg.DATA_HOME / 'themes' + ) if themes_dir else XDG.data_dir / 'themes' try: theme_files = [ name.stem for name in themes_dir.iterdir() diff --git a/poezio/core/core.py b/poezio/core/core.py index 7690e769..b1b6c8a2 100644 --- a/poezio/core/core.py +++ b/poezio/core/core.py @@ -66,7 +66,8 @@ from poezio.size_manager import SizeManager from poezio.user import User from poezio.text_buffer import TextBuffer from poezio.timed_events import DelayedEvent -from poezio import keyboard, xdg +from poezio import keyboard +from poezio.libpoezio import XDG from poezio.core.completions import CompletionCore from poezio.core.tabs import Tabs @@ -154,7 +155,7 @@ class Core: self.bookmarks = BookmarkList() self.remote_fifo = None self.avatar_cache = FileSystemPerJidCache( - str(xdg.CACHE_HOME), 'avatars', binary=True) + str(XDG.cache_dir), 'avatars', binary=True) # a unique buffer used to store global information # that are displayed in almost all tabs, in an # information window. diff --git a/poezio/libpoezio.pyi b/poezio/libpoezio.pyi index 1212d2c2..cc5a7311 100644 --- a/poezio/libpoezio.pyi +++ b/poezio/libpoezio.pyi @@ -1,4 +1,10 @@ from typing import Any, Dict, List, Tuple +from pathlib import Path def to_curses_attr(fg: int, bg: int, attrs: str) -> int: ... def run_cmdline_args(argv: List[str]) -> Tuple[Dict[Any, Any], bool]: ... + +class XDG: + cache_dir: Path + config_dir: Path + data_dir: Path diff --git a/poezio/plugin_manager.py b/poezio/plugin_manager.py index 17673a9e..ba3f94a1 100644 --- a/poezio/plugin_manager.py +++ b/poezio/plugin_manager.py @@ -13,7 +13,8 @@ from pathlib import Path from os import path import pkg_resources -from poezio import tabs, xdg +from poezio import tabs +from poezio.libpoezio import XDG from poezio.core.structs import Command, Completion from poezio.plugin import PluginAPI from poezio.config import config @@ -395,7 +396,7 @@ class PluginManager: """ plugins_conf_dir = config.getstr('plugins_conf_dir') self.plugins_conf_dir = Path(plugins_conf_dir).expanduser( - ) if plugins_conf_dir else xdg.CONFIG_HOME / 'plugins' + ) if plugins_conf_dir else XDG.config_dir / 'plugins' self.check_create_plugins_conf_dir() def check_create_plugins_conf_dir(self): @@ -420,7 +421,7 @@ class PluginManager: """ plugins_dir = config.getstr('plugins_dir') self.plugins_dir = Path(plugins_dir).expanduser( - ) if plugins_dir else xdg.DATA_HOME / 'plugins' + ) if plugins_dir else XDG.data_dir / 'plugins' self.check_create_plugins_dir() def check_create_plugins_dir(self): diff --git a/poezio/theming.py b/poezio/theming.py index 446455e0..319440ec 100755 --- a/poezio/theming.py +++ b/poezio/theming.py @@ -77,7 +77,7 @@ from typing import Dict, List, Union, Tuple, Optional, cast from pathlib import Path from os import path from datetime import datetime -from poezio import colors, xdg, libpoezio +from poezio import colors, libpoezio from importlib import machinery finder = machinery.PathFinder() @@ -450,7 +450,7 @@ def update_themes_dir(option: Optional[str] = None, # import from the user-defined prefs themes_dir_str = config.getstr('themes_dir') themes_dir = Path(themes_dir_str).expanduser( - ) if themes_dir_str else xdg.DATA_HOME / 'themes' + ) if themes_dir_str else libpoezio.XDG.data_dir / 'themes' try: themes_dir.mkdir(parents=True, exist_ok=True) except OSError: diff --git a/poezio/xdg.py b/poezio/xdg.py deleted file mode 100644 index d7ff9d73..00000000 --- a/poezio/xdg.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2018 Emmanuel Gil Peyrot -# -# This file is part of Poezio. -# -# Poezio is free software: you can redistribute it and/or modify -# it under the terms of the GPL-3.0+ license. See the COPYING file. -""" -Implements the XDG base directory specification. - -https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html -""" - -from pathlib import Path -from os import environ -from typing import Dict - -# $HOME has already been checked to not be None in test_env(). -DEFAULT_PATHS: Dict[str, Path] = { - 'XDG_CONFIG_HOME': Path.home() / '.config', - 'XDG_DATA_HOME': Path.home() / '.local' / 'share', - 'XDG_CACHE_HOME': Path.home() / '.cache', -} - - -def _get_directory(variable: str) -> Path: - """ - returns the default configuration directory path - """ - if variable not in DEFAULT_PATHS: - raise ValueError('Invalid XDG basedir variable') - xdg = environ.get(variable) - if xdg is not None: - xdg_path = Path(xdg) - if xdg_path.is_absolute(): - return xdg_path / 'poezio' - return DEFAULT_PATHS[variable] / 'poezio' - - -CONFIG_HOME = _get_directory('XDG_CONFIG_HOME') -DATA_HOME = _get_directory('XDG_DATA_HOME') -CACHE_HOME = _get_directory('XDG_CACHE_HOME') diff --git a/src/lib.rs b/src/lib.rs index 96cefa51..72007500 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ mod args; mod error; mod logger; mod theming; +mod xdg; use crate::args::parse_args; use crate::logger::LogItem; @@ -27,6 +28,7 @@ fn libpoezio(py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(to_curses_attr, m)?)?; m.add_function(wrap_pyfunction!(parse_logs, m)?)?; m.add_function(wrap_pyfunction!(run_cmdline_args, m)?)?; + m.add("XDG", xdg::PyProject::new(xdg::PROJECT.clone()))?; Ok(()) } diff --git a/src/xdg.rs b/src/xdg.rs new file mode 100644 index 00000000..971aa84d --- /dev/null +++ b/src/xdg.rs @@ -0,0 +1,69 @@ +// Copyright (C) 2018-2099 The crate authors. +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at your +// option) any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::cell::LazyCell; + +use directories::ProjectDirs; +use pyo3::{ + marker::Python, + prelude::{pyclass, pymethods, PyObject, PyResult}, + IntoPy, +}; + +/// Project qualifier +pub const QUALIFIER: &'static str = "io"; +/// Project organization +pub const ORGANIZATION: &'static str = "poez"; +/// Project appname +pub const APPNAME: &'static str = "Poezio"; + +/// Project directories +pub const PROJECT: LazyCell = LazyCell::new(|| { + ProjectDirs::from(QUALIFIER, ORGANIZATION, APPNAME).expect("HOME dir should be available.") +}); + +#[pyclass(name = "XDG")] +pub struct PyProject(ProjectDirs); + +fn get_path(py: Python<'_>) -> PyResult { + // TODO: Stop importing pathlib all the time + let pathlib = py.import("pathlib")?; + let path = pathlib.getattr("Path")?; + Ok(path.into_py(py)) +} + +impl PyProject { + pub fn new(dirs: ProjectDirs) -> Self { + PyProject(dirs) + } +} + +#[pymethods] +impl PyProject { + #[getter] + pub fn cache_dir(&self, py: Python<'_>) -> PyResult { + Ok(get_path(py)?.call1(py, (self.0.cache_dir(),))?) + } + + #[getter] + pub fn config_dir(&self, py: Python<'_>) -> PyResult { + Ok(get_path(py)?.call1(py, (self.0.config_dir(),))?) + } + + #[getter] + pub fn data_dir(&self, py: Python<'_>) -> PyResult { + Ok(get_path(py)?.call1(py, (self.0.data_dir(),))?) + } +}