Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 253 additions & 0 deletions src/cli.toit
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
// Use of this source code is governed by an MIT-style license that can be
// found in the package's LICENSE file.

import fs
import host.directory
import host.file
import host.pipe
import io
import log
import uuid show Uuid
import system
Expand Down Expand Up @@ -1086,6 +1091,254 @@ class OptionPath extends Option:
parse str/string --for-help-example/bool=false -> string:
return str

/**
An input file option.

The parsed value is an $InFile, which can be opened lazily.

If $allow-dash is true (the default), the value "-" is interpreted as
stdin.

If $check-exists is true (the default), the file is checked for
existence at parse time. This check is skipped for "-" (stdin).
*/
class OptionInFile extends Option:
default/string?
type/string

/**
Whether "-" is interpreted as stdin.
*/
allow-dash/bool

/**
Whether the file is checked for existence at parse time.
*/
check-exists/bool

/**
Creates a new input file option.

The $default value is null.
The $type defaults to "file".

If $allow-dash is true (the default), the value "-" is interpreted
as stdin.

If $check-exists is true (the default), the file must exist at parse
time. This check is skipped for "-" (stdin) and for help examples.

See $Option.constructor for the other parameters.
*/
constructor name/string
--.default=null
--.type="file"
--.allow-dash=true
--.check-exists=true
--short-name/string?=null
--help/string?=null
--required/bool=false
--hidden/bool=false
--multi/bool=false
--split-commas/bool=false
--completion/Lambda?=null:
if multi and default: throw "Multi option can't have default value."
if required and default: throw "Option can't have default value and be required."
super.from-subclass name --short-name=short-name --help=help \
--required=required --hidden=hidden --multi=multi \
--split-commas=split-commas --completion=completion

is-flag: return false

options-for-completion -> List: return []

completion-directive -> int?: return DIRECTIVE-FILE-COMPLETION_

parse str/string --for-help-example/bool=false -> any:
if allow-dash and str == "-":
return InFile.stdin_
if check-exists and not for-help-example:
Comment thread
floitsch marked this conversation as resolved.
if not file.is-file str:
throw "File not found for option '$name': '$str'."
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be done using Ui.abort. Not sure how to get the UI class, though.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferred to a follow-up PR. Passing a Ui to parse requires updating the abstract method signature and all call sites (including tests), so it's a larger change.

return InFile.from-path_ str

/**
An output file option.

The parsed value is an $OutFile, which can be opened lazily.

If $allow-dash is true (the default), the value "-" is interpreted as
stdout.

If $create-directories is true, parent directories are created
automatically when opening the file for writing.
*/
class OptionOutFile extends Option:
default/string?
type/string

/**
Whether "-" is interpreted as stdout.
*/
allow-dash/bool

/**
Whether parent directories are created when opening for writing.
*/
create-directories/bool

/**
Creates a new output file option.

The $default value is null.
The $type defaults to "file".

If $allow-dash is true (the default), the value "-" is interpreted
as stdout.

If $create-directories is true, parent directories are created
automatically when opening the file for writing. Defaults to false.

See $Option.constructor for the other parameters.
*/
constructor name/string
--.default=null
--.type="file"
--.allow-dash=true
--.create-directories=false
--short-name/string?=null
--help/string?=null
--required/bool=false
--hidden/bool=false
--multi/bool=false
--split-commas/bool=false
--completion/Lambda?=null:
if multi and default: throw "Multi option can't have default value."
if required and default: throw "Option can't have default value and be required."
super.from-subclass name --short-name=short-name --help=help \
--required=required --hidden=hidden --multi=multi \
--split-commas=split-commas --completion=completion

is-flag: return false

options-for-completion -> List: return []

completion-directive -> int?: return DIRECTIVE-FILE-COMPLETION_

parse str/string --for-help-example/bool=false -> any:
if allow-dash and str == "-":
return OutFile.stdout_ --create-directories=create-directories
return OutFile.from-path_ str --create-directories=create-directories

/**
A wrapper around an input file or stdin.

Returned by $OptionInFile when parsing command-line arguments.

Use $open or $do to read from the file or stdin.
*/
class InFile:
/** The file path, or null if this represents stdin. */
path/string?

/**
Whether this $InFile represents stdin.
*/
is-stdin/bool

constructor.from-path_ .path/string:
is-stdin = false

constructor.stdin_:
path = null
is-stdin = true

/**
Opens the file (or stdin) for reading.

The caller is responsible for closing the returned reader.
*/
open -> io.CloseableReader:
if is-stdin: return pipe.stdin.in
return (file.Stream.for-read path).in

/**
Opens the file (or stdin) for reading, calls the given $block
with the reader, and closes the reader afterwards.
*/
do [block] -> none:
reader := open
try:
block.call reader
finally:
reader.close

/**
Reads the entire content of the file or stdin.
*/
read-contents -> ByteArray:
if not is-stdin: return file.read-contents path
buffer := io.Buffer
reader := pipe.stdin.in
try:
while chunk := reader.read:
buffer.write chunk
finally:
reader.close
return buffer.bytes

/**
A wrapper around an output file or stdout.

Returned by $OptionOutFile when parsing command-line arguments.

Use $open or $do to write to the file or stdout.
*/
class OutFile:
/** The file path, or null if this represents stdout. */
path/string?

create-directories_/bool

/**
Whether this $OutFile represents stdout.
*/
is-stdout/bool

constructor.from-path_ .path/string --create-directories/bool:
create-directories_ = create-directories
is-stdout = false

constructor.stdout_ --create-directories/bool:
path = null
create-directories_ = create-directories
is-stdout = true

/**
Opens the file (or stdout) for writing.

If $OptionOutFile.create-directories was set, parent directories are
created automatically.

The caller is responsible for closing the returned writer.
*/
open -> io.CloseableWriter:
if is-stdout: return pipe.stdout.out
if create-directories_:
directory.mkdir --recursive (fs.dirname path)
return (file.Stream.for-write path).out

/**
Opens the file (or stdout) for writing, calls the given $block
with the writer, and closes the writer afterwards.
*/
do [block] -> none:
writer := open
try:
block.call writer
finally:
writer.close

Comment thread
floitsch marked this conversation as resolved.
/**
A Uuid option.
*/
Expand Down
Loading