Subject: Re: sysinst source niggles.... run_prog, logging/scripting rework?
To: Jonathan Stone <jonathan@DSG.Stanford.EDU>
From: Chris G. Demetriou <cgd@netbsd.org>
List: tech-install
Date: 07/01/1999 01:43:11
Since I just spent some time whacking on code near some of the things
you metion, I think i might have some useful input...  8-)

Jonathan Stone <jonathan@DSG.Stanford.EDU> writes:
> I've patched my local tree to use named variants for the 
> common cases to run_prog as follows:
> 
>         run_prog(0, 0, NULL, ...) -> run_silent(...);
>         run_prog(1, 0, NULL, ...) -> run_prog_or_die(...);
>         run_prog(0, 1, NULL, ...) -> run_prog_in_subwin(...);
> 
> joined the command lines to make them more readable.

Cool!

> run_prog() is
> replacd with a va_run_prog(), taking a va_alist as last arg, and all
> the run_* variants coded as wrappers to va_run_prog.

One of these things is not like the others...  8-)

It might be nice to have it named run_<something>, e.g. run_va.  it's
nice to be able to look for functions named 'run_.*'


> One thing it did
> highlight is that run_prog_or_die() simply calls exit. It needs to
> display a message saying what failed; not doing so is a bug,
> and we should really fix that for 1.4.1.

I'm kinda hesitant to buy into additional significant changes for
1.4.1's sysinst, at least until it gets some real user testing.

In what cases is run_prog_or_die() used (or the 'fatal' run_prog()
flag currently used)?  It seems to me that, in general, dying is a
very bad thing, and should be avoided.

For this (and the silent case), it probably makes sense to accumulate
error messages off-screen and, if a failure occurs, display them in a
message window like the run-w/display window.

In the longer term, sysinst's "exit strategy" needs some cleanup, in
my opinion, as does its data/state storage strategy.  It'd be nice to
just have the cleanup hook print, among other things, why the program
was dying.  However, it's not clear to me that 


> I've done a few more random cleanups: e.g., moving the script/log
> processing inside do_system() rather than dupliating it at each call
> to do_system(), and adding a target_rm() function rather than, e.g.,
> 
>       run_silent("rm -f %s", target_expand("/.profile"));
> 
> since target_expand() was supposed to be private to target.c.

Cool.


