diff --git a/API.md b/API.md
index b33c663..706526b 100644
--- a/API.md
+++ b/API.md
@@ -56,6 +56,7 @@
- [`read-all-lines`](#babashka.fs/read-all-lines) - Read all lines from a file.
- [`read-attributes`](#babashka.fs/read-attributes) - Same as read-attributes*
but turns attributes into a map and keywordizes keys.
- [`read-attributes*`](#babashka.fs/read-attributes*) - Reads attributes via Files/readAttributes.
+ - [`read-link`](#babashka.fs/read-link) - Reads the target of a symbolic link.
- [`readable?`](#babashka.fs/readable?) - Returns true if f is readable.
- [`real-path`](#babashka.fs/real-path) - Converts f into real path via Path#toRealPath.
- [`regular-file?`](#babashka.fs/regular-file?) - Returns true if f is a regular file, using Files/isRegularFile.
@@ -152,7 +153,7 @@ Copies src file to dest dir or file.
* `:replace-existing`
* `:copy-attributes`
* `:nofollow-links` (used to determine to copy symbolic link itself or not).
-
Source
+Source
## `copy-tree`
``` clojure
@@ -164,7 +165,7 @@ Copies src file to dest dir or file.
Copies entire file tree from src to dest. Creates dest if needed
using [`create-dirs`](#babashka.fs/create-dirs), passing it the `:posix-file-permissions`
option. Supports same options as copy.
-Source
+Source
## `create-dir`
``` clojure
@@ -174,7 +175,7 @@ Copies entire file tree from src to dest. Creates dest if needed
```
Creates dir using `Files#createDirectory`. Does not create parents.
-Source
+Source
## `create-dirs`
``` clojure
@@ -185,7 +186,7 @@ Creates dir using `Files#createDirectory`. Does not create parents.
Creates directories using `Files#createDirectories`. Also creates parents if needed.
Doesn't throw an exception if the dirs exist already. Similar to `mkdir -p`
-Source
+Source
## `create-file`
``` clojure
@@ -198,7 +199,7 @@ Creates empty file using `Files#createFile`.
File permissions can be specified with an `:posix-file-permissions` option.
String format for posix file permissions is described in the [`str->posix`](#babashka.fs/str->posix) docstring.
-Source
+Source
## `create-link`
``` clojure
@@ -207,7 +208,7 @@ Creates empty file using `Files#createFile`.
```
Create a hard link from path to target.
-Source
+Source
## `create-sym-link`
``` clojure
@@ -216,7 +217,7 @@ Create a hard link from path to target.
```
Create a soft link from path to target.
-Source
+Source
## `create-temp-dir`
``` clojure
@@ -234,7 +235,7 @@ Creates a temporary directory using Files#createDirectories.
is generated. If path is not provided, the directory is created as if called with `(create-temp-dir)`.
File permissions can be specified with an `:posix-file-permissions` option.
String format for posix file permissions is described in the [`str->posix`](#babashka.fs/str->posix) docstring.
-Source
+Source
## `create-temp-file`
``` clojure
@@ -252,7 +253,7 @@ Creates an empty temporary file using Files#createTempFile.
random ones are generated.
File permissions can be specified with an `:posix-file-permissions` option.
String format for posix file permissions is described in the [`str->posix`](#babashka.fs/str->posix) docstring.
-Source
+Source
## `creation-time`
``` clojure
@@ -262,7 +263,7 @@ Creates an empty temporary file using Files#createTempFile.
```
Returns creation time as FileTime.
-Source
+Source
## `cwd`
``` clojure
@@ -271,7 +272,7 @@ Returns creation time as FileTime.
```
Returns current working directory as path
-Source
+Source
## `delete`
``` clojure
@@ -281,7 +282,7 @@ Returns current working directory as path
Deletes f. Returns nil if the delete was successful,
throws otherwise. Does not follow symlinks.
-Source
+Source
## `delete-if-exists`
``` clojure
@@ -291,7 +292,7 @@ Deletes f. Returns nil if the delete was successful,
Deletes f if it exists. Returns true if the delete was successful,
false if f didn't exist. Does not follow symlinks.
-Source
+Source
## `delete-on-exit`
``` clojure
@@ -300,7 +301,7 @@ Deletes f if it exists. Returns true if the delete was successful,
```
Requests delete on exit via `File#deleteOnExit`. Returns f.
-Source
+Source
## `delete-tree`
``` clojure
@@ -311,7 +312,7 @@ Requests delete on exit via `File#deleteOnExit`. Returns f.
Deletes a file tree using [`walk-file-tree`](#babashka.fs/walk-file-tree). Similar to `rm -rf`. Does not follow symlinks.
`force` ensures read-only directories/files are deleted. Similar to `chmod -R +wx` + `rm -rf`
-Source
+Source
## `directory?`
``` clojure
@@ -330,7 +331,7 @@ Returns true if f is a directory, using Files/isDirectory.
```
Returns true if path this ends with path other.
-Source
+Source
## `exec-paths`
``` clojure
@@ -340,7 +341,7 @@ Returns true if path this ends with path other.
Returns executable paths (using the PATH environment variable). Same
as `(split-paths (System/getenv "PATH"))`.
-Source
+Source
## `executable?`
``` clojure
@@ -374,7 +375,7 @@ If [[`path`](#babashka.fs/path)](#babashka.fs/path) begins with a tilde (`~`), e
directory. This is (naively) assumed to be a directory with the same
name as the user relative to the parent of the current value of
`user.home`.
-Source
+Source
## `extension`
``` clojure
@@ -383,7 +384,7 @@ If [[`path`](#babashka.fs/path)](#babashka.fs/path) begins with a tilde (`~`), e
```
Returns the extension of a file via [`split-ext`](#babashka.fs/split-ext).
-Source
+Source
## `file`
``` clojure
@@ -418,7 +419,7 @@ Returns the name of the file or directory. E.g. (file-name "foo/bar/baz") return
```
Converts a java.nio.file.attribute.FileTime to a java.time.Instant.
-Source
+Source
## `file-time->millis`
``` clojure
@@ -427,7 +428,7 @@ Converts a java.nio.file.attribute.FileTime to a java.time.Instant.
```
Converts a java.nio.file.attribute.FileTime to epoch millis (long).
-Source
+Source
## `get-attribute`
``` clojure
@@ -435,7 +436,7 @@ Converts a java.nio.file.attribute.FileTime to epoch millis (long).
(get-attribute path attribute)
(get-attribute path attribute {:keys [:nofollow-links]})
```
-Source
+Source
## `glob`
``` clojure
@@ -456,10 +457,11 @@ Given a file and glob pattern, returns matches as vector of
* `:hidden` - match hidden paths. Implied when `pattern` starts with a dot. Note: on Windows files starting with a dot are not hidden, unless their hidden attribute is set.
* `:follow-links` - follow symlinks.
* `:recursive` - force recursive search. Implied when `pattern` contains `**` or `/`.
+ * `:max-depth` - max depth to descend into directory structure.
Examples:
`(fs/glob "." "**.clj")`
-Source
+Source
## `gunzip`
``` clojure
@@ -473,7 +475,7 @@ Extracts `gz-file` to `dest` directory (default `"."`).
Options:
* `:replace-existing` - `true` / `false`: overwrite existing files
-Source
+Source
## `gzip`
``` clojure
@@ -486,7 +488,7 @@ Gzips `source-file` and writes the output to `dir/out-file`.
If `out-file` is not provided, the `source-file` name with `.gz` appended is used.
If `dir` is not provided, the current directory is used.
Returns the created gzip file.
-Source
+Source
## `hidden?`
``` clojure
@@ -507,7 +509,7 @@ Returns true if f is hidden.
With no arguments, returns the current value of the `user.home`
system property. If a `user` is passed, returns that user's home
directory as found in the parent of home with no args.
-Source
+Source
## `instant->file-time`
``` clojure
@@ -516,7 +518,7 @@ With no arguments, returns the current value of the `user.home`
```
Converts a java.time.Instant to a java.nio.file.attribute.FileTime.
-Source
+Source
## `last-modified-time`
``` clojure
@@ -526,7 +528,7 @@ Converts a java.time.Instant to a java.nio.file.attribute.FileTime.
```
Returns last modified time as a java.nio.file.attribute.FileTime.
-Source
+Source
## `list-dir`
``` clojure
@@ -547,7 +549,7 @@ Returns all paths in dir as vector. For descending into subdirectories use `glob
Similar to list-dir but accepts multiple roots and returns the concatenated results.
- `glob-or-accept` - a glob string such as "*.edn" or a (fn accept [^java.nio.file.Path p]) -> truthy
-Source
+Source
## `match`
``` clojure
@@ -579,7 +581,7 @@ Given a file and match pattern, returns matches as vector of
```
Converts epoch millis (long) to a java.nio.file.attribute.FileTime.
-Source
+Source
## `modified-since`
``` clojure
@@ -593,7 +595,7 @@ Returns seq of regular files (non-directories, non-symlinks) from file-set that
to compare with. The file-set may be a regular file, directory or
collection of files (e.g. returned by glob). Directories are
searched recursively.
-Source
+Source
## `move`
``` clojure
@@ -603,7 +605,7 @@ Returns seq of regular files (non-directories, non-symlinks) from file-set that
```
Move or rename a file to a target dir or file via `Files/move`.
-Source
+Source
## `normalize`
``` clojure
@@ -632,7 +634,7 @@ Returns the owner of a file. Call `str` on it to get the owner name
```
Returns parent of f. Akin to `dirname` in bash.
-Source
+Source
## `path`
``` clojure
@@ -659,13 +661,13 @@ Coerces f into a Path. Multiple-arg versions treat the first argument as
```
Converts a set of PosixFilePermission to a string.
-Source
+Source
## `posix-file-permissions`
-Source
+Source
## `read-all-bytes`
``` clojure
@@ -674,7 +676,7 @@ Converts a set of PosixFilePermission to a string.
```
Returns contents of file as byte array.
-Source
+Source
## `read-all-lines`
``` clojure
@@ -684,7 +686,7 @@ Returns contents of file as byte array.
```
Read all lines from a file.
-Source
+Source
## `read-attributes`
``` clojure
@@ -695,7 +697,7 @@ Read all lines from a file.
Same as [`read-attributes*`](#babashka.fs/read-attributes*) but turns attributes into a map and keywordizes keys.
Keywordizing can be changed by passing a :key-fn in the options map.
-Source
+Source
## `read-attributes*`
``` clojure
@@ -705,7 +707,16 @@ Same as [`read-attributes*`](#babashka.fs/read-attributes*) but turns attributes
```
Reads attributes via Files/readAttributes.
-Source
+Source
+
+## `read-link`
+``` clojure
+
+(read-link path)
+```
+
+Reads the target of a symbolic link. The target need not exist.
+Source
## `readable?`
``` clojure
@@ -761,7 +772,7 @@ Returns relative path by comparing this with other.
```
Returns true if this is the same file as other.
-Source
+Source
## `set-attribute`
``` clojure
@@ -769,7 +780,7 @@ Returns true if this is the same file as other.
(set-attribute path attribute value)
(set-attribute path attribute value {:keys [:nofollow-links]})
```
-Source
+Source
## `set-creation-time`
``` clojure
@@ -779,7 +790,7 @@ Returns true if this is the same file as other.
```
Sets creation time of f to time (millis, java.time.Instant or java.nio.file.attribute.FileTime).
-Source
+Source
## `set-last-modified-time`
``` clojure
@@ -789,13 +800,13 @@ Sets creation time of f to time (millis, java.time.Instant or java.nio.file.attr
```
Sets last modified time of f to time (millis, java.time.Instant or java.nio.file.attribute.FileTime).
-Source
+Source
## `set-posix-file-permissions`
-Source
+Source
## `size`
``` clojure
@@ -804,7 +815,7 @@ Sets last modified time of f to time (millis, java.time.Instant or java.nio.file
```
Returns the size of a file (in bytes).
-Source
+Source
## `split-ext`
``` clojure
@@ -816,7 +827,7 @@ Returns the size of a file (in bytes).
Splits path on extension If provided, a specific extension `ext`, the
extension (without dot), will be used for splitting. Directories
are not processed.
-Source
+Source
## `split-paths`
``` clojure
@@ -826,7 +837,7 @@ Splits path on extension If provided, a specific extension `ext`, the
Splits a path list given as a string joined by the OS-specific path-separator into a vec of paths.
On UNIX systems, the separator is ':', on Microsoft Windows systems it is ';'.
-Source
+Source
## `starts-with?`
``` clojure
@@ -835,7 +846,7 @@ Splits a path list given as a string joined by the OS-specific path-separator in
```
Returns true if path this starts with path other.
-Source
+Source
## `str->posix`
``` clojure
@@ -846,7 +857,7 @@ Returns true if path this starts with path other.
Converts a string to a set of PosixFilePermission.
`s` is a string like `"rwx------"`.
-Source
+Source
## `strip-ext`
``` clojure
@@ -856,7 +867,7 @@ Converts a string to a set of PosixFilePermission.
```
Strips extension via [`split-ext`](#babashka.fs/split-ext).
-Source
+Source
## `sym-link?`
``` clojure
@@ -865,7 +876,7 @@ Strips extension via [`split-ext`](#babashka.fs/split-ext).
```
Determines if `f` is a symbolic link via `java.nio.file.Files/isSymbolicLink`.
-Source
+Source
## `temp-dir`
``` clojure
@@ -874,7 +885,7 @@ Determines if `f` is a symbolic link via `java.nio.file.Files/isSymbolicLink`.
```
Returns `java.io.tmpdir` property as path.
-Source
+Source
## `unixify`
``` clojure
@@ -883,7 +894,7 @@ Returns `java.io.tmpdir` property as path.
```
Returns path as string with Unix-style file separators (`/`).
-Source
+Source
## `unzip`
``` clojure
@@ -897,7 +908,7 @@ Unzips `zip-file` to `dest` directory (default `"."`).
Options:
* `:replace-existing` - `true` / `false`: overwrite existing files
-Source
+Source
## `update-file`
``` clojure
@@ -912,7 +923,7 @@ Updates the contents of text file [`path`](#babashka.fs/path) using `f` applied
Options:
* `:charset` - charset of file, default to "utf-8"
-Source
+Source
## `walk-file-tree`
``` clojure
@@ -944,7 +955,7 @@ Returns Path to first executable `program` found in `:paths` `opt`, similar to t
When `program` is a relative or absolute path, `:paths` is not consulted. On Windows, the `:win-exts`
variants are still searched. On other OSes, the path for `program` will be returned if executable,
else nil.
-Source
+Source
## `which-all`
``` clojure
@@ -954,7 +965,7 @@ Returns Path to first executable `program` found in `:paths` `opt`, similar to t
```
Returns every Path to `program` found in ([`exec-paths`](#babashka.fs/exec-paths)). See [`which`](#babashka.fs/which).
-Source
+Source
## `windows?`
``` clojure
@@ -963,7 +974,7 @@ Returns every Path to `program` found in ([`exec-paths`](#babashka.fs/exec-paths
```
Returns true if OS is Windows.
-Source
+Source
## `with-temp-dir`
``` clojure
@@ -978,7 +989,7 @@ Evaluate body with binding-name bound to a temporary directory.
and will be removed with [`delete-tree`](#babashka.fs/delete-tree) on exit from the scope.
`options` is a map with the keys as for create-temp-dir.
-Source
+Source
## `writable?`
``` clojure
@@ -1010,7 +1021,7 @@ Writes `bytes` to [`path`](#babashka.fs/path) via `java.nio.file.Files/write`.
(fs/write-bytes f (.getBytes (String. "foo"))) ;; overwrites + truncates or creates new file
(fs/write-bytes f (.getBytes (String. "foo")) {:append true})
```
-Source
+Source
## `write-lines`
``` clojure
@@ -1030,7 +1041,7 @@ Writes `lines`, a seqable of strings to [`path`](#babashka.fs/path) via `java.ni
* `:write` (default `true`)
* `:append` (default `false`)
* or any `java.nio.file.StandardOption`.
-Source
+Source
## `xdg-cache-home`
``` clojure
@@ -1043,7 +1054,7 @@ Path representing the base directory relative to which user-specific non-essenti
Returns path based on the value of env-var `XDG_CACHE_HOME` (if set and representing an absolute path), else `(fs/path (fs/home) ".cache")`.
When provided, appends `app` to the path.
-Source
+Source
## `xdg-config-home`
``` clojure
@@ -1056,7 +1067,7 @@ Path representing the base directory relative to which user-specific configurati
Returns path based on the value of env-var `XDG_CONFIG_HOME` (if set and representing an absolute path), else `(fs/path (fs/home) ".config")`.
When provided, appends `app` to the path.
-Source
+Source
## `xdg-data-home`
``` clojure
@@ -1069,7 +1080,7 @@ Path representing the base directory relative to which user-specific data files
Returns path based on the value of env-var `XDG_DATA_HOME` (if set and representing an absolute path), else `(fs/path (fs/home) ".local" "share")`.
When provided, appends `app` to the path.
-Source
+Source
## `xdg-state-home`
``` clojure
@@ -1082,7 +1093,7 @@ Path representing the base directory relative to which user-specific state files
Returns path based on the value of env-var `XDG_STATE_HOME` (if set and representing an absolute path), else `(fs/path (fs/home) ".local" "state")`.
When provided, appends `app` to the path.
-Source
+Source
## `zip`
``` clojure
@@ -1099,4 +1110,4 @@ Zips entry or entries into zip-file. An entry may be a file or
* `:root`: directory which will be elided in zip. E.g.: `(fs/zip ["src"] {:root "src"})`
* `:path-fn`: a single-arg function from file system path to zip entry path.
-Source
+Source
diff --git a/src/babashka/fs.cljc b/src/babashka/fs.cljc
index 399d589..790ec73 100644
--- a/src/babashka/fs.cljc
+++ b/src/babashka/fs.cljc
@@ -579,6 +579,11 @@
(as-path path)
(as-path target)))
+(defn read-link
+ "Reads the target of a symbolic link. The target need not exist."
+ [path]
+ (java.nio.file.Files/readSymbolicLink (as-path path)))
+
(defn delete
"Deletes f. Returns nil if the delete was successful,
throws otherwise. Does not follow symlinks."
diff --git a/test/babashka/fs_test.clj b/test/babashka/fs_test.clj
index 5f85da7..a3fe372 100644
--- a/test/babashka/fs_test.clj
+++ b/test/babashka/fs_test.clj
@@ -63,7 +63,9 @@
(let [tmp-dir1 (temp-dir)
_ (spit (fs/file tmp-dir1 "dude.txt") "contents")
tmp-dir2 (temp-dir)
- sym-link (fs/create-sym-link (fs/file tmp-dir2 "sym-link") tmp-dir1)]
+ sym-link (fs/create-sym-link (fs/file tmp-dir2 "sym-link") tmp-dir1)
+ target (fs/read-link sym-link)]
+ (is (= (str target) (str tmp-dir1)))
(is (empty? (fs/match sym-link "regex:.*")))
(is (= 1 (count (fs/match sym-link "regex:.*" {:follow-links true}))))
(is (= 1 (count (fs/match (fs/real-path sym-link) "regex:.*")))))))