File: entry.go

package info (click to toggle)
miller 6.17.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 88,244 kB
  • sloc: ruby: 162; sh: 120; makefile: 87; python: 46
file content (196 lines) | stat: -rw-r--r-- 5,013 bytes parent folder | download
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// This is the shell command-line entry point to the Miller REPL command line.
// E.g. at the shell prompt, you type 'mlr repl --json' -- this file will parse
// that.  It will then hand off control to a REPL session which will handle all
// subsequent REPL command-line statements you type in at a Miller REPL prompt.
//
// Example:
//
// bash$ mlr repl --json         <------------- this file handles this bit
// [mlr] :open myfile.json
// [mlr] :read
// [mlr] :context
// FILENAME="myfile.json",FILENUM=1,NR=1,FNR=1
// [mlr] $*
// {
//   "hostname": "localhost",
//   "pid": 12345
// }
// [mlr] :quit

package repl

import (
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/johnkerl/miller/v6/pkg/cli"
)

func replUsage(verbName string, o *os.File, exitCode int) {
	exeName := path.Base(os.Args[0])
	fmt.Fprintf(o, "Usage: %s %s [options] {zero or more data-file names}\n", exeName, verbName)

	// TODO: cli/UsageForReaderOptions
	// TODO: cli/UsageForWriterOptions
	// TODO: cli/UsageForReaderWriterOptions

	// TODO: maybe -f/-e as in put?
	// TODO: maybe -s as in put?
	// TODO: maybe -x as in put?
	// TODO: maybe -q as in put?

	fmt.Fprint(o,
		`-v Prints the expressions's AST (abstract syntax tree), which gives
   full transparency on the precedence and associativity rules of
   Miller's grammar, to stdout.

-d Like -v but uses a parenthesized-expression format for the AST.

-D Like -d but with output all on one line.

-w Show warnings about uninitialized variables

-q Don't show startup banner

-s Don't show prompts

--load {DSL script file} Load script file before presenting the prompt.
   If the name following --load is a directory, load all "*.mlr" files
   in that directory.

--mload {DSL script files} -- Like --load but works with more than one filename,
   e.g. '--mload *.mlr --'.

-h|--help Show this message.

Or any --icsv, --ojson, etc. reader/writer options as for the main Miller command line.

Any data-file names are opened just as if you had waited and typed :open {filenames}
at the Miller REPL prompt.
`)

	os.Exit(exitCode)
}

// Here the args are the full Miller command line: if the latter was "mlr
// --some-flag repl foo bar" then the former is "repl foo bar".
func ReplMain(args []string) int {
	exeName := os.Args[0]
	replName := args[0]
	argc := len(args)
	argi := 1

	showStartupBanner := true
	showPrompts := true
	astPrintMode := ASTPrintNone
	doWarnings := false
	strictMode := false
	options := cli.DefaultOptions()

	for argi < argc /* variable increment: 1 or 2 depending on flag */ {
		if !strings.HasPrefix(args[argi], "-") {
			break // No more flag options to process
		}

		if args[argi] == "-h" || args[argi] == "--help" {
			replUsage(replName, os.Stdout, 0)

		} else if args[argi] == "-q" {
			showStartupBanner = false
			argi++
		} else if args[argi] == "-s" {
			showPrompts = false
			argi++
		} else if args[argi] == "-v" {
			astPrintMode = ASTPrintIndent
			argi++
		} else if args[argi] == "-d" {
			astPrintMode = ASTPrintParex
			argi++
		} else if args[argi] == "-D" {
			astPrintMode = ASTPrintParexOneLine
			argi++
		} else if args[argi] == "-w" {
			doWarnings = true
			argi++

		} else if args[argi] == "-z" {
			strictMode = true
			argi++

		} else if args[argi] == "--load" {
			if argc-argi < 2 {
				replUsage(replName, os.Stderr, 1)
			}
			options.DSLPreloadFileNames = append(options.DSLPreloadFileNames, args[argi+1])
			argi += 2

		} else if args[argi] == "--mload" {
			if argc-argi < 2 {
				replUsage(replName, os.Stderr, 1)
			}
			argi += 1
			for argi < argc && args[argi] != "--" {
				options.DSLPreloadFileNames = append(options.DSLPreloadFileNames, args[argi])
				argi += 1
			}
			if args[argi] == "--" {
				argi += 1
			}

		} else if cli.FLAG_TABLE.Parse(args, argc, &argi, options) {

		} else {
			replUsage(replName, os.Stderr, 1)
		}
	}

	cli.FinalizeReaderOptions(&options.ReaderOptions)
	cli.FinalizeWriterOptions(&options.WriterOptions)

	// --auto-flatten is on by default. But if input and output formats are both JSON,
	// then we don't need to actually do anything. See also mlrcli_parse.go.
	options.WriterOptions.AutoFlatten = cli.DecideFinalFlatten(&options.WriterOptions)
	options.WriterOptions.AutoUnflatten = cli.DecideFinalUnflatten(options, [][]string{})

	recordOutputFileName := "(stdout)"
	recordOutputStream := os.Stdout

	repl, err := NewRepl(
		exeName,
		replName,
		showStartupBanner,
		showPrompts,
		astPrintMode,
		doWarnings,
		strictMode,
		options,
		recordOutputFileName,
		recordOutputStream,
	)
	if err != nil {
		fmt.Fprintf(os.Stderr, "mlr: %v\n", err)
		os.Exit(1)
	}

	filenames := args[argi:]
	if len(filenames) > 0 {
		repl.openFiles(filenames)
	}

	err = repl.handleSession(os.Stdin)
	if err != nil {
		fmt.Fprintf(os.Stderr, "mlr %s: %v\n", repl.replName, err)
		os.Exit(1)
	}

	repl.bufferedRecordOutputStream.Flush()
	err = repl.closeBufferedOutputStream()
	if err != nil {
		fmt.Fprintf(os.Stderr, "mlr %s: %v\n", repl.replName, err)
		os.Exit(1)
	}
	return 0
}