@@ -33,6 +33,7 @@ import {
33
33
TempSketchPrefix ,
34
34
} from './is-temp-sketch' ;
35
35
import { join } from 'path' ;
36
+ import { ErrnoException } from './utils/errors' ;
36
37
37
38
const RecentSketches = 'recent-sketches.json' ;
38
39
const DefaultIno = `void setup() {
@@ -187,6 +188,13 @@ export class SketchesServiceImpl
187
188
}
188
189
189
190
async loadSketch ( uri : string ) : Promise < SketchWithDetails > {
191
+ return this . doLoadSketch ( uri ) ;
192
+ }
193
+
194
+ private async doLoadSketch (
195
+ uri : string ,
196
+ detectInvalidSketchNameError = true
197
+ ) : Promise < SketchWithDetails > {
190
198
const { client, instance } = await this . coreClient ;
191
199
const req = new LoadSketchRequest ( ) ;
192
200
const requestSketchPath = FileUri . fsPath ( uri ) ;
@@ -201,17 +209,19 @@ export class SketchesServiceImpl
201
209
if ( err ) {
202
210
let rejectWith : unknown = err ;
203
211
if ( isNotFoundError ( err ) ) {
204
- const invalidMainSketchFilePath = await isInvalidSketchNameError (
205
- err ,
206
- requestSketchPath
207
- ) ;
208
- if ( invalidMainSketchFilePath ) {
209
- rejectWith = SketchesError . InvalidName (
210
- err . details ,
211
- FileUri . create ( invalidMainSketchFilePath ) . toString ( )
212
+ rejectWith = SketchesError . NotFound ( err . details , uri ) ;
213
+ // detecting the invalid sketch name error is not for free as it requires multiple filesystem access.
214
+ if ( detectInvalidSketchNameError ) {
215
+ const invalidMainSketchFilePath = await isInvalidSketchNameError (
216
+ err ,
217
+ requestSketchPath
212
218
) ;
213
- } else {
214
- rejectWith = SketchesError . NotFound ( err . details , uri ) ;
219
+ if ( invalidMainSketchFilePath ) {
220
+ rejectWith = SketchesError . InvalidName (
221
+ err . details ,
222
+ FileUri . create ( invalidMainSketchFilePath ) . toString ( )
223
+ ) ;
224
+ }
215
225
}
216
226
}
217
227
reject ( rejectWith ) ;
@@ -278,7 +288,7 @@ export class SketchesServiceImpl
278
288
) ;
279
289
}
280
290
} catch ( err ) {
281
- if ( 'code' in err && err . code === 'ENOENT' ) {
291
+ if ( ErrnoException . isENOENT ( err ) ) {
282
292
this . logger . debug (
283
293
`<<< '${ RecentSketches } ' does not exist yet. This is normal behavior. Falling back to empty data.`
284
294
) ;
@@ -317,7 +327,7 @@ export class SketchesServiceImpl
317
327
318
328
let sketch : Sketch | undefined = undefined ;
319
329
try {
320
- sketch = await this . loadSketch ( uri ) ;
330
+ sketch = await this . doLoadSketch ( uri , false ) ;
321
331
this . logger . debug (
322
332
`Loaded sketch ${ JSON . stringify (
323
333
sketch
@@ -390,7 +400,7 @@ export class SketchesServiceImpl
390
400
) ) {
391
401
let sketch : SketchWithDetails | undefined = undefined ;
392
402
try {
393
- sketch = await this . loadSketch ( uri ) ;
403
+ sketch = await this . doLoadSketch ( uri , false ) ;
394
404
} catch { }
395
405
if ( ! sketch ) {
396
406
needsUpdate = true ;
@@ -413,14 +423,14 @@ export class SketchesServiceImpl
413
423
414
424
async cloneExample ( uri : string ) : Promise < Sketch > {
415
425
const [ sketch , parentPath ] = await Promise . all ( [
416
- this . loadSketch ( uri ) ,
426
+ this . doLoadSketch ( uri , false ) ,
417
427
this . createTempFolder ( ) ,
418
428
] ) ;
419
429
const destinationUri = FileUri . create (
420
430
path . join ( parentPath , sketch . name )
421
431
) . toString ( ) ;
422
432
const copiedSketchUri = await this . copy ( sketch , { destinationUri } ) ;
423
- return this . loadSketch ( copiedSketchUri ) ;
433
+ return this . doLoadSketch ( copiedSketchUri , false ) ;
424
434
}
425
435
426
436
async createNewSketch ( ) : Promise < Sketch > {
@@ -477,7 +487,7 @@ export class SketchesServiceImpl
477
487
fs . mkdir ( sketchDir , { recursive : true } ) ,
478
488
] ) ;
479
489
await fs . writeFile ( sketchFile , inoContent , { encoding : 'utf8' } ) ;
480
- return this . loadSketch ( FileUri . create ( sketchDir ) . toString ( ) ) ;
490
+ return this . doLoadSketch ( FileUri . create ( sketchDir ) . toString ( ) , false ) ;
481
491
}
482
492
483
493
/**
@@ -528,7 +538,7 @@ export class SketchesServiceImpl
528
538
uri : string
529
539
) : Promise < SketchWithDetails | undefined > {
530
540
try {
531
- const sketch = await this . loadSketch ( uri ) ;
541
+ const sketch = await this . doLoadSketch ( uri , false ) ;
532
542
return sketch ;
533
543
} catch ( err ) {
534
544
if ( SketchesError . NotFound . is ( err ) || SketchesError . InvalidName . is ( err ) ) {
@@ -553,7 +563,7 @@ export class SketchesServiceImpl
553
563
}
554
564
// Nothing to do when source and destination are the same.
555
565
if ( sketch . uri === destinationUri ) {
556
- await this . loadSketch ( sketch . uri ) ; // Sanity check.
566
+ await this . doLoadSketch ( sketch . uri , false ) ; // Sanity check.
557
567
return sketch . uri ;
558
568
}
559
569
@@ -574,7 +584,10 @@ export class SketchesServiceImpl
574
584
if ( oldPath !== newPath ) {
575
585
await fs . rename ( oldPath , newPath ) ;
576
586
}
577
- await this . loadSketch ( FileUri . create ( destinationPath ) . toString ( ) ) ; // Sanity check.
587
+ await this . doLoadSketch (
588
+ FileUri . create ( destinationPath ) . toString ( ) ,
589
+ false
590
+ ) ; // Sanity check.
578
591
resolve ( ) ;
579
592
} catch ( e ) {
580
593
reject ( e ) ;
@@ -596,7 +609,7 @@ export class SketchesServiceImpl
596
609
}
597
610
598
611
async archive ( sketch : Sketch , destinationUri : string ) : Promise < string > {
599
- await this . loadSketch ( sketch . uri ) ; // sanity check
612
+ await this . doLoadSketch ( sketch . uri , false ) ; // sanity check
600
613
const { client } = await this . coreClient ;
601
614
const archivePath = FileUri . fsPath ( destinationUri ) ;
602
615
// The CLI cannot override existing archives, so we have to wipe it manually: https://github.com/arduino/arduino-cli/issues/1160
@@ -666,7 +679,7 @@ export class SketchesServiceImpl
666
679
667
680
return this . tryParse ( raw ) ;
668
681
} catch ( err ) {
669
- if ( 'code' in err && err . code === 'ENOENT' ) {
682
+ if ( ErrnoException . isENOENT ( err ) ) {
670
683
return undefined ;
671
684
}
672
685
throw err ;
@@ -695,7 +708,7 @@ export class SketchesServiceImpl
695
708
} ) ;
696
709
this . inoContent . resolve ( inoContent ) ;
697
710
} catch ( err ) {
698
- if ( 'code' in err && err . code === 'ENOENT' ) {
711
+ if ( ErrnoException . isENOENT ( err ) ) {
699
712
// Ignored. The custom `.ino` blueprint file is optional.
700
713
} else {
701
714
throw err ;
@@ -763,7 +776,7 @@ async function isInvalidSketchNameError(
763
776
. map ( ( name ) => path . join ( requestSketchPath , name ) ) [ 0 ]
764
777
) ;
765
778
} catch ( err ) {
766
- if ( 'code' in err && err . code === 'ENOTDIR' ) {
779
+ if ( ErrnoException . isENOENT ( err ) || ErrnoException . isENOTDIR ( err ) ) {
767
780
return undefined ;
768
781
}
769
782
throw err ;
0 commit comments