VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/db/gen-sql-comments.py@ 79449

Last change on this file since 79449 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: gen-sql-comments.py 76553 2019-01-01 01:45:53Z vboxsync $
4
5"""
6Converts doxygen style comments in SQL script to COMMENT ON statements.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2012-2019 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30
31import sys;
32import re;
33
34
35def errorMsg(sMsg):
36 sys.stderr.write('error: %s\n' % (sMsg,));
37 return 1;
38
39class SqlDox(object):
40 """
41 Class for parsing relevant comments out of a pgsql file
42 and emit COMMENT ON statements from it.
43 """
44
45 def __init__(self, oFile, sFilename):
46 self.oFile = oFile;
47 self.sFilename = sFilename;
48 self.iLine = 0; # The current input line number.
49 self.sComment = None; # The current comment.
50 self.fCommentComplete = False; # Indicates that the comment has ended.
51 self.sCommentSqlObj = None; # SQL object indicated by the comment (@table).
52 self.sOuterSqlObj = None; # Like 'table yyyy' or 'type zzzz'.
53 self.sPrevSqlObj = None; # Like 'table xxxx'.
54
55
56 def error(self, sMsg):
57 return errorMsg('%s(%d): %s' % (self.sFilename, self.iLine, sMsg,));
58
59 def dprint(self, sMsg):
60 sys.stderr.write('debug: %s\n' % (sMsg,));
61 return True;
62
63 def resetComment(self):
64 self.sComment = None;
65 self.fCommentComplete = False;
66 self.sCommentSqlObj = None;
67
68 def quoteSqlString(self, s):
69 return s.replace("'", "''");
70
71 def commitComment2(self, sSqlObj):
72 if self.sComment is not None and sSqlObj is not None:
73 print("COMMENT ON %s IS\n '%s';\n" % (sSqlObj, self.quoteSqlString(self.sComment.strip())));
74 self.resetComment();
75 return True;
76
77 def commitComment(self):
78 return self.commitComment2(self.sCommentSqlObj);
79
80 def process(self):
81 for sLine in self.oFile:
82 self.iLine += 1;
83
84 sLine = sLine.strip();
85 self.dprint('line %d: %s\n' % (self.iLine, sLine));
86 if sLine.startswith('--'):
87 if sLine.startswith('--- '):
88 #
89 # New comment.
90 # The first list may have a @table, @type or similar that we're interested in.
91 #
92 self.commitComment();
93
94 sLine = sLine.lstrip('- ');
95 if sLine.startswith('@table '):
96 self.sCommentSqlObj = 'TABLE ' + (sLine[7:]).rstrip();
97 self.sComment = '';
98 elif sLine.startswith('@type '):
99 self.sCommentSqlObj = 'TYPE ' + (sLine[6:]).rstrip();
100 self.sComment = '';
101 elif sLine.startswith('@todo') \
102 or sLine.startswith('@file') \
103 or sLine.startswith('@page') \
104 or sLine.startswith('@name') \
105 or sLine.startswith('@{') \
106 or sLine.startswith('@}'):
107 # Ignore.
108 pass;
109 elif sLine.startswith('@'):
110 return self.error('Unknown tag: %s' % (sLine,));
111 else:
112 self.sComment = sLine;
113
114 elif (sLine.startswith('-- ') or sLine == '--') \
115 and self.sComment is not None and self.fCommentComplete is False:
116 #
117 # Append line to comment.
118 #
119 if sLine == '--':
120 sLine = '';
121 else:
122 sLine = (sLine[3:]);
123 if self.sComment == '':
124 self.sComment = sLine;
125 else:
126 self.sComment += "\n" + sLine;
127
128 elif sLine.startswith('--< '):
129 #
130 # Comment that starts on the same line as the object it describes.
131 #
132 sLine = (sLine[4:]).rstrip();
133 # => Later/never.
134 else:
135 #
136 # Not a comment that interests us. So, complete any open
137 # comment and commit it if we know which SQL object it
138 # applies to.
139 #
140 self.fCommentComplete = True;
141 if self.sCommentSqlObj is not None:
142 self.commitComment();
143 else:
144 #
145 # Not a comment. As above, we complete and optionally commit
146 # any open comment.
147 #
148 self.fCommentComplete = True;
149 if self.sCommentSqlObj is not None:
150 self.commitComment();
151
152 #
153 # Check for SQL (very fuzzy and bad).
154 #
155 asWords = sLine.split(' ');
156 if len(asWords) >= 3 \
157 and asWords[0] == 'CREATE':
158 # CREATE statement.
159 sType = asWords[1];
160 sName = asWords[2];
161 if sType == 'UNIQUE' and sName == 'INDEX' and len(asWords) >= 4:
162 sType = asWords[2];
163 sName = asWords[3];
164 if sType in ('TABLE', 'TYPE', 'INDEX', 'VIEW'):
165 self.sOuterSqlObj = sType + ' ' + sName;
166 self.sPrevSqlObj = self.sOuterSqlObj;
167 self.dprint('%s' % (self.sOuterSqlObj,));
168 self.commitComment2(self.sOuterSqlObj);
169 elif len(asWords) >= 1 \
170 and self.sOuterSqlObj is not None \
171 and self.sOuterSqlObj.startswith('TABLE ') \
172 and re.search("^(as|al|bm|c|enm|f|i|l|s|ts|uid|uuid)[A-Z][a-zA-Z0-9]*$", asWords[0]) is not None:
173 # Possibly a column name.
174 self.sPrevSqlObj = 'COLUMN ' + self.sOuterSqlObj[6:] + '.' + asWords[0];
175 self.dprint('column? %s' % (self.sPrevSqlObj));
176 self.commitComment2(self.sPrevSqlObj);
177
178 #
179 # Check for semicolon.
180 #
181 if sLine.find(");") >= 0:
182 self.sOuterSqlObj = None;
183
184 return 0;
185
186
187def usage():
188 sys.stderr.write('usage: gen-sql-comments.py <filename.pgsql>\n'
189 '\n'
190 'The output goes to stdout.\n');
191 return 0;
192
193
194def main(asArgs):
195 # Parse the argument. :-)
196 sInput = None;
197 if (len(asArgs) != 2):
198 sys.stderr.write('syntax error: expected exactly 1 argument, a psql file\n');
199 usage();
200 return 2;
201 sInput = asArgs[1];
202
203 # Do the job, outputting to standard output.
204 try:
205 oFile = open(sInput, 'r');
206 except:
207 return errorMsg("failed to open '%s' for reading" % (sInput,));
208
209 # header.
210 print("-- $" "Id" "$");
211 print("--- @file");
212 print("-- Autogenerated from %s. Do not edit!" % (sInput,));
213 print("--");
214 print("");
215 for sLine in __copyright__.split('\n'):
216 if len(sLine) > 0:
217 print("-- %s" % (sLine,));
218 else:
219 print("--");
220 print("");
221 print("");
222 me = SqlDox(oFile, sInput);
223 return me.process();
224
225sys.exit(main(sys.argv));
226
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette