Solving Sphinx dependencies can be painful. Add a script to check if everything is ok. Signed-off-by: Mauro Carvalho Chehab <mchehab@xxxxxxxxxxxxxxxx> --- v4: changed default to use virtualenv for Sphinx and add switches to change its behavior to disable PDF and virtualenv. v3: check for DeJavu fonts on Ubuntu and add "sudo" to Fedora instructions v2: add support for Fedora 26 scripts/sphinx-pre-install | 378 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100755 scripts/sphinx-pre-install diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install new file mode 100755 index 000000000000..b0ea74d2f745 --- /dev/null +++ b/scripts/sphinx-pre-install @@ -0,0 +1,378 @@ +#!/usr/bin/perl +use strict; + + + +# +# Static vars +# + +my @missing; +my @opt_missing; +my $system_release; +my $need = 0; +my $optional = 0; +my $need_symlink = 0; +my $need_sphinx = 0; +my $install = ""; + +# +# Command line arguments +# + +my $pdf = 1; +my $virtualenv = 1; + +# +# Subroutines that checks if a feature exists +# + +sub catcheck($) +{ + my $res = ""; + $res = qx(cat $_[0]) if (-r $_[0]); + return $res; +} + +sub check_missing(%) +{ + my %map = %{$_[0]}; + + foreach my $prog (@missing) { + print "ERROR: please install \"$prog\", otherwise, build won't work.\n"; + if (defined($map{$prog})) { + $install .= " " . $map{$prog}; + } else { + $install .= " " . $prog; + } + } + foreach my $prog (@opt_missing) { + print "Warning: better to also install \"$prog\".\n"; + if (defined($map{$prog})) { + $install .= " " . $map{$prog}; + } else { + $install .= " " . $prog; + } + } + + $install =~ s/^\s//; +} + +sub add_package($$) +{ + my $package = shift; + my $is_optional = shift; + + if ($is_optional) { + push @opt_missing, $package; + + $optional++; + } else { + push @missing, $package; + + $need++; + } +} + +sub check_missing_file($$$) +{ + my $file = shift; + my $package = shift; + my $is_optional = shift; + + return if(-e $file); + + add_package($package, $is_optional); +} + +sub findprog($) +{ + foreach(split(/:/, $ENV{PATH})) { + return "$_/$_[0]" if(-x "$_/$_[0]"); + } +} + +sub check_program($$) +{ + my $prog = shift; + my $is_optional = shift; + + return if findprog($prog); + + add_package($prog, $is_optional); +} + +sub check_perl_module($$) +{ + my $prog = shift; + my $is_optional = shift; + + my $err = system("perl -M$prog -e 1 2>/dev/null /dev/null"); + return if ($err == 0); + + add_package($prog, $is_optional); +} + +sub check_python_module($$) +{ + my $prog = shift; + my $is_optional = shift; + + my $err = system("python3 -c 'import $prog' 2>/dev/null /dev/null"); + return if ($err == 0); + my $err = system("python -c 'import $prog' 2>/dev/null /dev/null"); + return if ($err == 0); + + add_package($prog, $is_optional); +} + +sub check_sphinx() +{ + return if findprog("sphinx-build"); + + if (findprog("sphinx-build-3")) { + $need_symlink = 1; + return; + } + + if ($virtualenv) { + check_program("virtualenv", 0); + check_program("pip", 0); + $need_sphinx = 1; + } else { + add_package("python-sphinx", 0); + } +} + +sub which($) +{ + my $file = shift; + my @path = split ":", $ENV{PATH}; + + foreach my $dir(@path) { + my $name = $dir.'/'.$file; + return $name if (-x $name ); + } + return undef; +} + +# +# Subroutines that check distro-specific hints +# + +sub give_debian_hints() +{ + my %map = ( + "python-sphinx" => "python3-sphinx", + "sphinx_rtd_theme" => "python3-sphinx-rtd-theme", + "virtualenv" => "python3-virtualenv", + "pip" => "python3-pip", + "dot" => "graphviz", + "convert" => "imagemagick", + "Pod::Usage" => "perl-modules", + "xelatex" => "texlive-xetex", + ); + + if ($pdf) { + check_missing_file("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + "fonts-dejavu", 1); + } + + check_missing(\%map); + + return if (!$need && !$optional); + printf("You should run:\n\n\tsudo apt-get install $install\n"); +} + +sub give_redhat_hints() +{ + my %map = ( + "python-sphinx" => "python3-sphinx", + "sphinx_rtd_theme" => "python3-sphinx_rtd_theme", + "virtualenv" => "python3-virtualenv", + "pip" => "python3-pip", + "dot" => "graphviz", + "convert" => "ImageMagick", + "Pod::Usage" => "perl-Pod-Usage", + "xelatex" => "texlive-xetex-bin python-sphinx-latex.noarch", + ); + + if ($pdf) { + check_missing_file("/usr/share/licenses/python-sphinx-latex/LICENSE", + "python-sphinx-latex", 1); + check_missing_file("/usr/share/fonts/dejavu/DejaVuSans.ttf", + "dejavu-sans-fonts", 1); + check_missing_file("/usr/share/fonts/dejavu/DejaVuSerif.ttf", + "dejavu-serif-fonts", 1); + check_missing_file("/usr/share/fonts/dejavu/DejaVuSansMono.ttf", + "dejavu-sans-mono-fonts", 1); + check_missing_file("/usr/share/texlive/texmf-dist/tex/latex/adjustbox/adjustbox.sty", + "texlive-adjustbox", 1); + } + + check_missing(\%map); + + return if (!$need && !$optional); + printf("You should run:\n\n\tsudo dnf install -y $install\n"); +} + +sub give_opensuse_hints() +{ + my %map = ( + # FIXME: add hints for SUSE here + ); + + check_missing(\%map); + + return if (!$need && !$optional); + printf("You should run:\n\n\tsudo zypper install $install\n"); +} + +sub give_arch_linux_hints() +{ + my %map = ( + # FIXME: add hints for arch-linux here + ); + + check_missing(\%map); + + return if (!$need && !$optional); + printf("You should install those package(s) (repository/package): $install\n"); +} + +sub give_gentoo_hints() +{ + my %map = ( + # FIXME: add hints for Gentoo here + ); + + check_missing(\%map); + + return if (!$need && !$optional); + printf("You should emerge those package(s): $install\n"); +} + +sub check_distros() +{ + # Distro-specific hints + if ($system_release =~ /Red Hat Enterprise Linux/) { + give_redhat_hints; + return; + } + if ($system_release =~ /Fedora/) { + give_redhat_hints; + return; + } + if ($system_release =~ /Ubuntu/) { + give_debian_hints; + return; + } + if ($system_release =~ /Debian/) { + give_debian_hints; + return; + } + if ($system_release =~ /openSUSE/) { + give_opensuse_hints; + return; + } + if ($system_release =~ /Arch Linux/) { + give_arch_linux_hints; + return; + } + if ($system_release =~ /Gentoo/) { + give_gentoo_hints; + return; + } + # Fall-back to generic hint code + my %map = ( + "sphinx-build" => "sphinx" + ); + check_missing(\%map); + print "I don't know distro $system_release. So, I can't provide you a hint with the install procedure.\n"; +} + +# +# Common dependencies +# + +sub check_needs() +{ + if ($system_release) { + print "Checking if the needed tools for $system_release are available\n"; + } else { + print "Checking if the needed tools are present\n"; + } + + # Check for needed programs/tools + check_sphinx(); + check_perl_module("Pod::Usage", 0); + check_program("make", 0); + check_program("gcc", 0); + check_python_module("sphinx_rtd_theme", 1) if (!$virtualenv); + check_program("xelatex", 1) if ($pdf); + check_program("dot", 1); + check_program("convert", 1); + + check_distros(); + + if ($need_symlink) { + printf "\tsudo ln -sf %s /usr/bin/sphinx-build\n\n", + which("sphinx-build-3"); + } + if ($need_sphinx) { + printf "\tvirtualenv sphinx_1.4\n"; + printf "\t. sphinx_1.4/bin/activate\n"; + printf "\tpip install 'docutils==0.12'\n"; + printf "\tpip install 'Sphinx==1.4.9'\n"; + printf "\tpip install sphinx_rtd_theme\n"; + } + printf "\n"; + + print "All optional dependenties are met.\n" if (!$optional); + + if ($need == 1) { + die "Can't build as $need mandatory dependency is missing"; + } elsif ($need) { + die "Can't build as $need mandatory dependencies are missing"; + } + + print "Needed package dependencies are met.\n"; +} + +# +# Main +# + +while (@ARGV) { + my $arg = shift(@ARGV); + + if ($arg eq "--no-virtualenv") { + $virtualenv = 0; + } elsif ($arg eq "--no-pdf"){ + $pdf = 0; + } else { + print "Usage:\n\t$0 <--no-virtualenv> <--no-pdf>\n\n"; + exit -1; + } +} + +# +# Determine the system type. There's no standard unique way that would +# work with all distros with a minimal package install. So, several +# methods are used here. +# +# By default, it will use lsb_release function. If not available, it will +# fail back to reading the known different places where the distro name +# is stored +# + +$system_release = qx(lsb_release -d) if which("lsb_release"); +$system_release =~ s/Description:\s*// if ($system_release); +$system_release = catcheck("/etc/system-release") if !$system_release; +$system_release = catcheck("/etc/redhat-release") if !$system_release; +$system_release = catcheck("/etc/lsb-release") if !$system_release; +$system_release = catcheck("/etc/gentoo-release") if !$system_release; +$system_release = catcheck("/etc/issue") if !$system_release; +$system_release =~ s/\s+$//; + +check_needs; -- 2.13.0 -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html