def _get_test_manifest(self):
        m = InstallManifest()
        m.add_symlink(self.tmppath("s_source"), "s_dest")
        m.add_copy(self.tmppath("c_source"), "c_dest")
        m.add_required_exists("e_dest")

        return m
Beispiel #2
0
    def test_adds(self):
        m = InstallManifest()
        m.add_symlink('s_source', 's_dest')
        m.add_copy('c_source', 'c_dest')
        m.add_required_exists('e_dest')
        m.add_optional_exists('o_dest')
        m.add_pattern_symlink('ps_base', 'ps/*', 'ps_dest')
        m.add_pattern_copy('pc_base', 'pc/**', 'pc_dest')

        self.assertEqual(len(m), 6)
        self.assertIn('s_dest', m)
        self.assertIn('c_dest', m)
        self.assertIn('e_dest', m)
        self.assertIn('o_dest', m)

        with self.assertRaises(ValueError):
            m.add_symlink('s_other', 's_dest')

        with self.assertRaises(ValueError):
            m.add_copy('c_other', 'c_dest')

        with self.assertRaises(ValueError):
            m.add_required_exists('e_dest')

        with self.assertRaises(ValueError):
            m.add_optional_exists('o_dest')

        with self.assertRaises(ValueError):
            m.add_pattern_symlink('ps_base', 'ps/*', 'ps_dest')

        with self.assertRaises(ValueError):
            m.add_pattern_copy('pc_base', 'pc/**', 'pc_dest')
Beispiel #3
0
    def test_adds(self):
        m = InstallManifest()
        m.add_symlink('s_source', 's_dest')
        m.add_copy('c_source', 'c_dest')
        m.add_required_exists('e_dest')
        m.add_optional_exists('o_dest')
        m.add_pattern_symlink('ps_base', 'ps/*', 'ps_dest')
        m.add_pattern_copy('pc_base', 'pc/**', 'pc_dest')

        self.assertEqual(len(m), 6)
        self.assertIn('s_dest', m)
        self.assertIn('c_dest', m)
        self.assertIn('e_dest', m)
        self.assertIn('o_dest', m)

        with self.assertRaises(ValueError):
            m.add_symlink('s_other', 's_dest')

        with self.assertRaises(ValueError):
            m.add_copy('c_other', 'c_dest')

        with self.assertRaises(ValueError):
            m.add_required_exists('e_dest')

        with self.assertRaises(ValueError):
            m.add_optional_exists('o_dest')

        with self.assertRaises(ValueError):
            m.add_pattern_symlink('ps_base', 'ps/*', 'ps_dest')

        with self.assertRaises(ValueError):
            m.add_pattern_copy('pc_base', 'pc/**', 'pc_dest')
Beispiel #4
0
    def _get_test_manifest(self):
        m = InstallManifest()
        m.add_symlink(self.tmppath('s_source'), 's_dest')
        m.add_copy(self.tmppath('c_source'), 'c_dest')
        m.add_required_exists('e_dest')
        m.add_optional_exists('o_dest')

        return m
Beispiel #5
0
    def _get_test_manifest(self):
        m = InstallManifest()
        m.add_symlink(self.tmppath('s_source'), 's_dest')
        m.add_copy(self.tmppath('c_source'), 'c_dest')
        m.add_preprocess(self.tmppath('p_source'), 'p_dest', self.tmppath('p_source.pp'), '#', {'FOO':'BAR', 'BAZ':'QUX'})
        m.add_required_exists('e_dest')
        m.add_optional_exists('o_dest')
        m.add_pattern_symlink('ps_base', '*', 'ps_dest')
        m.add_pattern_copy('pc_base', '**', 'pc_dest')

        return m
Beispiel #6
0
    def _get_test_manifest(self):
        m = InstallManifest()
        m.add_link(self.tmppath('s_source'), 's_dest')
        m.add_copy(self.tmppath('c_source'), 'c_dest')
        m.add_preprocess(self.tmppath('p_source'), 'p_dest', self.tmppath('p_source.pp'), '#', {'FOO':'BAR', 'BAZ':'QUX'})
        m.add_required_exists('e_dest')
        m.add_optional_exists('o_dest')
        m.add_pattern_link('ps_base', '*', 'ps_dest')
        m.add_pattern_copy('pc_base', '**', 'pc_dest')
        m.add_content('the content\non\nmultiple lines', 'content')

        return m
