1)
{
int delay = retryDelaysSeconds[attempt - 2];
Log.LogWarning("Downloading package \"" + package + "\" failed (" + reason + "), attempt " +
(attempt - 1) + " of " + attempts + "; retrying in " + delay + " s.");
if (TaskCanceled.WaitOne(delay * 1000))
{
Log.LogMessage(MessageImportance.High,
"Downloading canceled for package \"" + package + "\".");
return false;
}
}
reason = DownloadOnce(client, uri, output, urifilename);
if (reason == null)
{
return true;
}
if (File.Exists(output))
{
Log.LogMessage(MessageImportance.High,
"Deleting incomplete file " + output + " for package \"" + package + "\".");
try
{
File.Delete(output);
}
catch (Exception e)
{
// A scanner may still hold the file; the next attempt
// overwrites it anyway, so do not let this end the retries.
Log.LogWarning("Could not delete " + output + ": " + e.Message);
}
}
if (TaskCanceled.WaitOne(0))
{
Log.LogMessage(MessageImportance.High,
"Downloading canceled for package \"" + package + "\".");
return false;
}
}
Log.LogError("Downloading package \"" + package + "\" failed after " + attempts + " attempts: " + reason + ".");
return false;
}
// One attempt: null when the file arrived, otherwise why it did not.
private string DownloadOnce(WebClient client, Uri uri, string output, string urifilename)
{
var syncObject = new State
{
filename = urifilename,
progress = -1,
lastActivityTicks = DateTime.UtcNow.Ticks
};
lock (syncObject)
{
client.DownloadFileAsync(uri, output, syncObject);
// Wait on the completed flag, not on Monitor.Wait's result: a pulse
// that lands while a timed-out Wait is reacquiring the lock is lost.
while (!syncObject.completed)
{
if (Monitor.Wait(syncObject, 1000) || syncObject.completed)
{
continue;
}
if (TaskCanceled.WaitOne(0))
{
client.CancelAsync();
WaitCompleted(syncObject);
return "canceled";
}
// DownloadFileAsync ignores WebRequest timeouts, so a connection
// that stops delivering would otherwise wait forever.
long idle = DateTime.UtcNow.Ticks - Interlocked.Read(ref syncObject.lastActivityTicks);
if (idle > TimeSpan.FromSeconds(stallTimeoutSeconds).Ticks)
{
client.CancelAsync();
WaitCompleted(syncObject);
return "no data for " + stallTimeoutSeconds + " s";
}
}
}
if (syncObject.error != null)
{
return Describe(syncObject.error);
}
if (syncObject.cancelled)
{
return "canceled";
}
if (!File.Exists(output))
{
return "no file written";
}
if (new FileInfo(output).Length == 0)
{
return "0 bytes";
}
return null;
}
// Caller holds the lock on state.
private static void WaitCompleted(State state)
{
while (!state.completed)
{
Monitor.Wait(state);
}
}
private static string Describe(Exception error)
{
var web = error as WebException;
if (web != null)
{
var http = web.Response as HttpWebResponse;
if (http != null)
{
return "HTTP " + (int)http.StatusCode + " " + http.StatusDescription;
}
return web.Status + ": " + web.Message;
}
return error.GetType().Name + ": " + error.Message;
}
private void Extract(string filename, string extracttofolder)
{
// Use the caller-supplied extraction tool when set (the 7za bootstrap
// passes 7zr.exe to unpack the full 7za.exe out of the "extra" package);
// otherwise fall back to that bootstrapped 7za.exe for every other package.
string tool = (arctool != null && arctool.Trim() != "")
? arctool
: Path.Combine(new string[] { basedir, "libs", "win32", "7za", "7za.exe" });
string args = " x \"" + filename + "\" -y -o\"" + extracttofolder + "\"";
Log.LogMessage(MessageImportance.High,
"arctool : " + tool);
Log.LogMessage(MessageImportance.High,
"args : " + args);
Log.LogMessage(MessageImportance.High,
"WorkingDirectory : " + Path.GetDirectoryName(tool));
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = tool,
Arguments = args,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
WorkingDirectory = Path.GetDirectoryName(tool)
}
};
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
Log.LogMessage(MessageImportance.High,
Path.GetFileName(filename) + " : " + line);
if (TaskCanceled.WaitOne(0))
{
proc.Kill();
break;
}
}
proc.WaitForExit();
}
private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
var state = (State)e.UserState;
lock (state)
{
state.error = e.Error;
state.cancelled = e.Cancelled;
state.completed = true;
//releases blocked thread
Monitor.Pulse(state);
}
}
private string humanSize(double len)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return String.Format("{0:0.##} {1}", len, sizes[order]);
}
private void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
Interlocked.Exchange(ref ((State)e.UserState).lastActivityTicks, DateTime.UtcNow.Ticks);
if (((State)e.UserState).progress < e.ProgressPercentage)
{
((State)e.UserState).progress = e.ProgressPercentage;
// Displays the transfer progress.
Log.LogMessage(MessageImportance.High, ((State)e.UserState).filename + " : downloaded " + humanSize(e.BytesReceived) + " of " + humanSize(e.TotalBytesToReceive) + " " + e.ProgressPercentage + " % complete...");
}
}
}
]]>
26.02
https://github.com/ip7z/7zip/releases/download/$(SevenZipVersion)
7z$(SevenZipVersion.Replace('.',''))-extra
true