@@ -129,6 +129,14 @@ def _parse_locks(module_ctx, venv_specs):
129129 for d in package ["dependencies" ]:
130130 d ["name" ] = normalize_name (d ["name" ])
131131
132+ # Note that we also have to mangle the optional deps so they tie
133+ # off too. We don't mangle group names because they're
134+ # eliminated when we resolve the depgraph.
135+ if "optional-dependencies" in package :
136+ for name , group in package ["optional-dependencies" ].items ():
137+ for d in group :
138+ d ["name" ] = normalize_name (d ["name" ])
139+
132140 # FIXME: Should validate the lockfile but for now just stash it
133141 # Validating in starlark kinda rots anyway
134142 lock_specs [lock .hub_name ][lock .venv_name ] = lockfile
@@ -146,8 +154,15 @@ def _collect_configurations(repository_ctx, lock_specs):
146154 for hub_name , venvs in lock_specs .items ():
147155 for venv_name , lock in venvs .items ():
148156 for package in lock .get ("package" , []):
149- if "registry" not in package ["source" ]:
150- continue
157+ # Remote package sources
158+ # - { source = { registry = "https://some.registry/..." } }
159+ # - { source = { url = "https://ton.hosting.biz/some.whl" } }
160+ # FIXME: Git URLs?
161+ # FIXME: Egg URLs?
162+ #
163+ # These seem to be used by the package itself
164+ # - { source = { editable = "." } }
165+ # - { source = { virtual = "." } }
151166
152167 for whl in package .get ("wheels" , []):
153168 url = whl ["url" ]
@@ -167,7 +182,7 @@ def _collect_configurations(repository_ctx, lock_specs):
167182 # Ignore configurations for unsupported interpreters
168183 if not supported_python (python_tag ):
169184 continue
170-
185+
171186 python_tags [python_tag ] = 1
172187
173188 for platform_tag in parsed_wheel .platform_tags :
@@ -208,9 +223,6 @@ def _raw_sdist_repos(module_ctx, lock_specs):
208223 for hub_name , venvs in lock_specs .items ():
209224 for venv_name , lock in venvs .items ():
210225 for package in lock .get ("package" , []):
211- if "registry" not in package ["source" ]:
212- continue
213-
214226 sdist = package .get ("sdist" )
215227 if sdist == None :
216228 continue
@@ -253,9 +265,6 @@ def _raw_whl_repos(module_ctx, lock_specs):
253265 for hub_name , venvs in lock_specs .items ():
254266 for venv_name , lock in venvs .items ():
255267 for package in lock .get ("package" , []):
256- if "registry" not in package ["source" ]:
257- continue
258-
259268 wheels = package .get ("wheels" , [])
260269 for whl in wheels :
261270 url = whl ["url" ]
@@ -296,9 +305,6 @@ def _sbuild_repos(module_ctx, lock_specs):
296305 for hub_name , venvs in lock_specs .items ():
297306 for venv_name , lock in venvs .items ():
298307 for package in lock .get ("package" , []):
299- if "registry" not in package ["source" ]:
300- continue
301-
302308 if "sdist" not in package :
303309 continue
304310
@@ -322,9 +328,6 @@ def _whl_install_repos(module_ctx, lock_specs):
322328 for hub_name , venvs in lock_specs .items ():
323329 for venv_name , lock in venvs .items ():
324330 for package in lock .get ("package" , []):
325- if "registry" not in package ["source" ]:
326- continue
327-
328331 # This is where we need to actually choose which wheel we will
329332 # "install", and so this is where prebuild selection needs to
330333 # happen according to constraints.
@@ -353,32 +356,57 @@ def _venv_hub_name(hub, venv):
353356def _group_repos (module_ctx , lock_specs ):
354357 # Hub -> requirement -> venv -> True
355358 # For building hubs we need to know what venv configurations a given
359+
360+ # TODO: Missing support for `marker=""` specifications in `dependencies`.
361+ # Deps may be conditional on this or that predicate being satisfied.
362+ # Dependencies which have markers need to be rewritten so that the
363+ # dependency edge goes through a select.
364+ #
365+ # TODO: What happens if you have a cycle only when this or that feature is
366+ # active? Probably the fix is to turn on all dependency edges
367+
356368 package_venvs = {}
357369
358370 for hub_name , venvs in lock_specs .items ():
359371 package_venvs [hub_name ] = {}
360372
361373 for venv_name , lock in venvs .items ():
362- # First we need to build the adjacency graph
374+ # Index all the packages by name so activating extras is easy
375+ packages = {
376+ package ["name" ]: package
377+ for package in lock .get ("package" , [])
378+ }
379+
380+ # Build a graph {name: {dependency_name: dependency_marker_condition}}
363381 graph = {}
364382
365- for package in lock . get ( "package" , [] ):
383+ for name , package in packages . items ( ):
366384 if "registry" not in package ["source" ]:
367385 continue
368386
369- deps = []
387+ deps = {}
370388
371389 # Enter the package into the venv internal graph
372- graph [package ["name" ]] = deps
390+ graph .setdefault (package ["name" ], {})
391+
373392 for d in package .get ("dependencies" , []):
374- deps .append (d ["name" ])
393+ # Or in all the dep bits
394+ graph [package ["name" ]][d ["name" ]] = d .get ("marker" , "" )
395+
396+ # Activate extras
397+ extras = packages [d ["name" ]].get ("optional-dependencies" , {})
398+ for extra in d .get ("extra" , []):
399+ for extra_dep in extras .get (extra , []):
400+ graph .setdefault (d ["name" ], {})
401+ graph [d ["name" ]][extra_dep ["name" ]] = extra_dep .get ("marker" , "" )
375402
376403 # Enter the package into the venv hub manifest
377404 package_venvs [hub_name ].setdefault (package ["name" ], {})
378405 package_venvs [hub_name ][package ["name" ]][venv_name ] = 1
379406
380407 # So we can find sccs/clusters which need to co-occur
381- cycle_groups = sccs (graph )
408+ # Note that we're assuming ALL marker conditional deps are live.
409+ cycle_groups = sccs ({k : v .keys () for k , v in graph .items ()})
382410
383411 # Now we can assign names to the sccs and collect deps Note that
384412 # _every_ node in the graph will be in _a_ scc, those sccs are just
@@ -412,11 +440,12 @@ def _group_repos(module_ctx, lock_specs):
412440 if d not in scc :
413441 deps [name ][d ] = 1
414442
443+ # TODO: How do we plumb markers through here?
444+
415445 # At this point we have mapped every package to an scc (possibly of
416446 # size 1) which it participates in, named those sccs, and identified
417447 # their direct dependencies beyond the scc. So we can just lay down
418448 # targets.
419-
420449 venv_hub (
421450 name = _venv_hub_name (hub_name , venv_name ),
422451 aliases = scc_aliases , # String dict
0 commit comments