Skip to content

Commit 1a09ff6

Browse files
committed
feat: fundamental
1 parent ca40145 commit 1a09ff6

18 files changed

Lines changed: 555 additions & 0 deletions

File tree

.dockerignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
target/
2+
.git/
3+
.gitignore
4+
Dockerfile
5+
docker-compose.yml

.editorconfig

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# EditorConfig helps developers define and maintain consistent
2+
# coding styles between different editors and IDEs
3+
# editorconfig.org
4+
5+
root = true
6+
7+
[*]
8+
end_of_line = lf
9+
charset = utf-8
10+
trim_trailing_whitespace = true
11+
insert_final_newline = true
12+
indent_style = space
13+
indent_size = 4
14+
15+
[*.rs]
16+
max_line_length = 100
17+
18+
[*.md]
19+
# double whitespace at end of line
20+
# denotes a line break in Markdown
21+
trim_trailing_whitespace = false
22+
23+
[*.yml]
24+
indent_size = 2

.github/workflows/build.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Build & push to Docker Hub
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
branches: ["main"]
8+
workflow_dispatch:
9+
10+
concurrency:
11+
group: "build"
12+
cancel-in-progress: true
13+
14+
env:
15+
CARGO_TERM_COLOR: always
16+
17+
jobs:
18+
build:
19+
name: Build the image
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v5
23+
24+
- name: Get Git SHA
25+
id: git_sha
26+
run: |
27+
echo "full=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@v3
31+
32+
- name: Login to Docker Hub
33+
uses: docker/login-action@v3
34+
with:
35+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
36+
password: ${{ secrets.DOCKER_HUB_TOKEN }}
37+
38+
- name: Build and push
39+
uses: docker/build-push-action@v6
40+
with:
41+
context: .
42+
push: true
43+
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ vars.DOCKER_IMAGE_NAME }}:latest
44+
build-args: |
45+
GIT_COMMIT=${{ steps.git_sha.outputs.full }}

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
*/target
2+
/target
3+
/.vscode
4+
/.idea
5+
/.VSCodeCounter
6+
*/Cargo.lock
7+
/Cargo.lock
8+
.env
9+
10+
*.DS_Store

Cargo.toml

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
[package]
2+
name = "update"
3+
version = "0.2.0"
4+
edition = "2024"
5+
build = "build.rs"
6+
7+
[dependencies]
8+
api-framework = { git = "https://github.com/KessokuTeaTime/api-framework", default-features = false, features = [
9+
"framework",
10+
] }
11+
anyhow = "1.0.98"
12+
axum = "0.8.4"
13+
dotenvy = "0.15.7"
14+
serde = { version = "1.0.219", features = ["derive"] }
15+
tokio = { version = "1.47", features = ["rt-multi-thread", "process"] }
16+
tower-http = { version = "0.6.6", features = ["auth", "trace"] }
17+
tower-layer = "0.3.3"
18+
tracing = "0.1.41"
19+
tracing-subscriber = { version = "0.3.19", features = ["chrono"] }
20+
tracing-appender = "0.2.3"
21+
file-rotate = "0.8.0"
22+
clap = { version = "4.5.44", features = ["cargo"] }
23+
config-file = "0.2.3"
24+
25+
[build-dependencies]
26+
anyhow = "1.0.98"
27+
vergen = { version = "9.0.6", features = ["build", "cargo", "rustc", "si"] }
28+
29+
[workspace.lints.rust]
30+
missing-docs = "warn"
31+
missing-debug-implementations = "warn"
32+
let-underscore-drop = "warn"
33+
single-use-lifetimes = "warn"
34+
trivial-numeric-casts = "warn"
35+
elided-lifetimes-in-paths = "deny"
36+
unused-lifetimes = "forbid"
37+
unused-macro-rules = "warn"
38+
unused-qualifications = "warn"
39+
variant-size-differences = "warn"
40+
dyn-drop = "forbid"
41+
ellipsis-inclusive-range-patterns = "forbid"
42+
exported-private-dependencies = "forbid"
43+
uncommon-codepoints = "deny"
44+
45+
[workspace.lints.clippy]
46+
missing-panics-doc = "warn"
47+
missing-errors-doc = "warn"
48+
cloned-instead-of-copied = "warn"
49+
future-not-send = "warn"
50+
if-not-else = "warn"
51+
if-then-some-else-none = "warn"
52+
impl-trait-in-params = "warn"
53+
macro-use-imports = "deny"
54+
exhaustive-enums = "warn"
55+
str-to-string = "warn"
56+
iter-without-into-iter = "warn"
57+
decimal-literal-representation = "warn"
58+
ref-as-ptr = "warn"
59+
unused-trait-names = "warn"
60+
unnecessary-semicolon = "warn"
61+
unnecessary-debug-formatting = "warn"
62+
too-long-first-doc-paragraph = "warn"
63+
ref-option = "warn"
64+
redundant-test-prefix = "warn"
65+
map-with-unused-argument-over-ranges = "warn"
66+
manual-midpoint = "warn"
67+
manual-is-power-of-two = "warn"
68+
ip-constant = "warn"
69+
elidable-lifetime-names = "warn"
70+
coerce-container-to-any = "warn"
71+
todo = "warn"
72+
inline-always = "warn"
73+
# multiple-crate-versions = "warn"
74+
use-self = "warn"
75+
useless-let-if-seq = "warn"
76+
suboptimal-flops = "warn"
77+
redundant-clone = "warn"
78+
79+
[profile.release]
80+
opt-level = 3
81+
split-debuginfo = "packed"
82+
strip = "symbols"
83+
lto = true
84+
panic = "unwind"
85+
codegen-units = 1
86+
87+
[lints]
88+
workspace = true
89+
90+
[[bin]]
91+
name = "api-update"
92+
path = "src/main.rs"

