gtree

package module
v1.11.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2025 License: BSD-2-Clause Imports: 19 Imported by: 8

README

[^1]
GitHub Pages
GitHub release Go Reference
License Mentioned in Awesome Go
codecov Go Report Card ci


Using either Markdown or Programmatically to generate directory trees🌳 and directories🗂, and to verify directories🔍. Provide CLI, Golang library and Web.

Table of Contents

Acknowledgments

Thanks for providing very useful CLI for cloud storage tree output🤩🎉

Everyone is encouraged to use them!

orangekame3/stree

CLI for Amazon S3 tree output.
aws s3 command does not do what tree command does, but stree command can display tree!

owlinux1000/gcstree

CLI for Google Cloud Storage tree output.
gcloud storage command does not do what tree command does, but gcstree command can display tree!

gtree packeage has been utilized for other tools as well🚀

I hope you will use these tools as well!

Web

https://ddddddo.github.io/gtree/

This page is that converts from Markdown to tree!
This page calls a function that outputs tree. This function is a Go package compiled as WebAssembly.
The symbols that can be used in Markdown are *, -, +, and #.
Indentation represents hierarchy. The indentation can be whatever you specify, but use the same pattern.
You can change the branches like in the image below.
Also, once loaded, you can enjoy offline!

You can open it in your browser with

$ gtree web

source code

CLI

Installation

Go
$ go install github.com/ddddddO/gtree/cmd/gtree@latest

aqua
$ aqua g -i ddddddO/gtree

Homebrew
$ brew install gtree

Nix
$ nix-env -i gtree
or
$ nix-shell -p gtree

MacPorts
$ port install gtree

AUR
$ wip...

Scoop
$ scoop bucket add ddddddO https://github.com/ddddddO/scoop-bucket.git
$ scoop install ddddddO/gtree

deb
$ export GTREE_VERSION=X.X.X
$ curl -o gtree.deb -L https://github.com/ddddddO/gtree/releases/download/v$GTREE_VERSION/gtree_$GTREE_VERSION-1_amd64.deb
$ dpkg -i gtree.deb

rpm
$ export GTREE_VERSION=X.X.X
$ yum install https://github.com/ddddddO/gtree/releases/download/v$GTREE_VERSION/gtree_$GTREE_VERSION-1_amd64.rpm

apk
$ export GTREE_VERSION=X.X.X
$ curl -o gtree.apk -L https://github.com/ddddddO/gtree/releases/download/v$GTREE_VERSION/gtree_$GTREE_VERSION-1_amd64.apk
$ apk add --allow-untrusted gtree.apk

Docker
$ docker pull ghcr.io/ddddddo/gtree:latest
$ docker run ghcr.io/ddddddo/gtree:latest template | docker run -i ghcr.io/ddddddo/gtree:latest output
gtree
├── cmd
│   └── gtree
│       └── main.go
├── testdata
│   ├── sample1.md
│   └── sample2.md
├── Makefile
└── tree.go
etc

download binary from here.

Usage

$ gtree --help
NAME:
   gtree - This CLI uses Markdown to generate directory trees and directories itself, and also verifies directories.
           The symbols that can be used in Markdown are '-', '+', '*', and '#'.
           Within Markdown, indentation represents hierarchy. The indentation can be whatever you specify, but use the same pattern.

USAGE:
   gtree [global options] command [command options] [arguments...]

VERSION:
   1.10.2 / revision 85520a1

COMMANDS:
   output, o, out     Outputs tree from markdown.
                      Let's try 'gtree template | gtree output'.
   mkdir, m           Makes directories and files from markdown. It is possible to dry run.
                      Let's try 'gtree template | gtree mkdir -e .go -e .md -e Makefile'.
   verify, vf         Verifies tree structure represented in markdown by comparing it with existing directories.
                      Let's try 'gtree template | gtree verify'.
   template, t, tmpl  Outputs markdown template. Use it to try out gtree CLI.
   web, w, www        Opens "Tree Maker" in your browser and shows the URL in terminal.
   version, v         Prints the version.
   help, h            Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version
Output subcommand
$ gtree output --help
NAME:
   gtree output - Outputs tree from markdown.
                  Let's try 'gtree template | gtree output'.

USAGE:
   gtree output [command options] [arguments...]

OPTIONS:
   --file value, -f value               specify the path to markdown file. (default: stdin)
   --massive, -m                        set this option when there are very many blocks of markdown. (default: false)
   --massive-timeout value, --mt value  set this option if you want to set a timeout. (default: 0s)
   --format value                       set this option when specifying output format. "json", "yaml", "toml"
   --watch, -w                          follow changes in markdown file. (default: false)
   --help, -h                           show help
Try it!
$ gtree template
- gtree
        - cmd
                - gtree
                        - main.go
        - testdata
                - sample1.md
                - sample2.md
        - Makefile
        - tree.go
$ gtree template | gtree output
gtree
├── cmd
│   └── gtree
│       └── main.go
├── testdata
│   ├── sample1.md
│   └── sample2.md
├── Makefile
└── tree.go

Other pattern.

├── gtree output -f testdata/sample1.md
├── cat testdata/sample1.md | gtree output -f -
└── cat testdata/sample1.md | gtree output
Usage other than representing a directory.
$ cat testdata/sample2.md | gtree output
k8s_resources
├── (Tier3)
│   └── (Tier2)
│       └── (Tier1)
│           └── (Tier0)
├── Deployment
│   └── ReplicaSet
│       └── Pod
│           └── container(s)
├── CronJob
│   └── Job
│       └── Pod
│           └── container(s)
└── (empty)
    ├── DaemonSet
    │   └── Pod
    │       └── container(s)
    └── StatefulSet
        └── Pod
            └── container(s)
