c2cgeoportal-geoportal 2.6.0__py2.py3-none-any.whl → 2.8.1.180__py2.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 (225) hide show
  1. c2cgeoportal_geoportal/__init__.py +245 -95
  2. c2cgeoportal_geoportal/lib/__init__.py +67 -43
  3. c2cgeoportal_geoportal/lib/authentication.py +50 -26
  4. c2cgeoportal_geoportal/lib/bashcolor.py +17 -13
  5. c2cgeoportal_geoportal/lib/cacheversion.py +16 -8
  6. c2cgeoportal_geoportal/lib/caching.py +65 -193
  7. c2cgeoportal_geoportal/lib/check_collector.py +17 -10
  8. c2cgeoportal_geoportal/lib/checker.py +67 -65
  9. c2cgeoportal_geoportal/lib/common_headers.py +167 -0
  10. c2cgeoportal_geoportal/lib/dbreflection.py +61 -46
  11. c2cgeoportal_geoportal/lib/filter_capabilities.py +126 -88
  12. c2cgeoportal_geoportal/lib/fulltextsearch.py +6 -5
  13. c2cgeoportal_geoportal/lib/functionality.py +20 -17
  14. c2cgeoportal_geoportal/lib/headers.py +14 -5
  15. c2cgeoportal_geoportal/lib/i18n.py +4 -4
  16. c2cgeoportal_geoportal/lib/layers.py +30 -11
  17. c2cgeoportal_geoportal/lib/lingua_extractor.py +363 -240
  18. c2cgeoportal_geoportal/lib/loader.py +11 -16
  19. c2cgeoportal_geoportal/lib/metrics.py +28 -17
  20. c2cgeoportal_geoportal/lib/oauth2.py +392 -206
  21. c2cgeoportal_geoportal/lib/wmstparsing.py +105 -84
  22. c2cgeoportal_geoportal/lib/xsd.py +26 -16
  23. c2cgeoportal_geoportal/resources.py +15 -9
  24. c2cgeoportal_geoportal/scaffolds/advance_create/ci/config.yaml +26 -0
  25. c2cgeoportal_geoportal/scaffolds/advance_create/cookiecutter.json +18 -0
  26. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.dockerignore +6 -0
  27. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.eslintrc.yaml +19 -0
  28. c2cgeoportal_geoportal/scaffolds/{create/geoportal/+dot+prospector.yaml → advance_create/{{cookiecutter.project}}/geoportal/.prospector.yaml} +8 -2
  29. c2cgeoportal_geoportal/scaffolds/{create/geoportal/Dockerfile_tmpl → advance_create/{{cookiecutter.project}}/geoportal/Dockerfile} +22 -15
  30. c2cgeoportal_geoportal/scaffolds/{create/geoportal/alembic.yaml_tmpl → advance_create/{{cookiecutter.project}}/geoportal/alembic.yaml} +1 -1
  31. c2cgeoportal_geoportal/scaffolds/{create/geoportal/development.ini_tmpl → advance_create/{{cookiecutter.project}}/geoportal/development.ini} +34 -15
  32. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/gunicorn.conf.py +100 -0
  33. c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/lingua-client.cfg +1 -0
  34. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/production.ini +38 -0
  35. c2cgeoportal_geoportal/scaffolds/{create/geoportal/setup.py_tmpl → advance_create/{{cookiecutter.project}}/geoportal/setup.py} +6 -7
  36. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/tsconfig.json +8 -0
  37. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.api.js +77 -0
  38. c2cgeoportal_geoportal/scaffolds/{create/geoportal/webpack.apps.js_tmpl → advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js} +29 -28
  39. c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/webpack.commons.js +4 -7
  40. c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/webpack.config.js +1 -1
  41. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/__init__.py +42 -0
  42. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/authentication.py +10 -0
  43. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/dev.py +14 -0
  44. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/models.py +8 -0
  45. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/multi_organization.py +7 -0
  46. c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/resources.py +4 -3
  47. c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal/static-ngeo/api/index.js_tmpl → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/api/index.js} +1 -2
  48. c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal/static-ngeo/js/+package+module.js_tmpl → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/js/{{cookiecutter.package}}module.js} +4 -4
  49. c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal/subscribers.py_tmpl → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/subscribers.py} +1 -3
  50. c2cgeoportal_geoportal/scaffolds/advance_update/cookiecutter.json +18 -0
  51. c2cgeoportal_geoportal/scaffolds/{update/geoportal/CONST_Makefile_tmpl → advance_update/{{cookiecutter.project}}/geoportal/CONST_Makefile} +3 -27
  52. c2cgeoportal_geoportal/scaffolds/create/cookiecutter.json +18 -0
  53. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.dockerignore +14 -0
  54. c2cgeoportal_geoportal/scaffolds/create/{+dot+editorconfig → {{cookiecutter.project}}/.editorconfig} +2 -5
  55. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +57 -0
  56. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +46 -0
  57. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/update_l10n.yaml +66 -0
  58. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.gitignore +16 -0
  59. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierignore +1 -0
  60. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierrc.yaml +2 -0
  61. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Dockerfile +76 -0
  62. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +70 -0
  63. c2cgeoportal_geoportal/scaffolds/create/{README.rst_tmpl → {{cookiecutter.project}}/README.rst} +4 -4
  64. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +186 -0
  65. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/config.yaml +22 -0
  66. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/docker-compose-check +25 -0
  67. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/requirements.txt +1 -0
  68. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml +26 -0
  69. c2cgeoportal_geoportal/scaffolds/create/{docker-compose-lib.yaml → {{cookiecutter.project}}/docker-compose-lib.yaml} +165 -22
  70. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml +23 -0
  71. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml +66 -0
  72. c2cgeoportal_geoportal/scaffolds/create/{docker-compose.yaml → {{cookiecutter.project}}/docker-compose.yaml} +20 -15
  73. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.default +101 -0
  74. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.project +69 -0
  75. c2cgeoportal_geoportal/scaffolds/create/{geoportal/vars.yaml_tmpl → {{cookiecutter.project}}/geoportal/vars.yaml} +126 -36
  76. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/mobile.css +0 -0
  77. c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/data/Readme.txt +3 -3
  78. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/demo.map.tmpl +224 -0
  79. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.conf +15 -0
  80. c2cgeoportal_geoportal/scaffolds/create/{mapserver/mapserver.map.tmpl_tmpl → {{cookiecutter.project}}/mapserver/mapserver.map.tmpl} +9 -18
  81. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A3_Landscape.jrxml +13 -8
  82. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A3_Portrait.jrxml +13 -8
  83. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A4_Landscape.jrxml +13 -8
  84. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A4_Portrait.jrxml +13 -8
  85. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/config.yaml.tmpl +11 -4
  86. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation.properties +4 -0
  87. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation_fr.properties +4 -0
  88. c2cgeoportal_geoportal/scaffolds/create/{project.yaml_tmpl → {{cookiecutter.project}}/project.yaml} +6 -6
  89. c2cgeoportal_geoportal/scaffolds/create/{pyproject.toml → {{cookiecutter.project}}/pyproject.toml} +4 -0
  90. c2cgeoportal_geoportal/scaffolds/create/{qgisserver/pg_service.conf.tmpl_tmpl → {{cookiecutter.project}}/qgisserver/pg_service.conf.tmpl} +2 -2
  91. c2cgeoportal_geoportal/scaffolds/create/{run_alembic.sh → {{cookiecutter.project}}/run_alembic.sh} +3 -5
  92. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +110 -0
  93. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +114 -0
  94. c2cgeoportal_geoportal/scaffolds/create/{setup.cfg_tmpl → {{cookiecutter.project}}/setup.cfg} +1 -1
  95. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/spell-ignore-words.txt +5 -0
  96. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/__init__.py +0 -0
  97. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/test_app.py +38 -0
  98. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tilegeneration/config.yaml.tmpl +195 -0
  99. c2cgeoportal_geoportal/scaffolds/update/cookiecutter.json +18 -0
  100. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml +61 -0
  101. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +273 -0
  102. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py +48 -0
  103. c2cgeoportal_geoportal/scaffolds/update/{geoportal → {{cookiecutter.project}}/geoportal}/CONST_config-schema.yaml +64 -17
  104. c2cgeoportal_geoportal/scaffolds/update/{geoportal/CONST_vars.yaml_tmpl → {{cookiecutter.project}}/geoportal/CONST_vars.yaml} +396 -19
  105. c2cgeoportal_geoportal/scripts/__init__.py +16 -30
  106. c2cgeoportal_geoportal/scripts/c2cupgrade.py +272 -234
  107. c2cgeoportal_geoportal/scripts/create_demo_theme.py +3 -6
  108. c2cgeoportal_geoportal/scripts/manage_users.py +34 -39
  109. c2cgeoportal_geoportal/scripts/pcreate.py +310 -0
  110. c2cgeoportal_geoportal/scripts/theme2fts.py +128 -24
  111. c2cgeoportal_geoportal/scripts/urllogin.py +19 -11
  112. c2cgeoportal_geoportal/templates/login.html +88 -84
  113. c2cgeoportal_geoportal/templates/notlogin.html +59 -59
  114. c2cgeoportal_geoportal/templates/testi18n.html +6 -8
  115. c2cgeoportal_geoportal/views/__init__.py +23 -6
  116. c2cgeoportal_geoportal/views/dev.py +9 -7
  117. c2cgeoportal_geoportal/views/dynamic.py +56 -19
  118. c2cgeoportal_geoportal/views/entry.py +85 -24
  119. c2cgeoportal_geoportal/views/fulltextsearch.py +29 -23
  120. c2cgeoportal_geoportal/views/geometry_processing.py +17 -9
  121. c2cgeoportal_geoportal/views/i18n.py +91 -9
  122. c2cgeoportal_geoportal/views/layers.py +166 -133
  123. c2cgeoportal_geoportal/views/login.py +161 -93
  124. c2cgeoportal_geoportal/views/mapserverproxy.py +47 -31
  125. c2cgeoportal_geoportal/views/memory.py +12 -12
  126. c2cgeoportal_geoportal/views/ogcproxy.py +52 -30
  127. c2cgeoportal_geoportal/views/pdfreport.py +30 -26
  128. c2cgeoportal_geoportal/views/printproxy.py +60 -52
  129. c2cgeoportal_geoportal/views/profile.py +24 -23
  130. c2cgeoportal_geoportal/views/proxy.py +88 -72
  131. c2cgeoportal_geoportal/views/raster.py +37 -26
  132. c2cgeoportal_geoportal/views/resourceproxy.py +13 -11
  133. c2cgeoportal_geoportal/views/shortener.py +27 -25
  134. c2cgeoportal_geoportal/views/theme.py +472 -332
  135. c2cgeoportal_geoportal/views/tinyowsproxy.py +42 -44
  136. c2cgeoportal_geoportal/views/vector_tiles.py +80 -0
  137. {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.8.1.180.dist-info}/METADATA +19 -8
  138. c2cgeoportal_geoportal-2.8.1.180.dist-info/RECORD +191 -0
  139. {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.8.1.180.dist-info}/WHEEL +1 -1
  140. {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.8.1.180.dist-info}/entry_points.txt +3 -0
  141. tests/__init__.py +10 -5
  142. tests/test_cachebuster.py +3 -5
  143. tests/test_caching.py +18 -26
  144. tests/test_checker.py +1 -3
  145. tests/test_decimaljson.py +5 -5
  146. tests/test_headerstween.py +1 -3
  147. tests/test_i18n.py +2 -2
  148. tests/test_init.py +16 -20
  149. tests/test_locale_negociator.py +4 -6
  150. tests/test_mapserverproxy_route_predicate.py +1 -4
  151. tests/test_raster.py +15 -17
  152. tests/test_wmstparsing.py +10 -12
  153. tests/xmlstr.py +1 -3
  154. c2cgeoportal_geoportal/scaffolds/__init__.py +0 -227
  155. c2cgeoportal_geoportal/scaffolds/create/+dot+dockerignore_tmpl +0 -12
  156. c2cgeoportal_geoportal/scaffolds/create/+dot+github/workflows/main.yaml_tmpl +0 -89
  157. c2cgeoportal_geoportal/scaffolds/create/+dot+github/workflows/rebuild.yaml_tmpl +0 -78
  158. c2cgeoportal_geoportal/scaffolds/create/+dot+gitignore_tmpl +0 -16
  159. c2cgeoportal_geoportal/scaffolds/create/Dockerfile_tmpl +0 -67
  160. c2cgeoportal_geoportal/scaffolds/create/Makefile +0 -3
  161. c2cgeoportal_geoportal/scaffolds/create/build_tmpl +0 -167
  162. c2cgeoportal_geoportal/scaffolds/create/ci/config.yaml_tmpl +0 -23
  163. c2cgeoportal_geoportal/scaffolds/create/ci/requirements.txt +0 -1
  164. c2cgeoportal_geoportal/scaffolds/create/ci/trigger +0 -68
  165. c2cgeoportal_geoportal/scaffolds/create/docker-compose.override.sample.yaml +0 -54
  166. c2cgeoportal_geoportal/scaffolds/create/env.default_tmpl +0 -67
  167. c2cgeoportal_geoportal/scaffolds/create/env.project_tmpl +0 -48
  168. c2cgeoportal_geoportal/scaffolds/create/geoportal/+dot+dockerignore_tmpl +0 -6
  169. c2cgeoportal_geoportal/scaffolds/create/geoportal/+dot+eslintrc_tmpl +0 -15
  170. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/__init__.py_tmpl +0 -58
  171. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/models.py_tmpl +0 -10
  172. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static/robot.txt +0 -3
  173. c2cgeoportal_geoportal/scaffolds/create/geoportal/production.ini_tmpl +0 -106
  174. c2cgeoportal_geoportal/scaffolds/create/geoportal/tools/extract-messages.js +0 -39
  175. c2cgeoportal_geoportal/scaffolds/create/geoportal/tsconfig.json_tmpl +0 -9
  176. c2cgeoportal_geoportal/scaffolds/create/geoportal/webpack.api.js_tmpl +0 -72
  177. c2cgeoportal_geoportal/scaffolds/create/mapserver/demo.map.tmpl_tmpl +0 -262
  178. c2cgeoportal_geoportal/scaffolds/create/mapserver/tinyows.xml +0 -36
  179. c2cgeoportal_geoportal/scaffolds/create/print/print-apps/+package+/config.yaml +0 -168
  180. c2cgeoportal_geoportal/scaffolds/create/qgisserver/geomapfish.yaml.tmpl_tmpl +0 -16
  181. c2cgeoportal_geoportal/scaffolds/create/spell-ignore-words.txt +0 -1
  182. c2cgeoportal_geoportal/scaffolds/create/tilegeneration/config.yaml.tmpl_tmpl +0 -185
  183. c2cgeoportal_geoportal/scaffolds/create/yamllint.yaml +0 -11
  184. c2cgeoportal_geoportal/scaffolds/update/+dot+upgrade.yaml_tmpl +0 -181
  185. c2cgeoportal_geoportal/scaffolds/update/CONST_CHANGELOG.txt_tmpl +0 -454
  186. c2cgeoportal_geoportal/templates/dynamic.js +0 -21
  187. c2cgeoportal_geoportal-2.6.0.dist-info/RECORD +0 -173
  188. /c2cgeoportal_geoportal/{scaffolds/create/geoportal/+package+_geoportal/static/css/desktop.css → py.typed} +0 -0
  189. /c2cgeoportal_geoportal/scaffolds/{create/geoportal/Makefile_tmpl → advance_create/{{cookiecutter.project}}/geoportal/Makefile} +0 -0
  190. /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/alembic.ini +0 -0
  191. /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/language_mapping +0 -0
  192. /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/lingua-server.cfg +0 -0
  193. /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/requirements.txt +0 -0
  194. /c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/views/__init__.py +0 -0
  195. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/locale/en/LC_MESSAGES/+package+_geoportal-client.po → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/locale/en/LC_MESSAGES/{{cookiecutter.package}}_geoportal-client.po} +0 -0
  196. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/static/css/iframe_api.css → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/desktop.css} +0 -0
  197. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/static/css/mobile.css → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/iframe_api.css} +0 -0
  198. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/banner_left.png +0 -0
  199. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/banner_right.png +0 -0
  200. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/blank.png +0 -0
  201. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/markers/marker-blue.png +0 -0
  202. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/markers/marker-gold.png +0 -0
  203. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/markers/marker-green.png +0 -0
  204. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/markers/marker.png +0 -0
  205. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/robot.txt.tmpl +0 -0
  206. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/data/TM_EUROPE_BORDERS-0.3.sql +0 -0
  207. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arial.ttf +0 -0
  208. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arialbd.ttf +0 -0
  209. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arialbi.ttf +0 -0
  210. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Ariali.ttf +0 -0
  211. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Bold.ttf +0 -0
  212. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-BoldItalic.ttf +0 -0
  213. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Italic.ttf +0 -0
  214. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Regular.ttf +0 -0
  215. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdana.ttf +0 -0
  216. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanab.ttf +0 -0
  217. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanai.ttf +0 -0
  218. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanaz.ttf +0 -0
  219. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts.conf +0 -0
  220. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/tinyows.xml.tmpl +0 -0
  221. /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/legend.jrxml +0 -0
  222. /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/logo.png +0 -0
  223. /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/north.svg +0 -0
  224. /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/results.jrxml +0 -0
  225. {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.8.1.180.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # Copyright (c) 2014-2021, Camptocamp SA
1
+ # Copyright (c) 2014-2023, Camptocamp SA
4
2
  # All rights reserved.
5
3
 
6
4
  # Redistribution and use in source and binary forms, with or without
@@ -36,15 +34,16 @@ import re
36
34
  import shutil
37
35
  import subprocess
38
36
  import sys
39
- from argparse import ArgumentParser
37
+ from argparse import ArgumentParser, Namespace
38
+ from json.decoder import JSONDecodeError
40
39
  from subprocess import call, check_call, check_output
41
- from typing import Any, Dict, cast
40
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
42
41
 
43
42
  import pkg_resources
44
43
  import requests
45
44
  import yaml
46
45
 
47
- from c2cgeoportal_geoportal.lib.bashcolor import GREEN, RED, YELLOW, colorize
46
+ from c2cgeoportal_geoportal.lib.bashcolor import Color, colorize
48
47
 
49
48
  REQUIRED_TEMPLATE_KEYS = ["package", "srid", "extent"]
50
49
  TEMPLATE_EXAMPLE = {"package": "${package}", "srid": "${srid}", "extent": "489246, 78873, 837119, 296543"}
@@ -59,11 +58,44 @@ DIFF_NOTICE = (
59
58
  )
60
59
 
61
60
 
62
- def main():
63
- """
64
- tool used to do the application upgrade
65
- """
61
+ def fix_style() -> None:
62
+ """Fix the style of all the project files using isort, Black and Prettier."""
63
+
64
+ file_to_clean = []
65
+ for filename, content in (
66
+ (".prettierignore", "*.min.js\n"),
67
+ ("pyproject.toml", "[tool.black]\nline-length = 110\ntarget-version = ['py38']\n"),
68
+ (".prettierrc.yaml", "bracketSpacing: false\nquoteProps: preserve\n"),
69
+ (
70
+ ".editorconfig",
71
+ """root = true
72
+ [*]
73
+ max_line_length = 110
74
+ """,
75
+ ),
76
+ ):
77
+ if not os.path.exists(filename):
78
+ file_to_clean.append(filename)
79
+ if os.path.exists(os.path.join("CONST_create_template", filename)):
80
+ shutil.copyfile(os.path.join("CONST_create_template", filename), filename)
81
+ else:
82
+ with open(filename, "w", encoding="utf8") as file_:
83
+ file_.write(content)
84
+
85
+ if os.path.exists("ci/config.yaml"):
86
+ os.rename("ci/config.yaml", "ci/config.yaml_")
87
+ subprocess.run(["c2cciutils-checks", "--fix", "--check=isort"]) # pylint: disable=subprocess-run-check
88
+ subprocess.run(["c2cciutils-checks", "--fix", "--check=black"]) # pylint: disable=subprocess-run-check
89
+ subprocess.run(["c2cciutils-checks", "--fix", "--check=prettier"]) # pylint: disable=subprocess-run-check
90
+ if os.path.exists("ci/config.yaml_"):
91
+ os.rename("ci/config.yaml_", "ci/config.yaml")
92
+
93
+ for filename in file_to_clean:
94
+ os.remove(filename)
95
+
66
96
 
97
+ def main() -> None:
98
+ """Tool used to do the application upgrade."""
67
99
  parser = _fill_arguments()
68
100
  options = parser.parse_args()
69
101
 
@@ -71,7 +103,7 @@ def main():
71
103
  c2cupgradetool.upgrade()
72
104
 
73
105
 
74
- def _fill_arguments():
106
+ def _fill_arguments() -> ArgumentParser:
75
107
  parser = ArgumentParser()
76
108
  parser.add_argument(
77
109
  "--git-remote", metavar="GITREMOTE", help="Specify the remote branch", default="origin"
@@ -82,38 +114,40 @@ def _fill_arguments():
82
114
 
83
115
 
84
116
  class InteruptedException(Exception):
85
- pass
117
+ """The interrupted exception."""
86
118
 
87
119
 
88
120
  current_step_number = 0
89
121
 
90
122
 
91
123
  class Step:
92
- def __init__(self, step_number, file_marker=True):
124
+ """Decorator used for en upgrade step."""
125
+
126
+ def __init__(self, step_number: int, file_marker: bool = True):
93
127
  global current_step_number
94
128
  current_step_number = step_number
95
129
  self.step_number = step_number
96
130
  self.file_marker = file_marker
97
131
 
98
- def __call__(self, current_step):
99
- def decorate(c2cupgradetool, *args, **kwargs):
132
+ def __call__(
133
+ self, current_step: Callable[["C2cUpgradeTool", int], None]
134
+ ) -> Callable[["C2cUpgradeTool"], None]:
135
+ def decorate(c2cupgradetool: "C2cUpgradeTool") -> None:
100
136
  try:
101
- if os.path.isfile(".UPGRADE{}".format(self.step_number - 1)):
102
- os.unlink(".UPGRADE{}".format(self.step_number - 1))
137
+ if os.path.isfile(f".UPGRADE{self.step_number - 1}"):
138
+ os.unlink(f".UPGRADE{self.step_number - 1}")
103
139
  if self.file_marker:
104
- with open(".UPGRADE{}".format(self.step_number), "w"):
140
+ with open(f".UPGRADE{self.step_number}", "w", encoding="utf8"):
105
141
  pass
106
- print("Start step {}.".format(self.step_number))
142
+ print(f"Start step {self.step_number}.")
107
143
  sys.stdout.flush()
108
- current_step(c2cupgradetool, self.step_number, *args, **kwargs)
144
+ current_step(c2cupgradetool, self.step_number)
109
145
  except subprocess.CalledProcessError as exception:
146
+ command = " ".join([f"'{exception}'" for exception in exception.cmd])
110
147
  c2cupgradetool.print_step(
111
148
  self.step_number,
112
149
  error=True,
113
- message="The command `{}` returns the error code {}.".format(
114
- " ".join(["'{}'".format(exception) for exception in exception.cmd]),
115
- exception.returncode,
116
- ),
150
+ message=f"The command `{command}` returns the error code {exception.returncode}.",
117
151
  prompt="Fix the error and run the step again:",
118
152
  )
119
153
  sys.exit(1)
@@ -121,21 +155,20 @@ class Step:
121
155
  c2cupgradetool.print_step(
122
156
  self.step_number,
123
157
  error=True,
124
- message="There was an error: {}.".format(exception),
158
+ message=f"There was an error: {exception}.",
125
159
  prompt="Fix the error and run the step again:",
126
160
  )
127
161
  sys.exit(1)
128
162
  except Exception as exception:
129
- cautch_exception = exception
163
+ catch_exception = exception
130
164
 
131
- global current_step_number
132
165
  if self.step_number == current_step_number:
133
166
 
134
- def message():
167
+ def message() -> None:
135
168
  c2cupgradetool.print_step(
136
169
  self.step_number,
137
170
  error=True,
138
- message="The step had the error '{}'.".format(cautch_exception),
171
+ message=f"The step had the error '{catch_exception}'.",
139
172
  prompt="Fix the error and run the step again:",
140
173
  )
141
174
 
@@ -146,84 +179,100 @@ class Step:
146
179
 
147
180
 
148
181
  class C2cUpgradeTool:
182
+ """The tool used to upgrade the application."""
149
183
 
150
- color_bar = colorize("================================================================", GREEN)
184
+ color_bar = colorize("================================================================", Color.GREEN)
151
185
 
152
- def __init__(self, options):
186
+ def __init__(self, options: Namespace):
153
187
  self.options = options
154
- self.project: Dict[str, Any] = self.get_project()
188
+ self.project = self.get_project()
155
189
 
156
190
  @staticmethod
157
- def get_project():
191
+ def get_project() -> Dict[str, Any]:
158
192
  if not os.path.isfile("project.yaml"):
159
- print(colorize("Unable to find the required 'project.yaml' file.", RED))
193
+ print(colorize("Unable to find the required 'project.yaml' file.", Color.RED))
160
194
  sys.exit(1)
161
195
 
162
- with open("project.yaml", "r") as project_file:
163
- return yaml.safe_load(project_file)
196
+ with open("project.yaml", encoding="utf8") as project_file:
197
+ return cast(Dict[str, Any], yaml.safe_load(project_file))
164
198
 
165
199
  @staticmethod
166
- def get_upgrade(section):
200
+ def get_upgrade(section: str) -> Union[List[Any], Dict[str, Any]]:
167
201
  if not os.path.isfile(".upgrade.yaml"):
168
- print(colorize("Unable to find the required '.upgrade.yaml' file.", RED))
202
+ print(colorize("Unable to find the required '.upgrade.yaml' file.", Color.RED))
169
203
  sys.exit(1)
170
204
 
171
- with open(".upgrade.yaml", "r") as project_file:
172
- return yaml.safe_load(project_file)[section]
173
-
174
- def print_step(self, step, error=False, message=None, prompt="To continue, type:"):
175
- with open(".UPGRADE_INSTRUCTIONS", "w") as instructions:
205
+ with open(".upgrade.yaml", encoding="utf8") as project_file:
206
+ return cast(Union[List[Any], Dict[str, Any]], yaml.safe_load(project_file)[section])
207
+
208
+ def print_step(
209
+ self,
210
+ step: int,
211
+ error: bool = False,
212
+ message: Optional[str] = None,
213
+ prompt: str = "To continue, type:",
214
+ ) -> None:
215
+ with open(".UPGRADE_INSTRUCTIONS", "w", encoding="utf8") as instructions:
176
216
  print("")
177
217
  print(self.color_bar)
178
218
  if message is not None:
179
- print(colorize(message, RED if error else YELLOW))
180
- instructions.write("{}\n".format(message))
219
+ print(colorize(message, Color.RED if error else Color.YELLOW))
220
+ instructions.write(f"{message}\n")
181
221
  if step >= 0:
182
- print(colorize(prompt, GREEN))
183
- instructions.write("{}\n".format(prompt))
222
+ print(colorize(prompt, Color.GREEN))
223
+ instructions.write(f"{prompt}\n")
184
224
  cmd = ["./upgrade", os.environ["VERSION"]]
185
225
  if step != 0:
186
- cmd.append("{}".format(step))
187
- print(colorize(" ".join(cmd), GREEN))
188
- instructions.write("{}\n".format(" ".join(cmd)))
226
+ cmd.append(f"{step}")
227
+ print(colorize(" ".join(cmd), Color.GREEN))
228
+ instructions.write(f"{' '.join(cmd)}\n")
189
229
 
190
- def run_step(self, step):
191
- getattr(self, "step{}".format(step))()
230
+ def run_step(self, step: int) -> None:
231
+ getattr(self, f"step{step}")()
192
232
 
193
- def test_checkers(self):
194
- run_curl = "Run `curl --insecure {} '{}'` for more information.".format(
195
- " ".join(["--header {}={}".format(*i) for i in self.project.get("checker_headers", {}).items()]),
196
- self.project["checker_url"],
233
+ def test_checkers(self) -> Tuple[bool, Optional[str]]:
234
+ headers = " ".join(
235
+ [f"--header {i[0]}={i[1]}" for i in self.project.get("checker_headers", {}).items()]
197
236
  )
237
+ run_curl = f"Run `curl --insecure {headers} '{self.project['checker_url']}'` for more information."
198
238
  try:
199
- requests.packages.urllib3.disable_warnings()
239
+ requests.packages.urllib3.disable_warnings() # type: ignore
200
240
  resp = requests.get(
201
- self.project["checker_url"], headers=self.project.get("checker_headers"), verify=False
241
+ self.project["checker_url"],
242
+ headers=self.project.get("checker_headers"),
243
+ verify=False, # nosec
202
244
  )
203
245
  except requests.exceptions.ConnectionError as exception:
204
- return False, "\n".join(["Connection error: {}".format(exception), run_curl])
246
+ return False, "\n".join([f"Connection error: {exception}", run_curl])
205
247
  except ConnectionRefusedError as exception:
206
- return False, "\n".join(["Connection refused: {}".format(exception), run_curl])
248
+ return False, "\n".join([f"Connection refused: {exception}", run_curl])
207
249
  if resp.status_code < 200 or resp.status_code >= 300:
208
-
209
- print(colorize("=============", RED))
210
- print(colorize("Checker error", RED))
211
- for name, value in resp.json()["failures"].items():
212
- print(colorize("Test '{}' failed with result:".format(name), YELLOW))
213
- del value["level"]
214
- del value["timing"]
215
-
216
- print(yaml.dump(value) if value != {} else "No result")
250
+ print(colorize("=============", Color.RED))
251
+ print(colorize("Checker error", Color.RED))
252
+ try:
253
+ for name, value in resp.json()["failures"].items():
254
+ print(colorize(f"Test '{name}' failed with result:", Color.YELLOW))
255
+ del value["level"]
256
+ del value["timing"]
257
+
258
+ print(yaml.dump(value) if value != {} else "No result")
259
+ except JSONDecodeError:
260
+ print(
261
+ colorize(
262
+ f"Response is not a JSON '{resp.text}', {resp.reason} {resp.status_code}",
263
+ Color.RED,
264
+ )
265
+ )
217
266
 
218
267
  return False, "\n".join(["Checker error:", run_curl])
219
268
 
220
269
  return True, None
221
270
 
222
- def upgrade(self):
271
+ def upgrade(self) -> None:
223
272
  self.run_step(self.options.step)
224
273
 
225
274
  @Step(0, file_marker=False)
226
- def step0(self, step):
275
+ def step0(self, step: int) -> None:
227
276
  project_template_keys = list(cast(Dict[str, Any], self.project.get("template_vars")).keys())
228
277
  messages = []
229
278
  for required in REQUIRED_TEMPLATE_KEYS:
@@ -255,11 +304,11 @@ class C2cUpgradeTool:
255
304
  message="Here is the output of 'git status'. Please make sure to commit all your "
256
305
  "changes before going further. All uncommitted changes will be lost.\n"
257
306
  "Note that for debugging purpose it is possible to pass directly to step 2 "
258
- "e.-g.: ./upgrade --debug=../c2cgeoportal {version} 2".format(version=os.environ["VERSION"]),
307
+ f"e.-g.: ./upgrade --debug=../c2cgeoportal {os.environ['VERSION']} 2",
259
308
  )
260
309
 
261
310
  @Step(1)
262
- def step1(self, step):
311
+ def step1(self, step: int) -> None:
263
312
  shutil.copyfile("project.yaml", "/tmp/project.yaml")
264
313
  try:
265
314
  check_call(["git", "reset", "--hard"])
@@ -270,75 +319,38 @@ class C2cUpgradeTool:
270
319
  self.run_step(step + 1)
271
320
 
272
321
  @Step(2)
273
- def step2(self, step):
274
- with open(".eslintrc", "w") as eslintrc_file:
275
- eslintrc_file.write(
276
- """extends:
277
- - openlayers
278
- globals:
279
- '{}': false
280
- env:
281
- jquery: true
282
- parserOptions:
283
- ecmaVersion: 2017
284
- rules:
285
- no-console: 0
286
- comma-dangle: 0
287
- import/no-unresolved: 0
288
- valid-jsdoc: 0
289
- sort-imports-es6-autofix/sort-imports-es6: 0
290
- prettier/prettier: 1
291
- """.format(
292
- self.project["project_package"]
293
- )
294
- )
295
-
296
- app_js_files = []
297
- for base in ("CONST_create_template/", ""):
298
- try:
299
- app_js_files.extend(
300
- check_output(
301
- [
302
- "find",
303
- base + self.project["project_package"] + "_geoportal/static-ngeo/js",
304
- "-type",
305
- "f",
306
- "-name",
307
- "*.js",
308
- ]
309
- )
310
- .decode()
311
- .split()
312
- )
313
- except Exception:
314
- pass
315
-
316
- if app_js_files:
317
- call(["eslint", "--fix"] + app_js_files)
318
-
319
- os.remove(".eslintrc")
320
- check_call(["git", "add"] + app_js_files)
321
- call(["git", "commit", "--message=Run code style"])
322
+ def step2(self, step: int) -> None:
323
+ fix_style()
324
+ subprocess.run(["git", "add", "-A"]) # pylint: disable=subprocess-run-check
325
+ subprocess.run(["git", "commit", "--message=Run code style"]) # pylint: disable=subprocess-run-check
322
326
 
323
327
  self.run_step(step + 1)
324
328
 
325
329
  @Step(3)
326
- def step3(self, step):
330
+ def step3(self, step: int) -> None:
327
331
  project_path = os.path.join("/tmp", self.project["project_folder"])
328
332
  os.mkdir(project_path)
329
333
  shutil.copyfile("/src/project.yaml", os.path.join(project_path, "project.yaml"))
330
334
  check_call(
331
335
  [
332
336
  "pcreate",
333
- "--ignore-conflicting-name",
334
337
  "--overwrite",
335
- "--scaffold=c2cgeoportal_update",
338
+ "--scaffold=update",
336
339
  project_path,
337
340
  ]
338
341
  )
342
+ if self.get_project().get("advance", False):
343
+ check_call(
344
+ [
345
+ "pcreate",
346
+ "--overwrite",
347
+ "--scaffold=advance_update",
348
+ project_path,
349
+ ]
350
+ )
339
351
 
340
352
  shutil.copyfile(os.path.join(project_path, ".upgrade.yaml"), ".upgrade.yaml")
341
- for upgrade_file in self.get_upgrade("upgrade_files"):
353
+ for upgrade_file in cast(List[Dict[str, Any]], self.get_upgrade("upgrade_files")):
342
354
  action = upgrade_file["action"]
343
355
  if action == "remove":
344
356
  self.files_to_remove(upgrade_file, prefix="CONST_create_template", force=True)
@@ -354,7 +366,7 @@ rules:
354
366
  self.run_step(step + 1)
355
367
 
356
368
  @Step(4)
357
- def step4(self, step):
369
+ def step4(self, step: int) -> None:
358
370
  if os.path.exists("CONST_create_template"):
359
371
  check_call(["git", "rm", "-r", "--force", "CONST_create_template/"])
360
372
 
@@ -363,37 +375,79 @@ rules:
363
375
  check_call(
364
376
  [
365
377
  "pcreate",
366
- "--ignore-conflicting-name",
367
378
  "--overwrite",
368
- "--scaffold=c2cgeoportal_update",
379
+ "--scaffold=update",
369
380
  project_path,
370
381
  ]
371
382
  )
383
+ if self.get_project().get("advance", False):
384
+ check_call(
385
+ [
386
+ "pcreate",
387
+ "--overwrite",
388
+ "--scaffold=advance_update",
389
+ project_path,
390
+ ]
391
+ )
372
392
  os.remove(project_path)
373
393
 
394
+ check_call(["git", "add", "--all", "CONST_create_template/"])
395
+
396
+ def changed_files() -> List[str]:
397
+ try:
398
+ status = [
399
+ [s for s in status.strip().split(" ", maxsplit=1) if s]
400
+ for status in check_git_status_output().strip().split("\n")
401
+ if status
402
+ ]
403
+ return [
404
+ file.strip().split(" ")[-1]
405
+ for state, file in status
406
+ if state == "M" and not file.strip().startswith("CONST_")
407
+ ]
408
+ except: # pylint: disable=bare-except
409
+ self.print_step(
410
+ step,
411
+ error=True,
412
+ message=f"Error while getting changed files:\n{check_git_status_output()}",
413
+ prompt="Fix the error and run the step again:",
414
+ )
415
+ sys.exit(1)
416
+
417
+ changed_before_style = changed_files()
418
+
419
+ fix_style()
420
+
421
+ # Revert code style changes in the project otherwise we get an error: does not match index
422
+ # on git apply.
423
+ changed_after_style = changed_files()
424
+ to_checkout = [file for file in changed_after_style if file not in changed_before_style]
425
+ if to_checkout:
426
+ subprocess.run(["git", "checkout"] + to_checkout, check=True)
427
+
374
428
  check_call(["git", "add", "--all", "CONST_create_template/"])
375
429
  check_call(["git", "clean", "-Xf", "CONST_create_template/"])
376
430
  self.run_step(step + 1)
377
431
 
378
432
  @Step(5)
379
- def step5(self, step):
433
+ def step5(self, step: int) -> None:
380
434
  if "managed_files" not in self.project:
435
+ unmanaged_files = "\n".join(["- " + e for e in self.project.get("unmanaged_files", [])])
381
436
  self.print_step(
382
437
  step,
383
- message="In the new version, we will also manage almost all the create "
384
- "template files.\n"
385
- "By default, files conforming to the following regex pattern will not be replaced:\n{}"
386
- "Therefore, you should fill the 'managed_files' in you 'project.yaml' file with at least "
387
- "`[]`.".format("\n".join(["- " + e for e in self.project.get("unmanaged_files", [])])),
438
+ message="In the new version, we will also manage almost all the create template files.\n"
439
+ "By default, files conforming to the following regex pattern will not be replaced:\n"
440
+ f"{unmanaged_files} Therefore, you should fill the 'managed_files' in you 'project.yaml' "
441
+ "file with at least `[]`.",
388
442
  prompt="Fill it and run the step again:",
389
443
  )
390
444
  else:
391
445
  self.run_step(step + 1)
392
446
 
393
447
  @Step(6)
394
- def step6(self, step):
448
+ def step6(self, step: int) -> None:
395
449
  task_to_do = False
396
- for upgrade_file in self.get_upgrade("upgrade_files"):
450
+ for upgrade_file in cast(List[Dict[str, Any]], self.get_upgrade("upgrade_files")):
397
451
  action = upgrade_file["action"]
398
452
  if action == "remove":
399
453
  task_to_do |= self.files_to_remove(upgrade_file)
@@ -415,7 +469,7 @@ rules:
415
469
  else:
416
470
  self.run_step(step + 1)
417
471
 
418
- def files_to_remove(self, element, prefix="", force=False):
472
+ def files_to_remove(self, element: Dict[str, Any], prefix: str = "", force: bool = False) -> bool:
419
473
  task_to_do = False
420
474
  for path in element["paths"]:
421
475
  file_ = os.path.join(prefix, path.format(package=self.project["project_package"]))
@@ -433,31 +487,30 @@ rules:
433
487
  if no_touch:
434
488
  managed = True
435
489
  else:
436
- # fmt: off
437
- print(colorize(
438
- "The file '{}' has been removed but he is in the `managed_files` as '{}'."
439
- .format(file_, pattern),
440
- RED
441
- ))
442
- # fmt: on
490
+ print(
491
+ colorize(
492
+ f"The file '{file_}' has been removed but he is in the "
493
+ f"`managed_files` as '{pattern}'.",
494
+ Color.RED,
495
+ )
496
+ )
443
497
  task_to_do = True
444
498
  for pattern in self.project.get("unmanaged_files", []):
445
499
  if re.match(pattern + "$", file_):
446
- # fmt: off
447
- print(colorize(
448
- "The file '{}' has been removed but he is in the `unmanaged_files` as '{}'."
449
- .format(file_, pattern),
450
- YELLOW
451
- ))
452
- # fmt: on
500
+ print(
501
+ colorize(
502
+ f"The file '{file_}' has been removed but he is in the "
503
+ f"`unmanaged_files` as '{pattern}'.",
504
+ Color.YELLOW,
505
+ )
506
+ )
453
507
  task_to_do = True
454
508
  if not managed:
455
- print("The file '{}' is removed.".format(file_))
509
+ print(f"The file '{file_}' is removed.")
456
510
  if "version" in element and "from" in element:
457
511
  print(
458
- "Was used in version {}, to be removed from version {}.".format(
459
- element["from"], element["version"]
460
- )
512
+ f"Was used in version {element['from']}, to be removed from version "
513
+ f"{element['version']}."
461
514
  )
462
515
  if os.path.isdir(file_):
463
516
  shutil.rmtree(file_)
@@ -465,7 +518,7 @@ rules:
465
518
  os.remove(file_)
466
519
  return task_to_do
467
520
 
468
- def files_to_move(self, element, prefix="", force=False):
521
+ def files_to_move(self, element: Dict[str, Any], prefix: str = "", force: bool = False) -> bool:
469
522
  task_to_do = False
470
523
  src = os.path.join(prefix, element["from"].format(package=self.project["project_package"]))
471
524
  dst = os.path.join(prefix, element["to"].format(package=self.project["project_package"]))
@@ -486,20 +539,18 @@ rules:
486
539
  else:
487
540
  print(
488
541
  colorize(
489
- "The {} '{}' is present in the `managed_files` as '{}', "
490
- "but it has been moved to '{}'.".format(type_, src, pattern, dst),
491
- RED,
542
+ f"The {type_} '{src}' is present in the `managed_files` as '{pattern}', "
543
+ f"but it has been moved to '{dst}'.",
544
+ Color.RED,
492
545
  )
493
546
  )
494
547
  task_to_do = True
495
548
  if re.match(pattern + "$", dst):
496
549
  print(
497
550
  colorize(
498
- "The {} '{}' is present in the `managed_files` as '{}', "
499
- "but a file have been moved on it from '{}'.".format(
500
- type_, dst, pattern, src
501
- ),
502
- RED,
551
+ f"The {type_} '{dst}' is present in the `managed_files` as '{pattern}', "
552
+ f"but a file have been moved on it from '{src}'.",
553
+ Color.RED,
503
554
  )
504
555
  )
505
556
  task_to_do = True
@@ -507,45 +558,46 @@ rules:
507
558
  if re.match(pattern + "$", src):
508
559
  print(
509
560
  colorize(
510
- "The {} '{}' is present in the `unmanaged_files` as '{}', "
511
- "but it has been moved to '{}'.".format(type_, src, pattern, dst),
512
- YELLOW,
561
+ f"The {type_} '{src}' is present in the `unmanaged_files` as '{pattern}', "
562
+ f"but it has been moved to '{dst}'.",
563
+ Color.YELLOW,
513
564
  )
514
565
  )
515
566
  task_to_do = True
516
567
  if re.match(pattern + "$", dst):
517
568
  print(
518
569
  colorize(
519
- "The {} '{}' is present in the `unmanaged_files` as '{}', "
520
- "but a file have been moved on it from '{}'.".format(
521
- type_, dst, pattern, src
522
- ),
523
- YELLOW,
570
+ f"The {type_} '{dst}' is present in the `unmanaged_files` as '{pattern}', "
571
+ f"but a file have been moved on it from '{src}'.",
572
+ Color.YELLOW,
524
573
  )
525
574
  )
526
575
  task_to_do = True
527
576
  if not managed and os.path.exists(dst) and not element.get("override", False):
528
- print(colorize("The destination '{}' already exists, ignoring.".format(dst), YELLOW))
577
+ print(colorize(f"The destination '{dst}' already exists, ignoring.", Color.YELLOW))
529
578
  elif not managed:
530
- print("Move the {} '{}' to '{}'.".format(type_, src, dst))
579
+ print(f"Move the {type_} '{src}' to '{dst}'.")
531
580
  if "version" in element:
532
- print("Needed from version {}.".format(element["version"]))
581
+ print(f"Needed from version {element['version']}.")
533
582
  if os.path.dirname(dst) != "":
534
583
  os.makedirs(os.path.dirname(dst), exist_ok=True)
535
584
  try:
536
585
  check_call(["git", "mv", src, dst])
537
586
  except Exception as exception:
538
- print("[Warning] Git move error: {}.".format(exception))
587
+ print(f"[Warning] Git move error: {exception}.")
539
588
  os.rename(src, dst)
540
589
  return task_to_do
541
590
 
542
591
  @Step(7)
543
- def step7(self, step):
592
+ def step7(self, step: int) -> None:
544
593
  self.files_to_get(step)
545
594
  self.run_step(step + 1)
546
595
 
547
- def is_managed(self, file_, files_to_get=False):
548
- default_project_file = self.get_upgrade("default_project_file")
596
+ def is_managed(self, file_: str, files_to_get: bool = False) -> bool:
597
+ # Dictionary with:
598
+ # include: list of include regular expression
599
+ # exclude: list of exclude regular expression
600
+ default_project_file = cast(Dict[str, List[str]], self.get_upgrade("default_project_file"))
549
601
 
550
602
  # Managed means managed by the application owner, not the c2cupgrade
551
603
  managed = False
@@ -556,23 +608,23 @@ rules:
556
608
  ):
557
609
  for pattern in default_project_file["include"]:
558
610
  if re.match(pattern + "$", file_):
559
- print("File '{}' included by migration config pattern '{}'.".format(file_, pattern))
611
+ print(f"File '{file_}' included by migration config pattern '{pattern}'.")
560
612
  managed = True
561
613
  break
562
614
  if managed:
563
615
  for pattern in default_project_file["exclude"]:
564
616
  if re.match(pattern + "$", file_):
565
- print("File '{}' excluded by migration config pattern '{}'.".format(file_, pattern))
617
+ print(f"File '{file_}' excluded by migration config pattern '{pattern}'.")
566
618
  print("managed", file_, pattern)
567
619
  managed = False
568
620
  break
569
621
  else:
570
- print("New file '{}'.".format(file_))
622
+ print(f"New file '{file_}'.")
571
623
 
572
624
  if not managed and not os.path.exists(file_):
573
625
  for pattern in self.get_upgrade("extra"):
574
626
  if re.match(pattern + "$", file_):
575
- print("File '{}' is an extra by migration config pattern '{}'.".format(file_, pattern))
627
+ print(f"File '{file_}' is an extra by migration config pattern '{pattern}'.")
576
628
  managed = True
577
629
 
578
630
  if not managed:
@@ -582,39 +634,29 @@ rules:
582
634
  else:
583
635
  pattern = files["pattern"]
584
636
  if re.match(pattern + "$", file_):
585
- print(
586
- "File '{}' included by project config pattern `managed_files` '{}'.".format(
587
- file_, pattern
588
- )
589
- )
637
+ print(f"File '{file_}' included by project config pattern `managed_files` '{pattern}'.")
590
638
  print("managed", file_, pattern)
591
639
  managed = True
592
640
  break
593
641
  if managed:
594
642
  for pattern in self.project.get("unmanaged_files", []):
595
643
  if re.match(pattern + "$", file_):
596
- print(
597
- "File '{}' excluded by project config pattern `unmanaged_files` '{}'.".format(
598
- file_, pattern
599
- )
600
- )
644
+ print(f"File '{file_}' excluded by project config pattern `unmanaged_files` '{pattern}'.")
601
645
  managed = False
602
646
  break
603
647
 
604
648
  return managed
605
649
 
606
- def files_to_get(self, step, pre=False):
650
+ def files_to_get(self, step: int, pre: bool = False) -> bool:
607
651
  error = False
608
652
  for root, _, files in os.walk("CONST_create_template"):
609
- # fmt: off
610
- root = root[len("CONST_create_template/"):]
611
- # fmt: on
653
+ root = root[len("CONST_create_template/") :]
612
654
  for file_ in files:
613
655
  destination = os.path.join(root, file_)
614
656
  managed = self.is_managed(destination, True)
615
657
  source = os.path.join("CONST_create_template", destination)
616
658
  if not managed and (not os.path.exists(destination) or not filecmp.cmp(source, destination)):
617
- print(colorize("Get the file '{}' from the create template.".format(destination), GREEN))
659
+ print(colorize(f"Get the file '{destination}' from the create template.", Color.GREEN))
618
660
  if not pre:
619
661
  if os.path.dirname(destination) != "":
620
662
  os.makedirs(os.path.dirname(destination), exist_ok=True)
@@ -633,17 +675,17 @@ rules:
633
675
  )
