Compare commits
41 Commits
0.0.1.post
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| b561ac2577 | |||
| 7bab9f4a6b | |||
| 23a4b3794d | |||
|
|
d80ff553df | ||
|
|
88d06544c6 | ||
| ea7e642460 | |||
|
|
1db94a6c6b | ||
| 46f62367f5 | |||
|
|
439333ed59 | ||
| a249968a9d | |||
|
|
7d8d87b178 | ||
| 0c59a108f0 | |||
|
|
45d132c5ca | ||
| 0725782101 | |||
|
|
cd3a937423 | ||
|
|
5fdabae600 | ||
| 679db81ca6 | |||
|
|
d0cdad663d | ||
|
|
2b918837fd | ||
|
|
b78cbae422 | ||
| 639632b022 | |||
|
|
8797bd3ee1 | ||
|
|
6bfbc85758 | ||
| bce49c5f70 | |||
|
|
aa4e816bd2 | ||
| d6ebb953cf | |||
|
|
56badcbcf7 | ||
|
|
43721835be | ||
| f72833e6c1 | |||
|
|
29ec82d9ec | ||
| 085abb31f8 | |||
|
|
9250102184 | ||
|
|
04fbd77a97 | ||
|
|
d9f133bb14 | ||
|
|
af2aebd110 | ||
|
|
5d0ff79d05 | ||
|
|
00919c081f | ||
|
|
99beee0937 | ||
|
|
31b9f97d35 | ||
|
|
d8c78e7fc1 | ||
|
|
246d4c9529 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -42,4 +42,5 @@ helpers-results
|
||||
.coverage
|
||||
/.mypy_cache/
|
||||
.coverage
|
||||
.mypy_cache
|
||||
.mypy_cache
|
||||
test/tmp
|
||||
@@ -1,3 +1,12 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/pygamecfg/__init__.py=utf-8
|
||||
encoding//src/pygamecfg/__main__.py=utf-8
|
||||
encoding//src/pygamecfg/common_ut.py=utf-8
|
||||
encoding//src/pygamecfg/core_gamecfg.py=utf-8
|
||||
encoding//src/pygamecfg/game_cod4.py=utf-8
|
||||
encoding//src/pygamecfg/game_cod4_gungame.py=utf-8
|
||||
encoding//src/pygamecfg/game_cod4_promod.py=utf-8
|
||||
encoding//src/pygamecfg/game_ut2k4.py=utf-8
|
||||
encoding//src/pygamecfg/game_ut99.py=utf-8
|
||||
encoding//src/pygamecfg/tool_ini.py=utf-8
|
||||
encoding/<project>=UTF-8
|
||||
|
||||
71
Jenkinsfile
vendored
71
Jenkinsfile
vendored
@@ -27,7 +27,7 @@ def _bDraft = false
|
||||
// release content / changelog management
|
||||
def _bAutoChangelog = true //Not supported yet
|
||||
def _ReleaseContent_Title = "# _CI/CD Automatic Release_"
|
||||
def bPushMasterOnPypi = false
|
||||
def bPushMasterOnPypi = true
|
||||
// full rebuild toogle
|
||||
def _bFullRebuilt = true
|
||||
def _MkDocsWebURL = "dabauto--mkdocs-web.dmz.chacha.home/mkdocs-web/"
|
||||
@@ -183,8 +183,12 @@ pipeline {
|
||||
sh("virtualenv --pip=embed --setuptools=embed --wheel=embed --no-periodic-update --activators bash,python TEST_ENV")
|
||||
sh("virtualenv --pip=embed --setuptools=embed --wheel=embed --no-periodic-update --activators bash,python TOOLS_ENV")
|
||||
|
||||
sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade setuptools build pip copier jinja2-slug toml")
|
||||
sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade setuptools build pip")
|
||||
sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade 'copier==9.*' jinja2-slug toml")
|
||||
|
||||
sh(". ~/TEST_ENV/bin/activate && pip install --upgrade pip")
|
||||
|
||||
sh(". ~/TOOLS_ENV/bin/activate && pip install --upgrade pip")
|
||||
sh(". ~/TOOLS_ENV/bin/activate && pip install simple_rest_client requests twine packaging")
|
||||
|
||||
script {
|
||||
@@ -341,7 +345,7 @@ pipeline {
|
||||
|'''.strip()
|
||||
|
|
||||
|import copier
|
||||
|copier.run_copy("./", "../_gitrepo",vcs_ref="HEAD",use_prereleases=True,defaults=True,cleanup_on_error=False)
|
||||
|copier.run_copy("./", "../_gitrepo",vcs_ref="HEAD",use_prereleases=True,defaults=True,cleanup_on_error=False,unsafe=True)
|
||||
|
|
||||
|__EOWRAPPER__
|
||||
""".stripMargin())
|
||||
@@ -409,31 +413,39 @@ pipeline {
|
||||
stage("CheckCode") {
|
||||
steps {
|
||||
dir("gitrepo") {
|
||||
sh(". ~/TEST_ENV/bin/activate && python -m helpers --type-check --quality-check")
|
||||
sh(". ~/TEST_ENV/bin/activate && python -m chacha_cicd_helper --typecheck --qualitycheck")
|
||||
script {
|
||||
def jsonObj = readJSON file: "helpers-results/quality_check/metrics.json"
|
||||
def jsonObj = readJSON file: "helpers-results/cl_quality_check/metrics.json"
|
||||
quality_score = new BigDecimal(jsonObj["GlobalScore"])
|
||||
sz_quality_score = quality_score.setScale(2, RoundingMode.HALF_EVEN).toString()
|
||||
badge_quality.setStatus(sz_quality_score)
|
||||
badge_quality.setColor(getColorScale(quality_score))
|
||||
}
|
||||
sh(". ~/TEST_ENV/bin/activate && python -m helpers --complexity-check")
|
||||
sh(". ~/TEST_ENV/bin/activate && python -m chacha_cicd_helper --complexitycheck")
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
dir("gitrepo") {
|
||||
publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/types_check/cobertura.xml")]
|
||||
junit 'helpers-results/types_check/junit.xml'
|
||||
dir("gitrepo") {
|
||||
//publish coverage
|
||||
recordCoverage( sourceDirectories: [[path: 'src']],
|
||||
tools: [[parser: 'COBERTURA', pattern: 'helpers-results/cl_types_check/cobertura.xml']],
|
||||
id: 'COBERTURA', name: 'COBERTURA Coverage',
|
||||
sourceCodeRetention: 'EVERY_BUILD',)
|
||||
|
||||
//add type check to junit result set
|
||||
junit 'helpers-results/cl_types_check/junit.xml'
|
||||
|
||||
//publish html reports files
|
||||
publishHTML([
|
||||
reportDir: "helpers-results/quality_check",
|
||||
reportDir: "helpers-results/cl_quality_check",
|
||||
reportFiles: "report.html",
|
||||
reportName: "quality-report",
|
||||
allowMissing: false,
|
||||
alwaysLinkToLastBuild: true,
|
||||
keepAll: true])
|
||||
publishHTML([
|
||||
reportDir: "helpers-results/types_check",
|
||||
reportDir: "helpers-results/cl_types_check",
|
||||
reportFiles: "index.html",
|
||||
reportName: "types_check",
|
||||
allowMissing: false,
|
||||
@@ -447,7 +459,7 @@ pipeline {
|
||||
steps {
|
||||
|
||||
plot([ csvFileName: 'plot-df7f03dc-8146-11ed-a1eb-0242ac120002.csv',
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/quality_check/metrics_GlobalScore.csv', inclusionFlag: 'OFF', url: '']],
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/cl_quality_check/metrics_GlobalScore.csv', inclusionFlag: 'OFF', url: '']],
|
||||
group: 'metrics',
|
||||
title: 'code quality score',
|
||||
style: 'line',
|
||||
@@ -457,7 +469,7 @@ pipeline {
|
||||
yaxisMinimum: '0'])
|
||||
|
||||
plot([ csvFileName: 'plot-c731cc84-8145-11ed-a1eb-0242ac120002.csv',
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/quality_check/metrics_rawpercent.csv', inclusionFlag: 'OFF', url: '']],
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/cl_quality_check/metrics_rawpercent.csv', inclusionFlag: 'OFF', url: '']],
|
||||
group: 'metrics',
|
||||
title: 'code composition (%)',
|
||||
style: 'stackedArea',
|
||||
@@ -467,7 +479,7 @@ pipeline {
|
||||
yaxisMinimum: '0'])
|
||||
|
||||
plot([ csvFileName: 'plot-cac33982-8145-11ed-a1eb-0242ac120002.csv',
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/quality_check/metrics_Statistics.csv', inclusionFlag: 'OFF', url: '']],
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/cl_quality_check/metrics_Statistics.csv', inclusionFlag: 'OFF', url: '']],
|
||||
group: 'metrics',
|
||||
title: 'general statistics',
|
||||
style: 'line',
|
||||
@@ -475,7 +487,7 @@ pipeline {
|
||||
numBuilds: ''])
|
||||
|
||||
plot([ csvFileName: 'plot-cddaced2-8145-11ed-a1eb-0242ac120002.csv',
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/quality_check/metrics_MessagesCat.csv', inclusionFlag: 'OFF', url: '']],
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/cl_quality_check/metrics_MessagesCat.csv', inclusionFlag: 'OFF', url: '']],
|
||||
group: 'metrics',
|
||||
title: 'quality warnings',
|
||||
style: 'stackedArea',
|
||||
@@ -483,7 +495,7 @@ pipeline {
|
||||
numBuilds: ''])
|
||||
|
||||
plot([ csvFileName: 'plot-4ceb9ee2-ca78-11ed-afa1-0242ac120002.csv',
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/complexity_check/MI.csv', inclusionFlag: 'INCLUDE_BY_STRING',exclusionValues: 'MeanMaintainability', url: '']],
|
||||
csvSeries: [[ file: 'gitrepo/helpers-results/cl_complexity_check/MI.csv', inclusionFlag: 'INCLUDE_BY_STRING',exclusionValues: 'MeanMaintainability', url: '']],
|
||||
group: 'metrics',
|
||||
title: 'maintainability',
|
||||
style: 'stackedArea',
|
||||
@@ -495,14 +507,14 @@ pipeline {
|
||||
stage("RunUnitTests") {
|
||||
steps {
|
||||
dir("gitrepo") {
|
||||
sh(". ~/TEST_ENV/bin/activate && python -m helpers --unit-test --coverage-check")
|
||||
sh(". ~/TEST_ENV/bin/activate && python -m chacha_cicd_helper --unittest --coveragecheck")
|
||||
script {
|
||||
unit_test_full_name__html=findFiles(glob: "helpers-results/unit_test_full/*.html")[0].getName()
|
||||
unit_test_full_name__html=findFiles(glob: "helpers-results/cl_unit_test_full/*.html")[0].getName()
|
||||
println unit_test_full_name__html
|
||||
unit_test_full_name__xml=findFiles(glob: "helpers-results/unit_test_full/*.xml")[0].getName()
|
||||
unit_test_full_name__xml=findFiles(glob: "helpers-results/cl_unit_test_full/*.xml")[0].getName()
|
||||
println unit_test_full_name__xml
|
||||
|
||||
coverage_report_path = "helpers-results/unit_test_coverage/test_coverage.xml"
|
||||
coverage_report_path = "helpers-results/cl_unit_test_coverage/test_coverage.xml"
|
||||
println GetCoverageValue_lines_valid(coverage_report_path)
|
||||
println GetCoverageValue_lines_covered(coverage_report_path)
|
||||
println GetCoverageValue_line_rate(coverage_report_path)
|
||||
@@ -517,7 +529,7 @@ pipeline {
|
||||
badge_coverage.setColor(getColorScale(full_rate))
|
||||
|
||||
//badge_maintainability
|
||||
records = readCSV file: 'helpers-results/complexity_check/MI.csv'
|
||||
records = readCSV file: 'helpers-results/cl_complexity_check/MI.csv'
|
||||
maintainability = records[1][1]
|
||||
badge_maintainability.setStatus(maintainability)
|
||||
|
||||
@@ -532,11 +544,11 @@ pipeline {
|
||||
post {
|
||||
always {
|
||||
dir("gitrepo") {
|
||||
junit 'helpers-results/unit_test/*.xml'
|
||||
junit 'helpers-results/cl_unit_test/*.xml'
|
||||
// using cobertura format (= coverage xml format)
|
||||
publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/unit_test_coverage/test_coverage.xml")]
|
||||
recordCoverage(tools: [[parser: 'COBERTURA', pattern: 'helpers-results/cl_unit_test_coverage/test_coverage.xml']])
|
||||
publishHTML([
|
||||
reportDir: "helpers-results/unit_test_coverage",
|
||||
reportDir: "helpers-results/cl_unit_test_coverage",
|
||||
reportFiles: "index.html",
|
||||
reportName: "coverage-report-html",
|
||||
allowMissing: false,
|
||||
@@ -544,7 +556,7 @@ pipeline {
|
||||
keepAll: true])
|
||||
|
||||
publishHTML([
|
||||
reportDir: "helpers-results/unit_test_full",
|
||||
reportDir: "helpers-results/cl_unit_test_full",
|
||||
reportFiles: unit_test_full_name__html,
|
||||
reportName: "test-reports-full",
|
||||
allowMissing: false,
|
||||
@@ -558,15 +570,14 @@ pipeline {
|
||||
stage("GenDOC") {
|
||||
steps {
|
||||
dir("gitrepo") {
|
||||
//--doc-gen-pdf
|
||||
sh(". ~/TEST_ENV/bin/activate && python -m helpers --doc-gen --doc-gen-pdf")
|
||||
sh(". ~/TEST_ENV/bin/activate && python -m chacha_cicd_helper --docgen --docgenpdf")
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
dir("gitrepo") {
|
||||
publishHTML([
|
||||
reportDir: "helpers-results/doc_gen/site",
|
||||
reportDir: "helpers-results/cl_doc_gen/site",
|
||||
reportFiles: "index.html",
|
||||
reportName: "doc-html",
|
||||
allowMissing: false,
|
||||
@@ -671,11 +682,11 @@ pipeline {
|
||||
|
|
||||
|data = {
|
||||
| "name": "Documentation (pdf)",
|
||||
| 'attachment': ("${PY_PROJECT_NAME}_${PY_PROJECT_VERSION}_UserManual.pdf", open("helpers-results/doc_gen/site/pdf/manual.pdf", 'rb')),
|
||||
| 'attachment': ("${PY_PROJECT_NAME}_${PY_PROJECT_VERSION}_UserManual.pdf", open("helpers-results/cl_doc_gen/site/pdf/manual.pdf", 'rb')),
|
||||
|}
|
||||
|GiteaApi.assets.post("${_PROJECT_USER_NAME}","${PY_PROJECT_NAME}",new_release_id,files=data)
|
||||
|
|
||||
|shutil.make_archive("doc", 'zip', "helpers-results/doc_gen/site")
|
||||
|shutil.make_archive("doc", 'zip', "helpers-results/cl_doc_gen/site")
|
||||
|reqData={
|
||||
| "SECRET": "${MKDOCSTOKEN}",
|
||||
| "USER": "${_PROJECT_USER_NAME}",
|
||||
|
||||
40
README.md
40
README.md
@@ -8,46 +8,8 @@
|
||||
|
||||

|
||||
|
||||
# Python project template
|
||||
# pyGameCFG
|
||||
|
||||
A nice template to start blank python projets.
|
||||
|
||||
This template automate a lot of handy things and allow CI/CD automatic releases generation.
|
||||
|
||||
It is also collectings data to feed Jenkins build.
|
||||
|
||||
Checkout [Latest Documentation](https://chacha.ddns.net/mkdocs-web/chacha/{{repository}}/{{branch}}/latest/).
|
||||
|
||||
## Features
|
||||
|
||||
### Generic pipeline skeleton:
|
||||
- Prepare
|
||||
- GetCode
|
||||
- BuildPackage
|
||||
- Install
|
||||
- CheckCode
|
||||
- PlotMetrics
|
||||
- RunUnitTests
|
||||
- GenDOC
|
||||
- PostRelease
|
||||
|
||||
### CI/CD Environment
|
||||
- Jenkins
|
||||
- Gitea (with patch for dynamic Readme variables: https://chacha.ddns.net/gitea/chacha/GiteaMarkupVariable)
|
||||
- Docker
|
||||
- MkDocsWeb
|
||||
|
||||
### CI/CD Helper libs
|
||||
- VirtualEnv
|
||||
- Changelog generation based on commits
|
||||
- copier
|
||||
- pylint + pylint_json2html
|
||||
- mypy
|
||||
- unittest + xmlrunner + junitparser + junit2htmlreport
|
||||
- mkdocs
|
||||
|
||||
### Python project
|
||||
- Full .toml implementation
|
||||
- .whl automatic generation
|
||||
- dynamic versionning using git repository
|
||||
- embedded unit-test
|
||||
@@ -2,14 +2,15 @@
|
||||
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/${project_name}/helpers"/>
|
||||
<listEntry value="/pygamecfg/helpers_proxy"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="2"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING" value="UTF-8"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pygamecfg/helpers_proxy}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--complexity-check"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--complexitycheck"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="pygamecfg"/>
|
||||
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/${project_name}/helpers"/>
|
||||
<listEntry value="/pygamecfg/helpers_proxy"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="2"/>
|
||||
</listAttribute>
|
||||
<mapAttribute key="org.eclipse.debug.core.environmentVariables">
|
||||
<mapEntry key="PATH" value="C:\Program Files\GTK3-Runtime Win64\bin"/>
|
||||
</mapAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING" value="UTF-8"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pygamecfg/helpers_proxy}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--doc-gen --doc-gen-pdf"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--docgen --docgenpdf"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="pygamecfg"/>
|
||||
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/${project_name}/helpers"/>
|
||||
<listEntry value="/pygamecfg/helpers_proxy"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="2"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING" value="UTF-8"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pygamecfg/helpers_proxy}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--type-check --quality-check"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--qualitycheck"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="pygamecfg"/>
|
||||
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/${project_name}/helpers"/>
|
||||
<listEntry value="/pygamecfg/helpers_proxy"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="2"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING" value="UTF-8"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pygamecfg/helpers_proxy}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--changelog-gen"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--typecheck"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="pygamecfg"/>
|
||||
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
|
||||
@@ -2,14 +2,15 @@
|
||||
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/${project_name}/helpers"/>
|
||||
<listEntry value="/pygamecfg/helpers_proxy"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="2"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING" value="UTF-8"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pygamecfg/helpers_proxy}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--unit-test --coverage-check"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--unittest --coveragecheck"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="pygamecfg"/>
|
||||
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
# Usage
|
||||
|
||||
## Pulvinar dolor
|
||||
Donec dapibus est fermentum justo volutpat condimentum. Integer quis nunc neque. Donec dictum vehicula justo, in facilisis ex tincidunt in.
|
||||
Vivamus sollicitudin sem dui, id mollis orci facilisis ut. Proin sed pulvinar dolor. Donec volutpat commodo urna imperdiet pulvinar. Fusce eget aliquam risus.
|
||||
Vivamus viverra luctus ex, in finibus mi. Nullam elementum dapibus mollis. Ut suscipit volutpat ex, quis feugiat lacus consectetur eu.
|
||||
|
||||
## Condimentum faucibus
|
||||
Quisque auctor egestas sem, luctus suscipit ex maximus vitae. Duis facilisis augue et condimentum faucibus.
|
||||
Donec cursus, enim a sagittis egestas, lectus lorem eleifend libero, at tincidunt leo magna at libero.
|
||||
Nunc eros velit, suscipit luctus tempor vel, finibus et est. Curabitur efficitur pretium pulvinar.
|
||||
Donec urna lectus, vulputate quis turpis sed, placerat congue urna. Phasellus aliquet fermentum quam, non auctor elit porta nec. Morbi eu ligula at nisl ultricies condimentum vitae id ante.
|
||||
|
||||
## Aliquam lacinia
|
||||
In volutpat lorem ex, et fringilla nibh faucibus quis. Mauris et arcu elementum, auctor dui vitae, egestas arcu. Duis sit amet aliquam quam.
|
||||
Phasellus a odio turpis. Etiam tristique mi eu enim varius, eget facilisis est vestibulum. Aliquam lacinia nec purus sed luctus. Cras at laoreet erat.
|
||||
1
helpers/.gitignore
vendored
1
helpers/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/.mypy_cache/
|
||||
@@ -1,7 +0,0 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
@@ -1,108 +0,0 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pathlib import Path
|
||||
import tomli
|
||||
import argparse
|
||||
import os
|
||||
import logging
|
||||
import sys
|
||||
|
||||
if __package__ == "helpers":
|
||||
# when calling the module from: > python -m helpers
|
||||
from .types_check import types_check
|
||||
from .quality_check import quality_check
|
||||
from .unit_test import unit_test
|
||||
from .doc_gen import doc_gen
|
||||
from .complexity_check import complexity_check
|
||||
else:
|
||||
# when calling the __main__.py file (from IDE)
|
||||
from helpers.types_check import types_check
|
||||
from helpers.quality_check import quality_check
|
||||
from helpers.unit_test import unit_test
|
||||
from helpers.doc_gen import doc_gen
|
||||
from helpers.complexity_check import complexity_check
|
||||
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
if __name__ == "__main__":
|
||||
project_rootdir_path = Path(__file__).parent.parent.absolute()
|
||||
|
||||
with open(project_rootdir_path / "pyproject.toml", mode="rb") as fp:
|
||||
pyproject = tomli.load(fp)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="continuous-integration-helper", description="A tiny set of scripts to help continous integration on python"
|
||||
)
|
||||
|
||||
parser.add_argument("-tc", "--type-check", dest="typecheck", action="store_true", help="enable static typing check")
|
||||
|
||||
parser.add_argument("-ut", "--unit-test", dest="unittest", action="store_true", help="enable unit-test")
|
||||
parser.add_argument(
|
||||
"-cc", "--coverage-check", dest="coveragecheck", action="store_true", help="enable unit-test coverage check (requires unit-test)"
|
||||
)
|
||||
|
||||
parser.add_argument("-qc", "--quality-check", dest="qualitycheck", action="store_true", help="enable code quality check")
|
||||
|
||||
parser.add_argument("-dg", "--doc-gen", dest="docgen", action="store_true", help="enable documentation generation using MkDoc")
|
||||
parser.add_argument(
|
||||
"-pdf", "--doc-gen-pdf", dest="docgenpdf", action="store_true", help="enable pdf documentation export (requires doc-gen)"
|
||||
)
|
||||
|
||||
parser.add_argument("-cpc", "--complexity-check", dest="complexitycheck", action="store_true", help="enable complexity check")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
##################################
|
||||
# Dev / Debug forced toogles
|
||||
#
|
||||
# --------------------------------
|
||||
#
|
||||
# args.typecheck = True
|
||||
# args.qualitycheck = True
|
||||
# args.unittest = True
|
||||
# args.coveragecheck = True
|
||||
# args.docgen = True
|
||||
# args.docgenpdf = True
|
||||
# args.complexitycheck = True
|
||||
|
||||
helpers = []
|
||||
if args.typecheck == True:
|
||||
helpers.append(types_check)
|
||||
|
||||
if args.unittest == True:
|
||||
helpers.append(unit_test)
|
||||
|
||||
if args.coveragecheck == True:
|
||||
if args.unittest == True:
|
||||
unit_test.enable_coverage_check = True
|
||||
else:
|
||||
raise RuntimeError("unit-test is required to enable coverage-check")
|
||||
|
||||
if args.qualitycheck == True:
|
||||
helpers.append(quality_check)
|
||||
|
||||
if args.docgen == True:
|
||||
helpers.append(doc_gen)
|
||||
|
||||
if args.docgenpdf == True:
|
||||
if args.docgen == True:
|
||||
doc_gen.enable_gen_pdf = True
|
||||
else:
|
||||
raise RuntimeError("doc-gen is required to enable doc-gen-pdf")
|
||||
|
||||
if args.complexitycheck == True:
|
||||
helpers.append(complexity_check)
|
||||
|
||||
for helper in helpers:
|
||||
helper.set_context(project_rootdir_path, pyproject)
|
||||
helper.reset_result_dir()
|
||||
helper.do_job()
|
||||
@@ -1,70 +0,0 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
# from pathlib import Path
|
||||
# import os
|
||||
import statistics
|
||||
import csv
|
||||
from json import loads as JSON_LOADS
|
||||
from radon.complexity import cc_rank, SCORE
|
||||
from radon.cli import Config
|
||||
from radon.cli.harvest import CCHarvester, HCHarvester, MIHarvester
|
||||
|
||||
from .helper_base import helper_withresults_base
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
class complexity_check(helper_withresults_base):
|
||||
@classmethod
|
||||
def do_job(cls):
|
||||
config = Config(
|
||||
exclude="__init__\.py",
|
||||
ignore=None,
|
||||
order=SCORE,
|
||||
show_closures=False,
|
||||
no_assert=True,
|
||||
min="A",
|
||||
max="F",
|
||||
multi=False,
|
||||
)
|
||||
|
||||
h = MIHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
|
||||
res = JSON_LOADS(h)
|
||||
|
||||
with open(cls.get_result_dir() / "MI.json", "w", newline="") as oFile:
|
||||
oFile.write(h)
|
||||
|
||||
mean = statistics.mean(_["mi"] for _ in res.values())
|
||||
|
||||
if mean >= 65:
|
||||
rank = "A+"
|
||||
elif mean >= 20:
|
||||
rank = "A"
|
||||
elif mean >= 10:
|
||||
rank = "B"
|
||||
else:
|
||||
rank = "C"
|
||||
|
||||
RES_MI = {"MeanMaintainability": mean, "MaintainabilityIndex": rank}
|
||||
with open(cls.get_result_dir() / "MI.csv", "w", newline="") as oFile:
|
||||
writer = csv.DictWriter(oFile, fieldnames=RES_MI.keys())
|
||||
writer.writeheader()
|
||||
writer.writerow(RES_MI)
|
||||
|
||||
config = Config(exclude=None, ignore=None, order=SCORE, show_closures=False, no_assert=True, min="A", max="F", multi=False)
|
||||
h = CCHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
|
||||
with open(cls.get_result_dir() / "CC.json", "w", newline="") as oFile:
|
||||
oFile.write(h)
|
||||
|
||||
config = Config(exclude=None, ignore=None, order=SCORE, show_closures=False, no_assert=True, min="A", max="F", by_function=None)
|
||||
h = HCHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
|
||||
with open(cls.get_result_dir() / "HC.json", "w", newline="") as oFile:
|
||||
oFile.write(h)
|
||||
@@ -1,98 +0,0 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import shutil
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from distutils.dir_util import copy_tree
|
||||
|
||||
import yaml
|
||||
|
||||
try:
|
||||
from yaml import CLoader as Loader, CDumper as Dumper
|
||||
except ImportError:
|
||||
from yaml import Loader, Dumper
|
||||
|
||||
from .helper_base import helper_withresults_base
|
||||
|
||||
|
||||
class doc_gen(helper_withresults_base):
|
||||
enable_gen_pdf: bool = False
|
||||
|
||||
@classmethod
|
||||
def do_job(cls):
|
||||
|
||||
# create doc root dir
|
||||
doc_path = cls.project_rootdir_path / "docs"
|
||||
cls._reset_dir(doc_path)
|
||||
|
||||
site_path = cls.get_result_dir() / "site"
|
||||
cls._reset_dir(site_path)
|
||||
|
||||
# copy files from main project dir
|
||||
shutil.copyfile(str(cls.project_rootdir_path / "README.md"), str(doc_path / "README.md"))
|
||||
shutil.copyfile(str(cls.project_rootdir_path / "LICENSE.md"), str(doc_path / "LICENSE.md"))
|
||||
|
||||
# copy files from static-doc dir
|
||||
copy_tree(str(cls.project_rootdir_path / "docs-static"), str(doc_path))
|
||||
|
||||
# generating API doc + nav from python docstrings
|
||||
reference_path = doc_path / "reference"
|
||||
cls._reset_dir(reference_path)
|
||||
|
||||
for path in sorted((cls.project_rootdir_path / "src").rglob("*.py")):
|
||||
module_path = path.relative_to(cls.project_rootdir_path / "src").with_suffix("")
|
||||
doc_path = path.relative_to(cls.project_rootdir_path / "src").with_suffix(".md")
|
||||
full_doc_path = Path(reference_path, doc_path)
|
||||
|
||||
parts = list(module_path.parts)
|
||||
|
||||
if parts[-1] == "__init__":
|
||||
parts = parts[:-1]
|
||||
elif parts[-1] == "__main__":
|
||||
continue
|
||||
|
||||
cls._reset_dir(os.path.dirname(full_doc_path))
|
||||
with open(full_doc_path, "w+") as fd:
|
||||
identifier = "src." + ".".join(parts)
|
||||
print("::: " + identifier, file=fd)
|
||||
|
||||
cmdopts = [f"{sys.executable}", "-m", "mkdocs", "-v", "build", "--site-dir", str(site_path), "--clean"]
|
||||
|
||||
# little hack here, to enable / disable pdf generation using own class config
|
||||
# => reason is mkdocs seems to try loading the plugin even if we disable it, so we need to
|
||||
# manually process the configuration file.
|
||||
with open(cls.project_rootdir_path / "mkdocs.yml", "r") as mkdocsCfgFile:
|
||||
mkdocsCfg = yaml.load(mkdocsCfgFile, Loader=yaml.Loader)
|
||||
|
||||
if "plugins" in mkdocsCfg:
|
||||
mkdocsCfg["plugins"] = [_ for _ in mkdocsCfg["plugins"] if (not isinstance(_, dict) or "with-pdf" not in _.keys())]
|
||||
|
||||
if cls.enable_gen_pdf == True:
|
||||
mkdocsCfg["plugins"].append(
|
||||
{
|
||||
"with-pdf": {
|
||||
"cover_subtitle": "User Manual",
|
||||
"cover_logo": str(cls.project_rootdir_path / "docs-static" / "Library.jpg"),
|
||||
"verbose": False,
|
||||
"exclude_pages": ["LICENSE"],
|
||||
"output_path": str(site_path / "pdf" / "manual.pdf"),
|
||||
}
|
||||
}
|
||||
)
|
||||
with open(cls.project_rootdir_path / "mkdocs.yml", "w") as mkdocsCfgFile:
|
||||
mkdocsCfgFile.write(yaml.dump(mkdocsCfg, Dumper=Dumper, default_flow_style=False, sort_keys=False))
|
||||
|
||||
res = cls.run_cmd(cmdopts)
|
||||
print(res.decode())
|
||||
print(" !! done")
|
||||
@@ -1,75 +0,0 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
if TYPE_CHECKING: # Only imports the below statements during type checking
|
||||
from typing import Union
|
||||
|
||||
|
||||
class helper_base(ABC):
|
||||
project_rootdir_path: Union[Path, None] = None
|
||||
pyproject: Union[dict, None] = None
|
||||
current_dir: Union[Path, None] = None
|
||||
|
||||
@classmethod
|
||||
def set_context(cls, project_rootdir_path: Path, pyproject: dict):
|
||||
cls.project_rootdir_path = project_rootdir_path
|
||||
cls.pyproject = pyproject
|
||||
cls.current_dir = Path(__file__).parent.absolute()
|
||||
|
||||
@classmethod
|
||||
def get_result_dir(cls):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _reset_dir(dirpath: Path):
|
||||
dirpath = Path(dirpath)
|
||||
if not os.path.exists(dirpath):
|
||||
os.makedirs(dirpath)
|
||||
[f.unlink() for f in Path(dirpath).glob("*") if f.is_file()]
|
||||
|
||||
@classmethod
|
||||
def reset_result_dir(cls):
|
||||
result_dir = cls.get_result_dir()
|
||||
if result_dir != None:
|
||||
cls._reset_dir(result_dir)
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def do_job(cls):
|
||||
raise NotImplementedError()
|
||||
|
||||
@classmethod
|
||||
def run_cmd_(cls, cmdarray):
|
||||
process = subprocess.run(cmdarray, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, check=True)
|
||||
return process.stdout
|
||||
|
||||
@classmethod
|
||||
def run_cmd(cls, cmdarray, silent: bool = False):
|
||||
p = subprocess.run(cmdarray, capture_output=True)
|
||||
if not silent:
|
||||
print(p.stdout.decode())
|
||||
print(p.stderr.decode())
|
||||
return p.stdout
|
||||
|
||||
|
||||
class helper_withresults_base(helper_base):
|
||||
helper_results_dir: Union[Path, None] = None
|
||||
|
||||
@classmethod
|
||||
def get_result_dir(cls):
|
||||
if cls.helper_results_dir == None:
|
||||
cls.helper_results_dir = cls.__name__
|
||||
return Path(__file__).parent.parent.absolute() / "helpers-results" / cls.helper_results_dir
|
||||
@@ -1,247 +0,0 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from contextlib import redirect_stdout
|
||||
from io import StringIO
|
||||
import re
|
||||
import json
|
||||
from enum import Enum
|
||||
from contextlib import suppress
|
||||
import sys
|
||||
import pandas
|
||||
import csv
|
||||
import copy
|
||||
|
||||
from pylint.lint import Run as pylint_Run
|
||||
import pylint_json2html
|
||||
|
||||
from .helper_base import helper_withresults_base
|
||||
|
||||
|
||||
class PyLintMetricNotFound(Warning):
|
||||
pass
|
||||
|
||||
|
||||
class quality_check(helper_withresults_base):
|
||||
PylintMessageList = dict()
|
||||
|
||||
@classmethod
|
||||
def GetPylintMessageList(cls):
|
||||
Messagelist = dict()
|
||||
regex = r"^:([a-zA-Z-]+) \(([^\)]+)\)"
|
||||
for line in cls.run_cmd([sys.executable, "-m", "pylint", "--list-msgs"], True).splitlines():
|
||||
if res := re.search(regex, line.decode()):
|
||||
Messagelist[res.group(1)] = res.group(2)
|
||||
cls.PylintMessageList = Messagelist
|
||||
|
||||
@staticmethod
|
||||
def TryExtractPYReportMetric(line: str, tag: str):
|
||||
regex = f"^(?:\|{tag}\s*\|)(\d+)(?=\s*|)"
|
||||
if res := re.search(regex, line):
|
||||
return float(res.group(1))
|
||||
raise PyLintMetricNotFound()
|
||||
|
||||
@classmethod
|
||||
def do_job(cls):
|
||||
print("checking code quality ...")
|
||||
|
||||
cls.GetPylintMessageList()
|
||||
|
||||
RES_all = dict()
|
||||
with StringIO() as StdOutput:
|
||||
JsonContent = ""
|
||||
with redirect_stdout(StdOutput):
|
||||
pylint_Run(
|
||||
[
|
||||
"--load-plugins=pylint.extensions.mccabe",
|
||||
"--output-format=json,parseable",
|
||||
"--disable=invalid-name",
|
||||
"--ignore=_version.py",
|
||||
"--reports=y",
|
||||
"--score=yes",
|
||||
"--max-line-length=140",
|
||||
"src." + cls.pyproject["project"]["name"],
|
||||
],
|
||||
exit=False,
|
||||
)
|
||||
|
||||
with open(cls.get_result_dir() / "report.json", "w+", encoding="utf-8") as Outfile:
|
||||
# hacky way of exctracting json + having overall score...
|
||||
class TScanState(Enum):
|
||||
TEXT_REPORT = 1
|
||||
JSON_REPORT = 2
|
||||
OTHER_REPORT_START = 3
|
||||
OTHER_REPORT_STATISTICS = 4
|
||||
OTHER_REPORT_METRICS = 5
|
||||
OTHER_REPORT_DUPLICATION = 6
|
||||
OTHER_REPORT_MESSAGES_CAT = 7
|
||||
OTHER_REPORT_MESSAGES = 8
|
||||
OTHER_REPORT_END = 99
|
||||
|
||||
RES_all["Statistics"] = dict()
|
||||
RES_all["RawMetrics"] = dict()
|
||||
RES_all["RawMetricsPercent"] = dict()
|
||||
RES_all["Duplication"] = dict()
|
||||
RES_all["MessagesCat"] = dict()
|
||||
RES_all["Messages"] = dict()
|
||||
RES_all["GlobalScore"] = -999
|
||||
RES_all["NbAnalysedStatments"] = -999
|
||||
RES_all["NbAnalysedLines"] = -999
|
||||
|
||||
ScanState = TScanState.TEXT_REPORT
|
||||
for line in StdOutput.getvalue().split("\n"):
|
||||
print(line)
|
||||
if ScanState == TScanState.TEXT_REPORT:
|
||||
# ignoring this part, we need json
|
||||
if line == "[":
|
||||
JsonContent += line
|
||||
ScanState = TScanState.JSON_REPORT
|
||||
elif line == "[]":
|
||||
JsonContent += line
|
||||
ScanState = TScanState.OTHER_REPORT_START
|
||||
|
||||
elif ScanState == TScanState.JSON_REPORT:
|
||||
JsonContent += line
|
||||
if line == "]":
|
||||
ScanState = TScanState.OTHER_REPORT_START
|
||||
|
||||
elif ScanState == TScanState.OTHER_REPORT_START:
|
||||
if res := re.search(r"^(\d+)(?= statements analysed.)", line):
|
||||
RES_all["NbAnalysedStatments"] = float(res.group(1))
|
||||
if line == "Statistics by type":
|
||||
ScanState = TScanState.OTHER_REPORT_STATISTICS
|
||||
|
||||
elif ScanState == TScanState.OTHER_REPORT_STATISTICS:
|
||||
if res := re.search(r"^(\d+)(?= lines have been analyzed)", line):
|
||||
RES_all["NbAnalysedLines"] = float(res.group(1))
|
||||
elif line == "Raw metrics":
|
||||
ScanState = TScanState.OTHER_REPORT_METRICS
|
||||
else:
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["Statistics"]["module"] = cls.TryExtractPYReportMetric(line, "module")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["Statistics"]["class"] = cls.TryExtractPYReportMetric(line, "class")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["Statistics"]["method"] = cls.TryExtractPYReportMetric(line, "method")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["Statistics"]["function"] = cls.TryExtractPYReportMetric(line, "function")
|
||||
|
||||
elif ScanState == TScanState.OTHER_REPORT_METRICS:
|
||||
if line == "Duplication":
|
||||
RES_all["RawMetricsPercent"]["code"] = RES_all["RawMetrics"]["code"] / RES_all["NbAnalysedLines"]
|
||||
RES_all["RawMetricsPercent"]["docstring"] = RES_all["RawMetrics"]["docstring"] / RES_all["NbAnalysedLines"]
|
||||
RES_all["RawMetricsPercent"]["comment"] = RES_all["RawMetrics"]["comment"] / RES_all["NbAnalysedLines"]
|
||||
RES_all["RawMetricsPercent"]["empty"] = RES_all["RawMetrics"]["empty"] / RES_all["NbAnalysedLines"]
|
||||
ScanState = TScanState.OTHER_REPORT_DUPLICATION
|
||||
else:
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["RawMetrics"]["code"] = cls.TryExtractPYReportMetric(line, "code")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["RawMetrics"]["docstring"] = cls.TryExtractPYReportMetric(line, "docstring")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["RawMetrics"]["comment"] = cls.TryExtractPYReportMetric(line, "comment")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["RawMetrics"]["empty"] = cls.TryExtractPYReportMetric(line, "empty")
|
||||
|
||||
elif ScanState == TScanState.OTHER_REPORT_DUPLICATION:
|
||||
if line == "Messages by category":
|
||||
ScanState = TScanState.OTHER_REPORT_MESSAGES_CAT
|
||||
else:
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["Duplication"]["NbDupLines"] = cls.TryExtractPYReportMetric(line, "nb duplicated lines")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["Duplication"]["PersentDuplicatedLines"] = cls.TryExtractPYReportMetric(
|
||||
line, "percent duplicated lines"
|
||||
)
|
||||
|
||||
elif ScanState == TScanState.OTHER_REPORT_MESSAGES_CAT:
|
||||
if line == "Messages":
|
||||
ScanState = TScanState.OTHER_REPORT_MESSAGES
|
||||
else:
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["MessagesCat"]["Convention"] = cls.TryExtractPYReportMetric(line, "convention")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["MessagesCat"]["Refactor"] = cls.TryExtractPYReportMetric(line, "refactor")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["MessagesCat"]["Warning"] = cls.TryExtractPYReportMetric(line, "warning")
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["MessagesCat"]["Error"] = cls.TryExtractPYReportMetric(line, "error")
|
||||
|
||||
elif ScanState == TScanState.OTHER_REPORT_MESSAGES:
|
||||
# approx match because the number of '-' depend on screen width..
|
||||
if line.startswith("--------"):
|
||||
ScanState = TScanState.OTHER_REPORT_END
|
||||
else:
|
||||
for PylintMessage in cls.PylintMessageList.keys():
|
||||
with suppress(PyLintMetricNotFound):
|
||||
RES_all["Messages"][PylintMessage] = cls.TryExtractPYReportMetric(line, PylintMessage)
|
||||
|
||||
elif ScanState == TScanState.OTHER_REPORT_END:
|
||||
if res := re.search(r"(?<=Your code has been rated at )(\d+(?:\.\d+)?)/10", line):
|
||||
RES_all["GlobalScore"] = float(res.group(1))
|
||||
print(RES_all["GlobalScore"])
|
||||
else:
|
||||
raise RuntimeError("Invalid ScanState")
|
||||
Outfile.write(JsonContent)
|
||||
|
||||
with open(cls.get_result_dir() / "metrics.json", "w") as json_file:
|
||||
json.dump(RES_all, json_file)
|
||||
|
||||
# exporting all Data in one csv, unused atm because jenkins seems not able to select columns from csv an keep displaying all...
|
||||
# => to export a working full csv we need to a 'flat' dict (no more nested dict)
|
||||
RES_all_trim = copy.deepcopy(RES_all)
|
||||
del RES_all_trim["Messages"]
|
||||
flat_RES_all = pandas.json_normalize(RES_all_trim, sep="_").to_dict(orient="records")[0]
|
||||
|
||||
with open(cls.get_result_dir() / "metrics.csv", "w", newline="") as csv_file:
|
||||
writer = csv.DictWriter(csv_file, fieldnames=flat_RES_all.keys())
|
||||
writer.writeheader()
|
||||
writer.writerow(flat_RES_all)
|
||||
|
||||
# splited csv exports for jenkins plots: RawMetricsPercent
|
||||
RES_all_percent = RES_all["RawMetricsPercent"]
|
||||
with open(cls.get_result_dir() / "metrics_rawpercent.csv", "w", newline="") as csv_file:
|
||||
writer = csv.DictWriter(csv_file, fieldnames=RES_all_percent.keys())
|
||||
writer.writeheader()
|
||||
writer.writerow(RES_all_percent)
|
||||
|
||||
# splited csv exports for jenkins plots: Statistics + Duplication + NbAnalysedStatments + NbAnalysedLines
|
||||
RES_all_stats = copy.deepcopy(RES_all["Statistics"])
|
||||
RES_all_stats["NbDupLines"] = RES_all["Duplication"]["NbDupLines"]
|
||||
RES_all_stats["PersentDuplicatedLines"] = RES_all["Duplication"]["PersentDuplicatedLines"]
|
||||
RES_all_stats["NbAnalysedStatments"] = RES_all["NbAnalysedStatments"]
|
||||
RES_all_stats["NbAnalysedLines"] = RES_all["NbAnalysedLines"]
|
||||
with open(cls.get_result_dir() / "metrics_Statistics.csv", "w", newline="") as csv_file:
|
||||
writer = csv.DictWriter(csv_file, fieldnames=RES_all_stats.keys())
|
||||
writer.writeheader()
|
||||
writer.writerow(RES_all_stats)
|
||||
|
||||
# splited csv exports for jenkins plots: Statistics + Duplication
|
||||
RES_all_MessagesCat = RES_all["MessagesCat"]
|
||||
with open(cls.get_result_dir() / "metrics_MessagesCat.csv", "w", newline="") as csv_file:
|
||||
writer = csv.DictWriter(csv_file, fieldnames=RES_all_MessagesCat.keys())
|
||||
writer.writeheader()
|
||||
writer.writerow(RES_all_MessagesCat)
|
||||
|
||||
# splited csv exports for jenkins plots: GlobalScore
|
||||
RES_GlobalScore = {"GlobalScore": RES_all["GlobalScore"]}
|
||||
with open(cls.get_result_dir() / "metrics_GlobalScore.csv", "w", newline="") as csv_file:
|
||||
writer = csv.DictWriter(csv_file, fieldnames=RES_GlobalScore.keys())
|
||||
writer.writeheader()
|
||||
writer.writerow(RES_GlobalScore)
|
||||
|
||||
# converting the report using pylint_json2html (/!\ internal API, but as their is no leading '_' ...)
|
||||
with open(cls.get_result_dir() / "report.html", "w+", encoding="utf-8") as Outfile:
|
||||
raw_data = json.loads(JsonContent)
|
||||
report = pylint_json2html.Report(raw_data)
|
||||
Outfile.write(report.render())
|
||||
|
||||
print("Done")
|
||||
@@ -1,60 +0,0 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from mypy import api
|
||||
|
||||
from .helper_base import helper_withresults_base
|
||||
|
||||
|
||||
class types_check(helper_withresults_base):
|
||||
JUnitReportName = "junit.xml"
|
||||
|
||||
@classmethod
|
||||
def do_job(cls):
|
||||
print("checking code typing ...")
|
||||
result = api.run(
|
||||
[ # project path
|
||||
"-p",
|
||||
"src." + cls.pyproject["project"]["name"],
|
||||
# analysis configuration
|
||||
# "--show-traceback",
|
||||
"--explicit-package-bases",
|
||||
# "--strict-equality",
|
||||
# "--check-untyped-defs",
|
||||
# reports generation
|
||||
"--cobertura-xml-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--html-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--txt-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--xml-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--junit-xml",
|
||||
str(cls.get_result_dir()) + "/" + cls.JUnitReportName,
|
||||
]
|
||||
)
|
||||
|
||||
if result[0]:
|
||||
print("\nType checking report:\n")
|
||||
print(result[0]) # stdout
|
||||
# converting the report using pylint_json2html (/!\ internal API, but as their is no leading '_' ...)
|
||||
with open(cls.get_result_dir() / "raw_eport.txt", "w+", encoding="utf-8") as Outfile:
|
||||
Outfile.write(result[0])
|
||||
|
||||
if result[1]:
|
||||
print("\nError report:\n")
|
||||
print(result[1]) # stderr
|
||||
|
||||
print("\nExit status:", result[2])
|
||||
print("Done")
|
||||
@@ -1,81 +0,0 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
import datetime
|
||||
|
||||
import unittest
|
||||
import xmlrunner
|
||||
from junitparser import JUnitXml
|
||||
from junit2htmlreport import parser as junit2html_parser
|
||||
|
||||
from .helper_base import helper_withresults_base
|
||||
|
||||
|
||||
class unit_test(helper_withresults_base):
|
||||
enable_coverage_check: bool = False
|
||||
enable_xml_export: bool = True
|
||||
enable_full_xml_export: bool = True
|
||||
FullReportName: str = "full_report"
|
||||
CoverageReportName: str = "test_coverage"
|
||||
|
||||
@classmethod
|
||||
def do_job(cls):
|
||||
if cls.enable_coverage_check == True:
|
||||
import coverage
|
||||
|
||||
# preparing unittest framework
|
||||
test_loader = unittest.TestLoader()
|
||||
|
||||
if cls.enable_coverage_check == True:
|
||||
# we start coverage now because module files discovery is part of the coverage measurement
|
||||
CoverageReportPath = Path(str(cls.get_result_dir()) + "_coverage")
|
||||
cls._reset_dir(CoverageReportPath)
|
||||
cov = coverage.Coverage(cover_pylib=False, branch=True, source_pkgs=["src." + cls.pyproject["project"]["name"]])
|
||||
cov.start()
|
||||
|
||||
package_tests = test_loader.discover(
|
||||
start_dir=str(cls.project_rootdir_path / "test"), top_level_dir=str(cls.project_rootdir_path / "test")
|
||||
)
|
||||
if cls.enable_xml_export:
|
||||
testRunner = xmlrunner.XMLTestRunner(output=str(str(cls.get_result_dir())))
|
||||
else:
|
||||
testRunner = unittest.TextTestRunner()
|
||||
|
||||
# running the test
|
||||
testRunner.run(package_tests)
|
||||
|
||||
print("Test Finished")
|
||||
if cls.enable_coverage_check == True:
|
||||
cov.stop()
|
||||
cov.save()
|
||||
cov.html_report(directory=str(CoverageReportPath))
|
||||
cov.xml_report(outfile=(CoverageReportPath / f"{cls.CoverageReportName}.xml"))
|
||||
|
||||
# computing results (Only if xml available)
|
||||
if cls.enable_full_xml_export == True:
|
||||
print("Full reports generation...")
|
||||
FullReportPath = Path(str(cls.get_result_dir()) + "_full")
|
||||
cls._reset_dir(FullReportPath)
|
||||
|
||||
FullJUnitReport = JUnitXml()
|
||||
for fname in [fname for fname in os.listdir(cls.get_result_dir()) if fname.endswith(".xml")]:
|
||||
FullJUnitReport += JUnitXml.fromfile(str(cls.get_result_dir() / fname))
|
||||
|
||||
current_datetime = datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
|
||||
full_report_base_name = f'{cls.pyproject["project"]["name"]}-{cls.FullReportName}-{current_datetime}'
|
||||
FullJUnitReport.write(str(FullReportPath / f"{full_report_base_name}.xml"))
|
||||
report = junit2html_parser.Junit(FullReportPath / f"{full_report_base_name}.xml")
|
||||
html = report.html()
|
||||
with open(FullReportPath / f"{full_report_base_name}.html", "wb") as outfile:
|
||||
outfile.write(html.encode("utf-8"))
|
||||
print("Done")
|
||||
5
helpers_proxy/__main__.py
Normal file
5
helpers_proxy/__main__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from chacha_cicd_helper.__main__ import fct_main
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
fct_main(sys.argv[1:])
|
||||
45
mkdocs.yml
45
mkdocs.yml
@@ -1,19 +1,11 @@
|
||||
# pyChaChaDummyProject (c) by chacha
|
||||
#
|
||||
# pyChaChaDummyProject is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
docs_dir: docs
|
||||
site_name: 'pygamecfg'
|
||||
site_url: 'https://chacha.ddns.net/mkdocs-web/chacha/pygamecfg/latest/'
|
||||
site_description: 'A simple game config tool that provide bash API to read / write game config files (cod, ut ...)'
|
||||
site_author: 'chacha'
|
||||
repo_url: 'https://chacha.ddns.net/gitea/chacha/pygamecfg'
|
||||
site_name: pygamecfg
|
||||
site_url: https://chacha.ddns.net/mkdocs-web/chacha/pygamecfg/latest/
|
||||
site_description: A simple ini parser / factory
|
||||
site_author: chacha
|
||||
repo_url: https://chacha.ddns.net/gitea/chacha/pygamecfg
|
||||
use_directory_urls: false
|
||||
copyright: 'CC BY-NC-SA 4.0'
|
||||
copyright: CC BY-NC-SA 4.0
|
||||
theme:
|
||||
name: material
|
||||
features:
|
||||
@@ -22,11 +14,11 @@ theme:
|
||||
- navigation.tabs
|
||||
- navigation.tabs.sticky
|
||||
- navigation.footer
|
||||
- toc.integrate
|
||||
- navigation.path
|
||||
- navigation.top
|
||||
- navigation.section
|
||||
- content.code.annotate
|
||||
- navigation.prune
|
||||
- navigation.expand
|
||||
- toc.follow
|
||||
palette:
|
||||
- media: '(prefers-color-scheme: dark)'
|
||||
@@ -52,19 +44,30 @@ plugins:
|
||||
default_handler: python
|
||||
handlers:
|
||||
python:
|
||||
path:
|
||||
- src
|
||||
options:
|
||||
filters:
|
||||
- '!^_[^_]'
|
||||
inherited_members: true
|
||||
inherited_members: false
|
||||
show_if_no_docstring: true
|
||||
show_signature_annotations: true
|
||||
show_source: false
|
||||
show_category_heading: true
|
||||
group_by_category: true
|
||||
docstring_section_style: spacy
|
||||
show_root_full_path: false
|
||||
merge_init_into_class: true
|
||||
separate_signature: true
|
||||
heading_level: 2
|
||||
docstring_section_style: spacy
|
||||
show_root_toc_entry: false
|
||||
- with-pdf:
|
||||
cover_subtitle: User Manual
|
||||
cover_logo: C:\Users\chacha\git\pygamecfg\docs-static\Library.jpg
|
||||
verbose: false
|
||||
exclude_pages:
|
||||
- LICENSE
|
||||
output_path: C:\Users\chacha\git\pygamecfg\helpers-results\cl_doc_gen\site\pdf\manual.pdf
|
||||
markdown_extensions:
|
||||
- def_list
|
||||
- tables
|
||||
@@ -111,8 +114,8 @@ markdown_extensions:
|
||||
- footnotes
|
||||
- pymdownx.superfences
|
||||
- pymdownx.emoji:
|
||||
emoji_index: !!python/name:materialx.emoji.twemoji
|
||||
emoji_generator: !!python/name:materialx.emoji.to_svg
|
||||
emoji_index: !!python/name:materialx.emoji.twemoji ''
|
||||
emoji_generator: !!python/name:materialx.emoji.to_svg ''
|
||||
extra:
|
||||
branch: master
|
||||
repository: pygitversionhelper
|
||||
repository: pygamecfg
|
||||
|
||||
@@ -35,7 +35,8 @@ classifiers = [
|
||||
dependencies = [
|
||||
'importlib-metadata; python_version<"3.9"',
|
||||
'packaging',
|
||||
'pysimpleini>=0.3.1'
|
||||
'pysimpleini>=0.3.1',
|
||||
'typed-argument-parser==1.*'
|
||||
]
|
||||
dynamic = ["version"]
|
||||
|
||||
@@ -47,7 +48,21 @@ include-package-data = true
|
||||
where = ["src"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
"pygamecfg.data" = ["*.*"]
|
||||
"pysimpleini" = ["py.typed"]
|
||||
|
||||
# [[tool.mypy.overrides]]
|
||||
# module = ""
|
||||
# ignore_missing_imports = true
|
||||
|
||||
[tool.coverage.run]
|
||||
cover_pylib = false
|
||||
branch = true
|
||||
data_file="helpers-results/cl_unit_test_raw_coverage/.coverage"
|
||||
# debug = ["config","multiproc","process"]
|
||||
parallel = true
|
||||
concurrency = [
|
||||
'thread'
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://chacha.ddns.net/gitea/chacha/pygamecfg"
|
||||
@@ -55,13 +70,13 @@ Documentation = "https://chacha.ddns.net/mkdocs-web/chacha/pygamecfg/master/la
|
||||
Tracker = "https://chacha.ddns.net/gitea/chacha/pygamecfg/issues"
|
||||
|
||||
[project.optional-dependencies]
|
||||
test = ["junitparser>=2.8","junit2html>=30.1","xmlrunner>=1.7","mypy>=0.99" ]
|
||||
coverage-check = ["coverage>=7.0"]
|
||||
complexity-check = ["radon>=5.1"]
|
||||
quality-check = ["pylint>=2.15","pylint-json2html>=0.4","pandas>=1.5"]
|
||||
type-check = ["mypy[reports]>=0.99" ]
|
||||
doc-gen = ["mkdocs>=1.4.0", "mkdocs-material>=8.5","mkdocs-pymdownx-material-extras", "mkdocs-localsearch>=0.9.0", "mkdocstrings[python]>=0.19", "mkdocs-with-pdf>=0.9.3","pyyaml>=6.0","pymdown-extensions>=9","mkdocs-markdownextradata-plugin","mkdocs-mermaid2-plugin"]
|
||||
test = ["chacha_cicd_helper"]
|
||||
coverage-check = ["chacha_cicd_helper"]
|
||||
complexity-check = ["chacha_cicd_helper"]
|
||||
quality-check = ["chacha_cicd_helper"]
|
||||
type-check = ["chacha_cicd_helper"]
|
||||
doc-gen = ["chacha_cicd_helper"]
|
||||
|
||||
#[project.scripts]
|
||||
#my-script = "my_package.module:function"
|
||||
# [project.scripts]
|
||||
# my-script = "my_package.module:function"
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# pygamecfg (c) by chacha
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pygamecfg is licensed under a
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
"""
|
||||
Main module __init__ file.
|
||||
"""
|
||||
@@ -13,9 +16,6 @@ Main module __init__ file.
|
||||
from importlib.metadata import distribution, version, PackageNotFoundError
|
||||
import warnings
|
||||
|
||||
from .core import GameOptions_Factory
|
||||
|
||||
from . import ut99, ut2k4, cod4
|
||||
|
||||
try: # pragma: no cover
|
||||
__version__ = version("pygamecfg")
|
||||
@@ -36,3 +36,10 @@ try: # pragma: no cover
|
||||
except PackageNotFoundError: # pragma: no cover
|
||||
warnings.warn('can not read dist.metadata["Name"], assuming local test context, setting it to <pygamecfg>')
|
||||
__Name__ = "pygamecfg"
|
||||
|
||||
from .core_gamecfg import GameOptions_Factory
|
||||
from . import game_cod4
|
||||
from . import game_cod4_gungame
|
||||
from . import game_cod4_promod
|
||||
from . import game_ut99
|
||||
from . import game_ut2k4
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# PySimpleINI (c) by chacha
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# PySimpleINI is licensed under a
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
@@ -10,55 +11,98 @@
|
||||
|
||||
"""CLI interface module"""
|
||||
from __future__ import annotations
|
||||
from typing import Literal, cast, Union
|
||||
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
from tap import Tap
|
||||
|
||||
from . import __Summuary__, __Name__
|
||||
from . import GameOptions_Factory
|
||||
|
||||
|
||||
def fct_main(args: list[str]) -> int:
|
||||
parser = ArgumentParser(prog=__Name__, description=__Summuary__)
|
||||
parser.add_argument("-v", "--verbosity", action="count", default=0, help="increase output verbosity")
|
||||
class pygamecfg_args_SetOption(Tap):
|
||||
"""SetOption CLI arg subparser"""
|
||||
|
||||
parser.add_argument("-b", "--basegamedir", help="set the game base dir", default="./")
|
||||
parser.add_argument("-c", "--configfile", help="set the default config file", default="")
|
||||
parser.add_argument("-g", "--game", help="the target game", choices=["ut99", "cod4", "ut2k4"], required=True)
|
||||
subparsers = parser.add_subparsers(dest="command", help="command type", required=True)
|
||||
option: str
|
||||
value: str = ""
|
||||
|
||||
SetOption_subparser = subparsers.add_parser("SetOption", help="Set/Add a game config file option value (may need reboot)")
|
||||
SetOption_subparser.add_argument("option")
|
||||
SetOption_subparser.add_argument("value", nargs="?")
|
||||
def configure(self) -> None:
|
||||
self.add_argument("option")
|
||||
self.add_argument("value")
|
||||
|
||||
RemOption_subparser = subparsers.add_parser("RemOption", help="Remove a game config file option, w or w/o value (may need reboot)")
|
||||
RemOption_subparser.add_argument("option")
|
||||
RemOption_subparser.add_argument("value", nargs="?")
|
||||
|
||||
GetOption_subparser = subparsers.add_parser("GetOption", help="Get a game config file option value")
|
||||
GetOption_subparser.add_argument("option")
|
||||
class pygamecfg_args_RemOption(Tap):
|
||||
"""RemOption CLI arg subparser"""
|
||||
|
||||
args = parser.parse_args(args)
|
||||
option: str
|
||||
value: str = ""
|
||||
|
||||
def configure(self) -> None:
|
||||
self.add_argument("option")
|
||||
self.add_argument("value")
|
||||
|
||||
|
||||
class pygamecfg_args_GetOption(Tap):
|
||||
"""GetOption CLI arg subparser"""
|
||||
|
||||
option: str
|
||||
|
||||
def configure(self) -> None:
|
||||
self.add_argument("option")
|
||||
|
||||
|
||||
class pygamecfg_args(Tap):
|
||||
"""Main CLI arg parser"""
|
||||
|
||||
verbosity: int = 0
|
||||
basegamedir: str = "./"
|
||||
configfile: str = ""
|
||||
game: Literal["ut99", "cod4", "cod4_gungame", "cod4_promod", "ut2k4"]
|
||||
|
||||
def configure(self) -> None:
|
||||
self.add_argument("-v", "--verbosity", action="count", help="increase output verbosity")
|
||||
self.add_argument("-b", "--basegamedir", help="set the game base dir")
|
||||
self.add_argument("-c", "--configfile", help="set the default config file")
|
||||
self.add_argument("-g", "--game", help="the target game")
|
||||
self.add_subparsers(dest="command", help="command type", required=True)
|
||||
self.add_subparser("SetOption", pygamecfg_args_SetOption, help="Set/Add a game config file option value")
|
||||
self.add_subparser("RemOption", pygamecfg_args_RemOption, help="Remove a game config file option, w or w/o value")
|
||||
self.add_subparser("GetOption", pygamecfg_args_GetOption, help="Get a game config file option value")
|
||||
|
||||
def process_args(self) -> None:
|
||||
"""dynamically add self.command to avoid conflict with Tap/argparse while keep pylint happy"""
|
||||
self.command: Union[str, None] = cast(Union[str, None], self.command) # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
|
||||
def fct_main(i_args: list[str]) -> None:
|
||||
"""CLI main function"""
|
||||
parser: pygamecfg_args = pygamecfg_args(prog=__Name__, description=__Summuary__)
|
||||
|
||||
args: pygamecfg_args = parser.parse_args(i_args)
|
||||
|
||||
if args.verbosity:
|
||||
print("Using base game dir: {0}".format(args.basegamedir))
|
||||
print("Using config file: {0}".format(args.configfile))
|
||||
print(f"Using base game dir: {args.basegamedir}")
|
||||
print(f"Using config file: {args.configfile}")
|
||||
|
||||
if args.configfile == "":
|
||||
if args.game == "ut99":
|
||||
args.configfile = "./System/UnrealTournament.ini"
|
||||
if args.game == "ut2k4":
|
||||
args.configfile = "./System/UT2004.ini"
|
||||
elif args.game == "cod4":
|
||||
elif args.game in ("cod4", "cod4_gungame", "cod4_promod"):
|
||||
args.configfile = "./main/server.cfg"
|
||||
_GameOptions = GameOptions_Factory(args.game, args.basegamedir, args.configfile)
|
||||
|
||||
GameOptions = GameOptions_Factory(args.game, args.basegamedir, args.configfile)
|
||||
if args.command == "SetOption":
|
||||
_GameOptions.set(args.option, args.value)
|
||||
GameOptions.set(
|
||||
cast(pygamecfg_args_SetOption, args).option, cast(pygamecfg_args_SetOption, args).value # pylint: disable=no-member
|
||||
)
|
||||
elif args.command == "RemOption":
|
||||
_GameOptions.rem(args.option, args.value)
|
||||
GameOptions.rem(
|
||||
cast(pygamecfg_args_RemOption, args).option, cast(pygamecfg_args_RemOption, args).value # pylint: disable=no-member
|
||||
)
|
||||
elif args.command == "GetOption":
|
||||
res = _GameOptions.get(args.option)
|
||||
res = GameOptions.get(cast(pygamecfg_args_GetOption, args).option) # pylint: disable=no-member
|
||||
print(res)
|
||||
else:
|
||||
raise RuntimeError("Invalid argument")
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
import re
|
||||
from os.path import join
|
||||
|
||||
from .core import GameOptions_Factory_Register, GameOption, OptionType
|
||||
|
||||
|
||||
class GameOption_COD4(GameOption):
|
||||
szGameType = "cod4"
|
||||
TValueType = OptionType.OT_INVALID
|
||||
|
||||
szOptionName: str = ""
|
||||
szKeyName: str = ""
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = ""
|
||||
|
||||
def __init__(self, GameRootDir: str, ConfigFileRelPath: str) -> None:
|
||||
super().__init__(GameRootDir, ConfigFileRelPath)
|
||||
self.mainConfigFilePath = join(GameRootDir, ConfigFileRelPath)
|
||||
self.cfgfile = open(self.mainConfigFilePath, "r")
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
self.format(value)
|
||||
if self.bDblQuoted:
|
||||
value = '"' + value + '"'
|
||||
if self.szPrefix:
|
||||
value = self.szPrefix + " " + self.szKeyName + " " + value
|
||||
|
||||
for line in self.cfgfile.readlines():
|
||||
if re.search(r"\s+" + self.szPrefix + r"\s+"):
|
||||
print(f"found: {line}")
|
||||
|
||||
def rem(self, value: Union[str, None] = None) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
|
||||
regex = r"^\s*" + self.szPrefix + r"\s+" + self.szOptionName + r"\s*(?P<value>.*)"
|
||||
|
||||
bfound = False
|
||||
|
||||
newFile = ""
|
||||
for line in self.cfgfile.readlines():
|
||||
if re.search(regex, line):
|
||||
if bfound:
|
||||
print("[warning] Option defined multiple time")
|
||||
bfound = True
|
||||
else:
|
||||
newFile += line
|
||||
if not bfound:
|
||||
raise RuntimeError("Option not found in file")
|
||||
|
||||
self.cfgfile.close()
|
||||
with open(self.mainConfigFilePath, "w") as ofile:
|
||||
ofile.write(newFile)
|
||||
self.cfgfile = open(self.mainConfigFilePath, "r")
|
||||
|
||||
def get(self) -> Union[None, str]:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName not set")
|
||||
|
||||
if self.bDblQuoted:
|
||||
regex = r"^\s*" + self.szPrefix + r"\s+" + self.szOptionName + r"\s*\"(?P<value>.*)\""
|
||||
else:
|
||||
regex = r"^\s*" + self.szPrefix + r"\s+" + self.szOptionName + r"\s*(?P<value>.*)"
|
||||
bfound = False
|
||||
res = None
|
||||
for line in self.cfgfile.readlines():
|
||||
if result := re.search(regex, line):
|
||||
if bfound:
|
||||
raise RuntimeError("Option defined multiple time")
|
||||
res = result.groupdict()["value"]
|
||||
bfound = True
|
||||
if not bfound:
|
||||
raise RuntimeError("Option not found in file")
|
||||
return res
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_sv_maxclients(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "sv_maxclients"
|
||||
szKeyName: str = "sv_maxclients"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "12"
|
||||
szHelp = "Maximum client number"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_sv_mapRotation(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "sv_mapRotation"
|
||||
szKeyName: str = "sv_mapRotation"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "gametype dm map mp_block"
|
||||
szHelp = "Map rotation list"
|
||||
72
src/pygamecfg/common_ut.py
Normal file
72
src/pygamecfg/common_ut.py
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
"""common UT functions"""
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
from os.path import join
|
||||
from pathlib import Path
|
||||
|
||||
from pysimpleini import PySimpleINI
|
||||
|
||||
from .core_gamecfg import GameOption, OptionType
|
||||
|
||||
|
||||
class GameOption_UT(GameOption):
|
||||
"""generic UT Option class"""
|
||||
|
||||
szGameType = ""
|
||||
TValueType = OptionType.OT_INVALID
|
||||
|
||||
szOptionName = ""
|
||||
szSectionName = ""
|
||||
szKeyName = ""
|
||||
bForceAdd: bool = False
|
||||
bRemovable: bool = False
|
||||
|
||||
cachedFile: Union[None, PySimpleINI] = None
|
||||
cachedFilePath: Union[None, Path] = None
|
||||
|
||||
Cls_PySimpleINI: type[PySimpleINI] = PySimpleINI
|
||||
|
||||
@classmethod
|
||||
def openFile(cls, filepath: Path) -> PySimpleINI:
|
||||
"""Open the file"""
|
||||
if (not cls.cachedFile) or (filepath != cls.cachedFilePath):
|
||||
cls.cachedFilePath = filepath
|
||||
cls.cachedFile = cls.Cls_PySimpleINI(filepath)
|
||||
return cls.cachedFile
|
||||
|
||||
def __init__(self, GameRootDir: str, ConfigFileRelPath: str) -> None:
|
||||
super().__init__(GameRootDir, ConfigFileRelPath)
|
||||
self.mainConfigFilePath: Path = Path(join(GameRootDir, ConfigFileRelPath))
|
||||
self.inifile = self.openFile(self.mainConfigFilePath)
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
self.format(value)
|
||||
self.inifile.setaddkeyvalue(self.szSectionName, self.szKeyName, value, self.bForceAdd)
|
||||
self.inifile.writefile()
|
||||
|
||||
def rem(self, value: Union[None, str]) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
if not self.bRemovable:
|
||||
raise RuntimeError("this options is not removable")
|
||||
self.inifile.delkey_ex(self.szSectionName, self.szKeyName, None, value)
|
||||
self.inifile.writefile()
|
||||
|
||||
def get(self) -> Union[str, list[str]]:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName not set")
|
||||
return self.inifile.getkeyvalue(self.szSectionName, self.szKeyName)
|
||||
@@ -1,97 +0,0 @@
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class OptionType(Enum):
|
||||
OT_INVALID = 0
|
||||
OT_STRING = 1
|
||||
OT_INTEGER = 2
|
||||
OT_BOOLEAN = 3
|
||||
OT_FLOAT = 4
|
||||
|
||||
|
||||
class GameOption(metaclass=ABCMeta):
|
||||
szGameType: str = ""
|
||||
szOptionName: str = ""
|
||||
TValueType: OptionType = OptionType.OT_INVALID
|
||||
szDefaultValue: str = ""
|
||||
szHelp: str = ""
|
||||
szFormatedValue: str = ""
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, GameRootDir: str, ConfigFileRelPath: Union[None, str] = None):
|
||||
self.GameRootDir = GameRootDir
|
||||
self.ConfigFileRelPath = ConfigFileRelPath
|
||||
|
||||
def format(self, value: Union[int, str, float]) -> None:
|
||||
if self.TValueType == OptionType.OT_STRING:
|
||||
self.szFormatedValue = str(value)
|
||||
elif self.TValueType == OptionType.OT_INTEGER:
|
||||
self.szFormatedValue = str(int(value))
|
||||
elif self.TValueType == OptionType.OT_BOOLEAN:
|
||||
try:
|
||||
intval = int(value)
|
||||
self.szFormatedValue = str(bool(intval))
|
||||
except:
|
||||
self.szFormatedValue = str(True) if str(value).lower() == "true" else str(False)
|
||||
elif self.TValueType == OptionType.OT_FLOAT:
|
||||
self.szFormatedValue = str(float(value))
|
||||
else:
|
||||
raise RuntimeError("Invalid Option TValueType")
|
||||
|
||||
print("setting option <{0}> to: {1}".format(self.szOptionName, self.szFormatedValue))
|
||||
|
||||
@abstractmethod
|
||||
def set(self, value: str) -> None:
|
||||
raise NotImplementedError("method not implemented")
|
||||
|
||||
@abstractmethod
|
||||
def rem(self, value: Union[None, str]) -> None:
|
||||
raise NotImplementedError("method not implemented")
|
||||
|
||||
@abstractmethod
|
||||
def get(self) -> Union[None, str]:
|
||||
raise NotImplementedError("method not implemented")
|
||||
|
||||
|
||||
class GameOptions_Factory:
|
||||
ar_Options_cls = []
|
||||
|
||||
def __init__(self, szGameType: str, GameRootDir: str, ConfigFileRelPath: Union[None, str] = None) -> None:
|
||||
self.szGameType = szGameType
|
||||
self.ar_Options = []
|
||||
for Options_cls in GameOptions_Factory.ar_Options_cls:
|
||||
if Options_cls.szGameType == szGameType:
|
||||
self.ar_Options.append(Options_cls(GameRootDir, ConfigFileRelPath))
|
||||
|
||||
@classmethod
|
||||
def GameOptionRegister(cls, Option: GameOption) -> None:
|
||||
cls.ar_Options_cls.append(Option)
|
||||
|
||||
def set(self, OptionName: str, value: str) -> None:
|
||||
for _option in GameOptions_Factory.ar_Options:
|
||||
if _option.szOptionName == OptionName:
|
||||
_option.set(value)
|
||||
return
|
||||
raise RuntimeError("Option not found")
|
||||
|
||||
def rem(self, OptionName: str, value: Union[None, str]) -> None:
|
||||
for _option in self.ar_Options:
|
||||
if _option.szOptionName == OptionName:
|
||||
_option.rem(value)
|
||||
return
|
||||
raise RuntimeError("Option not found")
|
||||
|
||||
def get(self, OptionName: str) -> Union[None, str]:
|
||||
for _option in self.ar_Options:
|
||||
if _option.szOptionName == OptionName:
|
||||
return _option.get()
|
||||
raise RuntimeError("Option not found")
|
||||
|
||||
|
||||
def GameOptions_Factory_Register(cls):
|
||||
GameOptions_Factory.GameOptionRegister(cls)
|
||||
return cls
|
||||
179
src/pygamecfg/core_gamecfg.py
Normal file
179
src/pygamecfg/core_gamecfg.py
Normal file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
""" Core file of pygamecfg
|
||||
contain generic management code for GameOption
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class GameCfgException(Exception):
|
||||
"""Standard Exception to catch non existing key in configuration file"""
|
||||
|
||||
|
||||
class OptionNotFoundError(GameCfgException):
|
||||
"""Standard Exception to catch non existing configuration option"""
|
||||
|
||||
|
||||
class OptionType(Enum):
|
||||
"""Supported option data type"""
|
||||
|
||||
OT_INVALID = 0
|
||||
OT_STRING = 1
|
||||
OT_INTEGER = 2
|
||||
OT_BOOLEAN = 3
|
||||
OT_FLOAT = 4
|
||||
|
||||
|
||||
class GameOption(metaclass=ABCMeta):
|
||||
"""Game option base type"""
|
||||
|
||||
szGameType: str = ""
|
||||
szOptionName: str = ""
|
||||
TValueType: OptionType = OptionType.OT_INVALID
|
||||
szDefaultValue: str = ""
|
||||
szHelp: str = ""
|
||||
|
||||
def __init__(self, GameRootDir: str, ConfigFileRelPath: Union[None, str] = None):
|
||||
"""GameOption constructor.
|
||||
|
||||
///warning
|
||||
This object does not aim to be created
|
||||
///
|
||||
|
||||
Args:
|
||||
GameRootDir: root dir of the game
|
||||
ConfigFileRelPath: path to the configfile (relative to rootdir)
|
||||
"""
|
||||
self.GameRootDir = GameRootDir
|
||||
self.ConfigFileRelPath = ConfigFileRelPath
|
||||
|
||||
def __enter__(self) -> GameOption:
|
||||
"""contextlib enter hook"""
|
||||
return self
|
||||
|
||||
def __exit__(self, exception_type, exception_value, exception_traceback) -> None:
|
||||
"""contextlib exit hook"""
|
||||
self.close()
|
||||
|
||||
def close(self) -> None:
|
||||
"""user-define close() function (for subclassing)"""
|
||||
|
||||
def format_OT_STRING(self, value: Union[int, str, float]) -> str:
|
||||
""" "STRING specific format method (TO file)"""
|
||||
return str(value)
|
||||
|
||||
def format_OT_INTEGER(self, value: Union[int, str, float]) -> str:
|
||||
""" "INTEGER specific format method (TO file)"""
|
||||
return str(int(value))
|
||||
|
||||
def format_OT_BOOLEAN(self, value: Union[int, str, float]) -> str:
|
||||
""" "BOOLEAN specific format method (TO file)"""
|
||||
try:
|
||||
intval = int(value)
|
||||
return str(bool(intval))
|
||||
except ValueError:
|
||||
return str(True) if str(value).lower() == "true" else str(False)
|
||||
|
||||
def format_OT_FLOAT(self, value: Union[int, str, float]) -> str:
|
||||
""" "FLOAT specific format method (TO file)"""
|
||||
return str(float(value))
|
||||
|
||||
def format(self, value: Union[int, str, float]) -> str:
|
||||
"""standard method to format options before writing it TO file (overloadable)"""
|
||||
|
||||
FormatedValue: str = ""
|
||||
if self.TValueType == OptionType.OT_STRING:
|
||||
FormatedValue = self.format_OT_STRING(value)
|
||||
elif self.TValueType == OptionType.OT_INTEGER:
|
||||
FormatedValue = self.format_OT_INTEGER(value)
|
||||
elif self.TValueType == OptionType.OT_BOOLEAN:
|
||||
FormatedValue = self.format_OT_BOOLEAN(value)
|
||||
elif self.TValueType == OptionType.OT_FLOAT:
|
||||
FormatedValue = self.format_OT_FLOAT(value)
|
||||
else:
|
||||
raise RuntimeError("Invalid Option TValueType")
|
||||
|
||||
print(f"setting option <{self.szOptionName}> to: {FormatedValue}")
|
||||
return FormatedValue
|
||||
|
||||
@abstractmethod
|
||||
def set(self, value: str) -> None:
|
||||
"""generic set function"""
|
||||
raise NotImplementedError("method not implemented")
|
||||
|
||||
@abstractmethod
|
||||
def rem(self, value: Union[None, str]) -> None:
|
||||
"""generic rem function"""
|
||||
raise NotImplementedError("method not implemented")
|
||||
|
||||
@abstractmethod
|
||||
def get(self) -> Union[str, list[str]]:
|
||||
"""generic get function"""
|
||||
raise NotImplementedError("method not implemented")
|
||||
|
||||
|
||||
class GameOptions_Factory:
|
||||
"""factory that manage game options based on Game and the option itself"""
|
||||
|
||||
ar_Options_cls: list[type[GameOption]] = []
|
||||
ar_Options_cls_filtered: list[type[GameOption]] = []
|
||||
GameRootDir: str = "./"
|
||||
ConfigFileRelPath: str = ""
|
||||
|
||||
def __init__(self, szGameType: str, GameRootDir: str, ConfigFileRelPath: str) -> None:
|
||||
self.szGameType = szGameType
|
||||
self.GameRootDir = GameRootDir
|
||||
self.ConfigFileRelPath = ConfigFileRelPath
|
||||
for Options_cls in GameOptions_Factory.ar_Options_cls:
|
||||
if Options_cls.szGameType == szGameType:
|
||||
self.ar_Options_cls_filtered.append(Options_cls)
|
||||
|
||||
@classmethod
|
||||
def GameOptionRegister(cls, Option: type[GameOption]) -> None:
|
||||
"""interface option used by decorator to register option implementation classes"""
|
||||
GameOptions_Factory.ar_Options_cls.append(Option)
|
||||
|
||||
def set(self, OptionName: str, value: str) -> None:
|
||||
"""generic set function (API call)"""
|
||||
for _option in GameOptions_Factory.ar_Options_cls_filtered:
|
||||
if _option.szOptionName == OptionName:
|
||||
with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst:
|
||||
_optionInst.set(_optionInst.format(value))
|
||||
return
|
||||
raise OptionNotFoundError("Option not found")
|
||||
|
||||
def rem(self, OptionName: str, value: Union[None, str]) -> None:
|
||||
"""generic rem function (API call)"""
|
||||
for _option in self.ar_Options_cls_filtered:
|
||||
if _option.szOptionName == OptionName:
|
||||
with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst:
|
||||
_optionInst.rem(value)
|
||||
return
|
||||
raise OptionNotFoundError("Option not found")
|
||||
|
||||
def get(self, OptionName: str) -> Union[str, list[str]]:
|
||||
"""generic get function (API call)"""
|
||||
for _option in self.ar_Options_cls_filtered:
|
||||
if _option.szOptionName == OptionName:
|
||||
with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst:
|
||||
return _optionInst.get()
|
||||
raise OptionNotFoundError("Option not found")
|
||||
|
||||
|
||||
def GameOptions_Factory_Register(cls: type[GameOption]) -> type[GameOption]:
|
||||
"""decorator to register game option concrete implementation"""
|
||||
GameOptions_Factory.GameOptionRegister(cls)
|
||||
return cls
|
||||
@@ -1,7 +0,0 @@
|
||||
# pygamecfg (c) by chacha
|
||||
#
|
||||
# pygamecfg is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
703
src/pygamecfg/game_cod4.py
Normal file
703
src/pygamecfg/game_cod4.py
Normal file
@@ -0,0 +1,703 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
# pylint: disable=missing-class-docstring,missing-module-docstring,missing-function-docstring,duplicate-code,line-too-long
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
import re
|
||||
from os.path import join
|
||||
from os import linesep
|
||||
|
||||
from .core_gamecfg import GameOptions_Factory_Register, GameOption, OptionType, GameCfgException
|
||||
|
||||
|
||||
class COD4KeyNotFoundError(GameCfgException):
|
||||
"""Exception to catch non existing configuration key in COD4 configuration file"""
|
||||
|
||||
|
||||
class GameOption_COD4(GameOption):
|
||||
szGameType = "cod4"
|
||||
TValueType = OptionType.OT_INVALID
|
||||
|
||||
szOptionName: str = ""
|
||||
szKeyName: str = ""
|
||||
bDblQuoted: bool = False
|
||||
szPrefix: str = ""
|
||||
|
||||
def __init__(self, GameRootDir: str, ConfigFileRelPath: str) -> None:
|
||||
super().__init__(GameRootDir, ConfigFileRelPath)
|
||||
self.mainConfigFilePath = join(GameRootDir, ConfigFileRelPath)
|
||||
self.cfgfile = open(self.mainConfigFilePath, "r", encoding="utf8") # pylint: disable=consider-using-with
|
||||
|
||||
def format_OT_BOOLEAN(self, value: Union[int, str, float]) -> str:
|
||||
return "1" if super().format_OT_BOOLEAN(value).lower() == "true" else "0"
|
||||
|
||||
def close(self) -> None:
|
||||
self.cfgfile.close()
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
|
||||
FinalValue: str = value
|
||||
if self.bDblQuoted:
|
||||
FinalValue = '"' + FinalValue + '"'
|
||||
if self.szPrefix != "":
|
||||
FinalValue = self.szPrefix + " " + self.szKeyName + " " + FinalValue + linesep
|
||||
bfound = False
|
||||
newFile = ""
|
||||
|
||||
regex = r"^\s*" + self.szPrefix + r"\s+" + self.szKeyName + r"\s*(?P<value>.*)"
|
||||
|
||||
for line in self.cfgfile.readlines():
|
||||
if re.search(regex, line):
|
||||
if bfound:
|
||||
print("[warning] Option defined multiple time")
|
||||
newFile += FinalValue
|
||||
bfound = True
|
||||
else:
|
||||
newFile += line
|
||||
|
||||
if not bfound:
|
||||
# write new key at the top of the file to be sure we do not erase the map / map_rotate cmd
|
||||
newFile = FinalValue + newFile
|
||||
|
||||
self.cfgfile.close()
|
||||
with open(self.mainConfigFilePath, "w", encoding="utf8") as ofile:
|
||||
ofile.write(newFile)
|
||||
self.cfgfile = open(self.mainConfigFilePath, "r", encoding="utf8") # pylint: disable=consider-using-with
|
||||
|
||||
def rem(self, value: Union[str, None] = None) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
|
||||
regex = r"^\s*" + self.szPrefix + r"\s+" + self.szKeyName + r"\s*(?P<value>.*)"
|
||||
|
||||
bfound = False
|
||||
newFile = ""
|
||||
for line in self.cfgfile.readlines():
|
||||
if re.search(regex, line):
|
||||
if bfound:
|
||||
print("[warning] Option defined multiple time")
|
||||
bfound = True
|
||||
else:
|
||||
newFile += line
|
||||
if not bfound:
|
||||
raise COD4KeyNotFoundError("Option not found in file")
|
||||
|
||||
self.cfgfile.close()
|
||||
with open(self.mainConfigFilePath, "w", encoding="utf8") as ofile:
|
||||
ofile.write(newFile)
|
||||
self.cfgfile = open(self.mainConfigFilePath, "r", encoding="utf8") # pylint: disable=consider-using-with
|
||||
|
||||
def get(self) -> str:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName not set")
|
||||
|
||||
if self.bDblQuoted:
|
||||
regex = r"^\s*" + self.szPrefix + r"\s+" + self.szKeyName + r"\s*\"(?P<value>.*)\""
|
||||
else:
|
||||
regex = r"^\s*" + self.szPrefix + r"\s+" + self.szKeyName + r"\s*(?P<value>.*)"
|
||||
bfound = False
|
||||
|
||||
for line in self.cfgfile.readlines():
|
||||
if result := re.search(regex, line):
|
||||
if bfound:
|
||||
raise RuntimeError("Option defined multiple time")
|
||||
res = result.groupdict()["value"]
|
||||
bfound = True
|
||||
if not bfound:
|
||||
raise COD4KeyNotFoundError("Option not found in file")
|
||||
return res
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_Meta_Admin(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "meta_admin"
|
||||
szKeyName: str = "_Admin"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "sets"
|
||||
szDefaultValue = "ServAdmin"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_Meta_Email(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "meta_email"
|
||||
szKeyName: str = "_Email"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "sets"
|
||||
szDefaultValue = "ServEmail"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_Meta_Website(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "meta_website"
|
||||
szKeyName: str = "_Website"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "sets"
|
||||
szDefaultValue = "ServWebsite"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_Meta_Location(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "meta_location"
|
||||
szKeyName: str = "_Location"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "sets"
|
||||
szDefaultValue = "ServLocation"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_Meta_Maps(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "meta_maps"
|
||||
szKeyName: str = "_Maps"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "sets"
|
||||
szDefaultValue = ""
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_Meta_Gametype(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "meta_gametype"
|
||||
szKeyName: str = "_Gametype"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "sets"
|
||||
szDefaultValue = ""
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_Cod4x_AuthToken(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "cod4x_authtoken"
|
||||
szKeyName: str = "sv_authtoken"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = "Cod4x personnal auth token"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_Hostname(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "hostname"
|
||||
szKeyName: str = "sv_hostname"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = "Server Hostname"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_MOTD(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "motd"
|
||||
szKeyName: str = "g_motd"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "Welcome"
|
||||
szHelp = "Server Message Of The Day"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_dedicated(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "dedicated"
|
||||
szKeyName: str = "dedicated"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "2"
|
||||
szHelp = """0 = Listen, 1 = LAN, 2 = Internet ( you probably want 2 )"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_RCON_password(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "rcon_password"
|
||||
szKeyName: str = "rcon_password"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = "password for remote access, leave empty to deactivate, min 8 characters"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_game_password(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "game_password"
|
||||
szKeyName: str = "g_password"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = "join password, leave empty to deactivate"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_nb_private_clients(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "nb_privateClients"
|
||||
szKeyName: str = "sv_privateClients"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "3"
|
||||
szHelp = """Private Clients, number of slots that can only be changed with a password"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_private_password(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "private_password"
|
||||
szKeyName: str = "sv_privatePassword"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = "the password to join private slots"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_maxclients(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "maxclients"
|
||||
szKeyName: str = "sv_maxclients"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "12"
|
||||
szHelp = """Maximum client number"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_logsync(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "logsync"
|
||||
szKeyName: str = "g_logsync"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "2"
|
||||
szHelp = """0=no log, 1=buffered, 2=continuous, 3=append"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_enable_logfile(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "enable_logfile"
|
||||
szKeyName: str = "logfile"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """0 = NO log, 1 = log file enabled"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_logfile(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "logfile"
|
||||
szKeyName: str = "g_log"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "games_mp.log"
|
||||
szHelp = "Name of log file, default is games_mp.log"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_enable_logdamage(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "enable_logdamage"
|
||||
szKeyName: str = "sv_log_damage"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """0 = NO logdamage, 1 = logdamage enabled"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_statusfile(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "statusfile"
|
||||
szKeyName: str = "sv_statusfile"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "serverstatus.xml"
|
||||
szHelp = "writes an xml serverstatus to disc, leave empty to disable"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_ney_port(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "net_port"
|
||||
szKeyName: str = "net_port"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "28960"
|
||||
szHelp = """network port"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_maxRate(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "maxRate"
|
||||
szKeyName: str = "sv_maxRate"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "25000"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_minPing(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "minPing"
|
||||
szKeyName: str = "sv_minPing"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = "minimal ping [ms] for a player to join the server"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_maxPing(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "maxPing"
|
||||
szKeyName: str = "sv_maxPing"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "350"
|
||||
szHelp = "maximal ping [ms] for a player to join the server"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_randomMapRotation(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "randomMapRotation"
|
||||
szKeyName: str = "sv_randomMapRotation"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """0 = sv_mapRotation is randomized, 1 = sequential order of sv_mapRotation"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_teambalance(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "teambalance"
|
||||
szKeyName: str = "scr_teambalance"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = "auto-teambalance //0 = no, 1 = yes"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_team_fftype(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "team_fftype"
|
||||
szKeyName: str = "scr_team_fftype"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = "friendly-fire //0 = off, 1 = on, //2 = reflect damage, 3 = shared damage"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_enable_hardcore(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "hardcore"
|
||||
szKeyName: str = "scr_hardcore"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = """Hardcore Mode //0 = off 1 = on"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_enable_oldschool(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "oldschool"
|
||||
szKeyName: str = "scr_oldschool"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = """Oldschool Mode //0 = off, 1 = on"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_enable_friendlyPlayerCanBlock(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "friendlyPlayerCanBlock"
|
||||
szKeyName: str = "g_friendlyPlayerCanBlock"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """1 = player collision between friendly players, 0 = collision between friendly players is disabled"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_enable_FFAPlayerCanBlock(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "FFAPlayerCanBlock"
|
||||
szKeyName: str = "g_FFAPlayerCanBlock"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """1 = player collision, 0 = collision between players is disabled"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_DM_scorelimit(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "dm_scorelimit"
|
||||
szKeyName: str = "scr_dm_scorelimit"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1000"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_DM_timelimit(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "dm_timelimit"
|
||||
szKeyName: str = "scr_dm_timelimit"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "15"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_DM_roundlimit(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "dm_roundlimit"
|
||||
szKeyName: str = "scr_dm_roundlimit"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_DM_numlives(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "dm_numlives"
|
||||
szKeyName: str = "scr_dm_numlives"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_DM_playerrespawndelay(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "dm_playerrespawndelay"
|
||||
szKeyName: str = "scr_dm_playerrespawndelay"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_DM_waverespawndelay(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "dm_waverespawndelay"
|
||||
szKeyName: str = "scr_dm_waverespawndelay"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_TDM_scorelimit(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "tdm_scorelimit"
|
||||
szKeyName: str = "scr_war_scorelimit"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "2000"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_TDM_timelimit(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "tdm_timelimit"
|
||||
szKeyName: str = "scr_war_timelimit"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "10"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_TDM_roundlimit(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "tdm_roundlimit"
|
||||
szKeyName: str = "scr_war_roundlimit"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_TDM_numlives(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "tdm_numlives"
|
||||
szKeyName: str = "scr_war_numlives"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_TDM_playerrespawndelay(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "tdm_playerrespawndelay"
|
||||
szKeyName: str = "scr_war_playerrespawndelay"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_TDM_waverespawndelay(GameOption_COD4):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "tdm_waverespawndelay"
|
||||
szKeyName: str = "scr_war_waverespawndelay"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_gametype(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "gametype"
|
||||
szKeyName: str = "g_gametype"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "dm"
|
||||
szHelp = "gamemode, one of [war, dm, sd, sab, koth]"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_mapRotation(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "mapRotation"
|
||||
szKeyName: str = "sv_mapRotation"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "gametype dm map mp_block"
|
||||
szHelp = """Map rotation list"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_allowdownloadk(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "allowdownload"
|
||||
szKeyName: str = "sv_allowdownload"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_wwwDownload(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "wwwDownload"
|
||||
szKeyName: str = "sv_wwwDownload"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_wwwBaseURL(GameOption_COD4):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "wwwBaseURL"
|
||||
szKeyName: str = "sv_wwwBaseURL"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_wwwDlDisconnected(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "wwwDlDisconnected"
|
||||
szKeyName: str = "sv_wwwDlDisconnected"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = ""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_nosteamnames(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "nosteamnames"
|
||||
szKeyName: str = "sv_nosteamnames"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = "1 = Use names from steam if steam is available"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_punkbuster(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "punkbuster"
|
||||
szKeyName: str = "sv_punkbuster"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = "Enable Punkbuste (PB is not supported on CoD4x)"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_pure(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "pure"
|
||||
szKeyName: str = "sv_pure"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = "check IWD-data 0 = off, 1 = on"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_antilag(GameOption_COD4):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "antilag"
|
||||
szKeyName: str = "g_antilag"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = "0 = off, 1 = on // Anti lag checks for weapon hits"
|
||||
384
src/pygamecfg/game_cod4_gungame.py
Normal file
384
src/pygamecfg/game_cod4_gungame.py
Normal file
@@ -0,0 +1,384 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
# pylint: disable=missing-class-docstring,missing-module-docstring,missing-function-docstring,duplicate-code,line-too-long
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .core_gamecfg import GameOptions_Factory_Register, OptionType
|
||||
from .game_cod4 import GameOption_COD4
|
||||
|
||||
|
||||
class GameOption_COD4_GunGame(GameOption_COD4):
|
||||
szGameType = "cod4_gungame"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_kills_for_levelup(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "kills_for_levelup"
|
||||
szKeyName: str = "gg_kills_for_levelup"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "2"
|
||||
szHelp = """Number of kills you need to level-up"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_turbo(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "turbo"
|
||||
szKeyName: str = "gg_turbo"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """Turbo Mode: Give the new weapon immediately"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_level_down(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "level_down"
|
||||
szKeyName: str = "gg_level_down"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """Number of levels you lose on suicide, teamkill..."""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_health_regen_time(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "health_regen_time"
|
||||
szKeyName: str = "gg_health_regen_time"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "6"
|
||||
szHelp = """Time before health regeneration starts: 5 = default, 0 = disable health regen"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_health_text(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "health_text"
|
||||
szKeyName: str = "gg_health_text"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """Text in the bottom-left part of the screen that shows your health"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_weapon_drop(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "weapon_drop"
|
||||
szKeyName: str = "gg_weapon_drop"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """Drop weapons on death?"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_knife_nerf(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "knife_nerf"
|
||||
szKeyName: str = "gg_knife_nerf"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = """0 = default, 1 = knife needs 2 hits to kill"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_dont_cook_frags(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "dont_cook_frags"
|
||||
szKeyName: str = "gg_dont_cook_frags"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = """1 = don't cook frag grenades, 0 = default nades"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_end_music(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "end_music"
|
||||
szKeyName: str = "gg_end_music"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """Music at the end of the map"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_knife_pro(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "knife_pro"
|
||||
szKeyName: str = "gg_knife_pro"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """When you knife someone you steal a level from him"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_deadly_snipers(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "deadly_snipers"
|
||||
szKeyName: str = "gg_deadly_snipers"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """1 = increase damage for bolt-action snipers, 2 = increase damage for all snipers"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_handicap(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "handicap"
|
||||
szKeyName: str = "gg_handicap"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """If a player joins in the middle of the game he is auto leveled to the level the worst player has"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_ammo_frag(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "ammo_frag"
|
||||
szKeyName: str = "gg_ammo_frag"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "6"
|
||||
szHelp = """Ammo for frag grenades [1-10]"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_ammo_c4(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "ammo_c4"
|
||||
szKeyName: str = "gg_ammo_c4"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "4"
|
||||
szHelp = """Ammo for C4 [1-10]"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_ammo_rpg(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "ammo_rpg"
|
||||
szKeyName: str = "gg_ammo_rpg"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "3"
|
||||
szHelp = """Ammo for RPG [1-10]"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_rotate_empty(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "rotate_empty"
|
||||
szKeyName: str = "gg_rotate_empty"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "10"
|
||||
szHelp = """Minutes after which server rotates to next map if no active players"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_remove_turrets(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "remove_turrets"
|
||||
szKeyName: str = "gg_remove_turrets"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """Remove stationary turrets [0=turrets allwed; 1=turrets removed]"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_second_weapon(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "second_weapon"
|
||||
szKeyName: str = "gg_second_weapon"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "deserteagle"
|
||||
szHelp = """The second weapon the players will have (empty to disable)"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_second_weapon_levels(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "second_weapon_levels"
|
||||
szKeyName: str = "gg_second_weapon_levels"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "c4,rpg,frag_grenade,rpg"
|
||||
szHelp = """The second weapon the players will have (empty to disable)"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_weapon_sequence(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "weapon_sequence"
|
||||
szKeyName: str = "gg_weapon_sequence"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "beretta,usp,colt45,deserteagle,winchester1200,m1014,mp5,m40a3,skorpion,uzi,ak74u,p90,m16,ak47,m4,g3,g36c,m14,mp44,saw,rpd,m60e4,barett,remington700,rpg,frag_grenade,knife"
|
||||
szHelp = """comma separated list from: beretta,usp,colt45,deserteagle,winchester1200,m1014,mp5,skorpion,uzi,ak74u,p90,m16,ak47,m4,g3,g36c,m14,mp44,saw,rpd,m60e4,m40a3,m21,dragunov,remington700,barrett,frag_grenade,knife,c4,rpg"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Enable(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "mc_enable"
|
||||
szKeyName: str = "mc_enable"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = """Enable rotating messages? [0: disable; 1: new custom messages; 2: standard print messages bottom left]"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Delay(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "mc_delay"
|
||||
szKeyName: str = "mc_delay"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "20"
|
||||
szHelp = """Delay between messages (sec)"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_MaxMsg(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_INTEGER
|
||||
szOptionName: str = "mc_max_msg"
|
||||
szKeyName: str = "mc_max_msg"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = """Maximum number of messages to use [max 20]"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Message_0(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "mc_msg_0"
|
||||
szKeyName: str = "mc_msg_0"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = """message num 0 in rotation"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Message_1(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "mc_msg_1"
|
||||
szKeyName: str = "mc_msg_1"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = """message num 1 in rotation"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Message_2(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "mc_msg_2"
|
||||
szKeyName: str = "mc_msg_2"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = """message num 2 in rotation"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Message_3(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "mc_msg_3"
|
||||
szKeyName: str = "mc_msg_3"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = """message num 3 in rotation"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Message_4(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "mc_msg_4"
|
||||
szKeyName: str = "mc_msg_4"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = """message num 4 in rotation"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Message_5(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "mc_msg_5"
|
||||
szKeyName: str = "mc_msg_5"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = """message num 5 in rotation"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_MessageCenter_Message_6(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "mc_msg_6"
|
||||
szKeyName: str = "mc_msg_6"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = ""
|
||||
szHelp = """message num 6 in rotation"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_WelcomeMessage_Enable(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "wc_enable"
|
||||
szKeyName: str = "wc_enable"
|
||||
bDblQuoted: bool = False
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "1"
|
||||
szHelp = """Enable welcome message"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_WelcomeMessage_Messsage(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "wc_message"
|
||||
szKeyName: str = "wc_message"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = r"Welcome to the server <name>!\Please enjoy your stay!"
|
||||
szHelp = r"""The message [ <name> is replaced by players name and \ indicates a new line ]"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_GunGame_bottom_text(GameOption_COD4_GunGame):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "bottom_text"
|
||||
szKeyName: str = "gg_bottom_text"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "GunGame Server"
|
||||
szHelp = """ Hud [ custom text displayed on the bottom of the screen next to mod info ]"""
|
||||
43
src/pygamecfg/game_cod4_promod.py
Normal file
43
src/pygamecfg/game_cod4_promod.py
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
# pylint: disable=missing-class-docstring,missing-module-docstring,missing-function-docstring,duplicate-code,line-too-long
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .core_gamecfg import GameOptions_Factory_Register, OptionType
|
||||
from .game_cod4 import GameOption_COD4
|
||||
|
||||
|
||||
class GameOption_COD4_ProMod(GameOption_COD4):
|
||||
szGameType = "cod4_promod"
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_ProMod_promod_mode(GameOption_COD4_ProMod):
|
||||
TValueType = OptionType.OT_STRING
|
||||
szOptionName: str = "promod_mode"
|
||||
szKeyName: str = "promod_mode"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "comp_public"
|
||||
szHelp = """comp_public,custom_public,2v2_mr,1v1_mr,knockout_mr,match_mr"""
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
class GameOption_COD4_ProMod_promod_enable_scorebot(GameOption_COD4_ProMod):
|
||||
TValueType = OptionType.OT_BOOLEAN
|
||||
szOptionName: str = "promod_enable_scorebot"
|
||||
szKeyName: str = "promod_enable_scorebot"
|
||||
bDblQuoted: bool = True
|
||||
szPrefix = "set"
|
||||
szDefaultValue = "0"
|
||||
szHelp = """match-modes only"""
|
||||
@@ -1,74 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
# pylint: disable=missing-class-docstring,missing-function-docstring,duplicate-code,line-too-long
|
||||
"""UT2k4 command set"""
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
from pysimpleini import PySimpleINI, KeyNotFoundError, SectionNotFoundError, Section, Key
|
||||
from os.path import join
|
||||
from pysimpleini import KeyNotFoundError
|
||||
|
||||
from .core import GameOptions_Factory_Register, GameOption, OptionType
|
||||
from .core_gamecfg import GameOptions_Factory_Register, OptionType
|
||||
from .tool_ini import PySimpleINI_GroupKeysInSection
|
||||
from .common_ut import GameOption_UT
|
||||
|
||||
|
||||
class ChaChaSimpleINI_UT2k4(PySimpleINI):
|
||||
def GroupKeysInSection(self, szSectionName: str, szKeyName: str) -> None:
|
||||
try:
|
||||
_section = self.getSection(szSectionName)
|
||||
if type(_section) is Section:
|
||||
ar_ServerPackages = _section.getKey(szKeyName)
|
||||
if isinstance(ar_ServerPackages, Key):
|
||||
ar_ServerPackages = [ar_ServerPackages]
|
||||
else: # array
|
||||
pass
|
||||
for ServerPackages in ar_ServerPackages:
|
||||
_section.delKey(ServerPackages.name, None, ServerPackages.value)
|
||||
for ServerPackages in ar_ServerPackages:
|
||||
_section.setAddKeyValue(ServerPackages.name, ServerPackages.value, True)
|
||||
except SectionNotFoundError:
|
||||
pass
|
||||
|
||||
def writeFile(self, bBeautify: bool = False) -> None:
|
||||
self.GroupKeysInSection("Engine.GameEngine", "ServerPackages")
|
||||
self.GroupKeysInSection("Engine.GameEngine", "ServerActors")
|
||||
self.GroupKeysInSection("Core.System", "Suppress")
|
||||
self.GroupKeysInSection("Core.System", "Paths")
|
||||
self.GroupKeysInSection("Editor.EditorEngine", "EditPackages")
|
||||
self.GroupKeysInSection("Editor.EditorEngine", "CutdownPackages")
|
||||
super().writeFile(bBeautify)
|
||||
class PySimpleINI_UT2k4(PySimpleINI_GroupKeysInSection):
|
||||
GroupRules = [
|
||||
("Engine.GameEngine", "ServerPackages"),
|
||||
("Engine.GameEngine", "ServerActors"),
|
||||
("Core.System", "Suppress"),
|
||||
("Core.System", "Paths"),
|
||||
("Core.System", "Paths"),
|
||||
("Editor.EditorEngine", "EditPackages"),
|
||||
("Editor.EditorEngine", "CutdownPackages"),
|
||||
]
|
||||
|
||||
|
||||
class GameOption_UT2k4(GameOption):
|
||||
class GameOption_UT2k4(GameOption_UT):
|
||||
szGameType = "ut2k4"
|
||||
TValueType = OptionType.OT_INVALID
|
||||
|
||||
szOptionName = ""
|
||||
szSectionName = ""
|
||||
szKeyName = ""
|
||||
bForceAdd: bool = False
|
||||
bRemovable: bool = False
|
||||
|
||||
def __init__(self, GameRootDir: str, ConfigFileRelPath: Union[None, str]) -> None:
|
||||
super().__init__(GameRootDir, ConfigFileRelPath)
|
||||
self.mainConfigFilePath = join(GameRootDir, ConfigFileRelPath)
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
self.format(value)
|
||||
self.inifile = ChaChaSimpleINI_UT2k4(self.mainConfigFilePath)
|
||||
self.inifile.setAddKeyValue(self.szSectionName, self.szKeyName, self.szFormatedValue, self.bForceAdd)
|
||||
self.inifile.writeFile()
|
||||
|
||||
def rem(self, value: Union[None, str]) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
if not self.bRemovable:
|
||||
raise RuntimeError("this options is not removable")
|
||||
self.inifile.delKeyEx(self.szSectionName, self.szKeyName, None, value)
|
||||
self.inifile.writeFile()
|
||||
|
||||
def get(self) -> Union[None, str]:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName not set")
|
||||
res = self.inifile.getKeyValue(self.szSectionName, self.szKeyName)
|
||||
return res
|
||||
Cls_PySimpleINI = PySimpleINI_UT2k4
|
||||
|
||||
|
||||
class GameOption_UT2k4_GenAdd(GameOption_UT2k4):
|
||||
@@ -155,10 +122,10 @@ class GameOption_UT2k4_HostName(GameOption_UT2k4):
|
||||
szDefaultValue = "ChaCha Test Server"
|
||||
szHelp = "Server's HostName"
|
||||
|
||||
def set(self, value: str):
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("Engine.GameReplicationInfo", "ShortName", value)
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("Engine.GameReplicationInfo", "ShortName", value)
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -200,12 +167,12 @@ class GameOption_UT2k4_HTTPDownloadServer(GameOption_UT2k4):
|
||||
szDefaultValue = "http://chacha.ddns.net/games/ut2k4"
|
||||
szHelp = "FastDL url"
|
||||
|
||||
def set(self, value: str):
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("IpDrv.HTTPDownload", "UseCompression", "True")
|
||||
self.inifile.delKey("IpDrv.HTTPDownload", "ProxyServerHost")
|
||||
self.inifile.delKey("IpDrv.HTTPDownload", "ProxyServerPort")
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("IpDrv.HTTPDownload", "UseCompression", "True")
|
||||
self.inifile.delkey("IpDrv.HTTPDownload", "ProxyServerHost")
|
||||
self.inifile.delkey("IpDrv.HTTPDownload", "ProxyServerPort")
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -237,10 +204,10 @@ class GameOption_UT2k4_NetServerMaxTickRate(GameOption_UT2k4):
|
||||
szDefaultValue = "60"
|
||||
szHelp = "Server Max TickRate"
|
||||
|
||||
def set(self, value: str):
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("Engine.DemoRecDrive", "NetServerMaxTickRate", value)
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("Engine.DemoRecDrive", "NetServerMaxTickRate", value)
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -252,10 +219,10 @@ class GameOption_UT2k4_LanServerMaxTickRate(GameOption_UT2k4):
|
||||
szDefaultValue = "60"
|
||||
szHelp = "Lan Server Max TickRate"
|
||||
|
||||
def set(self, value: str):
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("Engine.DemoRecDrive", "LanServerMaxTickRate", value)
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("Engine.DemoRecDrive", "LanServerMaxTickRate", value)
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -730,7 +697,7 @@ class GameOption_UT2k4_WebServer(GameOption_UT2k4):
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
if int(value) > 0:
|
||||
self.inifile.setAddKeyValue("UWeb.WebServer", "bEnabled", "True")
|
||||
self.inifile.setaddkeyvalue("UWeb.WebServer", "bEnabled", "True")
|
||||
else:
|
||||
self.inifile.setAddKeyValue("UWeb.WebServer", "bEnabled", "False")
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("UWeb.WebServer", "bEnabled", "False")
|
||||
self.inifile.writefile()
|
||||
@@ -1,74 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
# pylint: disable=missing-class-docstring,missing-function-docstring,duplicate-code,line-too-long
|
||||
"""UT99 command set"""
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
from pysimpleini import PySimpleINI, KeyNotFoundError, SectionNotFoundError, Section, Key
|
||||
from os.path import join
|
||||
from pysimpleini import KeyNotFoundError, SectionNotFoundError
|
||||
|
||||
from .core import GameOptions_Factory_Register, GameOption, OptionType
|
||||
from .core_gamecfg import GameOptions_Factory_Register, OptionType
|
||||
from .tool_ini import PySimpleINI_GroupKeysInSection
|
||||
from .common_ut import GameOption_UT
|
||||
|
||||
|
||||
class PySimpleINI_UT99(PySimpleINI):
|
||||
def GroupKeysInSection(self, szSectionName: str, szKeyName: str) -> None:
|
||||
try:
|
||||
_section = self.getSection(szSectionName)
|
||||
if type(_section) is Section:
|
||||
ar_ServerPackages = _section.getKey(szKeyName)
|
||||
if isinstance(ar_ServerPackages, Key):
|
||||
ar_ServerPackages = [ar_ServerPackages]
|
||||
else: # array
|
||||
pass
|
||||
for ServerPackages in ar_ServerPackages:
|
||||
_section.delKey(ServerPackages.name, None, ServerPackages.value)
|
||||
for ServerPackages in ar_ServerPackages:
|
||||
_section.setAddKeyValue(ServerPackages.name, ServerPackages.value, True)
|
||||
except SectionNotFoundError:
|
||||
pass
|
||||
|
||||
def writeFile(self, bBeautify: bool = False) -> None:
|
||||
self.GroupKeysInSection("XC_Engine.XC_GameEngine", "ServerPackages")
|
||||
self.GroupKeysInSection("XC_Engine.XC_GameEngine", "ServerActors")
|
||||
self.GroupKeysInSection("Engine.GameEngine", "ServerPackages")
|
||||
self.GroupKeysInSection("Engine.GameEngine", "ServerActors")
|
||||
self.GroupKeysInSection("Core.System", "Suppress")
|
||||
self.GroupKeysInSection("Editor.EditorEngine", "EditPackages")
|
||||
super().writeFile(bBeautify)
|
||||
class PySimpleINI_UT99(PySimpleINI_GroupKeysInSection):
|
||||
GroupRules = [
|
||||
("XC_Engine.XC_GameEngine", "ServerPackages"),
|
||||
("XC_Engine.XC_GameEngine", "ServerActors"),
|
||||
("Engine.GameEngine", "ServerPackages"),
|
||||
("Engine.GameEngine", "ServerActors"),
|
||||
("Core.System", "Suppress"),
|
||||
("Editor.EditorEngine", "EditPackages"),
|
||||
]
|
||||
|
||||
|
||||
class GameOption_UT99(GameOption):
|
||||
class GameOption_UT99(GameOption_UT):
|
||||
szGameType = "ut99"
|
||||
TValueType = OptionType.OT_INVALID
|
||||
|
||||
szOptionName = ""
|
||||
szSectionName = ""
|
||||
szKeyName = ""
|
||||
bForceAdd: bool = False
|
||||
bRemovable: bool = False
|
||||
|
||||
def __init__(self, GameRootDir: str, ConfigFileRelPath: str) -> None:
|
||||
super().__init__(GameRootDir, ConfigFileRelPath)
|
||||
self.mainConfigFilePath = join(GameRootDir, ConfigFileRelPath)
|
||||
self.inifile = PySimpleINI_UT99(self.mainConfigFilePath)
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
self.format(value)
|
||||
self.inifile.setAddKeyValue(self.szSectionName, self.szKeyName, self.szFormatedValue, self.bForceAdd)
|
||||
self.inifile.writeFile()
|
||||
|
||||
def rem(self, value: Union[None, str]) -> None:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName is not set")
|
||||
if not self.bRemovable:
|
||||
raise RuntimeError("this options is not removable")
|
||||
self.inifile.delkey_ex(self.szSectionName, self.szKeyName, None, value)
|
||||
self.inifile.writeFile()
|
||||
|
||||
def get(self) -> Union[None, str]:
|
||||
if not self.szOptionName:
|
||||
raise RuntimeError("szOptionName not set")
|
||||
res = self.inifile.getkeyvalue(self.szSectionName, self.szKeyName)
|
||||
return res
|
||||
Cls_PySimpleINI = PySimpleINI_UT99
|
||||
|
||||
|
||||
class GameOption_UT99_GenAdd(GameOption_UT99):
|
||||
@@ -95,7 +61,7 @@ class GameOption_UT99_GenAdd__Engine(GameOption_UT99_GenAdd):
|
||||
prev = self.szSectionName
|
||||
|
||||
try:
|
||||
self.inifile.getSection("XC_Engine.XC_GameEngine")
|
||||
self.inifile.getsection("XC_Engine.XC_GameEngine")
|
||||
self.szSectionName = "XC_Engine.XC_GameEngine"
|
||||
super().set(value)
|
||||
except SectionNotFoundError:
|
||||
@@ -109,7 +75,7 @@ class GameOption_UT99_GenAdd__Engine(GameOption_UT99_GenAdd):
|
||||
prev = self.szSectionName
|
||||
|
||||
try:
|
||||
self.inifile.getSection("XC_Engine.XC_GameEngine")
|
||||
self.inifile.getsection("XC_Engine.XC_GameEngine")
|
||||
self.szSectionName = "XC_Engine.XC_GameEngine"
|
||||
super().rem(value)
|
||||
except SectionNotFoundError:
|
||||
@@ -174,8 +140,8 @@ class GameOption_UT99_HostName(GameOption_UT99):
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("Engine.GameReplicationInfo", "ShortName", value)
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("Engine.GameReplicationInfo", "ShortName", value)
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -239,8 +205,8 @@ class GameOption_UT99_AdminName(GameOption_UT99):
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("UTServerAdmin.UTServerAdmin", "AdminUsername", value)
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("UTServerAdmin.UTServerAdmin", "AdminUsername", value)
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -254,10 +220,10 @@ class GameOption_UT99_HTTPDownloadServer(GameOption_UT99):
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("IpDrv.HTTPDownload", "UseCompression", "True")
|
||||
self.inifile.delKey("IpDrv.HTTPDownload", "ProxyServerHost")
|
||||
self.inifile.delKey("IpDrv.HTTPDownload", "ProxyServerPort")
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("IpDrv.HTTPDownload", "UseCompression", "True")
|
||||
self.inifile.delkey("IpDrv.HTTPDownload", "ProxyServerHost")
|
||||
self.inifile.delkey("IpDrv.HTTPDownload", "ProxyServerPort")
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -291,8 +257,8 @@ class GameOption_UT99_NetServerMaxTickRate(GameOption_UT99):
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("Engine.DemoRecDriver", "NetServerMaxTickRate", value)
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("Engine.DemoRecDriver", "NetServerMaxTickRate", value)
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -306,8 +272,8 @@ class GameOption_UT99_LanServerMaxTickRate(GameOption_UT99):
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("Engine.DemoRecDriver", "LanServerMaxTickRate", value)
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("Engine.DemoRecDriver", "LanServerMaxTickRate", value)
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
@@ -321,10 +287,10 @@ class GameOption_UT99_AdminPassword(GameOption_UT99):
|
||||
|
||||
def set(self, value: str) -> None:
|
||||
super().set(value)
|
||||
self.inifile.setAddKeyValue("UTServerAdmin.UTServerAdmin", "AdminPassword", value)
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("UTServerAdmin.UTServerAdmin", "AdminPassword", value)
|
||||
self.inifile.writefile()
|
||||
|
||||
def get(self) -> Union[None, str]:
|
||||
def get(self) -> Union[str, list[str]]:
|
||||
try:
|
||||
return super().get()
|
||||
except KeyNotFoundError:
|
||||
@@ -458,15 +424,15 @@ class GameOption_UT99_WebServer(GameOption_UT99):
|
||||
def set(self, value: str) -> None:
|
||||
# fix ut99 v469c
|
||||
try:
|
||||
self.inifile.delKey("UWeb.WebServer", "Listenport")
|
||||
except:
|
||||
self.inifile.delkey("UWeb.WebServer", "Listenport")
|
||||
except KeyNotFoundError:
|
||||
pass
|
||||
super().set(value)
|
||||
if int(value) > 0:
|
||||
self.inifile.setAddKeyValue("UWeb.WebServer", "bEnabled", "True")
|
||||
self.inifile.setaddkeyvalue("UWeb.WebServer", "bEnabled", "True")
|
||||
else:
|
||||
self.inifile.setAddKeyValue("UWeb.WebServer", "bEnabled", "False")
|
||||
self.inifile.writeFile()
|
||||
self.inifile.setaddkeyvalue("UWeb.WebServer", "bEnabled", "False")
|
||||
self.inifile.writefile()
|
||||
|
||||
|
||||
@GameOptions_Factory_Register
|
||||
1
src/pygamecfg/py.typed
Normal file
1
src/pygamecfg/py.typed
Normal file
@@ -0,0 +1 @@
|
||||
# PlaceHolder
|
||||
44
src/pygamecfg/tool_ini.py
Normal file
44
src/pygamecfg/tool_ini.py
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pyGameCFG(c) by chacha
|
||||
#
|
||||
# pyGameCFG is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
"""utility module that contain PySimpleINI based helpers"""
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
from pysimpleini import PySimpleINI, SectionNotFoundError, Key, Section
|
||||
|
||||
|
||||
class PySimpleINI_GroupKeysInSection(PySimpleINI):
|
||||
"""a class base on PySimpleINI that allow user to force some key to be group together in a section"""
|
||||
|
||||
GroupRules: list[tuple[str, str]] = []
|
||||
|
||||
def groupkeysinsection(self, szSectionName: str, szKeyName: str) -> None:
|
||||
"""internal function that actually group keys"""
|
||||
try:
|
||||
_section: list[Section] = self.getsection(szSectionName)
|
||||
if len(_section) == 1:
|
||||
ar_ServerPackages: Union[list[Key], Key] = _section[0].getkey(szKeyName)
|
||||
if isinstance(ar_ServerPackages, Key):
|
||||
ar_ServerPackages = [ar_ServerPackages]
|
||||
else: # array
|
||||
pass
|
||||
for ServerPackages in ar_ServerPackages:
|
||||
_section[0].delkey(ServerPackages.getname(), None, ServerPackages.getvalue())
|
||||
for ServerPackages in ar_ServerPackages:
|
||||
_section[0].setaddkeyvalue(ServerPackages.getname(), ServerPackages.getvalue(), True)
|
||||
except SectionNotFoundError:
|
||||
pass
|
||||
|
||||
def writefile(self, bBeautify: bool = False, bWipeComments: bool = False) -> None:
|
||||
"""overload of the write function to call the group function before"""
|
||||
for GroupRule in self.GroupRules:
|
||||
self.groupkeysinsection(GroupRule[0], GroupRule[1])
|
||||
super().writefile(bBeautify, bWipeComments)
|
||||
143
test/data/COD4/main/server.cfg
Normal file
143
test/data/COD4/main/server.cfg
Normal file
@@ -0,0 +1,143 @@
|
||||
sets _Admin "TestAdmin"
|
||||
sets _Email "TestEmail@domain.com"
|
||||
sets _Website "www.TestWebSite.com"
|
||||
sets _Location "TestLocation"
|
||||
sets _Maps "TestMap"
|
||||
sets _Gametype "TestGametype"
|
||||
|
||||
set sv_authtoken "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
|
||||
set sv_hostname "TestHostName"
|
||||
set g_motd "TestMOTD"
|
||||
set dedicated "2"
|
||||
set rcon_password "TestRconPwd"
|
||||
set g_password "TestPwd"
|
||||
set sv_privateClients "3"
|
||||
set sv_privatePassword "TestPrivatePassword"
|
||||
set sv_authorizemode "0"
|
||||
set sv_showasranked 0
|
||||
set sv_maxclients "11"
|
||||
|
||||
set g_logsync "2"
|
||||
set logfile "1"
|
||||
set g_log "games_mp.log"
|
||||
set sv_log_damage "1"
|
||||
set sv_statusfile "serverstatus.xml"
|
||||
|
||||
//set net_port 28960
|
||||
|
||||
|
||||
set sv_minPing "0"
|
||||
set sv_maxPing "350"
|
||||
set sv_timeout 40
|
||||
set sv_connectTimeout 90
|
||||
set sv_zombieTime 2
|
||||
set sv_reconnectlimit 5
|
||||
|
||||
|
||||
|
||||
set sv_allowAnonymous "0"
|
||||
|
||||
|
||||
set g_deadChat "1"
|
||||
set voice_deadChat "0"
|
||||
set g_gravity "800"
|
||||
set sv_disableClientConsole "0"
|
||||
set scr_teambalance "1"
|
||||
set scr_team_fftype "0"
|
||||
set scr_game_spectatetype "2"
|
||||
set scr_hardcore 0
|
||||
set scr_oldschool "0"
|
||||
|
||||
set g_friendlyPlayerCanBlock 1
|
||||
set g_FFAPlayerCanBlock 1
|
||||
|
||||
set scr_drawfriend "1"
|
||||
set scr_enable_scoretext "1"
|
||||
set scr_game_allowkillcam "1"
|
||||
set scr_game_deathpointloss "0"
|
||||
set scr_game_suicidepointloss "0"
|
||||
set scr_game_matchstarttime "5"
|
||||
set scr_game_playerwaittime "0"
|
||||
set scr_player_forcerespawn "-1"
|
||||
set scr_player_healthregentime "5"
|
||||
set scr_player_maxhealth "100"
|
||||
set scr_player_sprinttime "4"
|
||||
set scr_game_onlyheadshots "0"
|
||||
set scr_teamKillPunishCount "3"
|
||||
set scr_team_teamkillspawndelay "20"
|
||||
set scr_team_teamkillpointloss "1"
|
||||
set scr_enable_hiticon "1"
|
||||
|
||||
set scr_dm_scorelimit "1000"
|
||||
set scr_dm_timelimit "15"
|
||||
set scr_dm_roundlimit "1"
|
||||
set scr_dm_numlives "0"
|
||||
set scr_dm_playerrespawndelay "0"
|
||||
set scr_dm_waverespawndelay "0"
|
||||
|
||||
set scr_war_scorelimit "2000"
|
||||
set scr_war_timelimit "10"
|
||||
set scr_war_roundlimit "1"
|
||||
set scr_war_numlives "0"
|
||||
set scr_war_playerrespawndelay "0"
|
||||
set scr_war_waverespawndelay "0"
|
||||
|
||||
set scr_dom_scorelimit "250"
|
||||
set scr_dom_timelimit "0"
|
||||
set scr_dom_numlives "0"
|
||||
set scr_dom_playerrespawndelay "0"
|
||||
set scr_dom_roundlimit "1"
|
||||
set scr_dom_waverespawndelay "0"
|
||||
|
||||
set scr_koth_scorelimit "250"
|
||||
set scr_koth_timelimit "15"
|
||||
set koth_kothmode "0"
|
||||
set koth_capturetime "20"
|
||||
set koth_spawntime "3"
|
||||
set scr_koth_numlives "0"
|
||||
set scr_koth_playerrespawndelay "3"
|
||||
set scr_koth_roundlimit "1"
|
||||
set scr_koth_roundswitch "1"
|
||||
set scr_koth_waverespawndelay "0"
|
||||
set koth_autodestroytime "60"
|
||||
set koth_delayPlayer "3"
|
||||
set koth_destroytime "10"
|
||||
set koth_spawnDelay "3"
|
||||
|
||||
set scr_sab_scorelimit "2"
|
||||
set scr_sab_timelimit "10"
|
||||
set scr_sab_roundswitch "1"
|
||||
set scr_sab_bombtimer "30"
|
||||
set scr_sab_planttime "2.5"
|
||||
set scr_sab_defusetime "5"
|
||||
set scr_sab_hotpotato "0"
|
||||
set scr_sab_numlives "0"
|
||||
set scr_sab_playerrespawndelay "0"
|
||||
set scr_sab_roundlimit "0"
|
||||
set scr_sab_waverespawndelay "0"
|
||||
|
||||
set scr_sd_scorelimit "9"
|
||||
set scr_sd_timelimit "2.5"
|
||||
set scr_sd_roundswitch "4"
|
||||
set scr_sd_bombtimer "45"
|
||||
set scr_sd_planttime "5"
|
||||
set scr_sd_defusetime "7"
|
||||
set scr_sd_multibomb "0"
|
||||
set scr_sd_numlives "1"
|
||||
set scr_sd_playerrespawndelay "0"
|
||||
set scr_sd_roundlimit "0"
|
||||
set scr_sd_waverespawndelay "0"
|
||||
|
||||
set g_gametype "dm"
|
||||
set sv_mapRotation "gametype dm map mp_backlot gametype dm map mp_bloc gametype dm map mp_bog gametype dm map mp_cargoship gametype dm map mp_citystreets gametype dm map mp_convoy gametype dm map mp_countdown gametype dm map mp_crash gametype dm map mp_crossfire gametype dm map mp_farm gametype dm map mp_overgrown gametype dm map mp_pipeline gametype dm map mp_shipment gametype dm map mp_showdown gametype dm map mp_strike gametype dm map mp_vacant"
|
||||
|
||||
|
||||
set sv_allowdownload "1"
|
||||
set sv_wwwDownload "1"
|
||||
set sv_wwwBaseURL "http://TestRedirect/"
|
||||
set sv_wwwDlDisconnected "0"
|
||||
|
||||
set sv_nosteamnames 1
|
||||
|
||||
map_rotate
|
||||
113
test/test_cod4.py
Normal file
113
test/test_cod4.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# pygamecfg (c) by chacha
|
||||
#
|
||||
# pygamecfg is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
import unittest
|
||||
from os import path, chdir
|
||||
from io import StringIO
|
||||
from contextlib import redirect_stdout, redirect_stderr
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from src import pygamecfg
|
||||
from src.pygamecfg.__main__ import fct_main
|
||||
from src.pygamecfg.game_cod4 import COD4KeyNotFoundError
|
||||
|
||||
testdir_path = Path(__file__).parent.resolve()
|
||||
|
||||
|
||||
class Testtest_cod4(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
chdir(testdir_path.parent.resolve())
|
||||
self.CleanTmp()
|
||||
shutil.copytree(testdir_path / "data", testdir_path / "tmp")
|
||||
print("======================")
|
||||
|
||||
def CleanTmp(self):
|
||||
# remove any file in tmp dir, except .keep
|
||||
if path.exists(testdir_path / "tmp"):
|
||||
shutil.rmtree(testdir_path / "tmp")
|
||||
|
||||
def test_normal_READ_sv_maxclients(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "maxclients"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("11\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_READ_sv_mapRotation(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "mapRotation"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual(
|
||||
"gametype dm map mp_backlot gametype dm map mp_bloc gametype dm map mp_bog gametype dm map mp_cargoship gametype dm map mp_citystreets gametype dm map mp_convoy gametype dm map mp_countdown gametype dm map mp_crash gametype dm map mp_crossfire gametype dm map mp_farm gametype dm map mp_overgrown gametype dm map mp_pipeline gametype dm map mp_shipment gametype dm map mp_showdown gametype dm map mp_strike gametype dm map mp_vacant\n",
|
||||
capted_stdout.getvalue(),
|
||||
)
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_WRITE_sv_maxclients(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "SetOption", "maxclients", "17"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("setting option <maxclients> to: 17\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "maxclients"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("17\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
# check if *other* key still there / untouched
|
||||
self.test_normal_READ_sv_mapRotation()
|
||||
|
||||
def test_defect_READ_net_port_NONEXISTS(self):
|
||||
with self.assertRaises(COD4KeyNotFoundError):
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "net_port"])
|
||||
|
||||
def test_normal_WRITE_net_port_NONEXISTS(self):
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "SetOption", "net_port", "132"])
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "net_port"])
|
||||
self.assertEqual("132\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_WRITE_oldschool(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "SetOption", "oldschool", "1"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("setting option <oldschool> to: 1\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "oldschool"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("1\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "SetOption", "oldschool", "0"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("setting option <oldschool> to: 0\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "oldschool"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("0\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "SetOption", "oldschool", "1"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("setting option <oldschool> to: 1\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "oldschool"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("1\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
@@ -7,17 +7,22 @@
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
import unittest
|
||||
from os import chdir
|
||||
from io import StringIO
|
||||
from contextlib import redirect_stdout, redirect_stderr
|
||||
|
||||
print(__name__)
|
||||
print(__package__)
|
||||
from pathlib import Path
|
||||
|
||||
from src import pygamecfg
|
||||
from src.pygamecfg.__main__ import fct_main
|
||||
|
||||
|
||||
testdir_path = Path(__file__).parent.resolve()
|
||||
|
||||
|
||||
class Testtest_gen(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
chdir(testdir_path.parent.resolve())
|
||||
|
||||
def test_version(self):
|
||||
self.assertNotEqual(pygamecfg.__version__, "?.?.?")
|
||||
|
||||
|
||||
@@ -7,21 +7,33 @@
|
||||
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
import unittest
|
||||
from os import linesep
|
||||
from os import path, chdir
|
||||
from io import StringIO
|
||||
from contextlib import redirect_stdout, redirect_stderr
|
||||
|
||||
print(__name__)
|
||||
print(__package__)
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from src import pygamecfg
|
||||
from src.pygamecfg.__main__ import fct_main
|
||||
|
||||
testdir_path = Path(__file__).parent.resolve()
|
||||
|
||||
|
||||
class Testtest_ut99(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
chdir(testdir_path.parent.resolve())
|
||||
self.CleanTmp()
|
||||
shutil.copytree(testdir_path / "data", testdir_path / "tmp")
|
||||
print("======================")
|
||||
|
||||
def CleanTmp(self):
|
||||
# remove any file in tmp dir, except .keep
|
||||
if path.exists(testdir_path / "tmp"):
|
||||
shutil.rmtree(testdir_path / "tmp")
|
||||
|
||||
def test_normal_ServerPackages(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "ServerPackages"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "ServerPackages"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual(
|
||||
"['SoldierSkins', 'CommandoSkins', 'FCommandoSkins', 'SGirlSkins', 'BossSkins', 'Botpack']\n", capted_stdout.getvalue()
|
||||
@@ -30,7 +42,7 @@ class Testtest_ut99(unittest.TestCase):
|
||||
|
||||
def test_normal_ServerActors(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "ServerActors"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "ServerActors"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual(
|
||||
"['IpDrv.UdpBeacon', 'IpServer.UdpServerQuery', 'IpServer.UdpServerUplink MasterServerAddress=unreal.epicgames.com MasterServerPort=27900', 'IpServer.UdpServerUplink MasterServerAddress=master0.gamespy.com MasterServerPort=27900', 'IpServer.UdpServerUplink MasterServerAddress=master.mplayer.com MasterServerPort=27900', 'UWeb.WebServer']\n",
|
||||
@@ -40,273 +52,273 @@ class Testtest_ut99(unittest.TestCase):
|
||||
|
||||
def test_normal_Port(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "Port"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "Port"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("7777\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_Map(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "Map"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "Map"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("Index.unr\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_GameType(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "GameType"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "GameType"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("Botpack.DeathMatchPlus\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_HostName(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "HostName"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "HostName"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("Test Server Name FULL\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MOTD(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MOTD"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MOTD"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("TestMOTDLine1\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MOTD2(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MOTD2"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MOTD2"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("TestMOTDLine2\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MOTD3(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MOTD3"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MOTD3"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("TestMOTDLine3\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MOTD4(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MOTD4"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MOTD4"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("TestMOTDLine4\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_AdminEmail(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "AdminEmail"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "AdminEmail"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("TestAdminName@test.com\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_AdminName(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "AdminName"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "AdminName"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("TestAdminName\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_HTTPDownloadServer(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "HTTPDownloadServer"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "HTTPDownloadServer"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("http://uz.ut-files.com/\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MaxClientRate(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MaxClientRate"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MaxClientRate"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("20000\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_NetServerMaxTickRate(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "NetServerMaxTickRate"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "NetServerMaxTickRate"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("20\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_LanServerMaxTickRate(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "LanServerMaxTickRate"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "LanServerMaxTickRate"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("35\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_AdminPassword(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "AdminPassword"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "AdminPassword"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("TestAdminPwd\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_GamePassword(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "GamePassword"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "GamePassword"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("TestPwd\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MaxPlayers(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MaxPlayers"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MaxPlayers"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("4\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MaxSpectators(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MaxSpectators"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MaxSpectators"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("1\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_AS_TimeLimit(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "AS_TimeLimit"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "AS_TimeLimit"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("123\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_DOM_TimeLimit(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "DOM_TimeLimit"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "DOM_TimeLimit"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("423\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_CTF_TimeLimit(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "CTF_TimeLimit"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "CTF_TimeLimit"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("223\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_DM_TimeLimit(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "DM_TimeLimit"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "DM_TimeLimit"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("323\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_GoalTeamScore(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "GoalTeamScore"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "GoalTeamScore"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("30\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MaxTeamSize(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MaxTeamSize"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MaxTeamSize"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("4\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_DM_FragLimit(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "DM_FragLimit"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "DM_FragLimit"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("321\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_ServerLogName(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "ServerLogName"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "ServerLogName"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("server.log\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_WebServer(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "WebServer"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "WebServer"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("9999\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_TournamentMode(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "TournamentMode"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "TournamentMode"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("False\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_InitialBots(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "InitialBots"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "InitialBots"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("7\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_MinPlayers(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "MinPlayers"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "MinPlayers"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("11\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_AS_UseTranslocator(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "AS_UseTranslocator"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "AS_UseTranslocator"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("True\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_CTF_UseTranslocator(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "CTF_UseTranslocator"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "CTF_UseTranslocator"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("True\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_DM_UseTranslocator(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "DM_UseTranslocator"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "DM_UseTranslocator"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("False\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_DOM_UseTranslocator(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "DOM_UseTranslocator"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "DOM_UseTranslocator"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("True\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_CTF_ForceRespawn(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "CTF_ForceRespawn"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "CTF_ForceRespawn"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("False\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_DM_ForceRespawn(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "DM_ForceRespawn"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "DM_ForceRespawn"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("True\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_DOM_ForceRespawn(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "DOM_ForceRespawn"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "DOM_ForceRespawn"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("False\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_AS_ForceRespawn(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "GetOption", "AS_ForceRespawn"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "GetOption", "AS_ForceRespawn"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("True\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
def test_normal_customcfgfile_HostName(self):
|
||||
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
|
||||
fct_main(["-g", "ut99", "-b", "test/data/UT99", "-c", "System/UT99.ini", "GetOption", "HostName"])
|
||||
fct_main(["-g", "ut99", "-b", "test/tmp/UT99", "-c", "System/UT99.ini", "GetOption", "HostName"])
|
||||
# /!\ add '\n' at the end of the string cause Python terminal newline is always this, regardless Windows / Linux os.linesep
|
||||
self.assertEqual("Alt Serv Name FULL\n", capted_stdout.getvalue())
|
||||
self.assertEqual("", capted_stderr.getvalue())
|
||||
|
||||
Reference in New Issue
Block a user