Pārlūkot izejas kodu

Update instances (new loader and utils)

Yann Weber 8 gadus atpakaļ
vecāks
revīzija
d4c346262a

+ 9
- 5
Lodel/settings_format.py Parādīt failu

@@ -4,17 +4,20 @@
4 4
 ## @brief List mandatory configurations keys
5 5
 MANDATORY = [
6 6
     'debug',
7
-    'debug_sql',
7
+
8 8
     'sitename',
9
-    'lodel2_lib_path',
10 9
     'em_file',
11
-    'dynamic_code_file',
12
-    'acl_dyn_api',
10
+
11
+    'acl_bypass',
12
+
13
+    'debug_sql',
13 14
     'ds_package',
14 15
     'datasource',
15 16
     'mh_classname',
16 17
     'migration_options',
17
-    'base_path'
18
+
19
+    'base_path',
20
+    'lodel2_lib_path',
18 21
 ]
19 22
 
20 23
 ## @brief List allowed (but not mandatory) configurations keys
@@ -23,3 +26,4 @@ ALLOWED = [
23 26
     'em_graph_format',
24 27
     'templates_base_dir'
25 28
 ]
29
+

+ 8
- 3
install/Makefile Parādīt failu

@@ -1,8 +1,11 @@
1 1
 all: refreshdyn dbinit dirinit
2 2
 
3
-refreshdyn: distclean
3
+refreshdyn: cleandyn dyncode
4 4
 	python -c "import utils; utils.refreshdyn()"
5 5
 
6
+dyncode:
7
+	mkdir dyncode; touch dyncode/__init__.py
8
+
6 9
 dbinit:
7 10
 	python -c "import utils; utils.db_init()"
8 11
 
@@ -14,11 +17,13 @@ emgraph:
14 17
 
15 18
 .PHONY: clean cleanpycache cleanpyc refreshdyn distclean
16 19
 
17
-distclean: clean
18
-	-@rm -vf dynleapi.py api.py
20
+distclean: clean cleandyn
19 21
 
20 22
 clean: cleanpycache
21 23
 
24
+cleandyn: cleanpycache
25
+	-@rm -vf dyncode/internal_api.py dyncode/acl_api.py dyncode/__init__.py ; rmdir dyncode
26
+
22 27
 cleanpyc:
23 28
 	-@rm -vf *.pyc
24 29
 

+ 67
- 0
install/README.txt Parādīt failu

@@ -1,6 +1,8 @@
1 1
 Common operations :
2 2
 ===================
3 3
 
4
+Configuration file : instance_settings.py
5
+
4 6
 Refresh leapi dynamic code (when the Editorial Model is updated) :
5 7
 	make refreshdyn
6 8
 
@@ -9,3 +11,68 @@ Update or init the database :
9 11
 
10 12
 To run an interactive python interpreter in the instance environnment run :
11 13
 	python loader.py
14
+
15
+Instance documentation
16
+======================
17
+
18
+loader.py
19
+---------
20
+
21
+This file expose all classes needed for a Lodel2 user :
22
+- All the dynamic code classes
23
+- leapidatasource
24
+- migrationhandler
25
+
26
+All those classes are imported/exposed given options. LeapiDataSource and the migration handler depends on the choosen datasource, and the dynamic code classes can be wrapped or not by ACL (the acl_bypass configuration variable)
27
+
28
+utils.py
29
+--------
30
+
31
+This file contains usefull utilities to manage an instance and import & expose the Lodel.settings.Settings class when imported.
32
+
33
+THIS FILE HAS TO BE IMPORTED IN ORDER TO BE ABLE TO ACCESS LODEL2 SETTINGS.
34
+
35
+### utility functions
36
+
37
+- utils.dyn_module_fullname  returns the module fullname for leapi or aclapi (Constant values hardcoded in the loader to be able to use from Foo import * syntax)
38
+- utils.dyn_code_filename : return the python code filename for leapi or aclapi (Constant values)
39
+- utils.refreshdyn : refresh dynamic code
40
+- utils.dbinit : Run full db migration
41
+- utils.em_graph : generate graphviz graph representing the editorial model
42
+- utils.dir_init : ???
43
+
44
+instance_settings.py
45
+--------------------
46
+
47
+Instance settings file
48
+
49
+dyncode directory
50
+-----------------
51
+
52
+Contains dynamically generated python code
53
+
54
+### dyncode/internal_api.py
55
+
56
+leapi dynamically generated code. Import this to be able to use the API without ACL
57
+
58
+### dyncode/acl_api.py
59
+
60
+ACL wrapper for leapi classes. Public access HAVE TO use the classes defined in this file.
61
+
62
+Makefile
63
+--------
64
+
65
+Defined target :
66
+- all : refresh dynamic code, init the database and init the directory
67
+- emgraph : generated graphviz graph representing the editorial model
68
+- refreshdyn : refresh dynamic code
69
+- dbinit : init the DB
70
+- dirinit : ???
71
+- clean : clean python *.pyc files and __pycache__ directories
72
+- distclean : call clean target and delete dynamically generated code
73
+
74
+em.json
75
+-------
76
+
77
+Contains the default EM for an instance
78
+

+ 0
- 171
install/dynleapi.py Parādīt failu

