update: add the package page

This commit is contained in:
ngn 2024-08-13 22:12:27 +03:00
parent a556ed08aa
commit aa0b373423
8 changed files with 345 additions and 43 deletions

View File

@ -1,11 +1,17 @@
package lib package lib
import ( import (
"archive/tar"
"bufio"
"compress/gzip"
"fmt" "fmt"
"io" "io"
"net/url" "net/url"
"os"
"path"
"strings" "strings"
"git.matterlinux.xyz/matter/tracker/log"
"github.com/bigkevmcd/go-configparser" "github.com/bigkevmcd/go-configparser"
) )
@ -16,6 +22,49 @@ type Package struct {
Depends []string `json:"depends"` Depends []string `json:"depends"`
Size string `json:"size"` Size string `json:"size"`
Desc string `json:"desc"` Desc string `json:"desc"`
Archive string `json:"archive"`
}
func (p *Package) Files() []string {
var (
gzip_reader io.Reader
header *tar.Header
result []string
file *os.File
err error
)
if file, err = os.Open(p.Archive); err != nil {
log.Error("Failed to open %s", p.Archive)
return result
}
defer file.Close()
if gzip_reader, err = gzip.NewReader(bufio.NewReader(file)); err != nil {
log.Error("Failed to create reader for %s", p.Archive)
return result
}
reader := tar.NewReader(gzip_reader)
for header, err = reader.Next(); err == nil; header, err = reader.Next() {
if header.Typeflag != tar.TypeReg {
continue
}
if path.Base(header.Name) != "files.tar.gz" {
continue
}
if result, err = GetFiles(reader); err == nil {
break
}
log.Error("Failed to get file list for %s: %s", p.Archive, err.Error())
return []string{}
}
return result
} }
func (p *Package) URL() string { func (p *Package) URL() string {

View File

@ -75,12 +75,14 @@ func (p *Pool) LoadList(list *[]Package) error {
} }
var pkg Package var pkg Package
pkg.Pool = p
if err = pkg.Load(reader); err != nil { if err = pkg.Load(reader); err != nil {
return err return err
} }
pkg.Archive = path.Join(p.Dir, fmt.Sprintf("%s_%s.mpf", pkg.Name, pkg.Version))
pkg.Pool = p
*list = append(*list, pkg) *list = append(*list, pkg)
} }

View File

