0

Is there any way I can create a link, that dynamically updates. My specific situation is, that I have multiple exercises (directories) and I want to link to the latest one:

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

so if I cd exercises/exercise_latest it always goes to the latest one. Adding a new directory exercise_04 would make the link point to that one instead.

The solutions I can come up with are:

  1. A cron job that runs once a minute and relinks if it detects a new directory.
  2. Not make it a link but a script that cds to the latest directory.
  3. Manually maintaining it

Neither solution is particularly elegant. 1. is really inefficient and potentially too slow. I cannot copy files into 2.. 3. defeats the purpose.

Versioned software releases do something similar. For example python3 always links to the latest Python 3 version. They however probably update every time a new version is installed.

Is there anything I can do that is more elegant than my ideas?

  • What about combining option 2 with creating another script that will copy files into the latest directory? That seems like the simplest and most robust solution. – davidmneedham Dec 10 '18 at 15:06
  • A fourth option is to incorporate the updating of exercise_latest into the creation of a new subdirectory, rather than trying to maintain it when you need to use it. – AFH Dec 10 '18 at 15:35
0

The way I solved this is creating a launchctl / launchd agent which can listen to files. This is macOS specific, but there are similar solutions for 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>

This executes a Python script (.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()

the LINK_ROOTS here contain all the files that are to be linked. All files matching matching a link root with an underscore and any numbers behind will match, the greatest one will be linked to the link root.

so if LINK_ROOTS = ['exercise'] the greatest one will be linked like this exercise -> exercise_04.

This is not a perfect solution, but it works quite reliably and is not super inefficient.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.