4545import os
4646
4747from commoncode import command
48- from plugincode .location_provider import get_location
49-
50- from os import fsencode
51-
52- TRACE = False
48+ from commoncode .system import on_windows
5349
5450"""
5551magic2 is minimal and specialized wrapper around a vendored libmagic file
5652identification library. This is NOT thread-safe. It is based on python-magic
5753by Adam Hup and adapted to the specific needs of ScanCode.
5854"""
55+
56+ # Tracing flag
57+ TRACE = True
58+
59+
60+ def logger_debug (* args ):
61+ pass
62+
63+
64+ if TRACE :
65+ import logging
66+ import sys
67+
68+ logger = logging .getLogger (__name__ )
69+ logging .basicConfig (stream = sys .stdout )
70+ logger .setLevel (logging .DEBUG )
71+
72+ def logger_debug (* args ):
73+ return logger .debug (' ' .join (isinstance (a , str ) and a or repr (a ) for a in args ))
74+
5975#
6076# Cached detectors
6177#
7490DETECT_ENC = MAGIC_NONE | MAGIC_MIME | MAGIC_MIME_ENCODING
7591
7692# keys for plugin-provided locations
77- TYPECODE_LIBMAGIC_LIBDIR = 'typecode.libmagic.libdir'
7893TYPECODE_LIBMAGIC_DLL = 'typecode.libmagic.dll'
79- TYPECODE_LIBMAGIC_DATABASE = 'typecode.libmagic.db'
94+ TYPECODE_LIBMAGIC_DB = 'typecode.libmagic.db'
95+
96+ TYPECODE_LIBMAGIC_PATH_ENVVAR = 'TYPECODE_LIBMAGIC_PATH'
97+ TYPECODE_LIBMAGIC_DB_PATH_ENVVAR = 'TYPECODE_LIBMAGIC_DB_PATH'
8098
8199
82100def load_lib ():
83101 """
84- Return the loaded libmagic shared library object from plugin-provided path.
102+ Return the libmagic shared library object loaded from either:
103+ - an environment variable ``TYPECODE_LIBMAGIC_PATH``
104+ - a plugin-provided path,
105+ - the system PATH.
106+ Raise an Exception if no libmagic can be found.
85107 """
86- dll = get_location (TYPECODE_LIBMAGIC_DLL )
87- libdir = get_location (TYPECODE_LIBMAGIC_LIBDIR )
88- if not (dll and libdir ) or not os .path .isfile (dll ) or not os .path .isdir (libdir ):
108+ from plugincode .location_provider import get_location
109+
110+ # try the environment first
111+ dll_loc = os .environ .get (TYPECODE_LIBMAGIC_PATH_ENVVAR )
112+
113+ if TRACE and dll_loc :
114+ logger_debug ('load_lib:' , 'got environ magic location:' , dll_loc )
115+
116+ # try a plugin-provided path second
117+ if not dll_loc :
118+ dll_loc = get_location (TYPECODE_LIBMAGIC_DLL )
119+
120+ if TRACE and dll_loc :
121+ logger_debug ('load_lib:' , 'got plugin magic location:' , dll_loc )
122+
123+ # try the PATH
124+ if not dll_loc :
125+ dll = 'libmagic.dll' if on_windows else 'libmagic.so'
126+ dll_loc = command .find_in_path (dll )
127+
128+ if TRACE and dll_loc :
129+ logger_debug ('load_lib:' , 'got path magic location:' , dll_loc )
130+
131+ if not dll_loc or not os .path .isfile (dll_loc ):
132+ raise Exception (
133+ 'CRITICAL: libmagic DLL and its magic database are not installed. '
134+ 'Unable to continue: you need to install a valid typecode-libmagic '
135+ 'plugin with a valid and proper libmagic and magic DB available. '
136+ f'OR set the { TYPECODE_LIBMAGIC_PATH_ENVVAR } environment variable.'
137+ )
138+ return command .load_shared_library (dll_loc )
139+
140+
141+ def get_magicdb_location (_cache = []):
142+ """
143+ Return the location of the magicdb loaded from either:
144+ - an environment variable ``TYPECODE_LIBMAGIC_DB_PATH``,
145+ - a plugin-provided path,
146+ - the system PATH.
147+ Raise an Exception if no magicdb command can be found.
148+ """
149+ if _cache :
150+ return _cache [0 ]
151+
152+ from plugincode .location_provider import get_location
153+
154+ # try the environment first
155+ magicdb_loc = os .environ .get (TYPECODE_LIBMAGIC_DB_PATH_ENVVAR )
156+
157+ if TRACE and magicdb_loc :
158+ logger_debug ('get_magicdb_location:' , 'got environ magicdb location:' , magicdb_loc )
159+
160+ # try a plugin-provided path second
161+ if not magicdb_loc :
162+ magicdb_loc = get_location (TYPECODE_LIBMAGIC_DB )
163+
164+ if TRACE and magicdb_loc :
165+ logger_debug ('get_magicdb_location:' , 'got plugin magicdb location:' , magicdb_loc )
166+
167+ # try the PATH
168+ if not magicdb_loc :
169+ db = 'magic.mgc'
170+ magicdb_loc = command .find_in_path (db )
171+
172+ if TRACE and magicdb_loc :
173+ logger_debug ('get_magicdb_location:' , 'got path magicdb location:' , magicdb_loc )
174+
175+ if not magicdb_loc or not os .path .isfile (magicdb_loc ):
89176 raise Exception (
90- 'CRITICAL: libmagic DLL and is magic database are not installed. '
177+ 'CRITICAL: Libmagic magic database is not installed. '
91178 'Unable to continue: you need to install a valid typecode-libmagic '
92- 'plugin with a valid and proper libmagic and magic DB available.'
179+ 'plugin with a valid magic database available. '
180+ 'OR set the TYPECODE_LIBMAGIC_DB_PATH environment variable.'
93181 )
94- return command .load_shared_library (dll , libdir )
182+ _cache .append (magicdb_loc )
183+ return magicdb_loc
95184
96185
97186if TRACE :
@@ -164,11 +253,11 @@ def __init__(self, flags, magic_db_location=None):
164253 self .flags = flags
165254 self .cookie = _magic_open (self .flags )
166255 if not magic_db_location :
167- magic_db_location = get_location ( TYPECODE_LIBMAGIC_DATABASE )
256+ magic_db_location = get_magicdb_location ( )
168257
169- # Note: this location must always be bytes on Python2 and 3, all OSes
258+ # Note: this location must always be FS-encoded bytes on all OSes
170259 if isinstance (magic_db_location , str ):
171- magic_db_location = fsencode (magic_db_location )
260+ magic_db_location = os . fsencode (magic_db_location )
172261
173262 _magic_load (self .cookie , magic_db_location )
174263
@@ -190,7 +279,7 @@ def get(self, location):
190279 # location string may therefore be mangled and the file not accessible
191280 # anymore by libmagic in some cases.
192281 try :
193- uloc = fsencode (location )
282+ uloc = os . fsencode (location )
194283 return _magic_file (self .cookie , uloc )
195284 except :
196285 # if all fails, read the start of the file instead
0 commit comments