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
« 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/>.
22import os
23import re
24import logging
25import subprocess
27from diffoscope.tools import tool_required
28from diffoscope.profiling import profile
29from diffoscope.difference import Difference
31from .utils.file import File
32from .utils.command import Command, our_check_output
34logger = logging.getLogger(__name__)
37class Ppudump(Command):
38 @tool_required("ppudump")
39 def cmdline(self):
40 return ["ppudump", self.path]
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
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
63class PpuFile(File):
64 DESCRIPTION = "FreePascal files (.ppu)"
65 FILE_EXTENSION_SUFFIX = {".ppu"}
67 @classmethod
68 def recognizes(cls, file):
69 if not super().recognizes(file):
70 return False
72 if not file.file_header.startswith(b"PPU"):
73 return False
75 ppu_version = file.file_header[3:6].decode("ascii", errors="ignore")
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")
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
109 return True
111 def compare_details(self, other, source=None):
112 return [Difference.from_operation(Ppudump, self.path, other.path)]