bare bones calibre db reading
This commit is contained in:
commit
65e17fc55b
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
result
|
208
Cargo.lock
generated
Normal file
208
Cargo.lock
generated
Normal file
@ -0,0 +1,208 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "calibre-db"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rusqlite",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
5
Cargo.toml
Normal file
5
Cargo.toml
Normal file
@ -0,0 +1,5 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"calibre-db",
|
||||
]
|
8
calibre-db/Cargo.toml
Normal file
8
calibre-db/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "calibre-db"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rusqlite = { version = "0.31.0", features = ["bundled"] }
|
||||
thiserror = "1.0.59"
|
94
calibre-db/src/calibre.rs
Normal file
94
calibre-db/src/calibre.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use rusqlite::Connection;
|
||||
|
||||
use crate::data::{author::Author, book::Book, error::DataStoreError, pagination::SortOrder};
|
||||
|
||||
pub struct Calibre {
|
||||
conn: Connection,
|
||||
}
|
||||
|
||||
impl Calibre {
|
||||
pub fn load(url: &str) -> Result<Self, DataStoreError> {
|
||||
let conn = Connection::open(url)?;
|
||||
Ok(Self { conn })
|
||||
}
|
||||
|
||||
pub fn books(
|
||||
&self,
|
||||
limit: u64,
|
||||
cursor: Option<&str>,
|
||||
sort_order: SortOrder,
|
||||
) -> Result<Vec<Book>, DataStoreError> {
|
||||
Book::books(&self.conn, limit, cursor, sort_order)
|
||||
}
|
||||
|
||||
pub fn authors(
|
||||
&self,
|
||||
limit: u64,
|
||||
cursor: Option<&str>,
|
||||
sort_order: SortOrder,
|
||||
) -> Result<Vec<Author>, DataStoreError> {
|
||||
Author::authors(&self.conn, limit, cursor, sort_order)
|
||||
}
|
||||
|
||||
pub fn author_books(
|
||||
&self,
|
||||
author_id: u64,
|
||||
limit: u64,
|
||||
cursor: Option<&str>,
|
||||
sort_order: SortOrder,
|
||||
) -> Result<Vec<Book>, DataStoreError> {
|
||||
Book::author_books(&self.conn, author_id, limit, cursor, sort_order)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn books() {
|
||||
let c = Calibre::load("./testdata/metadata.db").unwrap();
|
||||
let books = c.books(10, None, SortOrder::ASC).unwrap();
|
||||
assert_eq!(books.len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn authors() {
|
||||
let c = Calibre::load("./testdata/metadata.db").unwrap();
|
||||
let authors = c.authors(10, None, SortOrder::ASC).unwrap();
|
||||
assert_eq!(authors.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn author_books() {
|
||||
let c = Calibre::load("./testdata/metadata.db").unwrap();
|
||||
let books = c.author_books(1, 10, None, SortOrder::ASC).unwrap();
|
||||
assert_eq!(books.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pagination() {
|
||||
let c = Calibre::load("./testdata/metadata.db").unwrap();
|
||||
let authors = c.authors(1, None, SortOrder::ASC).unwrap();
|
||||
assert_eq!(authors.len(), 1);
|
||||
assert_eq!(authors[0].name, "Kevin R. Grazier");
|
||||
|
||||
let authors = c
|
||||
.authors(1, Some(&authors[0].sort), SortOrder::ASC)
|
||||
.unwrap();
|
||||
assert_eq!(authors.len(), 1);
|
||||
assert_eq!(authors[0].name, "Terry Pratchett");
|
||||
|
||||
let authors = c
|
||||
.authors(1, Some(&authors[0].sort), SortOrder::ASC)
|
||||
.unwrap();
|
||||
assert_eq!(authors.len(), 1);
|
||||
assert_eq!(authors[0].name, "Edward Noyes Westcott");
|
||||
|
||||
let authors = c
|
||||
.authors(1, Some(&authors[0].sort), SortOrder::DESC)
|
||||
.unwrap();
|
||||
assert_eq!(authors.len(), 1);
|
||||
assert_eq!(authors[0].name, "Terry Pratchett");
|
||||
}
|
||||
}
|
38
calibre-db/src/data/author.rs
Normal file
38
calibre-db/src/data/author.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use rusqlite::{Connection, Row};
|
||||
|
||||
use super::{
|
||||
error::DataStoreError,
|
||||
pagination::{Pagination, SortOrder},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Author {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub sort: String,
|
||||
}
|
||||
|
||||
impl Author {
|
||||
fn from_row(row: &Row<'_>) -> Result<Self, rusqlite::Error> {
|
||||
Ok(Self {
|
||||
id: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
sort: row.get(2)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn authors(
|
||||
conn: &Connection,
|
||||
limit: u64,
|
||||
cursor: Option<&str>,
|
||||
sort_order: SortOrder,
|
||||
) -> Result<Vec<Author>, DataStoreError> {
|
||||
let pagination = Pagination::new("sort", cursor, limit, sort_order);
|
||||
pagination.paginate(
|
||||
conn,
|
||||
"SELECT id, name, sort FROM authors",
|
||||
&[],
|
||||
Self::from_row,
|
||||
)
|
||||
}
|
||||
}
|
56
calibre-db/src/data/book.rs
Normal file
56
calibre-db/src/data/book.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use rusqlite::{Connection, Row};
|
||||
|
||||
use super::{
|
||||
error::DataStoreError,
|
||||
pagination::{Pagination, SortOrder},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Book {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
pub sort: String,
|
||||
}
|
||||
|
||||
impl Book {
|
||||
fn from_row(row: &Row<'_>) -> Result<Self, rusqlite::Error> {
|
||||
Ok(Self {
|
||||
id: row.get(0)?,
|
||||
title: row.get(1)?,
|
||||
sort: row.get(2)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn books(
|
||||
conn: &Connection,
|
||||
limit: u64,
|
||||
cursor: Option<&str>,
|
||||
sort_order: SortOrder,
|
||||
) -> Result<Vec<Book>, DataStoreError> {
|
||||
let pagination = Pagination::new("sort", cursor, limit, sort_order);
|
||||
pagination.paginate(
|
||||
conn,
|
||||
"SELECT id, title, sort FROM books",
|
||||
&[],
|
||||
Self::from_row,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn author_books(
|
||||
conn: &Connection,
|
||||
author_id: u64,
|
||||
limit: u64,
|
||||
cursor: Option<&str>,
|
||||
sort_order: SortOrder,
|
||||
) -> Result<Vec<Book>, DataStoreError> {
|
||||
let pagination = Pagination::new("books.sort", cursor, limit, sort_order);
|
||||
pagination.paginate(
|
||||
conn,
|
||||
"SELECT books.id, books.title, books.sort FROM books \
|
||||
INNER JOIN books_authors_link ON books.id = books_authors_link.book \
|
||||
WHERE books_authors_link.author = (:author_id) AND",
|
||||
&[(":author_id", &author_id)],
|
||||
Self::from_row,
|
||||
)
|
||||
}
|
||||
}
|
7
calibre-db/src/data/error.rs
Normal file
7
calibre-db/src/data/error.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DataStoreError {
|
||||
#[error("sqlite error")]
|
||||
SqliteError(#[from] rusqlite::Error),
|
||||
}
|
72
calibre-db/src/data/pagination.rs
Normal file
72
calibre-db/src/data/pagination.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use rusqlite::{Connection, Row, ToSql};
|
||||
|
||||
use super::error::DataStoreError;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SortOrder {
|
||||
ASC,
|
||||
DESC,
|
||||
}
|
||||
|
||||
pub struct Pagination<'a> {
|
||||
pub sort_col: &'a str,
|
||||
pub limit: u64,
|
||||
pub cursor: Option<&'a str>,
|
||||
pub sort_order: SortOrder,
|
||||
}
|
||||
|
||||
impl<'a> Pagination<'a> {
|
||||
pub fn new(
|
||||
sort_col: &'a str,
|
||||
cursor: Option<&'a str>,
|
||||
limit: u64,
|
||||
sort_order: SortOrder,
|
||||
) -> Self {
|
||||
Self {
|
||||
sort_col,
|
||||
limit,
|
||||
cursor,
|
||||
sort_order,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paginate<T, F>(
|
||||
&self,
|
||||
conn: &Connection,
|
||||
statement: &str,
|
||||
params: &[(&str, &dyn ToSql)],
|
||||
processor: F,
|
||||
) -> Result<Vec<T>, DataStoreError>
|
||||
where
|
||||
F: FnMut(&Row<'_>) -> Result<T, rusqlite::Error>,
|
||||
{
|
||||
let cursor = self.cursor.unwrap_or("");
|
||||
let comparison = if self.sort_order == SortOrder::ASC {
|
||||
">"
|
||||
} else {
|
||||
"<"
|
||||
};
|
||||
let where_sql = if statement.ends_with("AND") {
|
||||
""
|
||||
} else {
|
||||
"WHERE"
|
||||
};
|
||||
|
||||
let sort_col = self.sort_col;
|
||||
let sort_order = &self.sort_order;
|
||||
// DANGER: vulnerable to SQL injection if statement or sort_col variable is influenced by user input
|
||||
let mut stmt = conn.prepare(&format!(
|
||||
"{statement} {where_sql} {sort_col} {comparison} (:cursor) ORDER BY {sort_col} {sort_order:?} LIMIT (:limit)"
|
||||
))?;
|
||||
let params = [
|
||||
&[
|
||||
(":cursor", &cursor as &dyn ToSql),
|
||||
(":limit", &self.limit as &dyn ToSql),
|
||||
],
|
||||
params,
|
||||
]
|
||||
.concat();
|
||||
let iter = stmt.query_map(params.as_slice(), processor)?;
|
||||
Ok(iter.filter_map(Result::ok).collect())
|
||||
}
|
||||
}
|
7
calibre-db/src/lib.rs
Normal file
7
calibre-db/src/lib.rs
Normal file
@ -0,0 +1,7 @@
|
||||
pub mod calibre;
|
||||
pub mod data {
|
||||
pub mod author;
|
||||
pub mod book;
|
||||
pub mod error;
|
||||
pub mod pagination;
|
||||
}
|
BIN
calibre-db/testdata/metadata.db
vendored
Normal file
BIN
calibre-db/testdata/metadata.db
vendored
Normal file
Binary file not shown.
145
flake.lock
Normal file
145
flake.lock
Normal file
@ -0,0 +1,145 @@
|
||||
{
|
||||
"nodes": {
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1714544767,
|
||||
"narHash": "sha256-kF1bX+YFMedf1g0PAJYwGUkzh22JmULtj8Rm4IXAQKs=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "73124e1356bde9411b163d636b39fe4804b7ca45",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"naersk": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1713520724,
|
||||
"narHash": "sha256-CO8MmVDmqZX2FovL75pu5BvwhW+Vugc7Q6ze7Hj8heI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "c5037590290c6c7dae2e42e7da1e247e54ed2d49",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1714253743,
|
||||
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 0,
|
||||
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
|
||||
"path": "/nix/store/801l7gvdz7yaibhjsxqx82sc7zkakjbq-source",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1714253743,
|
||||
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"naersk": "naersk",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1714501997,
|
||||
"narHash": "sha256-g31zfxwUFzkPgX0Q8sZLcrqGmOxwjEZ/iqJjNx4fEGo=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "49e502b277a8126a9ad10c802d1aaa3ef1a280ef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
148
flake.nix
Normal file
148
flake.nix
Normal file
@ -0,0 +1,148 @@
|
||||
{
|
||||
description = "rusty-cops project";
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
naersk.url = "github:nix-community/naersk";
|
||||
fenix.url = "github:nix-community/fenix";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
naersk,
|
||||
fenix,
|
||||
flake-utils,
|
||||
...
|
||||
}:
|
||||
let
|
||||
buildTargets = {
|
||||
"x86_64-linux" = {
|
||||
crossSystemConfig = "x86_64-unknown-linux-musl";
|
||||
rustTarget = "x86_64-unknown-linux-musl";
|
||||
};
|
||||
|
||||
"i686-linux" = {
|
||||
crossSystemConfig = "i686-unknown-linux-musl";
|
||||
rustTarget = "i686-unknown-linux-musl";
|
||||
};
|
||||
|
||||
"aarch64-linux" = {
|
||||
crossSystemConfig = "aarch64-unknown-linux-musl";
|
||||
rustTarget = "aarch64-unknown-linux-musl";
|
||||
};
|
||||
|
||||
"armv6l-linux" = {
|
||||
crossSystemConfig = "armv6l-unknown-linux-musleabihf";
|
||||
rustTarget = "arm-unknown-linux-musleabihf";
|
||||
};
|
||||
};
|
||||
|
||||
eachSystem =
|
||||
supportedSystems: callback:
|
||||
builtins.foldl' (overall: system: overall // { ${system} = callback system; }) { } supportedSystems;
|
||||
|
||||
eachCrossSystem =
|
||||
supportedSystems: callback:
|
||||
eachSystem supportedSystems (
|
||||
buildSystem:
|
||||
builtins.foldl' (
|
||||
inner: targetSystem: inner // { "cross-${targetSystem}" = callback buildSystem targetSystem; }
|
||||
) { default = callback buildSystem buildSystem; } supportedSystems
|
||||
);
|
||||
|
||||
mkPkgs =
|
||||
buildSystem: targetSystem:
|
||||
import nixpkgs (
|
||||
{
|
||||
system = buildSystem;
|
||||
}
|
||||
// (
|
||||
if targetSystem == null then
|
||||
{ }
|
||||
else
|
||||
{ crossSystem.config = buildTargets.${targetSystem}.crossSystemConfig; }
|
||||
)
|
||||
);
|
||||
in
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
rust = fenix.packages.${system}.stable;
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
devShells.default = mkShell {
|
||||
buildInputs = [
|
||||
mosquitto
|
||||
rust.toolchain
|
||||
rust-analyzer
|
||||
sea-orm-cli
|
||||
];
|
||||
};
|
||||
}
|
||||
)
|
||||
// {
|
||||
packages = eachCrossSystem (builtins.attrNames buildTargets) (
|
||||
buildSystem: targetSystem:
|
||||
let
|
||||
pkgs = mkPkgs buildSystem null;
|
||||
pkgsCross = mkPkgs buildSystem targetSystem;
|
||||
rustTarget = buildTargets.${targetSystem}.rustTarget;
|
||||
|
||||
fenixPkgs = fenix.packages.${buildSystem};
|
||||
|
||||
mkToolchain = fenixPkgs: fenixPkgs.stable;
|
||||
|
||||
toolchain = fenixPkgs.combine [
|
||||
(mkToolchain fenixPkgs).rustc
|
||||
(mkToolchain fenixPkgs).cargo
|
||||
(mkToolchain fenixPkgs.targets.${rustTarget}).rust-std
|
||||
];
|
||||
|
||||
buildPackageAttrs =
|
||||
if builtins.hasAttr "makeBuildPackageAttrs" buildTargets.${targetSystem} then
|
||||
buildTargets.${targetSystem}.makeBuildPackageAttrs pkgsCross
|
||||
else
|
||||
{ };
|
||||
|
||||
naersk-lib = pkgs.callPackage naersk {
|
||||
cargo = toolchain;
|
||||
rustc = toolchain;
|
||||
};
|
||||
in
|
||||
naersk-lib.buildPackage (
|
||||
buildPackageAttrs
|
||||
// rec {
|
||||
src = ./.;
|
||||
strictDeps = true;
|
||||
doCheck = false;
|
||||
|
||||
OPENSSL_STATIC = "1";
|
||||
OPENSSL_LIB_DIR = "${pkgsCross.pkgsStatic.openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${pkgsCross.pkgsStatic.openssl.dev}/include";
|
||||
|
||||
# Required because ring crate is special. This also seems to have
|
||||
# fixed some issues with the x86_64-windows cross-compile :shrug:
|
||||
TARGET_CC = "${pkgsCross.stdenv.cc}/bin/${pkgsCross.stdenv.cc.targetPrefix}cc";
|
||||
|
||||
CARGO_BUILD_TARGET = rustTarget;
|
||||
CARGO_BUILD_RUSTFLAGS = [
|
||||
"-C"
|
||||
"target-feature=+crt-static"
|
||||
|
||||
# -latomic is required to build openssl-sys for armv6l-linux, but
|
||||
# it doesn't seem to hurt any other builds.
|
||||
# "-C"
|
||||
# "link-args=-static -latomic"
|
||||
|
||||
"-C"
|
||||
"linker=${TARGET_CC}"
|
||||
];
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user