Example #1
0
    def locales(self):
        """
        Yield an iterable of Locales whose strings are stored within
        this repo.
        """
        from pontoon.sync.utils import locale_directory_path

        locales = []  # Use list since we're caching the result.
        for locale in self.project.locales.all():
            try:
                locale_directory_path(self.checkout_path, locale.code)
                locales.append(locale)
            except IOError:
                pass  # Directory missing, not in this repo.

        return locales
Example #2
0
    def test_obsolete_vcs_resources_paths(self):
        """Tests if we remove obsolete resources"""
        obsolete_vcs_resources = [
            'obsolete.properties',
            'second_obsolete.properties',
        ]
        obsolete_paths = [
            os.path.join(
                locale_directory_path(self.vcs_project.checkout_path,
                                      self.translated_locale.code), path)
            for path in obsolete_vcs_resources
        ]

        # We test if we remove only resources available on disk
        self.changeset.changes['obsolete_vcs_resources'] = obsolete_paths + [
            'second_obsolete.properties'
        ]

        with patch('os.path.exists', side_effect=lambda p: p in obsolete_paths[:1]) as exists_mock,\
             patch('os.remove') as remove_mock:

            self.changeset.execute_obsolete_vcs_resources()
            exists_mock.assert_has_calls(
                [call(obsolete_paths[0]),
                 call(obsolete_paths[1])])
            remove_mock.assert_called_once_with(obsolete_paths[0])
        assert_equal(self.changeset.locales_to_commit,
                     {self.translated_locale})
Example #3
0
    def locales(self):
        """
        Yield an iterable of Locales whose strings are stored within
        this repo.
        """
        from pontoon.sync.utils import locale_directory_path

        locales = []  # Use list since we're caching the result.
        for locale in self.project.locales.all():
            try:
                locale_directory_path(self.checkout_path, locale.code)
                locales.append(locale)
            except IOError:
                pass  # Directory missing, not in this repo.

        return locales
Example #4
0
    def locale_directory_paths(self):
        """
        A map of locale codes and their absolute directory paths.
        Create locale directory, if not in repository yet.
        """
        locale_directory_paths = {}
        parent_directories = set()

        for locale in self.locales:
            try:
                if self.configuration:
                    locale_directory_paths[locale.code] = self.configuration.l10n_base
                else:
                    locale_directory_paths[locale.code] = locale_directory_path(
                        self.checkout_path, locale.code, parent_directories,
                    )
                parent_directory = get_parent_directory(
                    locale_directory_paths[locale.code]
                )

            except IOError:
                if not self.db_project.has_multi_locale_repositories:
                    source_directory = self.source_directory_path
                    parent_directory = get_parent_directory(source_directory)

                    locale_code = locale.code
                    if uses_undercore_as_separator(parent_directory):
                        locale_code = locale_code.replace("-", "_")

                    locale_directory = os.path.join(parent_directory, locale_code)

                    # For asymmetric formats, create empty folder
                    if is_asymmetric_resource(next(self.relative_resource_paths())):
                        os.makedirs(locale_directory)

                    # For other formats, copy resources from source directory
                    else:
                        shutil.copytree(source_directory, locale_directory)

                        for root, dirnames, filenames in scandir.walk(locale_directory):
                            for filename in filenames:
                                path = os.path.join(root, filename)
                                if is_resource(filename):
                                    os.rename(path, source_to_locale_path(path))
                                else:
                                    os.remove(path)

                    locale_directory_paths[locale.code] = locale_directory

                else:
                    raise MissingLocaleDirectoryError(
                        "Directory for locale `{0}` not found".format(locale.code)
                    )

            parent_directories.add(parent_directory)

        return locale_directory_paths
Example #5
0
    def locale_directory_paths(self):
        """
        A map of locale codes and their absolute directory paths.
        Create locale directory, if not in repository yet.
        """
        locale_directory_paths = {}
        parent_directories = set()

        for locale in self.locales:
            try:
                if self.configuration:
                    locale_directory_paths[locale.code] = self.configuration.l10n_base
                else:
                    locale_directory_paths[locale.code] = locale_directory_path(
                        self.checkout_path,
                        locale.code,
                        parent_directories,
                    )
                parent_directory = get_parent_directory(locale_directory_paths[locale.code])

            except IOError:
                if not self.db_project.has_multi_locale_repositories:
                    source_directory = self.source_directory_path
                    parent_directory = get_parent_directory(source_directory)

                    locale_code = locale.code
                    if uses_undercore_as_separator(parent_directory):
                        locale_code = locale_code.replace('-', '_')

                    locale_directory = os.path.join(parent_directory, locale_code)

                    # For asymmetric formats, create empty folder
                    if is_asymmetric_resource(next(self.relative_resource_paths())):
                        os.makedirs(locale_directory)

                    # For other formats, copy resources from source directory
                    else:
                        shutil.copytree(source_directory, locale_directory)

                        for root, dirnames, filenames in scandir.walk(locale_directory):
                            for filename in filenames:
                                path = os.path.join(root, filename)
                                if is_resource(filename):
                                    os.rename(path, source_to_locale_path(path))
                                else:
                                    os.remove(path)

                    locale_directory_paths[locale.code] = locale_directory

                else:
                    raise MissingLocaleDirectoryError(
                        'Directory for locale `{0}` not found'.format(locale.code)
                    )

            parent_directories.add(parent_directory)

        return locale_directory_paths
