danhper / fundle

A minimalist package manager for fish shell
MIT License
375 stars 22 forks source link

Global installation #50

Open BarbzYHOOL opened 5 years ago

BarbzYHOOL commented 5 years ago

I think when we install fundle in /etc/fish, the plugins should also be in a global directory so all users use the same plugins instead of installing each plugin for each user (which wastes time and disk)

hunter-richardson commented 5 years ago

One way I got this to work is place fundle.fish under /root/.config/fish/functions:

for i in functions completions
    command sudo wget https://raw.githubusercontent.com/danhper/fundle/master/$i/fundle.fish -O /root/.config/fish/$i/fundle.fish
    command sudo chmod o+x /root/.config/fish/$i/fundle.fish
end

... in /root/.config/fish/config.fish (or a file it references), set up the plugins and ln the loaded files to /etc/fish:

builtin source /root/.config/fish/functions/fundle.fish
fundle plugin 'one-line/per-plugin'
fundle init
if test ! -d /root/.config/fish/fundle
    fundle install
    for i in (fundle list | command grep -v https://github.com)
        for f in functions completions
            builtin test -d /root/.config/fish/fundle/$i/$f;
                and command chmod a+x /root/.config/fish/fundle/$i/$f/*;
                and command ln -v /root/.config/fish/fundle/$i/$f/* /etc/fish/$f/
        end
    end
end

Then just make sure root is the only one who updates fundle:

function __update_fundle
    command sudo --user=root fish -c "builtin source /root/.config/fish/functions/fundle.fish; fundle self-update; and fundle clean; and fundle update"
end

It's definitely not ideal, but it works.

BarbzYHOOL commented 5 years ago

yeah, with symlink there is always a solution xD but it's damn dirty

thank you for idea, for now I just install it on every user (hopefully in my final setup I'll have only 2 users lol)

BarbzYHOOL commented 1 year ago

@danhper

danhper commented 1 year ago

Hey, I agree this would be nicer indeed! Would you have time to send a PR for this please?

BarbzYHOOL commented 1 year ago

I don't know how to code this, I know a bit of fish scripting but what would be a good way to do all of this? at least if there was a plan to follow, me or someone could attempt to follow it

hunter-richardson commented 1 year ago

Okay, let's place functions/fundle.fish under /root/.config/fish/functions, and optionally sym-link it to /etc/fish/functions to allow non-sudoer plugin installation:

for i in functions completions
    command sudo mkdir -pv /etc/fish/$i /root/.config/$i
        and command sudo wget --show-progress -v https;//raw.githubusercontent.com/danhper/fundle/master/$i/fundle.fish -O /root/.config/fish/$i/
        and command sudo ln -v /root/.config/fish/$i/fundle.fish /etc/fish/$i/ # allows non-sudoer plugin installation
        and command chmod -c a+rx /root/.config/$i/fundle.fish # allows non-sudoer plugin installation
end

Configure /root/.config/fish/config.fish for fundle, if necessary:

builtin source /root/.config/fish/functions/fundle.fish

Write the following functions to functions/fundle.fish:

function __fundle_validate_sudo -d "test whether the user is a sudoer"
    command sudo -v
    builtin set -l temp $status
    builtin printf 'You are %sa sudoer!' (builtin test $temp -eq 0
                                            or builtin printf 'not ')
    builtin return $temp
end

functions __fundle_is_global -d "test whether fundle is installed globally or locally"
    builtin string match -qr (builtin printf '^/home/%s' (command whoami)) (builtin status fish-path)
        and builtin printf 'You should have installed fundle globally!\nSee https://github.com/danhper/fundle#global-installation'
        and builtin return 1
    builtin return 0
end

functions __fundle_list_plugins -d "list installed plugins under given directory" -a dir
    builtin test -n "$dir" -a -d $dir -a -r $dir
        and command find $dir -type d -mindepth 2 -maxdepth 2 2>/dev/null | command string replace $dir ''
end

function __fundle_local_plugins -d "list locally installed plugins"
    __fundle_list_plugins __fundle_plugins_dir
end

function __fundle_global_plugins -d "list globally installed plugins"
    __fundle_list_plugins /etc/fish/fundle
end

function __fundle_plugins -d "list all available plugins"
    begin; __fundle_global_plugins; and __fundle_local_plugins; end | command sort -dfu
end

function __fundle_global_plugin -d "install global plugin to fundle"
    __fundle_is_global
        or builtin return $status
    __fundle_validate_sudo
        or builtin return $status
    builtin set -l name (command awk -F '[[:blank:]@]+' '{print $1}' "$argv")
    command sudo --user=root fish -c "fundle plugin $argv; and fundle init; and fundle install; and command chmod -cR a+rx /root/.config/fish"
        and for f in (command find -L /root/.config/fish/fundle/$name -type f -name '*.fish')
                builtin set -l dir (builtin string replace /root/.config /etc (command dirname $f))
                    and command mkdir -pv $dir
                    and command sudo ln -v $f $dir
            end
end

function __fundle_update_global -d "update global plugins" -a name
    __fundle_is_global
        or builtin return $status
    __fundle_validate_sudo
        or builtin return $status
    builtin test -n "$name"
        and command sudo --user=root fish -c "fundle update $name"
        or command sudo --user=root fish -c "fundle update"
end

The following cases under the switch in the fundle function itself:

        case "global-plugin"
            __fundle_global_plugin $sub_args
        case "global-update"
            __fundle_update_global $sub_args

And the following lines to completions/fundle.fish:

builtin complete -f -c fundle -n '__fish_prog_needs_command' -a global-plugin -d "add a global plugin"
builtin complete -f -c fundle -n '__fish_prog_needs_command' -a global-update -d "update existing global plugin"
builtin complete -f -c fundle -n '__fish_prog_using_command global-plugin' -l url -d "set the plugin URL"
builtin complete -f -c fundle -n '__fish_prog_using_command global-plugin' -l path -d "set the plugin load path"

Now prevent the local installation of plugins already installed globally:

functions __fundle_plugin -d "add plugin to fundle" -a name
    ...
        if not contains $name (__fundle_plugins)
            ...
        end
end

Then configure the global /etc/fish/config.fish to search for sym-links, depth-last (this might break for paths containing whitespace):

for f in (command find /etc/fish -type l -name '*.fish' -printf '%d %p\n' | command sort | command cut -d' ' -f2-)
    builtin source (command readlink -f "$f")
end

Now (unless I missed something) a sudoer may choose to install/update plugins for all users, and to allow non-sudoers to install any other plugin.

NOTE: Due to complexity of the __fundle_global_plugin function (which is due to the sym-linking), there's no need to run fundle init or after fundle global-plugin <plugin-identifier>. They simply need to source /etc/fish/config.fish to load freshly-installed global plugins.

BarbzYHOOL commented 1 year ago

Why not make a PR if you have sorted it out Hunter?