File: metadata.rb

package info (click to toggle)
ruby-rb-sys 0.9.87-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 192 kB
  • sloc: ruby: 1,186; makefile: 4
file content (128 lines) | stat: -rw-r--r-- 3,268 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# frozen_string_literal: true

require "open3"
require "psych"

module RbSys
  module Cargo
    # Extracts metadata from a Cargo project using `cargo metadata`.
    class Metadata
      attr_reader :name

      # Initializes a new Cargo::Metadata instance.
      #
      # @param name [String] the name of the Cargo project
      def initialize(name, deps: false)
        raise ArgumentError, "name must be a String" unless name.is_a?(String)

        @name = name
        @cargo_metadata = nil
        @package_metadata = nil
        @deps = deps
      end

      # Returns the path where the Cargo project's Cargo.toml is located.
      #
      # @return [String]
      def manifest_directory
        @manifest_directory ||= File.dirname(manifest_path)
      end

      # Returns the target directory for the Cargo project.
      #
      # @return [String]
      def target_directory
        cargo_metadata.fetch("target_directory")
      end

      # Returns the workspace root for the Cargo project.
      #
      # @return [String]
      def workspace_root
        cargo_metadata.fetch("workspace_root")
      end

      # Returns the workspace members for the Cargo project.
      #
      # @return [Array<Hash>]
      def packages
        cargo_metadata.fetch("packages")
      end

      # Returns the path to the package's Cargo.toml.
      #
      # @return [String]
      def manifest_path
        package_metadata.fetch("manifest_path")
      end

      # Returns the package's version.
      #
      # @return [String]
      def version
        package_metadata.fetch("version")
      end

      # Returns the package's id.
      #
      # @return [String]
      def id
        package_metadata.fetch("id")
      end

      # Returns the package's Rust edition.
      #
      # @return [String]
      def edition
        package_metadata.fetch("edition")
      end

      # Returns the package's features.
      #
      # @return [Array<String>]
      def features
        package_metadata.fetch("features")
      end

      # Returns the package's custom metadata.
      #
      # @return [Hash]
      def metadata
        package_metadata.fetch("metadata")
      end

      # Returns the rb-sys version, if any.
      def rb_sys_version
        pkg = packages.find { |p| p.fetch("name") == "rb-sys" }
        return unless pkg
        pkg["version"]
      end

      private

      def package_metadata
        return @package_metadata if @package_metadata

        found = cargo_metadata.fetch("packages").find { |p| p.fetch("name") == name }
        raise PackageNotFoundError, @name unless found
        @package_metadata = found
      end

      def cargo_metadata
        return @cargo_metadata if @cargo_metadata

        ::Gem.load_yaml
        cargo = ENV["CARGO"] || "cargo"
        args = ["metadata", "--format-version", "1"]
        args << "--no-deps" unless @deps
        out, stderr, status = Open3.capture3(cargo, *args)
        raise "exited with non-zero status (#{status})" unless status.success?
        data = Gem::SafeYAML.safe_load(out)
        raise "metadata must be a Hash" unless data.is_a?(Hash)
        @cargo_metadata = data
      rescue => err
        raise CargoMetadataError.new(err, stderr)
      end
    end
  end
end