Coverage for diffoscope/comparators/ppu.py: 72%

57 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-04-07 13:38 +0000

1# 

2# diffoscope: in-depth comparison of files, archives, and directories 

3# 

4# Copyright © 2015 Daniel Kahn Gillmor <dkg@fifthhorseman.net> 

5# Copyright © 2015 Jérémy Bobbio <lunar@debian.org> 

6# Copyright © 2015 Paul Gevers <elbrus@debian.org> 

7# Copyright © 2016-2020 Chris Lamb <lamby@debian.org> 

8# 

9# diffoscope is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# diffoscope is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with diffoscope. If not, see <https://www.gnu.org/licenses/>. 

21 

22import os 

23import re 

24import logging 

25import subprocess 

26 

27from diffoscope.tools import tool_required 

28from diffoscope.profiling import profile 

29from diffoscope.difference import Difference 

30 

31from .utils.file import File 

32from .utils.command import Command, our_check_output 

33 

34logger = logging.getLogger(__name__) 

35 

36 

37class Ppudump(Command): 

38 @tool_required("ppudump") 

39 def cmdline(self): 

40 return ["ppudump", self.path] 

41 

42 def env(self): 

43 # ppudump will return times using the local timezone which is not ideal 

44 # to investigate files. TZ environment variable can be used to enforce UTC. 

45 # Currently there is no fpc release yet that includes the TC environment 

46 # variable, but it looks for timezone definitions in the directory 

47 # specified by TZDIR. So let's set it to a non-existent directory 

48 # so we get UTC output even when the system timezone is set otherwise. 

49 env = dict(os.environ) 

50 env["TZ"] = ":UTC" 

51 env["TZDIR"] = "/nonexistent" 

52 return env 

53 

54 def filter(self, line): 

55 if re.match( 

56 r"^Analyzing %s \(v[0-9]+\)$" % re.escape(self.path), 

57 line.decode("utf-8", errors="ignore"), 

58 ): 

59 return b"" 

60 return line 

61 

62 

63class PpuFile(File): 

64 DESCRIPTION = "FreePascal files (.ppu)" 

65 FILE_EXTENSION_SUFFIX = {".ppu"} 

66 

67 @classmethod 

68 def recognizes(cls, file): 

69 if not super().recognizes(file): 

70 return False 

71 

72 if not file.file_header.startswith(b"PPU"): 

73 return False 

74 

75 ppu_version = file.file_header[3:6].decode("ascii", errors="ignore") 

76 

77 if not hasattr(PpuFile, "ppu_version"): 

78 try: 

79 with profile("command", "ppudump"): 

80 our_check_output( 

81 ["ppudump", "-vh", file.path], 

82 stderr=subprocess.STDOUT, 

83 ) 

84 PpuFile.ppu_version = ppu_version 

85 except subprocess.CalledProcessError as e: 

86 error = e.output.decode("utf-8", errors="ignore") 

87 m = re.search("Expecting PPU version ([0-9]+)", error) 

88 try: 

89 PpuFile.ppu_version = m.group(1) 

90 except AttributeError: 

91 if m is None: 

92 PpuFile.ppu_version = None 

93 logger.debug("Unable to read PPU version") 

94 else: 

95 raise 

96 except OSError: 

97 PpuFile.ppu_version = None 

98 logger.debug("Unable to read PPU version") 

99 

100 if PpuFile.ppu_version != ppu_version: 

101 logger.debug( 

102 "ppudump version (%s) does not match header of %s (%s)", 

103 PpuFile.ppu_version, 

104 file.name, 

105 ppu_version, 

106 ) 

107 return False 

108 

109 return True 

110 

111 def compare_details(self, other, source=None): 

112 return [Difference.from_operation(Ppudump, self.path, other.path)]