--!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file os.lua -- -- load modules local io = require("base/io") local os = require("base/os") local utils = require("base/utils") local xmake = require("base/xmake") local option = require("base/option") local semver = require("base/semver") local scheduler = require("base/scheduler") local sandbox = require("sandbox/sandbox") local vformat = require("sandbox/modules/vformat") -- define module local sandbox_os = sandbox_os or {} -- inherit some builtin interfaces sandbox_os.shell = os.shell sandbox_os.term = os.term sandbox_os.host = os.host sandbox_os.arch = os.arch sandbox_os.subhost = os.subhost sandbox_os.subarch = os.subarch sandbox_os.is_host = os.is_host sandbox_os.is_arch = os.is_arch sandbox_os.is_subhost = os.is_subhost sandbox_os.is_subarch = os.is_subarch sandbox_os.syserror = os.syserror sandbox_os.strerror = os.strerror sandbox_os.exit = os.exit sandbox_os.atexit = os.atexit sandbox_os.date = os.date sandbox_os.time = os.time sandbox_os.args = os.args sandbox_os.args = os.args sandbox_os.argv = os.argv sandbox_os.mtime = os.mtime sandbox_os.raise = os.raise sandbox_os.fscase = os.fscase sandbox_os.isroot = os.isroot sandbox_os.mclock = os.mclock sandbox_os.nuldev = os.nuldev sandbox_os.getenv = os.getenv sandbox_os.setenv = os.setenv sandbox_os.addenv = os.addenv sandbox_os.setenvp = os.setenvp sandbox_os.addenvp = os.addenvp sandbox_os.getenvs = os.getenvs sandbox_os.setenvs = os.setenvs sandbox_os.addenvs = os.addenvs sandbox_os.joinenvs = os.joinenvs sandbox_os.pbpaste = os.pbpaste sandbox_os.pbcopy = os.pbcopy sandbox_os.cpuinfo = os.cpuinfo sandbox_os.meminfo = os.meminfo sandbox_os.default_njob = os.default_njob sandbox_os.emptydir = os.emptydir sandbox_os.filesize = os.filesize sandbox_os.features = os.features sandbox_os.workingdir = os.workingdir sandbox_os.programdir = os.programdir sandbox_os.programfile = os.programfile sandbox_os.projectdir = os.projectdir sandbox_os.projectfile = os.projectfile sandbox_os.getwinsize = os.getwinsize sandbox_os.getpid = os.getpid -- syserror code sandbox_os.SYSERR_UNKNOWN = os.SYSERR_UNKNOWN sandbox_os.SYSERR_NONE = os.SYSERR_NONE sandbox_os.SYSERR_NOT_PERM = os.SYSERR_NOT_PERM sandbox_os.SYSERR_NOT_FILEDIR = os.SYSERR_NOT_FILEDIR sandbox_os.SYSERR_NOT_ACCESS = os.SYSERR_NOT_ACCESS -- copy file or directory function sandbox_os.cp(srcpath, dstpath, opt) assert(srcpath and dstpath) srcpath = tostring(srcpath) dstpath = tostring(dstpath) local ok, errors = os.cp(vformat(srcpath), vformat(dstpath), opt) if not ok then os.raise(errors) end end -- move file or directory function sandbox_os.mv(srcpath, dstpath, opt) assert(srcpath and dstpath) srcpath = tostring(srcpath) dstpath = tostring(dstpath) local ok, errors = os.mv(vformat(srcpath), vformat(dstpath), opt) if not ok then os.raise(errors) end end -- remove files or directories function sandbox_os.rm(filepath, opt) assert(filepath) filepath = tostring(filepath) local ok, errors = os.rm(vformat(filepath), opt) if not ok then os.raise(errors) end end -- link file or directory to the new symfile function sandbox_os.ln(srcpath, dstpath, opt) assert(srcpath and dstpath) srcpath = tostring(srcpath) dstpath = tostring(dstpath) local ok, errors = os.ln(vformat(srcpath), vformat(dstpath), opt) if not ok then os.raise(errors) end end -- copy file or directory with the verbose info function sandbox_os.vcp(srcpath, dstpath, opt) assert(srcpath and dstpath) if option.get("verbose") then utils.cprint("${dim}> copy %s to %s", srcpath, dstpath) end return sandbox_os.cp(srcpath, dstpath, opt) end -- move file or directory with the verbose info function sandbox_os.vmv(srcpath, dstpath, opt) assert(srcpath and dstpath) if option.get("verbose") then utils.cprint("${dim}> move %s to %s", srcpath, dstpath) end return sandbox_os.mv(srcpath, dstpath, opt) end -- remove file or directory with the verbose info function sandbox_os.vrm(filepath, opt) assert(filepath) if option.get("verbose") then utils.cprint("${dim}> remove %s", filepath) end return sandbox_os.rm(filepath, opt) end -- link file or directory with the verbose info function sandbox_os.vln(srcpath, dstpath, opt) assert(srcpath and dstpath) if option.get("verbose") then utils.cprint("${dim}> link %s to %s", srcpath, dstpath) end return sandbox_os.ln(srcpath, dstpath, opt) end -- try to copy file or directory function sandbox_os.trycp(srcpath, dstpath, opt) assert(srcpath and dstpath) return os.cp(vformat(srcpath), vformat(dstpath), opt) end -- try to move file or directory function sandbox_os.trymv(srcpath, dstpath, opt) assert(srcpath and dstpath) return os.mv(vformat(srcpath), vformat(dstpath), opt) end -- try to remove files or directories function sandbox_os.tryrm(filepath, opt) assert(filepath) return os.rm(vformat(filepath), opt) end -- change to directory function sandbox_os.cd(dir) -- check assert(dir) -- format it first dir = vformat(dir) -- enter this directory local oldir, errors = os.cd(dir) if not oldir then os.raise(errors) end -- ok return oldir end -- touch file or directory function sandbox_os.touch(filepath, opt) assert(filepath) local ok, errors = os.touch(vformat(filepath), opt) if not ok then os.raise(errors) end end -- create directories function sandbox_os.mkdir(dir) assert(dir) local ok, errors = os.mkdir(vformat(dir)) if not ok then os.raise(errors) end end -- remove directories function sandbox_os.rmdir(dir, opt) assert(dir) local ok, errors = os.rmdir(vformat(dir), opt) if not ok then os.raise(errors) end end -- get the current directory function sandbox_os.curdir() return assert(os.curdir()) end -- get the temporary directory function sandbox_os.tmpdir(opt) return assert(os.tmpdir(opt)) end -- get the temporary file function sandbox_os.tmpfile(key, opt) return assert(os.tmpfile(key, opt)) end -- get the script directory function sandbox_os.scriptdir() local instance = sandbox.instance() local rootdir = instance:rootdir() assert(rootdir) return rootdir end -- quietly run command function sandbox_os.run(cmd, ...) cmd = vformat(cmd, ...) local ok, errors = os.run(cmd) if not ok then os.raise(errors) end end -- quietly run command with arguments list function sandbox_os.runv(program, argv, opt) program = vformat(program) local ok, errors = os.runv(program, argv, opt) if not ok then os.raise(errors) end end -- quietly run command and echo verbose info if [-v|--verbose] option is enabled function sandbox_os.vrun(cmd, ...) if option.get("verbose") then print(vformat(cmd, ...)) end (option.get("verbose") and sandbox_os.exec or sandbox_os.run)(cmd, ...) end -- quietly run command with arguments list and echo verbose info if [-v|--verbose] option is enabled function sandbox_os.vrunv(program, argv, opt) if option.get("verbose") then print(vformat(program) .. " " .. sandbox_os.args(argv or {})) end if not (opt and opt.dryrun) then (option.get("verbose") and sandbox_os.execv or sandbox_os.runv)(program, argv, opt) end end -- run command and return output and error data function sandbox_os.iorun(cmd, ...) cmd = vformat(cmd, ...) local ok, outdata, errdata, errors = os.iorun(cmd) if not ok then if not errors then errors = errdata or "" if #errors:trim() == 0 then errors = outdata or "" end end os.raise({errors = errors, stderr = errdata, stdout = outdata}) end return outdata, errdata end -- run command and return output and error data function sandbox_os.iorunv(program, argv, opt) program = vformat(program) local ok, outdata, errdata, errors = os.iorunv(program, argv, opt) if not ok then if not errors then errors = errdata or "" if #errors:trim() == 0 then errors = outdata or "" end end os.raise({errors = errors, stderr = errdata, stdout = outdata}) end return outdata, errdata end -- execute command function sandbox_os.exec(cmd, ...) cmd = vformat(cmd, ...) local ok, errors = os.exec(cmd) if ok ~= 0 then if ok ~= nil then errors = string.format("exec(%s) failed(%d), %s", cmd, ok, errors or "unknown reason") else errors = string.format("cannot exec(%s), %s", cmd, errors or "unknown reason") end os.raise(errors) end end -- execute command with arguments list function sandbox_os.execv(program, argv, opt) -- make program program = vformat(program) -- flush io buffer first for fixing redirect io output order -- -- e.g. -- -- xmake run > /tmp/a -- print("xxx1") -- os.exec("echo xxx2") -- -- cat /tmp/a -- xxx2 -- xxx1 -- io.flush() -- run it opt = opt or {} local ok, errors = os.execv(program, argv, opt) if ok ~= 0 and not opt.try then -- get command local cmd = program if argv then cmd = cmd .. " " .. os.args(argv) end -- get errors if ok ~= nil then errors = string.format("execv(%s) failed(%d), %s", cmd, ok, errors or "unknown reason") else errors = string.format("cannot execv(%s), %s", cmd, errors or "unknown reason") end os.raise(errors) end -- we need return results if opt.try is enabled return ok, errors end -- execute command and echo verbose info if [-v|--verbose] option is enabled function sandbox_os.vexec(cmd, ...) -- echo command if option.get("verbose") then utils.cprint("${color.dump.string}" .. vformat(cmd, ...)) end -- run it sandbox_os.exec(cmd, ...) end -- execute command with arguments list and echo verbose info if [-v|--verbose] option is enabled function sandbox_os.vexecv(program, argv, opt) -- echo command if option.get("verbose") then utils.cprint("${color.dump.string}" .. vformat(program) .. " " .. sandbox_os.args(argv)) end -- run it if not (opt and opt.dryrun) then return sandbox_os.execv(program, argv, opt) else return 0 end end -- match files or directories function sandbox_os.match(pattern, mode, opt) return os.match(vformat(tostring(pattern)), mode, opt) end -- match directories function sandbox_os.dirs(pattern, opt) return os.dirs(vformat(tostring(pattern)), opt) end -- match files function sandbox_os.files(pattern, opt) return os.files(vformat(tostring(pattern)), opt) end -- match files and directories function sandbox_os.filedirs(pattern, opt) return os.filedirs(vformat(tostring(pattern)), opt) end -- is directory? function sandbox_os.isdir(dirpath) assert(dirpath) dirpath = tostring(dirpath) return os.isdir(vformat(dirpath)) end -- is file? function sandbox_os.isfile(filepath) assert(filepath) filepath = tostring(filepath) return os.isfile(vformat(filepath)) end -- is symlink? function sandbox_os.islink(filepath) assert(filepath) filepath = tostring(filepath) return os.islink(vformat(filepath)) end -- is execute program? function sandbox_os.isexec(filepath) assert(filepath) filepath = tostring(filepath) return os.isexec(vformat(filepath)) end -- exists file or directory? function sandbox_os.exists(filedir) assert(filedir) filedir = tostring(filedir) return os.exists(vformat(filedir)) end -- read the content of symlink function sandbox_os.readlink(symlink) local result = os.readlink(tostring(symlink)) if not result then os.raise("cannot read link(%s)", symlink) end return result end -- sleep (support in coroutine) function sandbox_os.sleep(ms) if scheduler:co_running() then local ok, errors = scheduler:co_sleep(ms) if not ok then raise(errors) end else os.sleep(ms) end end -- get xmake version function sandbox_os.xmakever() -- fill cache if sandbox_os._XMAKEVER == nil then -- get xmakever local xmakever = semver.new(xmake._VERSION_SHORT) -- save to cache sandbox_os._XMAKEVER = xmakever or false end -- done return sandbox_os._XMAKEVER or nil end -- return module return sandbox_os