634
676
  sys.exit(1)
635
677
  elif managed:
636
- print("The file '{}' is managed by the project.".format(destination))
678
+ print(f"The file '{destination}' is managed by the project.")
637
679
  elif os.path.exists(destination) and filecmp.cmp(source, destination):
638
- print("The file '{}' does not change.".format(destination))
680
+ print(f"The file '{destination}' does not change.")
639
681
  else:
640
- print("Unknown stat for the file '{}'.".format(destination))
682
+ print(f"Unknown stat for the file '{destination}'.")
641
683
  sys.exit(2)
642
684
  return error
643
685
 
644
686
  @Step(8)
645
- def step8(self, step):
646
- with open("changelog.diff", "w") as diff_file:
687
+ def step8(self, step: int) -> None:
688
+ with open("changelog.diff", "w", encoding="utf8") as diff_file:
647
689
  check_call(["git", "diff", "--", "CONST_CHANGELOG.txt"], stdout=diff_file)
648
690
 
649
691
  from210 = False
@@ -664,30 +706,28 @@ rules:
664
706
  "file (listed in the `changelog.diff` file).",
665
707
  )
666
708
 
667
- def get_modified(self, status_path):
668
- status = check_git_status_output([status_path])
669
- status = [s for s in status.split("\n") if len(s) > 3]
709
+ def get_modified(self, status_path: str) -> List[str]:
710
+ status = check_git_status_output([status_path]).split("\n")
711
+ status = [s for s in status if len(s) > 3]
670
712
  status = [s[3:] for s in status if s[:3].strip() == "M"]
