spec: remove release macro
[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     # plugin scanner and generator
322     prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects',
323                                               'gstreamer', 'docs'),
324                     options.sysroot)
325     prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects',
326                                               'gst-plugins-base', 'tools'),
327                     options.sysroot)
328
329     # Library and binary search paths
330     prepend_env_var(env, "PATH", os.path.join(PREFIX_DIR, 'bin'),
331                     options.sysroot)
332     if lib_path_envvar != 'PATH':
333         prepend_env_var(env, lib_path_envvar, os.path.join(PREFIX_DIR, 'lib'),
334                         options.sysroot)
335         prepend_env_var(env, lib_path_envvar, os.path.join(PREFIX_DIR, 'lib64'),
336                         options.sysroot)
337     elif 'QMAKE' in os.environ:
338         # There's no RPATH on Windows, so we need to set PATH for the qt5 DLLs
339         prepend_env_var(env, 'PATH', os.path.dirname(os.environ['QMAKE']),
340                         options.sysroot)
341
342     meson = get_meson()
343     targets_s = subprocess.check_output(meson + ['introspect', options.builddir, '--targets'])
344     targets = json.loads(targets_s.decode())
345     paths = set()
346     mono_paths = set()
347     srcdir_path = pathlib.Path(options.srcdir)
348
349     build_options_s = subprocess.check_output(meson + ['introspect', options.builddir, '--buildoptions'])
350     build_options = json.loads(build_options_s.decode())
351     libdir, = [o['value'] for o in build_options if o['name'] == 'libdir']
352     libdir = PurePath(libdir)
353     prefix, = [o['value'] for o in build_options if o['name'] == 'prefix']
354     bindir, = [o['value'] for o in build_options if o['name'] == 'bindir']
355     prefix = PurePath(prefix)
356     bindir = prefix / bindir
357
358     global GSTPLUGIN_FILEPATH_REG_TEMPLATE
359     GSTPLUGIN_FILEPATH_REG_TEMPLATE = GSTPLUGIN_FILEPATH_REG_TEMPLATE.format(libdir=libdir.as_posix())
360
361     for target in targets:
362         filenames = listify(target['filename'])
363         if not target['installed']:
364             continue
365         for filename in filenames:
366             root = os.path.dirname(filename)
367             if srcdir_path / "subprojects/gst-devtools/validate/plugins" in (srcdir_path / root).parents:
368                 continue
369             if filename.endswith('.dll'):
370                 mono_paths.add(os.path.join(options.builddir, root))
371             if TYPELIB_REG.search(filename):
372                 prepend_env_var(env, "GI_TYPELIB_PATH",
373                                 os.path.join(options.builddir, root),
374                                 options.sysroot)
375             elif is_library_target_and_not_plugin(target, filename):
376                 prepend_env_var(env, lib_path_envvar,
377                                 os.path.join(options.builddir, root),
378                                 options.sysroot)
379             elif is_binary_target_and_in_path(target, filename, bindir):
380                 paths.add(os.path.join(options.builddir, root))
381             elif is_gio_module(target, filename, options.builddir):
382                 prepend_env_var(env, 'GIO_EXTRA_MODULES',
383                                 os.path.join(options.builddir, root),
384                                 options.sysroot)
385
386     with open(os.path.join(options.gstbuilddir, 'GstPluginsPath.json')) as f:
387         for plugin_path in json.load(f):
388             prepend_env_var(env, 'GST_PLUGIN_PATH', plugin_path,
389                             options.sysroot)
390
391     # Sort to iterate in a consistent order (`set`s and `hash`es are randomized)
392     for p in sorted(paths):
393         prepend_env_var(env, 'PATH', p, options.sysroot)
394
395     if os.name != 'nt':
396         for p in sorted(mono_paths):
397             prepend_env_var(env, "MONO_PATH", p, options.sysroot)
398
399     presets = set()
400     encoding_targets = set()
401     python_dirs = setup_gdb(options)
402     overrides_dirs = set()
403     if '--installed' in subprocess.check_output(meson + ['introspect', '-h']).decode():
404         installed_s = subprocess.check_output(meson + ['introspect', options.builddir, '--installed'])
405         for path, installpath in json.loads(installed_s.decode()).items():
406             installpath_parts = pathlib.Path(installpath).parts
407             path_parts = pathlib.Path(path).parts
408
409             # We want to add all python modules to the PYTHONPATH
410             # in a manner consistent with the way they would be imported:
411             # For example if the source path /home/meh/foo/bar.py
412             # is to be installed in /usr/lib/python/site-packages/foo/bar.py,
413             # we want to add /home/meh to the PYTHONPATH.
414             # This will only work for projects where the paths to be installed
415             # mirror the installed directory layout, for example if the path
416             # is /home/meh/baz/bar.py and the install path is
417             # /usr/lib/site-packages/foo/bar.py , we will not add anything
418             # to PYTHONPATH, but the current approach works with pygobject
419             # and gst-python at least.
420             if 'site-packages' in installpath_parts:
421                 install_subpath = os.path.join(*installpath_parts[installpath_parts.index('site-packages') + 1:])
422                 if path.endswith(install_subpath):
423                     if os.path.commonprefix(["gi/overrides", install_subpath]):
424                         overrides_dirs.add(os.path.dirname(path))
425                     else:
426                         python_dirs.add(path[:len (install_subpath) * -1])
427
428             if path.endswith('.prs'):
429                 presets.add(os.path.dirname(path))
430             elif path.endswith('.gep'):
431                 encoding_targets.add(
432                     os.path.abspath(os.path.join(os.path.dirname(path), '..')))
433
434             if path.endswith('gstomx.conf'):
435                 prepend_env_var(env, 'GST_OMX_CONFIG_DIR', os.path.dirname(path),
436                                 options.sysroot)
437
438         for p in sorted(presets):
439             prepend_env_var(env, 'GST_PRESET_PATH', p, options.sysroot)
440
441         for t in sorted(encoding_targets):
442             prepend_env_var(env, 'GST_ENCODING_TARGET_PATH', t, options.sysroot)
443
444     # Check if meson has generated -uninstalled pkgconfig files
445     meson_uninstalled = pathlib.Path(options.builddir) / 'meson-uninstalled'
446     if meson_uninstalled.is_dir():
447         prepend_env_var(env, 'PKG_CONFIG_PATH', str(meson_uninstalled), options.sysroot)
448
449     for python_dir in sorted(python_dirs):
450         prepend_env_var(env, 'PYTHONPATH', python_dir, options.sysroot)
451
452     for python_dir in sorted(overrides_dirs):
453         prepend_env_var(env, '_GI_OVERRIDES_PATH', python_dir, options.sysroot)
454
455     mesonpath = os.path.join(SCRIPTDIR, "meson")
456     if os.path.join(mesonpath):
457         # Add meson/ into PYTHONPATH if we are using a local meson
458         prepend_env_var(env, 'PYTHONPATH', mesonpath, options.sysroot)
459
460     # Ensure that gst-python/gi is used first
461     prepend_env_var(env, "PYTHONPATH", os.path.join(SCRIPTDIR, 'subprojects', 'gst-python'),
462                     options.sysroot)
463
464     # For devhelp books
465     if 'XDG_DATA_DIRS' not in env or not env['XDG_DATA_DIRS']:
466         # Preserve default paths when empty
467         prepend_env_var(env, 'XDG_DATA_DIRS', '/usr/local/share/:/usr/share/', '')
468
469     prepend_env_var (env, 'XDG_DATA_DIRS', os.path.join(options.builddir,
470                                                         'subprojects',
471                                                         'gst-docs',
472                                                         'GStreamer-doc'),
473                      options.sysroot)
474
475     if 'XDG_CONFIG_DIRS' not in env or not env['XDG_CONFIG_DIRS']:
476         # Preserve default paths when empty
477         prepend_env_var(env, 'XDG_CONFIG_DIRS', '/etc/local/xdg:/etc/xdg', '')
478
479     prepend_env_var(env, "XDG_CONFIG_DIRS", os.path.join(PREFIX_DIR, 'etc', 'xdg'),
480                     options.sysroot)
481
482     return env
483
484 def get_windows_shell():
485     command = ['powershell.exe' ,'-noprofile', '-executionpolicy', 'bypass', '-file',
486         os.path.join(SCRIPTDIR, 'data', 'misc', 'cmd_or_ps.ps1')]
487     result = subprocess.check_output(command)
488     return result.decode().strip()
489
490 if __name__ == "__main__":
491     parser = argparse.ArgumentParser(prog="gst-env")
492
493     parser.add_argument("--builddir",
494                         default=DEFAULT_BUILDDIR,
495                         help="The meson build directory")
496     parser.add_argument("--gstbuilddir",
497                         default=None,
498                         help="The meson GStreamer build directory (defaults to builddir)")
499     parser.add_argument("--srcdir",
500                         default=SCRIPTDIR,
501                         help="The top level source directory")
502     parser.add_argument("--sysroot",
503                         default='',
504                         help="The sysroot path used during cross-compilation")
505     parser.add_argument("--wine",
506                         default='',
507                         help="Build a wine env based on specified wine command")
508     parser.add_argument("--winepath",
509                         default='',
510                         help="Extra path to set to WINEPATH.")
511     parser.add_argument("--only-environment",
512                         action='store_true',
513                         default=False,
514                         help="Do not start a shell, only print required environment.")
515     options, args = parser.parse_known_args()
516
517     if not os.path.exists(options.builddir):
518         print("GStreamer not built in %s\n\nBuild it and try again" %
519               options.builddir)
520         exit(1)
521
522     if options.gstbuilddir and not os.path.exists(options.gstbuilddir):
523         print("GStreamer is not built in %s\n\nBuild it and try again" %
524               options.gstbuilddir)
525         exit(1)
526     elif not options.gstbuilddir:
527         options.gstbuilddir = options.builddir
528
529     options.builddir = os.path.abspath(options.builddir)
530     options.gstbuilddir = os.path.abspath(options.gstbuilddir)
531
532     if not os.path.exists(options.srcdir):
533         print("The specified source dir does not exist" %
534               options.srcdir)
535         exit(1)
536
537     # The following incantation will retrieve the current branch name.
538     try:
539       gst_version = git("rev-parse", "--symbolic-full-name", "--abbrev-ref", "HEAD",
540                         repository_path=options.srcdir).strip('\n')
541     except subprocess.CalledProcessError:
542       gst_version = "unknown"
543
544     if options.wine:
545         gst_version += '-' + os.path.basename(options.wine)
546
547     env = get_subprocess_env(options, gst_version)
548     if not args:
549         if os.name == 'nt':
550             shell = get_windows_shell()
551             if shell == 'powershell.exe':
552                 args = ['powershell.exe']
553                 args += ['-NoLogo', '-NoExit']
554                 prompt = 'function global:prompt {  "[gst-' + gst_version + '"+"] PS " + $PWD + "> "}'
555                 args += ['-Command', prompt]
556             else:
557                 args = [os.environ.get("COMSPEC", r"C:\WINDOWS\system32\cmd.exe")]
558                 args += ['/k', 'prompt [gst-{}] $P$G'.format(gst_version)]
559         else:
560             args = [os.environ.get("SHELL", os.path.realpath("/bin/sh"))]
561         if args[0].endswith('bash') and not str_to_bool(os.environ.get("GST_BUILD_DISABLE_PS1_OVERRIDE", r"FALSE")):
562             # Let the GC remove the tmp file
563             tmprc = tempfile.NamedTemporaryFile(mode='w')
564             bashrc = os.path.expanduser('~/.bashrc')
565             if os.path.exists(bashrc):
566                 with open(bashrc, 'r') as src:
567                     shutil.copyfileobj(src, tmprc)
568             tmprc.write('\nexport PS1="[gst-%s] $PS1"' % gst_version)
569             tmprc.flush()
570             if is_bash_completion_available(options):
571                 bash_completions_files = []
572                 for p in BASH_COMPLETION_PATHS:
573                     if os.path.exists(p):
574                         bash_completions_files +=  os.listdir(path=p)
575                 bc_rc = BC_RC.format(bash_completions=' '.join(bash_completions_files), bash_completions_paths=' '.join(BASH_COMPLETION_PATHS))
576                 tmprc.write(bc_rc)
577                 tmprc.flush()
578             args.append("--rcfile")
579             args.append(tmprc.name)
580         elif args[0].endswith('fish'):
581             # Ignore SIGINT while using fish as the shell to make it behave
582             # like other shells such as bash and zsh.
583             # See: https://gitlab.freedesktop.org/gstreamer/gst-build/issues/18
584             signal.signal(signal.SIGINT, lambda x, y: True)
585             # Set the prompt
586             args.append('--init-command')
587             prompt_cmd = '''functions --copy fish_prompt original_fish_prompt
588             function fish_prompt
589                 echo -n '[gst-{}] '(original_fish_prompt)
590             end'''.format(gst_version)
591             args.append(prompt_cmd)
592         elif args[0].endswith('zsh'):
593             tmpdir = tempfile.TemporaryDirectory()
594             # Let the GC remove the tmp file
595             tmprc = open(os.path.join(tmpdir.name, '.zshrc'), 'w')
596             zshrc = os.path.expanduser('~/.zshrc')
597             if os.path.exists(zshrc):
598                 with open(zshrc, 'r') as src:
599                     shutil.copyfileobj(src, tmprc)
600             tmprc.write('\nexport PROMPT="[gst-{}] $PROMPT"'.format(gst_version))
601             tmprc.flush()
602             env['ZDOTDIR'] = tmpdir.name
603     try:
604         if options.only_environment:
605             for name, value in env.items():
606                 print('{}={}'.format(name, shlex.quote(value)))
607                 print('export {}'.format(name))
608         else:
609             if os.environ.get("CI_PROJECT_NAME"):
610                 print("Ignoring SIGINT when running on the CI,"
611                       " as we get spurious sigint in there for some reason.")
612                 signal.signal(signal.SIGINT, signal.SIG_IGN)
613             exit(subprocess.call(args, close_fds=False, env=env))
614
615     except subprocess.CalledProcessError as e:
616         exit(e.returncode)