File: environment.py

package info (click to toggle)
python-proton-core 0.4.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 540 kB
  • sloc: python: 3,574; makefile: 15
file content (148 lines) | stat: -rw-r--r-- 4,841 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""
Copyright (c) 2023 Proton AG

This file is part of Proton.

Proton 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.

Proton 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 ProtonVPN.  If not, see <https://www.gnu.org/licenses/>.
"""
from .metaclasses import Singleton
import os
import shutil
# Try to get the BaseDirectory module
try:
    from xdg import BaseDirectory
except ImportError:
    BaseDirectory = None


class ExecutionEnvironment(metaclass=Singleton):
    PROTON_DIR_NAME = "Proton"

    def __init__(self):
        # If we run as a system user, use system paths
        if os.getuid() == 0:
            self._setup_as_system_user()
        else:
        # If we run as a normal user
            self._setup_as_regular_user()

    @property
    def path_config(self):
        self.generate_dirs(self._path_config)
        return self._path_config

    @property
    def path_cache(self):
        self.generate_dirs(self._path_cache)
        return self._path_cache

    @property
    def path_logs(self):
        self.generate_dirs(self._path_logs)
        return self._path_logs

    @property
    def path_runtime(self):
        self.generate_dirs(self._path_runtime)
        return self._path_runtime

    @property
    def systemd_unit(self):
        return self._path_systemd_unit

    def generate_dirs(self, path):
        if os.path.isdir(path):
            return

        os.makedirs(path, mode=0o700, exist_ok=True)

    def _setup_as_system_user(self):
        self._path_config = f'/etc/{self.PROTON_DIR_NAME}'
        self._path_cache = f'/var/cache/{self.PROTON_DIR_NAME}'
        self._path_logs = f'/var/log/{self.PROTON_DIR_NAME}'
        self._path_runtime = f'/run/{self.PROTON_DIR_NAME}'
        self._path_systemd_unit = '/etc/systemd/system'

    def _setup_as_regular_user(self):
        config_home, cache_home, runtime_dir = self._get_dir_paths()

        self._path_config = os.path.join(config_home, self.PROTON_DIR_NAME)
        self._path_cache = os.path.join(cache_home, self.PROTON_DIR_NAME)
        self._path_logs = os.path.join(cache_home, self.PROTON_DIR_NAME, 'logs')
        self._path_runtime = os.path.join(runtime_dir, self.PROTON_DIR_NAME)
        self._path_systemd_unit = os.path.join(config_home, "systemd", "user")

    def _get_dir_paths(self):
        # If BaseDirectory is found then we can extract valuable data from it
        if BaseDirectory:
            config_home = BaseDirectory.xdg_config_home
            cache_home = BaseDirectory.xdg_cache_home
            runtime_dir = BaseDirectory.get_runtime_dir()
        else:
        # Otherwise use default constructed from $HOME environment variable
            home = os.environ.get('HOME', None)
            if home is None:
                raise RuntimeError("Cannot figure out where to place files, is $HOME defined?")

            config_home = os.path.join(home, '.config')
            cache_home = os.path.join(home, '.cache')
            runtime_dir = f'/run/user/{os.getuid()}'

        return config_home, cache_home, runtime_dir

class ProductExecutionEnvironment(ExecutionEnvironment):
    """
    This class serves the purpose of helping in standardizing folder structure
    across products. Thus each product should derive from `ProductExecutionEnvironment`
    and setting the class property `PRODUCT` to match its correspondent product.

    This should help to more easily find files and improving cross-product
    collaboration. 
    """
    PRODUCT = None

    def __init__(self):
        super().__init__()
        if self.PRODUCT is None:
            raise RuntimeError("`PRODUCT` is not set")

    @property
    def path_config(self):
        path = os.path.join(super().path_config, self.PRODUCT)
        self.generate_dirs(path)
        return path

    @property
    def path_cache(self):
        path = os.path.join(super().path_cache, self.PRODUCT)
        self.generate_dirs(path)
        return path

    @property
    def path_logs(self):
        path = os.path.join(super().path_logs, self.PRODUCT)
        self.generate_dirs(path)
        return path

    @property
    def path_runtime(self):
        path = os.path.join(super().path_runtime, self.PRODUCT)
        self.generate_dirs(path)
        return path



class VPNExecutionEnvironment(ProductExecutionEnvironment):
    """Execution environment dedicated for the VPN product."""
    PRODUCT = "VPN"