-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathFileUtils.cs
More file actions
179 lines (160 loc) · 6.43 KB
/
FileUtils.cs
File metadata and controls
179 lines (160 loc) · 6.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Semmle.Util.Logging;
namespace Semmle.Util
{
public static class FileUtils
{
public const string NugetExeUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe";
public static string ConvertToWindows(string path)
{
return path.Replace('/', '\\');
}
public static string ConvertToUnix(string path)
{
return path.Replace('\\', '/');
}
public static string ConvertToNative(string path)
{
return Path.DirectorySeparatorChar == '/' ?
path.Replace('\\', '/') :
path.Replace('/', '\\');
}
/// <summary>
/// Moves the source file to the destination, overwriting the destination file if
/// it exists already.
/// </summary>
/// <param name="src">Source file.</param>
/// <param name="dest">Target file.</param>
public static void MoveOrReplace(string src, string dest)
{
File.Move(src, dest, overwrite: true);
}
/// <summary>
/// Attempt to delete the given file (ignoring I/O exceptions).
/// </summary>
/// <param name="file">The file to delete.</param>
public static void TryDelete(string file)
{
try
{
File.Delete(file);
}
catch (IOException)
{
// Ignore
}
}
/// <summary>
/// Finds the path for the program <paramref name="prog"/> based on the
/// <code>PATH</code> environment variable, and in the case of Windows the
/// <code>PATHEXT</code> environment variable.
///
/// Returns <code>null</code> of no path can be found.
/// </summary>
public static string? FindProgramOnPath(string prog)
{
var paths = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator);
string[] exes;
if (Win32.IsWindows())
{
var extensions = Environment.GetEnvironmentVariable("PATHEXT")?.Split(';')?.ToArray();
exes = extensions is null || extensions.Any(prog.EndsWith)
? new[] { prog }
: extensions.Select(ext => prog + ext).ToArray();
}
else
{
exes = new[] { prog };
}
var candidates = paths?.Where(path => exes.Any(exe0 => File.Exists(Path.Combine(path, exe0))));
return candidates?.FirstOrDefault();
}
/// <summary>
/// Computes the hash of <paramref name="filePath"/>.
/// </summary>
public static string ComputeFileHash(string filePath)
{
using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
using var shaAlg = SHA256.Create();
var sha = shaAlg.ComputeHash(fileStream);
var hex = new StringBuilder(sha.Length * 2);
foreach (var b in sha)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
private static async Task DownloadFileAsync(string address, string filename)
{
using var httpClient = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, address);
using var contentStream = await (await httpClient.SendAsync(request)).Content.ReadAsStreamAsync();
using var stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true);
await contentStream.CopyToAsync(stream);
}
/// <summary>
/// Downloads the file at <paramref name="address"/> to <paramref name="fileName"/>.
/// </summary>
public static void DownloadFile(string address, string fileName) =>
DownloadFileAsync(address, fileName).Wait();
public static string NestPaths(ILogger logger, string? outerpath, string innerpath)
{
var nested = innerpath;
if (!string.IsNullOrEmpty(outerpath))
{
// Remove all leading path separators / or \
// For example, UNC paths have two leading \\
innerpath = innerpath.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
if (innerpath.Length > 1 && innerpath[1] == ':')
innerpath = innerpath[0] + "_" + innerpath.Substring(2);
nested = Path.Combine(outerpath, innerpath);
}
try
{
var directoryName = Path.GetDirectoryName(nested);
if (directoryName is null)
{
logger.Log(Severity.Warning, "Failed to get directory name from path '" + nested + "'.");
throw new InvalidOperationException();
}
Directory.CreateDirectory(directoryName);
}
catch (PathTooLongException)
{
logger.Log(Severity.Warning, "Failed to create parent directory of '" + nested + "': Path too long.");
throw;
}
return nested;
}
public static string GetTemporaryWorkingDirectory(out bool shouldCleanUp)
{
shouldCleanUp = false;
var tempFolder = EnvironmentVariables.GetScratchDirectory();
if (string.IsNullOrEmpty(tempFolder))
{
var tempPath = Path.GetTempPath();
var name = Guid.NewGuid().ToString("N").ToUpper();
tempFolder = Path.Combine(tempPath, "GitHub", name);
shouldCleanUp = true;
}
return tempFolder;
}
public static FileInfo CreateTemporaryFile(string extension, out bool shouldCleanUpContainingFolder)
{
var tempFolder = GetTemporaryWorkingDirectory(out shouldCleanUpContainingFolder);
Directory.CreateDirectory(tempFolder);
string outputPath;
do
{
outputPath = Path.Combine(tempFolder, Path.GetRandomFileName() + extension);
}
while (File.Exists(outputPath));
File.Create(outputPath);
return new FileInfo(outputPath);
}
}
}