Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 1188 lines (1096 sloc) 45.2 KB
#!/usr/bin/env lua
package.cpath = "/home/kiwi/media/programs/lua/clyde/?.so;"..package.cpath
package.path ="/home/kiwi/media/programs/lua/clyde/?.lua;"..package.path
colorize = require "clydelib.colorize"
local util = require "clydelib.util"
local sync = require "clydelib.sync"
local query = require "clydelib.query"
local remove = require "clydelib.remove"
local upgrade = require "clydelib.upgrade"
local packages = require "clydelib.packages"
local alpm = require "lualpm"
local utilcore = require "clydelib.utilcore"
local signal = require "clydelib.signal"
local callback = require "clydelib.callback"
local aur = require "clydelib.aur"
local ui = require "clydelib.ui"
local needs_root = util.needs_root
local printf = util.printf
local lprintf = util.lprintf
local eprintf = util.eprintf
local basename = util.basename
local cleanup = util.cleanup
local tblinsert = util.tblinsert
local realpath = util.realpath
local strsplit = util.strsplit
local strtrim = util.strtrim
local g = utilcore.gettext
local bindtextdomain = utilcore.bindtextdomain
local textdomain = utilcore.textdomain
local geteuid = utilcore.geteuid
local C = colorize
local ROOTDIR = "/"
local PACMANCFG_PATH = "/etc/pacman.conf"
local CLYDECFG_PATH = "/etc/clyde.conf"
local DBPATH = "/var/lib/pacman/"
local CACHEDIR = "/var/cache/pacman/pkg/"
local LOGFILE = "/var/log/pacman.log"
local clydeconf = require "clydelib.config"
local PACKAGE = "clyde"
local LOCALEDIR = "/usr/share/locale"
local VERSION = '0.03.15'
local LUALPM_VERSION = '0.03'
local function usage(op, myname)
local str_opt = g("options")
local str_file = g("file(s)")
local str_pkg = g("package(s)")
local str_usg = g("usage")
local str_opr = g("operation")
if(op == "PM_OP_MAIN") then
printf("%s: %s <%s> [...]\n", str_usg, myname, str_opr)
printf(g("operations:\n"))
printf(" %s {-h --help}\n", myname)
printf(" %s {-V --version}\n", myname)
printf(" %s { --stats}\n", myname)
printf(" %s {-Q --query} [%s] [%s]\n", myname, str_opt, str_pkg)
printf(" %s {-R --remove} [%s] <%s>\n", myname, str_opt, str_pkg)
printf(" %s {-S --sync} [%s] [%s]\n", myname, str_opt, str_pkg)
printf(" %s {-U --upgrade} [%s] <%s>\n", myname, str_opt, str_file)
printf(" %s {-G --getpkgbuild} [%s] [%s]\n", myname, str_opt, str_pkg)
printf(g("\nuse '%s {-h --help}' with an operation for available options\n"), myname)
else
if (op == "PM_OP_REMOVE") then
printf("%s: %s {-R --remove} [%s] <%s>\n", str_usg, myname, str_opt, str_pkg)
printf("%s:\n", str_opt)
printf(g(" -c, --cascade remove packages and all packages that depend on them\n"))
printf(g(" -d, --nodeps skip dependency checks\n"))
printf(g(" -k, --dbonly only remove database entry, do not remove files\n"))
printf(g(" -n, --nosave remove configuration files as well\n"))
printf(g(" -s, --recursive remove dependencies also (that won't break packages)\
(-ss includes explicitly installed dependencies too)\n"))
printf(g(" -u, --unneeded remove unneeded packages (that won't break packages)\n"))
elseif(op == "PM_OP_UPGRADE") then
printf("%s: %s {-U --upgrade} [%s] <%s>\n", str_usg, myname, str_opt, str_file)
printf("%s:\n", str_opt)
printf(g(" --asdeps install packages as non-explicitly installed\n"))
printf(g(" --asexplicit install packages as explicitly installed\n"))
printf(g(" -d, --nodeps skip dependency checks\n"))
printf(g(" -f, --force force install, overwrite conflicting files\n"))
elseif(op == "PM_OP_QUERY") then
printf("%s: %s {-Q --query} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg)
printf("%s:\n", str_opt)
printf(g(" -c, --changelog view the changelog of a package\n"))
printf(g(" -d, --deps list packages installed as dependencies [filter]\n"))
printf(g(" -e, --explicit list packages explicitly installed [filter]\n"))
printf(g(" -g, --groups view all members of a package group\n"))
printf(g(" -i, --info view package information (-ii for backup files)\n"))
printf(g(" -k, --check check that the files owned by the package(s) are present\n"))
printf(g(" -l, --list list the contents of the queried package\n"))
printf(g(" -m, --foreign list installed packages not found in sync db(s) [filter]\n"))
printf(g(" -o, --owns <file> query the package that owns <file>\n"))
printf(g(" -p, --file <package> query a package file instead of the database\n"))
printf(g(" -s, --search <regex> search locally-installed packages for matching strings\n"))
printf(g(" -t, --unrequired list packages not required by any package [filter]\n"))
printf(g(" -u, --upgrades list outdated packages [filter]\n"))
printf(g(" -q, --quiet show less information for query and search\n"))
elseif(op == "PM_OP_SYNC") then
printf("%s: %s {-S --sync} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg)
printf("%s:\n", str_opt)
printf(g(" -a, --aur only search or install packages from AUR\n"))
printf(g(" --asdeps install packages as non-explicitly installed\n"))
printf(g(" --asexplicit install packages as explicitly installed\n"))
printf(g(" -c, --clean remove old packages from cache directory (-cc for all)\n"))
printf(g(" -d, --nodeps skip dependency checks\n"))
printf(g(" -f, --force force install, overwrite conflicting files\n"))
printf(g(" -g, --groups view all members of a package group\n"))
printf(g(" -i, --info view package information\n"))
printf(g(" -l, --list <repo> view a list of packages in a repo\n"))
printf(g(" -p, --print-uris print out URIs for given packages and their dependencies\n"))
printf(g(" -s, --search <regex> search remote repositories for matching strings\n"))
printf(g(" -u, --sysupgrade upgrade installed packages (-uu allows downgrade)\n"))
printf(g(" -w, --downloadonly download packages but do not install/upgrade anything\n"))
printf(g(" -y, --refresh download fresh package databases from the server\n"))
printf(g(" --user <user> user to run makepkg as when installing software from AUR\n"))
printf(g(" --needed don't reinstall up to date packages\n"))
printf(g(" --ignore <pkg> ignore a package upgrade (can be used more than once)\n"))
printf(g(" --ignoregroup <grp>\
ignore a group upgrade (can be used more than once)\n"))
printf(g(" --repos only search or install packages from the configured repositories\n"))
printf(g(" -q, --quiet show less information for query and search\n"))
elseif(op == "PM_OP_GETPKG") then
printf("%s: %s {-G --getpkgbuild} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg)
printf("%s:\n", str_opt)
printf(g(" -d, --deps download files for dependencies from AUR as well\n"))
end
printf(g(" --config <path> set an alternate configuration file\n"))
printf(g(" --logfile <path> set an alternate log file\n"))
printf(g(" --noconfirm do not ask for any confirmation\n"))
printf(g(" --noprogressbar do not show a progress bar when downloading files\n"))
printf(g(" --noscriptlet do not execute the install scriptlet if one exists\n"))
printf(g(" -v, --verbose be verbose\n"))
printf(g(" --debug display debug messages\n"))
printf(g(" -r, --root <path> set an alternate installation root\n"))
printf(g(" -b, --dbpath <path> set an alternate database location\n"))
printf(g(" --cachedir <dir> set an alternate package cache location\n"))
printf(g(" --builddir <dir> set an alternate package build location\n"))
printf(g(" --editor <prg> edit the PKGBUILD with the configured editor\n"))
printf(g(" --color enable colors\n"))
printf(g(" --nocolor disable colors\n"))
end
end
--[[
local function version()
printf("\n")
printf(" .--. .---. Clyde v0.0.1 - lualpm v0.1.0\n")
printf(" '-._ \\ .-. .-|O O | ~~ Copyright (C) 2009 Robert Djubek\n")
printf(g(" .-' / '-' '-|~~~ | ~~~ This program may be freely redistributed under\n"))
printf(g(" '--' |.-.-.| ~~ the terms of the GNU General Public License.\n"))
printf("\n")
end
--]]
local function version()
printf("\n")
printf(C.yelb(" .--. ")..C.yel(" .---. ")..
"Clyde v%s - lualpm v%s\n", VERSION, LUALPM_VERSION)
printf(C.yelb(" '-._ \\")..C.bright(" .-. .-")..C.yel("|O O | ")..C.cya("~~ ").."Copyright (C) 2010 Robert Djubek\n")
printf(C.yelb(" .-' /")..C.bright(" '-' '-")..C.yel("|~~~ |")..C.red(" ~~~ ").."This program may be freely redistributed under\n")
printf(C.yelb(" '--' ")..C.yel(" |.-.-.|")..C.gre(" ~~ ").."the terms of the GNU General Public License.\n")
printf("\n")
end
local ranlocalize = false
local function localize()
if (not ranlocalize) then
local ret = os.setlocale("", "all")
local bind = bindtextdomain(PACKAGE, LOCALEDIR)
local text = textdomain(PACKAGE)
end
end
local function getopt_long(argv, sh_opts, long_opts, option_tbl)
local options = {}
local exit = false
local opttbl = option_tbl
if not next(options) then
local numargs = {
["no_argument"] = 0;
["required_argument"] = 1;
["optional_argument"] = 2;
}
for short, accept in sh_opts:gmatch("(%a)(:?:?)") do
options[short] = {["numarg"] = #accept, ["short"] = short}
end
for i, v in ipairs(long_opts) do
options[v[1]] = {["short"] = v[4], ["numarg"] = numargs[v[2]]}
end
end
local optindex = 0
local index = 2
return function()
while optindex < #argv do
optindex = optindex + 1
local argument = argv[optindex]
if argument == "--" then
optindex = optindex + 1
break
elseif argument == "-" then
break
elseif argument:sub(1,2) == "--" then
local pos = argument:find("=", 1, true)
if pos then
local option = argument:sub(3, pos -1)
if options[option] then
if options[option].numarg > 0 then
if argument:sub(pos + 1) then
return options[option].short, argument:sub(pos + 1)
else
print(basename(argv[0]) .. ": option '--" .. option .. "' requires an argument")
end
else
print(basename(argv[0]) .. ": option '--" .. option .. "' doesn\'t allow an argument")
end
else
print(basename(argv[0]) .. ": unrecognized option '--" .. option .. "'")
exit = true
break
end
else
local option = argument:sub(3)
if options[option] then
if options[option].numarg == 1 then
if optindex == #argv then
print(basename(argv[0]) .. ": option --'" .. option .. "' requires an argument")
elseif not argv[optindex + 1]:match("^%-") then
if options[option].numarg == 2 then
opttbl[#opttbl + 1] = argv[optindex + 1]
optindex = optindex + 1
return options[option].short, nil
else
optindex = optindex + 1
return options[option].short, argv[optindex]
end
else
print(basename(argv[0]) .. ": option --'" .. option .. "' requires an argument")
end
else
if argv[optindex + 1] and not argv[optindex + 1]:match("^%-") then
opttbl[#opttbl + 1] = argv[optindex + 1]
optindex = optindex + 1
return options[option].short, nil
else
return options[option].short, nil
end
end
else
print(basename(argv[0]) .. ": unrecognized option '--" .. option .. "'")
exit = true
break
end
end
elseif argument:sub(1, 1) == "-" then
for j = index, #argument do
local option = argument:sub(j, j)
if options[option] then
if options[option].numarg > 0 then
if optindex == #argv then
print(basename(argv[0]) .. ": option requires an argument -- '" .. option .. "'")
elseif not argv[optindex + 1]:match("^%-") then
if options[option].numarg == 2 then
opttbl[#opttbl + 1] = argv[optindex + 1]
optindex = optindex + 1
return options[option].short, nil
else
optindex = optindex + 1
return options[option].short, argv[optindex]
end
else
print(basename(argv[0]) .. ": option requires an argument -- '" .. option .. "'")
end
else
optindex = optindex - 1
index = index + 1
return options[option].short, nil
end
else
print(basename(argv[0]) .. ": invalid option -- '" .. option .. "'")
exit = true
break
end
end
index = 2
else
if optindex <= #argv then
local option = argv[optindex]
opttbl[#opttbl +1] = argv[optindex]
end
end
end
if exit == true then cleanup(1) return nil end
end
end
local function set_builddir ( builddir )
lprintf("LOG_DEBUG", "config: builddir: %s\n", str)
config.builddir = builddir
end
local function parseargs()
local longopts = {
--[[
--clyde specific options
--]]
{"aur", "no_argument", 0, 'a'},
{"nocolor", "no_argument", 0, 'OP_NOCOLOR'},
{"color", "no_argument", 0, 'OP_COLOR'},
{"stats", "no_argument", 0, 'OP_STATS'},
{"editor", "required_argument",0, 'OP_EDITOR'},
{"repos", "no_argument", 0, 'OP_REPOS'},
{"getpkgbuild", "no_argument", 0, 'G'},
{"user", "required_argument",0, 'OP_BUILD'},
{"builddir", "required_argument",0, 'OP_BUILDDIR'},
--[[
--pacman feature functions
--]]
{"query", "no_argument", 0, 'Q'},
{"remove", "no_argument", 0, 'R'},
{"sync", "no_argument", 0, 'S'},
{"deptest", "no_argument", 0, 'T'},
{"upgrade", "no_argument", 0, 'U'},
{"version", "no_argument", 0, 'V'},
{"dbpath", "required_argument", 0, 'b'},
{"cascade", "no_argument", 0, 'c'},
{"changelog", "no_argument", 0, 'c'},
{"clean", "no_argument", 0, 'c'},
{"nodeps", "no_argument", 0, 'd'},
{"deps", "no_argument", 0, 'd'},
{"explicit", "no_argument", 0, 'e'},
{"force", "no_argument", 0, 'f'},
{"groups", "no_argument", 0, 'g'},
{"help", "no_argument", 0, 'h'},
{"info", "no_argument", 0, 'i'},
{"dbonly", "no_argument", 0, 'k'},
{"check", "no_argument", 0, 'k'},
{"list", "no_argument", 0, 'l'},
{"foreign", "no_argument", 0, 'm'},
{"nosave", "no_argument", 0, 'n'},
{"owns", "no_argument", 0, 'o'},
{"file", "no_argument", 0, 'p'},
{"print-uris", "no_argument", 0, 'p'},
{"quiet", "no_argument", 0, 'q'},
{"root", "required_argument", 0, 'r'},
{"recursive", "no_argument", 0, 's'},
{"search", "no_argument", 0, 's'},
{"unrequired", "no_argument", 0, 't'},
{"upgrades", "no_argument", 0, 'u'},
{"sysupgrade", "no_argument", 0, 'u'},
{"unneeded", "no_argument", 0, 'u'},
{"verbose", "no_argument", 0, 'v'},
{"downloadonly", "no_argument", 0, 'w'},
{"refresh", "no_argument", 0, 'y'},
{"noconfirm", "no_argument", 0, 'OP_NOCONFIRM'},
{"config", "required_argument", 0, 'OP_CONFIG'},
{"ignore", "required_argument", 0, 'OP_IGNORE'},
{"debug", "optional_argument", 0, 'OP_DEBUG'},
{"noprogressbar", "no_argument", 0, 'OP_NOPROGRESSBAR'},
{"noscriptlet", "no_argument", 0, 'OP_NOSCRIPTLET'},
-- {"ask", "required_argument", 0, 'OP_ASK'},
{"cachedir", "required_argument", 0, 'OP_CACHEDIR'},
{"asdeps", "no_argument", 0, 'OP_ASDEPS'},
{"logfile", "required_argument", 0, 'OP_LOGFILE'},
{"ignoregroup", "required_argument", 0, 'OP_IGNOREGROUP'},
{"needed", "no_argument", 0, 'OP_NEEDED'},
{"asexplicit", "no_argument", 0, 'OP_ASEXPLICIT'},
-- {"arch", "required_argument", 0, 'OP_ARCH'},
}
local settrans = function(val)
return function()
if config.op ~= "PM_OP_MAIN" then
config.op = nil
else
config.op = val
end
end
end
local lookuptbl = {
--[[
--clyde specific options
--]]
['a'] = function()
config.op_s_search_aur_only = true
config.op_s_upgrade_aur = true
end;
['OP_NOCOLOR'] = function()
config.op_use_color = false
colorize.disable()
end;
['OP_COLOR'] = function()
config.op_use_color = true
colorize.enable()
end;
['OP_STATS'] = function()
config.stats = true
end;
['OP_EDITOR'] = function(opt)
config.editor = opt
end;
['OP_REPOS'] = function()
config.op_s_search_repos_only = true
end;
['G'] = settrans('PM_OP_GETPKG');
['OP_BUILD'] = function(opt)
config.op_s_build_user = opt
end;
['OP_BUILDDIR'] = function(opt) set_builddir( opt ) end;
--[[
--pacman feature functions
--]]
['Q'] = settrans('PM_OP_QUERY');
['R'] = settrans('PM_OP_REMOVE');
['S'] = settrans('PM_OP_SYNC');
['T'] = settrans('PM_OP_DEPTEST');
['U'] = settrans('PM_OP_UPGRADE');
['V'] = function() config.version = true end;
['b'] = function(opt) config.dbpath = opt end;
['c'] = function()
config.op_s_clean = config.op_s_clean + 1
config.flags["cascade"] = true
config.op_q_changelog = true
end;
['d'] = function()
-- -d sets nodepver, -dd sets nodeps
-- ignore more than two, it would just confuse us...
if config.flags.nodeps then return end
if not config.flags.nodepver then
-- first time we see -d
config.op_q_deps = true
config.op_g_get_deps = true
config.flags.nodepver = true
else
-- second time
config.flags.nodepver = false
config.flags.nodeps = true
end
end;
['e'] = function() config.op_q_explicit = true end;
['f'] = function() config.flags["force"] = true end;
['g'] = function() config.group = config.group + 1 end;
['h'] = function() config.help = true end;
['i'] = function()
config.op_q_info = config.op_q_info + 1
config.op_s_info = true
end;
['k'] = function()
config.flags["dbonly"] = true
config.op_q_check = true
end;
['l'] = function() config.op_q_list = true end;
['m'] = function() config.op_q_foreign = true end;
['n'] = function() config.flags["nosave"] = true end;
['o'] = function() config.op_q_owns = true end;
['p'] = function()
config.op_q_isfile = true
config.op_s_printuris = true
config.flags["noconflicts"] = true
config.flags["nolock"] = true
end;
['q'] = function() config.quiet = true end;
['r'] = function(opt) config.rootdir = opt end;
['s'] = function()
config.op_s_search = true
config.op_q_search = true
if config.flags["recurse"] then
config.flags["recurseall"] = true
else
config.flags["recurse"] = true
end
end;
['t'] = function() config.op_q_unrequired = true end;
['u'] = function()
config.op_s_upgrade = config.op_s_upgrade + 1
config.op_q_upgrade = true
config.flags["unneeded"] = true
end;
['v'] = function() config.verbose = config.verbose + 1 end;
['w'] = function()
config.op_s_downloadonly = true
config.flags["downloadonly"] = true
config.flags["noconflicts"] = true
end;
['y'] = function() config.op_s_sync = config.op_s_sync + 1 end;
['OP_NOCONFIRM'] = function() config.noconfirm = true end;
['OP_CONFIG'] = function(opt) config.configfile = opt end;
['OP_IGNORE'] = function(opt)
if (opt) then
local list = strsplit(opt, ",")
for i, ignore in ipairs(list) do
alpm.option_add_ignorepkg(ignore)
end
end
end;
['OP_DEBUG'] = function(opt)
if (opt) then
if opt == '2' then
tblinsert(config.logmask, "LOG_FUNCTION")
tblinsert(config.logmask, "LOG_DEBUG")
elseif opt == '1' then
tblinsert(config.logmask, "LOG_DEBUG")
else
--TODO: logging
lprintf("LOG_ERROR", g("'%s' is not a valid debug level\n"), opt)
return 1
end
else
tblinsert(config.logmask, "LOG_DEBUG")
end
config.noprogressbar = true
end;
['OP_NOPROGRESSBAR'] = function() config.noprogressbar = true end;
['OP_NOSCRIPTLET'] = function()
config.flags["noscriptlet"] = true
end;
-- ['OP_ASK'] = function() end;
['OP_CACHEDIR'] = function(opt)
local result = alpm.option_add_cachedir(opt)
if (result ~= 0) then
lprintf("LOG_ERROR", g("problem adding cachedir '%s' (%s)\n"), opt, alpm.strerrorlast())
return 1
end
end;
['OP_ASDEPS'] = function()
config.flags["alldeps"] = true
end;
['OP_LOGFILE'] = function(opt) config.logfile = opt end;
['OP_IGNOREGROUP'] = function(opt)
if (opt) then
local list = strsplit(opt, ",")
for i, ignore in ipairs(list) do
alpm.option_add_ignoregrp(ignore)
end
end
end;
['OP_NEEDED'] = function() config.flags["needed"] = true end;
['OP_ASEXPLICIT'] = function() config.flags["allexplicit"] = true end;
-- ['OP_ARCH'] = function() end;
}
local shortopts = "RUQSTr:b:vkhscVfmnoldepqituwyg"
local clydeshortopts = "Ga"
shortopts = shortopts..clydeshortopts
local opttable = {}
for elem, option in getopt_long(arg, shortopts, longopts, opttable) do
if lookuptbl[elem] then
lookuptbl[elem](option)
-- TODO: check return code
else
print("not implemented yet, fix this")
end
end
if (config.op == nil) then
lprintf("LOG_ERROR", g("only one operation may be used at a time\n"))
return 1
end
if (config.stats) then
return 0
end
if (config.help) then
usage(config.op, basename(arg[0]))
return 2
end
if (config.version) then
version()
return 2
end
pm_targets = opttable
return 0
end
local ransetlibpaths = false
local function setlibpaths()
if (ransetlibpaths) then return end
ransetlibpaths = true
local result
lprintf("LOG_DEBUG", "setlibpaths() called\n")
if (config.rootdir) then
result = alpm.option_set_root(config.rootdir)
if (result ~= 0) then
lprintf("LOG_ERROR", g("problem setting rootdir '%s' (%s)\n"), config.rootdir, alpm.strerrorlast())
cleanup(ret)
end
if (not config.dbpath) then
config.dbpath = alpm.option_get_root() .. DBPATH:match("/(.*)")
end
if (not config.logfile) then
config.logfile = alpm.option_get_root() .. LOGFILE:match("/(.*)")
end
end
if (config.dbpath) then
result = alpm.option_set_dbpath(config.dbpath)
if (result ~= 0) then
eprintf("LOG_ERROR", g("problem setting dbpath '%s' (%s)\n"), config.dbpath, alpm.strerrorlast())
cleanup(result)
end
end
if (config.logfile) then
result = alpm.option_set_logfile(config.logfile)
if (result ~= 0) then
eprintf("LOG_ERROR", g("problem setting logfile '%s' (%s)\n"), config.logfile, alpm.strerrorlast)
cleanup(result)
end
end
if (not next(alpm.option_get_cachedirs())) then
alpm.option_add_cachedir(CACHEDIR)
end
end
local function config_init(uid)
config = clydeconf
tblinsert(config.logmask, "LOG_ERROR")
tblinsert(config.logmask, "LOG_WARNING")
local testconf = io.open(CLYDECFG_PATH)
if (testconf) then
config.configfile = CLYDECFG_PATH
testconf:close()
else
config.configfile = PACMANCFG_PATH
end
if (uid == 0 and not testconf) then
local response = util.yesno("You do not yet have a clyde.conf, would you like to create one?")
if (response) then
local fdpacman = io.open(PACMANCFG_PATH, "r")
local paclines = {}
while true do
local line = fdpacman:read("*l")
if line == nil then break end
table.insert(paclines, line .. "\n")
end
fdpacman:close()
-- move the header from pacman.conf to the top of clyde.conf
local header = ""
while paclines[1]:match("^#") do
header = header .. table.remove( paclines, 1 )
end
if paclines[1]:match("^%s*$") then
-- blank line too
table.remove( paclines, 1 )
end
header = header:gsub(PACMANCFG_PATH:gsub("%.", "%%."),
CLYDECFG_PATH:gsub ("%.", "%%."))
local confirm = false
local editor
printf("Please enter your default text editor: ")
while (not confirm) do
editor = io.read()
confirm = util.yesno("You entered '%s' as your default "
.. "editor, is this correct? ", editor)
if not confirm then printf("Editor: ") end
end
local clydeopts = [[
#
# CLYDE OPTIONS
#
[clydeoptions]
# Uncomment the following line to disable colors.
#NoColor
# Uncomment to only search the AUR explicitly. (You would have to use --aur)
#ReposOnly
# Which program to use for editing PKGBUILDs.
Editor = %s
# You must set this to a normal user to safely build packages from the AUR
# when running without sudo.
BuildUser = %s
# If no BuildDir is set, then a directory is created for your BuildUser
# Otherwise the exact directory name you provide is used.
#BuildDir = /tmp/clyde-<BuildUser> (default when unset)
]]
-- Not sure what to set for default BuildUser
local username = os.getenv("SUDO_USER") or "nobody"
clydeopts = string.format(clydeopts, editor, username)
local fdclyde = io.open(CLYDECFG_PATH, "w")
fdclyde:write(header, "\n", clydeopts, table.concat(paclines))
fdclyde:close()
printf([[Congratulations! Your new config file is ready to use.
Additional defaults have been set. Please double-check %s.
]], CLYDECFG_PATH)
config.configfile = CLYDECFG_PATH
end
end
end
local function config_free(conf)
if (type(conf) ~= "table") then return end
for k, v in pairs(conf) do
k = nil
end
conf = nil
end
local function option_add_holdpkg(name)
config.holdpkg[ name ] = true
end
local function option_add_syncfirst(name)
tblinsert(config.syncfirst, name)
end
local function setrepeatingoption(str, option, optionfunc)
local options = strsplit(str, ' ')
for i, opt in ipairs(options) do
optionfunc(opt)
lprintf("LOG_DEBUG", "config: %s: %s\n", option, opt)
end
end
local function _parseconfig(file, givensection, givendb)
local ret = 0
local cont = true
--TODO: make sure return configcleanup() is right
local function configcleanup()
if (fp) then
fp:close()
end
if (section) then
section = nil
end
setlibpaths()
lprintf("LOG_DEBUG", "config: finished parsing %s\n", file)
cont = false
return ret
--if (cont == false) then
-- return 1
--else
-- return 0
--end
end
local optionlookuptbl = {
--[[
--clyde specific options
--]]
['NoColor'] = function()
if (config.op_use_color ~= true) then
config.op_use_color = false
colorize.disable()
lprintf("LOG_DEBUG", "config: nocolor\n")
end
end;
['Editor'] = function(str)
if (not config.editor) then
config.editor = str
lprintf("LOG_DEBUG", "config: editor: %s\n", str)
end
end;
['ReposOnly'] = function()
if (not config.op_s_search_aur_only) then
config.op_s_search_repos_only = true
lprintf("LOG_DEBUG", "config: reposonly\n")
end
end;
['BuildUser'] = function (user)
if config.build_user then
lprintf("LOG_WARNING", "overwriting previous BuildUser\n")
end
local success, result = pcall(utilcore.getpwnam, user)
if not result then
result = "unknown user "..user
success = false
end
if not success then
lprintf("LOG_ERROR", "could not set BuildUser: %s\n", result)
ret = 1
return configcleanup()
end
config.build_user = { name = result.name;
uid = result.uid;
gid = result.gid }
lprintf("LOG_DEBUG", "config: builduser = "..user.."\n")
end;
['BuildDir'] = function(str) set_builddir(str) end;
--[[
--pacman feature functions
--]]
['UseSyslog'] = function() alpm.option_set_usesyslog(true)
lprintf("LOG_DEBUG", "config: usesyslog\n") end;
['ILoveCandy'] = function() config.chomp = true
lprintf("LOG_DEBUG", "config: chomp\n") end;
['ShowSize'] = function() config.showsize = true
lprintf("LOG_DEBUG", "config: showsize\n") end;
['UseDelta'] = function() alpm.option_set_usedelta(true)
lprintf("LOG_DEBUG", "config: usedelta\n") end;
['TotalDownload'] = function() config.totaldownload = true
lprintf("LOG_DEBUG", "config: totaldownload\n") end;
['CheckSpace'] = function ()
alpm.option_set_checkspace(true)
lprintf("LOG_DEBUG", "config: checkspace\n")
end;
['NoUpgrade'] = function(str)
setrepeatingoption(str, "NoUpgrade", alpm.option_add_noupgrade) end;
['NoExtract'] = function(str)
setrepeatingoption(str, "NoExtract", alpm.option_add_noextract) end;
['IgnorePkg'] = function(str)
setrepeatingoption(str, "IgnorePkg", alpm.option_add_ignorepkg) end;
['IgnoreGroup'] = function(str)
setrepeatingoption(str, "IgnoreGroup", alpm.option_add_ignoregrp) end;
['HoldPkg'] = function(str)
setrepeatingoption(str, "HoldPkg", option_add_holdpkg) end;
['SyncFirst'] = function(str)
setrepeatingoption(str, "SyncFirst", option_add_syncfirst) end;
['Architecture'] = function(str)
if (not alpm.option_get_arch()) then
if (str == "auto") then
str = utilcore.arch();
end
alpm.option_set_arch(str)
end
end;
['DBPath'] = function(str)
if (not config.dbpath) then
config.dbpath = str
lprintf("LOG_DEBUG", "config: dbpath: %s\n", str)
end
end;
['CacheDir'] = function(str)
if (not alpm.option_add_cachedir(str)) then
lprintf("LOG_ERROR", g("problem adding cachedir '%s' (%s)\n"),
str, alpm.strerrorlast())
ret = 1
return configcleanup()
end
lprintf("LOG_DEBUG", "config: cachedir: %s\n", str)
end;
['RootDir'] = function(str)
if (not config.rootdir) then
config.rootdir = str
lprintf("LOG_DEBUG", "config: rootdir: %s\n", str)
end
end;
['LogFile'] = function(str)
if (not config.logfile) then
config.logfile = str
lprintf("LOG_DEBUG", "config: logfile: %s\n", str)
end
end;
['XferCommand'] = function(str)
alpm.option_set_fetchcb( callback.create_xfercmd_cb( str ))
lprintf("LOG_DEBUG", "config: xfercommand: %s\n", str)
end;
['CleanMethod'] = function(str)
if (str == "KeepInstalled") then
config.cleanmethod = "CLEAN_KEEPINST"
elseif (str == "KeepCurrent") then
config.cleanmethod = "CLEAN_KEEPCUR"
else
lprintf("LOG_ERROR", g("invalid value for 'CleanMethod' : '%s'\n"), str)
ret = 1
return configcleanup()
end
lprintf("LOG_DEBUG", "config: cleanmethod: %s\n", str)
end;
}
local section, db
local linenum = 0
lprintf("LOG_DEBUG", "config: attempting to read file %s\n", file)
local fp, err = io.open(file)
if err then
lprintf("LOG_ERROR", g("config file %s could not be read.\n"), file)
return 1
end
if (givensection) then
section = givensection
end
if (givendb) then
db = givendb
end
for line in fp:lines() do
if (not cont) then return ret end
repeat
linenum = linenum + 1
line = strtrim(line)
if (#line == 0) or (line:match("^#")) then
break
end
local pos = line:find("#")
if pos then
line = line:sub(1, pos - 1)
line = strtrim(line)
end
if (line:sub(1,1) == '[') and (line:sub(-1) == ']') then
section = line:match("^%[(.+)%]$")
lprintf("LOG_DEBUG", "config: new section '%s'\n", section)
if #section == 0 then
lprintf("LOG_ERROR", g("config file %s, line %d: bad section name.\n"),
file, linenum)
ret = 1
return configcleanup()
end
if (section ~= "options" and section ~= "clydeoptions") then
db = alpm.db_register_sync(section)
if (db == nil) then
lprintf("LOG_ERROR", g("could not register '%s' database (%s)\n"),
section, alpm.strerrorlast())
ret = 1
return configcleanup()
end
end
else
local key, str = line:match("(%S+)%s*=%s*(.*)")
if (not key) then key = line end
if (not section) then
lprintf("LOG_ERROR", g("config file %s, line %d: All directives must belong to a section.\n"),
file, linenum)
ret = 1
return configcleanup()
end
if (str == nil) and (section == "options" or section == "clydeoptions") then
if (optionlookuptbl[key]) then
optionlookuptbl[key]()
else
lprintf("LOG_ERROR", g("config file %s, line %d: directive '%s' not recognized.\n"),
file, linenum, key)
ret = 1
return configcleanup()
end
else
if (key == "Include") then
lprintf("LOG_DEBUG", "config: including %s\n", str)
_parseconfig(str, section, db)
elseif (section == "options" or section == "clydeoptions") then
if (optionlookuptbl[key]) then
optionlookuptbl[key](str)
else
lprintf("LOG_ERROR", g("config file %s, line %d: directive '%s' not recognized.\n"),
file, linenum, key)
ret = 1
return configcleanup()
end
elseif (key == "Server") then
local server = str:gsub("%$repo", section)
if (server:match("%$arch")) then
local arch = alpm.option_get_arch()
if ( not arch ) then
lprintf("LOG_ERROR",
g("The mirror '%s' contains the $arch" ..
" variable, but no Architecture is defined.\n"), str)
ret = 1
return configcleanup()
end
server = server:gsub("%$arch", arch)
end
if (db:db_setserver(server) ~= 0) then
lprintf("LOG_ERROR", g("could not add server URL to database '%s': %s (%s)\n"),
db:db_get_name(), server, alpm.strerrorlast())
ret = 1
return configcleanup()
end
server = nil
else
lprintf("LOG_ERROR", g("config file %s, line %d: directive '%s' not recognized.\n"),
file, linenum, key)
ret = 1
return configcleanup()
end
end
end
until 1
end
return configcleanup()
end
local function parseconfig(file)
return _parseconfig(file, nil, nil)
end
-- Offer to install packages in the package_names list
-- Returns the names of packages they want to install.
local function offer_install_pkgs ( package_names )
if not next( package_names ) then return {} end
local bars = C.yelb("==>")
printf("\n%s %s\n%s %s\n",
bars,
C.bright("Enter #'s (separated by blanks) of packages "
.. "to be installed"),
bars, C.bright(string.rep( "-", 60 )), bars )
local max = #package_names
local chosen = ui.prompt_for_numbers( bars, max )
if not chosen then
print( "Aborting." )
return {}
end
for i, n in ipairs( chosen ) do chosen[i] = package_names[n] end
return chosen
end
function main()
local ret = 0
utilcore.setprocname( "clyde" )
utilcore.umask( "0133" ) -- should this be more restrictive?
signal.signal("SIGINT", function()
printf("\nInterrupt signal received\n\n")
alpm.trans_interrupt() -- try to be nice
util.trans_release()
cleanup(2)
end)
signal.signal("SIGTERM", function()
cleanup(15)
end)
signal.signal("SIGPIPE", nil)
local myuid = geteuid()
localize()
alpm.initialize()
config_init(myuid)
if (utilcore.isatty(1) == 0 and not config.op_use_color) then
colorize.disable()
end
alpm.option_set_logcb(callback.cb_log)
alpm.option_set_dlcb(callback.cb_dl_progress)
alpm.option_set_root(ROOTDIR)
alpm.option_set_dbpath(DBPATH)
alpm.option_set_logfile(LOGFILE)
ret = parseargs()
if (ret ~= 0) then
cleanup(ret)
end
ret = parseconfig(config.configfile)
if (ret ~= 0) then
cleanup(ret)
end
if (config.stats) then
packages.packagestats()
cleanup(0)
end
if (config.totaldownload) then
alpm.option_set_totaldlcb(callback.cb_dl_total)
end
if (myuid > 0 and needs_root()) then
lprintf("LOG_ERROR", g("you cannot perform this operation unless you are root.\n"))
cleanup(1)
end
if (config.verbose > 0) then
printf("Root : %s\n", alpm.option_get_root())
printf("Conf File : %s\n", config.configfile)
printf("DB Path : %s\n", alpm.option_get_dbpath())
printf("Cache Dirs: ")
local cachedirs = alpm.option_get_cachedirs()
for i, v in ipairs(cachedirs) do
printf("%s ", v)
end
print()
printf("Lock File : %s\n", alpm.option_get_lockfile())
printf("Log File : %s\n", alpm.option_get_logfile())
printf("Targets : ")
local targets = pm_targets or {}
for i, v in ipairs(targets) do
printf("%s ", v)
end
print()
end
local lookuptbl = {
['PM_OP_QUERY'] = function() return query.main(pm_targets) end;
['PM_OP_UPGRADE'] = function() return upgrade.main(pm_targets) end;
['PM_OP_REMOVE'] = function() return remove.main(pm_targets) end;
['PM_OP_SYNC'] = function() return sync.main(pm_targets) end;
['PM_OP_DEPTEST'] = function() return deptest.main(pm_targets) end;
['PM_OP_GETPKG'] = function() return sync.getpkgbuild(pm_targets) end;
}
local ran = false
if (config.op ~= "PM_OP_MAIN") then
ret = lookuptbl[config.op]()
ran = true
elseif next(pm_targets) then
local found_names = sync.sync_search( pm_targets, true )
if not next( found_names ) then return 1 end
local install = offer_install_pkgs( found_names )
if not next( install ) then return 1 end
if (myuid > 0) then
-- See whether sudo (preferable) or su exist
local sucmds = { { file = "/usr/bin/sudo",
prefix = "%s sh -c" },
{ file = "/bin/su",
prefix = "%s -c" }, }
local prefix
for i, sucmd in ipairs( sucmds ) do
-- Cannot use io.open because sudo doesn't give
-- read access to anyone.
if lfs.attributes( sucmd.file ) then
prefix = string.format( sucmd.prefix,
sucmd.file )
break
end
end
if not prefix then
eprintf( "LOG_ERROR",
"neither sudo nor su are installed, cannot "
.. "automatically install search results" )
os.exit( 1 )
end
local cmd = string.format( "%s '%s -S %s'",
prefix, arg[0],
table.concat( install, " " ))
return os.execute(cmd)
else
ret = sync.main(install)
return ret
end
else
eprintf("LOG_ERROR", g("no operation specified (use -h for help)\n"))
os.exit(1)
end
if (next(pm_targets) and ran and not ret and ret ~= nil) then
print(ret)
if alpm.trans_release() == -1 then
eprintf("LOG_ERROR", "%s\n", alpm.strerrorlast())
end
end
if (type(config.configfile) == "userdata") then
config.configfile:close()
end
return ret
end
os.exit(main())
-- Local Variables:
-- mode: lua
-- lua-indent-level: 4
-- End: