/*******************************************************************************
* Copyright (c) 2014 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package dtool.dub;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import dtool.dub.DubBundle.DubBundleException;
import melnorme.lang.tooling.BundlePath;
import melnorme.lang.tooling.bundle.DependencyRef;
/**
* A resolved DUB bundle description.
* This is usually derived from running the DUB describe tool, and as such it can be incomplete and have errors.
*/
public class DubBundleDescription {
public static final String BUNDLE_NAME_ERROR = "<error_undefined>";
protected final boolean isResolved;
protected final DubBundle mainDubBundle;
protected final DubBundle[] bundleDependencies; //not null
protected final DubBundleException error;
/** Constructor for unresolved descriptions. */
public DubBundleDescription(DubBundle unresolvedBundle) {
this(unresolvedBundle, EMTPY_BUNDLE_DEPS, false, unresolvedBundle.error);
}
public DubBundleDescription(DubBundle unresolvedBundle, DubBundleException error) {
this(unresolvedBundle, EMTPY_BUNDLE_DEPS, false, error);
}
public DubBundleDescription(DubBundle mainBundle, DubBundle[] bundleDeps) {
this(mainBundle, bundleDeps, true, findError(mainBundle, bundleDeps));
}
protected DubBundleDescription(DubBundle mainBundle, DubBundle[] bundleDeps, boolean isResolvedFlag,
DubBundleException error) {
this.mainDubBundle = assertNotNull(mainBundle);
this.bundleDependencies = assertNotNull(bundleDeps);
this.error = error;
this.isResolved = isResolvedFlag && error == null;
}
protected static DubBundleException findError(DubBundle mainDubBunble, DubBundle[] bundleDependencies) {
if(mainDubBunble.error != null) {
return mainDubBunble.error;
} else {
for (DubBundle dubBundle : bundleDependencies) {
if(dubBundle.error != null) {
return dubBundle.error;
}
}
return null;
}
}
protected static final DubBundle[] EMTPY_BUNDLE_DEPS = { };
public DubBundle getMainBundle() {
return mainDubBundle;
}
public DubBundle[] getBundleDependencies() {
return bundleDependencies;
}
/** A bundle description is considered resolved if dub.json had no errors, and if
* a 'dub describe' output was processed successfully. */
public boolean isResolved() {
return isResolved;
}
public boolean hasErrors() {
return error != null;
}
public DubBundleException getError() {
return error;
}
public boolean isParseError() {
if(getError() == null) {
return false;
}
if(getError().getMessage().startsWith(CommonDubParser.MSG_JSON_PARSE_ERROR)) {
return true;
}
return false;
}
/* ----------------- helper to create ResolvedManifest ----------------- */
public static class DubDescribeAnalysis {
protected final HashMap<String, DubBundle> bundlesMap = new HashMap<>();
protected final HashMap<String, ResolvedManifest> manifests = new HashMap<>();
protected final HashSet<String> manifestsBeingCalculated = new HashSet<>();
public final ResolvedManifest mainManifest;
public DubDescribeAnalysis(DubBundleDescription bundleDesc) {
DubBundle[] bundleDeps = bundleDesc.getBundleDependencies();
for (DubBundle depBundle : bundleDeps) {
bundlesMap.put(depBundle.getBundleName(), depBundle);
}
for (DubBundle dubBundle : bundleDeps) {
calculateResolvedManifest(dubBundle);
}
mainManifest = calculateResolvedManifest(bundleDesc.getMainBundle());
}
public Collection<ResolvedManifest> getAllManifests() {
return manifests.values();
}
public ResolvedManifest calculateResolvedManifest(DubBundle bundle) {
final BundlePath bundlePath = bundle.getBundlePath();
if(bundlePath == null) {
// dtoolServer.logError("DUB describe: invalid bundle path: " + bundlePath);
return null;
}
final String bundleName = bundle.getBundleName();
ResolvedManifest manifest = manifests.get(bundleName);
if(manifest != null) {
return manifest;
}
if(manifestsBeingCalculated.contains(bundleName)) {
// Error: cycle in DUB describe
// dtoolServer.logError("DUB describe: bundle dependencies cycle detected!");
return null;
}
manifestsBeingCalculated.add(bundleName); // Mark as being created, for cycle checking
ArrayList<ResolvedManifest> directDeps = calculateDirectDependencies(bundle);
manifest = new ResolvedManifest(bundle, directDeps);
manifests.put(bundleName, manifest);
return manifest;
}
protected ArrayList<ResolvedManifest> calculateDirectDependencies(DubBundle bundle) {
ArrayList<ResolvedManifest> directDeps = new ArrayList<>(bundle.getDependencyRefs().length);
for (DependencyRef directDependencyRef : bundle.getDependencyRefs()) {
String depName = directDependencyRef.getBundleName();
DubBundle depBundle = bundlesMap.get(depName);
if(depBundle == null) {
// dtoolServer.logError("DUB describe: missing dependency: " + depName, null);
continue;
}
ResolvedManifest manifest = calculateResolvedManifest(depBundle);
if(manifest == null) {
// dtoolServer.logError("DUB describe: invalid dependency: " + depName, null);
continue;
}
directDeps.add(manifest);
}
return directDeps;
}
}
}