package manager

This commit is contained in:
kepler155c@gmail.com 2018-11-04 13:00:37 -05:00
parent 67be1e0f2f
commit 99b2fa1b0b
7 changed files with 132 additions and 43 deletions

View File

@ -1,40 +1,52 @@
local json = require('json')
local Util = require('util')
-- Limit queries to once per minecraft day
-- TODO: will not work if time is stopped
local TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1'
local FILE_URL = 'https://raw.githubusercontent.com/%s/%s/%s/%s'
local git = { }
local fs = _G.fs
local os = _G.os
if not _G.GIT then
_G.GIT = { }
end
function git.list(repository, cache)
function git.list(repository)
local t = Util.split(repository, '(.-)/')
local user = t[1]
local repo = t[2]
local branch = t[3] or 'master'
local user = table.remove(t, 1)
local repo = table.remove(t, 1)
local branch = table.remove(t, 1) or 'master'
local path
local dataUrl = string.format(TREE_URL, user, repo, branch)
if _G.GIT[dataUrl] then
_G.GIT[dataUrl].count = _G.GIT[dataUrl].count + 1
else
_G.GIT[dataUrl] = {
count = 1
}
end
local contents = Util.download(dataUrl)
if not contents then
error('Invalid repository')
if not Util.empty(t) then
path = table.concat(t, '/') .. '/'
end
local data = json.decode(contents)
Util.writeTable('.git/' .. dataUrl, { day = os.day(), data = data })
local cacheKey = table.concat({ user, repo, branch }, '-')
local fname = fs.combine('.git', cacheKey)
local function getContents()
if fs.exists(fname) then
local contents = Util.readTable(fname)
if contents and contents.data == os.day() then
return contents.data
end
fs.delete(fname)
end
local dataUrl = string.format(TREE_URL, user, repo, branch)
local contents = Util.download(dataUrl)
if contents then
return json.decode(contents)
end
end
local data = getContents() or error('Invalid repository')
if data.message and data.message:find("API rate limit exceeded") then
error("Out of API calls, try again later")
end
@ -43,15 +55,26 @@ Util.writeTable('.git/' .. dataUrl, { day = os.day(), data = data })
error("Invalid repository")
end
local list = { }
if not fs.exists(fname) then
Util.writeTable('.git/' .. cacheKey, { day = os.day(), data = data })
end
local list = { }
for _,v in pairs(data.tree) do
if v.type == "blob" then
v.path = v.path:gsub("%s","%%20")
list[v.path] = {
url = string.format(FILE_URL, user, repo, branch, v.path),
size = v.size,
}
if not path then
list[v.path] = {
url = string.format(FILE_URL, user, repo, branch, v.path),
size = v.size,
}
elseif Util.startsWith(v.path, path) then
local p = string.sub(v.path, #path)
list[p] = {
url = string.format(FILE_URL, user, repo, branch, path .. p),
size = v.size,
}
end
end
end

View File

@ -34,8 +34,7 @@ function Packages:isInstalled(package)
end
function Packages:getManifest(package)
-- local fname = 'packages/' .. package .. '/.package'
local fname = 'usr/milo/.package'
local fname = 'packages/' .. package .. '/.package'
if fs.exists(fname) then
return Util.readTable(fname)
end

View File

@ -507,7 +507,7 @@ function Util.matches(str, pattern)
return t
end
function Util.startsWidth(s, match)
function Util.startsWith(s, match)
return string.sub(s, 1, #match) == match
end

View File

@ -82,7 +82,7 @@ local function loadApplications()
end
end
return true -- Util.startsWidth(a.run, 'http') or shell.resolveProgram(a.run)
return true -- Util.startsWith(a.run, 'http') or shell.resolveProgram(a.run)
end)
end

View File

@ -1,9 +1,11 @@
_G.requireInjector(_ENV)
local Git = require('git')
local Packages = require('packages')
local Util = require('util')
local fs = _G.fs
local fs = _G.fs
local term = _G.term
local args = { ... }
local action = table.remove(args, 1)
@ -16,6 +18,47 @@ if action == 'list' then
for k in pairs(Packages:list()) do
Util.print('[%s] %s', Packages:isInstalled(k) and 'x' or ' ', k)
end
return
end
local function progress(max)
-- modified from: https://pastebin.com/W5ZkVYSi (apemanzilla)
local _, y = term.getCursorPos()
local wide, _ = term.getSize()
term.setCursorPos(1, y)
term.write("[")
term.setCursorPos(wide - 6, y)
term.write("]")
local done = 0
return function()
done = done + 1
local value = done / max
term.setCursorPos(2,y)
term.write(("="):rep(math.floor(value * (wide - 8))))
local percent = math.floor(value * 100) .. "%"
term.setCursorPos(wide - percent:len(),y)
term.write(percent)
end
end
local function install(name)
local manifest = Packages:getManifest(name) or error('Invalid package')
local packageDir = fs.combine('packages', name)
local method = args[2] or 'local'
if method == 'remote' then
Util.writeTable(packageDir .. '/.install', {
mount = string.format('%s gitfs %s', packageDir, manifest.repository),
})
Util.writeTable(fs.combine(packageDir, '.package'), manifest)
else
local list = Git.list(manifest.repository)
local showProgress = progress(Util.size(list))
for path, entry in pairs(list) do
Util.download(entry.url, fs.combine(packageDir, path))
showProgress()
end
end
return
end
if action == 'install' then
@ -23,14 +66,30 @@ if action == 'install' then
if Packages:isInstalled(name) then
error('Package is already installed')
end
local manifest = Packages:getManifest(name) or error('Invalid package')
local packageDir = 'packages/' .. name
local method = args[2] or 'remote'
if method == 'remote' then
Util.writeTable(packageDir .. '/.install', {
mount = string.format('%s gitfs %s', packageDir, manifest.repository),
})
Util.writeTable(fs.combine(packageDir, '.package'), manifest)
print('success')
end
install(name)
print('installation complete')
return
end
if action == 'update' then
local name = args[1] or Syntax('Invalid package')
if not Packages:isInstalled(name) then
error('Package is not installed')
end
install(name)
print('update complete')
return
end
if action == 'uninstall' then
local name = args[1] or Syntax('Invalid package')
if not Packages:isInstalled(name) then
error('Package is not installed')
end
local packageDir = fs.combine('packages', name)
fs.delete(packageDir)
print('removed: ' .. packageDir)
return
end
error('Syntax: Package [list | install [name] ... | update [name] | uninstall [name]')

View File

@ -25,7 +25,7 @@ end
-- dependency graph
-- https://github.com/mpeterv/depgraph/blob/master/src/depgraph/init.lua
for name, package in pairs(Packages:installed()) do
for name in pairs(Packages:installed()) do
local packageDir = fs.combine('packages', name)
if fs.exists(fs.combine(packageDir, '.install')) then
local install = Util.readTable(fs.combine(packageDir, '.install'))

View File

@ -1,5 +1,13 @@
{
[ 'opus-neural' ] = 'file://packages/opus-neural/.package',
[ 'opus-miners' ] = 'file://packages/opus-miners/.package',
[ 'opus-milo' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/milo/.package',
[ 'core' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/core/.package',
[ 'builder' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/builder/.package',
[ 'farms' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/farms/.package',
[ 'forestry' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/forestry/.package',
[ 'glasses' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/glasses/.package',
[ 'milo' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/milo/.package',
[ 'miners' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/miners/.package',
[ 'neural' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/neural/.package',
[ 'pickup' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/pickup/.package',
[ 'recipeBook' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/recipeBook/.package',
[ 'storage' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/storage/.package',
}