9
9
from pathlib import Path , PurePath
10
10
from threading import Thread
11
11
12
- from os import environ as env , scandir , rename
12
+ from os import environ as env , scandir , rename , PathLike
13
13
from os .path import islink , realpath
14
14
15
- from typing import Literal
15
+ from typing import Callable , Literal , TypeAlias
16
16
from collections .abc import Iterable , Iterator
17
17
18
18
import tkinter as tk
22
22
from thonny import get_workbench , ui_utils , THONNY_USER_DIR
23
23
from thonny .languages import tr
24
24
25
+ StrPath : TypeAlias = str | PathLike [str ]
26
+ '''A type representing string-based filesystem paths.'''
27
+
28
+ PathAction : TypeAlias = Callable [[StrPath ], None ]
29
+ '''Represents an action applied to a single path-like object.'''
30
+
25
31
_JDK_PATTERN = re .compile (r"""
26
32
(?:java|jdk) # Match 'java' or 'jdk' (non-capturing group)
27
33
-? # Match optional hyphen '-'
@@ -82,7 +88,7 @@ def get_thonny_jdk_install() -> PurePath | Literal['']:
82
88
return '' # No JDK with required version found in THONNY_USER_DIR
83
89
84
90
85
- def set_java_home (jdk_path : PurePath | str ):
91
+ def set_java_home (jdk_path : StrPath ):
86
92
'''Add JDK path to config file (tools > options > general > env vars).'''
87
93
jdk_path = str (adjust_jdk_path (jdk_path ))
88
94
env ['JAVA_HOME' ] = jdk_path # Python's process points to Thonny's JDK
@@ -97,7 +103,7 @@ def set_java_home(jdk_path: PurePath | str):
97
103
showinfo ('JAVA_HOME' , jdk_path , parent = workbench )
98
104
99
105
100
- def adjust_jdk_path (jdk_path : PurePath | str ) -> PurePath :
106
+ def adjust_jdk_path (jdk_path : StrPath ) -> PurePath :
101
107
'''Adjust JDK path for the specificity of current platform.'''
102
108
jdk_path = PurePath (jdk_path )
103
109
@@ -108,7 +114,7 @@ def adjust_jdk_path(jdk_path: PurePath | str) -> PurePath:
108
114
return jdk_path
109
115
110
116
111
- def create_java_home_entry_from_path (jdk_path : PurePath | str ) -> str :
117
+ def create_java_home_entry_from_path (jdk_path : StrPath ) -> str :
112
118
'''Prefix JDK path with "JAVA_HOME=" to form a Thonny environment entry.'''
113
119
return f'JAVA_HOME={ jdk_path } '
114
120
@@ -123,28 +129,23 @@ def _non_java_home_predicate(entry: str) -> bool:
123
129
return not entry .startswith ('JAVA_HOME=' )
124
130
125
131
126
- def get_all_thonny_folders () -> list [str ]:
127
- """Return reverse-sorted names of subfolders within Thonny's user folder."""
128
- with scandir (THONNY_USER_DIR ) as entries :
129
- return sorted ((e .name for e in entries if e .is_dir ()), reverse = True )
130
-
131
-
132
- def get_all_thonny_folder_paths () -> Iterator [Path ]:
133
- '''Find all subfolder paths within Thonny's user folder'''
134
- return filter (Path .is_dir , _THONNY_USER_PATH .iterdir ())
135
-
136
-
137
132
def is_valid_jdk_version (jdk_version : str ) -> bool :
138
133
'''Check if JDK version meets minimum version requirement.'''
139
134
return jdk_version .isdigit () and int (jdk_version ) >= _REQUIRE_JDK
140
135
141
136
142
- def is_valid_jdk_path (jdk_path : PurePath | str ) -> bool :
137
+ def is_valid_jdk_path (jdk_path : StrPath ) -> bool :
143
138
'''Check if the given path points to a JDK install with a usable Java.'''
144
139
java_compiler = jdk ._IS_WINDOWS and 'javac.exe' or 'javac'
145
140
return Path (jdk_path , 'bin' , java_compiler ).is_file ()
146
141
147
142
143
+ def get_all_thonny_folders () -> list [str ]:
144
+ """Return reverse-sorted names of subfolders within Thonny's user folder."""
145
+ with scandir (THONNY_USER_DIR ) as entries :
146
+ return sorted ((e .name for e in entries if e .is_dir ()), reverse = True )
147
+
148
+
148
149
class DownloadJDK (Thread ):
149
150
'''Background thread for downloading & installing JDK into Thonny's folder.
150
151
@@ -155,20 +156,40 @@ class DownloadJDK(Thread):
155
156
'''
156
157
def run (self ):
157
158
'''Download and setup JDK (installs to Thonny's config directory)'''
158
- for path in get_all_thonny_folder_paths ():
159
- # Delete existing Thonny's JDK subfolders matching jdk-<version##>:
160
- if path .name .startswith (_JDK_DIR ): shutil .rmtree (path )
159
+ # Delete existing Thonny's JDK subfolders matching jdk-<version##>:
160
+ self .process_match_jdk_dirs (shutil .rmtree )
161
161
162
162
# Download and extract JDK subfolder into Thonny's user folder:
163
163
jdk .install (_VERSION_JDK , path = THONNY_USER_DIR )
164
164
165
- for path in get_all_thonny_folder_paths ():
166
- # Rename extracted Thonny's JDK subfolder to jdk-<version##>:
167
- if path .name .startswith (_JDK_DIR ): rename (path , _JDK_PATH ); break
165
+ # Rename extracted Thonny's JDK subfolder to jdk-<version##>:
166
+ self .process_match_jdk_dirs (self .rename_folder , True )
168
167
169
168
set_java_home (_JDK_HOME ) # Add a Thonny's JAVA_HOME entry for it
170
169
171
170
171
+ @staticmethod
172
+ def process_match_jdk_dirs (action : PathAction , only_1st = False ):
173
+ '''Apply an action to JDK-matching subfolders in Thonny's folder.'''
174
+ for path in DownloadJDK .get_all_thonny_folder_paths ():
175
+ if path .name .startswith (_JDK_DIR ): # Folder name matches <jdk-##>
176
+ action (path ) # Callback to run on each matching folder path
177
+ if only_1st : break # Stop at 1st match occurrence
178
+
179
+
180
+ @staticmethod
181
+ def get_all_thonny_folder_paths () -> Iterator [Path ]:
182
+ '''Find all subfolder paths within Thonny's user folder'''
183
+ return filter (Path .is_dir , _THONNY_USER_PATH .iterdir ())
184
+
185
+
186
+ @staticmethod
187
+ def rename_folder (path : StrPath ):
188
+ '''Rename a JDK subfolder to the expected jdk-<version##> format.'''
189
+ rename (path , _JDK_PATH )
190
+
191
+
192
+
172
193
class JdkDialog (ui_utils .CommonDialog ):
173
194
'''User-facing dialog prompting install of required JDK for py5 sketches.
174
195
0 commit comments