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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package utils
import (
"bytes"
"compress/gzip"
"crypto/sha256"
"encoding/hex"
"io"
"io/ioutil"
"os"
"strings"
"unicode"
)
// TODO(ericsnow) Move the quoting helpers into the shell package?
// ShQuote quotes s so that when read by bash, no metacharacters
// within s will be interpreted as such.
func ShQuote(s string) string {
// single-quote becomes single-quote, double-quote, single-quote, double-quote, single-quote
return `'` + strings.Replace(s, `'`, `'"'"'`, -1) + `'`
}
// WinPSQuote quotes s so that when read by powershell, no metacharacters
// within s will be interpreted as such.
func WinPSQuote(s string) string {
// See http://ss64.com/ps/syntax-esc.html#quotes.
// Double quotes inside single quotes are fine, double single quotes inside
// single quotes, not so much so. Having double quoted strings inside single
// quoted strings, ensure no expansion happens.
return `'` + strings.Replace(s, `'`, `"`, -1) + `'`
}
// WinCmdQuote quotes s so that when read by cmd.exe, no metacharacters
// within s will be interpreted as such.
func WinCmdQuote(s string) string {
// See http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx.
quoted := winCmdQuote(s)
return winCmdEscapeMeta(quoted)
}
func winCmdQuote(s string) string {
var escaped string
for _, c := range s {
switch c {
case '\\', '"':
escaped += `\`
}
escaped += string(c)
}
return `"` + escaped + `"`
}
func winCmdEscapeMeta(str string) string {
const meta = `()%!^"<>&|`
var newStr string
for _, c := range str {
if strings.Contains(meta, string(c)) {
newStr += "^"
}
newStr += string(c)
}
return newStr
}
// CommandString flattens a sequence of command arguments into a
// string suitable for executing in a shell, escaping slashes,
// variables and quotes as necessary; each argument is double-quoted
// if and only if necessary.
func CommandString(args ...string) string {
var buf bytes.Buffer
for i, arg := range args {
needsQuotes := false
var argBuf bytes.Buffer
for _, r := range arg {
if unicode.IsSpace(r) {
needsQuotes = true
} else if r == '"' || r == '$' || r == '\\' {
needsQuotes = true
argBuf.WriteByte('\\')
}
argBuf.WriteRune(r)
}
if i > 0 {
buf.WriteByte(' ')
}
if needsQuotes {
buf.WriteByte('"')
argBuf.WriteTo(&buf)
buf.WriteByte('"')
} else {
argBuf.WriteTo(&buf)
}
}
return buf.String()
}
// Gzip compresses the given data.
func Gzip(data []byte) []byte {
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
if _, err := w.Write(data); err != nil {
// Compression should never fail unless it fails
// to write to the underlying writer, which is a bytes.Buffer
// that never fails.
panic(err)
}
if err := w.Close(); err != nil {
panic(err)
}
return buf.Bytes()
}
// Gunzip uncompresses the given data.
func Gunzip(data []byte) ([]byte, error) {
r, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
}
return ioutil.ReadAll(r)
}
// ReadSHA256 returns the SHA256 hash of the contents read from source
// (hex encoded) and the size of the source in bytes.
func ReadSHA256(source io.Reader) (string, int64, error) {
hash := sha256.New()
size, err := io.Copy(hash, source)
if err != nil {
return "", 0, err
}
digest := hex.EncodeToString(hash.Sum(nil))
return digest, size, nil
}
// ReadFileSHA256 is like ReadSHA256 but reads the contents of the
// given file.
func ReadFileSHA256(filename string) (string, int64, error) {
f, err := os.Open(filename)
if err != nil {
return "", 0, err
}
defer f.Close()
return ReadSHA256(f)
}
|