1#
2# Gramps - a GTK+/GNOME based genealogy program
3#
4# Copyright (C) 2013       John Ralls <jralls@ceridwen.us>
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19#
20import sys
21import os
22import logging
23LOG = logging.getLogger("ResourcePath")
24_hdlr = logging.StreamHandler()
25_hdlr.setFormatter(logging.Formatter(fmt="%(name)s.%(levelname)s: %(message)s"))
26LOG.addHandler(_hdlr)
27
28from ..constfunc import get_env_var
29
30class ResourcePath:
31    """
32    ResourcePath is a singleton, meaning that only one of them is ever
33    created.  At startup it finds the paths to Gramps's resource files and
34    caches them for future use.
35
36    It should be called only by const.py; other code should retrieve the
37    paths from there.
38    """
39    instance = None
40    def __new__(cls):
41        if not cls.instance:
42            cls.instance = super(ResourcePath, cls).__new__(cls)
43            cls.instance.initialized = False
44
45        return cls.instance
46
47    def __init__(self):
48        if self.initialized:
49            return
50        resource_file = os.path.join(os.path.abspath(os.path.dirname(
51            __file__)), 'resource-path')
52        installed = os.path.exists(resource_file)
53        if installed:
54            test_path = os.path.join("gramps", "authors.xml")
55        else:
56            test_path = os.path.join("data", "authors.xml")
57        resource_path = None
58        tmp_path = get_env_var('GRAMPS_RESOURCES')
59        if (tmp_path and os.path.exists(os.path.join(tmp_path, test_path))):
60            resource_path = tmp_path
61        elif installed:
62            try:
63                with open(resource_file, encoding='utf-8',
64                                errors='strict') as fp:
65                    resource_path = fp.readline()
66            except UnicodeError as err:
67                LOG.exception("Encoding error while parsing resource path", err)
68                sys.exit(1)
69            except IOError as err:
70                LOG.exception("Failed to open resource file", err)
71                sys.exit(1)
72            if not os.path.exists(os.path.join(resource_path, test_path)):
73                LOG.error("Resource Path %s is invalid", resource_path)
74                sys.exit(1)
75        else:
76            # Let's try to run from source without env['GRAMPS_RESOURCES']:
77            resource_path = os.path.join(os.path.abspath(os.path.dirname(
78                __file__)), '..', "..", "..")
79            test_path = os.path.join("data", "authors.xml")
80            if (not os.path.exists(os.path.join(resource_path, test_path))):
81                LOG.error("Unable to determine resource path")
82                sys.exit(1)
83
84        resource_path = os.path.abspath(resource_path)
85        if installed:
86            self.locale_dir = os.path.join(resource_path, 'locale')
87            self.data_dir = os.path.join(resource_path, 'gramps')
88            self.image_dir = os.path.join(resource_path, 'gramps', 'images')
89            self.doc_dir = os.path.join(resource_path, 'doc', 'gramps')
90
91        else:
92            self.locale_dir = os.path.join(resource_path, 'build', 'mo')
93            self.image_dir = os.path.join(resource_path, 'images')
94            self.data_dir = os.path.join(resource_path, 'data')
95            self.doc_dir = os.path.join(resource_path, 'build', 'data')
96
97        self.initialized = True
98
99
100