diff options
-rw-r--r-- | .gitmodules | 3 | ||||
-rwxr-xr-x | build.sh | 10 | ||||
m--------- | lib/curl | 0 | ||||
-rw-r--r-- | lpm.c | 86 | ||||
-rw-r--r-- | lpm.lua | 47 |
5 files changed, 103 insertions, 43 deletions
diff --git a/.gitmodules b/.gitmodules index 9f578cd..0ee8ee3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,6 @@ [submodule "lib/zlib"] path = lib/zlib url = https://github.com/madler/zlib.git +[submodule "lib/curl"] + path = lib/curl + url = https://github.com/curl/curl.git @@ -8,11 +8,12 @@ SRCS="*.c" LDFLAGS="$LDFLAGS -lm -pthread -static-libgcc" -[[ "$@" == "clean" ]] && rm -rf lib/libgit2/build lib/zlib/build lib/openssl/build lib/prefix $BIN *.exe && exit 0 +[[ "$@" == "clean" ]] && rm -rf lib/libgit2/build lib/zlib/build lib/openssl/build lib/curl/build lib/prefix $BIN *.exe && exit 0 [[ $OSTYPE == 'msys'* || $CC == *'mingw'* ]] && SSL_CONFIGURE="mingw64" # Build supporting libraries, libgit2, libz, libssl (with libcrypto), libpcre if [[ "$@" != *"-lz"* ]]; then + [ ! -e "lib/zlib" ] && echo "Make sure you've cloned submodules. (git submodule update --init --depth=1)" && exit -1 [ ! -e "lib/zlib/build" ] && cd lib/zlib && mkdir build && cd build && ../configure --prefix=`pwd`/../../prefix && $MAKE -j $JOBS && $MAKE install && cd ../../../ LDFLAGS="$LDFLAGS -Llib/libz/build -l:libz.a" && CFLAGS="$CFLAGS -Ilib/prefix/include" && LDFLAGS="$LDFLAGS -Llib/prefix/lib -Llib/prefix/lib64" fi @@ -21,16 +22,19 @@ if [[ "$@" != *"-lssl"* && "$@" != *"-lcrypto"* ]]; then LDFLAGS="$LDFLAGS -Llib/libz/build" && CFLAGS="$CFLAGS -Ilib/prefix/include" && LDFLAGS="$LDFLAGS -Llib/prefix/lib -Llib/prefix/lib64 -l:libssl.a -l:libcrypto.a" fi if [[ "$@" != *"-lgit2"* ]]; then - [ ! -e "lib/libgit2/include" ] && echo "Make sure you've cloned submodules. (git submodule update --init --depth=1)" && exit -1 [ ! -e "lib/libgit2/build" ] && cd lib/libgit2 && mkdir build && cd build && cmake .. $GIT2_CONFIGURE -DCMAKE_PREFIX_PATH=`pwd`/../../prefix -DCMAKE_INSTALL_PREFIX=`pwd`/../../prefix -DOPENSSL_ROOT_DIR=`pwd`/../../prefix -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTS=OFF -DBUILD_CLI=OFF -DREGEX_BACKEND=builtin -DUSE_SSH=OFF && $MAKE -j $JOBS && $MAKE install && cd ../../../ LDFLAGS="-Llib/libgit2/build -l:libgit2.a $LDFLAGS" && CFLAGS="$CFLAGS -Ilib/prefix/include" && LDFLAGS="$LDFLAGS -Llib/prefix/lib -Llib/prefix/lib64" fi +if [[ "$@" != *"-lcurl"* ]]; then + [ ! -e "lib/curl/build" ] && cd lib/curl && mkdir build && cd build && cmake .. $CURL_CONFIGURE -DCMAKE_INSTALL_PREFIX=`pwd`/../../prefix -DENABLE_UNICODE=OFF -DBUILD_CURL_EXE=OFF -DCURL_USE_LIBSSH2=OFF -DOPENSSL_ROOT_DIR=`pwd`/../../prefix -DBUILD_SHARED_LIBS=OFF && $MAKE -j $JOBS && $MAKE install && cd ../../../ + LDFLAGS="-Llib/curl/build -l:libcurl.a $LDFLAGS" && CFLAGS="$CFLAGS -Ilib/prefix/include -DCURL_STATICLIB" && LDFLAGS="$LDFLAGS -Llib/prefix/lib" +fi [[ "$@" != *"-llua"* ]] && CFLAGS="$CFLAGS -Ilib/lua -DMAKE_LIB=1" && SRCS="$SRCS lib/lua/onelua.c" # Build the pre-packaged lua file into the executbale. xxd -i lpm.lua > lpm.lua.c -[[ $OSTYPE != 'msys'* && $CC != *'mingw'* && $CC != "emcc" ]] && LDFLAGS=" $LDFLAGS -ldl -pthread -lz" +[[ $OSTYPE != 'msys'* && $CC != *'mingw'* && $CC != "emcc" ]] && LDFLAGS=" $LDFLAGS -ldl -pthread -l:libidn2.a -l:libunistring.a" [[ $OSTYPE == 'msys'* || $CC == *'mingw'* ]] && LDFLAGS="$LDFLAGS -lws2_32 -lz -lwinhttp -lole32 -lcrypt32 -lrpcrt4" [[ "$@" != *" -g "* || "$@" != *" -O"* ]] && CFLAGS="$CFLAGS -O3" && LDFLAGS="$LDFLAGS -s" diff --git a/lib/curl b/lib/curl new file mode 160000 +Subproject 2ca0530a4d4bd1e1ccb9c876e954d8dc9a87da4 @@ -11,6 +11,8 @@ #include <sys/stat.h> #include <git2.h> +#include <openssl/sha.h> +#include <curl/curl.h> #ifdef _WIN32 #include <direct.h> @@ -18,26 +20,18 @@ #include <fileapi.h> #endif -/* 64bit fnv-1a hash */ -typedef unsigned long long hash_t; static char hexDigits[] = "0123456789abcdef"; -#define FNV_64_PRIME ((hash_t)0x100000001b3ULL) static int lpm_hash(lua_State* L) { - hash_t hval = 0; size_t len; const char* data = luaL_checklstring(L, 1, &len); - const unsigned char *bp = (unsigned char*)data; - const unsigned char *be = data + len; - while (bp < be) { - hval *= FNV_64_PRIME; - hval ^= (unsigned long long)*bp++; - } - char buffer[16]; + unsigned char buffer[SHA256_DIGEST_LENGTH]; + char hexBuffer[SHA256_DIGEST_LENGTH * 2]; + SHA256(data, len, buffer); for (size_t i = 0; i < len; ++i) { - buffer[i*2+0] = hexDigits[data[i] >> 4]; - buffer[i*2+1] = hexDigits[data[i] & 0xF]; + hexBuffer[i*2+0] = hexDigits[buffer[i] >> 4]; + hexBuffer[i*2+1] = hexDigits[buffer[i] & 0xF]; } - lua_pushlstring(L, buffer, 16); + lua_pushlstring(L, buffer, SHA256_DIGEST_LENGTH * 2); return 1; } @@ -310,7 +304,7 @@ static git_commit* git_retrieve_commit(git_repository* repository, const char* c } -int lpm_reset(lua_State* L) { +static int lpm_reset(lua_State* L) { git_repository* repository = luaL_checkgitrepo(L, 1); const char* commit_name = luaL_checkstring(L, 2); const char* type = luaL_checkstring(L, 3); @@ -333,7 +327,7 @@ int lpm_reset(lua_State* L) { } -int lpm_init(lua_State* L) { +static int lpm_init(lua_State* L) { const char* path = luaL_checkstring(L, 1); const char* url = luaL_checkstring(L, 2); git_repository* repository; @@ -350,7 +344,7 @@ int lpm_init(lua_State* L) { } -int lpm_fetch(lua_State* L) { +static int lpm_fetch(lua_State* L) { git_repository* repository = luaL_checkgitrepo(L, 1); git_remote* remote; if (git_remote_lookup(&remote, repository, "origin")) { @@ -369,7 +363,7 @@ int lpm_fetch(lua_State* L) { } -int lpm_set_certs(lua_State* L) { +static int lpm_set_certs(lua_State* L) { const char* type = luaL_checkstring(L, 1); const char* path = luaL_checkstring(L, 2); if (strcmp(type, "dir") == 0) @@ -379,8 +373,8 @@ int lpm_set_certs(lua_State* L) { return 0; } - -int lpm_status(lua_State* L) { +static CURL *curl; +static int lpm_status(lua_State* L) { const char* path = luaL_checkstring(L, 1); git_repository* repository; if (git_repository_open(&repository, path)) @@ -395,19 +389,45 @@ int lpm_status(lua_State* L) { } +static size_t lpm_curl_write_callback(char *ptr, size_t size, size_t nmemb, void *BL) { + luaL_Buffer* B = BL; + luaL_addlstring(B, ptr, size*nmemb); + return size*nmemb; +} + + +static int lpm_get(lua_State* L) { + const char* url = luaL_checkstring(L, 1); + curl_easy_reset(curl); + curl_easy_setopt(curl, CURLOPT_URL, url); + CURLcode res = curl_easy_perform(curl); + if (res != CURLE_OK) + return luaL_error(L, "curl error: %d", res); + luaL_Buffer B; + luaL_buffinit(L, &B); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, lpm_curl_write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &B); + luaL_pushresult(&B); + lua_newtable(L); + return 2; +} + + static const luaL_Reg system_lib[] = { - { "ls", lpm_ls }, // Returns an array of files. - { "stat", lpm_stat }, // Returns info about a single file. - { "mkdir", lpm_mkdir }, // Makes a directory. - { "rmdir", lpm_rmdir }, // Removes a directory. - { "hash", lpm_hash }, // Returns a hexhash. - { "init", lpm_init }, // Initializes a git repository with the specified remote. - { "fetch", lpm_fetch }, // Updates a git repository with the specified remote. - { "reset", lpm_reset }, // Updates a git repository to the specified commit/hash/branch. - { "status", lpm_status }, // Returns the git repository in question's current branch, if any, and commit hash. + { "ls", lpm_ls }, // Returns an array of files. + { "stat", lpm_stat }, // Returns info about a single file. + { "mkdir", lpm_mkdir }, // Makes a directory. + { "rmdir", lpm_rmdir }, // Removes a directory. + { "hash", lpm_hash }, // Returns a hex sha256 hash. + { "init", lpm_init }, // Initializes a git repository with the specified remote. + { "fetch", lpm_fetch }, // Updates a git repository with the specified remote. + { "reset", lpm_reset }, // Updates a git repository to the specified commit/hash/branch. + { "status", lpm_status }, // Returns the git repository in question's current branch, if any, and commit hash. + { "get", lpm_get }, // HTTP(s) GET request. { "set_certs", lpm_set_certs } // Returns the git repository in question's current branch, if any, and commit hash. }; + #ifndef LPM_VERSION #define LPM_VERSION "unknown" #endif @@ -415,6 +435,9 @@ static const luaL_Reg system_lib[] = { extern const char lpm_lua[]; extern unsigned int lpm_lua_len; int main(int argc, char* argv[]) { + curl = curl_easy_init(); + if (!curl) + return -1; git_libgit2_init(); lua_State* L = luaL_newstate(); luaL_openlibs(L); @@ -436,8 +459,8 @@ int main(int argc, char* argv[]) { #endif lua_setglobal(L, "PATHSEP"); lua_setglobal(L, "PLATFORM"); - if (luaL_loadbuffer(L, lpm_lua, lpm_lua_len, "lpm.lua")) { - // if (luaL_loadfile(L, "lpm.lua")) { + // if (luaL_loadbuffer(L, lpm_lua, lpm_lua_len, "lpm.lua")) { + if (luaL_loadfile(L, "lpm.lua")) { fprintf(stderr, "internal error when starting the application: %s\n", lua_tostring(L, -1)); return -1; } @@ -445,5 +468,6 @@ int main(int argc, char* argv[]) { int status = lua_tointeger(L, -1); lua_close(L); git_libgit2_shutdown(); + curl_easy_cleanup(curl); return status; } @@ -619,7 +619,7 @@ function Repository:parse_manifest(already_pulling) table.insert(remotes, repo) table.insert(self.plugins, Plugin.new(self, metadata)) else - log_warning("plugin " .. plugin.name .. " specifies remote as source, but ") + log_warning("plugin " .. metadata.name .. " specifies remote as source, but isn't a commit") end else table.insert(self.plugins, Plugin.new(self, metadata)) @@ -649,10 +649,14 @@ function Repository:generate_manifest() local plugins, plugin_map = {}, {} if system.stat(path .. PATHSEP .. "README.md") then -- If there's a README, parse it for a table like in our primary repository. for line in io.lines(path .. PATHSEP .. "README.md") do - local _, _, name, path, description = line:find("^%s*%|%s*%[`(%w+)%??.-`%]%((.-)%).-%|%s*(.-)%s*%|%s*$") + local _, _, name, path, description = line:find("^%s*%|%s*%[`([%w_]+)%??.-`%]%((.-)%).-%|%s*(.-)%s*%|%s*$") if name then plugin_map[name] = { name = name, description = description } - plugin_map[path:find("^http") and "remote" or "path"] = path + if path:find("^http") then + plugin_map[name].remote = path + else + plugin_map[name].path = path:gsub("%?.*$", "") + end end end end @@ -667,10 +671,18 @@ function Repository:generate_manifest() local _, _, required_plugin = line:find("require [\"']plugins.([%w_]+)") if required_plugin then if required_plugin ~= plugin.name then plugin.dependencies[required_plugin] = ">=1.0" end end end - if plugin_map[plugin.name] then plugin = common.merge(plugin, plugin_map[plugin.name]) end + if plugin_map[plugin.name] then + plugin = common.merge(plugin, plugin_map[plugin.name]) + plugin_map[plugin.name].plugin = plugin + end table.insert(plugins, plugin) end end + for k, v in pairs(plugin_map) do + if not v.plugin then + table.insert(plugins, common.merge({ dependencies = {}, mod_version = 3, version = "1.0", tags = {} }, v)) + end + end io.open(path .. PATHSEP .. "manifest.json", "wb"):write(json.encode({ plugins = plugins })):flush() end @@ -871,6 +883,18 @@ local function lpm_plugin_list() end end +local function lpm_plugin_upgrade() + for i,repo in ipairs(repositories) do + if not repo.plugins then error("can't find plugins for repo " .. repo.remote .. ":" .. (repo.commit or repo.branch or "master")) end + for j,plugin in ipairs(repo.plugins) do + if plugin:is_installed() then + local compatibles = get_plugin(plugin.name, ">" .. plugin.version) + table.sort(compatibles, function(a, b) return compare_version(b.version, a.version) end) + compatibles[1]:install() + end + end + end +end local function lpm_purge() log_action("Removed " .. CACHEDIR .. ".") @@ -932,10 +956,12 @@ local function run_command(ARGS) elseif ARGS[2] == "repo" and ARGS[3] == "list" then return lpm_repo_list() elseif ARGS[2] == "plugin" and ARGS[3] == "install" then lpm_plugin_install(table.unpack(common.slice(ARGS, 4))) elseif ARGS[2] == "plugin" and ARGS[3] == "uninstall" then lpm_plugin_uninstall(table.unpack(common.slice(ARGS, 4))) - elseif ARGS[2] == "plugin" and ARGS[3] == "list" then return lpm_plugin_list() + elseif ARGS[2] == "plugin" and ARGS[3] == "list" then return lpm_plugin_list(table.unpack(common.slice(ARGS, 4))) + elseif ARGS[2] == "plugin" and ARGS[3] == "upgrade" then return lpm_plugin_upgrade(table.unpack(common.slice(ARGS, 4))) + elseif ARGS[2] == "upgrade" then return lpm_plugin_upgrade(table.unpack(common.slice(ARGS, 3))) elseif ARGS[2] == "install" then lpm_plugin_install(table.unpack(common.slice(ARGS, 3))) elseif ARGS[2] == "uninstall" then lpm_plugin_uninstall(table.unpack(common.slice(ARGS, 3))) - elseif ARGS[2] == "list" then return lpm_plugin_list() + elseif ARGS[2] == "list" then return lpm_plugin_list(table.unpack(common.slice(ARGS, 3))) elseif ARGS[2] == "purge" then lpm_purge() else error("unknown command: " .. ARGS[2]) end if JSON then @@ -979,10 +1005,13 @@ It has the following commands: lpm [repo] update [<repository remote>] Update all/the specified repositories. [...<repository remote>] lpm [plugin] install <plugin name>[:<version>] Install the specific plugins in question. - [...<plugin name>:<version>] + [...<plugin name>:<version>] If the plugin is installed, upgrades it. lpm [plugin] uninstall <plugin name> Uninstall the specific plugin. [...<plugin name>] - lpm [plugin] list List all known plugins. + lpm [plugin] list <repository remote> List all/associated plugins. + [...<repository remote>] + lpm [plugin] upgrade Upgrades all installed plugins to new version + if applicable. lpm purge Completely purge all state for LPM. lpm - Read these commands from stdin in an interactive print-eval loop. @@ -1027,7 +1056,7 @@ Flags have the following effects: if not stat then error("can't find " .. ARGS["ssl_certs"]) end system.set_certs(stat.type, ARGS["ssl_certs"]) elseif not os.getenv("SSL_CERT_DIR") and not os.getenv("SSL_CERT_FILE") then - local paths = { + local paths = { -- https://serverfault.com/questions/62496/ssl-certificate-location-on-unix-linux#comment1155804_62500 "/etc/ssl/certs/ca-certificates.crt", -- Debian/Ubuntu/Gentoo etc. "/etc/pki/tls/certs/ca-bundle.crt", -- Fedora/RHEL 6 "/etc/ssl/ca-bundle.pem", -- OpenSUSE |