mirror of
				https://github.com/arsenetar/dupeguru.git
				synced 2025-09-11 17:58:17 +00:00 
			
		
		
		
	Remove Cocoa specific and other unused code
This commit is contained in:
		
							parent
							
								
									ebb81d9f03
								
							
						
					
					
						commit
						143147cb8e
					
				
							
								
								
									
										7
									
								
								build.py
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								build.py
									
									
									
									
									
								
							@ -109,10 +109,7 @@ def build_updatepot():
 | 
				
			|||||||
    print("Building columns.pot")
 | 
					    print("Building columns.pot")
 | 
				
			||||||
    loc.generate_pot(["core"], Path("locale", "columns.pot"), ["coltr"])
 | 
					    loc.generate_pot(["core"], Path("locale", "columns.pot"), ["coltr"])
 | 
				
			||||||
    print("Building ui.pot")
 | 
					    print("Building ui.pot")
 | 
				
			||||||
    # When we're not under OS X, we don't want to overwrite ui.pot because it contains Cocoa locs
 | 
					    loc.generate_pot(["qt"], Path("locale", "ui.pot"), ["tr"], merge=True)
 | 
				
			||||||
    # We want to merge the generated pot with the old pot in the most preserving way possible.
 | 
					 | 
				
			||||||
    ui_packages = ["qt", Path("cocoa", "inter")]
 | 
					 | 
				
			||||||
    loc.generate_pot(ui_packages, Path("locale", "ui.pot"), ["tr"], merge=True)
 | 
					 | 
				
			||||||
    print("Building qtlib.pot")
 | 
					    print("Building qtlib.pot")
 | 
				
			||||||
    loc.generate_pot(["qtlib"], Path("qtlib", "locale", "qtlib.pot"), ["tr"])
 | 
					    loc.generate_pot(["qtlib"], Path("qtlib", "locale", "qtlib.pot"), ["tr"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -121,13 +118,11 @@ def build_mergepot():
 | 
				
			|||||||
    print("Updating .po files using .pot files")
 | 
					    print("Updating .po files using .pot files")
 | 
				
			||||||
    loc.merge_pots_into_pos("locale")
 | 
					    loc.merge_pots_into_pos("locale")
 | 
				
			||||||
    loc.merge_pots_into_pos(Path("qtlib", "locale"))
 | 
					    loc.merge_pots_into_pos(Path("qtlib", "locale"))
 | 
				
			||||||
    # loc.merge_pots_into_pos(Path("cocoalib", "locale"))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def build_normpo():
 | 
					def build_normpo():
 | 
				
			||||||
    loc.normalize_all_pos("locale")
 | 
					    loc.normalize_all_pos("locale")
 | 
				
			||||||
    loc.normalize_all_pos(Path("qtlib", "locale"))
 | 
					    loc.normalize_all_pos(Path("qtlib", "locale"))
 | 
				
			||||||
    # loc.normalize_all_pos(Path("cocoalib", "locale"))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def build_pe_modules():
 | 
					def build_pe_modules():
 | 
				
			||||||
 | 
				
			|||||||
@ -20,13 +20,8 @@ import re
 | 
				
			|||||||
import importlib
 | 
					import importlib
 | 
				
			||||||
from datetime import datetime
 | 
					from datetime import datetime
 | 
				
			||||||
import glob
 | 
					import glob
 | 
				
			||||||
import sysconfig
 | 
					 | 
				
			||||||
import modulefinder
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from setuptools import setup, Extension
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .plat import ISWINDOWS
 | 
					from .plat import ISWINDOWS
 | 
				
			||||||
from .util import ensure_folder, delete_files_with_pattern
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def print_and_do(cmd):
 | 
					def print_and_do(cmd):
 | 
				
			||||||
@ -181,23 +176,6 @@ def build_dmg(app_path, destfolder):
 | 
				
			|||||||
    print("Build Complete")
 | 
					    print("Build Complete")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def copy_sysconfig_files_for_embed(destpath):
 | 
					 | 
				
			||||||
    # This normally shouldn't be needed for Python 3.3+.
 | 
					 | 
				
			||||||
    makefile = sysconfig.get_makefile_filename()
 | 
					 | 
				
			||||||
    configh = sysconfig.get_config_h_filename()
 | 
					 | 
				
			||||||
    shutil.copy(makefile, destpath)
 | 
					 | 
				
			||||||
    shutil.copy(configh, destpath)
 | 
					 | 
				
			||||||
    with open(op.join(destpath, "site.py"), "w") as fp:
 | 
					 | 
				
			||||||
        fp.write(
 | 
					 | 
				
			||||||
            """
 | 
					 | 
				
			||||||
import os.path as op
 | 
					 | 
				
			||||||
from distutils import sysconfig
 | 
					 | 
				
			||||||
sysconfig.get_makefile_filename = lambda: op.join(op.dirname(__file__), 'Makefile')
 | 
					 | 
				
			||||||
sysconfig.get_config_h_filename = lambda: op.join(op.dirname(__file__), 'pyconfig.h')
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def add_to_pythonpath(path):
 | 
					def add_to_pythonpath(path):
 | 
				
			||||||
    """Adds ``path`` to both ``PYTHONPATH`` env and ``sys.path``."""
 | 
					    """Adds ``path`` to both ``PYTHONPATH`` env and ``sys.path``."""
 | 
				
			||||||
    abspath = op.abspath(path)
 | 
					    abspath = op.abspath(path)
 | 
				
			||||||
@ -248,20 +226,6 @@ def copy_packages(packages_names, dest, create_links=False, extra_ignores=None):
 | 
				
			|||||||
                shutil.copy(source_path, dest_path)
 | 
					                shutil.copy(source_path, dest_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def copy_qt_plugins(folder_names, dest):  # This is only for Windows
 | 
					 | 
				
			||||||
    from PyQt5.QtCore import QLibraryInfo
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    qt_plugin_dir = QLibraryInfo.location(QLibraryInfo.PluginsPath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def ignore(path, names):
 | 
					 | 
				
			||||||
        if path == qt_plugin_dir:
 | 
					 | 
				
			||||||
            return [n for n in names if n not in folder_names]
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return [n for n in names if not n.endswith(".dll")]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    shutil.copytree(qt_plugin_dir, dest, ignore=ignore)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def build_debian_changelog(
 | 
					def build_debian_changelog(
 | 
				
			||||||
    changelogpath,
 | 
					    changelogpath,
 | 
				
			||||||
    destfile,
 | 
					    destfile,
 | 
				
			||||||
@ -349,183 +313,6 @@ def read_changelog_file(filename):
 | 
				
			|||||||
    return result
 | 
					    return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OSXAppStructure:
 | 
					 | 
				
			||||||
    def __init__(self, dest):
 | 
					 | 
				
			||||||
        self.dest = dest
 | 
					 | 
				
			||||||
        self.contents = op.join(dest, "Contents")
 | 
					 | 
				
			||||||
        self.macos = op.join(self.contents, "MacOS")
 | 
					 | 
				
			||||||
        self.resources = op.join(self.contents, "Resources")
 | 
					 | 
				
			||||||
        self.frameworks = op.join(self.contents, "Frameworks")
 | 
					 | 
				
			||||||
        self.infoplist = op.join(self.contents, "Info.plist")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def create(self, infoplist):
 | 
					 | 
				
			||||||
        ensure_empty_folder(self.dest)
 | 
					 | 
				
			||||||
        os.makedirs(self.macos)
 | 
					 | 
				
			||||||
        os.mkdir(self.resources)
 | 
					 | 
				
			||||||
        os.mkdir(self.frameworks)
 | 
					 | 
				
			||||||
        copy(infoplist, self.infoplist)
 | 
					 | 
				
			||||||
        open(op.join(self.contents, "PkgInfo"), "wt").write("APPLxxxx")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def copy_executable(self, executable):
 | 
					 | 
				
			||||||
        info = plistlib.readPlist(self.infoplist)
 | 
					 | 
				
			||||||
        self.executablename = info["CFBundleExecutable"]
 | 
					 | 
				
			||||||
        self.executablepath = op.join(self.macos, self.executablename)
 | 
					 | 
				
			||||||
        copy(executable, self.executablepath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def copy_resources(self, *resources, use_symlinks=False):
 | 
					 | 
				
			||||||
        for path in resources:
 | 
					 | 
				
			||||||
            resource_dest = op.join(self.resources, op.basename(path))
 | 
					 | 
				
			||||||
            action = symlink if use_symlinks else copy
 | 
					 | 
				
			||||||
            action(op.abspath(path), resource_dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def copy_frameworks(self, *frameworks):
 | 
					 | 
				
			||||||
        for path in frameworks:
 | 
					 | 
				
			||||||
            framework_dest = op.join(self.frameworks, op.basename(path))
 | 
					 | 
				
			||||||
            copy(path, framework_dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def create_osx_app_structure(
 | 
					 | 
				
			||||||
    dest,
 | 
					 | 
				
			||||||
    executable,
 | 
					 | 
				
			||||||
    infoplist,
 | 
					 | 
				
			||||||
    resources=None,
 | 
					 | 
				
			||||||
    frameworks=None,
 | 
					 | 
				
			||||||
    symlink_resources=False,
 | 
					 | 
				
			||||||
):
 | 
					 | 
				
			||||||
    # `dest`: A path to the destination .app folder
 | 
					 | 
				
			||||||
    # `executable`: the path of the executable file that goes in "MacOS"
 | 
					 | 
				
			||||||
    # `infoplist`: The path to your Info.plist file.
 | 
					 | 
				
			||||||
    # `resources`: A list of paths of files or folders going in the "Resources" folder.
 | 
					 | 
				
			||||||
    # `frameworks`: Same as above for "Frameworks".
 | 
					 | 
				
			||||||
    # `symlink_resources`: If True, will symlink resources into the structure instead of copying them.
 | 
					 | 
				
			||||||
    app = OSXAppStructure(dest)
 | 
					 | 
				
			||||||
    app.create(infoplist)
 | 
					 | 
				
			||||||
    app.copy_executable(executable)
 | 
					 | 
				
			||||||
    app.copy_resources(*resources, use_symlinks=symlink_resources)
 | 
					 | 
				
			||||||
    app.copy_frameworks(*frameworks)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class OSXFrameworkStructure:
 | 
					 | 
				
			||||||
    def __init__(self, dest):
 | 
					 | 
				
			||||||
        self.dest = dest
 | 
					 | 
				
			||||||
        self.contents = op.join(dest, "Versions", "A")
 | 
					 | 
				
			||||||
        self.resources = op.join(self.contents, "Resources")
 | 
					 | 
				
			||||||
        self.headers = op.join(self.contents, "Headers")
 | 
					 | 
				
			||||||
        self.infoplist = op.join(self.resources, "Info.plist")
 | 
					 | 
				
			||||||
        self._update_executable_path()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _update_executable_path(self):
 | 
					 | 
				
			||||||
        if not op.exists(self.infoplist):
 | 
					 | 
				
			||||||
            self.executablename = self.executablepath = None
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        info = plistlib.readPlist(self.infoplist)
 | 
					 | 
				
			||||||
        self.executablename = info["CFBundleExecutable"]
 | 
					 | 
				
			||||||
        self.executablepath = op.join(self.contents, self.executablename)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def create(self, infoplist):
 | 
					 | 
				
			||||||
        ensure_empty_folder(self.dest)
 | 
					 | 
				
			||||||
        os.makedirs(self.contents)
 | 
					 | 
				
			||||||
        os.mkdir(self.resources)
 | 
					 | 
				
			||||||
        os.mkdir(self.headers)
 | 
					 | 
				
			||||||
        copy(infoplist, self.infoplist)
 | 
					 | 
				
			||||||
        self._update_executable_path()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def create_symlinks(self):
 | 
					 | 
				
			||||||
        # Only call this after create() and copy_executable()
 | 
					 | 
				
			||||||
        os.symlink("A", op.join(self.dest, "Versions", "Current"))
 | 
					 | 
				
			||||||
        os.symlink(op.relpath(self.executablepath, self.dest), op.join(self.dest, self.executablename))
 | 
					 | 
				
			||||||
        os.symlink(op.relpath(self.headers, self.dest), op.join(self.dest, "Headers"))
 | 
					 | 
				
			||||||
        os.symlink(op.relpath(self.resources, self.dest), op.join(self.dest, "Resources"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def copy_executable(self, executable):
 | 
					 | 
				
			||||||
        copy(executable, self.executablepath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def copy_resources(self, *resources, use_symlinks=False):
 | 
					 | 
				
			||||||
        for path in resources:
 | 
					 | 
				
			||||||
            resource_dest = op.join(self.resources, op.basename(path))
 | 
					 | 
				
			||||||
            action = symlink if use_symlinks else copy
 | 
					 | 
				
			||||||
            action(op.abspath(path), resource_dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def copy_headers(self, *headers, use_symlinks=False):
 | 
					 | 
				
			||||||
        for path in headers:
 | 
					 | 
				
			||||||
            header_dest = op.join(self.headers, op.basename(path))
 | 
					 | 
				
			||||||
            action = symlink if use_symlinks else copy
 | 
					 | 
				
			||||||
            action(op.abspath(path), header_dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def copy_embeddable_python_dylib(dst):
 | 
					 | 
				
			||||||
    runtime = op.join(
 | 
					 | 
				
			||||||
        sysconfig.get_config_var("PYTHONFRAMEWORKPREFIX"),
 | 
					 | 
				
			||||||
        sysconfig.get_config_var("LDLIBRARY"),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    filedest = op.join(dst, "Python")
 | 
					 | 
				
			||||||
    shutil.copy(runtime, filedest)
 | 
					 | 
				
			||||||
    os.chmod(filedest, 0o774)  # We need write permission to use install_name_tool
 | 
					 | 
				
			||||||
    cmd = "install_name_tool -id @rpath/Python %s" % filedest
 | 
					 | 
				
			||||||
    print_and_do(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def collect_stdlib_dependencies(script, dest_folder, extra_deps=None):
 | 
					 | 
				
			||||||
    sysprefix = sys.prefix  # could be a virtualenv
 | 
					 | 
				
			||||||
    basesysprefix = sys.base_prefix  # seems to be path to non-virtual sys
 | 
					 | 
				
			||||||
    real_lib_prefix = sysconfig.get_config_var("LIBDEST")  # leaving this in case it is neede
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def is_stdlib_path(path):
 | 
					 | 
				
			||||||
        # A module path is only a stdlib path if it's in either sys.prefix or
 | 
					 | 
				
			||||||
        # sysconfig.get_config_var('prefix') (the 2 are different if we are in a virtualenv) and if
 | 
					 | 
				
			||||||
        # there's no "site-package in the path.
 | 
					 | 
				
			||||||
        if not path:
 | 
					 | 
				
			||||||
            return False
 | 
					 | 
				
			||||||
        if "site-package" in path:
 | 
					 | 
				
			||||||
            return False
 | 
					 | 
				
			||||||
        if not (path.startswith(sysprefix) or path.startswith(basesysprefix) or path.startswith(real_lib_prefix)):
 | 
					 | 
				
			||||||
            return False
 | 
					 | 
				
			||||||
        return True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ensure_folder(dest_folder)
 | 
					 | 
				
			||||||
    mf = modulefinder.ModuleFinder()
 | 
					 | 
				
			||||||
    mf.run_script(script)
 | 
					 | 
				
			||||||
    modpaths = [mod.__file__ for mod in mf.modules.values()]
 | 
					 | 
				
			||||||
    modpaths = filter(is_stdlib_path, modpaths)
 | 
					 | 
				
			||||||
    for p in modpaths:
 | 
					 | 
				
			||||||
        if p.startswith(real_lib_prefix):
 | 
					 | 
				
			||||||
            relpath = op.relpath(p, real_lib_prefix)
 | 
					 | 
				
			||||||
        elif p.startswith(sysprefix):
 | 
					 | 
				
			||||||
            relpath = op.relpath(p, sysprefix)
 | 
					 | 
				
			||||||
            assert relpath.startswith("lib/python3.")  # we want to get rid of that lib/python3.x part
 | 
					 | 
				
			||||||
            relpath = relpath[len("lib/python3.X/") :]
 | 
					 | 
				
			||||||
        elif p.startswith(basesysprefix):
 | 
					 | 
				
			||||||
            relpath = op.relpath(p, basesysprefix)
 | 
					 | 
				
			||||||
            assert relpath.startswith("lib/python3.")
 | 
					 | 
				
			||||||
            relpath = relpath[len("lib/python3.X/") :]
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            raise AssertionError()
 | 
					 | 
				
			||||||
        if relpath.startswith("lib-dynload"):  # We copy .so files in lib-dynload directly in our dest
 | 
					 | 
				
			||||||
            relpath = relpath[len("lib-dynload/") :]
 | 
					 | 
				
			||||||
        if relpath.startswith("encodings") or relpath.startswith("distutils"):
 | 
					 | 
				
			||||||
            # We force their inclusion later.
 | 
					 | 
				
			||||||
            continue
 | 
					 | 
				
			||||||
        dest_path = op.join(dest_folder, relpath)
 | 
					 | 
				
			||||||
        ensure_folder(op.dirname(dest_path))
 | 
					 | 
				
			||||||
        copy(p, dest_path)
 | 
					 | 
				
			||||||
    # stringprep is used by encodings.
 | 
					 | 
				
			||||||
    # We use real_lib_prefix with distutils because virtualenv messes with it and we need to refer
 | 
					 | 
				
			||||||
    # to the original distutils folder.
 | 
					 | 
				
			||||||
    FORCED_INCLUSION = [
 | 
					 | 
				
			||||||
        "encodings",
 | 
					 | 
				
			||||||
        "stringprep",
 | 
					 | 
				
			||||||
        op.join(real_lib_prefix, "distutils"),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
    if extra_deps:
 | 
					 | 
				
			||||||
        FORCED_INCLUSION += extra_deps
 | 
					 | 
				
			||||||
    copy_packages(FORCED_INCLUSION, dest_folder)
 | 
					 | 
				
			||||||
    # There's a couple of rather big exe files in the distutils folder that we absolutely don't
 | 
					 | 
				
			||||||
    # need. Remove them.
 | 
					 | 
				
			||||||
    delete_files_with_pattern(op.join(dest_folder, "distutils"), "*.exe")
 | 
					 | 
				
			||||||
    # And, finally, create an empty "site.py" that Python needs around on startup.
 | 
					 | 
				
			||||||
    open(op.join(dest_folder, "site.py"), "w").close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def fix_qt_resource_file(path):
 | 
					def fix_qt_resource_file(path):
 | 
				
			||||||
    # pyrcc5 under Windows, if the locale is non-english, can produce a source file with a date
 | 
					    # pyrcc5 under Windows, if the locale is non-english, can produce a source file with a date
 | 
				
			||||||
    # containing accented characters. If it does, the encoding is wrong and it prevents the file
 | 
					    # containing accented characters. If it does, the encoding is wrong and it prevents the file
 | 
				
			||||||
@ -537,21 +324,3 @@ def fix_qt_resource_file(path):
 | 
				
			|||||||
    lines = [line for line in lines if not line.startswith(b"#")]
 | 
					    lines = [line for line in lines if not line.startswith(b"#")]
 | 
				
			||||||
    with open(path, "wb") as fp:
 | 
					    with open(path, "wb") as fp:
 | 
				
			||||||
        fp.write(b"\n".join(lines))
 | 
					        fp.write(b"\n".join(lines))
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def build_cocoa_ext(extname, dest, source_files, extra_frameworks=(), extra_includes=()):
 | 
					 | 
				
			||||||
    extra_link_args = ["-framework", "CoreFoundation", "-framework", "Foundation"]
 | 
					 | 
				
			||||||
    for extra in extra_frameworks:
 | 
					 | 
				
			||||||
        extra_link_args += ["-framework", extra]
 | 
					 | 
				
			||||||
    ext = Extension(
 | 
					 | 
				
			||||||
        extname,
 | 
					 | 
				
			||||||
        source_files,
 | 
					 | 
				
			||||||
        extra_link_args=extra_link_args,
 | 
					 | 
				
			||||||
        include_dirs=extra_includes,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    setup(script_args=["build_ext", "--inplace"], ext_modules=[ext])
 | 
					 | 
				
			||||||
    # Our problem here is to get the fully qualified filename of the resulting .so but I couldn't
 | 
					 | 
				
			||||||
    # find a documented way to do so. The only thing I could find is this below :(
 | 
					 | 
				
			||||||
    fn = ext._file_name
 | 
					 | 
				
			||||||
    assert op.exists(fn)
 | 
					 | 
				
			||||||
    move(fn, op.join(dest, fn))
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,23 +0,0 @@
 | 
				
			|||||||
# Created By: Virgil Dupras
 | 
					 | 
				
			||||||
# Created On: 2011-04-19
 | 
					 | 
				
			||||||
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
 | 
					 | 
				
			||||||
# which should be included with this package. The terms are also available at
 | 
					 | 
				
			||||||
# http://www.gnu.org/licenses/gpl-3.0.html
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
import traceback
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Taken from http://bzimmer.ziclix.com/2008/12/17/python-thread-dumps/
 | 
					 | 
				
			||||||
def stacktraces():
 | 
					 | 
				
			||||||
    code = []
 | 
					 | 
				
			||||||
    for thread_id, stack in sys._current_frames().items():
 | 
					 | 
				
			||||||
        code.append("\n# ThreadID: %s" % thread_id)
 | 
					 | 
				
			||||||
        for filename, lineno, name, line in traceback.extract_stack(stack):
 | 
					 | 
				
			||||||
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
 | 
					 | 
				
			||||||
            if line:
 | 
					 | 
				
			||||||
                code.append("  %s" % (line.strip()))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return "\n".join(code)
 | 
					 | 
				
			||||||
@ -42,29 +42,6 @@ def special_folder_path(special_folder, appname=None, portable=False):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try:
 | 
					try:
 | 
				
			||||||
    # Normally, we would simply do "from cocoa import proxy", but due to a bug in pytest (currently
 | 
					 | 
				
			||||||
    # at v2.4.2), our test suite is broken when we do that. This below is a workaround until that
 | 
					 | 
				
			||||||
    # bug is fixed.
 | 
					 | 
				
			||||||
    import cocoa
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if not hasattr(cocoa, "proxy"):
 | 
					 | 
				
			||||||
        raise ImportError()
 | 
					 | 
				
			||||||
    proxy = cocoa.proxy
 | 
					 | 
				
			||||||
    _open_url = proxy.openURL_
 | 
					 | 
				
			||||||
    _open_path = proxy.openPath_
 | 
					 | 
				
			||||||
    _reveal_path = proxy.revealPath_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _special_folder_path(special_folder, appname=None, portable=False):
 | 
					 | 
				
			||||||
        if special_folder == SpecialFolder.CACHE:
 | 
					 | 
				
			||||||
            base = proxy.getCachePath()
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            base = proxy.getAppdataPath()
 | 
					 | 
				
			||||||
        if not appname:
 | 
					 | 
				
			||||||
            appname = proxy.bundleInfo_("CFBundleName")
 | 
					 | 
				
			||||||
        return op.join(base, appname)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
    from PyQt5.QtCore import QUrl, QStandardPaths
 | 
					    from PyQt5.QtCore import QUrl, QStandardPaths
 | 
				
			||||||
    from PyQt5.QtGui import QDesktopServices
 | 
					    from PyQt5.QtGui import QDesktopServices
 | 
				
			||||||
    from qtlib.util import get_appdata
 | 
					    from qtlib.util import get_appdata
 | 
				
			||||||
@ -97,7 +74,7 @@ except ImportError:
 | 
				
			|||||||
            folder = get_appdata(portable)
 | 
					            folder = get_appdata(portable)
 | 
				
			||||||
        return folder
 | 
					        return folder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    except ImportError:
 | 
					except ImportError:
 | 
				
			||||||
    # We're either running tests, and these functions don't matter much or we're in a really
 | 
					    # We're either running tests, and these functions don't matter much or we're in a really
 | 
				
			||||||
    # weird situation. Let's just have dummy fallbacks.
 | 
					    # weird situation. Let's just have dummy fallbacks.
 | 
				
			||||||
    logging.warning("Can't setup desktop functions!")
 | 
					    logging.warning("Can't setup desktop functions!")
 | 
				
			||||||
 | 
				
			|||||||
@ -1,216 +0,0 @@
 | 
				
			|||||||
# Created By: Virgil Dupras
 | 
					 | 
				
			||||||
# Created On: 2011-08-05
 | 
					 | 
				
			||||||
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
 | 
					 | 
				
			||||||
# which should be included with this package. The terms are also available at
 | 
					 | 
				
			||||||
# http://www.gnu.org/licenses/gpl-3.0.html
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from sys import maxsize as INF
 | 
					 | 
				
			||||||
from math import sqrt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VERY_SMALL = 0.0000001
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Point:
 | 
					 | 
				
			||||||
    def __init__(self, x, y):
 | 
					 | 
				
			||||||
        self.x = x
 | 
					 | 
				
			||||||
        self.y = y
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __repr__(self):
 | 
					 | 
				
			||||||
        return "<Point {:2.2f}, {:2.2f}>".format(*self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __iter__(self):
 | 
					 | 
				
			||||||
        yield self.x
 | 
					 | 
				
			||||||
        yield self.y
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def distance_to(self, other):
 | 
					 | 
				
			||||||
        return Line(self, other).length()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Line:
 | 
					 | 
				
			||||||
    def __init__(self, p1, p2):
 | 
					 | 
				
			||||||
        self.p1 = p1
 | 
					 | 
				
			||||||
        self.p2 = p2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __repr__(self):
 | 
					 | 
				
			||||||
        return "<Line {}, {}>".format(*self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __iter__(self):
 | 
					 | 
				
			||||||
        yield self.p1
 | 
					 | 
				
			||||||
        yield self.p2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def dx(self):
 | 
					 | 
				
			||||||
        return self.p2.x - self.p1.x
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def dy(self):
 | 
					 | 
				
			||||||
        return self.p2.y - self.p1.y
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def length(self):
 | 
					 | 
				
			||||||
        return sqrt(self.dx() ** 2 + self.dy() ** 2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def slope(self):
 | 
					 | 
				
			||||||
        if self.dx() == 0:
 | 
					 | 
				
			||||||
            return INF if self.dy() > 0 else -INF
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return self.dy() / self.dx()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def intersection_point(self, other):
 | 
					 | 
				
			||||||
        # with help from http://paulbourke.net/geometry/lineline2d/
 | 
					 | 
				
			||||||
        if abs(self.slope() - other.slope()) < VERY_SMALL:
 | 
					 | 
				
			||||||
            # parallel. Even if coincident, we return nothing
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        A, B = self
 | 
					 | 
				
			||||||
        C, D = other
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        denom = (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y)
 | 
					 | 
				
			||||||
        if denom == 0:
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
        numera = (D.x - C.x) * (A.y - C.y) - (D.y - C.y) * (A.x - C.x)
 | 
					 | 
				
			||||||
        numerb = (B.x - A.x) * (A.y - C.y) - (B.y - A.y) * (A.x - C.x)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mua = numera / denom
 | 
					 | 
				
			||||||
        mub = numerb / denom
 | 
					 | 
				
			||||||
        if (0 <= mua <= 1) and (0 <= mub <= 1):
 | 
					 | 
				
			||||||
            x = A.x + mua * (B.x - A.x)
 | 
					 | 
				
			||||||
            y = A.y + mua * (B.y - A.y)
 | 
					 | 
				
			||||||
            return Point(x, y)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Rect:
 | 
					 | 
				
			||||||
    def __init__(self, x, y, w, h):
 | 
					 | 
				
			||||||
        self.x = x
 | 
					 | 
				
			||||||
        self.y = y
 | 
					 | 
				
			||||||
        self.w = w
 | 
					 | 
				
			||||||
        self.h = h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __iter__(self):
 | 
					 | 
				
			||||||
        yield self.x
 | 
					 | 
				
			||||||
        yield self.y
 | 
					 | 
				
			||||||
        yield self.w
 | 
					 | 
				
			||||||
        yield self.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __repr__(self):
 | 
					 | 
				
			||||||
        return "<Rect {:2.2f}, {:2.2f}, {:2.2f}, {:2.2f}>".format(*self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def from_center(cls, center, width, height):
 | 
					 | 
				
			||||||
        x = center.x - width / 2
 | 
					 | 
				
			||||||
        y = center.y - height / 2
 | 
					 | 
				
			||||||
        return cls(x, y, width, height)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def from_corners(cls, pt1, pt2):
 | 
					 | 
				
			||||||
        x1, y1 = pt1
 | 
					 | 
				
			||||||
        x2, y2 = pt2
 | 
					 | 
				
			||||||
        return cls(min(x1, x2), min(y1, y2), abs(x1 - x2), abs(y1 - y2))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def center(self):
 | 
					 | 
				
			||||||
        return Point(self.x + self.w / 2, self.y + self.h / 2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def contains_point(self, point):
 | 
					 | 
				
			||||||
        x, y = point
 | 
					 | 
				
			||||||
        (x1, y1), (x2, y2) = self.corners()
 | 
					 | 
				
			||||||
        return (x1 <= x <= x2) and (y1 <= y <= y2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def contains_rect(self, rect):
 | 
					 | 
				
			||||||
        pt1, pt2 = rect.corners()
 | 
					 | 
				
			||||||
        return self.contains_point(pt1) and self.contains_point(pt2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def corners(self):
 | 
					 | 
				
			||||||
        return Point(self.x, self.y), Point(self.x + self.w, self.y + self.h)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def intersects(self, other):
 | 
					 | 
				
			||||||
        r1pt1, r1pt2 = self.corners()
 | 
					 | 
				
			||||||
        r2pt1, r2pt2 = other.corners()
 | 
					 | 
				
			||||||
        if r1pt1.x < r2pt1.x:
 | 
					 | 
				
			||||||
            xinter = r1pt2.x >= r2pt1.x
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            xinter = r2pt2.x >= r1pt1.x
 | 
					 | 
				
			||||||
        if not xinter:
 | 
					 | 
				
			||||||
            return False
 | 
					 | 
				
			||||||
        if r1pt1.y < r2pt1.y:
 | 
					 | 
				
			||||||
            yinter = r1pt2.y >= r2pt1.y
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            yinter = r2pt2.y >= r1pt1.y
 | 
					 | 
				
			||||||
        return yinter
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def lines(self):
 | 
					 | 
				
			||||||
        pt1, pt4 = self.corners()
 | 
					 | 
				
			||||||
        pt2 = Point(pt4.x, pt1.y)
 | 
					 | 
				
			||||||
        pt3 = Point(pt1.x, pt4.y)
 | 
					 | 
				
			||||||
        l1 = Line(pt1, pt2)
 | 
					 | 
				
			||||||
        l2 = Line(pt2, pt4)
 | 
					 | 
				
			||||||
        l3 = Line(pt3, pt4)
 | 
					 | 
				
			||||||
        l4 = Line(pt1, pt3)
 | 
					 | 
				
			||||||
        return l1, l2, l3, l4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def scaled_rect(self, dx, dy):
 | 
					 | 
				
			||||||
        """Returns a rect that has the same borders at self, but grown/shrunk by dx/dy on each side."""
 | 
					 | 
				
			||||||
        x, y, w, h = self
 | 
					 | 
				
			||||||
        x -= dx
 | 
					 | 
				
			||||||
        y -= dy
 | 
					 | 
				
			||||||
        w += dx * 2
 | 
					 | 
				
			||||||
        h += dy * 2
 | 
					 | 
				
			||||||
        return Rect(x, y, w, h)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def united(self, other):
 | 
					 | 
				
			||||||
        """Returns the bounding rectangle of this rectangle and `other`."""
 | 
					 | 
				
			||||||
        # ul=upper left lr=lower right
 | 
					 | 
				
			||||||
        ulcorner1, lrcorner1 = self.corners()
 | 
					 | 
				
			||||||
        ulcorner2, lrcorner2 = other.corners()
 | 
					 | 
				
			||||||
        corner1 = Point(min(ulcorner1.x, ulcorner2.x), min(ulcorner1.y, ulcorner2.y))
 | 
					 | 
				
			||||||
        corner2 = Point(max(lrcorner1.x, lrcorner2.x), max(lrcorner1.y, lrcorner2.y))
 | 
					 | 
				
			||||||
        return Rect.from_corners(corner1, corner2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # --- Properties
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def top(self):
 | 
					 | 
				
			||||||
        return self.y
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @top.setter
 | 
					 | 
				
			||||||
    def top(self, value):
 | 
					 | 
				
			||||||
        self.y = value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def bottom(self):
 | 
					 | 
				
			||||||
        return self.y + self.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @bottom.setter
 | 
					 | 
				
			||||||
    def bottom(self, value):
 | 
					 | 
				
			||||||
        self.y = value - self.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def left(self):
 | 
					 | 
				
			||||||
        return self.x
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @left.setter
 | 
					 | 
				
			||||||
    def left(self, value):
 | 
					 | 
				
			||||||
        self.x = value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def right(self):
 | 
					 | 
				
			||||||
        return self.x + self.w
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @right.setter
 | 
					 | 
				
			||||||
    def right(self, value):
 | 
					 | 
				
			||||||
        self.x = value - self.w
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def width(self):
 | 
					 | 
				
			||||||
        return self.w
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @width.setter
 | 
					 | 
				
			||||||
    def width(self, value):
 | 
					 | 
				
			||||||
        self.w = value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def height(self):
 | 
					 | 
				
			||||||
        return self.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @height.setter
 | 
					 | 
				
			||||||
    def height(self, value):
 | 
					 | 
				
			||||||
        self.h = value
 | 
					 | 
				
			||||||
							
								
								
									
										118
									
								
								hscommon/loc.py
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								hscommon/loc.py
									
									
									
									
									
								
							@ -1,14 +1,11 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
import os.path as op
 | 
					import os.path as op
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
import re
 | 
					 | 
				
			||||||
import tempfile
 | 
					import tempfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import polib
 | 
					import polib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import pygettext
 | 
					from . import pygettext
 | 
				
			||||||
from .util import modified_after, dedupe, ensure_folder
 | 
					 | 
				
			||||||
from .build import print_and_do, ensure_empty_folder
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
LC_MESSAGES = "LC_MESSAGES"
 | 
					LC_MESSAGES = "LC_MESSAGES"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -116,118 +113,3 @@ def normalize_all_pos(base_folder):
 | 
				
			|||||||
        for pofile in pofiles:
 | 
					        for pofile in pofiles:
 | 
				
			||||||
            p = polib.pofile(pofile)
 | 
					            p = polib.pofile(pofile)
 | 
				
			||||||
            p.save()
 | 
					            p.save()
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# --- Cocoa
 | 
					 | 
				
			||||||
def all_lproj_paths(folder):
 | 
					 | 
				
			||||||
    return files_with_ext(folder, ".lproj")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def escape_cocoa_strings(s):
 | 
					 | 
				
			||||||
    return s.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def unescape_cocoa_strings(s):
 | 
					 | 
				
			||||||
    return s.replace("\\\\", "\\").replace('\\"', '"').replace("\\n", "\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def strings2pot(target, dest):
 | 
					 | 
				
			||||||
    with open(target, "rt", encoding="utf-8") as fp:
 | 
					 | 
				
			||||||
        contents = fp.read()
 | 
					 | 
				
			||||||
    # We're reading an en.lproj file. We only care about the righthand part of the translation.
 | 
					 | 
				
			||||||
    re_trans = re.compile(r'".*" = "(.*)";')
 | 
					 | 
				
			||||||
    strings = re_trans.findall(contents)
 | 
					 | 
				
			||||||
    if op.exists(dest):
 | 
					 | 
				
			||||||
        po = polib.pofile(dest)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        po = polib.POFile()
 | 
					 | 
				
			||||||
    for s in dedupe(strings):
 | 
					 | 
				
			||||||
        s = unescape_cocoa_strings(s)
 | 
					 | 
				
			||||||
        entry = po.find(s)
 | 
					 | 
				
			||||||
        if entry is None:
 | 
					 | 
				
			||||||
            entry = polib.POEntry(msgid=s)
 | 
					 | 
				
			||||||
            po.append(entry)
 | 
					 | 
				
			||||||
        # we don't know or care about a line number so we put 0
 | 
					 | 
				
			||||||
        entry.occurrences.append((target, "0"))
 | 
					 | 
				
			||||||
        entry.occurrences = dedupe(entry.occurrences)
 | 
					 | 
				
			||||||
    po.save(dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def allstrings2pot(lprojpath, dest, excludes=None):
 | 
					 | 
				
			||||||
    allstrings = files_with_ext(lprojpath, STRING_EXT)
 | 
					 | 
				
			||||||
    if excludes:
 | 
					 | 
				
			||||||
        allstrings = [p for p in allstrings if op.splitext(op.basename(p))[0] not in excludes]
 | 
					 | 
				
			||||||
    for strings_path in allstrings:
 | 
					 | 
				
			||||||
        strings2pot(strings_path, dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def po2strings(pofile, en_strings, dest):
 | 
					 | 
				
			||||||
    # Takes en_strings and replace all righthand parts of "foo" = "bar"; entries with translations
 | 
					 | 
				
			||||||
    # in pofile, then puts the result in dest.
 | 
					 | 
				
			||||||
    po = polib.pofile(pofile)
 | 
					 | 
				
			||||||
    if not modified_after(pofile, dest):
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
    ensure_folder(op.dirname(dest))
 | 
					 | 
				
			||||||
    print("Creating {} from {}".format(dest, pofile))
 | 
					 | 
				
			||||||
    with open(en_strings, "rt", encoding="utf-8") as fp:
 | 
					 | 
				
			||||||
        contents = fp.read()
 | 
					 | 
				
			||||||
    re_trans = re.compile(r'(?<= = ").*(?=";\n)')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def repl(match):
 | 
					 | 
				
			||||||
        s = match.group(0)
 | 
					 | 
				
			||||||
        unescaped = unescape_cocoa_strings(s)
 | 
					 | 
				
			||||||
        entry = po.find(unescaped)
 | 
					 | 
				
			||||||
        if entry is None:
 | 
					 | 
				
			||||||
            print("WARNING: Could not find entry '{}' in .po file".format(s))
 | 
					 | 
				
			||||||
            return s
 | 
					 | 
				
			||||||
        trans = entry.msgstr
 | 
					 | 
				
			||||||
        return escape_cocoa_strings(trans) if trans else s
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    contents = re_trans.sub(repl, contents)
 | 
					 | 
				
			||||||
    with open(dest, "wt", encoding="utf-8") as fp:
 | 
					 | 
				
			||||||
        fp.write(contents)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def generate_cocoa_strings_from_code(code_folder, dest_folder):
 | 
					 | 
				
			||||||
    # Uses the "genstrings" command to generate strings file from all .m files in "code_folder".
 | 
					 | 
				
			||||||
    # The strings file (their name depends on the localization table used in the source) will be
 | 
					 | 
				
			||||||
    # placed in "dest_folder".
 | 
					 | 
				
			||||||
    # genstrings produces utf-16 files with comments. After having generated the files, we convert
 | 
					 | 
				
			||||||
    # them to utf-8 and remove the comments.
 | 
					 | 
				
			||||||
    ensure_empty_folder(dest_folder)
 | 
					 | 
				
			||||||
    print_and_do('genstrings -o "{}" `find "{}" -name *.m | xargs`'.format(dest_folder, code_folder))
 | 
					 | 
				
			||||||
    for stringsfile in os.listdir(dest_folder):
 | 
					 | 
				
			||||||
        stringspath = op.join(dest_folder, stringsfile)
 | 
					 | 
				
			||||||
        with open(stringspath, "rt", encoding="utf-16") as fp:
 | 
					 | 
				
			||||||
            content = fp.read()
 | 
					 | 
				
			||||||
        content = re.sub(r"/\*.*?\*/", "", content)
 | 
					 | 
				
			||||||
        content = re.sub(r"\n{2,}", "\n", content)
 | 
					 | 
				
			||||||
        # I have no idea why, but genstrings seems to have problems with "%" character in strings
 | 
					 | 
				
			||||||
        # and inserts (number)$ after it. Find these bogus inserts and remove them.
 | 
					 | 
				
			||||||
        content = re.sub(r"%\d\$", "%", content)
 | 
					 | 
				
			||||||
        with open(stringspath, "wt", encoding="utf-8") as fp:
 | 
					 | 
				
			||||||
            fp.write(content)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def generate_cocoa_strings_from_xib(xib_folder):
 | 
					 | 
				
			||||||
    xibs = [op.join(xib_folder, fn) for fn in os.listdir(xib_folder) if fn.endswith(".xib")]
 | 
					 | 
				
			||||||
    for xib in xibs:
 | 
					 | 
				
			||||||
        dest = xib.replace(".xib", STRING_EXT)
 | 
					 | 
				
			||||||
        print_and_do("ibtool {} --generate-strings-file {}".format(xib, dest))
 | 
					 | 
				
			||||||
        print_and_do("iconv -f utf-16 -t utf-8 {0} | tee {0}".format(dest))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def localize_stringsfile(stringsfile, dest_root_folder):
 | 
					 | 
				
			||||||
    stringsfile_name = op.basename(stringsfile)
 | 
					 | 
				
			||||||
    for lang in get_langs("locale"):
 | 
					 | 
				
			||||||
        pofile = op.join("locale", lang, "LC_MESSAGES", "ui.po")
 | 
					 | 
				
			||||||
        cocoa_lang = PO2COCOA.get(lang, lang)
 | 
					 | 
				
			||||||
        dest_lproj = op.join(dest_root_folder, cocoa_lang + ".lproj")
 | 
					 | 
				
			||||||
        ensure_folder(dest_lproj)
 | 
					 | 
				
			||||||
        po2strings(pofile, stringsfile, op.join(dest_lproj, stringsfile_name))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def localize_all_stringsfiles(src_folder, dest_root_folder):
 | 
					 | 
				
			||||||
    stringsfiles = [op.join(src_folder, fn) for fn in os.listdir(src_folder) if fn.endswith(STRING_EXT)]
 | 
					 | 
				
			||||||
    for path in stringsfiles:
 | 
					 | 
				
			||||||
        localize_stringsfile(path, dest_root_folder)
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -129,18 +129,6 @@ def install_gettext_trans(base_folder, lang):
 | 
				
			|||||||
    installed_lang = lang
 | 
					    installed_lang = lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def install_gettext_trans_under_cocoa():
 | 
					 | 
				
			||||||
    from cocoa import proxy
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    res_folder = proxy.getResourcePath()
 | 
					 | 
				
			||||||
    base_folder = op.join(res_folder, "locale")
 | 
					 | 
				
			||||||
    current_lang = proxy.systemLang()
 | 
					 | 
				
			||||||
    install_gettext_trans(base_folder, current_lang)
 | 
					 | 
				
			||||||
    localename = get_locale_name(current_lang)
 | 
					 | 
				
			||||||
    if localename is not None:
 | 
					 | 
				
			||||||
        locale.setlocale(locale.LC_ALL, localename)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def install_gettext_trans_under_qt(base_folder, lang=None):
 | 
					def install_gettext_trans_under_qt(base_folder, lang=None):
 | 
				
			||||||
    # So, we install the gettext locale, great, but we also should try to install qt_*.qm if
 | 
					    # So, we install the gettext locale, great, but we also should try to install qt_*.qm if
 | 
				
			||||||
    # available so that strings that are inside Qt itself over which I have no control are in the
 | 
					    # available so that strings that are inside Qt itself over which I have no control are in the
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user