~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit.Util/FS.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
This code is derived from jgit (http://eclipse.org/jgit).
 
3
Copyright owners are documented in jgit's IP log.
 
4
 
 
5
This program and the accompanying materials are made available
 
6
under the terms of the Eclipse Distribution License v1.0 which
 
7
accompanies this distribution, is reproduced below, and is
 
8
available at http://www.eclipse.org/org/documents/edl-v10.php
 
9
 
 
10
All rights reserved.
 
11
 
 
12
Redistribution and use in source and binary forms, with or
 
13
without modification, are permitted provided that the following
 
14
conditions are met:
 
15
 
 
16
- Redistributions of source code must retain the above copyright
 
17
  notice, this list of conditions and the following disclaimer.
 
18
 
 
19
- Redistributions in binary form must reproduce the above
 
20
  copyright notice, this list of conditions and the following
 
21
  disclaimer in the documentation and/or other materials provided
 
22
  with the distribution.
 
23
 
 
24
- Neither the name of the Eclipse Foundation, Inc. nor the
 
25
  names of its contributors may be used to endorse or promote
 
26
  products derived from this software without specific prior
 
27
  written permission.
 
28
 
 
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
42
*/
 
43
 
 
44
using System;
 
45
using System.Diagnostics;
 
46
using System.IO;
 
47
using NGit.Util;
 
48
using Sharpen;
 
49
 
 
50
namespace NGit.Util
 
51
{
 
52
        /// <summary>Abstraction to support various file system operations not in Java.</summary>
 
53
        /// <remarks>Abstraction to support various file system operations not in Java.</remarks>
 
54
        public abstract class FS
 
55
        {
 
56
                /// <summary>The auto-detected implementation selected for this operating system and JRE.
 
57
                ///     </summary>
 
58
                /// <remarks>The auto-detected implementation selected for this operating system and JRE.
 
59
                ///     </remarks>
 
60
                public static readonly NGit.Util.FS DETECTED = Detect();
 
61
 
 
62
                /// <summary>Auto-detect the appropriate file system abstraction.</summary>
 
63
                /// <remarks>Auto-detect the appropriate file system abstraction.</remarks>
 
64
                /// <returns>detected file system abstraction</returns>
 
65
                public static NGit.Util.FS Detect()
 
66
                {
 
67
                        return Detect(null);
 
68
                }
 
69
 
 
70
                /// <summary>
 
71
                /// Auto-detect the appropriate file system abstraction, taking into account
 
72
                /// the presence of a Cygwin installation on the system.
 
73
                /// </summary>
 
74
                /// <remarks>
 
75
                /// Auto-detect the appropriate file system abstraction, taking into account
 
76
                /// the presence of a Cygwin installation on the system. Using jgit in
 
77
                /// combination with Cygwin requires a more elaborate (and possibly slower)
 
78
                /// resolution of file system paths.
 
79
                /// </remarks>
 
80
                /// <param name="cygwinUsed">
 
81
                /// <ul>
 
82
                /// <li><code>Boolean.TRUE</code> to assume that Cygwin is used in
 
83
                /// combination with jgit</li>
 
84
                /// <li><code>Boolean.FALSE</code> to assume that Cygwin is
 
85
                /// <b>not</b> used with jgit</li>
 
86
                /// <li><code>null</code> to auto-detect whether a Cygwin
 
87
                /// installation is present on the system and in this case assume
 
88
                /// that Cygwin is used</li>
 
89
                /// </ul>
 
90
                /// Note: this parameter is only relevant on Windows.
 
91
                /// </param>
 
92
                /// <returns>detected file system abstraction</returns>
 
93
                public static NGit.Util.FS Detect(bool? cygwinUsed)
 
94
                {
 
95
                        if (FS_Win32.IsWin32())
 
96
                        {
 
97
                                if (cygwinUsed == null)
 
98
                                {
 
99
                                        cygwinUsed = Sharpen.Extensions.ValueOf(FS_Win32_Cygwin.IsCygwin());
 
100
                                }
 
101
                                if (cygwinUsed.Value)
 
102
                                {
 
103
                                        return new FS_Win32_Cygwin();
 
104
                                }
 
105
                                else
 
106
                                {
 
107
                                        return new FS_Win32();
 
108
                                }
 
109
                        }
 
110
                        else
 
111
                        {
 
112
                                if (FS_POSIX_Java6.HasExecute())
 
113
                                {
 
114
                                        return new FS_POSIX_Java6();
 
115
                                }
 
116
                                else
 
117
                                {
 
118
                                        return new FS_POSIX_Java5();
 
119
                                }
 
120
                        }
 
121
                }
 
122
 
 
123
                private volatile FS.Holder<FilePath> userHome;
 
124
 
 
125
                private volatile FS.Holder<FilePath> gitPrefix;
 
126
 
 
127
                /// <summary>Constructs a file system abstraction.</summary>
 
128
                /// <remarks>Constructs a file system abstraction.</remarks>
 
129
                public FS()
 
130
                {
 
131
                }
 
132
 
 
133
                /// <summary>Initialize this FS using another's current settings.</summary>
 
134
                /// <remarks>Initialize this FS using another's current settings.</remarks>
 
135
                /// <param name="src">the source FS to copy from.</param>
 
136
                protected internal FS(NGit.Util.FS src)
 
137
                {
 
138
                        // Do nothing by default.
 
139
                        userHome = src.userHome;
 
140
                        gitPrefix = src.gitPrefix;
 
141
                }
 
142
 
 
143
                /// <returns>a new instance of the same type of FS.</returns>
 
144
                public abstract NGit.Util.FS NewInstance();
 
145
 
 
146
                /// <summary>Does this operating system and JRE support the execute flag on files?</summary>
 
147
                /// <returns>
 
148
                /// true if this implementation can provide reasonably accurate
 
149
                /// executable bit information; false otherwise.
 
150
                /// </returns>
 
151
                public abstract bool SupportsExecute();
 
152
 
 
153
                /// <summary>Determine if the file is executable (or not).</summary>
 
154
                /// <remarks>
 
155
                /// Determine if the file is executable (or not).
 
156
                /// <p>
 
157
                /// Not all platforms and JREs support executable flags on files. If the
 
158
                /// feature is unsupported this method will always return false.
 
159
                /// </remarks>
 
160
                /// <param name="f">abstract path to test.</param>
 
161
                /// <returns>true if the file is believed to be executable by the user.</returns>
 
162
                public abstract bool CanExecute(FilePath f);
 
163
 
 
164
                /// <summary>Set a file to be executable by the user.</summary>
 
165
                /// <remarks>
 
166
                /// Set a file to be executable by the user.
 
167
                /// <p>
 
168
                /// Not all platforms and JREs support executable flags on files. If the
 
169
                /// feature is unsupported this method will always return false and no
 
170
                /// changes will be made to the file specified.
 
171
                /// </remarks>
 
172
                /// <param name="f">path to modify the executable status of.</param>
 
173
                /// <param name="canExec">true to enable execution; false to disable it.</param>
 
174
                /// <returns>true if the change succeeded; false otherwise.</returns>
 
175
                public abstract bool SetExecute(FilePath f, bool canExec);
 
176
 
 
177
                /// <summary>Resolve this file to its actual path name that the JRE can use.</summary>
 
178
                /// <remarks>
 
179
                /// Resolve this file to its actual path name that the JRE can use.
 
180
                /// <p>
 
181
                /// This method can be relatively expensive. Computing a translation may
 
182
                /// require forking an external process per path name translated. Callers
 
183
                /// should try to minimize the number of translations necessary by caching
 
184
                /// the results.
 
185
                /// <p>
 
186
                /// Not all platforms and JREs require path name translation. Currently only
 
187
                /// Cygwin on Win32 require translation for Cygwin based paths.
 
188
                /// </remarks>
 
189
                /// <param name="dir">directory relative to which the path name is.</param>
 
190
                /// <param name="name">path name to translate.</param>
 
191
                /// <returns>
 
192
                /// the translated path. <code>new File(dir,name)</code> if this
 
193
                /// platform does not require path name translation.
 
194
                /// </returns>
 
195
                public virtual FilePath Resolve(FilePath dir, string name)
 
196
                {
 
197
                        FilePath abspn = new FilePath(name);
 
198
                        if (abspn.IsAbsolute())
 
199
                        {
 
200
                                return abspn;
 
201
                        }
 
202
                        return new FilePath(dir, name);
 
203
                }
 
204
 
 
205
                /// <summary>Determine the user's home directory (location where preferences are).</summary>
 
206
                /// <remarks>
 
207
                /// Determine the user's home directory (location where preferences are).
 
208
                /// <p>
 
209
                /// This method can be expensive on the first invocation if path name
 
210
                /// translation is required. Subsequent invocations return a cached result.
 
211
                /// <p>
 
212
                /// Not all platforms and JREs require path name translation. Currently only
 
213
                /// Cygwin on Win32 requires translation of the Cygwin HOME directory.
 
214
                /// </remarks>
 
215
                /// <returns>the user's home directory; null if the user does not have one.</returns>
 
216
                public virtual FilePath UserHome()
 
217
                {
 
218
                        FS.Holder<FilePath> p = userHome;
 
219
                        if (p == null)
 
220
                        {
 
221
                                p = new FS.Holder<FilePath>(UserHomeImpl());
 
222
                                userHome = p;
 
223
                        }
 
224
                        return p.value;
 
225
                }
 
226
 
 
227
                /// <summary>Set the user's home directory location.</summary>
 
228
                /// <remarks>Set the user's home directory location.</remarks>
 
229
                /// <param name="path">
 
230
                /// the location of the user's preferences; null if there is no
 
231
                /// home directory for the current user.
 
232
                /// </param>
 
233
                /// <returns>
 
234
                /// 
 
235
                /// <code>this</code>
 
236
                /// .
 
237
                /// </returns>
 
238
                public virtual NGit.Util.FS SetUserHome(FilePath path)
 
239
                {
 
240
                        userHome = new FS.Holder<FilePath>(path);
 
241
                        return this;
 
242
                }
 
243
 
 
244
                /// <summary>Does this file system have problems with atomic renames?</summary>
 
245
                /// <returns>true if the caller should retry a failed rename of a lock file.</returns>
 
246
                public abstract bool RetryFailedLockFileCommit();
 
247
 
 
248
                /// <summary>Determine the user's home directory (location where preferences are).</summary>
 
249
                /// <remarks>Determine the user's home directory (location where preferences are).</remarks>
 
250
                /// <returns>the user's home directory; null if the user does not have one.</returns>
 
251
                protected internal virtual FilePath UserHomeImpl()
 
252
                {
 
253
                        string home = AccessController.DoPrivileged(new _PrivilegedAction_234());
 
254
                        if (home == null || home.Length == 0)
 
255
                        {
 
256
                                return null;
 
257
                        }
 
258
                        return new FilePath(home).GetAbsoluteFile();
 
259
                }
 
260
 
 
261
                private sealed class _PrivilegedAction_234 : PrivilegedAction<string>
 
262
                {
 
263
                        public _PrivilegedAction_234()
 
264
                        {
 
265
                        }
 
266
 
 
267
                        public string Run()
 
268
                        {
 
269
                                return Runtime.GetProperty("user.home");
 
270
                        }
 
271
                }
 
272
 
 
273
                internal static FilePath SearchPath(string path, params string[] lookFor)
 
274
                {
 
275
                        foreach (string p in path.Split(FilePath.pathSeparator))
 
276
                        {
 
277
                                foreach (string command in lookFor)
 
278
                                {
 
279
                                        FilePath e = new FilePath(p, command);
 
280
                                        if (e.IsFile())
 
281
                                        {
 
282
                                                return e.GetAbsoluteFile();
 
283
                                        }
 
284
                                }
 
285
                        }
 
286
                        return null;
 
287
                }
 
288
 
 
289
                /// <summary>Execute a command and return a single line of output as a String</summary>
 
290
                /// <param name="dir">Working directory for the command</param>
 
291
                /// <param name="command">as component array</param>
 
292
                /// <param name="encoding"></param>
 
293
                /// <returns>the one-line output of the command</returns>
 
294
                protected internal static string ReadPipe(FilePath dir, string[] command, string 
 
295
                        encoding)
 
296
                {
 
297
                        try
 
298
                        {
 
299
                                SystemProcess p = Runtime.GetRuntime().Exec(command, null, dir);
 
300
                                BufferedReader lineRead = new BufferedReader(new InputStreamReader(p.GetInputStream
 
301
                                        (), encoding));
 
302
                                string r = null;
 
303
                                try
 
304
                                {
 
305
                                        r = lineRead.ReadLine();
 
306
                                }
 
307
                                finally
 
308
                                {
 
309
                                        p.GetOutputStream().Close();
 
310
                                        p.GetErrorStream().Close();
 
311
                                        lineRead.Close();
 
312
                                }
 
313
                                for (; ; )
 
314
                                {
 
315
                                        try
 
316
                                        {
 
317
                                                if (p.WaitFor() == 0 && r != null && r.Length > 0)
 
318
                                                {
 
319
                                                        return r;
 
320
                                                }
 
321
                                                break;
 
322
                                        }
 
323
                                        catch (Exception)
 
324
                                        {
 
325
                                        }
 
326
                                }
 
327
                        }
 
328
                        catch (IOException e)
 
329
                        {
 
330
                                // Stop bothering me, I have a zombie to reap.
 
331
                                if (SystemReader.GetInstance().GetProperty("jgit.fs.debug") != null)
 
332
                                {
 
333
                                        System.Console.Error.WriteLine(e);
 
334
                                }
 
335
                        }
 
336
                        // Ignore error (but report)
 
337
                        return null;
 
338
                }
 
339
 
 
340
                /// <returns>the $prefix directory C Git would use.</returns>
 
341
                public virtual FilePath GitPrefix()
 
342
                {
 
343
                        FS.Holder<FilePath> p = gitPrefix;
 
344
                        if (p == null)
 
345
                        {
 
346
                                string overrideGitPrefix = SystemReader.GetInstance().GetProperty("jgit.gitprefix"
 
347
                                        );
 
348
                                if (overrideGitPrefix != null)
 
349
                                {
 
350
                                        p = new FS.Holder<FilePath>(new FilePath(overrideGitPrefix));
 
351
                                }
 
352
                                else
 
353
                                {
 
354
                                        p = new FS.Holder<FilePath>(DiscoverGitPrefix());
 
355
                                }
 
356
                                gitPrefix = p;
 
357
                        }
 
358
                        return p.value;
 
359
                }
 
360
 
 
361
                /// <returns>the $prefix directory C Git would use.</returns>
 
362
                protected internal abstract FilePath DiscoverGitPrefix();
 
363
 
 
364
                /// <summary>Set the $prefix directory C Git uses.</summary>
 
365
                /// <remarks>Set the $prefix directory C Git uses.</remarks>
 
366
                /// <param name="path">the directory. Null if C Git is not installed.</param>
 
367
                /// <returns>
 
368
                /// 
 
369
                /// <code>this</code>
 
370
                /// </returns>
 
371
                public virtual NGit.Util.FS SetGitPrefix(FilePath path)
 
372
                {
 
373
                        gitPrefix = new FS.Holder<FilePath>(path);
 
374
                        return this;
 
375
                }
 
376
 
 
377
                /// <summary>Initialize a ProcesssBuilder to run a command using the system shell.</summary>
 
378
                /// <remarks>Initialize a ProcesssBuilder to run a command using the system shell.</remarks>
 
379
                /// <param name="cmd">
 
380
                /// command to execute. This string should originate from the
 
381
                /// end-user, and thus is platform specific.
 
382
                /// </param>
 
383
                /// <param name="args">
 
384
                /// arguments to pass to command. These should be protected from
 
385
                /// shell evaluation.
 
386
                /// </param>
 
387
                /// <returns>
 
388
                /// a partially completed process builder. Caller should finish
 
389
                /// populating directory, environment, and then start the process.
 
390
                /// </returns>
 
391
                public abstract ProcessStartInfo RunInShell(string cmd, string[] args);
 
392
 
 
393
                private class Holder<V>
 
394
                {
 
395
                        internal readonly V value;
 
396
 
 
397
                        internal Holder(V value)
 
398
                        {
 
399
                                this.value = value;
 
400
                        }
 
401
                }
 
402
        }
 
403
}