Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Arch Linux
aurweb
Commits
cef3316d
Verified
Commit
cef3316d
authored
Mar 30, 2022
by
Kevin Morris
Browse files
Merge branch 'master' into live
parents
0c1e40a4
d8564e44
Pipeline
#16827
passed with stages
in 4 minutes and 32 seconds
Changes
5
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CONTRIBUTING.md
View file @
cef3316d
...
...
@@ -9,7 +9,7 @@ You can add a git hook to do this by installing `python-pre-commit` and running
`pre-commit install`
.
[
1
]:
https://lists.archlinux.org/listinfo/aur-dev
[
2
]:
https://gitlab.archlinu
n
x.org/archlinux/aurweb
[
2
]:
https://gitlab.archlinux.org/archlinux/aurweb
### Coding Guidelines
...
...
@@ -23,6 +23,76 @@ development.
3.
Use four space indentation
4.
Use
[
conventional commits
](
https://www.conventionalcommits.org/en/v1.0.0/
)
5.
DRY: Don't Repeat Yourself
6.
All code should be tested for good _and_ bad cases
6.
All code should be tested for good _and_ bad cases (see
[
test/README.md
][
3
]
)
[
3
]:
https://gitlab.archlinux.org/archlinux/aurweb/-/blob/master/test/README.md
Test patches that increase coverage in the codebase are always welcome.
### Coding Style
We use the
`flake8`
and
`isort`
tools to manage PEP-8 coherence and
import ordering in this project.
There are plugins for editors or IDEs which automate this process. Some
example plugins:
-
[
tell-k/vim-autopep8
](
https://github.com/tell-k/vim-autopep8
)
-
[
fisadev/vim-isort
](
https://github.com/fisadev/vim-isort
)
-
[
prabirshrestha/vim-lsp
](
https://github.com/prabirshrestha/vim-lsp
)
See
`setup.cfg`
for flake8 and isort specific rules.
Note: We are planning on switching to
[
psf/black
](
https://github.com/psf/black
)
.
For now, developers should ensure that flake8 and isort passes when submitting
merge requests or patch sets.
### Development Environment
To get started with local development, an instance of aurweb must be
brought up. This can be done using the following sections:
-
[
Using Docker
](
#using-docker
)
-
[
Using INSTALL
](
#using-install
)
There are a number of services aurweb employs to run the application
in its entirety:
-
ssh
-
cron jobs
-
starlette/fastapi asgi server
Project structure:
-
`./aurweb`
:
`aurweb`
Python package
-
`./templates`
: Jinja2 templates
-
`./docker`
: Docker scripts and configuration files
#### Using Docker
Using Docker, we can run the entire infrastructure in two steps:
# Build the aurweb:latest image
$ docker-compose build
# Start all services in the background
$ docker-compose up -d nginx
`docker-compose`
services will generate a locally signed root certificate
at
`./data/root_ca.crt`
. Users can import this into ca-certificates or their
browser if desired.
Accessible services (on the host):
-
https://localhost:8444 (python via nginx)
-
https://localhost:8443 (php via nginx)
-
localhost:13306 (mariadb)
-
localhost:16379 (redis)
Docker services, by default, are setup to be hot reloaded when source code
is changed.
#### Using INSTALL
The
[
INSTALL
](
INSTALL
)
file describes steps to install the application on
bare-metal systems.
aurweb/config.py
View file @
cef3316d
...
...
@@ -6,7 +6,7 @@ from typing import Any
# Publicly visible version of aurweb. This is used to display
# aurweb versioning in the footer and must be maintained.
# Todo: Make this dynamic/automated.
AURWEB_VERSION
=
"v6.0.2
5
"
AURWEB_VERSION
=
"v6.0.2
6
"
_parser
=
None
...
...
aurweb/packages/search.py
View file @
cef3316d
...
...
@@ -12,7 +12,7 @@ from aurweb.models.package_vote import PackageVote
class
PackageSearch
:
"""
A Package search query builder.
"""
"""A Package search query builder."""
# A constant mapping of short to full name sort orderings.
FULL_SORT_ORDER
=
{
"d"
:
"desc"
,
"a"
:
"asc"
}
...
...
@@ -24,14 +24,18 @@ class PackageSearch:
if
self
.
user
:
self
.
query
=
self
.
query
.
join
(
PackageVote
,
and_
(
PackageVote
.
PackageBaseID
==
PackageBase
.
ID
,
PackageVote
.
UsersID
==
self
.
user
.
ID
),
isouter
=
True
and_
(
PackageVote
.
PackageBaseID
==
PackageBase
.
ID
,
PackageVote
.
UsersID
==
self
.
user
.
ID
,
),
isouter
=
True
,
).
join
(
PackageNotification
,
and_
(
PackageNotification
.
PackageBaseID
==
PackageBase
.
ID
,
PackageNotification
.
UserID
==
self
.
user
.
ID
),
isouter
=
True
and_
(
PackageNotification
.
PackageBaseID
==
PackageBase
.
ID
,
PackageNotification
.
UserID
==
self
.
user
.
ID
,
),
isouter
=
True
,
)
self
.
ordering
=
"d"
...
...
@@ -47,7 +51,7 @@ class PackageSearch:
"m"
:
self
.
_search_by_maintainer
,
"c"
:
self
.
_search_by_comaintainer
,
"M"
:
self
.
_search_by_co_or_maintainer
,
"s"
:
self
.
_search_by_submitter
"s"
:
self
.
_search_by_submitter
,
}
# Setup SB (Sort By) callbacks.
...
...
@@ -58,7 +62,7 @@ class PackageSearch:
"w"
:
self
.
_sort_by_voted
,
"o"
:
self
.
_sort_by_notify
,
"m"
:
self
.
_sort_by_maintainer
,
"l"
:
self
.
_sort_by_last_modified
"l"
:
self
.
_sort_by_last_modified
,
}
self
.
_joined_user
=
False
...
...
@@ -66,12 +70,10 @@ class PackageSearch:
self
.
_joined_comaint
=
False
def
_join_user
(
self
,
outer
:
bool
=
True
)
->
orm
.
Query
:
"""
Centralized joining of a package base's maintainer.
"""
"""Centralized joining of a package base's maintainer."""
if
not
self
.
_joined_user
:
self
.
query
=
self
.
query
.
join
(
User
,
User
.
ID
==
PackageBase
.
MaintainerUID
,
isouter
=
outer
User
,
User
.
ID
==
PackageBase
.
MaintainerUID
,
isouter
=
outer
)
self
.
_joined_user
=
True
return
self
.
query
...
...
@@ -87,7 +89,7 @@ class PackageSearch:
self
.
query
=
self
.
query
.
join
(
PackageComaintainer
,
PackageComaintainer
.
PackageBaseID
==
PackageBase
.
ID
,
isouter
=
isouter
isouter
=
isouter
,
)
self
.
_joined_comaint
=
True
return
self
.
query
...
...
@@ -95,8 +97,10 @@ class PackageSearch:
def
_search_by_namedesc
(
self
,
keywords
:
str
)
->
orm
.
Query
:
self
.
_join_user
()
self
.
query
=
self
.
query
.
filter
(
or_
(
Package
.
Name
.
like
(
f
"%
{
keywords
}
%"
),
Package
.
Description
.
like
(
f
"%
{
keywords
}
%"
))
or_
(
Package
.
Name
.
like
(
f
"%
{
keywords
}
%"
),
Package
.
Description
.
like
(
f
"%
{
keywords
}
%"
),
)
)
return
self
...
...
@@ -132,8 +136,7 @@ class PackageSearch:
self
.
_join_user
()
if
keywords
:
self
.
query
=
self
.
query
.
filter
(
and_
(
User
.
Username
==
keywords
,
User
.
ID
==
PackageBase
.
MaintainerUID
)
and_
(
User
.
Username
==
keywords
,
User
.
ID
==
PackageBase
.
MaintainerUID
)
)
else
:
self
.
query
=
self
.
query
.
filter
(
PackageBase
.
MaintainerUID
.
is_
(
None
))
...
...
@@ -197,8 +200,7 @@ class PackageSearch:
# in terms of performance. We should improve this; there's no
# reason it should take _longer_.
column
=
getattr
(
case
([(
models
.
PackageVote
.
UsersID
==
self
.
user
.
ID
,
1
)],
else_
=
0
),
order
case
([(
models
.
PackageVote
.
UsersID
==
self
.
user
.
ID
,
1
)],
else_
=
0
),
order
)
name
=
getattr
(
models
.
Package
.
Name
,
order
)
self
.
query
=
self
.
query
.
order_by
(
column
(),
name
())
...
...
@@ -209,9 +211,8 @@ class PackageSearch:
# in terms of performance. We should improve this; there's no
# reason it should take _longer_.
column
=
getattr
(
case
([(
models
.
PackageNotification
.
UserID
==
self
.
user
.
ID
,
1
)],
else_
=
0
),
order
case
([(
models
.
PackageNotification
.
UserID
==
self
.
user
.
ID
,
1
)],
else_
=
0
),
order
,
)
name
=
getattr
(
models
.
Package
.
Name
,
order
)
self
.
query
=
self
.
query
.
order_by
(
column
(),
name
())
...
...
@@ -239,16 +240,16 @@ class PackageSearch:
return
callback
(
ordering
)
def
count
(
self
)
->
int
:
"""
Return internal query's count.
"""
"""Return internal query's count."""
return
self
.
query
.
count
()
def
results
(
self
)
->
orm
.
Query
:
"""
Return internal query.
"""
"""Return internal query."""
return
self
.
query
class
RPCSearch
(
PackageSearch
):
"""
A PackageSearch-derived RPC package search query builder.
"""A PackageSearch-derived RPC package search query builder.
With RPC search, we need a subset of PackageSearch's handlers,
with a few additional handlers added. So, within the RPCSearch
...
...
@@ -270,52 +271,60 @@ class RPCSearch(PackageSearch):
# We keep: "nd", "n" and "m". We also overlay four new by params
# on top: "depends", "makedepends", "optdepends" and "checkdepends".
self
.
search_by_cb
=
{
k
:
v
for
k
,
v
in
self
.
search_by_cb
.
items
()
k
:
v
for
k
,
v
in
self
.
search_by_cb
.
items
()
if
k
not
in
RPCSearch
.
keys_removed
}
self
.
search_by_cb
.
update
({
"depends"
:
self
.
_search_by_depends
,
"makedepends"
:
self
.
_search_by_makedepends
,
"optdepends"
:
self
.
_search_by_optdepends
,
"checkdepends"
:
self
.
_search_by_checkdepends
})
self
.
search_by_cb
.
update
(
{
"depends"
:
self
.
_search_by_depends
,
"makedepends"
:
self
.
_search_by_makedepends
,
"optdepends"
:
self
.
_search_by_optdepends
,
"checkdepends"
:
self
.
_search_by_checkdepends
,
}
)
# We always want an optional Maintainer in the RPC.
self
.
_join_user
()
def
_join_depends
(
self
,
dep_type_id
:
int
)
->
orm
.
Query
:
"""
Join Package with PackageDependency and filter results
"""Join Package with PackageDependency and filter results
based on `dep_type_id`.
:param dep_type_id: DependencyType ID
:returns: PackageDependency-joined orm.Query
"""
self
.
query
=
self
.
query
.
join
(
models
.
PackageDependency
).
filter
(
models
.
PackageDependency
.
DepTypeID
==
dep_type_id
)
models
.
PackageDependency
.
DepTypeID
==
dep_type_id
)
return
self
.
query
def
_search_by_depends
(
self
,
keywords
:
str
)
->
"RPCSearch"
:
self
.
query
=
self
.
_join_depends
(
DEPENDS_ID
).
filter
(
models
.
PackageDependency
.
DepName
==
keywords
)
models
.
PackageDependency
.
DepName
==
keywords
)
return
self
def
_search_by_makedepends
(
self
,
keywords
:
str
)
->
"RPCSearch"
:
self
.
query
=
self
.
_join_depends
(
MAKEDEPENDS_ID
).
filter
(
models
.
PackageDependency
.
DepName
==
keywords
)
models
.
PackageDependency
.
DepName
==
keywords
)
return
self
def
_search_by_optdepends
(
self
,
keywords
:
str
)
->
"RPCSearch"
:
self
.
query
=
self
.
_join_depends
(
OPTDEPENDS_ID
).
filter
(
models
.
PackageDependency
.
DepName
==
keywords
)
models
.
PackageDependency
.
DepName
==
keywords
)
return
self
def
_search_by_checkdepends
(
self
,
keywords
:
str
)
->
"RPCSearch"
:
self
.
query
=
self
.
_join_depends
(
CHECKDEPENDS_ID
).
filter
(
models
.
PackageDependency
.
DepName
==
keywords
)
models
.
PackageDependency
.
DepName
==
keywords
)
return
self
def
search_by
(
self
,
by
:
str
,
keywords
:
str
)
->
"RPCSearch"
:
"""
Override inherited search_by. In this override, we reduce the
"""Override inherited search_by. In this override, we reduce the
scope of what we handle within this function. We do not set `by`
to a default of "nd" in the RPC, as the RPC returns an error when
incorrect `by` fields are specified.
...
...
@@ -329,6 +338,4 @@ class RPCSearch(PackageSearch):
return
result
def
results
(
self
)
->
orm
.
Query
:
return
self
.
query
.
filter
(
models
.
PackageBase
.
PackagerUID
.
isnot
(
None
)
)
return
self
.
query
.
filter
(
models
.
PackageBase
.
PackagerUID
.
isnot
(
None
))
aurweb/prometheus.py
View file @
cef3316d
...
...
@@ -60,6 +60,9 @@ def http_requests_total() -> Callable[[Info], None]:
labelnames
=
(
"method"
,
"path"
,
"status"
))
def
instrumentation
(
info
:
Info
)
->
None
:
if
info
.
request
.
method
.
lower
()
in
(
"head"
,
"options"
):
# pragma: no cover
return
scope
=
info
.
request
.
scope
# Taken from https://github.com/stephenhillier/starlette_exporter
...
...
@@ -70,8 +73,8 @@ def http_requests_total() -> Callable[[Info], None]:
if
not
(
scope
.
get
(
"endpoint"
,
None
)
and
scope
.
get
(
"router"
,
None
)):
return
None
root_path
=
scope
.
get
(
"root_path"
,
""
)
app
=
scope
.
get
(
"app"
,
{}
)
root_path
=
scope
.
get
(
"root_path"
,
str
()
)
app
=
scope
.
get
(
"app"
,
dict
()
)
if
hasattr
(
app
,
"root_path"
):
app_root_path
=
getattr
(
app
,
"root_path"
)
...
...
@@ -102,6 +105,9 @@ def http_api_requests_total() -> Callable[[Info], None]:
labelnames
=
(
"type"
,
"status"
))
def
instrumentation
(
info
:
Info
)
->
None
:
if
info
.
request
.
method
.
lower
()
in
(
"head"
,
"options"
):
# pragma: no cover
return
if
info
.
request
.
url
.
path
.
rstrip
(
"/"
)
==
"/rpc"
:
type
=
info
.
request
.
query_params
.
get
(
"type"
,
"None"
)
if
info
.
response
:
...
...
pyproject.toml
View file @
cef3316d
...
...
@@ -8,7 +8,7 @@
#
[tool.poetry]
name
=
"aurweb"
version
=
"v6.0.2
5
"
version
=
"v6.0.2
6
"
license
=
"GPL-2.0-only"
description
=
"Source code for the Arch User Repository's website"
homepage
=
"https://aur.archlinux.org"
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment