package storage import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/storage/repository" ) // NewFileURI creates a new URI from the given file path. func NewFileURI(path string) fyne.URI { return repository.NewFileURI(path) } // NewURI creates a new URI from the given string representation. This could be // a URI from an external source or one saved from URI.String() // // Deprecated: use ParseURI instead func NewURI(s string) fyne.URI { u, _ := ParseURI(s) return u } // ParseURI creates a new URI instance by parsing a URI string. // // Parse URI will parse up to the first ':' present in the URI string to // extract the scheme, and then delegate further parsing to the registered // repository for the given scheme. If no repository is registered for that // scheme, the URI is parsed on a best-effort basis using net/url. // // As a special exception, URIs beginning with 'file:' are always parsed using // NewFileURI(), which will correctly handle back-slashes appearing in the URI // path component on Windows. // // Since: 2.0 func ParseURI(s string) (fyne.URI, error) { return repository.ParseURI(s) } // Parent returns a URI referencing the parent resource of the resource // referenced by the URI. For example, the Parent() of 'file://foo/bar.baz' is // 'file://foo'. The URI which is returned will be listable. // // NOTE: it is not a given that Parent() return a parent URI with the same // Scheme(), though this will normally be the case. // // This can fail in several ways: // // - If the URI refers to a filesystem root, then the Parent() implementation // must return (nil, URIRootError). // // - If the URI refers to a resource which does not exist in a hierarchical // context (e.g. the URI references something which does not have a // semantically meaningful "parent"), the Parent() implementation may return // an error. // // - If determining the parent of the referenced resource requires // interfacing with some external system, failures may propagate // through the Parent() implementation. For example if determining // the parent of a file:// URI requires reading information from // the filesystem, it could fail with a permission error. // // - If the scheme of the given URI does not have a registered // HierarchicalRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // NOTE: since v2.0.0, Parent() is backed by the repository system - this // function is a helper which calls into an appropriate repository instance for // the scheme of the URI it is given. // // Since: 1.4 func Parent(u fyne.URI) (fyne.URI, error) { repo, err := repository.ForURI(u) if err != nil { return nil, err } hrepo, ok := repo.(repository.HierarchicalRepository) if !ok { return nil, repository.ErrOperationNotSupported } return hrepo.Parent(u) } // Child returns a URI referencing a resource nested hierarchically below the // given URI, identified by a string. For example, the child with the string // component 'quux' of 'file://foo/bar' is 'file://foo/bar/quux'. // // This can fail in several ways: // // - If the URI refers to a resource which does not exist in a hierarchical // context (e.g. the URI references something which does not have a // semantically meaningful "child"), the Child() implementation may return an // error. // // - If generating a reference to a child of the referenced resource requires // interfacing with some external system, failures may propagate through the // Child() implementation. It is expected that this case would occur very // rarely if ever. // // - If the scheme of the given URI does not have a registered // HierarchicalRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // NOTE: since v2.0.0, Child() is backed by the repository system - this // function is a helper which calls into an appropriate repository instance for // the scheme of the URI it is given. // // Since: 1.4 func Child(u fyne.URI, component string) (fyne.URI, error) { repo, err := repository.ForURI(u) if err != nil { return nil, err } hrepo, ok := repo.(repository.HierarchicalRepository) if !ok { return nil, repository.ErrOperationNotSupported } return hrepo.Child(u, component) } // Exists determines if the resource referenced by the URI exists. // // This can fail in several ways: // // - If checking the existence of a resource requires interfacing with some // external system, then failures may propagate through Exists(). For // example, checking the existence of a resource requires reading a directory // may result in a permissions error. // // It is understood that a non-nil error value signals that the existence or // non-existence of the resource cannot be determined and is undefined. // // NOTE: since v2.0.0, Exists is backed by the repository system - this function // calls into a scheme-specific implementation from a registered repository. // // Exists may call into either a generic implementation, or into a // scheme-specific implementation depending on which storage repositories have // been registered. // // Since: 1.4 func Exists(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { return false, err } return repo.Exists(u) } // Delete destroys, deletes, or otherwise removes the resource referenced // by the URI. // // This can fail in several ways: // // - If removing the resource requires interfacing with some external system, // failures may propagate through Destroy(). For example, deleting a file may // fail with a permissions error. // // - If the referenced resource does not exist, attempting to destroy it should // throw an error. // // - If the scheme of the given URI does not have a registered // WritableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // Delete is backed by the repository system - this function calls // into a scheme-specific implementation from a registered repository. // // Since: 2.0 func Delete(u fyne.URI) error { repo, err := repository.ForURI(u) if err != nil { return err } wrepo, ok := repo.(repository.WritableRepository) if !ok { return repository.ErrOperationNotSupported } return wrepo.Delete(u) } // Reader returns URIReadCloser set up to read from the resource that the // URI references. // // This method can fail in several ways: // // - Different permissions or credentials are required to read the // referenced resource. // // - This URI scheme could represent some resources that can be read, // but this particular URI references a resources that is not // something that can be read. // // - Attempting to set up the reader depended on a lower level // operation such as a network or filesystem access that has failed // in some way. // // Reader is backed by the repository system - this function calls // into a scheme-specific implementation from a registered repository. // // Since: 2.0 func Reader(u fyne.URI) (fyne.URIReadCloser, error) { repo, err := repository.ForURI(u) if err != nil { return nil, err } return repo.Reader(u) } // CanRead determines if a given URI could be written to using the Reader() // method. It is preferred to check if a URI is readable using this method // before calling Reader(), because the underlying operations required to // attempt to read and then report an error may be slower than the operations // needed to test if a URI is readable. Keep in mind however that even if // CanRead returns true, you must still do appropriate error handling for // Reader(), as the underlying filesystem may have changed since you called // CanRead. // // The non-existence of a resource should not be treated as an error. In other // words, a Repository implementation which for some URI u returns false, nil // for Exists(u), CanRead(u) should also return false, nil. // // CanRead is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // // Since: 2.0 func CanRead(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { return false, err } return repo.CanRead(u) } // Writer returns URIWriteCloser set up to write to the resource that the // URI references. // // Writing to a non-extant resource should create that resource if possible // (and if not possible, this should be reflected in the return of CanWrite()). // Writing to an extant resource should overwrite it in-place. At present, this // API does not provide a mechanism for appending to an already-extant // resource, except for reading it in and writing all the data back out. // // This method can fail in several ways: // // - Different permissions or credentials are required to write to the // referenced resource. // // - This URI scheme could represent some resources that can be // written, but this particular URI references a resources that is // not something that can be written. // // - Attempting to set up the writer depended on a lower level // operation such as a network or filesystem access that has failed // in some way. // // - If the scheme of the given URI does not have a registered // WritableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // Writer is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // // Since: 2.0 func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { repo, err := repository.ForURI(u) if err != nil { return nil, err } wrepo, ok := repo.(repository.WritableRepository) if !ok { return nil, repository.ErrOperationNotSupported } return wrepo.Writer(u) } // CanWrite determines if a given URI could be written to using the Writer() // method. It is preferred to check if a URI is writable using this method // before calling Writer(), because the underlying operations required to // attempt to write and then report an error may be slower than the operations // needed to test if a URI is writable. Keep in mind however that even if // CanWrite returns true, you must still do appropriate error handling for // Writer(), as the underlying filesystem may have changed since you called // CanWrite. // CanWrite is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // // Since: 2.0 func CanWrite(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { return false, err } wrepo, ok := repo.(repository.WritableRepository) if !ok { return false, repository.ErrOperationNotSupported } return wrepo.CanWrite(u) } // Copy given two URIs, 'src', and 'dest' both of the same scheme, will copy // one to the other. If the source and destination are of different schemes, // then the Copy implementation for the storage repository registered to the // scheme of the source will be used. Implementations are recommended to use // repository.GenericCopy() as a fail-over in the case that they do not // understand how to operate on the scheme of the destination URI. However, the // behavior of calling Copy() on URIs of non-matching schemes is ultimately // defined by the storage repository registered to the scheme of the source // URI. // // This method may fail in several ways: // // - Different permissions or credentials are required to perform the // copy operation. // // - This URI scheme could represent some resources that can be copied, // but either the source, destination, or both are not resources // that support copying. // // - Performing the copy operation depended on a lower level operation // such as network or filesystem access that has failed in some way. // // - If the scheme of the given URI does not have a registered // CopyableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // Copy is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // // Since: 2.0 func Copy(source fyne.URI, destination fyne.URI) error { repo, err := repository.ForURI(source) if err != nil { return err } crepo, ok := repo.(repository.CopyableRepository) if !ok { return repository.ErrOperationNotSupported } return crepo.Copy(source, destination) } // Move returns a method that given two URIs, 'src' and 'dest' both of the same // scheme this will move src to dest. This means the resource referenced by // src will be copied into the resource referenced by dest, and the resource // referenced by src will no longer exist after the operation is complete. // // If the source and destination are of different schemes, then the Move // implementation for the storage repository registered to the scheme of the // source will be used. Implementations are recommended to use // repository.GenericMove() as a fail-over in the case that they do not // understand how to operate on the scheme of the destination URI. However, the // behavior of calling Move() on URIs of non-matching schemes is ultimately // defined by the storage repository registered to the scheme of the source // URI. // // This method may fail in several ways: // // - Different permissions or credentials are required to perform the // rename operation. // // - This URI scheme could represent some resources that can be renamed, // but either the source, destination, or both are not resources // that support renaming. // // - Performing the rename operation depended on a lower level operation // such as network or filesystem access that has failed in some way. // // - If the scheme of the given URI does not have a registered // MovableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // Move is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // // Since: 2.0 func Move(source fyne.URI, destination fyne.URI) error { repo, err := repository.ForURI(source) if err != nil { return err } mrepo, ok := repo.(repository.MovableRepository) if !ok { return repository.ErrOperationNotSupported } return mrepo.Move(source, destination) } // CanList will determine if the URI is listable or not. // // This method may fail in several ways: // // - Different permissions or credentials are required to check if the // URI supports listing. // // - This URI scheme could represent some resources that can be listed, // but this specific URI is not one of them (e.g. a file on a // filesystem, as opposed to a directory). // // - Checking for listability depended on a lower level operation // such as network or filesystem access that has failed in some way. // // - If the scheme of the given URI does not have a registered // ListableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // CanList is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // // Since: 2.0 func CanList(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { return false, err } lrepo, ok := repo.(repository.ListableRepository) if !ok { return false, repository.ErrOperationNotSupported } return lrepo.CanList(u) } // List returns a list of URIs that reference resources which are nested below // the resource referenced by the argument. For example, listing a directory on // a filesystem should return a list of files and directories it contains. // // This method may fail in several ways: // // - Different permissions or credentials are required to obtain a // listing for the given URI. // // - This URI scheme could represent some resources that can be listed, // but this specific URI is not one of them (e.g. a file on a // filesystem, as opposed to a directory). This can be tested in advance // using the Listable() function. // // - Obtaining the listing depended on a lower level operation such as // network or filesystem access that has failed in some way. // // - If the scheme of the given URI does not have a registered // ListableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // List is backed by the repository system - this function either calls into a // scheme-specific implementation from a registered repository, or fails with a // URIOperationNotSupported error. // // Since: 2.0 func List(u fyne.URI) ([]fyne.URI, error) { repo, err := repository.ForURI(u) if err != nil { return nil, err } lrepo, ok := repo.(repository.ListableRepository) if !ok { return nil, repository.ErrOperationNotSupported } return lrepo.List(u) } // CreateListable creates a new listable resource referenced by the given URI. // CreateListable will error if the URI already references an extant resource. // This method is used for storage repositories where listable resources are of // a different underlying type than other resources - for example, in a typical // filesystem ('file://'), CreateListable() corresponds to directory creation, // and Writer() implies file creation for non-extant operands. // // For storage repositories where listable and non-listable resources are the // of the same underlying type, CreateListable should be equivalent to calling // Writer(), writing zero bytes, and then closing the `URIWriteCloser - in // filesystem terms, the same as calling 'touch;'. // // Storage repositories which support listing, but not creation of listable // objects may return repository.ErrOperationNotSupported. // // CreateListable should generally fail if the parent of it's operand does not // exist, however this can vary by the implementation details of the specific // storage repository. In filesystem terms, this function is "mkdir" not "mkdir // -p". // // This method may fail in several ways: // // - Different permissions or credentials are required to create the requested // resource. // // - Creating the resource depended on a lower level operation such as network // or filesystem access that has failed in some way. // // - If the scheme of the given URI does not have a registered // ListableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // CreateListable is backed by the repository system - this function either // calls into a scheme-specific implementation from a registered repository, or // fails with a URIOperationNotSupported error. // // Since: 2.0 func CreateListable(u fyne.URI) error { repo, err := repository.ForURI(u) if err != nil { return err } lrepo, ok := repo.(repository.ListableRepository) if !ok { return repository.ErrOperationNotSupported } return lrepo.CreateListable(u) }