From be7cf3e8120e06533f73db82bee0ae9d6f9fb473 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 17 Nov 2019 05:45:20 +0200 Subject: [PATCH] compiler: support storing temporary files under TMPDIR/v/ Fix for filepath.join not \0 terminating its result --- vlib/compiler/main.v | 7 +++--- vlib/compiler/vhelp.v | 3 +++ vlib/compiler/vtmp.v | 21 +++++++++++++++++ vlib/filepath/filepath.v | 12 ++++------ vlib/os/os.v | 51 +++++++++++++++++++++++++++++++++------- vlib/os/os_test.v | 19 ++++++++++++++- 6 files changed, 92 insertions(+), 21 deletions(-) create mode 100644 vlib/compiler/vtmp.v diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index b99ca38979..48a5db5e15 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -799,6 +799,7 @@ pub fn new_v(args[]string) &V { vgen_buf.writeln('module vgen\nimport strings') joined_args := args.join(' ') + target_os := get_arg(joined_args, 'os', '') comptime_define := get_arg(joined_args, 'd', '') //println('comptimedefine=$comptime_define') @@ -930,8 +931,8 @@ pub fn new_v(args[]string) &V { println('Go to https://vlang.io to install V.') exit(1) } - // println('out_name:$out_name') - mut out_name_c := os.realpath('${out_name}.tmp.c') + + mut out_name_c := get_vtmp_filename( out_name, '.tmp.c') cflags := get_cmdline_cflags(args) @@ -978,7 +979,7 @@ pub fn new_v(args[]string) &V { println('C compiler=$pref.ccompiler') } if pref.is_so { - out_name_c = out_name.all_after(os.path_separator) + '_shared_lib.c' + out_name_c = get_vtmp_filename( out_name, '.tmp.so.c') } $if !linux { if pref.is_bare && !out_name.ends_with('.c') { diff --git a/vlib/compiler/vhelp.v b/vlib/compiler/vhelp.v index 8da96f3b71..8bf29eea8e 100644 --- a/vlib/compiler/vhelp.v +++ b/vlib/compiler/vhelp.v @@ -28,6 +28,9 @@ pub const ( You can set it like this: `export VFLAGS="-cc clang -debug"` on *nix, `set VFLAGS=-cc msvc` on Windows. + V respects the TMPDIR environment variable, and will put .tmp.c files in TMPDIR/v/ . + If you have not set it, a suitable platform specific folder (like /tmp) will be used. + Options/commands: -h, help Display this information. -o Write output to . diff --git a/vlib/compiler/vtmp.v b/vlib/compiler/vtmp.v new file mode 100644 index 0000000000..2505fe8d24 --- /dev/null +++ b/vlib/compiler/vtmp.v @@ -0,0 +1,21 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +module compiler + +import os +import filepath + +pub fn get_vtmp_folder() string { + vtmp := filepath.join(os.tmpdir(),'v') + if !os.dir_exists( vtmp ) { + os.mkdir(vtmp) + } + return vtmp +} + +pub fn get_vtmp_filename(base_file_name string, postfix string) string { + vtmp := get_vtmp_folder() + return os.realpath( filepath.join(vtmp, os.filename( base_file_name ) + postfix) ) +} diff --git a/vlib/filepath/filepath.v b/vlib/filepath/filepath.v index 016a84abf8..61ed5c79fb 100644 --- a/vlib/filepath/filepath.v +++ b/vlib/filepath/filepath.v @@ -2,7 +2,6 @@ module filepath import( os - strings ) // return the extension in the file `path` @@ -26,11 +25,8 @@ pub fn is_abs(path string) bool { // pass directories as parameters, returns path as string // TODO use []string.join once ...string becomes "[]string" pub fn join(base string, dirs ...string) string { - mut path := strings.new_builder(50) - path.write(base.trim_right('\\/')) - for d in dirs { - path.write(os.path_separator) - path.write(d) - } - return path.str() + mut result := []string + result << base.trim_right('\\/') + for d in dirs { result << d } + return result.join( os.path_separator ) } diff --git a/vlib/os/os.v b/vlib/os/os.v index 60a24cf06f..46880e61f4 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -145,17 +145,26 @@ pub fn cp(old, new string) ?bool { } } -pub fn cp_r(source_path, dest_path string, overwrite bool) ?bool{ +pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool{ + source_path := os.realpath( osource_path ) + dest_path := os.realpath( odest_path ) if !os.file_exists(source_path) { return error('Source path doesn\'t exist') } //single file copy if !os.is_dir(source_path) { adjasted_path := if os.is_dir(dest_path) { - filepath.join(dest_path, os.basedir(source_path)) } else { dest_path } + filepath.join(dest_path, os.filename(source_path)) + } else { + dest_path + } if os.file_exists(adjasted_path) { - if overwrite { os.rm(adjasted_path) } - else { return error('Destination file path already exist') } + if overwrite { + os.rm(adjasted_path) + } + else { + return error('Destination file path already exist') + } } os.cp(source_path, adjasted_path) or { return error(err) } return true @@ -558,7 +567,7 @@ pub fn basedir(path string) string { if pos == -1 { return path } - return path[..pos + 1] + return path[..pos ] // NB: *without* terminating / } pub fn filename(path string) string { @@ -835,10 +844,6 @@ pub fn realpath(fpath string) string { res = int( !isnil(C._fullpath( fullpath, fpath.str, MAX_PATH )) ) } $else{ - if fpath.len != strlen(fpath.str) { - l := strlen(fpath.str) - println('FIXME realpath diff len $fpath.len strlen=$l') - } ret := C.realpath(fpath.str, fullpath) if ret == 0 { return fpath @@ -965,3 +970,31 @@ pub fn join(base string, dirs ...string) string { println('use filepath.join') return filepath.join(base, dirs) } + +// tmpdir returns the path to a folder, that is suitable for storing temporary files +pub fn tmpdir() string { + mut path := os.getenv('TMPDIR') + $if linux { + if path == '' { path = '/tmp' } + } + $if mac { + /* + if path == '' { + // TODO untested + path = C.NSTemporaryDirectory() + } + */ + if path == '' { path = '/tmp' } + } + $if windows { + if path == '' { + // TODO see Qt's implementation? + // https://doc.qt.io/qt-5/qdir.html#tempPath + // https://github.com/qt/qtbase/blob/e164d61ca8263fc4b46fdd916e1ea77c7dd2b735/src/corelib/io/qfilesystemengine_win.cpp#L1275 + path = os.getenv('TEMP') + if path == '' { path = os.getenv('TMP') } + if path == '' { path = 'C:/tmp' } + } + } + return path +} diff --git a/vlib/os/os_test.v b/vlib/os/os_test.v index 2c11e29f42..b43e65c60c 100644 --- a/vlib/os/os_test.v +++ b/vlib/os/os_test.v @@ -152,6 +152,24 @@ fn test_cp_r() { os.cp_r('ex', './', true) or { panic(err) } } +fn test_tmpdir(){ + t := os.tmpdir() + assert t.len > 0 + assert os.is_dir(t) + + tfile := t + os.path_separator + 'tmpfile.txt' + + os.rm(tfile) // just in case + + tfile_content := 'this is a temporary file' + os.write_file(tfile, tfile_content) + + tfile_content_read := os.read_file(tfile) or { panic(err) } + assert tfile_content_read == tfile_content + + os.rm(tfile) +} + //fn test_fork() { // pid := os.fork() // if pid == 0 { @@ -179,7 +197,6 @@ fn test_zzz_cleanup(){ cleanup_leftovers() assert true } - // this function is called by both test_aaa_setup & test_zzz_cleanup // it ensures that os tests do not polute the filesystem with leftover // files so that they can be run several times in a row.