blob: 63cf5b77d3616f4d8c0cc9e1cb3db0a9068024aa [file] [log] [blame]
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -05001#!/usr/bin/python
2
3import os
4import pdb
Sapan Bhatiacdd90b72014-01-28 20:03:13 -05005import copy
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -05006import sys
7import json
8import re
9from django.template import Context, Template
Scott Bakerf3039902015-10-23 12:20:15 -070010from optparse import OptionParser
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050011
12# Django set up
13
14sys.path.append('.')
Scott Baker8fc378d2015-02-16 22:43:01 -080015os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
Sapan Bhatiaeb62ad62014-01-28 14:29:08 -050016from django.db.models.fields.related import ForeignKey, ManyToManyField
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050017
Scott Bakerf3039902015-10-23 12:20:15 -070018options = None
19
Sapan Bhatiaeb62ad62014-01-28 14:29:08 -050020def singular(foo, keys):
21 for k in keys:
22 if (foo==k+'es'):
23 return k
24 elif (foo==k+'s'):
25 return k
26 raise Exception('Plural to singular error for %s'%foo)
27
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050028g = globals()
29
Scott Bakerb2a8cc32015-10-20 11:13:50 -070030def enum_classes(apps):
31 model_classes = []
32 for app in apps:
33 app = app + ".models"
34 models_module = __import__(app)
35 for part in app.split(".")[1:]:
36 if hasattr(models_module, "PlCoreBase"):
37 break
38 models_module = getattr(models_module,part)
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050039
Scott Bakerb2a8cc32015-10-20 11:13:50 -070040 PlCoreBase = getattr(models_module,"PlCoreBase")
41
42 for classname in dir(models_module):
43 c = getattr(models_module, classname, None)
Scott Bakerf3039902015-10-23 12:20:15 -070044 if type(c)==type(PlCoreBase) and c.__name__ not in options.blacklist:
Scott Bakerb2a8cc32015-10-20 11:13:50 -070045 model_classes.append(c)
46
47 return model_classes
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050048
49class GenObj(object):
50 def __str__(self):
51 return str(self.model.__name__.lower())
52
53 def __init__(self, m):
54 self.model = m
55 self.props = []
56 self.refs = []
Sapan Bhatiabe42fba2014-01-28 23:53:49 -050057 self.plural_name = None
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050058
59 def plural(self):
Sapan Bhatiabe42fba2014-01-28 23:53:49 -050060 if (self.plural_name):
61 return self.plural_name
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050062 else:
Sapan Bhatiabe42fba2014-01-28 23:53:49 -050063 name = str(self)
64 if (name.endswith('s')):
65 return name+'es'
66 else:
67 return name+'s'
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050068
Scott Bakerf556b922014-11-10 15:58:58 -080069 def singular(self):
70 return str(self)
71
72 def rest_name(self):
73 # These are things that either for historic reasons or due to incorrect naming,
74 # got called something different than the autogen thinks they should be
75 # called.
Tony Mack06c8e472014-11-30 15:53:08 -050076 REST_FIXUP = {'controllernetworkses': 'controllernetworks',
77 'controllerimageses': 'controllerimages',
78 'controllersliceses': 'controllerslices',
79 'controlleruserses': 'controllerusers',
Scott Bakerf556b922014-11-10 15:58:58 -080080 'sitedeploymentses': 'sitedeployments',
81 'siteroles': 'site_roles',
82 'sliceprivileges': 'slice_privileges',
83 'sliceroles': 'slice_roles',
84 }
85 return REST_FIXUP.get(self.plural(), self.plural())
86
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050087 def camel(self):
88 name = str(self.model.__name__)
Sapan Bhatiadf2b49e2014-01-28 19:41:07 -050089 return name
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050090
91class Generator(dict):
92 def all(self):
93 return self.values()
Scott Baker853060e2015-10-23 13:09:49 -070094
95 def rest_models(self):
96 norest = [x.lower() for x in options.norest]
97 return [v for v in self.values() if not (str(v) in norest)]
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -050098
99 def regex(self, r):
100 filtered = filter(lambda o:re.match(r,str(o)), self.values())
101 return filtered
102
103 def add_object(self, o):
104 obj = GenObj(o)
105 fields = o._meta.fields
106 self[str(obj).lower()]=obj
107
108 def compute_links(self):
109 for obj in self.values():
Sapan Bhatiab5885402014-01-29 10:32:09 -0500110 #if (str(obj)=='network'):
Sapan Bhatiacdd90b72014-01-28 20:03:13 -0500111 # pdb.set_trace()
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -0500112 fields = obj.model._meta.fields
113 for f in fields:
Sapan Bhatiab5885402014-01-29 10:32:09 -0500114 if (f and f.rel):
115 to_name = str(f.rel.to)
116 else:
117 to_name = None
118
119 if type(f)==ForeignKey and to_name and to_name in self.keys():
120 refobj = self[f.to_name]
121
122 if (str(obj)=='slice' and f.to_name=='networks'):
123 obj.refs.append(refobj)
Sapan Bhatiabe42fba2014-01-28 23:53:49 -0500124 related_name = f.related_query_name()
Sapan Bhatiab5885402014-01-29 10:32:09 -0500125 if (related_name!='+' and related_name.lower()!=str(obj).lower()):
Sapan Bhatiabe42fba2014-01-28 23:53:49 -0500126 cobj = copy.deepcopy(obj)
127 cobj.multi = True
128 cobj.plural_name = related_name
129 refobj.refs.append(cobj)
Scott Baker225184c2015-10-30 09:42:34 -0700130 elif f.name.endswith("_ptr"):
131 # django inherited model, for example HPCService
132 # cause swagger and REST to break
133 pass
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -0500134 else:
135 obj.props.append(f.name)
Sapan Bhatiab5885402014-01-29 10:32:09 -0500136
Sapan Bhatiaeb62ad62014-01-28 14:29:08 -0500137 m2m = obj.model._meta.many_to_many
138 for f in m2m:
139 try:
140 related_model_name = f.m2m_reverse_field_name()
141 except:
142 related_model_name = f.m2m_db_table().rsplit('_',1)[-1]
143
Sapan Bhatiab5885402014-01-29 10:32:09 -0500144 related_name = f.related_query_name()
Sapan Bhatiaeb62ad62014-01-28 14:29:08 -0500145 if related_model_name in self.keys():
Scott Baker015e13d2014-12-15 16:12:43 -0800146 #print "XXX1", obj, f, related_name, related_model_name
Sapan Bhatiaeb62ad62014-01-28 14:29:08 -0500147 refobj = self[related_model_name]
Sapan Bhatiacdd90b72014-01-28 20:03:13 -0500148 cobj = copy.deepcopy(obj)
149 cobj.multi=True
150 refobj.refs.append(cobj)
Scott Baker1e67bb42014-07-03 17:58:10 -0700151
152 # deal with upgradeFrom_rel_+
153 if (related_name.endswith("+")):
154 continue
155
Scott Baker853060e2015-10-23 13:09:49 -0700156 if (related_name!='+') and related_model_name in self: # and related_name.lower()!=str(obj).lower()):
Scott Baker015e13d2014-12-15 16:12:43 -0800157 refobj = self[related_model_name]
Scott Baker853060e2015-10-23 13:09:49 -0700158 #print "XXX2", obj, f, related_name, related_model_name, refobj.plural_name
Scott Baker015e13d2014-12-15 16:12:43 -0800159 cobj = copy.deepcopy(refobj)
Sapan Bhatiabe42fba2014-01-28 23:53:49 -0500160 cobj.multi = True
Sapan Bhatiab5885402014-01-29 10:32:09 -0500161
Scott Baker015e13d2014-12-15 16:12:43 -0800162 obj.refs.append(cobj)
Sapan Bhatiab5885402014-01-29 10:32:09 -0500163
Sapan Bhatiabe42fba2014-01-28 23:53:49 -0500164
Sapan Bhatiaeb62ad62014-01-28 14:29:08 -0500165
Scott Bakerf3039902015-10-23 12:20:15 -0700166
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -0500167def main():
Scott Bakerf3039902015-10-23 12:20:15 -0700168 global options
169 parser = OptionParser(usage="modelgen [options] <template_fn>", )
170
171 parser.add_option("-a", "--app", dest="apps",
172 help="list of applications to parse", metavar="APP", default=[], action="append")
173 parser.add_option("-b", "--blacklist", dest="blacklist",
174 help="add model name to blacklist", metavar="MODEL", default=["SingletonModel", "PlCoreBase"], action="append")
Scott Baker853060e2015-10-23 13:09:49 -0700175 parser.add_option("-n", "--no-rest", dest="norest",
176 help="do not generate rest api for model", metavar="MODEL", default=["SingletonModel", "PlCoreBase"], action="append")
Scott Bakerf3039902015-10-23 12:20:15 -0700177
178 (options, args) = parser.parse_args(sys.argv[1:])
179
180 if not options.apps:
181 options.apps = ["core"]
182
183 if len(args)!=1:
184 print 'Usage: modelgen [options] <template_fn>'
185 exit(1)
186
187 output = args[0]
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -0500188
189 generator = Generator()
190
Scott Bakerf3039902015-10-23 12:20:15 -0700191 models = enum_classes(options.apps)
Sapan Bhatia3a45f8b2014-01-14 21:20:16 -0500192
193 for m in models:
194 generator.add_object(m)
195
196 generator.compute_links()
197 template_contents = open(output).read()
198 template = Template(template_contents)
199 context = Context({'generator':generator})
200 print template.render(context)
201
202
203if (__name__=='__main__'):
204 main()