def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: cb_work_dir = _get_source_code(recipe_dir) if cb_work_dir is None: return directories = set() with indir(cb_work_dir): for dp, dn, fn in os.walk("."): for f in fn: if f != "config.sub": continue if os.path.exists(os.path.join(dp, "config.guess")): directories.add(dp) if not directories: return with indir(recipe_dir): if not os.path.exists("build.sh"): return with open("build.sh", "r") as f: lines = list(f.readlines()) for line in lines: if line.strip().startswith( "cp $BUILD_PREFIX/share/libtool/build-aux/config", ): return if line.strip().startswith("autoreconf"): return if line.strip().startswith("./autogen.sh"): return insert_at = 0 if lines[0].startswith("#"): insert_at = 1 for d in directories: lines.insert( insert_at, f"cp $BUILD_PREFIX/share/libtool/build-aux/config.* {d}\n", ) lines.insert( insert_at, "# Get an updated config.sub and config.guess\n", ) with open("build.sh", "w") as f: f.write("".join(lines)) with open("meta.yaml") as f: lines = f.readlines() for i, line in enumerate(lines): if line.strip().startswith("- {{ compiler"): new_line = " " * (len(line) - len(line.lstrip())) new_line += "- libtool # [unix]\n" lines.insert(i, new_line) break with open("meta.yaml", "w") as f: f.write("".join(lines))
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> "MigrationUidTypedDict": # in case the render is old os.makedirs(os.path.join(recipe_dir, "../.ci_support"), exist_ok=True) with indir(os.path.join(recipe_dir, "../.ci_support")): os.makedirs("migrations", exist_ok=True) with indir("migrations"): with open(f"{self.name}.yaml", "w") as f: f.write(self.yaml_contents) eval_xonsh("git add .") with indir(recipe_dir): self.set_build_number("meta.yaml") return super().migrate(recipe_dir, attrs)
def migrate(self, recipe_dir, attrs, **kwargs): fname = os.path.join(recipe_dir, "conda_build_config.yaml") if os.path.exists(fname): parser = YAML(typ="rt") parser.indent(mapping=2, sequence=4, offset=2) parser.width = 320 with open(fname) as fp: cbc = parser.load(fp.read()) if "pin_run_as_build" in cbc: for mpi in MPIS: if mpi in cbc["pin_run_as_build"]: del cbc["pin_run_as_build"][mpi] if len(cbc["pin_run_as_build"]) == 0: del cbc["pin_run_as_build"] if len(cbc) > 0: with open(fname, "w") as fp: parser.dump(cbc, stream=fp) else: with indir(recipe_dir): subprocess.run("git rm -f conda_build_config.yaml", shell=True) subprocess.run("rm -f conda_build_config.yaml", shell=True)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs): with indir(recipe_dir): # Update build number # Remove blas related packages and features with open("meta.yaml", "r") as f: lines = f.readlines() reqs_line = "build:" for i, line in enumerate(lines): if line.strip() == "host:": reqs_line = "host:" for blas_pattern in self.blas_patterns: m = blas_pattern.match(line) if m is not None: lines[i] = "" break for i, line in enumerate(lines): sline = line.lstrip() if len(sline) != len(line) and line.strip() == reqs_line: for dep in ["libblas", "libcblas"]: print(lines[i], len(line) - len(sline)) lines[i] = (lines[i] + " " * (len(line) - len(sline)) + " - " + dep + "\n") new_text = "".join(lines) with open("meta.yaml", "w") as f: f.write(new_text) return super().migrate(recipe_dir, attrs)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> "MigrationUidTypedDict": with indir(recipe_dir): build_idx = [ l.rstrip() for l in attrs["raw_meta_yaml"].split("\n") ].index("build:", ) line = attrs["raw_meta_yaml"].split("\n")[build_idx + 1] spaces = len(line) - len(line.lstrip()) replace_in_file( "build:", f"build:\n{' ' * spaces}noarch: python", "meta.yaml", leading_whitespace=False, ) replace_in_file( "script:.+?", "script: python -m pip install --no-deps --ignore-installed .", "meta.yaml", ) replace_in_file( " build:", " host:", "meta.yaml", leading_whitespace=False, ) if "pip" not in attrs["req"]: replace_in_file( " host:", " host:\n - pip", "meta.yaml", leading_whitespace=False, ) self.set_build_number("meta.yaml") return super().migrate(recipe_dir, attrs)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): if not os.path.exists("build.sh"): return with open("build.sh", "r") as f: lines = list(f.readlines()) for i, line in enumerate(lines): if "CONDA_BUILD_CROSS_COMPILATION" in line: return if (line.startswith("make check") or line.startswith("ctest") or line.startswith("make test")): lines.insert( i, 'if [[ "${CONDA_BUILD_CROSS_COMPILATION}" != "1" ]]; then\n', ) insert_after = i + 1 while len(lines) > insert_after and lines[ insert_after].endswith("\\\n", ): insert_after += 1 if lines[insert_after][-1] != "\n": lines[insert_after] += "\n" lines.insert(insert_after + 1, "fi\n") break else: return with open("build.sh", "w") as f: f.write("".join(lines))
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): with open("meta.yaml") as fp: meta_yaml = fp.readlines() new_lines = [] in_req = False previous_was_build = False for line in meta_yaml: if previous_was_build: nspaces = len(line) - len(line.lstrip()) new_lines.append( " " * nspaces + "- cross-r-base {{ r_base }} # [build_platform != target_platform]\n", ) in_req = False previous_was_build = False if "requirements:" in line: in_req = True if in_req and line.strip().startswith("build:"): previous_was_build = True new_lines.append(line) with open("meta.yaml", "w") as f: f.write("".join(new_lines)) if os.path.exists("build.sh"): with open("build.sh", "w") as f: f.write(CRAN_BUILD_SH)
def _scrape_license_string(pkg): d = {} if pkg.startswith("r-"): pkg = pkg[2:] LOGGER.info("LICENSE running cran skeleton for pkg %s" % pkg) with tempfile.TemporaryDirectory() as tmpdir, indir(tmpdir): subprocess.run( [ "conda", "skeleton", "cran", "--allow-archived", "--use-noarch-generic", pkg, ], check=True, ) with open("r-%s/meta.yaml" % pkg) as fp: in_about = False meta_yaml = [] for line in fp.readlines(): if line.startswith("about:"): in_about = True elif line.startswith("extra:"): in_about = False if in_about: meta_yaml.append(line) if line.startswith("# License:"): d["cran_license"] = line[len("# License:"):].strip() cmeta = CondaMetaYAML("".join(meta_yaml)) d["license_file"] = [ lf for lf in cmeta.meta.get("about", {}).get("license_file", []) ] if len(d["license_file"]) == 0: d["license_file"] = None if "cran_license" in d: spdx = _munge_licenses([d["cran_license"]]) if "(Restricts use)" in cmeta.meta.get("about", {}).get("license", ""): if len(spdx) > 1: spdx = ["("] + spdx + [")", " AND ", "LicenseRef-RestrictsUse"] else: spdx = spdx + [" AND ", "LicenseRef-RestrictsUse"] d["spdx_license"] = "".join(spdx) else: d["spdx_license"] = None if d: return d else: return None
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: cb_work_dir = _get_source_code(recipe_dir) if cb_work_dir is None: return with indir(cb_work_dir): # look for a license file license_files = [ s for s in os.listdir(".") if any(s.lower().startswith(k) for k in ["license", "copying", "copyright"]) ] eval_xonsh(f"rm -r {cb_work_dir}") # if there is a license file in tarball update things if license_files: with indir(recipe_dir): """BSD 3-Clause License Copyright (c) 2017, Anthony Scopatz Copyright (c) 2018, The Regro Developers All rights reserved.""" with open("meta.yaml", "r") as f: raw = f.read() lines = raw.splitlines() ptn = re.compile(r"(\s*?)" + "license:") for i, line in enumerate(lines): m = ptn.match(line) if m is not None: break # TODO: Sketchy type assertion assert m is not None ws = m.group(1) if len(license_files) == 1: replace_in_file( line, line + "\n" + ws + f"license_file: {list(license_files)[0]}", "meta.yaml", ) else: # note that this white space is not perfect but works for # most of the situations replace_in_file( line, line + "\n" + ws + "license_file: \n" + "".join(f"{ws*2}- {z} \n" for z in license_files), "meta.yaml", )
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> "MigrationUidTypedDict": with indir(recipe_dir): content, self.messages = update_cb3("meta.yaml", self.cfp) with open("meta.yaml", "w") as f: f.write(content) self.set_build_number("meta.yaml") return super().migrate(recipe_dir, attrs)
def extract_deps_from_source(recipe_dir): cb_work_dir = _get_source_code(recipe_dir) with indir(cb_work_dir): return simple_import_to_pkg_map( cb_work_dir, builtins=BUILTINS, ignore=DEPFINDER_IGNORE, )
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> "MigrationUidTypedDict": with indir(recipe_dir): for f, p, n in self.patterns: p = eval_version(p) n = eval_version(n) replace_in_file(p, n, f, leading_whitespace=False) self.set_build_number("meta.yaml") return super().migrate(recipe_dir, attrs)
def __init__( self, graph: nx.DiGraph = None, name: Optional[str] = None, pr_limit: int = 0, piggy_back_migrations: Optional[Sequence[MiniMigrator]] = None, ): # rebuild the graph to only use edges from the arm and power requirements graph2 = nx.create_empty_copy(graph) for node, attrs in graph.nodes(data="payload"): for plat_arch in self.arches: deps = set().union( *attrs.get( f"{plat_arch}_requirements", attrs.get("requirements", {}), ).values() ) for dep in get_deps_from_outputs_lut(deps, graph.graph["outputs_lut"]): graph2.add_edge(dep, node) super().__init__( graph=graph2, pr_limit=pr_limit, check_solvable=False, piggy_back_migrations=piggy_back_migrations, ) assert not self.check_solvable, "We don't want to check solvability for aarch!" # We are constraining the scope of this migrator with indir("../conda-forge-pinning-feedstock/recipe/migrations"), open( "arch_rebuild.txt", ) as f: self.target_packages = set(f.read().split()) self.name = name # filter the graph down to the target packages if self.target_packages: self.target_packages.add("python") # hack that is ~harmless? packages = self.target_packages.copy() for target in self.target_packages: if target in self.graph.nodes: packages.update(nx.ancestors(self.graph, target)) self.graph.remove_nodes_from([n for n in self.graph if n not in packages]) # filter out stub packages and ignored packages for node, attrs in list(self.graph.nodes("payload")): if ( node.endswith("_stub") or (node.startswith("m2-")) or (node.startswith("m2w64-")) or (node in self.ignored_packages) or all_noarch(attrs) ): pluck(self.graph, node) self.graph.remove_edges_from(nx.selfloop_edges(self.graph))
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): with open("meta.yaml", "r") as fp: raw_yaml = fp.read() raw_yaml = _cleanup_raw_yaml(raw_yaml) # Rewrite the recipe file with open("meta.yaml", "w") as fp: fp.write(raw_yaml)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> "MigrationUidTypedDict": with indir(recipe_dir + "/.."): self.set_build_number("recipe/meta.yaml") with open("conda-forge.yml") as f: y = safe_load(f) y.update(self.additional_keys) with open("conda-forge.yml", "w") as f: safe_dump(y, f) return super().migrate(recipe_dir, attrs, **kwargs)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): with open("meta.yaml", "r") as fp: lines = fp.readlines() for var_name in self.vars_to_remove: lines = self._replace_jinja_key(var_name, lines) # Rewrite the recipe file with open("meta.yaml", "w") as fp: fp.writelines(lines)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): with open("meta.yaml") as fp: meta_yaml = fp.readlines() new_lines = [] for line in meta_yaml: if "conda inspect" in line: continue new_lines.append(line) with open("meta.yaml", "w") as f: f.write("".join(new_lines))
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): cfg_path = os.path.join("..", "conda-forge.yml") yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) with open(cfg_path, "r") as fp: cfg = yaml.load(fp.read()) for k in self.keys_to_remove: if k in cfg: del cfg[k] with open(cfg_path, "w") as fp: yaml.dump(cfg, fp)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> "MigrationUidTypedDict": with indir(recipe_dir + "/.."): self.set_build_number("recipe/meta.yaml") with open("conda-forge.yml") as f: y = safe_load(f) if "provider" not in y: y["provider"] = {} for k, v in self.arches.items(): if k not in y["provider"]: y["provider"][k] = v with open("conda-forge.yml", "w") as f: safe_dump(y, f) return super().migrate(recipe_dir, attrs, **kwargs)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): if not os.path.exists("../conda-forge.yml"): name = attrs.get("feedstock_name") LOGGER.info(f"no conda-forge.yml for {name}") return with open("../conda-forge.yml") as f: config = yaml_safe_load(f) build_platform = config.get("build_platform", {}) if build_platform: for arch in ["linux_aarch64", "linux_ppc64le"]: if arch in build_platform: continue if config.get("provider", {}).get(arch) == "default": config["build_platform"][arch] = "linux_64" with open("../conda-forge.yml", "w") as f: name = attrs.get("feedstock_name") LOGGER.info(f"new conda-forge.yml for {name}:={config}") yaml_safe_dump(config, f) if not os.path.exists("build.sh"): return with open("build.sh") as f: lines = list(f.readlines()) old_guard_lines = [ 'if [[ "${CONDA_BUILD_CROSS_COMPILATION:-}" != "1" ]]; then\n', 'if [[ "${CONDA_BUILD_CROSS_COMPILATION}" != "1" ]]; then\n', 'if [[ "$CONDA_BUILD_CROSS_COMPILATION" != "1" ]]; then\n', 'if [[ "$CONDA_BUILD_CROSS_COMPILATION" == "0" ]]; then\n', 'if [[ "${CONDA_BUILD_CROSS_COMPILATION}" == "0" ]]; then\n', ] new_guard_line = 'if [[ "${CONDA_BUILD_CROSS_COMPILATION:-}" != "1" || "${CROSSCOMPILING_EMULATOR}" != "" ]]; then\n' for i, line in enumerate(lines): if ((line.strip().startswith("make check") or line.strip().startswith("ctest") or line.strip().startswith("make test")) and i > 0 and lines[i - 1] in old_guard_lines): lines[i - 1] = new_guard_line break else: return with open("build.sh", "w") as f: f.write("".join(lines))
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: host_reqs = attrs.get("requirements", {}).get("host", set()) with indir(recipe_dir): with open("meta.yaml") as f: lines = f.readlines() in_reqs = False for i, line in enumerate(lines): if line.strip().startswith("requirements:"): in_reqs = True continue if in_reqs and len(line) > 0 and line[0] != " ": in_reqs = False if not in_reqs: continue if line.strip().startswith( "build:") or line.strip().startswith("host:", ): j = i + 1 while j < len(lines) and not lines[j].strip().startswith( "-"): j = j + 1 if j == len(lines): j = i + 1 spaces = len(line) - len(line.lstrip()) + 2 else: spaces = len(lines[j]) - len(lines[j].lstrip()) new_line = " " * spaces if line.strip().startswith("host:"): lines.insert(i, line.replace("host", "build")) for pkg in reversed([ "python", "cross-python_{{ target_platform }}", "cython", "numpy", "cffi", "pybind11", ], ): if pkg in host_reqs or pkg.startswith("cross-python"): new_line = ( " " * spaces + "- " + pkg.ljust(37) + " # [build_platform != target_platform]\n") lines.insert(i + 1, new_line) break with open("meta.yaml", "w") as f: f.write("".join(lines))
def migrate( self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any ) -> "MigrationUidTypedDict": migration_yaml_dict = { "__migrator": {"build_number": 1, "kind": "version", "migration_number": 1}, self.package_name: [self.new_pin_version], "migrator_ts": float(time.time()), } with indir(os.path.join(recipe_dir, "migrations")): mig_fname = "{}{}.yaml".format( self.package_name, self.new_pin_version.replace(".", ""), ) with open(mig_fname, "w") as f: yaml.dump(migration_yaml_dict, f, default_flow_style=False, indent=2) eval_cmd("git add .") return super().migrate(recipe_dir, attrs)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): with open("meta.yaml") as fp: meta_yaml = fp.readlines() new_lines = [] in_req = False previous_was_build = False for line in meta_yaml: if previous_was_build: nspaces = len(line) - len(line.lstrip()) new_lines.append( " " * nspaces + "- cross-r-base {{ r_base }} # [build_platform != target_platform]\n", ) # Add host R requirements to build host_reqs = attrs.get("requirements", {}).get("host", set()) r_host_reqs = [ req for req in host_reqs if req.startswith("r-") and req != "r-base" ] for r_req in r_host_reqs: # Ensure nice formatting post_nspaces = max(0, 25 - len(r_req)) new_lines.append( " " * nspaces + "- " + r_req + " " * post_nspaces + " # [build_platform != target_platform]\n", ) in_req = False previous_was_build = False if "requirements:" in line: in_req = True if in_req and line.strip().startswith("build:"): previous_was_build = True new_lines.append(line) with open("meta.yaml", "w") as f: f.write("".join(new_lines)) if os.path.exists("build.sh"): with open("build.sh", "w") as f: f.write(CRAN_BUILD_SH)
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): with open("meta.yaml") as fp: meta_yaml = fp.readlines() new_lines = [] in_req = False for line in meta_yaml: if "requirements:" in line: in_req = True if in_req and line.strip().startswith("build:"): start, rest = line.split("build:", 1) line = start + "host:" + rest in_req = False new_lines.append(line) with open("meta.yaml", "w") as f: f.write("".join(new_lines))
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): with open("meta.yaml", "r") as fp: lines = fp.readlines() new_lines = [] for line in lines: for b in self.bad_install: tst_str = "script: %s" % b if tst_str in line: line = line.replace( tst_str, "script: {{ PYTHON }} -m pip install . --no-deps -vv", ) break new_lines.append(line) with open("meta.yaml", "w") as fp: for line in new_lines: fp.write(line)
def audit_feedstock(fctx: FeedstockContext, ctx: MigratorSessionContext): """Uses Depfinder to audit the requirements for a python package """ # get feedstock feedstock_dir = os.path.join(ctx.rever_dir, fctx.package_name + "-feedstock") origin = feedstock_url(fctx=fctx, protocol="https") fetch_repo(feedstock_dir=feedstock_dir, origin=origin, upstream=origin, branch="master") recipe_dir = os.path.join(feedstock_dir, "recipe") # get source code cb_work_dir = _get_source_code(recipe_dir) with indir(cb_work_dir): # run depfinder on source code deps = simple_import_search(cb_work_dir, remap=True) for k in list(deps): deps[k] = set(deps[k]) return deps
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): if not os.path.exists("build.sh"): return with open("build.sh", "r") as f: lines = list(f.readlines()) for i, line in enumerate(lines): if "${CMAKE_ARGS}" in line or "$CMAKE_ARGS" in line: return for i, line in enumerate(lines): if line.startswith("cmake "): lines[i] = "cmake ${CMAKE_ARGS} " + line[len("cmake "):] break else: return with open("build.sh", "w") as f: f.write("".join(lines))
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> None: with indir(recipe_dir): cfg = "conda_build_config.yaml" yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) if os.path.exists("../conda-forge.yml"): with open("../conda-forge.yml") as fp: cfyml = yaml.load(fp.read()) else: cfyml = {} if (os.path.exists(cfg) and cfyml.get("os_version", {}).get( "linux_64", None) != "cos7"): with open(cfg) as fp: lines = fp.readlines() _munge_cos7_lines(lines) with open(cfg, "w") as fp: fp.write("".join(lines))
def migrate(self, recipe_dir: str, attrs: "AttrsTypedDict", **kwargs: Any) -> "MigrationUidTypedDict": # if conda-forge-pinning update the pins and close the migration if attrs.get("name", "") == "conda-forge-pinning": # read up the conda build config with indir(recipe_dir), open("conda_build_config.yaml") as f: cbc_contents = f.read() merged_cbc = merge_migrator_cbc(self.yaml_contents, cbc_contents) with indir(os.path.join(recipe_dir, "migrations")): os.remove(f"{self.name}.yaml") # replace the conda build config with the merged one with indir(recipe_dir), open("conda_build_config.yaml", "w") as f: f.write(merged_cbc) # don't need to bump build number once we move to datetime # version numbers for pinning return super().migrate(recipe_dir, attrs) else: # in case the render is old os.makedirs(os.path.join(recipe_dir, "../.ci_support"), exist_ok=True) with indir(os.path.join(recipe_dir, "../.ci_support")): os.makedirs("migrations", exist_ok=True) with indir("migrations"): with open(f"{self.name}.yaml", "w") as f: f.write(self.yaml_contents) eval_cmd("git add .") if self.conda_forge_yml_patches is not None: with indir(os.path.join(recipe_dir, "..")): with open("conda-forge.yml", "r") as fp: cfg = yaml.safe_load(fp.read()) _patch_dict(cfg, self.conda_forge_yml_patches) with open("conda-forge.yml", "w") as fp: yaml.dump(cfg, fp, default_flow_style=False, indent=2) eval_cmd("git add conda-forge.yml") with indir(recipe_dir): self.set_build_number("meta.yaml") return super().migrate(recipe_dir, attrs)
def test_migration_yaml_migration(tmock, in_out_yaml, caplog, tmpdir): caplog.set_level( logging.DEBUG, logger="conda_forge_tick.migrators.migration_yaml", ) tmock.return_value = 12345.2 pname = "boost" pin_ver = "1.99.0" curr_pin = "1.70.0" pin_spec = "x.x" MYM = MigrationYamlCreator(pname, pin_ver, curr_pin, pin_spec, "hi", G, G) with indir(tmpdir): eval_xonsh("git init .") os.makedirs(os.path.join(tmpdir, "migrations"), exist_ok=True) run_test_migration( m=MYM, inp=in_out_yaml[0], output=in_out_yaml[1], kwargs={}, prb="This PR has been triggered in an effort to update the pin", mr_out={ "migrator_name": "MigrationYamlCreator", "migrator_version": MYM.migrator_version, "name": pname, "pin_version": "1.99", }, tmpdir=tmpdir, ) boost_file = os.path.join(tmpdir, "migrations", "boost199.yaml") assert os.path.exists(boost_file) with open(boost_file) as fp: bf_out = fp.read() assert BOOST_YAML == bf_out