0

Please suggest best design for accomodating different versions of configuration file(INI format) into a single file. My requirement is I have three different versions of a configuration say V1.config, V2.config, V3.config. The different versions needs to be supported. I would like to achieve a file V.config from which I can read configuration info of all differnt versions.

My Requirement would be to support 3 different versions simultaneously with a sinlge file.

I working on a design where somehow i could combine these versions to a single file say V and read the data according to the version.Lets say [A\A2] will be there in this common/combined file but it is there in V1 and in V3 but not in V2. How can that be achieved.

What is the best practice usually followed, what would be possible design?

To help visualize: V1.config would be something like:

[A\A1]
/*section for config info */
[A\A2]
/*section for config info */

[A\A3]
/*section for config info */

V2.config

[A\A1]
    /*section for config info */

/* Removed a section */

[A\A3]
    /*section for config info */
[A\A4]
    /*Added new section for config info */

V3.config

 [A\A1]
    /*section for config info */
 [A\A2]
    /*Re-introduced the section in Version V1 for config info */


 /* Removed a section in Version V2 */
 [A\A4]
    /*section for config info */
  • 1
    What format do you use for your config? INI, XML, JSON, custom solution? – Kromster Oct 19 '15 at 13:12
  • Do you have enough resources to rewrite and retest older versions (V1/V2) support for new config format? – Kromster Oct 19 '15 at 13:14
  • So are you just swapping sections in and out, or does info within the sections change, too? Do old versions of the software ignore sections they don't recognize? – user82096 Oct 19 '15 at 13:43
  • @ Krom Stern ..I use INI format – user2954936 Oct 19 '15 at 15:35
  • @dan1111..the info within the sections changes too...the older version ignores sections the ones they don't recognize – user2954936 Oct 19 '15 at 15:42
1

You could take the web browser/HTML route. That is, whenever your program comes across some config info it doesn't understand (such as something added in a future version, or removed from a past version), it ignores it, and instead only pays attention to the sections it does understand.

This does come with the requirement that individual options behave consistently across versions. Either that, or your config file will rapidly become convoluted and repetitive.

In your example, V1 doesn't know about A\A4, so it would read it with the rest of the file, but then simply ignore it. Similarly, V2 doesn't care about A\A2, so anything in that section is ignored by V2. V3 reintroduces A\A2, which was ignored, rather than removed by V2, so it's still there, ready to be read and used.

The key to this is to never remove or change existing options. You can only ignore existing options or add new ones, unless you want to create a breaking change.


Here's a more in depth example of a fictitious program that uses a config file to remember some window settings. Say your V1 config file looks something like this:

[WindowDimensions]
width=400
height=300

[WindowLocation]
x=100
y=100

So V1 has a size and location for the window when it starts up. Here's a little pseudo code to read that and access the variables:

Dictionary loadConfig() {
    String configFile = readFile("config.ini")
    Dictionary config = parseIni(configFile) // parses the file into a tree of Dictionaries
    config = fillMissingDefaults(config) // check for missing elements
                                         // and fill any with (V1) defaults
    Log("Window width: %d, height: %d",
        config["WindowDimensions"]["width"],
        config["WindowDimensions"]["height"]) // logs "Window width: 400, height: 300"
    Log("Window location: (%d, %d)",
        config["WindowLocation"]["x"],
        config["WindowLocation"]["y"]) // logs "Window location: (100, 100)"
    return config
}

Then, fully 3D holographic displays come out, and everyone buys one. V2 is written to support them. Unfortunately, the tech is still new, and windows are always full screen, though the resolution is adjustable. So the V2 config file would look something like this:

[WindowDimensions]
width=400
height=300
depth=200

[WindowLocation]
x=100
y=100

We've added a depth to the WindowDimensions to account for the third dimension. Note that the WindowLocation section is still there. V2 doesn't need it (everything is fullscreen), but, since we want to maintain backwards compatibility with V1, it remains there. Now, for V2's config loader:

Dictionary loadConfig() {
    String configFile = readFile("config.ini")
    Dictionary config = parseIni(configFile) // identical to parseIni() in V1
    config = fillMissingDefaults(config) // check for missing elements
                                         // and fill any with (V2) defaults
    Log("Window width: %d, height: %d, depth: %d",
        config["WindowDimensions"]["width"],
        config["WindowDimensions"]["height"],
        config["WindowDimensions"]["depth"]) // logs "Window width: 400, height: 300, depth: 200"
    return config
}

Note that the config dictionary returned by parseIni() still contains WindowLocation and all it's children, but, since V2 doesn't care about it, it simply doesn't use it. Similarly, V1 can still use this new config file, even though there is now a new element in the config["WindowDimensions"] child dictionary.

Since config contains everything from config.ini, this has the added benefit of V2 saving the WindowLocation settings despite not knowing about it, simply by writing out the whole dictionary.

Now what if the config file was newly generated by V2 and thus really does have no mention of WindowLocation? That's what the defaults are for. If V1 one reads a new config file that previously had only been written by V2, then it would use, for example a default location of (300, 300), and would save that into the config file for future V1 use, along with all the V2 stuff it "doesn't" know about.

  • @8bittree..thanks for the reply..my requirement would be to support 3 different versions simultaneously with a sinlge file.For that how can V1 know what is the info required to be read by it. – user2954936 Oct 19 '15 at 15:53
  • @user2954936 V1 reads in the entire file, parses it, and stores it in a dynamic data structure (perhaps a dictionary/map/associative array). Then, it only access the keys that it knows about. Keys from later versions still get put into the dictionary, but they're never accessed in V1. Alternatively, create a fixed data structure (such as a class or struct), then, as you're reading in the config file, look for terms that V1 knows about and load those into the struct, and skip by unrecognized things. – 8bittree Oct 19 '15 at 16:06
  • @8bittree..thanks for clarification..is there any way i could combine these versions to a single file say V and read the data according to the version. – user2954936 Oct 19 '15 at 16:29
  • @8bittree....I working on a design where somehow i could combine these versions to a single file say V and read the data according to the version.Lets say [A\A2] will be there in this common/combined file but it is there in V1 and in V3 but not in V2. How can that be found out,any suggestions. – user2954936 Oct 19 '15 at 16:35
  • @user2954936 I added a more in depth example. See if that helps. – 8bittree Oct 19 '15 at 17:33
0

It depends - one 'best solution' is to have a common core of configuration settings, and then have a section with additions for different versions. This requires your system to handle obsolete settings still being present when new versions read them.

An alternative is to have a XML-style configuration where settings for different versions can be included in the same file. This is easier in that your settings block only has to contain an attribute saying what version it applies to, so you can have (for example) and in the sane file, and completely discard the obsolete version 1 set, or only have settings for 1 version. The disadvantage is that everything is duplicated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.