def unix_path(path, path_flavor=None): """"Used to translate windows paths to MSYS unix paths like c/users/path/to/file. Not working in a regular console or MinGW!""" if not path: return None if os.path.exists(path): path = get_cased_path( path ) # if the path doesn't exist (and abs) we cannot guess the casing path_flavor = path_flavor or OSInfo.detect_windows_subsystem() or MSYS2 path = path.replace(":/", ":\\") pattern = re.compile(r'([a-z]):\\', re.IGNORECASE) path = pattern.sub('/\\1/', path).replace('\\', '/') if path_flavor in (MSYS, MSYS2): return path.lower() elif path_flavor == CYGWIN: return '/cygdrive' + path.lower() elif path_flavor == WSL: return '/mnt' + path[0:2].lower() + path[2:] elif path_flavor == SFU: path = path.lower() return '/dev/fs' + path[0] + path[1:].capitalize() return None
def detect_windows_subsystem_test(self): # Dont raise test result = OSInfo.detect_windows_subsystem() if not OSInfo.bash_path() or platform.system() != "Windows": self.assertEqual(None, result) else: self.assertEqual(str, type(result))
def run_in_windows_bash(conanfile, bashcmd, cwd=None, subsystem=None, msys_mingw=True, env=None): """ Will run a unix command inside a bash terminal It requires to have MSYS2, CYGWIN, or WSL """ env = env or {} if platform.system() != "Windows": raise ConanException("Command only for Windows operating system") subsystem = subsystem or OSInfo.detect_windows_subsystem() if not subsystem: raise ConanException( "Cannot recognize the Windows subsystem, install MSYS2/cygwin " "or specify a build_require to apply it.") if subsystem == MSYS2 and msys_mingw: # This needs to be set so that msys2 bash profile will set up the environment correctly. env_vars = { "MSYSTEM": ("MINGW32" if conanfile.settings.get_safe("arch") == "x86" else "MINGW64"), "MSYS2_PATH_TYPE": "inherit" } else: env_vars = {} with environment_append(env_vars): hack_env = "" # In the bash.exe from WSL this trick do not work, always the /usr/bin etc at first place if subsystem != WSL: def get_path_value(container, subsystem_name): """Gets the path from the container dict and returns a string with the path for the subsystem_name""" _path_key = next( (name for name in container.keys() if "path" == name.lower()), None) if _path_key: _path_value = container.get(_path_key) if isinstance(_path_value, list): return ":".join([ unix_path(path, path_flavor=subsystem_name) for path in _path_value ]) else: return unix_path(_path_value, path_flavor=subsystem_name) # First get the PATH from the conanfile.env inherited_path = get_path_value(conanfile.env, subsystem) # Then get the PATH from the real env env_path = get_path_value(env, subsystem) # Both together full_env = ":".join(v for v in [env_path, inherited_path] if v) # Put the build_requires and requires path at the first place inside the shell hack_env = ' && PATH="%s:$PATH"' % full_env if full_env else "" for var_name, value in env.items(): if var_name == "PATH": continue hack_env += ' && %s=%s' % (var_name, value) # Needed to change to that dir inside the bash shell if cwd and not os.path.isabs(cwd): cwd = os.path.join(get_cwd(), cwd) curdir = unix_path(cwd or get_cwd(), path_flavor=subsystem) to_run = 'cd "%s"%s && %s ' % (curdir, hack_env, bashcmd) bash_path = OSInfo.bash_path() bash_path = '"%s"' % bash_path if " " in bash_path else bash_path wincmd = '%s --login -c %s' % (bash_path, escape_windows_cmd(to_run)) conanfile.output.info('run_in_windows_bash: %s' % wincmd) # If is there any other env var that we know it contains paths, convert it to unix_path used_special_vars = [ var for var in ["AR", "AS", "RANLIB", "LD", "STRIP", "CC", "CXX"] if var in conanfile.env.keys() ] normalized_env = { p: unix_path(conanfile.env[p], path_flavor=subsystem) for p in used_special_vars } # https://github.com/conan-io/conan/issues/2839 (subprocess=True) with environment_append(normalized_env): return conanfile._conan_runner(wincmd, output=conanfile.output, subprocess=True)