summaryrefslogtreecommitdiff
path: root/guides/setups/operating-systems/apps.org
blob: 583d4b6317469aa762687aeeebc35ab97a459b6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#+TITLE: Installing applications under =$HOME=

One day I woke up and decided to stop letting ~make install~ put
programs under =/usr/local/=.  Not every project provides an
=uninstall= target, so over time, as more and more applications get
lumped under that hierarchy, it becomes a clutter of stuff that I
cannot remove without…

1. guesstimating what files belong to any given program using
   timestamps,
2. weighing my odds of passing correctly crafted globs to the likes of
   =sudo find -delete= and =sudo rm -r= without destroying my system.

Instead I figured I would start ~./configure~'ing programs with
=--prefix=${HOME}/apps/${program}=, and teach whichever dotfiles
manage session environment variables to arrange for installed
resources to be found.

How hard could it be?

* =PATH=
The Correct Way™ to set environment variables seems to depend on

1. the kind of session (TTY vs GUI),
2. the init system (e.g. [[https://www.freedesktop.org/software/systemd/man/environment.d.html][systemd user environment variables]])
3. the desktop environment (e.g. [[https://userbase.kde.org/Session_Environment_Variables][Plasma session environment variables]]),
4. the display server,
5. the distro?
   - e.g. Debian's SSDM [[https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=794419][used not to]] source =~/.profile=,
   - and [[https://github.com/sddm/sddm/issues/448][developers said]] it should not anyway,
   - except [[https://github.com/sddm/sddm/issues/1551][it has provisions to do so]]?
6. [[https://man7.org/linux/man-pages/man8/pam_env.8.html][PAM]]?

Empirically with Plasma on both Tumbleweed (20230929) and Debian 12,
=~/.profile= seems to be run for both TTY and GUI sessions.  Unclear
what arcane magic is causing that: probably the login manager - on
Tumbleweed =/usr/share/sddm/scripts/Xsession= seems to start a ~bash
--login~, but getting lost in the =/usr/etc/X11/xdm/= weeds trying to
track down who might source that =Xesssion= script.

=~/.profile= it is, then 🤞

(For other DEs on X, my recollection was that =~/.xsessionrc= is the
way to go for GUI sessions?  No clue about Wayland)

* ~man~ pages
=manpath(5)= says:

#+begin_quote
By default, man-db examines the user's =$PATH=.  For each
=path_element= found there, it adds =manpath_element= to the search
path.

If there is no =MANPATH_MAP= line in the configuration file for a
given =path_element=, then it adds all of =path_element/../man=,
=path_element/man=, =path_element/../share=man=, and
=path_element/shared/=man= that exist as directories to the search
path.
#+end_quote

How convenient!  Setting =PATH= automatically takes care of ~man~
then… unless =MANPATH= is set, in which case that logic is bypassed.

** openSUSE
=/usr/etc/profile.d/manpath.sh= [fn:: sourced by =/etc/profile=,
sourced by =/usr/etc/profile= and =~/.profile=.] plays a little danse
to (a) query ~manpath~, which runs the heuristic described above (b)
set the resulting value "in stone" by exporting =MANPATH=.

This means that ~man~ will not consider any =PATH= element added by
the user after that profile fragment was sourced.

Solutions:

1. Unset =MANPATH= in =~/.profile=, after =/etc/profile= is read.
   =~/.profile= is "read each time a login shell is strated.  All
   other interactive shells will only read .bashrc", so unclear
   whether that will affect graphical sessions.
2. Extend =PATH= with apps /before/ those profile fragments are
   loaded.  Unclear how to accomplish that:
   - [[https://wiki.archlinux.org/title/environment_variables#Per_user][systemd user environment variables]]?  Seems to be limited to
     =KEY=VALUE= directives; I would like to run a bit of logic that
     will automatically add every =~/apps/*/bin= directory.
   - [[https://userbase.kde.org/Session_Environment_Variables][Plasma session environment variables]]?  Presumably will not affect
     TTYs?
3. Embrace the distro's method: if =MANPATH= is set, extend it.

Went with solution 1 because empirically =~/.profile= seems to be
sourced for GUI sessions (as noted in § =PATH=).

* ~info~ pages
Similar to ~man~, ~info~ knows to work with =PATH=.  The priority
[[https://git.savannah.gnu.org/cgit/texinfo.git/tree/info/infopath.c?h=texinfo-7.0.3#n41][seems to be]]:

1. the =INFOPATH= environment variable,
2. the =INFODIR= build macro, /if =infopath-no-defaults= is not set/,
3. the =DEFAULT_INFOPATH= build macro, /if =INFOPATH= is unset or ends
   with a trailing colon/.

Any of these can contain the =PATH= literal, which means "iterate over
=${PATH}= and add nearby =share/info= & =info= directories".  By
default, =DEFAULT_INFOPATH= contains =PATH= 🥳 but =INFODIR= has
priority and is set to something boring like =/usr/share/info= 😒

Solution:

#+begin_src bash
cat <<EOF > ~/.infokey
#var
# Disable INFODIR; fall back to DEFAULT_INFOPATH which prioritizes
# program PATH over /usr/share/info.
infopath-no-defaults=On
EOF
#+end_src

* TODO ~bash~ completions

* Putting it all together
Presenting =~/apps/activate=, to be sourced from =~/.profile=:

#+begin_src bash
# Hey Emacs; this is a -*- shell-script -*-.
# Hopefully invoked by bash 🤞

_apps_dir=$(dirname ${BASH_SOURCE})

_apps_PATH=$(
    shopt -s nullglob
    bins=( "${_apps_dir}"/*/bin )
    IFS=: eval 'echo "${bins[*]}"'
)

export PATH=${_apps_PATH}:${PATH}
#+end_src

* Resources
** [[https://nullprogram.com/blog/2017/06/19/][nullprogram.com]] — Building and Installing Software in $HOME
Explains how to set things up so that one can use =~/.local= as a
first-class citizen for applications, libraries and development
resources (headers, pkg-config, manpages).