@@ -1,171 +0,0 @@
1
-## @author LeFactory
2
-
3
-import EditorialModel
4
-from EditorialModel import fieldtypes
5
-from EditorialModel.fieldtypes import naturerelation, char, integer, datetime, pk
6
-
7
-import leapi
8
-import leapi.lecrud
9
-import leapi.leobject
10
-import leapi.lerelation
11
-from leapi.leclass import _LeClass
12
-from leapi.letype import _LeType
13
-
14
-import DataSource.MySQL.leapidatasource
15
-
16
-
17
-## @brief _LeCrud concret class
18
-# @see leapi.lecrud._LeCrud
19
-class LeCrud(leapi.lecrud._LeCrud):
20
-    _datasource = DataSource.MySQL.leapidatasource.LeDataSourceSQL(**{})
21
-    _uid_fieldtype = None
22
-
23
-## @brief _LeObject concret class
24
-# @see leapi.leobject._LeObject
25
-class LeObject(LeCrud, leapi.leobject._LeObject):
26
-    _me_uid = {1: 'Textes', 2: 'Personnes', 19: 'Numero', 5: 'Article', 6: 'Personne', 13: 'Publication', 14: 'Rubrique'}
27
-    _uid_fieldtype = { 'lodel_id': EditorialModel.fieldtypes.pk.EmFieldType(**{'internal': 'automatic'}) }
28
-    _leo_fieldtypes = {
29
-	'creation_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'now_on_create': True, 'internal': 'automatic'}),
30
-	'string': EditorialModel.fieldtypes.char.EmFieldType(**{'max_length': 128, 'internal': 'automatic'}),
31
-	'modification_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'now_on_update': True, 'now_on_create': True, 'internal': 'automatic'}),
32
-	'type_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'internal': 'automatic'}),
33
-	'class_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'internal': 'automatic'})
34
-	}
35
-
36
-## @brief _LeRelation concret class
37
-# @see leapi.lerelation._LeRelation
38
-class LeRelation(LeCrud, leapi.lerelation._LeRelation):
39
-    _uid_fieldtype = { 'id_relation': EditorialModel.fieldtypes.pk.EmFieldType(**{'internal': 'automatic'}) }
40
-    _rel_fieldtypes = {
41
-	'rank': EditorialModel.fieldtypes.integer.EmFieldType(**{'internal': 'automatic'}),
42
-	'nature': EditorialModel.fieldtypes.naturerelation.EmFieldType(**{}),
43
-	'depth': EditorialModel.fieldtypes.integer.EmFieldType(**{'internal': 'automatic'})
44
-	}
45
-    _rel_attr_fieldtypes = dict()
46
-
47
-class LeHierarch(LeRelation, leapi.lerelation._LeHierarch):
48
-    _rel_attr_fieldtypes = dict()
49
-
50
-class LeRel2Type(LeRelation, leapi.lerelation._LeRel2Type):
51
-    pass
52
-
53
-class LeClass(LeObject, _LeClass):
54
-    pass
55
-
56
-class LeType(LeClass, _LeType):
57
-    pass
58
-
59
-## @brief EmClass Textes LeClass child class
60
-# @see leapi.leclass.LeClass
61
-class Textes(LeClass, LeObject):
62
-    _class_id = 1
63
-
64
-
65
-## @brief EmClass Personnes LeClass child class
66
-# @see leapi.leclass.LeClass
67
-class Personnes(LeClass, LeObject):
68
-    _class_id = 2
69
-
70
-
71
-## @brief EmClass Publication LeClass child class
72
-# @see leapi.leclass.LeClass
73
-class Publication(LeClass, LeObject):
74
-    _class_id = 13
75
-
76
-
77
-## @brief EmType Article LeType child class
78
-# @see leobject::letype::LeType
79
-class Article(LeType, Textes):
80
-    _type_id = 5
81
-
82
-
83
-## @brief EmType Personne LeType child class
84
-# @see leobject::letype::LeType
85
-class Personne(LeType, Personnes):
86
-    _type_id = 6
87
-
88
-
89
-## @brief EmType Rubrique LeType child class
90
-# @see leobject::letype::LeType
91
-class Rubrique(LeType, Publication):
92
-    _type_id = 14
93
-
94
-
95
-## @brief EmType Numero LeType child class
96
-# @see leobject::letype::LeType
97
-class Numero(LeType, Publication):
98
-    _type_id = 19
99
-
100
-
101
-class Rel_textes2personne(LeRel2Type):
102
-    _rel_attr_fieldtypes = {
103
-    'adresse': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False})
104
-}
105
-
106
-
107
-#Initialisation of Textes class attributes
108
-Textes._fieldtypes = {
109
-    'modification_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'nullable': False, 'uniq': False, 'now_on_update': True, 'now_on_create': True, 'internal': 'automatic'}),
110
-    'soustitre': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
111
-    'string': EditorialModel.fieldtypes.char.EmFieldType(**{'nullable': True, 'uniq': False, 'max_length': 128, 'internal': 'automatic'}),
112
-    'titre': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
113
-    'bleu': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
114
-    'lodel_id': EditorialModel.fieldtypes.pk.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
115
-    'type_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
116
-    'class_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
117
-    'creation_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'uniq': False, 'nullable': False, 'now_on_create': True, 'internal': 'automatic'})
118
-}
119
-Textes._linked_types = [Personne]
120
-Textes._classtype = 'entity'
121
-
122
-#Initialisation of Personnes class attributes
123
-Personnes._fieldtypes = {
124
-    'nom': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
125
-    'age': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
126
-    'prenom': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
127
-    'string': EditorialModel.fieldtypes.char.EmFieldType(**{'nullable': True, 'uniq': False, 'max_length': 128, 'internal': 'automatic'}),
128
-    'lodel_id': EditorialModel.fieldtypes.pk.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
129
-    'modification_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'nullable': False, 'uniq': False, 'now_on_update': True, 'now_on_create': True, 'internal': 'automatic'}),
130
-    'type_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
131
-    'class_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
132
-    'creation_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'uniq': False, 'nullable': False, 'now_on_create': True, 'internal': 'automatic'})
133
-}
134
-Personnes._linked_types = []
135
-Personnes._classtype = 'person'
136
-
137
-#Initialisation of Publication class attributes
138
-Publication._fieldtypes = {
139
-    'modification_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'nullable': False, 'uniq': False, 'now_on_update': True, 'now_on_create': True, 'internal': 'automatic'}),
140
-    'creation_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'uniq': False, 'nullable': False, 'now_on_create': True, 'internal': 'automatic'}),
141
-    'string': EditorialModel.fieldtypes.char.EmFieldType(**{'nullable': True, 'uniq': False, 'max_length': 128, 'internal': 'automatic'}),
142
-    'lodel_id': EditorialModel.fieldtypes.pk.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
143
-    'titre': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
144
-    'type_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
145
-    'class_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'})
146
-}
147
-Publication._linked_types = []
148
-Publication._classtype = 'entity'
149
-
150
-#Initialisation of Article class attributes
151
-Article._fields = ['titre', 'class_id', 'soustitre', 'string', 'type_id', 'lodel_id', 'modification_date', 'creation_date']
152
-Article._superiors = {'parent': [Rubrique]}
153
-Article._leclass = Textes
154
-
155
-#Initialisation of Personne class attributes
156
-Personne._fields = ['nom', 'class_id', 'prenom', 'string', 'type_id', 'lodel_id', 'modification_date', 'creation_date']
157
-Personne._superiors = {}
158
-Personne._leclass = Personnes
159
-
160
-#Initialisation of Rubrique class attributes
161
-Rubrique._fields = ['titre', 'class_id', 'string', 'type_id', 'lodel_id', 'modification_date', 'creation_date']
162
-Rubrique._superiors = {'parent': [Rubrique, Numero]}
163
-Rubrique._leclass = Publication
164
-
165
-#Initialisation of Numero class attributes
166
-Numero._fields = ['titre', 'class_id', 'string', 'type_id', 'lodel_id', 'modification_date', 'creation_date']
167
-Numero._superiors = {}
168
-Numero._leclass = Publication
169
-
170
-## @brief Dict for getting LeClass and LeType child classes given an EM uid
171
-LeObject._me_uid = {1: Textes, 2: Personnes, 19: Numero, 5: Article, 6: Personne, 13: Publication, 14: Rubrique}

