@@ -225,38 +225,30 @@ def __init__(self, *args, **kwargs):
225225 self .cargo_home = os .path .join (self .builddir , '.cargo' )
226226 self .set_cargo_vars ()
227227
228+ # Populate sources from "crates" list of tuples
229+ sources = []
230+ for crate_info in self .crates :
231+ if len (crate_info ) == 2 :
232+ sources .append ({
233+ 'download_filename' : self .crate_download_filename (* crate_info ),
234+ 'filename' : self .crate_src_filename (* crate_info ),
235+ 'source_urls' : [CRATESIO_SOURCE ],
236+ 'alt_location' : 'crates.io' ,
237+ })
238+ else :
239+ crate , version , repo , rev = crate_info
240+ url , repo_name = repo .rsplit ('/' , maxsplit = 1 )
241+ if repo_name .endswith ('.git' ):
242+ repo_name = repo_name [:- 4 ]
243+ sources .append ({
244+ 'git_config' : {'url' : url , 'repo_name' : repo_name , 'commit' : rev },
245+ 'filename' : self .crate_src_filename (crate , version , rev = rev ),
246+ })
247+
228248 # copy EasyConfig instance before we make changes to it
229249 self .cfg = self .cfg .copy ()
230250
231- if self .is_extension :
232- self .cfg ['crates' ] = self .options .get ('crates' , []) # Don't inherit crates from parent
233- # The (regular) extract step for extensions is not run so our handling of crates as (multiple) sources
234- # cannot be used for extensions.
235- if self .crates :
236- raise EasyBuildError (f"Extension '{ self .name } ' cannot have crates. "
237- "You can add them to the top-level config parameters when using e.g."
238- "the Cargo or CargoPythonBundle easyblock." )
239- else :
240- # Populate sources from "crates" list of tuples
241- sources = []
242- for crate_info in self .crates :
243- if len (crate_info ) == 2 :
244- sources .append ({
245- 'download_filename' : self .crate_download_filename (* crate_info ),
246- 'filename' : self .crate_src_filename (* crate_info ),
247- 'source_urls' : [CRATESIO_SOURCE ],
248- 'alt_location' : 'crates.io' ,
249- })
250- else :
251- crate , version , repo , rev = crate_info
252- url , repo_name = repo .rsplit ('/' , maxsplit = 1 )
253- if repo_name .endswith ('.git' ):
254- repo_name = repo_name [:- 4 ]
255- sources .append ({
256- 'git_config' : {'url' : url , 'repo_name' : repo_name , 'commit' : rev },
257- 'filename' : self .crate_src_filename (crate , version , rev = rev ),
258- })
259- self .cfg .update ('sources' , sources )
251+ self .cfg .update ('sources' , sources )
260252
261253 def set_cargo_vars (self ):
262254 """Set environment variables for Rust compilation and Cargo"""
@@ -495,33 +487,40 @@ def configure_step(self):
495487 """Create lockfile if it doesn't exist"""
496488 cargo_lock = 'Cargo.lock'
497489 if self .crates and os .path .exists ('Cargo.toml' ) and not os .path .exists (cargo_lock ):
498- root_toml = run_shell_cmd ('cargo locate-project --message-format=plain --workspace' ).output
499- cargo_lock_path = os .path .join (os .path .dirname (root_toml ), cargo_lock )
500- if not os .path .exists (cargo_lock_path ):
501- rust_version = LooseVersion (get_software_version ('Rust' ))
502- # File format version, the latest supported is used for forward compatibility
503- # Versions 1 and 2 were internal only, 2 being autodetected
504- # 1.47 introduced the version marker as version 3
505- # 1.78 marked version 4 as stable
506- if rust_version < '1.47' :
507- version = None
508- elif rust_version < '1.78' :
509- version = 3
510- else :
511- version = 4
512- # Use vendored crates to ensure those versions are used
513- self .log .info (f"No { cargo_lock } file found, creating one at { cargo_lock_path } " )
514- content = f'version = { version } \n ' if version is not None else ''
515- for crate_info in self .crates :
516- if len (crate_info ) == 2 :
517- name , version = crate_info
518- source = CRATES_REGISTRY_URL
490+ locate_project_output = run_shell_cmd ('cargo -q locate-project --message-format=plain --workspace' ).output
491+ # Usually it is the only line, but there might be some prior messages like warnings
492+ # Find path right path by going backwards through each line
493+ try :
494+ root_toml = next (p for p in locate_project_output .splitlines ()[::- 1 ] if os .path .exists (p ))
495+ except StopIteration :
496+ self .log .warning ("Failed to find project Cargo.toml. Skipping lockfile check & creation." )
497+ else :
498+ cargo_lock_path = os .path .join (os .path .dirname (root_toml ), cargo_lock )
499+ if not os .path .exists (cargo_lock_path ):
500+ rust_version = LooseVersion (get_software_version ('Rust' ))
501+ # File format version, the latest supported is used for forward compatibility
502+ # Versions 1 and 2 were internal only, 2 being autodetected
503+ # 1.47 introduced the version marker as version 3
504+ # 1.78 marked version 4 as stable
505+ if rust_version < '1.47' :
506+ version = None
507+ elif rust_version < '1.78' :
508+ version = 3
519509 else :
520- name , version , repo , rev = crate_info
521- source = f'git+{ repo } ?rev={ rev } #{ rev } '
522-
523- content += CONFIG_LOCK_SOURCE .format (name = name , version = version , source = source )
524- write_file (cargo_lock_path , content )
510+ version = 4
511+ # Use vendored crates to ensure those versions are used
512+ self .log .info (f"No { cargo_lock } file found, creating one at { cargo_lock_path } " )
513+ content = f'version = { version } \n ' if version is not None else ''
514+ for crate_info in self .crates :
515+ if len (crate_info ) == 2 :
516+ name , version = crate_info
517+ source = CRATES_REGISTRY_URL
518+ else :
519+ name , version , repo , rev = crate_info
520+ source = f'git+{ repo } ?rev={ rev } #{ rev } '
521+
522+ content += CONFIG_LOCK_SOURCE .format (name = name , version = version , source = source )
523+ write_file (cargo_lock_path , content )
525524
526525 @property
527526 def profile (self ):
0 commit comments