def create_local_svn_checkout(files, repo_url, rel_project_path=None, commit_msg='default commit message', delete_checkout=True, folder=None): tmp_dir = folder or temp_folder() try: rel_project_path = rel_project_path or str(uuid.uuid4()) # Do not use SVN class as it is what we will be testing subprocess.check_output('svn co "{url}" "{path}"'.format(url=repo_url, path=tmp_dir), shell=True) tmp_project_dir = os.path.join(tmp_dir, rel_project_path) mkdir(tmp_project_dir) save_files(tmp_project_dir, files) with chdir(tmp_project_dir): subprocess.check_output("svn add .", shell=True) subprocess.check_output('svn commit -m "{}"'.format(commit_msg), shell=True) if SVN.get_version() >= SVN.API_CHANGE_VERSION: rev = check_output_runner("svn info --show-item revision").strip() else: import xml.etree.ElementTree as ET output = check_output_runner("svn info --xml").strip() root = ET.fromstring(output) rev = root.findall("./entry")[0].get("revision") project_url = repo_url + "/" + quote(rel_project_path.replace("\\", "/")) return project_url, rev finally: if delete_checkout: shutil.rmtree(tmp_dir, ignore_errors=False, onerror=try_remove_readonly)
def git_create_bare_repo(folder=None, reponame="repo.git"): folder = folder or temp_folder() cwd = os.getcwd() try: os.chdir(folder) check_output_runner('git init --bare {}'.format(reponame)) return os.path.join(folder, reponame).replace("\\", "/") finally: os.chdir(cwd)
def environment_deactivate_test(self): if platform.system() == "Windows": """ This test fails. The deactivation script takes the value of some envvars set by the activation script to recover the previous values (set PATH=OLD_PATH). As this test is running each command in a different shell, the envvar OLD_PATH that has been set by the 'activate' script doesn't exist when we run 'deactivate' in a different shell... TODO: Remove this test """ self.skipTest("This won't work in Windows") in_windows = platform.system() == "Windows" env_cmd = "set" if in_windows else "env" extension = "bat" if in_windows else "sh" def env_output_to_dict(env_output): env = {} for line in env_output.splitlines(): tmp = line.split("=") # OLDPWD is cleared when a child script is started if tmp[0] not in ["SHLVL", "_", "PS1", "OLDPWD"]: env[tmp[0]] = tmp[1].replace("\\", "/") return env def get_cmd(script_name): if in_windows: return "%s && set" % script_name else: return "bash -c 'source %s && env'" % script_name conanfile = textwrap.dedent(""" from conans import ConanFile class TestConan(ConanFile): settings = "os", "compiler", "arch", "build_type" generators = "virtualbuildenv" """) client = TestClient(path_with_spaces=False) client.save({"conanfile.py": conanfile}) client.run("install .") output = check_output_runner(env_cmd) normal_environment = env_output_to_dict(output) client.run("install .") act_build_file = os.path.join(client.current_folder, "activate_build.%s" % extension) deact_build_file = os.path.join(client.current_folder, "deactivate_build.%s" % extension) self.assertTrue(os.path.exists(act_build_file)) self.assertTrue(os.path.exists(deact_build_file)) output = check_output_runner(get_cmd(act_build_file)) activate_environment = env_output_to_dict(output) self.assertNotEqual(normal_environment, activate_environment) output = check_output_runner(get_cmd(deact_build_file)) deactivate_environment = env_output_to_dict(output) self.assertDictEqual(normal_environment, deactivate_environment)
def test_unix_to_dos_unit(self): def save_file(contents): tmp = temp_folder() filepath = os.path.join(tmp, "a_file.txt") save(filepath, contents) return filepath fp = save_file(b"a line\notherline\n") if platform.system() != "Windows": output = check_output_runner(["file", fp], stderr=subprocess.STDOUT) self.assertIn("ASCII text", str(output)) self.assertNotIn("CRLF", str(output)) tools.unix2dos(fp) output = check_output_runner(["file", fp], stderr=subprocess.STDOUT) self.assertIn("ASCII text", str(output)) self.assertIn("CRLF", str(output)) else: fc = tools.load(fp) self.assertNotIn("\r\n", fc) tools.unix2dos(fp) fc = tools.load(fp) self.assertIn("\r\n", fc) self.assertEqual("a line\r\notherline\r\n", str(tools.load(fp))) fp = save_file(b"a line\r\notherline\r\n") if platform.system() != "Windows": output = check_output_runner(["file", fp], stderr=subprocess.STDOUT) self.assertIn("ASCII text", str(output)) self.assertIn("CRLF", str(output)) tools.dos2unix(fp) output = check_output_runner(["file", fp], stderr=subprocess.STDOUT) self.assertIn("ASCII text", str(output)) self.assertNotIn("CRLF", str(output)) else: fc = tools.load(fp) self.assertIn("\r\n", fc) tools.dos2unix(fp) fc = tools.load(fp) self.assertNotIn("\r\n", fc) self.assertEqual("a line\notherline\n", str(tools.load(fp)))
def test_detect_default_in_mac_os_using_gcc_as_default(self): """ Test if gcc in Mac OS X is using apple-clang as frontend """ # See: https://github.com/conan-io/conan/issues/2231 try: output = check_output_runner(["gcc", "--version"], stderr=subprocess.STDOUT) except subprocess.CalledProcessError: # gcc is not installed or there is any error (no test scenario) return if "clang" not in output: # Not test scenario gcc should display clang in output # see: https://stackoverflow.com/questions/19535422/os-x-10-9-gcc-links-to-clang raise Exception( "Apple gcc doesn't point to clang with gcc frontend anymore!") output = TestBufferConanOutput() with tools.environment_append({"CC": "gcc"}): result = detect_defaults_settings( output, profile_path=DEFAULT_PROFILE_NAME) # result is a list of tuples (name, value) so converting it to dict result = dict(result) # No compiler should be detected self.assertIsNone(result.get("compiler", None)) self.assertIn("gcc detected as a frontend using apple-clang", output) self.assertIsNotNone(output.error)
def check_cmd_version( cmd_name: str, ver_range_expr: str, ver_opts: typing.List[str] = ('--version',), ver_output_pattern: str = r'.*?([0-9][.0-9a-zA-Z-_]+)', log_output: typing.Union[ScopedOutput, logging.Logger] = default_logger ) -> bool: cmd = [ cmd_name, ] cmd.extend(ver_opts) output = check_output_runner(cmd) if output: output = output.strip() match = re.match(ver_output_pattern, output) if match: results = [] ver_str = match.group(1) log_output.info('{} version = {}'.format(cmd_name, ver_str)) ver_satisfied = range_resolver.satisfying([ver_str,], ver_range_expr, results) for result in results: log_output.info(result) if ver_satisfied: return True else: log_output.info('{} version does not meet requirement {}'.format(cmd_name, ver_range_expr)) else: msg = 'WARNING: output from {} is {}, which does not match version pattern `{}`'.format(' '.join(cmd), output, ver_output_pattern.pattern) log_output.warn(msg) else: log_output.warn('WARNING: no output from command {}'.format(' '.join(cmd))) return False
def with_pacman(self): if self.is_linux: return self.linux_distro in ["arch", "manjaro"] elif self.is_windows and which('uname.exe'): uname = check_output_runner(['uname.exe', '-s']) return uname.startswith('MSYS_NT') and which('pacman.exe') return False
def test_check_output_runner(self): original_temp = temp_folder() patched_temp = os.path.join(original_temp, "dir with spaces") payload = "hello world" with patch("tempfile.mktemp") as mktemp: mktemp.return_value = patched_temp output = check_output_runner(["echo", payload], stderr=subprocess.STDOUT) self.assertIn(payload, str(output))
def run(self, command): command = "%s %s" % (self.cmd_command, command) with chdir(self.folder) if self.folder else no_op(): with environment_append({"LC_ALL": "en_US.UTF-8"}) if self._force_eng else no_op(): with pyinstaller_bundle_env_cleaned(): if not self._runner: return check_output_runner(command).strip() else: return self._runner(command)
def get_aix_conf(options=None): options = " %s" % options if options else "" if not OSInfo().is_aix: raise ConanException("Command only for AIX operating system") try: ret = check_output_runner("getconf%s" % options).strip() return ret except Exception: return None
def _parse_output(self, option): executable = self._conanfile.conf.get("tools.gnu:pkg_config", default="pkg-config") command = [executable, '--' + option, self._library, '--print-errors'] try: env = Environment() if self._pkg_config_path: env.prepend_path("PKG_CONFIG_PATH", self._pkg_config_path) with env.vars(self._conanfile).apply(): return check_output_runner(command).strip() except subprocess.CalledProcessError as e: raise ConanException('pkg-config command %s failed with error: %s' % (command, e))
def vcvars_dict(conanfile=None, arch=None, compiler_version=None, force=False, filter_known_paths=False, vcvars_ver=None, winsdk_version=None, only_diff=True, output=None, settings=None): known_path_lists = ("include", "lib", "libpath", "path") cmd = vcvars_command(conanfile, settings=settings, arch=arch, compiler_version=compiler_version, force=force, vcvars_ver=vcvars_ver, winsdk_version=winsdk_version, output=output) cmd += " && set" ret = check_output_runner(cmd) new_env = {} for line in ret.splitlines(): line = line.strip() if line == "\n" or not line: continue try: name_var, value = line.split("=", 1) new_value = value.split(os.pathsep) if name_var.lower() in known_path_lists else value # Return only new vars & changed ones, but only with the changed elements if the var is # a list if only_diff: old_value = os.environ.get(name_var) if name_var.lower() == "path": old_values_lower = [v.lower() for v in old_value.split(os.pathsep)] # Clean all repeated entries, not append if the element was already there new_env[name_var] = [v for v in new_value if v.lower() not in old_values_lower] elif old_value and value.endswith(os.pathsep + old_value): # The new value ends with separator and the old value, is a list, # get only the new elements new_env[name_var] = value[:-(len(old_value) + 1)].split(os.pathsep) elif value != old_value: # Only if the vcvars changed something, we return the variable, # otherwise is not vcvars related new_env[name_var] = new_value else: new_env[name_var] = new_value except ValueError: pass if filter_known_paths: def relevant_path(_path): _path = _path.replace("\\", "/").lower() keywords = "msbuild", "visual", "microsoft", "/msvc/", "/vc/", "system32", "windows" return any(word in _path for word in keywords) path_key = next((name for name in new_env.keys() if "path" == name.lower()), None) if path_key: path = [entry for entry in new_env.get(path_key, "") if relevant_path(entry)] new_env[path_key] = ";".join(path) return new_env
def git_add_changes_commit(folder, msg="fix"): cwd = os.getcwd() try: os.chdir(folder) # Make sure user and email exist, otherwise it can error check_output_runner('git config user.name "Your Name"') check_output_runner('git config user.email "*****@*****.**"') check_output_runner('git add . && git commit -m "{}"'.format(msg)) return check_output_runner("git rev-parse HEAD").strip() finally: os.chdir(cwd)
def test_short_paths_home_set_acl(self): """ When CONAN_USER_HOME_SHORT is living in NTFS file systems, current user needs to be granted with full control permission to avoid access problems when cygwin/msys2 windows subsystems are mounting/using that folder. """ cache_folder = temp_folder( False) # Creates a temporary folder in %HOME%\appdata\local\temp out = subprocess.check_output("wmic logicaldisk %s get FileSystem" % os.path.splitdrive(cache_folder)[0]) if "NTFS" not in str(out): return short_folder = os.path.join(temp_folder(False), ".cnacls") self.assertFalse(os.path.exists(short_folder), "short_folder: %s shouldn't exists" % short_folder) os.makedirs(short_folder) current_domain = os.environ['USERDOMAIN'] current_user = os.environ['USERNAME'] # Explicitly revoke full control permission to current user cmd = r'cacls %s /E /R "%s\%s"' % (short_folder, current_domain, current_user) try: subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: raise Exception("Error %s setting ACL to short_folder: '%s'." "Please check that cacls.exe exists" % (e, short_folder)) # Run conan export in using short_folder with tools.environment_append({"CONAN_USER_HOME_SHORT": short_folder}): client = TestClient(cache_folder=cache_folder) client.save({CONANFILE: conanfile_py.replace("False", "True")}) client.run("export . %s" % self.user_channel) # Retrieve ACLs from short_folder try: short_folder_acls = check_output_runner("cacls %s" % short_folder, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: raise Exception("Error %s getting ACL from short_folder: '%s'." % (e, short_folder)) # Check user has full control user_acl = "%s\\%s:(OI)(CI)F" % (current_domain, current_user) self.assertIn(user_acl, short_folder_acls)
def with_apt(self): if not self.is_linux: return False apt_location = which('apt-get') if apt_location: # Check if we actually have the official apt package. try: output = check_output_runner([apt_location, 'moo']) except CalledProcessErrorWithStderr: return False else: # Yes, we have mooed today. :-) MOOOOOOOO. return True else: return False
def test_virtualrunenv(self): client = TestClient(servers=self.servers, users={"default": [("lasote", "mypass")]}) client.run("install Pkg/0.1@lasote/testing -g virtualrunenv") with tools.chdir(client.current_folder): if platform.system() == "Windows": command = "activate_run.bat && say_hello" else: # It is not necessary to use the DYLD_LIBRARY_PATH in OSX because the activate_run.sh # will work perfectly. It is inside bash, so the loader will use DYLD_LIBRARY_PATH # values. It also works in command line with export DYLD_LIBRARY_PATH=[path] and then # running, or in the same line "$ DYLD_LIBRARY_PATH=[path] say_hello" command = "bash -c 'source activate_run.sh && say_hello'" output = check_output_runner(command) self.assertIn("Hello Tool!", output)
def uname(options=None): options = " %s" % options if options else "" if not OSInfo().is_windows: raise ConanException("Command only for Windows operating system") custom_bash_path = OSInfo.bash_path() if not custom_bash_path: raise ConanException("bash is not in the path") command = '"%s" -c "uname%s"' % (custom_bash_path, options) try: # the uname executable is many times located in the same folder as bash.exe with environment_append({"PATH": [os.path.dirname(custom_bash_path)]}): ret = check_output_runner(command).strip().lower() return ret except Exception: return None
def env_diff(cmd, only_diff): known_path_lists = ("include", "lib", "libpath", "path") if platform.system() == "Windows": cmd += " && set" else: cmd += " && export" ret = check_output_runner(cmd) new_env = {} for line in ret.splitlines(): line = line.strip() if line == "\n" or not line: continue try: name_var, value = line.split("=", 1) name_var = str(name_var) value = str(value) new_value = value.split( os.pathsep) if name_var.lower() in known_path_lists else value # Return only new vars & changed ones, but only with the changed elements if the var is # a list if only_diff: old_value = os.environ.get(name_var) if name_var.lower() == "path": old_values_lower = [ v.lower() for v in old_value.split(os.pathsep) ] # Clean all repeated entries, not append if the element was already there new_env[name_var] = [ v for v in new_value if v.lower() not in old_values_lower ] elif old_value and value.endswith(os.pathsep + old_value): # The new value ends with separator and the old value, is a list, # get only the new elements new_env[name_var] = value[:-(len(old_value) + 1)].split( os.pathsep) elif value != old_value: # Only if the vcvars changed something, we return the variable, # otherwise is not vcvars related new_env[name_var] = new_value else: new_env[name_var] = new_value except ValueError: pass return new_env
def with_apt(self): if not self.is_linux: return False # https://github.com/conan-io/conan/issues/8737 zypper-aptitude can fake it if "opensuse" in self.linux_distro or "sles" in self.linux_distro: return False apt_location = which('apt-get') if apt_location: # Check if we actually have the official apt package. try: output = check_output_runner([apt_location, 'moo']) except CalledProcessErrorWithStderr: return False else: # Yes, we have mooed today. :-) MOOOOOOOO. return True else: return False
def _get_install_name(path_to_dylib): command = "otool -D {}".format(path_to_dylib) install_name = check_output_runner(command).strip().split(":")[1].strip() return install_name
def cmd_output(cmd): return check_output_runner(cmd).strip()
def get_aix_version(): try: ret = check_output_runner("oslevel").strip() return Version(ret) except Exception: return Version("%s.%s" % (platform.version(), platform.release()))
def _cmd_output(command): return check_output_runner(command).strip()
def runner_no_strip(command): return check_output_runner(command)
def _run(self, cmd): with chdir(self._conanfile, self.folder): return check_output_runner("git {}".format(cmd)).strip()
def vswhere(all_=False, prerelease=False, products=None, requires=None, version="", latest=False, legacy=False, property_="", nologo=True): # 'version' option only works if Visual Studio 2017 is installed: # https://github.com/Microsoft/vswhere/issues/91 products = list() if products is None else products requires = list() if requires is None else requires if legacy and (products or requires): raise ConanException( "The 'legacy' parameter cannot be specified with either the " "'products' or 'requires' parameter") installer_path = None program_files = get_env("ProgramFiles(x86)") or get_env("ProgramFiles") if program_files: expected_path = os.path.join(program_files, "Microsoft Visual Studio", "Installer", "vswhere.exe") if os.path.isfile(expected_path): installer_path = expected_path vswhere_path = installer_path or which("vswhere") if not vswhere_path: raise ConanException( "Cannot locate vswhere in 'Program Files'/'Program Files (x86)' " "directory nor in PATH") arguments = list() arguments.append(vswhere_path) # Output json format arguments.append("-format") arguments.append("json") if all_: arguments.append("-all") if prerelease: arguments.append("-prerelease") if products: arguments.append("-products") arguments.extend(products) if requires: arguments.append("-requires") arguments.extend(requires) if len(version) != 0: arguments.append("-version") arguments.append(version) if latest: arguments.append("-latest") if legacy: arguments.append("-legacy") if len(property_) != 0: arguments.append("-property") arguments.append(property_) if nologo: arguments.append("-nologo") try: output = check_output_runner(arguments).strip() # Ignore the "description" field, that even decoded contains non valid charsets for json # (ignored ones) output = "\n".join([ line for line in output.splitlines() if not line.strip().startswith('"description"') ]) except (ValueError, subprocess.CalledProcessError, UnicodeDecodeError) as e: raise ConanException("vswhere error: %s" % str(e)) return json.loads(output)