github.com/rogpeppe/go-internal@v1.12.1-0.20240509064211-c8567cf8e95f/cmd/txtar-c/savedir.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // The txtar-c command archives a directory tree as a txtar archive printed to standard output. 6 // 7 // Usage: 8 // 9 // txtar-c /path/to/dir >saved.txtar 10 // 11 // See https://godoc.org/golang.org/x/tools/txtar for details of the format 12 // and how to parse a txtar file. 13 package main 14 15 import ( 16 "bytes" 17 stdflag "flag" 18 "fmt" 19 "log" 20 "os" 21 "path/filepath" 22 "strings" 23 "unicode/utf8" 24 25 "github.com/rogpeppe/go-internal/txtar" 26 ) 27 28 var flag = stdflag.NewFlagSet(os.Args[0], stdflag.ContinueOnError) 29 30 func usage() { 31 fmt.Fprintf(os.Stderr, "usage: txtar-c dir >saved.txtar\n") 32 flag.PrintDefaults() 33 } 34 35 var ( 36 quoteFlag = flag.Bool("quote", false, "quote files that contain txtar file markers instead of failing") 37 allFlag = flag.Bool("a", false, "include dot files too") 38 ) 39 40 func main() { 41 os.Exit(main1()) 42 } 43 44 func main1() int { 45 flag.Usage = usage 46 if flag.Parse(os.Args[1:]) != nil { 47 return 2 48 } 49 if flag.NArg() != 1 { 50 usage() 51 return 2 52 } 53 54 log.SetPrefix("txtar-c: ") 55 log.SetFlags(0) 56 57 dir := flag.Arg(0) 58 59 a := new(txtar.Archive) 60 dir = filepath.Clean(dir) 61 if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 62 if err != nil { 63 return err 64 } 65 if path == dir { 66 return nil 67 } 68 name := info.Name() 69 if strings.HasPrefix(name, ".") && !*allFlag { 70 if info.IsDir() { 71 return filepath.SkipDir 72 } 73 return nil 74 } 75 if !info.Mode().IsRegular() { 76 return nil 77 } 78 data, err := os.ReadFile(path) 79 if err != nil { 80 return err 81 } 82 if !utf8.Valid(data) { 83 log.Printf("%s: ignoring file with invalid UTF-8 data", path) 84 return nil 85 } 86 if len(data) > 0 && !bytes.HasSuffix(data, []byte("\n")) { 87 log.Printf("%s: adding final newline", path) 88 data = append(data, '\n') 89 } 90 filename := strings.TrimPrefix(path, dir+string(filepath.Separator)) 91 if txtar.NeedsQuote(data) { 92 if !*quoteFlag { 93 log.Printf("%s: ignoring file with txtar marker in", path) 94 return nil 95 } 96 data, err = txtar.Quote(data) 97 if err != nil { 98 log.Printf("%s: ignoring unquotable file: %v", path, err) 99 return nil 100 } 101 a.Comment = append(a.Comment, []byte("unquote "+filename+"\n")...) 102 } 103 a.Files = append(a.Files, txtar.File{ 104 Name: filepath.ToSlash(filename), 105 Data: data, 106 }) 107 return nil 108 }); err != nil { 109 log.Fatal(err) 110 } 111 112 data := txtar.Format(a) 113 os.Stdout.Write(data) 114 115 return 0 116 }