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
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')
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')
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
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 _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
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")
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")
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
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")
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