diff --git a/lib/package.go b/lib/package.go index 2d18f21..6fcb7e2 100644 --- a/lib/package.go +++ b/lib/package.go @@ -1,11 +1,17 @@ package lib import ( + "archive/tar" + "bufio" + "compress/gzip" "fmt" "io" "net/url" + "os" + "path" "strings" + "git.matterlinux.xyz/matter/tracker/log" "github.com/bigkevmcd/go-configparser" ) @@ -16,6 +22,49 @@ type Package struct { Depends []string `json:"depends"` Size string `json:"size"` 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 { diff --git a/lib/pool.go b/lib/pool.go index 3ffe96e..f06b4ec 100644 --- a/lib/pool.go +++ b/lib/pool.go @@ -75,12 +75,14 @@ func (p *Pool) LoadList(list *[]Package) error { } var pkg Package - pkg.Pool = p if err = pkg.Load(reader); err != nil { return err } + pkg.Archive = path.Join(p.Dir, fmt.Sprintf("%s_%s.mpf", pkg.Name, pkg.Version)) + pkg.Pool = p + *list = append(*list, pkg) } diff --git a/lib/util.go b/lib/util.go index 7488f0e..45c6fd3 100644 --- a/lib/util.go +++ b/lib/util.go @@ -1,13 +1,41 @@ package lib import ( + "archive/tar" + "compress/gzip" "fmt" + "io" "strings" "time" "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 { res := "" for _, e := range l { diff --git a/main.go b/main.go index 119c1d5..941d679 100644 --- a/main.go +++ b/main.go @@ -92,7 +92,7 @@ func main() { }) 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 { return lib.RenderError(c, 404) diff --git a/public/style.css b/public/style.css index b094708..ed5d47f 100644 --- a/public/style.css +++ b/public/style.css @@ -5,43 +5,157 @@ main { padding: 40px 10% 0% 10%; } -.search { - display: flex; - color: var(--bright-main); - background: var(--dark-second); - border: solid 1px var(--bright-main); - flex-direction: column; - padding: 30px; - gap: 10px; +.package-main { + padding: 40px 20% 0% 20%; } -.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); + 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; flex-direction: row; align-items: center; justify-content: space-between; + margin-bottom: 18px; } -form { - flex-direction: row; - justify-content: space-around; +.detail h3 { + font-size: 30px; + color: var(--bright-main); +} + +.detail .links { 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; } -form input { - flex-grow: 4; +form { + 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; color: white; background: var(--dark-main); padding: 10px; outline: none; - flex-grow: 4; 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; flex-grow: 1; font-size: 15px; @@ -52,7 +166,7 @@ form select { cursor: pointer; display: grid; border: none; - width: 10%; + width: 100%; border: solid 1px var(--bright-third); margin: 0; @@ -77,17 +191,17 @@ form select { background-repeat: no-repeat; } -table { +.list { margin-top: 20px; border-collapse: collapse; width: 100%; } -table tr { +.list tr { font-size: 15px; } -table th, table td { +.list th, .list td { padding: 10px; border: 1px solid var(--bright-second); background: var(--dark-second); @@ -96,15 +210,19 @@ table th, table td { flex-grow: 4; } -table td a { +.list td a { color: var(--bright-second); } -table th { +.list td a:hover { + color: var(--bright-main); +} + +.list th { font-weight: 900; color: var(--bright-main); } -table td { +.list td { font-style: italic; } diff --git a/routes/package.go b/routes/package.go index f045e6a..8a29cd8 100644 --- a/routes/package.go +++ b/routes/package.go @@ -1,8 +1,44 @@ 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 { - //name := c.Params("name") - return c.Render("package", &fiber.Map{}) + var ( + 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) } diff --git a/templates/index.html b/templates/index.html index d5739a9..430dbf5 100644 --- a/templates/index.html +++ b/templates/index.html @@ -9,27 +9,36 @@
{{template "parts/bar" .}}