45 Commits

Author SHA1 Message Date
Elara6331 814fbb1bed Merge branch 'master' into public
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-09 21:12:46 -07:00
Elara6331 c2dec3db36 Set CI platform to linux/amd64
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-09 21:12:29 -07:00
Elara6331 8d80e27336 Add CPU arch constraint
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-09 21:11:09 -07:00
Elara6331 533e20c082 Merge branch 'master' into public
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-09 21:07:14 -07:00
Elara6331 e5150177c4 Update README
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-09 21:06:11 -07:00
Elara6331 6e00419e2f Replace FAQ with About page
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-09 21:04:58 -07:00
Elara6331 48e228adad Redirect to gitea instead of using static install script 2023-08-09 19:49:57 -07:00
Elara6331 42b2e55994 Redesign site 2023-08-09 19:14:07 -07:00
Elara6331 dbe75ce5fd Merge branch 'master' into public
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-16 12:45:13 -07:00
Elara6331 81926a53f9 Update nomad template to use new api server image
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-16 12:43:38 -07:00
Elara6331 eb59764b75 Switch back to upstream drone-nomad image 2023-05-16 12:43:11 -07:00
Elara6331 8c023ab05c Add the ability to get badges for packages 2023-05-16 12:42:36 -07:00
Elara6331 0e6a2fdf2f Merge branch 'master' into public
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-09 09:45:44 -07:00
Elara6331 b5672f2e05 Run npm audit fix
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-09 09:44:29 -07:00
Elara6331 30edd51714 Remove docker.sh
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-09 09:00:55 -07:00
Elara6331 58cf7a72bb Move api url setting to docker build arg
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-09 08:58:36 -07:00
Elara6331 d23da62dfc Use my fork of the drone-nomad image
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-05 15:11:21 +00:00
Elara6331 cb38468ddd Update videos
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-04 18:04:31 -07:00
Elara6331 fffc7a0b40 Update domain 2023-05-04 17:18:35 -07:00
Elara6331 ff8f176120 Provide github secret
ci/woodpecker/push/woodpecker Pipeline was successful
2023-05-04 15:14:01 -07:00
Elara6331 41d3d712e4 Set deploy to only happen on push to public
ci/woodpecker/push/woodpecker Pipeline failed
2023-05-04 15:11:44 -07:00
Elara6331 480c3ac20d Add nomad template
ci/woodpecker/push/woodpecker Pipeline failed
2023-05-04 15:10:09 -07:00
Elara6331 b717e3b131 Add woodpecker file
ci/woodpecker/push/woodpecker Pipeline failed
2023-05-04 14:59:56 -07:00
Elara6331 0f7c55a4d8 Update domain 2023-04-20 20:07:23 -07:00
Elara6331 4073538ee6 Merge pull request #4 from nxjosephofficial/master
Replace lure-bin with linux-user-repository-bin
2023-04-08 21:55:17 +00:00
nxjosephofficial d7a47f2963 Replace lure-bin with linux-user-repository-bin 2023-04-08 23:59:08 +03:00
Elara6331 3f3867da00 Provide SVG LURE icons 2022-12-25 22:02:17 -08:00
Elara6331 38d191fa53 Improve wording and add more information to the FAQ 2022-12-25 21:28:17 -08:00
Elara6331 bbe139f779 Fix page flickering 2022-12-25 19:29:30 -08:00
Elara6331 a0df472552 Switch to dark footer 2022-12-25 17:20:41 -08:00
Elara6331 8aafff96dc Add new footer 2022-12-25 17:10:35 -08:00
Elara6331 688cd83481 Convert text in header logo to path 2022-12-22 09:25:06 -08:00
Elara6331 4c4916159d Use new logo 2022-12-22 00:25:46 -08:00
Elara6331 e6d71b9b3f Use dynamic import as Vime does not work in SSR 2022-12-21 14:05:30 -08:00
Elara6331 321113aec5 Improve video quality 2022-12-21 13:39:27 -08:00
Elara6331 aac1fbfd1d Switch to video player instead of GIF 2022-12-21 13:26:39 -08:00
Elara6331 5a90de4ef5 Disable docker build cache 2022-12-21 11:36:39 -08:00
Elara6331 65e297d792 Don't provide SPDX link for custom licenses 2022-12-21 11:22:52 -08:00
Elara6331 42469e9ef8 Add meta description tags 2022-12-21 11:16:15 -08:00
Elara6331 f18b76424e Add title tags 2022-12-21 11:09:29 -08:00
Elara6331 18cf85ee9d Switch to AGPLv3 2022-12-20 22:24:30 -08:00
Elara6331 76d7bd8d6d Fix dockerfile 2022-12-20 14:24:22 -08:00
Elara6331 e3f7a5667c Add docker build script 2022-12-20 14:22:54 -08:00
Elara6331 ddec44c807 Add Dockerfile 2022-12-20 14:03:40 -08:00
Elara6331 cea2117b56 Initial Commit 2022-12-20 11:54:09 -08:00
59 changed files with 8658 additions and 1629 deletions
+13
View File
@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
+20
View File
@@ -0,0 +1,20 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['svelte3', '@typescript-eslint'],
ignorePatterns: ['*.cjs'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': () => require('typescript')
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
env: {
browser: true,
es2017: true,
node: true
}
};
+10 -1
View File
@@ -1 +1,10 @@
/lure-web
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
+1
View File
@@ -0,0 +1 @@
engine-strict=true
+13
View File
@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
+9
View File
@@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}
+24 -12
View File
@@ -1,15 +1,27 @@
platform: linux/amd64
steps:
docker:
image: gitea.elara.ws/elara6331/builder
environment:
- REGISTRY=gitea.elara.ws
- REGISTRY_USERNAME=Elara6331
- KO_DOCKER_REPO=gitea.elara.ws/lure
- KO_DEFAULTBASEIMAGE=gitea.elara.ws/elara6331/static
secrets: [ registry_password ]
commands:
- registry-login
- ko build -B --platform=linux/amd64,linux/arm64,linux/riscv64 -t latest,${CI_COMMIT_TAG} --sbom=none
publish:
image: woodpeckerci/plugin-docker-buildx
secrets: [docker_username, docker_password]
settings:
repo: elara6331/lure-web
dockerfile: docker/Dockerfile
platforms: linux/amd64,linux/arm64
build_args: api_url=https://api.lure.elara.ws
tag: latest
when:
event: tag
branch: public
event: push
deploy:
image: loq9/drone-nomad
secrets: [lure_api_github_secret]
settings:
addr: http://192.168.100.62:4646
template: template.nomad
environment:
- PLUGIN_WATCH_DEPLOYMENT=true
- PLUGIN_WATCH_DEPLOYMENT_TIMEOUT=10m
when:
branch: public
event: push
+2 -68
View File
@@ -1,69 +1,3 @@
# lure-web
`lure-web` is a website for LURE and a web interface that lets users search and get information about LURE's packages.
LURE Web is powered by [Salix](https://gitea.elara.ws/Elara6331/salix) and [PicoCSS](https://picocss.com/).
## API
### Search Packages
- **Endpoint:** `GET /api/search`
- **Description:** Search for packages based on specified search options.
- **Parameters:**
- None
- **Query Parameters:**
- `sort` (optional) - Sort the results by a specific attribute.
- Possible values: "name", "version", "repo"
- `filter` (optional) - Apply a filter to narrow down the search results.
- Possible values: "inrepo", "arch"
- `fv` (optional) - Filter value to be used based on the selected filter.
- `q` (optional) - The search query string.
- **Response:**
- Content-Type: application/json
- Body: List of translated packages based on search criteria.
### Get Package Information
- **Endpoint:** `GET /api/pkg/:repo/:pkg`
- **Description:** Get detailed information about a specific package.
- **Parameters:**
- `:repo` - Repository name
- `:pkg` - Package name
- **Response:**
- Content-Type: application/json
- Body: Translated information about the specified package.
### Get Package Script
- **Endpoint:** `GET /api/pkg/:repo/:pkg/script`
- **Description:** Get the script associated with a specific package.
- **Parameters:**
- `:repo` - Repository name
- `:pkg` - Package name
- **Query Parameters:**
- `highlight` (optional) - If set to `true`, the script will be returned with syntax highlighting.
- **Response:**
- If `highlight` is `true`:
- Content-Type: text/html
- Body: Script with syntax highlighting in HTML format.
- If `highlight` is not provided or set to "false":
- Content-Type: text/x-shellscript
- Body: Raw script content.
### Language Translation
- **Header:** `Accept-Language`
- Use the Accept-Language header to specify the preferred language for response translations.
- **Query Parameter:** `lang`
- You can also include a `lang` query parameter instead of `Accept-Language` to specify the translation language.
### Error Handling
- **Response:**
- Content-Type: application/json
- Body: A JSON object with a single `error` string field containing an explanation of the error.
---
# LURE Web
LURE Web is a website for LURE and a web interface that allows users to search LURE packages
-73
View File
@@ -1,73 +0,0 @@
package main
import (
"io"
"net/http"
"github.com/rs/cors"
"github.com/uptrace/bunrouter"
"lure.sh/lure/pkg/loggerctx"
"lure.sh/lure/pkg/search"
"go.elara.ws/logger/log"
)
func registerAPI(mux *bunrouter.Router) {
g := mux.NewGroup(
"/api",
bunrouter.WithMiddleware(apiErrorHandler, corsMiddleware()),
)
g.GET("/*path", func(w http.ResponseWriter, req bunrouter.Request) error {
return HTTPError{404, "endpoint not found: " + req.URL.Path}
})
g.GET("/search", func(w http.ResponseWriter, req bunrouter.Request) error {
ctx := loggerctx.With(req.Context(), log.Logger)
pkgs, err := search.Search(ctx, searchOptions(req.Request))
if err != nil {
return err
}
return bunrouter.JSON(w, translatePkgs(getLanguages(req.Request), pkgs))
})
g.GET("/pkg/:repo/:pkg", func(w http.ResponseWriter, req bunrouter.Request) error {
ctx := loggerctx.With(req.Context(), log.Logger)
pkg, err := search.GetPkg(ctx, req.Param("repo"), req.Param("pkg"))
if err != nil {
return err
}
return bunrouter.JSON(w, translatePkg(getLanguages(req.Request), pkg))
})
g.GET("/pkg/:repo/:pkg/script", func(w http.ResponseWriter, req bunrouter.Request) error {
ctx := loggerctx.With(req.Context(), log.Logger)
script, err := search.GetScript(ctx, req.Param("repo"), req.Param("pkg"))
if err != nil {
return err
}
defer script.Close()
if req.URL.Query().Get("highlight") == "true" {
data, err := highlight(script)
if err != nil {
return err
}
w.Header().Set("Content-Type", "text/html")
_, err = io.WriteString(w, string(data))
return err
} else {
w.Header().Set("Content-Type", "text/x-shellscript")
_, err = io.Copy(w, script)
return err
}
})
}
func corsMiddleware() bunrouter.MiddlewareFunc {
ch := cors.AllowAll()
return func(next bunrouter.HandlerFunc) bunrouter.HandlerFunc {
return bunrouter.HTTPHandler(ch.Handler(next))
}
}
-89
View File
@@ -1,89 +0,0 @@
package main
import (
"context"
_ "embed"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"strings"
"github.com/uptrace/bunrouter"
"lure.sh/lure/pkg/search"
)
type pkgCtxKey struct{}
//go:embed static/icons/badge-logo.base64
var logoData string
// registerBadge registers the route for generating LURE badges
func registerBadge(mux *bunrouter.Router) {
// rp is a reverse proxy that will route user requests to shields.io
// and return the responses, stripped of any irrelevant headers.
rp := &httputil.ReverseProxy{
Rewrite: func(pr *httputil.ProxyRequest) {
pkg := pr.In.Context().Value(pkgCtxKey{}).(search.Package)
pr.Out.URL = genBadgeURL(pkg, pr.In.URL.Query().Get("style"))
pr.Out.Host = pr.Out.URL.Host
},
ModifyResponse: func(r *http.Response) error {
// Remove all the irrelevant headers from the response.
r.Header.Del("Alt-Svc")
r.Header.Del("Cache-Control")
r.Header.Del("Report-To")
r.Header.Del("Cf-Cache-Status")
r.Header.Del("Cf-Ray")
r.Header.Del("Fly-Request-Id")
r.Header.Del("Nel")
r.Header.Del("Report-To")
r.Header.Del("Server")
r.Header.Del("Via")
r.Header.Del("Set-Cookie")
return nil
},
}
mux.GET("/pkg/:repo/:pkg/badge.svg", func(w http.ResponseWriter, req bunrouter.Request) error {
repo := req.Param("repo")
name := req.Param("pkg")
pkg, err := search.GetPkg(req.Context(), repo, name)
if err != nil {
return err
}
ctx := context.WithValue(req.Context(), pkgCtxKey{}, pkg)
rp.ServeHTTP(w, req.Request.WithContext(ctx))
return nil
})
}
func genBadgeURL(pkg search.Package, style string) *url.URL {
v := url.Values{}
v.Set("label", pkg.Name)
v.Set("message", genBadgeVersion(pkg))
v.Set("logo", logoData)
v.Set("color", "0060A8")
if style != "" {
v.Set("style", style)
}
return &url.URL{Scheme: "https", Host: "img.shields.io", Path: "/static/v1", RawQuery: v.Encode()}
}
func genBadgeVersion(pkg search.Package) string {
sb := strings.Builder{}
if pkg.Epoch != 0 {
sb.WriteString(strconv.Itoa(int(pkg.Epoch)))
sb.WriteByte(':')
}
sb.WriteString(pkg.Version)
if pkg.Release != 0 {
sb.WriteByte('-')
sb.WriteString(strconv.Itoa(pkg.Release))
}
return sb.String()
}
+13
View File
@@ -0,0 +1,13 @@
FROM node:19-alpine
ARG api_url
ENV LURE_WEB_API_URL $api_url
RUN apk add git
RUN git clone https://gitea.elara.ws/Elara6331/lure-web
RUN cd lure-web && \
npm i && \
npm run build
WORKDIR /lure-web
ENTRYPOINT node build
-90
View File
@@ -1,90 +0,0 @@
package main
import (
"database/sql"
"errors"
"net/http"
"github.com/uptrace/bunrouter"
"go.elara.ws/logger/log"
"go.elara.ws/salix"
)
type HTTPError struct {
StatusCode int `json:"status_code"`
Msg string `json:"error"`
}
func (he HTTPError) Error() string {
return he.Msg
}
func (he HTTPError) StatusText() string {
return http.StatusText(he.StatusCode)
}
func httpError(err error) *HTTPError {
switch err := err.(type) {
case nil:
return nil
case HTTPError:
return &err
case *HTTPError:
return err
default:
switch {
case errors.Is(err, sql.ErrNoRows):
return &HTTPError{404, err.Error()}
default:
return &HTTPError{500, err.Error()}
}
}
}
func siteErrorHandler(ns *salix.Namespace) bunrouter.MiddlewareFunc {
return func(next bunrouter.HandlerFunc) bunrouter.HandlerFunc {
tmpl, ok := ns.GetTemplate("error.html")
if !ok {
return basicErrorHandler(next)
}
return func(w http.ResponseWriter, req bunrouter.Request) error {
err := next(w, req)
if err != nil {
he := httpError(err)
w.WriteHeader(he.StatusCode)
err := tmpl.
WithVarMap(map[string]any{"error": he}).
Execute(w)
if err != nil {
log.Error("Error while executing error template").Err(err).Send()
}
}
return err
}
}
}
func apiErrorHandler(next bunrouter.HandlerFunc) bunrouter.HandlerFunc {
return func(w http.ResponseWriter, req bunrouter.Request) error {
err := next(w, req)
if err != nil {
he := httpError(err)
w.WriteHeader(he.StatusCode)
_ = bunrouter.JSON(w, map[string]string{"error": he.Msg})
}
return err
}
}
func basicErrorHandler(next bunrouter.HandlerFunc) bunrouter.HandlerFunc {
return func(w http.ResponseWriter, req bunrouter.Request) error {
err := next(w, req)
if err != nil {
he := httpError(err)
http.Error(w, he.Msg, he.StatusCode)
}
return err
}
}
-68
View File
@@ -1,68 +0,0 @@
module lure.sh/lure-web
go 1.21.2
toolchain go1.21.6
require (
github.com/alecthomas/chroma/v2 v2.9.1
github.com/rs/cors v1.10.1
github.com/uptrace/bunrouter v1.0.21
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090
go.elara.ws/salix v0.0.0-20240119074218-9bf56b50a461
golang.org/x/text v0.13.0
lure.sh/lure v0.1.4-0.20231223033536-5dc31f43aa39
)
require (
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-git/go-git/v5 v5.9.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gookit/color v1.5.1 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/skeema/knownhosts v1.2.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/term v0.12.0 // indirect
golang.org/x/tools v0.13.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
lure.sh/fakeroot v0.0.0-20231024000108-b130d64a68ee // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.24.1 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.6.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sqlite v1.25.0 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
mvdan.cc/sh/v3 v3.7.0 // indirect
)
-245
View File
@@ -1,245 +0,0 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/chroma/v2 v2.9.1 h1:0O3lTQh9FxazJ4BYE/MOi/vDGuHn7B+6Bu902N2UZvU=
github.com/alecthomas/chroma/v2 v2.9.1/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY=
github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ=
github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/uptrace/bunrouter v1.0.21 h1:HXarvX+N834sXyHpl+I/TuE11m19kLW/qG5u3YpHUag=
github.com/uptrace/bunrouter v1.0.21/go.mod h1:TwT7Bc0ztF2Z2q/ZzMuSVkcb/Ig/d3MQeP2cxn3e1hI=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090 h1:RVC8XvWo6Yw4HUshqx4TSzuBDScDghafU6QFRJ4xPZg=
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090/go.mod h1:qng49owViqsW5Aey93lwBXONw20oGbJIoLVscB16mPM=
go.elara.ws/salix v0.0.0-20240119074218-9bf56b50a461 h1:vVyRue86HMRBEguyDUoarLEQjVKQ/r8x6kX3qGgvVkM=
go.elara.ws/salix v0.0.0-20240119074218-9bf56b50a461/go.mod h1:niWia13iw7qDrS1C1mlqv5hxO1sunt8CcOQAB5yVlNU=
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4 h1:Ep54XceQlKhcCHl9awG+wWP4kz4kIP3c3Lzw/Gc/zwY=
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4/go.mod h1:/7PNW7nFnDR5W7UXZVc04gdVLR/wBNgkm33KgIz0OBk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lure.sh/fakeroot v0.0.0-20231024000108-b130d64a68ee h1:kSXIuMid56Q29WEl7EQb5QUtmGqQqAu66EZ2G0OSUfU=
lure.sh/fakeroot v0.0.0-20231024000108-b130d64a68ee/go.mod h1:/v0u0AZ+wbzUWhV02KzciOf1KFNh7/7rbkz5Z0b5gDA=
lure.sh/lure v0.1.4-0.20231223033536-5dc31f43aa39 h1:9Rw9+Pmmkbjxiq0eREq4RJPn+ggL1jYFpgrgOkgQ9YQ=
lure.sh/lure v0.1.4-0.20231223033536-5dc31f43aa39/go.mod h1:h1+OIDD39zDosjThxQ9szoWW9Z1lGcm7M6eeo6v0OJY=
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
-49
View File
@@ -1,49 +0,0 @@
package main
import (
"context"
"embed"
"net/http"
"os"
"github.com/uptrace/bunrouter"
"go.elara.ws/logger"
"go.elara.ws/logger/log"
"lure.sh/lure/pkg/loggerctx"
"lure.sh/lure/pkg/repos"
)
//go:embed static
var static embed.FS
func init() {
log.Logger = logger.NewPretty(os.Stderr)
}
func main() {
mux := bunrouter.New()
fileServer := http.FileServer(http.FS(static))
mux.Use(cache).GET("/static/*path", bunrouter.HTTPHandler(fileServer))
ctx := loggerctx.With(context.Background(), log.Logger)
err := repos.Pull(ctx, nil)
if err != nil {
log.Fatal("Error pulling repos").Err(err).Send()
}
registerBadge(mux)
registerSite(mux)
registerAPI(mux)
registerWebhook(ctx, mux)
http.ListenAndServe(":8080", mux)
}
func cache(next bunrouter.HandlerFunc) bunrouter.HandlerFunc {
return bunrouter.HandlerFunc(func(w http.ResponseWriter, req bunrouter.Request) error {
w.Header().Set("Cache-Control", "max-age=86400, stale-while-revalidate=86400")
return next(w, req)
})
}
+5417
View File
File diff suppressed because it is too large Load Diff
+42
View File
@@ -0,0 +1,42 @@
{
"name": "lure-web",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@iconify/svelte": "^3.0.1",
"@sveltejs/adapter-auto": "^1.0.0",
"@sveltejs/adapter-node": "^1.0.0",
"@sveltejs/kit": "^1.0.0",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"bulma": "^0.9.4",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte3": "^4.0.0",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.8.1",
"sass": "^1.53.0",
"svelte": "^3.54.0",
"svelte-check": "^2.9.2",
"svelte-highlight": "^6.2.1",
"svelte-loading-spinners": "^0.3.4",
"svelte-preprocess": "^4.10.7",
"tslib": "^2.4.1",
"typescript": "^4.9.3",
"vite": "^4.0.0"
},
"type": "module",
"dependencies": {
"protoscript": "^0.0.14",
"twirpscript": "^0.0.66"
}
}
-111
View File
@@ -1,111 +0,0 @@
package main
import (
"fmt"
"net/http"
"golang.org/x/text/language"
"lure.sh/lure/pkg/search"
)
type Package struct {
Name string `json:"name"`
Repository string `json:"repository"`
Version string `json:"version"`
Release int `json:"release"`
Epoch uint `json:"epoch"`
Description string `json:"description"`
Homepage string `json:"homepage"`
Maintainer string `json:"maintainer"`
Architectures []string `json:"architectures"`
Licenses []string `json:"licenses"`
Provides []string `json:"provides"`
Conflicts []string `json:"conflicts"`
Replaces []string `json:"replaces"`
Depends map[string][]string `json:"depends"`
BuildDepends map[string][]string `json:"build_depends"`
}
func (p Package) FullVersion() string {
ver := fmt.Sprintf("%s-%d", p.Version, p.Release)
if p.Epoch != 0 {
ver = fmt.Sprintf("%d:%s", p.Epoch, ver)
}
return ver
}
func translatePkgs(langs []string, pkgs []search.Package) []Package {
out := make([]Package, len(pkgs))
for i, pkg := range pkgs {
out[i] = translatePkg(langs, pkg)
}
return out
}
func translatePkg(langs []string, pkg search.Package) Package {
return Package{
Name: pkg.Name,
Repository: pkg.Repository,
Version: pkg.Version,
Release: pkg.Release,
Epoch: pkg.Epoch,
Description: performTranslation(langs, pkg.Description),
Homepage: performTranslation(langs, pkg.Homepage),
Maintainer: performTranslation(langs, pkg.Maintainer),
Architectures: pkg.Architectures,
Licenses: pkg.Licenses,
Provides: pkg.Provides,
Conflicts: pkg.Conflicts,
Depends: pkg.Depends,
BuildDepends: pkg.BuildDepends,
}
}
func getLanguages(req *http.Request) []string {
al := req.Header.Get("Accept-Language")
lang := req.URL.Query().Get("lang")
if al == "" && lang == "" {
return nil
}
tags, _, _ := language.ParseAcceptLanguage(al)
if lang != "" {
langTag, err := language.Parse(lang)
if err == nil {
tags = append(tags, langTag)
}
}
return getLangBases(tags)
}
func getLangBases(langs []language.Tag) []string {
out := make([]string, len(langs)+1)
for i, lang := range langs {
base, _ := lang.Base()
out[i] = base.String()
}
return out
}
func performTranslation(langs []string, v map[string]string) string {
if len(langs) == 0 {
val, ok := v[""]
if !ok {
return "<unknown>"
}
return val
}
for _, name := range langs {
val, ok := v[name]
if !ok {
continue
}
return val
}
return "<unknown>"
}
-198
View File
@@ -1,198 +0,0 @@
package main
import (
"embed"
"io"
"io/fs"
"net/http"
"strings"
"time"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
"github.com/uptrace/bunrouter"
"go.elara.ws/logger/log"
"go.elara.ws/salix"
"lure.sh/lure/pkg/loggerctx"
"lure.sh/lure/pkg/search"
)
//go:embed tmpls
var tmpls embed.FS
func registerSite(mux *bunrouter.Router) {
tmplFS, err := fs.Sub(tmpls, "tmpls")
if err != nil {
panic(err)
}
ns := salix.New().
WithEscapeHTML(true).
WithWriteOnSuccess(true).
WithVarMap(map[string]any{
"now": time.Now,
})
err = ns.ParseFSGlob(tmplFS, "*.html")
if err != nil {
panic(err)
}
g := mux.WithMiddleware(siteErrorHandler(ns))
g.GET("/*path", func(w http.ResponseWriter, req bunrouter.Request) error {
if req.Param("path") == "" {
return ns.ExecuteTemplate(w, "home.html", nil)
}
return HTTPError{404, "page not found: " + req.URL.Path}
})
g.GET("/install", func(w http.ResponseWriter, req bunrouter.Request) error {
http.Redirect(w, req.Request, "https://gitea.elara.ws/lure/lure/raw/branch/master/scripts/install.sh", http.StatusFound)
return nil
})
g.GET("/about", func(w http.ResponseWriter, req bunrouter.Request) error {
return ns.ExecuteTemplate(w, "about.html", nil)
})
g.GET("/icons", func(w http.ResponseWriter, req bunrouter.Request) error {
return ns.ExecuteTemplate(w, "icons.html", nil)
})
g.GET("/pkgs", func(w http.ResponseWriter, req bunrouter.Request) error {
ctx := loggerctx.With(req.Context(), log.Logger)
pkgs, err := search.Search(ctx, searchOptions(req.Request))
if err != nil {
return err
}
return ns.ExecuteTemplate(w, "pkgs.html", map[string]any{
"pkgs": translatePkgs(getLanguages(req.Request), pkgs),
"query": req.URL.Query(),
})
})
g.GET("/pkg/:repo/:pkg", func(w http.ResponseWriter, req bunrouter.Request) error {
ctx := loggerctx.With(req.Context(), log.Logger)
pkg, err := search.GetPkg(ctx, req.Param("repo"), req.Param("pkg"))
if err != nil {
return err
}
return ns.ExecuteTemplate(w, "pkg.html", map[string]any{
"url": getURL(req.Request),
"pkg": translatePkg(getLanguages(req.Request), pkg),
})
})
g.GET("/pkg/:repo/:pkg/script", func(w http.ResponseWriter, req bunrouter.Request) error {
repoName := req.Param("repo")
pkgName := req.Param("pkg")
ctx := loggerctx.With(req.Context(), log.Logger)
script, err := search.GetScript(ctx, repoName, pkgName)
if err != nil {
return err
}
defer script.Close()
data, err := highlight(script)
if err != nil {
return err
}
return ns.ExecuteTemplate(w, "script.html", map[string]any{
"repoName": repoName,
"pkgName": pkgName,
"script": data,
})
})
}
// searchOptions gets a search.Options struct from the request's
// query parameters.
func searchOptions(r *http.Request) search.Options {
sort := search.SortBy(search.SortByNone)
switch r.URL.Query().Get("sort") {
case "name":
sort = search.SortByName
case "version":
sort = search.SortByVersion
case "repo":
sort = search.SortByRepo
}
filter := search.FilterNone
switch r.URL.Query().Get("filter") {
case "inrepo":
filter = search.FilterInRepo
case "arch":
filter = search.FilterSupportsArch
}
return search.Options{
Filter: filter,
FilterValue: r.URL.Query().Get("fv"),
SortBy: sort,
Query: r.URL.Query().Get("q"),
}
}
// highlight returns an HTML string with syntax highlighting
// for the contents of the given reader.
func highlight(r io.Reader) (salix.HTML, error) {
data, err := io.ReadAll(r)
if err != nil {
panic(err)
}
lexer := lexers.Get("bash")
if lexer == nil {
lexer = lexers.Fallback
}
lexer = chroma.Coalesce(lexer)
style := styles.Get("modus-vivendi")
formatter := html.New()
iterator, err := lexer.Tokenise(nil, string(data))
if err != nil {
return "", err
}
out := &strings.Builder{}
err = formatter.Format(out, style, iterator)
if err != nil {
return "", err
}
return salix.HTML(out.String()), nil
}
// getURL attempts to get the current URL of the request
func getURL(r *http.Request) string {
u := *r.URL
xfp := r.Header.Get("X-Forwarded-Proto")
if xfp == "" {
if r.TLS == nil {
u.Scheme = "http"
} else {
u.Scheme = "https"
}
} else {
u.Scheme = xfp
}
xfh := r.Header.Get("X-Forwarded-Host")
if xfh == "" {
if r.URL.Host == "" {
u.Host = r.Host
}
} else {
u.Host = xfh
}
return u.String()
}
+9
View File
@@ -0,0 +1,9 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
+13
View File
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@vime/core@^5/themes/default.css" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div id="page-container">%sveltekit.body%</div>
</body>
</html>
+68
View File
@@ -0,0 +1,68 @@
/* Write your global styles here, in SCSS syntax. Variables and mixins from the src/variables.scss file are available here without importing */ /* Import only what you need from Bulma */
@import 'bulma/sass/utilities/_all';
@import 'bulma/sass/base/_all';
@import 'bulma/sass/elements/_all';
@import 'bulma/sass/form/_all';
@import 'bulma/sass/components/_all';
@import 'bulma/sass/grid/_all';
@import 'bulma/sass/helpers/_all';
@import 'bulma/sass/layout/_all';
@import './darkly/overrides.scss';
.input::placeholder {
color: darken($grey-light, 10) !important;
opacity: 1;
}
.input::-webkit-input-placeholder {
color: darken($grey-light, 10) !important;
opacity: 1;
}
.input::-moz-placeholder {
color: darken($grey-light, 10) !important;
opacity: 1;
}
.input::-ms-input-placeholder {
color: darken($grey-light, 10) !important;
opacity: 1;
}
pre {
background-color: transparent;
}
.terminal-player {
max-width: 735px;
max-height: 450px;
}
.sc-carousel__carousel-container {
--sc-arrow-size: 3px;
}
button.sc-carousel-arrow__circle {
width: 30px !important;
height: 30px !important;
}
body {
margin: 0;
}
#page-container {
display: flex;
flex-direction: column;
min-height: 100vh;
}
#page-container > * {
width: 100%
}
.hljs {
background: $grey-darker !important;
border-radius: 15px;
}
+291
View File
@@ -0,0 +1,291 @@
////////////////////////////////////////////////
// DARKLY
////////////////////////////////////////////////
// Overrides
hr {
height: $border-width;
}
h6 {
text-transform: uppercase;
letter-spacing: 0.5px;
}
.hero {
background-color: $grey-dark;
}
a {
transition: all 200ms ease;
}
.button {
transition: all 200ms ease;
border-width: $border-width;
color: $white;
&.is-active,
&.is-focused,
&:active,
&:focus {
box-shadow: 0 0 0 2px rgba($button-focus-border-color, 0.5);
}
@each $name, $pair in $colors {
$color: nth($pair, 1);
$color-invert: nth($pair, 2);
&.is-#{$name} {
&.is-hovered,
&:hover {
background-color: lighten($color, 7.5%);
}
&.is-active,
&.is-focused,
&:active,
&:focus {
border-color: $color;
box-shadow: 0 0 0 2px rgba($color, 0.5);
}
}
}
}
.label {
color: $grey-lighter;
}
.input,
.textarea {
transition: all 200ms ease;
box-shadow: none;
border-width: $border-width;
padding-left: 1em;
padding-right: 1em;
background-color: $body-background-color;
color: $text
}
.select {
&:after,
select {
border-width: $border-width;
background-color: $body-background-color;
color: $text
}
}
.control {
&.has-addons {
.button,
.input,
.select {
margin-right: -$border-width;
}
}
}
.notification {
background-color: $grey-dark;
}
.card {
$card-border-color: lighten($grey-darker, 5);
box-shadow: none;
border: $border-width solid $card-border-color;
background-color: $grey-darker;
border-radius: $radius;
.card-image {
img {
border-radius: $radius $radius 0 0;
}
}
.card-header {
box-shadow: none;
background-color: rgba($black-bis, 0.2);
border-radius: $radius $radius 0 0;
}
.card-footer {
background-color: rgba($black-bis, 0.2);
}
.card-footer,
.card-footer-item {
border-width: $border-width;
border-color: $card-border-color;
}
}
.notification {
@each $name, $pair in $colors {
$color: nth($pair, 1);
$color-invert: nth($pair, 2);
&.is-#{$name} {
a:not(.button) {
color: $color-invert;
text-decoration: underline;
}
}
}
}
.tag {
border-radius: $radius;
}
.menu-list {
a {
transition: all 300ms ease;
}
}
.modal-card-body {
background-color: $grey-darker;
}
.modal-card-foot,
.modal-card-head {
border-color: $grey-dark;
}
.message-header {
font-weight: $weight-bold;
background-color: $grey-dark;
color: $white;
}
.message-body {
border-width: $border-width;
border-color: $grey-dark;
}
.navbar {
border-radius: $radius;
&.is-transparent {
background: none;
}
&.is-primary {
.navbar-dropdown {
a.navbar-item.is-active {
background-color: $link;
}
}
}
@include until($navbar-breakpoint) {
.navbar-menu {
background-color: $navbar-background-color;
border-radius: 0 0 $radius $radius;
}
}
}
.hero .navbar,
body > .navbar {
border-radius: 0;
}
.pagination-link,
.pagination-next,
.pagination-previous {
border-width: $border-width;
}
.panel-block,
.panel-heading,
.panel-tabs {
border-width: $border-width;
&:first-child {
border-top-width: $border-width;
}
}
.panel-heading {
font-weight: $weight-bold;
}
.panel-tabs {
a {
border-width: $border-width;
margin-bottom: -$border-width;
&.is-active {
border-bottom-color: $link-active;
}
}
}
.panel-block {
&:hover {
color: $link-hover;
.panel-icon {
color: $link-hover;
}
}
&.is-active {
.panel-icon {
color: $link-active;
}
}
}
.tabs {
a {
border-bottom-width: $border-width;
margin-bottom: -$border-width;
}
ul {
border-bottom-width: $border-width;
}
&.is-boxed {
a {
border-width: $border-width;
}
li.is-active a {
background-color: darken($grey-darker, 4);
}
}
&.is-toggle {
li a {
border-width: $border-width;
margin-bottom: 0;
}
li + li {
margin-left: -$border-width;
}
}
}
.hero {
// Colors
@each $name, $pair in $colors {
$color: nth($pair, 1);
$color-invert: nth($pair, 2);
&.is-#{$name} {
.navbar {
.navbar-dropdown {
.navbar-item:hover {
background-color: $navbar-dropdown-item-hover-background-color;
}
}
}
}
}
}
+121
View File
@@ -0,0 +1,121 @@
////////////////////////////////////////////////
// DARKLY
////////////////////////////////////////////////
// Variables
$grey-lighter: #9c9fa2;
$grey-light: #7e8185;
$grey: darken($grey-light, 16);
$grey-dark: darken($grey, 16);
$grey-darker: darken($grey, 23);
$white: #dddedf;
$orange: #DF691A;
$yellow: #f1b70e;
$green: #2ecc71;
$turquoise: #00FDBA;
$blue: #3498db;
$purple: #8e44ad;
$red: #e74c3c;
$white-ter: #ecf0f1;
$primary: #0060a8 !default;
$yellow-invert: #fff;
$family-sans-serif: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI",
"Helvetica Neue", "Helvetica", "Arial", sans-serif;
$family-monospace: "Inconsolata", "Consolas", "Monaco", monospace;
$radius-small: 3px;
$radius: 0.4em;
$radius-large: 8px;
$size-6: 15px;
$size-7: 0.85em;
$title-weight: 500;
$subtitle-weight: 400;
$subtitle-color: $grey-lighter;
$border-width: 2px;
$border: $grey;
$body-background-color: darken($grey-darker, 4);
$body-size: 15px;
$background: $grey-darker;
$footer-background-color: $background;
$button-background-color: $background;
$button-border-color: lighten($button-background-color, 15);
$title-color: $white;
$subtitle-color: $grey-lighter;
$subtitle-strong-color: $grey-light;
$text: $white;
$text-light: lighten($text, 10);
$text-strong: darken($text, 5);
$box-color: $text;
$box-background-color: $grey-dark;
$box-shadow: none;
$link: $turquoise;
$link-hover: lighten($link, 5);
$link-focus: darken($link, 5);
$link-active: darken($link, 5);
$link-focus-border: $grey-light;
$button-color: $primary;
$button-hover-color: darken($text, 5); // text-dark
$button-focus: darken($text, 5); // text-dark
$button-active-color: darken($text, 5); // text-dark
$button-disabled-background-color: $grey-light;
$button-focus-border-color: $link-focus-border;
$control-height: 2.5em;
$input-color: $grey-darker;
$input-icon-color: $grey;
$input-icon-active-color: $input-color;
$input-hover-color: $grey-light;
$input-disabled-background-color: $grey-light;
$input-disabled-border: $grey-lighter;
$table-color: $text;
$table-head: $grey-lighter;
$table-background-color: $grey-dark;
$table-cell-border: 1px solid $grey;
$table-row-hover-background-color: $grey-darker;
$table-striped-row-even-background-color: $grey-darker;
$table-striped-row-even-hover-background-color: lighten($grey-darker, 2);
$pagination-color: $link;
$pagination-border-color: $border;
$navbar-height: 4rem;
$navbar-background-color: $primary;
$navbar-item-color: $text;
$navbar-item-hover-color: $link;
$navbar-item-hover-background-color: transparent;
$navbar-item-active-color: $link;
$navbar-dropdown-arrow: #fff;
$navbar-divider-background-color: rgba(0, 0, 0, 0.2);
$navbar-dropdown-border-top: 1px solid $navbar-divider-background-color;
$navbar-dropdown-background-color: $primary;
$navbar-dropdown-item-hover-color: $grey-lighter;
$navbar-dropdown-item-hover-background-color: transparent;
$navbar-dropdown-item-active-background-color: transparent;
$navbar-dropdown-item-active-color: $link;
$dropdown-content-background-color: $background;
$dropdown-item-color: $text;
$progress-value-background-color: $grey-lighter;
$bulmaswatch-import-font: true !default;
$file-cta-background-color: $grey-darker;
$progress-bar-background-color: $grey-dark;
$panel-heading-background-color: $grey-dark;
+1830
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
<script>
import '../app.scss';
</script>
<slot />
+50
View File
@@ -0,0 +1,50 @@
<script>
import Header from './header.svelte';
import Footer from './footer.svelte';
import Highlight from 'svelte-highlight';
import bash from 'svelte-highlight/languages/bash';
import arta from 'svelte-highlight/styles/arta';
</script>
<svelte:head>
<title>Home | LURE Web</title>
<meta name="description" content="LURE Web home page" />
{@html arta}
</svelte:head>
<Header />
<section class="container content">
<div class="has-text-centered">
<img src="/lure-no-text.svg" width="200" alt="LURE logo without text" />
<p class="title">LURE</p>
<p class="subtitle">The community repository missing from your Linux distro</p>
</div>
<hr />
<p class="title">What does LURE do?</p>
<p class="subtitle">LURE allows you to:</p>
<ul>
<li>Access a wide range of software beyond what's available in official repositories</li>
<li>Get new versions of software as they come out, before official repositories ship them</li>
<li>Install unofficial software without having to deal with a separate package manager</li>
<li>Release software for Linux without having to package it for different distributions</li>
</ul>
<hr />
<p class="title">Install LURE</p>
<p class="subtitle">
Paste this into your Linux terminal and the install script will set everything up for you
</p>
<Highlight language={bash} code="curl -fsSL lure.elara.ws/install | bash" />
<p>
LURE is also available on the AUR as <a
href="https://aur.archlinux.org/packages/linux-user-repository-bin"
>
<code>linux-user-repository-bin</code>
</a>
and distro packages are provided at the
<a href="https://gitea.elara.ws/Elara6331/lure/releases/latest">latest Gitea release</a>.
</p>
</section>
<Footer />
+79
View File
@@ -0,0 +1,79 @@
<script>
import Header from '../header.svelte';
import Footer from '../footer.svelte';
</script>
<svelte:head>
<title>About | LURE Web</title>
<meta name="description" content="I" />
</svelte:head>
<Header />
<section class="container content">
<p class="title">About</p>
<hr />
<p class="subtitle">Why does LURE exist?</p>
<p>
LURE was created because packaging software for multiple Linux distros can be difficult and
error-prone, and installing those packages can be a nightmare for users unless they're available
in their distro's official repositories.
</p>
<p>
Take Discord for example. It only provides a deb file and a tar.gz file, and it's not available
in most official repositories. That means users of RPM distros have to manually install discord
using the tarball or rely on community-maintained repoositories that don't always have
up-to-date versions of Discord. That's also made worse by the fact that Discord refuses to run
if there's a newer version available.
</p>
<p>
LURE fixes that by always providing the most up to date version of Discord. That means all that
RPM users have to do is run <code>lure in discord</code> and LURE will get the tarball and
automatically build an RPM package out of it. Then if there's a newer version of Discord
available, users can just run <code>lure up</code> and LURE will automatically download the updated
version of Discord and install it. This also helps users of deb distros because it means they don't
have to manually download packages for software like Discord.
</p>
<hr />
<p class="subtitle">How does LURE work?</p>
<p>
Similar to Arch Linux's AUR, LURE has a repository of shell scripts that tell it how to build a
package. When you run a LURE command, it updates its repository and interprets the shell script
for the package you want to install using its built-in bash implementation. Then, it uses the
code inside the script to build a file structure to be included in the final package. It detects
which distro you're running, resolves dependencies, detects which package manager you have and
which package format it uses, builds metadata for the package from the information in the shell
script, builds the final package, and then runs the install command for your package manager to
install it.
</p>
<hr />
<p class="subtitle">How does LURE keep its packages up to date?</p>
<p>
LURE can automatically update its packages using a bot called
<a href="https://gitea.elara.ws/Elara6331/lure-updater">lure-updater</a>. It accepts plugins
that detect when software is updated upstream and update the LURE package accordingly. The
plugins that are currently running in my instance of the bot can be found in my
<a href="https://gitea.elara.ws/Elara6331/updater-plugins">updater-plugins</a> repo. The
<code>discord-bin</code> package, for example, checks Discord's API every hour to see if they've
released an updated version, and if they have, it pushes an update to LURE's repo.
</p>
<hr />
<p class="subtitle">How do I add my own package to LURE?</p>
<p>
LURE provides
<a href="https://github.com/Elara6331/lure/blob/master/docs/packages">
comprehensive documentation
</a> for packagers. If you need help with anything, feel free to ask on LURE's subreddit, which you
can find in the footer of this site. If you find a bug or a missing feature, please open an issue
on LURE's git repo.
</p>
<hr />
<p class="subtitle">Can I use and modify LURE's icons?</p>
<p>
LURE's icons are available on the <a href="/icons">icons page</a> of this site. They're licensed
under CC-BY-NC-SA 4.0, which means you're free to share, modify, and use the icons for non-commercial
purposes as long as you give appropriate credit and indicate any changes made to the original icons.
</p>
</section>
<Footer />
+15
View File
@@ -0,0 +1,15 @@
<script>
import Icon from '@iconify/svelte';
</script>
<br style="margin-top: 20px">
<div class="hero is-dark is-small">
<div class="hero-body has-text-centered">
<p>Copyright &copy; {new Date().getFullYear()} LURE Web Contributors. Licensed under the <a class="has-text-link" href="https://www.gnu.org/licenses/agpl-3.0-standalone.html">AGPLv3</a>.</p>
<div class="is-size-4">
<a href="https://gitea.elara.ws/Elara6331/lure-web"><Icon icon="cib:gitea"/></a>
<a href="https://github.com/Elara6331/lure-web"><Icon icon="mdi:github"/></a>
<a href="https://reddit.com/r/linux_user_repository"><Icon icon="ic:round-reddit"/></a>
</div>
</div>
</div>
+42
View File
@@ -0,0 +1,42 @@
<script>
import { page } from '$app/stores';
import Icon from '@iconify/svelte';
function isActive(path) {
return $page.route.id == path ? 'is-active' : '';
}
let navbarIsActive = false;
</script>
<nav class="navbar mb-5">
<div class="navbar-brand">
<a class="navbar-item" href="/"><img src="/lure-text-white.svg" alt="LURE Logo" /></a>
<button
class="navbar-burger {navbarIsActive ? 'is-active' : ''}"
aria-label="menu"
on:click={() => {
navbarIsActive = !navbarIsActive;
}}
>
<span aria-hidden="true" />
<span aria-hidden="true" />
<span aria-hidden="true" />
</button>
</div>
<div id="main-navbar" class="navbar-menu {navbarIsActive ? 'is-active' : ''}">
<div class="navbar-end">
<a class="navbar-item {isActive('/')}" href="/">
<Icon icon="material-symbols:house" inline="true" /> Home
</a>
<a class="navbar-item {isActive('/pkgs')}" href="/pkgs">
<Icon icon="mdi:package-variant-closed" inline="true" />&nbsp;Packages
</a>
<a class="navbar-item {isActive('/about')}" href="/about">
<Icon icon="mdi:question-mark-circle" inline="true" />&nbsp;About
</a>
</div>
</div>
</nav>
+72
View File
@@ -0,0 +1,72 @@
<script>
import Header from "../header.svelte";
import Footer from "../footer.svelte";
</script>
<svelte:head>
<title>FAQ | LURE Web</title>
<meta name="description" content="LURE Icons">
</svelte:head>
<Header/>
<div class="container">
<p class="title">Icons</p>
<br>
<div class="columns">
<div class="column ">
<div class="card">
<div class="card-header">
<p class="card-header-title">
Without Text
</p>
</div>
<div class="card-content has-text-centered">
<figure class="image is-16by9">
<img src="/lure-no-text.svg" alt="LURE icon without text">
</figure>
</div>
<footer class="card-footer">
<a class="card-footer-item" href="/lure-no-text.svg" download>Download</a>
</footer>
</div>
</div>
<div class="column ">
<div class="card">
<div class="card-header">
<p class="card-header-title">
With Text
</p>
</div>
<div class="card-content has-text-centered">
<figure class="image is-16by9">
<img src="/lure-text.svg" alt="LURE icon with text">
</figure>
</div>
<footer class="card-footer">
<a class="card-footer-item" href="/lure-text.svg" download>Download</a>
</footer>
</div>
</div>
<div class="column">
<div class="card">
<div class="card-header">
<p class="card-header-title">
White With Text
</p>
</div>
<div class="card-content has-text-centered">
<figure class="image is-16by9">
<img src="/lure-text-white.svg" alt="White LURE icon with white text">
</figure>
</div>
<footer class="card-footer">
<a class="card-footer-item" href="/lure-text-white.svg" download>Download</a>
</footer>
</div>
</div>
</div>
<p class="has-text-weight-bold">Note: The icons on this page are licensed under CC-BY-NC-SA 4.0 unless otherwise specified</p>
</div>
<Footer/>
+5
View File
@@ -0,0 +1,5 @@
import { redirect } from '@sveltejs/kit';
export function load() {
throw redirect(302, 'https://gitea.elara.ws/Elara6331/lure/raw/branch/master/scripts/install.sh');
}
+170
View File
@@ -0,0 +1,170 @@
<script>
import { page } from '$app/stores';
import { client } from 'twirpscript';
import { GetPkg } from '$lib/lure.pb';
import { LURE_WEB_API_URL } from '$env/static/public';
import { DoubleBounce } from 'svelte-loading-spinners';
import Header from '../../../header.svelte';
import Footer from '../../../footer.svelte';
import Icon from '@iconify/svelte';
import { onMount } from 'svelte';
client.baseURL = LURE_WEB_API_URL;
client.prefix = '';
let currentURL = ``;
onMount(() => (currentURL = window.location.href));
function fullVer(pkg) {
let ver = `${pkg.version}-${pkg.release}`;
if (pkg.epoch != 0) {
ver = `${pkg.epoch}:${ver}`;
}
return ver;
}
function objToMap(o) {
return new Map(Object.entries(o));
}
let modalActive = false;
function showModal() {
modalActive = true;
}
function hideModal() {
modalActive = false;
}
</script>
<svelte:head>
<title>{$page.params.name} Package | LURE Web</title>
<meta name="description" content="Information about the {$page.params.name} LURE package." />
</svelte:head>
<Header />
<section class="container">
<a href="/pkgs"><Icon icon="material-symbols:arrow-back-rounded" inline="true" /> Back</a>
{#await GetPkg({ name: $page.params.name, repository: $page.params.repo })}
<center><DoubleBounce color="#375a7f" /></center>
{:then pkg}
<div class="modal {modalActive ? 'is-active' : ''}">
<div class="modal-background"/>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Badge</p>
<button class="delete" aria-label="close" on:click={hideModal}/>
</header>
<section class="modal-card-body">
<img
src="{LURE_WEB_API_URL}/badge/{$page.params.repo}/{$page.params.name}"
alt="badge for {$page.params.name} package"
/>
<p>Markdown</p>
<input
class="input"
value="[![LURE badge for {$page.params.name} package]({LURE_WEB_API_URL}/badge/{$page.params.repo}/{$page.params.name})]({currentURL})"
readonly
/>
<p>HTML</p>
<input
class="input"
value='<a href="{currentURL}"><img src="{LURE_WEB_API_URL}/badge/{$page.params.repo}/{$page.params.name}" alt="LURE badge for {$page.params.name} package"></a>'
readonly
/>
</section>
<footer class="modal-card-foot">
<button class="button is-primary" on:click={hideModal}>Close</button>
</footer>
</div>
</div>
<p class="title">{pkg.name}</p>
<p class="subtitle mb-3">{fullVer(pkg)}</p>
<a href="/pkg/{pkg.repository}/{pkg.name}/lure.sh" class="button is-primary mb-5">View lure.sh</a>
<button href="/pkg/{pkg.repository}/{pkg.name}/lure.sh" class="button is-success mb-5 ml-1" on:click={showModal}>View badge</button>
<div class="box">
<table class="table is-hoverable is-fullwidth">
<tbody>
{#if pkg.description != ''}
<tr>
<th>Description:</th>
<td>{pkg.description}</td>
</tr>
{/if}
{#if pkg.homepage != ''}
<tr>
<th>Homepage:</th>
<td><a href={pkg.homepage}>{pkg.homepage}</a></td>
</tr>
{/if}
{#if pkg.maintainer != ''}
<tr>
<th>Maintainer:</th>
<td>{pkg.maintainer}</td>
</tr>
{/if}
{#if pkg.licenses.length != 0}
<tr>
<th>Licenses:</th>
<td>
{#each pkg.licenses as license, index}
{#if license.startsWith('custom')}
{license}{#if index + 1 < pkg.licenses.length},&nbsp{/if}
{:else}
<a href="https://spdx.org/licenses/{license}.html">{license}</a
>{#if index + 1 < pkg.licenses.length},&nbsp;{/if}
{/if}
{/each}
</td>
</tr>
{/if}
{#if pkg.architectures.length != 0}
<tr>
<th>Architectures:</th>
<td>{pkg.architectures.join(', ')}</td>
</tr>
{/if}
{#if pkg.conflicts.length != 0}
<tr>
<th>Conflicts:</th>
<td>{pkg.conflicts.join(', ')}</td>
</tr>
{/if}
{#if pkg.provides.length != 0}
<tr>
<th>Provides:</th>
<td>{pkg.provides.join(', ')}</td>
</tr>
{/if}
{#each [...objToMap(pkg.depends)] as [override, pkgList]}
<tr>
<th>Depends ({override == '' ? 'default' : override}):</th>
<td>{pkgList.entries.join(', ')}</td>
</tr>
{/each}
{#each [...objToMap(pkg.buildDepends)] as [override, pkgList]}
<tr>
<th>Build Depends ({override != '' ? override : 'default'}):</th>
<td>{pkgList.entries.join(', ')}</td>
</tr>
{/each}
<tr>
<th>Repository:</th>
<td>{pkg.repository}</td>
</tr>
</tbody>
</table>
</div>
{:catch err}
<div class="notification is-danger my-3">
Error: {err.msg}
</div>
{/await}
</section>
<Footer />
@@ -0,0 +1,46 @@
<script>
import { page } from '$app/stores';
import { client } from 'twirpscript';
import { GetBuildScript } from '$lib/lure.pb';
import { LURE_WEB_API_URL } from '$env/static/public';
import { DoubleBounce } from 'svelte-loading-spinners';
import Highlight from 'svelte-highlight';
import bash from 'svelte-highlight/languages/bash';
import atom from 'svelte-highlight/styles/bright';
import Header from '../../../../header.svelte';
import Footer from '../../../../footer.svelte';
import Icon from '@iconify/svelte';
client.baseURL = LURE_WEB_API_URL;
client.prefix = '';
</script>
<svelte:head>
<title>{$page.params.name} Build Script | LURE Web</title>
<meta name="description" content="The build script for the {$page.params.name} LURE package." />
{@html atom}
</svelte:head>
<Header />
<section class="container">
<a href="."><Icon icon="material-symbols:arrow-back-rounded" inline="true" /> Back</a>
{#await GetBuildScript({ name: $page.params.name, repository: $page.params.repo })}
<center><DoubleBounce color="#375a7f" /></center>
{:then resp}
<p class="title">Build Script</p>
<p class="subtitle">{$page.params.repo} / {$page.params.name}</p>
<div class="box">
<Highlight language={bash} code={resp.script} />
</div>
{:catch err}
<div class="notification is-danger my-3">
Error: {err.msg}
</div>
{/await}
</section>
<Footer />
+129
View File
@@ -0,0 +1,129 @@
<script>
import { client } from 'twirpscript';
import { Search } from '$lib/lure.pb';
import { searchReq } from '../../stores.js';
import { LURE_WEB_API_URL } from '$env/static/public';
import Header from "../header.svelte";
import Footer from "../footer.svelte";
import { DoubleBounce } from 'svelte-loading-spinners';
import Icon from '@iconify/svelte';
client.baseURL = LURE_WEB_API_URL
client.prefix = ""
let searchPromise = Search(
$searchReq ?? {
query: "",
limit: BigInt(0),
sortBy: "UNSORTED",
filterType: "NO_FILTER",
}
);
function onSubmit(e) {
let formData = new FormData(e.target);
let filterValue = formData.get('filter-value');
let req = {
query: formData.get('query'),
limit: BigInt(0),
sortBy: formData.get('sort-by'),
filterType: formData.get('filter'),
filterValue: filterValue == '' ? null : filterValue,
}
searchReq.set(req)
searchPromise = Search(req);
}
function onFilterChange(e) {
let filterVal = document.getElementById('filter-val');
if (e.target.value != "NO_FILTER") {
filterVal.classList.remove('is-hidden');
} else {
filterVal.classList.add('is-hidden');
}
}
</script>
<svelte:head>
<title>Package Search | LURE Web</title>
<meta name="description" content="Search for LURE packages">
</svelte:head>
<Header/>
<section class="container">
<p class="title">Package Search</p>
<form on:submit|preventDefault={onSubmit}>
<div class="field">
<div class="control">
<input class="input" type="text" name="query" value="" placeholder="Query">
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<div class="control select is-fullwidth">
<select name="sort-by">
<option value="UNSORTED" selected>Unsorted</option>
<option value="NAME">Sort by Name</option>
<option value="VERSION">Sort by Version</option>
<option value="REPOSITORY">Sort by Repository</option>
</select>
</div>
</div>
</div>
<div class="column">
<div class="field">
<div class="control select is-fullwidth">
<select name="filter" on:change={onFilterChange}>
<option value="NO_FILTER" selected>No Filter</option>
<option value="IN_REPOSITORY">In Repo</option>
<option value="SUPPORTS_ARCH">Supports Architecture</option>
</select>
</div>
</div>
</div>
</div>
<div class="field">
<div class="control">
<input id="filter-val" class="input is-hidden" type="text" value="" name="filter-value" placeholder="Filter Value">
</div>
</div>
<input type="submit" class="button is-fullwidth" value="Search">
</form>
<hr>
{#await searchPromise}
<center><DoubleBounce color="#375a7f" /></center>
{:then resp}
{#each resp.packages as pkg}
<div class="card my-5">
<header class="card-header">
<p class="card-header-title">{pkg.repository} / {pkg.name}</p>
<div class="card-header-icon">{pkg.version}</div>
</header>
<div class="card-content">
{pkg.description}
</div>
<footer class="card-footer">
<a class="card-footer-item" href="/pkg/{pkg.repository}/{pkg.name}">More info <Icon icon="material-symbols:arrow-forward-rounded" inline=true/></a>
</footer>
</div>
{/each}
{#if resp.packages.length === 0}
<p class="subtitle has-text-centered has-text-danger my-5 is-fullwidth">No Results</p>
{/if}
{:catch err}
<div class="notification is-danger my-3">
Error: {err.msg}
</div>
{/await}
</section>
<Footer/>
+3
View File
@@ -0,0 +1,3 @@
import { writable } from "svelte/store";
export const searchReq = writable()
+6
View File
@@ -0,0 +1,6 @@
/* Variables and mixins declared here will be available in all other SCSS files */ /* https://github.com/jgthms/bulma/issues/1293 */
$body-overflow-y: auto;
@import './darkly/variables.scss';
$family-sans-serif: "Ubuntu", sans-serif;
-108
View File
@@ -1,108 +0,0 @@
:root {
--primary: #0060A8;
--primary-hover: #026EBF;
--secondary: #0EAAAA;
--secondary-hover: #13b4b4;
--font-size: 16px;
}
.centered {
text-align: center;
}
.left {
text-align: left;
}
.right {
text-align: right;
}
.justify-space-between {
display: flex;
justify-content: space-between;
}
.hidden {
display: none;
}
a.close {
cursor: pointer;
}
nav:not([aria-label="breadcrumb"]) {
/* Workaround for horizontal overflow due to justify-content */
overflow-x: hidden;
}
/* Add some spacing between the navbar items and the edge of the page */
nav:not([aria-label="breadcrumb"]) ul {
padding-left: 2rem;
padding-right: 2rem;
}
nav:not([aria-label="breadcrumb"]) a {
color: #dddedf;
}
nav:not([aria-label="breadcrumb"]) a.active {
background-color: var(--primary);
}
nav:not([aria-label="breadcrumb"]) a:hover:not(.active) {
color: var(--primary-hover);
}
/* Keep the footer at the bottom */
body > main {
min-height: 100vh;
}
/* Make the footer smaller */
body > footer {
--block-spacing-vertical: 2rem;
}
/* Make card header and footer smaller */
article > header, article > footer {
padding-top: 1rem;
padding-bottom: 1rem;
}
/* Make the bottom margin on card headers smaller */
article > header {
margin-bottom: calc(var(--block-spacing-vertical) / 2);
}
/* Make the top margin on card footers smaller */
article > footer {
margin-top: calc(var(--block-spacing-vertical) / 2);
}
/* Fix the icon height to 100px to make cards uniform */
article > img.icon {
height: 100px;
}
th {
width: 30%;
}
td {
word-break: break-word;
cursor: text;
width: 70%;
}
pre code {
cursor: text;
}
.marginless {
margin: 0;
}
[role="link"], a {
--color: var(--secondary);
}
-5
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

-1
View File
@@ -1 +0,0 @@
data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACNklEQVQ4jX3T32vXdRTH8cf5fL+zITLsJrroh3Rjd0VpfDPaXLMpDIbNgoTIiG6kLnPUP1AMU7qqC1G86Yfg1Km52Tf7zso5tnDRRVBBjrEugm7Km32/2+f99mIlrm297s7hvJ6cwzmHuzXb2ObX8bqfrm6+kxub6HTh+qjhyU3WULEiChtRU8ZlN77d/E/uIVmvFKM+mVoFiVXIn6/WNGNUM36zEIctxjm3Ki9rxnHNmLAYPV7f3lq7A9jaNSnplj2Az5RxVlv+XHYQU0qvrj/CXGOnm+M83vmDFM/IMSvbo/SFtnxS0hL6wPszVe/N3AX44+tBoSF5zcw37Sp5QNaDX4QJi/GKMAiO3tigMKx0ZBnw11eDijwknFPGGRUjGFLJhyRPKuOmcAwJp1TyKZH7hd8Lrfo7CkPCackB8rDQi3nhCDpFXjYXDijjJWGvwiH3FEereFA4rWK/7GNhF+YVupWxQ+E8xhT5uKXifmFA4V1vP/EBVJX5TUUU7u1J5hr3LZtzl6V4UeQhEZdU7dNfW3BiuhB53lvbzq99B3ONEc14Tiued6vyp1bULcQWzRizGC8YqC38d+sr15gdwwYpRrXlDkkXfpTtUsaIT6fa/x/wcPdFKfZjk+Syttyhd8djUvTJOpVGnJhuXx8AW7vOSHbLqpIrrlx71N7al5J9sp1KF3z0/R3f6l/4V5PfPaUVdc34Wyue1ff0rJPT/ZY84o3tH67rW6HxazX1ibpL1zvWK7kNwWfQQO79fcgAAAAASUVORK5CYII=
Binary file not shown.

Before

Width:  |  Height:  |  Size: 644 B

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

+26
View File
@@ -0,0 +1,26 @@
import preprocess from 'svelte-preprocess';
import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: [
vitePreprocess(),
preprocess({
scss: {
prependData: '@use "src/variables.scss" as *;'
}
})
],
kit: {
adapter: adapter(),
env: {
publicPrefix: "LURE_WEB_"
},
}
};
export default config;
+77
View File
@@ -0,0 +1,77 @@
job "lure-web" {
region = "global"
datacenters = ["dc1"]
type = "service"
group "lure-web" {
network {
port "api" {
to = 8080
}
port "http" {
to = 3000
}
}
task "lure-api-server" {
driver = "docker"
env {
LURE_API_GITHUB_SECRET = "${LURE_API_GITHUB_SECRET}"
// Hack to force Nomad to re-deploy the service
// instead of ignoring it
COMMIT_SHA = "${DRONE_COMMIT_SHA}"
}
config {
image = "elara6331/lure-api-server:latest"
ports = ["api"]
}
service {
name = "lure-api-server"
port = "api"
tags = [
"traefik.enable=true",
"traefik.http.routers.lure-api-server.rule=Host(`api.lure.elara.ws`)",
"traefik.http.routers.lure-api-server.tls.certresolver=letsencrypt"
]
check {
type = "tcp"
port = "api"
interval = "30s"
timeout = "2s"
}
}
}
task "lure-web" {
driver = "docker"
config {
image = "elara6331/lure-web:latest"
ports = ["http"]
}
service {
name = "lure-web"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.lure-web.rule=Host(`lure.elara.ws`)",
"traefik.http.routers.lure-web.tls.certresolver=letsencrypt",
]
}
}
}
constraint {
attribute = "${attr.cpu.arch}"
operator = "set_contains_any"
value = "amd64,arm64"
}
}
-77
View File
@@ -1,77 +0,0 @@
#macro("content"):
<nav aria-label="breadcrumb">
<ul>
<li><a href="/">Home</a></li>
<li>About</li>
</ul>
</nav>
<h1>About LURE</h1>
<section class="container">
<hgroup><h2>Why does LURE exist?</h2></hgroup>
<p>
LURE was created because packaging software for multiple Linux distros can be difficult and
error-prone, and installing those packages can be a nightmare for users unless they're available
in their distro's official repositories.
</p>
<p>
Take Discord for example. It only provides a deb file and a tar.gz file, and it's not available
in most official repositories. That means users of RPM distros have to manually install discord
using the tarball or rely on community-maintained repositories that don't always have
up-to-date versions of Discord. That's also made worse by the fact that Discord refuses to run
if there's a newer version available.
</p>
<p>
LURE fixes that by always providing the most up to date version of Discord, which means all that
RPM users have to do is run <code>lure in discord</code> and LURE will get the tarball and
automatically build an RPM package out of it for them. When there's a newer version of Discord
available, users can just run <code>lure up</code> and LURE will automatically download the updated
version of Discord and install it. That also helps users of deb distros because it means they don't
have to manually download packages for software like Discord.
</p>
</section>
<section class="container">
<hgroup><h2>How does LURE work?</h2></hgroup>
<p>
Similar to Arch Linux's AUR, LURE has a repository of shell scripts that tell it how to build a
package. When you run a LURE command, it updates its repository and interprets the shell script
for the package you want to install using its built-in bash implementation. Then, it uses the
code inside the script to build a file structure to be included in the final package. It detects
which distro you're running, resolves dependencies, detects which package manager you have and
which package format it uses, builds metadata for the package from the information in the shell
script, builds the final package, and then runs the install command for your package manager to
install it.
</p>
</section>
<section class="container">
<hgroup><h2>How does LURE keep its packages up to date?</h2></hgroup>
<p>
LURE can automatically update its packages using a bot called
<a href="https://gitea.elara.ws/lure/lure-updater">lure-updater</a>. It accepts plugins that
detect when software is updated upstream and updates the LURE package accordingly. The plugins
that are currently running in my instance of the bot can be found in the
<a href="https://gitea.elara.ws/lure/updater-plugins">updater-plugins</a> repo. The
<code>discord-bin</code> package, for example, checks Discord's API every hour to see if they've
released an updated version, and if they have, it pushes an update to LURE's repo.
</p>
</section>
<section class="container">
<hgroup><h2>How do I add my own package to LURE?</h2></hgroup>
<p>
LURE provides <a href="https://github.com/lure-sh/lure/blob/master/docs/packages">comprehensive documentation</a>
for packagers. If you need help with anything, feel free to ask on LURE's <a href="https://reddit.com/r/linux_user_repository">subreddit</a>.
If you find a bug or would like a feature to be added, please open an issue on LURE's git repo.
</p>
</section>
<section class="container">
<hgroup><h2>Can I use and modify LURE's icons?</h2></hgroup>
<p>
LURE's icons are available on the <a href="/icons">icons page</a> of this site. They're licensed
under CC-BY-NC-SA 4.0, which means you're free to share, modify, and use the icons for non-commercial
purposes as long as you give appropriate credit and indicate any changes made to the original icons.
</p>
</section>
#!macro
#include("base.html", title = "About", desc = "About the Linux User Repository")
-35
View File
@@ -1,35 +0,0 @@
<!DOCTYPE html>
<html data-theme="dark">
<head>
<title>#(title) | LURE Web</title>
<meta name="description" content='#(desc | title + " on LURE Web")' />
<meta name="viewport" content="width=device-width, initial-scale=0.8" />
<link rel="stylesheet" href="/static/css/pico.min.css">
<link rel="stylesheet" href="/static/css/lure.css">
<link rel="icon" href="/static/icons/favicon.ico">
</head>
<body>
<nav>
<ul>
<li><a href="/"><img src="/static/icons/lure-text-white.svg" alt="LURE Logo" width="85"></a></li>
</ul>
<ul>
<li><a href="/" class='#(title == "Home" ? "active" : "")'>Home</a></li>
<li><a href="/pkgs" class='#(title == "Package Search" ? "active" : "")'>Packages</a></li>
<li><a href="/about" class='#(title == "About" ? "active" : "")'>About</a></li>
</ul>
</nav>
<main class="container">
#macro("content")
</main>
<footer class="container">
<div class="headings marginless">
<h2>Copyright &copy; #(now().Year()) LURE Web Contributors</h2>
</div>
<a href="https://github.com/lure-sh/lure-web" target="_blank">Source Code</a>
</footer>
</body>
</html>
-25
View File
@@ -1,25 +0,0 @@
#macro("content"):
<nav aria-label="breadcrumb">
<ul>
<li><a href="/">Home</a></li>
<li>Error</li>
</ul>
</nav>
<h1>Error</h1>
<br><br>
<section class="container centered">
<div>
<hgroup>
<h1>Something Went Wrong!</h1>
<h2>Error #(error.StatusCode): #(error.StatusText())</h2>
</hgroup>
<pre><code>#(error.Msg)</code></pre>
<a href="/" role="button">Go Back Home</a>
</div>
</section>
#!macro
#include("base.html", title = sprintf("Error %d", error.StatusCode), desc = sprintf("Error %d: %s", error.StatusCode, error.StatusText()))
-32
View File
@@ -1,32 +0,0 @@
#macro("content"):
<section class="container centered">
<img src="/static/icons/lure-no-text.svg" alt="LURE logo without text" width="200">
<hgroup>
<h1>LURE</h1>
<h2>The community repository missing from your Linux distro</h2>
</hgroup>
</section>
<section class="container">
<hgroup>
<h1>What does LURE do?</h1>
<h2>LURE allows you to:</h2>
</hgroup>
<ul>
<li>Access a wide range of software beyond what's available in official repositories</li>
<li>Get new versions of software as they come out, before official repositories ship them</li>
<li>Install unofficial software without having to deal with a separate package manager</li>
<li>Release software for Linux without having to package it for different distributions</li>
</ul>
</section>
<section class="container">
<hgroup>
<h1>Install LURE</h1>
<h2>Paste this into your Linux terminal and the install script will set everything up for you</h2>
</hgroup>
<pre><code>curl -fsSL lure.sh/install | bash</code></pre>
<p>LURE is also available on the AUR as <code>linux-user-repository-bin</code> and distro packages are provided at the <a href="https://gitea.elara.ws/lure/lure/releases/latest">latest Gitea release</a></p>
</section>
#!macro
#include("base.html", title = "Home", desc = "The community repository missing from your Linux distro")
-39
View File
@@ -1,39 +0,0 @@
#macro("content"):
<nav aria-label="breadcrumb">
<ul>
<li><a href="/">Home</a></li>
<li>Icons</li>
</ul>
</nav>
<h1>Icons</h1>
<section class="container">
<div class="grid">
<div>
<article class="centered">
<header><strong>Without Text</strong></header>
<img class="icon" src="/static/icons/lure-no-text.svg" alt="LURE icon without text">
<footer><a href="/static/icons/lure-no-text.svg" download>Download</a></footer>
</article>
</div>
<div>
<article class="centered">
<header><strong>With Text</strong></header>
<img class="icon" src="/static/icons/lure-text.svg" alt="LURE icon with text">
<footer><a href="/static/icons/lure-text.svg" download>Download</a></footer>
</article>
</div>
<div>
<article class="centered">
<header><strong>White With Text</strong></header>
<img class="icon" src="/static/icons/lure-text-white.svg" alt="LURE icon with text">
<footer><a href="/static/icons/lure-text-white.svg" download>Download</a></footer>
</article>
</div>
</div>
<strong>Note: The icons on this page are licensed under CC-BY-NC-SA 4.0 unless otherwise specified</strong>
</section>
#!macro
#include("base.html", title = "Icons", desc = "Linux User Repository icons and logos")
-142
View File
@@ -1,142 +0,0 @@
#macro("content"):
<nav aria-label="breadcrumb">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/pkgs">Packages</a></li>
<li>#(pkg.Name)</li>
</ul>
</nav>
<hgroup>
<h1>#(pkg.Name)</h1>
<h2>#(pkg.FullVersion())</h2>
</hgroup>
<a href="/pkg/#(pkg.Repository)/#(pkg.Name)/script" role="button">View script</a>
<a href="javascript:openModal()" role="button" class="secondary">View badge</a>
<br>
<article>
<h3 >Package Information</h3>
<table>
<tbody>
#if(pkg.Description != ""):
<tr>
<th>Description:</th>
<td>#(pkg.Description)</td>
</tr>
#!if
#if(pkg.Homepage != ""):
<tr>
<th>Homepage:</th>
<td><a href="#(pkg.Homepage)" target="_blank">#(pkg.Homepage)</a></td>
</tr>
#!if
#if(pkg.Maintainer != ""):
<tr>
<th>Maintainer:</th>
<td>#(pkg.Maintainer)</td>
</tr>
#!if
#if(len(pkg.Licenses) != 0):
<tr>
<th>Licenses:</th>
<td>
#for(i, license in pkg.Licenses):
#if(hasPrefix(license, "custom")):
#(license)#if(i != len(pkg.Licenses) - 1):,&nbsp;#!if
#else:
<a href="https://spdx.org/licenses/#(license).html" target="_blank">#(license)</a>#if(i != len(pkg.Licenses) - 1):,&nbsp;#!if
#!if
#!for
</td>
</tr>
#!if
#if(len(pkg.Architectures) != 0):
<tr>
<th>Architectures:</th>
<td>#(join(pkg.Architectures, ", "))</td>
</tr>
#!if
#if(len(pkg.Conflicts) != 0):
<tr>
<th>Conflicts:</th>
<td>#(join(pkg.Conflicts, ", "))</td>
</tr>
#!if
#if(len(pkg.Provides) != 0):
<tr>
<th>Provides:</th>
<td>#(join(pkg.Provides, ", "))</td>
</tr>
#!if
<tr>
<th>Repository:</th>
<td>#(pkg.Repository)</td>
</tr>
</tbody>
</table>
</article>
#if(len(pkg.Depends) > 0):
<article>
<h3 >Runtime Dependencies</h3>
<table>
<tbody>
#for(override, pkgList in pkg.Depends):
<tr>
<th>#(override == "" ? "default" : override):</th>
<td>#(join(pkgList, ", "))</td>
</tr>
#!for
</tbody>
</table>
</article>
#!if
#if(len(pkg.BuildDepends) > 0):
<article>
<h3 >Build Dependencies</h3>
<table>
<tbody>
#for(override, pkgList in pkg.BuildDepends):
<tr>
<th>#(override == "" ? "default" : override):</th>
<td>#(join(pkgList, ", "))</td>
</tr>
#!for
</tbody>
</table>
</article>
#!if
<dialog id="badgeModal">
<article style="min-width: 60%">
<header>
<strong>Badge</strong>
<a aria-label="Close" class="close" href="javascript:closeModal()"></a>
</header>
<p class="centered">
<img src="#(url)/badge.svg" alt="LURE badge for #(pkg.Name)">
<hr>
</p>
<label for="badgeMarkdown">Markdown</label>
<input id="badgeMarkdown" value="[![LURE badge for #(pkg.Name)](#(url)/badge.svg)](#(url))" readonly />
<label for="badgeHTML">HTML</label>
<input id="badgeHTML" value='<a href="#(url)"><img src="#(url)/badge.svg" alt="LURE badge for #(pkg.Name)">' readonly />
</article>
</dialog>
<script>
function openModal() {
let modal = document.getElementById("badgeModal");
document.documentElement.classList.add('modal-is-open');
modal.setAttribute('open', true);
}
function closeModal() {
let modal = document.getElementById("badgeModal");
document.documentElement.classList.remove('modal-is-open');
modal.removeAttribute('open');
}
</script>
#!macro
#include("base.html", title = pkg.Name + " Package", desc = sprintf("%s %s - %s", pkg.Name, pkg.FullVersion(), pkg.Description))
-62
View File
@@ -1,62 +0,0 @@
#macro("content"):
<nav aria-label="breadcrumb">
<ul>
<li><a href="/">Home</a></li>
<li>Packages</li>
</ul>
</nav>
<h1>Package Search</h1>
<form action="/pkgs">
<input type="text" id="query" name="q" value='#(query.Get("q"))' placeholder="Query"/>
<div class="grid">
<div>
<select name="sort">
<option value="">Unsorted</option>
<option value="name" #(query.Get("sort") == "name" ? "selected" : "")>Sort by Name</option>
<option value="version" #(query.Get("sort") == "version" ? "selected" : "")>Sort by Version</option>
<option value="repo" #(query.Get("sort") == "repo" ? "selected" : "")>Sort by Repository</option>
</select>
</div>
<div>
<select name="filter" onchange="onFilterChange(event)">
<option value="">No Filter</option>
<option value="inrepo" #(query.Get("filter") == "inrepo" ? "selected" : "")>In Repo</option>
<option value="arch" #(query.Get("filter") == "arch" ? "selected" : "")>Supports Architecture</option>
</select>
</div>
</div>
<input class='#(query.Get("filter") == "" ? "hidden" : "")' type="text" id="filterValue" name="fv" value='#(query.Get("fv"))' placeholder="Filter Value"/>
<button type="submit">Search</button>
</form>
<hr>
#for(pkg in pkgs):
<article>
<header>
<div class="justify-space-between">
<span class="left"><strong>#(pkg.Repository) / #(pkg.Name)</strong></span>
<span class="right">#(pkg.Version)</span>
</div>
</header>
<p>#(pkg.Description)</p>
<footer class="centered">
<a href="/pkg/#(pkg.Repository)/#(pkg.Name)">More Info &rarr;</a>
</footer>
</article>
#!for
<script>
function onFilterChange(e) {
let filterValue = document.getElementById('filterValue');
if (e.srcElement.value == '') {
filterValue.classList.add('hidden');
} else {
filterValue.classList.remove('hidden');
}
}
</script>
#!macro
#include("base.html", title = "Package Search", desc = "Search for LURE packages")
-19
View File
@@ -1,19 +0,0 @@
#macro("content"):
<nav aria-label="breadcrumb">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/pkgs">Packages</a></li>
<li><a href="/pkg/#(repoName)/#(pkgName)">#(pkgName)</a></li>
<li>Script</li>
</ul>
</nav>
<hgroup>
<h1>Build Script</h1>
<h2>#(repoName) / #(pkgName)</h2>
</hgroup>
#(script)
#!macro
#include("base.html", title = pkgName + " Build Script", desc = sprintf("Build script for the %s package", pkgName))
+17
View File
@@ -0,0 +1,17 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}
+20
View File
@@ -0,0 +1,20 @@
import { sveltekit } from '@sveltejs/kit/vite';
/** @type {import('vite').UserConfig} */
const config = {
plugins: [sveltekit()],
css: {
preprocessorOptions: {
scss: {
additionalData: '@use "src/variables.scss" as *;'
}
}
},
server: {
host: '0.0.0.0'
}
};
export default config;
-79
View File
@@ -1,79 +0,0 @@
package main
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"io"
"net/http"
"os"
"strings"
"sync"
"github.com/uptrace/bunrouter"
"go.elara.ws/logger/log"
"lure.sh/lure/pkg/repos"
)
func registerWebhook(ctx context.Context, mux *bunrouter.Router) {
g := mux.WithMiddleware(apiErrorHandler)
g.POST("/webhook", func(w http.ResponseWriter, req bunrouter.Request) error {
if req.Header.Get("X-GitHub-Event") != "push" {
return HTTPError{http.StatusBadRequest, "only push events are accepted by this bot"}
}
err := verifySecure(req.Request)
if err != nil {
return err
}
go pullRepos(ctx)
return nil
})
}
func verifySecure(req *http.Request) error {
sigStr := req.Header.Get("X-Hub-Signature-256")
sig, err := hex.DecodeString(strings.TrimPrefix(sigStr, "sha256="))
if err != nil {
return HTTPError{http.StatusBadRequest, "invalid hmac value"}
}
secretStr, ok := os.LookupEnv("LURE_WEB_GITHUB_SECRET")
if !ok {
return HTTPError{http.StatusInternalServerError, "LURE_WEB_GITHUB_SECRET must be set to the secret used for setting up the github webhook"}
}
secret := []byte(secretStr)
h := hmac.New(sha256.New, secret)
_, err = io.Copy(h, req.Body)
if err != nil {
return err
}
if !hmac.Equal(h.Sum(nil), sig) {
log.Warn("Insecure webhook request").
Str("from", req.RemoteAddr).
Bytes("sig", sig).
Bytes("hmac", h.Sum(nil)).
Send()
return HTTPError{http.StatusUnauthorized, "insecure webhook request"}
}
return nil
}
var pullMtx sync.Mutex
func pullRepos(ctx context.Context) {
pullMtx.Lock()
defer pullMtx.Unlock()
err := repos.Pull(ctx, nil)
if err != nil {
log.Warn("Error while pulling repositories").Err(err).Send()
}
}