671
713
  for pattern in self.get_upgrade("no_diff"):
672
- matcher = re.compile("CONST_create_template/{}$".format(pattern))
714
+ matcher = re.compile(f"CONST_create_template/{pattern}$")
673
715
  status = [s for s in status if not matcher.match(s)]
674
- # fmt: off
675
- status = [s for s in status if os.path.exists(s[len("CONST_create_template/"):])]
676
- status = [s for s in status if not filecmp.cmp(s, s[len("CONST_create_template/"):])]
677
- # fmt: on
716
+ status = [s for s in status if os.path.exists(s[len("CONST_create_template/") :])]
717
+ status = [s for s in status if not filecmp.cmp(s, s[len("CONST_create_template/") :])]
678
718
  return status
679
719
 
680
720
  @Step(9)
681
- def step9(self, step):
721
+ def step9(self, step: int) -> None:
682
722
  if os.path.isfile("changelog.diff"):
683
723
  os.unlink("changelog.diff")
684
724
 
685
725
  status = self.get_modified(
686
- "CONST_create_template/geoportal/{}_geoportal/static-ngeo".format(self.project["project_package"])
726
+ f"CONST_create_template/geoportal/{self.project['project_package']}_geoportal/static-ngeo"
687
727
  )
688
728
  status += ["CONST_create_template/geoportal/vars.yaml"]
