Skip to main content
Glama
lock_generate.py4.2 kB
#!/usr/bin/env python3 # Copyright (c) Meta Platforms, Inc. and affiliates. # # This source code is licensed under both the MIT license found in the # LICENSE-MIT file in the root directory of this source tree and the Apache # License, Version 2.0 found in the LICENSE-APACHE file in the root directory # of this source tree. import argparse import json import conan_common def parse_lockfile(lockfile): """Parse Conan lockfile into a package collection.""" with open(lockfile) as f: data = json.load(f) assert data["version"] == "0.4", "Unsupported Conan lockfile version" graph = data["graph_lock"] # TODO[AH] Enable Conan revisions for reproducibility # assert graph["revisions_enabled"] == True, "Enable revisions for reproducibility" nodes = graph["nodes"] pkgs = {} for key, item in nodes.items(): if key == "0": # Skip the root package, it just bundles all dependencies. continue ref = item["ref"] name, _, _, _, _ = conan_common.parse_reference(ref) package_id = item["package_id"] options = item["options"] requires = item.get("requires", []) build_requires = item.get("build_requires", []) # context = item["context"] # TODO[AH] Do we need this? pkgs[key] = { "name": name, "reference": ref, "package_id": package_id, "options": options, "requires": requires, "build_requires": build_requires, } return pkgs def generate_targets(lockfile_label, pkgs, targets_out): """Write Buck2 targets for the packages to bzl_out.""" package_template = """\ conan_package( name = {name!r}, lockfile = {lockfile!r}, reference = {reference!r}, package_id = {package_id!r}, deps = {deps!r}, build_deps = {build_deps!r}, ) """ with open(targets_out, "w") as f: for pkg in pkgs.values(): name = "_package_" + pkg["name"] reference = pkg["reference"] package_id = pkg["package_id"] deps = [":_package_" + pkgs[key]["name"] for key in pkg["requires"]] build_deps = [ ":_package_" + pkgs[key]["name"] for key in pkg["build_requires"] ] f.write( package_template.format( name=name, # TODO[AH] Remove that lockfile and generate a minimal one in the rule. # Using the full lock file means that any change to the set # of Conan packages will require a rebuild of all Conan # packages. Generating minimal lock files with only the # required information per package will only invalidate those # packages that were affected by a change. Note, the lock # file also contains the Conan profile, which defines the # Buck2 provided C/C++ toolchain. This information would need # to be included in a minimal lockfile. lockfile=lockfile_label, reference=reference, package_id=package_id, deps=deps, build_deps=build_deps, ) ) def main(): parser = argparse.ArgumentParser( prog="lock_generate", description="Generate Buck2 build targets for Conan packages.", ) parser.add_argument( "--lockfile", metavar="FILE", type=str, required=False, help="Path to the Conan lock-file.", ) parser.add_argument( "--lockfile-label", metavar="LABEL", type=str, required=False, help="Buck2 label for the Conan lock-file.", ) parser.add_argument( "--targets-out", metavar="FILE", type=str, required=False, help="Write the generated targets to this file.", ) args = parser.parse_args() pkgs = parse_lockfile(args.lockfile) generate_targets(args.lockfile_label, pkgs, args.targets_out) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server