Commits (5)
diffoscope (182) UNRELEASED; urgency=medium
diffoscope (182) unstable; urgency=medium
* WIP (generated upon release).
-- Chris Lamb <lamby@debian.org> Fri, 20 Aug 2021 10:04:49 +0100
[ Chris Lamb ]
* Also ignore, for example, spurious "fwGCC: (Debian ... )" lines in output
from strings(1).
* Only use "java -jar /path/to/apksigner.jar" if we have a .jar as newer
versions of apksigner use a shell wrapper script which will obviously be
rejected by the JVM. Also mention in the diff if apksigner is missing.
* Pass "-f" to apktool to avoid creating a strangely-named subdirectory and
to simplify code.
* If we specify a suffix for temporary file or directory, ensure it starts
with a "_" to make the generated filenames more human-readable.
* Drop an unused File import.
* Update the minimum version of the Black source code formatter.
[ Santiago Torres Arias ]
* Support parsing the return value of squashfs versions which discriminate
between fatal and non-fatal errors.
-- Chris Lamb <lamby@debian.org> Fri, 27 Aug 2021 09:11:44 +0100
diffoscope (181) unstable; urgency=medium
......
......@@ -17,4 +17,4 @@
# You should have received a copy of the GNU General Public License
# along with diffoscope. If not, see <https://www.gnu.org/licenses/>.
VERSION = "181"
VERSION = "182"
......@@ -28,7 +28,6 @@ from diffoscope.exc import RequiredToolNotFound
from diffoscope.tools import tool_required, find_executable
from diffoscope.tempfiles import get_temporary_directory
from .utils.file import File
from .utils.archive import Archive
from .utils.command import Command
from .utils.compare import compare_files
......@@ -48,22 +47,22 @@ class ApkContainer(Archive):
def open_archive(self):
self._members = []
self._tmpdir = get_temporary_directory(suffix="apk")
self._unpacked = os.path.join(
self._tmpdir.name, os.path.basename(self.source.name)
)
self._andmanifest = None
self._andmanifest_orig = None
logger.debug("Extracting %s to %s", self.source.name, self._unpacked)
logger.debug(
"Extracting %s to %s", self.source.name, self._tmpdir.name
)
subprocess.check_call(
(
"apktool",
"d",
"-f",
"-k",
"-m",
"-o",
self._unpacked,
self._tmpdir.name,
self.source.path,
),
stderr=None,
......@@ -73,7 +72,7 @@ class ApkContainer(Archive):
# Optionally extract a few files that apktool does not
for x in ("classes.dex", "resources.arsc"):
subprocess.call(
("unzip", "-d", self._unpacked, self.source.path, x),
("unzip", "-d", self._tmpdir.name, self.source.path, x),
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
)
......@@ -85,7 +84,7 @@ class ApkContainer(Archive):
(
"unzip",
"-d",
self._unpacked,
self._tmpdir.name,
self.source.path,
f"classes{x}.dex",
),
......@@ -95,28 +94,28 @@ class ApkContainer(Archive):
except subprocess.CalledProcessError:
break
for root, _, files in os.walk(self._unpacked):
for root, _, files in os.walk(self._tmpdir.name):
current_dir = []
for filename in files:
abspath = os.path.join(root, filename)
# apktool.yml is a file created by apktool and containing
# metadata information. Rename it to clarify and always make it
# appear at the beginning of the directory listing for
# apktool.yml is a file created by apktool which contains
# metadata information. We eename it for clarity and always
# make it appear at the beginning of the directory listing for
# reproducibility.
if filename == "apktool.yml":
abspath = filter_apk_metadata(
abspath, os.path.basename(self.source.path)
)
relpath = abspath[len(self._unpacked) + 1 :]
relpath = abspath[len(self._tmpdir.name) + 1 :]
current_dir.insert(0, relpath)
continue
relpath = abspath[len(self._unpacked) + 1 :]
relpath = abspath[len(self._tmpdir.name) + 1 :]
if filename == "AndroidManifest.xml":
containing_dir = root[len(self._unpacked) + 1 :]
containing_dir = root[len(self._tmpdir.name) + 1 :]
if containing_dir == "original":
self._andmanifest_orig = relpath
if containing_dir == "":
......@@ -146,7 +145,7 @@ class ApkContainer(Archive):
return self._members
def extract(self, member_name, dest_dir):
return os.path.join(self._unpacked, member_name)
return os.path.join(self._tmpdir.name, member_name)
def compare_manifests(self, other):
my_android_manifest = self.get_android_manifest()
......@@ -193,15 +192,18 @@ class Apksigner(Command):
@tool_required("apksigner")
def cmdline(self):
# In Debian, the `apksigner` binary is a symbolic link to the .jar file
# itself, requiring binfmt_misc support to execute directly. We
# therefore resolve its location and pass that to `java -jar`.
apksigner_jar = find_executable("apksigner")
return [
"java",
"-jar",
apksigner_jar,
# Older versions of the `apksigner` binary under /usr/bin (or similar)
# are a symbolic link to the apksigner .jar file. If we detect a .jar
# we resolve its 'real' location and pass that to `java -jar`, so we
# don't need kernel binfmt_misc to execute. We can't do this in all
# situations as later versions of apksigner use a wrapper script and
# will therefore fail to run at all if we use `java -jar`.
apksigner = os.path.realpath(find_executable("apksigner"))
prefix = ["java", "-jar"] if apksigner.endswith(".jar") else []
return prefix + [
apksigner,
"verify",
"--verbose",
"--print-certs",
......