77using System ;
88using System . IO ;
99using System . IO . Compression ;
10+ using System . Linq ;
1011using System . Net ;
1112using System . Net . Http ;
13+ using System . Text . RegularExpressions ;
1214
1315namespace nanoFramework . Tools . FirmwareFlasher
1416{
@@ -64,132 +66,243 @@ protected FirmwarePackage(string targetName, string fwVersion, bool stable)
6466 /// <returns>a dictionary which keys are the start addresses and the values are the complete filenames (the bin files)</returns>
6567 protected async System . Threading . Tasks . Task < ExitCodes > DownloadAndExtractAsync ( )
6668 {
69+ string fwFileName = null ;
70+
6771 // reference targets
6872 var repoName = _stable ? _refTargetsStableRepo : _refTargetsDevRepo ;
6973 string requestUri = $ "{ _bintrayApiPackages } /{ repoName } /{ _targetName } ";
7074
71- if ( Verbosity >= VerbosityLevel . Normal )
75+ // flag to signal if the work-flow step was successful
76+ bool stepSuccesful = false ;
77+
78+ // flag to skip download if the fw package exists and it's recent
79+ bool skipDownload = false ;
80+
81+ // setup download folder
82+ // set download path
83+ LocationPath = Path . Combine (
84+ Environment . GetFolderPath ( Environment . SpecialFolder . UserProfile ) ,
85+ ".nanoFramework" ) ;
86+
87+ try
7288 {
73- Console . Write ( $ "Trying to find { _targetName } in { ( _stable ? "stable" : "developement" ) } repository...") ;
89+ // create home directory
90+ Directory . CreateDirectory ( LocationPath ) ;
91+
92+ // add readme file
93+ File . WriteAllText (
94+ Path . Combine (
95+ LocationPath ,
96+ "README.txt" ) ,
97+ _readmeContent ) ;
98+
99+ // set location path to target folder
100+ LocationPath = Path . Combine (
101+ Environment . GetFolderPath ( Environment . SpecialFolder . UserProfile ) ,
102+ ".nanoFramework" ,
103+ _targetName ) ;
74104 }
105+ catch
106+ {
107+ Console . WriteLine ( "" ) ;
75108
76- HttpResponseMessage response = await _bintrayClient . GetAsync ( requestUri ) ;
109+ return ExitCodes . E9006 ;
110+ }
77111
78- if ( response . StatusCode == HttpStatusCode . NotFound )
112+ var fwFiles = Directory . EnumerateFiles ( LocationPath , $ "{ _targetName } -*.zip") . OrderByDescending ( f => f ) . ToList ( ) ;
113+
114+ if ( fwFiles . Any ( ) )
79115 {
80- if ( Verbosity >= VerbosityLevel . Normal )
116+ // get file creation date (from the 1st one)
117+ if ( ( DateTime . UtcNow - File . GetLastWriteTimeUtc ( fwFiles . First ( ) ) ) . TotalHours < 4 )
81118 {
82- Console . WriteLine ( "" ) ;
83- Console . Write ( $ "Trying to find { _targetName } in community targets repository...") ;
119+ // fw package has less than 4 hours
120+ // skip download
121+ skipDownload = true ;
84122 }
123+ }
124+
125+ if ( ! skipDownload )
126+ {
127+ // try to perform request
128+ try
129+ {
130+ if ( Verbosity >= VerbosityLevel . Normal )
131+ {
132+ Console . Write ( $ "Trying to find { _targetName } in { ( _stable ? "stable" : "developement" ) } repository...") ;
133+ }
85134
86- // try with community targets
87- requestUri = $ "{ _bintrayApiPackages } /{ _communityTargetsepo } /{ _targetName } ";
88- repoName = _communityTargetsepo ;
135+ HttpResponseMessage response = await _bintrayClient . GetAsync ( requestUri ) ;
89136
90- response = await _bintrayClient . GetAsync ( requestUri ) ;
137+ if ( response . StatusCode == HttpStatusCode . NotFound )
138+ {
139+ if ( Verbosity >= VerbosityLevel . Normal )
140+ {
141+ Console . WriteLine ( "" ) ;
142+ Console . Write ( $ "Trying to find { _targetName } in community targets repository...") ;
143+ }
144+
145+ // try with community targets
146+ requestUri = $ "{ _bintrayApiPackages } /{ _communityTargetsepo } /{ _targetName } ";
147+ repoName = _communityTargetsepo ;
148+
149+ response = await _bintrayClient . GetAsync ( requestUri ) ;
150+
151+ if ( response . StatusCode == HttpStatusCode . NotFound )
152+ {
153+ if ( Verbosity >= VerbosityLevel . Normal )
154+ {
155+ Console . WriteLine ( "" ) ;
156+ }
157+
158+ // can't find this target
159+ return ExitCodes . E9005 ;
160+ }
161+ }
91162
92- if ( response . StatusCode == HttpStatusCode . NotFound )
93- {
94163 if ( Verbosity >= VerbosityLevel . Normal )
95164 {
96- Console . WriteLine ( " ") ;
165+ Console . WriteLine ( $ "OK ") ;
97166 }
98167
99- // can't find this target
100- return ExitCodes . E9005 ;
101- }
102- }
168+ // read and parse response
169+ string responseBody = await response . Content . ReadAsStringAsync ( ) ;
170+ BintrayPackageInfo packageInfo = JsonConvert . DeserializeObject < BintrayPackageInfo > ( responseBody ) ;
103171
104- if ( Verbosity >= VerbosityLevel . Normal )
105- {
106- Console . WriteLine ( $ "OK") ;
172+ // if no specific version was requested, use latest available
173+ if ( string . IsNullOrEmpty ( _fwVersion ) )
174+ {
175+ _fwVersion = packageInfo . LatestVersion ;
176+ }
107177
108- Console . Write ( $ "Downloading firmware package...") ;
178+ // set exposed property
179+ Version = _fwVersion ;
180+
181+ stepSuccesful = true ;
182+ }
183+ catch
184+ {
185+ // exception with download, assuming it's something with network connection or Bintray API
186+ }
109187 }
110188
111- // read and parse response
112- string responseBody = await response . Content . ReadAsStringAsync ( ) ;
113- BintrayPackageInfo packageInfo = JsonConvert . DeserializeObject < BintrayPackageInfo > ( responseBody ) ;
189+ // cleanup any fw file in the folder
190+ var filesToDelete = Directory . EnumerateFiles ( LocationPath , "*.bin" ) . ToList ( ) ;
191+ filesToDelete . AddRange ( Directory . EnumerateFiles ( LocationPath , "*.hex" ) . ToList ( ) ) ;
192+ filesToDelete . AddRange ( Directory . EnumerateFiles ( LocationPath , "*.s19" ) . ToList ( ) ) ;
193+ filesToDelete . AddRange ( Directory . EnumerateFiles ( LocationPath , "*.dfu" ) . ToList ( ) ) ;
114194
115- // if no specific version was requested, use latest available
116- if ( string . IsNullOrEmpty ( _fwVersion ) )
195+ foreach ( var file in filesToDelete )
117196 {
118- _fwVersion = packageInfo . LatestVersion ;
197+ File . Delete ( file ) ;
119198 }
120199
121- // set exposed property
122- Version = _fwVersion ;
123-
124- // setup download folder
125- try
200+ // check for file existence or download one
201+ if ( stepSuccesful &&
202+ ! skipDownload )
126203 {
127- // set download path
128- LocationPath = Path . Combine (
129- Path . GetTempPath ( ) ,
130- Guid . NewGuid ( ) . ToString ( ) ) ;
204+ // reset flag
205+ stepSuccesful = false ;
131206
132- // create directory
133- Directory . CreateDirectory ( LocationPath ) ;
207+ fwFileName = $ "{ _targetName } -{ _fwVersion } .zip";
134208
135- if ( Verbosity >= VerbosityLevel . Normal )
209+ // check if we already have the file
210+ if ( ! File . Exists (
211+ Path . Combine (
212+ LocationPath ,
213+ fwFileName ) ) )
136214 {
137- Console . WriteLine ( "OK" ) ;
215+ if ( Verbosity >= VerbosityLevel . Normal )
216+ {
217+ Console . Write ( $ "Downloading firmware package...") ;
218+ }
219+
220+ try
221+ {
222+ // setup and perform download request
223+ requestUri = $ "https://dl.bintray.com/nfbot/{ repoName } /{ fwFileName } ";
224+
225+ using ( var fwFileResponse = await _bintrayClient . GetAsync ( requestUri ) )
226+ {
227+ if ( fwFileResponse . IsSuccessStatusCode )
228+ {
229+ using ( var readStream = await fwFileResponse . Content . ReadAsStreamAsync ( ) )
230+ {
231+ using ( var fileStream = new FileStream (
232+ Path . Combine ( LocationPath , fwFileName ) ,
233+ FileMode . Create , FileAccess . Write ) )
234+ {
235+ await readStream . CopyToAsync ( fileStream ) ;
236+ }
237+ }
238+ }
239+ else
240+ {
241+ return ExitCodes . E9007 ;
242+ }
243+ }
244+
245+ if ( Verbosity >= VerbosityLevel . Normal )
246+ {
247+ Console . WriteLine ( "OK" ) ;
248+ }
249+
250+ stepSuccesful = true ;
251+ }
252+ catch
253+ {
254+ // exception with download, assuming it's something with network connection or Bintray API
255+ }
138256 }
139257 else
140258 {
141- Console . WriteLine ( "" ) ;
259+ // file already exists
260+ stepSuccesful = true ;
142261 }
143-
144- if ( Verbosity >= VerbosityLevel . Detailed )
145- {
146- Console . WriteLine ( $ "Download location is { LocationPath } ") ;
147- }
148-
149- // add readme file
150- File . WriteAllText (
151- Path . Combine (
152- LocationPath ,
153- "README.txt" ) ,
154- _readmeContent ) ;
155262 }
156- catch
263+
264+ if ( ! stepSuccesful )
157265 {
158- Console . WriteLine ( "" ) ;
266+ // couldn't download the fw file
267+ // check if there is one available
268+ fwFiles = Directory . EnumerateFiles ( LocationPath , $ "{ _targetName } -*.zip") . OrderByDescending ( f => f ) . ToList ( ) ;
159269
160- return ExitCodes . E9006 ;
161- }
270+ if ( fwFiles . Any ( ) )
271+ {
272+ // take the 1st one
273+ fwFileName = fwFiles . First ( ) ;
162274
163- // setup and perform download request
164- string fwFileName = $ " { _targetName } - { _fwVersion } . zip";
165- requestUri = $ "https://dl.bintray.com/nfbot/ { repoName } / { fwFileName } " ;
275+ // get the version form the file name
276+ var pattern = @"(\d+\.\d+\.\d+)(\.\d+|-.+)(?=\. zip) ";
277+ var match = Regex . Matches ( fwFileName , pattern , RegexOptions . IgnoreCase ) ;
166278
167- using ( var fwFileResponse = await _bintrayClient . GetAsync ( requestUri ) )
168- {
169- if ( fwFileResponse . IsSuccessStatusCode )
170- {
171- using ( var readStream = await fwFileResponse . Content . ReadAsStreamAsync ( ) )
279+ // set property
280+ Version = match [ 0 ] . Value ;
281+
282+ if ( Verbosity >= VerbosityLevel . Normal )
172283 {
173- using ( var fileStream = new FileStream (
174- Path . Combine ( LocationPath , fwFileName ) ,
175- FileMode . Create , FileAccess . Write ) )
176- {
177- await readStream . CopyToAsync ( fileStream ) ;
178- }
284+ Console . WriteLine ( "Using cached firmware package" ) ;
179285 }
180286 }
181287 else
182288 {
289+ // no fw file available
290+
291+ if ( Verbosity >= VerbosityLevel . Normal )
292+ {
293+ Console . WriteLine ( "Failure to download package and couldn't find one in the cache." ) ;
294+ }
295+
183296 return ExitCodes . E9007 ;
184297 }
185298 }
186299
187- Console . WriteLine ( $ "Updating to { _fwVersion } " ) ;
300+ // got here, must have a file!
188301
189302 // unzip the firmware
190303 if ( Verbosity >= VerbosityLevel . Detailed )
191304 {
192- Console . Write ( $ "Extracting { fwFileName } ...") ;
305+ Console . Write ( $ "Extracting { Path . GetFileName ( fwFileName ) } ...") ;
193306 }
194307
195308 ZipFile . ExtractToDirectory (
@@ -198,9 +311,21 @@ protected async System.Threading.Tasks.Task<ExitCodes> DownloadAndExtractAsync()
198311
199312 if ( Verbosity >= VerbosityLevel . Detailed )
200313 {
201- Console . WriteLine ( "" ) ;
314+ Console . WriteLine ( "OK " ) ;
202315 }
203316
317+ // be nice to the user and delete any fw packages other than the last one
318+ var allFwFiles = Directory . EnumerateFiles ( LocationPath , "*.zip" ) . OrderByDescending ( f => f ) . ToList ( ) ;
319+ if ( allFwFiles . Count > 1 )
320+ {
321+ foreach ( var file in allFwFiles . Skip ( 1 ) )
322+ {
323+ File . Delete ( file ) ;
324+ }
325+ }
326+
327+ Console . WriteLine ( $ "Updating to { Version } ") ;
328+
204329 return ExitCodes . OK ;
205330 }
206331
0 commit comments