1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4# Copyright (C) 2011 Chris Dekter
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19import sys
20import re
21from collections import namedtuple
22import subprocess
23from pathlib import Path
24import warnings
25import shutil
26
27try:
28    from setuptools import setup
29except ImportError:
30    print("Autokey needs setuptools in order to build. Install it with your package"
31          "manager (python-setuptools) or via pip (pip install setuptools)")
32    sys.exit(1)
33else:
34    import setuptools.command.build_py
35
36if sys.version_info < (3, 5, 0):
37    print("Autokey requires Python 3.5 or later. You are using " + ".".join(map(str, sys.version_info[:3])))
38    sys.exit(1)
39
40
41AutoKeyData = namedtuple("AutoKeyData", ["version", "author", "author_email", "maintainer", "maintainer_email"])
42
43
44def extract_autokey_data() -> AutoKeyData:
45    source_file_name = "./lib/autokey/common.py"
46    with open(source_file_name, "r") as data_source_file:
47        source = data_source_file.read()
48    if not source:
49        print("Cannot read AutoKey source file containing required information. Unreadable: {}".format(
50            source_file_name))
51        sys.exit(1)
52
53    def search_for(pattern: str) -> str:
54        return re.search(
55            r"""^{}\s*=\s*('(.*)'|"(.*)")""".format(pattern),  # Search for assignments: VAR = 'VALUE' or VAR = "VALUE"
56            source,
57            re.M
58        ).group(1)[1:-1]  # Cut off outer quotation marks
59
60    return AutoKeyData(
61        version=search_for("VERSION"),
62        author=search_for("AUTHOR"),
63        author_email=search_for("AUTHOR_EMAIL"),
64        maintainer=search_for("MAINTAINER"),
65        maintainer_email=search_for("MAINTAINER_EMAIL")
66    )
67
68
69class BuildWithQtResources(setuptools.command.build_py.build_py):
70    """Try to build the Qt resources file for autokey-qt."""
71    def run(self):
72        if not self.dry_run:
73            resource_dir = (Path(__file__).parent / "lib" / "autokey" / "qtui" / "resources").resolve()
74            resource_file = resource_dir / "resources.qrc"
75            self._copy_icon_files_into_qt_resources_directory(resource_dir)
76            compiled_qt_resources = self._compile_resource_file(resource_file)
77            if compiled_qt_resources:
78                target_directory = Path(self.build_lib) / "autokey" / "qtui"
79                self.mkpath(str(target_directory))
80                with open(str(target_directory / "compiled_resources.py"), "w") as compiled_qt_resources_file:
81                    compiled_qt_resources_file.write(compiled_qt_resources)
82            else:
83                # If here, compilation failed for a known reason, so include the resource files directly.
84                # Ok, always include this for now. setup.py seems to not like this
85                # self.package_data["autokey.qtui"] += ["resources/icons/*", "resources/ui/*.ui"]
86                pass
87        super(BuildWithQtResources, self).run()
88
89    @staticmethod
90    def _compile_resource_file(resource_file: Path) -> str:
91        command = ("pyrcc5", str(resource_file))
92        try:
93            compiled = subprocess.check_output(command, universal_newlines=True)  # type: str
94        except (FileNotFoundError, subprocess.CalledProcessError) as e:
95            warnings.warn("An exception occurred during resource compilation for autokey-qt: {}".format(e))
96            return ""
97        else:
98            return compiled
99
100    def _copy_icon_files_into_qt_resources_directory(self, resource_dir: Path):
101        target_directory = resource_dir / "icons"
102        self.mkpath(str(target_directory))
103        icon_source_path = (Path(__file__).parent / "config").resolve()  # type: Path
104        for icon_name in (
105                "autokey.png",
106                "autokey.svg",
107                "autokey-status.svg",
108                "autokey-status-dark.svg",
109                "autokey-status-error.svg"):
110            icon = icon_source_path / icon_name
111            shutil.copy(str(icon), str(target_directory))
112
113
114ak_data = extract_autokey_data()
115
116setup(
117    name='autokey',
118    version=ak_data.version,
119    description='AutoKey (Python 3)',
120    author=ak_data.author,
121    author_email=ak_data.author_email,
122    maintainer=ak_data.maintainer,
123    maintainer_email=ak_data.maintainer_email,
124    url='https://github.com/autokey/autokey',
125    cmdclass={'build_py': BuildWithQtResources},
126    license='GPLv3',
127    packages=[
128        'autokey',
129        'autokey.iomediator',
130        'autokey.gtkui',
131        'autokey.qtui',
132        'autokey.qtui.dialogs',
133        'autokey.qtui.settings'
134    ],
135    package_dir={'': 'lib'},
136
137    package_data={'autokey.qtui': ['data/*', 'resources/icons/*', 'resources/ui/*.ui'],
138                  'autokey.gtkui': ['data/*']},
139    data_files=[('share/icons/hicolor/scalable/apps',
140                 ['config/autokey.svg',
141                  'config/autokey-status.svg',
142                  'config/autokey-status-dark.svg',
143                  'config/autokey-status-error.svg']),
144                ('share/icons/hicolor/96x96/apps',  # TODO: Remove later. https://github.com/autokey/autokey/issues/160
145                 ['config/autokey.png']),
146                ('share/icons/Humanity/scalable/apps',
147                 ['config/Humanity/autokey-status.svg',
148                  'config/Humanity/autokey-status-error.svg']),
149                ('share/icons/ubuntu-mono-dark/apps/48',
150                 ['config/ubuntu-mono-dark/autokey-status.svg',
151                  'config/ubuntu-mono-dark/autokey-status-error.svg']),
152                ('share/icons/ubuntu-mono-light/apps/48',
153                 ['config/ubuntu-mono-light/autokey-status.svg',
154                  'config/ubuntu-mono-light/autokey-status-error.svg']),
155                ('share/applications',
156                 ['config/autokey-qt.desktop',
157                  'config/autokey-gtk.desktop']),
158                ('man/man1/',
159                 ['doc/man/autokey-qt.1',
160                  'doc/man/autokey-gtk.1',
161                  'doc/man/autokey-run.1'])
162                ],
163    entry_points={
164        'console_scripts': [
165            'autokey-gtk=autokey.gtkui.__main__:main',
166            'autokey-qt=autokey.qtui.__main__:Application'
167        ]
168    },
169    scripts=['autokey-run', 'autokey-shell'],
170    install_requires=['pyinotify', 'python-xlib'],
171    classifiers=[
172        'Development Status :: 4 - Beta',
173        'Intended Audience :: Developers',
174        'Intended Audience :: End Users/Desktop',
175        'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
176        'Natural Language :: English',
177        'Operating System :: POSIX :: Linux',
178        'Programming Language :: Python :: 3.5',
179    ],
180)
181