diff --git a/build.py b/build.py new file mode 100755 index 0000000000000000000000000000000000000000..1e86313433a95771288d412078a336d72442c811 --- /dev/null +++ b/build.py @@ -0,0 +1,654 @@ +#!/usr/bin/env python3 +# +# This is the Ring build helper, it can do these things: +# - Build Ring +# - Install Ring +# - Run Ring +# + +import argparse +import os +import subprocess +import sys +import time +import platform +import multiprocessing +import shlex +import shutil +import signal + +IOS_DISTRIBUTION_NAME = "ios" +OSX_DISTRIBUTION_NAME = "osx" +ANDROID_DISTRIBUTION_NAME = "android" +WIN32_DISTRIBUTION_NAME = "win32" + +QT5_VERSION = "5.15.0" + +# vs vars +win_sdk_default = '10.0.16299.0' +win_toolset_default = '142' + +APT_BASED_DISTROS = [ + 'debian', + 'ubuntu', + 'trisquel', + 'linuxmint', + 'raspbian', +] + +DNF_BASED_DISTROS = [ + 'fedora', 'rhel', +] + +PACMAN_BASED_DISTROS = [ + 'arch', +] + +ZYPPER_BASED_DISTROS = [ + 'opensuse-leap', 'opensuse-tumbleweed', +] + +FLATPAK_BASED_RUNTIMES = [ + 'org.gnome.Platform', +] + +APT_INSTALL_SCRIPT = [ + 'apt-get update', + 'apt-get install -y %(packages)s' +] + +BREW_UNLINK_SCRIPT = [ + 'brew unlink %(packages)s' +] + +BREW_INSTALL_SCRIPT = [ + 'brew update', + 'brew install %(packages)s', + 'brew link --force --overwrite %(packages)s' +] + +RPM_INSTALL_SCRIPT = [ + 'dnf update', + 'dnf install -y %(packages)s' +] + +PACMAN_INSTALL_SCRIPT = [ + 'pacman -Sy', + 'pacman -S --asdeps --needed %(packages)s' +] + +ZYPPER_INSTALL_SCRIPT = [ + 'zypper update', + 'zypper install -y %(packages)s' +] + +ZYPPER_DEPENDENCIES = [ + # build system + 'autoconf', 'autoconf-archive', 'automake', 'cmake', 'make', 'patch', 'gcc-c++', + 'libtool', 'which', 'pandoc','nasm', 'doxygen', 'graphviz', + # contrib dependencies + 'curl', 'gzip', 'bzip2', + # daemon + 'speexdsp-devel', 'speex-devel', 'libdbus-c++-devel', 'jsoncpp-devel', 'yaml-cpp-devel', + 'yasm', 'libuuid-devel', 'libnettle-devel', 'libopus-devel', 'libexpat-devel', + 'libgnutls-devel', 'msgpack-devel', 'libavcodec-devel', 'libavdevice-devel', 'pcre-devel', + 'alsa-devel', 'libpulse-devel', 'libudev-devel', 'libva-devel', 'libvdpau-devel', + 'libopenssl-devel', 'libavutil-devel', + # lrc + 'libQt5Core-devel', 'libQt5DBus-devel', 'libqt5-linguist-devel', + # client gnome / qt + 'qrencode-devel', 'NetworkManager-devel' +] + +ZYPPER_CLIENT_GNOME_DEPENDENCIES = [ + 'gtk3-devel', 'clutter-gtk-devel', 'gettext-tools', 'libnotify-devel', 'libappindicator3-devel', + 'webkit2gtk3-devel', 'libcanberra-gtk3-devel' +] + +ZYPPER_CLIENT_QT_DEPENDENCIES = [ + 'libqt5-qtsvg-devel', 'libqt5-qtwebengine-devel', 'libqt5-qtmultimedia-devel', + 'libqt5-qtdeclarative-devel', 'libQt5QuickControls2-devel', 'libqt5-qtquickcontrols' +] + +DNF_DEPENDENCIES = [ + 'autoconf', 'autoconf-archive', 'automake', 'cmake', 'make', 'speexdsp-devel', 'pulseaudio-libs-devel', + 'libtool', 'dbus-devel', 'expat-devel', 'pcre-devel', 'doxygen', 'graphviz', + 'yaml-cpp-devel', 'boost-devel', 'dbus-c++-devel', 'dbus-devel', + 'libXext-devel', 'libXfixes-devel', 'yasm', + 'speex-devel', 'chrpath', 'check', 'astyle', 'uuid-c++-devel', 'gettext-devel', + 'gcc-c++', 'which', 'alsa-lib-devel', 'systemd-devel', 'libuuid-devel', + 'uuid-devel', 'gnutls-devel', 'nettle-devel', 'opus-devel', 'speexdsp-devel', + 'yaml-cpp-devel', 'qt5-qtbase-devel', 'swig', 'jsoncpp-devel', + 'patch', 'libva-devel', 'openssl-devel', 'libvdpau-devel', 'msgpack-devel', + 'sqlite-devel', 'openssl-static', 'pandoc', 'nasm', 'qrencode-devel', 'NetworkManager-libnm-devel', + 'bzip2' +] + +DNF_CLIENT_GNOME_DEPENDENCIES = [ + 'gtk3-devel', 'clutter-devel', 'clutter-gtk-devel', 'libnotify-devel','libappindicator-gtk3-devel', + 'webkitgtk4-devel', 'libcanberra-devel' +] + +DNF_CLIENT_QT_DEPENDENCIES = [ + 'qt5-qtsvg-devel', 'qt5-qtwebengine-devel', 'qt5-qtmultimedia-devel', 'qt5-qtdeclarative-devel', + 'qt5-qtquickcontrols2-devel', 'qt5-qtquickcontrols' +] + +APT_DEPENDENCIES = [ + 'autoconf', 'autoconf-archive', 'autopoint', 'automake', 'cmake', 'make', 'dbus', 'doxygen', 'graphviz', + 'g++', 'gettext', 'gnome-icon-theme-symbolic', 'libasound2-dev', 'libavcodec-dev', + 'libavdevice-dev', 'libavformat-dev', 'libboost-dev', + 'libclutter-gtk-1.0-dev', 'libcppunit-dev', 'libdbus-1-dev', + 'libdbus-c++-dev', 'libebook1.2-dev', 'libexpat1-dev', 'libgnutls28-dev', + 'libgtk-3-dev', 'libjack-dev', 'libnotify-dev', + 'libopus-dev', 'libpcre3-dev', 'libpulse-dev', 'libssl-dev', + 'libspeex-dev', 'libspeexdsp-dev', 'libswscale-dev', 'libtool', + 'libudev-dev', 'libyaml-cpp-dev', 'qtbase5-dev', 'libqt5sql5-sqlite', 'sip-tester', 'swig', + 'uuid-dev', 'yasm', 'libjsoncpp-dev', 'libva-dev', 'libvdpau-dev', 'libmsgpack-dev', + 'pandoc', 'nasm', 'libqrencode-dev', 'libnm-dev', 'dpkg-dev' +] + +APT_CLIENT_GNOME_DEPENDENCIES = [ + 'libwebkit2gtk-4.0-dev', 'libappindicator3-dev', 'libcanberra-gtk3-dev' +] + +APT_CLIENT_QT_DEPENDENCIES = [ + 'qtmultimedia5-dev', 'libqt5svg5-dev', 'qtwebengine5-dev', 'qtdeclarative5-dev', + 'qtquickcontrols2-5-dev', 'qml-module-qtquick2', 'qml-module-qtquick-controls', + 'qml-module-qtquick-controls2', 'qml-module-qtquick-dialogs', + 'qml-module-qtquick-layouts', 'qml-module-qtquick-privatewidgets', + 'qml-module-qtquick-shapes', 'qml-module-qtquick-window2', + 'qml-module-qtquick-templates2', 'qml-module-qt-labs-platform', + 'qml-module-qtwebengine', 'qml-module-qtwebchannel' +] + +PACMAN_DEPENDENCIES = [ + 'autoconf', 'autoconf-archive', 'gettext', 'cmake', 'dbus', 'doxygen', 'graphviz', + 'gcc', 'ffmpeg', 'boost', 'cppunit', 'libdbus', 'dbus-c++', 'libe-book', 'expat', + 'jack', 'opus', 'pcre', 'libpulse', 'speex', 'speexdsp', 'libtool', 'yaml-cpp', + 'qt5-base', 'swig', 'yasm', 'qrencode', 'make', 'patch', 'pkg-config', + 'automake', 'libva', 'libnm', 'libvdpau', 'openssl', 'pandoc', 'nasm' +] + +PACMAN_CLIENT_GNOME_DEPENDENCIES = [ + 'clutter-gtk','gnome-icon-theme-symbolic', 'gtk3', 'libappindicator-gtk3', + 'libcanberra', 'libnotify', 'webkit2gtk' +] + +PACMAN_CLIENT_QT_DEPENDENCIES = [ + 'qt5-declarative', 'qt5-graphicaleffects', 'qt5-multimedia', 'qt5-quickcontrols', + 'qt5-quickcontrols2', 'qt5-svg', 'qt5-tools', 'qt5-webengine' +] + +OSX_DEPENDENCIES = [ + 'autoconf', 'cmake', 'gettext', 'pkg-config', 'qt5', + 'libtool', 'yasm', 'nasm', 'automake' +] + +OSX_DEPENDENCIES_UNLINK = [ + 'autoconf*', 'cmake*', 'gettext*', 'pkg-config*', 'qt*', 'qt@5.*', + 'libtool*', 'yasm*', 'nasm*', 'automake*', 'gnutls*', 'nettle*', 'msgpack*' +] + +IOS_DEPENDENCIES = [ + 'autoconf', 'automake', 'cmake', 'yasm', 'libtool', + 'pkg-config', 'gettext', 'swiftlint', 'swiftgen' +] + +IOS_DEPENDENCIES_UNLINK = [ + 'autoconf*', 'automake*', 'cmake*', 'yasm*', 'libtool*', + 'pkg-config*', 'gettext*', 'swiftlint*', 'swiftgen*' +] + +UNINSTALL_DAEMON_SCRIPT = [ + 'make -C daemon uninstall' +] + +OSX_UNINSTALL_SCRIPT = [ + 'make -C daemon uninstall', + 'rm -rf install/client-macosx' +] + +def run_powersell_cmd(cmd): + p = subprocess.Popen(["powershell.exe", cmd], stdout=sys.stdout) + p.communicate() + p.wait() + return + + +def write_qt_conf(path, qt5version=QT5_VERSION): + # Add a configuration that can be supplied to qmake + # e.g. `qmake -qt=5.15 [mode] [options] [files]` + if path == '': + return + with open('/usr/share/qtchooser/' + qt5version + '.conf', 'w+') as fd: + fd.write(path.rstrip('/') + '/bin\n') + fd.write(path.rstrip('/') + '/lib\n') + return + + +def run_dependencies(args): + if args.qt is not None: + write_qt_conf(args.qt, args.qtver) + + if args.distribution == WIN32_DISTRIBUTION_NAME: + run_powersell_cmd( + 'Set-ExecutionPolicy Unrestricted; .\\scripts\\install-deps-windows.ps1') + + elif args.distribution in APT_BASED_DISTROS: + if args.qt is None: + APT_DEPENDENCIES.extend(APT_CLIENT_GNOME_DEPENDENCIES) + else: + APT_DEPENDENCIES.extend(APT_CLIENT_QT_DEPENDENCIES) + execute_script( + APT_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, APT_DEPENDENCIES))} + ) + + elif args.distribution in DNF_BASED_DISTROS: + if args.qt is None: + DNF_DEPENDENCIES.extend(DNF_CLIENT_GNOME_DEPENDENCIES) + else: + DNF_DEPENDENCIES.extend(DNF_CLIENT_QT_DEPENDENCIES) + execute_script( + RPM_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, DNF_DEPENDENCIES))} + ) + + elif args.distribution in PACMAN_BASED_DISTROS: + if args.qt is None: + PACMAN_DEPENDENCIES.extend(PACMAN_CLIENT_GNOME_DEPENDENCIES) + else: + PACMAN_DEPENDENCIES.extend(PACMAN_CLIENT_QT_DEPENDENCIES) + execute_script( + PACMAN_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, PACMAN_DEPENDENCIES))} + ) + + elif args.distribution in ZYPPER_BASED_DISTROS: + if args.qt is None: + ZYPPER_DEPENDENCIES.extend(ZYPPER_CLIENT_GNOME_DEPENDENCIES) + else: + ZYPPER_DEPENDENCIES.extend(ZYPPER_CLIENT_QT_DEPENDENCIES) + execute_script( + ZYPPER_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, ZYPPER_DEPENDENCIES))} + ) + + elif args.distribution == OSX_DISTRIBUTION_NAME: + execute_script( + BREW_UNLINK_SCRIPT, + {"packages": ' '.join(map(shlex.quote, OSX_DEPENDENCIES_UNLINK))}, + False + ) + execute_script( + BREW_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, OSX_DEPENDENCIES))}, + False + ) + + elif args.distribution == IOS_DISTRIBUTION_NAME: + execute_script( + BREW_UNLINK_SCRIPT, + {"packages": ' '.join(map(shlex.quote, IOS_DEPENDENCIES_UNLINK))}, + False + ) + execute_script( + BREW_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, IOS_DEPENDENCIES))}, + False + ) + + elif args.distribution == ANDROID_DISTRIBUTION_NAME: + print("The Android version does not need more dependencies.\nPlease continue with the --install instruction.") + sys.exit(1) + + elif args.distribution == WIN32_DISTRIBUTION_NAME: + print("The win32 version does not install dependencies with this script.\nPlease continue with the --install instruction.") + sys.exit(1) + + else: + print("Not yet implemented for current distribution (%s). Please continue with the --install instruction. Note: You may need to install some dependencies manually." % + args.distribution) + sys.exit(1) + + +def run_init(): + # Extract modules path from '.gitmodules' file + module_names = [] + with open('.gitmodules') as fd: + for line in fd.readlines(): + if line.startswith('[submodule "'): + module_names.append(line[line.find('"')+1:line.rfind('"')]) + + subprocess.run(["git", "submodule", "update", "--init"], check=True) + subprocess.run(["git", "submodule", "foreach", + "git checkout master && git pull"], check=True) + for name in module_names: + copy_file("./scripts/commit-msg", ".git/modules/"+name+"/hooks") + + module_names_to_format = ['daemon', 'lrc', 'client-qt', 'plugins'] + for name in module_names_to_format: + execute_script( + ['./scripts/format.sh --install %(path)s'], + {"path": ".git/modules/" + name + "/hooks"} + ) + + +def copy_file(src, dest): + print("Copying:" + src + " to " + dest) + try: + shutil.copy2(src, dest) + # eg. src and dest are the same file + except shutil.Error as e: + print('Error: %s' % e) + # eg. source or destination doesn't exist + except IOError as e: + print('Error: %s' % e.strerror) + + +def run_install(args): + # Platforms with special compilation scripts + if args.distribution == IOS_DISTRIBUTION_NAME: + return subprocess.run(["./compile-ios.sh"], cwd="./client-ios", check=True) + elif args.distribution == ANDROID_DISTRIBUTION_NAME: + return subprocess.run(["./compile.sh"], cwd="./client-android", check=True) + elif args.distribution == WIN32_DISTRIBUTION_NAME: + return subprocess.run([ + sys.executable, os.path.join( + os.getcwd(), "scripts/build-windows.py"), + "--toolset", args.toolset, + "--sdk", args.sdk, + "--qtver", args.qtver + ], check=True) + + # Unix-like platforms + environ = os.environ.copy() + + install_args = ['-p', str(multiprocessing.cpu_count())] + if args.static: + install_args.append('-s') + if args.global_install: + install_args.append('-g') + if args.prefix is not None: + install_args += ('-P', args.prefix) + if not args.priv_install: + install_args.append('-u') + + if args.distribution == OSX_DISTRIBUTION_NAME: + # The `universal_newlines` parameter has been renamed to `text` in + # Python 3.7+ and triggering automatical binary to text conversion is + # what it actually does + proc = subprocess.run(["brew", "--prefix", "qt5"], + stdout=subprocess.PIPE, check=True, + universal_newlines=True) + + environ['CMAKE_PREFIX_PATH'] = proc.stdout.rstrip("\n") + environ['CONFIGURE_FLAGS'] = '--without-dbus' + install_args += ("-c", "client-macosx") + else: + if args.distribution in ZYPPER_BASED_DISTROS: + # fix jsoncpp pkg-config bug, remove when jsoncpp package bumped + environ['JSONCPP_LIBS'] = "-ljsoncpp" + if args.qt is None: + install_args += ("-c", "client-gnome") + else: + install_args += ("-c", "client-qt") + install_args += ("-q", args.qtver) + install_args += ("-Q", args.qt) + + return subprocess.run(["./scripts/install.sh"] + install_args, env=environ, check=True) + + +def run_uninstall(args): + if args.distribution == OSX_DISTRIBUTION_NAME: + execute_script(OSX_UNINSTALL_SCRIPT) + else: + execute_script(UNINSTALL_DAEMON_SCRIPT) + + CLIENT_SUFFIX = 'qt' if (args.qt is not None) else 'gnome' + INSTALL_DIR = '/build-global' if args.global_install else '/build-local' + + # Client needs to be uninstalled first + if (os.path.exists('./client-' + CLIENT_SUFFIX + INSTALL_DIR)): + UNINSTALL_CLIENT = [ + 'make -C client-' + CLIENT_SUFFIX + INSTALL_DIR + ' uninstall', + 'rm -rf ./client-' + CLIENT_SUFFIX + INSTALL_DIR + ] + execute_script(UNINSTALL_CLIENT) + + if (os.path.exists('./lrc' + INSTALL_DIR)): + UNINSTALL_LRC = [ + 'make -C lrc' + INSTALL_DIR + ' uninstall', + 'rm -rf ./lrc' + INSTALL_DIR + ] + execute_script(UNINSTALL_LRC) + +def run_run(args): + if args.distribution == OSX_DISTRIBUTION_NAME: + subprocess.Popen( + ["install/client-macosx/Ring.app/Contents/MacOS/Ring"]) + return True + + run_env = os.environ + run_env['LD_LIBRARY_PATH'] = run_env.get( + 'LD_LIBRARY_PATH', '') + ":install/lrc/lib" + + try: + dring_log = open("daemon.log", 'a') + dring_log.write('=== Starting daemon (%s) ===' % + time.strftime("%d/%m/%Y %H:%M:%S")) + dring_process = subprocess.Popen( + ["./install/daemon/lib/ring/dring", "-c", "-d"], + stdout=dring_log, + stderr=dring_log + ) + + with open('daemon.pid', 'w') as f: + f.write(str(dring_process.pid)+'\n') + + client_suffix = "" + if args.qt is not None: + client_suffix += "qt" + else: + client_suffix += "gnome" + client_log = open("jami-" + client_suffix + ".log", 'a') + client_log.write('=== Starting client (%s) ===' % + time.strftime("%d/%m/%Y %H:%M:%S")) + client_process = subprocess.Popen( + ["./install/client-" + client_suffix + + "/bin/jami-" + client_suffix, "-d"], + stdout=client_log, + stderr=client_log, + env=run_env + ) + + with open("jami-" + client_suffix + ".pid", 'w') as f: + f.write(str(client_process.pid)+'\n') + + if args.debug: + subprocess.call( + ['gdb', '-x', 'gdb.gdb', './install/daemon/lib/ring/dring'], + ) + + if args.background == False: + dring_process.wait() + client_process.wait() + + except KeyboardInterrupt: + print("\nCaught KeyboardInterrupt...") + + finally: + if args.background == False: + try: + # Only kill the processes if they are running, as they could + # have been closed by the user. + print("Killing processes...") + dring_log.close() + if dring_process.poll() is None: + dring_process.kill() + client_log.close() + if client_process.poll() is None: + client_process.kill() + except UnboundLocalError: + # Its okay! We crashed before we could start a process or open a + # file. All that matters is that we close files and kill processes + # in the right order. + pass + return True + + +def run_stop(args): + client_suffix = "qt" if (args.qt is not None) else "gnome" + STOP_SCRIPT = [ + 'xargs kill < daemon.pid', + 'xargs kill < jami-' + client_suffix + '.pid' + ] + execute_script(STOP_SCRIPT) + + +def execute_script(script, settings=None, fail=True): + if settings == None: + settings = {} + for line in script: + line = line % settings + rv = os.system(line) + if rv != 0 and fail == True: + print('Error executing script! Exit code: %s' % + rv, file=sys.stderr) + sys.exit(1) + + +def validate_args(parsed_args): + """Validate the args values, exit if error is found""" + + # Filter unsupported distributions. + supported_distros = [ + ANDROID_DISTRIBUTION_NAME, OSX_DISTRIBUTION_NAME, IOS_DISTRIBUTION_NAME, + WIN32_DISTRIBUTION_NAME + ] + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS \ + + ZYPPER_BASED_DISTROS + FLATPAK_BASED_RUNTIMES + + if parsed_args.distribution not in supported_distros: + print('WARNING: Distribution \'{0}\' not supported.\nChoose one of: {1}'.format( + parsed_args.distribution, ', '.join(supported_distros) + ), file=sys.stderr) + + # The Qt client support will be added incrementally. + if parsed_args.qt is not None: + supported_qt_distros = [ + WIN32_DISTRIBUTION_NAME + ] + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS + + if parsed_args.distribution not in supported_qt_distros: + print('Distribution \'{0}\' not supported when building the Qt client.' + '\nChoose one of: {1}'.format( + parsed_args.distribution, ', '.join(supported_qt_distros) + ), file=sys.stderr) + sys.exit(1) + + # The windows client can only be built on a Windows 10 host. + if parsed_args.distribution == WIN32_DISTRIBUTION_NAME: + if platform.release() != '10': + print('Windows version must be built on Windows 10') + sys.exit(1) + + +def parse_args(): + ap = argparse.ArgumentParser(description="Ring build tool") + + ga = ap.add_mutually_exclusive_group(required=True) + ga.add_argument( + '--init', action='store_true', + help='Init Ring repository') + ga.add_argument( + '--dependencies', action='store_true', + help='Install ring build dependencies') + ga.add_argument( + '--install', action='store_true', + help='Build and install Ring') + ga.add_argument( + '--uninstall', action='store_true', + help='Uninstall Ring') + ga.add_argument( + '--run', action='store_true', + help='Run the Ring daemon and client') + ga.add_argument( + '--stop', action='store_true', + help='Stop the Ring processes') + + ap.add_argument('--distribution') + ap.add_argument('--prefix') + ap.add_argument('--static', default=False, action='store_true') + ap.add_argument('--global-install', default=False, action='store_true') + ap.add_argument('--debug', default=False, action='store_true') + ap.add_argument('--background', default=False, action='store_true') + ap.add_argument('--no-priv-install', dest='priv_install', + default=True, action='store_false') + ap.add_argument('--qt', nargs='?', const='', type=str, + help='Build the Qt client with the Qt path supplied') + ap.add_argument('--qtver', default=QT5_VERSION, + help='Sets the Qt version to build with') + + dist = choose_distribution() + if dist == WIN32_DISTRIBUTION_NAME: + ap.add_argument('--toolset', default=win_toolset_default, type=str, + help='Windows use only, specify Visual Studio toolset version') + ap.add_argument('--sdk', default=win_sdk_default, type=str, + help='Windows use only, specify Windows SDK version') + + parsed_args = ap.parse_args() + + if (parsed_args.distribution is not None): + parsed_args.distribution = parsed_args.distribution.lower() + else: + parsed_args.distribution = dist + + validate_args(parsed_args) + + return parsed_args + + +def choose_distribution(): + system = platform.system().lower() + + if system == "linux" or system == "linux2": + if os.path.isfile("/etc/arch-release"): + return "arch" + with open("/etc/os-release") as f: + for line in f: + k, v = line.split("=") + if k.strip() == 'ID': + return v.strip().replace('"', '').split(' ')[0] + elif system == "darwin": + return OSX_DISTRIBUTION_NAME + elif system == "windows": + return WIN32_DISTRIBUTION_NAME + + return 'Unknown' + + +def main(): + parsed_args = parse_args() + + if parsed_args.dependencies: + run_dependencies(parsed_args) + + elif parsed_args.init: + run_init() + + elif parsed_args.install: + run_install(parsed_args) + + elif parsed_args.uninstall: + run_uninstall(parsed_args) + + elif parsed_args.run: + run_run(parsed_args) + + elif parsed_args.stop: + run_stop(parsed_args) + + +if __name__ == "__main__": + main() diff --git a/make-ring.py b/make-ring.py deleted file mode 100755 index 1e86313433a95771288d412078a336d72442c811..0000000000000000000000000000000000000000 --- a/make-ring.py +++ /dev/null @@ -1,654 +0,0 @@ -#!/usr/bin/env python3 -# -# This is the Ring build helper, it can do these things: -# - Build Ring -# - Install Ring -# - Run Ring -# - -import argparse -import os -import subprocess -import sys -import time -import platform -import multiprocessing -import shlex -import shutil -import signal - -IOS_DISTRIBUTION_NAME = "ios" -OSX_DISTRIBUTION_NAME = "osx" -ANDROID_DISTRIBUTION_NAME = "android" -WIN32_DISTRIBUTION_NAME = "win32" - -QT5_VERSION = "5.15.0" - -# vs vars -win_sdk_default = '10.0.16299.0' -win_toolset_default = '142' - -APT_BASED_DISTROS = [ - 'debian', - 'ubuntu', - 'trisquel', - 'linuxmint', - 'raspbian', -] - -DNF_BASED_DISTROS = [ - 'fedora', 'rhel', -] - -PACMAN_BASED_DISTROS = [ - 'arch', -] - -ZYPPER_BASED_DISTROS = [ - 'opensuse-leap', 'opensuse-tumbleweed', -] - -FLATPAK_BASED_RUNTIMES = [ - 'org.gnome.Platform', -] - -APT_INSTALL_SCRIPT = [ - 'apt-get update', - 'apt-get install -y %(packages)s' -] - -BREW_UNLINK_SCRIPT = [ - 'brew unlink %(packages)s' -] - -BREW_INSTALL_SCRIPT = [ - 'brew update', - 'brew install %(packages)s', - 'brew link --force --overwrite %(packages)s' -] - -RPM_INSTALL_SCRIPT = [ - 'dnf update', - 'dnf install -y %(packages)s' -] - -PACMAN_INSTALL_SCRIPT = [ - 'pacman -Sy', - 'pacman -S --asdeps --needed %(packages)s' -] - -ZYPPER_INSTALL_SCRIPT = [ - 'zypper update', - 'zypper install -y %(packages)s' -] - -ZYPPER_DEPENDENCIES = [ - # build system - 'autoconf', 'autoconf-archive', 'automake', 'cmake', 'make', 'patch', 'gcc-c++', - 'libtool', 'which', 'pandoc','nasm', 'doxygen', 'graphviz', - # contrib dependencies - 'curl', 'gzip', 'bzip2', - # daemon - 'speexdsp-devel', 'speex-devel', 'libdbus-c++-devel', 'jsoncpp-devel', 'yaml-cpp-devel', - 'yasm', 'libuuid-devel', 'libnettle-devel', 'libopus-devel', 'libexpat-devel', - 'libgnutls-devel', 'msgpack-devel', 'libavcodec-devel', 'libavdevice-devel', 'pcre-devel', - 'alsa-devel', 'libpulse-devel', 'libudev-devel', 'libva-devel', 'libvdpau-devel', - 'libopenssl-devel', 'libavutil-devel', - # lrc - 'libQt5Core-devel', 'libQt5DBus-devel', 'libqt5-linguist-devel', - # client gnome / qt - 'qrencode-devel', 'NetworkManager-devel' -] - -ZYPPER_CLIENT_GNOME_DEPENDENCIES = [ - 'gtk3-devel', 'clutter-gtk-devel', 'gettext-tools', 'libnotify-devel', 'libappindicator3-devel', - 'webkit2gtk3-devel', 'libcanberra-gtk3-devel' -] - -ZYPPER_CLIENT_QT_DEPENDENCIES = [ - 'libqt5-qtsvg-devel', 'libqt5-qtwebengine-devel', 'libqt5-qtmultimedia-devel', - 'libqt5-qtdeclarative-devel', 'libQt5QuickControls2-devel', 'libqt5-qtquickcontrols' -] - -DNF_DEPENDENCIES = [ - 'autoconf', 'autoconf-archive', 'automake', 'cmake', 'make', 'speexdsp-devel', 'pulseaudio-libs-devel', - 'libtool', 'dbus-devel', 'expat-devel', 'pcre-devel', 'doxygen', 'graphviz', - 'yaml-cpp-devel', 'boost-devel', 'dbus-c++-devel', 'dbus-devel', - 'libXext-devel', 'libXfixes-devel', 'yasm', - 'speex-devel', 'chrpath', 'check', 'astyle', 'uuid-c++-devel', 'gettext-devel', - 'gcc-c++', 'which', 'alsa-lib-devel', 'systemd-devel', 'libuuid-devel', - 'uuid-devel', 'gnutls-devel', 'nettle-devel', 'opus-devel', 'speexdsp-devel', - 'yaml-cpp-devel', 'qt5-qtbase-devel', 'swig', 'jsoncpp-devel', - 'patch', 'libva-devel', 'openssl-devel', 'libvdpau-devel', 'msgpack-devel', - 'sqlite-devel', 'openssl-static', 'pandoc', 'nasm', 'qrencode-devel', 'NetworkManager-libnm-devel', - 'bzip2' -] - -DNF_CLIENT_GNOME_DEPENDENCIES = [ - 'gtk3-devel', 'clutter-devel', 'clutter-gtk-devel', 'libnotify-devel','libappindicator-gtk3-devel', - 'webkitgtk4-devel', 'libcanberra-devel' -] - -DNF_CLIENT_QT_DEPENDENCIES = [ - 'qt5-qtsvg-devel', 'qt5-qtwebengine-devel', 'qt5-qtmultimedia-devel', 'qt5-qtdeclarative-devel', - 'qt5-qtquickcontrols2-devel', 'qt5-qtquickcontrols' -] - -APT_DEPENDENCIES = [ - 'autoconf', 'autoconf-archive', 'autopoint', 'automake', 'cmake', 'make', 'dbus', 'doxygen', 'graphviz', - 'g++', 'gettext', 'gnome-icon-theme-symbolic', 'libasound2-dev', 'libavcodec-dev', - 'libavdevice-dev', 'libavformat-dev', 'libboost-dev', - 'libclutter-gtk-1.0-dev', 'libcppunit-dev', 'libdbus-1-dev', - 'libdbus-c++-dev', 'libebook1.2-dev', 'libexpat1-dev', 'libgnutls28-dev', - 'libgtk-3-dev', 'libjack-dev', 'libnotify-dev', - 'libopus-dev', 'libpcre3-dev', 'libpulse-dev', 'libssl-dev', - 'libspeex-dev', 'libspeexdsp-dev', 'libswscale-dev', 'libtool', - 'libudev-dev', 'libyaml-cpp-dev', 'qtbase5-dev', 'libqt5sql5-sqlite', 'sip-tester', 'swig', - 'uuid-dev', 'yasm', 'libjsoncpp-dev', 'libva-dev', 'libvdpau-dev', 'libmsgpack-dev', - 'pandoc', 'nasm', 'libqrencode-dev', 'libnm-dev', 'dpkg-dev' -] - -APT_CLIENT_GNOME_DEPENDENCIES = [ - 'libwebkit2gtk-4.0-dev', 'libappindicator3-dev', 'libcanberra-gtk3-dev' -] - -APT_CLIENT_QT_DEPENDENCIES = [ - 'qtmultimedia5-dev', 'libqt5svg5-dev', 'qtwebengine5-dev', 'qtdeclarative5-dev', - 'qtquickcontrols2-5-dev', 'qml-module-qtquick2', 'qml-module-qtquick-controls', - 'qml-module-qtquick-controls2', 'qml-module-qtquick-dialogs', - 'qml-module-qtquick-layouts', 'qml-module-qtquick-privatewidgets', - 'qml-module-qtquick-shapes', 'qml-module-qtquick-window2', - 'qml-module-qtquick-templates2', 'qml-module-qt-labs-platform', - 'qml-module-qtwebengine', 'qml-module-qtwebchannel' -] - -PACMAN_DEPENDENCIES = [ - 'autoconf', 'autoconf-archive', 'gettext', 'cmake', 'dbus', 'doxygen', 'graphviz', - 'gcc', 'ffmpeg', 'boost', 'cppunit', 'libdbus', 'dbus-c++', 'libe-book', 'expat', - 'jack', 'opus', 'pcre', 'libpulse', 'speex', 'speexdsp', 'libtool', 'yaml-cpp', - 'qt5-base', 'swig', 'yasm', 'qrencode', 'make', 'patch', 'pkg-config', - 'automake', 'libva', 'libnm', 'libvdpau', 'openssl', 'pandoc', 'nasm' -] - -PACMAN_CLIENT_GNOME_DEPENDENCIES = [ - 'clutter-gtk','gnome-icon-theme-symbolic', 'gtk3', 'libappindicator-gtk3', - 'libcanberra', 'libnotify', 'webkit2gtk' -] - -PACMAN_CLIENT_QT_DEPENDENCIES = [ - 'qt5-declarative', 'qt5-graphicaleffects', 'qt5-multimedia', 'qt5-quickcontrols', - 'qt5-quickcontrols2', 'qt5-svg', 'qt5-tools', 'qt5-webengine' -] - -OSX_DEPENDENCIES = [ - 'autoconf', 'cmake', 'gettext', 'pkg-config', 'qt5', - 'libtool', 'yasm', 'nasm', 'automake' -] - -OSX_DEPENDENCIES_UNLINK = [ - 'autoconf*', 'cmake*', 'gettext*', 'pkg-config*', 'qt*', 'qt@5.*', - 'libtool*', 'yasm*', 'nasm*', 'automake*', 'gnutls*', 'nettle*', 'msgpack*' -] - -IOS_DEPENDENCIES = [ - 'autoconf', 'automake', 'cmake', 'yasm', 'libtool', - 'pkg-config', 'gettext', 'swiftlint', 'swiftgen' -] - -IOS_DEPENDENCIES_UNLINK = [ - 'autoconf*', 'automake*', 'cmake*', 'yasm*', 'libtool*', - 'pkg-config*', 'gettext*', 'swiftlint*', 'swiftgen*' -] - -UNINSTALL_DAEMON_SCRIPT = [ - 'make -C daemon uninstall' -] - -OSX_UNINSTALL_SCRIPT = [ - 'make -C daemon uninstall', - 'rm -rf install/client-macosx' -] - -def run_powersell_cmd(cmd): - p = subprocess.Popen(["powershell.exe", cmd], stdout=sys.stdout) - p.communicate() - p.wait() - return - - -def write_qt_conf(path, qt5version=QT5_VERSION): - # Add a configuration that can be supplied to qmake - # e.g. `qmake -qt=5.15 [mode] [options] [files]` - if path == '': - return - with open('/usr/share/qtchooser/' + qt5version + '.conf', 'w+') as fd: - fd.write(path.rstrip('/') + '/bin\n') - fd.write(path.rstrip('/') + '/lib\n') - return - - -def run_dependencies(args): - if args.qt is not None: - write_qt_conf(args.qt, args.qtver) - - if args.distribution == WIN32_DISTRIBUTION_NAME: - run_powersell_cmd( - 'Set-ExecutionPolicy Unrestricted; .\\scripts\\install-deps-windows.ps1') - - elif args.distribution in APT_BASED_DISTROS: - if args.qt is None: - APT_DEPENDENCIES.extend(APT_CLIENT_GNOME_DEPENDENCIES) - else: - APT_DEPENDENCIES.extend(APT_CLIENT_QT_DEPENDENCIES) - execute_script( - APT_INSTALL_SCRIPT, - {"packages": ' '.join(map(shlex.quote, APT_DEPENDENCIES))} - ) - - elif args.distribution in DNF_BASED_DISTROS: - if args.qt is None: - DNF_DEPENDENCIES.extend(DNF_CLIENT_GNOME_DEPENDENCIES) - else: - DNF_DEPENDENCIES.extend(DNF_CLIENT_QT_DEPENDENCIES) - execute_script( - RPM_INSTALL_SCRIPT, - {"packages": ' '.join(map(shlex.quote, DNF_DEPENDENCIES))} - ) - - elif args.distribution in PACMAN_BASED_DISTROS: - if args.qt is None: - PACMAN_DEPENDENCIES.extend(PACMAN_CLIENT_GNOME_DEPENDENCIES) - else: - PACMAN_DEPENDENCIES.extend(PACMAN_CLIENT_QT_DEPENDENCIES) - execute_script( - PACMAN_INSTALL_SCRIPT, - {"packages": ' '.join(map(shlex.quote, PACMAN_DEPENDENCIES))} - ) - - elif args.distribution in ZYPPER_BASED_DISTROS: - if args.qt is None: - ZYPPER_DEPENDENCIES.extend(ZYPPER_CLIENT_GNOME_DEPENDENCIES) - else: - ZYPPER_DEPENDENCIES.extend(ZYPPER_CLIENT_QT_DEPENDENCIES) - execute_script( - ZYPPER_INSTALL_SCRIPT, - {"packages": ' '.join(map(shlex.quote, ZYPPER_DEPENDENCIES))} - ) - - elif args.distribution == OSX_DISTRIBUTION_NAME: - execute_script( - BREW_UNLINK_SCRIPT, - {"packages": ' '.join(map(shlex.quote, OSX_DEPENDENCIES_UNLINK))}, - False - ) - execute_script( - BREW_INSTALL_SCRIPT, - {"packages": ' '.join(map(shlex.quote, OSX_DEPENDENCIES))}, - False - ) - - elif args.distribution == IOS_DISTRIBUTION_NAME: - execute_script( - BREW_UNLINK_SCRIPT, - {"packages": ' '.join(map(shlex.quote, IOS_DEPENDENCIES_UNLINK))}, - False - ) - execute_script( - BREW_INSTALL_SCRIPT, - {"packages": ' '.join(map(shlex.quote, IOS_DEPENDENCIES))}, - False - ) - - elif args.distribution == ANDROID_DISTRIBUTION_NAME: - print("The Android version does not need more dependencies.\nPlease continue with the --install instruction.") - sys.exit(1) - - elif args.distribution == WIN32_DISTRIBUTION_NAME: - print("The win32 version does not install dependencies with this script.\nPlease continue with the --install instruction.") - sys.exit(1) - - else: - print("Not yet implemented for current distribution (%s). Please continue with the --install instruction. Note: You may need to install some dependencies manually." % - args.distribution) - sys.exit(1) - - -def run_init(): - # Extract modules path from '.gitmodules' file - module_names = [] - with open('.gitmodules') as fd: - for line in fd.readlines(): - if line.startswith('[submodule "'): - module_names.append(line[line.find('"')+1:line.rfind('"')]) - - subprocess.run(["git", "submodule", "update", "--init"], check=True) - subprocess.run(["git", "submodule", "foreach", - "git checkout master && git pull"], check=True) - for name in module_names: - copy_file("./scripts/commit-msg", ".git/modules/"+name+"/hooks") - - module_names_to_format = ['daemon', 'lrc', 'client-qt', 'plugins'] - for name in module_names_to_format: - execute_script( - ['./scripts/format.sh --install %(path)s'], - {"path": ".git/modules/" + name + "/hooks"} - ) - - -def copy_file(src, dest): - print("Copying:" + src + " to " + dest) - try: - shutil.copy2(src, dest) - # eg. src and dest are the same file - except shutil.Error as e: - print('Error: %s' % e) - # eg. source or destination doesn't exist - except IOError as e: - print('Error: %s' % e.strerror) - - -def run_install(args): - # Platforms with special compilation scripts - if args.distribution == IOS_DISTRIBUTION_NAME: - return subprocess.run(["./compile-ios.sh"], cwd="./client-ios", check=True) - elif args.distribution == ANDROID_DISTRIBUTION_NAME: - return subprocess.run(["./compile.sh"], cwd="./client-android", check=True) - elif args.distribution == WIN32_DISTRIBUTION_NAME: - return subprocess.run([ - sys.executable, os.path.join( - os.getcwd(), "scripts/build-windows.py"), - "--toolset", args.toolset, - "--sdk", args.sdk, - "--qtver", args.qtver - ], check=True) - - # Unix-like platforms - environ = os.environ.copy() - - install_args = ['-p', str(multiprocessing.cpu_count())] - if args.static: - install_args.append('-s') - if args.global_install: - install_args.append('-g') - if args.prefix is not None: - install_args += ('-P', args.prefix) - if not args.priv_install: - install_args.append('-u') - - if args.distribution == OSX_DISTRIBUTION_NAME: - # The `universal_newlines` parameter has been renamed to `text` in - # Python 3.7+ and triggering automatical binary to text conversion is - # what it actually does - proc = subprocess.run(["brew", "--prefix", "qt5"], - stdout=subprocess.PIPE, check=True, - universal_newlines=True) - - environ['CMAKE_PREFIX_PATH'] = proc.stdout.rstrip("\n") - environ['CONFIGURE_FLAGS'] = '--without-dbus' - install_args += ("-c", "client-macosx") - else: - if args.distribution in ZYPPER_BASED_DISTROS: - # fix jsoncpp pkg-config bug, remove when jsoncpp package bumped - environ['JSONCPP_LIBS'] = "-ljsoncpp" - if args.qt is None: - install_args += ("-c", "client-gnome") - else: - install_args += ("-c", "client-qt") - install_args += ("-q", args.qtver) - install_args += ("-Q", args.qt) - - return subprocess.run(["./scripts/install.sh"] + install_args, env=environ, check=True) - - -def run_uninstall(args): - if args.distribution == OSX_DISTRIBUTION_NAME: - execute_script(OSX_UNINSTALL_SCRIPT) - else: - execute_script(UNINSTALL_DAEMON_SCRIPT) - - CLIENT_SUFFIX = 'qt' if (args.qt is not None) else 'gnome' - INSTALL_DIR = '/build-global' if args.global_install else '/build-local' - - # Client needs to be uninstalled first - if (os.path.exists('./client-' + CLIENT_SUFFIX + INSTALL_DIR)): - UNINSTALL_CLIENT = [ - 'make -C client-' + CLIENT_SUFFIX + INSTALL_DIR + ' uninstall', - 'rm -rf ./client-' + CLIENT_SUFFIX + INSTALL_DIR - ] - execute_script(UNINSTALL_CLIENT) - - if (os.path.exists('./lrc' + INSTALL_DIR)): - UNINSTALL_LRC = [ - 'make -C lrc' + INSTALL_DIR + ' uninstall', - 'rm -rf ./lrc' + INSTALL_DIR - ] - execute_script(UNINSTALL_LRC) - -def run_run(args): - if args.distribution == OSX_DISTRIBUTION_NAME: - subprocess.Popen( - ["install/client-macosx/Ring.app/Contents/MacOS/Ring"]) - return True - - run_env = os.environ - run_env['LD_LIBRARY_PATH'] = run_env.get( - 'LD_LIBRARY_PATH', '') + ":install/lrc/lib" - - try: - dring_log = open("daemon.log", 'a') - dring_log.write('=== Starting daemon (%s) ===' % - time.strftime("%d/%m/%Y %H:%M:%S")) - dring_process = subprocess.Popen( - ["./install/daemon/lib/ring/dring", "-c", "-d"], - stdout=dring_log, - stderr=dring_log - ) - - with open('daemon.pid', 'w') as f: - f.write(str(dring_process.pid)+'\n') - - client_suffix = "" - if args.qt is not None: - client_suffix += "qt" - else: - client_suffix += "gnome" - client_log = open("jami-" + client_suffix + ".log", 'a') - client_log.write('=== Starting client (%s) ===' % - time.strftime("%d/%m/%Y %H:%M:%S")) - client_process = subprocess.Popen( - ["./install/client-" + client_suffix + - "/bin/jami-" + client_suffix, "-d"], - stdout=client_log, - stderr=client_log, - env=run_env - ) - - with open("jami-" + client_suffix + ".pid", 'w') as f: - f.write(str(client_process.pid)+'\n') - - if args.debug: - subprocess.call( - ['gdb', '-x', 'gdb.gdb', './install/daemon/lib/ring/dring'], - ) - - if args.background == False: - dring_process.wait() - client_process.wait() - - except KeyboardInterrupt: - print("\nCaught KeyboardInterrupt...") - - finally: - if args.background == False: - try: - # Only kill the processes if they are running, as they could - # have been closed by the user. - print("Killing processes...") - dring_log.close() - if dring_process.poll() is None: - dring_process.kill() - client_log.close() - if client_process.poll() is None: - client_process.kill() - except UnboundLocalError: - # Its okay! We crashed before we could start a process or open a - # file. All that matters is that we close files and kill processes - # in the right order. - pass - return True - - -def run_stop(args): - client_suffix = "qt" if (args.qt is not None) else "gnome" - STOP_SCRIPT = [ - 'xargs kill < daemon.pid', - 'xargs kill < jami-' + client_suffix + '.pid' - ] - execute_script(STOP_SCRIPT) - - -def execute_script(script, settings=None, fail=True): - if settings == None: - settings = {} - for line in script: - line = line % settings - rv = os.system(line) - if rv != 0 and fail == True: - print('Error executing script! Exit code: %s' % - rv, file=sys.stderr) - sys.exit(1) - - -def validate_args(parsed_args): - """Validate the args values, exit if error is found""" - - # Filter unsupported distributions. - supported_distros = [ - ANDROID_DISTRIBUTION_NAME, OSX_DISTRIBUTION_NAME, IOS_DISTRIBUTION_NAME, - WIN32_DISTRIBUTION_NAME - ] + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS \ - + ZYPPER_BASED_DISTROS + FLATPAK_BASED_RUNTIMES - - if parsed_args.distribution not in supported_distros: - print('WARNING: Distribution \'{0}\' not supported.\nChoose one of: {1}'.format( - parsed_args.distribution, ', '.join(supported_distros) - ), file=sys.stderr) - - # The Qt client support will be added incrementally. - if parsed_args.qt is not None: - supported_qt_distros = [ - WIN32_DISTRIBUTION_NAME - ] + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS - - if parsed_args.distribution not in supported_qt_distros: - print('Distribution \'{0}\' not supported when building the Qt client.' - '\nChoose one of: {1}'.format( - parsed_args.distribution, ', '.join(supported_qt_distros) - ), file=sys.stderr) - sys.exit(1) - - # The windows client can only be built on a Windows 10 host. - if parsed_args.distribution == WIN32_DISTRIBUTION_NAME: - if platform.release() != '10': - print('Windows version must be built on Windows 10') - sys.exit(1) - - -def parse_args(): - ap = argparse.ArgumentParser(description="Ring build tool") - - ga = ap.add_mutually_exclusive_group(required=True) - ga.add_argument( - '--init', action='store_true', - help='Init Ring repository') - ga.add_argument( - '--dependencies', action='store_true', - help='Install ring build dependencies') - ga.add_argument( - '--install', action='store_true', - help='Build and install Ring') - ga.add_argument( - '--uninstall', action='store_true', - help='Uninstall Ring') - ga.add_argument( - '--run', action='store_true', - help='Run the Ring daemon and client') - ga.add_argument( - '--stop', action='store_true', - help='Stop the Ring processes') - - ap.add_argument('--distribution') - ap.add_argument('--prefix') - ap.add_argument('--static', default=False, action='store_true') - ap.add_argument('--global-install', default=False, action='store_true') - ap.add_argument('--debug', default=False, action='store_true') - ap.add_argument('--background', default=False, action='store_true') - ap.add_argument('--no-priv-install', dest='priv_install', - default=True, action='store_false') - ap.add_argument('--qt', nargs='?', const='', type=str, - help='Build the Qt client with the Qt path supplied') - ap.add_argument('--qtver', default=QT5_VERSION, - help='Sets the Qt version to build with') - - dist = choose_distribution() - if dist == WIN32_DISTRIBUTION_NAME: - ap.add_argument('--toolset', default=win_toolset_default, type=str, - help='Windows use only, specify Visual Studio toolset version') - ap.add_argument('--sdk', default=win_sdk_default, type=str, - help='Windows use only, specify Windows SDK version') - - parsed_args = ap.parse_args() - - if (parsed_args.distribution is not None): - parsed_args.distribution = parsed_args.distribution.lower() - else: - parsed_args.distribution = dist - - validate_args(parsed_args) - - return parsed_args - - -def choose_distribution(): - system = platform.system().lower() - - if system == "linux" or system == "linux2": - if os.path.isfile("/etc/arch-release"): - return "arch" - with open("/etc/os-release") as f: - for line in f: - k, v = line.split("=") - if k.strip() == 'ID': - return v.strip().replace('"', '').split(' ')[0] - elif system == "darwin": - return OSX_DISTRIBUTION_NAME - elif system == "windows": - return WIN32_DISTRIBUTION_NAME - - return 'Unknown' - - -def main(): - parsed_args = parse_args() - - if parsed_args.dependencies: - run_dependencies(parsed_args) - - elif parsed_args.init: - run_init() - - elif parsed_args.install: - run_install(parsed_args) - - elif parsed_args.uninstall: - run_uninstall(parsed_args) - - elif parsed_args.run: - run_run(parsed_args) - - elif parsed_args.stop: - run_stop(parsed_args) - - -if __name__ == "__main__": - main() diff --git a/make-ring.py b/make-ring.py new file mode 120000 index 0000000000000000000000000000000000000000..0f74e2a77724252e4d1ef4112c74d21fd563878f --- /dev/null +++ b/make-ring.py @@ -0,0 +1 @@ +build.py \ No newline at end of file