/
cat-main.go
152 lines (133 loc) · 3.58 KB
/
cat-main.go
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
148
149
150
151
152
/*
* Minio Client, (C) 2015 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"errors"
"fmt"
"io"
"os"
"strings"
"syscall"
"github.com/minio/cli"
"github.com/minio/minio-xl/pkg/probe"
)
var (
catFlags = []cli.Flag{
cli.BoolFlag{
Name: "help, h",
Usage: "Help of cat",
},
}
)
// Display contents of a file.
var catCmd = cli.Command{
Name: "cat",
Usage: "Display contents of a file.",
Action: mainCat,
Flags: append(catFlags, globalFlags...),
CustomHelpTemplate: `NAME:
mc {{.Name}} - {{.Usage}}
USAGE:
mc {{.Name}} [FLAGS] SOURCE [SOURCE...]
FLAGS:
{{range .Flags}}{{.}}
{{end}}
EXAMPLES:
1. Stream an object from Amazon S3 cloud storage to mplayer standard input.
$ mc {{.Name}} s3/ferenginar/klingon_opera_aktuh_maylotah.ogg | mplayer -
2. Concantenate contents of file1.txt and stdin to standard output.
$ mc {{.Name}} file1.txt - > file.txt
3. Concantenate multiple files to one.
$ mc {{.Name}} part.* > complete.img
`,
}
// checkCatSyntax performs command-line input validation for cat command.
func checkCatSyntax(ctx *cli.Context) {
args := ctx.Args()
if !args.Present() {
args = []string{"-"}
}
for _, arg := range args {
if strings.HasPrefix(arg, "-") && len(arg) > 1 {
fatalIf(probe.NewError(errors.New("")), fmt.Sprintf("Unknown flag ‘%s’ passed.", arg))
}
}
}
// catURL displays contents of a URL to stdout.
func catURL(sourceURL string) *probe.Error {
var reader io.ReadSeeker
switch sourceURL {
case "-":
reader = os.Stdin
default:
// Ignore size, since os.Stat() would not return proper size all the
// time for local filesystem for example /proc files.
var err *probe.Error
if reader, err = getSource(sourceURL); err != nil {
return err.Trace(sourceURL)
}
}
return catOut(reader).Trace(sourceURL)
}
// catOut reads from reader stream and writes to stdout.
func catOut(r io.Reader) *probe.Error {
// Read till EOF.
if _, err := io.Copy(os.Stdout, r); err != nil {
switch e := err.(type) {
case *os.PathError:
if e.Err == syscall.EPIPE {
// stdout closed by the user. Gracefully exit.
return nil
}
return probe.NewError(err)
default:
return probe.NewError(err)
}
}
return nil
}
// mainCat is the main entry point for cat command.
func mainCat(ctx *cli.Context) {
// Set global flags from context.
setGlobalsFromContext(ctx)
// check 'cat' cli arguments.
checkCatSyntax(ctx)
// Set command flags from context.
stdinMode := false
if !ctx.Args().Present() {
stdinMode = true
}
// handle std input data.
if stdinMode {
fatalIf(catOut(os.Stdin).Trace(), "Unable to read from standard input.")
return
}
// if Args contain ‘-’, we need to preserve its order specially.
args := []string(ctx.Args())
if ctx.Args().First() == "-" {
for i, arg := range os.Args {
if arg == "cat" {
// Overwrite ctx.Args with os.Args.
args = os.Args[i+1:]
break
}
}
}
// Convert arguments to URLs: expand alias, fix format.
for _, url := range args {
fatalIf(catURL(url).Trace(url), "Unable to read from ‘"+url+"’.")
}
}