class TestFileFinder(MatchTestTemplate, TestWithTmpDir):
    def add(self, path):
        ensure_parent_dir(self.tmppath(path))
        open(self.tmppath(path), 'wb').write(path)

    def do_check(self, pattern, result):
        if result:
            self.assertTrue(self.finder.contains(pattern))
        else:
            self.assertFalse(self.finder.contains(pattern))
        self.assertEqual(sorted(list(f for f, c in self.finder.find(pattern))),
                         sorted(result))

    def test_file_finder(self):
        self.finder = FileFinder(self.tmpdir)
        self.do_match_test()
        self.add('foo/.foo')
        self.add('foo/.bar/foo')
        self.assertTrue(self.finder.contains('foo/.foo'))
        self.assertTrue(self.finder.contains('foo/.bar'))
        self.assertTrue('foo/.foo' in [f for f, c in
                                       self.finder.find('foo/.foo')])
        self.assertTrue('foo/.bar/foo' in [f for f, c in
                                           self.finder.find('foo/.bar')])
        self.assertEqual(sorted([f for f, c in self.finder.find('foo/.*')]),
                         ['foo/.bar/foo', 'foo/.foo'])
        for pattern in ['foo', '**', '**/*', '**/foo', 'foo/*']:
            self.assertFalse('foo/.foo' in [f for f, c in
                                            self.finder.find(pattern)])
            self.assertFalse('foo/.bar/foo' in [f for f, c in
                                                self.finder.find(pattern)])
            self.assertEqual(sorted([f for f, c in self.finder.find(pattern)]),
                             sorted([f for f, c in self.finder
                                     if mozpack.path.match(f, pattern)]))
Example #2
0
def unpack_msix(input_msix, output, log=None, verbose=False):
    r"""Unpack the given MSIX to the given output directory.

    MSIX packages are ZIP files, but they are Zip64/version 4.5 ZIP files, so
    `mozjar.py` doesn't yet handle.  Unpack using `unzip{.exe}` for simplicity.

    In addition, file names inside the MSIX package are URL quoted.  URL unquote
    here.
    """

    log(
        logging.INFO,
        "msix",
        {
            "input_msix": input_msix,
            "output": output,
        },
        "Unpacking input MSIX '{input_msix}' to directory '{output}'",
    )

    unzip = find_sdk_tool("unzip.exe", log=log)
    if not unzip:
        raise ValueError("unzip is required; set UNZIP or PATH")

    subprocess.check_call(
        [unzip, input_msix, "-d", output] + (["-q"] if not verbose else []),
        universal_newlines=True,
    )

    # Sanity check: is this an MSIX?
    temp_finder = FileFinder(output)
    if not temp_finder.contains("AppxManifest.xml"):
        raise ValueError("MSIX file does not contain 'AppxManifest.xml'?")

    # Files in the MSIX are URL encoded/quoted; unquote here.
    for dirpath, dirs, files in os.walk(output):
        # This is a one way to update (in place, for os.walk) the variable `dirs` while iterating
        # over it and `files`.
        for i, (p, var) in itertools.chain(
            enumerate((f, files) for f in files), enumerate((g, dirs) for g in dirs)
        ):
            q = urllib.parse.unquote(p)
            if p != q:
                log(
                    logging.DEBUG,
                    "msix",
                    {
                        "dirpath": dirpath,
                        "p": p,
                        "q": q,
                    },
                    "URL unquoting '{p}' -> '{q}' in {dirpath}",
                )

                var[i] = q
                os.rename(os.path.join(dirpath, p), os.path.join(dirpath, q))

    # The "package root" of our MSIX packages is like "Mozilla Firefox Beta Package Root", i.e., it
    # varies by channel.  This is an easy way to determine it.
    for p, _ in temp_finder.find("**/application.ini"):
        relpath = os.path.split(p)[0]

    # The application executable, like `firefox.exe`, is in this directory.
    return mozpath.normpath(mozpath.join(output, relpath))