689
729
 
690
- with open("ngeo.diff", "w") as diff_file:
730
+ with open("ngeo.diff", "w", encoding="utf8") as diff_file:
691
731
  if status:
692
732
  check_call(
693
733
  ["git", "diff", "--relative=CONST_create_template", "--staged", "--"] + status,
@@ -705,7 +745,7 @@ rules:
705
745
  )
706
746
 
707
747
  @Step(10)
708
- def step10(self, step):
748
+ def step10(self, step: int) -> None:
709
749
  if os.path.isfile("ngeo.diff"):
710
750
  os.unlink("ngeo.diff")
711
751
 
@@ -714,15 +754,13 @@ rules:
714
754
  s
715
755
  for s in status
716
756
  if not s.startswith(
717
- "CONST_create_template/geoportal/{}_geoportal/static-ngeo/".format(
718
- self.project["project_package"]
719
- )
757
+ f"CONST_create_template/geoportal/{self.project['project_package']}_geoportal/static-ngeo/"
720
758
  )
721
759
  ]
722
760
  status = [s for s in status if s != "CONST_create_template/geoportal/vars.yaml"]
723
761
 
724
762
  if status:
725
- with open("create.diff", "w") as diff_file:
763
+ with open("create.diff", "w", encoding="utf8") as diff_file:
726
764
  if status:
