1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6'''
7Manage separate databases and caches for different user projects.
9Squirrel based applications can either use the user's global database which
10lives in Pyrocko's global cache directory (by default under
11``'$HOME/.pyrocko/cache/squirrel'``) or a project specific local database which
12can be conveniently created in the top level directory of a user's project
13under ``'.squirrel'`` or ``'squirrel'``. The choice of database and associated
14cache directory locations is referred to here as the Squirrel environment. This
15module provides functions to create local environments and to look for a usable
16environment in the hierarchy of a user's project directory.
17'''
19import os
20import logging
22from pyrocko.guts import String, load
23from pyrocko import config
24from pyrocko.has_paths import HasPaths, Path
26from . import error
27from .database import close_database
29logger = logging.getLogger('psq.environment')
31guts_prefix = 'squirrel'
34g_db_filename = 'nuts.sqlite'
35g_cache_dirname = 'cache'
36g_config_filename = 'config.yaml'
39def get_config_path(squirrel_path):
40 return os.path.join(squirrel_path, g_config_filename)
43def get_squirrel_path(path=None):
44 if path is None:
45 path = os.curdir
47 path = os.path.abspath(path)
48 if os.path.isdir(path) and os.path.exists(
49 os.path.join(path, g_db_filename)):
50 return path
52 while True:
53 for entry in ['squirrel', '.squirrel']:
54 candidate = os.path.join(path, entry)
55 if os.path.isdir(candidate) \
56 and os.path.exists(os.path.join(candidate, g_db_filename)):
58 return candidate
60 path_new = os.path.dirname(path)
61 if path_new == path:
62 break
64 path = path_new
66 return os.path.join(config.config().cache_dir, 'squirrel')
69def get_environment(path=None):
70 '''
71 Get default Squirrel environment relevant for a given file system path.
73 :param path:
74 Directory path to use as starting point for detection of the Squirrel
75 environment. By default, the current working directory is used as
76 starting point. When searching for a usable environment the directory
77 ``'.squirrel'`` or ``'squirrel'`` in the current (or starting point)
78 directory is used if it exists, otherwise the parent directories are
79 search upwards for the existence of such a directory. If no such
80 directory is found, the user's global Squirrel environment, usually
81 ``'$HOME/.pyrocko/cache/squirrel'``, is used.
83 :returns:
84 :py:class:`Environment` object containing the detected database
85 and cache directory paths.
86 '''
87 if path is None:
88 path = os.curdir
90 squirrel_path = get_squirrel_path(path)
92 if os.path.exists(get_config_path(squirrel_path)):
93 return Environment.load(squirrel_path)
94 else:
95 return Environment.make(squirrel_path)
98def init_environment(path=None):
99 '''
100 Initialize empty Squirrel environment.
102 :param path:
103 Path to the directory where the new environment's ``'.squirrel'``
104 directory should be created. If set to ``None``, the current working
105 directory is used.
107 If a ``'.squirrel'`` directory already exists at the given location,
108 :py:exc:`~pyrocko.squirrel.error.SquirrelError` is raised.
109 '''
110 if path is None:
111 path = os.curdir
113 squirrel_path = os.path.join(path, '.squirrel')
114 try:
115 logger.info(
116 'Creating squirrel environment directory: %s'
117 % os.path.abspath(squirrel_path))
118 os.mkdir(squirrel_path)
119 except OSError:
120 raise error.SquirrelError(
121 'Cannot create squirrel directory: %s' % squirrel_path)
123 from .base import Squirrel
124 env = Environment.make(squirrel_path)
125 env.dump(filename=get_config_path(squirrel_path))
126 sq = Squirrel(env)
127 database = sq.get_database()
128 del sq
129 close_database(database)
132class Environment(HasPaths):
133 '''
134 Configuration object providing paths to database and cache.
135 '''
137 database_path = Path.T(optional=True)
138 cache_path = Path.T(optional=True)
139 persistent = String.T(optional=True)
141 @classmethod
142 def make(cls, squirrel_path):
143 env = cls(
144 database_path=g_db_filename,
145 cache_path=g_cache_dirname)
147 env.set_basepath(squirrel_path)
148 return env
150 @classmethod
151 def load(cls, squirrel_path):
152 path = get_config_path(squirrel_path)
153 try:
154 env = load(filename=path)
155 except OSError:
156 raise error.SquirrelError(
157 'Cannot read environment config file: %s' % path)
159 if not isinstance(env, Environment):
160 raise error.SquirrelError(
161 'Invalid environment config file "%s".' % path)
163 env.set_basepath(squirrel_path)
164 return env
167__all__ = [
168 'get_squirrel_path',
169 'get_environment',
170 'init_environment',
171 'Environment']