mirror of
https://github.com/Lumither/nocturne.git
synced 2026-10-17 10:26:21 +00:00
feat(backend) update (unfinished)
This commit is contained in:
20 files changed
+131
-317
No files matched your search
@@ -9,7 +9,8 @@ fn main() {
|
|||||||
.peel_to_commit()
|
.peel_to_commit()
|
||||||
.expect("failed to get HEAD commit");
|
.expect("failed to get HEAD commit");
|
||||||
let hash = commit.id().to_string();
|
let hash = commit.id().to_string();
|
||||||
let utc_date = Utc::now().date_naive().format("%Y%m%d").to_string();
|
let utc_timestamp = Utc::now().date_naive().format("%Y%m%d").to_string();
|
||||||
let build_id = format!("{}@{}", utc_date, &hash[..8]);
|
let pkg_version = env!("CARGO_PKG_VERSION");
|
||||||
|
let build_id = format!("{}:{}@{}", pkg_version, &hash[..8], utc_timestamp);
|
||||||
println!("cargo:rustc-env=BUILD_ID={}", build_id);
|
println!("cargo:rustc-env=BUILD_ID={}", build_id);
|
||||||
}
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
CREATE TABLE tag
|
|
||||||
(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
name VARCHAR(20) UNIQUE NOT NULL,
|
|
||||||
description TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE category
|
|
||||||
(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
name VARCHAR(20) UNIQUE NOT NULL,
|
|
||||||
description TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE post
|
|
||||||
(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
identifier VARCHAR(50) UNIQUE NOT NULL,
|
|
||||||
title VARCHAR(255) NOT NULL,
|
|
||||||
subtitle VARCHAR(255) NOT NULL,
|
|
||||||
published_date DATE NOT NULL,
|
|
||||||
last_update DATE,
|
|
||||||
content TEXT NOT NULL,
|
|
||||||
|
|
||||||
category SERIAL REFERENCES category (id) NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE post_tag
|
|
||||||
(
|
|
||||||
post SERIAL REFERENCES post (id),
|
|
||||||
tag SERIAL REFERENCES tag (id)
|
|
||||||
)
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
mod database;
|
mod database;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod schema;
|
|
||||||
|
|
||||||
use std::{env, panic};
|
use std::{env, panic};
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
use sqlx::{query, Pool, Postgres};
|
|
||||||
use tracing::info;
|
|
||||||
//
|
|
||||||
// const POST_BASE_MODEL: &str = r##"
|
|
||||||
// CREATE TABLE IF NOT EXISTS Post
|
|
||||||
// (
|
|
||||||
// post_id UUID PRIMARY KEY,
|
|
||||||
// title VARCHAR(255) NOT NULL,
|
|
||||||
// category VARCHAR(255) NOT NULL,
|
|
||||||
// filename TEXT UNIQUE NOT NULL,
|
|
||||||
// summary TEXT,
|
|
||||||
// sub_title TEXT,
|
|
||||||
// content TEXT NOT NULL,
|
|
||||||
// last_update TIMESTAMPTZ,
|
|
||||||
// first_update TIMESTAMPTZ NOT NULL
|
|
||||||
// );
|
|
||||||
// "##;
|
|
||||||
//
|
|
||||||
// // base model, will add more cols at runtime
|
|
||||||
// const POST_META_MODEL: &str = r##"
|
|
||||||
// CREATE TABLE IF NOT EXISTS Meta
|
|
||||||
// (
|
|
||||||
// post_id UUID PRIMARY KEY
|
|
||||||
// );
|
|
||||||
// "##;
|
|
||||||
//
|
|
||||||
// const POST_HASH_MODEL: &str = r##"
|
|
||||||
// CREATE TABLE IF NOT EXISTS Hash
|
|
||||||
// (
|
|
||||||
// post_id UUID PRIMARY KEY,
|
|
||||||
// hash VARCHAR(44)
|
|
||||||
// );
|
|
||||||
// "##;
|
|
||||||
//
|
|
||||||
// const TAG_MODEL: &str = r##"
|
|
||||||
// CREATE TABLE IF NOT EXISTS Tag
|
|
||||||
// (
|
|
||||||
// post_id UUID NOT NULL,
|
|
||||||
// tag VARCHAR(255) NOT NULL
|
|
||||||
// );
|
|
||||||
// "##;
|
|
||||||
|
|
||||||
pub async fn init(db_connection: &Pool<Postgres>) {
|
|
||||||
// query(POST_BASE_MODEL).execute(db_connection).await.unwrap();
|
|
||||||
// query(POST_META_MODEL).execute(db_connection).await.unwrap();
|
|
||||||
// query(TAG_MODEL).execute(db_connection).await.unwrap();
|
|
||||||
// query(POST_HASH_MODEL).execute(db_connection).await.unwrap();
|
|
||||||
info!("database schema initialized");
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
|
#[allow(dead_code)]
|
||||||
mod constants;
|
mod constants;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod scheduler;
|
||||||
|
|
||||||
mod init;
|
mod init;
|
||||||
mod modules;
|
mod modules;
|
||||||
mod scheduler;
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use crate::init::{logger, start};
|
use crate::init::{logger, start};
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
use crate::constants::blog::PAGE_SIZE;
|
|
||||||
|
|
||||||
use axum::extract::State;
|
|
||||||
use axum::Json;
|
|
||||||
use serde_json::{json, Value};
|
|
||||||
use sqlx::{query, PgPool, Row};
|
|
||||||
use tracing::error;
|
|
||||||
|
|
||||||
pub async fn get_page_count(
|
|
||||||
State(db_connection): State<PgPool>,
|
|
||||||
) -> Result<Json<Value>, Json<Value>> {
|
|
||||||
match query("select cast(ceil(count(*) / $1) as integer) as res from post")
|
|
||||||
.bind(PAGE_SIZE as f32)
|
|
||||||
.fetch_one(&db_connection)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(res) => {
|
|
||||||
let res: i32 = res.get("res");
|
|
||||||
Ok(Json::from(json!({"res": res})))
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// todo: rename
|
|
||||||
error!("Failed to get blog page count: {}", e.to_string());
|
|
||||||
Err(Json::from(json!({"error": e.to_string()})))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
use crate::constants::blog::PAGE_SIZE;
|
||||||
|
|
||||||
|
use axum::{extract::State, Json};
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
use sqlx::{query, PgPool, Row};
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
const GET_PAGE_COUNT_QUERY: &str = include_str!("post_page_count.sql");
|
||||||
|
|
||||||
|
pub async fn handler(State(db_connection): State<PgPool>) -> Result<Json<Value>, Json<Value>> {
|
||||||
|
match query(GET_PAGE_COUNT_QUERY)
|
||||||
|
.bind(PAGE_SIZE as i64)
|
||||||
|
.fetch_one(&db_connection)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(res) => {
|
||||||
|
let res: i32 = res.get("count");
|
||||||
|
Ok(Json::from(json!({"res": res})))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to get blog page count: {}", e.to_string());
|
||||||
|
Err(Json::from(json!({"error": e.to_string()})))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
SELECT cast(ceil(count(*) / cast($1 AS FLOAT)) AS INTEGER) AS count
|
||||||
|
FROM posts;
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
use axum::{
|
|
||||||
extract::{Path, State},
|
|
||||||
http::StatusCode,
|
|
||||||
Json,
|
|
||||||
};
|
|
||||||
use serde_json::{json, Value};
|
|
||||||
use sqlx::{query, Error, PgPool, Row};
|
|
||||||
use std::str::FromStr;
|
|
||||||
use tracing::error;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
pub async fn get_post(
|
|
||||||
State(db_connection): State<PgPool>,
|
|
||||||
Path(post_id): Path<String>,
|
|
||||||
) -> Result<Json<Value>, (StatusCode, Json<Value>)> {
|
|
||||||
let post_id = match Uuid::from_str(post_id.as_str()) {
|
|
||||||
Ok(id) => id,
|
|
||||||
Err(e) => {
|
|
||||||
error!(
|
|
||||||
"Failed to parse UUID <{}>: {}",
|
|
||||||
post_id.as_str(),
|
|
||||||
e.to_string()
|
|
||||||
);
|
|
||||||
return Err((
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
Json::from(json!(("error", e.to_string()))),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let post = match query(
|
|
||||||
r#"
|
|
||||||
SELECT jsonb_strip_nulls(to_jsonb(t.*)) - 'post_id' AS post
|
|
||||||
FROM post t
|
|
||||||
WHERE post_id = $1;
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.bind(post_id)
|
|
||||||
.fetch_one(&db_connection)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(value) => value.get::<Value, _>("post"),
|
|
||||||
Err(e) => {
|
|
||||||
error!(
|
|
||||||
"Database error on Reading `base post information` from table `post`: <{}>: {}",
|
|
||||||
post_id.to_string(),
|
|
||||||
e.to_string()
|
|
||||||
);
|
|
||||||
return match e {
|
|
||||||
Error::RowNotFound => Err((
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
Json::from(json!({"error": e.to_string()})),
|
|
||||||
)),
|
|
||||||
_ => Err((
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json::from(json!({"error": e.to_string()})),
|
|
||||||
)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let tags: Vec<_> = match query("SELECT tag FROM Tag WHERE post_id = $1;")
|
|
||||||
.bind(post_id)
|
|
||||||
.fetch_all(&db_connection)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(tags) => tags.iter().map(|tag| tag.get::<String, _>("tag")).collect(),
|
|
||||||
Err(e) => {
|
|
||||||
error!("Database query error :{}", e.to_string());
|
|
||||||
return Err((
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json::from(json!({"error": e.to_string()})),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let meta = match query(
|
|
||||||
r#"
|
|
||||||
SELECT jsonb_strip_nulls(to_jsonb(t.*)) - 'post_id' AS meta
|
|
||||||
FROM meta t
|
|
||||||
WHERE post_id = $1;
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.bind(post_id)
|
|
||||||
.fetch_one(&db_connection)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(value) => value.get::<Value, _>("meta"),
|
|
||||||
Err(e) => {
|
|
||||||
error!(
|
|
||||||
"Database error on Reading `{}` from table `{}`: <{}>: {}",
|
|
||||||
"post meta data",
|
|
||||||
"meta",
|
|
||||||
post_id.to_string(),
|
|
||||||
e.to_string()
|
|
||||||
);
|
|
||||||
return Err((
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json::from(json!({"error": e.to_string()})),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let adjacent = match query(r"
|
|
||||||
WITH target_post AS (SELECT t.date FROM meta t WHERE post_id = $1),
|
|
||||||
prev AS (SELECT post_id, t.title, t.sub_title, t.header_img
|
|
||||||
FROM meta t
|
|
||||||
WHERE t.date < (SELECT date FROM target_post)
|
|
||||||
ORDER BY t.date DESC
|
|
||||||
LIMIT 1),
|
|
||||||
next AS (SELECT post_id, t.title, t.sub_title, t.header_img
|
|
||||||
FROM meta t
|
|
||||||
WHERE t.date > (SELECT date FROM target_post)
|
|
||||||
ORDER BY t.date
|
|
||||||
LIMIT 1)
|
|
||||||
SELECT json_strip_nulls(json_build_object(
|
|
||||||
'prev',
|
|
||||||
(SELECT json_build_object('id', post_id, 'title', title, 'sub_title', sub_title, 'header_img', header_img)
|
|
||||||
FROM prev),
|
|
||||||
'next',
|
|
||||||
(SELECT json_build_object('id', post_id, 'title', title, 'sub_title', sub_title, 'header_img', header_img)
|
|
||||||
FROM next)
|
|
||||||
)) AS result;
|
|
||||||
"
|
|
||||||
)
|
|
||||||
.bind(post_id)
|
|
||||||
.fetch_one(&db_connection)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(res) => {res.get::<Value, _>("result")}
|
|
||||||
Err(e) => {
|
|
||||||
error!(
|
|
||||||
"Database error on Reading `{}` from table `{}`: <{}>: {}",
|
|
||||||
"adjoint posts data",
|
|
||||||
"meta",
|
|
||||||
post_id.to_string(),
|
|
||||||
e.to_string()
|
|
||||||
);
|
|
||||||
return Err((
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json::from(json!({"error": e.to_string()})),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut res = post.as_object().unwrap().to_owned();
|
|
||||||
res.insert("tags".to_string(), tags.into());
|
|
||||||
res.insert("meta".to_string(), meta);
|
|
||||||
res.insert("adj".to_string(), adjacent);
|
|
||||||
|
|
||||||
Ok(Json::from(json!(res)))
|
|
||||||
}
|
|
||||||
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,30 @@
|
|||||||
|
use axum::response::IntoResponse;
|
||||||
|
use axum::{
|
||||||
|
extract::{Path, State},
|
||||||
|
Json,
|
||||||
|
};
|
||||||
|
use serde_json::json;
|
||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
const GET_POST_BY_I64_ID: &str = include_str!("get_post_by_i64_id.sql");
|
||||||
|
const GET_POST_BY_STR_ID: &str = include_str!("get_post_by_str_id.sql");
|
||||||
|
|
||||||
|
pub async fn handler(
|
||||||
|
State(db_connection): State<PgPool>,
|
||||||
|
Path(identifier): Path<String>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let post = if let Ok(id) = identifier.parse::<i64>() {
|
||||||
|
select_post_with_i64_id(&db_connection, id).await
|
||||||
|
} else {
|
||||||
|
select_post_with_str_id(&db_connection, &identifier).await
|
||||||
|
};
|
||||||
|
Json::from(json!({"res": "ok"})).into_response()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn select_post_with_i64_id(db: &PgPool, id: i64) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn select_post_with_str_id(db: &PgPool, id: &str) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
pub mod get_page_count;
|
pub mod get_page_count;
|
||||||
pub mod get_post;
|
pub mod get_post;
|
||||||
pub mod get_post_list;
|
// pub mod get_post_list;
|
||||||
@@ -1 +1 @@
|
|||||||
pub mod check_update;
|
// pub mod check_update;
|
||||||
@@ -5,13 +5,14 @@ use crate::{
|
|||||||
modules::{
|
modules::{
|
||||||
blog::{
|
blog::{
|
||||||
api::{
|
api::{
|
||||||
get_page_count::get_page_count, get_post::get_post, get_post_list::get_post_list,
|
get_page_count,
|
||||||
|
get_post,
|
||||||
|
// get_post_list::get_post_list,
|
||||||
},
|
},
|
||||||
cron::check_update,
|
// cron::check_update,
|
||||||
},
|
},
|
||||||
Module,
|
Module,
|
||||||
},
|
},
|
||||||
scheduler::tasks::basic::BasicTask,
|
|
||||||
scheduler::tasks::CronTask,
|
scheduler::tasks::CronTask,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,11 +28,12 @@ pub struct Blog {
|
|||||||
impl Module for Blog {
|
impl Module for Blog {
|
||||||
fn get_server_router(&self) -> Router {
|
fn get_server_router(&self) -> Router {
|
||||||
let db_handler = self.db_handler.clone();
|
let db_handler = self.db_handler.clone();
|
||||||
// todo: remove new in get func?
|
// todo: move resource init to new func
|
||||||
|
// todo: remove debug comment
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/get_post_list", get(get_post_list))
|
// .route("/get_post_list", get(get_post_list))
|
||||||
.route("/get_page_count", get(get_page_count))
|
.route("/get_page_count", get(get_page_count::handler))
|
||||||
.route("/get_post/:post_id", get(get_post))
|
.route("/get_post/{identifier}", get(get_post::handler))
|
||||||
.with_state(db_handler)
|
.with_state(db_handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,11 +42,11 @@ impl Module for Blog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_cron_tasks(&self) -> Vec<Box<dyn CronTask>> {
|
fn get_cron_tasks(&self) -> Vec<Box<dyn CronTask>> {
|
||||||
let db_handler = self.db_handler.clone();
|
// let db_handler = self.db_handler.clone();
|
||||||
vec![
|
vec![
|
||||||
BasicTask::new(move || check_update::task(&db_handler), "0/15 * * * * *")
|
// BasicTask::new(move || check_update::task(&db_handler), "0/15 * * * * *")
|
||||||
.unwrap()
|
// .unwrap()
|
||||||
.to_task(),
|
// .to_task(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
CREATE TABLE tags
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(20) UNIQUE NOT NULL,
|
||||||
|
description TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE categories
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(20) UNIQUE NOT NULL,
|
||||||
|
description TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE posts
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
identifier VARCHAR(50) UNIQUE NOT NULL,
|
||||||
|
title VARCHAR(255) NOT NULL,
|
||||||
|
subtitle VARCHAR(255) NOT NULL,
|
||||||
|
published_date DATE NOT NULL,
|
||||||
|
last_update DATE,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
|
||||||
|
category SERIAL REFERENCES categories (id) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE post_tag
|
||||||
|
(
|
||||||
|
post SERIAL REFERENCES posts (id),
|
||||||
|
tag SERIAL REFERENCES tags (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE metadata
|
||||||
|
(
|
||||||
|
pid SERIAL REFERENCES posts (id) NOT NULL,
|
||||||
|
meta_key VARCHAR(50) NOT NULL,
|
||||||
|
meta_value TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT meta_pk PRIMARY KEY (pid, meta_key)
|
||||||
|
);
|
||||||
@@ -16,6 +16,7 @@ pub struct FileDelta {
|
|||||||
pub status: Delta,
|
pub status: Delta,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn do_fetch<'a>(
|
fn do_fetch<'a>(
|
||||||
repo: &'a Repository,
|
repo: &'a Repository,
|
||||||
refs: &[&str],
|
refs: &[&str],
|
||||||
@@ -23,8 +24,6 @@ fn do_fetch<'a>(
|
|||||||
) -> Result<AnnotatedCommit<'a>, git2::Error> {
|
) -> Result<AnnotatedCommit<'a>, git2::Error> {
|
||||||
let mut fetch_option = FetchOptions::new();
|
let mut fetch_option = FetchOptions::new();
|
||||||
|
|
||||||
// Always fetch all tags.
|
|
||||||
// Perform a download and also update tips
|
|
||||||
fetch_option.download_tags(AutotagOption::All);
|
fetch_option.download_tags(AutotagOption::All);
|
||||||
remote.fetch(refs, Some(&mut fetch_option), None)?;
|
remote.fetch(refs, Some(&mut fetch_option), None)?;
|
||||||
|
|
||||||
@@ -32,6 +31,7 @@ fn do_fetch<'a>(
|
|||||||
repo.reference_to_annotated_commit(&fetch_head)
|
repo.reference_to_annotated_commit(&fetch_head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn fast_forward(
|
fn fast_forward(
|
||||||
repo: &Repository,
|
repo: &Repository,
|
||||||
lb: &mut Reference,
|
lb: &mut Reference,
|
||||||
@@ -45,16 +45,11 @@ fn fast_forward(
|
|||||||
// println!("{}", msg);
|
// println!("{}", msg);
|
||||||
lb.set_target(rc.id(), &msg)?;
|
lb.set_target(rc.id(), &msg)?;
|
||||||
repo.set_head(&name)?;
|
repo.set_head(&name)?;
|
||||||
repo.checkout_head(Some(
|
repo.checkout_head(Some(build::CheckoutBuilder::default().force()))?;
|
||||||
build::CheckoutBuilder::default()
|
|
||||||
// For some reason, the force is required to make the working directory actually get updated
|
|
||||||
// I suspect we should be adding some logic to handle dirty working directory states,
|
|
||||||
// but this is just an example so maybe not.
|
|
||||||
.force(),
|
|
||||||
))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn normal_merge(
|
fn normal_merge(
|
||||||
repo: &Repository,
|
repo: &Repository,
|
||||||
local: &AnnotatedCommit,
|
local: &AnnotatedCommit,
|
||||||
@@ -73,13 +68,12 @@ fn normal_merge(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let result_tree = repo.find_tree(idx.write_tree_to(repo)?)?;
|
let result_tree = repo.find_tree(idx.write_tree_to(repo)?)?;
|
||||||
// now create the merge commit
|
|
||||||
let msg = format!("merge({}) -> {}", remote.id(), local.id());
|
let msg = format!("merge({}) -> {}", remote.id(), local.id());
|
||||||
let sig = repo.signature()?;
|
let sig = repo.signature()?;
|
||||||
let local_commit = repo.find_commit(local.id())?;
|
let local_commit = repo.find_commit(local.id())?;
|
||||||
let remote_commit = repo.find_commit(remote.id())?;
|
let remote_commit = repo.find_commit(remote.id())?;
|
||||||
|
|
||||||
// Do our merge commit and set the current branch head to that commit.
|
|
||||||
let _merge_commit = repo.commit(
|
let _merge_commit = repo.commit(
|
||||||
Some("HEAD"),
|
Some("HEAD"),
|
||||||
&sig,
|
&sig,
|
||||||
@@ -88,34 +82,26 @@ fn normal_merge(
|
|||||||
&result_tree,
|
&result_tree,
|
||||||
&[&local_commit, &remote_commit],
|
&[&local_commit, &remote_commit],
|
||||||
)?;
|
)?;
|
||||||
// Set working tree to match head.
|
|
||||||
repo.checkout_head(None)?;
|
repo.checkout_head(None)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn do_merge<'a>(
|
fn do_merge<'a>(
|
||||||
repo: &'a Repository,
|
repo: &'a Repository,
|
||||||
remote_branch: &str,
|
remote_branch: &str,
|
||||||
fetch_commit: AnnotatedCommit<'a>,
|
fetch_commit: AnnotatedCommit<'a>,
|
||||||
) -> Result<Vec<FileDelta>, git2::Error> {
|
) -> Result<Vec<FileDelta>, git2::Error> {
|
||||||
// 1. do a merge analysis
|
|
||||||
let analysis = repo.merge_analysis(&[&fetch_commit])?;
|
let analysis = repo.merge_analysis(&[&fetch_commit])?;
|
||||||
|
|
||||||
let head_commit = repo.reference_to_annotated_commit(&repo.head()?)?;
|
let head_commit = repo.reference_to_annotated_commit(&repo.head()?)?;
|
||||||
|
|
||||||
// 2. Do the appropriate merge
|
|
||||||
if analysis.0.is_fast_forward() {
|
if analysis.0.is_fast_forward() {
|
||||||
// println!("Doing a fast-forward");
|
|
||||||
// do a fast-forward
|
|
||||||
let ref_name = format!("refs/heads/{}", remote_branch);
|
let ref_name = format!("refs/heads/{}", remote_branch);
|
||||||
match repo.find_reference(&ref_name) {
|
match repo.find_reference(&ref_name) {
|
||||||
Ok(mut r) => {
|
Ok(mut r) => {
|
||||||
fast_forward(repo, &mut r, &fetch_commit)?;
|
fast_forward(repo, &mut r, &fetch_commit)?;
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// The branch doesn't exist, so set the reference to the
|
|
||||||
// commit directly. Usually this is because you are pulling
|
|
||||||
// into an empty repository.
|
|
||||||
repo.reference(
|
repo.reference(
|
||||||
&ref_name,
|
&ref_name,
|
||||||
fetch_commit.id(),
|
fetch_commit.id(),
|
||||||
@@ -132,17 +118,12 @@ fn do_merge<'a>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else if analysis.0.is_normal() {
|
} else if analysis.0.is_normal() {
|
||||||
// do a normal merge
|
|
||||||
normal_merge(repo, &head_commit, &fetch_commit)?;
|
normal_merge(repo, &head_commit, &fetch_commit)?;
|
||||||
}
|
}
|
||||||
// else {
|
|
||||||
// // already up-to-date
|
|
||||||
// println!("Nothing to do...");
|
|
||||||
// }
|
|
||||||
|
|
||||||
calculate_diff(repo, &head_commit, &fetch_commit)
|
calculate_diff(repo, &head_commit, &fetch_commit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn calculate_diff(
|
fn calculate_diff(
|
||||||
repo: &Repository,
|
repo: &Repository,
|
||||||
local: &AnnotatedCommit,
|
local: &AnnotatedCommit,
|
||||||
@@ -156,23 +137,12 @@ fn calculate_diff(
|
|||||||
|
|
||||||
if let Err(e) = diff.foreach(
|
if let Err(e) = diff.foreach(
|
||||||
&mut |d, _| {
|
&mut |d, _| {
|
||||||
// let delta = d.status();
|
|
||||||
//
|
|
||||||
// let n_path = d.new_file().path();
|
|
||||||
// let o_path = d.old_file().path();
|
|
||||||
//
|
|
||||||
// if let Some(path) = n_path {
|
|
||||||
// updated_files.insert(path.to_owned());
|
|
||||||
// }
|
|
||||||
// if let Some(path) = o_path {
|
|
||||||
// updated_files.insert(path.to_owned());
|
|
||||||
// }
|
|
||||||
updated_files.push(FileDelta {
|
updated_files.push(FileDelta {
|
||||||
old_path: d.old_file().path().map(PathBuf::from),
|
old_path: d.old_file().path().map(PathBuf::from),
|
||||||
new_path: d.new_file().path().map(PathBuf::from),
|
new_path: d.new_file().path().map(PathBuf::from),
|
||||||
status: d.status(),
|
status: d.status(),
|
||||||
});
|
});
|
||||||
true // Continue
|
true
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@@ -184,6 +154,7 @@ fn calculate_diff(
|
|||||||
Ok(updated_files.into_iter().collect())
|
Ok(updated_files.into_iter().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn sync(
|
pub fn sync(
|
||||||
remote_name: &str,
|
remote_name: &str,
|
||||||
remote_branch: &str,
|
remote_branch: &str,
|
||||||
|
|||||||
File renamed without changes.
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "loadbalancer"
|
name = "gateway"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
File renamed without changes.
Reference in new issue
Block a user