A scheme to manage several ZSH config file collections?

Hi all,
some of you might be aware of grml, a live boot CD which uses ZSH as its default shell. I suggested integrating several different zshrc files along with whatever other files they need and offer the user a selection of said configuration files.
Now, we are wondering if there is a clean and maintainable way to do this. I have had a few ideas in this direction and would like to discuss those here. New suggestions are more than welcome as well, of course. Ideally, the same versions should be usable on the machines of whoever maintains those files, so that changes can be merged back and forth easily, which will allow more people to participate.
1) Make ZSH load the RC files from different paths (/etc/zsh/config1 ..) Pro: Almost drop-in, minimal work necessary Cleanly seperated Different ttys might run with different RC files Con: Needs modification to fpath etc Shells can not be allowed to start prior to rc file selection
2) Use symlinks Pro: Fast to set up Con: All shells are forced to use the same RC files Shells can not be allowed to start prior to rc file selection Ugly & hackish
3) Use $ZSHRC_PREFIX or some similar variable Pro: Drop-in solution once you change your RC files for the first time Cleanly seperated Different ttys might run with different RC files Con: Shells can not be allowed to start prior to rc file selection Needs a way for ZSH to be started with a variable set before it is invoked
Are there any other options? Pros or Cons I overlooked? Anything else? The main thing I worry about is to make the shells wait for their RC files in a robust & fail-safe way?
Personally, I lean towards solution 3, but I am not hell-bent onto using it.
Thanks, Richard
PS: Yes, in a second step, this system could be expanded for VIM etc, as well.