727
765
  check_call(
728
766
  ["git", "diff", "--relative=CONST_create_template", "--staged", "--"] + status,
@@ -743,24 +781,24 @@ rules:
743
781
  self.run_step(step + 1)
744
782
 
745
783
  @Step(11)
746
- def step11(self, step):
784
+ def step11(self, step: int) -> None:
747
785
  if os.path.isfile("create.diff"):
748
786
  os.unlink("create.diff")
749
787
 
750
788
  message = [
751
789
  "The upgrade is nearly done, now you should:",
752
790
  "- Build your application with `./upgrade --finalize [build arguments]`",
753
- "- Test your application on '{}'.".format(self.project.get("application_url", "... missing ...")),
791
+ f"- Test your application on '{self.project.get('application_url', '... missing ...')}'.",
754
792
  ]
755
793
 
756
794
  if os.path.isfile(".upgrade.yaml"):
757
795
  os.unlink(".upgrade.yaml")
758
- with open(".UPGRADE_SUCCESS", "w"):
796
+ with open(".UPGRADE_SUCCESS", "w", encoding="utf8"):
759
797
  pass
760
798
  self.print_step(step + 1, message="\n".join(message))
761
799
 
762
800
  @Step(12, file_marker=False)
763
- def step12(self, step):
801
+ def step12(self, step: int) -> None:
764
802
  if os.path.isfile(".UPGRADE_SUCCESS"):
765
803
  os.unlink(".UPGRADE_SUCCESS")
766
804
  good, message = self.test_checkers()
@@ -772,12 +810,12 @@ rules:
772
810
  error=True,
773
811
  message=message,
774
812
  prompt="Correct the checker, then run the step again "
775
- "(If you want to fix it later you can pass to the next step):",
813
+ "(If you want to fix it later you can pass to the next step:int):",
776
814
  )