Multiple roots
$ cat testdata/sample6.md | gtree output
Artiodactyla
├── Artiofabula
│   ├── Cetruminantia
│   │   ├── Whippomorpha
│   │   │   ├── Hippopotamidae
│   │   │   └── Cetacea
│   │   └── Ruminantia
│   └── Suina
└── Tylopoda
Carnivora
├── Feliformia
└── Caniformia
    ├── Canidae
    └── Arctoidea
        ├── Ursidae
        └── x
            ├── Pinnipedia
            └── Musteloidea
                ├── Ailuridae
                └── x
                    ├── Mephitidae
                    └── x
                        ├── Procyonidae
                        └── Mustelidae
Output JSON
see
$ cat testdata/sample5.md | gtree output --format json | jq
{
  "value": "a",
  "children": [
    {
      "value": "i",
      "children": [
        {
          "value": "u",
          "children": [
            {
              "value": "k",
              "children": null
            },
            {
              "value": "kk",
              "children": null
            }
          ]
        },
        {
          "value": "t",
          "children": null
        }
      ]
    },
    {
      "value": "e",
      "children": [
        {
          "value": "o",
          "children": null
        }
      ]
    },
    {
      "value": "g",
      "children": null
    }
  ]
}
Output YAML
see
$ cat testdata/sample5.md | gtree output --format yaml
value: a
children:
- value: i
  children:
  - value: u
    children:
    - value: k
      children: []
    - value: kk
      children: []
  - value: t
    children: []
- value: e
  children:
  - value: o
    children: []
- value: g
  children: []
Output TOML
see
$ cat testdata/sample5.md | gtree output --format toml
value = 'a'
[[children]]
value = 'i'
[[children.children]]
value = 'u'
[[children.children.children]]
value = 'k'
children = []
[[children.children.children]]
value = 'kk'
children = []

[[children.children]]
value = 't'
children = []

[[children]]
value = 'e'
[[children.children]]
value = 'o'
children = []

[[children]]
value = 'g'
children = []

Mkdir subcommand
$ gtree mkdir --help
NAME:
   gtree mkdir - Makes directories and files from markdown. It is possible to dry run.
                 Let's try 'gtree template | gtree mkdir -e .go -e .md -e Makefile'.

USAGE:
   gtree mkdir [command options] [arguments...]

OPTIONS:
   --file value, -f value                                       specify the path to markdown file. (default: stdin)
   --dry-run, -d                                                dry run. detects node that is invalid for directory generation. the order of the output and made directories does not always match. (default: false)
   --extension value, -e value [ --extension value, -e value ]  set this option if you want to create file instead of directory. for example, if you want to generate files with ".go" extension: "-e .go"
   --target-dir value                                           set this option if you want to specify the directory you want to make directory. (default: current directory)
   --help, -h                                                   show help
Try it!
$ gtree template
- gtree
        - cmd
                - gtree
                        - main.go
        - testdata
                - sample1.md
                - sample2.md
        - Makefile
        - tree.go
$ gtree template | gtree mkdir
$ tree gtree/
gtree/
├── cmd
│   └── gtree
│       └── main.go
├── Makefile
├── testdata
│   ├── sample1.md
│   └── sample2.md
└── tree.go

8 directories, 0 files
make directories and files
$ gtree template
- gtree
        - cmd
                - gtree
                        - main.go
        - testdata
                - sample1.md
                - sample2.md
        - Makefile
        - tree.go
$ gtree template | gtree mkdir -e .go -e .md -e Makefile
$ tree gtree/
gtree/
├── cmd
│   └── gtree
│       └── main.go
├── Makefile
├── testdata
│   ├── sample1.md
│   └── sample2.md
└── tree.go

3 directories, 5 files
dry run

Does not create a file and directory.

$ gtree template | gtree mkdir --dry-run -e .go -e .md -e Makefile
gtree
├── cmd
│   └── gtree
│       └── main.go
├── testdata
│   ├── sample1.md
│   └── sample2.md
├── Makefile
└── tree.go

4 directories, 5 files

Any invalid file or directory name will result in an error.

$ gtree mkdir --dry-run <<EOS
- root
  - aa
  - bb
    - b/b
EOS
invalid node name: b/b
$ gtree mkdir --dry-run <<EOS
- /root
  - aa
  - bb
    - bb
EOS
invalid node name: /root
Verify subcommand
$ gtree verify --help
NAME:
   gtree verify - Verifies tree structure represented in markdown by comparing it with existing directories.
                  Let's try 'gtree template | gtree verify'.

USAGE:
   gtree verify [command options] [arguments...]

OPTIONS:
   --file value, -f value  specify the path to markdown file. (default: stdin)
   --target-dir value      set this option if you want to specify the directory you want to verify. (default: current directory)
   --strict                set this option if you want strict directory match validation. (default: non strict)
   --help, -h              show help
Try it!
$ tree example
example
├── README.md
├── find_pipe_programmable-gtree
│   ├── README.md
│   ├── go.mod
│   ├── go.sum
│   └── main.go
├── go-list_pipe_programmable-gtree
│   ├── README.md
│   ├── go.mod
│   ├── go.sum
│   └── main.go
├── like_cli
│   ├── adapter
│   │   ├── executor.go
│   │   └── indentation.go
│   └── main.go
├── noexist
│   └── xxx
└── programmable
    └── main.go

6 directories, 14 files
$ cat testdata/sample9.md
- example
        - README.md
        - find_pipe_programmable-gtree
                - README.md
                - go.mod
                - go.sum
                - main.go
        - go-list_pipe_programmable-gtree
                - README.md
                - go.mod
                - go.sum
                - main.go
        - like_cli
                - adapter
                        - executor.go
                        - indentation.go
                - main.go
                - kkk
        - programmable
                - main.go
$ cat testdata/sample9.md | gtree verify --strict
Extra paths exist:
        example/noexist
        example/noexist/xxx
Required paths does not exist:
        example/like_cli/kkk

inspired by mactat/framed !

Library - Markdown to tree structure

Installation

Go version requires 1.24 or later.

$ go get github.com/ddddddO/gtree

Usage

The symbols that can be used in Markdown are *, -, +, and #.

Function Description Available optional functions
OutputFromMarkdown can output trees WithBranchFormatIntermedialNode
WithBranchFormatLastNode
WithEncodeJSON
WithEncodeTOML
WithEncodeYAML
WithMassive
MkdirFromMarkdown can create directories WithTargetDir
WithFileExtensions
WithDryRun
WithMassive
VerifyFromMarkdown can output the difference between markdown and directories WithTargetDir
WithStrictVerify
WithMassive
WalkFromMarkdown can execute user-defined function while traversing tree structure recursively WithBranchFormatIntermedialNode
WithBranchFormatLastNode
WithMassive

Library - Programmable tree structure

[!NOTE] There are sample repositories that use gtree library.
See here for details.

Installation

Go version requires 1.24 or later.

$ go get github.com/ddddddO/gtree

Usage

Function Description Available optional functions
OutputFromRoot can output tree WithBranchFormatIntermedialNode
WithBranchFormatLastNode
WithEncodeJSON
WithEncodeTOML
WithEncodeYAML
MkdirFromRoot can create directories WithTargetDir
WithFileExtensions
WithDryRun
VerifyFromRoot can output the difference between tree you composed and directories WithTargetDir
WithStrictVerify
WalkFromRoot can execute user-defined function while traversing tree structure recursively WithBranchFormatIntermedialNode
WithBranchFormatLastNode
WalkIterFromRoot it returns each node resulting from a recursive traversal of the tree structure, so you can process on each node WithBranchFormatIntermedialNode
WithBranchFormatLastNode

Process

[!NOTE] This process is for the Massive Roots mode.

e.g. gtree/pipeline_tree.go

Performance

see
ddddddo@debian:~/github.com/ddddddO/gtree$ make bench
rm -rf ./root/ ./root1/ ./root2/ ./root3/ ./root4/ ./root5/ ./root6/ ./root7/ ./root8/ Primate/ gtree/
rm -rf ./root_a/ ./root_b/ ./root_c/ ./root_d/ ./root_e/ ./root_f/ ./root_g/ ./root_h/ ./root_i/ ./root_j/
go test -benchmem -bench Benchmark -benchtime 100x benchmark_simple_test.go
goos: linux
goarch: amd64
cpu: 13th Gen Intel(R) Core(TM) i7-1370P
BenchmarkOutput_simple_singleRoot-20                 100             10149 ns/op            9987 B/op        231 allocs/op
BenchmarkOutput_simple_tenRoots-20                   100             70643 ns/op           59373 B/op       2121 allocs/op
BenchmarkOutput_simple_fiftyRoots-20                 100            315096 ns/op          281426 B/op      10488 allocs/op
BenchmarkOutput_simple_hundredRoots-20               100            586092 ns/op          578288 B/op      20942 allocs/op
BenchmarkOutput_simple_fiveHundredsRoots-20          100           2934791 ns/op         2817802 B/op     104552 allocs/op
BenchmarkOutput_simple_thousandRoots-20              100           6264854 ns/op         5785893 B/op     209058 allocs/op
BenchmarkOutput_simple_3000Roots-20                  100          18641680 ns/op        17045688 B/op     627068 allocs/op
BenchmarkOutput_simple_6000Roots-20                  100          38605597 ns/op        34247794 B/op    1254075 allocs/op
BenchmarkOutput_simple_10000Roots-20                 100          79987941 ns/op        59397951 B/op    2090080 allocs/op
BenchmarkOutput_simple_20000Roots-20                 100         153445564 ns/op        118746704 B/op   4180088 allocs/op
PASS
ok      command-line-arguments  30.503s
go test -benchmem -bench Benchmark -benchtime 100x benchmark_pipeline_test.go
goos: linux
goarch: amd64
cpu: 13th Gen Intel(R) Core(TM) i7-1370P
BenchmarkOutput_pipeline_singleRoot-20                       100             67536 ns/op           20754 B/op        356 allocs/op
BenchmarkOutput_pipeline_tenRoots-20                         100            235060 ns/op          115166 B/op       2715 allocs/op
BenchmarkOutput_pipeline_fiftyRoots-20                       100            800429 ns/op          544849 B/op      13215 allocs/op
BenchmarkOutput_pipeline_hundredRoots-20                     100           1566669 ns/op         1098099 B/op      26321 allocs/op
BenchmarkOutput_pipeline_fiveHundredsRoots-20                100           9370155 ns/op         5395556 B/op     131178 allocs/op
BenchmarkOutput_pipeline_thousandRoots-20                    100          19935090 ns/op        10937746 B/op     262249 allocs/op
BenchmarkOutput_pipeline_3000Roots-20                        100          61218588 ns/op        32470598 B/op     786461 allocs/op
BenchmarkOutput_pipeline_6000Roots-20                        100         140668786 ns/op        65080805 B/op    1572765 allocs/op
BenchmarkOutput_pipeline_10000Roots-20                       100         251359838 ns/op        110717084 B/op   2621057 allocs/op
BenchmarkOutput_pipeline_20000Roots-20                       100         517510413 ns/op        221188080 B/op   5241583 allocs/op
PASS
ok      command-line-arguments  101.444s
go test -benchmem -bench Benchmark -benchtime 100x benchmark_iterator_test.go
goos: linux
goarch: amd64
cpu: 13th Gen Intel(R) Core(TM) i7-1370P
BenchmarkOutput_iterator_singleRoot-20                       100             23219 ns/op           10966 B/op        265 allocs/op
BenchmarkOutput_iterator_tenRoots-20                         100             95018 ns/op           60049 B/op       2151 allocs/op
BenchmarkOutput_iterator_fiftyRoots-20                       100            415429 ns/op          281107 B/op      10516 allocs/op
BenchmarkOutput_iterator_hundredRoots-20                     100            801343 ns/op          576557 B/op      20969 allocs/op
BenchmarkOutput_iterator_fiveHundredsRoots-20                100           4025727 ns/op         2807096 B/op     104577 allocs/op
BenchmarkOutput_iterator_thousandRoots-20                    100           8343427 ns/op         5765146 B/op     209084 allocs/op
BenchmarkOutput_iterator_3000Roots-20                        100          20800851 ns/op        16965023 B/op     627100 allocs/op
BenchmarkOutput_iterator_6000Roots-20                        100          46313662 ns/op        34079177 B/op    1254118 allocs/op
BenchmarkOutput_iterator_10000Roots-20                       100          74729899 ns/op        59063939 B/op    2090141 allocs/op
BenchmarkOutput_iterator_20000Roots-20                       100         151050139 ns/op        117922359 B/op   4180162 allocs/op
PASS
ok      command-line-arguments  31.057s
ddddddo@debian:~/github.com/ddddddO/gtree$
old data

[!WARNING] The following benchmarks are for simple implementation before iterator implementation. The simple implementation is now an iterator implementation, and the performance of the simple implementation is better. Depends on the environment.

  • Comparison simple implementation and pipeline implementation.
  • In the case of few Roots, simple implementation is faster in execution!
    • Use this one by default.
  • However, for multiple Roots, pipeline implementation execution speed tends to be faster💪✨
    • In the CLI, it is available by specifying --massive.
    • In the Go program, it is available by specifying WithMassive func.
Benchmark log

Simple implementation

11:19:22 > go test -benchmem -bench Benchmark -benchtime 100x benchmark_simple_test.go
goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz
BenchmarkOutput_singleRoot-4                 100             35375 ns/op           13856 B/op        171 allocs/op
BenchmarkOutput_tenRoots-4                   100            200540 ns/op           72920 B/op       1597 allocs/op
BenchmarkOutput_fiftyRoots-4                 100            730156 ns/op          569851 B/op       7919 allocs/op
BenchmarkOutput_hundredRoots-4               100           1706493 ns/op         1714260 B/op      15820 allocs/op
BenchmarkOutput_fiveHundredsRoots-4          100          16412090 ns/op        32245140 B/op      79022 allocs/op
BenchmarkOutput_thousandRoots-4              100          55142492 ns/op        120929674 B/op    158025 allocs/op
BenchmarkOutput_3000Roots-4                  100         489121246 ns/op        1035617527 B/op   474029 allocs/op
BenchmarkOutput_6000Roots-4                  100        1613641261 ns/op        4087694372 B/op   948033 allocs/op
BenchmarkOutput_10000Roots-4                 100        3913090646 ns/op        11293191221 B/op         1580035 allocs/op
PASS
ok      command-line-arguments  614.944s

Pipeline implementation

11:29:43 > go test -benchmem -bench Benchmark -benchtime 100x benchmark_pipeline_test.go
goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz
BenchmarkOutput_pipeline_singleRoot-4                100            188706 ns/op           24236 B/op        300 allocs/op
BenchmarkOutput_pipeline_tenRoots-4                  100            367758 ns/op          115970 B/op       2186 allocs/op
BenchmarkOutput_pipeline_fiftyRoots-4                100            947879 ns/op          542188 B/op      10592 allocs/op
BenchmarkOutput_pipeline_hundredRoots-4              100           1711537 ns/op         1099636 B/op      21094 allocs/op
BenchmarkOutput_pipeline_fiveHundredsRoots-4         100           6892261 ns/op         5524905 B/op     105107 allocs/op
BenchmarkOutput_pipeline_thousandRoots-4             100          13100335 ns/op        11225942 B/op     210115 allocs/op
BenchmarkOutput_pipeline_3000Roots-4                 100          40694497 ns/op        33399766 B/op     630142 allocs/op
BenchmarkOutput_pipeline_6000Roots-4                 100          85807944 ns/op        66974524 B/op    1260171 allocs/op
BenchmarkOutput_pipeline_10000Roots-4                100         151486713 ns/op        113908462 B/op   2100208 allocs/op
PASS
ok      command-line-arguments  30.670s

Documents

English

Japanese

Test coverage

treemap

...generated by nikolaydubina/go-cover-treemap !

Stargazers over time

Stargazers over time

[^1]: Gopher retrieved from egonelbre/gophers !

Documentation

Overview

Package gtree provides output or directory creation of tree structure.

Example
package main

import (
	"bytes"
	"fmt"
	"os"

	"github.com/ddddddO/gtree"
)

func main() {
	var root *gtree.Node = gtree.NewRoot("root")
	root.Add("child 1").Add("child 2")
	root.Add("child 1").Add("child 3")
	child4 := root.Add("child 4")

	var child7 *gtree.Node = child4.Add("child 5").Add("child 6").Add("child 7")
	child7.Add("child 8")

	buf := &bytes.Buffer{}
	if err := gtree.OutputFromRoot(buf, root); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fmt.Println(buf.String())
}
Output:

root
├── child 1
│   ├── child 2
│   └── child 3
└── child 4
    └── child 5
        └── child 6
            └── child 7
                └── child 8

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNilNode is returned if the argument *gtree.Node of OutputProgrammably / MkdirProgrammably / VerifyProgrammably function is nill.
	ErrNilNode = errors.New("nil node")
	// ErrNotRoot is returned if the argument *gtree.Node of OutputProgrammably / MkdirProgrammably / VerifyProgrammably function is not root of the tree.
	ErrNotRoot = errors.New("not root node")
)
View Source
var (
	// ErrExistPath is returned if the argument *gtree.Node of MkdirProgrammably function is path already exists.
	ErrExistPath = errors.New("path already exists")
)

Functions

func Mkdir deprecated added in v1.3.0

func Mkdir(r io.Reader, options ...Option) error

Mkdir makes directories.

Deprecated: Call MkdirFromMarkdown.

func MkdirFromMarkdown added in v1.11.1

func MkdirFromMarkdown(r io.Reader, options ...Option) error

MkdirFromMarkdown makes directories.

func MkdirFromRoot added in v1.11.1

func MkdirFromRoot(root *Node, options ...Option) error

MkdirFromRoot makes directories. This function requires node generated by NewRoot function.

Example
package main

import (
	"fmt"
	"os"

	"github.com/ddddddO/gtree"
)

func main() {
	preparePrimate := func() *gtree.Node {
		primate := gtree.NewRoot("Primate")
		strepsirrhini := primate.Add("Strepsirrhini")
		haplorrhini := primate.Add("Haplorrhini")
		lemuriformes := strepsirrhini.Add("Lemuriformes")
		lorisiformes := strepsirrhini.Add("Lorisiformes")

		lemuroidea := lemuriformes.Add("Lemuroidea")
		lemuroidea.Add("Cheirogaleidae")
		lemuroidea.Add("Indriidae")
		lemuroidea.Add("Lemuridae")
		lemuroidea.Add("Lepilemuridae")

		lemuriformes.Add("Daubentonioidea").Add("Daubentoniidae")

		lorisiformes.Add("Galagidae")
		lorisiformes.Add("Lorisidae")

		haplorrhini.Add("Tarsiiformes").Add("Tarsiidae")
		simiiformes := haplorrhini.Add("Simiiformes")

		platyrrhini := haplorrhini.Add("Platyrrhini")
		ceboidea := platyrrhini.Add("Ceboidea")
		ceboidea.Add("Atelidae")
		ceboidea.Add("Cebidae")
		platyrrhini.Add("Pithecioidea").Add("Pitheciidae")

		catarrhini := simiiformes.Add("Catarrhini")
		catarrhini.Add("Cercopithecoidea").Add("Cercopithecidae")
		hominoidea := catarrhini.Add("Hominoidea")
		hominoidea.Add("Hylobatidae")
		hominoidea.Add("Hominidae")

		return primate
	}

	if err := gtree.MkdirFromRoot(preparePrimate()); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	// want(using Linux 'tree' command):
	// 22:20:43 > tree Primate/
	// Primate/
	// ├── Haplorrhini
	// │   ├── Simiiformes
	// │   │   ├── Catarrhini
	// │   │   │   ├── Cercopithecoidea
	// │   │   │   │   └── Cercopithecidae
	// │   │   │   └── Hominoidea
	// │   │   │       ├── Hominidae
	// │   │   │       └── Hylobatidae
	// │   │   └── Platyrrhini
	// │   │       ├── Ceboidea
	// │   │       │   ├── Atelidae
	// │   │       │   └── Cebidae
	// │   │       └── Pithecioidea
	// │   │           └── Pitheciidae
	// │   └── Tarsiiformes
	// │       └── Tarsiidae
	// └── Strepsirrhini
	// 	├── Lemuriformes
	// 	│   ├── Daubentonioidea
	// 	│   │   └── Daubentoniidae
	// 	│   └── Lemuroidea
	// 	│       ├── Cheirogaleidae
	// 	│       ├── Indriidae
	// 	│       ├── Lemuridae
	// 	│       └── Lepilemuridae
	// 	└── Lorisiformes
	// 		├── Galagidae
	// 		└── Lorisidae
	//
	// 28 directories, 0 files
}
Output:

Example (Second)
package main

import (
	"fmt"
	"os"

	"github.com/ddddddO/gtree"
)

func main() {
	gtreeDir := gtree.NewRoot("gtree")
	gtreeDir.Add("cmd").Add("gtree").Add("main.go")
	gtreeDir.Add("Makefile")
	testdataDir := gtreeDir.Add("testdata")
	testdataDir.Add("sample1.md")
	testdataDir.Add("sample2.md")
	gtreeDir.Add("tree.go")

	// make directories and files with specific extensions.
	if err := gtree.MkdirFromRoot(
		gtreeDir,
		gtree.WithFileExtensions([]string{".go", ".md", "Makefile"}),
	); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	// want(using Linux 'tree' command):
	// 09:44:50 > tree gtree/
	// gtree/
	// ├── cmd
	// │   └── gtree
	// │       └── main.go
	// ├── Makefile
	// ├── testdata
	// │   ├── sample1.md
	// │   └── sample2.md
	// └── tree.go
	//
	// 3 directories, 5 files
}
Output:

func MkdirProgrammably deprecated added in v1.3.0

func MkdirProgrammably(root *Node, options ...Option) error

MkdirProgrammably makes directories. This function requires node generated by NewRoot function.

Deprecated: Call MkdirFromRoot.

func Output deprecated added in v1.3.0

func Output(w io.Writer, r io.Reader, options ...Option) error

Output outputs a tree to w with r as Markdown format input.

Deprecated: Call OutputFromMarkdown.

func OutputFromMarkdown added in v1.11.1

func OutputFromMarkdown(w io.Writer, r io.Reader, options ...Option) error

OutputFromMarkdown outputs a tree to w with r as Markdown format input.

Example
package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"

	"github.com/ddddddO/gtree"
)

func main() {
	md := bytes.NewBufferString(strings.TrimSpace(`
- root
	- dddd
		- kkkkkkk
			- lllll
				- ffff
				- LLL
					- WWWWW
						- ZZZZZ
				- ppppp
					- KKK
						- 1111111
							- AAAAAAA
	- eee`))
	if err := gtree.OutputFromMarkdown(os.Stdout, md); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
Output:

root
├── dddd
│   └── kkkkkkk
│       └── lllll
│           ├── ffff
│           ├── LLL
│           │   └── WWWWW
│           │       └── ZZZZZ
│           └── ppppp
│               └── KKK
│                   └── 1111111
│                       └── AAAAAAA
└── eee
Example (Second)
package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"

	"github.com/ddddddO/gtree"
)

