texlive[59143] Master: fmtutil and tlmgr improvements

commits+preining at tug.org commits+preining at tug.org
Sun May 9 04:23:44 CEST 2021


Revision: 59143
          http://tug.org/svn/texlive?view=revision&revision=59143
Author:   preining
Date:     2021-05-09 04:23:44 +0200 (Sun, 09 May 2021)
Log Message:
-----------
fmtutil and tlmgr improvements

fmtutil.pl
- if run as mktexfmt and TEXMFSYSVAR is writable, use
  it instead of TEXMFVAR (actual code in TLUtils.pm).
- add --dry-run | -n option
  it is not guaranteed to be 100% dry-run, though
- add --status-file=FILE where the status of each
  format creating is written to
- warn on running fmtutil in user mode the first time
  (similar to updmap)
- warn on shadowing formats
- documentation fixes

tlmgr.pl
- use fmtutil --status-file and report back failed
  format rebuilds
- regeneration all formats now only exists existing
  formats (use --refresh with fmtutil)
- report when commands are logged to the respective
  log file
- documentation fixes

TLUtils.pm
- update setup_sys_user_mode for the fmtutil/mktexfmt
  changes mentioned above
- documentation fixes

Modified Paths:
--------------
    trunk/Master/texmf-dist/scripts/texlive/fmtutil.pl
    trunk/Master/texmf-dist/scripts/texlive/tlmgr.pl
    trunk/Master/tlpkg/TeXLive/TLUtils.pm

Modified: trunk/Master/texmf-dist/scripts/texlive/fmtutil.pl
===================================================================
--- trunk/Master/texmf-dist/scripts/texlive/fmtutil.pl	2021-05-08 23:50:00 UTC (rev 59142)
+++ trunk/Master/texmf-dist/scripts/texlive/fmtutil.pl	2021-05-09 02:23:44 UTC (rev 59143)
@@ -59,7 +59,13 @@
 
 my @deferred_stderr;
 my @deferred_stdout;
+# $::opt_verbosity = 3; # manually enable debugging
 
+my $first_time_creation_in_usermode = 0;
+
+my $DRYRUN = "";
+my $STATUS_FH;
+
 (our $prg = basename($0)) =~ s/\.pl$//;
 
 # make sure that the main binary path is available at the front
@@ -89,11 +95,12 @@
 }
 
 #
-# these need to be our since they are used from the 
-# functions in TLUtils.pm
+# these need to be "our" variables since they are used from the 
+# functions in TLUtils.pm.
 our $texmfconfig = $TEXMFCONFIG;
 our $texmfvar    = $TEXMFVAR;
 our $alldata;
+
 # command line options with defaults
 # 20160623 - switch to turn on strict mode
 our %opts = ( quiet => 0 , strict => 1 );
@@ -116,6 +123,7 @@
   "sys",
   "user",
   "cnffile=s@", 
+  "dry-run|n",
   "fmtdir=s",
   "no-engine-subdir",
   "no-error-if-no-engine=s",
@@ -123,6 +131,7 @@
   "nohash",
   "recorder",
   "refresh",
+  "status-file=s",
   "strict!",
   "quiet|silent|q",
   "catcfg",
@@ -156,13 +165,25 @@
     # (and nothing else), since kpathsea can only deal with one.
     $mktexfmtMode = 1;
 
-    # TODO TODO
-    # which mode are we running in?
-    # what happens if root runs mktexfmt?
+    # we default to user mode here, in particular because **if** TEXMFSYSVAR
+    # is writable we will use it to save format dumps created by mktexfmt
+    # If root is running mktexfmt, then most probably the formats will end
+    # up in TEXMFSYSVAR which is fine.
     $opts{'user'} = 1;
 
-    GetOptions ( "help" => \$opts{'help'}, "version" => \$opts{'version'} )
-      || die "$prg: Unknown option in mktexfmt command line arguments.\n";
+    my @save_argv = @ARGV;
+    GetOptions (
+      "dry-run|n", \$opts{'dry-run'},
+      "help" => \$opts{'help'},
+      "version" => \$opts{'version'}
+      ) || die "$prg: Unknown option in mktexfmt command line: @save_argv\n";
+
+    help() if $opts{'help'};
+    if ($opts{'version'}) {
+      print version();
+      exit 0;  # no final print_info
+    }
+
     if ($ARGV[0]) {
       if ($ARGV[0] =~ m/^(.*)\.(fmt|mem|base?)$/) {
         $opts{'byfmt'} = $1;
@@ -214,11 +235,17 @@
       }
     }
   }
+
+  $DRYRUN = "echo " if ($opts{'dry-run'});
+
+  if ($opts{'status-file'}) {
+    open $STATUS_FH, '>>', $opts{'status-file'}
+      || printf STDERR "Cannot open status-file: $opts{'status-file'}\nWill not write status information!\n";
+  }
   
-  # these two functions should go to TLUtils (for use in updmap)
-  ($texmfconfig, $texmfvar) = 
-    TeXLive::TLUtils::setup_sys_user_mode($prg, \%opts,
-      $TEXMFCONFIG, $TEXMFSYSCONFIG, $TEXMFVAR, $TEXMFSYSVAR);
+  ($texmfconfig, $texmfvar)
+    = TeXLive::TLUtils::setup_sys_user_mode($prg, \%opts,
+                       $TEXMFCONFIG, $TEXMFSYSCONFIG, $TEXMFVAR, $TEXMFSYSVAR);
 
   determine_config_files("fmtutil.cnf");
   my $changes_config_file = $alldata->{'changes_config'};
@@ -252,7 +279,7 @@
       touch($bakFile);
       touch($changes_config_file);
     }
-    system($editor, $changes_config_file);
+    system("$DRYRUN$editor", $changes_config_file);
     $changed = files_are_different($bakFile, $changes_config_file);
 
   } elsif ($opts{'showhyphen'}) {
@@ -311,6 +338,10 @@
     return 1;
   }
 
+  if ($STATUS_FH) {
+    close($STATUS_FH) || print STDERR "Cannot close fh for $opts{'status-file'}.\n";
+  }
+
   unless ($opts{'nohash'}) {
     # TODO should only do this if built something, e.g., not --listcfg
     print_info("updating ls-R files\n");
@@ -328,6 +359,12 @@
   print Data::Dumper::Dumper($alldata);
 }
 
+#
+sub log_to_status {
+  if ($STATUS_FH) {
+    print $STATUS_FH "@_\n";
+  }
+}
 
 # 
 callback_build_formats - (re)builds the formats as selected,
 # returns exit status or dies.  Exit status is always zero unless
@@ -341,39 +378,43 @@
   # On W32 it seems that File::Temp creates restrictive permissions (ok)
   # that are copied over with the files created inside it (not ok).
   # So make our own temp dir.
