Skip to content

Commit fd31816

Browse files
committed
improve cargo/install_package
1 parent bcd6a83 commit fd31816

1 file changed

Lines changed: 91 additions & 0 deletions

File tree

xmake/modules/package/manager/cargo/install_package.lua

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,90 @@ function _translate_local_path_in_deps(cargotoml, rootdir)
4747
io.writefile(cargotoml, content)
4848
end
4949

50+
-- is it a cargo workspace manifest? (it contains a [workspace] or [workspace.xxx] table)
51+
function _is_workspace_manifest(content)
52+
for _, line in ipairs(content:split("\n", {plain = true, strict = true})) do
53+
if line:match("^%s*%[workspace[%].]") then
54+
return true
55+
end
56+
end
57+
return false
58+
end
59+
60+
-- get the workspace inheritance tables from the workspace root manifest
61+
--
62+
-- if the given Cargo.toml is a member of a cargo workspace and uses workspace inheritance,
63+
-- e.g. `anyhow.workspace = true`, `version.workspace = true`, `[lints] workspace = true`,
64+
-- we need to inject the `[workspace.package]`/`[workspace.dependencies]`/`[workspace.lints]`
65+
-- tables from the workspace root manifest, otherwise cargo will fail to resolve them, e.g.
66+
--
67+
-- error inheriting `anyhow` from workspace root manifest's `workspace.dependencies.anyhow`
68+
-- `workspace.dependencies` was not defined
69+
--
70+
-- @see https://github.com/xmake-io/xmake/issues/7619
71+
-- https://doc.rust-lang.org/cargo/reference/workspaces.html#the-workspacedependencies-table
72+
function _get_workspace_inherited_tables(cargo_toml)
73+
74+
-- find the workspace root manifest by walking up
75+
local rootmanifest
76+
local dir = path.directory(path.absolute(cargo_toml))
77+
while dir and #dir > 0 do
78+
local manifest = path.join(dir, "Cargo.toml")
79+
if os.isfile(manifest) then
80+
local content = io.readfile(manifest)
81+
if content and _is_workspace_manifest(content) then
82+
rootmanifest = manifest
83+
break
84+
end
85+
end
86+
local parentdir = path.directory(dir)
87+
if parentdir == dir then
88+
break
89+
end
90+
dir = parentdir
91+
end
92+
93+
-- not a workspace member, or the manifest itself is the workspace root (self-contained)
94+
if not rootmanifest or path.absolute(rootmanifest) == path.absolute(cargo_toml) then
95+
return
96+
end
97+
98+
-- extract all the [workspace.xxx] sub-tables, e.g. [workspace.package]/[workspace.dependencies]/[workspace.lints]
99+
-- we do not copy the bare [workspace] table (members/exclude), otherwise cargo will search for the member crates.
100+
local content = io.readfile(rootmanifest)
101+
if not content then
102+
return
103+
end
104+
local result = {}
105+
local in_subtable = false
106+
for _, line in ipairs(content:split("\n", {plain = true, strict = true})) do
107+
local header = line:match("^%s*%[(.-)%]%s*$")
108+
if header then
109+
in_subtable = header:trim():startswith("workspace.")
110+
if in_subtable then
111+
table.insert(result, line)
112+
end
113+
elseif in_subtable then
114+
table.insert(result, line)
115+
end
116+
end
117+
if #result == 0 then
118+
return
119+
end
120+
121+
-- translate the local paths in the workspace dependencies, they are relative to the workspace root directory
122+
local rootdir = path.directory(rootmanifest)
123+
local workspace_toml = table.concat(result, "\n")
124+
workspace_toml = workspace_toml:gsub("path%s+=%s+\"(.-)\"", function (localpath)
125+
if not path.is_absolute(localpath) then
126+
localpath = path.absolute(localpath, rootdir)
127+
end
128+
localpath = localpath:gsub("\\", "/")
129+
return "path = \"" .. localpath .. "\""
130+
end)
131+
return workspace_toml
132+
end
133+
50134
-- install package
51135
--
52136
-- e.g.
@@ -101,6 +185,13 @@ function main(name, opt)
101185
tomlfile:print("")
102186
tomlfile:print("[workspace]")
103187
tomlfile:print("")
188+
-- inject the workspace inheritance tables if the given Cargo.toml is a workspace member,
189+
-- e.g. `anyhow.workspace = true`. @see https://github.com/xmake-io/xmake/issues/7619
190+
local workspace_toml = _get_workspace_inherited_tables(configs.cargo_toml)
191+
if workspace_toml then
192+
tomlfile:write(workspace_toml)
193+
tomlfile:print("")
194+
end
104195
tomlfile:close()
105196
else
106197
local tomlfile = io.open(cargotoml, "w")

0 commit comments

Comments
 (0)