2020import sys
2121import os
2222import re
23+ import requests
2324
2425from ruamel import yaml
2526
3536VALUES_YAML = "values.yaml"
3637ISTIO_IO_DIR = os .path .abspath (__file__ + "/../../" )
3738CONFIG_INDEX_DIR = "content/docs/reference/config/installation-options/index.md"
39+ CONFIG_INDEX_DIFF_DIR = "content/docs/reference/config/installation-options-changes/index.md"
40+ CONFIG_IGNORE_LIST = ["global.hub" ]
3841
3942def endOfTheList (context , lineNum , lastLineNum , totalNum ):
4043 flag = 0
@@ -67,7 +70,15 @@ def endOfTheList(context, lineNum, lastLineNum, totalNum):
6770
6871 return True , valueList
6972
73+ # ordered dictionary to store the configuration options for the subcomponents of Istio. This
74+ # will be used to populate a new index.md
7075prdict = collections .defaultdict (list )
76+ # ordered dictionary to store the differences of configuration options between the new
77+ # index.md and the previous version (i.e, configurations options already listed in the index.md).
78+ od_diff = collections .defaultdict (list )
79+ od_diff_new = collections .defaultdict (list )
80+ od_diff_removed = collections .defaultdict (list )
81+ od_diff_unchanged = collections .defaultdict (list )
7182
7283def decode_helm_yaml (s ):
7384 ret_val = ''
@@ -307,10 +318,243 @@ def sanitizeValueStr(value):
307318 if value != None and regex .search (value ) != None :
308319 value = value .replace ("|" , "\|" );
309320 return value
310-
311-
321+
322+ # Compares the configuration option value from the newly discovered set of values (stored
323+ # in prdict dictionary) and its previous version (stored in index.md). If there is no
324+ # change in the configuration option value between the 2 versions, it will be ignored. If
325+ # there are any differences, we will store the differences (will track differences for key,
326+ # value and description of a configuration option) in the 'od_diff' dictionary. The values
327+ # stored in this dictionary will later be written to CONFIG_INDEX_DIFF_DIR.
328+ #
329+ # The difference between the configuration option values is stored in the CONFIG_INDEX_DIFF_DIR
330+ # in the format:
331+ # | KEY | OLD DEFAULT VALUE | NEW DEFAULT VALUE | OLD DESCRIPTION | NEW DESCRIPTION |
332+ # | ------ | ------------ | ------------ | ------------ | ------------ |
333+ # | Key | oldValue | newValue | oldDesc | newDesc |
334+ #
335+ # If a configuration option is present only in the latest version, then the oldKey, oldValue
336+ # and oldDescription will be represented as 'n/a' (vice-versa applies to newKey, newValue and
337+ # newDescription).
338+ #
339+ # oValue - configuration option from the existing index.md
340+ # nValue - configuration option from the current processing of configuration options to be
341+ # stored in a new version of index.md
342+ # k - istio component name for which these configuration options are being processed. This is
343+ # used to populate the contents of 'od_diff' dictionary.
344+ #
345+ def compareValues (oValue , nValue , k ):
346+ # oValue and nVAlue contains configuration option in the format:
347+ # '| `<Key>` | `<Value>` | `<Description>` |
348+ # This needs to be split in order to get the Key, Value and Description values to compare.
349+ oldKey = ''
350+ oldValue = ''
351+ oldDesc = ''
352+
353+ newKey = ''
354+ newValue = ''
355+ newDesc = ''
356+
357+ key = None
358+
359+ if nValue is not None :
360+ groups = re .search ("\| \`(.*)\` \| \`(.*)\` \| (.*) |" , nValue .strip ())
361+ if groups :
362+ newKey = groups .group (1 )
363+ newValue = groups .group (2 )
364+ newDesc = groups .group (3 )
365+
366+ if oValue is not None and nValue is not None :
367+ if len (oValue ) == 1 :
368+ item = oValue [0 ]
369+
370+ if item == nValue :
371+ key = newKey
372+ oValue .remove (item )
373+ od_diff_unchanged [k ].append ("| `%s` | `%s` | %s |" % (newKey , newValue .rstrip (), newDesc ))
374+ else :
375+ groups = re .search ("\| \`(.*)\` \| \`(.*)\` \|\s*(.*)\s*\|" , item .strip ())
376+ if groups :
377+ oldKey = groups .group (1 )
378+ oldValue = groups .group (2 )
379+ oldDesc = groups .group (3 )
380+ key = oldKey
381+
382+ if oldKey in CONFIG_IGNORE_LIST :
383+ oValue .remove (item )
384+ return key
385+
386+ if oldValue != newValue :
387+ if oldValue is None :
388+ oldValue = 'n/a'
389+ if newValue is None :
390+ newValue = 'n/a'
391+
392+ if oldDesc .strip () != newDesc .strip ():
393+ if (newDesc == None or newDesc == '' ) and (oldDesc is None or oldDesc == '' ):
394+ pass
395+ if oldDesc is None :
396+ oldDesc = 'n/a'
397+ if newDesc is None or newDesc == '' :
398+ newDesc = 'n/a'
399+ oValue .remove (item )
400+ od_diff [k ].append ("| `%s` | `%s` | `%s` | %s | %s |" % (newKey , oldValue .rstrip (), newValue .rstrip (), oldDesc , newDesc ))
401+ else :
402+ # This is the case where values are the same but descriptions are different. Right now, there is nothing more to do since
403+ # we do not care about displaying values that haven't changed between releases.
404+ oValue .remove (item )
405+
406+ #od_diff_unchanged[k].append("| `%s` | `%s` | %s |" % (newKey, newValue.rstrip(), newDesc))
407+ else :
408+ foundItem = 'false'
409+ for item in oValue :
410+ if item == nValue :
411+ key = newKey
412+ oValue .remove (item )
413+ od_diff_unchanged [k ].append ("| `%s` | `%s` | %s |" % (newKey , newValue .rstrip (), newDesc ))
414+ foundItem = 'true'
415+ break
416+ else :
417+ groups = re .search ("\| \`(.*)\` \| \`(.*)\` \|\s*(.*)\s*\|" , item .strip ())
418+ if groups :
419+ oldKey = groups .group (1 )
420+ oldValue = groups .group (2 )
421+ oldDesc = groups .group (3 )
422+
423+ if oldKey == newKey :
424+ if oldValue == newValue and oldDesc != newDesc :
425+ key = newKey
426+ od_diff [k ].append ("| `%s` | `%s` | `%s` | %s | %s |" % (newKey , oldValue .rstrip (), newValue .rstrip (), oldDesc , newDesc ))
427+ oValue .remove (item )
428+ foundItem = 'true'
429+ break
430+
431+ if foundItem == 'false' :
432+ od_diff_new [k ].append ("| `%s` | `%s` | %s |" % (newKey , newValue .rstrip (), newDesc ))
433+ elif oValue is None :
434+ key = newKey
435+ od_diff_new [k ].append ("| `%s` | `%s` | %s |" % (newKey , newValue .rstrip (), newDesc ))
436+ elif nValue is None :
437+ for item in oValue :
438+ groups = re .search ("\| \`(.*)\` \| \`(.*)\` \|\s*(.*)\s*\|" , item .strip ())
439+ if groups :
440+ oldKey = groups .group (1 )
441+ oldValue = groups .group (2 )
442+ oldDesc = groups .group (3 )
443+
444+ key = oldKey
445+ od_diff_removed [k ].append ("| `%s` | `%s` | %s |" % (oldKey , oldValue .rstrip (), oldDesc ))
446+
447+ return key
448+
449+ #
450+ # Get the previous release number so that we can retrieve the index.md for that
451+ # release. The release branches are tagged in the following format: release-<number>
452+ #
453+ def getPreviousRelease ():
454+ req = requests .get ('https://api.github.com/repos/istio/istio.io/branches' )
455+ jsonData = req .json ()
456+ previousRelease = 0.0
457+
458+ for x in jsonData :
459+ releaseName = x ['name' ]
460+ if releaseName .startswith ('release-' ):
461+ releaseNum = releaseName .split ('release-' )
462+ if releaseNum [1 ] > previousRelease :
463+ previousRelease = releaseNum [1 ]
464+ return previousRelease
465+
466+ #
467+ # Get the index.md for the previous release.
468+ #
469+ def getContentFromPreviousRelease (releaseName ):
470+ istio_url = 'https://raw.githubusercontent.com/istio/istio.io/release-' + releaseName + '/content/docs/reference/config/installation-options/index.md'
471+ req = requests .get (istio_url )
472+ content = req .text
473+ indexMap = collections .defaultdict (list )
474+
475+ # store all the configurations options from the index.md file into the indexMap
476+ # dictionary. This will be used to compare the values with the latest version
477+ # of configuration options.
478+ data = content .split ('\n ' )
479+ for d in data :
480+ if d .rstrip () != '' and d != '| Key | Default Value | Description |' and d != '| --- | --- | --- |' and d [0 :1 ] == '|' and d [- 1 ] == '|' :
481+ groups = re .search ("\| \`(.*)\` \| \`(.*)\` \| (.*) |" , d .strip ())
482+ if groups :
483+ key = groups .group (1 )
484+ if key in indexMap :
485+ value = indexMap .get (key )
486+ value .append (d .strip ())
487+ else :
488+ indexMap [key ].append (d .strip ())
489+ return indexMap
490+
491+ def writeVersionDiffs (index_diff_file ):
492+ meta = ""
493+
494+ for d in index_diff_file :
495+ meta = meta + d
496+ if "<!-- AUTO-GENERATED-START -->" in d :
497+ break
498+
499+ index_diff_file .seek (0 )
500+ index_diff_file .write (meta )
501+
502+ '''
503+ if od_diff_unchanged:
504+ index_diff_file.write('\n ## Unmodified configuration options\n ')
505+
506+ for k, v in od_diff_unchanged.items():
507+ index_diff_file.write("\n ### Unmodified `%s` key/value pairs\n \n " % k)
508+ index_diff_file.write('| Key | Default Value | Description |\n ')
509+ index_diff_file.write('| --- | --- | --- |\n ')
510+
511+ for value in v:
512+ index_diff_file.write('%s\n ' % (value))
513+ '''
514+
515+ if od_diff :
516+ index_diff_file .write ('\n ## Modified configuration options\n ' )
517+
518+ for k , v in od_diff .items ():
519+ index_diff_file .write ("\n ### Modified `%s` key/value pairs\n \n " % k )
520+ index_diff_file .write ('| Key | Old Default Value | New Default Value | Old Description | New Description |\n ' )
521+ index_diff_file .write ('| --- | --- | --- | --- | --- |\n ' )
522+
523+ for value in v :
524+ index_diff_file .write ('%s\n ' % (value ))
525+
526+ if od_diff_new :
527+ index_diff_file .write ('\n ## New configuration options\n ' )
528+
529+ for k , v in od_diff_new .items ():
530+ index_diff_file .write ("\n ### New `%s` key/value pairs\n \n " % k )
531+ index_diff_file .write ('| Key | Default Value | Description |\n ' )
532+ index_diff_file .write ('| --- | --- | --- |\n ' )
533+
534+ for value in v :
535+ index_diff_file .write ('%s\n ' % (value ))
536+
537+ if od_diff_removed :
538+ index_diff_file .write ('\n ## Removed configuration options\n ' )
539+
540+ for k , v in od_diff_removed .items ():
541+ index_diff_file .write ("\n ### Removed `%s` key/value pairs\n \n " % k )
542+ index_diff_file .write ('| Key | Default Value | Description |\n ' )
543+ index_diff_file .write ('| --- | --- | --- |\n ' )
544+
545+ for value in v :
546+ index_diff_file .write ('%s\n ' % (value ))
547+
548+ index_diff_file .write ("\n <!-- AUTO-GENERATED-END -->\n " )
549+
312550with open (os .path .join (ISTIO_IO_DIR , CONFIG_INDEX_DIR ), 'r' ) as f :
313551 endReached = False
552+ key = ''
553+ # A list used to track the configuration options that has been compared and processed when going
554+ # through the configurations processed in the latest version
555+ indexList = []
556+ previousRelease = getPreviousRelease ()
557+ indexMap = getContentFromPreviousRelease (previousRelease )
314558
315559 data = f .read ().split ('\n ' )
316560 for d in data :
@@ -332,11 +576,34 @@ def sanitizeValueStr(value):
332576 print '| Key | Default Value | Description |'
333577 print '| --- | --- | --- |'
334578 for value in v :
335- print ('%s' % (value ))
579+ print ('%s' % (value ))
580+ # Compare configuration option values from the latest version
581+ # with the older version.
582+ groups = re .search ("\| \`(.*)\` \| \`(.*)\` \| (.*) |" , value .strip ())
583+ if groups :
584+ key = groups .group (1 )
585+ indexValue = indexMap .get (key )
586+
587+ indexList .append (compareValues (indexValue , value , k ))
336588 print ('' )
337589
338590 for d in data :
339591 if "<!-- AUTO-GENERATED-END -->" in d :
340592 endReached = True
341593 if endReached :
342594 print d
595+
596+ # We want to include any configuration options that was discovered in
597+ # the older version but not available in the current version
598+ for k in indexMap .keys ():
599+ key = k .split ('.' )[0 ]
600+ indexList .append (compareValues (indexMap .get (k ), None , key ))
601+
602+ # This index.md file is used to track the differences of configuration
603+ # option values between the current and previous release. All the
604+ # differences in configuration option values between the current
605+ # and previous release (tracked in the 'od_diff' dictionary) will be
606+ # written to the index.md file
607+ index_diff_file = open (os .path .join (ISTIO_IO_DIR , CONFIG_INDEX_DIFF_DIR ), 'r+' )
608+ writeVersionDiffs (index_diff_file )
609+ index_diff_file .close ()
0 commit comments