// 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.workspace; import com.google.common.collect.Lists; import com.google.common.io.Files; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.StoredEventHandler; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.unix.UnixFileSystem; import com.google.devtools.build.lib.util.OS; import com.google.devtools.build.lib.vfs.FileSystem; import com.google.devtools.build.lib.vfs.JavaIoFileSystem; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.workspace.maven.DefaultModelResolver; import com.google.devtools.build.workspace.maven.Resolver; import com.google.devtools.common.options.OptionsParser; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.List; /** * Generates a WORKSPACE file for Bazel from other types of dependency trackers. */ public class GenerateWorkspace { private final EventHandler handler; private final FileSystem fileSystem; private final Resolver resolver; private final List<String> inputs; private final Path outputDir; public static void main(String[] args) throws InterruptedException { OptionsParser parser = OptionsParser.newOptionsParser(GenerateWorkspaceOptions.class); parser.parseAndExitUponError(args); GenerateWorkspaceOptions options = parser.getOptions(GenerateWorkspaceOptions.class); if (options.mavenProjects.isEmpty() && options.bazelProjects.isEmpty() && options.artifacts.isEmpty()) { printUsage(parser); return; } GenerateWorkspace workspaceFileGenerator = new GenerateWorkspace(options.outputDir); workspaceFileGenerator.generateFromWorkspace(options.bazelProjects); workspaceFileGenerator.generateFromPom(options.mavenProjects); workspaceFileGenerator.generateFromArtifacts(options.artifacts); if (!workspaceFileGenerator.hasErrors()) { workspaceFileGenerator.writeResults(); } workspaceFileGenerator.cleanup(); if (workspaceFileGenerator.hasErrors()) { System.exit(1); } } private static void printUsage(OptionsParser parser) { System.out.println("Usage: generate_workspace (-b PATH|-m PATH|-a coord)+ [-o PATH]\n\n" + "Generates a WORKSPACE file from the given projects and a BUILD file with a rule that " + "contains all of the transitive dependencies. At least one bazel_project, " + "maven_project, or artifact coordinate must be specified. If output_dir is not " + "specified, the generated files will be written to a temporary directory.\n"); System.out.println(parser.describeOptions(Collections.<String, String>emptyMap(), OptionsParser.HelpVerbosity.LONG)); } private GenerateWorkspace(String outputDir) { this.handler = new EventHandler(); this.fileSystem = getFileSystem(); this.resolver = new Resolver(handler, new DefaultModelResolver()); this.inputs = Lists.newArrayList(); if (outputDir.isEmpty()) { this.outputDir = fileSystem.getPath(Files.createTempDir().toString()); } else { this.outputDir = fileSystem.getPath(outputDir); } } static FileSystem getFileSystem() { return OS.getCurrent() == OS.WINDOWS ? new JavaIoFileSystem() : new UnixFileSystem(); } private void generateFromWorkspace(List<String> projects) throws InterruptedException { for (String project : projects) { WorkspaceResolver workspaceResolver = new WorkspaceResolver(resolver, handler); Path projectPath = fileSystem.getPath(getAbsolute(project)).getRelative("WORKSPACE"); Package externalPackage = workspaceResolver.parse(projectPath); inputs.add(projectPath.getPathString()); workspaceResolver.resolveTransitiveDependencies(externalPackage); } } private void generateFromPom(List<String> projects) { for (String project : projects) { String pomFile = resolver.resolvePomDependencies(getAbsolute(project)); if (pomFile != null) { inputs.add(pomFile); } } } private void generateFromArtifacts(List<String> artifacts) { for (String artifactCoord : artifacts) { inputs.add(artifactCoord); resolver.resolveArtifact(artifactCoord); } } private String getAbsolute(String path) { return Paths.get(System.getProperty("user.dir")).resolve(path).toString(); } /** * Returns if there were any errors generating the WORKSPACE and BUILD files. */ private boolean hasErrors() { return handler.hasErrors(); } private void writeResults() { String date = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); File workspaceFile = outputDir.getRelative("WORKSPACE").getPathFile(); File buildFile = outputDir.getRelative("BUILD").getPathFile(); // Don't overwrite existing files with generated ones. if (workspaceFile.exists()) { workspaceFile = outputDir.getRelative(date + ".WORKSPACE").getPathFile(); } if (buildFile.exists()) { buildFile = outputDir.getRelative(date + ".BUILD").getPathFile(); } try (PrintStream workspaceStream = new PrintStream(workspaceFile); PrintStream buildStream = new PrintStream(buildFile)) { ResultWriter writer = new ResultWriter(inputs, resolver.getRules()); writer.writeWorkspace(workspaceStream); writer.writeBuild(buildStream); } catch (IOException e) { handler.handle(Event.error( "Could not write WORKSPACE and BUILD files to " + outputDir + ": " + e.getMessage())); return; } System.err.println("Wrote:\n" + workspaceFile + "\n" + buildFile); } private void cleanup() { for (Event event : handler.getEvents()) { System.err.println(event); } } private class EventHandler extends StoredEventHandler { @Override public void handle(Event event) { System.err.println(event.getKind() + ": " + event.getMessage()); } } }