├── CONTRIBUTING.md ├── Godeps ├── Godeps.json ├── Readme └── _workspace │ └── .gitignore ├── LICENSE ├── README.md ├── bin └── vet ├── build ├── circle.yml ├── dist ├── README.md ├── ftree-darwin-386 ├── ftree-darwin-386.sha256 ├── ftree-darwin-386.sig ├── ftree-darwin-amd64 ├── ftree-darwin-amd64.sha256 ├── ftree-darwin-amd64.sig ├── ftree-freebsd-386 ├── ftree-freebsd-386.sha256 ├── ftree-freebsd-386.sig ├── ftree-freebsd-amd64 ├── ftree-freebsd-amd64.sha256 ├── ftree-freebsd-amd64.sig ├── ftree-freebsd-arm ├── ftree-freebsd-arm.sha256 ├── ftree-freebsd-arm.sig ├── ftree-linux-386 ├── ftree-linux-386.sha256 ├── ftree-linux-386.sig ├── ftree-linux-amd64 ├── ftree-linux-amd64.sha256 ├── ftree-linux-amd64.sig ├── ftree-linux-arm ├── ftree-linux-arm.sha256 ├── ftree-linux-arm.sig ├── ftree-openbsd-386 ├── ftree-openbsd-386.sha256 ├── ftree-openbsd-386.sig ├── ftree-openbsd-amd64 ├── ftree-openbsd-amd64.sha256 ├── ftree-openbsd-amd64.sig ├── ftree-windows-386 ├── ftree-windows-386.sha256 ├── ftree-windows-386.sig ├── ftree-windows-amd64 ├── ftree-windows-amd64.sha256 └── ftree-windows-amd64.sig ├── main.go └── tree ├── node.go ├── node_test.go ├── tree.go └── tree_test.go /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | We love pull requests from everyone. 5 | 6 | Fork the repo. 7 | 8 | Get a working [Go installation], 9 | and clone the project into your [Go work environment] 10 | \(that is, `$GOPATH/src/github.com/thoughtbot/ftree`). 11 | If your Go environment is already set up, you can get the code instead with 12 | `go get github.com/thoughtbot/ftree`. It will be in the same location as the 13 | previous path. 14 | 15 | [Go installation]: http://golang.org/doc/install 16 | [Go work environment]: http://golang.org/doc/code.html 17 | 18 | ## Dependencies 19 | 20 | We use `godep` to manage dependencies. You can install that with 21 | `go get github.com/tools/godep`. You don't need to unless you're making changes 22 | to the dependencies. 23 | 24 | If you add or update a dependency, 25 | run `godep save ./...` to vendor the changes. 26 | 27 | ## Developing 28 | 29 | You can compile and run the current code with `go run main.go`. 30 | 31 | ## Testing 32 | 33 | To test the `ftree` package, run `go test ./...`. 34 | 35 | ## Installing 36 | 37 | To install the `ftree` binary, run `go install ./...`. 38 | 39 | ## Building 40 | 41 | To build the `ftree` binary, run `go build`. `go test` and `go install` do 42 | this for you, but if you need the artifact this is how you can get that. 43 | 44 | ## Changes 45 | 46 | Make your change, with new passing tests. 47 | 48 | Push to your fork. Write a [good commit message][commit]. Submit a pull request. 49 | 50 | [commit]: https://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-messag://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message 51 | 52 | Others will give constructive feedback. 53 | This is a time for discussion and improvements, 54 | and making the necessary changes will be required before we can 55 | merge the contribution. 56 | -------------------------------------------------------------------------------- /Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "github.com/calebthompson/ftree", 3 | "GoVersion": "go1.5.1", 4 | "Deps": [] 5 | } 6 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /Godeps/_workspace/.gitignore: -------------------------------------------------------------------------------- 1 | /pkg 2 | /bin 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Caleb Thompson & thoughtbot 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ftree 2 | ===== 3 | 4 | Convert lists of files into `tree(1)`-like output. 5 | 6 | Usage 7 | ----- 8 | 9 | ```shell 10 | ❯ git ls-files | ftree 11 | ├── README.md 12 | └── ftree.go 13 | 14 | ❯ lsrc | cut -f 1 -d : | ftree 15 | └── Users/gordon 16 | ├── .agignore 17 | ├── .config 18 | │ ├── git 19 | │ │ ├── config 20 | │ │ └── ignore 21 | │ └── zsh 22 | │ ├── aliases.zsh 23 | │ ├── completion.zsh 24 | │ └── prompt.zsh 25 | ├── .gemrc 26 | ├── .local/bin 27 | │ ├── addcontact 28 | │ ├── git-review 29 | │ ├── keychain.py 30 | │ └── tat 31 | ├── .muttrc 32 | ├── .rcrc 33 | ├── .vimrc 34 | └── .zshrc 35 | 36 | ❯ find ~/code/jsbox/{app,spec}/models 37 | /Users/caleb/code/jsbox/app/models 38 | /Users/caleb/code/jsbox/app/models/.keep 39 | /Users/caleb/code/jsbox/app/models/analytics.rb 40 | /Users/caleb/code/jsbox/app/models/concerns 41 | /Users/caleb/code/jsbox/app/models/concerns/.keep 42 | /Users/caleb/code/jsbox/app/models/execution_record.rb 43 | /Users/caleb/code/jsbox/app/models/guest.rb 44 | /Users/caleb/code/jsbox/app/models/organization.rb 45 | /Users/caleb/code/jsbox/app/models/script.rb 46 | /Users/caleb/code/jsbox/app/models/script_runner.rb 47 | /Users/caleb/code/jsbox/app/models/subscription.rb 48 | /Users/caleb/code/jsbox/app/models/user.rb 49 | /Users/caleb/code/jsbox/spec/models 50 | /Users/caleb/code/jsbox/spec/models/script_runner_spec.rb 51 | /Users/caleb/code/jsbox/spec/models/script_spec.rb 52 | /Users/caleb/code/jsbox/spec/models/subscription_spec.rb 53 | /Users/caleb/code/jsbox/spec/models/user_spec.rb 54 | 55 | ❯ !! | ftree 56 | └── Users/caleb/code/jsbox 57 | ├── app/models 58 | │ ├── .keep 59 | │ ├── analytics.rb 60 | │ ├── concerns/.keep 61 | │ ├── execution_record.rb 62 | │ ├── guest.rb 63 | │ ├── organization.rb 64 | │ ├── script.rb 65 | │ ├── script_runner.rb 66 | │ ├── subscription.rb 67 | │ └── user.rb 68 | └── spec/models 69 | ├── script_runner_spec.rb 70 | ├── script_spec.rb 71 | ├── subscription_spec.rb 72 | └── user_spec.rb 73 | ``` 74 | 75 | Installation 76 | ------------ 77 | 78 | See [/dist](/dist). 79 | 80 | 81 | About 82 | ----- 83 | 84 | `ftree` is maintained by Caleb Thompson and [thoughtbot's Go development team]. 85 | 86 | [thoughtbot's Go development team]: "Go development team | Hire thoughtbot Gophers" 87 | 88 | ![thoughtbot](https://thoughtbot.com/logo.png) 89 | 90 | The names and logos for thoughtbot are trademarks of thoughtbot, inc. 91 | -------------------------------------------------------------------------------- /bin/vet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # validates that the project is clean of formatting and vet errors. 4 | # symlink as .git/hooks/pre-commit to use as a pre-commit check. 5 | # 6 | 7 | if [[ -n "${GIT_INDEX_FILE}" ]]; then 8 | gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$') 9 | else 10 | gofiles=$(find . ! -path "*/_*" -name "*.go") 11 | fi 12 | 13 | [ -z "$gofiles" ] && exit 0 14 | 15 | function checkfmt() { 16 | unformatted=$(gofmt -l $*) 17 | [ -z "$unformatted" ] && return 0 18 | 19 | echo >&2 "Go files must be formatted with gofmt. Please run:" 20 | for fn in $unformatted; do 21 | echo >&2 " gofmt -w $PWD/$fn" 22 | done 23 | 24 | return 1 25 | } 26 | 27 | function checkvet() { 28 | unvetted=$(go vet ./... 2>&1 | grep -v "exit status") 29 | [ -z "$unvetted" ] && return 0 30 | 31 | echo >&2 "Go files must be vetted. Check these problems:" 32 | IFS=$'\n' 33 | for line in $unvetted; do 34 | echo >&2 " $line" 35 | done 36 | unset IFS 37 | 38 | return 1 39 | } 40 | 41 | checkfmt $gofiles || fail=yes 42 | checkvet $gofiles || fail=yes 43 | 44 | [ -z "$fail" ] || exit 1 45 | -------------------------------------------------------------------------------- /build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2012 The Go Authors. All rights reserved. 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file. 5 | 6 | # support functions for go cross compilation 7 | 8 | type setopt >/dev/null 2>&1 && setopt shwordsplit 9 | PLATFORMS="darwin/386 darwin/amd64 freebsd/386 freebsd/amd64 freebsd/arm linux/386 linux/amd64 linux/arm windows/386 windows/amd64 openbsd/386 openbsd/amd64" 10 | 11 | function go-build-all { 12 | rm dist/ftree-* 13 | local FAILURES="" 14 | for PLATFORM in $PLATFORMS; do 15 | local GOOS=${PLATFORM%/*} 16 | local GOARCH=${PLATFORM#*/} 17 | local SRCFILENAME=`echo $@ | sed 's/\.go//'` 18 | local CURDIRNAME=${PWD##*/} 19 | local OUTPUT="${SRCFILENAME:-$CURDIRNAME}-${GOOS}-${GOARCH}" # if no src file given, use current dir name 20 | local CMD="env GOOS=$GOOS GOARCH=$GOARCH go build -o dist/$OUTPUT" 21 | echo "$CMD" 22 | $CMD || (FAILURES="$FAILURES $PLATFORM" && continue) 23 | local SIGN="gpg2 --detach-sign dist/$OUTPUT" 24 | echo "$SIGN" 25 | $SIGN || (FAILURES="$FAILURES gpg:$PLATFORM" && continue) 26 | local SUM="shasum --algorithm=256 $OUTPUT" 27 | echo "$SUM" 28 | $( cd dist/ && $SUM > $OUTPUT.sha256 || (FAILURES="$FAILURES sha:$PLATFORM" && continue)) 29 | done 30 | if [ "$FAILURES" != "" ]; then 31 | echo "*** go-build-all FAILED on $FAILURES ***" 32 | return 1 33 | fi 34 | } 35 | 36 | go-build-all 37 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | # See https://robots.thoughtbot.com/configure-circleci-for-go 2 | machine: 3 | environment: 4 | IMPORT_PATH: "github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME" 5 | MYGOPATH: "$(echo $GOPATH | cut -d : -f 1)" 6 | 7 | dependencies: 8 | pre: 9 | - go get github.com/tools/godep 10 | 11 | override: 12 | - mkdir -p "$MYGOPATH/src/$IMPORT_PATH" 13 | - rsync -azC --delete ./ "$MYGOPATH/src/$IMPORT_PATH/" 14 | 15 | test: 16 | pre: 17 | - bin/vet 18 | 19 | override: 20 | - godep go test ./... 21 | -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | # Installing 2 | 3 | Pick the binary that matches your operating system and architecture. For 4 | example, on my Macbook Pro I would use `ftree-darwin-amd64`. Copy that somewhere 5 | in your path and rename to `ftree`. Presto bango. 6 | 7 | ## Verifying 8 | 9 | The best way to verify the release is to examine the PGP signature. You can find 10 | my public key at http://calebthompson.io/pubkey.asc, 11 | , and via GnuPG 12 | with `gpg --recv-keys A0ACE70A`. 13 | 14 | You can find a signed and verifiable statement of my ownership of that key at 15 | . 16 | 17 | Once you have that key, verification with: 18 | 19 | ```shell 20 | $ gpg --verify ftree--.sig ftree-- 21 | ``` 22 | 23 | If you don't have GnuPG, you can verify the SHA sums. 24 | 25 | ```shell 26 | $ shasum --algorithm 256 --check ftree--.sha256 27 | ``` 28 | -------------------------------------------------------------------------------- /dist/ftree-darwin-386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-darwin-386 -------------------------------------------------------------------------------- /dist/ftree-darwin-386.sha256: -------------------------------------------------------------------------------- 1 | a5267b5816b9f9ab8b89af6a1779bd071304b429f06dacd5179aaab566985206 ftree-darwin-386 2 | -------------------------------------------------------------------------------- /dist/ftree-darwin-386.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-darwin-386.sig -------------------------------------------------------------------------------- /dist/ftree-darwin-amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-darwin-amd64 -------------------------------------------------------------------------------- /dist/ftree-darwin-amd64.sha256: -------------------------------------------------------------------------------- 1 | a7342c0f695e229092aa304e2ffd7908035e9ff6e237acdf4650e2783c862212 ftree-darwin-amd64 2 | -------------------------------------------------------------------------------- /dist/ftree-darwin-amd64.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-darwin-amd64.sig -------------------------------------------------------------------------------- /dist/ftree-freebsd-386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-freebsd-386 -------------------------------------------------------------------------------- /dist/ftree-freebsd-386.sha256: -------------------------------------------------------------------------------- 1 | d5af8edc8fe70f4d47962fedd43a1cb78feb9ac4c31fdc7eb2993fbac297a029 ftree-freebsd-386 2 | -------------------------------------------------------------------------------- /dist/ftree-freebsd-386.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-freebsd-386.sig -------------------------------------------------------------------------------- /dist/ftree-freebsd-amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-freebsd-amd64 -------------------------------------------------------------------------------- /dist/ftree-freebsd-amd64.sha256: -------------------------------------------------------------------------------- 1 | 974675de42485775a7680b17d64a959774d3f30938031a9c0cc769b3d8390ecd ftree-freebsd-amd64 2 | -------------------------------------------------------------------------------- /dist/ftree-freebsd-amd64.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-freebsd-amd64.sig -------------------------------------------------------------------------------- /dist/ftree-freebsd-arm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-freebsd-arm -------------------------------------------------------------------------------- /dist/ftree-freebsd-arm.sha256: -------------------------------------------------------------------------------- 1 | 4f40bc23fd27528c425ced3589390f236e21f0315be709d25feda1fcc6bec327 ftree-freebsd-arm 2 | -------------------------------------------------------------------------------- /dist/ftree-freebsd-arm.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-freebsd-arm.sig -------------------------------------------------------------------------------- /dist/ftree-linux-386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-linux-386 -------------------------------------------------------------------------------- /dist/ftree-linux-386.sha256: -------------------------------------------------------------------------------- 1 | 63db38af6cc935e5932e39262b7c74f23a9d86391b72f20e8653c1f05bd64d51 ftree-linux-386 2 | -------------------------------------------------------------------------------- /dist/ftree-linux-386.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-linux-386.sig -------------------------------------------------------------------------------- /dist/ftree-linux-amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-linux-amd64 -------------------------------------------------------------------------------- /dist/ftree-linux-amd64.sha256: -------------------------------------------------------------------------------- 1 | 6db6ca1bcf1b71c17efd217e191858918beceed6fac2377f248147b2426794ed ftree-linux-amd64 2 | -------------------------------------------------------------------------------- /dist/ftree-linux-amd64.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-linux-amd64.sig -------------------------------------------------------------------------------- /dist/ftree-linux-arm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-linux-arm -------------------------------------------------------------------------------- /dist/ftree-linux-arm.sha256: -------------------------------------------------------------------------------- 1 | 125b671a679f31aea7bed5d7e5084d48b2ba8bd9c60bc182583184c3ab468e65 ftree-linux-arm 2 | -------------------------------------------------------------------------------- /dist/ftree-linux-arm.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-linux-arm.sig -------------------------------------------------------------------------------- /dist/ftree-openbsd-386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-openbsd-386 -------------------------------------------------------------------------------- /dist/ftree-openbsd-386.sha256: -------------------------------------------------------------------------------- 1 | 784ecb724d0a278ec01a838965f40f3752675a253005216d8f1cbe5b59e27b94 ftree-openbsd-386 2 | -------------------------------------------------------------------------------- /dist/ftree-openbsd-386.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-openbsd-386.sig -------------------------------------------------------------------------------- /dist/ftree-openbsd-amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-openbsd-amd64 -------------------------------------------------------------------------------- /dist/ftree-openbsd-amd64.sha256: -------------------------------------------------------------------------------- 1 | 55879adec498eb68a54ec5f103dab6e6cc576bd29d6dffce54b0ff2cd98a7bb0 ftree-openbsd-amd64 2 | -------------------------------------------------------------------------------- /dist/ftree-openbsd-amd64.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-openbsd-amd64.sig -------------------------------------------------------------------------------- /dist/ftree-windows-386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-windows-386 -------------------------------------------------------------------------------- /dist/ftree-windows-386.sha256: -------------------------------------------------------------------------------- 1 | 7a7ec6d2c0f4526b0e3bf24cc4d8f595bba8206b9e02ce2466ad9a5aa3318925 ftree-windows-386 2 | -------------------------------------------------------------------------------- /dist/ftree-windows-386.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-windows-386.sig -------------------------------------------------------------------------------- /dist/ftree-windows-amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-windows-amd64 -------------------------------------------------------------------------------- /dist/ftree-windows-amd64.sha256: -------------------------------------------------------------------------------- 1 | 8a11b9bf7b0ed2f4b3c33a068dd8cdc62192a620294b607959cdf006bb67f483 ftree-windows-amd64 2 | -------------------------------------------------------------------------------- /dist/ftree-windows-amd64.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/ftree/33aa20fb08346690cf679e0665a51d58fbc9c06b/dist/ftree-windows-amd64.sig -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/calebthompson/ftree/tree" 9 | ) 10 | 11 | const ( 12 | version = "v0.2.0" 13 | help = `Pipe output from some command that lists a single file per line to ftree. 14 | find . | ftree 15 | git ls-files {app,spec}/models | ftree 16 | lsrc | cut -d : -f 1 | ftree 17 | ` 18 | ) 19 | 20 | func main() { 21 | handleArguments() 22 | 23 | r := bufio.NewScanner(os.Stdin) 24 | lines := []string{} 25 | for r.Scan() { 26 | lines = append(lines, r.Text()) 27 | } 28 | 29 | t := tree.Tree(lines, "/") 30 | t.Print(0, nil) 31 | } 32 | 33 | func handleArguments() { 34 | for _, a := range os.Args[1:] { 35 | switch a { 36 | case "--version", "-v": 37 | fmt.Printf("ftree %s\n", version) 38 | os.Exit(0) 39 | case "--help", "-h": 40 | fmt.Print(help) 41 | os.Exit(0) 42 | default: 43 | fmt.Fprintf(os.Stderr, "No such argument: %v\n", a) 44 | os.Exit(1) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tree/node.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | ) 7 | 8 | // Node is a tree of string. Leaves are empty Nodes or nil. 9 | type Node map[string]Node 10 | 11 | // Print recurses through n and its member Nodes to pretty-print a Node as a 12 | // tree such as: 13 | // 14 | // ├── ftree 15 | // │ ├── node.go 16 | // │ ├── tree.go 17 | // │ └── tree_test.go 18 | // └── main.go 19 | // 20 | // Print should initially be called as n.Print(0, nil). The arguments are 21 | // primarily interesting during recursion. 22 | func (n Node) Print(indent int, leaders []string) { 23 | var keys []string 24 | for k := range n { 25 | keys = append(keys, k) 26 | } 27 | sort.Strings(keys) 28 | 29 | for i, part := range keys { 30 | if part == "" { 31 | n[part].Print(indent, leaders) 32 | continue 33 | } 34 | 35 | for _, l := range leaders { 36 | fmt.Print(l) 37 | } 38 | 39 | // For chains of single element maps, such as 40 | // { "Users": { "caleb": { "code": {}, "books": {} } }, 41 | // combine to { "Users/caleb": { "code": {}, "books": {} } }. 42 | for { 43 | if len(n[part]) != 1 { 44 | break 45 | } 46 | for k, v := range n[part] { 47 | part += "/" + k 48 | n[part] = v 49 | } 50 | } 51 | 52 | if i == len(keys)-1 { 53 | fmt.Printf("%s %s\n", "└──", part) 54 | n[part].Print(indent+1, append(leaders, " ")) 55 | } else { 56 | fmt.Printf("%s %s\n", "├──", part) 57 | n[part].Print(indent+1, append(leaders, "│ ")) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tree/node_test.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | func ExamplePrint() { 4 | tree := Node{ 5 | "caleb": Node{ 6 | "code": Node{"ftree": Node{}}, 7 | "books": Node{ 8 | "Learning Go": Node{}, 9 | "The Little Go Book": Node{}, 10 | }, 11 | }, 12 | } 13 | 14 | tree.Print(0, nil) 15 | 16 | // Output: 17 | // └── caleb 18 | // ├── books 19 | // │ ├── Learning Go 20 | // │ └── The Little Go Book 21 | // └── code/ftree 22 | } 23 | -------------------------------------------------------------------------------- /tree/tree.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import "strings" 4 | 5 | // Tree splits each line in lines on delim and builds a Node: a tree data 6 | // structure of maps with string keys. 7 | func Tree(lines []string, delim string) Node { 8 | var parts []Node 9 | for _, line := range lines { 10 | parts = append(parts, buildTree(line, delim)) 11 | } 12 | 13 | var tree Node 14 | for _, part := range parts { 15 | tree = merge(part, tree) 16 | } 17 | 18 | return tree 19 | } 20 | 21 | func buildTree(line, delim string) Node { 22 | var subtree = Node{} 23 | split := strings.SplitN(line, delim, 2) 24 | if len(split) > 1 { 25 | subtree[split[0]] = buildTree(split[1], delim) 26 | } else { 27 | subtree[split[0]] = Node{} 28 | } 29 | return subtree 30 | } 31 | 32 | func merge(src Node, dest Node) Node { 33 | if dest == nil { 34 | dest = Node{} 35 | } 36 | for k, v := range src { 37 | dest[k] = merge(v, dest[k]) 38 | } 39 | return dest 40 | } 41 | -------------------------------------------------------------------------------- /tree/tree_test.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestTree(t *testing.T) { 9 | lines := []string{ 10 | "caleb/code/ftree", 11 | "caleb/books", 12 | } 13 | 14 | want := Node{ 15 | "caleb": Node{ 16 | "code": Node{"ftree": Node{}}, 17 | "books": Node{}, 18 | }, 19 | } 20 | 21 | got := Tree(lines, "/") 22 | 23 | if !reflect.DeepEqual(want, got) { 24 | t.Fatalf("Expected \n%#v, got \n%#v", want, got) 25 | } 26 | } 27 | --------------------------------------------------------------------------------