"""
Module to govern all the user's directories that are used by Pisak applications.
"""
import os
from gi.repository import GLib
from pisak import res, logger
_LOG = logger.get_logger(__name__)
[docs]def ensure_dir(dirpath):
"""
Checks if a given directory exists, if not then creates one,
and finally returns it.
:param dirpath: directory path.
:return: directory path, same as the one passed as a param.
"""
if not os.path.exists(dirpath):
os.makedirs(dirpath)
return dirpath
# ---------------------------
# HOME general specification
# ---------------------------
"""
Path to the user's home directory.
"""
HOME = os.path.expanduser("~")
"""
Path to a folder in user's home directory. Contains any files that user has
added and wants them to be available inside of some of the Pisak applications
or files that user has access to and can modify them in order to achieve some
kind of different behaviour or look of some of the Pisak applications.
"""
HOME_PISAK_DIR = ensure_dir(os.path.join(HOME, ".pisak"))
# ------------------------------
# HOME files and subdirectories
# ------------------------------
"""
Path to the configurations directory.
"""
HOME_PISAK_CONFIGS = ensure_dir(os.path.join(HOME_PISAK_DIR, "configs"))
"""
Path to the favouritess directory.
"""
HOME_PISAK_FAVOURITES = ensure_dir(os.path.join(HOME_PISAK_DIR, "favourites"))
"""
Path to the databases directory.
"""
HOME_PISAK_DATABASES = ensure_dir(os.path.join(HOME_PISAK_DIR, "databases"))
"""
Directory with logging files.
"""
HOME_LOGS_DIR = ensure_dir(os.path.join(HOME_PISAK_DIR, "logs"))
"""
Directory that contains custom icons created by the user. Each icon's name has
to correspond to the name of an generic icon that it is supposed to replace.
Accepted format of an icon file is SVG.
"""
HOME_ICONS_DIR = ensure_dir(os.path.join(HOME_PISAK_DIR, "icons"))
"""
Path to a subdirectory in user's home Pisak directory. Contains files in
json format, created and added by user when one wants to change the graphical
layout of some of the Pisak applications. Files structure: main 'json' folder
contains subfolders, each for every application, named as the related
application name, then each of these subfolders contains one or more json
files, each file with the same name as of the related view and 'json' extension.
"""
HOME_JSON_DIR = ensure_dir(os.path.join(HOME_PISAK_DIR, "json"))
"""
Path to a subdirectory in user's home Pisak directory. Contains files in
css format, created and added by user when one wants to change the look of
some elements of a graphical interface or of the whole view of some of
the Pisak applications. Files structure: in this folder there can be one
css file for every application, name of each file must be the same as the
application name with 'css' extension.
"""
HOME_STYLE_DIR = ensure_dir(os.path.join(HOME_PISAK_DIR, "css"))
"""
Folder in user's home Pisak directory, that contains custom made symbols
to be used within the 'symboler' application.
Each custom made symbol replaces a default one or, if there is no default,
extends the collection of all symbols.
"""
HOME_SYMBOLS_DIR = ensure_dir(os.path.join(HOME_PISAK_DIR, "symbols"))
"""
Folder in user's home Pisak directory, that contains custom sounds which can be played
during scanning and button selection.
"""
HOME_SOUNDS_DIR = ensure_dir(os.path.join(HOME_PISAK_DIR, "sounds"))
"""
Path to the spreadsheet containing custom symbols topology for
"symboler" application.
"""
HOME_SYMBOLS_SHEETS = ensure_dir(os.path.join(HOME_PISAK_DIR, "symboler_sheets"))
"""
Path to the main configuration file avalaible for the user.
"""
HOME_MAIN_CONFIG = os.path.join(HOME_PISAK_CONFIGS, "main_config.ini")
"""
Path to the symbols model for "symboler" application.
"""
HOME_SYMBOLS_MODEL = os.path.join(HOME_PISAK_DIR, "symbols_model.ini")
"""
Path to the symbols entries file generated by "symboler" application.
"""
HOME_SYMBOLS_ENTRY = os.path.join(HOME_PISAK_DIR, "symbols_entry.ini")
"""
Path to a file containing all information and list of URLs to blogs that are being
followed by the user.
"""
HOME_FOLLOWED_BLOGS = os.path.join(HOME_PISAK_DIR, "followed_blogs.ini")
"""
Path to a file with all the blog settings or configuration parameters, like: user
credentials, blog address etc.
"""
HOME_BLOG_CONFIG = os.path.join(HOME_PISAK_CONFIGS, "blog_config.ini")
"""
Path to a file where all the necessary setting of an email account are stored.
"""
HOME_EMAIL_CONFIG = os.path.join(HOME_PISAK_CONFIGS, "email_config.ini")
"""
Path to the file with email application address book.
"""
HOME_EMAIL_ADDRESS_BOOK = os.path.join(
HOME_PISAK_DATABASES, "email_address_book.db")
"""
Database with info about text files generated by the 'speller' application.
"""
HOME_TEXT_DOCUMENTS_DB = os.path.join(HOME_PISAK_DATABASES,'documents.db')
# ----------------------------------------------------------------------
# Files and folders from the resources directory in the PISAK repository
# ----------------------------------------------------------------------
"""
Default main configuration file.
"""
RES_MAIN_CONFIG = res.get(os.path.join('configs', 'default_config.ini'))
# ---------------------------
# Default system directories
# ---------------------------
"""
Dictionary with paths to various file system default directories.
"""
USER_FOLDERS = {
"desktop": GLib.USER_DIRECTORY_DESKTOP,
"documents": GLib.USER_DIRECTORY_DOCUMENTS,
"downloads": GLib.USER_DIRECTORY_DOWNLOAD,
"music": GLib.USER_DIRECTORY_MUSIC,
"pictures": GLib.USER_DIRECTORY_PICTURES,
"public": GLib.USER_DIRECTORY_PUBLIC_SHARE,
"templates": GLib.USER_DIRECTORY_TEMPLATES,
"videos": GLib.USER_DIRECTORY_VIDEOS
}
# ----------------------------------------------------
# Functions managing content from various directories
# ----------------------------------------------------
[docs]def find_path(folder1, folder2, file_name, with_raise=False,
custom_msg=''):
"""
Helper function to check if the file is in one folder or the other.
:param folder1: str, full path to user folder to check
:param folder2: str, name of folder in PISAK res folder in which to check
:param file_name: str, name of the file
:param with_raise: bool, whether to raise an error or log a warning
:param custom_msg: str, custom_msg for the error, should contain two '{}'
specifying the places for the file paths
:return: path to the found file or None
"""
msg = custom_msg or 'No such file found as {} or {}.'
path = path1 = os.path.join(folder1, file_name)
if not os.path.isfile(path1):
path = path2 = os.path.join(res.get(folder2), file_name)
if not os.path.isfile(path2):
msg = msg.format(path1, path2)
path = None
if with_raise:
raise FileNotFoundError(msg)
else:
_LOG.warning(msg)
return path
[docs]def get_general_configs():
"""
Get paths to files with general configuration.
:return: list of configuration files, from the most default
to the most custom one.
"""
configs = []
if os.path.isfile(RES_MAIN_CONFIG):
configs.append(RES_MAIN_CONFIG)
else:
raise FileNotFoundError(
"Default general config not found in the res directory.")
if os.path.isfile(HOME_MAIN_CONFIG):
configs.append(HOME_MAIN_CONFIG)
return configs
[docs]def get_icon_path(name):
"""
Get path to an icon with the given name. First look for a custom one in
user home directory, if nothing found, then look for a default one in
res directory. Accepted file format is SVG.
:param name: name of the icon, that is a name of the file containing the
icon without an extension. Accepted file format is SVG.
:return: path to the icon or None if nothing was found.
"""
full_name = name + '.svg'
icon_path = find_path(HOME_ICONS_DIR, 'icons', full_name,
with_raise=True,
custom_msg='No such icon found as {} or {}.')
return icon_path
[docs]def get_css_path(skin='default'):
"""
Get css file with the global style description for the whole program.
Hierarchy of directories being scanned in search for the proper file is
as follows: first the pisak directory in user's home,
then css folder in res.
Structure of style related directories: in pisak folder in user's home -
'css' folder with css files named the same as the given skin;
in res directory - the same as in the home.
:param skin: name of the skin or None for default css.
:return: path to css file.
"""
full_name = skin + '.css'
css_path = find_path(HOME_STYLE_DIR, 'css', full_name, with_raise=True,
custom_msg="Css not found in {} or {}.")
return css_path
[docs]def get_blog_css_path():
"""
Get css file to style Blog posts.
:return: path to a blog CSS file.
"""
full_name = 'blog_style.css'
css_path = find_path(HOME_STYLE_DIR, 'css', full_name, with_raise=True,
custom_msg='CSS file not found as {} or {}.')
return css_path
[docs]def get_json_path(view, layout='default_default', app=''):
"""
Get a json file responsible for building one of the views of the given
application. Shape of the view is described by 'layout' parameter.
Hierarchy of directories being scanned in search for the proper file is
as follows: first the pisak directory in user's home, then json
directory in res for the specific layout and finally json directory in
res for the default layout.
Structure of json related directories: in pisak folder in user's home -
'json' folder with subfolders for different applications, each named as
the corresponding application, then in each of them subfolders for
specific 'layout' with 'json' extended files inside;
in res directory - the same as for the home.
:param view: name of the view.
:param layout: name of the layout of the view or None for default layout.
:param app: name of the application or None, when None then general
jsons are looked for.
:return: path to the json file.
"""
# check home pisak dir
view_path = os.path.join(HOME_JSON_DIR, app, layout, view) + ".json"
# if none has been found look in res directory:
if not os.path.isfile(view_path):
json_dir = res.get(os.path.join("json", app, layout))
view_path = os.path.join(json_dir, view) + ".json"
if not os.path.isfile(view_path) and layout is not "default_default":
default_json_dir = res.get(os.path.join("json", app, "default_default"))
view_path = os.path.join(default_json_dir, view) + ".json"
if not os.path.isfile(view_path):
msg = "Default json for '{}' view of the '{}' application not " \
"found in the res directory."
raise FileNotFoundError(msg.format(view, app))
return view_path
[docs]def get_user_dir(folder):
"""
Get path to one of the XDG user folders.
:param folder: folder name as str, lowercase, possible are:
desktop, documents, downloads, music, pictures, public, templates, videos.
:return: path to XDG user directory.
"""
return GLib.get_user_special_dir(USER_FOLDERS[folder])
[docs]def get_sound_path(name):
"""
Get path to a sound with the given name. First look for a custom sound in
user home directory, if nothing found, then look for a default sound in
res directory. Accepted file format is wav.
:param name: name of the sound file, that is a name of the file without an extension.
Accepted file format is WAV.
:return: path to the sound or None if nothing was found.
"""
name = name.lower().replace(' ', '_').replace('\n', '_')
sound_path = find_path(HOME_SOUNDS_DIR, 'sounds', name,
custom_msg='No sound file found as {} or {}.')
return sound_path
[docs]def get_symbols_spreadsheet(name):
"""
Get path to a spreadsheet with the given name.
:param name: name of the spreadsheet.
:return: path to the spreadsheet.
"""
full_name = name + '.ods'
path = find_path(HOME_SYMBOLS_SHEETS, 'symboler_sheets', full_name,
with_raise=True,
custom_msg='No such spreadsheet found as {} or {}.')
return path
[docs]def get_symbol_path(name):
"""
Get full path to a symbol with the given name.
:param name: name of a symbol, without any extension.
:return: path to a symbol, string.
"""
full_name = name + '.png'
path = find_path(HOME_SYMBOLS_DIR, 'symbols', full_name,
with_raise=True)
return path