Nigel Tao | a540fbc | 2020-02-25 15:54:53 +1100 | [diff] [blame] | 1 | // Copyright 2020 The Wuffs Authors. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | // +build ignore |
| 16 | |
| 17 | package main |
| 18 | |
| 19 | // print-file-sizes-json.go prints a JSON object containing the names and sizes |
| 20 | // of the files and directories under the current working directory, |
| 21 | // recursively. |
| 22 | // |
| 23 | // A directory is printed as a JSON object whose keys are its children's names. |
| 24 | // Child directories' values are also JSON objects. Child files' values are the |
| 25 | // file size as a JSON number. |
| 26 | // |
| 27 | // A directory's JSON object also contains a key-value pair for the empty |
| 28 | // string key. Its value is the sum of all children and descendent file sizes. |
| 29 | // Note that this is just the total raw file size, and does not account for any |
| 30 | // file system overhead for directories or for rounding up a file sizes to a |
| 31 | // multiple of a disk block size. |
| 32 | |
| 33 | import ( |
| 34 | "encoding/json" |
| 35 | "os" |
| 36 | "path/filepath" |
| 37 | "strings" |
| 38 | ) |
| 39 | |
| 40 | func main() { |
| 41 | if err := main1(); err != nil { |
| 42 | os.Stderr.WriteString(err.Error() + "\n") |
| 43 | os.Exit(1) |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | func main1() error { |
| 48 | root := dir{"": int64(0)} |
| 49 | |
| 50 | if err := filepath.Walk(".", func(path string, info os.FileInfo, walkErr error) error { |
| 51 | if walkErr != nil { |
| 52 | return walkErr |
| 53 | } |
| 54 | if (path != "") && (path[0] == '.') { |
| 55 | if info.IsDir() && (path != ".") { |
| 56 | return filepath.SkipDir |
| 57 | } |
| 58 | return nil |
| 59 | } |
| 60 | path = filepath.ToSlash(path) |
| 61 | |
| 62 | ancestors := []dir{} |
| 63 | d := root |
| 64 | for remaining := ""; len(path) > 0; path = remaining { |
| 65 | ancestors = append(ancestors, d) |
| 66 | if i := strings.IndexByte(path, '/'); i >= 0 { |
| 67 | path, remaining = path[:i], path[i+1:] |
| 68 | } else { |
| 69 | remaining = "" |
| 70 | } |
| 71 | if (remaining == "") && !info.IsDir() { |
| 72 | n := info.Size() |
| 73 | d[path] = n |
| 74 | for _, a := range ancestors { |
| 75 | a[""] = a[""].(int64) + n |
| 76 | } |
| 77 | } else if next, ok := d[path]; ok { |
| 78 | d = next.(dir) |
| 79 | } else { |
| 80 | next := dir{"": int64(0)} |
| 81 | d[path] = next |
| 82 | d = next |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | return nil |
| 87 | }); err != nil { |
| 88 | return err |
| 89 | } |
| 90 | |
| 91 | if enc, err := json.Marshal(root); err != nil { |
| 92 | return err |
| 93 | } else { |
| 94 | os.Stdout.Write(enc) |
| 95 | } |
| 96 | return nil |
| 97 | } |
| 98 | |
| 99 | type dir map[string]interface{} |