3
3
import java .io .ByteArrayInputStream ;
4
4
import java .net .URI ;
5
5
import java .util .HashMap ;
6
+ import java .util .Iterator ;
6
7
import java .util .Map ;
7
8
import java .util .Map .Entry ;
8
9
import java .util .TreeMap ;
14
15
import org .eclipse .cdt .core .model .CoreModel ;
15
16
import org .eclipse .cdt .core .settings .model .ICConfigurationDescription ;
16
17
import org .eclipse .cdt .core .settings .model .ICProjectDescription ;
18
+ import org .eclipse .cdt .core .settings .model .util .CDataUtil ;
17
19
import org .eclipse .cdt .managedbuilder .core .IConfiguration ;
18
20
import org .eclipse .cdt .managedbuilder .core .IManagedProject ;
19
21
import org .eclipse .cdt .managedbuilder .core .IProjectType ;
48
50
import io .sloeber .core .toolchain .SloeberConfigurationVariableSupplier ;
49
51
import io .sloeber .core .tools .Helpers ;
50
52
import io .sloeber .core .tools .Libraries ;
53
+ import io .sloeber .core .txt .KeyValueTree ;
51
54
import io .sloeber .core .txt .TxtFile ;
52
55
53
56
public class SloeberProject extends Common {
@@ -57,28 +60,26 @@ public class SloeberProject extends Common {
57
60
private Map <String , OtherDescription > myOtherDescriptions = new HashMap <>();
58
61
private TxtFile myCfgFile = null ;
59
62
private IProject myProject = null ;
60
- private boolean isConfigured = false ;
63
+ private boolean isInMemory = false ;
61
64
private boolean isDirty = false ; // if anything has changed
65
+ private boolean myNeedToPersist = false ; // Do we need to write data to disk
62
66
private boolean myNeedsClean = false ; // is there old sloeber data that needs cleaning
67
+ private boolean myNeedsSyncWithCDT = false ; // Knows CDT all configs Sloeber Knows
63
68
64
69
private static final String ENV_KEY_BUILD_SOURCE_PATH = BUILD + DOT + SOURCE + DOT + PATH ;
65
70
private static final String ENV_KEY_BUILD_GENERIC_PATH = BUILD + DOT + "generic" + DOT + PATH ; //$NON-NLS-1$
66
71
private static final String ENV_KEY_COMPILER_PATH = COMPILER + DOT + PATH ;
67
72
private static final String SLOEBER_MAKE_LOCATION = ENV_KEY_SLOEBER_START + "make_location" ; //$NON-NLS-1$
68
- private static final String CONFIG_DOT = "Config." ;//$NON-NLS-1$
73
+ private static final String CONFIG = "Config" ;//$NON-NLS-1$
74
+ private static final String CONFIG_DOT = CONFIG + DOT ;
69
75
70
- private SloeberProject (IProject project , boolean isProjectCreating ) {
76
+ private SloeberProject (IProject project ) {
71
77
myProject = project ;
72
78
try {
73
79
project .setSessionProperty (sloeberQualifiedName , this );
74
80
} catch (CoreException e ) {
75
81
e .printStackTrace ();
76
82
}
77
- if (isProjectCreating ) {
78
- return ;
79
- }
80
- configureProject ();
81
-
82
83
}
83
84
84
85
/**
@@ -163,7 +164,7 @@ public void run(IProgressMonitor internalMonitor) throws CoreException {
163
164
CCorePlugin cCorePlugin = CCorePlugin .getDefault ();
164
165
ICProjectDescription prjCDesc = cCorePlugin .getProjectDescription (newProjectHandle );
165
166
166
- SloeberProject arduinoProjDesc = new SloeberProject (newProjectHandle , true );
167
+ SloeberProject arduinoProjDesc = new SloeberProject (newProjectHandle );
167
168
for (ICConfigurationDescription curConfigDesc : prjCDesc .getConfigurations ()) {
168
169
// Even though we use the same boardDescriptor for all configurations during
169
170
// project creation
@@ -250,36 +251,60 @@ private HashMap<String, String> getEnvVars(ICConfigurationDescription confDesc)
250
251
return allVars ;
251
252
}
252
253
253
- private void configureProject () {
254
+ private void configure () {
254
255
255
256
CCorePlugin cCorePlugin = CCorePlugin .getDefault ();
256
257
ICProjectDescription prjCDesc = cCorePlugin .getProjectDescription (myProject );
257
- configureProject (prjCDesc , false );
258
+ configure (prjCDesc , false );
258
259
}
259
260
260
- private void configureProject (ICProjectDescription prjCDesc , boolean prjDescWritable ) {
261
- if (isConfigured ) {
261
+ private void configure (ICProjectDescription prjCDesc , boolean prjDescWritable ) {
262
+ if (isInMemory ) {
262
263
if (isDirty ) {
263
264
createSloeberConfigFiles (prjCDesc );
264
265
setEnvironmentVariables (prjCDesc );
266
+ isDirty = false ;
265
267
}
266
- if (prjDescWritable && myNeedsClean ) {
267
- cleanOldData (prjCDesc );
268
+ if (myNeedToPersist ) {
269
+ createSloeberConfigFiles (prjCDesc );
270
+ }
271
+ if (prjDescWritable ) {
272
+ if (myNeedsSyncWithCDT ) {
273
+ syncWithCDT (prjCDesc , prjDescWritable );
274
+ }
275
+ if (myNeedsClean ) {
276
+ cleanOldData (prjCDesc );
277
+ }
268
278
}
269
279
return ;
270
280
}
271
- // first configuration of the sloeber project
272
- if (readSloeberConfig (prjCDesc )) {
273
- // we migrated from a previous sloeber configuration
274
- myNeedsClean = true ;
281
+ // first read the sloeber files in memory
282
+ readSloeberConfig (prjCDesc , prjDescWritable );
283
+ if (myNeedToPersist || isDirty ) {
275
284
createSloeberConfigFiles (prjCDesc );
276
- // we need a writable project description to clean the old sloeber data
277
- if (prjDescWritable ) {
285
+ isDirty = false ;
286
+ }
287
+ if (prjDescWritable ) {
288
+ if (myNeedsClean ) {
289
+ // we migrated from a previous sloeber configuration
290
+ // and we can safely delete the old data
278
291
cleanOldData (prjCDesc );
279
292
}
293
+ if (myNeedsSyncWithCDT ) {
294
+ syncWithCDT (prjCDesc , prjDescWritable );
295
+ }
280
296
}
281
297
setEnvironmentVariables (prjCDesc );
282
- isConfigured = true ;
298
+ isInMemory = true ;
299
+ }
300
+
301
+ /**
302
+ * sync the Sloeber configuration info with CDT Currently only Sloeber known
303
+ * confighgurations will be created by Sloeber inside CDT
304
+ */
305
+ private void syncWithCDT (ICProjectDescription prjCDesc , boolean prjDescWritable ) {
306
+ readSloeberConfig (prjCDesc , prjDescWritable );
307
+ myNeedsSyncWithCDT = false ;
283
308
}
284
309
285
310
/**
@@ -313,22 +338,44 @@ private void cleanOldData(ICProjectDescription prjCDesc) {
313
338
* @param confDesc
314
339
* returns true if the config needs saving otherwise false
315
340
*/
316
- private boolean readSloeberConfig (final ICProjectDescription prjCDesc ) {
317
- boolean needToCreateConfigFiles = false ;
341
+ private void readSloeberConfig (ICProjectDescription prjCDesc , boolean prjDescWritable ) {
318
342
IFile file = getConfigLocalFile ();
319
343
if (file .exists ()) {
320
344
myCfgFile = new TxtFile (file .getLocation ().toFile ());
321
345
IFile versionFile = getConfigVersionFile ();
322
346
if (versionFile .exists ()) {
323
347
myCfgFile .mergeFile (versionFile .getLocation ().toFile ());
324
348
}
325
- for (ICConfigurationDescription confDesc : prjCDesc .getConfigurations ()) {
326
- BoardDescription boardDesc = new BoardDescription (myCfgFile , getBoardPrefix (confDesc ));
327
- CompileDescription compileDescription = new CompileDescription (myCfgFile , getCompilePrefix (confDesc ));
328
- OtherDescription otherDesc = new OtherDescription (myCfgFile , getOtherPrefix (confDesc ));
329
- myBoardDescriptions .put (confDesc .getId (), boardDesc );
330
- myCompileDescriptions .put (confDesc .getId (), compileDescription );
331
- myOtherDescriptions .put (confDesc .getId (), otherDesc );
349
+ KeyValueTree allFileConfigs = myCfgFile .getData ().getChild (CONFIG );
350
+ for (Entry <String , KeyValueTree > curChild : allFileConfigs .getChildren ().entrySet ()) {
351
+ String curConfName = curChild .getKey ();
352
+ BoardDescription boardDesc = new BoardDescription (myCfgFile , getBoardPrefix (curConfName ));
353
+ CompileDescription compileDescription = new CompileDescription (myCfgFile ,
354
+ getCompilePrefix (curConfName ));
355
+ OtherDescription otherDesc = new OtherDescription (myCfgFile , getOtherPrefix (curConfName ));
356
+ ICConfigurationDescription curConfDesc = prjCDesc .getConfigurationByName (curConfName );
357
+ if (curConfDesc == null ) {
358
+ myNeedsSyncWithCDT = true ;
359
+ // I set persist because most likely this new config comes from sloeber.cfg
360
+ // and it must be copied to .sproject
361
+ myNeedToPersist = true ;
362
+ if (prjDescWritable ) {
363
+ String id = CDataUtil .genId (null );
364
+ try {
365
+ curConfDesc = prjCDesc .createConfiguration (id , curConfName ,
366
+ prjCDesc .getActiveConfiguration ());
367
+ } catch (Exception e ) {
368
+ // ignore as we will try again later
369
+ }
370
+ }
371
+ }
372
+ if (curConfDesc != null ) {
373
+ String curConfID = curConfDesc .getId ();
374
+ myBoardDescriptions .put (curConfID , boardDesc );
375
+ myCompileDescriptions .put (curConfID , compileDescription );
376
+ myOtherDescriptions .put (curConfID , otherDesc );
377
+ myNeedsSyncWithCDT = false ;
378
+ }
332
379
}
333
380
334
381
} else {
@@ -339,7 +386,8 @@ private boolean readSloeberConfig(final ICProjectDescription prjCDesc) {
339
386
} else {
340
387
// Maybe this is a old Sloeber project with the data in the eclipse build
341
388
// environment variables
342
- needToCreateConfigFiles = true ;
389
+ myNeedToPersist = true ;
390
+ myNeedsClean = true ;
343
391
for (ICConfigurationDescription confDesc : prjCDesc .getConfigurations ()) {
344
392
345
393
BoardDescription boardDesc = BoardDescription .getFromCDT (confDesc );
@@ -352,7 +400,6 @@ private boolean readSloeberConfig(final ICProjectDescription prjCDesc) {
352
400
353
401
}
354
402
}
355
- return needToCreateConfigFiles ;
356
403
}
357
404
358
405
private boolean setActiveConfig (ICConfigurationDescription confDesc ) {
@@ -397,12 +444,32 @@ private void createSloeberConfigFiles(final ICProjectDescription prjCDesc) {
397
444
Map <String , String > versionVars = new TreeMap <>();
398
445
399
446
for (ICConfigurationDescription confDesc : prjCDesc .getConfigurations ()) {
400
- BoardDescription boardDescription = myBoardDescriptions .get (confDesc .getId ());
401
- CompileDescription compileDescription = myCompileDescriptions .get (confDesc .getId ());
402
- OtherDescription otherDescription = myOtherDescriptions .get (confDesc .getId ());
403
- String boardPrefix = getBoardPrefix (confDesc );
404
- String compPrefix = getCompilePrefix (confDesc );
405
- String otherPrefix = getOtherPrefix (confDesc );
447
+ String confID = confDesc .getId ();
448
+ String confName = confDesc .getName ();
449
+ BoardDescription boardDescription = myBoardDescriptions .get (confID );
450
+ CompileDescription compileDescription = myCompileDescriptions .get (confID );
451
+ OtherDescription otherDescription = myOtherDescriptions .get (confID );
452
+ // when a new configuration has been created not in project properties
453
+ // the descriptions can be null
454
+ // first get a config to copy from
455
+ Iterator <Entry <String , BoardDescription >> iterator = myBoardDescriptions .entrySet ().iterator ();
456
+ Entry <String , BoardDescription > actualValue = iterator .next ();
457
+ String copyConfID = actualValue .getKey ();
458
+ if (null == boardDescription ) {
459
+ boardDescription = new BoardDescription (myBoardDescriptions .get (copyConfID ));
460
+ myBoardDescriptions .put (confID , boardDescription );
461
+ }
462
+ if (null == compileDescription ) {
463
+ compileDescription = new CompileDescription (myCompileDescriptions .get (copyConfID ));
464
+ myCompileDescriptions .put (confID , compileDescription );
465
+ }
466
+ if (null == otherDescription ) {
467
+ otherDescription = new OtherDescription (myOtherDescriptions .get (copyConfID ));
468
+ myOtherDescriptions .put (confID , otherDescription );
469
+ }
470
+ String boardPrefix = getBoardPrefix (confName );
471
+ String compPrefix = getCompilePrefix (confName );
472
+ String otherPrefix = getOtherPrefix (confName );
406
473
407
474
configVars .putAll (boardDescription .getEnvVarsConfig (boardPrefix ));
408
475
configVars .putAll (compileDescription .getEnvVarsConfig (compPrefix ));
@@ -418,11 +485,11 @@ private void createSloeberConfigFiles(final ICProjectDescription prjCDesc) {
418
485
try {
419
486
storeConfigurationFile (getConfigVersionFile (), versionVars );
420
487
storeConfigurationFile (getConfigLocalFile (), configVars );
421
- isDirty = false ;
422
488
} catch (CoreException e ) {
423
489
Common .log (new Status (IStatus .ERROR , io .sloeber .core .Activator .getId (),
424
490
"failed to save the sloeber config files" , e )); //$NON-NLS-1$
425
491
}
492
+ myNeedToPersist = false ;
426
493
427
494
}
428
495
@@ -499,7 +566,7 @@ public static synchronized SloeberProject getSloeberProject(IProject project, bo
499
566
e .printStackTrace ();
500
567
}
501
568
if (!allowNull ) {
502
- SloeberProject ret = new SloeberProject (project , false );
569
+ SloeberProject ret = new SloeberProject (project );
503
570
return ret ;
504
571
}
505
572
}
@@ -545,21 +612,21 @@ public void setOtherDescription(ICConfigurationDescription confDesc, OtherDescri
545
612
*/
546
613
public BoardDescription getBoardDescription (ICConfigurationDescription confDesc , boolean allowNull ) {
547
614
if (!allowNull ) {
548
- configureProject ();
615
+ configure ();
549
616
}
550
617
return myBoardDescriptions .get (confDesc .getId ());
551
618
}
552
619
553
620
public CompileDescription getCompileDescription (ICConfigurationDescription confDesc , boolean allowNull ) {
554
621
if (!allowNull ) {
555
- configureProject ();
622
+ configure ();
556
623
}
557
624
return myCompileDescriptions .get (confDesc .getId ());
558
625
}
559
626
560
627
public OtherDescription getOtherDescription (ICConfigurationDescription confDesc , boolean allowNull ) {
561
628
if (!allowNull ) {
562
- configureProject ();
629
+ configure ();
563
630
}
564
631
return myOtherDescriptions .get (confDesc .getId ());
565
632
}
@@ -596,16 +663,16 @@ public String getDecoratedText(String text) {
596
663
return text ;
597
664
}
598
665
599
- private static String getBoardPrefix (ICConfigurationDescription confDesc ) {
600
- return CONFIG_DOT + confDesc . getName () + DOT + "board." ; //$NON-NLS-1$
666
+ private static String getBoardPrefix (String confDescName ) {
667
+ return CONFIG_DOT + confDescName + DOT + "board." ; //$NON-NLS-1$
601
668
}
602
669
603
- private static String getCompilePrefix (ICConfigurationDescription confDesc ) {
604
- return CONFIG_DOT + confDesc . getName () + DOT + "compile." ; //$NON-NLS-1$
670
+ private static String getCompilePrefix (String confDescName ) {
671
+ return CONFIG_DOT + confDescName + DOT + "compile." ; //$NON-NLS-1$
605
672
}
606
673
607
- private static String getOtherPrefix (ICConfigurationDescription confDesc ) {
608
- return CONFIG_DOT + confDesc . getName () + DOT + "other." ; //$NON-NLS-1$
674
+ private static String getOtherPrefix (String confDescName ) {
675
+ return CONFIG_DOT + confDescName + DOT + "other." ; //$NON-NLS-1$
609
676
}
610
677
611
678
private IFile getConfigVersionFile () {
@@ -619,9 +686,28 @@ private IFile getConfigLocalFile() {
619
686
public void configChangeAboutToApply (ICProjectDescription newProjDesc , ICProjectDescription oldProjDesc ) {
620
687
ICConfigurationDescription newActiveConfig = newProjDesc .getActiveConfiguration ();
621
688
ICConfigurationDescription oldActiveConfig = oldProjDesc .getActiveConfiguration ();
689
+
690
+ // make sure the dirty flag is set when needed
691
+ if (!isDirty ) {
692
+ // set dirty when the number of configurations changed
693
+ int newNumberOfConfigs = newProjDesc .getConfigurations ().length ;
694
+ int oldNumberOfConfigs = oldProjDesc .getConfigurations ().length ;
695
+ if (newNumberOfConfigs != oldNumberOfConfigs ) {
696
+ isDirty = true ;
697
+ } else {
698
+ // set dirty if a configname changed
699
+ for (ICConfigurationDescription curConfig : newProjDesc .getConfigurations ()) {
700
+ if (oldProjDesc .getConfigurationByName (curConfig .getName ()) == null ) {
701
+ isDirty = true ;
702
+ }
703
+ }
704
+ }
705
+ }
706
+ // in many cases we also need to set the active config
622
707
boolean needsConfigSet = myNeedsClean || isDirty
623
708
|| !newActiveConfig .getName ().equals (oldActiveConfig .getName ());
624
- configureProject (newProjDesc , true );
709
+
710
+ configure (newProjDesc , true );
625
711
if (needsConfigSet ) {
626
712
setActiveConfig (newActiveConfig );
627
713
}
0 commit comments