com.google.devtools.build.lib.bazel.repository.MavenServerFunction.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.lib.bazel.repository.MavenServerFunction.java

Source

// Copyright 2015 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.build.lib.bazel.repository;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.bazel.rules.workspace.MavenServerRule;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryNotFoundException;
import com.google.devtools.build.lib.rules.repository.WorkspaceAttributeMapper;
import com.google.devtools.build.lib.skyframe.FileValue;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.RootedPath;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.building.DefaultSettingsBuilder;
import org.apache.maven.settings.building.DefaultSettingsBuilderFactory;
import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
import org.apache.maven.settings.building.SettingsBuildingException;
import org.apache.maven.settings.building.SettingsBuildingResult;

/**
 * Implementation of maven_repository.
 */
public class MavenServerFunction implements SkyFunction {
    public static final SkyFunctionName NAME = SkyFunctionName.create("MAVEN_SERVER_FUNCTION");

    private static final String USER_KEY = "user";
    private static final String SYSTEM_KEY = "system";

    public MavenServerFunction() {
    }

    @Nullable
    @Override
    public SkyValue compute(SkyKey skyKey, Environment env)
            throws InterruptedException, RepositoryFunctionException {
        String repository = (String) skyKey.argument();
        Rule repositoryRule = null;
        try {
            repositoryRule = RepositoryFunction.getRule(repository, env);
        } catch (RepositoryNotFoundException ex) {
            // Ignored. We throw a new one below.
        }
        BlazeDirectories directories = PrecomputedValue.BLAZE_DIRECTORIES.get(env);
        if (env.valuesMissing()) {
            return null;
        }
        String serverName;
        String url;
        Map<String, FileValue> settingsFiles;
        boolean foundRepoRule = repositoryRule != null
                && repositoryRule.getRuleClass().equals(MavenServerRule.NAME);
        if (!foundRepoRule) {
            if (repository.equals(MavenServerValue.DEFAULT_ID)) {
                settingsFiles = getDefaultSettingsFile(directories, env);
                serverName = MavenServerValue.DEFAULT_ID;
                url = MavenConnector.getMavenCentralRemote().getUrl();
            } else {
                throw new RepositoryFunctionException(
                        new IOException("Could not find maven repository " + repository), Transience.TRANSIENT);
            }
        } else {
            WorkspaceAttributeMapper mapper = WorkspaceAttributeMapper.of(repositoryRule);
            serverName = repositoryRule.getName();
            try {
                url = mapper.get("url", Type.STRING);
                if (!mapper.isAttributeValueExplicitlySpecified("settings_file")) {
                    settingsFiles = getDefaultSettingsFile(directories, env);
                } else {
                    PathFragment settingsFilePath = new PathFragment(mapper.get("settings_file", Type.STRING));
                    RootedPath settingsPath = RootedPath.toRootedPath(
                            directories.getWorkspace().getRelative(settingsFilePath), PathFragment.EMPTY_FRAGMENT);
                    FileValue fileValue = (FileValue) env.getValue(FileValue.key(settingsPath));
                    if (fileValue == null) {
                        return null;
                    }

                    if (!fileValue.exists()) {
                        throw new RepositoryFunctionException(
                                new IOException("Could not find settings file " + settingsPath),
                                Transience.TRANSIENT);
                    }
                    settingsFiles = ImmutableMap.<String, FileValue>builder().put(USER_KEY, fileValue).build();
                }
            } catch (EvalException e) {
                throw new RepositoryFunctionException(e, Transience.PERSISTENT);
            }
        }

        if (settingsFiles == null) {
            return null;
        }

        Fingerprint fingerprint = new Fingerprint();
        try {
            for (Map.Entry<String, FileValue> entry : settingsFiles.entrySet()) {
                fingerprint.addString(entry.getKey());
                Path path = entry.getValue().realRootedPath().asPath();
                if (path.exists()) {
                    fingerprint.addBoolean(true);
                    fingerprint.addBytes(path.getDigest());
                } else {
                    fingerprint.addBoolean(false);
                }
            }
        } catch (IOException e) {
            throw new RepositoryFunctionException(e, Transience.TRANSIENT);
        }

        byte[] fingerprintBytes = fingerprint.digestAndReset();

        if (settingsFiles.isEmpty()) {
            return new MavenServerValue(serverName, url, new Server(), fingerprintBytes);
        }

        DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
        if (settingsFiles.containsKey(SYSTEM_KEY)) {
            request.setGlobalSettingsFile(settingsFiles.get(SYSTEM_KEY).realRootedPath().asPath().getPathFile());
        }
        if (settingsFiles.containsKey(USER_KEY)) {
            request.setUserSettingsFile(settingsFiles.get(USER_KEY).realRootedPath().asPath().getPathFile());
        }
        DefaultSettingsBuilder builder = (new DefaultSettingsBuilderFactory()).newInstance();
        SettingsBuildingResult result;
        try {
            result = builder.build(request);
        } catch (SettingsBuildingException e) {
            throw new RepositoryFunctionException(
                    new IOException("Error parsing settings files: " + e.getMessage()), Transience.TRANSIENT);
        }
        if (!result.getProblems().isEmpty()) {
            throw new RepositoryFunctionException(new IOException(
                    "Errors interpreting settings file: " + Arrays.toString(result.getProblems().toArray())),
                    Transience.PERSISTENT);
        }
        Settings settings = result.getEffectiveSettings();
        Server server = settings.getServer(serverName);
        server = server == null ? new Server() : server;
        return new MavenServerValue(serverName, url, server, fingerprintBytes);
    }