Example #6
0
    def __init__(self, vcs_project, path, locales=None):
        """
        Load the resource file for each enabled locale and store its
        translations in VCSEntity instances.
        """
        from pontoon.base.models import Locale
        from pontoon.sync import formats  # Avoid circular import.

        self.vcs_project = vcs_project
        self.path = path
        self.locales = locales or []
        self.files = {}
        self.entities = {}

        # Create entities using resources from the source directory,
        source_resource_path = os.path.join(vcs_project.source_directory_path(), self.path)
        source_resource_path = locale_to_source_path(source_resource_path)
        source_resource_file = formats.parse(source_resource_path, locale=Locale.objects.get(code='en-US'))
        for index, translation in enumerate(source_resource_file.translations):
            vcs_entity = VCSEntity(
                resource=self,
                key=translation.key,
                string=translation.source_string,
                string_plural=translation.source_string_plural,
                comments=translation.comments,
                source=translation.source,
                order=translation.order or index
            )
            self.entities[vcs_entity.key] = vcs_entity

        # Fill in translations from the locale resources.
        for locale in locales:
            resource_path = os.path.join(
                locale_directory_path(vcs_project.checkout_path, locale.code),
                self.path
            )

            log.debug('Parsing resource file: %s', resource_path)

            try:
                resource_file = formats.parse(resource_path, source_resource_path, locale)
            except (IOError, ParseError):
                continue  # File doesn't exist or is invalid, let's move on

            self.files[locale] = resource_file

            log.debug('Discovered %s translations.', len(resource_file.translations))

            for translation in resource_file.translations:
                try:
                    self.entities[translation.key].translations[locale.code] = translation
                except KeyError:
                    # If the source is missing an entity, we consider it
                    # deleted and don't add it.
                    pass
Example #7
0
 def execute_obsolete_vcs_resources(self):
     for path in self.changes['obsolete_vcs_resources']:
         for locale in self.db_project.locales.all():
             file_path = os.path.join(
                 locale_directory_path(self.vcs_project.checkout_path, locale.code),
                 path
             )
             if os.path.exists(file_path):
                 log.info('Removing obsolete file {} for {}.'.format(path, locale.code))
                 os.remove(file_path)
                 self.locales_to_commit.add(locale)
Example #8
0
    def locale_directories(self, repo):
        """
        A map of paths to their respective locales.
        """
        locales_paths = {}

        for locale in self.db_project.locales.all():
            path = locale_directory_path(repo.checkout_path, locale.code)[len(repo.checkout_path):].lstrip(os.sep)
            locales_paths[path] = locale

        return locales_paths
Example #9
0
 def execute_obsolete_vcs_resources(self):
     for path in self.changes['obsolete_vcs_resources']:
         for locale in self.db_project.locales.all():
             file_path = os.path.join(
                 locale_directory_path(self.vcs_project.checkout_path,
                                       locale.code), path)
             if os.path.exists(file_path):
                 log.info('Removing obsolete file {} for {}.'.format(
                     path, locale.code))
                 os.remove(file_path)
                 self.locales_to_commit.add(locale)
Example #10
0
def commit_changes(db_project, vcs_project, changeset, locale):
    """Commit the changes we've made back to the VCS."""
    authors = changeset.commit_authors_per_locale.get(locale.code, [])

    # Use the top translator for this batch as commit author, or
    # the fake Pontoon user if there are no authors.
    if len(authors) > 0:
        commit_author = Counter(authors).most_common(1)[0][0]
    else:
        commit_author = User(first_name="Mozilla Pontoon", email="*****@*****.**")

    commit_message = render_to_string('sync/commit_message.jinja', {
        'locale': locale,
        'project': db_project,
        'authors': set(authors)
    })

    locale_path = locale_directory_path(vcs_project.checkout_path, locale.code)
    repo = db_project.repository_for_path(locale_path)
    repo.commit(commit_message, commit_author, locale_path)
Example #11
0
def commit_changes(db_project, vcs_project, changeset, locale):
    """Commit the changes we've made back to the VCS."""
    authors = changeset.commit_authors_per_locale.get(locale.code, [])

    # Use the top translator for this batch as commit author, or
    # the fake Pontoon user if there are no authors.
    if len(authors) > 0:
        commit_author = Counter(authors).most_common(1)[0][0]
    else:
        commit_author = User(first_name="Mozilla Pontoon", email="*****@*****.**")

    commit_message = render_to_string('sync/commit_message.jinja', {
        'locale': locale,
        'project': db_project,
        'authors': set(authors)
    })

    locale_path = locale_directory_path(vcs_project.checkout_path, locale.code)
    repo = db_project.repository_for_path(locale_path)
    repo.commit(commit_message, commit_author, locale_path)
Example #12
0
    def test_obsolete_vcs_resources_paths(self):
        """Tests if we remove obsolete resources"""
        obsolete_vcs_resources = [
            'obsolete.properties',
            'second_obsolete.properties',
        ]
        obsolete_paths = [
            os.path.join(locale_directory_path(self.vcs_project.checkout_path, self.translated_locale.code), path)
            for path in obsolete_vcs_resources
        ]

        # We test if we remove only resources available on disk
        self.changeset.changes['obsolete_vcs_resources'] = obsolete_paths + ['second_obsolete.properties']

        with patch('os.path.exists', side_effect=lambda p: p in obsolete_paths[:1]) as exists_mock,\
             patch('os.remove') as remove_mock:

            self.changeset.execute_obsolete_vcs_resources()
            exists_mock.assert_has_calls([
                call(obsolete_paths[0]),
                call(obsolete_paths[1])
            ])
            remove_mock.assert_called_once_with(obsolete_paths[0])
        assert_equal(self.changeset.locales_to_commit, {self.translated_locale})