File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\EnvVars.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Red Hat, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson;
25
26 import hudson.remoting.Callable;
27 import hudson.remoting.VirtualChannel;
28 import hudson.util.CaseInsensitiveComparator;
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.util.Map;
33 import java.util.TreeMap;
34 import java.util.Arrays;
35 import java.util.UUID;
36
37 /**
38 * Environment variables.
39 *
40 * <p>
41 * While all the platforms I tested (Linux 2.6, Solaris, and Windows XP) have the case sensitive
42 * environment variable table, Windows batch script handles environment variable in the case preserving
43 * but case <b>insensitive</b> way (that is, cmd.exe can get both FOO and foo as environment variables
44 * when it's launched, and the "set" command will display it accordingly, but "echo %foo%" results in
45 * echoing the value of "FOO", not "foo" &mdash; this is presumably caused by the behavior of the underlying
46 * Win32 API <tt>GetEnvironmentVariable</tt> acting in case insensitive way.) Windows users are also
47 * used to write environment variable case-insensitively (like %Path% vs %PATH%), and you can see many
48 * documents on the web that claims Windows environment variables are case insensitive.
49 *
50 * <p>
51 * So for a consistent cross platform behavior, it creates the least confusion to make the table
52 * case insensitive but case preserving.
53 *
54 * <p>
55 * In Jenkins, often we need to build up "environment variable overrides"
56 * on master, then to execute the process on slaves. This causes a problem
57 * when working with variables like <tt>PATH</tt>. So to make this work,
58 * we introduce a special convention <tt>PATH+FOO</tt> &mdash; all entries
59 * that starts with <tt>PATH+</tt> are merged and prepended to the inherited
60 * <tt>PATH</tt> variable, on the process where a new process is executed.
61 *
62 * @author Kohsuke Kawaguchi
63 */
64 public class EnvVars extends TreeMap<String,String> {
65 /**
66 * If this {@link EnvVars} object represents the whole environment variable set,
67 * not just a partial list used for overriding later, then we need to know
68 * the platform for which this env vars are targeted for, or else we won't know
69 * how to merge variables properly.
70 *
71 * <p>
72 * So this property remembers that information.
73 */
74 private Platform platform;
75
76 public EnvVars() {
77 super(CaseInsensitiveComparator.INSTANCE);
78 }
79
80 public EnvVars(Map<String,String> m) {
81 this();
82 putAll(m);
83
84 // because of the backward compatibility, some parts of Jenkins passes
85 // EnvVars as Map<String,String> so downcasting is safer.
86 if (m instanceof EnvVars) {
87 EnvVars lhs = (EnvVars) m;
88 this.platform = lhs.platform;
89 }
90 }
91
92 public EnvVars(EnvVars m) {
93 // this constructor is so that in future we can get rid of the downcasting.
94 this((Map)m);
95 }
96
97 /**
98 * Builds an environment variables from an array of the form <tt>"key","value","key","value"...</tt>
99 */
100 public EnvVars(String... keyValuePairs) {
101 this();
102 if(keyValuePairs.length%2!=0)
103 throw new IllegalArgumentException(Arrays.asList(keyValuePairs).toString());
104 for( int i=0; i<keyValuePairs.length; i+=2 )
105 put(keyValuePairs[i],keyValuePairs[i+1]);
106 }
107
108 /**
109 * Overrides the current entry by the given entry.
110 *
111 * <p>
112 * Handles <tt>PATH+XYZ</tt> notation.
113 */
114 public void override(String key, String value) {
115 if(value==null || value.length()==0) {
116 remove(key);
117 return;
118 }
119
120 int idx = key.indexOf('+');
121 if(idx>0) {
122 String realKey = key.substring(0,idx);
123 String v = get(realKey);
124 if(v==null) v=value;
125 else {
126 // we might be handling environment variables for a slave that can have different path separator
127 // than the master, so the following is an attempt to get it right.
128 // it's still more error prone that I'd like.
129 char ch = platform==null ? File.pathSeparatorChar : platform.pathSeparator;
130 v=value+ch+v;
131 }
132 put(realKey,v);
133 return;
134 }
135
136 put(key,value);
137 }
138
139 /**
140 * Overrides all values in the map by the given map.
141 * See {@link #override(String, String)}.
142 * @return this
143 */
144 public EnvVars overrideAll(Map<String,String> all) {
145 for (Map.Entry<String, String> e : all.entrySet()) {
146 override(e.getKey(),e.getValue());
147 }
148 return this;
149 }
150
151 /**
152 * Resolves environment variables against each other.
153 */
154 public static void resolve(Map<String, String> env) {
155 for (Map.Entry<String,String> entry: env.entrySet()) {
156 entry.setValue(Util.replaceMacro(entry.getValue(), env));
157 }
158 }
159
160 /**
161 * Convenience message
162 * @since 1.485
163 **/
164 public String get(String key, String defaultValue) {
165 String v = get(key);
166 if (v==null) v=defaultValue;
167 return v;
168 }
169
170 @Override
171 public String put(String key, String value) {
172 if (value==null) throw new IllegalArgumentException("Null value not allowed as an environment variable: "+key);
173 return super.put(key,value);
174 }
175
176 /**
177 * Takes a string that looks like "a=b" and adds that to this map.
178 */
179 public void addLine(String line) {
180 int sep = line.indexOf('=');
181 if(sep > 0) {
182 put(line.substring(0,sep),line.substring(sep+1));
183 }
184 }
185
186 /**
187 * Expands the variables in the given string by using environment variables represented in 'this'.
188 */
189 public String expand(String s) {
190 return Util.replaceMacro(s, this);
191 }
192
193 /**
194 * Creates a magic cookie that can be used as the model environment variable
195 * when we later kill the processes.
196 */
197 public static EnvVars createCookie() {
198 return new EnvVars("HUDSON_COOKIE", UUID.randomUUID().toString());
199 }
200
201 /**
202 * Obtains the environment variables of a remote peer.
203 *
204 * @param channel
205 * Can be null, in which case the map indicating "N/A" will be returned.
206 * @return
207 * A fresh copy that can be owned and modified by the caller.
208 */
209 public static EnvVars getRemote(VirtualChannel channel) throws IOException, InterruptedException {
210 if(channel==null)
211 return new EnvVars("N/A","N/A");
212 return channel.call(new GetEnvVars());
213 }
214
215 private static final class GetEnvVars implements Callable<EnvVars,RuntimeException> {
216 public EnvVars call() {
217 return new EnvVars(EnvVars.masterEnvVars);
218 }
219 private static final long serialVersionUID = 1L;
220 }
221
222 /**
223 * Environmental variables that we've inherited.
224 *
225 * <p>
226 * Despite what the name might imply, this is the environment variable
227 * of the current JVM process. And therefore, it is Jenkins master's environment
228 * variables only when you access this from the master.
229 *
230 * <p>
231 * If you access this field from slaves, then this is the environment
232 * variable of the slave agent.
233 */
234 public static final Map<String,String> masterEnvVars = initMaster();
235
236 private static EnvVars initMaster() {
237 EnvVars vars = new EnvVars(System.getenv());
238 vars.platform = Platform.current();
239 if(Main.isUnitTest || Main.isDevelopmentMode)
240 // if unit test is launched with maven debug switch,
241 // we need to prevent forked Maven processes from seeing it, or else
242 // they'll hang
243 vars.remove("MAVEN_OPTS");
244 return vars;
245 }
246 }
247