diff --git a/README.md b/README.md index 993de02..2e789b1 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,38 @@ Otherwise, this is possibly not the droid you were looking for. Run `bundle exec rake` to run the tests and the style autofixer. You can also run `bundle exec pry` for an interactive prompt that will allow you to experiment. +### Building from source + +`bundle exec rake libdatadog:build` builds libdatadog from source for the current platform +using libdatadog's own [`builder` crate](https://github.com/DataDog/libdatadog/tree/main/builder). +It requires a Rust toolchain (plus `cmake` and autotools); the Nix dev shell provides all of these. +The default build writes artifacts to `vendor/libdatadog-//` (the +location the gem is packaged from); explicit-ref builds (see below) write to a directory named +after the ref instead, so they are not mislabeled as the pinned release. + +By default it builds the pinned `v` tag. Set the optional `LIBDATADOG_REF` +environment variable to build something else. Its value is always an explicit +`:` pair, where `kind` is one of: + +- `tag` — a git tag, e.g. `LIBDATADOG_REF=tag:v33.0.0`. +- `branch` — a git branch, e.g. `LIBDATADOG_REF=branch:my-feature`. +- `commit` — a git commit, e.g. `LIBDATADOG_REF=commit:`. +- `path` — a local libdatadog checkout, e.g. `LIBDATADOG_REF=path:/path/to/libdatadog`. + +The kind is always stated explicitly (no guessing), so a value without a recognized prefix +fails fast. When `LIBDATADOG_REF` is unset, the pinned `v` tag is built. + +Independently of the above, `LIBDATADOG_FEATURES` sets a comma-separated cargo feature +override and applies to any build. + +Git builds (tag/branch/commit) pass `cargo install --locked`, so they reproducibly use the +dependency versions pinned in libdatadog's `Cargo.lock`. Local-path builds omit `--locked`, +since the checkout may be modified. + +```sh +LIBDATADOG_REF=commit: bundle exec rake libdatadog:build +``` + ### Testing packaging locally You can use `bundle exec rake package` to generate packages locally without publishing them. diff --git a/tasks/build.rake b/tasks/build.rake index dfe1300..1e35c19 100644 --- a/tasks/build.rake +++ b/tasks/build.rake @@ -69,34 +69,51 @@ module BuildFromSource tmp / "cmake-out" end - # Vendor output tree - def vendor - root / "vendor" / "libdatadog-#{Libdatadog::LIB_VERSION}" + # Vendor output tree. `label` names the build (default: the pinned LIB_VERSION, + # which is the canonical, packageable location); explicit refs use a ref-derived + # label so artifacts are not mislabeled as the pinned release. + def vendor(label = Libdatadog::LIB_VERSION) + root / "vendor" / "libdatadog-#{label}" end - def vendor_target(ruby_platform = Target.ruby_platform) - vendor / ruby_platform + def vendor_target(ruby_platform = Target.ruby_platform, label: Libdatadog::LIB_VERSION) + vendor(label) / ruby_platform end end end module Builder + LIBDATADOG_GIT_URL = "https://github.com/DataDog/libdatadog" + + # Cargo flag used for each git ref kind. + GIT_FLAG = {tag: "--tag", branch: "--branch", commit: "--rev"}.freeze + + # Recognized ":" ref kinds: a local path plus the git ref kinds above. + VALID_KINDS = [:path, *GIT_FLAG.keys].freeze + class << self # Build the cargo install command for the builder crate's `release` binary. # - # source: optional path to a local libdatadog checkout - # features: optional comma-separated feature override - def cargo_install_cmd(source: nil, features: nil) + # The libdatadog code to build is selected by `ref`, an explicit ":" + # string where kind is one of: + # path — a local libdatadog checkout. Built via --path, WITHOUT --locked, + # since the checkout may be modified locally. + # tag — a git tag. Built via --git --tag --locked. + # branch — a git branch. Built via --git --branch --locked. + # commit — a git commit. Built via --git --rev --locked. + # When ref is blank, defaults to the pinned --tag v --locked. + # + # Git builds pass --locked so they reproducibly use libdatadog's Cargo.lock. + # features: optional comma-separated cargo feature override, appended in all cases. + def cargo_install_cmd(ref: nil, features: nil) + kind, value = ref ? parse_ref(ref) : [:tag, "v#{Libdatadog::LIB_VERSION}"] + cmd = %W[cargo install --bin release --root #{Paths.builder_root} --force] - cmd += if source - ["--path", (Pathname.new(source).expand_path / "builder").to_s] + cmd += if kind == :path + ["--path", (Pathname.new(value).expand_path / "builder").to_s] else - [ - "--git", "https://github.com/DataDog/libdatadog", - "--tag", "v#{Libdatadog::LIB_VERSION}", - "builder" - ] + ["--git", LIBDATADOG_GIT_URL, GIT_FLAG.fetch(kind), value, "--locked", "builder"] end cmd += ["--no-default-features", "--features", features] if features @@ -104,6 +121,29 @@ module BuildFromSource cmd end + # Parse an explicit ":" ref into [kind_symbol, value]. + # No auto-detection: a value with an unrecognized/missing kind prefix or an + # empty value is an error. + def parse_ref(ref) + kind, value = ref.split(":", 2) + kind = kind.to_sym if kind + + unless VALID_KINDS.include?(kind) && value && !value.empty? + raise %(LIBDATADOG_REF must be ":" where kind is one of ) + + %(#{VALID_KINDS.join(", ")} (e.g. tag:v33.0.0); got #{ref.inspect}) + end + + [kind, value] + end + + # Vendor directory label for a parsed ref ("libdatadog-