VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 4 months ago

Copyright year updates by scm.

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