Skip to content

Commit

Permalink
convert the NIOFileSystem example code to a Snippet (#2746)
Browse files Browse the repository at this point in the history
* convert the NIOFileSystem example code to a Snippet

* fix compilation error

* add missing license header

* exclude snippets from soundness.sh
  • Loading branch information
tayloraswift authored Jun 21, 2024
1 parent e5a216b commit 38f6b98
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 97 deletions.
97 changes: 97 additions & 0 deletions Snippets/NIOFileSystemTour.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// snippet.hide
import _NIOFileSystem
import NIOCore
// snippet.show

// NIOFileSystem provides access to the local file system via the FileSystem
// type which is available as a global shared instance.
let fileSystem = FileSystem.shared

// Files can be inspected by using 'info':
if let info = try await fileSystem.info(forFileAt: "/Users/hal9000/demise-of-dave.txt") {
print("demise-of-dave.txt has type '\(info.type)'")
} else {
print("demise-of-dave.txt doesn't exist")
}

// Let's find out what's in that file.
do {
// Reading a whole file requires a limit. If the file is larger than the limit
// then an error is thrown. This avoids accidentally consuming too much memory
// if the file is larger than expected.
let plan = try await ByteBuffer(
contentsOf: "/Users/hal9000/demise-of-dave.txt",
maximumSizeAllowed: .mebibytes(1)
)
print("Plan for Dave's demise:", String(decoding: plan.readableBytesView, as: UTF8.self))
} catch let error as FileSystemError where error.code == .notFound {
// All errors thrown by the module have type FileSystemError (or
// Swift.CancellationError). It looks like the file doesn't exist. Let's
// create it now.
//
// The code above for reading the file is shorthand for opening the file in
// read-only mode and then reading its contents. The FileSystemProtocol
// has a few different 'withFileHandle' methods for opening a file in different
// modes. Let's open a file for writing, creating it at the same time.
try await fileSystem.withFileHandle(
forWritingAt: "/Users/hal9000/demise-of-dave.txt",
options: .newFile(replaceExisting: false)
) { file in
let plan = ByteBuffer(string: "TODO...")
try await file.write(contentsOf: plan.readableBytesView, toAbsoluteOffset: 0)
}
}

// Directories can be opened like regular files but they cannot be read from or
// written to. However, their contents can be listed:
let path: FilePath? = try await fileSystem.withDirectoryHandle(atPath: "/Users/hal9000/Music") { directory in
for try await entry in directory.listContents() {
if entry.name.extension == "mp3", entry.name.stem.contains("daisy") {
// Found it!
return entry.path
}
}
// No luck.
return nil
}

if let path = path {
print("Found file at '\(path)'")
}

// The file system can also be used to perform the following operations on files
// and directories:
// - copy,
// - remove,
// - rename, and
// - replace.
//
// Here's an example of copying a directory:
try await fileSystem.copyItem(at: "/Users/hal9000/Music", to: "/Volumes/Tardis/Music")

// Symbolic links can also be created (and read with 'destinationOfSymbolicLink(at:)').
try await fileSystem.createSymbolicLink(at: "/Users/hal9000/Backup", withDestination: "/Volumes/Tardis")

// Opening a symbolic link opens its destination so in most cases there's no
// need to read the destination of a symbolic link:
try await fileSystem.withDirectoryHandle(atPath: "/Users/hal9000/Backup") { directory in
// Beyond listing the contents of a directory, the directory handle provides a
// number of other functions, many of which are also available on regular file
// handles.
//
// This includes getting information about a file, such as its permissions, last access time,
// and last modification time:
let info = try await directory.info()
print("The directory has permissions '\(info.permissions)'")

// Where supported, the extended attributes of a file can also be accessed, read, and modified:
for attribute in try await directory.attributeNames() {
let value = try await directory.valueForAttribute(attribute)
print("Extended attribute '\(attribute)' has value '\(value)'")
}

// Once this closure returns the file system will close the directory handle freeing
// any resources required to access it such as file descriptors. Handles can also be opened
// with the 'openFile' and 'openDirectory' APIs but that places the onus you to close the
// handle at an appropriate time to avoid leaking resources.
}
97 changes: 1 addition & 96 deletions Sources/NIOFileSystem/Docs.docc/NIOFileSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,102 +23,7 @@ to a set of protocols for creating other file system implementations.

The following sample code demonstrates a number of the APIs offered by this module:

```swift
import _NIOFileSystem

// NIOFileSystem provides access to the local file system via the FileSystem
// type which is available as a global shared instance.
let fileSystem = FileSystem.shared

// Files can be inspected by using 'info':
if let info = try await fileSystem.info(forFileAt: "/Users/hal9000/demise-of-dave.txt") {
print("demise-of-dave.txt has type '\(info.type)'")
} else {
print("demise-of-dave.txt doesn't exist")
}

// Let's find out what's in that file.
do {
// Reading a whole file requires a limit. If the file is larger than the limit
// then an error is thrown. This avoids accidentally consuming too much memory
// if the file is larger than expected.
let plan = try await ByteBuffer(
contentsOf: "/Users/hal9000/demise-of-dave.txt",
maximumSizeAllowed: .mebibytes(1)
)
print("Plan for Dave's demise:", String(decoding: plan, as: UTF8.self))
} catch let error as FileSystemError where error.code == .notFound {
// All errors thrown by the module have type FileSystemError (or
// Swift.CancellationError). It looks like the file doesn't exist. Let's
// create it now.
//
// The code above for reading the file is shorthand for opening the file in
// read-only mode and then reading its contents. The FileSystemProtocol
// has a few different 'withFileHandle' methods for opening a file in different
// modes. Let's open a file for writing, creating it at the same time.
try await fileSystem.withFileHandle(
forWritingAt: "/Users/hal9000/demise-of-dave.txt",
options: .newFile(replaceExisting: false)
) { file in
let plan = ByteBuffer(string: "TODO...")
try await file.write(contentsOf: plan.readableBytesView, toAbsoluteOffset: 0)
}
}

// Directories can be opened like regular files but they cannot be read from or
// written to. However, their contents can be listed:
let path: FilePath? = try await fileSystem.withDirectoryHandle(atPath: "/Users/hal9000/Music") { directory in
for try await entry in directory.listContents() {
if entry.name.extension == "mp3", entry.name.stem.contains("daisy") {
// Found it!
return entry.path
}
}
// No luck.
return nil
}

if let path = path {
print("Found file at '\(path)'")
}

// The file system can also be used to perform the following operations on files
// and directories:
// - copy,
// - remove,
// - rename, and
// - replace.
//
// Here's an example of copying a directory:
try await fileSystem.copyItem(at: "/Users/hal9000/Music", to: "/Volumes/Tardis/Music")

// Symbolic links can also be created (and read with 'destinationOfSymbolicLink(at:)').
try await fileSystem.createSymbolicLink(at: "/Users/hal9000/Backup", withDestination: "/Volumes/Tardis")

// Opening a symbolic link opens its destination so in most cases there's no
// need to read the destination of a symbolic link:
try await fileSystem.withDirectoryHandle(atPath: "/Users/hal9000/Backup") { directory in
// Beyond listing the contents of a directory, the directory handle provides a
// number of other functions, many of which are also available on regular file
// handles.
//
// This includes getting information about a file, such as its permissions, last access time,
// and last modification time:
let info = try await directory.info()
print("The directory has permissions '\(info.permissions)'")

// Where supported, the extended attributes of a file can also be accessed, read, and modified:
for attribute in try await directory.attributeNames() {
let value = try await directory.valueForAttribute(attribute)
print("Extended attribute '\(attribute)' has value '\(value)'")
}

// Once this closure returns the file system will close the directory handle freeing
// any resources required to access it such as file descriptors. Handles can also be opened
// with the 'openFile' and 'openDirectory' APIs but that places the onus you to close the
// handle at an appropriate time to avoid leaking resources.
}
```
@Snippet(path: "swift-nio/Snippets/NIOFileSystemTour")

In depth documentation can be found in the following sections.

Expand Down
2 changes: 1 addition & 1 deletion scripts/soundness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ for language in swift-or-c bash dtrace python; do
matching_files=( -name '*' )
case "$language" in
swift-or-c)
exceptions=( -name c_nio_llhttp.c -o -name c_nio_api.c -o -name c_nio_http.c -o -name c_nio_llhttp.h -o -name cpp_magic.h -o -name Package.swift -o -name 'Package@*.swift' -o -name CNIOSHA1.h -o -name c_nio_sha1.c -o -name ifaddrs-android.c -o -name ifaddrs-android.h)
exceptions=( -name c_nio_llhttp.c -o -name c_nio_api.c -o -name c_nio_http.c -o -name c_nio_llhttp.h -o -name cpp_magic.h -o -name Package.swift -o -name 'Package@*.swift' -o -path './Snippets/*' -o -name CNIOSHA1.h -o -name c_nio_sha1.c -o -name ifaddrs-android.c -o -name ifaddrs-android.h)
matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' )
cat > "$tmp" <<"EOF"
//===----------------------------------------------------------------------===//
Expand Down

0 comments on commit 38f6b98

Please sign in to comment.