[dropping zsh-users from Cc: as they would only be marginally involved here]
Richard Hartmann richih.mailinglist@gmail.com: [..multiple zshrcs in grml..]
- Make ZSH load the RC files from different paths (/etc/zsh/config1 ..) Pro: Almost drop-in, minimal work necessary Cleanly seperated Different ttys might run with different RC files Con: Needs modification to fpath etc Shells can not be allowed to start prior to rc file selection
[...]
- Use $ZSHRC_PREFIX or some similar variable Pro: Drop-in solution once you change your RC files for the first time Cleanly seperated Different ttys might run with different RC files Con: Shells can not be allowed to start prior to rc file selection Needs a way for ZSH to be started with a variable set before it is invoked
I've snipped out solution no2, as I don't think that it is the best way to go.
Actually, I'm tending towards a mixture of the two remaining solutions:
1. Don't touch the current zshrc at all. It works fine and should be left intact unmodified.
2. Give all added rcs their own file + function dir (I don't think an additional completion dir is needed):
/etc/zsh/rcs/zshrc.richih /etc/zsh/rcs/richih.d/
3. Put *every* function file, that does not collide with the ones that are already in grml's configuration into /etc/zsh/functions.d; There's no reason from keeping non-colliding function to not be in the standard config.
4. add /etc/zsh/rcs/richih.d/ at the *beginning* be $fpath so that colliding functions are not taken from the default dir, but from the dir that is part of the config, that is in action.
5. If $ZSHRC_ALT (I think _ALT is a better name when choosing an alternate configuration) is set to a name (say richih), use /etc/zsh/rcs/zshrc.$ZSHRC_ALT if it is available.
Do NOT source /etc/zsh/zshrc in that case. Do NOT source ~/.zshrc in that case (set $ZDOTDIR to ~/.zshrc.$ZSHRC_ALT - that would make ~/.zshrc.$ZSHRC_ALT/.zshrc to be sourced; standard zsh mechanism.)
5. Do the handling of $ZSHRC_ALT, $ZDOTDIR and $fpath in the global zshenv (/etc/zsh/zshenv) in a
if [[ -o interactive ]] ; then fi
Block;
That should be a pretty robust yet very easy to implement way, that would leave our zshrc completely untouched and hence be still usable on other systems without a hassle. And the only thing you'd have to make sure is to set $ZSHRC_ALT before/when calling zsh.
I hope I didn't forget to wrap up one of the steps I did in my head.
Regards, Frank

Frank Terbeck ft@grml.org:
Richard Hartmann richih.mailinglist@gmail.com: [..multiple zshrcs in grml..]
- Make ZSH load the RC files from different paths (/etc/zsh/config1 ..) Pro: Almost drop-in, minimal work necessary Cleanly seperated Different ttys might run with different RC files Con: Needs modification to fpath etc Shells can not be allowed to start prior to rc file selection
[...]
- Use $ZSHRC_PREFIX or some similar variable Pro: Drop-in solution once you change your RC files for the first time Cleanly seperated Different ttys might run with different RC files Con: Shells can not be allowed to start prior to rc file selection Needs a way for ZSH to be started with a variable set before it is invoked
Some more thoughts:
I've snipped out solution no2, as I don't think that it is the best way to go.
Actually, I'm tending towards a mixture of the two remaining solutions:
- Don't touch the current zshrc at all. It works fine and should be left intact unmodified.
We'll need to stop the normal zshrc from sourcing, so something like:
[[ -n $ZSHRC_ALT ]] && [[ -e /etc/zsh/rcs/zshrc.$ZSHRC_ALT ]] && return
...would be needed.
Give all added rcs their own file + function dir (I don't think an additional completion dir is needed):
/etc/zsh/rcs/zshrc.richih /etc/zsh/rcs/richih.d/
Put *every* function file, that does not collide with the ones that are already in grml's configuration into /etc/zsh/functions.d; There's no reason from keeping non-colliding function to not be in the standard config.
Unless, the function does only have value in connection with the configuration in question.
add /etc/zsh/rcs/richih.d/ at the *beginning* be $fpath so that colliding functions are not taken from the default dir, but from the dir that is part of the config, that is in action.
If $ZSHRC_ALT (I think _ALT is a better name when choosing an alternate configuration) is set to a name (say richih), use /etc/zsh/rcs/zshrc.$ZSHRC_ALT if it is available.
Do NOT source /etc/zsh/zshrc in that case. Do NOT source ~/.zshrc in that case (set $ZDOTDIR to ~/.zshrc.$ZSHRC_ALT - that would make ~/.zshrc.$ZSHRC_ALT/.zshrc to be sourced; standard zsh mechanism.)
That gives full support for user configuration, as pws mentioned on zsh-users.
We should touch a .zshrc in there if a given configuration does not provide one in order to avoid the newuser-module-dialog.
Do the handling of $ZSHRC_ALT, $ZDOTDIR and $fpath in the global zshenv (/etc/zsh/zshenv) in a
if [[ -o interactive ]] ; then fi
Block;
Regards, Frank

On Thu, Jul 24, 2008 at 14:58, Frank Terbeck ft@grml.org wrote:
- Don't touch the current zshrc at all. It works fine and should be left intact unmodified.
We'll need to stop the normal zshrc from sourcing, so something like:
If there _is_ no normal zshrc, zsh-newuser-install will run. As we can easily replace this function, ZSH does the handling of this for free. The default zsh could be loaded the second a user presses enter on the little welcome screen menu grml displays on tty1 and everything set up to use this config, as well. Said menu would run from zsh-newuser-install then, btw.
- Put *every* function file, that does not collide with the ones that are already in grml's configuration into /etc/zsh/functions.d; There's no reason from keeping non-colliding function to not be in the standard config.
Unless, the function does only have value in connection with the configuration in question.
As I autoload every one of my functions in my zshrc via globbing, I would want to keep softlinks for the functions moved into main, but yes, that is a good idea.
- add /etc/zsh/rcs/richih.d/ at the *beginning* be $fpath so that colliding functions are not taken from the default dir, but from the dir that is part of the config, that is in action.
[[ -n $ZSHRC_ALT ]] && . /etc/zsh/rcs/$ZSHRC_ALT.d
in all zshrcs would mean you can fork and otherwise mangle them without needing to touch anything in the actual file.
Do NOT source /etc/zsh/zshrc in that case.
This should exist and overwrite the normal zsh-newuser-install.
Do NOT source ~/.zshrc in that case (set $ZDOTDIR to ~/.zshrc.$ZSHRC_ALT - that would make ~/.zshrc.$ZSHRC_ALT/.zshrc to be sourced; standard zsh mechanism.)
We should touch a .zshrc in there if a given configuration does not provide one in order to avoid the newuser-module-dialog.
I would rather have a ~/.zshrc that simply uses $ZDOTDIR to source everything. Solves two problems in one go.
Do the handling of $ZSHRC_ALT, $ZDOTDIR and $fpath in the global zshenv (/etc/zsh/zshenv) in a
if [[ -o interactive ]] ; then fi
Block;
Would also be solved by the above, so make that three.
Richard

Richard Hartmann richih.mailinglist@gmail.com:
On Thu, Jul 24, 2008 at 14:58, Frank Terbeck ft@grml.org wrote:
- Don't touch the current zshrc at all. It works fine and should be left intact unmodified.
We'll need to stop the normal zshrc from sourcing, so something like:
If there _is_ no normal zshrc, zsh-newuser-install will run. As we can easily replace this function, ZSH does the handling of this for free.
As I said, I would not want to touch /etc/zsh/zshrc. It will always be there. Hence, the catch is needed.
I also do not want to touch ~/.zshrc. It should always be there. If we can set ZDOTDIR before zsh is run, we do have means to support the *full* range of zsh config files. No need to touch ~/.zshrc at all.
I really would prefer to keep grml's zsh config like it is now, and if you want to switch, you use a function, say 'zmode <whateverrc>' to spawn a differently set up shell.
You can even write the current mode into a file, so that subsequently opened shells automatically use that setup.
No need to fiddle with newuser-install, at all.
[...]
- add /etc/zsh/rcs/richih.d/ at the *beginning* be $fpath so that colliding functions are not taken from the default dir, but from the dir that is part of the config, that is in action.
[[ -n $ZSHRC_ALT ]] && . /etc/zsh/rcs/$ZSHRC_ALT.d
in all zshrcs would mean you can fork and otherwise mangle them without needing to touch anything in the actual file.
With '/etc/zsh/rcs/$ZSHRC_ALT.d' being a directory, that would certainly lead to funny results.
It should be a directory that holds the function files specific for the configuration in question. And in order to overwrite same-named functions from /etc/zsh/functions.d it *must* be put at the start of $fpath.
Do NOT source /etc/zsh/zshrc in that case.
This should exist and overwrite the normal zsh-newuser-install.
It shou
Do NOT source ~/.zshrc in that case (set $ZDOTDIR to ~/.zshrc.$ZSHRC_ALT - that would make ~/.zshrc.$ZSHRC_ALT/.zshrc to be sourced; standard zsh mechanism.)
We should touch a .zshrc in there if a given configuration does not provide one in order to avoid the newuser-module-dialog.
I would rather have a ~/.zshrc that simply uses $ZDOTDIR to source everything. Solves two problems in one go.
That's not what $ZDOTDIR is meant for at all. It is meant for switching to alternate configurations.
If $ZDOTDIR is unset, the value of $HOME is used. Hence $HOME/.zshrc is used in normal environments.
Is $ZDOTDIR is /foo/bar/, /foo/bar/.zshrc is used. No matter what $HOME is set to.
This is (besides the obvious need to set $ZSHRC_ALT, and the previously explained need for setting $fpath) the reason for my point no. 5.
Do the handling of $ZSHRC_ALT, $ZDOTDIR and $fpath in the global zshenv (/etc/zsh/zshenv) in a
if [[ -o interactive ]] ; then fi
Block;
Would also be solved by the above, so make that three.
It wouldn't. IMHO. See above.
Regards, Frank

Frank Terbeck ft@grml.org:
Richard Hartmann richih.mailinglist@gmail.com:
On Thu, Jul 24, 2008 at 14:58, Frank Terbeck ft@grml.org wrote:
[...]
Do NOT source /etc/zsh/zshrc in that case.
This should exist and overwrite the normal zsh-newuser-install.
It shou
*sigh* I wish, I had someone who'd proveread my mails, before I send them out...
What I wanted to say here, is that I don't understand what is meant by that sentence. I've read it a few times, I just don't undestand, what it is supposed to say.
Regards, Frank

Frank Terbeck ft@grml.org:
Richard Hartmann richih.mailinglist@gmail.com:
On Thu, Jul 24, 2008 at 14:58, Frank Terbeck ft@grml.org wrote:
- Don't touch the current zshrc at all. It works fine and should be left intact unmodified.
We'll need to stop the normal zshrc from sourcing, so something like:
If there _is_ no normal zshrc, zsh-newuser-install will run. As we can easily replace this function, ZSH does the handling of this for free.
As I said, I would not want to touch /etc/zsh/zshrc. It will always be there. Hence, the catch is needed.
I also do not want to touch ~/.zshrc. It should always be there. If we can set ZDOTDIR before zsh is run, we do have means to support the *full* range of zsh config files. No need to touch ~/.zshrc at all.
I really would prefer to keep grml's zsh config like it is now, and if you want to switch, you use a function, say 'zmode <whateverrc>' to spawn a differently set up shell.
You can even write the current mode into a file, so that subsequently opened shells automatically use that setup.
No need to fiddle with newuser-install, at all.
[...]
Do NOT source ~/.zshrc in that case (set $ZDOTDIR to ~/.zshrc.$ZSHRC_ALT - that would make ~/.zshrc.$ZSHRC_ALT/.zshrc to be sourced; standard zsh mechanism.)
We should touch a .zshrc in there if a given configuration does not provide one in order to avoid the newuser-module-dialog.
I would rather have a ~/.zshrc that simply uses $ZDOTDIR to source everything. Solves two problems in one go.
That's not what $ZDOTDIR is meant for at all. It is meant for switching to alternate configurations.
If $ZDOTDIR is unset, the value of $HOME is used. Hence $HOME/.zshrc is used in normal environments.
Is $ZDOTDIR is /foo/bar/, /foo/bar/.zshrc is used. No matter what $HOME is set to.
[...]
So, maybe a bit of code makes things clearer:
[snip] diff -r f344eeb49c9f etc/zsh/zshenv --- a/etc/zsh/zshenv Fri May 30 14:59:34 2008 +0200 +++ b/etc/zsh/zshenv Thu Jul 24 22:32:19 2008 +0200 @@ -103,5 +103,51 @@ # MAKEDEV should be usable on udev as well by default: export WRITE_ON_UDEV=yes
+if [[ -o interactive ]] ; then + + function zmode() { + mode=$1 ; shift + + typeset -g ZSHRC_ALT="${mode}" + print ${mode} > /var/run/zsh.${USER}.mode + if [[ -o login ]] ; then + exec zsh -l + else + exec zsh + fi + } + + [[ -z ${ZSHRC_ALT} ]] && [[ -e /var/run/zsh.${USER}.mode ]] && ZSHRC_ALT=$(</var/run/zsh.${USER}.mode) + + if [[ -n ${ZSHRC_ALT} ]] ; then + if [[ -e /etc/zsh/rcs/zshrc.${ZSHRC_ALT} ]] \ + && [[ -d /etc/zsh/rcs/${ZSHRC_ALT}.d ]]; then + + setopt extendedglob + + fpath=( + /etc/zsh/rcs/${ZSHRC_ALT}.d + /etc/zsh/functions.d + /etc/zsh/completion.d + $fpath + ) + + for func in /etc/zsh/functions.d/[^_]*[^~] ; do + autoload -Uz ${func:t} + done + + ZDOTDIR="$HOME/.zshrc.${ZSHRC_ALT}" + [[ ! -d ${ZDOTDIR} ]] && mkdir ${ZDOTDIR} + [[ ! -e ${ZDOTDIR}/.zshrc ]] && touch ${ZDOTDIR}/.zshrc + + setopt noextendedglob + + else + unset ZSHRC_ALT + fi + fi + +fi + ## END OF FILE ################################################################# # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4 diff -r f344eeb49c9f etc/zsh/zshrc --- a/etc/zsh/zshrc Fri May 30 14:59:34 2008 +0200 +++ b/etc/zsh/zshrc Thu Jul 24 22:32:19 2008 +0200 @@ -84,6 +84,11 @@ # exactly the same as @@INSERT-aliases-default@@. If you want a list of # *all* aliases, for example, use @@INSERT-aliases-all@@. #}}} + +if [[ -n ${ZSHRC_ALT} ]] ; then + source /etc/zsh/rcs/zshrc.${ZSHRC_ALT} + return +fi
# zsh profiling {{{ # just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details [snap]
I didn't test this at all. But I think it implements most of the needed mechanisms.
I do not think a releasable version would be a lot more complex. And IMO this is quite simple.
Regards, Frank
Teilnehmer (2)
-
Frank Terbeck
-
Richard Hartmann