dtool.dub.DubManifestParser.java Source code

Java tutorial

Introduction

Here is the source code for dtool.dub.DubManifestParser.java

Source

/*******************************************************************************
 * Copyright (c) 2013 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 static melnorme.utilbox.misc.StringUtil.nullAsEmpty;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;

import com.google.gson.stream.JsonToken;
import com.google.gson.stream.MalformedJsonException;

import dtool.dub.DubBundle.BundleFile;
import dtool.dub.DubBundle.DubBundleException;
import dtool.dub.DubBundle.DubConfiguration;
import dtool.util.JsonReaderExt;
import melnorme.lang.tooling.BundlePath;
import melnorme.lang.tooling.bundle.DependencyRef;
import melnorme.utilbox.collections.ArrayList2;
import melnorme.utilbox.core.CommonException;
import melnorme.utilbox.misc.ArrayUtil;
import melnorme.utilbox.misc.FileUtil;
import melnorme.utilbox.misc.Location;
import melnorme.utilbox.misc.MiscUtil;
import melnorme.utilbox.misc.PathUtil;
import melnorme.utilbox.misc.StringUtil;

/**
 * Parse a Dub bundle in a filesystem location into an in-memory description of the bundle.
 */
public class DubManifestParser extends CommonDubParser {

    public static final String ERROR_BUNDLE_NAME_UNDEFINED = "Bundle name not defined.";

    public static DubBundle parseDubBundleFromLocation2(BundlePath bundlePath) {
        assertNotNull(bundlePath);
        Location manifestLocation = bundlePath.getManifestLocation(true);
        if (manifestLocation != null && nullAsEmpty(manifestLocation.getFileName()).endsWith(".sdl")) {
            return null; // We only know how to parse JSON
        }
        return new DubManifestParser().parseDubBundle(bundlePath, manifestLocation);
    }

    protected String source;

    protected String bundleName = null;
    protected String pathString = null;

    protected String version = null;
    protected String[] sourceFolders = null;
    protected ArrayList2<BundleFile> bundleFiles = null;
    protected DependencyRef[] dependencies = null;
    protected String targetName = null;
    protected String targetPath = null;

    protected ArrayList2<DubConfiguration> configurations = null;

    protected DubManifestParser() {
    }

    protected DubBundle parseDubBundle(BundlePath bundlePath, Location manifestLocation) {
        try {
            parseFromLocation(manifestLocation);
        } catch (DubBundleException e) {
            dubError = e;
        }
        return createBundle(bundlePath, true);
    }

    protected void parseFromLocation(Location jsonManifestLocation) throws DubBundleException {
        try {
            source = FileUtil.readStringFromFile(jsonManifestLocation.toFile(), StringUtil.UTF8);
        } catch (IOException e) {
            throw new DubBundleException(e);
        }
        parseFromSource(source);
    }

    public DubBundle createBundle(BundlePath bundlePath, boolean searchImplicitSourceFolders) {
        if (bundleName == null) {
            bundleName = "<undefined>";

            putError(ERROR_BUNDLE_NAME_UNDEFINED);
        }

        if (bundlePath == null) {
            if (pathString == null) {
                putError("Missing path entry.");
            } else {
                bundlePath = BundlePath.create(pathString);
                if (bundlePath == null) {
                    putError("Invalid path: " + pathString);
                }
            }
        }
        Path[] effectiveSourceFolders;
        if (sourceFolders != null) {
            effectiveSourceFolders = createPaths(sourceFolders);
        } else if (searchImplicitSourceFolders && bundlePath != null) {
            effectiveSourceFolders = searchImplicitSrcFolders(bundlePath.getLocation());
        } else {
            effectiveSourceFolders = null;
        }

        return new DubBundle(bundlePath, bundleName, dubError, version, sourceFolders, effectiveSourceFolders,
                bundleFiles, dependencies, targetName, targetPath, configurations);
    }

    protected Path[] createPaths(String[] paths) {
        if (paths == null)
            return null;

        ArrayList<Path> pathArray = new ArrayList<>();
        for (String pathString : paths) {
            try {
                pathArray.add(PathUtil.createPath(pathString, "Invalid source/import path: "));
            } catch (CommonException ce) {
                putError(ce.getMessage());
            }
        }

        return ArrayUtil.createFrom(pathArray, Path.class);
    }

    protected Path[] searchImplicitSrcFolders(Location location) {
        if (location == null) {
            return new Path[0];
        }
        File locationDir = location.toFile();
        if (!locationDir.isDirectory()) {
            putError("location is not a directory");
            return new Path[0];
        }

        final ArrayList<Path> implicitFolders = new ArrayList<>();
        locationDir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                if (dir.isDirectory() && (name.equals("src") || name.equals("source"))) {
                    implicitFolders.add(MiscUtil.createValidPath(name));
                }
                return false;
            }
        });

        return ArrayUtil.createFrom(implicitFolders, Path.class);
    }

    @Override
    protected void readData(JsonReaderExt jsonParser) throws IOException, DubBundleException {
        readBundle(jsonParser);
    }

    protected DubManifestParser readBundle(JsonReaderExt jsonReader) throws IOException, DubBundleException {
        jsonReader.consumeExpected(JsonToken.BEGIN_OBJECT);

        while (jsonReader.hasNext()) {
            JsonToken tokenType = jsonReader.peek();

            if (tokenType == JsonToken.NAME) {
                String propertyName = jsonReader.nextName();

                if (propertyName.equals("name")) {
                    bundleName = jsonReader.consumeStringValue();
                } else if (propertyName.equals("version")) {
                    version = jsonReader.consumeStringValue();
                } else if (propertyName.equals("path")) {
                    pathString = jsonReader.consumeStringValue();
                } else if (propertyName.equals("importPaths")) {
                    sourceFolders = parseSourcePaths(jsonReader);
                } else if (propertyName.equals("dependencies")) {
                    dependencies = parseDependencies(jsonReader);
                } else if (propertyName.equals("files")) {
                    bundleFiles = parseFiles(jsonReader);
                } else if (propertyName.equals("targetName")) {
                    targetName = jsonReader.consumeStringValue();
                } else if (propertyName.equals("targetPath")) {
                    targetPath = jsonReader.consumeStringValue();
                } else if (propertyName.equals("configurations")) {
                    configurations = parseConfigurations(jsonReader);
                } else {
                    jsonReader.skipValue();
                }
            } else {
                jsonReader.errorUnexpected(tokenType);
            }
        }

        jsonReader.consumeExpected(JsonToken.END_OBJECT);
        return this;
    }

    protected String[] parseSourcePaths(JsonReaderExt jsonReader) throws IOException {
        ArrayList<String> stringArray = jsonReader.consumeStringArray(true);
        return ArrayUtil.createFrom(stringArray, String.class);
    }

    protected ArrayList2<BundleFile> parseFiles(JsonReaderExt jsonReader) throws IOException {
        jsonReader.consumeExpected(JsonToken.BEGIN_ARRAY);

        ArrayList2<BundleFile> bundleFiles = new ArrayList2<>();

        while (jsonReader.hasNext()) {
            BundleFile bundleFile = parseFile(jsonReader);
            bundleFiles.add(bundleFile);
        }

        jsonReader.consumeExpected(JsonToken.END_ARRAY);
        return bundleFiles;
    }

    protected BundleFile parseFile(JsonReaderExt jsonReader) throws IOException {
        jsonReader.consumeExpected(JsonToken.BEGIN_OBJECT);
        String path = null;
        boolean importOnly = false;

        while (jsonReader.hasNext()) {
            String propName = jsonReader.consumeExpectedPropName();

            switch (propName) {
            case "path":
                path = jsonReader.consumeStringValue();
                break;
            case "type":
                //TODO

            default:
                jsonReader.skipValue();
            }
        }
        jsonReader.consumeExpected(JsonToken.END_OBJECT);
        if (path == null) {
            path = "<missing_path>";
            putError("missing path property for files entry.");
        }
        return new DubBundle.BundleFile(path, importOnly);
    }

    protected DependencyRef[] parseDependencies(JsonReaderExt jsonParser) throws IOException {
        return new BundleDependenciesSegmentParser(jsonParser).parse();
    }

    protected class BundleDependenciesSegmentParser {

        protected JsonReaderExt jsonReader;

        public BundleDependenciesSegmentParser(JsonReaderExt jsonParser) {
            this.jsonReader = jsonParser;
        }

        public DependencyRef[] parse() throws IOException {
            if (jsonReader.peek() == JsonToken.BEGIN_OBJECT)
                return parseRawDeps();

            return parseResolvedDeps();
        }

        public DependencyRef[] parseRawDeps() throws IOException, MalformedJsonException {
            jsonReader.consumeExpected(JsonToken.BEGIN_OBJECT);

            ArrayList<DependencyRef> deps = new ArrayList<>();

            while (jsonReader.hasNext()) {
                String depName = jsonReader.consumeExpectedPropName();
                jsonReader.skipValue(); // Ignore value for now, TODO

                deps.add(new DependencyRef(depName, null));
            }
            jsonReader.consumeExpected(JsonToken.END_OBJECT);
            return ArrayUtil.createFrom(deps, DependencyRef.class);
        }

        public DependencyRef[] parseResolvedDeps() throws IOException, MalformedJsonException {
            jsonReader.consumeExpected(JsonToken.BEGIN_ARRAY);

            ArrayList<DependencyRef> deps = new ArrayList<>();

            while (jsonReader.hasNext()) {
                String depName = jsonReader.nextString();
                deps.add(new DependencyRef(depName, null));
            }
            jsonReader.consumeExpected(JsonToken.END_ARRAY);
            return ArrayUtil.createFrom(deps, DependencyRef.class);
        }
    }

    protected ArrayList2<DubConfiguration> parseConfigurations(JsonReaderExt jsonReader)
            throws IOException, DubBundleException {
        jsonReader.consumeExpected(JsonToken.BEGIN_ARRAY);

        ArrayList2<DubConfiguration> bundleFiles = new ArrayList2<>();

        while (jsonReader.hasNext()) {
            DubConfiguration element = parseConfiguration(jsonReader);
            bundleFiles.add(element);
        }

        jsonReader.consumeExpected(JsonToken.END_ARRAY);
        return bundleFiles;
    }

    protected DubConfiguration parseConfiguration(JsonReaderExt jsonReader) throws IOException, DubBundleException {
        jsonReader.consumeExpected(JsonToken.BEGIN_OBJECT);

        String name = null;
        String targetType = null;
        String targetName = null;
        String targetPath = null;

        while (jsonReader.hasNext()) {
            String propName = jsonReader.consumeExpectedPropName();

            switch (propName) {
            case "name":
                name = jsonReader.consumeStringValue();
                break;
            case "targetType":
                targetType = jsonReader.consumeStringValue();
                break;
            case "targetName":
                targetName = jsonReader.consumeStringValue();
                break;
            case "targetPath":
                targetPath = jsonReader.consumeStringValue();
                break;

            default:
                jsonReader.skipValue();
            }
        }
        jsonReader.consumeExpected(JsonToken.END_OBJECT);

        if (name == null) {
            throw new DubBundleException("Build configuration has no name attribute");
        }

        return new DubConfiguration(name, targetType, targetName, targetPath);
    }

}