forked from EnMasseProject/enmasse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse.py
executable file
·182 lines (154 loc) · 6.57 KB
/
parse.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env python2
__license__ = """
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
"""
# Parse ascii doc files and generate json file.
# The json file will be used in the enmasse console to display UI elements like form labels and tooltips
import re
import json
import argparse
import os
from glob import glob
import sys
# flatten the keys in a dict
def flatten(d,result=None,index=None,Key=None):
if result is None:
result = {}
if isinstance(d, dict):
for key in d:
# *.external keys are optional so remove them from the flattened output
if key == 'external' and isinstance(d[key], basestring):
continue
value = d[key]
if Key is not None and index is not None:
newkey = ".".join([Key,(str(key).replace(" ", "") + str(index))])
elif Key is not None:
newkey = ".".join([Key,(str(key).replace(" ", ""))])
else:
newkey= str(key).replace(" ", "")
flatten(value, result, index=None, Key=newkey)
else:
result[Key]=1
return result.keys()
# test to see if the keys in the expected file are in the dictionary
def complete(expected, jobj):
try:
with open(expected, "r") as in_file:
expected = json.load(in_file)
generated = flatten(jobj)
missing = [x for x in expected if x not in generated]
extra = [x for x in generated if x not in expected]
if len(missing):
print "The following keys are missing from the ascii docs:"
for line in missing:
print line
if len(extra):
print "The following keys are in the ascii docs but not in the expected file:"
for line in extra:
print line
if len(missing) or len(extra):
return False
except IOError:
print >> sys.stderr, "Unable to open or parse", args.input
return False
return True
# parse a list of files for formatted comments
# the list of files should already be tested for existance
def parse(names, verbose):
if verbose:
print "Parsing ascii doc files for comments:"
base = {}
p = re.compile("^// !(.*?)\:(.*)")
for fname in names:
try:
modeldoc = open(fname, "r")
except IOError:
print >> sys.stderr, "Unable to open ", fname
continue
if verbose:
print " ", fname
longDescription = None
for line in modeldoc:
s = p.search(line)
if s:
obj = base
keystr = s.group(1) # // address.queue.shortDescription
value = s.group(2) # :the text after the first :
keys = keystr.split('.')
for i, key in enumerate(keys):
# the first keys define the object heirarchy
if i < len(keys) - 1:
if not key in obj:
obj[key] = {}
obj = obj[key]
# the last key gets the value
else:
# :start and :stop lines surround block values
if value == 'start':
longDescription = [] # start accumulating description lines
continue
elif value == 'stop':
obj[key] = ' '.join(longDescription) # join the description lines in to one line
longDescription = None
continue
# assign the value to the last key
obj[key] = value
# are we accumulating longDescription lines
elif longDescription is not None:
longDescription.append(line.rstrip())
modeldoc.close()
return base
parser = argparse.ArgumentParser(description='Output json file made from Extracting comments from one or more asciidoc files.')
parser.add_argument('fnames', metavar='f', type=str, nargs='+',
help='Name[s] of the input asciidoc file[s] or directories')
parser.add_argument('-v', "--verbose", action='store_true', help='verbose output')
parser.add_argument("-o", "--output", help="Output file name. If ommitted the output will go to stdout.")
parser.add_argument("-i", "--input", help="Name of the file that contains all the expected help keys.")
args = parser.parse_args()
# extract all the directories from the list of file names on the command line
dirs = [x for x in args.fnames if os.path.isdir(x)]
# extract all the flat files from the list of file names. Any files that don't exist are ignored
files = [x for x in args.fnames if os.path.isfile(x)]
# get list of all *.adoc files in all passed in dirs and their subdirs
result = [y for z in dirs for x in os.walk(z) for y in glob(os.path.join(x[0], '*.adoc'))]
# combine files found in dirs with explicitly passed in file names
result.extend(files)
if len(result) == 0:
print "No ascii docs found"
exit (1)
# parse all the files and create a single dict
jfile = parse(result, args.verbose)
# test the dict against the passed in key file for completeness
if args.input:
if not complete(args.input, jfile):
exit (1)
else:
print "Warning: output not checked against a key file for completeness."
# convert dict into string for output
jstr = json.dumps(jfile, sort_keys=True, indent=4, separators=(',', ': '))
# either save the json to a file or output it to the console
if args.output:
try:
with open(args.output, "w") as text_file:
text_file.write(jstr)
if args.verbose:
print args.output, "created"
except IOError:
print >> sys.stderr, "Unable to open ", args.output, "for output."
exit(1)
else:
print jstr
exit(0)