denoland / std

The Deno Standard Library
https://jsr.io/@std
MIT License
3.2k stars 620 forks source link

fs.ensureSymlink does not work! #6191

Open amir-reza-bijandi opened 1 day ago

amir-reza-bijandi commented 1 day ago

Describe the bug ensureSymlink method does not work! Well... Mostly... I'm new to using Deno and it's std library and I was trying out @std/fs and that's when I encountered an error with my very basic code...

await fs.ensureSymlink("./dir/test.txt", "./dir/test.link.txt");

Error:

error: Uncaught (in promise) NotFound: No such file or directory (os error 2): lstat '/home/arb/Programming/Javascript/Practice/deno-hello-world/dir/dir/test.txt'
  const srcStatInfo = await Deno.lstat(targetRealPath);
                      ^
    at async Object.lstat (ext:deno_fs/30_fs.js:397:15)
    at async Module.ensureSymlink (https://jsr.io/@std/fs/1.0.5/ensure_symlink.ts:56:23)
    at async file:///home/arb/Programming/Javascript/Practice/deno-hello-world/main.ts:6:1

As you can see the target file exists and i'm trying to create the symlink inside the same directory as the target file: Screenshot From 2024-11-17 21-38-41

I tried removing the ./ from the paths, but it didn't work, and I got the same error again. The funny part is that if the target file and the path for creating symlink are both at the root of the working directory, The method work! So this line of code works with no problem:

await fs.ensureSymlink("test.txt", "test.link.txt");

One more thing that i tried that also did not work was this:

await fs.ensureSymlink("test.txt", "new-dir/test.link.txt");

I even made the new-dir directory myself but i still got the same error.

Steps to Reproduce

I'm not doing anything special!

  1. Create a new project using deno init
  2. Change content of main.ts to this:
    
    import * as fs from "@std/fs";

await fs.ensureSymlink("./dir/test.txt", "./dir/test.link.txt");


3. Create a file with this path: `./dir/test.txt`

**Expected behavior**

Creating a new symlink?

**Environment**

- OS: Fedora 41
- deno version: 2.0.6 (Stable)
- std version: @std/fs 1.0.5
kt3k commented 1 day ago

It looks like the first argument needs to be a relative path from link's path to target. If I modified the main.ts like the below, it worked:

import * as fs from "@std/fs";
await fs.ensureSymlink("./test.txt", "./dir/test.link.txt");
$ tree dir 
dir
├── test.link.txt -> ./test.txt
└── test.txt

1 directory, 2 files

I agree this is not clear from the documentation. I think we need to update the parameter document to make this clear.

amir-reza-bijandi commented 1 day ago

I agree this is not clear from the documentation. I think we need to update the parameter document to make this clear.

I don't think this is a documentation issue. The reason for that is that it just doesn't make any sense. Just think about it, Deno.symlink and fs.ensureLink do not have this issue and do not need a relative relation between two paths, so why would fs.ensureSymlink behave this way?

Even after seeing your solution and testing it, it just doesn't click in my head... I get it... but it always takes a second to process what the hell is going on...

kt3k commented 1 hour ago

I checked how Deno.symlink works, and it looks like working as the same way as fs.ensureSymlink:

When you have file in this way:

$ tree dir 
dir
└── file.txt

and you'd like to create a symlink dir/link.txt pointing dir/file.txt, then you need to call Deno.symlink like:

await Deno.symlink("file.txt", "dir/link.txt");

and the below doesn't work (the below script creates a broken symlink):

await Deno.symlink("dir/file.txt", "dir/link.txt");

I think this behavior comes from how ln -s command works. If you like to achieve the same as ln -s, you need to call:

ln -s file.txt dir/link.txt

and the below creates a broken link:

ln -s dir/file.txt dir/link.txt