Package jenkins.util

Class VirtualFile

java.lang.Object
jenkins.util.VirtualFile
All Implemented Interfaces:
Serializable, Comparable<VirtualFile>

public abstract class VirtualFile extends Object implements Comparable<VirtualFile>, Serializable
Abstraction over File, FilePath, or other items such as network resources or ZIP entries. Assumed to be read-only and makes very limited assumptions, just enough to display content and traverse directories.

To obtain a VirtualFile representation for an existing file, use forFile(File) or FilePath.toVirtualFile()

How are VirtualFile and FilePath different?

FilePath abstracts away Files on machines that are connected over Channel, whereas VirtualFile makes no assumption about where the actual files are, or whether there really exists Files somewhere. This makes VirtualFile more abstract.

Opening files from other machines

While VirtualFile is marked Serializable, it is not safe in general to transfer over a Remoting channel. (For example, an implementation from forFilePath(hudson.FilePath) could be sent on the same channel, but an implementation from forFile(java.io.File) will not.) Thus callers should assume that methods such as open() will work only on the node on which the object was created.

Since some implementations may in fact use external file storage, callers may request optional APIs to access those services more efficiently. Otherwise, for example, a plugin copying a file previously saved by ArtifactManager to an external storage service which tunneled a stream from open() using RemoteInputStream would wind up transferring the file from the service to the Jenkins master and then on to an agent. Similarly, if DirectoryBrowserSupport rendered a link to an in-Jenkins URL, a large file could be transferred from the service to the Jenkins master and then on to the browser. To avoid this overhead, callers may check whether an implementation supports toExternalURL().

