Diretórios de links dinâmicos

Diretórios de links dinâmicos

Existe alguma maneira de criar um link que seja atualizado dinamicamente. Minha situação específica é que tenho vários exercícios (diretórios) e quero vincular ao mais recente:

exercises/
│   exercise_01/
│   │    files ...
│   exercise_02/
│   │    files ...
│   exercise_03/
│   │    files ...
│   exercise_latest/ -> exercise_03/

então se eu cd exercises/exercise_latestsempre for para o mais recente. Adicionar um novo diretório exercise_04faria com que o link apontasse para aquele.

As soluções que posso encontrar são:

  1. Um cron job que é executado uma vez por minuto e é vinculado novamente se detectar um novo diretório.
  2. Não faça dele um link, mas um script que cdleva ao diretório mais recente.
  3. Mantendo-o manualmente

Nenhuma das soluções é particularmente elegante. 1.é realmente ineficiente e potencialmente muito lento. Não consigo copiar arquivos para 2.. 3.derrota o propósito.

As versões de software versionadas fazem algo semelhante. Por exemplo, python3sempre há links para a versão mais recente do Python 3. No entanto, eles provavelmente são atualizados sempre que uma nova versão é instalada.

Existe algo que eu possa fazer que seja mais elegante do que minhas ideias?

Responder1

A maneira como resolvi isso foi criando um agente launchctl/launchd que pode ouvir arquivos. Isso é específico do macOS, mas existem soluções semelhantes para Linux.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.me.exercise_listener.plist</string>

    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/python3</string>
        <string>/path/to/exercises/.ln_monitor.py</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/path/to/exercises/</string>
    </array>
    <key>StandardOutPath</key>
    <string>/path/to/exercises/.ln_monitor.log</string>
    <key>StandardErrorPath</key>
    <string>/path/to/exercises/.ln_monitor.log</string>
</dict>
</plist>

Isso executa um script Python ( .ln_monitor.py)

#!/usr/bin/env python3

import os
import re
from pathlib import Path
import time


DIR = Path(os.path.dirname(os.path.realpath(__file__)))
LINK_ROOTS = ['exercise']
VERBOSE = True


def cprint(*args):
    if VERBOSE:
        print(*args)


def main():
    for root in LINK_ROOTS:
        regex = r'^' + root + r'_\d+$'
        matches = [
            directory for directory in DIR.iterdir()
            if directory.is_dir() and
            re.match(regex, directory.name)]
        match_link = DIR / root
        if matches:
            match = sorted(matches)[-1]
            cprint(f'link to {match.name}')
            if match_link.is_symlink():
                if match_link.resolve() == match:
                    cprint('is already linked')
                    continue
                match_link.unlink()
                cprint('unlinking')
                time.sleep(0.5)
            else:
                cprint('no link yet')
            match_link.symlink_to(match)
            cprint('linked')


if __name__ == '__main__':
    main()

aqui LINK_ROOTScontém todos os arquivos que devem ser vinculados. Todos os arquivos correspondentes a uma raiz de link com um sublinhado e quaisquer números atrás corresponderão, o maior deles será vinculado à raiz do link.

então se LINK_ROOTS = ['exercise']o maior deles estiver vinculado assim exercise -> exercise_04.

Esta não é uma solução perfeita, mas funciona de forma bastante confiável e não é superineficiente.

informação relacionada