Updated README.md and .gitignore files

-Fixed issue where `gdpm` would to work because of missing directory
-Changed `constexpr const char *` constants to use `const std::string`
string instead to use with `HOME` variable
-Changed where packages are stored. Now, they should stored in the
user's `$HOME/.config/gdpm/packages.db` by default. This may change to
use `$HOME/.cache/gdpm/packages.db` by default in the future.
This commit is contained in:
David Allen 2022-08-07 09:17:25 -05:00
parent 2bf0186f98
commit e36f0aee79
6 changed files with 75 additions and 58 deletions

3
.gitignore vendored
View file

@ -1,8 +1,9 @@
build/** build/**
bin/gdpm
tests tests
*/tmp/** */tmp/**
vgcore.* vgcore.*
.cache .cache
.vscode .vscode
config.json config.json
*.txt *.txt

View file

@ -1,20 +1,20 @@
# Godot Package Manager (GDPM) # Godot Package Manager (GDPM)
GDPM is an attempt to make a front-end, package manager designed to handle assets from the Godot Game Engine's official asset library. It is written in C++ to be lightwight and fast with a few common dependencies found in most Linux distributions and can be used completely independent of Godot. It is designed to add more functionality not included with the AssetLib with the ability to automate builds on different systems. So far, the package manager is capable of searching, downloading, installing and removing packages and makes managing Godot assets across multiple projects much easier. GDPM has not been tested on Windows yet and there are no currently plans to support macOS. GDPM is an attempt to make a front-end, command-line, package manager designed to handle assets from the Godot Game Engine's official asset library. It is written in C++ to be lightwight and fast with a few common dependencies found in most Linux distributions and can be used completely independent of Godot. It is designed to add more functionality not included with the official AssetLib with the ability to automate downloads for different systems. So far, the package manager is capable of searching, downloading, installing, and removing packages and makes managing Godot assets across multiple projects much easier. GDPM has not been tested to work on Windows or Mac.
## Why not just use the Asset Library? ## Why not just use the Asset Library?
The AssetLib is a bit limited for my use case. Personally, I wanted a way to quickly download and install all the assets I'd need for a project once and only once. Then, when I'd need that same asset for another project, I could just reuse the ones installed for the previous project. This is where the issues begin. The AssetLib doesn't have a way to reuse asset across multiple projects without having to either redownload the asset again from the AssetLib or copy the assets from somewhere locally. Likewise, this would force game developers to have to copy their assets manually from one project to another and keep track of their assets themselves. The AssetLib actually works well enough for most use cases. However, it's common to download the same asset multiple times for different projects. If there isn't a need to modify the asset itself, it makes more sense to download the asset only once. That way, there will only be one copy of the asset and it can be linked to all new projects. The AssetLib does not have a way to manage assets like this, and therefore requires redownload assets for each new project. Additionally, the AssetLib is integrated into the engine itself with no command-line interface. When downloading multiple assets, it is much more convenient to be able to automate the downloads using a list from a text file. If the user knows, which assets to download, they can make a list and point to it.
Some assets are more common such as the "First Person Controller" are likely to be reused with little to no modification. Therefore, it made sense to provide some method to download and install the assets once and then provide a symbolic link back to the stored packages. GDPM attempts to fix this by storing the assets in a single location and creating symlinks/shortcuts to each project. By have a separate, simple binary executable, the package manager can be used in shell scripts to automate tasks and download assets quickly. Some assets are more common such as the "First Person Controller" are likely to be reused with little to no modification. Therefore, it made sense to provide some method to download and install the assets once and then provide a symbolic link back to the stored packages. GDPM attempts to fix this by storing the assets in a single location and creating symlinks/shortcuts to each project. By having a separate, simple binary executable, the package manager can be used in shell scripts to download assets more quickly.
Currently, there is no dependency management as it is not needed. There are future plans to implement a system to handle dependencies, but the implementation is still being fleshed out. Currently, there is no dependency management as it is not needed yet. There are future plans to implement a system to handle dependencies, but the implementation is still being fleshed out.
## How It Works ## How It Works
GDPM is built to work with an instance of [Godot's Asset API](https://github.com/godotengine/godot-asset-library). When installing packages, GDPM will first make HTTP requests to retrieve required asset data to download the asset and sync it in with a local database. Then, it will make another API request to retrieve the rest of an asset's data, update it in the database, then download it from the remote repository. Unfortunately, the package manager requires at least 2 request for a single asset. Therefore, there's an intentional 200 ms delay by default between each request to not bombard the API server, but is configurable at compile time (see "Building from source" section below). GDPM is built to work with an instance of [Godot's Asset API](https://github.com/godotengine/godot-asset-library). When installing packages, GDPM will first make HTTP requests to retrieve required asset data to download the asset and sync it in with a local database. Then, it will make another API request to retrieve the rest of an asset's data, update it in the database, then download it from the remote repository. Unfortunately, the package manager requires at least 2 request for a single asset. Therefore, there's an intentional 200 ms delay by default between each request to not bombard the API server, but is configurable at compile time (see "[Building from Source](#building-from-source)" section below).
When removing a package, the unzip files are remove but the temporary files are keep in the .tmp directory unless using the '--clean' option. This allows the user to remove the uncompressed files, but easily reinstall the package without having to download it remotely again. When removing a package, the unzip files are remove but the temporary files are keep in the specified `.tmp` directory unless using the `--clean` option. This allows the user to remove the uncompressed files, but easily reinstall the package without having to download it remotely again.
The local database stores all the information sent by the Asset API with additional information like "install_path" and "remote_source" for the API used to gather information. The local database stores all the information sent by the Asset API with additional information like "install_path" and "remote_source" for the API used to gather information.
@ -28,11 +28,9 @@ The local database stores all the information sent by the Asset API with additio
- Create package groups to copy a set of packages into a Godot project. - Create package groups to copy a set of packages into a Godot project.
-
## Building from Source ## Building from Source
The project uses the CMake or Meson build system and has been tested with GCC and Clang on Arch/Manjaro Linux. Meson is preferred, but a CMakeLists.txt is provided due to CMake's popularity and should work with some tweaking. Building on Windows has not been tested yet so it's not guaranteed to work. Compiling with CMake will build an executable, shared, and archive library, while compiling with Meson only builds an executable that links with a shared library. The project uses the CMake or Meson build system and has been tested with GCC and Clang on Arch/Manjaro Linux. Meson is preferred, but a CMakeLists.txt is provided due to CMake's popularity and should work with some tweaking. Building on Windows or Mac has not been tested yet so it's not guaranteed to work. Compiling with CMake will build an executable, shared, and archive library, while compiling with Meson only builds an executable that links with a shared library.
### Prerequisites ### Prerequisites
@ -58,8 +56,8 @@ After installing all necessary dependencies, run the following commands:
```bash ```bash
# Start by cloning the repo, then... # Start by cloning the repo, then...
git clone $(repo_name) git clone https://github.com/davidallendj/gdpm
cd $(repo_name) cd https://github.com/davidallendj/gdpm
# ...if using Meson with Clang on Linux... # ...if using Meson with Clang on Linux...
meson build meson build
@ -131,7 +129,7 @@ To see more help information:
gdpm help gdpm help
``` ```
Packages can be installed using the "install" command and providing a list of comma-delimited package names with no spaces or by providing a one-package-per-line file using the '--file' option. Using the '-y' option will bypass the user prompt. The '--no-sync' option with bypass syncing the local package database with the AssetLib API and use locally stored information only. See the '--search' command to find a list of available packages. Packages can be installed using the `install` command and providing a list of comma-delimited package names with no spaces or by providing a one-package-per-line file using the `--file` option. Using the `-y` option will bypass the user prompt. The `--no-sync` option with bypass syncing the local package database with the AssetLib API and use locally stored information only. See the `search` command to find a list of available packages.
```bash ```bash
gdpm install "Flappy Godot" "GodotNetworking" -y gdpm install "Flappy Godot" "GodotNetworking" -y
@ -142,7 +140,7 @@ Packages can be removed similiarly to installing.
```bash ```bash
gdpm remove "Flappy Godot" "GodotNetworking" -y gdpm remove "Flappy Godot" "GodotNetworking" -y
gdpm remove -f packages.txt gdpm remove -f packages.txt --config config.json --no-sync --no-prompt
``` ```
Packages can be updated like installing or removing packages. However, if no argument is passed, GDPM will prompt the user to update ALL packages to latest instead. Packages can be updated like installing or removing packages. However, if no argument is passed, GDPM will prompt the user to update ALL packages to latest instead.
@ -205,6 +203,13 @@ gdpm list packages --verbose
gdpm list remote-sources gdpm list remote-sources
``` ```
If you want to try `gdpm` without installing it to your system, make a symlink to the built executable and add the `bin` directory to your PATH variable.
```bash
ln -s path/to/build/gdpm path/to/bin/gdpm
export PATH=$PATH:path/to/bin/gdpm
```
## Planned Features ## Planned Features
- [ ] Dependency management. There is no way of handling dependencies using the Godot Asset API. This is a [hot topic](https://github.com/godotengine/godot-proposals/issues/142) and might change in the near future. - [ ] Dependency management. There is no way of handling dependencies using the Godot Asset API. This is a [hot topic](https://github.com/godotengine/godot-proposals/issues/142) and might change in the near future.
@ -219,6 +224,10 @@ gdpm list remote-sources
- [ ] Support for paid assets. - [ ] Support for paid assets.
## Known Issues
- The `help` command does not should the command/options correctly. Commands do not use the double hypen, `--command` format. Commands should be use like `gdpm command --option` instead.
## License ## License
See the LICENSE.md file. See the LICENSE.md file.

View file

@ -27,7 +27,7 @@ namespace gdpm::config{
std::string to_json(const config_context& params); std::string to_json(const config_context& params);
config_context load(std::filesystem::path path, int verbose = 0); config_context load(std::filesystem::path path, int verbose = 0);
int save(const config_context& config, int verbose = 0); int save(const config_context& config, int verbose = 0);
config_context make_config(const std::string& username = GDPM_CONFIG_USERNAME, const std::string& password = GDPM_CONFIG_PASSWORD, const std::string& path = GDPM_CONFIG_PATH, const std::string& token = GDPM_CONFIG_TOKEN, const std::string& godot_version = GDPM_CONFIG_GODOT_VERSION, const std::string& packages_dir = GDPM_CONFIG_LOCAL_PACKAGES_DIR, const std::string& tmp_dir = GDPM_CONFIG_LOCAL_TMP_DIR, const std::set<std::string>& remote_sources = {GDPM_CONFIG_REMOTE_SOURCES}, size_t threads = GDPM_CONFIG_THREADS, size_t timeout = 0, bool enable_sync = GDPM_CONFIG_ENABLE_SYNC, bool enable_file_logging = GDPM_CONFIG_ENABLE_FILE_LOGGING, int verbose = GDPM_CONFIG_VERBOSE); config_context make_context(const std::string& username = GDPM_CONFIG_USERNAME, const std::string& password = GDPM_CONFIG_PASSWORD, const std::string& path = GDPM_CONFIG_PATH, const std::string& token = GDPM_CONFIG_TOKEN, const std::string& godot_version = GDPM_CONFIG_GODOT_VERSION, const std::string& packages_dir = GDPM_CONFIG_LOCAL_PACKAGES_DIR, const std::string& tmp_dir = GDPM_CONFIG_LOCAL_TMP_DIR, const std::set<std::string>& remote_sources = {GDPM_CONFIG_REMOTE_SOURCES}, size_t threads = GDPM_CONFIG_THREADS, size_t timeout = 0, bool enable_sync = GDPM_CONFIG_ENABLE_SYNC, bool enable_file_logging = GDPM_CONFIG_ENABLE_FILE_LOGGING, int verbose = GDPM_CONFIG_VERBOSE);
extern config_context config; extern config_context config;
} }

View file

@ -2,25 +2,27 @@
#include <rapidjson/rapidjson.h> #include <rapidjson/rapidjson.h>
#include <string> #include <string>
#include <string_view>
namespace gdpm::constants{ namespace gdpm::constants{
constexpr const char *ConfigPath = "config.ini"; const std::string HomePath(std::string(std::getenv("HOME")) + "/");
constexpr const char *LocalPackagesDir = "$HOME/.config/gdpm"; const std::string ConfigPath(HomePath + ".config/gdpm/config.json");
constexpr const char *UserAgent = "libcurl-agent/1.0"; const std::string LockfilePath(HomePath + ".config/gdpm/gdpm.lck");
constexpr const char *AssetRepo = "https://godotengine.org/asset-library/api/asset"; const std::string LocalPackagesDir(HomePath + ".config/gdpm/packages");
constexpr const char *HostUrl = "https://godotengine.org/asset-library/api"; const std::string TemporaryPath(HomePath + ".config/gdpm/tmp");
constexpr const char *LockfilePath = "$HOME/.config/gdpm/gdpm.lck"; const std::string UserAgent("libcurl-agent/1.0");
constexpr const char *TmpPath = "$HOME/.config/gdpm/tmp"; const std::string AssetRepo("https://godotengine.org/asset-library/api/asset");
const std::string HostUrl("https://godotengine.org/asset-library/api");
} }
/* Define default macros to set when building with -DGPM_* */ /* Define default macros to set when building with -DGPM_* */
#define GDPM_CONFIG_USERNAME "" #define GDPM_CONFIG_USERNAME ""
#define GDPM_CONFIG_PASSWORD "" #define GDPM_CONFIG_PASSWORD ""
#define GDPM_CONFIG_PATH "config.json" #define GDPM_CONFIG_PATH gdpm::constants::ConfigPath
#define GDPM_CONFIG_TOKEN "" #define GDPM_CONFIG_TOKEN ""
#define GDPM_CONFIG_GODOT_VERSION "3.4" #define GDPM_CONFIG_GODOT_VERSION "3.4"
#define GDPM_CONFIG_LOCAL_PACKAGES_DIR "tests/gdpm/packages" #define GDPM_CONFIG_LOCAL_PACKAGES_DIR gdpm::constants::LocalPackagesDir
#define GDPM_CONFIG_LOCAL_TMP_DIR "tests/gdpm/.tmp" #define GDPM_CONFIG_LOCAL_TMP_DIR gdpm::constants::TemporaryPath
#define GDPM_CONFIG_REMOTE_SOURCES constants::HostUrl #define GDPM_CONFIG_REMOTE_SOURCES constants::HostUrl
#define GDPM_CONFIG_THREADS 1 #define GDPM_CONFIG_THREADS 1
#define GDPM_CONFIG_TIMEOUT_MS 30000 #define GDPM_CONFIG_TIMEOUT_MS 30000
@ -30,7 +32,7 @@ namespace gdpm::constants{
/* Defines the default package cache for local storage */ /* Defines the default package cache for local storage */
#define GDPM_PACKAGE_CACHE_ENABLE 1 #define GDPM_PACKAGE_CACHE_ENABLE 1
#define GDPM_PACKAGE_CACHE_PATH "tests/gdpm/packages.db" #define GDPM_PACKAGE_CACHE_PATH gdpm::constants::LocalPackagesDir + "/packages.db"
#define GDPM_PACKAGE_CACHE_TABLENAME "cache" #define GDPM_PACKAGE_CACHE_TABLENAME "cache"
#define GDPM_PACKAGE_CACHE_COLNAMES "asset_id, type, title, author, author_id, version, godot_version, cost, description, modify_date, support_level, category, remote_source, download_url, download_hash, is_installed, install_path" #define GDPM_PACKAGE_CACHE_COLNAMES "asset_id, type, title, author, author_id, version, godot_version, cost, description, modify_date, support_level, category, remote_source, download_url, download_hash, is_installed, install_path"
@ -55,25 +57,26 @@ namespace gdpm::constants{
#define GDPM_DLL_EXPORT #define GDPM_DLL_EXPORT
#define GDPM_DLL_IMPORT #define GDPM_DLL_IMPORT
#endif #endif
#define GDPM_READFILE_IMPL 1 #define GDPM_READFILE_IMPL 1
#define GDPM_DELAY_HTTP_REQUESTS 1 #define GDPM_DELAY_HTTP_REQUESTS 1
#ifndef GDPM_REQUEST_DELAY #ifndef GDPM_REQUEST_DELAY
#define GDPM_REQUEST_DELAY 200ms #define GDPM_REQUEST_DELAY 200ms
#endif #endif
#ifndef GDPM_ENABLE_COLORS #ifndef GDPM_ENABLE_COLORS
#define GDPM_ENABLE_COLORS 1 #define GDPM_ENABLE_COLORS 1
#endif #endif
#ifndef GDPM_LOG_LEVEL #ifndef GDPM_LOG_LEVEL
#define GDPM_LOG_LEVEL 1 #define GDPM_LOG_LEVEL 1
#endif #endif
#ifndef GDPM_ENABLE_TIMESTAMPS #ifndef GDPM_ENABLE_TIMESTAMPS
#define GDPM_ENABLE_TIMESTAMPS 1 #define GDPM_ENABLE_TIMESTAMPS 1
#endif #endif
#ifndef GDPM_TIMESTAMP_FORMAT #ifndef GDPM_TIMESTAMP_FORMAT
#define GDPM_TIMESTAMP_FORMAT ":%I:%M:%S %p; %Y-%m-%d" #define GDPM_TIMESTAMP_FORMAT ":%I:%M:%S %p; %Y-%m-%d"
#endif #endif

View file

@ -61,7 +61,10 @@ namespace gdpm::config{
std::fstream file; std::fstream file;
file.open(path, std::ios::in); file.open(path, std::ios::in);
if(!file){ if(!file){
log::error("Could not open file"); if(verbose){
log::info("No configuration file found. Creating a new one.");
save(make_context(), verbose);
}
return config; return config;
} }
else if(file.is_open()){ else if(file.is_open()){
@ -158,7 +161,7 @@ namespace gdpm::config{
return 0; return 0;
} }
config_context make_config(const std::string& username, const std::string& password, const std::string& path, const std::string& token, const std::string& godot_version, const std::string& packages_dir, const std::string& tmp_dir, const std::set<std::string>& remote_sources, size_t threads, size_t timeout, bool enable_sync, bool enable_file_logging, int verbose){ config_context make_context(const std::string& username, const std::string& password, const std::string& path, const std::string& token, const std::string& godot_version, const std::string& packages_dir, const std::string& tmp_dir, const std::set<std::string>& remote_sources, size_t threads, size_t timeout, bool enable_sync, bool enable_file_logging, int verbose){
config_context config { config_context config {
.username = username, .username = username,
.password = password, .password = password,

View file

@ -46,7 +46,7 @@ namespace gdpm::package_manager{
int initialize(int argc, char **argv){ int initialize(int argc, char **argv){
// curl_global_init(CURL_GLOBAL_ALL); // curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init(); curl = curl_easy_init();
config = config::make_config(); config = config::make_context();
params = rest_api::make_context(); params = rest_api::make_context();
command = none; command = none;
@ -87,7 +87,7 @@ namespace gdpm::package_manager{
params.verbose = config.verbose; params.verbose = config.verbose;
/* TODO: Need a way to use remote sources from config until no left */ /* TODO: Need a way to use remote sources from config until none left */
/* Check if the package data is already stored in cache. If it is, there /* Check if the package data is already stored in cache. If it is, there
is no need to do a lookup to synchronize the local database since we is no need to do a lookup to synchronize the local database since we
@ -130,7 +130,7 @@ namespace gdpm::package_manager{
using ss_pair = std::pair<std::string, std::string>; using ss_pair = std::pair<std::string, std::string>;
std::vector<ss_pair> dir_pairs; std::vector<ss_pair> dir_pairs;
for(auto& p : p_found){ for(auto& p : p_found){
log::info_n("Fetching asset data for \"{}\"...", p.title); log::info("Fetching asset data for \"{}\"...", p.title);
/* TODO: Try fetching the data with all available remote sources until retrieved */ /* TODO: Try fetching the data with all available remote sources until retrieved */
for(const auto& remote_url : config.remote_sources){ for(const auto& remote_url : config.remote_sources){
@ -189,7 +189,7 @@ namespace gdpm::package_manager{
if(!std::filesystem::exists(package_dir)) if(!std::filesystem::exists(package_dir))
std::filesystem::create_directory(package_dir); std::filesystem::create_directory(package_dir);
std::ofstream ofs(package_dir + "/package.json"); std::ofstream ofs(package_dir + "/asset.json");
OStreamWrapper osw(ofs); OStreamWrapper osw(ofs);
PrettyWriter<OStreamWrapper> writer(osw); PrettyWriter<OStreamWrapper> writer(osw);
doc.Accept(writer); doc.Accept(writer);
@ -200,7 +200,7 @@ namespace gdpm::package_manager{
} }
else{ else{
/* Download all the package files and place them in tmp directory. */ /* Download all the package files and place them in tmp directory. */
log::print("Downloading \"{}\"...", p.title); log::info_n("Downloading \"{}\"...", p.title);
std::string download_url = p.download_url;// doc["download_url"].GetString(); std::string download_url = p.download_url;// doc["download_url"].GetString();
std::string title = p.title;// doc["title"].GetString(); std::string title = p.title;// doc["title"].GetString();
http::response response = http::download_file(download_url, tmp_zip); http::response response = http::download_file(download_url, tmp_zip);
@ -224,9 +224,9 @@ namespace gdpm::package_manager{
utils::extract_zip(p.first.c_str(), p.second.c_str()); utils::extract_zip(p.first.c_str(), p.second.c_str());
/* Update the cache data with information from */ /* Update the cache data with information from */
log::info_n("Updating local package database..."); log::info_n("Updating local asset data...");
cache::update_package_info(p_found); cache::update_package_info(p_found);
log::println("Done."); log::println("done.");
} }
@ -307,9 +307,9 @@ namespace gdpm::package_manager{
p.is_installed = false; p.is_installed = false;
} }
log::println("Done."); log::println("Done.");
log::info_n("Updating local package database..."); log::info_n("Updating local asset data...");
cache::update_package_info(p_cache); cache::update_package_info(p_cache);
log::println("Done."); log::println("done.");
} }
@ -376,7 +376,7 @@ namespace gdpm::package_manager{
request_url += rest_api::endpoints::GET_Asset; request_url += rest_api::endpoints::GET_Asset;
Document doc = rest_api::get_assets_list(request_url, params); Document doc = rest_api::get_assets_list(request_url, params);
if(doc.IsNull()){ if(doc.IsNull()){
log::error("Could not search for packages. Are you connected to the internet?"); log::error("Could not search for packages.");
return; return;
} }
@ -566,28 +566,29 @@ namespace gdpm::package_manager{
/* Parse command-line arguments using cxxopts */ /* Parse command-line arguments using cxxopts */
cxxopts::Options options( cxxopts::Options options(
argv[0], argv[0],
"Package manager made for managing Godot assets." "Experimental package manager made for managing assets for the Godot game engine.\n"
); );
options.allow_unrecognised_options(); options.allow_unrecognised_options();
options.custom_help("This is a custom help string."); options.custom_help("[COMMAND] [OPTIONS...]");
options.add_options("Command") options.add_options("Command")
("input", "", cxxopts::value<std::vector<std::string>>()) ("command", "Specify the input parameters", cxxopts::value<std::vector<std::string>>())
("install", "Install package or packages.", cxxopts::value<std::vector<std::string>>()->implicit_value(""), "<packages...>") ("install", "Install package or packages.", cxxopts::value<std::vector<std::string>>()->implicit_value(""), "<packages...>")
("remove", "Remove a package or packages.", cxxopts::value<std::vector<std::string>>()->implicit_value(""), "<packages...>") ("remove", "Remove a package or packages.", cxxopts::value<std::vector<std::string>>()->implicit_value(""), "<packages...>")
("update", "Update a package or packages. This option will update all packages if no argument is supplied.", cxxopts::value<std::vector<std::string>>()->implicit_value(""), "<packages...>") ("update", "Update a package or packages. This will update all packages if no argument is provided.", cxxopts::value<std::vector<std::string>>()->implicit_value(""), "<packages...>")
("search", "Search for a package or packages.", cxxopts::value<std::vector<std::string>>(), "<packages...>") ("search", "Search for a package or packages.", cxxopts::value<std::vector<std::string>>(), "<packages...>")
("list", "Show list of is_installed packages.") ("list", "Show list of installed packages.")
("link", "Create a symlink (or shortcut) to target directory.", cxxopts::value<std::vector<std::string>>(), "<packages...>") ("link", "Create a symlink (or shortcut) to target directory. Must be used with the `--path` argument.", cxxopts::value<std::vector<std::string>>(), "<packages...>")
("clone", "Clone packages into target directory.", cxxopts::value<std::vector<std::string>>(), "<packages...>") ("clone", "Clone packages into target directory. Must be used with the `--path` argument.", cxxopts::value<std::vector<std::string>>(), "<packages...>")
("clean", "Clean temporary downloaded files.") ("clean", "Clean temporary downloaded files.")
("sync", "Sync local database with remote server.") ("fetch", "Fetch asset data from remote sources.")
("add-remote", "Set a source repository.", cxxopts::value<std::string>()->default_value(constants::AssetRepo), "<url>") ("add-remote", "Set a source repository.", cxxopts::value<std::string>()->default_value(constants::AssetRepo), "<url>")
("delete-remote", "Remove a source repository from list.", cxxopts::value<std::string>(), "<url>") ("delete-remote", "Remove a source repository from list.", cxxopts::value<std::string>(), "<url>")
("remote", "One time remote source use. Source is not saved and override sources used in config.", cxxopts::value<std::vector<std::string>>(), "<url>") ("quick-remote", "One time remote source use. Source is not saved and override sources used in config.", cxxopts::value<std::vector<std::string>>(), "<url>")
("h,help", "Print this message and exit.") ("h,help", "Print this message and exit.")
("version", "Show the version and exit.") ("version", "Show the current version and exit.")
; ;
options.parse_positional({"input"}); options.parse_positional({"command"});
options.positional_help("");
options.add_options("Options") options.add_options("Options")
("c,config", "Set the config file path.", cxxopts::value<std::string>()) ("c,config", "Set the config file path.", cxxopts::value<std::string>())
("f,file", "Read file to install or remove packages.", cxxopts::value<std::string>(), "<path>") ("f,file", "Read file to install or remove packages.", cxxopts::value<std::string>(), "<path>")
@ -711,12 +712,12 @@ namespace gdpm::package_manager{
log::println("{}", json); log::println("{}", json);
} }
if(!result.count("input")){ if(!result.count("command")){
log::error("Command required. See \"help\" for more information."); log::error("Command required. See \"help\" for more information.");
return; return;
} }
std::vector<std::string> argv = result["input"].as<std::vector<std::string>>(); std::vector<std::string> argv = result["command"].as<std::vector<std::string>>();
std::vector<std::string> opts{argv.begin()+1, argv.end()}; std::vector<std::string> opts{argv.begin()+1, argv.end()};
if(packages.empty() && opts.size() > 0){ if(packages.empty() && opts.size() > 0){
for(const auto& opt : opts){ for(const auto& opt : opts){
@ -818,7 +819,7 @@ namespace gdpm::package_manager{
int total_items = 0; int total_items = 0;
int items_left = 0; int items_left = 0;
log::info_n("Sychronizing database..."); log::info("Sychronizing database...");
do{ do{
/* Make the GET request to get page data and store it in the local /* Make the GET request to get page data and store it in the local
package database. Also, check to see if we need to keep going. */ package database. Also, check to see if we need to keep going. */
@ -828,7 +829,7 @@ namespace gdpm::package_manager{
params.page += 1; params.page += 1;
if(doc.IsNull()){ if(doc.IsNull()){
log::error("\nCould not get response from server. Aborting."); log::error("Could not get response from server. Aborting.");
return {}; return {};
} }