1212from pathlib import Path
1313from typing import TextIO
1414
15+ from packaging .version import InvalidVersion , Version
16+
1517from ... import ui_messages as ui
1618from ...utils .json_io import read_json_object , write_json_document_atomically
1719from .attrs import bool_attr
1820from .types import PrinterLike
1921
2022_VSCODE_EXTENSION_TIP_KEY = "vscode_extension"
23+ _DEAD_CODE_REACHABILITY_MIGRATION_TIP_KEY = (
24+ "dead_code_reachability_2_0_1_migration_shown"
25+ )
2126_TIPS_SCHEMA_VERSION = 1
2227_VSCODE_EXTENSION_URL = (
2328 "https://marketplace.visualstudio.com/items?itemName=orenlab.codeclone"
2429)
30+ _DEAD_CODE_REACHABILITY_BASELINE_MIN = Version ("2.0.0b1" )
31+ _DEAD_CODE_REACHABILITY_BASELINE_MAX = Version ("2.0.0" )
32+ _DEAD_CODE_REACHABILITY_CURRENT_MIN = Version ("2.0.1" )
2533_CI_ENV_KEYS : tuple [str , ...] = (
2634 "CI" ,
2735 "GITHUB_ACTIONS" ,
@@ -91,6 +99,16 @@ def _tip_last_shown_version(state: Mapping[str, object], *, tip_key: str) -> str
9199 return ""
92100
93101
102+ def _tip_was_shown (state : Mapping [str , object ], * , tip_key : str ) -> bool :
103+ tips = state .get ("tips" )
104+ if not isinstance (tips , dict ):
105+ return False
106+ entry = tips .get (tip_key )
107+ if not isinstance (entry , dict ):
108+ return False
109+ return entry .get ("shown" ) is True
110+
111+
94112def _remember_tip_version (
95113 * ,
96114 path : Path ,
@@ -113,6 +131,60 @@ def _remember_tip_version(
113131 )
114132
115133
134+ def _remember_tip_shown (
135+ * ,
136+ path : Path ,
137+ state : Mapping [str , object ],
138+ tip_key : str ,
139+ ) -> None :
140+ tips = state .get ("tips" )
141+ updated_tips = dict (tips ) if isinstance (tips , dict ) else {}
142+ updated_tips [tip_key ] = {"shown" : True }
143+ write_json_document_atomically (
144+ path ,
145+ {
146+ "schema_version" : _TIPS_SCHEMA_VERSION ,
147+ "tips" : updated_tips ,
148+ },
149+ sort_keys = True ,
150+ indent = True ,
151+ trailing_newline = True ,
152+ )
153+
154+
155+ def _tip_context_allowed (
156+ * ,
157+ args : object ,
158+ environ : Mapping [str , str ],
159+ stream : TextIO ,
160+ ) -> bool :
161+ if bool_attr (args , "quiet" ) or bool_attr (args , "ci" ):
162+ return False
163+ if _is_ci_environment (environ ):
164+ return False
165+ return _stream_is_tty (stream )
166+
167+
168+ def _dead_code_reachability_migration_applies (
169+ * ,
170+ baseline_generator_version : str | None ,
171+ codeclone_version : str ,
172+ ) -> bool :
173+ if not baseline_generator_version :
174+ return False
175+ try :
176+ baseline_version = Version (baseline_generator_version )
177+ current_version = Version (codeclone_version )
178+ except InvalidVersion :
179+ return False
180+ return (
181+ _DEAD_CODE_REACHABILITY_BASELINE_MIN
182+ <= baseline_version
183+ <= _DEAD_CODE_REACHABILITY_BASELINE_MAX
184+ and current_version >= _DEAD_CODE_REACHABILITY_CURRENT_MIN
185+ )
186+
187+
116188def maybe_print_vscode_extension_tip (
117189 * ,
118190 args : object ,
@@ -124,11 +196,11 @@ def maybe_print_vscode_extension_tip(
124196) -> bool :
125197 effective_environ = os .environ if environ is None else environ
126198 effective_stream = sys .stdout if stream is None else stream
127- if bool_attr ( args , "quiet" ) or bool_attr ( args , "ci" ):
128- return False
129- if _is_ci_environment ( effective_environ ):
130- return False
131- if not _stream_is_tty ( effective_stream ):
199+ if not _tip_context_allowed (
200+ args = args ,
201+ environ = effective_environ ,
202+ stream = effective_stream ,
203+ ):
132204 return False
133205 if not _is_vscode_environment (effective_environ ):
134206 return False
@@ -154,6 +226,55 @@ def maybe_print_vscode_extension_tip(
154226 return True
155227
156228
229+ def maybe_print_dead_code_reachability_migration_note (
230+ * ,
231+ args : object ,
232+ console : PrinterLike ,
233+ codeclone_version : str ,
234+ cache_path : Path ,
235+ baseline_generator_version : str | None ,
236+ baseline_trusted_for_diff : bool ,
237+ environ : Mapping [str , str ] | None = None ,
238+ stream : TextIO | None = None ,
239+ ) -> bool :
240+ if not baseline_trusted_for_diff :
241+ return False
242+ if not _dead_code_reachability_migration_applies (
243+ baseline_generator_version = baseline_generator_version ,
244+ codeclone_version = codeclone_version ,
245+ ):
246+ return False
247+
248+ effective_environ = os .environ if environ is None else environ
249+ effective_stream = sys .stdout if stream is None else stream
250+ if not _tip_context_allowed (
251+ args = args ,
252+ environ = effective_environ ,
253+ stream = effective_stream ,
254+ ):
255+ return False
256+
257+ state_path = _tips_state_path (cache_path )
258+ state = _load_tips_state (state_path )
259+ if _tip_was_shown (
260+ state ,
261+ tip_key = _DEAD_CODE_REACHABILITY_MIGRATION_TIP_KEY ,
262+ ):
263+ return False
264+
265+ console .print (ui .fmt_dead_code_reachability_migration_note ())
266+ try :
267+ _remember_tip_shown (
268+ path = state_path ,
269+ state = state ,
270+ tip_key = _DEAD_CODE_REACHABILITY_MIGRATION_TIP_KEY ,
271+ )
272+ except OSError :
273+ return True
274+ return True
275+
276+
157277__all__ = [
278+ "maybe_print_dead_code_reachability_migration_note" ,
158279 "maybe_print_vscode_extension_tip" ,
159280]
0 commit comments