+ 2
- 2
install/instance_settings.py Parādīt failu

@@ -11,8 +11,6 @@ templates_base_dir = 'LODEL2_INSTANCE_TEMPLATES_BASE_DIR'
11 11
 debug = False
12 12
 
13 13
 em_file = 'em.json'
14
-dynamic_code_file = 'dynleapi.py' #Warning hardcoded module name in utils.py and loader.py
15
-acl_dyn_api = 'api.py' #Warning hardcoded module name in utils.py and loader.py
16 14
 
17 15
 ds_package = 'MySQL'
18 16
 mh_classname = 'MysqlMigrationHandler'
@@ -25,3 +23,5 @@ datasource = {
25 23
         'db': 'DBNAME'
26 24
     }
27 25
 }
26
+
27
+acl_bypass = False

+ 6
- 12
install/loader.py Parādīt failu

@@ -1,19 +1,13 @@
1
-import instance_settings
2
-import importlib
3
-import sys
4 1
 import os
5
-
6
-sys.path.append(instance_settings.lodel2_lib_path)
7
-
2
+import importlib
3
+from utils import dyn_code_filename
8 4
 from Lodel.settings import Settings
9 5
 
10
-# Settings initialisation
11
-Settings.load_module(instance_settings)
12
-globals()['Settings'] = Settings
13
-
14 6
 # Import dynamic code
15
-if os.path.isfile(Settings.dynamic_code_file):
16
-    from api import *
7
+if Settings.acl_bypass:
8
+    from dyncode.internal_api import *
9
+else:
10
+    from dyncode.acl_api import *
17 11
 
18 12
 # Import wanted datasource objects
19 13
 for db_modname in ['leapidatasource', 'migrationhandler']:

+ 41
- 7
install/utils.py Parādīt failu

@@ -1,30 +1,63 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3
-from loader import *
4 3
 import warnings
4
+import sys
5 5
 
