~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/utils/trivial.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012, 2013 Canonical Ltd.
 
2
// Licensed under the LGPLv3, see LICENCE file for details.
 
3
 
 
4
package utils
 
5
 
 
6
import (
 
7
        "bytes"
 
8
        "compress/gzip"
 
9
        "crypto/sha256"
 
10
        "encoding/hex"
 
11
        "io"
 
12
        "io/ioutil"
 
13
        "os"
 
14
        "strings"
 
15
        "unicode"
 
16
)
 
17
 
 
18
// TODO(ericsnow) Move the quoting helpers into the shell package?
 
19
 
 
20
// ShQuote quotes s so that when read by bash, no metacharacters
 
21
// within s will be interpreted as such.
 
22
func ShQuote(s string) string {
 
23
        // single-quote becomes single-quote, double-quote, single-quote, double-quote, single-quote
 
24
        return `'` + strings.Replace(s, `'`, `'"'"'`, -1) + `'`
 
25
}
 
26
 
 
27
// WinPSQuote quotes s so that when read by powershell, no metacharacters
 
28
// within s will be interpreted as such.
 
29
func WinPSQuote(s string) string {
 
30
        // See http://ss64.com/ps/syntax-esc.html#quotes.
 
31
        // Double quotes inside single quotes are fine, double single quotes inside
 
32
        // single quotes, not so much so. Having double quoted strings inside single
 
33
        // quoted strings, ensure no expansion happens.
 
34
        return `'` + strings.Replace(s, `'`, `"`, -1) + `'`
 
35
}
 
36
 
 
37
// WinCmdQuote quotes s so that when read by cmd.exe, no metacharacters
 
38
// within s will be interpreted as such.
 
39
func WinCmdQuote(s string) string {
 
40
        // See http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx.
 
41
        quoted := winCmdQuote(s)
 
42
        return winCmdEscapeMeta(quoted)
 
43
}
 
44
 
 
45
func winCmdQuote(s string) string {
 
46
        var escaped string
 
47
        for _, c := range s {
 
48
                switch c {
 
49
                case '\\', '"':
 
50
                        escaped += `\`
 
51
                }
 
52
                escaped += string(c)
 
53
        }
 
54
        return `"` + escaped + `"`
 
55
}
 
56
 
 
57
func winCmdEscapeMeta(str string) string {
 
58
        const meta = `()%!^"<>&|`
 
59
        var newStr string
 
60
        for _, c := range str {
 
61
                if strings.Contains(meta, string(c)) {
 
62
                        newStr += "^"
 
63
                }
 
64
                newStr += string(c)
 
65
        }
 
66
        return newStr
 
67
}
 
68
 
 
69
// CommandString flattens a sequence of command arguments into a
 
70
// string suitable for executing in a shell, escaping slashes,
 
71
// variables and quotes as necessary; each argument is double-quoted
 
72
// if and only if necessary.
 
73
func CommandString(args ...string) string {
 
74
        var buf bytes.Buffer
 
75
        for i, arg := range args {
 
76
                needsQuotes := false
 
77
                var argBuf bytes.Buffer
 
78
                for _, r := range arg {
 
79
                        if unicode.IsSpace(r) {
 
80
                                needsQuotes = true
 
81
                        } else if r == '"' || r == '$' || r == '\\' {
 
82
                                needsQuotes = true
 
83
                                argBuf.WriteByte('\\')
 
84
                        }
 
85
                        argBuf.WriteRune(r)
 
86
                }
 
87
                if i > 0 {
 
88
                        buf.WriteByte(' ')
 
89
                }
 
90
                if needsQuotes {
 
91
                        buf.WriteByte('"')
 
92
                        argBuf.WriteTo(&buf)
 
93
                        buf.WriteByte('"')
 
94
                } else {
 
95
                        argBuf.WriteTo(&buf)
 
96
                }
 
97
        }
 
98
        return buf.String()
 
99
}
 
100
 
 
101
// Gzip compresses the given data.
 
102
func Gzip(data []byte) []byte {
 
103
        var buf bytes.Buffer
 
104
        w := gzip.NewWriter(&buf)
 
105
        if _, err := w.Write(data); err != nil {
 
106
                // Compression should never fail unless it fails
 
107
                // to write to the underlying writer, which is a bytes.Buffer
 
108
                // that never fails.
 
109
                panic(err)
 
110
        }
 
111
        if err := w.Close(); err != nil {
 
112
                panic(err)
 
113
        }
 
114
        return buf.Bytes()
 
115
}
 
116
 
 
117
// Gunzip uncompresses the given data.
 
118
func Gunzip(data []byte) ([]byte, error) {
 
119
        r, err := gzip.NewReader(bytes.NewReader(data))
 
120
        if err != nil {
 
121
                return nil, err
 
122
        }
 
123
        return ioutil.ReadAll(r)
 
124
}
 
125
 
 
126
// ReadSHA256 returns the SHA256 hash of the contents read from source
 
127
// (hex encoded) and the size of the source in bytes.
 
128
func ReadSHA256(source io.Reader) (string, int64, error) {
 
129
        hash := sha256.New()
 
130
        size, err := io.Copy(hash, source)
 
131
        if err != nil {
 
132
                return "", 0, err
 
133
        }
 
134
        digest := hex.EncodeToString(hash.Sum(nil))
 
135
        return digest, size, nil
 
136
}
 
137
 
 
138
// ReadFileSHA256 is like ReadSHA256 but reads the contents of the
 
139
// given file.
 
140
func ReadFileSHA256(filename string) (string, int64, error) {
 
141
        f, err := os.Open(filename)
 
142
        if err != nil {
 
143
                return "", 0, err
 
144
        }
 
145
        defer f.Close()
 
146
        return ReadSHA256(f)
 
147
}