Dockerfile

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# rust builder
2+
3+
FROM rust:bookworm AS rust_builder
4+
5+
ARG GIT_COMMIT
6+
7+
ENV GIT_COMMIT=$GIT_COMMIT
8+
9+
WORKDIR /app
10+
11+
COPY rust-toolchain.toml ./
12+
RUN rustup toolchain install --profile minimal $(grep "channel" rust-toolchain.toml | cut -d'"' -f2)
13+
14+
COPY . .
15+
RUN cargo build --release
16+
17+
# runtime image
18+
19+
FROM debian:bookworm-slim
20+
21+
WORKDIR /app
22+
23+
COPY --from=rust_builder /app/target/release/api-main .
24+
RUN apt-get update && \
25+
apt-get install -y ca-certificates curl gnupg lsb-release && \
26+
install -m 0755 -d /etc/apt/keyrings && \
27+
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
28+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" \
29+
> /etc/apt/sources.list.d/docker.list && \
30+
apt-get update && \
31+
apt-get install -y docker-ce-cli && \
32+
rm -rf /var/lib/apt/lists/*
33+
34+
# commands
35+
36+
CMD ["./api-main"]

build.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//! Generates static build info.
2+
3+
use std::process::Command;
4+
5+
use anyhow::Error;
6+
use vergen::{BuildBuilder, CargoBuilder, Emitter, RustcBuilder, SysinfoBuilder};
7+
8+
fn main() -> Result<(), Error> {
9+
{
10+
let git_hash = std::env::var("GIT_COMMIT").unwrap_or_else(|_| {
11+
let output = Command::new("git")
12+
.args(["rev-parse", "HEAD"])
13+
.output()
14+
.unwrap();
15+
String::from_utf8(output.stdout).unwrap()
16+
});
17+
println!("cargo:rustc-env=GIT_HASH={}", git_hash.trim());
18+
}
19+
20+
{
21+
let build = BuildBuilder::all_build()?;
22+
let cargo = CargoBuilder::all_cargo()?;
23+
let rustc = RustcBuilder::all_rustc()?;
24+
let si = SysinfoBuilder::all_sysinfo()?;
25+
26+
Emitter::default()
27+
.add_instructions(&build)?
28+
.add_instructions(&cargo)?
29+
.add_instructions(&rustc)?
30+
.add_instructions(&si)?
31+
.emit()?;
32+
}
33+
34+
Ok(())
35+
}

rust-toolchain.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[toolchain]
2+
channel = "stable"
3+
components = ["rustfmt", "clippy"]

rustfmt.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
edition = "2024"
2+
match_arm_leading_pipes = "Preserve"
3+
newline_style = "Unix"
4+
use_field_init_shorthand = true
5+
hard_tabs = false
6+
tab_spaces = 4

src/config/mod.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//! Reads configs.
2+
3+
use std::path::PathBuf;
4+
5+
use serde::Deserialize;
6+
7+
use crate::env::CONFIG_DIR;
8+
9+
/// The available config files.
10+
#[non_exhaustive]
11+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12+
pub enum ConfigFile {
13+
/// The services to update.
14+
Services,
15+
}
16+
17+
impl ConfigFile {
18+
/// The file name of the config file.
19+
pub fn file_name(&self) -> &'static str {
20+
match self {
21+
Self::Services => "services.toml",
22+
}
23+
}
24+
25+
/// The path to the config file, respecting [`CONFIG_DIR`].
26+
pub fn path(&self) -> PathBuf {
27+
CONFIG_DIR.join(self.file_name())
28+
}
29+
}
30+
31+
/// A trait for configs that can be deserialized.
32+
pub trait Config<'de>: Deserialize<'de> {
33+
/// The [`ConfigFile`] this config corresponds to.
34+
fn file() -> ConfigFile;
35+
}
36+
37+
/// The services config.
38+
pub mod services {
39+
use super::*;
40+
41+
/// Defines a service to update.
42+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
43+
pub struct ServiceConfig {
44+
/// An optional name for the service, for easier identification.
45+
pub name: Option<String>,
46+
/// The label of the service.
47+
///
48+
/// This is used to identify the target of update requests. Must be unique among all services.
49+
pub service_label: String,
50+
/// The container name of the service.
51+
///
52+
/// This is used to identify the Docker container to update. Must match the actual container name.
53+
pub container_name: String,
54+
/// The image to update the service from.
55+
pub image: String,
56+
}
57+
58+
/// Defines the services related to updates.
59+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
60+
pub struct ServicesConfig {
61+
/// The list of services to update.
62+
pub services: Vec<ServiceConfig>,
63+
}
64+
65+
impl Config<'_> for ServicesConfig {
66+
fn file() -> ConfigFile {
67+
ConfigFile::Services
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)