Skip to content

Instantly share code, notes, and snippets.

@zhaozg
Created August 18, 2015 05:20
Show Gist options
  • Save zhaozg/1cfaeffebb4a5a9431d0 to your computer and use it in GitHub Desktop.
Save zhaozg/1cfaeffebb4a5a9431d0 to your computer and use it in GitHub Desktop.
luvit_thread_test.lua
local uv = require'uv' --to get new_thread
local luvi = require'luvi' --to get bundle base
local timer = require'timer' --lib in luvit
local interval = timer.setInterval(1000, function ()
print('Main Thread')
end)
print("Main ...running...")
function thread(cli,base)
print(cli,'running')
print('require',require)
init = require'thread_init'
init(base)
local uv = require'uv'
print('require',require)
local timer = require'timer'
local interval = timer.setInterval(1000, function ()
print(cli,'tick')
end)
uv.run()
end
local base = luvi.bundle.base
uv.new_thread(thread,'cli1',base)
uv.new_thread(thread,'cli2',base)
uv.new_thread(thread,'cli3',base)
--[[
Copyright 2014 The Luvit Authors. All Rights Reserved.
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.
--]]
local os = require('ffi').os
local env = require('env')
local uv = require('uv')
local luvi = require('luvi')
local miniz = require('miniz')
local getPrefix, splitPath, joinParts
local tmpBase = os == "Windows" and (env.get("TMP") or uv.cwd()) or
(env.get("TMPDIR") or '/tmp')
if os == "Windows" then
-- Windows aware path utilities
function getPrefix(path)
return path:match("^%a:\\") or
path:match("^/") or
path:match("^\\+")
end
function splitPath(path)
local parts = {}
for part in string.gmatch(path, '([^/\\]+)') do
table.insert(parts, part)
end
return parts
end
function joinParts(prefix, parts, i, j)
if not prefix then
return table.concat(parts, '/', i, j)
elseif prefix ~= '/' then
return prefix .. table.concat(parts, '\\', i, j)
else
return prefix .. table.concat(parts, '/', i, j)
end
end
else
-- Simple optimized versions for UNIX systems
function getPrefix(path)
return path:match("^/")
end
function splitPath(path)
local parts = {}
for part in string.gmatch(path, '([^/]+)') do
table.insert(parts, part)
end
return parts
end
function joinParts(prefix, parts, i, j)
if prefix then
return prefix .. table.concat(parts, '/', i, j)
end
return table.concat(parts, '/', i, j)
end
end
local function pathJoin(...)
local inputs = {...}
local l = #inputs
-- Find the last segment that is an absolute path
-- Or if all are relative, prefix will be nil
local i = l
local prefix
while true do
prefix = getPrefix(inputs[i])
if prefix or i <= 1 then break end
i = i - 1
end
-- If there was one, remove its prefix from its segment
if prefix then
inputs[i] = inputs[i]:sub(#prefix)
end
-- Split all the paths segments into one large list
local parts = {}
while i <= l do
local sub = splitPath(inputs[i])
for j = 1, #sub do
parts[#parts + 1] = sub[j]
end
i = i + 1
end
-- Evaluate special segments in reverse order.
local skip = 0
local reversed = {}
for idx = #parts, 1, -1 do
local part = parts[idx]
if part == '.' then
-- Ignore
elseif part == '..' then
skip = skip + 1
elseif skip > 0 then
skip = skip - 1
else
reversed[#reversed + 1] = part
end
end
-- Reverse the list again to get the correct order
parts = reversed
for idx = 1, #parts / 2 do
local j = #parts - idx + 1
parts[idx], parts[j] = parts[j], parts[idx]
end
local path = joinParts(prefix, parts)
return path
end
-- Bundle from folder on disk
local function folderBundle(base)
local bundle = { base = base }
function bundle.stat(path)
path = pathJoin(base, "./" .. path)
local raw, err = uv.fs_stat(path)
if not raw then return nil, err end
return {
type = string.lower(raw.type),
size = raw.size,
mtime = raw.mtime,
}
end
function bundle.readdir(path)
path = pathJoin(base, "./" .. path)
local req, err = uv.fs_scandir(path)
if not req then
return nil, err
end
local files = {}
repeat
local ent = uv.fs_scandir_next(req)
if ent then
files[#files + 1] = ent.name
end
until not ent
return files
end
function bundle.readfile(path)
path = pathJoin(base, "./" .. path)
local fd, stat, data, err
stat, err = uv.fs_stat(path)
if not stat then return nil, err end
if stat.type ~= "file" then return end
fd, err = uv.fs_open(path, "r", 0644)
if not fd then return nil, err end
if stat then
data, err = uv.fs_read(fd, stat.size, 0)
end
uv.fs_close(fd)
return data, err
end
return bundle
end
-- Insert a prefix into all bundle calls
local function chrootBundle(bundle, prefix)
local bundleStat = bundle.stat
function bundle.stat(path)
return bundleStat(prefix .. path)
end
local bundleReaddir = bundle.readdir
function bundle.readdir(path)
return bundleReaddir(prefix .. path)
end
local bundleReadfile = bundle.readfile
function bundle.readfile(path)
return bundleReadfile(prefix .. path)
end
end
-- Use a zip file as a bundle
local function zipBundle(base, zip)
local bundle = { base = base }
function bundle.stat(path)
path = pathJoin("./" .. path)
if path == "" then
return {
type = "directory",
size = 0,
mtime = 0
}
end
local err
local index = zip:locate_file(path)
if not index then
index, err = zip:locate_file(path .. "/")
if not index then return nil, err end
end
local raw = zip:stat(index)
return {
type = raw.filename:sub(-1) == "/" and "directory" or "file",
size = raw.uncomp_size,
mtime = raw.time,
}
end
function bundle.readdir(path)
path = pathJoin("./" .. path)
local index, err
if path == "" then
index = 0
else
path = path .. "/"
index, err = zip:locate_file(path )
if not index then return nil, err end
if not zip:is_directory(index) then
return nil, path .. " is not a directory"
end
end
local files = {}
for i = index + 1, zip:get_num_files() do
local filename = zip:get_filename(i)
if string.sub(filename, 1, #path) ~= path then break end
filename = filename:sub(#path + 1)
local n = string.find(filename, "/")
if n == #filename then
filename = string.sub(filename, 1, #filename - 1)
n = nil
end
if not n then
files[#files + 1] = filename
end
end
return files
end
function bundle.readfile(path)
path = pathJoin("./" .. path)
local index, err = zip:locate_file(path)
if not index then return nil, err end
return zip:extract(index)
end
-- Support zips with a single folder inserted at top-level
local entries = bundle.readdir("")
if #entries == 1 and bundle.stat(entries[1]).type == "directory" then
chrootBundle(bundle, entries[1] .. '/')
end
return bundle
end
-- Given a list of bundles, merge them into a single VFS. Lower indexed items
-- overshadow later items.
local function combinedBundle(bundles)
local bases = {}
for i = 1, #bundles do
bases[i] = bundles[i].base
end
local bundle = { base = table.concat(bases, ";") }
function bundle.stat(path)
local err
for i = 1, #bundles do
local stat
stat, err = bundles[i].stat(path)
if stat then return stat end
end
return nil, err
end
function bundle.readdir(path)
local has = {}
local files, err
for i = 1, #bundles do
local list
list, err = bundles[i].readdir(path)
if list then
for j = 1, #list do
local name = list[j]
if has[name] then
print("Warning multiple overlapping versions of " .. name)
else
has[name] = true
if files then
files[#files + 1] = name
else
files = { name }
end
end
end
end
end
if files then
return files
else
return nil, err
end
end
function bundle.readfile(path)
local err
for i = 1, #bundles do
local data
data, err = bundles[i].readfile(path)
if data then return data end
end
return nil, err
end
return bundle
end
local function makeBundle(bundlePaths)
local parts = {}
for n = 1, #bundlePaths do
local path = pathJoin(uv.cwd(), bundlePaths[n])
bundlePaths[n] = path
local bundle
local zip = miniz.new_reader(path)
if zip then
bundle = zipBundle(path, zip)
else
local stat = uv.fs_stat(path)
if not stat or stat.type ~= "directory" then
error("ERROR: " .. path .. " is not a zip file or a folder")
end
bundle = folderBundle(path)
end
parts[n] = bundle
end
if #parts == 1 then
return parts[1]
end
return combinedBundle(parts)
end
local function commonBundle(bundle, args, bundlePaths, mainPath)
luvi.makeBundle = makeBundle
luvi.bundle = bundle
mainPath = mainPath or "main.lua"
bundle.paths = bundlePaths
bundle.mainPath = mainPath
luvi.path = {
join = pathJoin,
getPrefix = getPrefix,
splitPath = splitPath,
joinparts = joinParts,
}
function bundle.action(path, action, ...)
-- If it's a real path, run it directly.
if uv.fs_access(path, "r") then return action(path) end
-- Otherwise, copy to a temporary folder and run from there
local data, err = bundle.readfile(path)
if not data then return nil, err end
local dir = assert(uv.fs_mkdtemp(pathJoin(tmpBase, "lib-XXXXXX")))
path = pathJoin(dir, path:match("[^/\\]+$"))
local fd = uv.fs_open(path, "w", 384) -- 0600
uv.fs_write(fd, data, 0)
uv.fs_close(fd)
local success, ret = pcall(action, path, ...)
uv.fs_unlink(path)
uv.fs_rmdir(dir)
assert(success, ret)
return ret
end
function bundle.register(name, path)
if not path then path = name + ".lua" end
package.preload[name] = function (...)
local lua = assert(bundle.readfile(path))
return assert(loadstring(lua, "bundle:" .. path))(...)
end
end
_G.args = args
-- Auto-register the require system if present
local mainRequire
local stat = bundle.stat("deps/require.lua")
if stat and stat.type == "file" then
bundle.register('require', "deps/require.lua")
_G.require = require('require')("bundle:main.lua")
end
-- Auto-setup global p and libuv version of print
if require and bundle.stat("deps/pretty-print") or bundle.stat("deps/pretty-print.lua") then
_G.p = require('pretty-print').prettyPrint
end
end
return function(base)
-- First check for a bundled zip file appended to the executable
local path = uv.exepath()
local zip = miniz.new_reader(path)
if zip then
return commonBundle(zipBundle(path, zip), {}, {path})
end
-- Parse the arguments
local bundles = { base or '.' }
local bundle = assert(makeBundle(bundles))
-- Run the luvi app with the extra args
return commonBundle(bundle, {}, bundles)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment