com.google.devtools.bazel.e4b.BazelProjectSupport.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.bazel.e4b.BazelProjectSupport.java

Source

// Copyright 2016 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.bazel.e4b;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;

import com.google.common.collect.ImmutableList;
import com.google.devtools.bazel.e4b.classpath.BazelClasspathContainer;
import com.google.devtools.bazel.e4b.command.BazelCommand;
import com.google.devtools.bazel.e4b.command.BazelCommand.BazelInstance;
import com.google.devtools.bazel.e4b.command.BazelNotFoundException;
import com.google.devtools.bazel.e4b.projectviews.ProjectView;

/**
 * A utility class to create e4b projects.
 */
public class BazelProjectSupport {

    private static final String STANDARD_VM_CONTAINER_PREFIX = "org.eclipse.jdt.launching.JRE_CONTAINER/"
            + "org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.";

    /**
     * Create a e4b project. This method adds the natures to the project, saves the list of targets
     * and the workspace root to the project settings, make Bazel the default builder instead of ECJ
     * and create the classpath using ide build informations from Bazel.
     */
    public static IProject createProject(String projectName, URI location, String workspaceRoot, List<String> paths,
            List<String> targets, int javaLanguageVersion) {

        IProject project = createBaseProject(projectName, location);
        try {
            addNature(project, ProjectNature.NATURE_ID);
            addNature(project, JavaCore.NATURE_ID);
            addSettings(project, workspaceRoot, targets, ImmutableList.of());
            setBuilders(project);
            createClasspath(new Path(workspaceRoot), paths, JavaCore.create(project), javaLanguageVersion);
        } catch (CoreException e) {
            e.printStackTrace();
            project = null;
        } catch (BackingStoreException e) {
            e.printStackTrace();
            project = null;
        }

        return project;
    }

    private static void addSettings(IProject project, String workspaceRoot, List<String> targets,
            List<String> buildFlags) throws BackingStoreException {
        IScopeContext projectScope = new ProjectScope(project);
        Preferences projectNode = projectScope.getNode(Activator.PLUGIN_ID);
        int i = 0;
        for (String target : targets) {
            projectNode.put("target" + i, target);
            i++;
        }
        projectNode.put("workspaceRoot", workspaceRoot);
        i = 0;
        for (String flag : buildFlags) {
            projectNode.put("buildFlag" + i, flag);
            i++;
        }
        projectNode.flush();
    }

    private static void setBuilders(IProject project) throws CoreException {
        IProjectDescription description = project.getDescription();
        final ICommand buildCommand = description.newCommand();
        buildCommand.setBuilderName("com.google.devtools.bazel.e4b.builder");
        description.setBuildSpec(new ICommand[] { buildCommand });
        project.setDescription(description, null);
    }

    private static void createClasspath(IPath root, List<String> paths, IJavaProject javaProject,
            int javaLanguageLevel) throws CoreException {
        String name = root.lastSegment();
        IFolder base = javaProject.getProject().getFolder(name);
        if (!base.isLinked()) {
            base.createLink(root, IResource.NONE, null);
        }
        List<IClasspathEntry> list = new LinkedList<>();
        for (String path : paths) {
            IPath workspacePath = base.getFullPath().append(path);
            list.add(JavaCore.newSourceEntry(workspacePath));
        }
        list.add(JavaCore.newContainerEntry(new Path(BazelClasspathContainer.CONTAINER_NAME)));

        list.add(JavaCore.newContainerEntry(new Path(STANDARD_VM_CONTAINER_PREFIX + javaLanguageLevel)));
        IClasspathEntry[] newClasspath = list.toArray(new IClasspathEntry[0]);
        javaProject.setRawClasspath(newClasspath, null);
    }

    private static IProject createBaseProject(String projectName, URI location) {
        IProject newProject = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);

        if (!newProject.exists()) {
            URI projectLocation = location;
            IProjectDescription desc = newProject.getWorkspace().newProjectDescription(newProject.getName());
            if (location != null && ResourcesPlugin.getWorkspace().getRoot().getLocationURI().equals(location)) {
                projectLocation = null;
            }

            desc.setLocationURI(projectLocation);
            try {
                newProject.create(desc, null);
                if (!newProject.isOpen()) {
                    newProject.open(null);
                }
            } catch (CoreException e) {
                e.printStackTrace();
            }
        }

