#lang scribble/doc
@(require
scribble/manual
(for-label "../fs.ss"))
@title[#:tag "fs" #:style '(toc)]{Subversion File System}
@local-table-of-contents[]
@defmodule[(planet "fs.ss" ("murphy" "svn.plt" 1 0))]{
This module provides access to (sub)versioned file systems. Direct
Subversion file system access operates on a lower level than
repository access – for example creating a file system does not
create some of the management files of a repository and the direct
file system access functions don't care about things like repository
hooks.
}
@section{Filesystems}
@deftogether[(
@defthing[_fs ctype?]
@defthing[_fs/null ctype?]
)]{
C pointer type representing file system objects.
}
@defproc[(fs? [obj any/c])
any]{
Checks whether the given @scheme[obj] is a file system object.
}
@defproc[(fs-create [path path-string?])
fs?]{
Creates a new Subversion file system at @scheme[path].
}
@defproc[(fs-open [path path-string?])
fs?]{
Opens an existing Subversion file system at @scheme[path].
}
@defproc[(fs-hotcopy [source path-string?] [target path-string?]
[clean? any/c])
void?]{
Creates a new Subversion file system at @scheme[target] that is a
duplicate of the existing one at @scheme[source].
The @scheme[clean?] argument determines whether the source
filesystem is cleaned up during the process.
}
@defproc[(fs-delete-fs [path path-string?])
void?]{
Deletes the Subversion file system at @scheme[path].
}
@defproc[(fs-type [path path-string?])
symbol?]{
Determines the type of the Subversion file system at @scheme[path].
Returns a symbol naming the file system type, for example
@scheme['bdb] or @scheme['fsfs].
}
@defproc[(fs-path [fs fs?])
path?]{
Retrieves the location of the file system @scheme[fs] on the disk.
}
@deftogether[(
@defproc[(fs-uuid [fs fs?]) bytes?]
@defproc[(set-fs-uuid! [fs fs?] [uuid (or/c bytes? #f)]) void?]
@defform[#:id set!/fs-uuid #:literals (set! fs-uuid) (set! (fs-uuid fs) uuid)]
)]{
Retrieves or sets the universal ID of the file system as a binary
string.
When the universal ID is set to @scheme[#f], a new ID is computed
for the file system.
}
@section{Access Contexts}
@deftogether[(
@defthing[_fs-access ctype?]
@defthing[_fs-access/null ctype?]
)]{
C pointer type representing file system access contexts.
}
@defproc[(fs-access? [obj any/c])
any]{
Checks whether the given @scheme[obj] is a file system access
context.
}
@defproc[(make-fs-access [username string?])
fs-access?]{
Creates a new file system access context for the user called
@scheme[username].
}
@defproc[(fs-access-username [context fs-access?])
string?]{
Retrieves the name of the user represented by the given access
@scheme[context].
}
@defproc[(fs-access-add-lock-token! [context fs-access?] [token bytes?])
void?]{
Adds the lock identified by @scheme[token] to the given access
@scheme[context]. This is necessary when committing to locked
nodes.
}
@deftogether[(
@defproc[(fs-access [fs fs?]) (or/c fs-access? #f)]
@defproc[(set-fs-access! [fs fs?] [context (or/c fs-access? #f)]) void?]
@defform[#:id set!/fs-access #:literals (set! fs-access) (set! (fs-access fs) context)]
)]{
Retrieves or sets the access context of a file system.
An access context value of @scheme[#f] means that no context is
associated with the file system. Setting the context to @scheme[#f]
disassociates any present context from the file system.
}
@section{Revisions}
@defproc[(fs-youngest-rev [fs fs?])
exact-nonnegative-integer?]{
Retrieves the number of the youngest revision that has been
committed to the file system.
}
@deftogether[(
@defproc[(fs-rev-prop [fs fs?] [rev exact-nonnegative-integer?] [prop-name symbol?]) (or/c bytes? #f)]
@defproc[(set-fs-rev-prop [fs fs?] [rev exact-nonnegative-integer?] [prop-name symbol?] [value (or/c bytes? #f)]) void?]
@defform[#:id set!/fs-rev-prop #:literals (set! fs-rev-prop) (set! (fs-rev-prop fs rev prop-name) value)]
)]{
Retrieves or sets a revision property as a binary string.
A non-existent property is represented by the value @scheme[#f].
When a property is set to @scheme[#f], it is deleted.
}
@defproc[(fs-list-rev-props [fs fs?] [rev exact-nonnegative-integer?])
(listof symbol?)]{
Retrieves a list of all properties set on a revision.
}
@defproc[(fs-deltify-rev [fs fs?] [rev exact-nonnegative-integer?])
void?]{
Tries to conserve space in the file system by storing changes
leading up to the given revision as deltas.
}
@section{Locks}
@defstruct[lock-info ([path path?]
[token bytes?]
[owner string?]
[comment (or/c string? #f)]
[creation-time time?]
[expiration-time (or/c time? #f)])]{
A structure containing information about a lock.
The @scheme[path] and @scheme[token] can be used to identify
the lock in @scheme[fs-access-add-lock-token!], @scheme[fs-lock!]
and @scheme[fs-unlock!] operations.
}
@defproc[(fs-lock! [fs fs?] [path path-string?]
[#:token token (or/c bytes? #f) #f]
[#:comment comment (or/c string? #f) #f]
[#:expiration-time expiration-time (or/c time? #f) #f]
[#:current-rev current-rev (or/c exact-nonnegative-integer? #f) #f]
[#:steal steal? any/c #f])
lock-info?]{
Locks the specified @scheme[path] in the file system @scheme[fs].
The file system must have an associated access context, the user of
the access context becomes the owner of the lock.
The @scheme[token] uniquely identifies the lock. If it is not
specified, a fresh token is generated for the lock. If it is
specified and a lock with that token already exists, it must be
installed at the same path as the new lock.
The @scheme[comment] is purely descriptive and need not be
specified.
An @scheme[expiration-time] is optional. If specified, it must
be a SRFI-19 UTC time or a duration. A duration is added to the
current time to produce a value to be passed to the Subversion
library. Locks without expiration time never expire.
If a @scheme[current-rev] is specified, the lock operation only
succeeds if the path hasn't been modified or deleted since that
revision.
If @scheme[steal?] is not @scheme[#f], any existing lock at the
given path is removed and replaced by a new one.
}
@defproc[(fs-unlock! [fs fs?] [path path-string?] [token (or/c bytes? #f)])
void?]{
Unlocks the specified @scheme[path] in the file system @scheme[fs].
Fails if the lock is expired or no lock is present at all.
If @scheme[token] is @scheme[#f], the lock at the given path is
broken regardless of its owner.
}
@defproc[(call-with-fs-lock [fs fs?] [path path-string?] [thunk (-> any)]
[#:token token (or/c bytes? #f) #f]
[#:comment comment (or/c string? #f) #f]
[#:expiration-time expiration-time (or/c time? #f) #f]
[#:current-rev current-rev (or/c exact-nonnegative-integer? #f) #f]
[#:steal steal? any/c #f])
any]{
Calls the given @scheme[thunk] in a dynamic context, that
establishes a lock at @scheme[path] in the file system @scheme[fs]
upon entry and releases the lock upon exit.
When the lock is established, its token is also added to the current
access context of the file system.
See @scheme[fs-lock!] for the precise meaning of the keyword
arguments.
}
@defproc[(fs-lock-info [fs fs?] [path path-string?])
(or/c lock-info? #f)]{
Checks for the presence of a lock at @scheme[path] in the file
system @scheme[fs]. Returns a lock information object, if there
is a lock and @scheme[#f] otherwise.
}
@defproc[(fs-list-locks [fs fs?] [path path-string?])
(listof lock-info?)]{
Retrieves a list of lock information objects for any locks at or
below @scheme[path] in file system @scheme[fs].
}
@section{Transactions}
@deftogether[(
@defthing[_fs-txn ctype?]
@defthing[_fs-txn/null ctype?]
)]{
C pointer type representing transaction objects.
}
@defproc[(fs-txn? [obj any/c])
any]{
Checks whether the given @scheme[obj] is a transaction object.
}
@defproc[(fs-begin-txn [fs fs?] [rev exact-nonnegative-integer?])
fs-txn?]{
Creates a new transaction in @scheme[fs], based on revision
@scheme[rev].
}
@defproc[(fs-open-txn [fs fs?] [txn-name bytes?])
fs-txn?]{
Opens an existing transaction in @scheme[fs] with the given binary
@scheme[txn-name].
}
@defproc[(fs-commit-txn [txn fs-txn?])
exact-nonnegative-integer?]{
Commits the transaction @scheme[txn]. Returns the new revision
number representing the committed data.
}
@defproc[(fs-abort-txn [txn fs-txn?])
void?]{
Aborts the transaction @scheme[txn].
}
@defproc[(fs-purge-txn [fs fs?] [txn-name bytes?])
void?]{
Purges the inactive transaction with the binary name
@scheme[txn-name] from @scheme[fs].
}
@defproc[(fs-txn-name [txn fs-txn?])
bytes?]{
Retrieves the binary name of the given transaction.
}
@defproc[(fs-txn-base-rev [txn fs-txn?])
exact-nonnegative-integer?]{
Retrieves the base revision number of the given transaction.
}
@deftogether[(
@defproc[(fs-txn-prop [txn fs-txn?] [prop-name symbol?]) (or/c bytes? #f)]
@defproc[(set-fs-txn-prop! [txn fs-txn?] [prop-name symbol?] [value (or/c bytes? #f)]) void?]
@defform[#:id set!/fs-txn-prop #:literals (set! fs-txn-prop) (set! (fs-txn-prop txn prop-name) value)]
)]{
Retrieves or sets a transaction property as a binary string.
A non-existent property is represented by the value @scheme[#f].
When a property is set to @scheme[#f], it is deleted.
}
@defproc[(fs-list-txn-props [txn fs-txn?])
(listof symbol?)]{
Retrieves a list of all properties set on a transaction.
}
@defproc[(fs-list-txns [fs fs?])
(listof fs-txn?)]{
Lists the binary names of all active transactions in the file system
@scheme[fs].
}
@defproc[(call-with-fs-txn [fs fs?] [rev exact-nonnegative-integer?]
[proc (-> txn? any)])
any]{
Creates a new transaction in the file system @scheme[fs] with base
revision @scheme[rev]. Applies @scheme[proc] to the new transaction
and commits the transaction.
If the dynamic context of the @scheme[call-with-fs-txn] expression
is left after the transaction has been started but before it has
been committed, the transaction is aborted.
Returns the new revision number containing the data committed in the
transaction and all values (except the first one if it satisfies
@scheme[void?]) returned by @scheme[proc].
}
@section{Filesystem Roots}
@deftogether[(
@defthing[_fs-root ctype?]
@defthing[_fs-root/null ctype?]
)]{
C pointer type representing file system root objects.
}
@defproc[(fs-root? [obj any/c])
any]{
Checks whether the given @scheme[obj] is a file system root object.
}
@defproc[(fs-rev-root [fs fs?] [rev exact-nonnegative-integer?])
fs-root?]{
Retrieves the root of revision @scheme[rev] in @scheme[fs]. Data
can be read from files via a revision root, but they are
immutable.
}
@defproc[(fs-txn-root [txn fs-txn?])
fs-root?]{
Retrieves the root of the transaction @scheme[txn]. Data can be
read from and written to files via a transaction root. When the
transaction is committed, data written to files becomes visible
outside the transaction in a new revision.
}
@defproc[(fs-txn-root? [root fs-root?])
boolean?]{
Checks whether the given file system root is a transaction root.
}
@defproc[(fs-txn-root-name [root fs-root?])
(or/c bytes? #f)]{
Retrieves the binary name of the transaction to which the given
@scheme[root] belongs. If the root is not a transaction root,
the procedure returns @scheme[#f].
}
@defproc[(fs-root-fs [root fs-root?])
fs?]{
Retrieves the file system to which the given @scheme[root] belongs.
}
@section{Nodes}
@defproc[(fs-make-directory [root fs-root?] [path path-string?])
void?]{
Creates a new directory at @scheme[path] below @scheme[root].
}
@defproc[(fs-make-file [root fs-root?] [path path-string?])
void?]{
Creates a new empty file at @scheme[path] below @scheme[root].
}
@defproc[(fs-copy-node [src-root fs-root?] [src-path path-string?]
[tgt-root fs-root?] [tgt-path path-string?])
void?]{
Copies the file at @scheme[src-path] below @scheme[src-root] to
@scheme[tgt-path] below @scheme[tgt-root]. Records copy history for
the new file.
}
@defproc[(fs-rev-link-node [src-root fs-root?] [tgt-root fs-root?]
[path path-string?])
void?]{
Links the file at @scheme[path] below @scheme[src-root] to the same
path below @scheme[tgt-root]. Does not record copy history for the
file.
}
@defproc[(fs-merge-nodes [src-root fs-root?] [src-path path-string?]
[tgt-root fs-root?] [tgt-path path-string?]
[ancestor-root fs-root?] [ancestor-path path-string?])
void?]{
Merges changes from the ancestor at @scheme[ancestor-path] below
@scheme[ancestor-root] the source at @scheme[src-path] below
@scheme[scr-root] and between the ancestor and the target at
@scheme[tgt-path] below @scheme[tgt-root] into the target.
}
@defproc[(fs-delete-node [root fs-root?] [path path-string?])
void?]{
Deletes the node at @scheme[path] below @scheme[root].
}
@defthing[_fs-node-kind ctype?]{
C enumeration type classifying the node at a given path. The
possible values are @scheme['none], @scheme['file], @scheme['dir]
and @scheme['unknown].
}
@defproc[(fs-node-kind [root fs-root?] [path path-string?])
(one-of/c 'none 'file 'dir 'unknown)]{
Classifies the node at @scheme[path] below @scheme[root]. Returns
a symbol describing the type of node or @scheme['none] to indicate
that no node exists at the given path.
}
@deftogether[(
@defproc[(fs-node-directory? [root fs-root?] [path path-string?])
boolean?]
@defproc[(fs-node-file? [root fs-root?] [path path-string?])
boolean?]
)]{
Checks whether a node at @scheme[path] below @scheme[root] exists
and is a directory or file respectively.
}
@defproc[(fs-node-created-rev [root fs-root?] [path path-string?])
(or/c exact-nonnegative-integer? #f)]{
Retrieves the revision in which the node at @scheme[path] below
@scheme[root] was created.
Returns @scheme[#f] for nodes that have not been committed, yet.
}
@defproc[(fs-node-created-path [root fs-root?] [path path-string?])
path?]{
Retrieves the path at which the node at @scheme[path] below
@scheme[root] was originally created.
}
@defproc[(fs-node-copied-from [root fs-root?] [path path-string?])
(values (or/c exact-nonnegative-integer? #f)
(or/c path? #f))]{
If the node at @scheme[path] below @scheme[root] was copied from
some other node, this procedure returns the revision and path it was
copied from. Otherwise it returns two @scheme[#f] values.
}
@defproc[(fs-node-closest-copy [root fs-root?] [path path-string?])
(values (or/c fs-root? #f)
(or/c path? #f))]{
Retrieves the revision root and path of the destination of the most
recent copy event that caused @scheme[path] to exist where it does
in @scheme[root]. Returns two @scheme[#f] values if no such copy
exists.
}
@defproc[(fs-directory-list [root fs-root?] [path path-string?])
(listof path?)]{
Retrieves a list of entries in the directory at @scheme[path]
below @scheme[root]. The returned paths are relative to their
containing directory.
}
@defproc[(fs-file-length [root fs-root?] [path path-string?])
exact-nonnegative-integer?]{
Retrieves the length in bytes of the file located at @scheme[path]
below @scheme[root].
}
@defproc[(fs-file-contents-changed? [src-root fs-root?] [src-path path-string?]
[tgt-root fs-root?] [tgt-path path-string?])
boolean?]{
Checks whether the contents of the source at @scheme[src-path] below
@scheme[src-root] differ from those of the target at @scheme[tgt-path]
below @scheme[tgt-root].
}
@deftogether[(
@defproc[(fs-node-prop [root fs-root?] [path path-string?] [prop-name symbol?]) (or/c bytes? #f)]
@defproc[(set-fs-node-prop! [root fs-root?] [path path-string?] [prop-name symbol?] [value (or/c bytes? #f)]) void?]
@defform[#:id set!/fs-node-prop #:literals (set! fs-node-prop) (set! (fs-node-prop root path prop-name) value)]
)]{
Retrieves or sets a node property as a binary string.
A non-existent property is represented by the value @scheme[#f].
When a property is set to @scheme[#f], it is deleted.
}
@defproc[(fs-list-node-props [root fs-root?] [path path-string?])
(listof symbol?)]{
Retrieves a list of all properties set on a node.
}
@section{History}
@deftogether[(
@defthing[_fs-history ctype?]
@defthing[_fs-history/null ctype?]
)]{
C pointer type representing file system history objects. A history
object represents some event when a file system node is modified or
copied, which doesn't necessarily mean that the node's contents or
properties change with every history event.
}
@defproc[(fs-history? [obj any/c])
any]{
Checks whether the given @scheme[obj] is a file system history
object.
}
@defproc[(fs-node-history [root fs-root?] [path path-string?])
fs-history?]{
Retrieves a history object for the node at @scheme[path] below
@scheme[root].
}
@defproc[(fs-history-prev [history fs-history?] [cross-copies? any/c])
(or/c fs-history? #f)]{
Retrieves the next elder history object preceding @scheme[history].
If @scheme[cross-copies?] is not @scheme[#f], the history chain is
followed across copy events.
When @scheme[fs-history-prev] is called for the first time on a
return value of @scheme[fs-node-history], it may return an object
equivalent to the one that was passed in, in case that object itself
represents an interesting history event.
}
@defproc[(fs-history-location [history fs-history?])
(values exact-nonnegative-integer?
path?)]{
Retrieves the revision number and the path of the given
@scheme[history] event.
}
@section{Node Contents}
@defproc[(fs-open-input-file [root fs-root?] [path path-string?])
input-port?]{
Opens an input port from which the contents of the file at
@scheme[path] below @scheme[root] can be read.
}
@defproc[(fs-open-output-file [root fs-root?] [path path-string?]
[#:deltify deltify? any/c #t]
[#:base-checksum base-checksum (or/c bytes? #f) #f]
[#:result-checksum result-checksum (or/c bytes? #f) #f])
output-stream?]{
Opens an output port to which the new contents of the file at
@scheme[path] below @scheme[root] can be written.
If @scheme[deltify] is not @scheme[#f], writing data to the stream
automatically generated a delta to the previous contents of the file.
Otherwise, the new revision stores the full new contents of the file.
@scheme[base-checksum] and @scheme[result-checksum] are checksums of
the file's content before and after the change. These arguments may
be ignored, even if provided, but if provided, they must be correct.
}
@defproc[(call-with-fs-input-file [root fs-root?] [path path-string?]
[proc (-> input-port? any)])
any]{
Calls @scheme[fs-open-input-file] with the @scheme[root] and
@scheme[path] arguments and passes the resulting port to
@scheme[proc].
When @scheme[proc] returns, the newly opened port is closed.
The result of @scheme[proc] is the result of the
@scheme[call-with-fs-input-file] call.
}
@defproc[(call-with-fs-output-file [root fs-root?] [path path-string?]
[proc (-> output-port? any)]
[#:deltify deltify? any/c #t]
[#:base-checksum base-checksum (or/c bytes? #f) #f]
[#:result-checksum result-checksum (or/c bytes? #f) #f])
any]{
Calls @scheme[fs-open-output-file] with the @scheme[root],
@scheme[path], @scheme[deltify?], @scheme[base-checksum] and
@scheme[result-checksum] arguments and passes the resulting port to
@scheme[proc].
When @scheme[proc] returns, the newly opened port is closed.
The result of @scheme[proc] is the result of the
@scheme[call-with-fs-output-file] call.
}
@defproc[(call-with-fs-input-file* [root fs-root?] [path path-string?]
[proc (-> input-port? any)])
any]{
Like @scheme[call-with-fs-input-file], but the newly opened port is
closed whenever the dynamic scope of @scheme[call-with-fs-input-file*]
is left.
}
@defproc[(call-with-fs-output-file* [root fs-root?] [path path-string?]
[proc (-> output-port? any)]
[#:deltify deltify? any/c #t]
[#:base-checksum base-checksum (or/c bytes? #f) #f]
[#:result-checksum result-checksum (or/c bytes? #f) #f])
any]{
Like @scheme[call-with-fs-output-file], but the newly opened port is
closed whenever the dynamic scope of @scheme[call-with-fs-output-file*]
is left.
}
@defproc[(with-fs-input-from-file [root fs-root?] [path path-string?]
[thunk (-> any)])
any]{
Like @scheme[call-with-fs-input-file*], but the newly opened
port is not passed to @scheme[thunk] but rather installed as the
current input port using a parameterization.
}
@defproc[(with-fs-output-to-file [root fs-root?] [path path-string?]
[thunk (-> any)]
[#:deltify deltify? any/c #t]
[#:base-checksum base-checksum (or/c bytes? #f) #f]
[#:result-checksum result-checksum (or/c bytes? #f) #f])
any]{
Like @scheme[call-with-fs-output-file*], but the newly opened
port is not passed to @scheme[thunk] but rather installed as the
current output port using a parameterization.
}