7777CARGO_CHECKSUM_JSON = '{{"files": {{}}, "package": "{checksum}"}}'
7878
7979
80- def get_virtual_workspace_members (crate_dir ):
81- """Find all members of a cargo virtual workspace in crate_dir.
80+ def get_workspace_members (crate_dir ):
81+ """Find all members of a cargo workspace in crate_dir.
8282
8383 (Minimally) parse the Cargo.toml file.
84- If it is a virtual workspace ([workspace] and no [package]) return all members (subfolder names).
85- Otherwise return None.
84+
85+ Return a tuple: (has_package, workspace-members).
86+ has_package determines if the manifest contains a '[package]' section and hence is not a virtual manifest.
87+ workspace-members are all members (subfolder names) if it is a workspace, otherwise None
8688 """
8789 cargo_toml = os .path .join (crate_dir , 'Cargo.toml' )
8890 lines = [line .strip () for line in read_file (cargo_toml ).splitlines ()]
89- if ' [package]' in lines :
90- return None
91+ # A virtual (workspace) manifest has no [package], but only a [workspace] section.
92+ has_package = '[package]' in lines
9193
9294 # We are looking for this:
9395 # [workspace]
@@ -100,7 +102,7 @@ def get_virtual_workspace_members(crate_dir):
100102 try :
101103 start_idx = lines .index ('[workspace]' )
102104 except ValueError :
103- return None
105+ return has_package , None
104106 # Find "members = [" and concatenate the value, stop at end of section or file
105107 member_str = None
106108 for line in lines [start_idx + 1 :]:
@@ -127,7 +129,7 @@ def get_virtual_workspace_members(crate_dir):
127129 if invalid_members :
128130 raise EasyBuildError ('Failed to parse %s: Found seemingly invalid members: %s' ,
129131 cargo_toml , ', ' .join (invalid_members ))
130- return members
132+ return has_package , members
131133
132134
133135def get_checksum (src , log ):
@@ -360,13 +362,15 @@ def _setup_offline_config(self, git_sources):
360362 self .log .debug (f'No source found for { crate_dir } . Using nul-checksum for vendoring' )
361363 checksum = 'null'
362364 # Sources might contain multiple crates/folders in a so-called "workspace".
363- # If there isn't a main package (Only "[workspace]" section and no "[package]" section) we have to move
364- # the individual packages out of the workspace or cargo fails with
365+ # We have to move the individual packages out of the workspace so cargo can find them.
366+ # If there is a main package it should to used too,
367+ # otherwise (Only "[workspace]" section and no "[package]" section)
368+ # we have to remove the top-level folder or cargo fails with:
365369 # "found a virtual manifest at [...]Cargo.toml instead of a package manifest"
366- member_dirs = get_virtual_workspace_members (crate_dir )
370+ has_package , member_dirs = get_workspace_members (crate_dir )
367371 if member_dirs :
368- self .log .info (f'Found virtual manifest in { crate_dir } . Members: ' + ', ' .join (member_dirs ))
369- crate_dirs = []
372+ self .log .info (f'Found workspace in { crate_dir } . Members: ' + ', ' .join (member_dirs ))
373+ cargo_pkg_dirs = []
370374 tmp_crate_dir = os .path .join (tmp_dir , os .path .basename (crate_dir ))
371375 shutil .move (crate_dir , tmp_crate_dir )
372376 for crate in member_dirs :
@@ -376,13 +380,22 @@ def _setup_offline_config(self, git_sources):
376380 f'as target path { target_path } exists' )
377381 # Use copy_dir to resolve symlinks that might point to the parent folder
378382 copy_dir (os .path .join (tmp_crate_dir , crate ), target_path , symlinks = False )
379- crate_dirs .append (target_path )
380- remove_dir (tmp_crate_dir )
383+ cargo_pkg_dirs .append (target_path )
384+ if has_package :
385+ # Remove the copied crate folders
386+ for crate in member_dirs :
387+ remove_dir (os .path .join (tmp_crate_dir , crate ))
388+ # Keep the main package in the original location
389+ shutil .move (tmp_crate_dir , crate_dir )
390+ cargo_pkg_dirs .append (crate_dir )
391+ else :
392+ self .log .info (f'Virtual manifest found in { crate_dir } , removing it' )
393+ remove_dir (tmp_crate_dir )
381394 else :
382- crate_dirs = [crate_dir ]
383- for crate_dir in crate_dirs :
384- self .log .info ('creating .cargo-checksums.json file for %s' , os .path .basename (crate_dir ))
385- chkfile = os .path .join (crate_dir , '.cargo-checksum.json' )
395+ cargo_pkg_dirs = [crate_dir ]
396+ for pkg_dir in cargo_pkg_dirs :
397+ self .log .info ('creating .cargo-checksums.json file for %s' , os .path .basename (pkg_dir ))
398+ chkfile = os .path .join (pkg_dir , '.cargo-checksum.json' )
386399 write_file (chkfile , CARGO_CHECKSUM_JSON .format (checksum = checksum ))
387400
388401 self .log .debug ("Writting config.toml entry for vendored crates from crate.io" )
0 commit comments