From 84a4ebe25150db9d7283d7e74370d3f5d66cb754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 30 Oct 2023 17:48:05 +0100 Subject: [PATCH] Init SMP importer project --- .github/workflows/build.yml | 150 +++++++++++++++++++++++ Dockerfile | 30 +++++ pyproject.toml | 46 +++++++ requirements.txt | 11 ++ scripts/build-info.sh | 0 setup.py | 3 + src/smp_importer/__init__.py | 3 + src/smp_importer/app.py | 44 +++++++ src/smp_importer/static/favicon.png | Bin 0 -> 3226 bytes src/smp_importer/static/script.js | 0 src/smp_importer/static/style.css | 0 src/smp_importer/templates/index.html.j2 | 42 +++++++ 12 files changed, 329 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 Dockerfile create mode 100644 pyproject.toml create mode 100644 requirements.txt create mode 100644 scripts/build-info.sh create mode 100644 setup.py create mode 100644 src/smp_importer/__init__.py create mode 100644 src/smp_importer/app.py create mode 100644 src/smp_importer/static/favicon.png create mode 100644 src/smp_importer/static/script.js create mode 100644 src/smp_importer/static/style.css create mode 100644 src/smp_importer/templates/index.html.j2 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..351333e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,150 @@ +name: Build + +on: + push: + +jobs: + package: + name: Python Package + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + cache: pip + cache-dependency-path: | + **/pyproject.toml + **/requirements*.txt + + - name: Prepare Python env + run: | + python -m pip install -U pip setuptools wheel + + - name: Create build info + run: | + bash scripts/build-info.sh + + - name: Install dependencies + run: | + pip install -r requirements.txt + + - name: Install package + run: | + pip install . + + - name: Build package sdist + run: | + python setup.py sdist + + - name: Build package bdist (wheel) + run: | + python setup.py bdist_wheel + + + docker: + name: Docker + runs-on: ubuntu-latest + + env: + PUBLIC_IMAGE_PREFIX: 'datastewardshipwizard' + DOCKER_IMAGE_NAME: 'smp-importer' + DOCKER_META_CONTEXT: '.' + DOCKER_META_FILE: 'Dockerfile' + DOCKER_META_PLATFORMS: 'linux/amd64,linux/arm64' + + steps: + - name: Check out repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 + + - name: Create build info + run: | + bash scripts/build-info.sh + + # TEST DOCKER IMAGE BUILD + - name: Docker meta [test] + id: meta-test + uses: docker/metadata-action@v4 + with: + images: | + ${{ env.PUBLIC_IMAGE_PREFIX }}/${{ env.DOCKER_IMAGE_NAME }} + tags: | + type=sha + + - name: Docker build [test] + uses: docker/build-push-action@v4 + with: + context: ${{ env.DOCKER_META_CONTEXT }} + file: ${{ env.DOCKER_META_FILE }} + platforms: ${{ env.DOCKER_META_PLATFORMS }} + push: false + tags: ${{ steps.meta-test.outputs.tags }} + labels: ${{ steps.meta-test.outputs.labels }} + + # PREPARE + - name: Docker login [docker.io] + if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + + # DEVELOPMENT IMAGES + - name: Docker meta [dev] + id: meta-dev + if: github.event_name != 'pull_request' + uses: docker/metadata-action@v4 + with: + images: | + ${{ secrets.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }} + tags: | + type=ref,event=branch + + - name: Docker build+push [dev] + uses: docker/build-push-action@v4 + if: github.event_name != 'pull_request' && steps.meta-dev.outputs.tags != '' + with: + context: ${{ env.DOCKER_META_CONTEXT }} + file: ${{ env.DOCKER_META_FILE }} + platforms: ${{ env.DOCKER_META_PLATFORMS }} + push: true + tags: ${{ steps.meta-dev.outputs.tags }} + labels: ${{ steps.meta-dev.outputs.labels }} + + # PUBLIC IMAGES + - name: Docker meta [public] + id: meta-public + if: github.event_name != 'pull_request' + uses: docker/metadata-action@v4 + with: + images: | + ${{ env.PUBLIC_IMAGE_PREFIX }}/${{ env.DOCKER_IMAGE_NAME }} + tags: | + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }} + + - name: Docker build+push [public] + uses: docker/build-push-action@v4 + if: github.event_name != 'pull_request' && steps.meta-public.outputs.tags != '' + with: + context: ${{ env.DOCKER_META_CONTEXT }} + file: ${{ env.DOCKER_META_FILE }} + platforms: ${{ env.DOCKER_META_PLATFORMS }} + push: true + tags: ${{ steps.meta-public.outputs.tags }} + labels: ${{ steps.meta-public.outputs.labels }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6af5c95 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +FROM datastewardshipwizard/python-base:3.11-alpine as builder + +WORKDIR /app + +COPY . /app + +RUN python -m pip wheel --no-cache-dir --wheel-dir=/app/wheels -r /app/requirements.txt \ + && python -m pip wheel --no-cache-dir --no-deps --wheel-dir=/app/wheels /app + + +FROM datastewardshipwizard/python-base:3.11-alpine + +ENV PATH "/home/user/.local/bin:$PATH" + +# Setup non-root user +USER user + +# Prepare dirs +WORKDIR /home/user +RUN mkdir -p /home/user/data + +RUN pip install uvicorn + +# Install Python packages +COPY --from=builder --chown=user:user /app/wheels /home/user/wheels +RUN python -m pip install --user --no-cache --no-index /home/user/wheels/* \ + && rm -rf /home/user/wheels + +# Run +CMD ["uvicorn", "smp_importer:app", "--proxy-headers", "--forwarded-allow-ips=*", "--host", "0.0.0.0", "--port", "8000"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..739e465 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,46 @@ +[build-system] +requires = ['setuptools'] +build-backend = 'setuptools.build_meta' + +[project] +name = 'smp-importer' +version = '0.1.0' +description = 'Importer of maSMPs for Software Management Wizard' +readme = 'README.md' +keywords = ['dsw', 'smp', 'masmp', 'import', 'mapping'] +license = { text = 'Apache License 2.0' } +authors = [ + { name = 'Marek Suchánek', email = 'marek.suchanek@ds-wizard.org' }, + { name = 'Vojtěch Knaisl', email = 'vojtech.knaisl@ds-wizard.org' } +] +classifiers = [ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Topic :: Text Processing', + 'Topic :: Utilities', +] +requires-python = '>=3.10, <4' +dependencies = [ + 'fastapi', + 'Jinja2', +] + +[project.urls] +Homepage = 'https://smw.ds-wizard.org' +Repository = 'https://github.com/ds-wizard/smp-importer' + +[tool.setuptools] +zip-safe = false + +[tool.setuptools.packages.find] +namespaces = true +where = ['src'] + +[tool.setuptools.package-data] +'*' = ['*.css', '*.js', '*.j2', '*.png'] + +[tool.distutils.bdist_wheel] +universal = true diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..851d177 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +annotated-types==0.6.0 +anyio==3.7.1 +fastapi==0.104.1 +idna==3.4 +Jinja2==3.1.2 +MarkupSafe==2.1.3 +pydantic==2.4.2 +pydantic_core==2.10.1 +sniffio==1.3.0 +starlette==0.27.0 +typing_extensions==4.8.0 diff --git a/scripts/build-info.sh b/scripts/build-info.sh new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b908cbe --- /dev/null +++ b/setup.py @@ -0,0 +1,3 @@ +import setuptools + +setuptools.setup() diff --git a/src/smp_importer/__init__.py b/src/smp_importer/__init__.py new file mode 100644 index 0000000..8a1c803 --- /dev/null +++ b/src/smp_importer/__init__.py @@ -0,0 +1,3 @@ +from .app import app + +__all__ = ['app'] diff --git a/src/smp_importer/app.py b/src/smp_importer/app.py new file mode 100644 index 0000000..1b4c271 --- /dev/null +++ b/src/smp_importer/app.py @@ -0,0 +1,44 @@ +import logging +import os +import pathlib + +import fastapi +import fastapi.responses +import fastapi.staticfiles +import fastapi.templating + + +ROOT_DIR = pathlib.Path(__file__).parent +STATIC_DIR = ROOT_DIR / 'static' +TEMPLATES_DIR = ROOT_DIR / 'templates' +LOG = logging.getLogger(__name__) + + +app = fastapi.FastAPI() +app.mount( + path='/static', + app=fastapi.staticfiles.StaticFiles(directory=STATIC_DIR), + name='static', +) +templates = fastapi.templating.Jinja2Templates(directory=TEMPLATES_DIR) + + +@app.get('/', response_class=fastapi.responses.HTMLResponse) +async def get_index(request: fastapi.Request): + return templates.TemplateResponse( + name='index.html.j2', + context={ + 'request': request, + 'debug': os.environ.get('IMPORTER_DEBUG', '') == 'true', + 'development': os.environ.get('IMPORTER_DEV', '') == 'true', + }, + ) + + +@app.get('/api/import', response_class=fastapi.responses.JSONResponse) +async def list_fips(request: fastapi.Request): + try: + return fastapi.responses.JSONResponse(content={'text': 'Hello'}) + except Exception as e: + LOG.error(f'Error appeared: {str(e)}', exc_info=e) + raise fastapi.HTTPException(status_code=500) diff --git a/src/smp_importer/static/favicon.png b/src/smp_importer/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..7a83303b346a38d4fce93d3540d5228b59ca2e81 GIT binary patch literal 3226 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 WA9$jb%oWc8?Ahk($*kNOc=|s!zO$wP literal 0 HcmV?d00001 diff --git a/src/smp_importer/static/script.js b/src/smp_importer/static/script.js new file mode 100644 index 0000000..e69de29 diff --git a/src/smp_importer/static/style.css b/src/smp_importer/static/style.css new file mode 100644 index 0000000..e69de29 diff --git a/src/smp_importer/templates/index.html.j2 b/src/smp_importer/templates/index.html.j2 new file mode 100644 index 0000000..f7e4892 --- /dev/null +++ b/src/smp_importer/templates/index.html.j2 @@ -0,0 +1,42 @@ + + + + + SIP Importer + + + + + + + + {% if development %} + + {% endif %} + + + +
+

SMP Importer

+
+ + \ No newline at end of file