func main() {
	md := bytes.NewBufferString(strings.TrimSpace(`
- a
  - i
    - u
      - k
      - kk
    - t
  - e
    - o
  - g`))

	// You can customize branch format.
	if err := gtree.OutputFromMarkdown(os.Stdout, md,
		gtree.WithBranchFormatIntermedialNode("+->", ":   "),
		gtree.WithBranchFormatLastNode("+->", "    "),
	); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
Output:

a
+-> i
:   +-> u
:   :   +-> k
:   :   +-> kk
:   +-> t
+-> e
:   +-> o
+-> g

func OutputFromRoot added in v1.11.1

func OutputFromRoot(w io.Writer, root *Node, options ...Option) error

OutputFromRoot outputs tree to w. This function requires node generated by NewRoot function.

Example
package main

import (
	"fmt"
	"os"

	"github.com/ddddddO/gtree"
)

func main() {
	var root *gtree.Node = gtree.NewRoot("root")
	root.Add("child 1").Add("child 2").Add("child 3")
	var child4 *gtree.Node = root.Add("child 1").Add("child 2").Add("child 4")
	child4.Add("child 5")
	child4.Add("child 6").Add("child 7")
	root.Add("child 8")
	// you can customize branch format.
	if err := gtree.OutputFromRoot(os.Stdout, root,
		gtree.WithBranchFormatIntermedialNode("+--", ":   "),
		gtree.WithBranchFormatLastNode("+--", "    "),
	); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
Output:

root
+-- child 1
:   +-- child 2
:       +-- child 3
:       +-- child 4
:           +-- child 5
:           +-- child 6
:               +-- child 7
+-- child 8
Example (Second)
package main

import (
	"fmt"
	"os"

	"github.com/ddddddO/gtree"
)

func main() {
	preparePrimate := func() *gtree.Node {
		primate := gtree.NewRoot("Primate")
		strepsirrhini := primate.Add("Strepsirrhini")
		haplorrhini := primate.Add("Haplorrhini")
		lemuriformes := strepsirrhini.Add("Lemuriformes")
		lorisiformes := strepsirrhini.Add("Lorisiformes")

		lemuroidea := lemuriformes.Add("Lemuroidea")
		lemuroidea.Add("Cheirogaleidae")
		lemuroidea.Add("Indriidae")
		lemuroidea.Add("Lemuridae")
		lemuroidea.Add("Lepilemuridae")

		lemuriformes.Add("Daubentonioidea").Add("Daubentoniidae")

		lorisiformes.Add("Galagidae")
		lorisiformes.Add("Lorisidae")

		haplorrhini.Add("Tarsiiformes").Add("Tarsiidae")
		simiiformes := haplorrhini.Add("Simiiformes")

		platyrrhini := haplorrhini.Add("Platyrrhini")
		ceboidea := platyrrhini.Add("Ceboidea")
		ceboidea.Add("Atelidae")
		ceboidea.Add("Cebidae")
		platyrrhini.Add("Pithecioidea").Add("Pitheciidae")

		catarrhini := simiiformes.Add("Catarrhini")
		catarrhini.Add("Cercopithecoidea").Add("Cercopithecidae")
		hominoidea := catarrhini.Add("Hominoidea")
		hominoidea.Add("Hylobatidae")
		hominoidea.Add("Hominidae")

		return primate
	}

	primate := preparePrimate()
	// default branch format.
	if err := gtree.OutputFromRoot(os.Stdout, primate); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
Output:

Primate
├── Strepsirrhini
│   ├── Lemuriformes
│   │   ├── Lemuroidea
│   │   │   ├── Cheirogaleidae
│   │   │   ├── Indriidae
│   │   │   ├── Lemuridae
│   │   │   └── Lepilemuridae
│   │   └── Daubentonioidea
│   │       └── Daubentoniidae
│   └── Lorisiformes
│       ├── Galagidae
│       └── Lorisidae
└── Haplorrhini
    ├── Tarsiiformes
    │   └── Tarsiidae
    ├── Simiiformes
    │   └── Catarrhini
    │       ├── Cercopithecoidea
    │       │   └── Cercopithecidae
    │       └── Hominoidea
    │           ├── Hylobatidae
    │           └── Hominidae
    └── Platyrrhini
        ├── Ceboidea
        │   ├── Atelidae
        │   └── Cebidae
        └── Pithecioidea
            └── Pitheciidae
Example (Third)
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	"github.com/ddddddO/gtree"
)

func main() {
	// Example: The program below converts the result of `find` into a tree.
	//
	// $ cd github.com/ddddddO/gtree
	// $ find . -type d -name .git -prune -o -type f -print
	// ./config.go
	// ./node_generator_test.go
	// ./example/like_cli/adapter/indentation.go
	// ./example/like_cli/adapter/executor.go
	// ./example/like_cli/main.go
	// ./example/find_pipe_programmable-gtree/main.go
	// ...
	// $ find . -type d -name .git -prune -o -type f -print | go run example/find_pipe_programmable-gtree/main.go
	// << See "want:" below. >>
	var (
		root *gtree.Node
		node *gtree.Node
	)
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line := scanner.Text()              // e.g.) "./example/find_pipe_programmable-gtree/main.go"
		splited := strings.Split(line, "/") // e.g.) [. example find_pipe_programmable-gtree main.go]

		for i, s := range splited {
			if root == nil {
				root = gtree.NewRoot(s) // s := "."
				node = root
				continue
			}
			if i == 0 {
				continue
			}

			tmp := node.Add(s)
			node = tmp
		}
		node = root
	}

	if err := gtree.OutputFromRoot(os.Stdout, root); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	// want:
	// .
	// ├── config.go
	// ├── node_generator_test.go
	// ├── example
	// │   ├── like_cli
	// │   │   ├── adapter
	// │   │   │   ├── indentation.go
	// │   │   │   └── executor.go
	// │   │   └── main.go
	// │   ├── find_pipe_programmable-gtree
	// │   │   └── main.go
	// │   ├── go-list_pipe_programmable-gtree
	// │   │   └── main.go
	// │   └── programmable
	// │       └── main.go
	// ├── file_considerer.go
	// ├── node.go
	// ├── node_generator.go
	// ├── .gitignore
	// ...
}
Output:

func OutputProgrammably deprecated added in v1.3.0

func OutputProgrammably(w io.Writer, root *Node, options ...Option) error

OutputProgrammably outputs tree to w. This function requires node generated by NewRoot function.

Deprecated: Call OutputFromRoot.

func Verify deprecated added in v1.9.1

func Verify(r io.Reader, options ...Option) error

Verify verifies directories.

Deprecated: Call VerifyFromMarkdown.

func VerifyFromMarkdown added in v1.11.1

func VerifyFromMarkdown(r io.Reader, options ...Option) error

VerifyFromMarkdown verifies directories.

func VerifyFromRoot added in v1.11.1

func VerifyFromRoot(root *Node, options ...Option) error

VerifyFromRoot verifies directory. This function requires node generated by NewRoot function.

func VerifyProgrammably deprecated added in v1.9.1

func VerifyProgrammably(root *Node, options ...Option) error

VerifyProgrammably verifies directory. This function requires node generated by NewRoot function.

Deprecated: Call VerifyFromRoot.

func Walk deprecated added in v1.10.0

func Walk(r io.Reader, callback func(*WalkerNode) error, options ...Option) error

Walk executes user-defined function while traversing tree structure recursively.

Deprecated: Call WalkFromMarkdown.

func WalkFromMarkdown added in v1.11.1

func WalkFromMarkdown(r io.Reader, callback func(*WalkerNode) error, options ...Option) error

WalkFromMarkdown executes user-defined function while traversing tree structure recursively.

Example
package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/ddddddO/gtree"
)