-  my $tmpdir;
-  if (win32()) {
-    my $foo;
-    my $tmp_deflt = File::Spec->tmpdir;
-    for my $i (1..5) {
-      # $foo = "$texmfvar/temp.$$." . int(rand(1000000));
-      $foo = (($texmfvar =~ m!^//!) ? $tmp_deflt : $texmfvar)
-        . "/temp.$$." . int(rand(1000000));
-      if (! -d $foo) {
-        TeXLive::TLUtils::mkdirhier($foo);
-        sleep 1;
-        if (-d $foo) {
-          $tmpdir = $foo;
-          last;
+  my $tmpdir = "";
+  if (! $opts{"dry-run"}) {
+    if (win32()) {
+      my $foo;
+      my $tmp_deflt = File::Spec->tmpdir;
+      for my $i (1..5) {
+        # $foo = "$texmfvar/temp.$$." . int(rand(1000000));
+        $foo = (($texmfvar =~ m!^//!) ? $tmp_deflt : $texmfvar)
+          . "/temp.$$." . int(rand(1000000));
+        if (! -d $foo) {
+          TeXLive::TLUtils::mkdirhier($foo);
+          sleep 1;
+          if (-d $foo) {
+            $tmpdir = $foo;
+            last;
+          }
         }
       }
+      if (! $tmpdir) {
+        die "Cannot get a temporary directory after five iterations, sorry!";
+      }
+      if ($texmfvar =~ m!^//!) {
+        # used File::Spec->tmpdir; fix permissions
+        TeXLive::TLWinGoo::maybe_make_ro ($tmpdir);
+      }
+    } else {
+      $tmpdir = File::Temp::tempdir(CLEANUP => 1);
     }
-    if (! $tmpdir) {
-      die "Cannot get a temporary directory after five iterations ... sorry!";
-    }
-    if ($texmfvar =~ m!^//!) {
-      # used File::Spec->tmpdir; fix permissions
-      TeXLive::TLWinGoo::maybe_make_ro ($tmpdir);
-    }
-  } else {
-    $tmpdir = File::Temp::tempdir(CLEANUP => 1);
   }
   # set up destination directory
   $opts{'fmtdir'} ||= "$texmfvar/web2c";
-  TeXLive::TLUtils::mkdirhier($opts{'fmtdir'}) if (! -d $opts{'fmtdir'});
-  if (! -w $opts{'fmtdir'}) {
-    print_error("format directory not writable: $opts{fmtdir}\n");
-    exit 1;
+  if (! $opts{"dry-run"}) {
+    TeXLive::TLUtils::mkdirhier($opts{'fmtdir'}) if (! -d $opts{'fmtdir'});
+    if (! -w $opts{'fmtdir'}) {
+      print_error("format directory not writable: $opts{fmtdir}\n");
+      exit 1;
+    }
   }
   # since the directory does not exist, we can make it absolute with abs_path
   # without any trickery around non-existing dirs
@@ -397,7 +438,8 @@
   $ENV{'TEXFORMATS'} = "$tmpdir$sep$ENV{TEXFORMATS}";
 
   # switch to temporary directory for format generation
-  chdir($tmpdir) || die "Cannot change to directory $tmpdir: $!";
+  $opts{"dry-run"} || chdir($tmpdir)
+  || die "Cannot change to directory $tmpdir: $!";
   
   # we rebuild formats in two rounds:
   # round 1: only formats with the same name as engine (pdftex/pdftex)
@@ -418,13 +460,28 @@
         next if ($swi eq "format!=engine" && $fmt eq $eng);
         $total++;
         my $val = select_and_rebuild_format($fmt, $eng, $what, $whatarg);
-        if ($val == $FMT_DISABLED)    { $disabled++; }
-        elsif ($val == $FMT_NOTSELECTED) { $nobuild++; }
-        elsif ($val == $FMT_FAILURE)  { $err++; push (@err, "$eng/$fmt"); }
-        elsif ($val == $FMT_SUCCESS)  { $suc++; }
-        elsif ($val == $FMT_NOTAVAIL) { $notavail++; }
-        else { print_error("callback_build_format (round 1): unknown return "
-               . "from select_and_rebuild.\n"); }
+        if ($val == $FMT_DISABLED)    {
+          log_to_status("DISABLED", $fmt, $eng, $what, $whatarg);
+          $disabled++;
+        } elsif ($val == $FMT_NOTSELECTED) {
+          log_to_status("NOTSELECTED", $fmt, $eng, $what, $whatarg);
+          $nobuild++;
+        } elsif ($val == $FMT_FAILURE)  {
+          log_to_status("FAILURE", $fmt, $eng, $what, $whatarg);
+          $err++;
+          push (@err, "$eng/$fmt");
+        } elsif ($val == $FMT_SUCCESS)  {
+          log_to_status("SUCCESS", $fmt, $eng, $what, $whatarg);
+          $suc++;
+        } elsif ($val == $FMT_NOTAVAIL) {
+          log_to_status("NOTAVAIL", $fmt, $eng, $what, $whatarg);
+          $notavail++; 
+        }
+        else {
+          log_to_status("UNKNOWN", $fmt, $eng, $what, $whatarg);
+          print_error("callback_build_format (round 1): unknown return "
+           . "from select_and_rebuild.\n");
+        }
       }
     }
   }
@@ -455,7 +512,37 @@
     # try to remove the tmpdir with all files
     TeXLive::TLUtils::rmtree($tmpdir);
   }
-   # return 
+  #
+  # In case of user mode and formats rebuilt, warn that these formats
+  # will shadow future updates. Can be suppressed with --quiet which
+  # does not show print_info output
+  if ($opts{'user'} && $suc && $first_time_creation_in_usermode) {
+    print_info("
+*************************************************************
+*                                                           *
+* WARNING: you are switching to fmtutil's per-user formats. *
+*         Please read the following warnings!               *
+*                                                           *
+*************************************************************
+
+You have run fmtutil-user (as opposed to fmtutil-sys) for the first time;
+this has created format files which are local to your personal account.
+
+From now on, any changes in system formats will *not* be automatically
+reflected in your files; furthermore, running fmtutil-sys will no longer
+have any effect for you.
+
+As a consequence, you yourself have to rerun fmtutil-user after any
+change in the system directories. For example, when one of the LaTeX or
+other format source files changes, which happens frequently.
+See https://tug.org/texlive/scripts-sys-user.html for details.
+
+If you want to undo this, remove the files mentioned above.
+
+Run $prg --help for full documentation of fmtutil.
+");
+  }
+  # return 
   return $opts{"strict"} ? $err : 0;
 }
 
@@ -519,6 +606,7 @@
     }
   }
   if ($doit) {
+    check_and_warn_on_user_format($fmt,$eng);
     return rebuild_one_format($fmt,$eng,$kpsefmt,$destdir,$fmtfile,$logfile);
   } else {
     return $FMT_NOTSELECTED;
@@ -525,6 +613,21 @@
   }
 }
 
+sub check_and_warn_on_user_format {
+  my ($fmt, $eng) = @_;
+  # do nothing if we are updating files in $TEXMFVAR
+  return if ($opts{'fmtdir'} eq $TEXMFVAR);
+  my $saved_fmtdir = $opts{'fmtdir'};
+  $opts{'fmtdir'} = "$TEXMFVAR/web2c";
+  my ($kpsefmt, $destdir, $fmtfile, $logfile) = compute_format_destination($fmt, $eng);
+  if (-r "$destdir/$fmtfile") {
+    print_deferred_warning("you have a shadowing format dump in TEXMFVAR for $fmt/$eng!!!\n");
+  }
+  $opts{'fmtdir'} = $saved_fmtdir;
+}
+  
+
+
 # 
 compute_format_destination
 # takes fmt/eng and returns the locations where format and log files
 # should be saved, that is, a list: (dump file full path, log file full path)
@@ -679,7 +782,7 @@
     # in mktexfmtMode we must redirect *all* output to stderr
     $cmdline .= " >&2" if $mktexfmtMode;
     $cmdline .= " <$nul";
-    my $retval = system($cmdline);
+    my $retval = system("$DRYRUN$cmdline");
     
     # report error if it failed.
     if ($retval != 0) {
@@ -689,7 +792,7 @@
 
     # Copy the log file after the program is run, so that the log file
     # is available to inspect even on failure. So we need the dest dir tree.
-    TeXLive::TLUtils::mkdirhier($destdir);
+    TeXLive::TLUtils::mkdirhier($destdir) if ! $opts{"dry-run"};
     #
     # Here and in the following we use copy instead of move
     # to make sure that in SElinux enabled cases the rules of
@@ -698,7 +801,8 @@
     if (File::Copy::copy($logfile, "$destdir/$logfile")) {
       print_info("log file copied to: $destdir/$logfile\n");
     } else {
-      print_deferred_error("cannot copy log $logfile to: $destdir\n");
+      print_deferred_error("cannot copy log $logfile to: $destdir\n")
+        unless $opts{"dry-run"};
     }
 
     # original shell script did *not* check the return value
@@ -748,8 +852,13 @@
   }
 
   my $destfile = "$destdir/$fmtfile";
+  # set flag to warn that new user format was installed
+  # we check whether the next command **would** create a new file,
+  # and if it succeeded, we set the actual flag.
+  my $possibly_warn = ($opts{'user'} && ! -r $destfile);
   if (File::Copy::copy($fmtfile, $destfile )) {
     print_info("$destfile installed.\n");
+    $first_time_creation_in_usermode = $possibly_warn;
     #
     # original fmtutil.sh did some magic trick for mplib-luatex.mem
     #
@@ -1090,30 +1199,14 @@
       }
     }
     #
-    # user mode (no -sys):
-    # ====================
-    # TEXMFCONFIG    $HOME/.texliveYYYY/texmf-config/web2c/$fn
-    # TEXMFVAR       $HOME/.texliveYYYY/texmf-var/web2c/$fn
-    # TEXMFHOME      $HOME/texmf/web2c/$fn
-    # TEXMFSYSCONFIG $TEXLIVE/YYYY/texmf-config/web2c/$fn
-    # TEXMFSYSVAR    $TEXLIVE/YYYY/texmf-var/web2c/$fn
-    # TEXMFLOCAL     $TEXLIVE/texmf-local/web2c/$fn
-    # TEXMFDIST      $TEXLIVE/YYYY/texmf-dist/web2c/$fn
-    # 
-    # root mode (--sys):
-    # ==================
-    # TEXMFSYSCONFIG $TEXLIVE/YYYY/texmf-config/web2c/$fn
-    # TEXMFSYSVAR    $TEXLIVE/YYYY/texmf-var/web2c/$fn
-    # TEXMFLOCAL     $TEXLIVE/texmf-local/web2c/$fn
-    # TEXMFDIST      $TEXLIVE/YYYY/texmf-dist/web2c/$fn
+    # See help message for list of locations.
+    @{$opts{'cnffile'}} = @used_files;
     #
-    @{$opts{'cnffile'}}  = @used_files;
-    #
     # determine the config file that we will use for changes
     # if in the list of used files contains either one from
-    # TEXMFHOME or TEXMFCONFIG (which is TEXMFSYSCONFIG in the -sys case)
+    # TEXMFHOME or TEXMFCONFIG (TEXMFSYSCONFIG in the -sys case)
     # then use the *top* file (which will be either one of the two),
-    # if none of the two exists, create a file in TEXMFCONFIG and use it
+    # if neither of the two exists, create a file in TEXMFCONFIG and use it.
     my $use_top = 0;
     for my $f (@used_files) {
       if ($f =~ m!(\Q$TEXMFHOME\E|\Q$texmfconfig\E)/web2c/$fn!) {
@@ -1316,21 +1409,22 @@
 Usage: $prg      [-user|-sys] [OPTION] ... [COMMAND]
    or: $prg-sys  [OPTION] ... [COMMAND]
    or: $prg-user [OPTION] ... [COMMAND]
-   or: mktexfmt  FORMAT.fmt|BASE.base|FMTNAME.EXT
+   or: mktexfmt  FORMAT.fmt|BASE.base|FMTNAME
 
 Rebuild and manage TeX fmts and Metafont bases, collectively called
 "formats" here. (MetaPost no longer uses the past-equivalent "mems".)
 
+If not operating in mktexfmt mode, exactly one command must be given,
+filename suffixes should generally not be specified, no non-option
+arguments are allowed, and multiple formats can be generated.
+
 If the command name ends in mktexfmt, only one format can be created.
 The only options supported are --help and --version, and the command
 line must be either a format name, with extension, or a plain name that
 is passed as the argument to --byfmt (see below).  The full name of the
-generated file (if any) is written to stdout, and nothing else.
+generated file (if any) is written to stdout, and nothing else.  The
+system directories are used if they are writable, else the user directories.
 
-If not operating in mktexfmt mode, exactly one command must be given,
-extensions should generally not be specified, no non-option arguments
-are allowed, and multiple formats can be generated, as follows.
-
 By default, the return status is zero if all formats requested are
 successfully built, else nonzero.
 
@@ -1340,16 +1434,18 @@
   --cnffile FILE          read FILE instead of fmtutil.cnf
                            (can be given multiple times, in which case
                            all the files are used)
+  --dry-run, -n           don't actually build formts
   --fmtdir DIR            write formats under DIR instead of TEXMF[SYS]VAR
   --no-engine-subdir      don't use engine-specific subdir of the fmtdir
-  --no-error-if-no-format exit successfully if no format is selected
+  --no-error-if-no-format  exit successfully if no format is selected
   --no-error-if-no-engine=ENGINE1,ENGINE2,...
-                          exit successfully even if a required engine
+                          exit successfully even if a required ENGINE
                            is missing, if it is included in the list.
   --no-strict             exit successfully even if a format fails to build
   --nohash                don't update ls-R files
   --recorder              pass the -recorder option and save .fls files
   --refresh               recreate only existing format files
+  --status-file FILE      append status information about built formats to FILE
   --quiet                 be silent
   --catcfg                (does nothing, exists for compatibility)
   --dolinks               (does nothing, exists for compatibility)
@@ -1362,8 +1458,8 @@
   --byengine ENGINE       (re)create formats built with ENGINE
   --byfmt FORMAT          (re)create format FORMAT
   --byhyphen HYPHENFILE   (re)create formats that depend on HYPHENFILE
-  --enablefmt  FORMAT[/ENGINE] enable FORMAT, as built with ENGINE
-  --disablefmt FORMAT[/ENGINE] disable FORMAT, as built with ENGINE
+  --enablefmt  FORMAT[/ENGINE]  enable FORMAT, as built with ENGINE
+  --disablefmt FORMAT[/ENGINE]  disable FORMAT, as built with ENGINE
                           If multiple formats have the same name and
                            different engines, /ENGINE specifier is required.
   --listcfg               list (enabled and disabled) configurations,
@@ -1376,8 +1472,8 @@
 
   If --cnffile is specified on the command line (possibly multiple
   times), its value(s) are used.  Otherwise, fmtutil reads all the
-  fmtutil.cnf files found by running \`kpsewhich -all fmtutil.cnf', in the
-  order returned by kpsewhich. Files passed in via --cnffile are
+  fmtutil.cnf files found by running "kpsewhich -all fmtutil.cnf", in the
+  order returned by kpsewhich.  Files specified via --cnffile are
   first tried to be loaded directly, and if not found and the file names
   don't contain directory parts, are searched via kpsewhich.
 
@@ -1405,19 +1501,21 @@
   
   (where YYYY is the TeX Live release version).
   
-  According to the actions, fmtutil might write to one of the given files
-  or create a new fmtutil.cnf, described further below.
+  According to the actions, fmtutil might update one of the existing cnf
+  files or create a new fmtutil.cnf, as described below.
 
-Where formats are written:
+Where format files are written:
+
+  By default, format files are (re)written in \$TEXMFSYSVAR/ENGINE by
+  fmtutil-sys, and \$TEXMFVAR/ENGINE by fmtutil-user, where /ENGINE is
+  a subdirectory named for the engine used, such as "pdftex".
+
+  For mktexfmt, TEXMFSYSVAR is used if it is writable, else TEXMFVAR.
   
-  By default, format files are (re)written in TEXMFSYSVAR/ENGINE by
-  fmtutil-sys, and TEXMFVAR/ENGINE by fmtutil, where /ENGINE is a
-  subdirectory named for the engine used, such as "pdftex".
-  
   If the --fmtdir=DIR option is specified, DIR is used instead of
   TEXMF[SYS]VAR, but the /ENGINE subdir is still used by default.
   
-  In any case, if the --no-engine-subdir option is specified, the
+  In all cases, if the --no-engine-subdir option is specified, the
   /ENGINE subdir is omitted.
   
 Where configuration changes are saved: 
@@ -1424,13 +1522,14 @@
 
   If config files are given on the command line, then the first one 
   given will be used to save any changes from --enable or --disable.  
+  
   If the config files are taken from kpsewhich output, then the 
-  algorithm is more complex:
+  algorithm is more complicated:
 
-    1) If \$TEXMFCONFIG/web2c/fmtutil.cnf or \$TEXMFHOME/web2c/fmtutil.cnf
-    appears in the list of used files, then the one listed first by
-    kpsewhich --all (equivalently, the one returned by kpsewhich
-    fmtutil.cnf), is used.
+    1) If \$TEXMFCONFIG/web2c/fmtutil.cnf or
+    \$TEXMFHOME/web2c/fmtutil.cnf appears in the list of used files,
+    then the one listed first by kpsewhich --all (equivalently, the one
+    returned by "kpsewhich fmtutil.cnf"), is used.
       
     2) If neither of the above two are present and changes are made, a
     new config file is created in \$TEXMFCONFIG/web2c/fmtutil.cnf.
@@ -1438,7 +1537,7 @@
   In general, the idea is that if a given config file is not writable, a
   higher-level one can be used.  That way, the distribution's settings
   can be overridden system-wide using TEXMFLOCAL, and system settings
-  can be overridden again in a particular user's TEXMFHOME.
+  can be overridden again in a particular user's TEXMFHOME or TEXMFCONF.
 
 Resolving multiple definitions of a format:
 
@@ -1449,11 +1548,11 @@
 
   fmtutil.cnf files with higher priority (listed earlier) can disable
   formats in lower priority (listed later) fmtutil.cnf files by
-  writing a line like
+  writing a line like this in the higher-priority fmtutil.cnf file:
     \#! <fmtname> <enginename> <hyphen> <args>
-  in the higher-priority fmtutil.cnf file.   The \#! must be at the
-  beginning of the line, with at least one space or tab afterward, and
-  there must be whitespace between each word on the list.
+  The \#! must be at the beginning of the line, with at least one space
+  or tab afterward, and there must be whitespace between each word on
+  the list.
 
   For example, you can disable the luajitlatex format by creating
   the file \$TEXMFCONFIG/web2c/fmtutil.cnf with the line
@@ -1460,21 +1559,21 @@
     #! luajitlatex luajittex language.dat,language.dat.lua lualatex.ini
   (As it happens, the luajittex-related formats are precisely why the
   --no-error-if-no-engine option exists, since luajittex cannot be
-  compiled on all platforms.)
+  compiled on all platforms. So this is not needed.)
 
 fmtutil-user (fmtutil -user) vs. fmtutil-sys (fmtutil -sys):
 
-  When fmtutil-sys is run or the command line option -sys is used, 
-  TEXMFSYSCONFIG and TEXMFSYSVAR are used instead of TEXMFCONFIG and 
-  TEXMFVAR, respectively.  This is the primary difference between 
+  When fmtutil-sys is run or the command line option -sys is used,
+  TEXMFSYSCONFIG and TEXMFSYSVAR are used instead of TEXMFCONFIG and
+  TEXMFVAR, respectively. This is the primary difference between
   fmtutil-sys and fmtutil-user.
 
-  See http://tug.org/texlive/scripts-sys-user.html for details.
+  See https://tug.org/texlive/scripts-sys-user.html for details.
 
   Other locations may be used if you give them on the command line, or
   these trees don't exist, or you are not using the original TeX Live.
 
-Supporting development binaries
+Supporting development binaries:
 
   If an engine name ends with "-dev", formats are created in
   the respective directory with the -dev stripped.  This allows for
@@ -1482,7 +1581,7 @@
   binaries.
 
 Report bugs to: tex-live\@tug.org
-TeX Live home page: <http://tug.org/texlive/>
+TeX Live home page: <https://tug.org/texlive/>
 EOF
 ;
   print &version();

Modified: trunk/Master/texmf-dist/scripts/texlive/tlmgr.pl
===================================================================
--- trunk/Master/texmf-dist/scripts/texlive/tlmgr.pl	2021-05-08 23:50:00 UTC (rev 59142)
+++ trunk/Master/texmf-dist/scripts/texlive/tlmgr.pl	2021-05-09 02:23:44 UTC (rev 59143)
@@ -24,6 +24,7 @@
 our $loadmediasrcerror;
 our $packagelogfile;
 our $packagelogged;
+our $commandslogged;
 our $commandlogfile;
 our $tlmgr_config_file;
 our $pinfile;
@@ -632,6 +633,7 @@
   # package related actions (install, remove, update) to
   # the package-log file TEXMFSYSVAR/web2c/tlmgr.log
   $packagelogged = 0;  # how many msgs we logged
+  $commandslogged = 0;
   chomp (my $texmfsysvar = `kpsewhich -var-value=TEXMFSYSVAR`);
   $packagelogfile = $opts{"package-logfile"};
   if ($opts{"usermode"}) {
@@ -699,9 +701,15 @@
   my $ret = execute_action($action, @ARGV);
 
   # close the special log file
-  if ($packagelogfile && !$::gui_mode) {
-    info("$prg: package log updated: $packagelogfile\n") if $packagelogged;
-    close(PACKAGELOG);
+  if (!$::gui_mode) {
+    if ($packagelogfile) {
+      info("$prg: package log updated: $packagelogfile\n") if $packagelogged;
+      close(PACKAGELOG);
+    }
+    if ($commandlogfile) {
+      info("$prg: command log updated: $commandlogfile\n") if $commandslogged;
+      close(COMMANDLOG);
+    }
   }
 
   # F_ERROR stops processing immediately, and prevents postactions from
@@ -828,6 +836,7 @@
   # and show it to the user before the possibly long delay.
   info("running $cmd ...\n");
   logcommand("running $cmd");
+  logpackage("command: $cmd");
   my ($out, $ret);
   if ($opts{"dry-run"}) {
     $ret = $F_OK;
@@ -867,12 +876,15 @@
   my $errors = 0;
 
   my $sysmode = ($opts{"usermode"} ? "-user" : "-sys");
-  my $invoke_fmtutil = "fmtutil$sysmode $common_fmtutil_args";
+  my $fmtutil_cmd = "fmtutil$sysmode";
+  my $status_file = TeXLive::TLUtils::tl_tmpfile();
+  my $fmtutil_args = "$common_fmtutil_args --status-file=$status_file";
 
+
   # if create_formats is false (NOT the default) we add --refresh so that
   # only existing formats are recreated
   if (!$localtlpdb->option("create_formats")) {
-    $invoke_fmtutil .= " --refresh";
+    $fmtutil_args .= " --refresh";
     debug("refreshing only existing formats per user option (create_formats=0)\n");
   }
 
@@ -973,7 +985,9 @@
       for my $e (keys %updated_engines) {
         debug ("updating formats based on $e\n");
         $errors += do_cmd_and_check
-                    ("$invoke_fmtutil --no-error-if-no-format --byengine $e");
+                    ("$fmtutil_cmd --byengine $e --no-error-if-no-format $fmtutil_args");
+        read_and_report_fmtutil_status_file($status_file);
+        unlink($status_file);
       }
       # now rebuild all other formats
       for my $f (keys %do_enable) {
@@ -981,7 +995,9 @@
         # ignore disabled formats
         next if !$::execute_actions{'enable'}{'formats'}{$f}{'mode'};
         debug ("(re)creating format dump $f\n");
-        $errors += do_cmd_and_check ("$invoke_fmtutil --byfmt $f");
+        $errors += do_cmd_and_check ("$fmtutil_cmd --byfmt $f $fmtutil_args");
+        read_and_report_fmtutil_status_file($status_file);
+        unlink($status_file);
         $done_formats{$f} = 1;
       }
     }
@@ -1000,7 +1016,9 @@
           $lang = "$TEXMFSYSVAR/tex/generic/config/$lang";
         }
         if (!$::regenerate_all_formats) {
-          $errors += do_cmd_and_check ("$invoke_fmtutil --byhyphen \"$lang\"");
+          $errors += do_cmd_and_check ("$fmtutil_cmd --byhyphen \"$lang\" $fmtutil_args");
+          read_and_report_fmtutil_status_file($status_file);
+          unlink($status_file);
         }
       }
     }
@@ -1010,7 +1028,9 @@
     if ($::regenerate_all_formats) {
       info("Regenerating existing formats, this may take some time ...");
       # --refresh might already be in $invoke_fmtutil, but we don't care
-      $errors += do_cmd_and_check("$invoke_fmtutil --refresh --all");
+      $errors += do_cmd_and_check("$fmtutil_cmd --refresh --all $fmtutil_args");
+      read_and_report_fmtutil_status_file($status_file);
+      unlink($status_file);
       info("done\n");
       $::regenerate_all_formats = 0;
     }
@@ -1028,6 +1048,42 @@
   }
 }
 
+sub read_and_report_fmtutil_status_file {
+  my $status_file = shift;
+  my $fh;
+  if (!open($fh, '<', $status_file)) {
+    printf STDERR "Cannot read status file $status_file, strange!\n";
+    return;
+  }
+  chomp(my @lines = <$fh>);
+  close $fh;
+  my @failed;
+  my @success;
+  for my $l (@lines) {
+    my ($status, $fmt, $eng, $what, $whatargs) = split(' ', $l, 5);
+    if ($status eq "DISABLED") {
+      # ignore for now
+    } elsif ($status eq "NOTSELECTED") {
+      # ignore for now
+    } elsif ($status eq "FAILURE") {
+      push @failed, "${fmt}.fmt/$eng";
+    } elsif ($status eq "SUCCESS") {
+      push @success, "${fmt}.fmt/$eng";
+    } elsif ($status eq "NOTAVAIL") {
+      # ignore for now
+    } elsif ($status eq "UNKNOWN") {
+      # ignore for now
+    } else {
+      # ignore for now
+    }
+  }
+  logpackage("  OK: @success") if (@success);
+  logpackage("  ERROR: @failed") if (@failed);
+  logcommand("  OK: @success") if (@success);
+  logcommand("  ERROR: @failed") if (@failed);
+  info("  OK: @success\n") if (@success);
+  info("  ERROR: @failed\n") if (@failed);
+}
 
 # 
 GET_MIRROR
 #
@@ -7543,6 +7599,7 @@
 }
 sub logcommand {
   if ($commandlogfile) {
+    $commandslogged++;
     my $tim = localtime();
     print COMMANDLOG "[$tim] @_\n";
   }

Modified: trunk/Master/tlpkg/TeXLive/TLUtils.pm
===================================================================
--- trunk/Master/tlpkg/TeXLive/TLUtils.pm	2021-05-08 23:50:00 UTC (rev 59142)
+++ trunk/Master/tlpkg/TeXLive/TLUtils.pm	2021-05-09 02:23:44 UTC (rev 59143)
@@ -4585,8 +4585,12 @@
 }
 
 

-=item C<setup_sys_user_mode($user,$sys,$tmfc, $tmfsc, $tmfv, $tmfsv)>
+=item C<setup_sys_user_mode($prg, $optsref, $tmfc, $tmfsc, $tmfv, $tmfsv)>
 
+Return two-element list C<($texmfconfig,$texmfvar)> of which directories
+to use, either user or sys. If C<$prg> is C<mktexfmt>, and the system
+dirs are writable, use them even if we are in user mode.
+
 =cut
 
 sub setup_sys_user_mode {
@@ -4613,7 +4617,8 @@
       exit(1);
     }
     if (!$optsref->{'sys'}) {
-      print STDERR "$prg [WARNING]: hidden sys mode found, switching to sys mode.\n" if (!$optsref->{'quiet'});
+      print STDERR "$prg [WARNING]: hidden sys mode found, switching to sys mode.\n"
+        if (!$optsref->{'quiet'});
       $optsref->{'sys'} = 1;
     }
   }
@@ -4623,16 +4628,42 @@
     # we are running as updmap-sys, make sure that the right tree is used
     $texmfconfig = $TEXMFSYSCONFIG;
     $texmfvar    = $TEXMFSYSVAR;
+    &debug("TLUtils::setup_sys_user_mode: sys mode\n");
+
   } elsif ($optsref->{'user'}) {
     $texmfconfig = $TEXMFCONFIG;
     $texmfvar    = $TEXMFVAR;
+    &debug("TLUtils::setup_sys_user_mode: user mode\n");
+
+    # mktexfmt is run (accidentally or on purpose) by a user with
+    # missing formats; we want to put the resulting format dumps in
+    # TEXMFSYSVAR if possible, so that future format updates will just
+    # work. Until 2021, they were put in TEXMFVAR, causing problems.
+    # 
+    # We only do this for mktexfmt, not fmtutil; if fmtutil is called
+    # explicitly with fmtutil -user, ok, do what they said to do.
+    #
+    if ($prg eq "mktexfmt") {
+      my $switchit = 0;
+      if (-d "$TEXMFSYSVAR/web2c") {
+        $switchit = 1 if (-w "$TEXMFSYSVAR/web2c");
+      } elsif (-d $TEXMFSYSVAR && -w $TEXMFSYSVAR) {
+        $switchit = 1;
+      }
+      if ($switchit) {
+        $texmfvar = $TEXMFSYSVAR;
+        &ddebug("  switched to $texmfvar for mktexfmt\n");
+      }
+    }
   } else {
-    print STDERR "" .
+    print STDERR
       "$prg [ERROR]: Either -sys or -user mode is required.\n" .
       "$prg [ERROR]: In nearly all cases you should use $prg -sys.\n" .
       "$prg [ERROR]: For special cases see https://tug.org/texlive/scripts-sys-user.html\n" ;
     exit(1);
   }
+
+  &debug("  returning: ($texmfconfig,$texmfvar)\n");
   return ($texmfconfig, $texmfvar);
 }
 



More information about the tex-live-commits mailing list.