Compare commits

...

21 Commits

Author SHA1 Message Date
raoul db16d9f57d Merge pull request 'Add license and link on about page' (#15) from add-url-to-about into master
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline failed Details
Reviewed-on: #15
2023-07-30 23:42:50 +00:00
Raoul Snyman 421303948a Add license and link on about page
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
2023-07-30 16:40:35 -07:00
raoul bf20fd1a76 Merge pull request 'Force hypercorn to bind to 0.0.0.0:8000' (#14) from fix-hypercorn-listen-ip into master
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
Reviewed-on: #14
2023-07-30 05:33:14 +00:00
Raoul Snyman 7234b85394 Force hypercorn to bind to 0.0.0.0:8000
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details
2023-07-29 22:30:56 -07:00
raoul 7fde570f87 Merge pull request 'Use Alpine images to reduce image size' (#13) from use-alpine-images into master
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
Reviewed-on: #13
2023-07-30 05:17:20 +00:00
Raoul Snyman f3b60f4c39 Use Alpine images to reduce image size
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details
2023-07-29 22:15:13 -07:00
raoul eceffadf1a Merge pull request 'Fix various issues relating to the Docker image and running a container' (#12) from fix-various-docker-issues into master
ci/woodpecker/push/woodpecker Pipeline was successful Details
Reviewed-on: #12
2023-07-30 05:01:07 +00:00
Raoul Snyman c04b2a4102 Fix an issue with hypercorn not finding the application in the docker image; correct the README; fix a co-routine that wasn't being awaited
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details
2023-07-29 21:58:59 -07:00
Raoul Snyman 8a355f59a5 Fix a image tag
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
2023-07-29 14:51:54 -07:00
Raoul Snyman 249d02c4c7 Fix a typo in the command
ci/woodpecker/push/woodpecker Pipeline failed Details
2023-07-29 14:49:46 -07:00
Raoul Snyman 53cf0d3a55 Fix dockerfile names
ci/woodpecker/push/woodpecker Pipeline failed Details
2023-07-29 14:47:27 -07:00
raoul 00c6c3a37b Merge pull request 'Try to fix docker login' (#10) from fix-docker-pipeline into master
ci/woodpecker/push/woodpecker Pipeline failed Details
Reviewed-on: #10
2023-07-29 21:31:58 +00:00
Raoul Snyman 63505b27e1 Try to fix docker login
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details
2023-07-29 14:29:18 -07:00
raoul e90bfb65b7 Merge pull request 'Just use the plain docker container' (#9) from simplified-docker-build into master
ci/woodpecker/push/woodpecker Pipeline failed Details
Reviewed-on: #9
2023-07-29 21:25:28 +00:00
Raoul Snyman e62641a661 Just use the plain docker container
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
2023-07-29 12:05:22 -07:00
raoul e6a13fa4c9 Merge pull request 'Add building nightly images' (#8) from nightly-images into master
ci/woodpecker/push/woodpecker Pipeline failed Details
Reviewed-on: #8
2023-07-29 18:46:04 +00:00
Raoul Snyman 19265e034f Add building nightly images
ci/woodpecker/pr/woodpecker Pipeline was successful Details
2023-07-29 11:40:05 -07:00
raoul a4291920aa Merge pull request 'Add a step in the CI pipeline to build a container image' (#7) from build-image into master
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline failed Details
Reviewed-on: #7
2023-07-29 02:31:48 +00:00
Raoul Snyman 080c68661b Add a step in the CI pipeline to build a container image
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details
2023-07-28 16:54:03 -07:00
raoul 96ed72778a Merge pull request 'Getting things ready to containerize CodeSmigen' (#6) from container-image into master
ci/woodpecker/push/woodpecker Pipeline was successful Details
Reviewed-on: #6
2023-07-28 20:10:40 +00:00
Raoul Snyman 62029b9acd Getting things ready to containerize CodeSmigen
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details
- Update the Dockerfile to pull the correct package
- Update the README.rst with environment variables
- Add typing annotations
- Refactor config to be loaded via environment variables as well as a file
2023-07-28 13:07:11 -07:00
11 changed files with 137 additions and 48 deletions

View File

@ -22,3 +22,33 @@ steps:
- pip_token
when:
event: tag
nightly-image:
image: docker
commands:
- "docker login git.snyman.info -u $DOCKER_USERNAME -p $DOCKER_TOKEN"
- "docker build -t git.snyman.info/raoul/codesmidgen:nightly -t git.snyman.info/raoul/codesmidgen:${CI_COMMIT_SHA:0:8} -f Dockerfile.nightly ."
- "docker push git.snyman.info/raoul/codesmidgen:nightly"
- "docker push git.snyman.info/raoul/codesmidgen:${CI_COMMIT_SHA:0:8}"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
secrets:
- docker_username
- docker_token
when:
- branch: master
event: push
release-image:
image: docker
commands:
- "docker login git.snyman.info -u $DOCKER_USERNAME -p $DOCKER_TOKEN"
- "docker build -t git.snyman.info/raoul/codesmidgen:latest -t git.snyman.info/raoul/codesmidgen:${CI_COMMIT_TAG##v} -f Dockerfile.release ."
- "docker push git.snyman.info/raoul/codesmidgen:latest"
- "docker push git.snyman.info/raoul/codesmidgen:${CI_COMMIT_TAG##v}"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
secrets:
- docker_username
- docker_token
when:
- branch: master
event: tag

View File

@ -1,6 +0,0 @@
FROM python:3.11
RUN pip install stickynotes --index-url https://git.snyman.info/packages/raoul/index
EXPOSE 8000
CMD ["hypercorn", "stickynotes.app"]

10
Dockerfile.nightly Normal file
View File

@ -0,0 +1,10 @@
FROM python:3.11-alpine
WORKDIR /app
ADD . /app
RUN apk add git
RUN pip install -e .
RUN pip install hypercorn
EXPOSE 8000
CMD ["hypercorn", "--bind", "0.0.0.0:8000", "codesmidgen.app:application"]

6
Dockerfile.release Normal file
View File

@ -0,0 +1,6 @@
FROM python:3.11-alpine
RUN pip install --extra-index-url https://git.snyman.info/api/packages/raoul/pypi/simple/ CodeSmidgen hypercorn
EXPOSE 8000
CMD ["hypercorn", "--bind", "0.0.0.0:8000", "codesmidgen.app:application"]

9
LICENSE.txt Normal file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2015-present Raoul Snyman <raoul@snyman.info>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -25,7 +25,8 @@ The easiest way to install CodeSmidgen is via Docker and Docker Compose. Here's
app:
image: git.snyman.info/raoul/codesmidgen:latest
env:
- SQLALCHEMY_URL=postgres://codesmidgen:codesmidgen@postgres/codesmidgen
- SMIDGEN_SECRET_KEY=yoursecrethere
- SQLALCHEMY_DATABASE_URI=postgresql://codesmidgen:codesmidgen@postgres/codesmidgen
restart: unless-stopped
ports:
- "127.0.0.1:8000:8000"

View File

@ -2,48 +2,25 @@
"""
CodeSmidgen, yet another paste bin
"""
from configparser import ConfigParser
from pathlib import Path
import quart_flask_patch # noqa: F401
from quart import Quart
from codesmidgen.config import get_config
from codesmidgen.db import db
from codesmidgen.views import views
def read_config(config_path=None):
"""
Read the configuration file and return the values in a dictionary
"""
if config_path:
config_file = config_path / 'codesmidgen.cfg'
else:
config_file = Path(__file__).parent / '..' / 'codesmidgen.cfg'
if not config_file.exists():
return {}
config_parser = ConfigParser()
config_parser.read(config_file)
config = {}
for option in config_parser.options('codesmidgen'):
config[option.upper()] = config_parser.get('codesmidgen', option)
return config
def make_app(config_path=None):
def make_app() -> Quart:
"""
Create the application object
"""
app = Quart(__name__)
# Load the config file
config = read_config(config_path)
app.config.update(config)
app.config.update({'SQLALCHEMY_TRACK_MODIFICATIONS': False})
app.config.update(get_config())
db.init_app(app)
app.register_blueprint(views)
@app.before_first_request
async def setup_db():
async def setup_db() -> None:
db.create_all()
return app

View File

@ -2,10 +2,9 @@
"""
This is the entry point for the WSGI server
"""
from pathlib import Path
from codesmidgen import make_app
application = make_app(Path(__file__).parent.parent)
application = make_app()
if __name__ == '__main__':
application.run(debug=True)

62
codesmidgen/config.py Normal file
View File

@ -0,0 +1,62 @@
import json
import os
from configparser import ConfigParser
from pathlib import Path
from typing import Any
CONFIG_DEFAULTS = {
'SQLALCHEMY_TRACK_MODIFICATIONS': False
}
CONFIG_PREFIXES = ['SMIDGEN_', 'SQLALCHEMY_']
STRIPPED_PREFIXES = ['SMIDGEN_']
def read_from_file() -> dict:
"""Read the configuration file and return the values in a dictionary"""
config_file = Path(__file__).parent / '..' / 'codesmidgen.cfg'
if not config_file.exists():
return {}
config_parser = ConfigParser()
config_parser.read(config_file)
config: dict[str, Any] = {}
for option in config_parser.options('codesmidgen'):
config[option.upper()] = config_parser.get('codesmidgen', option)
return config
def read_from_envvars() -> dict:
"""Read the configuration from environment variables"""
config: dict[str, Any] = {}
for key in sorted(os.environ):
if not any([key.startswith(prefix) for prefix in CONFIG_PREFIXES]):
continue
value = os.environ[key]
try:
value = json.loads(value)
except Exception:
# If the value is not JSON parseable, just leave it as a string
pass
for prefix in STRIPPED_PREFIXES:
key = key.replace(prefix, '')
# Check if there are any "nested" values
if '__' not in key:
config[key] = value
continue
# Navigate the nested values and build the structure
*parents, child = key.split('__')
item = config
for parent in parents:
if parent not in item:
item[parent] = {}
item = item[parent]
item[child] = value
return config
def get_config() -> dict:
"""Read configuration from files, environment variables, etc."""
config = {}
config.update(CONFIG_DEFAULTS)
config.update(read_from_file())
config.update(read_from_envvars())
return config

View File

@ -4,6 +4,7 @@
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<h2>About CodeSmidgen</h2>
<p>CodeSmidgen is a quick code paste application written in Python with Quartz, SQLAlchemy, Mako, Pygments and a few other Python libraries.</p>
<p>CodeSmidgen is open source under the MIT license, and is available from <a href="https://git.snyman.info/raoul/codesmidgen">https://git.snyman.info/raoul/codesmidgen</a></p>
</div>
</div>
{% endblock %}

View File

@ -7,7 +7,7 @@ import secrets
import string
from datetime import timedelta, datetime
from quart import Blueprint, redirect, request, flash, make_response, current_app, render_template
from quart import Blueprint, Response, redirect, request, flash, make_response, current_app, render_template
from pygments import highlight
from pygments.formatters.html import HtmlFormatter
from pygments.lexers import get_lexer_by_name, get_all_lexers
@ -30,7 +30,7 @@ EXPIRY_DELTAS = {
}
def _generate_short_url():
def _generate_short_url() -> str:
"""
Encode the URL
"""
@ -40,7 +40,7 @@ def _generate_short_url():
@views.route('/', methods=['GET'])
async def index():
async def index() -> str:
"""
Add a new sticky note
"""
@ -51,7 +51,7 @@ async def index():
@views.route('/notes', methods=['GET'])
async def notes():
async def notes() -> str:
"""
Show a list of recent notes
"""
@ -64,7 +64,7 @@ async def notes():
@views.route('/about', methods=['GET'])
async def about():
async def about() -> str:
"""
Show the about page
"""
@ -72,7 +72,7 @@ async def about():
@views.route('/', methods=['POST'])
async def save():
async def save() -> Response:
"""
Save a sticky note
"""
@ -101,13 +101,13 @@ async def save():
session.commit()
return redirect('/' + note.url)
except Exception as e:
flash(str(e), 'danger')
await flash(str(e), 'danger')
session.rollback()
return redirect('/')
@views.route('/<string:note_url>', methods=['GET'])
async def view(note_url):
async def view(note_url: str) -> Response | str:
"""
Show a sticky note
@ -115,7 +115,7 @@ async def view(note_url):
"""
note = Smidgen.query.filter(Smidgen.url == note_url).first()
if not note:
flash('That note does not exist', 'danger')
await flash('That note does not exist', 'danger')
return redirect('/')
lexer = get_lexer_by_name(note.lexer)
@ -125,7 +125,7 @@ async def view(note_url):
@views.route('/raw/<string:note_url>', methods=['GET'])
async def raw(note_url):
async def raw(note_url: str) -> Response | str:
"""
Show the raw version of a sticky note
@ -133,13 +133,13 @@ async def raw(note_url):
"""
note = Smidgen.query.filter(Smidgen.url == note_url).scalar()
if not note:
flash('That note does not exist', 'danger')
await flash('That note does not exist', 'danger')
return redirect('/')
return await render_template('raw.html', source=note.source), 200, {'Content-Type': 'text/plain; charset=utf-8'}
@views.route('/pygments.css', methods=['GET'])
async def pygments_css():
async def pygments_css() -> Response:
"""
Return the Pygments CSS to the browser
"""