        return newProject;
    }

    private static void addNature(IProject project, String nature) throws CoreException {
        if (!project.hasNature(nature)) {
            IProjectDescription description = project.getDescription();
            String[] prevNatures = description.getNatureIds();
            String[] newNatures = new String[prevNatures.length + 1];
            System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
            newNatures[prevNatures.length] = nature;
            description.setNatureIds(newNatures);

            project.setDescription(description, null);
        }
    }

    /**
     * List targets configure for <code>project</code>. Each project configured for Bazel is
     * configured to track certain targets and this function fetch this list from the project
     * preferences.
     */
    public static List<String> getTargets(IProject project) throws BackingStoreException {
        // Get the list of targets from the preferences
        IScopeContext projectScope = new ProjectScope(project);
        Preferences projectNode = projectScope.getNode(Activator.PLUGIN_ID);
        ImmutableList.Builder<String> builder = ImmutableList.builder();
        for (String s : projectNode.keys()) {
            if (s.startsWith("target")) {
                builder.add(projectNode.get(s, ""));
            }
        }
        return builder.build();
    }

    /**
     * List of build flags for <code>project</code>, taken from the project configuration
     */
    public static List<String> getBuildFlags(IProject project) throws BackingStoreException {
        // Get the list of targets from the preferences
        IScopeContext projectScope = new ProjectScope(project);
        Preferences projectNode = projectScope.getNode(Activator.PLUGIN_ID);
        ImmutableList.Builder<String> builder = ImmutableList.builder();
        for (String s : projectNode.keys()) {
            if (s.startsWith("buildArgs")) {
                builder.add(projectNode.get(s, ""));
            }
        }
        return builder.build();
    }

    /**
     * Return the {@link BazelInstance} corresponding to the given <code>project</code>. It looks for
     * the instance that runs for the workspace root configured for that project.
     *
     * @throws BazelNotFoundException
     */
    public static BazelCommand.BazelInstance getBazelCommandInstance(IProject project)
            throws BackingStoreException, IOException, InterruptedException, BazelNotFoundException {
        IScopeContext projectScope = new ProjectScope(project.getProject());
        Preferences projectNode = projectScope.getNode(Activator.PLUGIN_ID);
        File workspaceRoot = new File(projectNode.get("workspaceRoot", project.getLocation().toFile().toString()));
        return Activator.getDefault().getCommand().getInstance(workspaceRoot);
    }

    /**
     * Convert an Eclipse JDT project into an IntelliJ project view
     */
    public static ProjectView getProjectView(IProject project) throws BackingStoreException, JavaModelException {
        com.google.devtools.bazel.e4b.projectviews.Builder builder = ProjectView.builder();
        IScopeContext projectScope = new ProjectScope(project);
        Preferences projectNode = projectScope.getNode(Activator.PLUGIN_ID);
        for (String s : projectNode.keys()) {
            if (s.startsWith("buildArgs")) {
                builder.addBuildFlag(projectNode.get(s, ""));
            } else if (s.startsWith("target")) {
                builder.addTarget(projectNode.get(s, ""));
            }
        }

        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        for (IClasspathEntry entry : ((IJavaProject) project).getRawClasspath()) {
            switch (entry.getEntryKind()) {
            case IClasspathEntry.CPE_SOURCE:
                IResource res = root.findMember(entry.getPath());
                if (res != null) {
                    builder.addDirectory(res.getProjectRelativePath().removeFirstSegments(1).toOSString());
                }
                break;
            case IClasspathEntry.CPE_CONTAINER:
                String path = entry.getPath().toOSString();
                if (path.startsWith(STANDARD_VM_CONTAINER_PREFIX)) {
                    builder.setJavaLanguageLevel(
                            Integer.parseInt(path.substring(STANDARD_VM_CONTAINER_PREFIX.length())));
                }
                break;
            }
        }
        return builder.build();
    }
}