Initial project sketch

This commit is contained in:
TennesseeTrash 2025-12-20 06:37:29 +01:00
commit cdfbcf4f61
15 changed files with 246 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.cache/
build/

13
CMake/cpr.cmake Normal file
View file

@ -0,0 +1,13 @@
include(FetchContent)
FetchContent_Declare(
cpr
GIT_REPOSITORY ssh://git@code.3011.io/Mirrors/cpr.git
GIT_TAG 1.14.1
)
set(BUILD_SHARED_LIBS OFF)
FetchContent_MakeAvailable(
cpr
)

11
CMake/libprocess.cmake Normal file
View file

@ -0,0 +1,11 @@
include(FetchContent)
FetchContent_Declare(
libcbor
GIT_REPOSITORY ssh://git@code.3011.io/TennesseeTrash/LibProcess.git
GIT_TAG v0.0.1
)
FetchContent_MakeAvailable(
libcbor
)

7
CMakeLists.txt Normal file
View file

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.25)
project(Toolchain
LANGUAGES CXX
)
add_subdirectory(Toolchain)

29
Toolchain/CMakeLists.txt Normal file
View file

@ -0,0 +1,29 @@
include(${PROJECT_SOURCE_DIR}/CMake/cpr.cmake)
include(${PROJECT_SOURCE_DIR}/CMake/libprocess.cmake)
add_executable(Toolchain)
target_compile_features(Toolchain
PRIVATE
cxx_std_23
)
target_include_directories(Toolchain
PRIVATE
"Include"
)
target_link_libraries(Toolchain
PRIVATE
"cpr::cpr"
"LibProcess"
)
target_sources(Toolchain
PRIVATE
"Main.cpp"
"Source/Command.cpp"
"Source/Download.cpp"
"Source/Package.cpp"
"Source/Unpack.cpp"
)

View file

View file

@ -0,0 +1,12 @@
#ifndef TOOLCHAIN_COMMON_HPP
#define TOOLCHAIN_COMMON_HPP
#include <filesystem> // IWYU pragma: export
namespace Toolchain
{
// NOLINTNEXTLINE: We're defining this to make life easier.
namespace fs = std::filesystem;
}
#endif // TOOLCHAIN_COMMON_HPP

View file

@ -0,0 +1,11 @@
#ifndef TOOLCHAIN_DOWNLOAD_HPP
#define TOOLCHAIN_DOWNLOAD_HPP
#include "Common.hpp"
namespace Toolchain
{
bool DownloadFile(const fs::path &path, std::string_view url);
}
#endif // TOOLCHAIN_DOWNLOAD_HPP

View file

@ -0,0 +1,34 @@
#ifndef TOOLCHAIN_PACKAGE_HPP
#define TOOLCHAIN_PACKAGE_HPP
namespace Toolchain
{
// The package should have a name, version, source url, and it should describe
// the series of steps necessary to take to properly build and install the package
// into the final destination.
// There are some things that are still to be decided. Should there be a set of abstractions
// to deal with common build systems, and package installation steps? How should a potential
// escape hatch work for this?
// The package download and extraction should be identical for every single package.
// Afterwards, the process should be split up into three separate stages, the configuration,
// the build, and the installation. Every single step should be as isolated from the host system
// as possible, to prevent dirtying the result with dependencies on system libraries or binaries.
// All the package sets should be split into three stages. Stage0 should be used to bootstrap
// a suitable compiler for maximum compatibility and cross compilation.
// Stage1 should be a full toolchain independent from the host system, including most packages.
// Finally, stage2 should produce three full toolchains, cross compiled for all target systems.
// Initially, the scope should be to stop at stage1, it should be good enough to get started
// with all the other projects. It will still require system dependencies for certain bits, but
// that doesn't matter too much, as long as the host has a reasonably complete package registry.
class Package
{
};
}
#endif // TOOLCHAIN_PACKAGE_HPP

View file

@ -0,0 +1,11 @@
#ifndef TOOLCHAIN_UNPACK_HPP
#define TOOLCHAIN_UNPACK_HPP
#include "Common.hpp"
namespace Toolchain
{
bool UnpackArchive(const fs::path &sourceArchive, const fs::path &destinationDirectory);
}
#endif // TOOLCHAIN_UNPACK_HPP

12
Toolchain/Main.cpp Normal file
View file

@ -0,0 +1,12 @@
#include "Download.hpp"
#include <print>
int main()
{
std::println("Hello World!");
if (!Toolchain::DownloadFile("index.html", "https://3011.io/")) {
std::println("Unlucky");
}
}

View file

View file

@ -0,0 +1,65 @@
#include "Download.hpp"
#include <cpr/cpr.h>
#include <print>
namespace
{
struct CursorGuard
{
public:
CursorGuard()
{
std::print("\033[?25l");
}
~CursorGuard()
{
std::print("\033[?25h");
}
};
}
namespace Toolchain
{
bool DownloadFile(const fs::path &path, std::string_view url)
{
using offset_t = cpr::cpr_off_t;
std::ofstream file(path, std::ios::binary);
if (!file) {
return false;
}
CursorGuard guard;
cpr::Response response = cpr::Get(
cpr::Url(url),
cpr::WriteCallback(
[&file] (std::string_view data, std::intptr_t) {
file.write(data.data(), data.size());
return true;
}
),
cpr::ProgressCallback(
[path] (offset_t dt, offset_t dp, offset_t ut, offset_t up, std::intptr_t) {
double progress = double(dp) / double(dt);
std::print("\rDownloading {}: {:.2f}% ({}/{})",
path.c_str(), progress * 100, dp, dt);
return true;
}
)
);
std::println();
if (response.status_code != 200) {
std::println("Download failed with status: {}, {}",
response.status_code, response.status_line);
return false;
}
file.close();
return true;
}
}

View file

@ -0,0 +1,6 @@
#include "Package.hpp"
namespace Toolchain
{
}

View file

@ -0,0 +1,33 @@
#include "Unpack.hpp"
#include <Process/Process.hpp>
namespace Toolchain
{
bool UnpackArchive(const fs::path &sourceArchive, const fs::path &destinationDirectory)
{
// Select the command based on the file extension
// Extract the archive into a temporary directory
// Check how many items were extracted (non-recursively, we only care about the top level)
// If there was only one item, and it's a directory, it should be moved (and renamed)
// to the destination. In case it's a file, the destination should be created, and the
// file moved there.
// If there are multiple items, the destination will be created, and all items moved into
// the destination.
// Error handling and cleanup should be done so the temporary directory is always
// kept clean in case the program tries to use it for other stuff.
// The reasoning behind this sort of behaviour is that the whole thing should always be as
// consistent as possible, we want everything to be as consistent as possible, and easy to
// work with afterwards. The point is that for the most part, the structure is know, so
// it is easy to proceed, and otherwise it should be easy to analyze the contents
// programatically.
return false;
}
}