X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst-env.py;h=ab74730e6b6a12bffb27747d0709004f33e65247;hb=2ea4d0d3545bf72975787826ab827b659cd23d65;hp=d91381a7316ae82c22425dd5b6d5b86266dba9a7;hpb=d570c770adeb89ab5b954f4dadb89d6daadbd238;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst-env.py b/gst-env.py index d91381a..ab74730 100755 --- a/gst-env.py +++ b/gst-env.py @@ -15,10 +15,10 @@ import sys import tempfile import pathlib import signal -from pathlib import PurePath +from functools import lru_cache +from pathlib import PurePath, Path -from distutils.sysconfig import get_python_lib -from distutils.util import strtobool +from typing import Any from scripts.common import get_meson from scripts.common import git @@ -42,6 +42,28 @@ SHAREDLIB_REG = re.compile(r'\.so|\.dylib|\.dll') GSTPLUGIN_FILEPATH_REG_TEMPLATE = r'.*/{libdir}/gstreamer-1.0/[^/]+$' GSTPLUGIN_FILEPATH_REG = None +BC_RC = ''' +BASH_COMPLETION_SCRIPTS="{bash_completions}" +BASH_COMPLETION_PATHS="{bash_completions_paths}" +for p in $BASH_COMPLETION_PATHS; do +for f in $BASH_COMPLETION_SCRIPTS; do + [ -f "$p/$f" ] && . "$p/$f" +done +done +''' +BASH_COMPLETION_PATHS = [SCRIPTDIR + '/subprojects/gstreamer/data/bash-completion/completions'] +BASH_COMPLETION_PATHS += [SCRIPTDIR + '/subprojects/gst-devtools/validate/data/bash-completion/completions'] + + +def str_to_bool(value: Any) -> bool: + """Return whether the provided string (or any value really) represents true. Otherwise false. + Just like plugin server stringToBoolean. + """ + if not value: + return False + return str(value).lower() in ("y", "yes", "t", "true", "on", "1") + + def listify(o): if isinstance(o, str): return [o] @@ -59,6 +81,8 @@ def stringify(o): raise AssertionError('Object {!r} must be a string or a list'.format(o)) def prepend_env_var(env, var, value, sysroot): + if var is None: + return if value.startswith(sysroot): value = value[len(sysroot):] # Try not to exceed maximum length limits for env vars on Windows @@ -72,28 +96,72 @@ def prepend_env_var(env, var, value, sysroot): env[var] = val + env_val env[var] = env[var].replace(os.pathsep + os.pathsep, os.pathsep).strip(os.pathsep) +def get_target_install_filename(target, filename): + ''' + Checks whether this file is one of the files installed by the target + ''' + basename = os.path.basename(filename) + for install_filename in listify(target['install_filename']): + if install_filename.endswith(basename): + return install_filename + return None + +def get_pkgconfig_variable_from_pcfile(pcfile, varname): + variables = {} + substre = re.compile('\$\{[^${}]+\}') + with pcfile.open('r', encoding='utf-8') as f: + for line in f: + if '=' not in line: + continue + key, value = line[:-1].split('=', 1) + subst = {} + for each in substre.findall(value): + substkey = each[2:-1] + subst[each] = variables.get(substkey, '') + for k, v in subst.items(): + value = value.replace(k, v) + variables[key] = value + return variables.get(varname, '') + +@lru_cache() +def get_pkgconfig_variable(builddir, pcname, varname): + ''' + Parsing isn't perfect, but it's good enough. + ''' + pcfile = Path(builddir) / 'meson-private' / (pcname + '.pc') + if pcfile.is_file(): + return get_pkgconfig_variable_from_pcfile(pcfile, varname) + return subprocess.check_output(['pkg-config', pcname, '--variable=' + varname], + universal_newlines=True, encoding='utf-8') + + +def is_gio_module(target, filename, builddir): + if target['type'] != 'shared module': + return False + install_filename = get_target_install_filename(target, filename) + if not install_filename: + return False + giomoduledir = PurePath(get_pkgconfig_variable(builddir, 'gio-2.0', 'giomoduledir')) + fpath = PurePath(install_filename) + if fpath.parent != giomoduledir: + return False + return True + def is_library_target_and_not_plugin(target, filename): ''' Don't add plugins to PATH/LD_LIBRARY_PATH because: 1. We don't need to 2. It causes us to exceed the PATH length limit on Windows and Wine ''' - if not target['type'].startswith('shared'): - return False - if not target['installed']: + if target['type'] != 'shared library': return False # Check if this output of that target is a shared library if not SHAREDLIB_REG.search(filename): return False # Check if it's installed to the gstreamer plugin location - for install_filename in listify(target['install_filename']): - if install_filename.endswith(os.path.basename(filename)): - break - else: - # None of the installed files in the target correspond to the built - # filename, so skip + install_filename = get_target_install_filename(target, filename) + if not install_filename: return False - global GSTPLUGIN_FILEPATH_REG if GSTPLUGIN_FILEPATH_REG is None: GSTPLUGIN_FILEPATH_REG = re.compile(GSTPLUGIN_FILEPATH_REG_TEMPLATE) @@ -104,15 +172,9 @@ def is_library_target_and_not_plugin(target, filename): def is_binary_target_and_in_path(target, filename, bindir): if target['type'] != 'executable': return False - if not target['installed']: - return False # Check if this file installed by this target is installed to bindir - for install_filename in listify(target['install_filename']): - if install_filename.endswith(os.path.basename(filename)): - break - else: - # None of the installed files in the target correspond to the built - # filename, so skip + install_filename = get_target_install_filename(target, filename) + if not install_filename: return False fpath = PurePath(install_filename) if fpath.parent != bindir: @@ -160,8 +222,11 @@ def setup_gdb(options): python_paths.add(str(bdir / gdb_path)) python_paths.add(os.path.join(options.srcdir, gdb_path)) try: - os.symlink(gdb_helper, str(autoload_path / os.path.basename(gdb_helper))) - except FileExistsError: + if os.name == 'nt': + shutil.copy(gdb_helper, str(autoload_path / os.path.basename(gdb_helper))) + else: + os.symlink(gdb_helper, str(autoload_path / os.path.basename(gdb_helper))) + except (FileExistsError, shutil.SameFileError): pass gdbinit_line = 'add-auto-load-scripts-directory {}\n'.format(bdir / 'gdb-auto-load') @@ -177,24 +242,35 @@ def setup_gdb(options): return python_paths +def is_bash_completion_available (options): + return os.path.exists(os.path.join(options.builddir, 'subprojects/gstreamer/data/bash-completion/helpers/gst')) def get_subprocess_env(options, gst_version): env = os.environ.copy() env["CURRENT_GST"] = os.path.normpath(SCRIPTDIR) env["GST_VERSION"] = gst_version - env["GST_VALIDATE_SCENARIOS_PATH"] = os.path.normpath( - "%s/subprojects/gst-devtools/validate/data/scenarios" % SCRIPTDIR) + prepend_env_var (env, "GST_VALIDATE_SCENARIOS_PATH", os.path.normpath( + "%s/subprojects/gst-devtools/validate/data/scenarios" % SCRIPTDIR), + options.sysroot) env["GST_VALIDATE_PLUGIN_PATH"] = os.path.normpath( "%s/subprojects/gst-devtools/validate/plugins" % options.builddir) - env["GST_VALIDATE_APPS_DIR"] = os.path.normpath( - "%s/subprojects/gst-editing-services/tests/validate" % SCRIPTDIR) + prepend_env_var (env, "GST_VALIDATE_APPS_DIR", os.path.normpath( + "%s/subprojects/gst-editing-services/tests/validate" % SCRIPTDIR), + options.sysroot) env["GST_ENV"] = 'gst-' + gst_version env["GST_REGISTRY"] = os.path.normpath(options.builddir + "/registry.dat") prepend_env_var(env, "PATH", os.path.normpath( "%s/subprojects/gst-devtools/validate/tools" % options.builddir), options.sysroot) + prepend_env_var (env, "GST_VALIDATE_SCENARIOS_PATH", os.path.normpath( + "%s/subprojects/gst-examples/webrtc/check/validate/scenarios" % + SCRIPTDIR), options.sysroot) + prepend_env_var (env, "GST_VALIDATE_APPS_DIR", os.path.normpath( + "%s/subprojects/gst-examples/webrtc/check/validate/apps" % + SCRIPTDIR), options.sysroot) + if options.wine: return get_wine_subprocess_env(options, env) @@ -210,7 +286,8 @@ def get_subprocess_env(options, gst_version): if os.name == 'nt': lib_path_envvar = 'PATH' elif platform.system() == 'Darwin': - lib_path_envvar = 'DYLD_LIBRARY_PATH' + # RPATH is sufficient on macOS, and DYLD_LIBRARY_PATH can cause issues with dynamic linker path priority + lib_path_envvar = None else: lib_path_envvar = 'LD_LIBRARY_PATH' @@ -234,13 +311,17 @@ def get_subprocess_env(options, gst_version): options.sysroot) # gst-indent - prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'gstreamer', 'tools'), + prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'scripts'), options.sysroot) # tools: gst-launch-1.0, gst-inspect-1.0 prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects', 'gstreamer', 'tools'), options.sysroot) + # plugin scanner and generator + prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects', + 'gstreamer', 'docs'), + options.sysroot) prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects', 'gst-plugins-base', 'tools'), options.sysroot) @@ -279,6 +360,8 @@ def get_subprocess_env(options, gst_version): for target in targets: filenames = listify(target['filename']) + if not target['installed']: + continue for filename in filenames: root = os.path.dirname(filename) if srcdir_path / "subprojects/gst-devtools/validate/plugins" in (srcdir_path / root).parents: @@ -295,23 +378,28 @@ def get_subprocess_env(options, gst_version): options.sysroot) elif is_binary_target_and_in_path(target, filename, bindir): paths.add(os.path.join(options.builddir, root)) + elif is_gio_module(target, filename, options.builddir): + prepend_env_var(env, 'GIO_EXTRA_MODULES', + os.path.join(options.builddir, root), + options.sysroot) - with open(os.path.join(options.builddir, 'GstPluginsPath.json')) as f: + with open(os.path.join(options.gstbuilddir, 'GstPluginsPath.json')) as f: for plugin_path in json.load(f): prepend_env_var(env, 'GST_PLUGIN_PATH', plugin_path, options.sysroot) - for p in paths: + # Sort to iterate in a consistent order (`set`s and `hash`es are randomized) + for p in sorted(paths): prepend_env_var(env, 'PATH', p, options.sysroot) if os.name != 'nt': - for p in mono_paths: + for p in sorted(mono_paths): prepend_env_var(env, "MONO_PATH", p, options.sysroot) presets = set() encoding_targets = set() - pkg_dirs = set() python_dirs = setup_gdb(options) + overrides_dirs = set() if '--installed' in subprocess.check_output(meson + ['introspect', '-h']).decode(): installed_s = subprocess.check_output(meson + ['introspect', options.builddir, '--installed']) for path, installpath in json.loads(installed_s.decode()).items(): @@ -332,45 +420,47 @@ def get_subprocess_env(options, gst_version): if 'site-packages' in installpath_parts: install_subpath = os.path.join(*installpath_parts[installpath_parts.index('site-packages') + 1:]) if path.endswith(install_subpath): - python_dirs.add(path[:len (install_subpath) * -1]) + if os.path.commonprefix(["gi/overrides", install_subpath]): + overrides_dirs.add(os.path.dirname(path)) + else: + python_dirs.add(path[:len (install_subpath) * -1]) if path.endswith('.prs'): presets.add(os.path.dirname(path)) elif path.endswith('.gep'): encoding_targets.add( os.path.abspath(os.path.join(os.path.dirname(path), '..'))) - elif path.endswith('.pc'): - # Is there a -uninstalled pc file for this file? - uninstalled = "{0}-uninstalled.pc".format(path[:-3]) - if os.path.exists(uninstalled): - pkg_dirs.add(os.path.dirname(path)) if path.endswith('gstomx.conf'): prepend_env_var(env, 'GST_OMX_CONFIG_DIR', os.path.dirname(path), options.sysroot) - for p in presets: + for p in sorted(presets): prepend_env_var(env, 'GST_PRESET_PATH', p, options.sysroot) - for t in encoding_targets: + for t in sorted(encoding_targets): prepend_env_var(env, 'GST_ENCODING_TARGET_PATH', t, options.sysroot) - for pkg_dir in pkg_dirs: - prepend_env_var(env, "PKG_CONFIG_PATH", pkg_dir, options.sysroot) - # Check if meson has generated -uninstalled pkgconfig files meson_uninstalled = pathlib.Path(options.builddir) / 'meson-uninstalled' if meson_uninstalled.is_dir(): prepend_env_var(env, 'PKG_CONFIG_PATH', str(meson_uninstalled), options.sysroot) - for python_dir in python_dirs: + for python_dir in sorted(python_dirs): prepend_env_var(env, 'PYTHONPATH', python_dir, options.sysroot) + for python_dir in sorted(overrides_dirs): + prepend_env_var(env, '_GI_OVERRIDES_PATH', python_dir, options.sysroot) + mesonpath = os.path.join(SCRIPTDIR, "meson") if os.path.join(mesonpath): # Add meson/ into PYTHONPATH if we are using a local meson prepend_env_var(env, 'PYTHONPATH', mesonpath, options.sysroot) + # Ensure that gst-python/gi is used first + prepend_env_var(env, "PYTHONPATH", os.path.join(SCRIPTDIR, 'subprojects', 'gst-python'), + options.sysroot) + # For devhelp books if 'XDG_DATA_DIRS' not in env or not env['XDG_DATA_DIRS']: # Preserve default paths when empty @@ -392,7 +482,8 @@ def get_subprocess_env(options, gst_version): return env def get_windows_shell(): - command = ['powershell.exe' ,'-noprofile', '-executionpolicy', 'bypass', '-file', 'cmd_or_ps.ps1'] + command = ['powershell.exe' ,'-noprofile', '-executionpolicy', 'bypass', '-file', + os.path.join(SCRIPTDIR, 'data', 'misc', 'cmd_or_ps.ps1')] result = subprocess.check_output(command) return result.decode().strip() @@ -402,6 +493,9 @@ if __name__ == "__main__": parser.add_argument("--builddir", default=DEFAULT_BUILDDIR, help="The meson build directory") + parser.add_argument("--gstbuilddir", + default=None, + help="The meson GStreamer build directory (defaults to builddir)") parser.add_argument("--srcdir", default=SCRIPTDIR, help="The top level source directory") @@ -424,7 +518,16 @@ if __name__ == "__main__": print("GStreamer not built in %s\n\nBuild it and try again" % options.builddir) exit(1) + + if options.gstbuilddir and not os.path.exists(options.gstbuilddir): + print("GStreamer is not built in %s\n\nBuild it and try again" % + options.gstbuilddir) + exit(1) + elif not options.gstbuilddir: + options.gstbuilddir = options.builddir + options.builddir = os.path.abspath(options.builddir) + options.gstbuilddir = os.path.abspath(options.gstbuilddir) if not os.path.exists(options.srcdir): print("The specified source dir does not exist" % @@ -455,7 +558,7 @@ if __name__ == "__main__": args += ['/k', 'prompt [gst-{}] $P$G'.format(gst_version)] else: args = [os.environ.get("SHELL", os.path.realpath("/bin/sh"))] - if args[0].endswith('bash') and not strtobool(os.environ.get("GST_BUILD_DISABLE_PS1_OVERRIDE", r"FALSE")): + if args[0].endswith('bash') and not str_to_bool(os.environ.get("GST_BUILD_DISABLE_PS1_OVERRIDE", r"FALSE")): # Let the GC remove the tmp file tmprc = tempfile.NamedTemporaryFile(mode='w') bashrc = os.path.expanduser('~/.bashrc') @@ -464,6 +567,14 @@ if __name__ == "__main__": shutil.copyfileobj(src, tmprc) tmprc.write('\nexport PS1="[gst-%s] $PS1"' % gst_version) tmprc.flush() + if is_bash_completion_available(options): + bash_completions_files = [] + for p in BASH_COMPLETION_PATHS: + if os.path.exists(p): + bash_completions_files += os.listdir(path=p) + bc_rc = BC_RC.format(bash_completions=' '.join(bash_completions_files), bash_completions_paths=' '.join(BASH_COMPLETION_PATHS)) + tmprc.write(bc_rc) + tmprc.flush() args.append("--rcfile") args.append(tmprc.name) elif args[0].endswith('fish'): @@ -495,6 +606,10 @@ if __name__ == "__main__": print('{}={}'.format(name, shlex.quote(value))) print('export {}'.format(name)) else: + if os.environ.get("CI_PROJECT_NAME"): + print("Ignoring SIGINT when running on the CI," + " as we get spurious sigint in there for some reason.") + signal.signal(signal.SIGINT, signal.SIG_IGN) exit(subprocess.call(args, close_fds=False, env=env)) except subprocess.CalledProcessError as e: