X Tutup
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,14 @@ def run(self):
# Abort if any of the required packages can not be built.
if required_failed:
print_line()
print_message(
"The following required packages can not "
"be built: %s" %
', '.join(x.name for x in required_failed))
message = ("The following required packages can not "
"be built: %s" %
", ".join(x.name for x in required_failed))
for pkg in required_failed:
pkg_help = pkg.install_help_msg()
if pkg_help:
message += "\n* " + pkg_help
print_message(message)
sys.exit(1)

# Now collect all of the information we need to build all of the
Expand Down
75 changes: 75 additions & 0 deletions setupext.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import glob
import multiprocessing
import os
import platform
import re
import subprocess
from subprocess import check_output
Expand Down Expand Up @@ -412,6 +413,14 @@ class CheckFailed(Exception):

class SetupPackage(object):
optional = False
pkg_names = {
"apt-get": None,
"yum": None,
"dnf": None,
"brew": None,
"port": None,
"windows_url": None
}

def check(self):
"""
Expand Down Expand Up @@ -531,6 +540,56 @@ def do_custom_build(self):
"""
pass

def install_help_msg(self):
"""
Do not override this method !

Generate the help message to show if the package is not installed.
To use this in subclasses, simply add the dictionary `pkg_names` as
a class variable:

pkg_names = {
"apt-get": <Name of the apt-get package>,
"yum": <Name of the yum package>,
"dnf": <Name of the dnf package>,
"brew": <Name of the brew package>,
"port": <Name of the port package>,
"windows_url": <The url which has installation instructions>
}

All the dictionary keys are optional. If a key is not present or has
the value `None` no message is provided for that platform.
"""
def _try_managers(*managers):
for manager in managers:
pkg_name = self.pkg_names.get(manager, None)
if pkg_name:
try:
# `shutil.which()` can be used when Python 2.7 support
# is dropped. It is available in Python 3.3+
_ = check_output(["which", manager],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a shutil.which, but unfortunately, it's 3.3+. It's probably not worth it to conditionally call it, but can you add a comment about switching to it when we drop 2.7?

stderr=subprocess.STDOUT)
return ('Try installing {0} with `{1} install {2}`'
.format(self.name, manager, pkg_name))
except subprocess.CalledProcessError:
pass

message = None
if sys.platform == "win32":
url = self.pkg_names.get("windows_url", None)
if url:
message = ('Please check {0} for instructions to install {1}'
.format(url, self.name))
elif sys.platform == "darwin":
message = _try_managers("brew", "port")
elif sys.platform.startswith("linux"):
release = platform.linux_distribution()[0].lower()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a note I wanted to mention here. platform.linux_distribution() is deprecated in Py 3.5 and is planned to be removed in Py 3.7. The related bug can be found at https://bugs.python.org/issue1322

I found the package https://pypi.python.org/pypi/distro which makes a pypi package out of this, but I am not sure of a good way to install this to use it in the setup.py. Suggestions ? (setup_requires is meant for this, but it's known to be buggy IIRC)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a 'fun' bug report.

if release in ('debian', 'ubuntu'):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this do on Debian/Ubuntu derivatives like Linux Mint?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The supported distros in that function are:


_supported_dists = (
    'SuSE', 'debian', 'fedora', 'redhat', 'centos',
    'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
    'UnitedLinux', 'turbolinux')

If this is run on a non-supported distro, it returns empty strings ("", "", "").

There are also some issues with Ubuntu btw ... Some Ubuntu systems are detected as "debian" - http://bugs.python.org/issue9514

message = _try_managers('apt-get')
elif release in ('centos', 'redhat', 'fedora'):
message = _try_managers('dnf', 'yum')
return message

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need two blank lines between classes.


class OptionalPackage(SetupPackage):
optional = True
Expand Down Expand Up @@ -953,6 +1012,14 @@ def add_flags(self, ext, add_sources=True):

class FreeType(SetupPackage):
name = "freetype"
pkg_names = {
"apt-get": "libfreetype6-dev",
"yum": "freetype-devel",
"dnf": "freetype-devel",
"brew": "freetype",
"port": "freetype",
"windows_url": "http://gnuwin32.sourceforge.net/packages/freetype.htm"
}

def check(self):
if options.get('local_freetype'):
Expand Down Expand Up @@ -1167,6 +1234,14 @@ def get_extension(self):

class Png(SetupPackage):
name = "png"
pkg_names = {
"apt-get": "libpng12-dev",
"yum": "libpng-devel",
"dnf": "libpng-devel",
"brew": "libpng",
"port": "libpng",
"windows_url": "http://gnuwin32.sourceforge.net/packages/libpng.htm"
}

def check(self):
if sys.platform == 'win32':
Expand Down
X Tutup