diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE
index d08b8a9528..d32209bfd7 100644
--- a/.github/PULL_REQUEST_TEMPLATE
+++ b/.github/PULL_REQUEST_TEMPLATE
@@ -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.
diff --git a/.github/workflows/alpine.test.sh b/.github/workflows/alpine.test.sh
index 32f611ac80..784a849aa1 100755
--- a/.github/workflows/alpine.test.sh
+++ b/.github/workflows/alpine.test.sh
@@ -10,6 +10,6 @@ du -s .
ls -lat
-./v test v
+./v test-compiler
echo "DONE"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ec71d2ba3e..0ffda1dee8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -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
diff --git a/.gitignore b/.gitignore
index cf118032f5..c47b41c540 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/examples/.gitignore b/examples/.gitignore
index 45c94880f0..182d47571f 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -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
diff --git a/examples/eventbus/some_module/some_module.v b/examples/eventbus/modules/some_module/some_module.v
similarity index 100%
rename from examples/eventbus/some_module/some_module.v
rename to examples/eventbus/modules/some_module/some_module.v
diff --git a/examples/game_of_life/automaton/automaton.v b/examples/game_of_life/modules/automaton/automaton.v
similarity index 100%
rename from examples/game_of_life/automaton/automaton.v
rename to examples/game_of_life/modules/automaton/automaton.v
diff --git a/examples/log.v b/examples/log.v
index 466439319c..cdcac94cde 100644
--- a/examples/log.v
+++ b/examples/log.v
@@ -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')
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644
index 0000000000..fcb39ffda3
--- /dev/null
+++ b/tools/.gitignore
@@ -0,0 +1,9 @@
+gen_vc
+performance_compare
+vcreate
+vnames
+vpm
+vrepl
+vtest
+vtest-compiler
+vup
diff --git a/tools/fast/fast.v b/tools/fast/fast.v
index d5eaefb2e9..468fcbe692 100644
--- a/tools/fast/fast.v
+++ b/tools/fast/fast.v
@@ -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 =
'
@@ -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)
diff --git a/tools/gen_vc.v b/tools/gen_vc.v
index 267b054300..9404c5146c 100644
--- a/tools/gen_vc.v
+++ b/tools/gen_vc.v
@@ -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(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')
}
}
diff --git a/tools/modules/testing/common.v b/tools/modules/testing/common.v
new file mode 100644
index 0000000000..64b5077078
--- /dev/null
+++ b/tools/modules/testing/common.v
@@ -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
+}
diff --git a/tools/vbuild-examples.v b/tools/vbuild-examples.v
new file mode 100644
index 0000000000..a8db8f075f
--- /dev/null
+++ b/tools/vbuild-examples.v
@@ -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)
+ }
+}
diff --git a/tools/vbuild-tools.v b/tools/vbuild-tools.v
new file mode 100644
index 0000000000..3c8d2de68f
--- /dev/null
+++ b/tools/vbuild-tools.v
@@ -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)
+ }
+}
diff --git a/tools/vcreate.v b/tools/vcreate.v
index 3537383654..0a0806fef7 100644
--- a/tools/vcreate.v
+++ b/tools/vcreate.v
@@ -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() {'
diff --git a/tools/vtest-compiler.v b/tools/vtest-compiler.v
new file mode 100644
index 0000000000..1c34ef8811
--- /dev/null
+++ b/tools/vtest-compiler.v
@@ -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)
+ }
+
+}
diff --git a/tools/vtest.v b/tools/vtest.v
index 19d84d5ecc..cbd9d613b5 100644
--- a/tools/vtest.v
+++ b/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')
- */
-}
diff --git a/v.v b/v.v
index b34832ab11..33b7a1fbe6 100755
--- a/v.v
+++ b/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')
diff --git a/vlib/compiler/cgen.v b/vlib/compiler/cgen.v
index 288ff2d09d..0fb0c3a4ab 100644
--- a/vlib/compiler/cgen.v
+++ b/vlib/compiler/cgen.v
@@ -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{}
}
diff --git a/vlib/compiler/module_header.v b/vlib/compiler/module_header.v
index 454c2ab780..2d02a0ebd1 100644
--- a/vlib/compiler/module_header.v
+++ b/vlib/compiler/module_header.v
@@ -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"
diff --git a/vlib/compiler/vfmt.v b/vlib/compiler/vfmt.v
index 582d15dc00..9d498918a1 100644
--- a/vlib/compiler/vfmt.v
+++ b/vlib/compiler/vfmt.v
@@ -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
}
diff --git a/vlib/compiler/x64/elf.v b/vlib/compiler/x64/elf.v
index bef5cac00d..3a97ab46fe 100644
--- a/vlib/compiler/x64/elf.v
+++ b/vlib/compiler/x64/elf.v
@@ -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()
diff --git a/vlib/flag/flag.v b/vlib/flag/flag.v
index c132ab6b4a..4e20128d26 100644
--- a/vlib/flag/flag.v
+++ b/vlib/flag/flag.v
@@ -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)
diff --git a/vlib/flag/flag_test.v b/vlib/flag/flag_test.v
index afea40be20..39364db85a 100644
--- a/vlib/flag/flag_test.v
+++ b/vlib/flag/flag_test.v
@@ -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')
+}
diff --git a/vlib/log/log.v b/vlib/log/log.v
index 5ab445398d..ac36be27dd 100644
--- a/vlib/log/log.v
+++ b/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)
+}
+
diff --git a/vlib/os/os.v b/vlib/os/os.v
index e0f2c5e267..5206967719 100644
--- a/vlib/os/os.v
+++ b/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)
diff --git a/vlib/os/os_test.v b/vlib/os/os_test.v
index cd6e335d75..911cc5d506 100644
--- a/vlib/os/os_test.v
+++ b/vlib/os/os_test.v
@@ -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
}
diff --git a/vlib/ui/ui_lin.v b/vlib/ui/ui_linux.v
similarity index 100%
rename from vlib/ui/ui_lin.v
rename to vlib/ui/ui_linux.v
diff --git a/vlib/vweb/assets/assets.v b/vlib/vweb/assets/assets.v
index 07d56e4813..963653f4e9 100644
--- a/vlib/vweb/assets/assets.v
+++ b/vlib/vweb/assets/assets.v
@@ -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)