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