public void activateInStages(Collection<GhidraBundle> bundles, TaskMonitor monitor,
			PrintWriter console) {
		Map<GhidraBundle, List<BundleRequirement>> requirementMap = new HashMap<>();
		for (GhidraBundle bundle : bundles) {
			try {
				List<BundleRequirement> requirements = bundle.getAllRequirements();
				// remove optional requirements
				requirements.removeIf(r -> {
					BundleRequirementImpl rimpl = (BundleRequirementImpl) r;
					return rimpl.isOptional();
				});
				requirementMap.put(bundle, requirements);
			}
			catch (GhidraBundleException e) {
				// TODO should we report failing bundles to the console as well so they get logged
				// in headless mode?
				fireBundleException(e);
			}
		}

		List<GhidraBundle> bundlesRemaining = new ArrayList<>(requirementMap.keySet());
		monitor.setMaximum(bundlesRemaining.size());
		while (!bundlesRemaining.isEmpty() && !monitor.isCancelled()) {
			List<GhidraBundle> resolvableBundles = bundlesRemaining.stream()
					.filter(bundle -> canResolveAll(requirementMap.get(bundle)))
					.collect(Collectors.toList());
			if (resolvableBundles.isEmpty()) {
				// final round, try everything that hasn't already been eliminated.
				// this can generate helpful error messages
				resolvableBundles = bundlesRemaining;
				bundlesRemaining = Collections.emptyList();
			}
			else {
				bundlesRemaining.removeAll(resolvableBundles);
			}

			for (GhidraBundle bundle : resolvableBundles) {
				if (monitor.isCancelled()) {
					break;
				}
				try {
					bundle.build(console);
					activateSynchronously(bundle.getLocationIdentifier());
				}
				catch (GhidraBundleException e) {
					// TODO should we report failing bundles to the console as well so they get logged
					// in headless mode?
					fireBundleException(e);
				}
				catch (Exception e) {
					// write the error to the console or log file
					console.println("Unexpected error activating bundle: " + bundle);
					e.printStackTrace(console);
				}
				monitor.incrementProgress(1);
			}
		}
	}
Activate a set of bundles in dependency topological order by resolving against currently
active bundles in stages.  <b>No bundles outside those requested will be activated.</b>

<p>To have inactive dependencies loaded, call 
{@link #activateAll(Collection, TaskMonitor, PrintWriter)}.

@param bundles bundles to activate
@param monitor a task monitor
@param console where to write build messages
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleHost.java