diff --git a/nanoFirmwareFlasher/FirmwarePackage.cs b/nanoFirmwareFlasher/FirmwarePackage.cs index 79c2500a..aa7185f4 100644 --- a/nanoFirmwareFlasher/FirmwarePackage.cs +++ b/nanoFirmwareFlasher/FirmwarePackage.cs @@ -7,8 +7,10 @@ using System; using System.IO; using System.IO.Compression; +using System.Linq; using System.Net; using System.Net.Http; +using System.Text.RegularExpressions; namespace nanoFramework.Tools.FirmwareFlasher { @@ -64,132 +66,243 @@ protected FirmwarePackage(string targetName, string fwVersion, bool stable) /// a dictionary which keys are the start addresses and the values are the complete filenames (the bin files) protected async System.Threading.Tasks.Task DownloadAndExtractAsync() { + string fwFileName = null; + // reference targets var repoName = _stable ? _refTargetsStableRepo : _refTargetsDevRepo; string requestUri = $"{_bintrayApiPackages}/{repoName}/{_targetName}"; - if (Verbosity >= VerbosityLevel.Normal) + // flag to signal if the work-flow step was successful + bool stepSuccesful = false; + + // flag to skip download if the fw package exists and it's recent + bool skipDownload = false; + + // setup download folder + // set download path + LocationPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".nanoFramework"); + + try { - Console.Write($"Trying to find {_targetName} in {(_stable ? "stable" : "developement")} repository..."); + // create home directory + Directory.CreateDirectory(LocationPath); + + // add readme file + File.WriteAllText( + Path.Combine( + LocationPath, + "README.txt"), + _readmeContent); + + // set location path to target folder + LocationPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".nanoFramework", + _targetName); } + catch + { + Console.WriteLine(""); - HttpResponseMessage response = await _bintrayClient.GetAsync(requestUri); + return ExitCodes.E9006; + } - if (response.StatusCode == HttpStatusCode.NotFound) + var fwFiles = Directory.EnumerateFiles(LocationPath, $"{_targetName}-*.zip").OrderByDescending(f => f).ToList(); + + if (fwFiles.Any()) { - if (Verbosity >= VerbosityLevel.Normal) + // get file creation date (from the 1st one) + if ((DateTime.UtcNow - File.GetLastWriteTimeUtc(fwFiles.First())).TotalHours < 4) { - Console.WriteLine(""); - Console.Write($"Trying to find {_targetName} in community targets repository..."); + // fw package has less than 4 hours + // skip download + skipDownload = true; } + } + + if (!skipDownload) + { + // try to perform request + try + { + if (Verbosity >= VerbosityLevel.Normal) + { + Console.Write($"Trying to find {_targetName} in {(_stable ? "stable" : "developement")} repository..."); + } - // try with community targets - requestUri = $"{_bintrayApiPackages}/{_communityTargetsepo}/{_targetName}"; - repoName = _communityTargetsepo; + HttpResponseMessage response = await _bintrayClient.GetAsync(requestUri); - response = await _bintrayClient.GetAsync(requestUri); + if (response.StatusCode == HttpStatusCode.NotFound) + { + if (Verbosity >= VerbosityLevel.Normal) + { + Console.WriteLine(""); + Console.Write($"Trying to find {_targetName} in community targets repository..."); + } + + // try with community targets + requestUri = $"{_bintrayApiPackages}/{_communityTargetsepo}/{_targetName}"; + repoName = _communityTargetsepo; + + response = await _bintrayClient.GetAsync(requestUri); + + if (response.StatusCode == HttpStatusCode.NotFound) + { + if (Verbosity >= VerbosityLevel.Normal) + { + Console.WriteLine(""); + } + + // can't find this target + return ExitCodes.E9005; + } + } - if (response.StatusCode == HttpStatusCode.NotFound) - { if (Verbosity >= VerbosityLevel.Normal) { - Console.WriteLine(""); + Console.WriteLine($"OK"); } - // can't find this target - return ExitCodes.E9005; - } - } + // read and parse response + string responseBody = await response.Content.ReadAsStringAsync(); + BintrayPackageInfo packageInfo = JsonConvert.DeserializeObject(responseBody); - if (Verbosity >= VerbosityLevel.Normal) - { - Console.WriteLine($"OK"); + // if no specific version was requested, use latest available + if (string.IsNullOrEmpty(_fwVersion)) + { + _fwVersion = packageInfo.LatestVersion; + } - Console.Write($"Downloading firmware package..."); + // set exposed property + Version = _fwVersion; + + stepSuccesful = true; + } + catch + { + // exception with download, assuming it's something with network connection or Bintray API + } } - // read and parse response - string responseBody = await response.Content.ReadAsStringAsync(); - BintrayPackageInfo packageInfo = JsonConvert.DeserializeObject(responseBody); + // cleanup any fw file in the folder + var filesToDelete = Directory.EnumerateFiles(LocationPath, "*.bin").ToList(); + filesToDelete.AddRange(Directory.EnumerateFiles(LocationPath, "*.hex").ToList()); + filesToDelete.AddRange(Directory.EnumerateFiles(LocationPath, "*.s19").ToList()); + filesToDelete.AddRange(Directory.EnumerateFiles(LocationPath, "*.dfu").ToList()); - // if no specific version was requested, use latest available - if (string.IsNullOrEmpty(_fwVersion)) + foreach (var file in filesToDelete) { - _fwVersion = packageInfo.LatestVersion; + File.Delete(file); } - // set exposed property - Version = _fwVersion; - - // setup download folder - try + // check for file existence or download one + if (stepSuccesful && + !skipDownload) { - // set download path - LocationPath = Path.Combine( - Path.GetTempPath(), - Guid.NewGuid().ToString()); + // reset flag + stepSuccesful = false; - // create directory - Directory.CreateDirectory(LocationPath); + fwFileName = $"{_targetName}-{_fwVersion}.zip"; - if (Verbosity >= VerbosityLevel.Normal) + // check if we already have the file + if (!File.Exists( + Path.Combine( + LocationPath, + fwFileName))) { - Console.WriteLine("OK"); + if (Verbosity >= VerbosityLevel.Normal) + { + Console.Write($"Downloading firmware package..."); + } + + try + { + // setup and perform download request + requestUri = $"https://dl.bintray.com/nfbot/{repoName}/{fwFileName}"; + + using (var fwFileResponse = await _bintrayClient.GetAsync(requestUri)) + { + if (fwFileResponse.IsSuccessStatusCode) + { + using (var readStream = await fwFileResponse.Content.ReadAsStreamAsync()) + { + using (var fileStream = new FileStream( + Path.Combine(LocationPath, fwFileName), + FileMode.Create, FileAccess.Write)) + { + await readStream.CopyToAsync(fileStream); + } + } + } + else + { + return ExitCodes.E9007; + } + } + + if (Verbosity >= VerbosityLevel.Normal) + { + Console.WriteLine("OK"); + } + + stepSuccesful = true; + } + catch + { + // exception with download, assuming it's something with network connection or Bintray API + } } else { - Console.WriteLine(""); + // file already exists + stepSuccesful = true; } - - if (Verbosity >= VerbosityLevel.Detailed) - { - Console.WriteLine($"Download location is {LocationPath}"); - } - - // add readme file - File.WriteAllText( - Path.Combine( - LocationPath, - "README.txt"), - _readmeContent); } - catch + + if (!stepSuccesful) { - Console.WriteLine(""); + // couldn't download the fw file + // check if there is one available + fwFiles = Directory.EnumerateFiles(LocationPath, $"{_targetName}-*.zip").OrderByDescending(f => f).ToList(); - return ExitCodes.E9006; - } + if (fwFiles.Any()) + { + // take the 1st one + fwFileName = fwFiles.First(); - // setup and perform download request - string fwFileName = $"{_targetName}-{_fwVersion}.zip"; - requestUri = $"https://dl.bintray.com/nfbot/{repoName}/{fwFileName}"; + // get the version form the file name + var pattern = @"(\d+\.\d+\.\d+)(\.\d+|-.+)(?=\.zip)"; + var match = Regex.Matches(fwFileName, pattern, RegexOptions.IgnoreCase); - using (var fwFileResponse = await _bintrayClient.GetAsync(requestUri)) - { - if (fwFileResponse.IsSuccessStatusCode) - { - using (var readStream = await fwFileResponse.Content.ReadAsStreamAsync()) + // set property + Version = match[0].Value; + + if (Verbosity >= VerbosityLevel.Normal) { - using (var fileStream = new FileStream( - Path.Combine(LocationPath, fwFileName), - FileMode.Create, FileAccess.Write)) - { - await readStream.CopyToAsync(fileStream); - } + Console.WriteLine("Using cached firmware package"); } } else { + // no fw file available + + if (Verbosity >= VerbosityLevel.Normal) + { + Console.WriteLine("Failure to download package and couldn't find one in the cache."); + } + return ExitCodes.E9007; } } - Console.WriteLine($"Updating to {_fwVersion}"); + // got here, must have a file! // unzip the firmware if (Verbosity >= VerbosityLevel.Detailed) { - Console.Write($"Extracting {fwFileName}..."); + Console.Write($"Extracting {Path.GetFileName(fwFileName)}..."); } ZipFile.ExtractToDirectory( @@ -198,9 +311,21 @@ protected async System.Threading.Tasks.Task DownloadAndExtractAsync() if (Verbosity >= VerbosityLevel.Detailed) { - Console.WriteLine(""); + Console.WriteLine("OK"); } + // be nice to the user and delete any fw packages other than the last one + var allFwFiles = Directory.EnumerateFiles(LocationPath, "*.zip").OrderByDescending(f => f).ToList(); + if (allFwFiles.Count > 1) + { + foreach (var file in allFwFiles.Skip(1)) + { + File.Delete(file); + } + } + + Console.WriteLine($"Updating to {Version}"); + return ExitCodes.OK; } diff --git a/version.json b/version.json index cd2bc313..3fa120eb 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "1.16.0-preview.{height}", + "version": "1.16.1-preview.{height}", "assemblyVersion": { "precision": "revision" },