Since:
1.532
See Also:
  • Constructor Details

    • VirtualFile

      public VirtualFile()
  • Method Details

    • getName

      @NonNull public abstract String getName()
      Gets the base name, meaning just the last portion of the path name without any directories. For a “root directory” this may be the empty string.
      Returns:
      a simple name (no slashes)
    • toURI

      @NonNull public abstract URI toURI()
      Gets a URI. Should at least uniquely identify this virtual file within its root, but not necessarily globally.

      When toExternalURL() is implemented, that same value could be used here, unless some sort of authentication is also embedded.

      Returns:
      a URI (need not be absolute)
    • getParent

      public abstract VirtualFile getParent()
      Gets the parent file. Need only operate within the originally given root.
      Returns:
      the parent
    • isDirectory

      public abstract boolean isDirectory() throws IOException
      Checks whether this file exists and is a directory.
      Returns:
      true if it is a directory, false if a file or nonexistent
      Throws:
      IOException - in case checking status failed
    • isFile

      public abstract boolean isFile() throws IOException
      Checks whether this file exists and is a plain file.
      Returns:
      true if it is a file, false if a directory or nonexistent
      Throws:
      IOException - in case checking status failed
    • readLink

      @CheckForNull public String readLink() throws IOException
      If this file is a symlink, returns the link target.

      The default implementation always returns null. Some implementations may not support symlinks under any conditions.

      Returns:
      a target (typically a relative path in some format), or null if this is not a link
      Throws:
      IOException - if reading the link, or even determining whether this file is a link, failed
      Since:
      2.118
    • exists

      public abstract boolean exists() throws IOException
      Checks whether this file exists. The behavior is undefined for symlinks; if in doubt, check readLink() first.
      Returns:
      true if it is a plain file or directory, false if nonexistent
      Throws:
      IOException - in case checking status failed
    • list

      @NonNull public abstract VirtualFile[] list() throws IOException
      Lists children of this directory. Only one level deep.
      Returns:
      a list of children (files and subdirectories); empty for a file or nonexistent directory
      Throws:
      IOException - if this directory exists but listing was not possible for some other reason
    • list

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) @NonNull public VirtualFile[] list(OpenOption... openOptions) throws IOException
      Lists children of this directory. Only one level deep. This is intended to allow the caller to provide LinkOption.NOFOLLOW_LINKS to ignore symlinks. However, this cannot be enforced. The base implementation here in VirtualFile ignores the openOptions. Some VirtualFile subclasses may not be able to provide an implementation in which NOFOLLOW_LINKS is used or makes sense. Implementations are free to ignore openOptions. Some subclasses of VirtualFile may not have a concept of symlinks.
      Parameters:
      openOptions - the options to apply when opening.
      Returns:
      a list of children (files and subdirectories); empty for a file or nonexistent directory
      Throws:
      IOException - if it could not be opened
    • supportsQuickRecursiveListing

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public boolean supportsQuickRecursiveListing()
    • hasSymlink

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public boolean hasSymlink(OpenOption... openOptions) throws IOException
      Determines when a VirtualFile has a recognized symlink. A recognized symlink can be the file itself or any containing directory between it and the optional root directory. If there is no provided root directory then only the file itself is considered. This base implementation ignores the existence of symlinks.
      Parameters:
      openOptions - the various open options to apply to the operation.
      Returns:
      True if the file is a symlink or is referenced within a containing symlink. directory before reaching the root directory.
      Throws:
      IOException - If there is a problem accessing the file.
    • listOnlyDescendants

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) @NonNull public List<VirtualFile> listOnlyDescendants() throws IOException
      Lists only the children that are descendant of the root directory (not necessarily the current VirtualFile). Only one level deep.
      Returns:
      a list of descendant children (files and subdirectories); empty for a file or nonexistent directory
      Throws:
      IOException - if this directory exists but listing was not possible for some other reason
    • list

      @Deprecated @NonNull public String[] list(String glob) throws IOException
      Deprecated.
      Throws:
      IOException
    • list

      @NonNull public Collection<String> list(@NonNull String includes, @CheckForNull String excludes, boolean useDefaultExcludes) throws IOException
      Lists recursive files of this directory with pattern matching.

      The default implementation calls list() recursively inside run(hudson.remoting.Callable<V, java.io.IOException>) and applies filtering to the result. Implementations may wish to override this more efficiently.

      Parameters:
      includes - comma-separated Ant-style globs as per Util.createFileSet(File, String, String) using / as a path separator; the empty string means no matches (use SelectorUtils.DEEP_TREE_MATCH if you want to match everything except some excludes)
      excludes - optional excludes in similar format to includes
      useDefaultExcludes - as per AbstractFileSet.setDefaultexcludes(boolean)
      Returns:
      a list of /-separated relative names of children (files directly inside or in subdirectories)
      Throws:
      IOException - if this is not a directory, or listing was not possible for some other reason
      Since:
      2.118
    • list

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) @NonNull public Collection<String> list(@NonNull String includes, @CheckForNull String excludes, boolean useDefaultExcludes, OpenOption... openOptions) throws IOException
      Lists recursive files of this directory with pattern matching.

      The default implementation calls list() recursively inside run(hudson.remoting.Callable<V, java.io.IOException>) and applies filtering to the result. Implementations may wish to override this more efficiently. This method allows the user to specify that symlinks should not be followed by passing LinkOption.NOFOLLOW_LINKS as true. However, some implementations may not be able to reliably prevent link following. The base implementation here in VirtualFile ignores this parameter.

      Parameters:
      includes - comma-separated Ant-style globs as per Util.createFileSet(File, String, String) using / as a path separator; the empty string means no matches (use SelectorUtils.DEEP_TREE_MATCH if you want to match everything except some excludes)
      excludes - optional excludes in similar format to includes
      useDefaultExcludes - as per AbstractFileSet.setDefaultexcludes(boolean)
      openOptions - the options to apply when opening.
      Returns:
      a list of /-separated relative names of children (files directly inside or in subdirectories)
      Throws:
      IOException - if this is not a directory, or listing was not possible for some other reason
      Since:
      2.275 and 2.263.2
    • containsSymLinkChild

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public boolean containsSymLinkChild(OpenOption... openOptions) throws IOException
      Throws:
      IOException
    • containsTmpDirChild

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public boolean containsTmpDirChild(OpenOption... openOptions) throws IOException
      Throws:
      IOException
    • zip

      public int zip(OutputStream outputStream, String includes, String excludes, boolean useDefaultExcludes, String prefix, OpenOption... openOptions) throws IOException
      Create a ZIP archive from the list of folders/files using the includes and excludes to filter them.

      The default implementation calls other existing methods to list the folders/files, then retrieve them and zip them all.

      Parameters:
      includes - comma-separated Ant-style globs as per Util.createFileSet(File, String, String) using / as a path separator; the empty string means no matches (use SelectorUtils.DEEP_TREE_MATCH if you want to match everything except some excludes)
      excludes - optional excludes in similar format to includes
      useDefaultExcludes - as per AbstractFileSet.setDefaultexcludes(boolean)
      prefix - the partial path that will be added before each entry inside the archive. If non-empty, a trailing slash will be enforced.
      openOptions - the options to apply when opening.
      Returns:
      the number of files inside the archive (not the folders)
      Throws:
      IOException - if this is not a directory, or listing was not possible for some other reason
      Since:
      2.275 and 2.263.2
    • child

      @NonNull public abstract VirtualFile child(@NonNull String name)
      Obtains a child file.
      Parameters:
      name - a relative path, possibly including / (but not ..)
      Returns:
      a representation of that child, whether it actually exists or not
    • length

      public abstract long length() throws IOException
      Gets the file length.
      Returns:
      a length, or 0 if inapplicable (e.g. a directory)
      Throws:
      IOException - if checking the length failed
    • lastModified

      public abstract long lastModified() throws IOException
      Gets the file timestamp.
      Returns:
      a length, or 0 if inapplicable
      Throws:
      IOException - if checking the timestamp failed
    • mode

      public int mode() throws IOException
      Gets the file’s Unix mode, if meaningful. If the file is symlink (see readLink()), the mode is that of the link target, not the link itself.
      Returns:
      for example, 0644 ~ rw-r--r--; -1 by default, meaning unknown or inapplicable
      Throws:
      IOException - if checking the mode failed
      Since:
      2.118
    • canRead

      public abstract boolean canRead() throws IOException
      Checks whether this file can be read.
      Returns:
      true normally
      Throws:
      IOException - if checking status failed
    • open

      public abstract InputStream open() throws IOException
      Opens an input stream on the file so its contents can be read.
      Returns:
      an open stream
      Throws:
      IOException - if it could not be opened
    • open

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public InputStream open(OpenOption... openOptions) throws IOException
      Opens an input stream on the file so its contents can be read.
      Parameters:
      openOptions - the options to apply when opening.
      Returns:
      an open stream
      Throws:
      IOException - if it could not be opened
    • compareTo

      public final int compareTo(VirtualFile o)
      Does case-insensitive comparison.
      Specified by:
      compareTo in interface Comparable<VirtualFile>
    • equals

      public final boolean equals(Object obj)
      Compares according to toURI().
      Overrides:
      equals in class Object
    • hashCode

      public final int hashCode()
      Hashes according to toURI().
      Overrides:
      hashCode in class Object
    • toString

      public final String toString()
      Displays toURI().
      Overrides:
      toString in class Object
    • run

      public <V> V run(hudson.remoting.Callable<V,IOException> callable) throws IOException
      Does some calculations in batch. For a remote file, this can be much faster than doing the corresponding operations one by one as separate requests. The default implementation just calls the block directly.
      Type Parameters:
      V - a value type
      Parameters:
      callable - something to run all at once (only helpful if any mentioned files are on the same system)
      Returns:
      the callable result
      Throws:
      IOException - if remote communication failed
      Since:
      1.554
    • toExternalURL

      @CheckForNull public URL toExternalURL() throws IOException
      Optionally obtains a URL which may be used to retrieve file contents from any process on any node. For example, given cloud storage this might produce a permalink to the file.

      Only http and https protocols are permitted. It is recommended to use RobustHTTPClient.downloadFile to work with these URLs.

      This is only meaningful for isFile(): no ZIP etc. archiving protocol is defined to allow bulk access to directory trees.

      Any necessary authentication must be encoded somehow into the URL itself; do not include any tokens or other authentication which might allow access to unrelated files (for example ArtifactManager builds from a different job). Authentication should be limited to download, not upload or any other modifications.

      The URL might be valid for only a limited amount of time or even only a single use; this method should be called anew every time an external URL is required.

      Returns:
      an externally usable URL like https://gist.githubusercontent.com/ACCT/GISTID/raw/COMMITHASH/FILE, or null if there is no such support
      Throws:
      IOException
      Since:
      2.118
      See Also:
    • supportIsDescendant

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public boolean supportIsDescendant()
      Determine if the implementation supports the isDescendant(String) method TODO un-restrict it in a weekly after the patch
    • isDescendant

      @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public boolean isDescendant(String childRelativePath) throws IOException
      Check if the relative path is really a descendant of this folder, following the symbolic links. Meant to be used in coordination with child(String). TODO un-restrict it in a weekly after the patch
      Throws:
      IOException
    • forFile

      public static VirtualFile forFile(File f)
      Creates a virtual file wrapper for a local file.
      Parameters:
      f - a disk file (need not exist)
      Returns:
      a wrapper
    • forFilePath

      public static VirtualFile forFilePath(FilePath f)
      Creates a virtual file wrapper for a remotable file.
      Parameters:
      f - a local or remote file (need not exist)
      Returns:
      a wrapper