RaphGL / Tuckr

Super powered replacement for GNU Stow
GNU General Public License v3.0
134 stars 10 forks source link

Pain point: using multiple repositories (e.g. for work vs personal) #36

Closed jasha-hrp closed 1 month ago

jasha-hrp commented 1 month ago

Hi @RaphGL,

Do you have a recommended workflow for using tuckr with multiple stow repositories on the same machine? I want to deploy dotfiles from two separate repos:

The first repo e.g. contains IDE config, my personal .bashrc, etc. The second repo contains work-specific stuff, e.g. aliases that I use at my job.

I wouldn't feel right committing work stuff to a personal repository, and I don't think my employer would appreciate it either, hence the need for two separate repos.

If I clone these repos, I'll get two folders ~/.dotfiles and ~/dotfiles in my home folder. I'd like to be able to use tuckr with both of these at the same time.

jasha-hrp commented 1 month ago

Here is the current behavior: if both ~/.dotfiles and ~/dotfiles are present then tuckr ignores ~/dotfiles.

$ erd .dotfiles
4096 B       ┌─ food
4096 B    ┌─ foo
4096 B ┌─ Configs
4096 B .dotfiles

2 directories, 1 file
$ erd dotfiles
4096 B       ┌─ bard
4096 B    ┌─ bar
4096 B ┌─ Configs
4096 B dotfiles

2 directories, 1 file
$ tuckr add foo  # success
$ tuckr add bar  # failure
bar doesn't exist.
RaphGL commented 1 month ago

I saw your message on friday but was taking the time to think about it for a bit longer.

I was thinking about whether adding support for this somehow or just doing some form of workaround.

If I clone these repos, I'll get two folders ~/.dotfiles and ~/dotfiles in my home folder. I'd like to be able to use tuckr with both of these at the same time.

I think using both ~/.dotfiles and ~/.config/dotfiles together is a bad idea, the lookup path is only there because some people might prefer having their dotfiles on their home directory but the XDG_DIRS standard paths are preferred so it was never intended to look and use 2 directories for dotfiles.

The workarounds

When the dotfiles are isolated

If you have isolated dotfiles used at work and at home and they're never deployed together I think just making a small script that swaps the dotfiles is enough. You could create a .config/dotfiles_home and .config/dotfiles_work and then make a small script to swap them like this:

#!/usr/bin/env python3
from pathlib import Path
from typing import Optional
import shutil
import os

home_dotfile = Path("~/.config/dotfiles_home").expanduser()
work_dotfile = Path("~/.config/dotfiles_work").expanduser()
dotfiles_dir = Path("~/.config/dotfiles").expanduser()

def active_dotfile() -> Optional[Path]:
    if not dotfiles_dir.exists():
        return None

    if home_dotfile.exists() and not work_dotfile.exists():
        return work_dotfile
    elif not home_dotfile.exists() and work_dotfile.exists():
        return home_dotfile
    else:
        return None

def main():
    current_dotfile = active_dotfile()

    if current_dotfile is None:
        shutil.move(home_dotfile, dotfiles_dir)
        os.system("tuckr add \\*")
        print(f"made dotfiles become: {home_dotfile}")

    elif current_dotfile == home_dotfile:
        os.system("tuckr rm \\*")
        shutil.move(dotfiles_dir, current_dotfile)
        shutil.move(work_dotfile, dotfiles_dir)
        os.system("tuckr add \\*")
        print(f"swapped dotfiles to: {work_dotfile}")

    elif current_dotfile == work_dotfile:
        os.system("tuckr rm \\*")
        shutil.move(dotfiles_dir, work_dotfile)
        shutil.move(home_dotfile, dotfiles_dir)
        print(f"swapped dotfiles to: {home_dotfile}")
        os.system("tuckr add \\*")

if __name__ == "__main__":
    main()

When dotfiles are supposed to be together

If they're supposed to be together you could try leveraging git by creating a private repo and then creating a work group which is a git submodule. This should work fine as long as it retains the structure that tuckr expects.

This does mean you can no longer control each dotfile group individual for your work dotfiles though.

Adding a new functionality approach

Honestly this one is the one that I try to avoid since it requires making the code more complicated but the alternate approach that I came up with is probably by allowing multiple dotfile directories, but I'd have to somehow find a sensible naming scheme for this and it also requires messing with all the symlinking related commands so they're aware of the existence of multiple dotfile directories.

jasha-hrp commented 1 month ago

Thank you for your reply!

I am using my work dotfiles and my personal dotfiles together on the same computer.

For now I will use tuckr for personal and GNU stow for work (or vice versa) so that I can get around this limitation.

raphaelahrens commented 1 month ago

Mhh I think it would be more useful to have a sperate tool which takes two repos and merges them into a single dotfile folder.

So the workflow could be to clone $WORK_REPO into $WORK and $PERSONAL_REPO into $PERSONAL.

The script should then create ~/.dotfiles by running

merge_dot "$WORK" "$PERSONAL"

This tool could then take care of all the issues which may happen and does not need changes to tuckr.

Which OSes do you use?

RaphGL commented 1 month ago

So the workflow could be to clone $WORK_REPO into $WORK and $PERSONAL_REPO into $PERSONAL.

Yeah this is not entirely a bad workaround. But you do lose git tracking for each repo doing this.

So I guess one possible workaround for that could be to symlink all groups of $WORK_REPO and $PERSONAL_REPO into .dotfiles/Configs and let tuckr continue working as it usually does.

I could make command for this that resolves conflicts with some name mangling like if there's a groupx in both dotfile directories I could do groupx_from_workdotfiles or something.

Some other possible solutions

  1. We could have a flag that changes the lookup path but this is slightly annoying from a user perspective

    $ tuckr -c ~/.config/dotfiles_work add \*
  2. We could create a profiles with file extensions dotfiles_* and have a ls-profiles command to know which ones are available This would also be easier to implement since I wouldn't have to change the entire symlink logic to accomodate it. There's a function called get_dotfiles_path with the following signature

fn get_dotfiles_path() -> Result<path::PathBuf, String>;

I think I can change it to

fn get_dotfiles_path(profile: Option<&str>) -> Result<PathBuf, String>;

and get the profiles stuff "for free".

As for usage it would be something like this

Defaults to None profile

$ tuckr status 

Using work profile

$ tuckr -p work status
RaphGL commented 1 month ago

I've just added profiles to tuckr using the CLI described on the last option

tuckr -p <profile> <command>

The profile name is whatever comes after an underscore, so dotfiles_work, dotfiles_some_long_name and can be used as such:

$ tuckr -p some_long_name add group1
$ tuckr -p work s

Since I've only implemented the core functionality here, I'll be improving error messages and adding and updating documentation on the README and wiki on https://github.com/RaphGL/Tuckr/issues/37