| /* |
| * Copyright 2013-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.shell; |
| |
| import com.facebook.buck.step.ExecutionContext; |
| import com.facebook.buck.step.Step; |
| import com.google.common.base.Charsets; |
| import com.google.common.base.Function; |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.Lists; |
| import com.google.common.io.Files; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Path; |
| import java.util.List; |
| |
| /** |
| * When executed, generates a shell script at the specified location. |
| */ |
| public class GenerateShellScriptStep implements Step { |
| |
| private final Path basePath; |
| private final Path scriptToRun; |
| private final Iterable<Path> resources; |
| private final Path outputFile; |
| |
| public GenerateShellScriptStep( |
| Path basePath, |
| Path scriptToRun, |
| Iterable<Path> resources, |
| Path outputFile) { |
| this.basePath = Preconditions.checkNotNull(basePath); |
| this.scriptToRun = Preconditions.checkNotNull(scriptToRun); |
| this.resources = Preconditions.checkNotNull(resources); |
| this.outputFile = Preconditions.checkNotNull(outputFile); |
| } |
| |
| @Override |
| public int execute(ExecutionContext context) { |
| List<String> lines = Lists.newArrayList(); |
| // Run with -e so the script will fail if any of the steps fail. |
| lines.add("#!/bin/sh"); |
| lines.add("set -e"); |
| |
| // Create a tmp directory that will be deleted when this script exits. |
| lines.add("BUCK_PROJECT_ROOT=`mktemp -d -t sh_binary.XXXXXXXXXX`"); |
| lines.add("trap \"chmod -R 755 $BUCK_PROJECT_ROOT " + |
| "&& rm -rf $BUCK_PROJECT_ROOT\" EXIT HUP INT TERM"); |
| |
| // Navigate to the tmp directory. |
| lines.add("cd $BUCK_PROJECT_ROOT"); |
| |
| // Symlink the resources to the $BUCK_PROJECT_ROOT directory. |
| Function<String, String> pathRelativizer = context.getProjectFilesystem().getPathRelativizer(); |
| createSymlinkCommands(resources, pathRelativizer, lines); |
| |
| // Make everything in $BUCK_PROJECT_ROOT read-only. |
| lines.add("find $BUCK_PROJECT_ROOT -type d -exec chmod 555 {} \\;"); |
| lines.add("find $BUCK_PROJECT_ROOT -type f -exec chmod 444 {} \\;"); |
| |
| // Forward the args to this generated script to scriptToRun and execute it. |
| lines.add(String.format( |
| "BUCK_PROJECT_ROOT=$BUCK_PROJECT_ROOT %s \"$@\"", |
| pathRelativizer.apply(scriptToRun.toString()))); |
| |
| // Write the contents to the file. |
| File output = context.getProjectFilesystem().getFileForRelativePath(outputFile.toString()); |
| try { |
| Files.write(Joiner.on('\n').join(lines) + '\n', output, Charsets.UTF_8); |
| } catch (IOException e) { |
| e.printStackTrace(context.getStdErr()); |
| return 1; |
| } |
| |
| // Make sure the file is executable. |
| if (output.setExecutable(/* executable */ true, /* ownerOnly */ false)) { |
| return 0; |
| } else { |
| context.getConsole().printErrorText("Failed to set file as executable: " + output); |
| return 1; |
| } |
| } |
| |
| private void createSymlinkCommands(Iterable<Path> paths, |
| Function<String, String> pathRelativizer, |
| List<String> lines) { |
| for (Path path : paths) { |
| Preconditions.checkArgument(basePath.toString().isEmpty() |
| || path.startsWith(basePath), "%s should start with %s", path, basePath); |
| |
| if (path.getNameCount() > 1) { |
| lines.add(String.format("mkdir -p %s", path.getParent())); |
| } |
| lines.add(String.format("ln -s %s $BUCK_PROJECT_ROOT/%s", |
| pathRelativizer.apply(path.toString()), |
| path)); |
| } |
| } |
| |
| @Override |
| public String getShortName() { |
| return "gen_sh"; |
| } |
| |
| @Override |
| public String getDescription(ExecutionContext context) { |
| return "write " + context.getProjectFilesystem().getFileForRelativePath(outputFile.toString()); |
| } |
| } |