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 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").
|
Don't use past tense (e.g. "fixed foo bar").
|
||||||
|
|
||||||
Explain what your PR does and why.
|
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.
|
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
|
||||||
./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.
|
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
|
ls -lat
|
||||||
|
|
||||||
./v test v
|
./v test-compiler
|
||||||
|
|
||||||
echo "DONE"
|
echo "DONE"
|
||||||
|
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
|||||||
- name: Build V using V
|
- name: Build V using V
|
||||||
run: ./v -o v2 v.v && ./v2 -o v3 v.v
|
run: ./v -o v2 v.v && ./v2 -o v3 v.v
|
||||||
- name: Test v->c
|
- name: Test v->c
|
||||||
run: ./v test v
|
run: ./v test-compiler
|
||||||
# - name: Test v->js
|
# - name: Test v->js
|
||||||
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||||
- name: Test symlink
|
- name: Test symlink
|
||||||
@ -58,7 +58,7 @@ jobs:
|
|||||||
- name: Build V
|
- name: Build V
|
||||||
run: make && ./v -cc gcc -o v v.v
|
run: make && ./v -cc gcc -o v v.v
|
||||||
- name: Test V
|
- name: Test V
|
||||||
run: ./v test v
|
run: ./v test-compiler
|
||||||
# - name: Test v->js
|
# - name: Test v->js
|
||||||
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||||
- name: Build Vorum
|
- name: Build Vorum
|
||||||
@ -110,7 +110,7 @@ jobs:
|
|||||||
sudo ln -s /var/tmp/tcc/bin/tcc /usr/local/bin/tcc
|
sudo ln -s /var/tmp/tcc/bin/tcc /usr/local/bin/tcc
|
||||||
tcc -version
|
tcc -version
|
||||||
./v -o v2 v.v # Make sure vtcc can build itself
|
./v -o v2 v.v # Make sure vtcc can build itself
|
||||||
./v test v
|
./v test-compiler
|
||||||
|
|
||||||
ubuntu-musl:
|
ubuntu-musl:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
@ -124,7 +124,7 @@ jobs:
|
|||||||
- name: Build v
|
- name: Build v
|
||||||
run: make && ./v -cc musl-gcc -o v v.v
|
run: make && ./v -cc musl-gcc -o v v.v
|
||||||
# - name: Test v->c
|
# - name: Test v->c
|
||||||
# run: ./v test v
|
# run: ./v test-compiler
|
||||||
# - name: Test v->js
|
# - name: Test v->js
|
||||||
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ jobs:
|
|||||||
.\make.bat -gcc
|
.\make.bat -gcc
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
run: |
|
||||||
.\v.exe test v
|
.\v.exe test-compiler
|
||||||
## v.js dosent work on windows
|
## v.js dosent work on windows
|
||||||
#.\v.exe -o hi.js examples/hello_v_js.v
|
#.\v.exe -o hi.js examples/hello_v_js.v
|
||||||
#node hi.js
|
#node hi.js
|
||||||
@ -164,7 +164,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
VFLAGS: -cc msvc
|
VFLAGS: -cc msvc
|
||||||
run: |
|
run: |
|
||||||
.\v.exe test v
|
.\v.exe test-compiler
|
||||||
## v.js dosent work on windows
|
## v.js dosent work on windows
|
||||||
#.\v.exe -o hi.js examples/hello_v_js.v
|
#.\v.exe -o hi.js examples/hello_v_js.v
|
||||||
#node hi.js
|
#node hi.js
|
||||||
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
fns.txt
|
||||||
*.dSYM
|
*.dSYM
|
||||||
*_test
|
*_test
|
||||||
/v
|
/v
|
||||||
@ -12,12 +13,18 @@
|
|||||||
/tools/vrepl.exe
|
/tools/vrepl.exe
|
||||||
/tools/vtest
|
/tools/vtest
|
||||||
/tools/vtest.exe
|
/tools/vtest.exe
|
||||||
|
/tools/vtest-compiler
|
||||||
|
/tools/vtest-compiler.exe
|
||||||
/tools/vup
|
/tools/vup
|
||||||
/tools/vup.exe
|
/tools/vup.exe
|
||||||
/tools/vpm
|
/tools/vpm
|
||||||
/tools/vpm.exe
|
/tools/vpm.exe
|
||||||
/tools/vcreate
|
/tools/vcreate
|
||||||
/tools/vcreate.exe
|
/tools/vcreate.exe
|
||||||
|
/tools/vbuild-examples
|
||||||
|
/tools/vbuild-examples.exe
|
||||||
|
/tools/vbuild-tools
|
||||||
|
/tools/vbuild-tools.exe
|
||||||
*.exe
|
*.exe
|
||||||
*.o
|
*.o
|
||||||
.*.c
|
.*.c
|
||||||
@ -38,3 +45,6 @@ vjs
|
|||||||
._*
|
._*
|
||||||
.vrepl_temp.v
|
.vrepl_temp.v
|
||||||
a.out
|
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
|
/hello_v_js
|
||||||
/fibonacci
|
/fibonacci
|
||||||
/sqlite
|
/sqlite
|
||||||
|
empty_gg_freetype
|
||||||
|
game_of_life/life_gg
|
||||||
|
random_ips
|
||||||
|
vweb/vweb_example
|
||||||
|
x64/hello_world
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import log
|
import log
|
||||||
|
|
||||||
fn main() {
|
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.info('info')
|
||||||
l.warn('warn')
|
l.warn('warn')
|
||||||
l.error('error')
|
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"')
|
commit_date := exec('git log -n1 --pretty="format:%at"')
|
||||||
message := exec('git log -n1 --pretty="format:%s"')
|
message := exec('git log -n1 --pretty="format:%s"')
|
||||||
date := time.unix(commit_date.int())
|
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
|
// Place the new row on top
|
||||||
table =
|
table =
|
||||||
'<tr>
|
'<tr>
|
||||||
@ -57,7 +57,7 @@ fn main() {
|
|||||||
// Regenerate index.html
|
// Regenerate index.html
|
||||||
header := os.read_file('header.html') or { panic(err) }
|
header := os.read_file('header.html') or { panic(err) }
|
||||||
footer := os.read_file('footer.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(header)
|
||||||
res.writeln(table)
|
res.writeln(table)
|
||||||
res.writeln(footer)
|
res.writeln(footer)
|
||||||
|
@ -45,7 +45,7 @@ const(
|
|||||||
// name
|
// name
|
||||||
app_name = 'gen_vc'
|
app_name = 'gen_vc'
|
||||||
// version
|
// version
|
||||||
app_version = '0.1.0'
|
app_version = '0.1.1'
|
||||||
// description
|
// description
|
||||||
app_description = 'This tool regenerates V\'s bootstrap .c files every time the V master branch is updated.'
|
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
|
// assume something went wrong if file size less than this
|
||||||
@ -114,17 +114,22 @@ fn main() {
|
|||||||
fp.version(app_version)
|
fp.version(app_version)
|
||||||
fp.description(app_description)
|
fp.description(app_description)
|
||||||
fp.skip_executable()
|
fp.skip_executable()
|
||||||
|
|
||||||
|
show_help:=fp.bool('help', false, 'Show this help screen\n')
|
||||||
flag_options := parse_flags(mut fp)
|
flag_options := parse_flags(mut fp)
|
||||||
|
|
||||||
_ = fp.finalize() or {
|
if( show_help ){ println( fp.usage() ) exit(0) }
|
||||||
|
|
||||||
|
fp.finalize() or {
|
||||||
eprintln(err)
|
eprintln(err)
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// webhook server mode
|
// webhook server mode
|
||||||
if flag_options.serve {
|
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
|
// cmd mode
|
||||||
else {
|
else {
|
||||||
@ -136,15 +141,14 @@ fn main() {
|
|||||||
|
|
||||||
// new GenVC
|
// new GenVC
|
||||||
fn new_gen_vc(flag_options FlagOptions) &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{
|
return &GenVC{
|
||||||
// options
|
|
||||||
options: flag_options
|
options: flag_options
|
||||||
// logger
|
logger: logger
|
||||||
logger: if flag_options.log_to == 'file' {
|
|
||||||
&log.Log{log.DEBUG, flag_options.log_file}
|
|
||||||
} else {
|
|
||||||
&log.Log{log.DEBUG, 'terminal'}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +179,7 @@ fn parse_flags(fp mut flag.FlagParser) FlagOptions {
|
|||||||
purge : fp.bool('purge', false, 'force purge the local repositories')
|
purge : fp.bool('purge', false, 'force purge the local repositories')
|
||||||
port : fp.int('port', int(server_port), 'port for web server to listen on')
|
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_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')
|
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() {
|
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
|
mut vmod_content := []string
|
||||||
vmod_content << '#V Project#\n'
|
vmod_content << '#V Project#\n'
|
||||||
vmod_content << 'Module {'
|
vmod_content << 'Module {'
|
||||||
@ -31,7 +31,7 @@ fn (c Create)write_vmod() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (c Create)write_main() {
|
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
|
mut main_content := []string
|
||||||
main_content << 'module main\n'
|
main_content << 'module main\n'
|
||||||
main_content << 'fn main() {'
|
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 (
|
import (
|
||||||
os
|
os
|
||||||
term
|
testing
|
||||||
benchmark
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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() {
|
pub fn main() {
|
||||||
args := os.args
|
args := os.args
|
||||||
if args.last() == 'test' {
|
if args.last() == 'test' {
|
||||||
println('Usage:')
|
println('Usage:')
|
||||||
println(' A)')
|
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 test folder/ : run all v tests in the given folder.')
|
||||||
println(' v -stats test folder/ : the same, but print more stats.')
|
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 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(' 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.')
|
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 ')
|
args_after := args_string.all_after('test ')
|
||||||
|
|
||||||
if args_after == 'v' {
|
if args_after == 'v' {
|
||||||
v_test_v(args_before)
|
eprintln('`v test v` has been deprecated.')
|
||||||
return
|
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(' ') {
|
for targ in args_after.split(' ') {
|
||||||
if os.file_exists(targ) && targ.ends_with('_test.v') {
|
if os.file_exists(targ) && targ.ends_with('_test.v') {
|
||||||
ts.files << targ
|
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..]
|
stuff_after_executable := os.args[1..]
|
||||||
commands := stuff_after_executable.filter(!it.starts_with('-'))
|
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.
|
// Print the version and exit.
|
||||||
if '-v' in options || '--version' in options || 'version' in commands {
|
if '-v' in options || '--version' in options || 'version' in commands {
|
||||||
version_hash := compiler.vhash()
|
version_hash := compiler.vhash()
|
||||||
@ -39,10 +47,6 @@ fn main() {
|
|||||||
println('Translating C to V will be available in V 0.3')
|
println('Translating C to V will be available in V 0.3')
|
||||||
return
|
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 {
|
else if 'search' in commands || 'install' in commands || 'update' in commands || 'remove' in commands {
|
||||||
compiler.launch_tool('vpm')
|
compiler.launch_tool('vpm')
|
||||||
return
|
return
|
||||||
@ -55,10 +59,6 @@ fn main() {
|
|||||||
compiler.create_symlink()
|
compiler.create_symlink()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
else if 'create' in commands {
|
|
||||||
compiler.launch_tool('vcreate')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO quit if the v compiler is too old
|
// TODO quit if the v compiler is too old
|
||||||
// u := os.file_last_mod_unix('v')
|
// 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
|
// 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)
|
compiler.vfmt(args)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
else if 'test' in commands {
|
|
||||||
compiler.launch_tool('vtest')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// No args? REPL
|
// No args? REPL
|
||||||
else if 'runrepl' in commands || commands.len == 0 || (args.len == 2 && args[1] == '-') {
|
else if 'runrepl' in commands || commands.len == 0 || (args.len == 2 && args[1] == '-') {
|
||||||
compiler.launch_tool('vrepl')
|
compiler.launch_tool('vrepl')
|
||||||
|
@ -42,7 +42,7 @@ mut:
|
|||||||
|
|
||||||
fn new_cgen(out_name_c string) &CGen {
|
fn new_cgen(out_name_c string) &CGen {
|
||||||
path := out_name_c
|
path := out_name_c
|
||||||
out := os.create(path) or {
|
mut out := os.create(path) or {
|
||||||
println('failed to create $path')
|
println('failed to create $path')
|
||||||
return &CGen{}
|
return &CGen{}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ fn generate_vh(mod string) {
|
|||||||
os.mkdir_all(pdir)
|
os.mkdir_all(pdir)
|
||||||
// os.mkdir(os.realpath(dir)) or { panic(err) }
|
// 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("\\", "/")
|
mod_path := mod.replace("\\", "/")
|
||||||
out.writeln('// $mod_path module header\n')
|
out.writeln('// $mod_path module header\n')
|
||||||
mod_def := if mod_path.contains('/') { mod_path.all_after('/') } else { mod_path } // "os"
|
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
|
return
|
||||||
}
|
}
|
||||||
println('generating ${p.file_name}.v')
|
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')
|
verror('failed to create fmt.v')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ pub fn (g mut Gen) generate_elf_footer() {
|
|||||||
// -5 is for "e8 00 00 00 00"
|
// -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)
|
g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos+1)
|
||||||
// Create the binary
|
// 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)
|
os.chmod(g.out_name, 0775)
|
||||||
f.write_bytes(g.buf.data, g.buf.len)
|
f.write_bytes(g.buf.data, g.buf.len)
|
||||||
f.close()
|
f.close()
|
||||||
|
@ -45,7 +45,7 @@ module flag
|
|||||||
// ```
|
// ```
|
||||||
|
|
||||||
// data object storing information about a defined flag
|
// data object storing information about a defined flag
|
||||||
struct Flag {
|
pub struct Flag {
|
||||||
pub:
|
pub:
|
||||||
name string // name as it appears on command line
|
name string // name as it appears on command line
|
||||||
abbr byte // shortcut
|
abbr byte // shortcut
|
||||||
@ -55,7 +55,7 @@ pub:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
struct FlagParser {
|
pub struct FlagParser {
|
||||||
pub mut:
|
pub mut:
|
||||||
args []string // the arguments to be parsed
|
args []string // the arguments to be parsed
|
||||||
flags []Flag // registered flags
|
flags []Flag // registered flags
|
||||||
@ -69,7 +69,7 @@ pub mut:
|
|||||||
args_description string
|
args_description string
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
pub const (
|
||||||
// used for formating usage message
|
// used for formating usage message
|
||||||
SPACE = ' '
|
SPACE = ' '
|
||||||
UNDERLINE = '-----------------------------------------------'
|
UNDERLINE = '-----------------------------------------------'
|
||||||
@ -125,14 +125,13 @@ fn (fs mut FlagParser) parse_value(n string, ab byte) ?string {
|
|||||||
c := '--$n'
|
c := '--$n'
|
||||||
for i, a in fs.args {
|
for i, a in fs.args {
|
||||||
if a == c || (a.len == 2 && a[1] == ab) {
|
if a == c || (a.len == 2 && a[1] == ab) {
|
||||||
if fs.args.len > i+1 && fs.args[i+1].left(2) != '--' {
|
if i+1 > fs.args.len { panic('Missing argument for \'$n\'') }
|
||||||
val := fs.args[i+1]
|
nextarg := fs.args[i+1]
|
||||||
fs.args.delete(i+1)
|
if nextarg.limit(2) == '--' { panic('Missing argument for \'$n\'') }
|
||||||
fs.args.delete(i)
|
val := fs.args[i+1]
|
||||||
return val
|
fs.args.delete(i+1)
|
||||||
} else {
|
fs.args.delete(i)
|
||||||
panic('Missing argument for \'$n\'')
|
return val
|
||||||
}
|
|
||||||
} else if a.len > c.len && c == a[..c.len] && a[c.len..c.len+1] == '=' {
|
} else if a.len > c.len && c == a[..c.len] && a[c.len..c.len+1] == '=' {
|
||||||
val := a[c.len+1..]
|
val := a[c.len+1..]
|
||||||
fs.args.delete(i)
|
fs.args.delete(i)
|
||||||
|
@ -247,3 +247,20 @@ fn test_allow_abreviations() {
|
|||||||
u := fp.usage()
|
u := fp.usage()
|
||||||
assert u.contains(' -v') && u.contains(' -o') && u.contains(' -i') && u.contains(' -f')
|
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 os
|
||||||
import time
|
import time
|
||||||
import term
|
import term
|
||||||
|
import filepath
|
||||||
|
|
||||||
pub enum LogLevel {
|
pub enum LogLevel {
|
||||||
fatal
|
fatal = 1
|
||||||
error
|
error
|
||||||
warning
|
warn
|
||||||
info
|
info
|
||||||
debug
|
debug
|
||||||
}
|
}
|
||||||
@ -16,8 +17,8 @@ fn tag(l LogLevel) string {
|
|||||||
return match l {
|
return match l {
|
||||||
.fatal { term.red('F') }
|
.fatal { term.red('F') }
|
||||||
.error { term.red('E') }
|
.error { term.red('E') }
|
||||||
.warning { term.yellow('W') }
|
.warn { term.yellow('W') }
|
||||||
.info { term.white('I') }
|
.info { term.white('I') }
|
||||||
.debug { term.blue('D') }
|
.debug { term.blue('D') }
|
||||||
else { ' ' }
|
else { ' ' }
|
||||||
}
|
}
|
||||||
@ -40,17 +41,21 @@ interface Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Log {
|
pub struct Log {
|
||||||
mut:
|
mut:
|
||||||
level LogLevel
|
level LogLevel
|
||||||
output_label string
|
output_label string
|
||||||
|
|
||||||
|
ofile os.File
|
||||||
output_to_file bool
|
output_to_file bool
|
||||||
|
pub:
|
||||||
|
output_file_name string
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (l mut Log) set_level(level int){
|
pub fn (l mut Log) set_level(level int){
|
||||||
l.level = match level {
|
l.level = match level {
|
||||||
FATAL { LogLevel.fatal }
|
FATAL { LogLevel.fatal }
|
||||||
ERROR { LogLevel.error }
|
ERROR { LogLevel.error }
|
||||||
WARN { LogLevel.warning }
|
WARN { LogLevel.warn }
|
||||||
INFO { LogLevel.info }
|
INFO { LogLevel.info }
|
||||||
DEBUG { LogLevel.debug }
|
DEBUG { LogLevel.debug }
|
||||||
else { .debug }
|
else { .debug }
|
||||||
@ -61,79 +66,74 @@ pub fn (l mut Log) set_output_level(level LogLevel){
|
|||||||
l.level = level
|
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
|
l.output_label = label
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (l mut Log) set_output(output string){
|
pub fn (l mut Log) set_output_path(output_file_path string) {
|
||||||
l.output_label = output
|
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) {
|
pub fn (l mut Log) close(){
|
||||||
filename := '${l.output_label}.log'.replace(' ', '')
|
l.ofile.close()
|
||||||
f := os.open_append(filename) or {
|
}
|
||||||
panic('error reading file $filename')
|
|
||||||
}
|
fn (l mut Log) log_file(s string, level LogLevel) {
|
||||||
timestamp := time.now().format_ss()
|
timestamp := time.now().format_ss()
|
||||||
e := tag(level)
|
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)
|
f := tag(level)
|
||||||
t := time.now()
|
t := time.now()
|
||||||
println('[$f ${t.format_ss()}] $s')
|
println('[$f ${t.format_ss()}] $s')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (l Log) fatal(s string){
|
fn (l mut Log) send_output(s &string, level LogLevel){
|
||||||
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
|
|
||||||
}
|
|
||||||
if l.output_to_file {
|
if l.output_to_file {
|
||||||
l.log_file(s, .debug)
|
l.log_file(s, level)
|
||||||
} else {
|
} 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 {
|
pub struct File {
|
||||||
cfile voidptr // Using void* instead of FILE*
|
cfile voidptr // Using void* instead of FILE*
|
||||||
|
mut:
|
||||||
|
opened bool
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
@ -68,14 +70,17 @@ fn C.getenv(byteptr) &char
|
|||||||
fn C.sigaction(int, voidptr, int)
|
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
|
// 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)
|
return f.read_bytes_at(size, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// read_bytes_at reads an amount of bytes at the given position in the file
|
// 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)
|
mut arr := [`0`].repeat(size)
|
||||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
C.fseek(f.cfile, pos, C.SEEK_SET)
|
||||||
nreadbytes := C.fread(arr.data, 1, size, f.cfile)
|
nreadbytes := C.fread(arr.data, 1, size, f.cfile)
|
||||||
@ -281,6 +286,7 @@ pub fn open(path string) ?File {
|
|||||||
if isnil(file.cfile) {
|
if isnil(file.cfile) {
|
||||||
return error('failed to open file "$path"')
|
return error('failed to open file "$path"')
|
||||||
}
|
}
|
||||||
|
file.opened = true
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,6 +308,7 @@ pub fn create(path string) ?File {
|
|||||||
if isnil(file.cfile) {
|
if isnil(file.cfile) {
|
||||||
return error('failed to create file "$path"')
|
return error('failed to create file "$path"')
|
||||||
}
|
}
|
||||||
|
file.opened = true
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,10 +329,11 @@ pub fn open_append(path string) ?File {
|
|||||||
if isnil(file.cfile) {
|
if isnil(file.cfile) {
|
||||||
return error('failed to create(append) file "$path"')
|
return error('failed to create(append) file "$path"')
|
||||||
}
|
}
|
||||||
|
file.opened = true
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (f File) write(s string) {
|
pub fn (f mut File) write(s string) {
|
||||||
C.fputs(s.str, f.cfile)
|
C.fputs(s.str, f.cfile)
|
||||||
// C.fwrite(s.str, 1, s.len, 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
|
// convert any value to []byte (LittleEndian) and write it
|
||||||
// for example if we have write(7, 4), "07 00 00 00" gets written
|
// for example if we have write(7, 4), "07 00 00 00" gets written
|
||||||
// write(0x1234, 2) => "34 12"
|
// 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)
|
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.fseek(f.cfile, pos, C.SEEK_SET)
|
||||||
C.fwrite(data, 1, size, f.cfile)
|
C.fwrite(data, 1, size, f.cfile)
|
||||||
C.fseek(f.cfile, 0, C.SEEK_END)
|
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)
|
// C.fwrite(s.str, 1, s.len, f.cfile)
|
||||||
// ss := s.clone()
|
// ss := s.clone()
|
||||||
// TODO perf
|
// TODO perf
|
||||||
@ -352,11 +361,15 @@ pub fn (f File) writeln(s string) {
|
|||||||
C.fputs('\n', f.cfile)
|
C.fputs('\n', f.cfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (f File) flush() {
|
pub fn (f mut File) flush() {
|
||||||
|
if !f.opened { return }
|
||||||
C.fflush(f.cfile)
|
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)
|
C.fclose(f.cfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,7 +720,7 @@ pub fn home_dir() string {
|
|||||||
|
|
||||||
// write_file writes `text` data to a file in `path`.
|
// write_file writes `text` data to a file in `path`.
|
||||||
pub fn write_file(path, text string) {
|
pub fn write_file(path, text string) {
|
||||||
f := os.create(path) or {
|
mut f := os.create(path) or {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.write(text)
|
f.write(text)
|
||||||
|
@ -43,7 +43,7 @@ fn test_write_and_read_bytes() {
|
|||||||
file_name := './byte_reader_writer.tst'
|
file_name := './byte_reader_writer.tst'
|
||||||
payload := [`I`, `D`, `D`, `Q`, `D`]
|
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')
|
eprintln('failed to create file $file_name')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ fn test_write_and_read_bytes() {
|
|||||||
|
|
||||||
assert payload.len == os.file_size(file_name)
|
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')
|
eprintln('failed to open file $file_name')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ fn (am mut AssetManager) combine(asset_type string, to_file bool) string {
|
|||||||
if !os.dir_exists(am.cache_dir) {
|
if !os.dir_exists(am.cache_dir) {
|
||||||
os.mkdir(am.cache_dir) or { panic(err) }
|
os.mkdir(am.cache_dir) or { panic(err) }
|
||||||
}
|
}
|
||||||
file := os.create(out_file) or {
|
mut file := os.create(out_file) or {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
file.write(out)
|
file.write(out)
|
||||||
|
Loading…
Reference in New Issue
Block a user