@@ -137,6 +137,9 @@ def _parse_locks(module_ctx, venv_specs):
137137 lock_specs .setdefault (lock .hub_name , {})
138138
139139 lockfile = toml .decode_file (module_ctx , lock .src )
140+ if lockfile .get ("version" ) != 1 :
141+ fail ("Lockfile %s is an unsupported format version!" % lock .src )
142+
140143 if not lockfile :
141144 problems .append ("Failed to extract {} in {}" .format (lock .src , mod .name ))
142145 continue
@@ -198,6 +201,55 @@ Problems:
198201
199202 return lock_specs
200203
204+ _default_annotations = struct (
205+ per_package = {},
206+ default_build_deps = [
207+ {"name" : "setuptools" },
208+ {"name" : "build" },
209+ ],
210+ )
211+
212+ def _parse_annotations (module_ctx , hub_specs , venv_specs ):
213+ # Map of hub to venv to lock contents
214+ annotations = {}
215+
216+ for mod in module_ctx .modules :
217+ for ann in mod .tags .annotate_requirements :
218+ if ann .hub_name not in venv_specs :
219+ fail ("Annotations file %s attaches to undefined hub %s" % (ann .src , ann .hub_name ))
220+
221+ annotations .setdefault (ann .hub_name , {})
222+
223+ if ann .venv_name not in venv_specs .get (ann .hub_name , {}):
224+ fail ("Annotations file %s attaches to undefined venv %s" % (ann .src , ann .venv_name ))
225+
226+ # FIXME: Allow the default build deps to be changed
227+ annotations [ann .hub_name ].setdefault (ann .venv_name , struct (
228+ per_package = {},
229+ default_build_deps = [] + _default_annotations .default_build_deps ,
230+ ))
231+
232+ annotations = toml .decode_file (module_ctx , ann .src )
233+ if annotations .get ("version" ) != "0.0.0" :
234+ fail ("Annotations file %s doesn't specify a valid version= key" % ann .src )
235+
236+ for package in annotations .get ("package" , []):
237+ if not "name" in package :
238+ fail ("Annotations file %s is invalid; all [[package]] entries must have a name" % ann .src )
239+
240+ # Apply name normalization so we don't forget about it
241+ package ["name" ] = normalize_name (package ["name" ])
242+
243+ if not "build-dependencies" in package :
244+ fail ("Annotations file %s is invalid; all [[package]] entries must specify build-dependencies" % ann .src )
245+
246+ if package ["name" ] in annotations [ann .hub_name ][ann .venv_name ]:
247+ fail ("Annotation conflict! Package %s is annotated in venv %s multiple times!" % (package ["name" ], ann .venv_name ))
248+
249+ annotations [ann .hub_name ][ann .venv_name ].per_package [package ["name" ]] = package
250+
251+ return annotations
252+
201253def _parse_overrides (module_ctx , venv_specs ):
202254 # Map of hub -> venv -> target -> override label
203255 overrides = {}
@@ -379,7 +431,7 @@ def _venv_target(hub_name, venv, package_name):
379431 package_name ,
380432 )
381433
382- def _sbuild_repos (module_ctx , lock_specs , override_specs ):
434+ def _sbuild_repos (module_ctx , lock_specs , annotation_specs , override_specs ):
383435 for hub_name , venvs in lock_specs .items ():
384436 for venv_name , lock in venvs .items ():
385437 for package in lock .get ("package" , []):
@@ -392,17 +444,22 @@ def _sbuild_repos(module_ctx, lock_specs, override_specs):
392444
393445 name = _sbuild_repo_name (hub_name , venv_name , package )
394446
447+ venv_anns = annotation_specs .get (hub_name , {}).get (venv_name , _default_annotations )
448+ build_deps = venv_anns .per_package .get (package ["name" ], {}).get ("build-dependencies" , [])
449+
450+ # Per-package build deps, plus global defaults
451+ build_deps = {
452+ it ["name" ]: it for it in build_deps + venv_anns .default_build_deps
453+ }
454+
395455 # print("Creating sdist repo", name)
396456 sdist_build (
397457 name = name ,
398458 src = "@" + _sdist_repo_name (package ) + "//file" ,
399459 # FIXME: Add support for build deps and annotative build deps
400460 deps = [
401461 "@" + _venv_target (hub_name , venv_name , package ["name" ])
402- for package in package .get ("build-dependencies" , [
403- {"name" : "setuptools" },
404- {"name" : "build" }
405- ])
462+ for package in build_deps .values ()
406463 ],
407464 )
408465
@@ -732,6 +789,8 @@ def _uv_impl(module_ctx):
732789 venv_specs = _parse_venvs (module_ctx , hub_specs )
733790
734791 lock_specs = _parse_locks (module_ctx , venv_specs )
792+
793+ annotation_specs = _parse_annotations (module_ctx , hub_specs , venv_specs )
735794
736795 override_specs = _parse_overrides (module_ctx , venv_specs )
737796 # Roll through all the configured wheels, collect & validate the unique
@@ -741,15 +800,15 @@ def _uv_impl(module_ctx):
741800
742801 # Collect declared entrypoints for packages
743802 entrypoints = _collect_entrypoints (module_ctx , lock_specs )
744- print (entrypoints )
803+ # print(entrypoints)
745804
746805 # Roll through and create sdist and whl repos for all configured sources
747806 # Note that these have no deps to this point
748807 _raw_sdist_repos (module_ctx , lock_specs , override_specs )
749808 _raw_whl_repos (module_ctx , lock_specs , override_specs )
750809
751810 # Roll through and create per-venv sdist build repos
752- _sbuild_repos (module_ctx , lock_specs , override_specs )
811+ _sbuild_repos (module_ctx , lock_specs , annotation_specs , override_specs )
753812
754813 # Roll through and create per-venv whl installs
755814 #
@@ -792,7 +851,7 @@ _lockfile_tag = tag_class(
792851 },
793852)
794853
795- _install_requires_tag = tag_class (
854+ _annotations_tag = tag_class (
796855 attrs = {
797856 "hub_name" : attr .string (mandatory = True ),
798857 "venv_name" : attr .string (mandatory = True ),
@@ -829,7 +888,7 @@ uv = module_extension(
829888 "declare_hub" : _hub_tag ,
830889 "declare_venv" : _venv_tag ,
831890 "lockfile" : _lockfile_tag ,
832- "annotate_requirements" : _install_requires_tag ,
891+ "annotate_requirements" : _annotations_tag ,
833892 "declare_entrypoint" : _declare_entrypoint ,
834893 "discover_entrypoints" : _create_entrypoints ,
835894 "override_requirement" : _override_requirement ,
0 commit comments