mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
v test v => v test-compiler
This commit is contained in:
parent
854309a7d8
commit
ec15bfb7d1
10
.github/PULL_REQUEST_TEMPLATE
vendored
10
.github/PULL_REQUEST_TEMPLATE
vendored
@ -1,6 +1,7 @@
|
||||
**Please delete this information after reading it.*
|
||||
|
||||
Please title your PR as follows: `time: fix foo bar`. Always start with the thing you are fixing, then describe the fix.
|
||||
Please title your PR as follows: `time: fix foo bar`.
|
||||
Always start with the thing you are fixing, then describe the fix.
|
||||
Don't use past tense (e.g. "fixed foo bar").
|
||||
|
||||
Explain what your PR does and why.
|
||||
@ -20,10 +21,13 @@ fn test_foo() {
|
||||
|
||||
If you are fixing a bug, please add a test that covers it.
|
||||
|
||||
Before submitting a PR, please run the tests with `v test v`, and make sure V can still compile itself. Run this twice:
|
||||
|
||||
Before submitting a PR, please:
|
||||
A) run the tests with `v test-compiler` .
|
||||
B) make sure, that V can still compile itself:
|
||||
```shell
|
||||
./v -o v v.v
|
||||
./v -o v v.v
|
||||
```
|
||||
|
||||
I try to process PRs as soon as possible. They should be handled within 24 hours.
|
||||
|
||||
|
2
.github/workflows/alpine.test.sh
vendored
2
.github/workflows/alpine.test.sh
vendored
@ -10,6 +10,6 @@ du -s .
|
||||
|
||||
ls -lat
|
||||
|
||||
./v test v
|
||||
./v test-compiler
|
||||
|
||||
echo "DONE"
|
||||
|
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
- name: Build V using V
|
||||
run: ./v -o v2 v.v && ./v2 -o v3 v.v
|
||||
- name: Test v->c
|
||||
run: ./v test v
|
||||
run: ./v test-compiler
|
||||
# - name: Test v->js
|
||||
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
- name: Test symlink
|
||||
@ -58,7 +58,7 @@ jobs:
|
||||
- name: Build V
|
||||
run: make && ./v -cc gcc -o v v.v
|
||||
- name: Test V
|
||||
run: ./v test v
|
||||
run: ./v test-compiler
|
||||
# - name: Test v->js
|
||||
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
- name: Build Vorum
|
||||
@ -110,7 +110,7 @@ jobs:
|
||||
sudo ln -s /var/tmp/tcc/bin/tcc /usr/local/bin/tcc
|
||||
tcc -version
|
||||
./v -o v2 v.v # Make sure vtcc can build itself
|
||||
./v test v
|
||||
./v test-compiler
|
||||
|
||||
ubuntu-musl:
|
||||
runs-on: ubuntu-18.04
|
||||
@ -124,7 +124,7 @@ jobs:
|
||||
- name: Build v
|
||||
run: make && ./v -cc musl-gcc -o v v.v
|
||||
# - name: Test v->c
|
||||
# run: ./v test v
|
||||
# run: ./v test-compiler
|
||||
# - name: Test v->js
|
||||
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
|
||||
@ -142,7 +142,7 @@ jobs:
|
||||
.\make.bat -gcc
|
||||
- name: Test
|
||||
run: |
|
||||
.\v.exe test v
|
||||
.\v.exe test-compiler
|
||||
## v.js dosent work on windows
|
||||
#.\v.exe -o hi.js examples/hello_v_js.v
|
||||
#node hi.js
|
||||
@ -164,7 +164,7 @@ jobs:
|
||||
env:
|
||||
VFLAGS: -cc msvc
|
||||
run: |
|
||||
.\v.exe test v
|
||||
.\v.exe test-compiler
|
||||
## v.js dosent work on windows
|
||||
#.\v.exe -o hi.js examples/hello_v_js.v
|
||||
#node hi.js
|
||||
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
fns.txt
|
||||
*.dSYM
|
||||
*_test
|
||||
/v
|
||||
@ -12,12 +13,18 @@
|
||||
/tools/vrepl.exe
|
||||
/tools/vtest
|
||||
/tools/vtest.exe
|
||||
/tools/vtest-compiler
|
||||
/tools/vtest-compiler.exe
|
||||
/tools/vup
|
||||
/tools/vup.exe
|
||||
/tools/vpm
|
||||
/tools/vpm.exe
|
||||
/tools/vcreate
|
||||
/tools/vcreate.exe
|
||||
/tools/vbuild-examples
|
||||
/tools/vbuild-examples.exe
|
||||
/tools/vbuild-tools
|
||||
/tools/vbuild-tools.exe
|
||||
*.exe
|
||||
*.o
|
||||
.*.c
|
||||
@ -38,3 +45,6 @@ vjs
|
||||
._*
|
||||
.vrepl_temp.v
|
||||
a.out
|
||||
vlib/os/bare/bare_example_linux
|
||||
|
||||
info.log
|
||||
|
5
examples/.gitignore
vendored
5
examples/.gitignore
vendored
@ -12,3 +12,8 @@
|
||||
/hello_v_js
|
||||
/fibonacci
|
||||
/sqlite
|
||||
empty_gg_freetype
|
||||
game_of_life/life_gg
|
||||
random_ips
|
||||
vweb/vweb_example
|
||||
x64/hello_world
|
||||
|
@ -1,7 +1,12 @@
|
||||
import log
|
||||
|
||||
fn main() {
|
||||
mut l := log.Log { log.LogLevel.info, 'info', true }
|
||||
mut l := log.Log{}
|
||||
l.set_level(log.INFO)
|
||||
// Make a new file called info.log in the current folder
|
||||
l.set_full_logpath('./info.log')
|
||||
println('Please check the file: ${l.output_file_name} after this example crashes.')
|
||||
|
||||
l.info('info')
|
||||
l.warn('warn')
|
||||
l.error('error')
|
||||
|
9
tools/.gitignore
vendored
Normal file
9
tools/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
gen_vc
|
||||
performance_compare
|
||||
vcreate
|
||||
vnames
|
||||
vpm
|
||||
vrepl
|
||||
vtest
|
||||
vtest-compiler
|
||||
vup
|
@ -39,7 +39,7 @@ fn main() {
|
||||
commit_date := exec('git log -n1 --pretty="format:%at"')
|
||||
message := exec('git log -n1 --pretty="format:%s"')
|
||||
date := time.unix(commit_date.int())
|
||||
out := os.create('table.html') or { panic(err) }
|
||||
mut out := os.create('table.html') or { panic(err) }
|
||||
// Place the new row on top
|
||||
table =
|
||||
'<tr>
|
||||
@ -57,7 +57,7 @@ fn main() {
|
||||
// Regenerate index.html
|
||||
header := os.read_file('header.html') or { panic(err) }
|
||||
footer := os.read_file('footer.html') or { panic(err) }
|
||||
res := os.create('index.html') or { panic(err) }
|
||||
mut res := os.create('index.html') or { panic(err) }
|
||||
res.writeln(header)
|
||||
res.writeln(table)
|
||||
res.writeln(footer)
|
||||
|
@ -45,7 +45,7 @@ const(
|
||||
// name
|
||||
app_name = 'gen_vc'
|
||||
// version
|
||||
app_version = '0.1.0'
|
||||
app_version = '0.1.1'
|
||||
// description
|
||||
app_description = 'This tool regenerates V\'s bootstrap .c files every time the V master branch is updated.'
|
||||
// assume something went wrong if file size less than this
|
||||
@ -114,17 +114,22 @@ fn main() {
|
||||
fp.version(app_version)
|
||||
fp.description(app_description)
|
||||
fp.skip_executable()
|
||||
|
||||
|
||||
show_help:=fp.bool('help', false, 'Show this help screen\n')
|
||||
flag_options := parse_flags(mut fp)
|
||||
|
||||
_ = fp.finalize() or {
|
||||
|
||||
if( show_help ){ println( fp.usage() ) exit(0) }
|
||||
|
||||
fp.finalize() or {
|
||||
eprintln(err)
|
||||
println(fp.usage())
|
||||
return
|
||||
}
|
||||
|
||||
// webhook server mode
|
||||
if flag_options.serve {
|
||||
vweb.run<WebhookServer>(flag_options.port)
|
||||
app := WebhookServer{ gen_vc: new_gen_vc(flag_options) }
|
||||
vweb.run(mut app, flag_options.port)
|
||||
}
|
||||
// cmd mode
|
||||
else {
|
||||
@ -136,15 +141,14 @@ fn main() {
|
||||
|
||||
// new GenVC
|
||||
fn new_gen_vc(flag_options FlagOptions) &GenVC {
|
||||
mut logger := &log.Log{}
|
||||
logger.set_level(log.DEBUG)
|
||||
if flag_options.log_to == 'file' {
|
||||
logger.set_full_logpath( flag_options.log_file )
|
||||
}
|
||||
return &GenVC{
|
||||
// options
|
||||
options: flag_options
|
||||
// logger
|
||||
logger: if flag_options.log_to == 'file' {
|
||||
&log.Log{log.DEBUG, flag_options.log_file}
|
||||
} else {
|
||||
&log.Log{log.DEBUG, 'terminal'}
|
||||
}
|
||||
logger: logger
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,7 +179,7 @@ fn parse_flags(fp mut flag.FlagParser) FlagOptions {
|
||||
purge : fp.bool('purge', false, 'force purge the local repositories')
|
||||
port : fp.int('port', int(server_port), 'port for web server to listen on')
|
||||
log_to : fp.string('log-to', log_to, 'log to is \'file\' or \'terminal\'')
|
||||
log_file : fp.string('log_file', log_file, 'log file to use when log-to is \'file\'')
|
||||
log_file : fp.string('log-file', log_file, 'log file to use when log-to is \'file\'')
|
||||
dry_run : fp.bool('dry-run', dry_run, 'when specified dont push anything to remote repo')
|
||||
}
|
||||
}
|
||||
|
126
tools/modules/testing/common.v
Normal file
126
tools/modules/testing/common.v
Normal file
@ -0,0 +1,126 @@
|
||||
module testing
|
||||
|
||||
import (
|
||||
os
|
||||
term
|
||||
benchmark
|
||||
filepath
|
||||
)
|
||||
|
||||
pub struct TestSession {
|
||||
pub mut:
|
||||
files []string
|
||||
vexe string
|
||||
vargs string
|
||||
failed bool
|
||||
benchmark benchmark.Benchmark
|
||||
|
||||
ok string
|
||||
fail string
|
||||
}
|
||||
|
||||
pub fn new_test_sesion(vargs string) TestSession {
|
||||
return TestSession{
|
||||
vexe: vexe_path()
|
||||
vargs: vargs
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vexe_path() string {
|
||||
// NB: tools extracted from v require that the first
|
||||
// argument to them to be the v executable location.
|
||||
// They are usually launched by vlib/compiler/vtools.v,
|
||||
// launch_tool/1 , which provides it.
|
||||
return os.args[1]
|
||||
}
|
||||
|
||||
|
||||
pub fn (ts mut TestSession) init() {
|
||||
ts.ok = term.ok_message('OK')
|
||||
ts.fail = term.fail_message('FAIL')
|
||||
ts.benchmark = benchmark.new_benchmark()
|
||||
}
|
||||
|
||||
pub fn (ts mut TestSession) test() {
|
||||
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 )
|
||||
$if windows {
|
||||
if file.contains('sqlite') { continue }
|
||||
}
|
||||
$if msvc {
|
||||
if file.contains('asm') { continue }
|
||||
}
|
||||
$if tinyc {
|
||||
if file.contains('asm') { continue }
|
||||
}
|
||||
tmpc_filepath := file.replace('.v', '.tmp.c')
|
||||
|
||||
cmd := '"$ts.vexe" $ts.vargs "$file"'
|
||||
|
||||
ts.benchmark.step()
|
||||
if show_stats {
|
||||
println('-------------------------------------------------')
|
||||
status := os.system(cmd)
|
||||
if status == 0 {
|
||||
ts.benchmark.ok()
|
||||
}else{
|
||||
ts.benchmark.fail()
|
||||
ts.failed = true
|
||||
continue
|
||||
}
|
||||
}else{
|
||||
r := os.exec(cmd) or {
|
||||
ts.benchmark.fail()
|
||||
ts.failed = true
|
||||
println(ts.benchmark.step_message('$relative_file ${ts.fail}'))
|
||||
continue
|
||||
}
|
||||
if r.exit_code != 0 {
|
||||
ts.benchmark.fail()
|
||||
ts.failed = true
|
||||
println(ts.benchmark.step_message('$relative_file ${ts.fail}\n`$file`\n (\n$r.output\n)'))
|
||||
} else {
|
||||
ts.benchmark.ok()
|
||||
println(ts.benchmark.step_message('$relative_file ${ts.ok}'))
|
||||
}
|
||||
}
|
||||
os.rm( tmpc_filepath )
|
||||
}
|
||||
ts.benchmark.stop()
|
||||
}
|
||||
|
||||
pub fn vlib_should_be_present( parent_dir string ) {
|
||||
vlib_dir := filepath.join( parent_dir, 'vlib' )
|
||||
if !os.dir_exists( vlib_dir ){
|
||||
println('$vlib_dir is missing, it must be next to the V executable')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn v_build_failing(vargs string, folder string) bool {
|
||||
main_label := 'Building $folder ...'
|
||||
finish_label := 'building $folder'
|
||||
vexe := vexe_path()
|
||||
parent_dir := os.dir(vexe)
|
||||
vlib_should_be_present( parent_dir )
|
||||
|
||||
println(main_label)
|
||||
mut session := new_test_sesion( 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.test()
|
||||
println( session.benchmark.total_message( finish_label ) )
|
||||
|
||||
return session.failed
|
||||
}
|
14
tools/vbuild-examples.v
Normal file
14
tools/vbuild-examples.v
Normal file
@ -0,0 +1,14 @@
|
||||
module main
|
||||
|
||||
import (
|
||||
os
|
||||
testing
|
||||
)
|
||||
|
||||
fn main() {
|
||||
args := os.args
|
||||
args_string := args[1..].join(' ')
|
||||
if testing.v_build_failing(args_string.all_before('build-examples'), 'examples') {
|
||||
exit(1)
|
||||
}
|
||||
}
|
14
tools/vbuild-tools.v
Normal file
14
tools/vbuild-tools.v
Normal file
@ -0,0 +1,14 @@
|
||||
module main
|
||||
|
||||
import (
|
||||
os
|
||||
testing
|
||||
)
|
||||
|
||||
fn main() {
|
||||
args := os.args
|
||||
args_string := args[1..].join(' ')
|
||||
if testing.v_build_failing(args_string.all_before('build-tools'), 'tools') {
|
||||
exit(1)
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ fn cerror(e string){
|
||||
}
|
||||
|
||||
fn (c Create)write_vmod() {
|
||||
vmod := os.create('${c.name}/v.mod') or { cerror(err) exit(1) }
|
||||
mut vmod := os.create('${c.name}/v.mod') or { cerror(err) exit(1) }
|
||||
mut vmod_content := []string
|
||||
vmod_content << '#V Project#\n'
|
||||
vmod_content << 'Module {'
|
||||
@ -31,7 +31,7 @@ fn (c Create)write_vmod() {
|
||||
}
|
||||
|
||||
fn (c Create)write_main() {
|
||||
main := os.create('${c.name}/${c.name}.v') or { cerror(err) exit(2) }
|
||||
mut main := os.create('${c.name}/${c.name}.v') or { cerror(err) exit(2) }
|
||||
mut main_content := []string
|
||||
main_content << 'module main\n'
|
||||
main_content << 'fn main() {'
|
||||
|
77
tools/vtest-compiler.v
Normal file
77
tools/vtest-compiler.v
Normal file
@ -0,0 +1,77 @@
|
||||
module main
|
||||
|
||||
import (
|
||||
os
|
||||
testing
|
||||
benchmark
|
||||
)
|
||||
|
||||
pub const (
|
||||
v_modules_path = os.home_dir() + '.vmodules'
|
||||
)
|
||||
|
||||
fn main() {
|
||||
args := os.args
|
||||
args_string := args[1..].join(' ')
|
||||
v_test_compiler(args_string.all_before('test-compiler'))
|
||||
}
|
||||
|
||||
fn v_test_compiler(vargs string){
|
||||
vexe := testing.vexe_path()
|
||||
parent_dir := os.dir(vexe)
|
||||
testing.vlib_should_be_present( parent_dir )
|
||||
|
||||
// Changing the current directory is needed for some of the compiler tests,
|
||||
// compiler/tests/local_test.v and compiler/tests/repl/repl_test.v
|
||||
os.chdir( parent_dir )
|
||||
|
||||
/*
|
||||
if !os.file_exists(parent_dir + '/v.v') {
|
||||
println('v.v is missing, it must be next to the V executable')
|
||||
exit(1)
|
||||
}
|
||||
*/
|
||||
|
||||
// Make sure v.c can be compiled without warnings
|
||||
$if mac {
|
||||
if os.file_exists('/v.v') {
|
||||
os.system('$vexe -o v.c v.v')
|
||||
if os.system('cc -Werror v.c') != 0 {
|
||||
println('cc failed to build v.c without warnings')
|
||||
exit(1)
|
||||
}
|
||||
println('v.c can be compiled without warnings. This is good :)')
|
||||
}
|
||||
}
|
||||
|
||||
building_tools_failed := testing.v_build_failing(vargs, 'tools')
|
||||
|
||||
println('\nTesting all _test.v files...')
|
||||
mut compiler_test_session := testing.new_test_sesion( vargs )
|
||||
compiler_test_session.files << os.walk_ext(parent_dir, '_test.v')
|
||||
compiler_test_session.test()
|
||||
println( compiler_test_session.benchmark.total_message('running V tests') )
|
||||
|
||||
println('')
|
||||
building_examples_failed := testing.v_build_failing(vargs, 'examples')
|
||||
|
||||
v_module_install_cmd := '$vexe install nedpals.args'
|
||||
println('\nInstalling a v module with: $v_module_install_cmd ')
|
||||
mut vmark := benchmark.new_benchmark()
|
||||
ret := os.system(v_module_install_cmd)
|
||||
if ret != 0 {
|
||||
println('failed to run v install')
|
||||
exit(1)
|
||||
}
|
||||
if !os.file_exists(v_modules_path + '/nedpals/args') {
|
||||
println('v failed to install a test module')
|
||||
exit(1)
|
||||
}
|
||||
vmark.stop()
|
||||
println( 'Installing a v module took: ' + vmark.total_duration().str() + 'ms')
|
||||
|
||||
if building_tools_failed || compiler_test_session.failed || building_examples_failed {
|
||||
exit(1)
|
||||
}
|
||||
|
||||
}
|
156
tools/vtest.v
156
tools/vtest.v
@ -2,44 +2,17 @@ module main
|
||||
|
||||
import (
|
||||
os
|
||||
term
|
||||
benchmark
|
||||
testing
|
||||
)
|
||||
|
||||
struct TestSession {
|
||||
mut:
|
||||
files []string
|
||||
vexe string
|
||||
vargs string
|
||||
failed bool
|
||||
benchmark benchmark.Benchmark
|
||||
}
|
||||
|
||||
pub fn new_test_sesion(vargs string) TestSession {
|
||||
return TestSession{
|
||||
vexe: vexe_path()
|
||||
vargs: vargs
|
||||
}
|
||||
}
|
||||
|
||||
fn vexe_path() string {
|
||||
// NB: tools extracted from v require that the first
|
||||
// argument to them to be the v executable location.
|
||||
// They are usually launched by vlib/compiler/vtools.v,
|
||||
// launch_tool/1 , which provides it.
|
||||
return os.args[1]
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
args := os.args
|
||||
if args.last() == 'test' {
|
||||
println('Usage:')
|
||||
println(' A)')
|
||||
println(' v test v : run all v tests and build all the examples')
|
||||
println(' B)')
|
||||
println(' v test folder/ : run all v tests in the given folder.')
|
||||
println(' v -stats test folder/ : the same, but print more stats.')
|
||||
println(' C)')
|
||||
println(' B)')
|
||||
println(' v test file_test.v : run test functions in a given test file.')
|
||||
println(' v -stats test file_test.v : as above, but with more stats.')
|
||||
println(' NB: you can also give many and mixed folder/ file_test.v arguments after test.')
|
||||
@ -52,11 +25,12 @@ pub fn main() {
|
||||
args_after := args_string.all_after('test ')
|
||||
|
||||
if args_after == 'v' {
|
||||
v_test_v(args_before)
|
||||
return
|
||||
eprintln('`v test v` has been deprecated.')
|
||||
eprintln('Use `v test-compiler` instead.')
|
||||
exit(1)
|
||||
}
|
||||
|
||||
mut ts := new_test_sesion(args_before)
|
||||
|
||||
mut ts := testing.new_test_sesion(args_before)
|
||||
for targ in args_after.split(' ') {
|
||||
if os.file_exists(targ) && targ.ends_with('_test.v') {
|
||||
ts.files << targ
|
||||
@ -79,119 +53,3 @@ pub fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (ts mut TestSession) test() {
|
||||
ok := term.ok_message('OK')
|
||||
fail := term.fail_message('FAIL')
|
||||
show_stats := '-stats' in ts.vargs.split(' ')
|
||||
ts.benchmark = benchmark.new_benchmark()
|
||||
for dot_relative_file in ts.files {
|
||||
relative_file := dot_relative_file.replace('./', '')
|
||||
file := os.realpath( relative_file )
|
||||
$if windows {
|
||||
if file.contains('sqlite') { continue }
|
||||
}
|
||||
$if msvc {
|
||||
if file.contains('asm') { continue }
|
||||
}
|
||||
$if tinyc {
|
||||
if file.contains('asm') { continue }
|
||||
}
|
||||
tmpc_filepath := file.replace('.v', '.tmp.c')
|
||||
|
||||
cmd := '"$ts.vexe" $ts.vargs "$file"'
|
||||
|
||||
ts.benchmark.step()
|
||||
if show_stats {
|
||||
println('-------------------------------------------------')
|
||||
status := os.system(cmd)
|
||||
if status == 0 {
|
||||
ts.benchmark.ok()
|
||||
}else{
|
||||
ts.benchmark.fail()
|
||||
ts.failed = true
|
||||
continue
|
||||
}
|
||||
}else{
|
||||
r := os.exec(cmd) or {
|
||||
ts.benchmark.fail()
|
||||
ts.failed = true
|
||||
println(ts.benchmark.step_message('$relative_file $fail'))
|
||||
continue
|
||||
}
|
||||
if r.exit_code != 0 {
|
||||
ts.benchmark.fail()
|
||||
ts.failed = true
|
||||
println(ts.benchmark.step_message('$relative_file $fail\n`$file`\n (\n$r.output\n)'))
|
||||
} else {
|
||||
ts.benchmark.ok()
|
||||
println(ts.benchmark.step_message('$relative_file $ok'))
|
||||
}
|
||||
}
|
||||
os.rm( tmpc_filepath )
|
||||
}
|
||||
ts.benchmark.stop()
|
||||
}
|
||||
|
||||
pub fn v_test_v(args_before_test string){
|
||||
vexe := vexe_path()
|
||||
parent_dir := os.dir(vexe)
|
||||
// Changing the current directory is needed for some of the compiler tests,
|
||||
// compiler/tests/local_test.v and compiler/tests/repl/repl_test.v
|
||||
os.chdir( parent_dir )
|
||||
if !os.dir_exists(parent_dir + '/vlib') {
|
||||
println('vlib/ is missing, it must be next to the V executable')
|
||||
exit(1)
|
||||
}
|
||||
/*
|
||||
if !os.file_exists(parent_dir + '/v.v') {
|
||||
println('v.v is missing, it must be next to the V executable')
|
||||
exit(1)
|
||||
}
|
||||
*/
|
||||
// Make sure v.c can be compiled without warnings
|
||||
$if mac {
|
||||
if os.file_exists('/v.v') {
|
||||
os.system('$vexe -o v.c v.v')
|
||||
if os.system('cc -Werror v.c') != 0 {
|
||||
println('cc failed to build v.c without warnings')
|
||||
exit(1)
|
||||
}
|
||||
println('v.c can be compiled without warnings. This is good :)')
|
||||
}
|
||||
}
|
||||
//
|
||||
println('Testing...')
|
||||
mut ts := new_test_sesion( args_before_test )
|
||||
ts.files << os.walk_ext(parent_dir, '_test.v')
|
||||
ts.test()
|
||||
println( ts.benchmark.total_message('running V tests') )
|
||||
//
|
||||
println('\nBuilding examples...')
|
||||
mut es := new_test_sesion( args_before_test )
|
||||
files := os.walk_ext(parent_dir+'/examples','.v')
|
||||
stable := files.filter(!it.contains('automaton.v') && !it.contains('some_module.v'))
|
||||
es.files << stable
|
||||
es.test()
|
||||
println( es.benchmark.total_message('building examples') )
|
||||
//
|
||||
test_vget()
|
||||
if ts.failed || es.failed {
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_vget() {
|
||||
/*
|
||||
vexe := vexe_path()
|
||||
ret := os.system('$vexe install nedpals.args')
|
||||
if ret != 0 {
|
||||
println('failed to run v install')
|
||||
exit(1)
|
||||
}
|
||||
if !os.file_exists(v_modules_path + '/nedpals/args') {
|
||||
println('v failed to install a test module')
|
||||
exit(1)
|
||||
}
|
||||
println('vget is OK')
|
||||
*/
|
||||
}
|
||||
|
20
v.v
20
v.v
@ -25,6 +25,14 @@ fn main() {
|
||||
stuff_after_executable := os.args[1..]
|
||||
commands := stuff_after_executable.filter(!it.starts_with('-'))
|
||||
|
||||
simple_tools := ['up', 'create', 'test', 'test-compiler', 'build-tools', 'build-examples']
|
||||
for tool in simple_tools {
|
||||
if tool in commands {
|
||||
compiler.launch_tool('v$tool')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Print the version and exit.
|
||||
if '-v' in options || '--version' in options || 'version' in commands {
|
||||
version_hash := compiler.vhash()
|
||||
@ -39,10 +47,6 @@ fn main() {
|
||||
println('Translating C to V will be available in V 0.3')
|
||||
return
|
||||
}
|
||||
else if 'up' in commands {
|
||||
compiler.launch_tool('vup')
|
||||
return
|
||||
}
|
||||
else if 'search' in commands || 'install' in commands || 'update' in commands || 'remove' in commands {
|
||||
compiler.launch_tool('vpm')
|
||||
return
|
||||
@ -55,10 +59,6 @@ fn main() {
|
||||
compiler.create_symlink()
|
||||
return
|
||||
}
|
||||
else if 'create' in commands {
|
||||
compiler.launch_tool('vcreate')
|
||||
return
|
||||
}
|
||||
// TODO quit if the v compiler is too old
|
||||
// u := os.file_last_mod_unix('v')
|
||||
// If there's no tmp path with current version yet, the user must be using a pre-built package
|
||||
@ -68,10 +68,6 @@ fn main() {
|
||||
compiler.vfmt(args)
|
||||
return
|
||||
}
|
||||
else if 'test' in commands {
|
||||
compiler.launch_tool('vtest')
|
||||
return
|
||||
}
|
||||
// No args? REPL
|
||||
else if 'runrepl' in commands || commands.len == 0 || (args.len == 2 && args[1] == '-') {
|
||||
compiler.launch_tool('vrepl')
|
||||
|
@ -42,7 +42,7 @@ mut:
|
||||
|
||||
fn new_cgen(out_name_c string) &CGen {
|
||||
path := out_name_c
|
||||
out := os.create(path) or {
|
||||
mut out := os.create(path) or {
|
||||
println('failed to create $path')
|
||||
return &CGen{}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ fn generate_vh(mod string) {
|
||||
os.mkdir_all(pdir)
|
||||
// os.mkdir(os.realpath(dir)) or { panic(err) }
|
||||
}
|
||||
out := os.create(path) or { panic(err) }
|
||||
mut out := os.create(path) or { panic(err) }
|
||||
mod_path := mod.replace("\\", "/")
|
||||
out.writeln('// $mod_path module header\n')
|
||||
mod_def := if mod_path.contains('/') { mod_path.all_after('/') } else { mod_path } // "os"
|
||||
|
@ -200,7 +200,7 @@ fn (p mut Parser) gen_fmt() {
|
||||
return
|
||||
}
|
||||
println('generating ${p.file_name}.v')
|
||||
out := os.create('/var/tmp/fmt/' + p.file_name) or {
|
||||
mut out := os.create('/var/tmp/fmt/' + p.file_name) or {
|
||||
verror('failed to create fmt.v')
|
||||
return
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ pub fn (g mut Gen) generate_elf_footer() {
|
||||
// -5 is for "e8 00 00 00 00"
|
||||
g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos+1)
|
||||
// Create the binary
|
||||
f := os.create(g.out_name) or { panic(err) }
|
||||
mut f := os.create(g.out_name) or { panic(err) }
|
||||
os.chmod(g.out_name, 0775)
|
||||
f.write_bytes(g.buf.data, g.buf.len)
|
||||
f.close()
|
||||
|
@ -45,7 +45,7 @@ module flag
|
||||
// ```
|
||||
|
||||
// data object storing information about a defined flag
|
||||
struct Flag {
|
||||
pub struct Flag {
|
||||
pub:
|
||||
name string // name as it appears on command line
|
||||
abbr byte // shortcut
|
||||
@ -55,7 +55,7 @@ pub:
|
||||
}
|
||||
|
||||
//
|
||||
struct FlagParser {
|
||||
pub struct FlagParser {
|
||||
pub mut:
|
||||
args []string // the arguments to be parsed
|
||||
flags []Flag // registered flags
|
||||
@ -69,7 +69,7 @@ pub mut:
|
||||
args_description string
|
||||
}
|
||||
|
||||
const (
|
||||
pub const (
|
||||
// used for formating usage message
|
||||
SPACE = ' '
|
||||
UNDERLINE = '-----------------------------------------------'
|
||||
@ -125,14 +125,13 @@ fn (fs mut FlagParser) parse_value(n string, ab byte) ?string {
|
||||
c := '--$n'
|
||||
for i, a in fs.args {
|
||||
if a == c || (a.len == 2 && a[1] == ab) {
|
||||
if fs.args.len > i+1 && fs.args[i+1].left(2) != '--' {
|
||||
val := fs.args[i+1]
|
||||
fs.args.delete(i+1)
|
||||
fs.args.delete(i)
|
||||
return val
|
||||
} else {
|
||||
panic('Missing argument for \'$n\'')
|
||||
}
|
||||
if i+1 > fs.args.len { panic('Missing argument for \'$n\'') }
|
||||
nextarg := fs.args[i+1]
|
||||
if nextarg.limit(2) == '--' { panic('Missing argument for \'$n\'') }
|
||||
val := fs.args[i+1]
|
||||
fs.args.delete(i+1)
|
||||
fs.args.delete(i)
|
||||
return val
|
||||
} else if a.len > c.len && c == a[..c.len] && a[c.len..c.len+1] == '=' {
|
||||
val := a[c.len+1..]
|
||||
fs.args.delete(i)
|
||||
|
@ -247,3 +247,20 @@ fn test_allow_abreviations() {
|
||||
u := fp.usage()
|
||||
assert u.contains(' -v') && u.contains(' -o') && u.contains(' -i') && u.contains(' -f')
|
||||
}
|
||||
|
||||
fn test_allow_kebab_options() {
|
||||
default_value := 'this_is_the_default_value_of_long_option'
|
||||
long_option_value := 'this_is_a_long_option_value_as_argument'
|
||||
|
||||
mut fp := flag.new_flag_parser(['--my-long-flag', 'true', '--my-long-option', long_option_value ])
|
||||
|
||||
my_flag := fp.bool('my-long-flag', false, 'flag with long-kebab-name')
|
||||
my_option := fp.string('my-long-option', default_value, 'string with long-kebab-name')
|
||||
|
||||
assert my_flag == true
|
||||
assert my_option == long_option_value
|
||||
|
||||
u := fp.usage()
|
||||
assert u.contains(' --my-long-flag')
|
||||
assert u.contains(' --my-long-option')
|
||||
}
|
||||
|
128
vlib/log/log.v
128
vlib/log/log.v
@ -3,11 +3,12 @@ module log
|
||||
import os
|
||||
import time
|
||||
import term
|
||||
import filepath
|
||||
|
||||
pub enum LogLevel {
|
||||
fatal
|
||||
fatal = 1
|
||||
error
|
||||
warning
|
||||
warn
|
||||
info
|
||||
debug
|
||||
}
|
||||
@ -16,8 +17,8 @@ fn tag(l LogLevel) string {
|
||||
return match l {
|
||||
.fatal { term.red('F') }
|
||||
.error { term.red('E') }
|
||||
.warning { term.yellow('W') }
|
||||
.info { term.white('I') }
|
||||
.warn { term.yellow('W') }
|
||||
.info { term.white('I') }
|
||||
.debug { term.blue('D') }
|
||||
else { ' ' }
|
||||
}
|
||||
@ -40,17 +41,21 @@ interface Logger {
|
||||
}
|
||||
|
||||
pub struct Log {
|
||||
mut:
|
||||
mut:
|
||||
level LogLevel
|
||||
output_label string
|
||||
|
||||
ofile os.File
|
||||
output_to_file bool
|
||||
pub:
|
||||
output_file_name string
|
||||
}
|
||||
|
||||
pub fn (l mut Log) set_level(level int){
|
||||
l.level = match level {
|
||||
FATAL { LogLevel.fatal }
|
||||
ERROR { LogLevel.error }
|
||||
WARN { LogLevel.warning }
|
||||
WARN { LogLevel.warn }
|
||||
INFO { LogLevel.info }
|
||||
DEBUG { LogLevel.debug }
|
||||
else { .debug }
|
||||
@ -61,79 +66,74 @@ pub fn (l mut Log) set_output_level(level LogLevel){
|
||||
l.level = level
|
||||
}
|
||||
|
||||
pub fn (l mut Log) set_output_label(label string) {
|
||||
pub fn (l mut Log) set_full_logpath(full_log_path string) {
|
||||
rlog_file := os.realpath( full_log_path )
|
||||
l.set_output_label( os.filename( rlog_file ) )
|
||||
l.set_output_path( os.basedir( rlog_file ) )
|
||||
}
|
||||
|
||||
pub fn (l mut Log) set_output_label(label string){
|
||||
l.output_label = label
|
||||
}
|
||||
|
||||
pub fn (l mut Log) set_output(output string){
|
||||
l.output_label = output
|
||||
pub fn (l mut Log) set_output_path(output_file_path string) {
|
||||
if l.ofile.is_opened() { l.ofile.close() }
|
||||
l.output_to_file = true
|
||||
l.output_file_name = filepath.join( os.realpath( output_file_path ) , l.output_label )
|
||||
mut ofile := os.open_append( l.output_file_name ) or {
|
||||
panic('error while opening log file ${l.output_file_name} for appending')
|
||||
}
|
||||
l.ofile = ofile
|
||||
}
|
||||
|
||||
fn (l Log) log_file(s string, level LogLevel) {
|
||||
filename := '${l.output_label}.log'.replace(' ', '')
|
||||
f := os.open_append(filename) or {
|
||||
panic('error reading file $filename')
|
||||
}
|
||||
pub fn (l mut Log) close(){
|
||||
l.ofile.close()
|
||||
}
|
||||
|
||||
fn (l mut Log) log_file(s string, level LogLevel) {
|
||||
timestamp := time.now().format_ss()
|
||||
e := tag(level)
|
||||
f.writeln('$timestamp [$e] $s')
|
||||
l.ofile.writeln('$timestamp [$e] $s')
|
||||
}
|
||||
|
||||
fn (l Log) log_cli(s string, level LogLevel) {
|
||||
fn (l mut Log) log_cli(s string, level LogLevel) {
|
||||
f := tag(level)
|
||||
t := time.now()
|
||||
println('[$f ${t.format_ss()}] $s')
|
||||
}
|
||||
|
||||
pub fn (l Log) fatal(s string){
|
||||
if l.level == .fatal {
|
||||
if l.output_to_file {
|
||||
l.log_file(s, .fatal)
|
||||
} else {
|
||||
l.log_cli(s, .fatal)
|
||||
}
|
||||
panic('$l.output_label: $s')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (l Log) error(s string){
|
||||
if l.level in [.info, .debug, .warning, .error] {
|
||||
if l.output_to_file {
|
||||
l.log_file(s, .error)
|
||||
} else {
|
||||
l.log_cli(s, .error)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (l Log) warn(s string){
|
||||
if l.level in [.info, .debug, .warning] {
|
||||
if l.output_to_file {
|
||||
l.log_file(s, .warning)
|
||||
} else {
|
||||
l.log_cli(s, .warning)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (l Log) info(s string){
|
||||
if l.level in [.info, .debug] {
|
||||
if l.output_to_file {
|
||||
l.log_file(s, .info)
|
||||
} else {
|
||||
l.log_cli(s, .info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (l Log) debug(s string){
|
||||
if l.level != .debug {
|
||||
return
|
||||
}
|
||||
fn (l mut Log) send_output(s &string, level LogLevel){
|
||||
if l.output_to_file {
|
||||
l.log_file(s, .debug)
|
||||
l.log_file(s, level)
|
||||
} else {
|
||||
l.log_cli(s, .debug)
|
||||
l.log_cli(s, level)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (l mut Log) fatal(s string){
|
||||
if l.level < .fatal { return }
|
||||
l.send_output(s, .fatal)
|
||||
l.ofile.close()
|
||||
panic('$l.output_label: $s')
|
||||
}
|
||||
|
||||
pub fn (l mut Log) error(s string){
|
||||
if l.level < .error { return }
|
||||
l.send_output(s, .error)
|
||||
}
|
||||
|
||||
pub fn (l mut Log) warn(s string){
|
||||
if l.level < .warn { return }
|
||||
l.send_output(s, .warn)
|
||||
}
|
||||
|
||||
pub fn (l mut Log) info(s string){
|
||||
if l.level < .info { return }
|
||||
l.send_output(s, .info)
|
||||
}
|
||||
|
||||
pub fn (l mut Log) debug(s string){
|
||||
if l.level < .debug { return }
|
||||
l.send_output(s, .debug)
|
||||
}
|
||||
|
||||
|
31
vlib/os/os.v
31
vlib/os/os.v
@ -33,6 +33,8 @@ pub const (
|
||||
|
||||
pub struct File {
|
||||
cfile voidptr // Using void* instead of FILE*
|
||||
mut:
|
||||
opened bool
|
||||
}
|
||||
|
||||
struct FileInfo {
|
||||
@ -68,14 +70,17 @@ fn C.getenv(byteptr) &char
|
||||
fn C.sigaction(int, voidptr, int)
|
||||
|
||||
|
||||
pub fn (f File) is_opened() bool {
|
||||
return f.opened
|
||||
}
|
||||
|
||||
// read_bytes reads an amount of bytes from the beginning of the file
|
||||
pub fn (f File) read_bytes(size int) []byte {
|
||||
pub fn (f mut File) read_bytes(size int) []byte {
|
||||
return f.read_bytes_at(size, 0)
|
||||
}
|
||||
|
||||
// read_bytes_at reads an amount of bytes at the given position in the file
|
||||
pub fn (f File) read_bytes_at(size, pos int) []byte {
|
||||
pub fn (f mut File) read_bytes_at(size, pos int) []byte {
|
||||
mut arr := [`0`].repeat(size)
|
||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
||||
nreadbytes := C.fread(arr.data, 1, size, f.cfile)
|
||||
@ -281,6 +286,7 @@ pub fn open(path string) ?File {
|
||||
if isnil(file.cfile) {
|
||||
return error('failed to open file "$path"')
|
||||
}
|
||||
file.opened = true
|
||||
return file
|
||||
}
|
||||
|
||||
@ -302,6 +308,7 @@ pub fn create(path string) ?File {
|
||||
if isnil(file.cfile) {
|
||||
return error('failed to create file "$path"')
|
||||
}
|
||||
file.opened = true
|
||||
return file
|
||||
}
|
||||
|
||||
@ -322,10 +329,11 @@ pub fn open_append(path string) ?File {
|
||||
if isnil(file.cfile) {
|
||||
return error('failed to create(append) file "$path"')
|
||||
}
|
||||
file.opened = true
|
||||
return file
|
||||
}
|
||||
|
||||
pub fn (f File) write(s string) {
|
||||
pub fn (f mut File) write(s string) {
|
||||
C.fputs(s.str, f.cfile)
|
||||
// C.fwrite(s.str, 1, s.len, f.cfile)
|
||||
}
|
||||
@ -333,17 +341,18 @@ pub fn (f File) write(s string) {
|
||||
// convert any value to []byte (LittleEndian) and write it
|
||||
// for example if we have write(7, 4), "07 00 00 00" gets written
|
||||
// write(0x1234, 2) => "34 12"
|
||||
pub fn (f File) write_bytes(data voidptr, size int) {
|
||||
pub fn (f mut File) write_bytes(data voidptr, size int) {
|
||||
C.fwrite(data, 1, size, f.cfile)
|
||||
}
|
||||
|
||||
pub fn (f File) write_bytes_at(data voidptr, size, pos int) {
|
||||
pub fn (f mut File) write_bytes_at(data voidptr, size, pos int) {
|
||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
||||
C.fwrite(data, 1, size, f.cfile)
|
||||
C.fseek(f.cfile, 0, C.SEEK_END)
|
||||
}
|
||||
|
||||
pub fn (f File) writeln(s string) {
|
||||
pub fn (f mut File) writeln(s string) {
|
||||
if !f.opened { return }
|
||||
// C.fwrite(s.str, 1, s.len, f.cfile)
|
||||
// ss := s.clone()
|
||||
// TODO perf
|
||||
@ -352,11 +361,15 @@ pub fn (f File) writeln(s string) {
|
||||
C.fputs('\n', f.cfile)
|
||||
}
|
||||
|
||||
pub fn (f File) flush() {
|
||||
pub fn (f mut File) flush() {
|
||||
if !f.opened { return }
|
||||
C.fflush(f.cfile)
|
||||
}
|
||||
|
||||
pub fn (f File) close() {
|
||||
pub fn (f mut File) close() {
|
||||
if !f.opened { return }
|
||||
f.opened = false
|
||||
C.fflush(f.cfile)
|
||||
C.fclose(f.cfile)
|
||||
}
|
||||
|
||||
@ -707,7 +720,7 @@ pub fn home_dir() string {
|
||||
|
||||
// write_file writes `text` data to a file in `path`.
|
||||
pub fn write_file(path, text string) {
|
||||
f := os.create(path) or {
|
||||
mut f := os.create(path) or {
|
||||
return
|
||||
}
|
||||
f.write(text)
|
||||
|
@ -43,7 +43,7 @@ fn test_write_and_read_bytes() {
|
||||
file_name := './byte_reader_writer.tst'
|
||||
payload := [`I`, `D`, `D`, `Q`, `D`]
|
||||
|
||||
file_write := os.create(os.realpath(file_name)) or {
|
||||
mut file_write := os.create(os.realpath(file_name)) or {
|
||||
eprintln('failed to create file $file_name')
|
||||
return
|
||||
}
|
||||
@ -56,7 +56,7 @@ fn test_write_and_read_bytes() {
|
||||
|
||||
assert payload.len == os.file_size(file_name)
|
||||
|
||||
file_read := os.open(os.realpath(file_name)) or {
|
||||
mut file_read := os.open(os.realpath(file_name)) or {
|
||||
eprintln('failed to open file $file_name')
|
||||
return
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ fn (am mut AssetManager) combine(asset_type string, to_file bool) string {
|
||||
if !os.dir_exists(am.cache_dir) {
|
||||
os.mkdir(am.cache_dir) or { panic(err) }
|
||||
}
|
||||
file := os.create(out_file) or {
|
||||
mut file := os.create(out_file) or {
|
||||
panic(err)
|
||||
}
|
||||
file.write(out)
|
||||
|
Loading…
Reference in New Issue
Block a user