env: Fix deprecations from python 3.10
[platform/upstream/gstreamer.git] / gst-env.py
1 #!/usr/bin/env python3
2
3 import argparse
4 import contextlib
5 import glob
6 import json
7 import os
8 import platform
9 import re
10 import site
11 import shlex
12 import shutil
13 import subprocess
14 import sys
15 import tempfile
16 import pathlib
17 import signal
18 from functools import lru_cache
19 from pathlib import PurePath, Path
20
21 from typing import Any
22
23 from scripts.common import get_meson
24 from scripts.common import git
25 from scripts.common import win32_get_short_path_name
26 from scripts.common import get_wine_shortpath
27
28 SCRIPTDIR = os.path.dirname(os.path.realpath(__file__))
29 PREFIX_DIR = os.path.join(SCRIPTDIR, 'prefix')
30 # Look for the following build dirs: `build` `_build` `builddir`
31 DEFAULT_BUILDDIR = os.path.join(SCRIPTDIR, 'build')
32 if not os.path.exists(DEFAULT_BUILDDIR):
33     DEFAULT_BUILDDIR = os.path.join(SCRIPTDIR, '_build')
34 if not os.path.exists(DEFAULT_BUILDDIR):
35     DEFAULT_BUILDDIR = os.path.join(SCRIPTDIR, 'builddir')
36
37 TYPELIB_REG = re.compile(r'.*\.typelib$')
38 SHAREDLIB_REG = re.compile(r'\.so|\.dylib|\.dll')
39
40 # libdir is expanded from option of the same name listed in the `meson
41 # introspect --buildoptions` output.
42 GSTPLUGIN_FILEPATH_REG_TEMPLATE = r'.*/{libdir}/gstreamer-1.0/[^/]+$'
43 GSTPLUGIN_FILEPATH_REG = None
44
45 BC_RC =  '''
46 BASH_COMPLETION_SCRIPTS="{bash_completions}"
47 BASH_COMPLETION_PATHS="{bash_completions_paths}"
48 for p in $BASH_COMPLETION_PATHS; do
49 for f in $BASH_COMPLETION_SCRIPTS; do
50   [ -f "$p/$f" ] && . "$p/$f"
51 done
52 done
53 '''
54 BASH_COMPLETION_PATHS = [SCRIPTDIR + '/subprojects/gstreamer/data/bash-completion/completions']
55 BASH_COMPLETION_PATHS += [SCRIPTDIR + '/subprojects/gst-devtools/validate/data/bash-completion/completions']
56
57
58 def str_to_bool(value: Any) -> bool:
59     """Return whether the provided string (or any value really) represents true. Otherwise false.
60     Just like plugin server stringToBoolean.
61     """
62     if not value:
63         return False
64     return str(value).lower() in ("y", "yes", "t", "true", "on", "1")
65
66
67 def listify(o):
68     if isinstance(o, str):
69         return [o]
70     if isinstance(o, list):
71         return o
72     raise AssertionError('Object {!r} must be a string or a list'.format(o))
73
74 def stringify(o):
75     if isinstance(o, str):
76         return o
77     if isinstance(o, list):
78         if len(o) == 1:
79             return o[0]
80         raise AssertionError('Did not expect object {!r} to have more than one element'.format(o))
81     raise AssertionError('Object {!r} must be a string or a list'.format(o))
82
83 def prepend_env_var(env, var, value, sysroot):
84     if var is None:
85         return
86     if value.startswith(sysroot):
87         value = value[len(sysroot):]
88     # Try not to exceed maximum length limits for env vars on Windows
89     if os.name == 'nt':
90         value = win32_get_short_path_name(value)
91     env_val = env.get(var, '')
92     val = os.pathsep + value + os.pathsep
93     # Don't add the same value twice
94     if val in env_val or env_val.startswith(value + os.pathsep):
95         return
96     env[var] = val + env_val
97     env[var] = env[var].replace(os.pathsep + os.pathsep, os.pathsep).strip(os.pathsep)
98
99 def get_target_install_filename(target, filename):
100     '''
101     Checks whether this file is one of the files installed by the target
102     '''
103     basename = os.path.basename(filename)
104     for install_filename in listify(target['install_filename']):
105         if install_filename.endswith(basename):
106             return install_filename
107     return None
108
109 def get_pkgconfig_variable_from_pcfile(pcfile, varname):
110     variables = {}
111     substre = re.compile('\$\{[^${}]+\}')
112     with pcfile.open('r', encoding='utf-8') as f:
113         for line in f:
114             if '=' not in line:
115                 continue
116             key, value = line[:-1].split('=', 1)
117             subst = {}
118             for each in substre.findall(value):
119                 substkey = each[2:-1]
120                 subst[each] = variables.get(substkey, '')
121             for k, v in subst.items():
122                 value = value.replace(k, v)
123             variables[key] = value
124     return variables.get(varname, '')
125
126 @lru_cache()
127 def get_pkgconfig_variable(builddir, pcname, varname):
128     '''
129     Parsing isn't perfect, but it's good enough.
130     '''
131     pcfile = Path(builddir) / 'meson-private' / (pcname + '.pc')
132     if pcfile.is_file():
133         return get_pkgconfig_variable_from_pcfile(pcfile, varname)
134     return subprocess.check_output(['pkg-config', pcname, '--variable=' + varname],
135                                    universal_newlines=True, encoding='utf-8')
136
137
138 def is_gio_module(target, filename, builddir):
139     if target['type'] != 'shared module':
140         return False
141     install_filename = get_target_install_filename(target, filename)
142     if not install_filename:
143         return False
144     giomoduledir = PurePath(get_pkgconfig_variable(builddir, 'gio-2.0', 'giomoduledir'))
145     fpath = PurePath(install_filename)
146     if fpath.parent != giomoduledir:
147         return False
148     return True
149
150 def is_library_target_and_not_plugin(target, filename):
151     '''
152     Don't add plugins to PATH/LD_LIBRARY_PATH because:
153     1. We don't need to
154     2. It causes us to exceed the PATH length limit on Windows and Wine
155     '''
156     if target['type'] != 'shared library':
157         return False
158     # Check if this output of that target is a shared library
159     if not SHAREDLIB_REG.search(filename):
160         return False
161     # Check if it's installed to the gstreamer plugin location
162     install_filename = get_target_install_filename(target, filename)
163     if not install_filename:
164         return False
165     global GSTPLUGIN_FILEPATH_REG
166     if GSTPLUGIN_FILEPATH_REG is None:
167         GSTPLUGIN_FILEPATH_REG = re.compile(GSTPLUGIN_FILEPATH_REG_TEMPLATE)
168     if GSTPLUGIN_FILEPATH_REG.search(install_filename.replace('\\', '/')):
169         return False
170     return True
171
172 def is_binary_target_and_in_path(target, filename, bindir):
173     if target['type'] != 'executable':
174         return False
175     # Check if this file installed by this target is installed to bindir
176     install_filename = get_target_install_filename(target, filename)
177     if not install_filename:
178         return False
179     fpath = PurePath(install_filename)
180     if fpath.parent != bindir:
181         return False
182     return True
183
184
185 def get_wine_subprocess_env(options, env):
186     with open(os.path.join(options.builddir, 'meson-info', 'intro-buildoptions.json')) as f:
187         buildoptions = json.load(f)
188
189     prefix, = [o for o in buildoptions if o['name'] == 'prefix']
190     path = os.path.normpath(os.path.join(prefix['value'], 'bin'))
191     prepend_env_var(env, "PATH", path, options.sysroot)
192     wine_path = get_wine_shortpath(
193         options.wine.split(' '),
194         [path] + env.get('WINEPATH', '').split(';')
195     )
196     if options.winepath:
197         wine_path += ';' + options.winepath
198     env['WINEPATH'] = wine_path
199     env['WINEDEBUG'] = 'fixme-all'
200
201     return env
202
203 def setup_gdb(options):
204     python_paths = set()
205
206     if not shutil.which('gdb'):
207         return python_paths
208
209     bdir = pathlib.Path(options.builddir).resolve()
210     for libpath, gdb_path in [
211             (os.path.join("subprojects", "gstreamer", "gst"),
212              os.path.join("subprojects", "gstreamer", "libs", "gst", "helpers")),
213             (os.path.join("subprojects", "glib", "gobject"), None),
214             (os.path.join("subprojects", "glib", "glib"), None)]:
215
216         if not gdb_path:
217             gdb_path = libpath
218
219         autoload_path = (pathlib.Path(bdir) / 'gdb-auto-load').joinpath(*bdir.parts[1:]) / libpath
220         autoload_path.mkdir(parents=True, exist_ok=True)
221         for gdb_helper in glob.glob(str(bdir / gdb_path / "*-gdb.py")):
222             python_paths.add(str(bdir / gdb_path))
223             python_paths.add(os.path.join(options.srcdir, gdb_path))
224             try:
225                 if os.name == 'nt':
226                     shutil.copy(gdb_helper, str(autoload_path / os.path.basename(gdb_helper)))
227                 else:
228                     os.symlink(gdb_helper, str(autoload_path / os.path.basename(gdb_helper)))
229             except (FileExistsError, shutil.SameFileError):
230                 pass
231
232     gdbinit_line = 'add-auto-load-scripts-directory {}\n'.format(bdir / 'gdb-auto-load')
233     try:
234         with open(os.path.join(options.srcdir, '.gdbinit'), 'r') as f:
235             if gdbinit_line in f.readlines():
236                 return python_paths
237     except FileNotFoundError:
238         pass
239
240     with open(os.path.join(options.srcdir, '.gdbinit'), 'a') as f:
241         f.write(gdbinit_line)
242
243     return python_paths
244
245 def is_bash_completion_available (options):
246     return  os.path.exists(os.path.join(options.builddir, 'subprojects/gstreamer/data/bash-completion/helpers/gst'))
247
248 def get_subprocess_env(options, gst_version):
249     env = os.environ.copy()
250
251     env["CURRENT_GST"] = os.path.normpath(SCRIPTDIR)
252     env["GST_VERSION"] = gst_version
253     prepend_env_var (env, "GST_VALIDATE_SCENARIOS_PATH", os.path.normpath(
254         "%s/subprojects/gst-devtools/validate/data/scenarios" % SCRIPTDIR),
255         options.sysroot)
256     env["GST_VALIDATE_PLUGIN_PATH"] = os.path.normpath(
257         "%s/subprojects/gst-devtools/validate/plugins" % options.builddir)
258     prepend_env_var (env, "GST_VALIDATE_APPS_DIR", os.path.normpath(
259         "%s/subprojects/gst-editing-services/tests/validate" % SCRIPTDIR),
260         options.sysroot)
261     env["GST_ENV"] = 'gst-' + gst_version
262     env["GST_REGISTRY"] = os.path.normpath(options.builddir + "/registry.dat")
263     prepend_env_var(env, "PATH", os.path.normpath(
264         "%s/subprojects/gst-devtools/validate/tools" % options.builddir),
265         options.sysroot)
266
267     prepend_env_var (env, "GST_VALIDATE_SCENARIOS_PATH", os.path.normpath(
268         "%s/subprojects/gst-examples/webrtc/check/validate/scenarios" %
269         SCRIPTDIR), options.sysroot)
270     prepend_env_var (env, "GST_VALIDATE_APPS_DIR", os.path.normpath(
271         "%s/subprojects/gst-examples/webrtc/check/validate/apps" %
272         SCRIPTDIR), options.sysroot)
273
274     if options.wine:
275         return get_wine_subprocess_env(options, env)
276
277     prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'meson'),
278         options.sysroot)
279
280     env["GST_PLUGIN_SYSTEM_PATH"] = ""
281     env["GST_PLUGIN_SCANNER"] = os.path.normpath(
282         "%s/subprojects/gstreamer/libs/gst/helpers/gst-plugin-scanner" % options.builddir)
283     env["GST_PTP_HELPER"] = os.path.normpath(
284         "%s/subprojects/gstreamer/libs/gst/helpers/gst-ptp-helper" % options.builddir)
285
286     if os.name == 'nt':
287         lib_path_envvar = 'PATH'
288     elif platform.system() == 'Darwin':
289         # RPATH is sufficient on macOS, and DYLD_LIBRARY_PATH can cause issues with dynamic linker path priority
290         lib_path_envvar = None
291     else:
292         lib_path_envvar = 'LD_LIBRARY_PATH'
293
294     prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(SCRIPTDIR, 'subprojects',
295                                                         'gst-python', 'plugin'),
296                     options.sysroot)
297     prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(PREFIX_DIR, 'lib',
298                                                         'gstreamer-1.0'),
299                     options.sysroot)
300     prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(options.builddir, 'subprojects',
301                                                          'libnice', 'gst'),
302                     options.sysroot)
303     prepend_env_var(env, "GST_VALIDATE_SCENARIOS_PATH",
304                     os.path.join(PREFIX_DIR, 'share', 'gstreamer-1.0',
305                                  'validate', 'scenarios'),
306                     options.sysroot)
307     prepend_env_var(env, "GI_TYPELIB_PATH", os.path.join(PREFIX_DIR, 'lib',
308                                                          'lib', 'girepository-1.0'),
309                     options.sysroot)
310     prepend_env_var(env, "PKG_CONFIG_PATH", os.path.join(PREFIX_DIR, 'lib', 'pkgconfig'),
311                     options.sysroot)
312
313     # gst-indent
314     prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'scripts'),
315                     options.sysroot)
316
317     # tools: gst-launch-1.0, gst-inspect-1.0
318     prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects',
319                                               'gstreamer', 'tools'),
320                     options.sysroot)
321     prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects',
322                                               'gst-plugins-base', 'tools'),
323                     options.sysroot)
324
325     # Library and binary search paths
326     prepend_env_var(env, "PATH", os.path.join(PREFIX_DIR, 'bin'),
327                     options.sysroot)
328     if lib_path_envvar != 'PATH':
329         prepend_env_var(env, lib_path_envvar, os.path.join(PREFIX_DIR, 'lib'),
330                         options.sysroot)
331         prepend_env_var(env, lib_path_envvar, os.path.join(PREFIX_DIR, 'lib64'),
332                         options.sysroot)
333     elif 'QMAKE' in os.environ:
334         # There's no RPATH on Windows, so we need to set PATH for the qt5 DLLs
335         prepend_env_var(env, 'PATH', os.path.dirname(os.environ['QMAKE']),
336                         options.sysroot)
337
338     meson = get_meson()
339     targets_s = subprocess.check_output(meson + ['introspect', options.builddir, '--targets'])
340     targets = json.loads(targets_s.decode())
341     paths = set()
342     mono_paths = set()
343     srcdir_path = pathlib.Path(options.srcdir)
344
345     build_options_s = subprocess.check_output(meson + ['introspect', options.builddir, '--buildoptions'])
346     build_options = json.loads(build_options_s.decode())
347     libdir, = [o['value'] for o in build_options if o['name'] == 'libdir']
348     libdir = PurePath(libdir)
349     prefix, = [o['value'] for o in build_options if o['name'] == 'prefix']
350     bindir, = [o['value'] for o in build_options if o['name'] == 'bindir']
351     prefix = PurePath(prefix)
352     bindir = prefix / bindir
353
354     global GSTPLUGIN_FILEPATH_REG_TEMPLATE
355     GSTPLUGIN_FILEPATH_REG_TEMPLATE = GSTPLUGIN_FILEPATH_REG_TEMPLATE.format(libdir=libdir.as_posix())
356
357     for target in targets:
358         filenames = listify(target['filename'])
359         if not target['installed']:
360             continue
361         for filename in filenames:
362             root = os.path.dirname(filename)
363             if srcdir_path / "subprojects/gst-devtools/validate/plugins" in (srcdir_path / root).parents:
364                 continue
365             if filename.endswith('.dll'):
366                 mono_paths.add(os.path.join(options.builddir, root))
367             if TYPELIB_REG.search(filename):
368                 prepend_env_var(env, "GI_TYPELIB_PATH",
369                                 os.path.join(options.builddir, root),
370                                 options.sysroot)
371             elif is_library_target_and_not_plugin(target, filename):
372                 prepend_env_var(env, lib_path_envvar,
373                                 os.path.join(options.builddir, root),
374                                 options.sysroot)
375             elif is_binary_target_and_in_path(target, filename, bindir):
376                 paths.add(os.path.join(options.builddir, root))
377             elif is_gio_module(target, filename, options.builddir):
378                 prepend_env_var(env, 'GIO_EXTRA_MODULES',
379                                 os.path.join(options.builddir, root),
380                                 options.sysroot)
381
382     with open(os.path.join(options.gstbuilddir, 'GstPluginsPath.json')) as f:
383         for plugin_path in json.load(f):
384             prepend_env_var(env, 'GST_PLUGIN_PATH', plugin_path,
385                             options.sysroot)
386
387     # Sort to iterate in a consistent order (`set`s and `hash`es are randomized)
388     for p in sorted(paths):
389         prepend_env_var(env, 'PATH', p, options.sysroot)
390
391     if os.name != 'nt':
392         for p in sorted(mono_paths):
393             prepend_env_var(env, "MONO_PATH", p, options.sysroot)
394
395     presets = set()
396     encoding_targets = set()
397     python_dirs = setup_gdb(options)
398     overrides_dirs = set()
399     if '--installed' in subprocess.check_output(meson + ['introspect', '-h']).decode():
400         installed_s = subprocess.check_output(meson + ['introspect', options.builddir, '--installed'])
401         for path, installpath in json.loads(installed_s.decode()).items():
402             installpath_parts = pathlib.Path(installpath).parts
403             path_parts = pathlib.Path(path).parts
404
405             # We want to add all python modules to the PYTHONPATH
406             # in a manner consistent with the way they would be imported:
407             # For example if the source path /home/meh/foo/bar.py
408             # is to be installed in /usr/lib/python/site-packages/foo/bar.py,
409             # we want to add /home/meh to the PYTHONPATH.
410             # This will only work for projects where the paths to be installed
411             # mirror the installed directory layout, for example if the path
412             # is /home/meh/baz/bar.py and the install path is
413             # /usr/lib/site-packages/foo/bar.py , we will not add anything
414             # to PYTHONPATH, but the current approach works with pygobject
415             # and gst-python at least.
416             if 'site-packages' in installpath_parts:
417                 install_subpath = os.path.join(*installpath_parts[installpath_parts.index('site-packages') + 1:])
418                 if path.endswith(install_subpath):
419                     if os.path.commonprefix(["gi/overrides", install_subpath]):
420                         overrides_dirs.add(os.path.dirname(path))
421                     else:
422                         python_dirs.add(path[:len (install_subpath) * -1])
423
424             if path.endswith('.prs'):
425                 presets.add(os.path.dirname(path))
426             elif path.endswith('.gep'):
427                 encoding_targets.add(
428                     os.path.abspath(os.path.join(os.path.dirname(path), '..')))
429
430             if path.endswith('gstomx.conf'):
431                 prepend_env_var(env, 'GST_OMX_CONFIG_DIR', os.path.dirname(path),
432                                 options.sysroot)
433
434         for p in sorted(presets):
435             prepend_env_var(env, 'GST_PRESET_PATH', p, options.sysroot)
436
437         for t in sorted(encoding_targets):
438             prepend_env_var(env, 'GST_ENCODING_TARGET_PATH', t, options.sysroot)
439
440     # Check if meson has generated -uninstalled pkgconfig files
441     meson_uninstalled = pathlib.Path(options.builddir) / 'meson-uninstalled'
442     if meson_uninstalled.is_dir():
443         prepend_env_var(env, 'PKG_CONFIG_PATH', str(meson_uninstalled), options.sysroot)
444
445     for python_dir in sorted(python_dirs):
446         prepend_env_var(env, 'PYTHONPATH', python_dir, options.sysroot)
447
448     for python_dir in sorted(overrides_dirs):
449         prepend_env_var(env, '_GI_OVERRIDES_PATH', python_dir, options.sysroot)
450
451     mesonpath = os.path.join(SCRIPTDIR, "meson")
452     if os.path.join(mesonpath):
453         # Add meson/ into PYTHONPATH if we are using a local meson
454         prepend_env_var(env, 'PYTHONPATH', mesonpath, options.sysroot)
455
456     # Ensure that gst-python/gi is used first
457     prepend_env_var(env, "PYTHONPATH", os.path.join(SCRIPTDIR, 'subprojects', 'gst-python'),
458                     options.sysroot)
459
460     # For devhelp books
461     if 'XDG_DATA_DIRS' not in env or not env['XDG_DATA_DIRS']:
462         # Preserve default paths when empty
463         prepend_env_var(env, 'XDG_DATA_DIRS', '/usr/local/share/:/usr/share/', '')
464
465     prepend_env_var (env, 'XDG_DATA_DIRS', os.path.join(options.builddir,
466                                                         'subprojects',
467                                                         'gst-docs',
468                                                         'GStreamer-doc'),
469                      options.sysroot)
470
471     if 'XDG_CONFIG_DIRS' not in env or not env['XDG_CONFIG_DIRS']:
472         # Preserve default paths when empty
473         prepend_env_var(env, 'XDG_CONFIG_DIRS', '/etc/local/xdg:/etc/xdg', '')
474
475     prepend_env_var(env, "XDG_CONFIG_DIRS", os.path.join(PREFIX_DIR, 'etc', 'xdg'),
476                     options.sysroot)
477
478     return env
479
480 def get_windows_shell():
481     command = ['powershell.exe' ,'-noprofile', '-executionpolicy', 'bypass', '-file',
482         os.path.join(SCRIPTDIR, 'data', 'misc', 'cmd_or_ps.ps1')]
483     result = subprocess.check_output(command)
484     return result.decode().strip()
485
486 if __name__ == "__main__":
487     parser = argparse.ArgumentParser(prog="gst-env")
488
489     parser.add_argument("--builddir",
490                         default=DEFAULT_BUILDDIR,
491                         help="The meson build directory")
492     parser.add_argument("--gstbuilddir",
493                         default=None,
494                         help="The meson GStreamer build directory (defaults to builddir)")
495     parser.add_argument("--srcdir",
496                         default=SCRIPTDIR,
497                         help="The top level source directory")
498     parser.add_argument("--sysroot",
499                         default='',
500                         help="The sysroot path used during cross-compilation")
501     parser.add_argument("--wine",
502                         default='',
503                         help="Build a wine env based on specified wine command")
504     parser.add_argument("--winepath",
505                         default='',
506                         help="Extra path to set to WINEPATH.")
507     parser.add_argument("--only-environment",
508                         action='store_true',
509                         default=False,
510                         help="Do not start a shell, only print required environment.")
511     options, args = parser.parse_known_args()
512
513     if not os.path.exists(options.builddir):
514         print("GStreamer not built in %s\n\nBuild it and try again" %
515               options.builddir)
516         exit(1)
517
518     if options.gstbuilddir and not os.path.exists(options.gstbuilddir):
519         print("GStreamer is not built in %s\n\nBuild it and try again" %
520               options.gstbuilddir)
521         exit(1)
522     elif not options.gstbuilddir:
523         options.gstbuilddir = options.builddir
524
525     options.builddir = os.path.abspath(options.builddir)
526     options.gstbuilddir = os.path.abspath(options.gstbuilddir)
527
528     if not os.path.exists(options.srcdir):
529         print("The specified source dir does not exist" %
530               options.srcdir)
531         exit(1)
532
533     # The following incantation will retrieve the current branch name.
534     try:
535       gst_version = git("rev-parse", "--symbolic-full-name", "--abbrev-ref", "HEAD",
536                         repository_path=options.srcdir).strip('\n')
537     except subprocess.CalledProcessError:
538       gst_version = "unknown"
539
540     if options.wine:
541         gst_version += '-' + os.path.basename(options.wine)
542
543     env = get_subprocess_env(options, gst_version)
544     if not args:
545         if os.name == 'nt':
546             shell = get_windows_shell()
547             if shell == 'powershell.exe':
548                 args = ['powershell.exe']
549                 args += ['-NoLogo', '-NoExit']
550                 prompt = 'function global:prompt {  "[gst-' + gst_version + '"+"] PS " + $PWD + "> "}'
551                 args += ['-Command', prompt]
552             else:
553                 args = [os.environ.get("COMSPEC", r"C:\WINDOWS\system32\cmd.exe")]
554                 args += ['/k', 'prompt [gst-{}] $P$G'.format(gst_version)]
555         else:
556             args = [os.environ.get("SHELL", os.path.realpath("/bin/sh"))]
557         if args[0].endswith('bash') and not str_to_bool(os.environ.get("GST_BUILD_DISABLE_PS1_OVERRIDE", r"FALSE")):
558             # Let the GC remove the tmp file
559             tmprc = tempfile.NamedTemporaryFile(mode='w')
560             bashrc = os.path.expanduser('~/.bashrc')
561             if os.path.exists(bashrc):
562                 with open(bashrc, 'r') as src:
563                     shutil.copyfileobj(src, tmprc)
564             tmprc.write('\nexport PS1="[gst-%s] $PS1"' % gst_version)
565             tmprc.flush()
566             if is_bash_completion_available(options):
567                 bash_completions_files = []
568                 for p in BASH_COMPLETION_PATHS:
569                     if os.path.exists(p):
570                         bash_completions_files +=  os.listdir(path=p)
571                 bc_rc = BC_RC.format(bash_completions=' '.join(bash_completions_files), bash_completions_paths=' '.join(BASH_COMPLETION_PATHS))
572                 tmprc.write(bc_rc)
573                 tmprc.flush()
574             args.append("--rcfile")
575             args.append(tmprc.name)
576         elif args[0].endswith('fish'):
577             # Ignore SIGINT while using fish as the shell to make it behave
578             # like other shells such as bash and zsh.
579             # See: https://gitlab.freedesktop.org/gstreamer/gst-build/issues/18
580             signal.signal(signal.SIGINT, lambda x, y: True)
581             # Set the prompt
582             args.append('--init-command')
583             prompt_cmd = '''functions --copy fish_prompt original_fish_prompt
584             function fish_prompt
585                 echo -n '[gst-{}] '(original_fish_prompt)
586             end'''.format(gst_version)
587             args.append(prompt_cmd)
588         elif args[0].endswith('zsh'):
589             tmpdir = tempfile.TemporaryDirectory()
590             # Let the GC remove the tmp file
591             tmprc = open(os.path.join(tmpdir.name, '.zshrc'), 'w')
592             zshrc = os.path.expanduser('~/.zshrc')
593             if os.path.exists(zshrc):
594                 with open(zshrc, 'r') as src:
595                     shutil.copyfileobj(src, tmprc)
596             tmprc.write('\nexport PROMPT="[gst-{}] $PROMPT"'.format(gst_version))
597             tmprc.flush()
598             env['ZDOTDIR'] = tmpdir.name
599     try:
600         if options.only_environment:
601             for name, value in env.items():
602                 print('{}={}'.format(name, shlex.quote(value)))
603                 print('export {}'.format(name))
604         else:
605             if os.environ.get("CI_PROJECT_NAME"):
606                 print("Ignoring SIGINT when running on the CI,"
607                       " as we get spurious sigint in there for some reason.")
608                 signal.signal(signal.SIGINT, signal.SIG_IGN)
609             exit(subprocess.call(args, close_fds=False, env=env))
610
611     except subprocess.CalledProcessError as e:
612         exit(e.returncode)