    private Map<String, FileValue> getDefaultSettingsFile(BlazeDirectories directories, Environment env)
            throws InterruptedException {
        // The system settings file is at $M2_HOME/conf/settings.xml.
        String m2Home = System.getenv("M2_HOME");
        ImmutableList.Builder<SkyKey> settingsFilesBuilder = ImmutableList.builder();
        SkyKey systemKey = null;
        if (m2Home != null) {
            PathFragment mavenInstallSettings = new PathFragment(m2Home).getRelative("conf/settings.xml");
            systemKey = FileValue.key(RootedPath.toRootedPath(
                    directories.getWorkspace().getRelative(mavenInstallSettings), PathFragment.EMPTY_FRAGMENT));
            settingsFilesBuilder.add(systemKey);
        }

        // The user settings file is at $HOME/.m2/settings.xml.
        String userHome = System.getenv("HOME");
        SkyKey userKey = null;
        if (userHome != null) {
            PathFragment userSettings = new PathFragment(userHome).getRelative(".m2/settings.xml");
            userKey = FileValue.key(RootedPath.toRootedPath(directories.getWorkspace().getRelative(userSettings),
                    PathFragment.EMPTY_FRAGMENT));
            settingsFilesBuilder.add(userKey);
        }

        ImmutableList<SkyKey> settingsFiles = settingsFilesBuilder.build();
        if (settingsFiles.isEmpty()) {
            return ImmutableMap.of();
        }
        Map<SkyKey, SkyValue> values = env.getValues(settingsFiles);
        ImmutableMap.Builder<String, FileValue> settingsBuilder = ImmutableMap.builder();
        for (Map.Entry<SkyKey, SkyValue> entry : values.entrySet()) {
            if (entry.getValue() == null) {
                return null;
            }
            if (systemKey != null && systemKey.equals(entry.getKey())) {
                settingsBuilder.put(SYSTEM_KEY, (FileValue) entry.getValue());
            } else if (userKey != null && userKey.equals(entry.getKey())) {
                settingsBuilder.put(USER_KEY, (FileValue) entry.getValue());
            }
        }
        return settingsBuilder.build();
    }

    @Nullable
    @Override
    public String extractTag(SkyKey skyKey) {
        return null;
    }
}