Beispiel #7
0
    def _get_test_manifest(self):
        m = InstallManifest()
        m.add_symlink(self.tmppath("s_source"), "s_dest")
        m.add_copy(self.tmppath("c_source"), "c_dest")
        m.add_preprocess(
            self.tmppath("p_source"), "p_dest", self.tmppath("p_source.pp"), "#", {"FOO": "BAR", "BAZ": "QUX"}
        )
        m.add_required_exists("e_dest")
        m.add_optional_exists("o_dest")
        m.add_pattern_symlink("ps_base", "*", "ps_dest")
        m.add_pattern_copy("pc_base", "**", "pc_dest")

        return m
    def test_adds(self):
        m = InstallManifest()
        m.add_symlink("s_source", "s_dest")
        m.add_copy("c_source", "c_dest")
        m.add_required_exists("e_dest")

        self.assertEqual(len(m), 3)
        self.assertIn("s_dest", m)
        self.assertIn("c_dest", m)
        self.assertIn("e_dest", m)

        with self.assertRaises(ValueError):
            m.add_symlink("s_other", "s_dest")

        with self.assertRaises(ValueError):
            m.add_copy("c_other", "c_dest")

        with self.assertRaises(ValueError):
            m.add_required_exists("e_dest")
Beispiel #9
0
    def test_adds(self):
        m = InstallManifest()
        m.add_link("s_source", "s_dest")
        m.add_copy("c_source", "c_dest")
        m.add_required_exists("e_dest")
        m.add_optional_exists("o_dest")
        m.add_pattern_link("ps_base", "ps/*", "ps_dest")
        m.add_pattern_copy("pc_base", "pc/**", "pc_dest")
        m.add_preprocess("p_source", "p_dest", "p_source.pp")
        m.add_content("content", "content")

        self.assertEqual(len(m), 8)
        self.assertIn("s_dest", m)
        self.assertIn("c_dest", m)
        self.assertIn("p_dest", m)
        self.assertIn("e_dest", m)
        self.assertIn("o_dest", m)
        self.assertIn("content", m)

        with self.assertRaises(ValueError):
            m.add_link("s_other", "s_dest")

        with self.assertRaises(ValueError):
            m.add_copy("c_other", "c_dest")

        with self.assertRaises(ValueError):
            m.add_preprocess("p_other", "p_dest", "p_other.pp")

        with self.assertRaises(ValueError):
            m.add_required_exists("e_dest")

        with self.assertRaises(ValueError):
            m.add_optional_exists("o_dest")

        with self.assertRaises(ValueError):
            m.add_pattern_link("ps_base", "ps/*", "ps_dest")

        with self.assertRaises(ValueError):
            m.add_pattern_copy("pc_base", "pc/**", "pc_dest")

        with self.assertRaises(ValueError):
            m.add_content("content", "content")
Beispiel #10
0
    def _get_test_manifest(self):
        m = InstallManifest()
        m.add_link(self.tmppath("s_source"), "s_dest")
        m.add_copy(self.tmppath("c_source"), "c_dest")
        m.add_preprocess(
            self.tmppath("p_source"),
            "p_dest",
            self.tmppath("p_source.pp"),
            "#",
            {
                "FOO": "BAR",
                "BAZ": "QUX"
            },
        )
        m.add_required_exists("e_dest")
        m.add_optional_exists("o_dest")
        m.add_pattern_link("ps_base", "*", "ps_dest")
        m.add_pattern_copy("pc_base", "**", "pc_dest")
        m.add_content("the content\non\nmultiple lines", "content")

        return m
Beispiel #11
0
    def test_adds(self):
        m = InstallManifest()
        m.add_symlink("s_source", "s_dest")
        m.add_copy("c_source", "c_dest")
        m.add_required_exists("e_dest")
        m.add_optional_exists("o_dest")
        m.add_pattern_symlink("ps_base", "ps/*", "ps_dest")
        m.add_pattern_copy("pc_base", "pc/**", "pc_dest")
        m.add_preprocess("p_source", "p_dest", "p_source.pp")

        self.assertEqual(len(m), 7)
        self.assertIn("s_dest", m)
        self.assertIn("c_dest", m)
        self.assertIn("p_dest", m)
        self.assertIn("e_dest", m)
        self.assertIn("o_dest", m)

        with self.assertRaises(ValueError):
            m.add_symlink("s_other", "s_dest")

        with self.assertRaises(ValueError):
            m.add_copy("c_other", "c_dest")

        with self.assertRaises(ValueError):
            m.add_preprocess("p_other", "p_dest", "p_other.pp")

        with self.assertRaises(ValueError):
            m.add_required_exists("e_dest")

        with self.assertRaises(ValueError):
            m.add_optional_exists("o_dest")

        with self.assertRaises(ValueError):
            m.add_pattern_symlink("ps_base", "ps/*", "ps_dest")

        with self.assertRaises(ValueError):
            m.add_pattern_copy("pc_base", "pc/**", "pc_dest")
