mega_snake 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mega_snake/__init__.py +1 -0
- mega_snake/__main__.py +107 -0
- mega_snake/config.properties +11 -0
- mega_snake/config_environment/__init__.py +1 -0
- mega_snake/config_environment/create_working_env.py +437 -0
- mega_snake/config_environment/gradle_set.py +209 -0
- mega_snake/config_environment/graphql_schema.py +79 -0
- mega_snake/config_environment/java_set.py +292 -0
- mega_snake/config_environment/local_config.py +72 -0
- mega_snake/config_environment/maven_set.py +330 -0
- mega_snake/config_environment/models/github_queries.py +78 -0
- mega_snake/config_environment/models/log_viewer_watcher.py +70 -0
- mega_snake/config_environment/models/tools_version.py +204 -0
- mega_snake/config_environment/models/vscode_input.py +117 -0
- mega_snake/config_environment/models/vscode_launch.py +140 -0
- mega_snake/config_environment/models/vscode_task.py +266 -0
- mega_snake/config_environment/module.py +33 -0
- mega_snake/config_environment/util.py +61 -0
- mega_snake/config_setup.ps1 +44 -0
- mega_snake/config_setup.sh +48 -0
- mega_snake/constants.py +60 -0
- mega_snake/diff_tree/__init__.py +1 -0
- mega_snake/diff_tree/file_type.py +81 -0
- mega_snake/diff_tree/module.py +154 -0
- mega_snake/light_weight/__init__.py +1 -0
- mega_snake/light_weight/create_release.py +105 -0
- mega_snake/light_weight/echo.py +81 -0
- mega_snake/light_weight/jks_expired_certs.py +105 -0
- mega_snake/light_weight/module.py +30 -0
- mega_snake/light_weight/release.py +132 -0
- mega_snake/light_weight/release_handler.py +76 -0
- mega_snake/light_weight/shell_init.py +76 -0
- mega_snake/remote_branches/__init__.py +1 -0
- mega_snake/remote_branches/cleanup_remote_branches.py +63 -0
- mega_snake/remote_branches/details_remote_branches.py +101 -0
- mega_snake/remote_branches/module.py +24 -0
- mega_snake/remote_branches/parse_remote_branches.py +73 -0
- mega_snake/remote_branches/remote_branch.py +161 -0
- mega_snake/resources/java-formatter.xml +337 -0
- mega_snake/util/__init__.py +1 -0
- mega_snake/util/cli_group.py +71 -0
- mega_snake/util/formatting.py +234 -0
- mega_snake/util/props.py +384 -0
- mega_snake/util/util.py +247 -0
- mega_snake-0.1.0.dist-info/METADATA +258 -0
- mega_snake-0.1.0.dist-info/RECORD +49 -0
- mega_snake-0.1.0.dist-info/WHEEL +4 -0
- mega_snake-0.1.0.dist-info/entry_points.txt +2 -0
- mega_snake-0.1.0.dist-info/licenses/LICENSE +201 -0
mega_snake/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
""" init file for setup configuration package """
|
mega_snake/__main__.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Sets the environment configuration"""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import Optional
|
|
5
|
+
import sys
|
|
6
|
+
import click
|
|
7
|
+
from .diff_tree.module import main as diff_tree
|
|
8
|
+
from .light_weight.module import main as create_release, add_wrapper as create_release_result_callback
|
|
9
|
+
from .remote_branches.module import main as remote_branches, add_wrapper as remote_branches_result_callback
|
|
10
|
+
from .config_environment.module import main as config_environment, add_wrapper as config_env_result_callback
|
|
11
|
+
from .constants import LOGGING_OPT, SHELL_OPT, APP_NAME
|
|
12
|
+
from .util.formatting import get_traceback
|
|
13
|
+
from .util.props import init_app_properties
|
|
14
|
+
from .util.formatting import WorkspaceError, ws_advice
|
|
15
|
+
from .util.cli_group import CliGroup
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.group(
|
|
19
|
+
help="""A CLI tool focused on simplifying Java development with VSCode by automating workspace configuration.
|
|
20
|
+
|
|
21
|
+
Main features:
|
|
22
|
+
- Automated workspace setup for Java/Gradle projects
|
|
23
|
+
- Java and Gradle version management
|
|
24
|
+
- VSCode extensions and settings configuration
|
|
25
|
+
- Debug configurations and launch settings
|
|
26
|
+
- Local development environment setup
|
|
27
|
+
- Git integration and workspace organization""",
|
|
28
|
+
epilog="""Examples:\n
|
|
29
|
+
# Set up a complete workspace environment\n
|
|
30
|
+
mgsnake working-env\n
|
|
31
|
+
\n
|
|
32
|
+
# Configure Java version\n
|
|
33
|
+
mgsnake set-java\n
|
|
34
|
+
\n
|
|
35
|
+
# Configure Gradle version\n
|
|
36
|
+
mgsnake set-gradle\n
|
|
37
|
+
\n
|
|
38
|
+
# Initialize local configurations\n
|
|
39
|
+
mgsnake init-local-config\n
|
|
40
|
+
\n
|
|
41
|
+
# Run with debug logging\n
|
|
42
|
+
mgsnake --log-level DEBUG <command>\n
|
|
43
|
+
\n
|
|
44
|
+
For more details on specific commands, use: mgsnake <command> --help""",
|
|
45
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
46
|
+
cls=CliGroup,
|
|
47
|
+
no_args_is_help=True,
|
|
48
|
+
)
|
|
49
|
+
@click.option("--log-level", "-l", type=click.Choice(list(LOGGING_OPT), False), default="INFO", help="log level")
|
|
50
|
+
@click.pass_context
|
|
51
|
+
def cli(ctx: click.Context, log_level: str) -> None:
|
|
52
|
+
"""cli entry point"""
|
|
53
|
+
ctx.ensure_object(dict) # Ensures ctx.obj is a dictionary
|
|
54
|
+
try:
|
|
55
|
+
light_weight: bool = False
|
|
56
|
+
cmd_name = ctx.invoked_subcommand
|
|
57
|
+
if cmd_name:
|
|
58
|
+
cmd = cli.get_command(ctx, cmd_name)
|
|
59
|
+
if not cmd:
|
|
60
|
+
raise click.ClickException(f"Command '{cmd_name}' not found")
|
|
61
|
+
# check if the command has cli_metadata
|
|
62
|
+
metadata = getattr(cmd.callback, "flags", {})
|
|
63
|
+
flags: Optional[set[str]] = metadata.get("flags")
|
|
64
|
+
if flags and "no_init" in flags:
|
|
65
|
+
return
|
|
66
|
+
ws_advice(f"Invoking subcommand: {cmd_name}")
|
|
67
|
+
if flags and "skip" in flags:
|
|
68
|
+
ws_advice("'skip' flag detected. Running in light-weight mode if local working directory is not found.")
|
|
69
|
+
light_weight = True
|
|
70
|
+
shell = os.environ.get("MEGA_SNAKE_SHELL")
|
|
71
|
+
if not shell:
|
|
72
|
+
raise EnvironmentError("Environment variable 'MEGA_SNAKE_SHELL' is not set")
|
|
73
|
+
if shell not in SHELL_OPT:
|
|
74
|
+
raise ValueError(f"Unsupported shell: {shell}. Supported shells are: {', '.join(SHELL_OPT)}")
|
|
75
|
+
init_app_properties(log_level, shell, light_weight)
|
|
76
|
+
except Exception as e:
|
|
77
|
+
click.echo(f"Error during initialization: {e}", err=True)
|
|
78
|
+
click.echo(get_traceback(e), err=True)
|
|
79
|
+
raise SystemExit(e) from e
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@cli.result_callback()
|
|
83
|
+
@click.pass_context
|
|
84
|
+
def post_command(ctx, result, **kwargs) -> None:
|
|
85
|
+
"""Post-command execution logic"""
|
|
86
|
+
if ctx.invoked_subcommand:
|
|
87
|
+
ws_advice(
|
|
88
|
+
f"Command '{ctx.invoked_subcommand}' completed successfully with result: {result} and kwargs: {kwargs}"
|
|
89
|
+
)
|
|
90
|
+
exit_code: int = ctx.obj.get("exit_code", 0)
|
|
91
|
+
if exit_code:
|
|
92
|
+
sys.exit(exit_code)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
cli.add_command_with_alias(diff_tree, ["dt", "tree"])
|
|
96
|
+
for command in create_release.commands.values():
|
|
97
|
+
cli.add_command(create_release_result_callback(command))
|
|
98
|
+
for command in config_environment.commands.values():
|
|
99
|
+
cli.add_command(config_env_result_callback(command))
|
|
100
|
+
for command in remote_branches.commands.values():
|
|
101
|
+
cli.add_command(remote_branches_result_callback(command))
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
try:
|
|
105
|
+
cli.main(prog_name=APP_NAME)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
raise WorkspaceError("Error during cli execution", e) from e
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
python_module=mega_snake
|
|
2
|
+
resources_path=resources
|
|
3
|
+
working_path=workspace_temp
|
|
4
|
+
log_file_name=python_snake
|
|
5
|
+
local_config_file_name=local_config
|
|
6
|
+
local_env_file_name=.mgsnake.env
|
|
7
|
+
graphql_schema_file_name=schema
|
|
8
|
+
python_virtual_bash=.venv/bin/activate
|
|
9
|
+
python_virtual_ps1_osx=.venv/bin/Activate.ps1
|
|
10
|
+
python_virtual_ps1_linux=.venv/bin/activate.ps1
|
|
11
|
+
python_virtual_ps1_win=.venv/Scripts/Activate.ps1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
""" init file for the config_environment module """
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
"""This module contains the functions for setting the workspace for the project."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import shutil
|
|
6
|
+
import json
|
|
7
|
+
import re
|
|
8
|
+
from typing import Any
|
|
9
|
+
import click
|
|
10
|
+
import jq
|
|
11
|
+
from mega_snake.constants import APP_NAME, WORKSPACE_EXTENSIONS
|
|
12
|
+
from mega_snake.util.props import get_property
|
|
13
|
+
from mega_snake.util.formatting import ws_success
|
|
14
|
+
from mega_snake.config_environment.util import update_workspace
|
|
15
|
+
from mega_snake.config_environment.models.github_queries import PrQueries, IssuesQueries
|
|
16
|
+
from mega_snake.config_environment.models.log_viewer_watcher import LogWatcher
|
|
17
|
+
from mega_snake.config_environment.models.vscode_task import VscodeTask, TASKS_INPUT_QUERY
|
|
18
|
+
from mega_snake.config_environment.models.vscode_input import VscodeInput, InputType
|
|
19
|
+
from mega_snake.config_environment.models.vscode_launch import (
|
|
20
|
+
VscodeLaunch,
|
|
21
|
+
LAUNCH_INPUT_QUERY,
|
|
22
|
+
SUBSTITUTE_SHELL_TAG,
|
|
23
|
+
SUBSTITUTE_PROJECT_TAG,
|
|
24
|
+
REMOTE_DEBUG_PORT_QUERY,
|
|
25
|
+
)
|
|
26
|
+
from mega_snake.config_environment.java_set import execute as set_java
|
|
27
|
+
from mega_snake.config_environment.gradle_set import execute as set_gradle, set_gradle_version as gradle_command
|
|
28
|
+
from mega_snake.config_environment.maven_set import execute as set_maven, set_maven_version as maven_command
|
|
29
|
+
from mega_snake.config_environment.local_config import execute as initial_load
|
|
30
|
+
from mega_snake.util.formatting import ws_advice, ws_info, ws_warning
|
|
31
|
+
from mega_snake.util.util import (
|
|
32
|
+
get_command_return_code,
|
|
33
|
+
get_validated_input,
|
|
34
|
+
cli_metadata,
|
|
35
|
+
get_remote_url,
|
|
36
|
+
load_json_with_comments,
|
|
37
|
+
get_input_or_default,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@click.command(
|
|
42
|
+
name="working-env",
|
|
43
|
+
short_help="Configures the VS Code workspace environment",
|
|
44
|
+
help="Sets up the VS Code workspace with recommended extensions, default settings, tasks, launch configurations,"
|
|
45
|
+
" and git exclusions. Also configures Java and Gradle when applicable.",
|
|
46
|
+
epilog="""This command will:
|
|
47
|
+
- Create/update VSCode workspace file
|
|
48
|
+
- Configure git exclusions for workspace files
|
|
49
|
+
- Set up Java and Gradle configurations
|
|
50
|
+
- Add recommended extensions
|
|
51
|
+
- Configure default settings and file associations
|
|
52
|
+
- Set up tasks and launch configurations
|
|
53
|
+
- Configure log watchers and GitHub queries
|
|
54
|
+
|
|
55
|
+
usage: mgsnake working-env
|
|
56
|
+
""",
|
|
57
|
+
)
|
|
58
|
+
@cli_metadata(flags={"skip"})
|
|
59
|
+
def create_working_env() -> None: # previously untrackGradleProps
|
|
60
|
+
"""
|
|
61
|
+
Sets the workspace for the project.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
None
|
|
65
|
+
"""
|
|
66
|
+
git_repo: bool = True
|
|
67
|
+
if not shutil.which("git"):
|
|
68
|
+
git_repo = False
|
|
69
|
+
if (
|
|
70
|
+
get_validated_input(
|
|
71
|
+
"Git is not installed. Would you like to configure the workspace without git?", ["y", "n"]
|
|
72
|
+
).lower()
|
|
73
|
+
== "n"
|
|
74
|
+
):
|
|
75
|
+
ws_warning("Git is required to configure the workspace. Exiting...")
|
|
76
|
+
return
|
|
77
|
+
else:
|
|
78
|
+
if get_command_return_code("git rev-parse --is-inside-work-tree") != 0:
|
|
79
|
+
git_repo = False
|
|
80
|
+
if (
|
|
81
|
+
get_validated_input(
|
|
82
|
+
"Not inside a git repository. Would you like to configure the workspace anyway?", ["y", "n"]
|
|
83
|
+
).lower()
|
|
84
|
+
== "n"
|
|
85
|
+
):
|
|
86
|
+
ws_warning("Not inside a git repository. Exiting...")
|
|
87
|
+
return
|
|
88
|
+
_execute(git_repo)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _execute(git_repo: bool) -> None: # previously untrackGradleProps
|
|
92
|
+
"""
|
|
93
|
+
Sets the workspace for the project.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
None
|
|
97
|
+
"""
|
|
98
|
+
workspace_file: str = _get_workspace_file()
|
|
99
|
+
working_path: str = _get_working_path()
|
|
100
|
+
if git_repo:
|
|
101
|
+
_git_exclude(working_path)
|
|
102
|
+
initial_load(False)
|
|
103
|
+
set_java(False, workspace_file)
|
|
104
|
+
# verifying if build.gradle or build.gradle.kts exists
|
|
105
|
+
build_file: str = f"{os.getcwd()}/build.gradle"
|
|
106
|
+
build_kts_file: str = f"{os.getcwd()}/build.gradle.kts"
|
|
107
|
+
if not os.path.exists(build_file) and not os.path.exists(build_kts_file):
|
|
108
|
+
ws_warning(
|
|
109
|
+
f"build.gradle or build.gradle.kts file not found in the current directory. "
|
|
110
|
+
f"Please run '{APP_NAME} {gradle_command.name}' command if you want to set the Gradle version anyway."
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
set_gradle(False, workspace_file)
|
|
114
|
+
# verifying if pom.xml exists
|
|
115
|
+
pom_file: str = f"{os.getcwd()}/pom.xml"
|
|
116
|
+
if not os.path.exists(pom_file):
|
|
117
|
+
ws_warning(
|
|
118
|
+
f"pom.xml file not found in the current directory. "
|
|
119
|
+
f"Please run '{APP_NAME} {maven_command.name}' command if you want to set the Maven version anyway."
|
|
120
|
+
)
|
|
121
|
+
else:
|
|
122
|
+
set_maven(None, workspace_file)
|
|
123
|
+
_add_default_settings(workspace_file, working_path)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
FOLDER = os.path.basename(os.getcwd())
|
|
127
|
+
GIT_BLAME_QUERY = '.settings.["git-blame.gitWebUrl"]'
|
|
128
|
+
EXTENSIONS_QUERY = ".extensions.recommendations"
|
|
129
|
+
DEFAULT_PROPS: dict[str, Any] = {
|
|
130
|
+
REMOTE_DEBUG_PORT_QUERY: 5005,
|
|
131
|
+
"mgsnake.java.remoteDebug.profile": "dev",
|
|
132
|
+
"mgsnake.java.remoteDebug.jar": "build/libs/*.jar",
|
|
133
|
+
"terminal.integrated.scrollback": 9000,
|
|
134
|
+
"editor.largeFileOptimizations": False,
|
|
135
|
+
"editor.maxTokenizationLineLength": 2000000,
|
|
136
|
+
"logViewer.followTailMode": "auto",
|
|
137
|
+
"logViewer.chunkSizeKb": 81920,
|
|
138
|
+
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90"
|
|
139
|
+
" -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms100m -Xlog:disable",
|
|
140
|
+
}
|
|
141
|
+
FILE_ASSOCIATIONS: dict[str, str] = {
|
|
142
|
+
"**/.github/workflows/*.yml": "github-actions-workflow",
|
|
143
|
+
"*.yml": "yaml",
|
|
144
|
+
"*.gradle": "gradle",
|
|
145
|
+
}
|
|
146
|
+
FILE_ASSOCIATION_QUERY = '.settings.["files.associations"]'
|
|
147
|
+
NEW_WORKSPACE_CONTENTS: dict[str, Any] = {"folders": [{"name": "main", "path": "."}], "settings": {}}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _get_workspace_file() -> str:
|
|
151
|
+
"""
|
|
152
|
+
Gets the workspace file for the project. If not found, creates a new one.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
str - The workspace file path
|
|
156
|
+
"""
|
|
157
|
+
workspace_file: str = get_property("workspace_file")
|
|
158
|
+
if workspace_file:
|
|
159
|
+
ws_info(f"Vscode workspace file found: {workspace_file}")
|
|
160
|
+
# Check if the workspace file is in the current directory
|
|
161
|
+
if not os.path.exists(workspace_file):
|
|
162
|
+
raise FileNotFoundError(f"No workspace file found at {workspace_file}")
|
|
163
|
+
# Check if the workspace file is not empty
|
|
164
|
+
with open(workspace_file, "r", encoding="utf-8") as file:
|
|
165
|
+
if file.read().strip():
|
|
166
|
+
return workspace_file
|
|
167
|
+
ws_warning("Vscode workspace file is empty")
|
|
168
|
+
else:
|
|
169
|
+
ws_warning("Vscode workspace file not found in current directory")
|
|
170
|
+
if get_validated_input("Would you like to create a new default workspace file?", ["y", "n"]).lower() == "n":
|
|
171
|
+
raise RuntimeError("Vscode workspace file is required to configure the working environment. Exiting...")
|
|
172
|
+
workspace_file = f"{os.getcwd()}/{FOLDER}.code-workspace"
|
|
173
|
+
with open(workspace_file, "w", encoding="utf-8") as file:
|
|
174
|
+
json.dump(NEW_WORKSPACE_CONTENTS, file, indent=4)
|
|
175
|
+
ws_success(f"Vscode workspace file created at {workspace_file}")
|
|
176
|
+
return workspace_file
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _get_working_path() -> str:
|
|
180
|
+
"""
|
|
181
|
+
Gets the working path for the project. If not found, creates a new one.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
str - The working path
|
|
185
|
+
"""
|
|
186
|
+
working_path: str = get_property("working_path")
|
|
187
|
+
assert working_path, (
|
|
188
|
+
"Working path is required to configure the working environment, but not found in the properties. This is a bug."
|
|
189
|
+
)
|
|
190
|
+
assert Path(working_path).resolve().is_relative_to(Path.cwd().resolve()), (
|
|
191
|
+
"Working path is not in the current directory. This is a bug."
|
|
192
|
+
)
|
|
193
|
+
if os.path.exists(working_path):
|
|
194
|
+
ws_info(f"Working path found: {working_path}")
|
|
195
|
+
return working_path
|
|
196
|
+
ws_warning("Working path not found in current directory")
|
|
197
|
+
if get_validated_input("Would you like to create a new default working path?", ["y", "n"]).lower() == "n":
|
|
198
|
+
raise RuntimeError("Working path is required to configure the working environment. Exiting...")
|
|
199
|
+
os.makedirs(working_path, exist_ok=True)
|
|
200
|
+
ws_success(f"Working path created at {working_path}")
|
|
201
|
+
return working_path
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _git_exclude(working_path: str) -> None:
|
|
205
|
+
"""
|
|
206
|
+
Excludes the .vscode folder and the working path from git.
|
|
207
|
+
"""
|
|
208
|
+
working_path = os.path.basename(working_path)
|
|
209
|
+
ex_file: str = ".git/info/exclude"
|
|
210
|
+
# Reading git exclude file
|
|
211
|
+
with open(ex_file, "r", encoding="utf-8") as file:
|
|
212
|
+
exclude: str = file.read()
|
|
213
|
+
if not exclude.endswith("\n"):
|
|
214
|
+
exclude += "\n"
|
|
215
|
+
regex = re.compile(r"^\s*\.vscode/?\s*$", re.MULTILINE)
|
|
216
|
+
if regex.search(exclude):
|
|
217
|
+
ws_advice(f".vscode folder already excluded in {ex_file}")
|
|
218
|
+
else:
|
|
219
|
+
exclude += ".vscode/\n"
|
|
220
|
+
ws_success(f"Excluded .vscode folder in {ex_file}")
|
|
221
|
+
regex = re.compile(rf"^\s*{working_path}/?\s*$", re.MULTILINE)
|
|
222
|
+
if regex.search(exclude):
|
|
223
|
+
ws_advice(f"{working_path} folder already excluded in {ex_file}")
|
|
224
|
+
else:
|
|
225
|
+
exclude += f"{working_path}/\n"
|
|
226
|
+
ws_success(f"Excluded {working_path} folder in {ex_file}")
|
|
227
|
+
regex = re.compile(r"^\s*/\*\.code-workspace\s*$", re.MULTILINE)
|
|
228
|
+
if regex.search(exclude):
|
|
229
|
+
ws_advice(f"root code-workspace file already excluded in {ex_file}")
|
|
230
|
+
else:
|
|
231
|
+
exclude += "/*.code-workspace\n"
|
|
232
|
+
ws_success(f"Excluded root code-workspace file in {ex_file}")
|
|
233
|
+
# Writing git exclude file
|
|
234
|
+
with open(ex_file, "w", encoding="utf-8") as file:
|
|
235
|
+
file.write(exclude)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _add_default_settings(workspace_file: str, working_path: str) -> None:
|
|
239
|
+
"""
|
|
240
|
+
Adds default settings to the workspace file.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
workspace_file (str): The workspace file path
|
|
244
|
+
working_path (str): The working path
|
|
245
|
+
"""
|
|
246
|
+
json_data: dict[str, Any] = load_json_with_comments(workspace_file)
|
|
247
|
+
update_file: bool = False
|
|
248
|
+
|
|
249
|
+
json_data, updated = _add_recommended_extensions(json_data)
|
|
250
|
+
update_file = update_file or updated
|
|
251
|
+
|
|
252
|
+
json_data, updated = _update_git_blame(json_data)
|
|
253
|
+
update_file = update_file or updated
|
|
254
|
+
|
|
255
|
+
json_data, updated = _update_github_queries(json_data)
|
|
256
|
+
update_file = update_file or updated
|
|
257
|
+
|
|
258
|
+
json_data, updated = _update_log_watchers(json_data, working_path)
|
|
259
|
+
update_file = update_file or updated
|
|
260
|
+
|
|
261
|
+
json_data, updated = _update_vscode_tasks(json_data, working_path)
|
|
262
|
+
update_file = update_file or updated
|
|
263
|
+
|
|
264
|
+
json_data, updated = _update_vscode_launch(json_data, working_path)
|
|
265
|
+
update_file = update_file or updated
|
|
266
|
+
|
|
267
|
+
json_data, updated = _update_input_props(json_data)
|
|
268
|
+
update_file = update_file or updated
|
|
269
|
+
|
|
270
|
+
json_data, updated = _update_file_associations(json_data)
|
|
271
|
+
update_file = update_file or updated
|
|
272
|
+
|
|
273
|
+
if update_file:
|
|
274
|
+
temp_file = f"{working_path}/blame.json"
|
|
275
|
+
update_workspace(json_data, temp_file, workspace_file)
|
|
276
|
+
ws_success("Workspace settings updated successfully")
|
|
277
|
+
else:
|
|
278
|
+
ws_advice("Workspace settings already up-to-date")
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _add_recommended_extensions(json_data: dict[str, Any]) -> tuple[dict[str, Any], bool]:
|
|
282
|
+
"""
|
|
283
|
+
Adds recommended extensions to the json contents.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
json_data (dict): The workspace file contents
|
|
287
|
+
"""
|
|
288
|
+
update_file: bool = False
|
|
289
|
+
result = jq.compile(EXTENSIONS_QUERY).input(json_data).all()
|
|
290
|
+
if not result or not result[0]:
|
|
291
|
+
jq_query = f"{EXTENSIONS_QUERY} = {json.dumps(WORKSPACE_EXTENSIONS)}"
|
|
292
|
+
json_data = jq.compile(jq_query).input(json_data).first()
|
|
293
|
+
update_file = True
|
|
294
|
+
else:
|
|
295
|
+
ext_list: list[str] = []
|
|
296
|
+
for ext in WORKSPACE_EXTENSIONS:
|
|
297
|
+
if ext not in result[0]:
|
|
298
|
+
ext_list.append(ext)
|
|
299
|
+
if ext_list:
|
|
300
|
+
jq_query = f"{EXTENSIONS_QUERY} += {json.dumps(ext_list)}"
|
|
301
|
+
json_data = jq.compile(jq_query).input(json_data).first()
|
|
302
|
+
update_file = True
|
|
303
|
+
return json_data, update_file
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _update_git_blame(json_data: dict[str, Any]) -> tuple[dict[str, Any], bool]:
|
|
307
|
+
"""Update git blame settings in workspace"""
|
|
308
|
+
result = jq.compile(GIT_BLAME_QUERY).input(json_data).first()
|
|
309
|
+
remote_url = get_remote_url()
|
|
310
|
+
if not result and remote_url:
|
|
311
|
+
remote_url = re.sub(r"^git@", "https://", remote_url)
|
|
312
|
+
match = re.match(r"https\://\w+\.\w+\:", remote_url)
|
|
313
|
+
if match:
|
|
314
|
+
repl = re.sub(r"\:$", "/", match.group())
|
|
315
|
+
remote_url = remote_url.replace(match.group(), repl)
|
|
316
|
+
jq_query = f'{GIT_BLAME_QUERY} = "{remote_url}/tree/$ID"'
|
|
317
|
+
json_data = jq.compile(jq_query).input(json_data).first()
|
|
318
|
+
return json_data, True
|
|
319
|
+
return json_data, False
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _update_github_queries(json_data: dict[str, Any]) -> tuple[dict[str, Any], bool]:
|
|
323
|
+
"""Update GitHub PR and Issues queries"""
|
|
324
|
+
updated = False
|
|
325
|
+
for pr_query in PrQueries:
|
|
326
|
+
res = pr_query.add_query(json_data)
|
|
327
|
+
if res:
|
|
328
|
+
updated = True
|
|
329
|
+
json_data = res
|
|
330
|
+
|
|
331
|
+
for issue_query in IssuesQueries:
|
|
332
|
+
res = issue_query.add_query(json_data)
|
|
333
|
+
if res:
|
|
334
|
+
updated = True
|
|
335
|
+
json_data = res
|
|
336
|
+
|
|
337
|
+
return json_data, updated
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def _update_log_watchers(json_data: dict[str, Any], working_path: str) -> tuple[dict[str, Any], bool]:
|
|
341
|
+
"""Update log watchers configuration"""
|
|
342
|
+
updated = False
|
|
343
|
+
for watcher in LogWatcher:
|
|
344
|
+
res = watcher.add_watcher(json_data, working_path)
|
|
345
|
+
if res:
|
|
346
|
+
updated = True
|
|
347
|
+
json_data = res
|
|
348
|
+
return json_data, updated
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def _update_vscode_tasks(json_data: dict[str, Any], working_path: str) -> tuple[dict[str, Any], bool]:
|
|
352
|
+
"""Update VSCode tasks configuration"""
|
|
353
|
+
updated = False
|
|
354
|
+
|
|
355
|
+
res = VscodeTask.add_tasks_version(json_data)
|
|
356
|
+
if res:
|
|
357
|
+
updated = True
|
|
358
|
+
json_data = res
|
|
359
|
+
|
|
360
|
+
for input_type in [a for a in VscodeInput if a.enum_type != InputType.LAUNCH]:
|
|
361
|
+
res = input_type.add_tasks_input(json_data, TASKS_INPUT_QUERY)
|
|
362
|
+
if res:
|
|
363
|
+
updated = True
|
|
364
|
+
json_data = res
|
|
365
|
+
|
|
366
|
+
for task in VscodeTask:
|
|
367
|
+
res = task.add_tasks_task(json_data, working_path)
|
|
368
|
+
if res:
|
|
369
|
+
updated = True
|
|
370
|
+
json_data = res
|
|
371
|
+
|
|
372
|
+
return json_data, updated
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def _update_vscode_launch(json_data: dict[str, Any], working_path: str) -> tuple[dict[str, Any], bool]:
|
|
376
|
+
"""Update VSCode launch configuration"""
|
|
377
|
+
updated = False
|
|
378
|
+
|
|
379
|
+
res = VscodeLaunch.add_launch_version(json_data)
|
|
380
|
+
if res:
|
|
381
|
+
updated = True
|
|
382
|
+
json_data = res
|
|
383
|
+
|
|
384
|
+
for input_type in [a for a in VscodeInput if a.enum_type != InputType.TASK]:
|
|
385
|
+
res = input_type.add_tasks_input(json_data, LAUNCH_INPUT_QUERY)
|
|
386
|
+
if res:
|
|
387
|
+
updated = True
|
|
388
|
+
json_data = res
|
|
389
|
+
|
|
390
|
+
for launch in VscodeLaunch:
|
|
391
|
+
res = launch.add_launch_config(json_data, _launch_substituter, working_path)
|
|
392
|
+
if res:
|
|
393
|
+
updated = True
|
|
394
|
+
json_data = res
|
|
395
|
+
|
|
396
|
+
return json_data, updated
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def _update_input_props(json_data: dict[str, Any]) -> tuple[dict[str, Any], bool]:
|
|
400
|
+
"""Update VSCode input properties"""
|
|
401
|
+
updated = False
|
|
402
|
+
for key, value in DEFAULT_PROPS.items():
|
|
403
|
+
snake_query: str = f'.settings.["{key}"]'
|
|
404
|
+
result = jq.compile(snake_query).input(json_data).first()
|
|
405
|
+
if result is None:
|
|
406
|
+
prompt: str = f"Enter the value a value for {key}"
|
|
407
|
+
value = get_input_or_default(prompt, value)
|
|
408
|
+
jq_query = f"{snake_query} = {json.dumps(value)}"
|
|
409
|
+
json_data = jq.compile(jq_query).input(json_data).first()
|
|
410
|
+
updated = True
|
|
411
|
+
|
|
412
|
+
return json_data, updated
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def _update_file_associations(json_data: dict[str, Any]) -> tuple[dict[str, Any], bool]:
|
|
416
|
+
"""Update file associations in workspace"""
|
|
417
|
+
updated = False
|
|
418
|
+
for key, value in FILE_ASSOCIATIONS.items():
|
|
419
|
+
file_query: str = f'{FILE_ASSOCIATION_QUERY}.["{key}"]'
|
|
420
|
+
result = jq.compile(file_query).input(json_data).first()
|
|
421
|
+
if not result:
|
|
422
|
+
jq_query = f"{file_query} = {json.dumps(value)}"
|
|
423
|
+
json_data = jq.compile(jq_query).input(json_data).first()
|
|
424
|
+
updated = True
|
|
425
|
+
return json_data, updated
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _launch_substituter(launch: str) -> str:
|
|
429
|
+
"""
|
|
430
|
+
Substitutes launch tags with values
|
|
431
|
+
"""
|
|
432
|
+
# verify if the launch contains the tags
|
|
433
|
+
if SUBSTITUTE_SHELL_TAG in launch:
|
|
434
|
+
launch = launch.replace(SUBSTITUTE_SHELL_TAG, get_property("shell"))
|
|
435
|
+
if SUBSTITUTE_PROJECT_TAG in launch:
|
|
436
|
+
launch = launch.replace(SUBSTITUTE_PROJECT_TAG, FOLDER)
|
|
437
|
+
return launch
|