2525DEFAULT_TAG = "3.14"
2626
2727
28+ # TODO: Remove the /dev/ for stable release
29+ HELP_URL = "https://docs.python.org/dev/using/windows"
30+
31+
2832COPYRIGHT = f"""Python installation manager { __version__ }
2933Copyright (c) Python Software Foundation. All Rights Reserved.
3034"""
3135
3236
37+ if EXE_NAME .casefold () == "py-manager" .casefold ():
38+ EXE_NAME = "py"
39+
40+
3341WELCOME = f"""!B!Python install manager was successfully updated to { __version__ } .!W!
3442"""
3543
@@ -188,6 +196,7 @@ def execute(self):
188196 "enable-shortcut-kinds" : ("enable_shortcut_kinds" , _NEXT , config_split ),
189197 "disable-shortcut-kinds" : ("disable_shortcut_kinds" , _NEXT , config_split ),
190198 "help" : ("show_help" , True ), # nested to avoid conflict with command
199+ "configure" : ("configure" , True ),
191200 # Set when the manager is doing an automatic install.
192201 # Generally won't be set by manual invocation
193202 "automatic" : ("automatic" , True ),
@@ -202,6 +211,10 @@ def execute(self):
202211 "force" : ("confirm" , False ),
203212 "help" : ("show_help" , True ), # nested to avoid conflict with command
204213 },
214+
215+ "**first_run" : {
216+ "explicit" : ("explicit" , True ),
217+ },
205218}
206219
207220
@@ -240,6 +253,16 @@ def execute(self):
240253 "disable_shortcut_kinds" : (str , config_split_append ),
241254 },
242255
256+ "first_run" : {
257+ "enabled" : (config_bool , None , "env" ),
258+ "explicit" : (config_bool , None ),
259+ "check_app_alias" : (config_bool , None , "env" ),
260+ "check_long_paths" : (config_bool , None , "env" ),
261+ "check_py_on_path" : (config_bool , None , "env" ),
262+ "check_any_install" : (config_bool , None , "env" ),
263+ "check_global_dir" : (config_bool , None , "env" ),
264+ },
265+
243266 # These configuration settings are intended for administrative override only
244267 # For example, if you are managing deployments that will use your own index
245268 # and/or your own builds.
@@ -419,11 +442,11 @@ def __init__(self, args, root=None):
419442 # If our command has any config, load them to override anything that
420443 # wasn't set on the command line.
421444 try :
422- cmd_config = config [self .CMD ]
445+ cmd_config = config [self .CMD . lstrip ( "*" ) ]
423446 except (AttributeError , LookupError ):
424447 pass
425448 else :
426- arg_names = frozenset (CONFIG_SCHEMA [self .CMD ])
449+ arg_names = frozenset (CONFIG_SCHEMA [self .CMD . lstrip ( "*" ) ])
427450 for k , v in cmd_config .items ():
428451 if k in arg_names and k not in _set_args :
429452 LOGGER .debug ("Overriding command option %s with %r" , k , v )
@@ -511,7 +534,7 @@ def get_log_file(self):
511534 logs_dir = Path (os .getenv ("TMP" ) or os .getenv ("TEMP" ) or os .getcwd ())
512535 from _native import datetime_as_str
513536 self ._log_file = logs_dir / "python_{}_{}_{}.log" .format (
514- self .CMD , datetime_as_str (), os .getpid ()
537+ self .CMD . strip ( "*" ) , datetime_as_str (), os .getpid ()
515538 )
516539 return self ._log_file
517540
@@ -545,28 +568,13 @@ def show_usage(cls):
545568 if usage_ljust % 4 :
546569 usage_ljust += 4 - (usage_ljust % 4 )
547570 usage_ljust = max (usage_ljust , 16 ) + 1
548- sp = " " * usage_ljust
549571
550572 LOGGER .print ("!G!Usage:!W!" )
551573 for k , d in usage_docs :
552- if k .endswith ("\n " ) and len (logging .strip_colour (k )) >= usage_ljust :
553- LOGGER .print (k .rstrip ())
554- r = sp
555- else :
556- k = k .rstrip ()
557- r = k .ljust (usage_ljust + len (k ) - len (logging .strip_colour (k )))
558- for b in d .split (" " ):
559- if len (r ) >= logging .CONSOLE_MAX_WIDTH :
560- LOGGER .print (r .rstrip ())
561- r = sp
562- r += b + " "
563- if r .rstrip ():
564- LOGGER .print (r )
565-
566- LOGGER .print ()
567- # TODO: Remove the /dev/ for stable release
568- LOGGER .print ("Find additional information at !B!https://docs.python.org/dev/using/windows!W!." )
569- LOGGER .print ()
574+ for s in logging .wrap_and_indent (d , indent = usage_ljust , hang = k .rstrip ()):
575+ LOGGER .print (s )
576+
577+ LOGGER .print ("\n Find additional information at !B!%s!W!.\n " , HELP_URL )
570578
571579 @classmethod
572580 def help_text (cls ):
@@ -746,6 +754,7 @@ class InstallCommand(BaseCommand):
746754 -u, --update Overwrite existing install if a newer version is available.
747755 --dry-run Choose runtime but do not install
748756 --refresh Update shortcuts and aliases for all installed versions.
757+ --configure Re-run the system configuration helper.
749758 --by-id Require TAG to exactly match the install ID. (For advanced use.)
750759 !B!<TAG> <TAG>!W! ... One or more tags to install (Company\Tag format)
751760
@@ -775,6 +784,7 @@ class InstallCommand(BaseCommand):
775784 dry_run = False
776785 refresh = False
777786 by_id = False
787+ configure = False
778788 automatic = False
779789 from_script = None
780790 enable_shortcut_kinds = None
@@ -801,9 +811,13 @@ def __init__(self, args, root=None):
801811 self .download = Path (self .download ).absolute ()
802812
803813 def execute (self ):
804- from .install_command import execute
805814 self .show_welcome ()
806- execute (self )
815+ if self .configure :
816+ cmd = FirstRun (["**first_run" , "--explicit" ], self .root )
817+ cmd .execute ()
818+ else :
819+ from .install_command import execute
820+ execute (self )
807821
808822
809823class UninstallCommand (BaseCommand ):
@@ -867,6 +881,7 @@ class HelpCommand(BaseCommand):
867881"""
868882
869883 _create_log_file = False
884+ commands_only = False
870885
871886 def __init__ (self , args , root = None ):
872887 super ().__init__ ([self .CMD ], root )
@@ -891,7 +906,7 @@ def execute(self):
891906
892907
893908class HelpWithErrorCommand (HelpCommand ):
894- CMD = "__help_with_error "
909+ CMD = "**help_with_error "
895910
896911 def __init__ (self , args , root = None ):
897912 # Essentially disable argument processing for this command
@@ -945,6 +960,28 @@ def __init__(self, root):
945960 super ().__init__ ([], root )
946961
947962
963+ class FirstRun (BaseCommand ):
964+ CMD = "**first_run"
965+ enabled = True
966+ explicit = False
967+ check_app_alias = True
968+ check_long_paths = True
969+ check_py_on_path = True
970+ check_any_install = True
971+ check_global_dir = True
972+
973+ def execute (self ):
974+ if not self .enabled :
975+ return
976+ from .firstrun import first_run
977+ first_run (self )
978+ if not self .explicit :
979+ self .show_usage ()
980+ if self .confirm and not self .ask_ny ("View online help?" ):
981+ import os
982+ os .startfile (HELP_URL )
983+
984+
948985def load_default_config (root ):
949986 return DefaultConfig (root )
950987
0 commit comments