Skip to content

Commit 8ac816e

Browse files
committed
feat: add Dockerfile publishing
1 parent 0a0adba commit 8ac816e

File tree

8 files changed

+95
-22
lines changed

8 files changed

+95
-22
lines changed

.dockerignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
target/
2+
.git/
3+
.gitignore
4+
.dockerignore
5+
.mise/
6+
.env
7+
.env.local
8+
.env.development.local
9+
.env.test.local
10+
.env.production.local
11+
.env.local

.github/workflows/docker.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Build and Publish Docker Image
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
tags:
8+
- 'lib**[0-9]+.[0-9]+.[0-9]'
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
build-and-push:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v5
19+
20+
- name: Set up Docker Buildx
21+
uses: docker/setup-buildx-action@v3
22+
23+
- name: Log in to Docker Hub
24+
uses: docker/login-action@v3
25+
with:
26+
username: ${{ secrets.DOCKERHUB_USERNAME }}
27+
password: ${{ secrets.DOCKERHUB_TOKEN }}
28+
29+
- name: Determine tags
30+
id: tags
31+
run: |
32+
IMAGE="${{ secrets.DOCKERHUB_USERNAME }}/odict"
33+
TAGS="${IMAGE}:latest"
34+
35+
if [[ "${{ github.ref }}" == refs/tags/lib* ]]; then
36+
TAG_NAME=${GITHUB_REF#refs/tags/}
37+
# Tag with the full tag name (e.g., lib/1.2.3) and also latest
38+
TAGS="${IMAGE}:${TAG_NAME},${TAGS}"
39+
fi
40+
41+
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
42+
43+
- name: Build and push Docker image
44+
uses: docker/build-push-action@v5
45+
with:
46+
context: .
47+
file: ./Dockerfile
48+
push: true
49+
tags: ${{ steps.tags.outputs.tags }}
50+
cache-from: type=gha
51+
cache-to: type=gha,mode=max
52+

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Dockerfile

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1-
ARG ODICT_VERSION=2.1.0
2-
3-
FROM debian:slim
1+
ARG ODICT_VERSION=3.2.2
42

53
ARG ODICT_VERSION
6-
ENV ODICT_VERSION=${ODICT_VERSION}
74

8-
RUN curl -fsSL https://github.com/TheOpenDictionary/odict/releases/download/cli%2F${ODICT_VERSION}/odict-cli-installer.sh | sh
5+
FROM jdxcode/mise AS builder
6+
7+
SHELL ["/bin/bash", "-c"]
8+
9+
WORKDIR /odict
10+
COPY . .
11+
12+
RUN mise trust -y
13+
RUN mise install rust
14+
RUN mise run build --release
15+
16+
FROM debian:latest
917

10-
WORKDIR /dictionaries
11-
VOLUME /dictionaries
18+
COPY --from=builder /odict/target/release/odict /usr/local/bin/odict
1219

1320
ENTRYPOINT ["odict", "serve"]
14-
CMD []
21+
CMD []

cli/src/serve/lookup.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::get_lookup_entries;
1515

1616
#[derive(Debug, Deserialize)]
1717
pub struct LookupRequest {
18-
queries: String,
18+
q: String,
1919
follow: Option<bool>,
2020
split: Option<usize>,
2121
}
@@ -59,7 +59,7 @@ async fn handle_lookup(
5959
dictionary_cache: Data<crate::serve::DictionaryCache>,
6060
) -> Result<impl Responder, LookupError> {
6161
let LookupRequest {
62-
queries: raw_queries,
62+
q: raw_queries,
6363
follow,
6464
split,
6565
} = params.0;

cli/src/serve/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,23 @@ impl DictionaryCache {
105105
pub async fn get(&self, key: &str) -> anyhow::Result<Option<Arc<OpenDictionary>>> {
106106
{
107107
let cache = self.cache.read().unwrap();
108+
108109
if let Some(file) = cache.peek(key) {
109110
// Return a clone of the Arc (cheap operation)
110111
return Ok(Some(Arc::clone(file)));
111112
}
112113
}
113114

114115
// Not in cache, need to load it
115-
if let Some(path) = self.dictionaries.get(key) {
116-
let dict = OpenDictionary::from_path(path.to_string_lossy().as_ref())?;
116+
if let Some(dict) = self.dictionaries.get(key) {
117+
let dict = OpenDictionary::load(dict.to_string_lossy().as_ref()).await?;
117118

118119
// Now get a write lock to update the cache
119120
let mut cache = self.cache.write().unwrap();
120121

121122
// Wrap in Arc before putting in cache
122123
let arc_dict = Arc::new(dict);
124+
123125
cache.put(String::from(key), Arc::clone(&arc_dict));
124126

125127
return Ok(Some(arc_dict));
@@ -174,7 +176,7 @@ pub async fn serve<'a>(ctx: &mut CLIContext<'a>, args: &ServeArgs) -> anyhow::Re
174176
.service(search::handle_search)
175177
.service(tokenize::handle_tokenize)
176178
})
177-
.bind(("127.0.0.1", *port))?
179+
.bind(("0.0.0.0", *port))?
178180
.run()
179181
.await?;
180182

cli/src/serve/search.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use serde::Deserialize;
1010

1111
#[derive(Debug, Deserialize)]
1212
pub struct SearchRequest {
13-
query: String,
13+
q: String,
1414
limit: Option<usize>,
1515
}
1616

@@ -52,7 +52,7 @@ async fn handle_search(
5252
dict: Path<String>,
5353
dictionary_cache: Data<crate::serve::DictionaryCache>,
5454
) -> Result<impl Responder, SearchError> {
55-
let SearchRequest { query, limit } = params.0;
55+
let SearchRequest { q, limit } = params.0;
5656

5757
let dictionary_name = dict.into_inner();
5858

@@ -73,7 +73,7 @@ async fn handle_search(
7373
})?;
7474

7575
let entries = dictionary
76-
.search(&query, SearchOptions::default().limit(limit.unwrap_or(10)))
76+
.search(&q, SearchOptions::default().limit(limit.unwrap_or(10)))
7777
.map_err(|e| SearchError::SearchError {
7878
message: e.to_string(),
7979
})?;

cli/src/serve/tokenize.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,21 @@ async fn handle_tokenize(
5555
let TokenizeRequest { text, follow } = params.0;
5656

5757
let dictionary_name = dict.into_inner();
58+
println!("dictionary_name: {}", dictionary_name);
5859

5960
let file = dictionary_cache
6061
.get(&dictionary_name)
6162
.await
62-
.map_err(|_e| TokenizeError::DictionaryReadError {
63-
name: dictionary_name.to_string(),
63+
.map_err(|e| TokenizeError::DictionaryReadError {
64+
name: format!("{}: {}", dictionary_name, e),
6465
})?
6566
.ok_or(TokenizeError::DictionaryNotFound {
6667
name: dictionary_name.to_string(),
6768
})?;
6869

6970
let dictionary = file
7071
.contents()
71-
.map_err(|_e| TokenizeError::DictionaryReadError {
72+
.map_err(|_| TokenizeError::DictionaryReadError {
7273
name: dictionary_name.to_string(),
7374
})?;
7475

0 commit comments

Comments
 (0)