summaryrefslogtreecommitdiff
path: root/scripts/builder
authorGiulio Cesare Solaroli <giulio.cesare@solaroli.it>2011-10-05 22:54:04 (UTC)
committer Giulio Cesare Solaroli <giulio.cesare@solaroli.it>2011-10-05 22:54:04 (UTC)
commit13ebf1b1987a1566d081ff1ba89b4dca197b7d2e (patch) (unidiff)
treedcd7121febab3bd2c1436d2f55a5a2ac07ad2e83 /scripts/builder
parentbbd415769410aac765f889e74a28992bc8483f94 (diff)
parent2a98e81b954ab84efc8d3f4e1d837bf190f77d7d (diff)
downloadclipperz-13ebf1b1987a1566d081ff1ba89b4dca197b7d2e.zip
clipperz-13ebf1b1987a1566d081ff1ba89b4dca197b7d2e.tar.gz
clipperz-13ebf1b1987a1566d081ff1ba89b4dca197b7d2e.tar.bz2
Merge pull request #7 from themiurgo/master
Fixes shebang for python builder scripts
Diffstat (limited to 'scripts/builder') (more/less context) (ignore whitespace changes)
-rw-r--r--scripts/builder/backendBuilder.py2
-rw-r--r--scripts/builder/frontendBuilder.py2
-rwxr-xr-xscripts/builder/main.py4
-rw-r--r--scripts/builder/phpBuilder.py2
-rw-r--r--scripts/builder/pythonBuilder.py2
5 files changed, 6 insertions, 6 deletions
diff --git a/scripts/builder/backendBuilder.py b/scripts/builder/backendBuilder.py
index f5dc7b2..16dbe2f 100644
--- a/scripts/builder/backendBuilder.py
+++ b/scripts/builder/backendBuilder.py
@@ -1,89 +1,89 @@
1#!/usr/bin/python 1#!/usr/bin/env python
2# -*- coding: UTF-8 -*- 2# -*- coding: UTF-8 -*-
3 3
4import sys, os, json 4import sys, os, json
5import shutil 5import shutil
6import main 6import main
7import hashlib 7import hashlib
8 8
9class BackendBuilder: 9class BackendBuilder:
10 10
11 def __init__ (self, projectTargetDir, frontends, versions, settings): 11 def __init__ (self, projectTargetDir, frontends, versions, settings):
12 self.projectTargetDir = projectTargetDir 12 self.projectTargetDir = projectTargetDir
13 self.frontends = frontends 13 self.frontends = frontends
14 self.versions = versions 14 self.versions = versions
15 self.settings = settings 15 self.settings = settings
16 16
17 def name (self): 17 def name (self):
18 raise NotImplementedError() 18 raise NotImplementedError()
19 19
20 def relativePath (self): 20 def relativePath (self):
21 raise NotImplementedError() 21 raise NotImplementedError()
22 22
23 def compileCode (self): 23 def compileCode (self):
24 pass 24 pass
25 25
26 def copyCompiledCodeToTargetDir (self): 26 def copyCompiledCodeToTargetDir (self):
27 src = self.sourceFolder() 27 src = self.sourceFolder()
28 dst = self.targetFolder() 28 dst = self.targetFolder()
29 main.createFolder(os.path.dirname(dst)) 29 main.createFolder(os.path.dirname(dst))
30 shutil.copytree(src, dst) 30 shutil.copytree(src, dst)
31 31
32 def sourceFolder (self): 32 def sourceFolder (self):
33 return main.projectBaseDir() + '/backend/' + self.relativePath() + '/src' 33 return main.projectBaseDir() + '/backend/' + self.relativePath() + '/src'
34 34
35 35
36 def targetFolder (self): 36 def targetFolder (self):
37 return self.projectTargetDir + self.relativePath() 37 return self.projectTargetDir + self.relativePath()
38 38
39 def createTargetFolder (self): 39 def createTargetFolder (self):
40 main.createFolder(self.targetFolder()) 40 main.createFolder(self.targetFolder())
41 41
42 42
43 #def copyFrontendResources (self, frontend): 43 #def copyFrontendResources (self, frontend):
44 # print "copying resources for frontend: " + frontend 44 # print "copying resources for frontend: " + frontend
45 # print "SETTINGS: " + str(self.settings) 45 # print "SETTINGS: " + str(self.settings)
46 46
47 47
48 def writeToTargetFolder (self, filename, content): 48 def writeToTargetFolder (self, filename, content):
49 file = open(self.targetFolder() + '/' + filename, 'w') 49 file = open(self.targetFolder() + '/' + filename, 'w')
50 file.write(content.encode('utf-8')) 50 file.write(content.encode('utf-8'))
51 file.close() 51 file.close()
52 52
53 53
54 def configureIndexContent (self, indexContent): 54 def configureIndexContent (self, indexContent):
55 result = indexContent 55 result = indexContent
56 result = result.replace( '@request.path@', self.settings['request.path'] ) 56 result = result.replace( '@request.path@', self.settings['request.path'] )
57 result = result.replace( '@should.pay.toll@', self.settings['should.pay.toll'] ) 57 result = result.replace( '@should.pay.toll@', self.settings['should.pay.toll'] )
58 58
59 return result 59 return result
60 60
61 61
62 def logChecksums (self, content, message): 62 def logChecksums (self, content, message):
63 md5Digest = hashlib.md5(content.encode('utf-8')).hexdigest() 63 md5Digest = hashlib.md5(content.encode('utf-8')).hexdigest()
64 shaDigest = hashlib.sha1(content.encode('utf-8')).hexdigest() 64 shaDigest = hashlib.sha1(content.encode('utf-8')).hexdigest()
65 sha256Digest= hashlib.sha256(content.encode('utf-8')).hexdigest() 65 sha256Digest= hashlib.sha256(content.encode('utf-8')).hexdigest()
66 print message + ": " + md5Digest + " (md5)" 66 print message + ": " + md5Digest + " (md5)"
67 print message + ": " + shaDigest + " (sha1)" 67 print message + ": " + shaDigest + " (sha1)"
68 print message + ": " + sha256Digest + " (sha256)" 68 print message + ": " + sha256Digest + " (sha256)"
69 69
70 70
71 71
72 def run (self): 72 def run (self):
73 print self.name() + " - RUN" 73 print self.name() + " - RUN"
74 74
75 self.compileCode() 75 self.compileCode()
76 self.copyCompiledCodeToTargetDir() 76 self.copyCompiledCodeToTargetDir()
77 77
78 for frontend in self.frontends: 78 for frontend in self.frontends:
79 frontendPath = frontend.module + '/' 79 frontendPath = frontend.module + '/'
80 if 'debug' in self.versions: 80 if 'debug' in self.versions:
81 frontend.copyResourcesToTargetFolder(self.targetFolder()) 81 frontend.copyResourcesToTargetFolder(self.targetFolder())
82 #self.writeToTargetFolder(frontendPath + 'index_debug.html', self.configureIndexContent(frontend.assembleDebugVersion())) 82 #self.writeToTargetFolder(frontendPath + 'index_debug.html', self.configureIndexContent(frontend.assembleDebugVersion()))
83 self.writeToTargetFolder(frontendPath + 'index_debug.html', self.configureIndexContent(frontend.assemble(assemblyMode='DEBUG', versionType='DEBUG'))) 83 self.writeToTargetFolder(frontendPath + 'index_debug.html', self.configureIndexContent(frontend.assemble(assemblyMode='DEBUG', versionType='DEBUG')))
84 84
85 if 'install' in self.versions: 85 if 'install' in self.versions:
86 index = self.configureIndexContent(frontend.assemble()) 86 index = self.configureIndexContent(frontend.assemble())
87 self.writeToTargetFolder(frontendPath + 'index.html', index) 87 self.writeToTargetFolder(frontendPath + 'index.html', index)
88 self.logChecksums(index, "[" + self.name() + " - " + frontend.module + "] index.html checksum") 88 self.logChecksums(index, "[" + self.name() + " - " + frontend.module + "] index.html checksum")
89 89
diff --git a/scripts/builder/frontendBuilder.py b/scripts/builder/frontendBuilder.py
index b796438..55054ee 100644
--- a/scripts/builder/frontendBuilder.py
+++ b/scripts/builder/frontendBuilder.py
@@ -1,97 +1,97 @@
1#!/usr/bin/python 1#!/usr/bin/env python
2# -*- coding: UTF-8 -*- 2# -*- coding: UTF-8 -*-
3 3
4import sys, os, re 4import sys, os, re
5import cssmin 5import cssmin
6import jsmin 6import jsmin
7import codecs 7import codecs
8import shutil 8import shutil
9import StringIO 9import StringIO
10import urllib 10import urllib
11 11
12#from mercurial import ui, hg 12#from mercurial import ui, hg
13#from mercurial.node import hex 13#from mercurial.node import hex
14from dulwich.repo import Repo 14from dulwich.repo import Repo
15 15
16import main 16import main
17 17
18 18
19 19
20class FrontendBuilder: 20class FrontendBuilder:
21 21
22 def __init__ (self, frontend, settings): 22 def __init__ (self, frontend, settings):
23 if '.' in frontend: 23 if '.' in frontend:
24 moduleComponents = frontend.split('.') 24 moduleComponents = frontend.split('.')
25 self.module = moduleComponents[0] 25 self.module = moduleComponents[0]
26 self.submodule = moduleComponents[1] 26 self.submodule = moduleComponents[1]
27 else: 27 else:
28 self.module = frontend 28 self.module = frontend
29 self.submodule = frontend 29 self.submodule = frontend
30 30
31 self.settings = settings 31 self.settings = settings
32 self.projectDir = main.projectBaseDir() 32 self.projectDir = main.projectBaseDir()
33 self.processedFiles = {} 33 self.processedFiles = {}
34 34
35 35
36 def mercurialRepositoryVersion (self): 36 def mercurialRepositoryVersion (self):
37 repo = hg.repository(ui.ui(), self.projectDir) 37 repo = hg.repository(ui.ui(), self.projectDir)
38 context = repo['tip'] 38 context = repo['tip']
39 result = str(context) 39 result = str(context)
40 40
41 return result 41 return result
42 42
43 43
44 def gitRepositoryVersion (self): 44 def gitRepositoryVersion (self):
45 repo = Repo(self.projectDir) 45 repo = Repo(self.projectDir)
46 #if repo.is_dirty(): 46 #if repo.is_dirty():
47 #print "WARNING: build run with dirty repository" 47 #print "WARNING: build run with dirty repository"
48 result = repo.refs['HEAD'] 48 result = repo.refs['HEAD']
49 49
50 return result 50 return result
51 51
52 52
53 53
54 def repositoryVersion (self): 54 def repositoryVersion (self):
55 cacheKey = 'repositoryVersion' 55 cacheKey = 'repositoryVersion'
56 if not self.processedFiles.has_key(cacheKey): 56 if not self.processedFiles.has_key(cacheKey):
57 #result = self.mercurialRepositoryVersion() 57 #result = self.mercurialRepositoryVersion()
58 result = self.gitRepositoryVersion() 58 result = self.gitRepositoryVersion()
59 self.processedFiles[cacheKey] = result 59 self.processedFiles[cacheKey] = result
60 else: 60 else:
61 result = self.processedFiles[cacheKey] 61 result = self.processedFiles[cacheKey]
62 62
63 return result 63 return result
64 64
65 65
66 #def relativePath (self): 66 #def relativePath (self):
67 #return self.module 67 #return self.module
68 # 68 #
69 69
70 def log (self, message): 70 def log (self, message):
71 print "frontend [" + self.module + "]: " + message 71 print "frontend [" + self.module + "]: " + message
72 72
73 73
74 def absolutePathForSourceFile (self, folder, basePath, file): 74 def absolutePathForSourceFile (self, folder, basePath, file):
75 return folder + '/frontend/' + self.module + '/' + basePath + '/' + file 75 return folder + '/frontend/' + self.module + '/' + basePath + '/' + file
76 76
77 77
78 def absolutePathForTargetFile (self, folder, basePath, file): 78 def absolutePathForTargetFile (self, folder, basePath, file):
79 return folder + '/' + self.module + '/' + basePath + '/' + file 79 return folder + '/' + self.module + '/' + basePath + '/' + file
80 80
81 def filterFiles (self, files): 81 def filterFiles (self, files):
82 result = [] 82 result = []
83 83
84 for file in files: 84 for file in files:
85 if file.startswith('--'): 85 if file.startswith('--'):
86 pass 86 pass
87 else: 87 else:
88 result.append(file) 88 result.append(file)
89 89
90 return result 90 return result
91 91
92 92
93 def copyResources (self, sourceFolder, destinationFolder, fileType): 93 def copyResources (self, sourceFolder, destinationFolder, fileType):
94 for file in self.filterFiles(self.settings[fileType]): 94 for file in self.filterFiles(self.settings[fileType]):
95 src = self.absolutePathForSourceFile(sourceFolder, fileType, file) 95 src = self.absolutePathForSourceFile(sourceFolder, fileType, file)
96 dst = self.absolutePathForTargetFile(destinationFolder, fileType, file) 96 dst = self.absolutePathForTargetFile(destinationFolder, fileType, file)
97 main.createFolder(os.path.dirname(dst)) 97 main.createFolder(os.path.dirname(dst))
diff --git a/scripts/builder/main.py b/scripts/builder/main.py
index ba0c72a..94f738f 100755
--- a/scripts/builder/main.py
+++ b/scripts/builder/main.py
@@ -1,166 +1,166 @@
1#!/usr/bin/python 1#!/usr/bin/env python
2# -*- coding: UTF-8 -*- 2# -*- coding: UTF-8 -*-
3 3
4import sys, os, json 4import sys, os, json
5import shutil 5import shutil
6import pprint 6import pprint
7import frontendBuilder 7import frontendBuilder
8import codecs 8import codecs
9import itertools 9import itertools
10 10
11from collections import deque 11from collections import deque
12from phpBuilder import PhpBuilder 12from phpBuilder import PhpBuilder
13from pythonBuilder import PythonBuilder 13from pythonBuilder import PythonBuilder
14 14
15pp = pprint.PrettyPrinter(indent=4, depth=4) 15pp = pprint.PrettyPrinter(indent=4, depth=4)
16 16
17#-------------------------------------------------------------------- 17#--------------------------------------------------------------------
18 18
19def scriptDir (): 19def scriptDir ():
20 return os.path.dirname(sys.argv[0]) 20 return os.path.dirname(sys.argv[0])
21 21
22def projectBaseDir (): 22def projectBaseDir ():
23 return os.path.abspath(scriptDir() + '/../..') 23 return os.path.abspath(scriptDir() + '/../..')
24 24
25def projectTargetDir(): 25def projectTargetDir():
26 return projectBaseDir() + '/target/' 26 return projectBaseDir() + '/target/'
27 27
28#-------------------------------------------------------------------- 28#--------------------------------------------------------------------
29 29
30def createFolder (path): 30def createFolder (path):
31 if not os.path.exists(path): 31 if not os.path.exists(path):
32 os.makedirs(path) 32 os.makedirs(path)
33 33
34#-------------------------------------------------------------------- 34#--------------------------------------------------------------------
35 35
36def loadSettings (component, module): 36def loadSettings (component, module):
37 print "MODULE: " + module 37 print "MODULE: " + module
38 38
39 if '.' in module: 39 if '.' in module:
40 moduleComponents = module.split('.') 40 moduleComponents = module.split('.')
41 module = moduleComponents[0] 41 module = moduleComponents[0]
42 submodule = moduleComponents[1] 42 submodule = moduleComponents[1]
43 else: 43 else:
44 submodule = module 44 submodule = module
45 45
46 settings = codecs.open(projectBaseDir() + '/' + component + '/' + module + '/properties/' + submodule + '.properties.json', 'r', 'utf-8') 46 settings = codecs.open(projectBaseDir() + '/' + component + '/' + module + '/properties/' + submodule + '.properties.json', 'r', 'utf-8')
47 result = json.load(settings) 47 result = json.load(settings)
48 settings.close 48 settings.close
49 49
50 return result 50 return result
51 51
52#==================================================================== 52#====================================================================
53# 53#
54# def assembleFrontend (frontend, versions): 54# def assembleFrontend (frontend, versions):
55 # result = {} 55 # result = {}
56 # settings = loadSettings('frontend', frontend) 56 # settings = loadSettings('frontend', frontend)
57 # builder = frontendBuilder.FrontendBuilder(frontend, settings, projectBaseDir()) 57 # builder = frontendBuilder.FrontendBuilder(frontend, settings, projectBaseDir())
58 # 58 #
59 # for version in versions: 59 # for version in versions:
60 # if version == 'install': 60 # if version == 'install':
61 # result[version] = builder.assembleInstallVersion() 61 # result[version] = builder.assembleInstallVersion()
62 # elif version == 'debug': 62 # elif version == 'debug':
63 # result[version] = builder.assembleDebugVersion() 63 # result[version] = builder.assembleDebugVersion()
64 # else: 64 # else:
65 # raise Exception('unrecognized version: ' + version) 65 # raise Exception('unrecognized version: ' + version)
66 # 66 #
67 # return result 67 # return result
68# 68#
69#==================================================================== 69#====================================================================
70 70
71def assembleBackend (backend, frontends, versions): 71def assembleBackend (backend, frontends, versions):
72 settings = loadSettings('backend', backend) 72 settings = loadSettings('backend', backend)
73 73
74 if backend == 'php': 74 if backend == 'php':
75 backendBuilder = PhpBuilder(projectTargetDir(), frontends, versions, settings) 75 backendBuilder = PhpBuilder(projectTargetDir(), frontends, versions, settings)
76 elif backend == 'python': 76 elif backend == 'python':
77 backendBuilder = PythonBuilder(projectTargetDir(), frontends, versions, settings) 77 backendBuilder = PythonBuilder(projectTargetDir(), frontends, versions, settings)
78 #elif backend == 'java': 78 #elif backend == 'java':
79 #buildJavaBackend (frontends, versions, settings) 79 #buildJavaBackend (frontends, versions, settings)
80 else: 80 else:
81 raise Exception('unrecognized backend: ' + backend) 81 raise Exception('unrecognized backend: ' + backend)
82 82
83 backendBuilder.run() 83 backendBuilder.run()
84 84
85#==================================================================== 85#====================================================================
86 86
87def build (settings): 87def build (settings):
88 frontends = [] 88 frontends = []
89 89
90 for frontend in settings['frontends']: 90 for frontend in settings['frontends']:
91 frontends.append(frontendBuilder.FrontendBuilder(frontend, loadSettings('frontend', frontend))) 91 frontends.append(frontendBuilder.FrontendBuilder(frontend, loadSettings('frontend', frontend)))
92 92
93 for backend in settings['backends']: 93 for backend in settings['backends']:
94 assembleBackend(backend, frontends, settings['versions']) 94 assembleBackend(backend, frontends, settings['versions'])
95 95
96#-------------------------------------------------------------------- 96#--------------------------------------------------------------------
97 97
98def clean (): 98def clean ():
99 print "cleaning up …" 99 print "cleaning up …"
100 if os.path.exists(projectTargetDir()): 100 if os.path.exists(projectTargetDir()):
101 shutil.rmtree(projectTargetDir()) 101 shutil.rmtree(projectTargetDir())
102 102
103#-------------------------------------------------------------------- 103#--------------------------------------------------------------------
104 104
105def usage (message): 105def usage (message):
106 if message != None: 106 if message != None:
107 print "ERROR: " + message 107 print "ERROR: " + message
108 108
109 print 109 print
110 print "build.py clean" 110 print "build.py clean"
111 print "build.py clean install" 111 print "build.py clean install"
112 print "build.py install --ALL" 112 print "build.py install --ALL"
113 print "build.py install debug --ALL" 113 print "build.py install debug --ALL"
114 print "build.py clean install debug --ALL" 114 print "build.py clean install debug --ALL"
115 print "build.ph install, debug --backends php java --frontends beta gamma" 115 print "build.ph install, debug --backends php java --frontends beta gamma"
116 print "build.ph install, debug --backends php java --frontends beta gamma gamma.mobile" 116 print "build.ph install, debug --backends php java --frontends beta gamma gamma.mobile"
117 exit(1) 117 exit(1)
118 118
119#-------------------------------------------------------------------- 119#--------------------------------------------------------------------
120 120
121def main (): 121def main ():
122 settings = {} 122 settings = {}
123 parameters = list(itertools.islice(sys.argv, 1, None)) 123 parameters = list(itertools.islice(sys.argv, 1, None))
124 124
125 shouldClean = len(filter(lambda x: x == 'clean', parameters)) > 0 125 shouldClean = len(filter(lambda x: x == 'clean', parameters)) > 0
126 if (shouldClean): 126 if (shouldClean):
127 clean () 127 clean ()
128 128
129 parameters = filter(lambda x: x != 'clean', parameters) 129 parameters = filter(lambda x: x != 'clean', parameters)
130 versions = list(itertools.takewhile(lambda x: not x.startswith('--'), parameters)) 130 versions = list(itertools.takewhile(lambda x: not x.startswith('--'), parameters))
131 settings['versions'] = versions; #['debug', 'install'] 131 settings['versions'] = versions; #['debug', 'install']
132 parameters = deque(itertools.dropwhile(lambda x: not x.startswith('--'), parameters)) 132 parameters = deque(itertools.dropwhile(lambda x: not x.startswith('--'), parameters))
133 133
134 if len(parameters) > 0: 134 if len(parameters) > 0:
135 parameter = parameters.popleft() 135 parameter = parameters.popleft()
136 if parameter == "--ALL": 136 if parameter == "--ALL":
137 settings['frontends'] = ['beta', 'gamma', 'mobile'] 137 settings['frontends'] = ['beta', 'gamma', 'mobile']
138 settings['backends'] = ['php', 'python', 'java'] 138 settings['backends'] = ['php', 'python', 'java']
139 else: 139 else:
140 while parameter != None: 140 while parameter != None:
141 values = list(itertools.takewhile(lambda x: not x.startswith('--'), parameters)) 141 values = list(itertools.takewhile(lambda x: not x.startswith('--'), parameters))
142 142
143 if parameter == "--backends": 143 if parameter == "--backends":
144 settings['backends'] = values 144 settings['backends'] = values
145 elif parameter == "--frontends": 145 elif parameter == "--frontends":
146 settings['frontends'] = values 146 settings['frontends'] = values
147 147
148 parameters = deque(itertools.dropwhile(lambda x: not x.startswith('--'), parameters)) 148 parameters = deque(itertools.dropwhile(lambda x: not x.startswith('--'), parameters))
149 if parameters: 149 if parameters:
150 parameter = parameters.popleft() 150 parameter = parameters.popleft()
151 else: 151 else:
152 parameter = None 152 parameter = None
153 153
154 if (not settings.has_key('versions')): 154 if (not settings.has_key('versions')):
155 usage("missing 'versions'") 155 usage("missing 'versions'")
156 if (not settings.has_key('frontends')): 156 if (not settings.has_key('frontends')):
157 usage("missing 'frontends'") 157 usage("missing 'frontends'")
158 if (not settings.has_key('backends')): 158 if (not settings.has_key('backends')):
159 usage("missing 'backends'") 159 usage("missing 'backends'")
160 160
161 build (settings) 161 build (settings)
162 162
163 163
164 164
165if __name__ == "__main__": 165if __name__ == "__main__":
166 main() \ No newline at end of file 166 main()
diff --git a/scripts/builder/phpBuilder.py b/scripts/builder/phpBuilder.py
index 9512192..cb4661d 100644
--- a/scripts/builder/phpBuilder.py
+++ b/scripts/builder/phpBuilder.py
@@ -1,14 +1,14 @@
1#!/usr/bin/python 1#!/usr/bin/env python
2# -*- coding: UTF-8 -*- 2# -*- coding: UTF-8 -*-
3 3
4from backendBuilder import BackendBuilder 4from backendBuilder import BackendBuilder
5 5
6class PhpBuilder(BackendBuilder): 6class PhpBuilder(BackendBuilder):
7 7
8 def name(self): 8 def name(self):
9 return "PHP builder" 9 return "PHP builder"
10 10
11 def relativePath(self): 11 def relativePath(self):
12 return 'php' 12 return 'php'
13 13
14 14
diff --git a/scripts/builder/pythonBuilder.py b/scripts/builder/pythonBuilder.py
index 44c62a8..a84598d 100644
--- a/scripts/builder/pythonBuilder.py
+++ b/scripts/builder/pythonBuilder.py
@@ -1,14 +1,14 @@
1#!/usr/bin/python 1#!/usr/bin/env python
2# -*- coding: UTF-8 -*- 2# -*- coding: UTF-8 -*-
3 3
4from backendBuilder import BackendBuilder 4from backendBuilder import BackendBuilder
5 5
6class PythonBuilder(BackendBuilder): 6class PythonBuilder(BackendBuilder):
7 7
8 def name(self): 8 def name(self):
9 return "Python builder" 9 return "Python builder"
10 10
11 def relativePath(self): 11 def relativePath(self):
12 return 'python' 12 return 'python'
13 13
14 14