001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube 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 * SonarQube 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 */
020 package org.sonar.api.utils.command;
021
022 import com.google.common.base.Joiner;
023 import com.google.common.base.Preconditions;
024 import com.google.common.collect.ImmutableList;
025 import com.google.common.collect.ImmutableMap;
026 import com.google.common.collect.Lists;
027 import com.google.common.collect.Maps;
028 import org.apache.commons.lang.StringUtils;
029 import org.sonar.api.utils.System2;
030
031 import java.io.File;
032 import java.util.Collections;
033 import java.util.List;
034 import java.util.Map;
035
036 /**
037 * @since 2.7
038 */
039 public class Command {
040 private final String executable;
041 private final List<String> arguments = Lists.newArrayList();
042 private final List<String> argumentsForLogs = Lists.newArrayList();
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 }