777
815
  sys.exit(1)
778
816
 
779
817
  @Step(13, file_marker=False)
780
- def step13(self, step):
818
+ def step13(self, step: int) -> None:
781
819
  # Required to remove from the Git stage the ignored file when we lunch the step again
782
820
  check_call(["git", "reset", "--mixed"])
783
821
 
@@ -788,35 +826,35 @@ rules:
788
826
  step + 1,
789
827
  message="We will commit all the above files!\n"
790
828
  "If there are some files which should not be committed, then you should "
791
- "add them into the `.gitignore` file and launch upgrade {} again.".format(step),
829
+ f"add them into the `.gitignore` file and launch upgrade {step} again.",
792
830
  prompt="Then to commit your changes type:",
793
831
  )
794
832
 
795
833
  @Step(14, file_marker=False)
796
- def step14(self, _):
834
+ def step14(self, _: int) -> None:
797
835
  if os.path.isfile(".UPGRADE_INSTRUCTIONS"):
798
836
  os.unlink(".UPGRADE_INSTRUCTIONS")
799
837
  check_call(
800
838
  [
801
839
  "git",
802
840
  "commit",
803
- "--message=Upgrade to GeoMapFish {}".format(
804
- pkg_resources.get_distribution("c2cgeoportal_commons").version
805
- ),
841
+ "--message=Upgrade to GeoMapFish "
842
+ f"{pkg_resources.get_distribution('c2cgeoportal_commons').version}",
806
843
  ]
807
844
  )
808
845
 
809
846
  print("")
810
847
  print(self.color_bar)
811
848
  print("")
812
- print(colorize("Congratulations, your upgrade was successful.", GREEN))
849
+ print(colorize("Congratulations, your upgrade was successful.", Color.GREEN))
813
850
  print("")
814
851
  branch = check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).decode("utf-8").strip()
815
852
  print("Now all your files are committed; you should do a git push:")
816
- print("git push {0!s} {1!s}.".format(self.options.git_remote, branch))
853
+ print(f"git push {self.options.git_remote} {branch}.")
817
854
 
818
855
 
819
- def check_git_status_output(args=None):
856
+ def check_git_status_output(args: Optional[List[str]] = None) -> str:
857
+ """Check if there is something that's not committed."""
820
858
  return check_output(["git", "status", "--short"] + (args if args is not None else [])).decode("utf-8")
821
859
 
822
860