001/* 002 * SonarQube 003 * Copyright (C) 2009-2016 SonarSource SA 004 * mailto:contact AT sonarsource DOT com 005 * 006 * This program is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.utils.command; 021 022import com.google.common.base.Joiner; 023import com.google.common.base.Preconditions; 024import com.google.common.collect.ImmutableList; 025import com.google.common.collect.ImmutableMap; 026import com.google.common.collect.Maps; 027import org.apache.commons.lang.StringUtils; 028import org.sonar.api.utils.System2; 029 030import java.io.File; 031import java.util.ArrayList; 032import java.util.Collections; 033import java.util.List; 034import java.util.Map; 035 036/** 037 * @since 2.7 038 */ 039public class Command { 040 private final String executable; 041 private final List<String> arguments = new ArrayList<>(); 042 private final List<String> argumentsForLogs = new ArrayList<>(); 043 private final Map<String, String> env; 044 private File directory; 045 private boolean newShell = false; 046 private final System2 system; 047 048 Command(String executable, System2 system) { 049 Preconditions.checkArgument(!StringUtils.isBlank(executable), "Command executable can not be blank"); 050 this.executable = executable; 051 this.env = Maps.newHashMap(system.envVariables()); 052 this.system = system; 053 } 054 055 /** 056 * Create a command line without any arguments 057 * 058 * @param executable 059 */ 060 public static Command create(String executable) { 061 return new Command(executable, System2.INSTANCE); 062 } 063 064 public String getExecutable() { 065 return executable; 066 } 067 068 public List<String> getArguments() { 069 return ImmutableList.copyOf(arguments); 070 } 071 072 public Command addArgument(String arg) { 073 arguments.add(arg); 074 argumentsForLogs.add(arg); 075 return this; 076 } 077 078 public Command addMaskedArgument(String arg) { 079 arguments.add(arg); 080 argumentsForLogs.add("********"); 081 return this; 082 } 083 084 public Command addArguments(List<String> args) { 085 arguments.addAll(args); 086 argumentsForLogs.addAll(args); 087 return this; 088 } 089 090 public Command addArguments(String[] args) { 091 Collections.addAll(arguments, args); 092 Collections.addAll(argumentsForLogs, args); 093 return this; 094 } 095 096 public File getDirectory() { 097 return directory; 098 } 099 100 /** 101 * Sets working directory. 102 */ 103 public Command setDirectory(File d) { 104 this.directory = d; 105 return this; 106 } 107 108 /** 109 * @see org.sonar.api.utils.command.Command#getEnvironmentVariables() 110 * @since 3.2 111 */ 112 public Command setEnvironmentVariable(String name, String value) { 113 this.env.put(name, value); 114 return this; 115 } 116 117 /** 118 * Environment variables that are propagated during command execution. 119 * The initial value is a copy of the environment of the current process. 120 * 121 * @return a non-null and immutable map of variables 122 * @since 3.2 123 */ 124 public Map<String, String> getEnvironmentVariables() { 125 return ImmutableMap.copyOf(env); 126 } 127 128 /** 129 * <code>true</code> if a new shell should be used to execute the command. 130 * The default behavior is to not use a new shell. 131 * 132 * @since 3.3 133 */ 134 public boolean isNewShell() { 135 return newShell; 136 } 137 138 /** 139 * Set to <code>true</code> if a new shell should be used to execute the command. 140 * This is useful when the executed command is a script with no execution rights (+x on unix). 141 * 142 * On windows, the command will be executed with <code>cmd /C executable</code>. 143 * On other platforms, the command will be executed with <code>sh executable</code>. 144 * 145 * @since 3.3 146 */ 147 public Command setNewShell(boolean b) { 148 this.newShell = b; 149 return this; 150 } 151 152 List<String> toStrings(boolean forLogs) { 153 ImmutableList.Builder<String> command = ImmutableList.builder(); 154 if (newShell) { 155 if (system.isOsWindows()) { 156 command.add("cmd", "/C", "call"); 157 } else { 158 command.add("sh"); 159 } 160 } 161 command.add(executable); 162 command.addAll(forLogs ? argumentsForLogs : arguments); 163 return command.build(); 164 } 165 166 public String toCommandLine() { 167 return Joiner.on(" ").join(toStrings(false)); 168 } 169 170 @Override 171 public String toString() { 172 return Joiner.on(" ").join(toStrings(true)); 173 } 174}