1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

vfmt: it can now be used for _platform.v files too, no matter the host os

This commit is contained in:
Delyan Angelov
2019-12-27 18:59:04 +02:00
committed by Alexander Medvednikov
parent 84fbd5b3d0
commit 6c16bac908
12 changed files with 253 additions and 175 deletions

View File

@@ -9,14 +9,13 @@ import (
pub struct TestSession {
pub mut:
files []string
vexe string
vargs string
failed bool
files []string
vexe string
vargs string
failed bool
benchmark benchmark.Benchmark
ok string
fail string
ok string
fail string
}
pub fn new_test_session(vargs string) TestSession {
@@ -27,55 +26,74 @@ pub fn new_test_session(vargs string) TestSession {
}
pub fn vexe_path() string {
// NB: tools extracted from v require that the VEXE
// NB: tools extracted from v require that the VEXE
// environment variable contains the path to the v executable location.
// They are usually launched by vlib/compiler/vtools.v,
// launch_tool/1 , which provides it.
return os.getenv('VEXE')
}
pub fn (ts mut TestSession) init() {
ts.ok = term.ok_message('OK')
ts.ok = term.ok_message('OK')
ts.fail = term.fail_message('FAIL')
ts.benchmark = benchmark.new_benchmark()
}
pub fn (ts mut TestSession) test() {
tmpd := os.tmpdir()
ts.init()
show_stats := '-stats' in ts.vargs.split(' ')
for dot_relative_file in ts.files {
relative_file := dot_relative_file.replace('./', '')
file := os.realpath( relative_file )
file := os.realpath(relative_file)
$if windows {
if file.contains('sqlite') { continue }
if file.contains('sqlite') {
continue
}
}
$if !macos {
if file.contains('customer') { continue }
if file.contains('customer') {
continue
}
}
$if msvc {
if file.contains('asm') { continue }
if file.contains('asm') {
continue
}
}
$if tinyc {
if file.contains('asm') { continue }
if file.contains('asm') {
continue
}
}
tmpc_filepath := file.replace('.v', '.tmp.c')
cmd := '"$ts.vexe" $ts.vargs "$file"'
//eprintln('>>> v cmd: $cmd')
// Ensure that the generated binaries will be stored in the temporary folder.
// Remove them after a test passes/fails.
fname := filepath.filename(file)
generated_binary_fname := if os.user_os() == 'windows' { fname.replace('.v', '.exe') } else { fname.replace('.v', '') }
generated_binary_fpath := filepath.join(tmpd,generated_binary_fname)
if os.exists(generated_binary_fpath) {
os.rm(generated_binary_fpath)
}
mut cmd_options := [ts.vargs]
if !ts.vargs.contains('fmt') {
cmd_options << ' -o "$generated_binary_fpath"'
}
cmd := '"${ts.vexe}" ' + cmd_options.join(' ') + ' "${file}"'
// eprintln('>>> v cmd: $cmd')
ts.benchmark.step()
if show_stats {
eprintln('-------------------------------------------------')
status := os.system(cmd)
if status == 0 {
ts.benchmark.ok()
}else{
}
else {
ts.benchmark.fail()
ts.failed = true
continue
}
}else{
}
else {
r := os.exec(cmd) or {
ts.benchmark.fail()
ts.failed = true
@@ -86,20 +104,23 @@ pub fn (ts mut TestSession) test() {
ts.benchmark.fail()
ts.failed = true
eprintln(ts.benchmark.step_message('$relative_file ${ts.fail}\n`$file`\n (\n$r.output\n)'))
} else {
}
else {
ts.benchmark.ok()
eprintln(ts.benchmark.step_message('$relative_file ${ts.ok}'))
}
}
os.rm( tmpc_filepath )
if os.exists(generated_binary_fpath) {
os.rm(generated_binary_fpath)
}
}
ts.benchmark.stop()
eprintln(term.h_divider())
}
pub fn vlib_should_be_present( parent_dir string ) {
vlib_dir := filepath.join( parent_dir, 'vlib' )
if !os.is_dir( vlib_dir ){
pub fn vlib_should_be_present(parent_dir string) {
vlib_dir := filepath.join(parent_dir,'vlib')
if !os.is_dir(vlib_dir) {
eprintln('$vlib_dir is missing, it must be next to the V executable')
exit(1)
}
@@ -110,36 +131,26 @@ pub fn v_build_failing(zargs string, folder string) bool {
finish_label := 'building $folder'
vexe := vexe_path()
parent_dir := filepath.dir(vexe)
vlib_should_be_present( parent_dir )
vlib_should_be_present(parent_dir)
vargs := zargs.replace(vexe, '')
eprintln(main_label)
eprintln(' v compiler args: "$vargs"')
mut session := new_test_session( vargs )
files := os.walk_ext(filepath.join(parent_dir, folder),'.v')
mut session := new_test_session(vargs)
files := os.walk_ext(filepath.join(parent_dir,folder), '.v')
mains := files.filter(!it.contains('modules'))
mut rebuildable_mains := mains
if os.user_os() == 'windows' {
// on windows, an executable can not be rebuilt, while it is running
myself := os.executable().replace('.exe', '') + '.v'
mains_without_myself := mains.filter(!it.contains(myself))
rebuildable_mains = mains_without_myself // workaround a bug in it.contains generation
}
session.files << rebuildable_mains
session.files << mains
session.test()
eprintln( session.benchmark.total_message( finish_label ) )
eprintln(session.benchmark.total_message(finish_label))
return session.failed
}
pub fn build_v_cmd_failed (cmd string) bool {
pub fn build_v_cmd_failed(cmd string) bool {
res := os.exec(cmd) or {
return true
}
if res.exit_code != 0 {
eprintln('')
eprintln( res.output )
eprintln(res.output)
return true
}
return false
@@ -150,20 +161,17 @@ pub fn building_any_v_binaries_failed() bool {
eprintln('VFLAGS is: "' + os.getenv('VFLAGS') + '"')
vexe := testing.vexe_path()
parent_dir := filepath.dir(vexe)
testing.vlib_should_be_present( parent_dir )
os.chdir( parent_dir )
testing.vlib_should_be_present(parent_dir)
os.chdir(parent_dir)
mut failed := false
v_build_commands := [
'$vexe -o v_g -g v.v',
'$vexe -o v_prod_g -prod -g v.v',
'$vexe -o v_cg -cg v.v',
'$vexe -o v_prod_cg -prod -cg v.v',
'$vexe -o v_prod -prod v.v',
v_build_commands := ['$vexe -o v_g -g v.v',
'$vexe -o v_prod_g -prod -g v.v',
'$vexe -o v_cg -cg v.v',
'$vexe -o v_prod_cg -prod -cg v.v',
'$vexe -o v_prod -prod v.v',
]
mut bmark := benchmark.new_benchmark()
bok := term.ok_message('OK')
bok := term.ok_message('OK')
bfail := term.fail_message('FAIL')
for cmd in v_build_commands {
bmark.step()
@@ -178,8 +186,7 @@ pub fn building_any_v_binaries_failed() bool {
eprintln(bmark.step_message('$cmd => ${bok}'))
}
bmark.stop()
eprintln(term.h_divider())
eprintln( bmark.total_message( 'building v binaries' ) )
eprintln(term.h_divider())
eprintln(bmark.total_message('building v binaries'))
return failed
}

View File

@@ -11,23 +11,42 @@ import (
)
struct FormatOptions {
is_l bool
is_c bool
is_w bool
is_diff bool
is_verbose bool
is_all bool
is_worker bool
is_debug bool
}
const (
platform_and_file_extensions = [['windows', '_win.v', '_windows.v'],
['linux', '_lin.v', '_linux.v', '_nix.v'],
['macos', '_mac.v', '_darwin.v'],
['freebsd', '_bsd.v', '_freebsd.v'],
['solaris', '_solaris.v'],
['haiku', '_haiku.v'],
]
)
fn main() {
toolexe := os.executable()
compiler.set_vroot_folder(filepath.dir(filepath.dir(toolexe)))
args := compiler.env_vflags_and_os_args()
foptions := FormatOptions{
is_c: '-c' in args
is_l: '-l' in args
is_w: '-w' in args
is_diff: '-diff' in args
is_verbose: '-verbose' in args || '--verbose' in args
is_all: '-all' in args || '--all' in args
is_worker: '-worker' in args
is_debug: '-debug' in args
}
if foptions.is_verbose {
eprintln('vfmt foptions: $foptions')
}
if foptions.is_worker {
// -worker should be added by a parent vfmt process.
@@ -45,7 +64,6 @@ fn main() {
eprintln('vfmt args: ' + os.args.str())
eprintln('vfmt env_vflags_and_os_args: ' + args.str())
eprintln('vfmt possible_files: ' + possible_files.str())
eprintln('vfmt foptions: $foptions')
}
mut files := []string
for file in possible_files {
@@ -78,7 +96,9 @@ fn main() {
}
cmdcode := os.system(worker_cmd)
if cmdcode != 0 {
eprintln('vfmt error while formatting file: $file .')
if cmdcode == 1 {
eprintln('vfmt error while formatting file: $file .')
}
errors++
}
}
@@ -91,29 +111,23 @@ fn main() {
fn (foptions &FormatOptions) format_file(file string) {
tmpfolder := os.tmpdir()
mut compiler_params := []string
target_os := file_to_target_os(file)
if target_os != '' {
compiler_params << ['-os', target_os]
}
mut cfile := file
mut mod_folder_parent := tmpfolder
fcontent := os.read_file(file) or {
return
}
is_test_file := file.ends_with('_test.v')
is_module_file := fcontent.contains('module ') && !fcontent.contains('module main\n')
mod_name,is_module_file := file_to_mod_name_and_is_module_file(file)
use_tmp_main_program := is_module_file && !is_test_file
mod_folder := filepath.basedir(file)
mut mod_name := 'main'
if is_module_file {
mod_name = filepath.filename(mod_folder)
}
if use_tmp_main_program {
// TODO: remove the need for this
// This makes a small program that imports the module,
// so that the module files will get processed by the
// vfmt implementation.
mod_folder_parent = filepath.basedir(mod_folder)
mut main_program_content := 'import ${mod_name} \n fn main(){}'
if fcontent.contains('module builtin\n') {
main_program_content = 'fn main(){}'
}
mut main_program_content := if mod_name == 'builtin' || mod_name == 'main' { 'fn main(){}\n' } else { 'import ${mod_name}\n' + 'fn main(){}\n' }
main_program_file := filepath.join(tmpfolder,'vfmt_tmp_${mod_name}_program.v')
if os.exists(main_program_file) {
os.rm(main_program_file)
@@ -137,7 +151,9 @@ fn (foptions &FormatOptions) format_file(file string) {
}
formatted_file_path := foptions.compile_file(file, compiler_params)
if use_tmp_main_program {
os.rm(cfile)
if !foptions.is_debug {
os.rm(cfile)
}
}
if formatted_file_path.len == 0 {
return
@@ -150,17 +166,42 @@ fn (foptions &FormatOptions) format_file(file string) {
os.system('$diff_cmd --minimal --text --unified=2 --show-function-line="fn " "$file" "$formatted_file_path" ')
return
}
if foptions.is_w {
os.mv_by_cp(formatted_file_path, file) or {
panic(err)
fc := os.read_file(file) or {
eprintln('File $file could not be read')
return
}
formatted_fc := os.read_file(formatted_file_path) or {
eprintln('File $formatted_file_path could not be read')
return
}
is_formatted_different := fc != formatted_fc
if foptions.is_c {
if is_formatted_different {
eprintln('File is not formatted: $file')
exit(2)
}
eprintln('Reformatted file in place: $file .')
return
}
if foptions.is_l {
if is_formatted_different {
eprintln('File needs formatting: $file')
}
return
}
if foptions.is_w {
if is_formatted_different {
os.mv_by_cp(formatted_file_path, file) or {
panic(err)
}
eprintln('Reformatted file: $file')
}
else {
eprintln('Already formatted file: $file')
}
return
}
else {
content := os.read_file(formatted_file_path) or {
panic(err)
}
print(content)
print(formatted_fc)
}
}
@@ -168,7 +209,10 @@ fn usage() {
print('Usage: tools/vfmt [flags] fmt path_to_source.v [path_to_other_source.v]
Formats the given V source files, and prints their formatted source to stdout.
Options:
-c check if file is already formatted.
If it is not, print filepath, and exit with code 2.
-diff display only diffs between the formatted source and the original source.
-l list files whose formatting differs from vfmt.
-w write result to (source) file(s) instead of to stdout.
')
}
@@ -186,6 +230,10 @@ fn find_working_diff_command() ?string {
}
fn (foptions &FormatOptions) compile_file(file string, compiler_params []string) string {
if foptions.is_verbose {
eprintln('> new_v_compiler_with_args file: ' + file)
eprintln('> new_v_compiler_with_args compiler_params: ' + compiler_params.join(' '))
}
mut v := compiler.new_v_compiler_with_args(compiler_params)
v.v_fmt_file = file
if foptions.is_all {
@@ -196,5 +244,37 @@ fn (foptions &FormatOptions) compile_file(file string, compiler_params []string)
}
pub fn (f FormatOptions) str() string {
return 'FormatOptions{ ' + ' is_w: $f.is_w' + ' is_diff: $f.is_diff' + ' is_verbose: $f.is_verbose' + ' is_all: $f.is_all' + ' is_worker: $f.is_worker' + ' }'
return 'FormatOptions{ ' + ' is_l: $f.is_l' + ' is_w: $f.is_w' + ' is_diff: $f.is_diff' + ' is_verbose: $f.is_verbose' + ' is_all: $f.is_all' + ' is_worker: $f.is_worker' + ' is_debug: $f.is_debug' + ' }'
}
fn file_to_target_os(file string) string {
for extensions in platform_and_file_extensions {
for ext in extensions {
if file.ends_with(ext) {
return extensions[0]
}
}
}
return ''
}
fn file_to_mod_name_and_is_module_file(file string) (string,bool) {
mut mod_name := 'main'
mut is_module_file := false
raw_fcontent := os.read_file(file) or {
return mod_name,is_module_file
}
fcontent := raw_fcontent.replace('\r\n', '\n')
flines := fcontent.split('\n')
for fline in flines {
line := fline.trim_space()
if line.starts_with('module ') {
if !line.starts_with('module main') {
is_module_file = true
mod_name = line.replace('module ', ' ').trim_space()
}
break
}
}
return mod_name,is_module_file
}

View File

@@ -3,26 +3,10 @@ module main
import (
os
testing
benchmark
)
fn main() {
args := os.args
args_string := args[1..].join(' ')
v_test_formatting(args_string.all_before('test-fmt'))
}
fn v_test_formatting(vargs string) {
// NB: vfmt have to be build with '-d vfmt' . V itself knows about this,
// and v will rebuild tools/vfmt, if it is missing.
// Removing the binaries below is needed, since the building tools step
// rebuilds all the tools without the special option needed by vfmt
// by simply compiling each of them with `v tools/{toolname}.v`
// os.rm('tools/vfmt')
// os.rm('tools/vfmt.exe')
mut files_able_to_be_formatted := []string
all_test_files := os.walk_ext('.', '.v')
known_failing_exceptions := ['./examples/vweb/vweb_example.v',
const (
known_failing_exceptions = ['./examples/vweb/vweb_example.v',
'./tools/gen_vc.v',
'./tutorials/code/blog/article.v',
'./tutorials/code/blog/blog.v',
@@ -42,25 +26,40 @@ fn v_test_formatting(vargs string) {
'./vlib/crypto/aes/cypher_generic.v',
'./vlib/crypto/rc4/rc4.v',
'./vlib/eventbus/eventbus_test.v',
'./vlib/flag/flag.v',
'./vlib/os/bare/bare_example_linux.v',
'./vlib/szip/szip.v',
'./vlib/ui/examples/users_gui/users.v',
'./vlib/vweb/assets/assets.v',
'./vlib/vweb/vweb.v',
]
for tfile in all_test_files {
if tfile in known_failing_exceptions {
continue
}
files_able_to_be_formatted << tfile
}
)
fn main() {
args := os.args
args_string := args[1..].join(' ')
v_test_formatting(args_string.all_before('test-fmt'))
}
fn v_test_formatting(vargs string) {
all_v_files := v_files()
eprintln('Run "v fmt" over all .v files')
mut vfmt_test_session := testing.new_test_session('$vargs fmt')
vfmt_test_session.files << files_able_to_be_formatted
mut vfmt_test_session := testing.new_test_session('$vargs fmt -worker')
vfmt_test_session.files << all_v_files
vfmt_test_session.test()
eprintln(vfmt_test_session.benchmark.total_message('running vfmt over V test files'))
eprintln(vfmt_test_session.benchmark.total_message('running vfmt over V files'))
if vfmt_test_session.benchmark.nfail > 0 {
panic('\nWARNING: v fmt failed ${vfmt_test_session.benchmark.nfail} times.\n')
}
}
fn v_files() []string {
mut files_that_can_be_formatted := []string
all_test_files := os.walk_ext('.', '.v')
for tfile in all_test_files {
if tfile in known_failing_exceptions {
continue
}
files_that_can_be_formatted << tfile
}
return files_that_can_be_formatted
}