NAME
Stow - manage farms of symbolic links
SYNOPSIS
my $stow = new Stow(%$options);
$stow->plan_unstow(@pkgs_to_unstow);
$stow->plan_stow (@pkgs_to_stow);
my %conflicts = $stow->get_conflicts;
$stow->process_tasks() unless %conflicts;
DESCRIPTION
This is the backend Perl module for GNU Stow, a program for managing the installation of software packages, keeping them separate (/usr/local/stow/emacs
vs. /usr/local/stow/perl
, for example) while making them appear to be installed in the same place (/usr/local
).
Stow doesn't store an extra state between runs, so there's no danger of mangling directories when file hierarchies don't match the database. Also, stow will never delete any files, directories, or links that appear in a stow directory, so it is always possible to rebuild the target tree.
CONSTRUCTORS
new(%options)
Required options
dir - the stow directory
target - the target directory
Non-mandatory options
See the documentation for the stow CLI front-end for information on these.
conflicts
simulate
verbose
paranoid
compat
test_mode
adopt
no-folding
ignore
override
defer
N.B. This sets the current working directory to the target directory.
set_stow_dir([$dir])
Sets a new stow directory. This allows the use of multiple stow directories within one Stow instance, e.g.
$stow->plan_stow('foo');
$stow->set_stow_dir('/different/stow/dir');
$stow->plan_stow('bar');
$stow->process_tasks;
If $dir
is omitted, uses the value of the dir
parameter passed to the new() constructor.
METHODS
plan_unstow(@packages)
Plan which symlink/directory creation/removal tasks need to be executed in order to unstow the given packages. Any potential conflicts are then accessible via get_conflicts().
plan_stow(@packages)
Plan which symlink/directory creation/removal tasks need to be executed in order to stow the given packages. Any potential conflicts are then accessible via get_conflicts().
within_target_do($code)
Execute code within target directory, preserving cwd.
This is done to ensure that the consumer of the Stow interface doesn't have to worry about (a) what their cwd is, and (b) that their cwd might change.
stow_contents($stow_path, $package, $pkg_subdir, $target_subdir)
Stow the contents of the given directory.
- $stow_path
-
Relative path from current (i.e. target) directory to the stow dir containing the package to be stowed. This can differ from
$self-
{stow_path}> when unfolding a (sub)tree which is already stowed from a package in a different stow directory (see the "Multiple Stow Directories" section of the manual). - $package
-
The package whose contents are being stowed.
- $pkg_subdir
-
Subdirectory of the installation image in the package directory which needs stowing as a symlink which points to it. This is relative to the top-level package directory.
- $target_subdir
-
Subdirectory of the target directory which either needs a symlink to the corresponding package subdirectory in the installation image, or if it's an existing directory, it's an unfolded tree which may need to be folded or recursed into.
stow_node()
and stow_contents()
are mutually recursive.
stow_node($stow_path, $package, $pkg_subpath, $target_subpath)
Stow the given node
- $stow_path
-
Relative path from current (i.e. target) directory to the stow dir containing the node to be stowed. This can differ from
$self-
{stow_path}> when unfolding a (sub)tree which is already stowed from a package in a different stow directory (see the "Multiple Stow Directories" section of the manual). - $package
-
The package containing the node being stowed.
- $pkg_subpath
-
Subpath of the installation image in the package directory which needs stowing as a symlink which points to it. This is relative to the top-level package directory.
- $target_subpath
-
Subpath of the target directory which either needs a symlink to the corresponding package subpathectory in the installation image, or if it's an existing directory, it's an unfolded tree which may need to be folded or recursed into.
stow_node()
and stow_contents()
are mutually recursive.
should_skip_target($target_subdir)
Determine whether $target_subdir
is a stow directory which should not be stowed to or unstowed from. This mechanism protects stow directories from being altered by stow, and is a necessary safety check because the stow directory could live beneath the target directory.
Returns true iff target is a stow directory
cwd must be the top-level target directory, otherwise marked_stow_dir()
won't work.
unstow_contents($package, $pkg_subdir, $target_subdir)
Unstow the contents of the given directory
- $package
-
The package whose contents are being unstowed.
- $pkg_subdir
-
Subdirectory of the installation image in the package directory which may need a symlink pointing to it to be unstowed. This is relative to the top-level package directory.
- $target_subdir
-
Subdirectory of the target directory which either needs unstowing of a symlink to the corresponding package subdirectory in the installation image, or if it's an existing directory, it's an unfolded tree which may need to be recursed into.
unstow_node()
and unstow_contents()
are mutually recursive. Here we traverse the package tree, rather than the target tree.
unstow_node($package, $pkg_subpath, $target_subpath)
Unstow the given node.
- $package
-
The package containing the node being unstowed.
- $pkg_subpath
-
Subpath of the installation image in the package directory which needs stowing as a symlink which points to it. This is relative to the top-level package directory.
- $target_subpath
-
Subpath of the target directory which either needs a symlink to the corresponding package subpathectory in the installation image, or if it's an existing directory, it's an unfolded tree which may need to be folded or recursed into.
unstow_node()
and unstow_contents()
are mutually recursive.
link_owned_by_package($target_subpath, $link_dest)
Determine whether the given link points to a member of a stowed package.
- $target_subpath
-
Path to a symbolic link under current directory.
- $link_dest
-
Where that link points to.
Lossy wrapper around find_stowed_path().
Returns the package iff link is owned by stow, otherwise ''.
find_stowed_path($target_subpath, $link_dest)
Determine whether the given symlink within the target directory is a stowed path pointing to a member of a package under the stow dir, and if so, obtain a breakdown of information about this stowed path.
- $target_subpath
-
Path to a symbolic link somewhere under the target directory, relative to the top-level target directory (which is also expected to be the current directory).
- $link_dest
-
Where that link points to (needed because link might not exist yet due to two-phase approach, so we can't just call
readlink()
). If this is owned by Stow, it will be expressed relative to (the directory containing)$target_subpath
. However if it's not, it could of course be relative or absolute, point absolutely anywhere, and could even be dangling.
Returns ($pkg_path_from_cwd, $stow_path, $package)
where $pkg_path_from_cwd
and $stow_path
are relative from the top-level target directory. $pkg_path_from_cwd
is the full relative path to the member of the package pointed to by $link_dest
; $stow_path
is the relative path to the stow directory; and $package
is the name of the package; or ('', '', '')
if link is not owned by stow.
cwd must be the top-level target directory, otherwise find_containing_marked_stow_dir()
won't work. Allow for stow dir not being under target dir.
link_dest_within_stow_dir($link_dest)
Detect whether symlink destination is within current stow dir
Returns ($package, $pkg_subpath)
- package within the current stow dir and subpath within that package which the symlink points to.
find_containing_marked_stow_dir($pkg_path_from_cwd)
Detect whether path is within a marked stow directory
Returns ($stow_path, $package)
where $stow_path
is the highest directory (relative from the top-level target directory) which is marked as a Stow directory, and $package
is the containing package; or ('', '')
if no containing directory is marked as a stow directory.
cwd must be the top-level target directory, otherwise marked_stow_dir()
won't work.
cleanup_invalid_links($dir)
Clean up orphaned links that may block folding
This is invoked by unstow_contents()
. We only clean up links which are both orphaned and owned by Stow, i.e. they point to a non-existent location within a Stow package. These can block tree folding, and they can easily occur when a file in Stow package is renamed or removed, so the benefit should outweigh the low risk of actually someone wanting to keep an orphaned link to within a Stow package.
foldable($target_subdir)
Determine whether a tree can be folded
- $target_subdir
-
Path to the target sub-directory to check for foldability, relative to the current directory (the top-level target directory).
Returns path to the parent dir iff the tree can be safely folded. The path returned is relative to the parent of $target_subdir
, i.e. it can be used as the source for a replacement symlink.
fold_tree($target_subdir, $pkg_subpath)
Fold the given tree
- $target_subdir
-
Directory that we will replace with a link to $pkg_subpath.
- $pkg_subpath
-
link to the folded tree source
Only called iff foldable() is true so we can remove some checks.
conflict($package, $message)
Handle conflicts in stow operations
get_conflicts()
Returns a nested hash of all potential conflicts discovered: the keys are actions ('stow' or 'unstow'), and the values are hashrefs whose keys are stow package names and whose values are conflict descriptions, e.g.:
(
stow => {
perl => [
"existing target is not owned by stow: bin/a2p"
"existing target is neither a link nor a directory: bin/perl"
]
}
)
get_conflict_count()
Returns the number of conflicts found.
get_tasks()
Returns a list of all symlink/directory creation/removal tasks.
get_action_count()
Returns the number of actions planned for this Stow instance.
ignore($stow_path, $package, $target)
Determine if the given path matches a regex in our ignore list.
- $stow_path
-
the stow directory containing the package
- $package
-
the package containing the path
- $target
-
the path to check against the ignore list relative to its package directory
Returns true iff the path should be ignored.
invalidate_memoized_regexp($file)
For efficiency of performance, regular expressions are compiled from each ignore list file the first time it is used by the Stow process, and then memoized for future use. If you expect the contents of these files to change during a single run, you will need to invalidate the memoized value from this cache. This method allows you to do that.
defer($path)
Determine if the given path matches a regex in our defer
list
Returns boolean.
override($path)
Determine if the given path matches a regex in our override
list
Returns boolean
process_tasks()
Process each task in the tasks list
- none
Returns : n/a Throws : fatal error if tasks list is corrupted or a task fails
process_task($task)
Process a single task.
Returns : n/a Throws : fatal error if task fails # # Must run from within target directory. Task involve either creating or deleting dirs and symlinks an action is set to 'skip' if it is found to be redundant
link_task_action($path)
Finds the link task action for the given path, if there is one
Returns 'remove'
, 'create'
, or ''
if there is no action. Throws a fatal exception if an invalid action is found.
dir_task_action($path)
Finds the dir task action for the given path, if there is one.
Returns 'remove'
, 'create'
, or ''
if there is no action. Throws a fatal exception if an invalid action is found.
parent_link_scheduled_for_removal($target_path)
Determine whether the given path or any parent thereof is a link scheduled for removal
Returns boolean
is_a_link($target_path)
Determine if the given path is a current or planned link.
Returns false if an existing link is scheduled for removal and true if a non-existent link is scheduled for creation.
is_a_dir($target_path)
Determine if the given path is a current or planned directory
Returns false if an existing directory is scheduled for removal and true if a non-existent directory is scheduled for creation. We also need to be sure we are not just following a link.
is_a_node($target_path)
Determine whether the given path is a current or planned node.
Returns false if an existing node is scheduled for removal, or true if a non-existent node is scheduled for creation. We also need to be sure we are not just following a link.
read_a_link($link)
Return the destination of a current or planned link.
Returns the destination of the given link. Throws a fatal exception if the given path is not a current or planned link.
do_link($link_dest, $link_src)
Wrap 'link' operation for later processing
Throws an error if this clashes with an existing planned operation. Cleans up operations that undo previous operations.
do_unlink($file)
Wrap 'unlink' operation for later processing
Throws an error if this clashes with an existing planned operation. Will remove an existing planned link.
do_mkdir($dir)
Wrap 'mkdir' operation
Throws a fatal exception if operation fails. Outputs a message if 'verbose' option is set. Does not perform operation if 'simulate' option is set. Cleans up operations that undo previous operations.
do_rmdir($dir)
Wrap 'rmdir' operation
Throws a fatal exception if operation fails. Outputs a message if 'verbose' option is set. Does not perform operation if 'simulate' option is set.
do_mv($src, $dst)
Wrap 'move' operation for later processing.
Throws an error if this clashes with an existing planned operation. Alters contents of package installation image in stow dir.
Returns : n/a Throws : n/a