> I've also looked at the logging and scriting functionality.  Both are
> great ideas but the implementation leaves something to be
> eseired. [ ... ]
> 
> I'd like to  add some functions to do log/script processing
> via a `FILE*/script/log handle, e.g.,

It seems to me that it's reasonable to assume in that code that the
script and log handles are globals.  (not clear if you meant that from
your statement above.)

I dunno, it might also be nice to have functions which stuff bits into
the log/script (one thing that jumps out at me is _comments_, so
somebody reading the thing can know what's going on!) if they're
enabled so that you don't need to even check for logging/scripting
being enabled.  They could be used by your proposed target_*()
functions, even.


> Comments?  Anyone like to review these before a commit?

If you'd like, and are willing to wait a little bit for a response (no
earlier than this weekend, I think), I'd be willing to take a gander
at them.


> Or should we
> give up on the sysinst codebase as a dead duck?

No.

While some people have indicated that they're working on Something
Better, it doesn't sound like they're particularly far along (or even
have a rough estimate of completion).  Therefore, as far as i'm
concerned, we're stuck with sysinst for the forseeable future.

I have a bunch of work planned for it, if I can make the time.  I
think the list is something like the following (in order):

[ in the entire discussion below, when i'm referring to menus i'm
referring to the things sysinst calls menus, which are really more
like selection boxes or something. ]

	1 convert the msg code to do automatic layout of text.  This
	  means several things:

		a add APIs to provide table formatting, i.e. no
		  auto-flow of text, and convert table formatting code
		  to use it.

		b turn on the simple layout engine that i committed
		  a week or two ago.  Right now this isn't enabled
		  because of the lossage with tables.

		c nuke unused APIs.

		d cleanup markup features for messages, e.g. "force
		  line break, force paragraph break."  Right now this
		  functionality is already in the layout engine, but
		  it's... kinda hokey since I wanted it to be mostly-
		  compatible with the existing message text.  Right
		  now, paragraphs are denoted by \n\n, and line breaks
		  are denoted by <space>\n.  If possible I'd like to
		  do these in an HTML compatible way, but I'll cross
		  that bridge when I come to it.  In general, this
		  item can be put off to much later.

	2 poke the message compiler so that messages have a couple of
	  attributes: "preformatted" (don't auto-flow, i.e. preserve
	  spacing), and "menu selection character."  The former would
	  be used for table headings and table body entries.

	3 nuke all native-language (i.e. not command names, etc., but
	  "user feedback" text) and table format string constants in
	  the code.  (You'd think with a message compiler there
	  wouldn't be any of the former, but you'd be wrong.  I made
	  the problem a tiny bit worse with my recent changes, but
	  there were hard-coded strings where it would have been easy
	  to DTRT already...).  Replace them with messages.

	4 nuke all public message APIs which operate directly on
	  strings.  Make them all require messages.

	5 make the menu system suck much, much less.  make all menus
	  dynamic, and capable of having entries changed, added, and
	  removed at run time.  What this really means is:

		a create a decent menu API.  Knowing little, I was
		  planning to grab one of my old copies of Inside
		  Macintosh and clone some of the basic menu
		  creation/deletion + item addition/removal APIs.
		  They worked pretty well for me when I had to use
		  them 10+ years ago.  8-)  Desired features:

			* create, destroy menus

			* add, remove menu items

			* change item text.

			* each item can have a predefined keyboard
			  shortcut, but failing that keyboard
			  shortcuts will be assigned as it's done
			  currently.

			* settable default item.

			* menu text items can be described by message
			  IDs.

		b convert the menu compiler to generate an init
		  function which generates calls to that API, rather
		  than hard-coding the tables.

		c make the menu compiler try to do basic menu size vs.
		  screen size sanity checks at startup, rather than as
		  menus are invoked.  No more exiting out in the
		  middle because there's not enough room for the menu!

		d depending on the space cost incurred by 5b, and the
		  pain involved in generating static entries for the
		  preconfigured menus, try to generate pregenerated
		  menu structures rather than just function calls.
		  This is an optimization, it can be deferred.

		[ note that this means that the menu system will
		  probably be using the message system's internal
		  APIs.  I don't consider this a bug; i consider the
		  two tightly intertwined. ]		
		
	6 move all of the menu message strings into the message files,
	  and nuke the language dependence in the menu files.  It's
	  just Evil to be mixing code and data like this.  A
	  maintenance nightmare, as I think most of us who've hacked
	  the code know by now.  8-)

	7 nuke all handling of fixed strings in the menu code, even
	  in the 'replace item text' code.  (There you can do
	  formatting based on messages.)  Require that all public APIs
	  operate on messages.

	8 Integrate message window and menu display, or at least put
	  in some status checking features so that the menus better
	  accomodate the size of the message in the message window.
	  Maybe glue them together even more tightly and require that
	  the message window be the entire stdscr.


Pie in the sky:

	* more advanced message formatting.  e.g. don't make the
	  message formatter just printf-like, make it support
	  additional types, such as messages.  For instance, it'd be
	  nice to say:

		message mi_foobar "foo bar: %m"
		message mi_foobar_placeholder "XXX"
		message mi_foobar_yes "Yes"
		message mi_foobar_no "No"

	  then msg_format(MSG_mi_foobar, MSG_mi_placeholder); to get
	  "foo bar: XXX".  (the reason for using a placeholder here
	  is so that the initial menu size check could try to
	  check for enough horizontal space to display the menu.  I
	  prefer that style to hard-coding one of the actual message
	  values, because e.g. the widest one may change from language
	  to language.)


Other code that I know needs work:

	* the code that reads the child's output from the pty and then
	  logs it and/or puts it into the display window is losing,
	  for a couple of reasons:

		* it does: parent_fork()->child1
		  child1_fork()->child2, child1 exec command, child2
		  read output and feed it back to parent.  This
		  seems...  unnecessarily complex.  If there's a
		  reason for it, it should be thorougly documented.
		  If not, it should be cleaned up to do only one fork.

		* if the command exits before all output has been
		  passed back to the parent, the parent won't ever
		  get (and therefore display/log) the last of the
		  output.  This is caused by incorrect loop
		  termination checks, but (given my experience) I
		  don't know enough that it's trivial to fix so I
		  punted on it for the time being.  I seem to recall
		  that running 'stty -a ; false' in a subwindow was
		  a good way to show the problem.  you might not need
		  the '; false' to trigger it, but if you have it
		  the window doesn't go away immediately and you can
		  see the last output pushed to the parent.  8-)

	* I've seen several cases now where (it would appear that)
	  running commands w/o display output has caused sysinst to
	  hang.  This could be because of some child-exit race
	  condition check, or something.  I've never bothered tracking
	  it down, and i'm not even sure the above description of the
	  trigger of the problem is accurate, but that's what's seemed
	  likely to me given the menus i'd accepted right before
	  sysinst hung.  sysinst was killable (via some kind of
	  signal, I forget which 8-).


Obviously, if anybody's interested in helping with any of these tasks
i'd more than welcome the help.
	

cgd
-- 
Chris Demetriou - cgd@netbsd.org - http://www.netbsd.org/People/Pages/cgd.html
Disclaimer: Not speaking for NetBSD, just expressing my own opinion.