@ -1,13 +1,41 @@
package lib package lib
import ( import (
"archive/tar"
"compress/gzip"
"fmt" "fmt"
"io"
"strings" "strings"
"time" "time"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
func GetFiles(r io.Reader) ([]string, error) {
var (
gzip_reader io.Reader
header *tar.Header
result []string
err error
)
if gzip_reader, err = gzip.NewReader(r); err != nil {
return result, err
}
reader := tar.NewReader(gzip_reader)
for header, err = reader.Next(); err == nil; header, err = reader.Next() {
if header.Typeflag != tar.TypeReg {
continue
}
result = append(result, header.Name)
}
return result, nil
}
func ListToStr(l []string) string { func ListToStr(l []string) string {
res := "" res := ""
for _, e := range l { for _, e := range l {

View File

@ -92,7 +92,7 @@ func main() {
}) })
app.Get("/", routes.GET_index) app.Get("/", routes.GET_index)
app.Get("/p/:name", routes.GET_package) app.Get("/p/:name/:version", routes.GET_package)
app.Get("*", func(c *fiber.Ctx) error { app.Get("*", func(c *fiber.Ctx) error {
return lib.RenderError(c, 404) return lib.RenderError(c, 404)

View File

@ -5,43 +5,157 @@ main {
padding: 40px 10% 0% 10%; padding: 40px 10% 0% 10%;
} }
.search { .package-main {
display: flex; padding: 40px 20% 0% 20%;
color: var(--bright-main);
background: var(--dark-second);
border: solid 1px var(--bright-main);
flex-direction: column;
padding: 30px;
gap: 10px;
} }
.status { .package {
border-collapse: collapse;
width: 100%;
}
.package tr {
font-size: 15px;
}
.package th {
padding: 10px;
border: 1px solid var(--bright-third);
background: var(--dark-second);
color: var(--bright-second);
text-align: left;
flex-grow: 4;
}
.package th {
color: var(--bright-main); color: var(--bright-main);
font-weight: 400;
font-size: 16px;
}
.package th a {
color: var(--bright-second);
}
.package th a:hover {
color: var(--bright-main);
}
.package tr th:first-child {
font-weight: 900;
width: 20%;
}
.package tr th:last-child {
font-weight: 400;
font-style: italic;
}
.package-name th {
background: var(--dark-third);
border: 1px solid var(--bright-second);
}
.detail {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 18px;
} }
form { .detail h3 {
flex-direction: row; font-size: 30px;
justify-content: space-around; color: var(--bright-main);
}
.detail .links {
display: flex; display: flex;
flex-direction: row;
}
.detail .links a {
border: solid 1px var(--bright-third);
background: var(--dark-second);
color: var(--bright-second);
font-size: 16px;
padding: 7px 10px;
}
.detail .links a:hover {
border: solid 1px var(--bright-second);
color: var(--bright-main);
}
.checkbox {
display: flex;
flex-direction: row;
align-items: center;
gap: 5px; gap: 5px;
} }
form input { form {
flex-grow: 4; display: flex;
flex-direction: row;
color: var(--bright-main);
background: var(--dark-second);
border: solid 1px var(--bright-second);
padding: 30px;
gap: 10px;
}
form .search {
width: 100%;
display: flex;
flex-direction: column;
gap: 10px;
flex: 0 0 80%;
}
@media only screen and (max-width: 1500px) {
form .search {
flex: 0 0 70%;
}
}
@media only screen and (max-width: 1000px) {
form .search {
flex: 0 0 60%;
}
}
form .search input {
font-size: 15px; font-size: 15px;
color: white; color: white;
background: var(--dark-main); background: var(--dark-main);
padding: 10px; padding: 10px;
outline: none; outline: none;
flex-grow: 4;
border: solid 1px var(--bright-third); border: solid 1px var(--bright-third);
} }
form select { form .search .status{
color: var(--bright-main);
display: flex;
flex-direction: row;
justify-content: space-between;
}
@media only screen and (max-width: 900px) {
form .search .status{
flex-direction: column;
align-items: left;
gap: 5px;
}
}
form .options {
width: 100%;
display: flex;
flex-direction: column;
gap: 10px;
}
form .options select {
appearance: none; appearance: none;
flex-grow: 1; flex-grow: 1;
font-size: 15px; font-size: 15px;
@ -52,7 +166,7 @@ form select {
cursor: pointer; cursor: pointer;
display: grid; display: grid;
border: none; border: none;
width: 10%; width: 100%;
border: solid 1px var(--bright-third); border: solid 1px var(--bright-third);
margin: 0; margin: 0;
@ -77,17 +191,17 @@ form select {
background-repeat: no-repeat; background-repeat: no-repeat;
} }
table { .list {
margin-top: 20px; margin-top: 20px;
border-collapse: collapse; border-collapse: collapse;
width: 100%; width: 100%;
} }
table tr { .list tr {
font-size: 15px; font-size: 15px;
} }
table th, table td { .list th, .list td {
padding: 10px; padding: 10px;
border: 1px solid var(--bright-second); border: 1px solid var(--bright-second);
background: var(--dark-second); background: var(--dark-second);
@ -96,15 +210,19 @@ table th, table td {
flex-grow: 4; flex-grow: 4;
} }
table td a { .list td a {
color: var(--bright-second); color: var(--bright-second);
} }
table th { .list td a:hover {
color: var(--bright-main);
}
.list th {
font-weight: 900; font-weight: 900;
color: var(--bright-main); color: var(--bright-main);
} }
table td { .list td {
font-style: italic; font-style: italic;
} }

View File

@ -1,8 +1,44 @@
package routes package routes
import "github.com/gofiber/fiber/v2" import (
"fmt"
"path"
"git.matterlinux.xyz/matter/tracker/lib"
"github.com/gofiber/fiber/v2"
)
func GET_package(c *fiber.Ctx) error { func GET_package(c *fiber.Ctx) error {
//name := c.Params("name") var (
return c.Render("package", &fiber.Map{}) name string
version string
list *[]lib.Package
)
is_json := c.Query("json") == "1"
is_download := c.Query("download") == "1"
list = c.Locals("list").(*[]lib.Package)
version = c.Params("version")
name = c.Params("name")
for _, pkg := range *list {
if pkg.Name != name || (version != "ANY" && pkg.Version != version) {
continue
}
if is_download {
c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", path.Base(pkg.Archive)))
return c.SendFile(pkg.Archive)
}
if is_json {
return c.JSON(pkg)
}
return c.Render("package", &pkg)
}
return lib.RenderError(c, 404)
} }

View File

@ -9,27 +9,36 @@
<body> <body>
{{template "parts/bar" .}} {{template "parts/bar" .}}
<main> <main>
<div class="search"> <form action="/" method="GET">
<form action="/" method="GET"> <div class="options">
{{if .query}}
<input placeholder="Hit enter to search" type="text" name="q" value="{{.query}}">
{{else}}
<input placeholder="Hit enter to search" type="text" name="q" autofocus>
{{end}}
<select name="pools"> <select name="pools">
<option value="">Select pool</option> <option value="">Select pool</option>
{{range .pools}} {{range .pools}}
<option value="{{.Name}}">{{.Display}}</option> <option value="{{.Name}}">{{.Display}}</option>
{{end}} {{end}}
</select> </select>
</form> <div class="checkbox">
<div class="status"> <input type="checkbox" name="exact" value="1">
<p>Listing {{len .list}} packages</p> <label>Only show exact matches</label>
<p>Last updated: {{.last}}</p> </div>
<div class="checkbox">
<input type="checkbox" name="json" value="1">
<label>Show results as JSON</label>
</div>
</div> </div>
</div> <div class="search">
{{if .query}}
<table class="pkgs"> <input placeholder="Hit enter to search" type="text" name="q" value="{{.query}}">
{{else}}
<input placeholder="Hit enter to search" type="text" name="q" autofocus>
{{end}}
<div class="status">
<p>Listing {{len .list}} packages</p>
<p>Last updated: {{.last}}</p>
</div>
</div>
</form>
<table class="list">
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Pool</th> <th>Pool</th>
@ -40,7 +49,7 @@
</tr> </tr>
{{range .list}} {{range .list}}
<tr> <tr>
<td><a href="{{.URL}}">{{.Name}}</a></td> <td><a href="/p/{{.Name}}/{{.Version}}">{{.Name}}</a></td>
{{if .Pool}} {{if .Pool}}
<td>{{.Pool.Display}}</td> <td>{{.Pool.Display}}</td>
{{else}} {{else}}

60
templates/package.html Normal file
View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>MatterLinux | {{.Name}} {{.Version}}</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=1200">
<link href="/style.css" rel="stylesheet">
</head>
<body>
{{template "parts/bar" .}}
<main class="package-main">
<div class="detail">
<h3>Package details</h3>
<div class="links">
<a href="{{.URL}}">View source</a>
<a href="/p/{{.Name}}/{{.Version}}?download=1">Download archive</a>
</div>
</div>
<table class="package">
<tr class="package-name">
<th>Name</th>
<th>{{.Name}}</th>
</tr>
<tr>
<th>Version</th>
<th>{{.Version}}</th>
</tr>
<tr>
<th>Size</th>
<th>{{.Size}}</th>
</tr>
<tr>
<th>Description</th>
<th>{{.Desc}}</th>
</tr>
{{if .Depends}}
<tr>
<th>Dependencies</th>
<th>
{{range .Depends}}
<a href="/p/{{.}}/ANY">{{.}}</a>
{{end}}
</th>
</tr>
{{end}}
{{$files := .Files}}
{{if $files}}
<tr>
<th>Files</th>
<th>
{{range $files}}
<p>/{{.}}</p>
{{end}}
</th>
</tr>
{{end}}
</table>
</main>
</body>
</html>