1212from collections import defaultdict
1313# Contextlib
1414from contextlib import contextmanager
15+ # Hashlib
16+ import hashlib
1517# Inspect
1618from inspect import getmodule
1719from inspect import currentframe
6365 'PLATFORM' ,
6466 'SOURCE_ENGINE' ,
6567 'SOURCE_ENGINE_BRANCH' ,
68+ 'check_info_output' ,
6669 'console_message' ,
70+ 'create_checksum' ,
6771 'echo_console' ,
6872 'get_interface' ,
6973 'get_public_ip' ,
@@ -281,3 +285,47 @@ def intercepter(severity, msg):
281285 yield msg_buffer
282286 finally :
283287 OnServerOutput .manager .unregister_listener (intercepter )
288+
289+ def create_checksum (data , ignore_wchars = True ):
290+ """Create an MD5 checksum for the given string.
291+
292+ :param str data:
293+ The string for which a checksum should be created.
294+ :param bool ignore_wchars:
295+ If ``True`` whitespace characters are ignored.
296+ :rtype: str
297+ """
298+ if ignore_wchars :
299+ data = '' .join (data .split ())
300+
301+ return hashlib .new ('md5' , bytes (data , encoding = 'utf-8' )).hexdigest ()
302+
303+ def check_info_output (output ):
304+ """Return whether the output of ``sp info`` has been modified.
305+
306+ :param str output:
307+ The output of ``sp info``.
308+ :raise ValueError:
309+ Raised if the checksum was not found in the output.
310+ :return:
311+ ``True`` if the output has been modified.
312+ :rtype: bool
313+ """
314+ checksum = None
315+ lines = output .strip ().split ('\n ' )
316+
317+ # Search the checksum entry
318+ while lines :
319+ line = lines .pop (0 )
320+ if line .startswith ('Checksum' ):
321+ checksum = line .split (':' , 1 )[1 ].strip ()
322+ break
323+
324+ if checksum is None :
325+ raise ValueError ('Checksum not found.' )
326+
327+ # Ignore last line if it's the separator
328+ if lines [- 1 ].startswith ('-' ):
329+ lines .pop ()
330+
331+ return create_checksum ('' .join (lines )) != checksum
0 commit comments