Compare commits
No commits in common. "master" and "v0.2.1" have entirely different histories.
13 changed files with 71 additions and 141 deletions
|
|
@ -1,40 +0,0 @@
|
||||||
default:
|
|
||||||
image: $CI_REGISTRY/imageroot/buildah:latest
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- build
|
|
||||||
|
|
||||||
.container:
|
|
||||||
before_script:
|
|
||||||
- podman login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY <<<$CI_REGISTRY_PASSWORD
|
|
||||||
- podman login -u $NEXUS_USERNAME --password-stdin $NEXUS_DOCKER_IO <<<$NEXUS_PASSWORD
|
|
||||||
- podman login -u $FORGEJO_PACKAGES_USER --password-stdin $FORGEJO_PACKAGES_DOMAIN <<<$FORGEJO_PACKAGES_TOKEN
|
|
||||||
|
|
||||||
build-master-container:
|
|
||||||
extends: .container
|
|
||||||
stage: build
|
|
||||||
script:
|
|
||||||
- podman build --build-arg DOCKER_IO=${NEXUS_DOCKER_IO} -t ${CI_REGISTRY_IMAGE}:master .
|
|
||||||
- podman push ${CI_REGISTRY_IMAGE}:master
|
|
||||||
rules:
|
|
||||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
||||||
|
|
||||||
build-tagged-container:
|
|
||||||
extends: .container
|
|
||||||
stage: build
|
|
||||||
variables:
|
|
||||||
FORGEJO_IMAGE: git.x59.dev/x59/time-go
|
|
||||||
script:
|
|
||||||
- podman build
|
|
||||||
--build-arg DOCKER_IO=${NEXUS_DOCKER_IO}
|
|
||||||
-t ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}
|
|
||||||
-t ${CI_REGISTRY_IMAGE}:latest
|
|
||||||
-t ${FORGEJO_IMAGE}:${CI_COMMIT_TAG}
|
|
||||||
-t ${FORGEJO_IMAGE}:latest
|
|
||||||
.
|
|
||||||
- podman push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}
|
|
||||||
- podman push ${CI_REGISTRY_IMAGE}:latest
|
|
||||||
- podman push ${FORGEJO_IMAGE}:${CI_COMMIT_TAG}
|
|
||||||
- podman push ${FORGEJO_IMAGE}:latest
|
|
||||||
rules:
|
|
||||||
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+/
|
|
||||||
22
Dockerfile
22
Dockerfile
|
|
@ -1,16 +1,14 @@
|
||||||
ARG DOCKER_IO=docker.io
|
FROM python:3.9-rc-alpine
|
||||||
|
|
||||||
FROM ${DOCKER_IO}/library/golang:1.24-alpine AS build
|
MAINTAINER Yehuda Deutsch <yeh@uda.co.il>
|
||||||
|
|
||||||
|
RUN apk add --virtual .build-deps gcc libc-dev make \
|
||||||
|
&& pip install fastapi uvicorn \
|
||||||
|
&& rm -Rf ~/.cache \
|
||||||
|
&& apk --purge del .build-deps gcc libc-dev make
|
||||||
|
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
|
ENV PYTHONPATH=/code
|
||||||
|
COPY time_app/ /code/time_app/
|
||||||
|
|
||||||
COPY time.go /code
|
CMD ["python", "time_app"]
|
||||||
RUN go build ./time.go
|
|
||||||
|
|
||||||
FROM ${DOCKER_IO}/library/alpine:latest AS final
|
|
||||||
|
|
||||||
RUN apk add --no-cache tzdata
|
|
||||||
WORKDIR /code
|
|
||||||
COPY --from=build /code/time /code/time
|
|
||||||
|
|
||||||
CMD ["/code/time"]
|
|
||||||
|
|
|
||||||
89
time.go
89
time.go
|
|
@ -1,89 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getTime(location string) (time.Time, error) {
|
|
||||||
loc, err := time.LoadLocation(location)
|
|
||||||
if err != nil {
|
|
||||||
return time.Now(), err
|
|
||||||
}
|
|
||||||
return time.Now().In(loc), err
|
|
||||||
}
|
|
||||||
|
|
||||||
var zoneDir string
|
|
||||||
|
|
||||||
func loadZoneLocations(path string) []string {
|
|
||||||
var locations []string
|
|
||||||
zoneFiles, _ := os.ReadDir("/usr/share/zoneinfo/" + path)
|
|
||||||
for _, file := range zoneFiles {
|
|
||||||
if file.IsDir() {
|
|
||||||
locations = append(locations, loadZoneLocations(path+"/"+file.Name())...)
|
|
||||||
} else {
|
|
||||||
if _, err := time.LoadLocation((path + "/" + file.Name())[1:]); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
locations = append(locations, (path + "/" + file.Name())[1:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return locations
|
|
||||||
}
|
|
||||||
|
|
||||||
var runtimeLocations = loadZoneLocations(zoneDir)
|
|
||||||
|
|
||||||
func mainHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
now, err := getTime("UTC")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
fmt.Fprint(w, "Could not get current time")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, now.Format("2006-01-02 15:04:05"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func dayInYearHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
now, err := getTime("UTC")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
fmt.Fprint(w, "Could not get current time")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "%s%d", string(now.Format("06")[1]), now.YearDay())
|
|
||||||
}
|
|
||||||
|
|
||||||
func timeAtZoneHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
timezone := r.PathValue("timezone")
|
|
||||||
now, err := getTime(timezone)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
fmt.Fprint(w, "Timezone not found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, now.Format("2006-01-02 15:04:05"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ZoneListHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
err := json.NewEncoder(w).Encode(runtimeLocations)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
fmt.Fprint(w, "Could not encode zones")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("GET /", mainHandler)
|
|
||||||
http.HandleFunc("GET /diy", dayInYearHandler)
|
|
||||||
http.HandleFunc("GET /at/{timezone...}", timeAtZoneHandler)
|
|
||||||
http.HandleFunc("GET /timezones", ZoneListHandler)
|
|
||||||
|
|
||||||
listen := ":8000"
|
|
||||||
fmt.Println("Listening on " + listen)
|
|
||||||
http.ListenAndServe(listen, nil)
|
|
||||||
}
|
|
||||||
1
time_app/__init__.py
Normal file
1
time_app/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
3
time_app/__main__.py
Normal file
3
time_app/__main__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
from time_app.main import run
|
||||||
|
|
||||||
|
run()
|
||||||
0
time_app/helpers/__init__.py
Normal file
0
time_app/helpers/__init__.py
Normal file
8
time_app/helpers/datetime.py
Normal file
8
time_app/helpers/datetime.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
utc = ZoneInfo('UTC')
|
||||||
|
|
||||||
|
|
||||||
|
def real_utc_now() -> datetime:
|
||||||
|
return datetime.now(tz=utc)
|
||||||
13
time_app/main.py
Normal file
13
time_app/main.py
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import uvicorn
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.responses import PlainTextResponse
|
||||||
|
|
||||||
|
from .views import main, api
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
app.include_router(main.router, tags=['text'], default_response_class=PlainTextResponse)
|
||||||
|
app.include_router(api.router, prefix='/api/v1', tags=['api'])
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
uvicorn.run("time_app.main:app", host="0.0.0.0", port=8000, log_level="info")
|
||||||
0
time_app/models/__init__.py
Normal file
0
time_app/models/__init__.py
Normal file
5
time_app/models/main.py
Normal file
5
time_app/models/main.py
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Now(BaseModel):
|
||||||
|
time: str
|
||||||
0
time_app/views/__init__.py
Normal file
0
time_app/views/__init__.py
Normal file
16
time_app/views/api.py
Normal file
16
time_app/views/api.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from time_app.helpers.datetime import real_utc_now
|
||||||
|
from time_app.models.main import Now
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/', name='Now', response_model=Now)
|
||||||
|
def now_view() -> dict:
|
||||||
|
return {"time": real_utc_now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/diy', name='Day in year', response_model=Now)
|
||||||
|
def day_in_year_view() -> dict:
|
||||||
|
return {"time": real_utc_now().strftime('%y%j')[-4:]}
|
||||||
15
time_app/views/main.py
Normal file
15
time_app/views/main.py
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from time_app.helpers.datetime import real_utc_now
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/', name='Now')
|
||||||
|
def now_view() -> str:
|
||||||
|
return real_utc_now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/diy', name='Day in year')
|
||||||
|
def day_in_year_view() -> str:
|
||||||
|
return real_utc_now().strftime('%y%j')[-4:]
|
||||||
Loading…
Add table
Reference in a new issue