/* * Copyright 2012-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.step.fs; import com.facebook.buck.io.MoreFiles; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.log.Logger; import com.facebook.buck.step.ExecutionContext; import com.facebook.buck.step.Step; import com.facebook.buck.step.StepExecutionResult; import com.facebook.buck.util.Escaper; import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.io.ByteSource; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; import java.nio.file.StandardCopyOption; public class WriteFileStep implements Step { private static final Logger LOG = Logger.get(WriteFileStep.class); private final ByteSource source; private final ProjectFilesystem filesystem; private final Path outputPath; private final boolean executable; public WriteFileStep( ProjectFilesystem filesystem, ByteSource content, Path outputPath, boolean executable) { Preconditions.checkArgument( !outputPath.isAbsolute(), "Output path must not be absolute: %s", outputPath); this.source = content; this.filesystem = filesystem; this.outputPath = outputPath; this.executable = executable; } public WriteFileStep( ProjectFilesystem filesystem, String content, Path outputPath, boolean executable) { this(filesystem, Suppliers.ofInstance(content), outputPath, executable); } public WriteFileStep( ProjectFilesystem filesystem, final Supplier<String> content, Path outputPath, boolean executable) { this( filesystem, new ByteSource() { @Override public InputStream openStream() throws IOException { // echo by default writes a trailing new line and so should we. return new ByteArrayInputStream((content.get() + "\n").getBytes(Charsets.UTF_8)); } }, outputPath, executable); } @Override public StepExecutionResult execute(ExecutionContext context) { try (InputStream sourceStream = source.openStream()) { filesystem.copyToPath(sourceStream, outputPath, StandardCopyOption.REPLACE_EXISTING); if (executable) { Path resolvedPath = filesystem.resolve(outputPath); MoreFiles.makeExecutable(resolvedPath); } return StepExecutionResult.SUCCESS; } catch (IOException e) { LOG.error(e, "Couldn't copy bytes to %s", outputPath); e.printStackTrace(context.getStdErr()); return StepExecutionResult.ERROR; } } @Override public String getShortName() { return "write_file"; } @Override public String getDescription(ExecutionContext context) { return String.format("echo ... > %s", Escaper.escapeAsBashString(outputPath)); } }