From 66dc2e7ea7011ae63e1d404ebffeaa7782a7f2f5 Mon Sep 17 00:00:00 2001 From: Daniel Narvaez Date: Wed, 14 Nov 2012 15:32:49 +0000 Subject: Refactor check-system to use a devbot module This is necessary to be able to share code, all the commands will be gradually refactored to follow this pattern. --- (limited to 'devbot') diff --git a/devbot/__init__.py b/devbot/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/devbot/__init__.py diff --git a/devbot/config.py b/devbot/config.py new file mode 100644 index 0000000..b63c6e6 --- /dev/null +++ b/devbot/config.py @@ -0,0 +1,32 @@ +import json +import os + +from devbot import distro + +config_path = None + +def set_path(path): + global config_path + config_path = path + +def load_packages(): + packages = _load_deps_json("packages-%s" % distro.get_system_version()) + +def load_prerequisites(): + return _load_deps_json("prerequisites") + +def load_checks(): + version = distro.get_system_version() + + checks = [] + checks.extend(_load_deps_json("system")) + checks.extend(_load_deps_json("sugar-build")) + checks.extend(_load_deps_json("sugar-buildtime-%s" % version)) + checks.extend(_load_deps_json("sugar-runtime-%s" % version)) + + return checks + +def _load_deps_json(name): + path = os.path.join(config_path, "%s.json" % name) + return json.load(open(path)) + diff --git a/devbot/distro.py b/devbot/distro.py new file mode 100644 index 0000000..34f54bc --- /dev/null +++ b/devbot/distro.py @@ -0,0 +1,47 @@ +import subprocess + +def get_system_version(): + name, version = _get_distro_info() + if (name == "ubuntu" and version == "12.10") or \ + (name == "fedora" and version == "18"): + return "3.6" + else: + return "3.4" + +def get_distro_name(): + name, version = _get_distro_info() + return name + +def _get_distro_info(): + distro = "unsupported" + version = "unknown" + + # Fedora + try: + fedora_release = open("/etc/fedora-release").read().strip() + if fedora_release == "Fedora release 17 (Beefy Miracle)": + distro = "fedora" + version = "17" + elif fedora_release == "Fedora release 18 (Spherical Cow)": + distro = "fedora" + version = "18" + except IOError: + pass + + # Ubuntu + try: + distributor = subprocess.check_output(["lsb_release", "-si"]).strip() + release = subprocess.check_output(["lsb_release", "-sr"]).strip() + + if distributor == "Ubuntu" and release == "12.10": + distro = "ubuntu" + version = "12.10" + except OSError: + pass + + arch = subprocess.check_output(["uname", "-i"]).strip() + if arch not in ["i386", "i686", "x86_64"]: + distro = "unsupported" + version = "unknown" + + return distro, version diff --git a/devbot/system.py b/devbot/system.py new file mode 100644 index 0000000..e3e5d67 --- /dev/null +++ b/devbot/system.py @@ -0,0 +1,187 @@ +import json +import os +import subprocess +import sys + +from devbot import config +from devbot import distro + +devnull = open("/dev/null", "w") +xvfb_display = ":100" + +libdirs = ["lib", + "lib64", + "lib/x86_64-linux-gnu", + "lib/i386-linux-gnu"] + +def check_binary(check): + return subprocess.call(["which", check], + stdout=devnull, + stderr=subprocess.STDOUT) + +def check_pkgconfig(check): + return subprocess.call(["pkg-config", "--exists", check]) == 1 + +def check_python(check): + return subprocess.call(["python", "-c", check], + stdout=devnull, stderr=subprocess.STDOUT) == 1 + +def check_gtkmodule(check): + # Not sure we can do better than this, the gtkmodule stuff is private + missing = True + + for libdir in libdirs: + if os.path.exists("/usr/%s/gtk-2.0/modules/lib%s.so" % (libdir, check)): + missing = False + + return missing + +def check_include(check): + return not os.path.exists(os.path.join("/usr/include/", check)) + +def check_dbus(check): + return not os.path.exists("/usr/share/dbus-1/services/%s.service" % check) + +def check_metacity_theme(check): + return not os.path.exists("/usr/share/themes/%s/metacity-1/metacity-theme-3.xml" % check) + +def check_gstreamer(check): + missing = True + + for libdir in libdirs: + if os.path.exists("/usr/%s/gstreamer-0.10/libgst%s.so" % (libdir, check)): + missing = False + + return missing + +checkers = { "binary": check_binary, + "python": check_python, + "pkgconfig": check_pkgconfig, + "gtkmodule": check_gtkmodule, + "dbus": check_dbus, + "gstreamer": check_gstreamer, + "metacity-theme": check_metacity_theme, + "include": check_include } + +def run_with_sudo(args): + args_with_sudo = ["sudo"] + args_with_sudo.extend(args) + + print " ".join(args_with_sudo) + subprocess.call(args_with_sudo) + +def install_packages(distro_name, packages): + if "SUGAR_BUILDBOT" in os.environ: + print "Missing packages %s" % " ".join(packages) + sys.exit(1) + + print "Installing required system packages" + + if distro_name == "fedora": + args = ["yum", "install"] + elif distro_name == "ubuntu": + args = ["apt-get", "install"] + + args.extend(packages) + run_with_sudo(args) + +def load_deps_json(name): + path = os.path.join(scriptdir, "deps", "%s.json" % name) + return json.load(open(path)) + +def run_checks(distro_name, checks, packages): + failed_checks = [] + to_install = [] + + for check in checks: + checker = checkers[check["checker"]] + if checker(check["check"]): + check_name = check.get("check_name", check["check"]) + if distro_name in packages[check_name]: + package_list = packages[check_name][distro_name] + if not isinstance(package_list, list): + package_list = [package_list] + + for package in package_list: + # Might be none, if so skip on this distro_name + if package and package not in packages: + to_install.append(package) + else: + failed_checks.append(check) + + if to_install: + install_packages(distro_name, to_install) + + if failed_checks: + print "Failed checks\n" + else: + return True + + for check in failed_checks: + print "[%s] %s" % (check["checker"], check["check"]) + + return False + +def start_xvfb(): + xvfb_proc = subprocess.Popen(args=["Xvfb", xvfb_display], + stdout=devnull, + stderr=subprocess.STDOUT) + orig_display = os.environ.get("DISPLAY", None) + os.environ["DISPLAY"] = xvfb_display + + return (xvfb_proc, orig_display) + +def stop_xvfb(xvfb_proc, orig_display): + if orig_display: + os.environ["DISPLAY"] = xvfb_display + else: + del os.environ["DISPLAY"] + + xvfb_proc.terminate() + +def apply_ubuntu_tweaks(): + # FIXME we don't want the package to depend on external scripts + devbot_dir = os.path.abspath(os.path.dirname(__file__)) + scripts_dir = os.path.join(os.path.dirname(devbot_dir), "scripts") + + wrapper_config = open("/etc/X11/Xwrapper.config").read() + if "allowed_users=anybody" not in wrapper_config: + if "SUGAR_BUILDBOT" in os.environ: + print "\nPlease allow anybody to run the X server with \n" \ + " sudo dpkg-reconfigure x11-common" + else: + print "\nWe are going to allow anybody to run the X server" + ubuntu_tweaks = os.path.join(scripts_dir, "ubuntu-tweaks") + run_with_sudo([ubuntu_tweaks]) + +def apply_distro_tweaks(distro_name): + if distro_name == "ubuntu": + apply_ubuntu_tweaks() + +def warn_if_unsupported(distro_name): + if distro_name == "unsupported": + print "*********************************************************\n" \ + "You are running an unsupported distribution. You might be\n" \ + "able to make sugar work by installing or building \n" \ + "packages but it certainly won't work out of the box.\n" \ + "You are strongly encouraged to pick one of the supported \n" \ + "distributions listed in the README.\n" \ + "*********************************************************\n" + +def check(): + distro_name = distro.get_distro_name() + + packages = config.load_packages() + + checks = config.load_prerequisites() + if not run_checks(distro_name, checks, packages): + sys.exit(1) + + xvfb_proc, orig_display = start_xvfb() + + run_checks(distro_name, config.load_checks(), config.load_packages()) + + warn_if_unsupported(distro_name) + apply_distro_tweaks(distro_name) + + stop_xvfb(xvfb_proc, orig_display) -- cgit v0.9.1