ct 0.10.8.114__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. cantools/__init__.py +24 -0
  2. cantools/_db.py +142 -0
  3. cantools/_memcache.py +76 -0
  4. cantools/_pay.py +46 -0
  5. cantools/admin.py +31 -0
  6. cantools/cfg.py +347 -0
  7. cantools/config.py +131 -0
  8. cantools/db/__init__.py +18 -0
  9. cantools/db/admin.py +27 -0
  10. cantools/db/gae/__init__.py +0 -0
  11. cantools/db/gae/model.py +127 -0
  12. cantools/db/gae/properties.py +35 -0
  13. cantools/db/wp.py +99 -0
  14. cantools/geo.py +188 -0
  15. cantools/hooks.py +13 -0
  16. cantools/scripts/__init__.py +0 -0
  17. cantools/scripts/bench.py +167 -0
  18. cantools/scripts/builder.py +272 -0
  19. cantools/scripts/deploy.py +154 -0
  20. cantools/scripts/doc.py +239 -0
  21. cantools/scripts/index.py +226 -0
  22. cantools/scripts/init.py +345 -0
  23. cantools/scripts/migrate.py +593 -0
  24. cantools/scripts/pubsub/__init__.py +28 -0
  25. cantools/scripts/pubsub/actor.py +13 -0
  26. cantools/scripts/pubsub/bots.py +143 -0
  27. cantools/scripts/pubsub/channel.py +85 -0
  28. cantools/scripts/pubsub/ps.py +145 -0
  29. cantools/scripts/pubsub/user.py +51 -0
  30. cantools/scripts/start.py +53 -0
  31. cantools/scripts/util.py +24 -0
  32. cantools/util/__init__.py +78 -0
  33. cantools/util/admin.py +620 -0
  34. cantools/util/data.py +109 -0
  35. cantools/util/media.py +303 -0
  36. cantools/util/package.py +125 -0
  37. cantools/util/system.py +73 -0
  38. cantools/web/__init__.py +9 -0
  39. cantools/web/dez_server/__init__.py +1 -0
  40. cantools/web/dez_server/controller.py +129 -0
  41. cantools/web/dez_server/cron.py +115 -0
  42. cantools/web/dez_server/daemons.py +64 -0
  43. cantools/web/dez_server/mail.py +24 -0
  44. cantools/web/dez_server/response.py +63 -0
  45. cantools/web/dez_server/routes.py +21 -0
  46. cantools/web/dez_server/server.py +229 -0
  47. cantools/web/dez_server/sms.py +12 -0
  48. cantools/web/gae_server.py +68 -0
  49. cantools/web/util.py +552 -0
  50. ct-0.10.8.114.dist-info/LICENSE +9 -0
  51. ct-0.10.8.114.dist-info/METADATA +25 -0
  52. ct-0.10.8.114.dist-info/RECORD +55 -0
  53. ct-0.10.8.114.dist-info/WHEEL +5 -0
  54. ct-0.10.8.114.dist-info/entry_points.txt +10 -0
  55. ct-0.10.8.114.dist-info/top_level.txt +1 -0