func main() {
	md := strings.TrimSpace(`
- a
	- i
		- u
			- k
	- kk
		- t
- e
	- o
		- g`)

	callback := func(wn *gtree.WalkerNode) error {
		fmt.Println(wn.Row())
		return nil
	}

	if err := gtree.WalkFromMarkdown(strings.NewReader(md), callback); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
Output:

a
├── i
│   └── u
│       └── k
└── kk
    └── t
e
└── o
    └── g
Example (Second)
package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/ddddddO/gtree"
)

func main() {
	md := strings.TrimSpace(`
- a
	- i
		- u
			- k
	- kk
		- t
- e
	- o
		- g`)

	callback := func(wn *gtree.WalkerNode) error {
		fmt.Println("WalkerNode's methods called...")
		fmt.Printf("\tName     : %s\n", wn.Name())
		fmt.Printf("\tBranch   : %s\n", wn.Branch())
		fmt.Printf("\tRow      : %s\n", wn.Row())
		fmt.Printf("\tLevel    : %d\n", wn.Level())
		fmt.Printf("\tPath     : %s\n", wn.Path())
		fmt.Printf("\tHasChild : %t\n", wn.HasChild())
		return nil
	}

	if err := gtree.WalkFromMarkdown(strings.NewReader(md), callback); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	// want:
	// WalkerNode's methods called...
	//	Name     : a
	//	Branch   :
	//	Row      : a
	//	Level    : 1
	//	Path     : a
	//	HasChild : true
	// WalkerNode's methods called...
	//	Name     : i
	//	Branch   : ├──
	//	Row      : ├── i
	//	Level    : 2
	//	Path     : a/i
	//	HasChild : true
	// WalkerNode's methods called...
	//	Name     : u
	//	Branch   : │   └──
	//	Row      : │   └── u
	//	Level    : 3
	//	Path     : a/i/u
	//	HasChild : true
	// WalkerNode's methods called...
	//	Name     : k
	//	Branch   : │       └──
	//	Row      : │       └── k
	//	Level    : 4
	//	Path     : a/i/u/k
	//	HasChild : false
	// WalkerNode's methods called...
	//	Name     : kk
	//	Branch   : └──
	//	Row      : └── kk
	//	Level    : 2
	//	Path     : a/kk
	//	HasChild : true
	// WalkerNode's methods called...
	//	Name     : t
	//	Branch   :     └──
	//	Row      :     └── t
	//	Level    : 3
	//	Path     : a/kk/t
	//	HasChild : false
	// WalkerNode's methods called...
	//	Name     : e
	//	Branch   :
	//	Row      : e
	//	Level    : 1
	//	Path     : e
	//	HasChild : true
	// WalkerNode's methods called...
	//	Name     : o
	//	Branch   : └──
	//	Row      : └── o
	//	Level    : 2
	//	Path     : e/o
	//	HasChild : true
	// WalkerNode's methods called...
	//	Name     : g
	//	Branch   :     └──
	//	Row      :     └── g
	//	Level    : 3
	//	Path     : e/o/g
	//	HasChild : false
}
Output:

func WalkFromRoot added in v1.11.1

func WalkFromRoot(root *Node, callback func(*WalkerNode) error, options ...Option) error

WalkFromRoot executes user-defined function while traversing tree structure recursively. This function requires node generated by NewRoot function.

Example
package main

import (
	"fmt"
	"os"

	"github.com/ddddddO/gtree"
)

