Add sqlite for tracking build history.
This commit is contained in:
166
Cargo.lock
generated
166
Cargo.lock
generated
@@ -17,6 +17,21 @@ version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.21"
|
||||
@@ -204,12 +219,34 @@ version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.54"
|
||||
@@ -270,6 +307,12 @@ version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
@@ -405,6 +448,12 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.11.1"
|
||||
@@ -702,6 +751,30 @@ dependencies = [
|
||||
"tokio-io-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "2.1.1"
|
||||
@@ -893,6 +966,7 @@ version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
@@ -1177,7 +1251,7 @@ dependencies = [
|
||||
"libc",
|
||||
"redox_syscall 0.5.18",
|
||||
"smallvec",
|
||||
"windows-link",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1523,6 +1597,12 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.5"
|
||||
@@ -1617,6 +1697,7 @@ checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"either",
|
||||
@@ -1637,8 +1718,11 @@ dependencies = [
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1675,6 +1759,7 @@ dependencies = [
|
||||
"sqlx-postgres",
|
||||
"sqlx-sqlite",
|
||||
"syn 2.0.114",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -1689,6 +1774,7 @@ dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc",
|
||||
"digest",
|
||||
"dotenvy",
|
||||
@@ -1717,6 +1803,7 @@ dependencies = [
|
||||
"stringprep",
|
||||
"thiserror 2.0.18",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
@@ -1730,6 +1817,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.11.0",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"crc",
|
||||
"dotenvy",
|
||||
"etcetera",
|
||||
@@ -1754,6 +1842,7 @@ dependencies = [
|
||||
"stringprep",
|
||||
"thiserror 2.0.18",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
@@ -1764,6 +1853,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"chrono",
|
||||
"flume",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1779,6 +1869,7 @@ dependencies = [
|
||||
"thiserror 2.0.18",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2233,6 +2324,16 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
@@ -2327,12 +2428,71 @@ dependencies = [
|
||||
"wasite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link 0.1.3",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@@ -2366,7 +2526,7 @@ version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2406,7 +2566,7 @@ version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.2.1",
|
||||
"windows_aarch64_gnullvm 0.53.1",
|
||||
"windows_aarch64_msvc 0.53.1",
|
||||
"windows_i686_gnu 0.53.1",
|
||||
|
||||
@@ -15,7 +15,7 @@ opentelemetry-semantic-conventions = { version = "0.12.0", optional = true }
|
||||
serde = { version = "1.0.228", default-features = false, features = ["std", "derive"] }
|
||||
serde_json = { version = "1.0.149", default-features = false, features = ["std"] }
|
||||
sha2 = { version = "0.10.9", default-features = false, features = ["std"] }
|
||||
sqlx = "0.8.6"
|
||||
sqlx = { version = "0.8.6", default-features = false, features = ["runtime-tokio", "sqlite", "migrate", "macros", "uuid", "chrono"] }
|
||||
tokio = { version = "1.49.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util", "process"] }
|
||||
toml = { version = "0.9.11", default-features = false, features = ["display", "parse", "serde", "std"] }
|
||||
tracing = { version = "0.1.37", optional = true }
|
||||
@@ -28,3 +28,7 @@ url = { version = "2.5.8", default-features = false, features = ["std"] }
|
||||
inherits = "release"
|
||||
lto = true
|
||||
strip = "symbols"
|
||||
|
||||
[profile.dev.package.sqlx-macros]
|
||||
# Faster compile-time verified macros
|
||||
opt-level = 3
|
||||
|
||||
48
flake.lock
generated
Normal file
48
flake.lock
generated
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1771008912,
|
||||
"narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a82ccc39b39b621151d6732718e3e250109076fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1771125043,
|
||||
"narHash": "sha256-ldf/s49n6rOAxl7pYLJGGS1N/assoHkCOWdEdLyNZkc=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "4912f951a26dc8142b176be2c2ad834319dc06e8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
66
flake.nix
Normal file
66
flake.nix
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
description = "nix_builder development environment";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
rust-overlay,
|
||||
}:
|
||||
let
|
||||
forAllSystems =
|
||||
func:
|
||||
builtins.listToAttrs (
|
||||
map (system: {
|
||||
name = system;
|
||||
value = func system;
|
||||
}) nixpkgs.lib.systems.flakeExposed
|
||||
);
|
||||
|
||||
in
|
||||
{
|
||||
devShells = forAllSystems (
|
||||
system:
|
||||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
};
|
||||
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
nativeBuildInputs = [
|
||||
pkgs.pkg-config
|
||||
rustToolchain
|
||||
];
|
||||
buildInputs = with pkgs; [
|
||||
sqlx-cli # For sqlx CLI to manage migrations
|
||||
sqlite # To access the database (sqlite is bundled into the nix_builder binary but this is for manually accessing the db).
|
||||
];
|
||||
shellHook = ''
|
||||
cat <<EOF
|
||||
nix_builder dev shell
|
||||
|
||||
Create new migrations with:
|
||||
sqlx migrate add -r <name>
|
||||
|
||||
Generate metadata for query!() macros:
|
||||
cargo sqlx prepare
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
1
migrations/20250708013159_init.down.sql
Normal file
1
migrations/20250708013159_init.down.sql
Normal file
@@ -0,0 +1 @@
|
||||
DROP TABLE build;
|
||||
7
migrations/20250708013159_init.up.sql
Normal file
7
migrations/20250708013159_init.up.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE build (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
start_time INTEGER NOT NULL,
|
||||
end_time INTEGER,
|
||||
status INTEGER,
|
||||
target TEXT NOT NULL
|
||||
) STRICT;
|
||||
@@ -1,18 +1,32 @@
|
||||
use crate::Result;
|
||||
use crate::cli::parameters::BuildArgs;
|
||||
use crate::config::Config;
|
||||
use crate::config::TargetConfig;
|
||||
use crate::error::CustomError;
|
||||
use crate::database::db_handle::DbHandle;
|
||||
use crate::fs_util::assert_directory;
|
||||
use crate::fs_util::is_git_repo;
|
||||
use crate::git_util::git_force_into_state;
|
||||
use crate::git_util::git_init_at_rev;
|
||||
use crate::nix_util::nixos_build_target;
|
||||
|
||||
pub(crate) async fn run_build(args: BuildArgs) -> Result<(), CustomError> {
|
||||
pub(crate) async fn run_build(args: BuildArgs) -> Result<()> {
|
||||
println!("{:?}", args);
|
||||
let config = Config::load_from_file(args.config).await?;
|
||||
println!("{:?}", config);
|
||||
|
||||
let database_path = config.get_database_path()?;
|
||||
let database_parent = database_path
|
||||
.parent()
|
||||
.expect("Database should exist in a folder.");
|
||||
let database_path = database_path.to_string_lossy();
|
||||
assert_directory!(
|
||||
database_parent,
|
||||
"Creating database directory {}",
|
||||
database_parent.to_string_lossy()
|
||||
);
|
||||
|
||||
let db_handle = DbHandle::new(Some(database_path)).await?;
|
||||
|
||||
for target_name in args.target {
|
||||
let target_config = {
|
||||
let target_config = config.get_target_config(&target_name)?;
|
||||
@@ -30,15 +44,12 @@ pub(crate) async fn run_build(args: BuildArgs) -> Result<(), CustomError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn prepare_flake_repo(
|
||||
config_root: &Config,
|
||||
target_config: &TargetConfig,
|
||||
) -> Result<(), CustomError> {
|
||||
async fn prepare_flake_repo(config_root: &Config, target_config: &TargetConfig) -> Result<()> {
|
||||
let repo_directory = target_config.get_repo_directory(config_root)?;
|
||||
assert_directory!(
|
||||
&repo_directory,
|
||||
"Creating repo directory {}",
|
||||
(&repo_directory).to_string_lossy()
|
||||
repo_directory.to_string_lossy()
|
||||
);
|
||||
|
||||
if is_git_repo(&repo_directory).await? {
|
||||
@@ -63,16 +74,13 @@ async fn prepare_flake_repo(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn build_target(
|
||||
config_root: &Config,
|
||||
target_config: &TargetConfig,
|
||||
) -> Result<(), CustomError> {
|
||||
async fn build_target(config_root: &Config, target_config: &TargetConfig) -> Result<()> {
|
||||
let flake_directory = target_config.get_flake_directory(config_root)?;
|
||||
let build_directory = target_config.get_build_directory(config_root)?;
|
||||
assert_directory!(
|
||||
&build_directory,
|
||||
"Creating build directory {}",
|
||||
(&build_directory).to_string_lossy()
|
||||
build_directory.to_string_lossy()
|
||||
);
|
||||
|
||||
nixos_build_target(build_directory, flake_directory, target_config.get_attr()?).await?;
|
||||
|
||||
@@ -73,4 +73,11 @@ impl Config {
|
||||
let work_dir = current_dir.join("work");
|
||||
Ok(Cow::Owned(work_dir))
|
||||
}
|
||||
|
||||
/// The path to the sqlite database where run history is stored.
|
||||
pub(crate) fn get_database_path(&self) -> Result<Cow<'_, Path>, CustomError> {
|
||||
let output_directory = self.get_output_directory()?;
|
||||
let database_path = output_directory.join("nix_builder.sqlite");
|
||||
Ok(Cow::Owned(database_path))
|
||||
}
|
||||
}
|
||||
|
||||
80
src/database/db_handle.rs
Normal file
80
src/database/db_handle.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use sqlx::Executor;
|
||||
use sqlx::Pool;
|
||||
use sqlx::Sqlite;
|
||||
use sqlx::migrate::MigrateDatabase;
|
||||
use sqlx::sqlite::SqlitePoolOptions;
|
||||
use tracing::info;
|
||||
use tracing::warn;
|
||||
|
||||
use super::migration::run_migrations;
|
||||
use crate::Result;
|
||||
|
||||
pub(crate) struct DbHandle {
|
||||
pub(crate) conn: Pool<Sqlite>,
|
||||
}
|
||||
|
||||
impl DbHandle {
|
||||
pub(crate) async fn new<P: AsRef<str>>(db_path: Option<P>) -> Result<DbHandle> {
|
||||
let db_path = db_path.as_ref().map(|p| p.as_ref());
|
||||
let options = SqlitePoolOptions::new()
|
||||
.max_connections(5)
|
||||
.test_before_acquire(true)
|
||||
.after_connect(|conn, _meta| {
|
||||
Box::pin(async move {
|
||||
// Enforce foreign keys.
|
||||
conn.execute("PRAGMA foreign_keys = ON;").await?;
|
||||
// Allows writes at the same time as reads.
|
||||
conn.execute("PRAGMA journal_mode = WAL;").await?;
|
||||
// Do not sync to disk after *every* write.
|
||||
conn.execute("PRAGMA synchronous = NORMAL;").await?;
|
||||
// Keep 10k database pages in memory (~40MiB).
|
||||
conn.execute("PRAGMA cache_size = 10000;").await?;
|
||||
// Stores temporary tables, indexes, and sorting operations in memory.
|
||||
conn.execute("PRAGMA temp_store = MEMORY;").await?;
|
||||
// Use mmap to access database.
|
||||
conn.execute("PRAGMA mmap_size = 268435456;").await?;
|
||||
// Clear space of deleted rows at transaction end.
|
||||
conn.execute("PRAGMA auto_vacuum = FULL;").await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.after_release(|conn, _meta| {
|
||||
Box::pin(async move {
|
||||
// Attempt to optimize the database. (Currently just runs ANALYZE)
|
||||
conn.execute("PRAGMA optimize;").await?;
|
||||
// Rebuild the DB file which defragments and clears out deleted pages.
|
||||
conn.execute("VACUUM;").await?;
|
||||
Ok(true)
|
||||
})
|
||||
});
|
||||
let conn = match db_path {
|
||||
Some(path) => {
|
||||
info!("Connecting to sqlite database at {path}");
|
||||
if !Sqlite::database_exists(path).await.unwrap_or(false) {
|
||||
info!("Creating a new sqlite database at {path}");
|
||||
Sqlite::create_database(path).await.unwrap();
|
||||
} else {
|
||||
info!("Connecting to existing sqlite database at {path}");
|
||||
}
|
||||
let full_url = format!("sqlite:{path}");
|
||||
options.connect(&full_url).await?
|
||||
}
|
||||
None => {
|
||||
warn!("No sqlite_path set in config. Using an in-memory database.");
|
||||
// We force it to a single connection that never dies or else the data and schema in the in-memory DB is lost.
|
||||
options
|
||||
.min_connections(1)
|
||||
.max_connections(1)
|
||||
.idle_timeout(None)
|
||||
.max_lifetime(None)
|
||||
.connect("sqlite::memory:")
|
||||
.await?
|
||||
}
|
||||
};
|
||||
|
||||
run_migrations(&conn).await?;
|
||||
|
||||
Ok(DbHandle { conn })
|
||||
}
|
||||
}
|
||||
15
src/database/migration.rs
Normal file
15
src/database/migration.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use sqlx::Acquire;
|
||||
use sqlx::migrate::Migrate;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
pub(crate) async fn run_migrations<'a, A>(db: A) -> Result<()>
|
||||
where
|
||||
A: Acquire<'a>,
|
||||
<A::Connection as Deref>::Target: Migrate,
|
||||
{
|
||||
sqlx::migrate!("./migrations").run(db).await?;
|
||||
Ok(())
|
||||
}
|
||||
2
src/database/mod.rs
Normal file
2
src/database/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub(crate) mod db_handle;
|
||||
pub(crate) mod migration;
|
||||
@@ -14,6 +14,8 @@ pub(crate) enum CustomError {
|
||||
FromUtf8(#[allow(dead_code)] FromUtf8Error),
|
||||
PathStripPrefix(#[allow(dead_code)] std::path::StripPrefixError),
|
||||
UrlParseError(#[allow(dead_code)] url::ParseError),
|
||||
Migrate(#[allow(dead_code)] sqlx::migrate::MigrateError),
|
||||
Sql(#[allow(dead_code)] sqlx::Error),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for CustomError {
|
||||
@@ -81,3 +83,15 @@ impl From<url::ParseError> for CustomError {
|
||||
CustomError::UrlParseError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::migrate::MigrateError> for CustomError {
|
||||
fn from(value: sqlx::migrate::MigrateError) -> Self {
|
||||
CustomError::Migrate(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for CustomError {
|
||||
fn from(value: sqlx::Error) -> Self {
|
||||
CustomError::Sql(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,7 @@ use crate::error::CustomError;
|
||||
|
||||
pub(crate) async fn is_directory<D: AsRef<Path>>(dir: D) -> Result<bool, CustomError> {
|
||||
let metadata = tokio::fs::metadata(dir).await;
|
||||
let result = match metadata {
|
||||
Ok(metadata) if metadata.is_dir() => true,
|
||||
_ => false,
|
||||
};
|
||||
let result = matches!(metadata, Ok(metadata) if metadata.is_dir());
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ where
|
||||
let dest = AsRef::<OsStr>::as_ref(dest.as_ref());
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["init"]);
|
||||
command.args(["init"]);
|
||||
command.arg(format!("--initial-branch={}", branch.as_ref()));
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
@@ -43,7 +43,7 @@ where
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["remote", "add"]);
|
||||
command.args(["remote", "add"]);
|
||||
command.arg(name);
|
||||
command.arg(url);
|
||||
command.kill_on_drop(true);
|
||||
@@ -78,7 +78,7 @@ where
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["fetch"]);
|
||||
command.args(["fetch"]);
|
||||
if let Some(d) = depth {
|
||||
command.arg(format!("--depth={}", d));
|
||||
}
|
||||
@@ -118,7 +118,7 @@ where
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["checkout"]);
|
||||
command.args(["checkout"]);
|
||||
if force {
|
||||
command.arg("--force");
|
||||
}
|
||||
@@ -149,7 +149,7 @@ where
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["remote", "get-url"]);
|
||||
command.args(["remote", "get-url"]);
|
||||
command.arg(remote.as_ref());
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
@@ -181,7 +181,7 @@ where
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["reset"]);
|
||||
command.args(["reset"]);
|
||||
if hard {
|
||||
command.arg("--hard");
|
||||
}
|
||||
@@ -213,7 +213,7 @@ where
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["clean"]);
|
||||
command.args(["clean"]);
|
||||
if recurse_into_untracked_directories {
|
||||
command.arg("-d");
|
||||
}
|
||||
|
||||
@@ -12,18 +12,21 @@ use self::init_tracing::shutdown_telemetry;
|
||||
mod cli;
|
||||
mod command;
|
||||
mod config;
|
||||
mod database;
|
||||
mod error;
|
||||
mod fs_util;
|
||||
mod git_util;
|
||||
mod init_tracing;
|
||||
mod nix_util;
|
||||
|
||||
fn main() -> Result<ExitCode, CustomError> {
|
||||
pub(crate) type Result<T> = std::result::Result<T, CustomError>;
|
||||
|
||||
fn main() -> Result<ExitCode> {
|
||||
let rt = tokio::runtime::Runtime::new()?;
|
||||
rt.block_on(async { main_body().await })
|
||||
}
|
||||
|
||||
async fn main_body() -> Result<ExitCode, CustomError> {
|
||||
async fn main_body() -> Result<ExitCode> {
|
||||
init_telemetry().expect("Telemetry should initialize successfully.");
|
||||
let args = Cli::parse();
|
||||
match args.command {
|
||||
|
||||
@@ -29,7 +29,7 @@ where
|
||||
// nixos-rebuild build --show-trace --sudo --max-jobs "$JOBS" --flake "$DIR/../../#odo" --log-format internal-json -v "${@}"
|
||||
let mut command = Command::new("nixos-rebuild");
|
||||
command.current_dir(build_path);
|
||||
command.args(&[
|
||||
command.args([
|
||||
"build",
|
||||
"--show-trace",
|
||||
"--sudo",
|
||||
|
||||
Reference in New Issue
Block a user