Beispiel #12
0
def main(output_dirname, verbose, *input_dirs):
    # Map directories to source paths, like
    # `{'values-large-v11': ['/path/to/values-large-v11/strings.xml',
    #                        '/path/to/values-large-v11/colors.xml', ...], ...}`.
    values = defaultdict(list)
    # Map unversioned resource names to maps from versions to source paths, like:
    # `{'drawable-large/icon.png':
    #     {None: '/path/to/drawable-large/icon.png',
    #      11: '/path/to/drawable-large-v11/icon.png', ...}, ...}`.
    resources = defaultdict(dict)

    manifest = InstallManifest()

    for p in uniqify(input_dirs):
        finder = FileFinder(p, find_executables=False)

        values_pattern = 'values*/*.xml'
        for path, _ in finder.find('*/*'):
            if path in MANIFEST_EXCLUSIONS:
                continue

            source_path = mozpath.join(finder.base, path)

            if mozpath.match(path, values_pattern):
                dir, _name = path.split('/')
                dir = with_version(dir)
                values[dir].append(source_path)
                continue

            (resource, version) = classify(path)

            # Earlier paths are taken in preference to later paths.
            # This agrees with aapt.
            if version not in resources:
                resources[resource][version] = source_path

    # Step 1: merge all XML values into one single, sorted
    # per-configuration values.xml file.  This apes what the Android
    # Gradle resource merging algorithm does.
    merged_values = defaultdict(list)

    for dir, files in values.items():
        for file in files:
            values = ET.ElementTree(file=file).getroot()
            merged_values[dir].extend(values)

        values = ET.Element('resources')
        # Sort by <type> tag, and then by name.  Note that <item
        # type="type"> is equivalent to <type>.
        key = lambda x: (resource_type.get(x.get('type', x.tag)), x.get('name')
                         )
        values[:] = sorted(merged_values[dir], key=key)

        for value in values:
            if value.get('name') == 'TextAppearance.Design.Snackbar.Message':
                if value.get('{http://schemas.android.com/tools}override',
                             False):
                    values.remove(value)
                    break

        merged_values[dir] = values

    for dir, values in merged_values.items():
        o = mozpath.join(output_dirname, dir, '{}.xml'.format(dir))
        ensureParentDir(o)
        ET.ElementTree(values).write(o)

        manifest.add_required_exists(mozpath.join(dir, '{}.xml'.format(dir)))

    # Step 2a: add version numbers for unversioned features
    # corresponding to when the feature was introduced.  Resource
    # qualifiers will never be recognized by Android versions before
    # they were introduced.  For example, density qualifiers are
    # supported only in Android v4 and above.  Therefore
    # "drawable-hdpi" is implicitly "drawable-hdpi-v4".  We version
    # such unversioned resources here.
    for (resource, versions) in resources.items():
        if None in versions:
            dir, name = resource.split('/')
            new_dir = with_version(dir)
            (new_resource,
             new_version) = classify('{}/{}'.format(new_dir, name))
            if new_resource != resource:
                raise ValueError('this is bad')

            # `new_version` might be None: for example, `dir` might be "drawable".
            source_path = versions.pop(None)
            versions[new_version] = source_path

            if verbose:
                if new_version:
                    print("Versioning unversioned resource {} as {}-v{}/{}".
                          format(source_path, dir, new_version, name))

    # TODO: make this a command line argument that takes MOZ_ANDROID_MIN_SDK_VERSION.
    min_sdk = 15
    retained = defaultdict(dict)

    # Step 2b: drop resource directories that will never be used by
    # Android on device.  This depends on the minimum supported
    # Android SDK version.  Suppose the minimum SDK is 15 and we have
    # drawable-v4/icon.png and drawable-v11/icon.png.  The v4 version
    # will never be chosen, since v15 is always greater than v11.
    for (resource, versions) in resources.items():

        def key(v):
            return 0 if v is None else v

        # Versions in descending order.
        version_list = sorted(versions.keys(), key=key, reverse=True)
        for version in version_list:
            retained[resource][version] = versions[version]
            if version is not None and version <= min_sdk:
                break

    if set(retained.keys()) != set(resources.keys()):
        raise ValueError('Something terrible has happened; retained '
                         'resource names do not match input resources '
                         'names')

    if verbose:
        for resource in resources:
            if resources[resource] != retained[resource]:
                for version in sorted(resources[resource].keys(),
                                      reverse=True):
                    if version in retained[resource]:
                        print("Keeping reachable resource {}".format(
                            resources[resource][version]))
                    else:
                        print("Dropping unreachable resource {}".format(
                            resources[resource][version]))

    # Populate manifest.
    for (resource, versions) in retained.items():
        for version in sorted(versions.keys(), reverse=True):
            path = resource
            if version:
                dir, name = resource.split('/')
                path = '{}-v{}/{}'.format(dir, version, name)
            manifest.add_copy(versions[version], path)

    copier = FileCopier()
    manifest.populate_registry(copier)
    print('mr', os.getcwd())
    result = copier.copy(output_dirname,
                         remove_unaccounted=True,
                         remove_all_directory_symlinks=False,
                         remove_empty_directories=True)

    if verbose:
        print('Updated:', result.updated_files_count)
        print('Removed:',
              result.removed_files_count + result.removed_directories_count)
        print('Existed:', result.existing_files_count)

    return 0