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 Map<String, String> env;
043 private File directory;
044 private boolean newShell = false;
045 private final System2 system;
046
047 Command(String executable, System2 system) {
048 Preconditions.checkArgument(!StringUtils.isBlank(executable), "Command executable can not be blank");
049 this.executable = executable;
050 this.env = Maps.newHashMap(system.envVariables());
051 this.system = system;
052 }
053
054 /**
055 * Create a command line without any arguments
056 *
057 * @param executable
058 */
059 public static Command create(String executable) {
060 return new Command(executable, System2.INSTANCE);
061 }
062
063 public String getExecutable() {
064 return executable;
065 }
066
067 public List<String> getArguments() {
068 return ImmutableList.copyOf(arguments);
069 }
070
071 public Command addArgument(String arg) {
072 arguments.add(arg);
073 return this;
074 }
075
076 public Command addArguments(List<String> args) {
077 arguments.addAll(args);
078 return this;
079 }
080
081 public Command addArguments(String[] args) {
082 Collections.addAll(arguments, args);
083 return this;
084 }
085
086 public File getDirectory() {
087 return directory;
088 }
089
090 /**
091 * Sets working directory.
092 */
093 public Command setDirectory(File d) {
094 this.directory = d;
095 return this;
096 }
097
098 /**
099 * @see org.sonar.api.utils.command.Command#getEnvironmentVariables()
100 * @since 3.2
101 */
102 public Command setEnvironmentVariable(String name, String value) {
103 this.env.put(name, value);
104 return this;
105 }
106
107 /**
108 * Environment variables that are propagated during command execution.
109 * The initial value is a copy of the environment of the current process.
110 *
111 * @return a non-null and immutable map of variables
112 * @since 3.2
113 */
114 public Map<String, String> getEnvironmentVariables() {
115 return ImmutableMap.copyOf(env);
116 }
117
118 /**
119 * <code>true</code> if a new shell should be used to execute the command.
120 * The default behavior is to not use a new shell.
121 *
122 * @since 3.3
123 */
124 public boolean isNewShell() {
125 return newShell;
126 }
127
128 /**
129 * Set to <code>true</code> if a new shell should be used to execute the command.
130 * This is useful when the executed command is a script with no execution rights (+x on unix).
131 *
132 * On windows, the command will be executed with <code>cmd /C executable</code>.
133 * On other platforms, the command will be executed with <code>sh executable</code>.
134 *
135 * @since 3.3
136 */
137 public Command setNewShell(boolean b) {
138 this.newShell = b;
139 return this;
140 }
141
142 List<String> toStrings() {
143 ImmutableList.Builder<String> command = ImmutableList.builder();
144 if (newShell) {
145 if (system.isOsWindows()) {
146 command.add("cmd", "/C", "call");
147 } else {
148 command.add("sh");
149 }
150 }
151 command.add(executable);
152 command.addAll(arguments);
153 return command.build();
154 }
155
156 public String toCommandLine() {
157 return Joiner.on(" ").join(toStrings());
158 }
159
160 @Override
161 public String toString() {
162 return toCommandLine();
163 }
164 }