6
+# Startup
7
+#
8
+# Loading instance config to fetch lodel2 lib path
9
+# @TODO migrate this portion of code in a bootstrap.py file
10
+import instance_settings
11
+sys.path.append(instance_settings.lodel2_lib_path)
12
+# Load Lodel2 settings module
13
+from Lodel.settings import Settings
14
+# Settings initialisation
15
+Settings.load_module(instance_settings)
16
+globals()['Settings'] = Settings
6 17
 
18
+
19
+## @brief fetch full module name of dynamic code
20
+# @warning hardcoded names are used in loader.py and in Makefile
21
+# @param name str : can be 'leapi' or 'aclapi'
22
+def dyn_module_fullname(name):
23
+    if name == 'leapi':
24
+        return 'dyncode.internal_api'
25
+    else:
26
+        return 'dyncode.acl_api'
27
+
28
+## @brief fetch dynamic codefile path
29
+# @warning hardcoded names are used in loader.py and in Makefile
30
+# @param name str : can be 'leapi' or 'aclapi'
31
+def dyn_code_filename(name):
32
+    if name == 'leapi':
33
+        return 'dyncode/internal_api.py'
34
+    else:
35
+        return 'dyncode/acl_api.py'
36
+
37
+## @brief Refresh dynamic code
7 38
 def refreshdyn():
8 39
     import sys
40
+    import os, os.path
9 41
     from EditorialModel.model import Model
10 42
     from leapi.lefactory import LeFactory
11 43
     from EditorialModel.backend.json_backend import EmBackendJson
12 44
     from DataSource.MySQL.leapidatasource import LeDataSourceSQL
13
-    OUTPUT = Settings.dynamic_code_file
45
+    from acl.factory import AclFactory
46
+
14 47
     EMJSON = Settings.em_file
15 48
     # Load editorial model
16 49
     em = Model(EmBackendJson(EMJSON))
17 50
     # Generate dynamic code
18
-    fact = LeFactory(OUTPUT)
51
+    fact = LeFactory(dyn_code_filename('leapi'))
19 52
     # Create the python file
20 53
     fact.create_pyfile(em, LeDataSourceSQL, {})
21 54
     # Generate wrapped API
22
-    from acl.factory import AclFactory
23
-    fact = AclFactory(Settings.acl_dyn_api)
24
-    fact.create_pyfile(em, 'dynleapi')
25
-
55
+    fact = AclFactory(dyn_code_filename('aclapi'))
56
+    fact.create_pyfile(em, dyn_module_fullname('leapi'))
26 57
 
27 58
 def db_init():
59
+    import loader
60
+    from loader import migrationhandler
28 61
     from EditorialModel.backend.json_backend import EmBackendJson
29 62
     from EditorialModel.model import Model
30 63
     mh = getattr(migrationhandler,Settings.mh_classname)()
@@ -33,6 +66,7 @@ def db_init():
33 66
 
34 67
 
35 68
 def em_graph(output_file = None, image_format = None):
69
+    import loader
36 70
     from EditorialModel.model import Model
37 71
     from EditorialModel.backend.json_backend import EmBackendJson
38 72
     from EditorialModel.backend.graphviz import EmBackendGraphviz

+ 13
- 0
lodel_init.sh Parādīt failu

@@ -1,5 +1,18 @@
1 1
 #!/bin/bash
2 2
 
3
+#
4
+# Create a Lodel2 instance
5
+#-------------------------
6
+#
7
+# Usage : ./lodel_init.sh instance_name instance_path [lodel2_lib_path]
8
+#
9
+# This script creates a new Lodel2 instance.
10
+#
11
+# It make a copy of install/ directory + some substitution in the instance_settings.py file
12
+# and then it generates dynamic code
13
+#
14
+
15
+
3 16
 usage() {
4 17
 	echo "Usage : $0 instance_name instance_dir [lodel_libdir]" 1>&2
5 18
 	exit 1

Notiek ielāde…
Atcelt
Saglabāt