Passed
Push — develop ( aa14d6...fc562f )
by Dean
03:00
created

LibrariesManager.setup()   C

Complexity

Conditions 7

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 7.0422
Metric Value
cc 7
dl 0
loc 44
ccs 19
cts 21
cp 0.9048
crap 7.0422
rs 5.5
1 1
from plugin.core.environment import Environment
2 1
from plugin.core.helpers.variable import merge
3 1
from plugin.core.libraries.cache import CacheManager
4 1
from plugin.core.libraries.constants import CONTENTS_PATH, NATIVE_DIRECTORIES, UNICODE_MAP
5 1
from plugin.core.libraries.helpers import PathHelper, StorageHelper, SystemHelper
6 1
from plugin.core.libraries.tests import LIBRARY_TESTS
7 1
from plugin.core.logger.handlers.error_reporter import RAVEN
8
9 1
import logging
10 1
import os
11 1
import sys
12
13 1
log = logging.getLogger(__name__)
14
15
16 1
class LibrariesManager(object):
17 1
    @classmethod
18 1
    def setup(cls, cache=False):
19
        """Setup native library directories
20
21
        :param cache: Enable native library caching
22
        :type cache: bool
23
        """
24
25
        # Retrieve libraries path
26 1
        libraries_path = cls.get_path(cache)
27
28 1
        log.info('Using native libraries at %r', StorageHelper.to_relative_path(libraries_path))
29
30
        # Retrieve system details
31 1
        system = SystemHelper.name()
32 1
        system_architecture = SystemHelper.architecture()
33
34 1
        if not system_architecture:
35
            return
36
37 1
        log.debug('System: %r, Architecture: %r', system, system_architecture)
38
39 1
        architectures = [system_architecture]
40
41 1
        if system_architecture == 'i686':
42
            # Fallback to i386
43
            architectures.append('i386')
44
45 1
        for architecture in reversed(architectures + ['universal']):
46
            # Common
47 1
            PathHelper.insert(libraries_path, system, architecture)
48
49
            # UCS
50 1
            if sys.maxunicode in UNICODE_MAP:
51 1
                PathHelper.insert(libraries_path, system, architecture, UNICODE_MAP[sys.maxunicode])
52
53
        # Log library paths
54 1
        for path in sys.path:
55 1
            path = os.path.abspath(path)
56
57 1
            if not StorageHelper.is_relative_path(path):
58 1
                continue
59
60 1
            log.info('[PATH] %s', StorageHelper.to_relative_path(path))
61
62 1
    @staticmethod
63
    def test():
64
        """Test native libraries to ensure they can be correctly loaded"""
65 1
        log.info('Testing native library support...')
66
67 1
        metadata = {}
68
69 1
        for test in LIBRARY_TESTS:
70
            # Run tests
71 1
            result = test.run()
0 ignored issues
show
Bug introduced by
The Class LList does not seem to have a member named run.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
Bug introduced by
The Class Cryptography does not seem to have a member named run.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
Bug introduced by
The Class PyOpenSSL does not seem to have a member named run.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
Bug introduced by
The Class Apsw does not seem to have a member named run.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
72
73 1
            if not result.get('success'):
74
                # Write message to logfile
75
                log.error('%s: unavailable - %s', test.name, result.get('message'), exc_info=result.get('exc_info'))
76
77
                if not test.optional:
78
                    return
79
80
                continue
81
82
            # Test successful
83 1
            t_metadata = result.get('metadata') or {}
84 1
            t_versions = t_metadata.get('versions')
85
86 1
            if t_versions:
87 1
                if len(t_versions) > 1:
88 1
                    log.info('%s: available (%s)', test.name, ', '.join([
89
                        '%s: %s' % (key, value)
90
                        for key, value in t_versions.items()
91
                    ]))
92
                else:
93 1
                    key = t_versions.keys()[0]
94
95 1
                    log.info('%s: available (%s)', test.name, t_versions[key])
96
            else:
97 1
                log.info('%s: available', test.name)
98
99
            # Merge result into `metadata`
100 1
            merge(metadata, t_metadata, recursive=True)
101
102
        # Include versions in error reports
103 1
        versions = metadata.get('versions') or {}
104
105 1
        RAVEN.tags.update(dict([
106
            ('%s.version' % key, value)
107
            for key, value in versions.items()
108
        ]))
109
110 1
    @classmethod
111 1
    def get_path(cls, cache=False):
112
        """Retrieve the native libraries base directory (and cache the libraries if enabled)
113
114
        :param cache: Enable native library caching
115
        :type cache: bool
116
        """
117
118 1
        if not cache:
119 1
            return Environment.path.libraries
120
121
        # Cache native libraries
122
        libraries_path = CacheManager.sync()
123
124
        if libraries_path:
125
            # Reset native library directories in `sys.path`
126
            cls.reset()
127
128
            return libraries_path
129
130
        return Environment.path.libraries
131
132 1
    @classmethod
133
    def reset(cls):
134
        """Remove all the native library directives from `sys.path`"""
135
136
        for path in sys.path:
137
            path = os.path.abspath(path)
138
139
            if not path.lower().startswith(CONTENTS_PATH.lower()):
140
                continue
141
142
            # Convert to relative path
143
            path_rel = os.path.relpath(path, CONTENTS_PATH)
144
145
            # Take the first two fragments
146
            path_rel = os.path.sep.join(path_rel.split(os.path.sep)[:2])
147
148
            # Ignore non-native library directories
149
            if path_rel not in NATIVE_DIRECTORIES:
150
                continue
151
152
            # Remove from `sys.path`
153
            PathHelper.remove(path)
154