func main() {
	root := gtree.NewRoot("root")
	root.Add("child 1").Add("child 2").Add("child 3")
	root.Add("child 5")
	root.Add("child 1").Add("child 2").Add("child 4")

	callback := func(wn *gtree.WalkerNode) error {
		fmt.Println(wn.Row())
		return nil
	}

	if err := gtree.WalkFromRoot(root, callback); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
Output:

root
├── child 1
│   └── child 2
│       ├── child 3
│       └── child 4
└── child 5
Example (Second)
package main

import (
	"fmt"
	"os"

	"github.com/ddddddO/gtree"
)

func main() {
	root := gtree.NewRoot("root")
	root.Add("child 1").Add("child 2").Add("child 3")
	root.Add("child 5")
	root.Add("child 1").Add("child 2").Add("child 4")

	callback := func(wn *gtree.WalkerNode) error {
		fmt.Println("WalkerNode's methods called...")
		fmt.Printf("\tName     : %s\n", wn.Name())
		fmt.Printf("\tBranch   : %s\n", wn.Branch())
		fmt.Printf("\tRow      : %s\n", wn.Row())
		fmt.Printf("\tLevel    : %d\n", wn.Level())
		fmt.Printf("\tPath     : %s\n", wn.Path())
		fmt.Printf("\tHasChild : %t\n", wn.HasChild())
		return nil
	}

	if err := gtree.WalkFromRoot(root, callback); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	// want:
	// WalkerNode's methods called...
	//         Name     : root
	//         Branch   :
	//         Row      : root
	//         Level    : 1
	//         Path     : root
	//         HasChild : true
	// WalkerNode's methods called...
	//         Name     : child 1
	//         Branch   : ├──
	//         Row      : ├── child 1
	//         Level    : 2
	//         Path     : root/child 1
	//         HasChild : true
	// WalkerNode's methods called...
	//         Name     : child 2
	//         Branch   : │   └──
	//         Row      : │   └── child 2
	//         Level    : 3
	//         Path     : root/child 1/child 2
	//         HasChild : true
	// WalkerNode's methods called...
	//         Name     : child 3
	//         Branch   : │       ├──
	//         Row      : │       ├── child 3
	//         Level    : 4
	//         Path     : root/child 1/child 2/child 3
	//         HasChild : false
	// WalkerNode's methods called...
	//         Name     : child 4
	//         Branch   : │       └──
	//         Row      : │       └── child 4
	//         Level    : 4
	//         Path     : root/child 1/child 2/child 4
	//         HasChild : false
	// WalkerNode's methods called...
	//         Name     : child 5
	//         Branch   : └──
	//         Row      : └── child 5
	//         Level    : 2
	//         Path     : root/child 5
	//         HasChild : false
}
Output:

func WalkIterFromRoot added in v1.11.1

func WalkIterFromRoot(root *Node, options ...Option) iter.Seq2[*WalkerNode, error]

WalkIterFromRoot returns each node resulting from recursively traversing tree structure. This function requires node generated by NewRoot function.

Example
package main

import (
	"fmt"
	"os"

	"github.com/ddddddO/gtree"
)

func main() {
	root := gtree.NewRoot("root")
	root.Add("child 1").Add("child 2").Add("child 3")
	root.Add("child 5")
	root.Add("child 1").Add("child 2").Add("child 4")

	for wn, err := range gtree.WalkIterFromRoot(root) {
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		fmt.Println(wn.Row())
	}
}
Output:

root
├── child 1
│   └── child 2
│       ├── child 3
│       └── child 4
└── child 5

func WalkIterProgrammably deprecated added in v1.11.0

func WalkIterProgrammably(root *Node, options ...Option) iter.Seq2[*WalkerNode, error]

WalkIterProgrammably returns each node resulting from recursively traversing tree structure. This function requires node generated by NewRoot function.

Deprecated: Call WalkIterFromRoot.

func WalkProgrammably deprecated added in v1.10.0

func WalkProgrammably(root *Node, callback func(*WalkerNode) error, options ...Option) error

WalkProgrammably executes user-defined function while traversing tree structure recursively. This function requires node generated by NewRoot function.

Deprecated: Call WalkFromRoot.

Types

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node is main struct for gtree.

func NewRoot

func NewRoot(text string) *Node

NewRoot creates a starting node for building tree.

func (*Node) Add

func (parent *Node) Add(text string) *Node

Add adds a node and returns an instance of it. If a node with the same text already exists in the same hierarchy of the tree, that node will be returned.

type Option added in v1.5.0

type Option func(*config)

Option is functional options pattern

func WithBranchFormatIntermedialNode added in v1.3.0

func WithBranchFormatIntermedialNode(directly, indirectly string) Option

WithBranchFormatIntermedialNode returns function for branch format.

func WithBranchFormatLastNode added in v1.3.0

func WithBranchFormatLastNode(directly, indirectly string) Option

WithBranchFormatLastNode returns function for branch format.

func WithDryRun added in v1.3.0

func WithDryRun() Option

WithDryRun returns function for dry run. Detects node that is invalid for directory generation.

func WithEncodeJSON added in v1.3.0

func WithEncodeJSON() Option

WithEncodeJSON returns function for output json format.

func WithEncodeTOML added in v1.3.0

func WithEncodeTOML() Option

WithEncodeTOML returns function for output toml format.

func WithEncodeYAML added in v1.3.0

func WithEncodeYAML() Option

WithEncodeYAML returns function for output yaml format.

func WithFileExtensions added in v1.5.0

func WithFileExtensions(extensions []string) Option

WithFileExtensions returns function for creating as a file instead of a directory.

func WithMassive added in v1.8.0

func WithMassive(ctx context.Context) Option

WithMassive returns function for large amount roots.

func WithNoUseIterOfSimpleOutput deprecated added in v1.11.3

func WithNoUseIterOfSimpleOutput() Option

Deprecated: This is for benchmark testing.

func WithStrictVerify added in v1.9.1

func WithStrictVerify() Option

WithStrictVerify returns function for verifing directory strictly.

func WithTargetDir added in v1.9.1

func WithTargetDir(dir string) Option

WithTargetDir returns function for specifying directory. Default is current directory.

type WalkerNode added in v1.10.0

type WalkerNode struct {
	// contains filtered or unexported fields
}

WalkerNode is used in user-defined function that can be executed with Walk/WalkProgrammably function.

func (*WalkerNode) Branch added in v1.10.0

func (wn *WalkerNode) Branch() string

Branch returns branch of node in completed tree structure.

func (*WalkerNode) HasChild added in v1.10.2

func (wn *WalkerNode) HasChild() bool

HasChild returns whether the node in completed tree structure has child nodes.

func (*WalkerNode) Level added in v1.10.0

func (wn *WalkerNode) Level() uint

Level returns level of node in completed tree structure.

func (*WalkerNode) Name added in v1.10.0

func (wn *WalkerNode) Name() string

Name returns name of node in completed tree structure.

func (*WalkerNode) Path added in v1.10.0

func (wn *WalkerNode) Path() string

Path returns path of node in completed tree structure. Path is the path from the root node to this node. The separator is / in any OS execution environment.

func (*WalkerNode) Row added in v1.10.0

func (wn *WalkerNode) Row() string

Row returns row of node in completed tree structure.

Directories

Path Synopsis
cmd
example

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL