v: run code from stdin `echo println(2+2) | v run -`, with no repl limits (#6884)

pull/6792/head
Nicolas Sauzede 2020-11-20 09:25:59 +01:00 committed by GitHub
parent 55a7c907ad
commit 159932d59b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 1 deletions

View File

@ -1,8 +1,11 @@
Usage: v [build flags] run <file.v|directory> [arguments...] Usage: v [build flags] run <file.v|directory|-> [arguments...]
This command is equivalent to running `v build` and running the compiled executable. This command is equivalent to running `v build` and running the compiled executable.
The executable is passed the arguments as provided in [arguments...]. The executable is passed the arguments as provided in [arguments...].
If the target is '-', it means that the V source code to build comes from stdin.
If the '-o' option is not specified, and the target is '-', a temporary base name for the executable will be used.
The exit status of run will be: The exit status of run will be:
* `1` if the compilation failed. * `1` if the compilation failed.
* The exit code of the compiled executable otherwise. * The exit code of the compiled executable otherwise.

View File

@ -6,6 +6,7 @@ module pref
import os.cmdline import os.cmdline
import os import os
import v.vcache import v.vcache
import rand
pub enum BuildMode { pub enum BuildMode {
// `v program.v' // `v program.v'
@ -408,6 +409,44 @@ pub fn parse_args(args []string) (&Preferences, string) {
} }
res.path = args[command_pos + 1] res.path = args[command_pos + 1]
res.run_args = args[command_pos + 2..] res.run_args = args[command_pos + 2..]
if res.path == '-' {
tmp_file_path := rand.ulid()
mut tmp_exe_file_path := res.out_name
mut output_option := ''
if tmp_exe_file_path == '' {
tmp_exe_file_path = '${tmp_file_path}.exe'
output_option = '-o "$tmp_exe_file_path"'
}
tmp_v_file_path := '${tmp_file_path}.v'
mut lines := []string{}
for {
iline := os.get_raw_line()
if iline.len == 0 {
break
}
lines << iline
}
contents := lines.join('')
os.write_file(tmp_v_file_path, contents) or {
panic('Failed to create temporary file $tmp_v_file_path')
}
run_options := cmdline.options_before(args, ['run']).join(' ')
command_options := cmdline.options_after(args, ['run'])[1..].join(' ')
vexe := vexe_path()
tmp_cmd := '"$vexe" $output_option $run_options run "$tmp_v_file_path" $command_options'
//
res.vrun_elog('tmp_cmd: $tmp_cmd')
tmp_result := os.system(tmp_cmd)
res.vrun_elog('exit code: $tmp_result')
//
if output_option.len != 0 {
res.vrun_elog('remove tmp exe file: $tmp_exe_file_path')
os.rm(tmp_exe_file_path)
}
res.vrun_elog('remove tmp v file: $tmp_v_file_path')
os.rm(tmp_v_file_path)
exit(tmp_result)
}
must_exist(res.path) must_exist(res.path)
if !res.path.ends_with('.v') && os.is_executable(res.path) && os.is_file(res.path) && if !res.path.ends_with('.v') && os.is_executable(res.path) && os.is_file(res.path) &&
os.is_file(res.path + '.v') { os.is_file(res.path + '.v') {
@ -430,6 +469,12 @@ pub fn parse_args(args []string) (&Preferences, string) {
return res, command return res, command
} }
fn (pref &Preferences) vrun_elog(s string) {
if pref.is_verbose {
eprintln('> v run -, $s')
}
}
fn must_exist(path string) { fn must_exist(path string) {
if !os.exists(path) { if !os.exists(path) {
eprintln('v expects that `$path` exists, but it does not') eprintln('v expects that `$path` exists, but it does not')

View File

@ -0,0 +1,23 @@
import os
const (
vexe = os.getenv('VEXE')
)
fn test_vexe_is_set() {
assert vexe != ''
}
fn test_pipe_to_v_run() ? {
cat_cmd := if os.user_os() == 'windows' { 'type' } else { 'cat' }
tmp_v_file := os.join_path(os.temp_dir(), 'generated_piped_program.v')
os.write_file(tmp_v_file, 'println(1 + 3)\nprintln("hello")\n') ?
assert os.is_file(tmp_v_file)
cmd := '"$cat_cmd" "$tmp_v_file" | "$vexe" run -'
res := os.exec(cmd) ?
// eprintln('>> cmd: $cmd | res: $res')
assert res.exit_code == 0
assert res.output.trim_space().split('\n') == ['4', 'hello']
os.rm(tmp_v_file)
assert !os.exists(tmp_v_file)
}