/*
* Copyright 2014-present Facebook, Inc.
*
* 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.facebook.buck.ocaml;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.Tool;
import com.facebook.buck.shell.ShellStep;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.util.ProcessExecutor;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import java.nio.file.Path;
import java.util.List;
import javax.annotation.Nullable;
/** This step runs ocamldep tool to compute dependencies among source files (*.mli and *.ml) */
public class OcamlDepToolStep extends ShellStep {
private final ImmutableList<SourcePath> input;
private final ImmutableList<String> flags;
private final SourcePathResolver resolver;
private Tool ocamlDepTool;
public OcamlDepToolStep(
Path workingDirectory,
SourcePathResolver resolver,
Tool ocamlDepTool,
List<SourcePath> input,
List<String> flags) {
super(workingDirectory);
this.resolver = resolver;
this.ocamlDepTool = ocamlDepTool;
this.flags = ImmutableList.copyOf(flags);
this.input = ImmutableList.copyOf(input);
}
@Override
public String getShortName() {
return "OCaml dependency";
}
@Override
protected void addOptions(
ExecutionContext context, ImmutableSet.Builder<ProcessExecutor.Option> options) {
// We need this else we get output with color codes which confuses parsing
options.add(ProcessExecutor.Option.EXPECTING_STD_ERR);
options.add(ProcessExecutor.Option.EXPECTING_STD_OUT);
}
@Override
protected ImmutableList<String> getShellCommandInternal(@Nullable ExecutionContext context) {
ImmutableList.Builder<String> cmd = ImmutableList.builder();
cmd.addAll(ocamlDepTool.getCommandPrefix(resolver))
.add("-one-line")
.add("-native")
.addAll(flags)
.add("-ml-synonym")
.add(".re")
.add("-mli-synonym")
.add(".rei");
boolean previousFileWasReason = false;
for (SourcePath sourcePath : input) {
String filePath = resolver.getAbsolutePath(sourcePath).toString();
String ext = Files.getFileExtension(filePath);
String dotExt = "." + ext;
boolean isImplementation =
dotExt.equals(OcamlCompilables.OCAML_ML) || dotExt.equals(OcamlCompilables.OCAML_RE);
boolean isReason =
dotExt.equals(OcamlCompilables.OCAML_RE) || dotExt.equals(OcamlCompilables.OCAML_REI);
if (isReason && !previousFileWasReason) {
cmd.add("-pp").add("refmt");
} else if (!isReason && previousFileWasReason) {
// Use cat to restore the preprocessor only when the previous file was Reason.
cmd.add("-pp").add("cat");
}
// Note -impl and -intf must go after the -pp flag, if any.
cmd.add(isImplementation ? "-impl" : "-intf");
cmd.add(filePath);
previousFileWasReason = isReason;
}
return cmd.build();
}
}