mirror of
https://github.com/spitkov/ynspkg.git
synced 2025-04-04 15:29:47 +02:00
Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
fa794685ad | |||
08d12cc656 | |||
e19ba7ac5e |
7 changed files with 298 additions and 264 deletions
41
.gitignore
vendored
41
.gitignore
vendored
|
@ -1,42 +1,5 @@
|
||||||
# Build directories
|
deps/
|
||||||
build/
|
build/
|
||||||
cmake-build-*/
|
|
||||||
|
|
||||||
# IDE specific files
|
|
||||||
.idea/
|
|
||||||
.vscode/
|
.vscode/
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
|
|
||||||
# Prerequisites
|
|
||||||
*.d
|
|
||||||
|
|
||||||
# Compiled Object files
|
|
||||||
*.slo
|
|
||||||
*.lo
|
|
||||||
*.o
|
*.o
|
||||||
*.obj
|
*.a
|
||||||
|
|
||||||
# Precompiled Headers
|
|
||||||
*.gch
|
|
||||||
*.pch
|
|
||||||
|
|
||||||
# Compiled Dynamic libraries
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
*.dll
|
|
||||||
|
|
||||||
# Compiled Static libraries
|
|
||||||
*.lai
|
|
||||||
*.la
|
|
||||||
*.a
|
|
||||||
*.lib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
|
||||||
|
|
||||||
# Package manager specific
|
|
||||||
/var/cache/yns/
|
|
||||||
/var/lib/yns/
|
|
|
@ -1,38 +1,31 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(yns VERSION 1.0)
|
project(yns)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
# Find required packages
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||||
find_package(CURL REQUIRED)
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
find_package(nlohmann_json REQUIRED)
|
set(CMAKE_EXE_LINKER_FLAGS "-static")
|
||||||
|
|
||||||
# Add executable
|
set(CURL_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/deps/install/include")
|
||||||
add_executable(yns
|
set(CURL_LIBRARY "${CMAKE_SOURCE_DIR}/deps/install/lib/libcurl.a")
|
||||||
|
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
|
||||||
|
add_executable(yns
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/package_manager.cpp
|
src/package_manager.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
# Include directories
|
|
||||||
target_include_directories(yns PRIVATE
|
target_include_directories(yns PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
${CMAKE_SOURCE_DIR}/include
|
||||||
${CURL_INCLUDE_DIRS}
|
${CURL_INCLUDE_DIR})
|
||||||
)
|
|
||||||
|
|
||||||
# Link libraries
|
target_link_libraries(yns PRIVATE
|
||||||
target_link_libraries(yns PRIVATE
|
${CURL_LIBRARY}
|
||||||
${CURL_LIBRARIES}
|
OpenSSL::SSL
|
||||||
nlohmann_json::nlohmann_json
|
OpenSSL::Crypto
|
||||||
)
|
ZLIB::ZLIB
|
||||||
|
-static
|
||||||
# Installation
|
-pthread)
|
||||||
install(TARGETS yns DESTINATION bin)
|
|
||||||
|
|
||||||
# Create required directories during installation
|
|
||||||
install(CODE "
|
|
||||||
execute_process(
|
|
||||||
COMMAND mkdir -p /var/cache/yns
|
|
||||||
COMMAND mkdir -p /var/lib/yns
|
|
||||||
)
|
|
||||||
")
|
|
||||||
|
|
170
README.md
170
README.md
|
@ -1,150 +1,58 @@
|
||||||
# YNS Package Manager
|
# YNS Package Manager
|
||||||
|
|
||||||
A lightweight package manager for Linux that uses a single repository source.
|
Simple package manager for Linux. Uses JSON for package definitions.
|
||||||
|
|
||||||
## Dependencies
|
## Build
|
||||||
|
|
||||||
- CMake (>= 3.10)
|
Install dependencies:
|
||||||
- C++17 compiler
|
|
||||||
- libcurl
|
|
||||||
- nlohmann-json
|
|
||||||
|
|
||||||
On Ubuntu/Debian, you can install the dependencies with:
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install build-essential cmake libcurl4-openssl-dev nlohmann-json3-dev
|
sudo apt-get install build-essential cmake libssl-dev zlib1g-dev nlohmann-json3-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building
|
We build our own curl because the system's libcurl is usually only available as a dynamic library. Building our own lets us:
|
||||||
|
- Create a static binary that works everywhere
|
||||||
|
- Include only the features we need (HTTP support)
|
||||||
|
- Avoid dependency problems during static linking
|
||||||
|
|
||||||
|
Build steps:
|
||||||
```bash
|
```bash
|
||||||
mkdir build
|
# Get the code
|
||||||
cd build
|
git clone https://github.com/spitkov/ynspkg.git
|
||||||
|
cd ynspkg
|
||||||
|
|
||||||
|
# Build static curl
|
||||||
|
chmod +x build_curl.sh
|
||||||
|
./build_curl.sh
|
||||||
|
|
||||||
|
# Build yns
|
||||||
|
mkdir build && cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
After building, you can install the package manager with:
|
|
||||||
```bash
|
|
||||||
sudo make install
|
|
||||||
```
|
|
||||||
|
|
||||||
This will:
|
|
||||||
- Install the `yns` binary to `/usr/local/bin`
|
|
||||||
- Create necessary directories:
|
|
||||||
- `/var/cache/yns/` - For package cache
|
|
||||||
- `/var/lib/yns/` - For installed package database
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Update package cache
|
|
||||||
```bash
|
```bash
|
||||||
yns update
|
yns update # Update package cache
|
||||||
|
yns install <package> # Install package
|
||||||
|
yns remove <package> # Remove package
|
||||||
|
yns upgrade <package> # Upgrade package
|
||||||
|
yns list # List packages
|
||||||
|
yns debug # Show debug info
|
||||||
|
yns interactive # Interactive mode
|
||||||
|
yns version # Show YNS version
|
||||||
|
yns updateyns # Update YNS to latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install a package
|
## Package Format
|
||||||
```bash
|
|
||||||
yns install <package_name>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Remove a package
|
```json
|
||||||
```bash
|
{
|
||||||
yns remove <package_name>
|
"packages": {
|
||||||
```
|
"package-name": {
|
||||||
|
"version": "1.0.0",
|
||||||
### Upgrade a package
|
"description": "Package description",
|
||||||
```bash
|
"install_script": "#!/bin/bash\n# Installation commands"
|
||||||
yns upgrade <package_name>
|
}
|
||||||
```
|
}
|
||||||
|
}
|
||||||
### List all packages
|
|
||||||
```bash
|
|
||||||
yns list
|
|
||||||
```
|
|
||||||
|
|
||||||
### Interactive Mode
|
|
||||||
```bash
|
|
||||||
yns interactive
|
|
||||||
```
|
|
||||||
|
|
||||||
Interactive mode provides a shell-like interface where you can execute multiple commands without the `yns` prefix. Available commands in interactive mode:
|
|
||||||
|
|
||||||
- `help` - Show available commands
|
|
||||||
- `update` - Update package cache
|
|
||||||
- `install <package>` - Install a package
|
|
||||||
- `remove <package>` - Remove a package
|
|
||||||
- `upgrade <package>` - Upgrade a package
|
|
||||||
- `list` - List all packages
|
|
||||||
- `clear` - Clear the screen
|
|
||||||
- `exit` - Exit interactive mode
|
|
||||||
|
|
||||||
Example interactive session:
|
|
||||||
```
|
|
||||||
$ yns interactive
|
|
||||||
YNS Package Manager Interactive Mode
|
|
||||||
Type 'help' for available commands or 'exit' to quit
|
|
||||||
yns> update
|
|
||||||
[100%] Package cache updated successfully
|
|
||||||
yns> list
|
|
||||||
Available packages:
|
|
||||||
==================
|
|
||||||
calc [installed 1.1, update available 2.0]
|
|
||||||
notepad [available 2.0]
|
|
||||||
yns> install notepad
|
|
||||||
[50%] Installing notepad@2.0
|
|
||||||
notepad@2.0 installed successfully
|
|
||||||
yns> exit
|
|
||||||
Goodbye!
|
|
||||||
```
|
|
||||||
|
|
||||||
## Color Coding
|
|
||||||
|
|
||||||
The package manager uses color-coded output for better visibility:
|
|
||||||
|
|
||||||
🔵 Blue:
|
|
||||||
- Progress indicators (e.g., "[50%] Installing package...")
|
|
||||||
- Available but not installed packages in `yns list`
|
|
||||||
- Interactive mode prompt
|
|
||||||
|
|
||||||
🟢 Green:
|
|
||||||
- Success messages
|
|
||||||
- Installed packages that are up to date in `yns list`
|
|
||||||
- Interactive mode welcome message
|
|
||||||
|
|
||||||
🟡 Yellow:
|
|
||||||
- Installed packages with updates available in `yns list`
|
|
||||||
|
|
||||||
🔴 Red:
|
|
||||||
- Error messages
|
|
||||||
|
|
||||||
Example `yns list` output:
|
|
||||||
```
|
|
||||||
Available packages:
|
|
||||||
==================
|
|
||||||
calc [installed 1.1, update available 2.0] # Yellow
|
|
||||||
notepad [available 2.0] # Blue
|
|
||||||
vim [installed 3.0] # Green
|
|
||||||
```
|
|
||||||
|
|
||||||
## Repository Structure
|
|
||||||
|
|
||||||
The package manager uses a single repository source at:
|
|
||||||
`https://raw.githubusercontent.com/spitkov/ynsrepo/refs/heads/main/repo.json`
|
|
||||||
|
|
||||||
The repository contains package information in JSON format, including:
|
|
||||||
- Package name
|
|
||||||
- Version
|
|
||||||
- Installation script URL
|
|
||||||
- Update script URL
|
|
||||||
- Remove script URL
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Colored terminal output
|
|
||||||
- Progress indicators
|
|
||||||
- Automatic package cache management
|
|
||||||
- Version tracking for installed packages
|
|
||||||
- Secure script execution
|
|
||||||
- Error handling and recovery
|
|
||||||
- Interactive shell mode
|
|
50
build_curl.sh
Executable file
50
build_curl.sh
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit on error
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CURL_VERSION="8.6.0"
|
||||||
|
BUILD_DIR="$(pwd)/deps"
|
||||||
|
INSTALL_DIR="$(pwd)/deps/install"
|
||||||
|
|
||||||
|
# Create directories
|
||||||
|
mkdir -p "$BUILD_DIR"
|
||||||
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
|
||||||
|
# Download and extract curl
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
wget "https://curl.se/download/curl-${CURL_VERSION}.tar.gz"
|
||||||
|
tar xf "curl-${CURL_VERSION}.tar.gz"
|
||||||
|
cd "curl-${CURL_VERSION}"
|
||||||
|
|
||||||
|
# Configure with minimal features
|
||||||
|
./configure \
|
||||||
|
--prefix="$INSTALL_DIR" \
|
||||||
|
--disable-shared \
|
||||||
|
--enable-static \
|
||||||
|
--disable-ldap \
|
||||||
|
--disable-ldaps \
|
||||||
|
--disable-rtsp \
|
||||||
|
--disable-dict \
|
||||||
|
--disable-telnet \
|
||||||
|
--disable-tftp \
|
||||||
|
--disable-pop3 \
|
||||||
|
--disable-imap \
|
||||||
|
--disable-smtp \
|
||||||
|
--disable-gopher \
|
||||||
|
--disable-smb \
|
||||||
|
--disable-mqtt \
|
||||||
|
--without-librtmp \
|
||||||
|
--without-libidn2 \
|
||||||
|
--without-libpsl \
|
||||||
|
--without-nghttp2 \
|
||||||
|
--without-libssh2 \
|
||||||
|
--without-zstd \
|
||||||
|
--without-brotli \
|
||||||
|
--without-gssapi \
|
||||||
|
--with-openssl \
|
||||||
|
CFLAGS="-fPIC"
|
||||||
|
|
||||||
|
# Build and install
|
||||||
|
make -j$(nproc)
|
||||||
|
make install
|
|
@ -8,6 +8,8 @@ using json = nlohmann::json;
|
||||||
|
|
||||||
class PackageManager {
|
class PackageManager {
|
||||||
public:
|
public:
|
||||||
|
static constexpr const char* VERSION = "1.1";
|
||||||
|
|
||||||
PackageManager();
|
PackageManager();
|
||||||
|
|
||||||
bool update();
|
bool update();
|
||||||
|
@ -17,6 +19,8 @@ public:
|
||||||
bool list();
|
bool list();
|
||||||
bool interactive_mode();
|
bool interactive_mode();
|
||||||
bool debug();
|
bool debug();
|
||||||
|
void version();
|
||||||
|
void updateYns();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr const char* REPO_URL = "https://raw.githubusercontent.com/spitkov/ynsrepo/refs/heads/main/repo.json";
|
static constexpr const char* REPO_URL = "https://raw.githubusercontent.com/spitkov/ynsrepo/refs/heads/main/repo.json";
|
||||||
|
@ -34,6 +38,7 @@ private:
|
||||||
void print_error(const std::string& message);
|
void print_error(const std::string& message);
|
||||||
void print_success(const std::string& message);
|
void print_success(const std::string& message);
|
||||||
void print_interactive_help();
|
void print_interactive_help();
|
||||||
|
bool confirm_action(const std::string& action);
|
||||||
|
|
||||||
json repo_cache;
|
json repo_cache;
|
||||||
json installed_packages;
|
json installed_packages;
|
||||||
|
|
93
src/main.cpp
93
src/main.cpp
|
@ -13,7 +13,9 @@ void print_usage() {
|
||||||
<< " upgrade <package> Upgrade a package\n"
|
<< " upgrade <package> Upgrade a package\n"
|
||||||
<< " list List all packages\n"
|
<< " list List all packages\n"
|
||||||
<< " debug Show debug information\n"
|
<< " debug Show debug information\n"
|
||||||
<< " interactive Start interactive mode\n\n"
|
<< " interactive Start interactive mode\n"
|
||||||
|
<< " version Show YNS version\n"
|
||||||
|
<< " updateyns Update YNS to latest version\n\n"
|
||||||
<< "Interactive Mode:\n"
|
<< "Interactive Mode:\n"
|
||||||
<< " Run 'yns interactive' to enter interactive mode where you can\n"
|
<< " Run 'yns interactive' to enter interactive mode where you can\n"
|
||||||
<< " execute multiple commands without prefix. Type 'help' in\n"
|
<< " execute multiple commands without prefix. Type 'help' in\n"
|
||||||
|
@ -24,7 +26,7 @@ bool needs_sudo(const std::string& command) {
|
||||||
return command == "update" || command == "install" ||
|
return command == "update" || command == "install" ||
|
||||||
command == "remove" || command == "upgrade" ||
|
command == "remove" || command == "upgrade" ||
|
||||||
command == "interactive" || command == "list" ||
|
command == "interactive" || command == "list" ||
|
||||||
command == "debug";
|
command == "debug" || command == "version" || command == "updateyns";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_self_path() {
|
std::string get_self_path() {
|
||||||
|
@ -35,67 +37,52 @@ std::string get_self_path() {
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
print_usage();
|
std::cerr << "Error: No command provided" << std::endl;
|
||||||
|
std::cout << "Usage: yns <command> [package_name]" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string command = argv[1];
|
std::string command = argv[1];
|
||||||
|
|
||||||
if (needs_sudo(command) && geteuid() != 0) {
|
|
||||||
std::string self = get_self_path();
|
|
||||||
std::string sudo_cmd = "sudo " + self;
|
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
sudo_cmd += " ";
|
|
||||||
sudo_cmd += argv[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "This operation requires root privileges.\n";
|
|
||||||
return system(sudo_cmd.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
PackageManager pm;
|
PackageManager pm;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (command == "update") {
|
if (command == "update") {
|
||||||
return pm.update() ? 0 : 1;
|
pm.update();
|
||||||
}
|
} else if (command == "install" && argc == 3) {
|
||||||
else if (command == "list") {
|
pm.install(argv[2]);
|
||||||
return pm.list() ? 0 : 1;
|
} else if (command == "remove" && argc == 3) {
|
||||||
}
|
pm.remove(argv[2]);
|
||||||
else if (command == "debug") {
|
} else if (command == "upgrade" && argc == 3) {
|
||||||
return pm.debug() ? 0 : 1;
|
pm.upgrade(argv[2]);
|
||||||
}
|
} else if (command == "list") {
|
||||||
else if (command == "interactive") {
|
pm.list();
|
||||||
return pm.interactive_mode() ? 0 : 1;
|
} else if (command == "debug") {
|
||||||
}
|
pm.debug();
|
||||||
else if (command == "install" || command == "remove" || command == "upgrade") {
|
} else if (command == "interactive") {
|
||||||
if (argc < 3) {
|
pm.interactive_mode();
|
||||||
std::cerr << "Error: Package name required for " << command << " command\n";
|
} else if (command == "version") {
|
||||||
print_usage();
|
pm.version();
|
||||||
return 1;
|
} else if (command == "updateyns") {
|
||||||
}
|
pm.updateYns();
|
||||||
|
} else {
|
||||||
std::string package_name = argv[2];
|
std::cerr << "Error: Unknown command '" << command << "'" << std::endl;
|
||||||
|
std::cout << "Usage: yns <command> [package_name]" << std::endl;
|
||||||
if (command == "install") {
|
std::cout << "\nCommands:\n";
|
||||||
return pm.install(package_name) ? 0 : 1;
|
std::cout << " update Update package cache\n";
|
||||||
}
|
std::cout << " install <package> Install a package\n";
|
||||||
else if (command == "remove") {
|
std::cout << " remove <package> Remove a package\n";
|
||||||
return pm.remove(package_name) ? 0 : 1;
|
std::cout << " upgrade <package> Upgrade a package\n";
|
||||||
}
|
std::cout << " list List all packages\n";
|
||||||
else {
|
std::cout << " debug Show debug information\n";
|
||||||
return pm.upgrade(package_name) ? 0 : 1;
|
std::cout << " interactive Start interactive mode\n";
|
||||||
}
|
std::cout << " version Show YNS version\n";
|
||||||
}
|
std::cout << " updateyns Update YNS to latest version\n";
|
||||||
else {
|
|
||||||
std::cerr << "Error: Unknown command '" << command << "'\n";
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
} catch (const std::exception& e) {
|
||||||
catch (const std::exception& e) {
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
std::cerr << "\033[31mError: " << e.what() << "\033[0m\n";
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ const std::string BLUE = "\033[34m";
|
||||||
const std::string YELLOW = "\033[33m";
|
const std::string YELLOW = "\033[33m";
|
||||||
const std::string RESET = "\033[0m";
|
const std::string RESET = "\033[0m";
|
||||||
|
|
||||||
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
|
static size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp) {
|
||||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||||
return size * nmemb;
|
return size * nmemb;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ bool PackageManager::download_file(const std::string& url, const std::string& ou
|
||||||
|
|
||||||
std::string response_data;
|
std::string response_data;
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||||
|
@ -132,7 +132,18 @@ void PackageManager::save_installed_db(const json& db) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackageManager::print_progress(const std::string& message, int percentage) {
|
void PackageManager::print_progress(const std::string& message, int percentage) {
|
||||||
std::cout << BLUE << "[" << percentage << "%] " << message << RESET << std::endl;
|
const int bar_width = 50;
|
||||||
|
int filled_width = bar_width * percentage / 100;
|
||||||
|
|
||||||
|
std::cout << BLUE << "\r[";
|
||||||
|
for (int i = 0; i < bar_width; ++i) {
|
||||||
|
if (i < filled_width) std::cout << "=";
|
||||||
|
else if (i == filled_width) std::cout << ">";
|
||||||
|
else std::cout << " ";
|
||||||
|
}
|
||||||
|
std::cout << "] " << percentage << "% " << message << RESET;
|
||||||
|
std::cout.flush();
|
||||||
|
if (percentage == 100) std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackageManager::print_error(const std::string& message) {
|
void PackageManager::print_error(const std::string& message) {
|
||||||
|
@ -147,6 +158,13 @@ bool PackageManager::update() {
|
||||||
return cache_repo();
|
return cache_repo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PackageManager::confirm_action(const std::string& action) {
|
||||||
|
std::cout << YELLOW << "Do you want to " << action << "? [y/N] " << RESET;
|
||||||
|
std::string response;
|
||||||
|
std::getline(std::cin, response);
|
||||||
|
return (response == "y" || response == "Y");
|
||||||
|
}
|
||||||
|
|
||||||
bool PackageManager::install(const std::string& package_name) {
|
bool PackageManager::install(const std::string& package_name) {
|
||||||
if (!update()) return false;
|
if (!update()) return false;
|
||||||
|
|
||||||
|
@ -166,18 +184,19 @@ bool PackageManager::install(const std::string& package_name) {
|
||||||
print_success(package_name + " is already installed (version " + installed_version + ")");
|
print_success(package_name + " is already installed (version " + installed_version + ")");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
print_progress("New version available: " + repo_version + " (currently installed: " + installed_version + ")", 0);
|
std::cout << "\nNew version available: " + repo_version + " (currently installed: " + installed_version + ")\n";
|
||||||
std::cout << "Would you like to upgrade? [y/N] ";
|
if (!confirm_action("upgrade to version " + repo_version)) {
|
||||||
std::string response;
|
|
||||||
std::getline(std::cin, response);
|
|
||||||
if (response == "y" || response == "Y") {
|
|
||||||
return upgrade(package_name);
|
|
||||||
} else {
|
|
||||||
print_success("Keeping current version " + installed_version);
|
print_success("Keeping current version " + installed_version);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return upgrade(package_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!confirm_action("install " + package_name + " version " + repo_version)) {
|
||||||
|
std::cout << "Installation cancelled.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string install_script = package["install"];
|
std::string install_script = package["install"];
|
||||||
std::string temp_script = "/tmp/yns_install_" + package_name + ".sh";
|
std::string temp_script = "/tmp/yns_install_" + package_name + ".sh";
|
||||||
|
@ -187,8 +206,9 @@ bool PackageManager::install(const std::string& package_name) {
|
||||||
print_error("Failed to download installation script");
|
print_error("Failed to download installation script");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_progress("Installing " + package_name + "@" + repo_version, 50);
|
print_progress("Downloading installation script", 100);
|
||||||
|
print_progress("Installing " + package_name + "@" + repo_version, 0);
|
||||||
|
|
||||||
std::string cmd = "chmod +x " + temp_script + " && " + temp_script;
|
std::string cmd = "chmod +x " + temp_script + " && " + temp_script;
|
||||||
int exit_code = system(cmd.c_str());
|
int exit_code = system(cmd.c_str());
|
||||||
|
@ -204,6 +224,8 @@ bool PackageManager::install(const std::string& package_name) {
|
||||||
print_error("Installation failed with exit code: " + std::to_string(status));
|
print_error("Installation failed with exit code: " + std::to_string(status));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_progress("Installing " + package_name + "@" + repo_version, 100);
|
||||||
|
|
||||||
installed_packages[package_name] = {
|
installed_packages[package_name] = {
|
||||||
{"version", repo_version}
|
{"version", repo_version}
|
||||||
|
@ -219,6 +241,12 @@ bool PackageManager::remove(const std::string& package_name) {
|
||||||
print_error("Package '" + package_name + "' is not installed");
|
print_error("Package '" + package_name + "' is not installed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string version = installed_packages[package_name]["version"];
|
||||||
|
if (!confirm_action("remove " + package_name + " version " + version)) {
|
||||||
|
std::cout << "Removal cancelled.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
repo_cache = read_cache();
|
repo_cache = read_cache();
|
||||||
if (!repo_cache["packages"].contains(package_name)) {
|
if (!repo_cache["packages"].contains(package_name)) {
|
||||||
|
@ -235,7 +263,8 @@ bool PackageManager::remove(const std::string& package_name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_progress("Removing " + package_name, 50);
|
print_progress("Downloading removal script", 100);
|
||||||
|
print_progress("Removing " + package_name, 0);
|
||||||
|
|
||||||
std::string cmd = "chmod +x " + temp_script + " && " + temp_script;
|
std::string cmd = "chmod +x " + temp_script + " && " + temp_script;
|
||||||
int exit_code = system(cmd.c_str());
|
int exit_code = system(cmd.c_str());
|
||||||
|
@ -251,6 +280,8 @@ bool PackageManager::remove(const std::string& package_name) {
|
||||||
print_error("Removal failed with exit code: " + std::to_string(status));
|
print_error("Removal failed with exit code: " + std::to_string(status));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_progress("Removing " + package_name, 100);
|
||||||
|
|
||||||
installed_packages.erase(package_name);
|
installed_packages.erase(package_name);
|
||||||
save_installed_db(installed_packages);
|
save_installed_db(installed_packages);
|
||||||
|
@ -447,4 +478,101 @@ bool PackageManager::debug() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackageManager::version() {
|
||||||
|
std::cout << "YNS Package Manager version " << VERSION << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackageManager::updateYns() {
|
||||||
|
std::cout << "Checking for YNS updates..." << std::endl;
|
||||||
|
|
||||||
|
CURL* curl = curl_easy_init();
|
||||||
|
if (!curl) {
|
||||||
|
print_error("Failed to initialize CURL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string response;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repos/spitkov/ynspkg/releases/latest");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "YNS Package Manager");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
|
||||||
|
print_progress("Checking for updates", 0);
|
||||||
|
CURLcode res = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
if (res != CURLE_OK) {
|
||||||
|
print_error("Failed to check for updates");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json release = json::parse(response);
|
||||||
|
std::string latest_version = release["tag_name"];
|
||||||
|
if (latest_version[0] == 'v') {
|
||||||
|
latest_version = latest_version.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_progress("Checking for updates", 100);
|
||||||
|
|
||||||
|
if (latest_version == VERSION) {
|
||||||
|
print_success("No new YNS version found. Latest version is " + std::string(VERSION));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\nNew version " << latest_version << " found (current: " << VERSION << ")" << std::endl;
|
||||||
|
|
||||||
|
if (!confirm_action("update YNS to version " + latest_version)) {
|
||||||
|
std::cout << "Update cancelled.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_progress("Downloading update", 0);
|
||||||
|
|
||||||
|
std::string download_url = release["assets"][0]["browser_download_url"];
|
||||||
|
std::string temp_file = "/tmp/yns_update";
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
FILE* fp = fopen(temp_file.c_str(), "wb");
|
||||||
|
if (!fp || !curl) {
|
||||||
|
print_error("Failed to prepare update");
|
||||||
|
if (fp) fclose(fp);
|
||||||
|
if (curl) curl_easy_cleanup(curl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, download_url.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||||
|
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
fclose(fp);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
print_progress("Downloading update", 100);
|
||||||
|
|
||||||
|
if (res != CURLE_OK) {
|
||||||
|
print_error("Failed to download update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_progress("Installing update", 0);
|
||||||
|
|
||||||
|
std::string cmd = "chmod +x " + temp_file + " && ";
|
||||||
|
cmd += "sudo cp " + temp_file + " /usr/bin/yns && ";
|
||||||
|
cmd += "sudo cp " + temp_file + " /bin/yns && ";
|
||||||
|
cmd += "rm " + temp_file;
|
||||||
|
|
||||||
|
if (system(cmd.c_str()) != 0) {
|
||||||
|
print_error("Failed to install update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_progress("Installing update", 100);
|
||||||
|
print_success("Successfully updated to version " + latest_version);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
print_error("Failed to parse update information");
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue