forked from twpayne/chezmoi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patharchivecmd.go
More file actions
116 lines (104 loc) · 2.89 KB
/
archivecmd.go
File metadata and controls
116 lines (104 loc) · 2.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package cmd
import (
"archive/tar"
"compress/gzip"
"fmt"
"os/user"
"strconv"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/twpayne/chezmoi/v2/internal/chezmoi"
)
type archiveCmdConfig struct {
exclude *chezmoi.EntryTypeSet
format string
gzip bool
include *chezmoi.EntryTypeSet
recursive bool
}
func (c *Config) newArchiveCmd() *cobra.Command {
archiveCmd := &cobra.Command{
Use: "archive [target]...",
Short: "Generate a tar archive of the target state",
Long: mustLongHelp("archive"),
Example: example("archive"),
RunE: c.runArchiveCmd,
Annotations: map[string]string{
persistentStateMode: persistentStateModeEmpty,
},
}
flags := archiveCmd.Flags()
flags.VarP(c.archive.exclude, "exclude", "x", "exclude entry types")
flags.StringVar(&c.archive.format, "format", "tar", "format (tar or zip)")
flags.BoolVarP(&c.archive.gzip, "gzip", "z", c.archive.gzip, "compress the output with gzip")
flags.VarP(c.archive.include, "include", "i", "include entry types")
flags.BoolVarP(&c.archive.recursive, "recursive", "r", c.archive.recursive, "recursive")
return archiveCmd
}
func (c *Config) runArchiveCmd(cmd *cobra.Command, args []string) error {
output := strings.Builder{}
var archiveSystem interface {
chezmoi.System
Close() error
}
switch c.archive.format {
case "tar":
archiveSystem = chezmoi.NewTARWriterSystem(&output, tarHeaderTemplate())
case "zip":
archiveSystem = chezmoi.NewZIPWriterSystem(&output, time.Now().UTC())
default:
return fmt.Errorf("%s: invalid format", c.archive.format)
}
if err := c.applyArgs(archiveSystem, "", args, applyArgsOptions{
include: c.archive.include.Sub(c.archive.exclude),
recursive: c.archive.recursive,
}); err != nil {
return err
}
if err := archiveSystem.Close(); err != nil {
return err
}
if c.archive.format == "zip" || !c.archive.gzip {
return c.writeOutputString(output.String())
}
gzippedArchive := strings.Builder{}
w := gzip.NewWriter(&gzippedArchive)
if _, err := w.Write([]byte(output.String())); err != nil {
return err
}
if err := w.Close(); err != nil {
return err
}
return c.writeOutputString(gzippedArchive.String())
}
// tarHeaderTemplate returns a tar.Header template populated with the current
// user and time.
func tarHeaderTemplate() tar.Header {
// Attempt to lookup the current user. Ignore errors because the default
// zero values are reasonable.
var (
uid int
gid int
uname string
gname string
)
if currentUser, err := user.Current(); err == nil {
uid, _ = strconv.Atoi(currentUser.Uid)
gid, _ = strconv.Atoi(currentUser.Gid)
uname = currentUser.Username
if group, err := user.LookupGroupId(currentUser.Gid); err == nil {
gname = group.Name
}
}
now := time.Now().UTC()
return tar.Header{
Uid: uid,
Gid: gid,
Uname: uname,
Gname: gname,
ModTime: now,
AccessTime: now,
ChangeTime: now,
}
}