Expand description
Untree: Undoing tree for fun and profit
Untree inverts the action of tree by converting tree diagrams of directory structures back into directory structures. Given a directory structure, tree produces a tree diagram, and given a tree diagram, untree produces a directory structure.
Let’s say you have the following directory structure, created by running tree
in the root of this project:
. ├── Cargo.lock ├── Cargo.toml ├── inputs │ └── test1.tree ├── lib │ ├── either.rs │ ├── errors.rs │ ├── functions.rs │ ├── mod.rs │ ├── more_context.rs │ ├── path_action.rs │ └── types.rs ├── LICENSE.txt ├── media │ ├── image1.png │ └── image2.png ├── README.md └── src └── main.rs
untree can create a mirror that directory structure, just based on that input:
tree | untree --dir path/to/output/dir
Here, test
is the destination directory where untree
is supposed to create
files. Now, if we tree
the newly created directory, we can see that it has the
same structure as the repository:
path/to/output/dir ├── Cargo.lock ├── Cargo.toml ├── inputs │ └── test1.tree ├── lib │ ├── either.rs │ ├── errors.rs │ ├── functions.rs │ ├── mod.rs │ ├── more_context.rs │ ├── path_action.rs │ └── types.rs ├── LICENSE.txt ├── media │ ├── image1.png │ └── image2.png ├── README.md └── src └── main.rs 4 directories, 15 files
untree
can also read in the tree from an input file, or you can paste it in
directly since it accepts input from standard input:
Motivating untree
I’ve noticed that in the past I’ve had to recreate directory structures in order to answer questions or run tests on the directory. For example, this question asks about ignoring certain kinds of files, and it provides a directory structure as reference.
The files themselves aren’t provided, nor do they need to be, but the directory structure itself is relevant to the question.
untree
allows you to replicate the structure of a directory printed with tree,
making it easy to answer questions about programs that traverse the directory
tree. This means that untree is also good for quickly creating directory
structures for the purpose of mocking input to other programs.
Using untree as a library
You can use untree as a library if you need that functionality included in your
program. In order to create a tree, invoke create_tree
with the given
directory, Lines
buffer, and options.
These options are very simple - there’s UntreeOptions::verbose
, which will
tell create_tree
and create_path
to print out any directories or files
that were created when set, and UntreeOptions::dry_run
, which will print out
any directories or files without actually creating them (dry_run
implies
verbose
).
Below is an example usage:
use untree::*;
use std::io::{BufRead, BufReader, stdin, Lines};
let options = UntreeOptions::new()
.dry_run(true) // Set dry_run to true
.verbose(true); // Set verbose to true
let lines = BufReader::new(stdin()).lines();
create_tree("path/to/directory", lines, options)?;
Additional functions include
create_path
, used to create a file or path with the given options,get_entry
, used to parse a line in a tree file,touch_directory
, used to create a directory,touch_file
, used to touch a file (does the same thing as unix touch)
The primary error type used by untree is Error
, which holds information
about a path and the action being done on it, in addition to the normal error
information provided by io::Error
.
User testimonials
When asked about untree, my friend said:
I retroactively want that for my time trying to get Conan to work. It woulda made certain things just a little less painful.
— some guy (He asked to be referred to as “some guy”)
Comments, feedback, or contributions are welcome!
I’m in the progress of learning rust, so any feedback you have is greatly
appreciated! Also, if untree
is useful to you, please let me know!
Re-exports
pub use ReadStdinType::ReadStdin;
pub use PathAction::*;
Structs
Represents additional options that can be passed to create_tree
or
create_path
. If options.verbose is set, print out the creation of the file
or directory. If options.dry_run is set, print out the creation of the file
or directory, but don’t actually create it (options.dry_run
implies
verbose)
Enums
Error type for untree. Provides additional context to errors, such as the path type.
Represents a type of action that can happen on a path. Used to provide additional context to errors, by describing what was happening when the error occured.
Enum used to indicate that a path should be created as a file
(PathKind::FilePath
) or a directory (PathKind::Directory
)
Tag type used to indicate that the context for an error was standard input
Traits
Sometimes an error can be missing external context. For example, when trying
to read a Lines
struct, the function may not know what the file or stream
was that was the source of the Lines
. In thic case, it’ll report a missing
context. Invoking more_context
on the result or the error allows
additional context to be filled in by the calling function
Functions
Create either a file (for kind == PathKind::File
) or a directory (for
kind == PathKind::Directory
). Provides additional options in the form of
UntreeOptions
.
Create a tree based on a sequence of lines describing the tree structure inside the given directory
Returns an entry in the tree, where the first result is the depth, and the second result is the file
Create a directory, along with any parents that haven’t been created
Atomically create a file, if it doesn’t already exist. This is an atomic operation on the filesystem. If the file already exists, this function exits without affecting that file.
Type Definitions
Type representing the context for a error. Contains a path, together with a
PathAction
indicating what was going on at the time of the error
Result type for untree.
untree::Result<T>
is a std::result::Result<T, untree::Error>
.