@@ -0,0 +1,167 @@
1
+ """
2
+ ### Usage: ctbench [-bmsv] [--domain=DOMAIN] [--port=PORT] [--number=NUMBER] [--concurrency=CONCURRENCY] [--weight=WEIGHT] [--keys=KEYS]
3
+
4
+ ### Options:
5
+ -h, --help show this help message and exit
6
+ -e, --encrypted use encrypted (https) connection
7
+ -d DOMAIN, --domain=DOMAIN
8
+ hostname (default: 0.0.0.0)
9
+ -p PORT, --port=PORT port (default=8080)
10
+ -n NUMBER, --number=NUMBER
11
+ number of requests (default=5000)
12
+ -c CONCURRENCY, --concurrency=CONCURRENCY
13
+ number of connections (default=100)
14
+ -w WEIGHT, --weight=WEIGHT
15
+ weight (size) of memcache blocks (default=10)
16
+ -k KEYS, --keys=KEYS key count - number of memcache blocks (default=10)
17
+ -l PIPELINERS, --pipeliners=PIPELINERS
18
+ number of pipelined requests (default=50)
19
+ -s, --static random static (html/css) requests (default=False)
20
+ -b, --blobs random blob requests (default=False)
21
+ -m, --memcache random memcache requests (default=False)
22
+ -v, --validate validate return values (default=False)
23
+ """
24
+
25
+ import os, rel, json
26
+ from optparse import OptionParser
27
+ from dez.bench import MultiTester
28
+ from cantools import config
29
+ from cantools.util import cmd, log, read, error, token
30
+ from cantools.web import post
31
+
32
+ NUMBER = 5000
33
+ CONCURRENCY = 100
34
+ WEIGHT = 10
35
+ KEYS = 10
36
+ PIPES = 50
37
+
38
+ class Bencher(object):
39
+ def __init__(self, options):
40
+ self.options = options
41
+ if options.blobs or options.memcache or options.static:
42
+ self.multi()
43
+ else:
44
+ self.single()
45
+
46
+ def single(self):
47
+ log("single (direct dbench) mode", important=True)
48
+ oz = self.options
49
+ rel.signal(2, rel.abort)
50
+ cstr = "dbench %s %s %s %s %s"%(oz.domain, oz.port, oz.number, oz.concurrency, oz.pipeliners)
51
+ if oz.encrypted:
52
+ cstr += " -e"
53
+ cmd(cstr)
54
+
55
+ def initmc(self):
56
+ oz = self.options
57
+ self.memcache = {}
58
+ self.mccount = 0
59
+ proto = oz.encrypted and "https" or "http"
60
+ for key in map(lambda k : "bencher%s"%(k,), range(oz.keys)):
61
+ val = self.memcache[key] = token(oz.weight)
62
+ post(oz.domain, "/_memcache", oz.port, {
63
+ "action": "set",
64
+ "key": key,
65
+ "value": val
66
+ }, proto, cb=self.regmc)
67
+ rel.signal(2, rel.abort)
68
+ rel.dispatch()
69
+
70
+ def initpaths(self):
71
+ oz = self.options
72
+ paths = self.paths = []
73
+ self.values = {}
74
+ if oz.blobs:
75
+ paths += self.regfiles("blob", binary=True)
76
+ if oz.static:
77
+ paths += self.regfiles("css")
78
+ paths += self.regfiles(config.build.web[config.mode] or config.build.web.compiled[config.mode],
79
+ "/", suffix=".html")
80
+ if oz.memcache:
81
+ paths += self.regfiles("memcache", "/_memcache?action=get&key=", self.memcache)
82
+ paths or error("nothing to request!")
83
+ log("randomizing requests among %s total items"%(len(paths),))
84
+
85
+ def validator(self, path, value, headers):
86
+ vlen = len(value)
87
+ clen = int(headers['content-length'])
88
+ if vlen != clen:
89
+ error("content-length mismatch! %s != %s"%(vlen, clen))
90
+ if "memcache" in path:
91
+ value = json.loads(value[1:])
92
+ elif "blob" not in path:
93
+ value = value.decode()
94
+ if path in self.values and self.values[path] != value:
95
+ log("returned:\n%s"%(value,), important=True)
96
+ log("should have returned:\n%s"%(self.values[path],), important=True)
97
+ error("return value mismatch: %s"%(path,))
98
+
99
+ def regmc(self, resp):
100
+ self.mccount += 1
101
+ log("regmc %s"%(self.mccount,))
102
+ if self.mccount == self.options.keys:
103
+ log("registered %s memcache keys"%(self.mccount,))
104
+ self._multi()
105
+
106
+ def regfiles(self, fpath, upath=None, files=None, binary=False, suffix=None):
107
+ upath = upath or "/%s/"%(fpath,)
108
+ fnames = files and files.keys() or os.listdir(fpath)
109
+ log("including %s %s files"%(len(fnames), fpath))
110
+ if self.options.validate:
111
+ paths = []
112
+ for fname in fnames:
113
+ if suffix and not fname.endswith(suffix):
114
+ continue
115
+ path = "%s%s"%(upath, fname)
116
+ paths.append(path)
117
+ self.values[path] = files and files[fname] or read(os.path.join(fpath, fname), binary=binary)
118
+ else:
119
+ paths = list(map(lambda n : "%s%s"%(upath, n), fnames))
120
+ return paths
121
+
122
+ def _multi(self):
123
+ oz = self.options
124
+ self.initpaths()
125
+ MultiTester(oz.domain, oz.port, self.paths, oz.number, oz.concurrency,
126
+ oz.pipeliners, oz.encrypted, oz.validate and self.validator).start()
127
+
128
+ def multi(self):
129
+ log("multi (randomized requests) mode", important=True)
130
+ if self.options.memcache:
131
+ self.initmc()
132
+ else:
133
+ self._multi()
134
+
135
+ def run():
136
+ parser = OptionParser("ctbench [-bmsve] [--domain=DOMAIN] [--port=PORT] [--number=NUMBER] [--concurrency=CONCURRENCY] [--weight=WEIGHT] [--keys=KEYS] [--pipeliners=PIPELINERS]")
137
+ parser.add_option("-e", "--encrypted", action="store_true", dest="encrypted",
138
+ default=False, help="use encrypted (https) connection")
139
+ parser.add_option("-d", "--domain", dest="domain", default=config.web.host,
140
+ help="hostname (default: %s)"%(config.web.host,))
141
+ parser.add_option("-p", "--port", dest="port", default=config.web.port,
142
+ help="port (default=%s)"%(config.web.port,))
143
+ parser.add_option("-n", "--number", dest="number", default=NUMBER,
144
+ help="number of requests (default=%s)"%(NUMBER,))
145
+ parser.add_option("-c", "--concurrency", dest="concurrency", default=CONCURRENCY,
146
+ help="number of connections (default=%s)"%(CONCURRENCY,))
147
+ parser.add_option("-w", "--weight", dest="weight", default=WEIGHT,
148
+ help="weight (size) of memcache blocks (default=%s)"%(WEIGHT,))
149
+ parser.add_option("-k", "--keys", dest="keys", default=KEYS,
150
+ help="key count - number of memcache blocks (default=%s)"%(KEYS,))
151
+ parser.add_option("-l", "--pipeliners", dest="pipeliners", default=PIPES,
152
+ help="number of pipelined requests (default=%s)"%(PIPES,))
153
+ parser.add_option("-s", "--static", action="store_true", dest="static",
154
+ default=False, help="random static (html/css) requests (default=False)")
155
+ parser.add_option("-b", "--blobs", action="store_true", dest="blobs",
156
+ default=False, help="random blob requests (default=False)")
157
+ parser.add_option("-m", "--memcache", action="store_true", dest="memcache",
158
+ default=False, help="random memcache requests (default=False)")
159
+ parser.add_option("-v", "--validate", action="store_true", dest="validate",
160
+ default=False, help="validate return values (default=False)")
161
+ options = parser.parse_args()[0]
162
+ for key in ["port", "number", "concurrency", "weight", "keys", "pipeliners"]:
163
+ setattr(options, key, int(getattr(options, key)))
164
+ Bencher(options)
165
+
166
+ if __name__ == "__main__":
167
+ run()
@@ -0,0 +1,272 @@
1
+ import subprocess, os, base64
2
+ from cantools import config
3
+ from cantools.util import log, error, read, write, mkdir
4
+
5
+ # jsmin was removed from the cantools requirements to reduce
6
+ # the maintenance burden for deployments on older systems
7
+ # (often with some degree of broken package management) that
8
+ # don't need to compile anything. so we check here instead.
9
+ try:
10
+ from jsmin import jsmin
11
+ BUILDER_READY = True
12
+ except:
13
+ BUILDER_READY = False
14
+
15
+ pcfg = config.build.prod
16
+ pwrap = {
17
+ "standard": "<script>%s</script>",
18
+ "closure": "<script>(function(){%s})();</script>"
19
+ }[pcfg.closure and "closure" or "standard"]
20
+ iwraps = {
21
+ "standard": "%s = %s || {}",
22
+ "closure": 'if (typeof %s == "undefined") %s = {}',
23
+ "closvar": 'if (typeof %s == "undefined") var %s = {}'
24
+ }
25
+ iwrap = iwraps[pcfg.closure and "closure" or "standard"]
26
+ bwrap = "Function(atob(\"%s\"))();"
27
+
28
+ def pwrapper(stxt):
29
+ if pcfg.b64:
30
+ stxt = bwrap%(base64.b64encode(stxt.encode()).decode(),)
31
+ return pwrap%(stxt,)
32
+
33
+ def iwrapper(mod):
34
+ if config.build.prod.closure:
35
+ parts = mod.split(".")
36
+ if len(parts) == 2: # good enough? ....
37
+ return iwraps["closvar"]%(parts[1], parts[1])
38
+ return iwrap%(mod, mod)
39
+
40
+ def nextQuote(text, lastIndex=0):
41
+ z = i = text.find('"', lastIndex)
42
+ while z > 0 and text[z-1] == "\\":
43
+ z -= 1
44
+ return ((i-z)%2 == 0) and i or nextQuote(text, i+1)
45
+
46
+ def encodestrings(text):
47
+ start = nextQuote(text) + 1
48
+ while start != 0:
49
+ end = nextQuote(text, start)
50
+ if end == -1:
51
+ error("parse",
52
+ "unclosed quote: character %s"%(start-1,),
53
+ "this quote: %s"%(text[start:start+config.parse_error_segment_length],),
54
+ text)
55
+ word = ''.join(["\\%s"%(oct(ord(ch))[1:],) for ch in list(text[start:end])])
56
+ if "\\134" not in word: # don't re-escape!
57
+ text = text[:start] + word + text[end:]
58
+ start = nextQuote(text, start + len(word) + 1) + 1
59
+ return text
60
+
61
+ def processhtml(html):
62
+ html = html.replace("{", "&#123").replace("}", "&#125").replace("</body>", "%s</body>"%(config.noscript,))
63
+ start = 0
64
+ while not start or html[start + config.js.offset + 1] == "/":
65
+ firststart = start = end = html.find(config.js.flag, start + 1)
66
+ js = []
67
+ while start != -1:
68
+ start += config.js.offset
69
+ end = html.find('"', start)
70
+ if end == -1:
71
+ error("no closing quote in this file: %s"%(html,))
72
+ js.append(html[start:end].strip("/"))
73
+ start = html.find(config.js.flag, end)
74
+ log("js: %s"%(js,), 1)
75
+ if start == end:
76
+ return html, ""
77
+ return html[:firststart] + "{jsspot}" + html[end+config.js.endoffset:], js
78
+
79
+ def compress(html):
80
+ log("compressing html", 1)
81
+ newhtml = html.replace("\n", " ").replace("\t", " ")
82
+ while " " in newhtml:
83
+ newhtml = newhtml.replace(" ", " ")
84
+ newhtml = newhtml.replace("> <", "><")
85
+ log("orig: %s. new: %s"%(len(html), len(newhtml)), 2)
86
+ return newhtml
87
+
88
+ def bfiles(dirname, fnames):
89
+ return [fname for fname in fnames if os.path.isfile(os.path.join(dirname, fname)) and fname != ".svn" and not fname.endswith("~") and not "_old." in fname]
90
+
91
+ def tryinit(iline, inits, prefixes):
92
+ if iline not in inits:
93
+ inits.add(iline)
94
+ prefixes.append(iline)
95
+
96
+ fragz = set()
97
+ def frag(path):
98
+ if '"' in path:
99
+ path = path.split('"')[0]
100
+ for root, dirs, files in os.walk(path, followlinks=True):
101
+ for sub in files:
102
+ if sub.endswith(".js"):
103
+ fp = os.path.join(root, sub)
104
+ log("fragment identified: %s"%(fp,), 1)
105
+ fragz.add(fp)
106
+ else:
107
+ fragz.add(path)
108
+
109
+ def require(line, jspaths, block, inits, admin_ct_path=None):
110
+ dynamic = False
111
+ if line.startswith("CT.scriptImport("):
112
+ rline = line[17:].split(line[16])[0]
113
+ if line[16] not in "'\"" or rline.startswith("http"):
114
+ log("skipping scriptImport: %s"%(line,), important=True)
115
+ return block
116
+ dynamic = True
117
+ else:
118
+ rline = line.split('require(')[1][1:].split(");")[0].strip(")")
119
+ if rline.endswith('"skip"'):
120
+ log("skipping require: %s"%(line,), important=True)
121
+ return block
122
+ elif rline.endswith(", true"):
123
+ dynamic = True
124
+ rline = rline.split(", ")[0]
125
+ rline = rline[:-1]
126
+ rsplit = rline.split(".")
127
+ log("module %s"%(rline,), important=True)
128
+ jspath = os.path.join(config.js.path, *rsplit) + ".js"
129
+ log("path %s"%(jspath,))
130
+ log("dynamic %s"%(dynamic,))
131
+ if jspath not in jspaths:
132
+ if dynamic:
133
+ frag(jspath)
134
+ else:
135
+ prefixes = []
136
+ fullp = "window"
137
+ for rword in rsplit:
138
+ if rword[0].isalpha():
139
+ fullp = ".".join([fullp, rword])
140
+ else:
141
+ fullp = "%s[%s]"%(fullp, rword)
142
+ tryinit(iwrapper(fullp), inits, prefixes)
143
+ pblock = ";".join(prefixes)
144
+ if pblock:
145
+ if config.build.prod.closure:
146
+ pblock = pblock.replace("window.", "")
147
+ jspaths.append(pblock)
148
+ block = block.replace(line, "%s;%s;%s"%(pblock, line.replace("require", "regmod"),
149
+ processjs(jspath, jspaths, inits, admin_ct_path)), 1)
150
+ return block
151
+
152
+ def processjs(path, jspaths=[], inits=set(), admin_ct_path=None):
153
+ log("processing js: %s"%(path,), 1)
154
+ p = path.split("#")[0] # potentially modded to locate file for prod (path remains the same for static)
155
+ if admin_ct_path: # admin pages
156
+ if path.startswith(config.js.path): # such as /js/CT/ct.js
157
+ p = admin_ct_path + path[len(config.js.path):]
158
+ else: # regular admin pages (/memcache/mc.js)
159
+ p = os.path.join(os.path.abspath(os.curdir), "dynamic", path)
160
+ block = read(p)
161
+ for line in [bit for bit in block.split("\n") if not bit.startswith("//")]:
162
+ for flag in ["CT.require(", "CT.scriptImport("]:
163
+ if flag in line and line[line.index(flag) - 1] != "'":
164
+ rline = line.strip().split(flag)[1]
165
+ if rline[0] != "\\" and rline[1] not in ".,": # require() is embedded in text. dot is weird.
166
+ block = require("%s%s"%(flag, rline),
167
+ jspaths, block, inits, admin_ct_path)
168
+ jspaths.append(path)
169
+ return "%s;\n"%(block,)
170
+
171
+ def compilejs(js, admin_ct_path=None):
172
+ jsblock = ""
173
+ jspaths = []
174
+ inits = set([iwrapper("window.CT")]) # already initialized
175
+ for p in js:
176
+ jsblock += processjs(p, jspaths, inits, admin_ct_path)
177
+ return jspaths, jsblock
178
+
179
+ def checkdir(p, recursive=False):
180
+ if not os.path.isdir(p):
181
+ mkdir(p, recursive)
182
+
183
+ def remerge(txt, js):
184
+ return txt.format(jsspot=js).replace("&#123", "{").replace("&#125", "}")
185
+
186
+ def build_frags(mode="web", admin_ct_path=None):
187
+ log("Compiling Dynamically-Referenced Fragments", important=True)
188
+ base = config.build[mode].compiled.production
189
+ if config.build.include:
190
+ log("Including Config-Specified Modules")
191
+ for p in config.build.include:
192
+ log("include: %s"%(p,), 1)
193
+ fragz.add(p)
194
+ fragged = set()
195
+ def build_frag(frag):
196
+ notjs = frag in config.build.notjs
197
+ if notjs:
198
+ log("not js: %s"%(frag,))
199
+ block = read(frag, binary=True)
200
+ else:
201
+ block = processjs(frag, admin_ct_path=admin_ct_path)
202
+ path = os.path.join(base, frag[len(config.js.path)+1:])
203
+ checkdir(path.rsplit("/", 1)[0], True)
204
+ if notjs or frag in config.build.exclude:
205
+ log("path excluded -- skipping compression/obfuscation", 2)
206
+ else:
207
+ log("mangling", 2)
208
+ block = jsmin(block)
209
+ write(block, path, binary=notjs)
210
+ while len(fragged) is not len(fragz):
211
+ fcopy = list(filter(lambda f : f not in fragged, fragz))
212
+ fragged.update(fcopy)
213
+ list(map(build_frag, fcopy))
214
+
215
+ def build(admin_ct_path, dirname, fnames):
216
+ """
217
+ This parses an html file, squishes together the javascript, scans
218
+ through for dynamic imports (CT.require statements), injects modules
219
+ wherever necessary, and sticks the result in a big <script> tag.
220
+ """
221
+ conf = admin_ct_path and config.build.admin or config.build.web
222
+ todir_stat = dirname.replace(conf.dynamic, conf.compiled.static)
223
+ todir_prod = dirname.replace(conf.dynamic, conf.compiled.production)
224
+ log("Target Static Directory: %s"%(todir_stat,), important=True)
225
+ log("Target Production Directory: %s"%(todir_prod,))
226
+ checkdir(todir_stat)
227
+ checkdir(todir_prod)
228
+ for fname in bfiles(dirname, fnames):
229
+ frompath = os.path.join(dirname, fname)
230
+ topath_stat = os.path.join(todir_stat, fname)
231
+ topath_prod = os.path.join(todir_prod, fname)
232
+ data = read(frompath)
233
+ if "fonts" in dirname or not fname.endswith(".html"):
234
+ log('copying non-html file (%s)'%(fname,), 1)
235
+ else:
236
+ log("processing html: %s"%(frompath,))
237
+ txt, js = processhtml(data)
238
+ if js:
239
+ jspaths, jsblock = compilejs(js, admin_ct_path)
240
+ log('writing static: %s -> %s'%(frompath, topath_stat), important=True)
241
+ write(remerge(txt, '\n'.join([p.split("#")[0].endswith("js") and '<script src="/%s"></script>'%(p,) or '<script>%s</script>'%(p,) for p in jspaths])), topath_stat)
242
+ log('writing production: %s -> %s'%(frompath, topath_prod))
243
+ jsb = jsblock.replace('"_encode": false,', '"_encode": true,').replace("CT.log._silent = false;", "CT.log._silent = true;")
244
+ if config.customscrambler:
245
+ jsb += '; CT.net.setScrambler("%s");'%(config.scrambler,)
246
+ write(remerge(compress(txt), pwrapper(jsmin(jsb))), topath_prod)
247
+ continue
248
+ else:
249
+ log('copying to prod/stat unmodified (%s)'%(fname,), important=True)
250
+ write(data, topath_stat)
251
+ write(data, topath_prod)
252
+ for fname in [f for f in fnames if os.path.isdir(os.path.join(dirname, f))]:
253
+ for dname, dirnames, filenames in os.walk(os.path.join(dirname, fname)):
254
+ build(admin_ct_path, dname, filenames + dirnames)
255
+
256
+ def silence_warnings():
257
+ from ply import yacc, lex
258
+ def quiet(*args, **kwargs):
259
+ pass
260
+ yacc.PlyLogger.warning = quiet
261
+ lex.PlyLogger.warning = quiet
262
+
263
+ def build_all(mode="web", admin_ct_path=None):
264
+ if not BUILDER_READY:
265
+ error("can't build - please install jsmin >= 2.2.2")
266
+ #silence_warnings() # is this unnecessary now.... maybe...
267
+ for dirname, dirnames, filenames in os.walk(config.build[mode].dynamic):
268
+ build(admin_ct_path, dirname, filenames + dirnames)
269
+ build_frags(mode, admin_ct_path)
270
+
271
+ if __name__ == "__main__":
272
+ build_all()
@@ -0,0 +1,154 @@
1
+ """
2
+ ### Usage: ctdeploy [-d|s|p] [-un] [--js_path=PATH]
3
+
4
+ ### Options:
5
+
6
+ -h, --help show this help message and exit
7
+ -d, --dynamic switch to dynamic (development) mode
8
+ -s, --static switch to static (debug) mode
9
+ -p, --production switch to production (garbled) mode
10
+ -u, --upload uploads project in specified mode and then (if
11
+ gae) switches back to dynamic (development) mode
12
+ -n, --no_build skip compilation step
13
+ -j JS_PATH, --js_path=JS_PATH
14
+ set javascript path (default=js)
15
+
16
+ ### Supports 3 modes:
17
+ - dynamic (files live in html)
18
+ - normal development files
19
+ - dynamic imports throughout
20
+ - original files are loaded ad-hoc
21
+ - chrome debugger plays nice
22
+ - no wire encryption
23
+ - all imports lazy
24
+ - static (files live in html-static)
25
+ - compiler builds same html files
26
+ - script imports in head
27
+ - otherwise unmodified source files
28
+ - original files are directly referenced
29
+ - chrome debugger prefers
30
+ - no wire encryption
31
+ - all hard requirements loaded in head
32
+ - lazy-designated imports still lazy
33
+ - production (files live in html-production)
34
+ - all code is compiled in head
35
+ - html is compressed
36
+ - javascript is minified and mangled
37
+ - original code is unrecognizable
38
+ - chrome debugger almost useless
39
+ - wire encryption
40
+ - designated lazy imports (indicated by second bool arg to CT.require)
41
+
42
+ Generates fresh 'static' and 'production' files (from 'development' source files in 'html' on every run, unless -n [or --no_build] flag is used). Mode is established in the app.yaml file, which routes requests to the appropriate directory, and the ct.cfg file, which determines backend behavior, especially regarding encryption.
43
+ """
44
+
45
+ import subprocess, os
46
+ from cantools import config, __version__
47
+ from cantools.util import log, error, read, write, cmd
48
+ from cantools.util.package import vpush
49
+ from .builder import build_all
50
+
51
+ try:
52
+ input = raw_input # py2/3 compatibility
53
+ except NameError:
54
+ pass
55
+
56
+ def doyaml(mode):
57
+ log("switching to %s mode"%(mode,))
58
+ lines = read(config.yaml.path, lines=True)
59
+ f = open(config.yaml.path, 'w')
60
+ m = None
61
+ for line in lines:
62
+ if line.startswith(config.yaml.start):
63
+ m = line[len(config.yaml.start):].strip()
64
+ elif line.startswith(config.yaml.end):
65
+ m = None
66
+ elif m == mode:
67
+ line = line.strip("#")
68
+ elif m:
69
+ line = "#%s"%(line.strip("#"),)
70
+ f.write(line)
71
+ f.close()
72
+
73
+ def setmode(mode):
74
+ doyaml(mode) # support other backends beyond app engine
75
+ ctpy = read(config.py.path)
76
+ isprod = mode == "production"
77
+ # set encode
78
+ ctpy = ctpy.replace(config.py.enc%(str(not isprod),),
79
+ config.py.enc%(str(isprod),))
80
+ # set mode
81
+ for m in ["dynamic", "static", "production"]:
82
+ if m != mode:
83
+ ctpy = ctpy.replace(config.py.mode%(m,), config.py.mode%(mode,))
84
+ write(ctpy, config.py.path)
85
+
86
+ def buildox():
87
+ cmd("ctinit -a")
88
+ cmd("ctdoc -w")
89
+ os.chdir("docs")
90
+ cmd("ctdeploy -p")
91
+ os.chdir("..")
92
+
93
+ def upit():
94
+ if config.web.server == "gae": # switches back to -d mode [ultra deprecated]
95
+ log("uploading files")
96
+ subprocess.call('appcfg.py update . --no_precompilation --noauth_local_webserver', shell=True)
97
+ setmode("dynamic")
98
+ return
99
+ upop = input("upload with git or svn or cancel ([G]it/[s]vn/[c]ancel)? ").lower()[:1]
100
+ if upop == "c":
101
+ return
102
+ if upop == "s":
103
+ cmd('svn commit html-production/ -m"prod"')
104
+ else: # default git
105
+ cmd("git add html-production/")
106
+ cmd('git commit -m "prod"')
107
+ cmd("git push")
108
+
109
+ def run():
110
+ from optparse import OptionParser
111
+ parser = OptionParser("ctdeploy [-d|s|p] [-un] [--js_path=PATH]")
112
+ parser.add_option("-d", "--dynamic", action="store_true", dest="dynamic",
113
+ default=False, help="switch to dynamic (development) mode")
114
+ parser.add_option("-s", "--static", action="store_true", dest="static",
115
+ default=False, help="switch to static (debug) mode")
116
+ parser.add_option("-p", "--production", action="store_true", dest="production",
117
+ default=False, help="switch to production (garbled) mode")
118
+ parser.add_option("-u", "--upload", action="store_true", dest="upload", default=False,
119
+ help="uploads project in specified mode and then (if gae) switches back to dynamic (development) mode")
120
+ parser.add_option("-n", "--no_build", action="store_true",
121
+ dest="no_build", default=False, help="skip compilation step")
122
+ parser.add_option("-j", "--js_path", dest="js_path", default=config.js.path,
123
+ help="set javascript path (default=%s)"%(config.js.path,))
124
+ parser.add_option("-v", "--vpush", action="store_true", dest="vpush",
125
+ default=False, help="push a new version of cantools [ct dev only]")
126
+ options, args = parser.parse_args()
127
+
128
+ if options.vpush:
129
+ vpush("cantools", "ct", __version__, buildox)
130
+ else:
131
+ mode = options.dynamic and "dynamic" or options.static and "static" or options.production and "production"
132
+ if not mode:
133
+ error("no mode specified")
134
+
135
+ # 0) set js path
136
+ if options.js_path != config.js.path:
137
+ log("setting js path to: %s"%(options.js_path,))
138
+ config.js.update("path", options.js_path)
139
+
140
+ # 1) build static/production files
141
+ if not options.no_build:
142
+ build_all()
143
+
144
+ # 2) switch to specified mode
145
+ setmode(mode)
146
+
147
+ # 3) if -u, upload project
148
+ if options.upload:
149
+ upit()
150
+
151
+ log("goodbye")
152
+
153
+ if __name__ == "__main__":
154
+ run()