Compare commits

..
8 Commits
10 changed files with 333 additions and 105 deletions
+49 -12
View File
@@ -16,7 +16,7 @@ Config file and package tracking utility.
If you are using *Arch Linux*, you can install the AUR package [[https://aur.archlinux.org/packages/manafiles-git/][manafiles-git]]. If you are using *Arch Linux*, you can install the AUR package [[https://aur.archlinux.org/packages/manafiles-git/][manafiles-git]].
Alternatively, you will have to [[#building][build from source]]. Alternatively, you will have to [[#compiling][build from source]].
*** Configuration *** Configuration
@@ -86,21 +86,29 @@ or uncomments them depending on the machine's configuration. Such a block looks
like this: like this:
#+BEGIN_SRC shell-script #+BEGIN_SRC shell-script
# >>> distro=arch hostname=arch-desktop user=anon # >>> distro=arch hostname=arch-desktop user=anon session=xorg
export PATH="$PATH:$HOME/.local/bin" export PATH="$PATH:$HOME/.local/bin"
# <<< # <<<
#+END_SRC #+END_SRC
This block uses all of the supported configurations, ~distro~, ~hostname~ and This block uses all of the supported configurations, ~distro~, ~hostname~,
~user~. These can be used in any combination and order. ~user~ and ~session~. These can be used in any combination and order.
If *all* of the given configurations match, manafiles will make sure that the If *all* of the given configurations match, manafiles will make sure that the
contents of the block are uncommented. If *any* of them do *not* match, then contents of the block are uncommented. If *any* of them do *not* match, then
manafiles will make sure that the contents of the block are commented. manafiles will make sure that the contents of the block are commented.
** Building ***** Usable values for the configurations
*** Build dependencies | distro | session |
|--------+---------|
| arch | xorg |
| debian | wayland |
| ubuntu | |
** Compiling
*** Dependencies
- ~gcc-libs~ - ~gcc-libs~
- (make) ~cmake~ - (make) ~cmake~
@@ -112,17 +120,46 @@ manafiles will make sure that the contents of the block are commented.
The optional requirements are for the package tracking functionality. The optional requirements are for the package tracking functionality.
*** Build compilation *** Building
To get the sources from the repository, run the following commands:
#+BEGIN_SRC shell-script
$ git clone https://github.com/riyyi/manafiles
$ cd manafiles
$ git submodule init
$ git submodule update
#+END_SRC
or
#+BEGIN_SRC shell-script
$ git clone --recursive https://github.com/riyyi/manafiles
$ cd manafiles
#+END_SRC
**** Compiling
To compile, run the following commands:
#+BEGIN_SRC shell-script #+BEGIN_SRC shell-script
$ mkdir build $ mkdir build
$ cd build $ cd build
$ cmake .. $ cmake ..
$ make $ make
#+END_SRC # Optional. This will install the manafiles executable in /usr/bin
*** Build installation
#+BEGIN_SRC shell-script
$ sudo make install $ sudo make install
#+END_SRC #+END_SRC
*** Uninstalling
To uninstall, run the following commands:
*Warning*: ~make uninstall~ will try to delete all files listed in the
~install_manifest.txt~ file inside your ~build~ folder. Make sure you first
check that it won't delete any important files.
#+BEGIN_SRC shell-script
$ cd build
$ sudo make uninstall
#+END_SRC
+6 -4
View File
@@ -1,4 +1,4 @@
.TH MANAFILES 1 "2022-01-29" "manafiles 0.5" "User Commands" .TH MANAFILES 1 "2025-02-02" "manafiles 0.6" "User Commands"
.SH NAME .SH NAME
manafiles \- config file and package tracking utility manafiles \- config file and package tracking utility
@@ -31,7 +31,7 @@ See File Options below.
.TP .TP
.BR \-P ", " \-\-package .BR \-P ", " \-\-package
Operate on packages. \ Operate on packages. \
This operation allows you to track installed packages and reinstall them. \ This operation allows tracking installed packages and reinstalling them. \
In the first case, if no package names are provided in the command line, all packages will be selected. \ In the first case, if no package names are provided in the command line, all packages will be selected. \
See Package Options below. See Package Options below.
@@ -67,8 +67,10 @@ Install all AUR packages of the stored list.
Install all official packages of the stored list. Install all official packages of the stored list.
.TP .TP
.BR \-s ", " \-\-store .BR \-s ", " \-\-search
Stores a list of all installed packages on the system. Search each locally-installed package for names via a partial match. \
When including multiple search terms, all packages with names matching any of those terms are returned. \
If the \fB-s\fR option is ommited, packages names are filtered via a full match.
.SH EXAMPLES .SH EXAMPLES
Usage examples: Usage examples:
+53 -19
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2021-2022 Riyyi * Copyright (C) 2021-2022,2025 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
@@ -15,11 +15,12 @@
#include <unistd.h> // geteuid, getlogin, setegid, seteuid #include <unistd.h> // geteuid, getlogin, setegid, seteuid
#include <vector> #include <vector>
#include "ruc/file.h"
#include "ruc/meta/assert.h"
#include "config.h" #include "config.h"
#include "dotfile.h" #include "dotfile.h"
#include "machine.h" #include "machine.h"
#include "ruc/file.h"
#include "ruc/meta/assert.h"
Dotfile::Dotfile(s) Dotfile::Dotfile(s)
{ {
@@ -114,7 +115,12 @@ bool Dotfile::match(const std::string& path, const std::vector<std::string>& pat
std::string pathString = path.substr(cutFrom); std::string pathString = path.substr(cutFrom);
for (const auto& pattern : patterns) { for (const auto& pattern : patterns) {
// A dot matches everything in the current working directory
if (pattern == ".") {
return true;
}
// Exact match is obviously true
if (pathString == pattern) { if (pathString == pattern) {
return true; return true;
} }
@@ -375,39 +381,58 @@ void Dotfile::selectivelyCommentOrUncomment(const std::string& path)
{ {
ruc::File dotfile(path); ruc::File dotfile(path);
const std::string search[3] = { const std::string search[4] = {
"distro=", "distro=",
"hostname=", "hostname=",
"user=", "user=",
"session=",
}; };
// State of the loop // State of the loop
bool isFiltering = false; bool isFiltering = false;
std::string filter[3]; std::string filter[4];
std::string commentCharacter; std::string commentCharacter;
std::string commentTerminationCharacter; std::string commentTerminationCharacter;
size_t positionInFile = 0; size_t positionInFile = 0;
auto commentOrUncommentLine = [&](std::string& line, bool addComment) { auto commentOrUncommentLine = [&](std::string& line, bool addComment) {
size_t indentation = line.find_first_not_of(" \t");
// Empty lines are skipped
if (line.empty() || indentation == std::string::npos) {
return;
}
size_t lineLength = line.size(); size_t lineLength = line.size();
size_t whiteSpaceBeforeComment = line.find_first_not_of(" \t"); size_t commentStart = line.find(commentCharacter, indentation);
size_t contentAfterComment = line.find_first_not_of(" \t" + commentCharacter); size_t commentEnd = line.rfind(commentTerminationCharacter);
// NOTE: The +1 is needed to take the newline into account bool hasComment = commentStart != std::string::npos && (commentTerminationCharacter.empty() || commentEnd != std::string::npos);
size_t contentLength = lineLength + 1 - contentAfterComment - (lineLength - line.find_last_not_of(" \t" + commentTerminationCharacter));
// If there was no comment, grab whitespace correctly // Lines that have a comment at the *end* of the line aren't considered commented lines
if (whiteSpaceBeforeComment == std::string::npos) { if (hasComment && line.find_first_not_of(" \t") < commentStart) {
whiteSpaceBeforeComment = contentAfterComment; hasComment = false;
} }
if (!addComment) { // Uncomment line
line = line.substr(0, whiteSpaceBeforeComment) if (hasComment && !addComment) {
+ line.substr(contentAfterComment, contentLength); size_t contentStart = line.find_first_not_of(" \t", commentStart + commentCharacter.size());
size_t contentLength = commentEnd - contentStart;
// Trim trailing whitespace
std::string content = line.substr(contentStart, contentLength);
content = content.substr(0, content.find_last_not_of(" \t") + 1);
line = line.substr(0, indentation)
+ content;
} }
else { // Comment line
line = line.substr(0, whiteSpaceBeforeComment) else if (!hasComment && addComment) {
size_t contentStart = line.find_first_not_of(" \t");
size_t contentLength = line.size() - contentStart;
line = line.substr(0, indentation)
+ commentCharacter + ' ' + commentCharacter + ' '
+ line.substr(contentAfterComment, contentLength) + line.substr(contentStart, contentLength)
+ (!commentTerminationCharacter.empty() ? ' ' + commentTerminationCharacter : ""); + (!commentTerminationCharacter.empty() ? ' ' + commentTerminationCharacter : "");
} }
@@ -420,7 +445,7 @@ void Dotfile::selectivelyCommentOrUncomment(const std::string& path)
if (line.find(">>>") != std::string::npos) { if (line.find(">>>") != std::string::npos) {
// Find machine info // Find machine info
size_t find = 0; size_t find = 0;
for (size_t i = 0; i < 3; ++i) { for (size_t i = 0; i < 4; ++i) {
find = line.find(search[i]) + search[i].size(); find = line.find(search[i]) + search[i].size();
if (find < search[i].size()) { if (find < search[i].size()) {
continue; continue;
@@ -435,6 +460,10 @@ void Dotfile::selectivelyCommentOrUncomment(const std::string& path)
if (i > 0 && commentCharacter.at(i - 1) == '/' && commentCharacter.at(i) == '*') { if (i > 0 && commentCharacter.at(i - 1) == '/' && commentCharacter.at(i) == '*') {
commentTerminationCharacter = "*/"; commentTerminationCharacter = "*/";
} }
// Support for <!-- XMl comments -->
if (i > 0 && commentCharacter.at(i - 1) == '<' && commentCharacter.at(i) == '!' && commentCharacter.at(i + 1) == '-' && commentCharacter.at(i + 2) == '-') {
commentTerminationCharacter = "-->";
}
// NOTE: Modification of the string should be at the end of the iteration to prevent 'out of range' errors // NOTE: Modification of the string should be at the end of the iteration to prevent 'out of range' errors
if (commentCharacter.at(i) == ' ' || commentCharacter.at(i) == '\t') { if (commentCharacter.at(i) == ' ' || commentCharacter.at(i) == '\t') {
commentCharacter.erase(i, 1); commentCharacter.erase(i, 1);
@@ -450,6 +479,7 @@ void Dotfile::selectivelyCommentOrUncomment(const std::string& path)
filter[0] = ""; filter[0] = "";
filter[1] = ""; filter[1] = "";
filter[2] = ""; filter[2] = "";
filter[3] = "";
commentCharacter.clear(); commentCharacter.clear();
commentTerminationCharacter.clear(); commentTerminationCharacter.clear();
continue; continue;
@@ -471,6 +501,10 @@ void Dotfile::selectivelyCommentOrUncomment(const std::string& path)
commentOrUncommentLine(line, true); commentOrUncommentLine(line, true);
continue; continue;
} }
else if (filter[3] != Machine::the().session() && !filter[3].empty()) {
commentOrUncommentLine(line, true);
continue;
}
commentOrUncommentLine(line, false); commentOrUncommentLine(line, false);
} }
+86 -2
View File
@@ -1,21 +1,25 @@
/* /*
* Copyright (C) 2022 Riyyi * Copyright (C) 2022,2025 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <cstdint> // int8_t
#include <filesystem> // std::filesystem::path
#include <pwd.h> // getpwnam #include <pwd.h> // getpwnam
#include <sstream> // istringstream #include <sstream> // istringstream
#include <unistd.h> // gethostname, getlogin #include <unistd.h> // gethostname, getlogin
#include "machine.h"
#include "ruc/file.h" #include "ruc/file.h"
#include "machine.h"
Machine::Machine(s) Machine::Machine(s)
{ {
fetchDistro(); fetchDistro();
fetchHostname(); fetchHostname();
fetchUsername(); fetchUsername();
fetchSession();
} }
Machine::~Machine() Machine::~Machine()
@@ -61,3 +65,83 @@ void Machine::fetchUsername()
perror("\033[31;1mError:\033[0m getpwnam"); perror("\033[31;1mError:\033[0m getpwnam");
} }
} }
void Machine::fetchSession()
{
// Determine if this is an Xorg or Wayland session
int8_t likelyWayland = 0;
// Detect via environment variable
const char* env;
env = std::getenv("XDG_SESSION_TYPE");
if (env != nullptr) {
auto session = std::string(env);
if (session == "wayland") {
likelyWayland++;
}
else if (session == "x11") {
likelyWayland--;
}
}
env = std::getenv("WAYLAND_DISPLAY");
if (env != nullptr) {
auto display = std::string(env);
if (display.find("wayland-", 0) == 0) {
likelyWayland++;
}
}
// Detect via Wayland socket
auto socket = std::filesystem::path("/run/user") / std::to_string(uid());
if (std::filesystem::exists(socket) && std::filesystem::is_directory(socket)) {
for (const auto& entry : std::filesystem::directory_iterator(socket)) {
if (entry.path().filename().string().find("wayland-", 0) == 0) {
likelyWayland++;
break;
}
}
}
// Detect via Xorg socket
if (std::filesystem::exists("/tmp/.X11-unix")) {
likelyWayland--;
}
// Detect via running processes, /proc/<id>/comm
std::filesystem::path processes = "/proc";
if (std::filesystem::exists(processes) && std::filesystem::is_directory(processes)) {
for (const auto& entry : std::filesystem::directory_iterator(processes)) {
if (std::filesystem::is_directory(entry)) {
std::filesystem::path comm = entry.path() / "comm";
if (!std::filesystem::exists(comm)) {
continue;
}
// Read the contents of the "comm" file
std::ifstream stream(comm);
std::string command;
std::getline(stream, command);
if (command == "Xwayland" || command == "sway" || command == "hyprland") {
likelyWayland++;
break;
}
if (command == "Xorg" || command == "xinit" || command == "i3" || command == "bspwm") {
likelyWayland--;
break;
}
}
}
}
// If we detected at least 2 ways, we can be fairly certain
m_session = "";
if (likelyWayland <= -2) {
m_session = "xorg";
}
else if (likelyWayland >= 2) {
m_session = "wayland";
}
}
+10 -6
View File
@@ -17,21 +17,25 @@ public:
Machine(s); Machine(s);
virtual ~Machine(); virtual ~Machine();
const std::string& distroId() { return m_distroId; } const std::string& distroId() const { return m_distroId; }
const std::string& distroIdLike() { return m_distroIdLike; } const std::string& distroIdLike() const { return m_distroIdLike; }
const std::string& hostname() { return m_hostname; } const std::string& hostname() const { return m_hostname; }
std::string username() { return m_passwd->pw_name; } std::string username() const { return std::string(m_passwd->pw_name); }
uint32_t uid() { return m_passwd->pw_uid; } uint32_t uid() const { return m_passwd->pw_uid; }
uint32_t gid() { return m_passwd->pw_gid; } uint32_t gid() const { return m_passwd->pw_gid; }
const std::string& session() const { return m_session; }
private: private:
void fetchDistro(); void fetchDistro();
void fetchHostname(); void fetchHostname();
void fetchUsername(); void fetchUsername();
void fetchSession();
std::string m_distroId; std::string m_distroId;
std::string m_distroIdLike; std::string m_distroIdLike;
std::string m_hostname; std::string m_hostname;
std::string m_session;
passwd* m_passwd { nullptr }; passwd* m_passwd { nullptr };
}; };
+14 -16
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2021-2022 Riyyi * Copyright (C) 2021-2022,2025 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
@@ -8,11 +8,12 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "ruc/argparser.h"
#include "ruc/timer.h"
#include "config.h" #include "config.h"
#include "dotfile.h" #include "dotfile.h"
#include "package.h" #include "package.h"
#include "ruc/argparser.h"
#include "ruc/timer.h"
int main(int argc, const char* argv[]) int main(int argc, const char* argv[])
{ {
@@ -23,7 +24,7 @@ int main(int argc, const char* argv[])
bool addOrAur = false; bool addOrAur = false;
bool install = false; bool install = false;
bool pull = false; bool pull = false;
bool pushOrStore = false; bool pushOrSearch = false;
bool verbose = false; bool verbose = false;
std::vector<std::string> targets {}; std::vector<std::string> targets {};
@@ -36,7 +37,7 @@ int main(int argc, const char* argv[])
argParser.addOption(addOrAur, 'a', "add", nullptr, nullptr); argParser.addOption(addOrAur, 'a', "add", nullptr, nullptr);
argParser.addOption(install, 'i', "install", nullptr, nullptr); argParser.addOption(install, 'i', "install", nullptr, nullptr);
argParser.addOption(pull, 'l', "pull", nullptr, nullptr); argParser.addOption(pull, 'l', "pull", nullptr, nullptr);
argParser.addOption(pushOrStore, 's', "push", nullptr, nullptr); argParser.addOption(pushOrSearch, 's', "push", nullptr, nullptr);
argParser.addOption(verbose, 'v', "verbose", nullptr, nullptr); argParser.addOption(verbose, 'v', "verbose", nullptr, nullptr);
argParser.addArgument(targets, "targets", nullptr, nullptr, ruc::ArgParser::Required::No); argParser.addArgument(targets, "targets", nullptr, nullptr, ruc::ArgParser::Required::No);
@@ -60,32 +61,29 @@ int main(int argc, const char* argv[])
if (pull) { if (pull) {
Dotfile::the().pull(targets); Dotfile::the().pull(targets);
} }
if (pushOrStore) { if (pushOrSearch) {
Dotfile::the().push(targets); Dotfile::the().push(targets);
} }
if (!addOrAur && !pull && !pushOrStore) { if (!addOrAur && !pull && !pushOrSearch) {
Dotfile::the().list(targets); Dotfile::the().list(targets);
} }
} }
else if (packageOperation) { else if (packageOperation) {
if (addOrAur) { if (addOrAur) {
Package::the().aurInstall(); Package::the().aurInstall(targets);
} }
if (install) { if (install) {
Package::the().install(); Package::the().install(targets);
} }
if (pushOrStore) { if (!addOrAur && !install) {
Package::the().store(); Package::the().list(targets, pushOrSearch);
}
if (!addOrAur && !install && !pushOrStore) {
Package::the().list(targets);
} }
} }
else if (helpOperation) { else if (helpOperation) {
// TODO open manpage // TODO: open manpage
} }
else { else {
// TODO open manpage // TODO: open manpage
} }
#ifndef NDEBUG #ifndef NDEBUG
+25 -29
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2021-2022 Riyyi * Copyright (C) 2021-2022,2025 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
@@ -14,12 +14,12 @@
#include <string> // getline #include <string> // getline
#include <vector> #include <vector>
#include "machine.h"
#include "package.h"
#include "ruc/file.h"
#include "ruc/shell.h" #include "ruc/shell.h"
#include "ruc/system.h" #include "ruc/system.h"
#include "machine.h"
#include "package.h"
Package::Package(s) Package::Package(s)
{ {
} }
@@ -30,17 +30,27 @@ Package::~Package()
// ----------------------------------------- // -----------------------------------------
void Package::aurInstall() void Package::aurInstall(const std::vector<std::string>& targets)
{ {
installOrAurInstall(InstallType::AurInstall); if (targets.size() > 1) {
fprintf(stderr, "\033[31;1mPackage:\033[0m only 1 file can be read packages from at a time\n");
return;
} }
void Package::install() installOrAurInstall(InstallType::AurInstall, targets.size() != 0 ? targets.front() : PACKAGE_FILE);
{
installOrAurInstall(InstallType::Install);
} }
void Package::list(const std::vector<std::string>& targets) void Package::install(const std::vector<std::string>& targets)
{
if (targets.size() > 1) {
fprintf(stderr, "\033[31;1mPackage:\033[0m only 1 file can be read packages from at a time\n");
return;
}
installOrAurInstall(InstallType::Install, targets.size() != 0 ? targets.front() : PACKAGE_FILE);
}
void Package::list(const std::vector<std::string>& targets, bool partialMatch)
{ {
auto packagesOrEmpty = getPackageList(); auto packagesOrEmpty = getPackageList();
@@ -62,7 +72,7 @@ void Package::list(const std::vector<std::string>& targets)
std::string line; std::string line;
while (std::getline(stream, line)) { while (std::getline(stream, line)) {
for (const auto& target : targets) { for (const auto& target : targets) {
if (line.find(target) != std::string::npos) { if (line == target || (partialMatch && line.find(target) != std::string::npos)) {
packages.append(line + '\n'); packages.append(line + '\n');
break; break;
} }
@@ -72,20 +82,6 @@ void Package::list(const std::vector<std::string>& targets)
printf("%s", packages.c_str()); printf("%s", packages.c_str());
} }
void Package::store()
{
auto packagesOrEmpty = getPackageList();
if (!packagesOrEmpty.has_value()) {
return;
}
auto packageFile = ruc::File::create("./packages");
packageFile.clear();
packageFile.append(packagesOrEmpty.value());
packageFile.flush();
}
// ----------------------------------------- // -----------------------------------------
std::optional<std::string> Package::fetchAurHelper() std::optional<std::string> Package::fetchAurHelper()
@@ -105,7 +101,7 @@ std::optional<std::string> Package::fetchAurHelper()
return {}; return {};
} }
void Package::installOrAurInstall(InstallType type) void Package::installOrAurInstall(InstallType type, const std::string& file)
{ {
distroDetect(); distroDetect();
distroDependencies(); distroDependencies();
@@ -129,12 +125,12 @@ void Package::installOrAurInstall(InstallType type)
ruc::System $; ruc::System $;
if (m_distro == Distro::Arch) { if (m_distro == Distro::Arch) {
// Grab everything off enabled official repositories that is in the list // Grab everything off enabled official repositories that is in the list
auto repoList = $("pacman -Ssq") | $("grep -xf ./packages"); auto repoList = $("pacman -Ssq") | $("grep -xf " + file);
if (type == InstallType::AurInstall) { if (type == InstallType::AurInstall) {
// Determine which packages in the list are from the AUR // Determine which packages in the list are from the AUR
// NOTE: ruc::System does not support commands with newlines // NOTE: ruc::System does not support commands with newlines
auto aurList = ruc::Shell()("grep -vx '" + repoList.output() + "' ./packages"); auto aurList = ruc::Shell()("grep -vx '" + repoList.output() + "' " + file);
command = aurHelper.value() + " -Sy --devel --needed --noconfirm " + aurList.output(); command = aurHelper.value() + " -Sy --devel --needed --noconfirm " + aurList.output();
} }
else { else {
@@ -143,7 +139,7 @@ void Package::installOrAurInstall(InstallType type)
} }
else if (m_distro == Distro::Debian) { else if (m_distro == Distro::Debian) {
// Grab everything off enabled official repositories that is in the list // Grab everything off enabled official repositories that is in the list
auto repoList = $("apt-cache search .").cut(1, ' ') | $("grep -xf ./packages"); auto repoList = $("apt-cache search .").cut(1, ' ') | $("grep -xf " + file);
command = "apt install " + repoList.output(); command = "apt install " + repoList.output();
} }
+7 -6
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2021-2022 Riyyi * Copyright (C) 2021-2022,2025 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
@@ -13,6 +13,8 @@
#include "ruc/singleton.h" #include "ruc/singleton.h"
#define PACKAGE_FILE "./packages"
class Package : public ruc::Singleton<Package> { class Package : public ruc::Singleton<Package> {
public: public:
Package(s); Package(s);
@@ -29,14 +31,13 @@ public:
AurInstall, AurInstall,
}; };
void aurInstall(); void aurInstall(const std::vector<std::string>& targets = {});
void install(); void install(const std::vector<std::string>& targets = {});
void list(const std::vector<std::string>& targets = {}); void list(const std::vector<std::string>& targets = {}, bool partialMatch = false);
void store();
private: private:
std::optional<std::string> fetchAurHelper(); std::optional<std::string> fetchAurHelper();
void installOrAurInstall(InstallType type); void installOrAurInstall(InstallType type, const std::string& file);
bool findDependency(const std::string& search); bool findDependency(const std::string& search);
bool distroDetect(); bool distroDetect();
+77 -5
View File
@@ -1,11 +1,10 @@
/* /*
* Copyright (C) 2022 Riyyi * Copyright (C) 2022,2025 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // uint32_t
#include <cstdio> // stderr #include <cstdio> // stderr
#include <filesystem> // path #include <filesystem> // path
#include <string> #include <string>
@@ -13,12 +12,12 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "ruc/file.h"
#include "config.h" #include "config.h"
#include "dotfile.h" #include "dotfile.h"
#include "machine.h" #include "machine.h"
#include "macro.h" #include "macro.h"
#include "ruc/file.h"
#include "ruc/system.h"
#include "testcase.h" #include "testcase.h"
#include "testsuite.h" #include "testsuite.h"
@@ -503,7 +502,7 @@ TEST_CASE(PushDotfilesWithIgnorePattern)
TEST_CASE(PushDotfilesSelectivelyComment) TEST_CASE(PushDotfilesSelectivelyComment)
{ {
std::vector<std::string> fileNames; std::vector<std::string> fileNames;
for (size_t i = 0; i < 36; ++i) { for (size_t i = 0; i < 44; ++i) {
fileNames.push_back("__test-file-" + std::to_string(i + 1)); fileNames.push_back("__test-file-" + std::to_string(i + 1));
} }
@@ -678,6 +677,43 @@ test data /**/ comment
/* test data /**/ uncomment */ /* test data /**/ uncomment */
/* <<< */ /* <<< */
)", )",
// Comment <!---->
"<!-- >>> distro=" + placeholder + " hostname=" + hostname + " user=" + username + " -->" + R"(
test data <!----> comment
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + placeholder + " user=" + username + " -->" + R"(
test data <!----> comment
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + placeholder + " -->" + R"(
test data <!----> comment
<!-- <<< -->
)",
" <!-- >>> distro=" + placeholder + " hostname=" + hostname + " user=" + username + " -->" + R"(
test data <!----> comment
<!-- <<< -->
)",
// Uncomment <!---->
"<!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + username + " -->" + R"(
<!-- test data <!----> uncomment -->
<!-- <<< -->
)",
" <!-- >>> distro="
+ distro + " hostname=" + hostname + " user=" + username + " -->" + R"(
<!-- test data <!----> uncomment -->
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + username + " -->" + R"(
<!-- test data <!----> uncomment -->
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + username + " -->" + R"(
<!-- test data <!----> uncomment -->
<!-- <<< -->
)",
}; };
std::vector<std::string> pushedFileContents = { std::vector<std::string> pushedFileContents = {
@@ -846,6 +882,42 @@ test data /**/ uncomment
test data /**/ uncomment test data /**/ uncomment
/* <<< */ /* <<< */
)", )",
// Comment <!---->
"<!-- >>> distro=" + placeholder + " hostname=" + hostname + " user=" + username + " -->" + R"(
<!-- test data <!----> comment -->
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + placeholder + " user=" + username + " -->" + R"(
<!-- test data <!----> comment -->
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + placeholder + " -->" + R"(
<!-- test data <!----> comment -->
<!-- <<< -->
)",
" <!-- >>> distro=" + placeholder + " hostname=" + hostname + " user=" + username + " -->" + R"(
<!-- test data <!----> comment -->
<!-- <<< -->
)",
// Uncomment <!---->
"<!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + username + " -->" + R"(
test data <!----> uncomment
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + username + " -->" + R"(
test data <!----> uncomment
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + username + " -->" + R"(
test data <!----> uncomment
<!-- <<< -->
)",
" <!-- >>> distro=" + distro + " hostname=" + hostname + " user=" + username + " -->" + R"(
test data <!----> uncomment
<!-- <<< -->
)",
}; };
createTestDotfiles(fileNames, fileContents); createTestDotfiles(fileNames, fileContents);
Vendored
+1 -1
Submodule vendor/ruc updated: d3de1fb635...243442a3b6