動的リンクディレクトリ

動的リンクディレクトリ

動的に更新されるリンクを作成する方法はありますか。私の具体的な状況としては、複数の演習 (ディレクトリ) があり、最新のものにリンクしたいというものです。

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

つまり、cd exercises/exercise_latest常に最新のものに移動します。新しいディレクトリを追加すると、exercise_04リンクは代わりにそのディレクトリを指すようになります。

私が思いつく解決策は次のとおりです。

  1. 1 分間に 1 回実行され、新しいディレクトリを検出すると再リンクする cron ジョブ。
  2. cdリンクではなく、最新のディレクトリに移動するスクリプトにします。
  3. 手動でメンテナンスする

どちらのソリューションも特にエレガントではありません。1.は非常に非効率的で、潜在的に遅すぎます。 にファイルをコピーできません2.3.目的に反します。

バージョン管理されたソフトウェア リリースも同様のことを行います。たとえば、python3常に最新の Python 3 バージョンにリンクします。ただし、新しいバージョンがインストールされるたびに更新される可能性があります。

私のアイデアよりもエレガントなことができるでしょうか?

答え1

これを解決した方法は、ファイルをリッスンできる launchctl / launchd エージェントを作成することです。これは macOS 固有ですが、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>

これは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()

ここLINK_ROOTSにはリンクされるすべてのファイルが含まれます。リンク ルートにアンダースコアと後ろの数字が一致するすべてのファイルが一致し、最大のものがリンク ルートにリンクされます。

それで、LINK_ROOTS = ['exercise']最も偉大なものはこのようにリンクされるでしょうexercise -> exercise_04

これは完璧な解決策ではありませんが、非常に信頼性が高く、非常に非効率的というわけではありません。

関連情報