diff --git a/packages/gnupg.shrap b/packages/gnupg.shrap new file mode 100644 index 0000000..677f4ce --- /dev/null +++ b/packages/gnupg.shrap @@ -0,0 +1,11 @@ +(package + (name "gnupg") + (version "2.5.17") + (homepage "https://www.gnupg.org/") + (dependencies libgnutls libksba libnpth libassuan libgcrypt) + (src (tar + (url "https://www.gnupg.org/ftp/gcrypt/gnupg/gnupg-2.5.17.tar.bz2") + (dir "gnupg-2.5.17") + (blake3 "174654d88ff05d2a6b3880ec81a684d23657da8d9518210862e659a9e7a6ee6c"))) + (build + (configure_make))) diff --git a/packages/graphviz.shrap b/packages/graphviz.shrap new file mode 100644 index 0000000..e899ad1 --- /dev/null +++ b/packages/graphviz.shrap @@ -0,0 +1,11 @@ +(package + (name "graphviz") + (version "14.1.2") + (homepage "https://www.graphviz.org/") + (dependencies make) + (src (tar + (url "https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/14.1.2/graphviz-14.1.2.tar.gz") + (dir "graphviz-14.1.2") + (blake3 "38544ae9666532110752889a723c869576723114da9c56e6add264558ed007fe"))) + (build + (configure_make))) diff --git a/packages/libassuan.shrap b/packages/libassuan.shrap new file mode 100644 index 0000000..87ea7f0 --- /dev/null +++ b/packages/libassuan.shrap @@ -0,0 +1,11 @@ +(package + (name "libassuan") + (version "3.0.2") + (homepage "https://www.gnupg.org/software/libassuan/index.html") + (dependencies libgpg-error) + (src (tar + (url "https://www.gnupg.org/ftp/gcrypt/libassuan/libassuan-3.0.2.tar.bz2") + (dir "libassuan-3.0.2") + (blake3 "c96b4e82157b358d889159b335f6f674e3da0ce8d2b37775e306d6a2bb111897"))) + (build + (configure_make))) diff --git a/packages/libbrotli.shrap b/packages/libbrotli.shrap new file mode 100644 index 0000000..17c6e4c --- /dev/null +++ b/packages/libbrotli.shrap @@ -0,0 +1,11 @@ +(package + (name "libbrotli") + (version "1.2.0") + (homepage "https://github.com/google/brotli") + (dependencies cmake) + (src (tar + (url "https://github.com/google/brotli/archive/refs/tags/v1.2.0.tar.gz") + (dir "brotli-1.2.0") + (blake3 "88a91819bc0e0b5bd27bd8c7d8ffddf132768851069f2cd5e905eac87e2860de"))) + (build + (cmake))) diff --git a/packages/libcares.shrap b/packages/libcares.shrap new file mode 100644 index 0000000..1fc9cf7 --- /dev/null +++ b/packages/libcares.shrap @@ -0,0 +1,11 @@ +(package + (name "libcares") + (version "1.34.6") + (homepage "https://c-ares.org/") + (dependencies make) + (src (tar + (url "https://github.com/c-ares/c-ares/releases/download/v1.34.6/c-ares-1.34.6.tar.gz") + (dir "c-ares-1.34.6") + (blake3 "053dfcbc7754502c2df605d0989f978793cf714014b18dbbef030bef405b1cc1"))) + (build + (configure_make))) diff --git a/packages/libgcrypt.shrap b/packages/libgcrypt.shrap new file mode 100644 index 0000000..5e107d2 --- /dev/null +++ b/packages/libgcrypt.shrap @@ -0,0 +1,11 @@ +(package + (name "libgcrypt") + (version "1.12.1") + (homepage "https://www.gnupg.org/software/libgcrypt/index.html") + (dependencies libgpg-error) + (src (tar + (url "https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.12.1.tar.bz2") + (dir "libgcrypt-1.12.1") + (blake3 "347bad07fd9b084e20cbfcafc3fe4f959610d8a7109632d6f15cdef373f744d6"))) + (build + (configure_make))) diff --git a/packages/libgpg-error.shrap b/packages/libgpg-error.shrap new file mode 100644 index 0000000..5d0d369 --- /dev/null +++ b/packages/libgpg-error.shrap @@ -0,0 +1,11 @@ +(package + (name "libgpg-error") + (version "1.59") + (homepage "https://www.gnupg.org/software/libgpg-error/index.html") + (dependencies bzip2) + (src (tar + (url "https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.59.tar.bz2") + (dir "libgpg-error-1.59") + (blake3 "e087c22deda3f6f5d6fd98dc14c2f9649d70c12e653979f229d0878cea0a60bf"))) + (build + (configure_make))) diff --git a/packages/libjpeg-turbo.shrap b/packages/libjpeg-turbo.shrap index 3b6b9fe..f953c97 100644 --- a/packages/libjpeg-turbo.shrap +++ b/packages/libjpeg-turbo.shrap @@ -8,6 +8,4 @@ (dir "libjpeg-turbo-3.1.3") (blake3 "fbcee6fae3d00fd550af865bec1af4d363f5e1feeaf85b60247ca6db1908b10e"))) (build - (cmake) - (shell "ln -sf /usr/lib/x86_64-linux-gnu/libjpeg.a /usr/lib/ || true") - (shell "ln -sf /usr/lib/x86_64-linux-gnu/pkgconfig/libjpeg.pc /usr/lib/pkgconfig/ || true"))) + (cmake))) diff --git a/packages/libksba.shrap b/packages/libksba.shrap new file mode 100644 index 0000000..d8fa419 --- /dev/null +++ b/packages/libksba.shrap @@ -0,0 +1,11 @@ +(package + (name "libksba") + (version "1.6.7") + (homepage "https://www.gnupg.org/software/libksba/index.html") + (dependencies libgpg-error) + (src (tar + (url "https://www.gnupg.org/ftp/gcrypt/libksba/libksba-1.6.7.tar.bz2") + (dir "libksba-1.6.7") + (blake3 "cb5bafe9d11429796c31358d9b96695ceeab80e33da75991902075c597c708cf"))) + (build + (configure_make))) diff --git a/packages/libnpth.shrap b/packages/libnpth.shrap new file mode 100644 index 0000000..1ac0464 --- /dev/null +++ b/packages/libnpth.shrap @@ -0,0 +1,11 @@ +(package + (name "libnpth") + (version "1.8") + (homepage "https://www.gnupg.org/software/npth/index.html") + (dependencies bzip2) + (src (tar + (url "https://www.gnupg.org/ftp/gcrypt/npth/npth-1.8.tar.bz2") + (dir "npth-1.8") + (blake3 "cac4aa343cb1d426a913b29cb1692b6145dd530c9e1896696cd6e85872b3df03"))) + (build + (configure_make))) diff --git a/packages/nodejs.shrap b/packages/nodejs.shrap new file mode 100644 index 0000000..d5dc59e --- /dev/null +++ b/packages/nodejs.shrap @@ -0,0 +1,12 @@ +(package + (name "nodejs") + (version "24.13.1") + (homepage "https://nodejs.org/") + (dependencies python libicu pkg-config libuv libnghttp2 zstd libbrotli libcares) + (src (tar + (url "https://nodejs.org/dist/v24.13.1/node-v24.13.1.tar.gz") + (dir "node-v24.13.1") + (blake3 "ae264a6e61bde11d84e1ead672ce2d278e5e8f3cc55e7c7867525dfd646f3182"))) + (build + (configure_make + (configure_flags "--shared-brotli --shared-cares --shared-libuv --shared-openssl --shared-nghttp2 --shared-zlib --shared-zstd --with-intl=system-icu")))) diff --git a/packages/python.shrap b/packages/python.shrap index b1bfbdd..eb6b389 100644 --- a/packages/python.shrap +++ b/packages/python.shrap @@ -2,7 +2,7 @@ (name "python") (version "3.14.3") (homepage "https://www.python.org/") - (dependencies zlib libopenssl bzip2 libffi sqlite3 libdb libreadline) + (dependencies zlib libopenssl bzip2 libffi libreadline) (src (tar (url "https://www.python.org/ftp/python/3.14.3/Python-3.14.3.tgz") (dir "Python-3.14.3") diff --git a/packages/sqlite3.shrap b/packages/sqlite3.shrap index 4ac01d7..479fff8 100644 --- a/packages/sqlite3.shrap +++ b/packages/sqlite3.shrap @@ -8,4 +8,5 @@ (dir "sqlite-autoconf-3510200") (blake3 "7ba8d2c972fb11430e8ce3ca2b2b0c3d583be6da5c8faf7cba50a12eb699601e"))) (build - (configure_make))) + (configure_make + (configure_flags "--all")))) diff --git a/packages/zstd.shrap b/packages/zstd.shrap index d6deb55..8762cff 100644 --- a/packages/zstd.shrap +++ b/packages/zstd.shrap @@ -8,4 +8,5 @@ (dir "zstd-1.5.7") (blake3 "730dca31244abd219e995f03a55d95b2cfb4b3e16cda055a79fa6f30a4f0e1db"))) (build - (make))) + (make + (install_flags "prefix=/usr")))) diff --git a/src/db.h b/src/db.h index 6fef851..6b2bf0c 100644 --- a/src/db.h +++ b/src/db.h @@ -1,5 +1,6 @@ #pragma once #include +#include class DB { public: @@ -32,6 +33,19 @@ public: insert.exec(); } + auto get_installed() { + std::vector> installed; + + SQLite::Statement query(m_db, "SELECT name, version FROM installed"); + while (query.executeStep()) { + std::string name = query.getColumn(0).getString(); + std::string version = query.getColumn(1).getString(); + installed.emplace_back(name, version); + } + + return installed; + } + private: SQLite::Database m_db{DB_PATH + "/shrap.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE}; diff --git a/src/main.cc b/src/main.cc index 225b658..48e456d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -8,15 +8,23 @@ #include #include -constexpr static const std::string BUILD_PATH = "/tmp/shrap"; +constexpr const std::string BUILD_PATH = "/tmp/shrap"; +constexpr const std::string CLR_RESET = "\033[0m"; +constexpr const std::string CLR_RED = "\033[31m"; +constexpr const std::string CLR_GREEN = "\033[32m"; +constexpr const std::string CLR_YELLOW = "\033[33m"; +constexpr const std::string CLR_BLUE = "\033[34m"; std::unordered_map packages; +size_t to_install_count; +size_t current_package_index; void load_packages() { for (const auto &e : std::filesystem::directory_iterator("./packages/")) { std::ifstream file(e.path()); if (!file) { - std::cerr << "Failed to open " << e.path() << "\n"; + std::cerr << CLR_RED << "Failed to open " << e.path() << "\n" + << CLR_RESET; std::exit(1); } @@ -26,12 +34,12 @@ void load_packages() { } std::vector -resolve_dependencies(const std::vector &roots, DB &db) { +resolve_dependencies(const std::vector &roots, DB *db) { std::unordered_map state; std::vector order; std::function dfs = [&](const std::string &name) { - if (db.is_installed(name)) { + if (db != nullptr && db->is_installed(name)) { return; } @@ -44,7 +52,8 @@ resolve_dependencies(const std::vector &roots, DB &db) { } if (!packages.contains(name)) { - std::cerr << "Package not found: " << name << "\n"; + std::cerr << CLR_RED << "Package not found: " << name << "\n" + << CLR_RESET; std::exit(1); } @@ -69,17 +78,18 @@ resolve_dependencies(const std::vector &roots, DB &db) { } void install_package(const std::string &name, DB &db) { - // TODO: track installed packages - if (!packages.contains(name)) { - std::cerr << "Package not found: " << name << "\n"; + std::cerr << CLR_RED << "Package not found: " << name << "\n" << CLR_RESET; std::exit(1); } Expr pkg = packages[name]; - std::cout << "\n\n\tInstalling " << pkg.get_one("name").value << " (" - << pkg.get_one("version").value << ")...\n\n"; + std::cout << CLR_BLUE << "\n\n 📦 Installing " << CLR_GREEN + << pkg.get_one("name").value << CLR_BLUE << " (" << CLR_YELLOW + << current_package_index << CLR_BLUE << " of " << CLR_YELLOW + << to_install_count << CLR_BLUE << ")...\n\n" + << CLR_RESET; Expr src = pkg.get_one("src"); std::string src_type = src.children[0].value; @@ -94,7 +104,7 @@ void install_package(const std::string &name, DB &db) { // dont redownload if checksum matches if (std::filesystem::exists(archive_path)) { - std::cout << "\tComputing checksum...\n"; + std::cout << CLR_BLUE << " 🔍 Computing checksum...\n" << CLR_RESET; std::string current_hash = Util::hash_file(archive_path); if (current_hash == expected_hash) { needs_download = false; @@ -104,17 +114,17 @@ void install_package(const std::string &name, DB &db) { if (needs_download) { Util::shell_command("./curl -L -o " + archive_path + " " + src_url); - std::cout << "\n\tComputing checksum...\n"; + std::cout << CLR_BLUE << "\n 🔍 Computing checksum...\n" << CLR_RESET; std::string hash = Util::hash_file(archive_path); if (expected_hash != hash) { - std::cerr << "Checksum check failed.\n"; + std::cerr << CLR_RED << "Checksum check failed.\n"; std::cerr << "Expected: " << expected_hash << "\n"; - std::cerr << "Got: " << hash << "\n"; + std::cerr << "Got: " << hash << "\n" << CLR_RESET; std::exit(1); } } - std::cout << "\n\tExtracting...\n"; + std::cout << CLR_BLUE << "\n 📂 Extracting...\n" << CLR_RESET; Util::shell_command("tar xf " + archive_path + " -C " + BUILD_PATH); } else { throw std::runtime_error("unrecognized src type"); @@ -122,7 +132,7 @@ void install_package(const std::string &name, DB &db) { std::string jobs = std::to_string(std::thread::hardware_concurrency()); - std::cout << "\n\tBuilding...\n\n"; + std::cout << CLR_BLUE << "\n 🔨 Building...\n\n" << CLR_RESET; for (const auto &step : pkg.get("build").children) { std::string step_type = step.children[0].value; @@ -179,9 +189,10 @@ void install_package(const std::string &name, DB &db) { } Util::shell_command("mkdir -p build", src_path); - Util::shell_command("cmake -DCMAKE_INSTALL_PREFIX=/usr " + - configure_flags + " ..", - src_path + "/build"); + Util::shell_command( + "cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib " + + configure_flags + " ..", + src_path + "/build"); Util::shell_command("make -j" + jobs, src_path + "/build"); Util::shell_command("make install", src_path + "/build"); } else if (step_type == "meson") { @@ -230,14 +241,16 @@ void generate_graph(const std::vector &to_highlight) { out.close(); Util::shell_command("dot -Tpng graph.dot > graph.png", BUILD_PATH); - std::cout << "Graph saved to " << BUILD_PATH << "/graph.png\n"; + std::cout << CLR_GREEN << "Graph saved to " << BUILD_PATH << "/graph.png\n" + << CLR_RESET; } int main(int argc, char **argv) { auto args = std::span(argv, static_cast(argc)); if (geteuid() != 0) { - std::cerr << "This program needs to be ran as root.\n"; + std::cerr << CLR_RED << "This program needs to be ran as root.\n" + << CLR_RESET; return 1; } @@ -251,6 +264,7 @@ int main(int argc, char **argv) { bool flag_raw = false; bool flag_graph = false; + bool flag_list = false; std::vector to_install; for (size_t i = 1; i < args.size(); ++i) { @@ -259,41 +273,57 @@ int main(int argc, char **argv) { flag_raw = true; } else if (arg == "-g") { flag_graph = true; + } else if (arg == "-l") { + flag_list = true; } else { to_install.push_back(arg); } } if (flag_graph) { - generate_graph(to_install); + generate_graph(resolve_dependencies(to_install, nullptr)); + return 0; + } + + if (flag_list) { + for (const auto &[k, v] : db.get_installed()) { + std::cout << k << " (" << v << ")\n"; + } return 0; } if (to_install.empty()) { - std::cerr << "Usage: " << args[0] << " [-g] [-r] package1 [package2 ...]\n"; + std::cerr << "Usage: " << args[0] + << " [-g] [-r] [-l] package1 [package2 ...]\n"; return 1; } if (!flag_raw) { - to_install = resolve_dependencies(to_install, db); + to_install = resolve_dependencies(to_install, &db); } - std::cout << "\nFollowing packages will be installed:\n"; + std::cout << CLR_BLUE << "\nFollowing packages will be installed:\n" + << CLR_RESET; for (const std::string &pkg : to_install) { if (!packages.contains(pkg)) { std::cerr << "Package not found: " << pkg << "\n"; std::exit(1); } - std::cout << " - " << pkg << " (" << packages[pkg].get_one("version").value - << ")" << std::endl; + std::cout << " - " << CLR_YELLOW << pkg << CLR_RESET << " (" + << packages[pkg].get_one("version").value << ")" << std::endl; } + std::cout << CLR_BLUE << "\nPress ENTER to proceed..." << CLR_RESET; std::cin.get(); + to_install_count = to_install.size(); + current_package_index = 1; + for (const std::string &pkg : to_install) { try { install_package(pkg, db); + current_package_index++; } catch (std::exception &e) { - std::cerr << "ERROR: " << e.what() << std::endl; + std::cerr << CLR_RED << "ERROR: " << e.what() << "\n" << CLR_RESET; return 1; } } diff --git a/src/util.h b/src/util.h index bdab65f..e53b4e7 100644 --- a/src/util.h +++ b/src/util.h @@ -27,7 +27,7 @@ static void shell_command(const std::string &cmd, _exit(1); } - std::cout << cmd << std::endl; + std::cout << "\n " << cmd << "\n\n"; execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr); // NOLINT(*-vararg) perror("execl failed");