pyinfra-dev / pyinfra-dev/pyinfra
files.link operation fails for hard link
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 6k
- Forks
- 548
- Avg merge
- 7d 17h
- Merged PRs (30d)
- 13
Description
Describe the bug
The files.link() operation checks if the path already exists is a symlink, but fails if the path is hardlinked.
To Reproduce
With the following deploy script "test-link.py":
from pyinfra.operations import files
files.file('/tmp/foo')
files.link('/tmp/foo-symlink', target='/tmp/foo')
files.link('/tmp/foo-hardlink', target='/tmp/foo', symbolic=False)
On the first run (clipped for brevity):
$ pyinfra @local test-link.py
...
--> Beginning operation run...
--> Starting operation: Files/File (/tmp/foo)
[@local] Success
--> Starting operation: Files/Link (/tmp/foo-symlink, target=/tmp/foo)
[@local] Success
--> Starting operation: Files/Link (/tmp/foo-hardlink, target=/tmp/foo, symbolic=False)
[@local] Success
On subsequent runs:
$ pyinfra @local test-link.py
...
--> Preparing Operations...
Loading: test-link.py
--> pyinfra error: /tmp/foo-hardlink exists and is not a link
Resultant generated output of initial deploy:
$ ls -li /tmp/foo*
673685 -rw-r--r-- 2 dt dt 0 Jan 23 18:21 /tmp/foo
673685 -rw-r--r-- 2 dt dt 0 Jan 23 18:21 /tmp/foo-hardlink
673686 lrwxrwxrwx 1 dt dt 8 Jan 23 18:21 /tmp/foo-symlink -> /tmp/foo
(note that the inode number of foo and foo-hardlink are the same, and the link count is two).
Expected behavior
The files.link() operation skips the hardlink creation as the path and target already exists, and are the same.
I started coding a fix for this, but it involves extending the amount of information returned by the file.File fact (adding inode, device id and nlink count to the stats, which would then be compared between path and target), but was unsure if this is the direction that Nick would want to go in.
Meta
- Include output of
pyinfra --support.
--> Support information:
If you are having issues with pyinfra or wish to make feature requests, please
check out the GitHub issues at https://github.com/Fizzadar/pyinfra/issues .
When adding an issue, be sure to include the following:
System: Linux
Platform: Linux-5.10.0-20-amd64-x86_64-with-glibc2.31
Release: 5.10.0-20-amd64
Machine: x86_64
pyinfra: v2.6.1
Executable: /home/dt/Work/pyinfra/pyinfra-git/venv/bin/pyinfra
Python: 3.9.2 (CPython, GCC 10.2.1 20210110)
- How was pyinfra installed (source/pip)?
- v2.6.1: git+venv+setup
- v2.6: pip+venv (issue occurs on both)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by inspecting the files.link operation and the file.File fact, using test-link.py to reproduce the first and subsequent runs. Check how existing symlinks are detected and how file metadata is exposed. Done means rerunning the script succeeds without error and an existing hard link to the target is left unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devops, infrastructure
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100