Compare commits

36 Commits

Author SHA1 Message Date
3f370adda1 now packets can get LICENSE and pageurl from package table 2025-11-04 19:15:29 -03:00
eb14177d7a added a cmd to see all files and directorys flagged as config 2025-11-04 19:13:49 -03:00
fe0da8ad63 improved sha256 checksum system and config cmd 2025-11-03 17:59:00 -03:00
885ce25fe9 database files and changes 2025-11-02 21:30:43 -03:00
1c3e448b8d changing to packets user and creating internal.db, improved bat-bin
Packet.lua
2025-11-02 21:29:52 -03:00
22fb19a550 now installing files into the system 2025-11-02 20:07:42 -03:00
aa98cd81b3 removing useless function 2025-11-02 20:07:08 -03:00
e33f7b6d3c creating database schemas for packets cli, started doing packets cli and
packing nginx
2025-11-02 17:10:49 -03:00
a0704d6ac6 modernized some parts of code and new flags system 2025-11-01 22:56:31 -03:00
c44abc78d6 improved bat Packet.lua script 2025-11-01 17:55:48 -03:00
064ee7f404 testing new features 2025-11-01 16:39:11 -03:00
52ecacc4fe installation system soft implemented 2025-11-01 16:39:01 -03:00
4c88ec3bc2 using CURRENT_ARCH_NORMALIZED 2025-10-31 21:32:51 -03:00
ff5e271195 adding getsourcefunction sha256 check 2025-10-31 21:32:35 -03:00
cbea1dd8b5 normalize arch function 2025-10-31 21:31:58 -03:00
acf00bc5f8 added lua functions from old version of packets 2025-10-31 21:31:12 -03:00
b15d847fd2 function to generate random text 2025-10-31 21:30:48 -03:00
05af0969e9 methods for PacketLua struct 2025-10-31 18:15:42 -03:00
dff912928b removing useless part 2025-10-31 18:15:16 -03:00
0001118bd0 file for test and debuging got in codebase for mistake 2025-10-31 18:08:23 -03:00
43a24a4f36 changing pkg() to install() 2025-10-31 18:04:25 -03:00
d3c4a604c3 New Packet.lua format, test parsing and entire new lua ecossystem 2025-10-31 17:52:40 -03:00
6c5abdf4d4 new Packet.lua format, testing it with bat 2025-10-31 13:32:03 -03:00
1c4ade5db9 removing everything to do final version of packets client 2025-10-31 12:54:42 -03:00
b31630a6c0 Merge pull request #4 from Caio1w/Solved-Issue#3
Solved Issue #3
2025-10-28 21:25:51 -03:00
Caio1w
25eabc92ed Update const.go 2025-10-28 21:23:14 -03:00
a111b060f1 Merge pull request #2 from roboogg133/build-system
A scrap of Packet.lua ecosystem
2025-10-26 21:53:15 -03:00
a62ddf8270 simple checking for remote packets 2025-10-26 21:47:06 -03:00
aa65b28112 Packet.lua with right version, serial and better version constraint 2025-10-26 21:46:46 -03:00
72a5ab7c5d removing debug changes 2025-10-26 18:24:10 -03:00
89b3fdbc84 getting functions from right table now and reading os and arch in package table 2025-10-26 18:23:16 -03:00
0a531488a3 Packet.lua example test 2025-10-26 18:06:08 -03:00
7fbaef7bd4 try to clone Packet.lua 2025-10-26 18:05:57 -03:00
b411eff6f4 systemd managment for daemons 2025-10-26 18:05:34 -03:00
befa4e3ea4 changing home dir for packets user to /etc/packets (configuration folder) 2025-10-26 18:04:07 -03:00
807d9fa784 removing dependencies from table packages in database 2025-10-26 18:03:19 -03:00
51 changed files with 2631 additions and 3410 deletions

View File

@@ -1,36 +0,0 @@
package main
import (
"fmt"
"log"
"net/http"
"os"
"packets/configs"
"packets/internal/consts"
"path/filepath"
)
type ConfigTOML struct {
Config struct {
DefaultHttpPort int `toml:"httpPort"`
DefaultCacheDir string `toml:"cacheDir"`
} `toml:"Config"`
}
func main() {
log.Println("Program started")
cfg, err := configs.GetConfigTOML()
if err != nil {
log.Fatal(err)
}
pid := os.Getpid()
if err := os.WriteFile(filepath.Join(consts.DefaultLinux_d, "http.pid"), []byte(fmt.Sprint(pid)), 0664); err != nil {
fmt.Println("error saving subprocess pid", err)
}
fs := http.FileServer(http.Dir(cfg.Config.Cache_d))
http.Handle("/", fs)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", cfg.Config.HttpPort), nil))
log.Printf("Listening and serving on port %d\n", cfg.Config.HttpPort)
}

66
cmd/packets/cli.go Normal file
View File

@@ -0,0 +1,66 @@
package main
import (
"os"
"os/exec"
"time"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
var docStyle = lipgloss.NewStyle().Margin(1, 2)
type item struct {
title, desc string
}
func (i item) Title() string { return i.title }
func (i item) Description() string { return i.desc }
func (i item) FilterValue() string { return i.title }
type model struct {
list list.Model
}
func (m model) Init() tea.Cmd {
return nil
}
type vimMsg struct{}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
if msg.String() == "ctrl+c" || msg.String() == "q" {
return m, tea.Quit
}
if msg.String() == "enter" {
path := m.list.SelectedItem().(item).desc
tea.ExecProcess(openEditor("vim", path), nil)
return m, tea.Quit
}
case tea.WindowSizeMsg:
h, v := docStyle.GetFrameSize()
m.list.SetSize(msg.Width-h, msg.Height-v)
}
var cmd tea.Cmd
m.list, cmd = m.list.Update(msg)
return m, cmd
}
func (m model) View() string {
return docStyle.Render(m.list.View())
}
func openEditor(editor, path string) *exec.Cmd {
time.Sleep(1 * time.Second)
cmd := exec.Command(editor, path)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
}

28
cmd/packets/config.go Normal file
View File

@@ -0,0 +1,28 @@
package main
import (
"os"
"path/filepath"
"github.com/pelletier/go-toml/v2"
)
type PacketsConfiguration struct {
BinDir string `toml:"BinDir"`
}
func GetConfiguration() error {
configFile := filepath.Join(ConfigurationDir, "config.toml")
data, err := os.ReadFile(configFile)
if err != nil {
return err
}
var config PacketsConfiguration
err = toml.Unmarshal(data, &config)
if err != nil {
return err
}
Config = &config
return nil
}

View File

@@ -0,0 +1,133 @@
package database
import (
"database/sql"
"fmt"
"strings"
"time"
_ "github.com/mattn/go-sqlite3"
"github.com/roboogg133/packets/internal/lua"
"github.com/roboogg133/packets/pkg/install"
"github.com/roboogg133/packets/pkg/packet.lua.d"
)
const (
CreateInstructions = `
CREATE TABLE IF NOT EXISTS installed_packages(
name TEXT NOT NULL,
id TEXT PRIMARY KEY,
version TEXT NOT NULL,
serial INTEGER NOT NULL,
maintainer TEXT NOT NULL,
verified INTEGER NOT NULL DEFAULT 0,
description TEXT NOT NULL,
upload_time TEXT NOT NULL,
installed_time INTEGER NOT NULL,
image BLOB,
UNIQUE(name, version),
UNIQUE(name, serial)
);
CREATE TABLE IF NOT EXISTS package_files(
package_id TEXT NOT NULL,
path TEXT NOT NULL,
is_dir INTEGER NOT NULL DEFAULT 0,
UNIQUE(package_id, path)
);
CREATE TABLE IF NOT EXISTS dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
version_constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
);
CREATE TABLE IF NOT EXISTS build_dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
version_constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
);
CREATE TABLE IF NOT EXISTS conflicts(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
version_constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
);
CREATE TABLE IF NOT EXISTS package_flags(
package_id TEXT NOT NULL,
flag TEXT NOT NULL,
name TEXT NOT NULL,
path TEXT NOT NULL
);
`
)
type DatabaseOptions struct {
// Add any additional options here
}
func MarkAsInstalled(pkg packet.PacketLua, files []install.BasicFileStatus, PACKETDIR string, flags []lua.Flag, db *sql.DB, image []byte, upload_time int64) error {
switch {
case upload_time == 0:
upload_time = time.Now().UnixMilli()
case image == nil:
image = []byte{1}
}
_, err := db.Exec("INSERT INTO installed_packages (name, id, version, installed_time, image, serial, maintainer, description, upload_time) VALUES (?, ?, ?, ?, ?, ?,?,?,?)", pkg.Name, pkg.Name+"@"+pkg.Version, pkg.Version, time.Now().UnixMilli(), image, pkg.Serial, pkg.Maintainer, pkg.Description, time.Now().UnixMilli())
if err != nil {
db.Exec("DELETE FROM installed_packages WHERE id = ?", pkg.Name+"@"+pkg.Version)
return err
}
for _, v := range files {
v.Filepath, _ = strings.CutPrefix(v.Filepath, PACKETDIR)
_, err = db.Exec("INSERT INTO package_files (package_id, path, is_dir) VALUES (?, ?, ?)", pkg.Name+"@"+pkg.Version, v.Filepath, v.IsDir)
if err != nil {
db.Exec("DELETE FROM installed_packages WHERE id = ?", pkg.Name+"@"+pkg.Version)
db.Exec("DELETE FROM package_files WHERE package_id = ?", pkg.Name+"@"+pkg.Version)
return err
}
}
for _, v := range flags {
_, err = db.Exec("INSERT INTO package_flags (package_id, flag, name, path) VALUES (?, ?, ?, ?)", pkg.Name+"@"+pkg.Version, v.FlagType, v.Name, v.Path)
if err != nil {
db.Exec("DELETE FROM installed_packages WHERE id = ?", pkg.Name+"@"+pkg.Version)
db.Exec("DELETE FROM package_files WHERE package_id = ?", pkg.Name+"@"+pkg.Version)
db.Exec("DELETE FROM package_flags WHERE package_id = ?", pkg.Name+"@"+pkg.Version)
return err
}
}
return nil
}
func MarkAsUninstalled(id string, db *sql.DB) error {
if _, err := db.Exec("DELETE FROM installed_packages WHERE id = ?", id); err != nil {
return err
}
if _, err := db.Exec("DELETE FROM package_files WHERE package_id = ?", id); err != nil {
return err
}
if _, err := db.Exec("DELETE FROM package_flags WHERE package_id = ?", id); err != nil {
return err
}
return nil
}
func PrepareDataBase(db *sql.DB) {
_, err := db.Exec(CreateInstructions)
if err != nil {
fmt.Println("Error preparing database:", err)
}
}

View File

@@ -0,0 +1,72 @@
package database
import (
"database/sql"
"strings"
"github.com/roboogg133/packets/internal/lua"
"github.com/roboogg133/packets/pkg/install"
"github.com/roboogg133/packets/pkg/packet.lua.d"
)
// this function will get from a package name an id based on installed packages
func GetPackageId(name string, db *sql.DB) (packet.PackageID, error) {
var id packet.PackageID
if strings.Contains(name, "@") {
id.ID = strings.SplitAfter(name, "@")[0]
return id, nil
}
err := db.QueryRow("SELECT id FROM installed_packages WHERE name = ?", name).Scan(&id.ID)
return id, err
}
func SearchIfIsInstalled(name string, db *sql.DB) (bool, error) {
var exists bool
err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM installed_packages WHERE name = ?)", name).Scan(&exists)
return exists, err
}
func GetAllFromFlag(packageID packet.PackageID, flagType string, db *sql.DB) ([]lua.Flag, error) {
var flags []lua.Flag
rows, err := db.Query("SELECT name, path FROM package_flags WHERE package_id = ? AND flag = ?", packageID.ID, flagType)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var flag lua.Flag
if err := rows.Scan(&flag.Name, &flag.Path); err != nil {
return nil, err
}
flag.FlagType = flagType
flags = append(flags, flag)
}
return flags, nil
}
func GetPackageFiles(packageID packet.PackageID, db *sql.DB) ([]install.BasicFileStatus, error) {
var files []install.BasicFileStatus
rows, err := db.Query("SELECT path, is_dir FROM package_files WHERE package_id = ?", packageID.ID)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var file install.BasicFileStatus
if err := rows.Scan(&file.Filepath, &file.IsDir); err != nil {
return nil, err
}
files = append(files, file)
}
if err := rows.Err(); err != nil {
return nil, err
}
return files, nil
}

View File

@@ -0,0 +1,153 @@
package decompress
import (
"archive/tar"
"archive/zip"
"bytes"
"compress/bzip2"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/klauspost/compress/zstd"
"github.com/pierrec/lz4/v4"
"github.com/ulikunitz/xz"
)
func extractZipFile(file *zip.File, dest string) error {
rc, err := file.Open()
if err != nil {
return err
}
defer rc.Close()
path := filepath.Join(dest, file.Name)
if file.FileInfo().IsDir() {
return os.MkdirAll(path, file.Mode())
}
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return err
}
outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer outFile.Close()
_, err = io.Copy(outFile, rc)
return err
}
func Decompress(data io.Reader, outputDir, filename string) error {
var reader io.Reader
switch {
case strings.HasSuffix(filename, ".gz"):
var err error
reader, err = gzip.NewReader(data)
if err != nil {
return err
}
filename, _ = strings.CutSuffix(filename, ".gz")
case strings.HasSuffix(filename, ".xz"):
var err error
reader, err = xz.NewReader(data)
if err != nil {
return err
}
filename, _ = strings.CutSuffix(filename, ".xz")
case strings.HasSuffix(filename, ".zst"), strings.HasSuffix(filename, ".pkt"):
var err error
reader, err = zstd.NewReader(data)
if err != nil {
return err
}
filename, _ = strings.CutSuffix(filename, ".zst")
case strings.HasSuffix(filename, ".bz2"):
reader = bzip2.NewReader(data)
filename, _ = strings.CutSuffix(filename, ".bz2")
case strings.HasSuffix(filename, ".lz4"):
reader = lz4.NewReader(data)
filename, _ = strings.CutSuffix(filename, ".lz4")
case strings.HasSuffix(filename, ".zip"):
content, err := io.ReadAll(data)
if err != nil {
return err
}
reader, err := zip.NewReader(bytes.NewReader(content), int64(len(content)))
if err != nil {
return err
}
if err := os.MkdirAll(outputDir, 0755); err != nil {
return err
}
for _, file := range reader.File {
err := extractZipFile(file, outputDir)
if err != nil {
return fmt.Errorf("error unziping %s: %w", file.Name, err)
}
}
return nil
}
if strings.HasSuffix(filename, ".tar") || strings.HasSuffix(filename, ".pkt") {
tarReader := tar.NewReader(reader)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
targetPath := filepath.Join(outputDir, filepath.Clean(header.Name))
if !strings.HasPrefix(targetPath, outputDir) {
return fmt.Errorf("invalid path: %s", targetPath)
}
switch header.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil {
return err
}
case tar.TypeReg, tar.TypeRegA:
if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
return err
}
outFile, err := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(header.Mode))
if err != nil {
return err
}
defer outFile.Close()
if _, err := io.Copy(outFile, tarReader); err != nil {
return err
}
case tar.TypeSymlink:
if err := os.Symlink(header.Linkname, targetPath); err != nil {
return err
}
case tar.TypeLink:
linkPath := filepath.Join(outputDir, header.Linkname)
if err := os.Link(linkPath, targetPath); err != nil {
return err
}
default:
return fmt.Errorf("unknown file type: %c => %s", header.Typeflag, header.Name)
}
}
}
return nil
}

77
cmd/packets/flags.go Normal file
View File

@@ -0,0 +1,77 @@
package main
import (
"database/sql"
"fmt"
"os"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/roboogg133/packets/cmd/packets/database"
"github.com/spf13/cobra"
)
var configCmd = &cobra.Command{
Use: "config {name or id}",
Short: "Show package configuration file",
Long: "Show package configuration file",
Args: cobra.RangeArgs(1, 1),
PreRun: func(cmd *cobra.Command, args []string) {
GrantPrivilegies()
},
Run: func(cmd *cobra.Command, args []string) {
insertedName := args[0]
db, err := sql.Open("sqlite3", InternalDB)
if err != nil {
fmt.Println("Error opening database:", err)
os.Exit(1)
}
defer db.Close()
database.PrepareDataBase(db)
id, err := database.GetPackageId(insertedName, db)
if err != nil {
if err == sql.ErrNoRows {
fmt.Printf("package %s not found\n", insertedName)
} else {
fmt.Println("Error getting package ID:", err)
}
os.Exit(1)
}
flags, err := database.GetAllFromFlag(id, "config", db)
if err != nil {
fmt.Println("Error getting flags:", err)
os.Exit(1)
}
if raw, _ := cmd.Flags().GetBool("raw"); raw {
for _, flag := range flags {
fmt.Printf("%s->%s\n", flag.Name, flag.Path)
}
return
}
var all []list.Item
for _, flag := range flags {
item := item{
title: flag.Name,
desc: flag.Path,
}
all = append(all, item)
}
m := model{list: list.New(all, list.NewDefaultDelegate(), 0, 0)}
m.list.Title = "Configuration files"
p := tea.NewProgram(m, tea.WithAltScreen())
if _, err := p.Run(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
},
}

44
cmd/packets/functions.go Normal file
View File

@@ -0,0 +1,44 @@
package main
import (
"bytes"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"github.com/go-git/go-git/v6"
"github.com/roboogg133/packets/cmd/packets/decompress"
"github.com/roboogg133/packets/pkg/packet.lua.d"
)
func DownloadSource(sources *[]packet.Source, configs *packet.Config) error {
for _, source := range *sources {
downloaded, err := packet.GetSource(source.Url, source.Method, source.Specs, NumberOfTryAttempts)
if err != nil {
return fmt.Errorf("error: %s", err.Error())
}
if source.Method == "GET" || source.Method == "POST" {
f := downloaded.([]byte)
buf := bytes.NewBuffer(f)
_ = os.MkdirAll(configs.SourcesDir, 0755)
if err := decompress.Decompress(buf, configs.SourcesDir, path.Base(source.Url)); err != nil {
return fmt.Errorf("error: %s", err.Error())
}
} else {
options := downloaded.(*git.CloneOptions)
repoName, _ := strings.CutSuffix(filepath.Base(source.Url), ".git")
_ = os.MkdirAll(filepath.Join(configs.SourcesDir, repoName), 0755)
_, err := git.PlainClone(filepath.Join(configs.SourcesDir, repoName), options)
if err != nil {
return fmt.Errorf("error: %s", err.Error())
}
os.RemoveAll(filepath.Join(configs.SourcesDir, repoName, ".git"))
}
}
return nil
}

View File

@@ -1,677 +1,320 @@
package main package main
import ( import (
"archive/tar"
"database/sql" "database/sql"
"fmt" "fmt"
"io" "io"
"log" "io/fs"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"sync"
"packets/configs" "github.com/klauspost/compress/zstd"
"packets/internal/consts" _ "github.com/mattn/go-sqlite3"
errors_packets "packets/internal/errors" "github.com/roboogg133/packets/cmd/packets/database"
"packets/internal/packet" "github.com/roboogg133/packets/cmd/packets/decompress"
"packets/internal/utils" "github.com/roboogg133/packets/pkg/install"
packets "packets/pkg" "github.com/roboogg133/packets/pkg/packet.lua.d"
"github.com/pelletier/go-toml/v2"
"github.com/spf13/cobra" "github.com/spf13/cobra"
lua "github.com/yuin/gopher-lua"
_ "modernc.org/sqlite"
) )
// init is doing some verifications func GrantPrivilegies() {
func init() { if os.Geteuid() != 0 {
log.SetPrefix("error: ") fmt.Println("error: this operation must be run as root")
log.SetFlags(0) os.Exit(1)
//log.SetFlags(log.Lshortfile)
_, err := os.Stat(consts.DefaultLinux_d)
if os.IsNotExist(err) {
err := os.Mkdir(consts.DefaultLinux_d, 0777)
if err != nil {
if os.IsPermission(err) {
log.Fatal("can't create packets root directory, please run as root")
} else {
log.Fatal(err)
}
}
} }
}
_, err = os.Stat(filepath.Join(consts.DefaultLinux_d, "index.db")) var Config *PacketsConfiguration
if err != nil {
if os.IsNotExist(err) { var rootCmd = &cobra.Command{
if len(os.Args) > 1 && os.Args[0] != "sync" { Use: "packets",
} else { Short: "A tool for managing packets",
fmt.Println("index.db does not exist, try to use \"packets sync\"") Long: "A multiplatform package manager",
}
var executeCmd = &cobra.Command{
Use: "execute {path}",
Short: "Installs a package from a given .pkt file",
Long: "Installs a package from a given .pkt file",
Args: cobra.MinimumNArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
GrantPrivilegies()
return GetConfiguration()
},
Run: func(cmd *cobra.Command, args []string) {
for _, v := range args {
var pkg packet.PacketLua
if !strings.HasSuffix(v, ".pkt") {
fmt.Printf("error: %s is not a valid Packets packet file\n", v)
os.Exit(1)
} }
} else {
log.Fatal(err)
}
}
_, err = os.Stat(filepath.Join(consts.DefaultLinux_d, "installed.db")) contentBlob, err := os.Open(v)
if err != nil {
if os.IsNotExist(err) {
db, err := sql.Open("sqlite", filepath.Join(consts.DefaultLinux_d, "installed.db"))
if err != nil { if err != nil {
log.Fatal(db) fmt.Printf("error: %s could not be read\n", v)
os.Exit(1)
}
defer contentBlob.Close()
pkg, err = packet.ReadPacketFromZSTDF(contentBlob, &packet.Config{BinDir: Config.BinDir})
if err != nil {
fmt.Printf("error: %s", err.Error())
os.Exit(1)
}
rootdir, err := filepath.Abs(filepath.Join(PackageRootDir, pkg.Name+"@"+pkg.Version))
if err != nil {
fmt.Printf("error: %s", err.Error())
os.Exit(1)
}
sourcesdir, err := filepath.Abs(filepath.Join(rootdir, "src"))
if err != nil {
fmt.Printf("error: %s", err.Error())
os.Exit(1)
}
packetsdir, err := filepath.Abs(filepath.Join(rootdir, "packet"))
if err != nil {
fmt.Printf("error: %s", err.Error())
os.Exit(1)
}
configs := &packet.Config{
BinDir: Config.BinDir,
RootDir: rootdir,
SourcesDir: sourcesdir,
PacketDir: packetsdir,
}
db, err := sql.Open("sqlite3", InternalDB)
if err != nil {
fmt.Printf("error: %s", err.Error())
os.Exit(1)
} }
defer db.Close() defer db.Close()
if _, err := db.Exec(consts.InstalledDatabaseSchema); err != nil {
log.Fatal(err)
}
} else {
log.Fatal(err)
}
}
_, err = os.Stat(filepath.Join(consts.DefaultLinux_d, "config.toml")) database.PrepareDataBase(db)
if os.IsNotExist(err) {
f, err := os.Create(filepath.Join(consts.DefaultLinux_d, "config.toml"))
if err != nil {
log.Fatal(err)
}
defer f.Close() if installed, err := database.SearchIfIsInstalled(pkg.Name, db); err == nil {
encoder := toml.NewEncoder(f)
cfg, err := configs.DefaultConfigTOML()
if err != nil {
log.Fatal(err)
}
if err = encoder.Encode(*cfg); err != nil {
log.Fatal(err)
}
}
_ = os.MkdirAll("/var/lib/packets", 0777)
}
// COBRA CMDS
var rootCmd = &cobra.Command{Use: "packets"}
var syncCmd = &cobra.Command{
Use: "sync [url]",
Args: cobra.MaximumNArgs(1),
Short: "Syncronizes with an remote index.db, and check if the data dir is changed",
Run: func(cmd *cobra.Command, args []string) {
_, err := os.Stat(consts.IndexDB)
if err != nil {
if !os.IsNotExist(err) {
log.Fatal("index.db does not exist, try to use \"packets sync\"")
}
}
if os.Getuid() != 0 {
log.Fatal("are you running packets as root?")
}
syncUrl := consts.DefaultSyncUrl
if len(args) > 0 {
syncUrl = args[0]
}
DBB, err := utils.GetFileHTTP(syncUrl)
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile(consts.IndexDB, DBB, 0774); err != nil {
log.Fatal(err)
}
fmt.Printf(":: Sucessifully syncronized index.db with [ %s ]\n", syncUrl)
os.Exit(0)
},
}
type Quer1 struct {
Name string
Version string
Description string
}
var installCmd = &cobra.Command{
Use: "install {package} [packages...]",
Short: "Install a package",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
_, err := os.Stat(consts.IndexDB)
if err != nil {
if !os.IsNotExist(err) {
log.Fatal("index.db does not exist, try to use \"packets sync\"")
}
}
if os.Getuid() != 0 {
log.Fatal("you must run this command as root")
}
db, err := sql.Open("sqlite", consts.IndexDB)
if err != nil {
fmt.Println(err)
}
defer db.Close()
cfg, err := configs.GetConfigTOML()
if err != nil {
log.Fatal(err)
}
for _, inputName := range args {
runtime.GC()
var exist bool = false
err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM packages WHERE id = ?)", inputName).Scan(&exist)
if err != nil {
log.Fatal(err)
}
if exist {
installed, err := utils.CheckIfPackageInstalled(inputName)
if err != nil {
log.Fatal(err)
}
if installed { if installed {
fmt.Printf("Package %s is already installed\n", inputName) fmt.Printf("package %s is already installed", pkg.Name)
continue continue
} }
fmt.Printf("Checking dependencies of (%s)\n", inputName) } else {
dependenciesRaw, err := utils.GetDependencies(db, inputName) fmt.Printf("error: %s", err.Error())
if err != nil { os.Exit(1)
log.Fatal(err) }
}
dependencies, err := utils.ResolvDependencies(dependenciesRaw) backupDir, err := filepath.Abs(".")
if err != nil { _ = ChangeToNoPermission()
log.Fatal(err) _ = os.MkdirAll(configs.RootDir, 0755)
} contentBlob.Seek(0, io.SeekStart)
if err := decompress.Decompress(contentBlob, configs.RootDir, filepath.Base(v)); err != nil {
fmt.Printf("error: %s", err.Error())
os.Exit(1)
}
_ = os.MkdirAll(configs.SourcesDir, 0755)
_ = os.MkdirAll(configs.PacketDir, 0755)
if len(dependencies) > 0 { if err := DownloadSource(pkg.GlobalSources, configs); err != nil {
var wg sync.WaitGroup fmt.Printf("error: %s", err.Error())
var mu sync.Mutex os.Exit(1)
fmt.Printf(":: Packets will install %s and %d dependencies\nPackages to install:\n", inputName, len(dependencies)) }
fmt.Println(dependencies)
fmt.Println("Are you sure? (y/N)") if pkg.Plataforms != nil {
var a string
fmt.Scanf("%s", &a) temp := *pkg.Plataforms
if a != "y" && a != "Y" {
if plataform, exists := temp[packet.OperationalSystem(runtime.GOOS)]; exists {
if err := DownloadSource(plataform.Sources, configs); err != nil {
fmt.Printf("error: %s", err.Error())
os.Exit(1) os.Exit(1)
} }
for _, depn := range dependencies {
wg.Add(1)
go AyncFullInstall(depn, cfg.Config.StorePackages, filepath.Join(cfg.Config.Data_d, depn), &wg, &mu)
}
wg.Wait()
} }
fmt.Printf("Downloading (%s) \n", inputName)
p, err := utils.GetPackage(inputName)
if err != nil {
log.Fatal(err)
}
fmt.Printf(":: Installing (%s) \n", inputName)
if err := packets.InstallPackage(p.PackageF, filepath.Join(cfg.Config.Data_d, inputName)); err != nil {
log.Fatal(err)
}
if cfg.Config.StorePackages {
_, err := p.Write()
if err != nil {
log.Fatal(err)
}
err = p.AddToInstalledDB(1, filepath.Join(cfg.Config.Data_d, inputName))
if err != nil {
log.Fatal(err)
}
} else {
err := p.AddToInstalledDB(0, filepath.Join(cfg.Config.Data_d, inputName))
if err != nil {
log.Fatal(err)
}
}
continue
} }
var id string
err = db.QueryRow("SELECT id FROM packages WHERE query_name = ? ORDER BY serial DESC LIMIT 1", inputName).Scan(&id)
if err != nil { if err != nil {
if err == sql.ErrNoRows { fmt.Printf("error: %s", err.Error())
log.Panicf("can't find any results for (%s)\n", inputName) os.Exit(1)
}
log.Fatal(err)
} }
installed, err := utils.CheckIfPackageInstalled(inputName) pkg.ExecuteBuild(configs)
pkg.ExecuteInstall(configs)
_ = ElevatePermission()
os.Chdir(backupDir)
files, err := install.GetPackageFiles(configs.PacketDir)
if err != nil { if err != nil {
log.Fatal(err) fmt.Printf("error: %s", err.Error())
os.Exit(1)
} }
if installed { if err := install.InstallFiles(files, configs.PacketDir); err != nil {
fmt.Printf(":: Package %s is already installed, searching for upgrades...\n", inputName) fmt.Printf("error: %s", err.Error())
var wg sync.WaitGroup os.Exit(1)
wg.Add(1)
go AsyncFullyUpgrade(inputName, cfg.Config.StorePackages, filepath.Join(cfg.Config.Data_d, id), &wg, db)
continue
} }
fmt.Printf("Checking dependencies of (%s)\n", inputName) if err := database.MarkAsInstalled(pkg, files, configs.PacketDir, pkg.Flags, db, nil, 0); err != nil {
dependenciesRaw, err := utils.GetDependencies(db, id) fmt.Printf("error: %s", err.Error())
if err != nil { os.Exit(1)
log.Fatal(err)
} }
dependencies, err := utils.ResolvDependencies(dependenciesRaw)
if err != nil {
log.Fatal(err)
}
if len(dependencies) > 0 {
var wg sync.WaitGroup
var mu sync.Mutex
fmt.Printf(":: Packets will install %s and %d dependencies\nPackages to install:\n", id, len(dependencies))
fmt.Println(dependencies)
fmt.Println("Are you sure? (y/N)")
var a string
fmt.Scanf("%s", &a)
if a != "y" && a != "Y" {
os.Exit(1)
}
for _, depn := range dependencies {
wg.Add(1)
go AyncFullInstall(depn, cfg.Config.StorePackages, filepath.Join(cfg.Config.Data_d, depn), &wg, &mu)
}
wg.Wait()
}
fmt.Printf("Downloading %s \n", inputName)
p, err := utils.GetPackage(id)
if err != nil {
log.Fatal(err)
}
cfg, err := configs.GetConfigTOML()
if err != nil {
log.Fatal(err)
}
fmt.Printf(":: Installing %s \n", inputName)
if err := packets.InstallPackage(p.PackageF, filepath.Join(cfg.Config.Data_d, id)); err != nil {
log.Fatal(err)
}
if cfg.Config.StorePackages {
_, err := p.Write()
if err != nil {
log.Fatal(err)
}
err = p.AddToInstalledDB(1, filepath.Join(cfg.Config.Data_d, id))
if err != nil {
log.Fatal(err)
}
} else {
err := p.AddToInstalledDB(0, filepath.Join(cfg.Config.Data_d, id))
if err != nil {
log.Fatal(err)
}
}
continue
} }
}, },
} }
var removeCmd = &cobra.Command{ var removeCmd = &cobra.Command{
Use: "remove {package name}[package name...] ", Use: "remove {name or id}",
Short: "Removes a package from the system",
Long: "Removes a package from the system",
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
Short: "Remove a package from the given names", PreRun: func(cmd *cobra.Command, args []string) {
GrantPrivilegies()
},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
for _, arg := range args {
if os.Getuid() != 0 { db, err := sql.Open("sqlite3", InternalDB)
log.Fatal("you must run this command as root")
}
fmt.Print("WARNING: This command will remove permanently this packages, are you sure? (y/N) ")
var a string
fmt.Scanf("%s", &a)
if a != "y" && a != "Y" {
os.Exit(1)
}
for _, pkgName := range args {
installed, err := utils.CheckIfPackageInstalled(pkgName)
if err != nil { if err != nil {
log.Fatal(err) fmt.Printf("error: %s\n", err.Error())
os.Exit(1)
} }
if installed { defer db.Close()
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
log.Fatal(err)
}
var packageDir string
if err := db.QueryRow("SELECT package_d FROM packages WHERE query_name = ? OR id = ?", pkgName, pkgName).Scan(&packageDir); err != nil {
log.Fatal(err)
}
f, err := os.Open(filepath.Join(packageDir, "Packet.lua")) id, err := database.GetPackageId(arg, db)
if err != nil { if err != nil {
log.Fatal(err) if err == sql.ErrNoRows {
fmt.Printf("package %s not found\n", arg)
continue
} }
fmt.Printf("error: %s\n", err.Error())
fBLob, err := io.ReadAll(f)
if err != nil {
log.Fatal(err)
}
manifest, err := packet.ReadPacket(fBLob)
if err != nil {
log.Fatal(err)
}
fmt.Println(":: Removing", pkgName)
os.Chdir(packageDir)
if err := manifest.ExecuteRemove(lua.NewState()); err != nil {
log.Panic(err)
}
if err := os.RemoveAll(packageDir); err != nil {
log.Fatal(err)
}
if err := utils.RemoveFromInstalledDB(pkgName); err != nil {
log.Fatal(err)
}
fmt.Println("Sucessifully removed")
continue continue
} }
log.Fatalf("%s not installed", pkgName)
files, err := database.GetPackageFiles(id, db)
if err != nil {
fmt.Printf("error: %s\n", err.Error())
continue
}
for _, file := range files {
if !file.IsDir {
if err := os.Remove(file.Filepath); err != nil {
fmt.Printf("error: %s\n", err.Error())
continue
}
}
}
if err := database.MarkAsUninstalled(id.ID, db); err != nil {
fmt.Printf("error removing package from database but successfully removed it from the system: %s\n", err.Error())
continue
}
}
},
}
var devCmd = &cobra.Command{
Use: "dev",
Short: "Develop a package",
Long: "Useful commands for developing packages",
}
var packCmd = &cobra.Command{
Use: "pack",
Short: "Package a directory",
Long: "Package a directory",
Run: func(cmd *cobra.Command, args []string) {
for _, arg := range args {
packetDotLuaBlob, err := os.ReadFile(filepath.Join(arg, "Packet.lua"))
if err != nil {
fmt.Printf("invalid package dir can't find Packet.lua")
continue
}
packet, err := packet.ReadPacket(packetDotLuaBlob, nil)
if err != nil {
fmt.Printf("error: %s\n", err.Error())
continue
}
packageFile, err := os.OpenFile(packet.Name+"@"+packet.Version+".pkt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
fmt.Printf("error: %s\n", err.Error())
continue
}
zstdWriter, err := zstd.NewWriter(packageFile)
if err != nil {
fmt.Printf("error: %s\n", err.Error())
continue
}
defer zstdWriter.Close()
baseDir := filepath.Clean(arg)
tarWriter := tar.NewWriter(zstdWriter)
defer tarWriter.Close()
filepath.Walk(arg, func(path string, info fs.FileInfo, err error) error {
header, err := tar.FileInfoHeader(info, "")
if err != nil {
return err
}
relPath, err := filepath.Rel(baseDir, path)
if err != nil {
return err
}
if relPath == "." {
return nil
}
header.Name = relPath
if err := tarWriter.WriteHeader(header); err != nil {
return err
}
if !info.IsDir() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
if _, err := io.Copy(tarWriter, file); err != nil {
return err
}
}
return nil
})
} }
os.Exit(0)
}, },
} }
var listCmd = &cobra.Command{ var listCmd = &cobra.Command{
Use: "list", Use: "list",
Args: cobra.NoArgs,
Short: "List all installed packages", Short: "List all installed packages",
Long: "List all installed packages",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db, err := sql.Open("sqlite", consts.InstalledDB) fmt.Println("odasd")
if err != nil {
log.Fatal(err)
}
defer db.Close()
var count int
if err := db.QueryRow("SELECT COUNT(*) FROM packages").Scan(&count); err != nil {
log.Fatal(err)
}
rows, err := db.Query("SELECT query_name, id, version, description, package_d, os, arch FROM packages")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
fmt.Printf(":: Listing all %d packages installed:\n\n", count)
for rows.Next() {
var queryName, name, version, description, packageDir, os, arch string
if err := rows.Scan(&queryName, &name, &version, &description, &packageDir, &os, &arch); err != nil {
log.Fatal(err)
}
fmt.Printf(" Package %s \n ├──Id: %s\n ├──Version: %s \n ├──Package dir: %s\n ├──OS: %s\n ├──Arch: %s\n └──Description: %s\n", queryName, name, version, packageDir, os, arch, description)
}
},
}
var searchCmd = &cobra.Command{
Use: "search [query]",
Args: cobra.MaximumNArgs(1),
Short: "Search for packages in the index.db",
Run: func(cmd *cobra.Command, args []string) {
db, err := sql.Open("sqlite", consts.IndexDB)
if err != nil {
log.Fatal(err)
}
defer db.Close()
var count int
if err := db.QueryRow("SELECT COUNT(*) FROM packages").Scan(&count); err != nil {
log.Fatal(err)
}
var rows *sql.Rows
if len(args) > 0 {
rows, err = db.Query("SELECT query_name, id, version, description, os, arch FROM packages WHERE name LIKE ? OR description LIKE ? OR query_name LIKE ?", args[0], args[0], args[0])
if err != nil {
log.Fatal(err)
}
defer rows.Close()
} else {
rows, err = db.Query("SELECT query_name, id, version, description, os, arch FROM packages")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
}
fmt.Printf(":: Listing all %d packages:\n\n", count)
for rows.Next() {
var queryName, name, version, description, os, arch string
if err := rows.Scan(&queryName, &name, &version, &description, &os, &arch); err != nil {
log.Fatal(err)
}
fmt.Printf(" Package %s \n ├──Query name: %s\n ├──Version: %s \n ├──OS: %s\n ├──Arch: %s\n └──Description: %s\n", name, queryName, version, os, arch, description)
}
},
}
var upgradeCmd = &cobra.Command{
Use: "upgrade",
Args: cobra.NoArgs,
Short: "upgrade all installed packages",
Run: func(cmd *cobra.Command, args []string) {
if os.Getuid() != 0 {
log.Fatal("you must run this command as root")
}
cfg, err := configs.GetConfigTOML()
if err != nil {
log.Fatal(err)
}
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query("SELECT query_name FROM packages")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var installedPackagesQName []string
for rows.Next() {
var queryName string
if err := rows.Scan(&queryName); err != nil {
log.Fatal(err)
}
installedPackagesQName = append(installedPackagesQName, queryName)
}
var wg sync.WaitGroup
for _, v := range installedPackagesQName {
wg.Add(1)
go AsyncFullyUpgrade(v, cfg.Config.StorePackages, cfg.Config.Data_d, &wg, db)
}
wg.Wait()
}, },
} }
func main() { func main() {
rootCmd.AddCommand(installCmd) rootCmd.AddCommand(executeCmd)
rootCmd.AddCommand(removeCmd) rootCmd.AddCommand(removeCmd)
rootCmd.AddCommand(syncCmd) configCmd.Flags().Bool("raw", false, "show config names and dir in stdout")
rootCmd.AddCommand(listCmd) rootCmd.AddCommand(configCmd)
rootCmd.AddCommand(searchCmd)
rootCmd.AddCommand(upgradeCmd) rootCmd.AddCommand(devCmd)
devCmd.AddCommand(packCmd)
rootCmd.Execute() rootCmd.Execute()
} }
func AyncFullInstall(dep string, storePackages bool, installPath string, wg *sync.WaitGroup, mu *sync.Mutex) {
defer wg.Done()
fmt.Printf(" downloading %s \n", dep)
p, err := utils.GetPackage(dep)
if err != nil {
log.Fatal(err)
}
fmt.Printf(" installing %s \n", dep)
if err := packets.InstallPackage(p.PackageF, installPath); err != nil {
log.Fatal(err)
}
if storePackages {
_, err := p.Write()
if err != nil {
log.Fatal(err)
return
}
mu.Lock()
defer mu.Unlock()
err = p.AddToInstalledDB(1, installPath)
if err != nil {
log.Fatal(err)
return
}
} else {
mu.Lock()
defer mu.Unlock()
err := p.AddToInstalledDB(0, installPath)
if err != nil {
log.Println(err)
return
}
}
}
func AsyncFullyUpgrade(queryName string, storePackages bool, installDir string, wg *sync.WaitGroup, db *sql.DB) {
defer wg.Done()
installed, err := utils.CheckIfPackageInstalled(queryName)
if err != nil {
log.Println(err)
return
}
if !installed {
log.Println(errors_packets.ErrNotInstalled)
return
}
idb, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
log.Panic(err)
return
}
var oldSerial int
if err := idb.QueryRow("SELECT serial FROM packages WHERE query_name = ?", queryName).Scan(&oldSerial); err != nil {
log.Println(err)
return
}
var newSerial int
var id string
if err := db.QueryRow("SELECT serial, id FROM packages WHERE query_name = ? ORDER BY serial DESC LIMIT 1", queryName).Scan(&newSerial, &id); err != nil {
log.Println(err)
return
}
installPath := filepath.Join(installDir, id)
if oldSerial == newSerial {
log.Println(errors_packets.ErrAlredyUpToDate)
return
}
var v int
if storePackages {
v = 1
} else {
v = 0
}
if err := UpgradeToThis(id, installPath, idb, v); err != nil {
log.Println(err)
return
}
}
func UpgradeToThis(id string, installPath string, installedDB *sql.DB, storePkgFile int) error {
p, err := utils.GetPackage(id)
if err != nil {
return err
}
query_name := strings.SplitN(id, "@", 2)[0]
var oldPath string
if err := installedDB.QueryRow("SELECT package_d FROM packages WHERE query_name = ?", query_name).Scan(&oldPath); err != nil {
return err
}
if err := os.Rename(oldPath, installPath); err != nil {
return err
}
if err := packets.InstallPackage(p.PackageF, installPath); err != nil {
if err := os.Rename(installPath, oldPath); err != nil {
return err
}
return err
}
_, err = installedDB.Exec(`
UPDATE packages
SET query_name = ?, id = ?, version = ?, description = ?,
serial = ?, package_d = ?, filename = ?, os = ?, arch = ?, in_cache = ?
`,
p.QueryName,
p.Manifest.Id,
p.Version,
p.Description,
p.Serial,
installPath,
p.Filename,
p.OS,
p.Arch,
storePkgFile,
)
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,11 @@
package main
const (
ConfigurationDir = "/etc/packets"
InternalDB = ConfigurationDir + "/internal.db"
HomeDir = "/var/lib/packets"
PackageRootDir = "/var/lib/packets/packages"
NumberOfTryAttempts = 4
UserHomeDirPlaceholder = "{{ USER HOME FOLDER }}"
UsernamePlaceholder = "{{ USERNAME }}"
)

37
cmd/packets/user.go Normal file
View File

@@ -0,0 +1,37 @@
package main
import (
"os/exec"
"strconv"
"strings"
"syscall"
)
func GetPacketsUID() (int, error) {
_ = exec.Command("useradd", "-M", "-N", "-r", "-s", "/bin/false", "-d", "/etc/packets", "packets").Run()
cmd := exec.Command("id", "-u", "packets")
out, err := cmd.CombinedOutput()
if err != nil {
return -1, err
}
s := strings.TrimSpace(string(out))
uid, err := strconv.Atoi(s)
if err != nil {
return -1, err
}
return uid, nil
}
func ChangeToNoPermission() error {
uid, err := GetPacketsUID()
if err != nil {
return err
}
return syscall.Setresuid(0, uid, 0)
}
func ElevatePermission() error { return syscall.Setresuid(0, 0, 0) }

View File

@@ -1,63 +0,0 @@
package main
import (
"fmt"
"log"
"net"
"os"
"packets/configs"
"packets/internal/consts"
"path/filepath"
"strings"
)
func CheckDownloaded(filename string) bool {
cfg, err := configs.GetConfigTOML()
if err != nil {
log.Fatal(err)
}
_, err = os.Stat(filepath.Join(cfg.Config.Cache_d, filename))
return err == nil
}
func main() {
log.Println("Program started")
pid := os.Getpid()
if err := os.WriteFile(filepath.Join(consts.DefaultLinux_d, "udp.pid"), []byte(fmt.Sprint(pid)), 0664); err != nil {
fmt.Println("error saving subprocess pid", err)
}
cfg, err := configs.GetConfigTOML()
if err != nil {
log.Fatal(err)
}
addr := net.UDPAddr{IP: net.IPv4zero, Port: 1333}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
log.Fatal(err)
}
log.Println("Started connection listener")
defer conn.Close()
buf := make([]byte, 1500)
for {
n, remote, err := conn.ReadFromUDP(buf)
if err != nil {
log.Println("error creating udp socket", err)
}
msg := string(buf[:n])
log.Printf("Received message : %s\n", msg)
if !strings.HasPrefix(msg, "Q:") {
log.Println("error: invalid message, this message don't follow the protocol")
continue
}
filename := strings.TrimPrefix(msg, "Q:")
if CheckDownloaded(filename) {
reply := fmt.Sprintf("H:%s:%d", filename, cfg.Config.HttpPort)
log.Printf("Package founded in cache dir, answering with: '%s'\n", reply)
conn.WriteToUDP([]byte(reply), remote)
}
}
}

View File

@@ -1,60 +0,0 @@
package configs
import (
"os"
"packets/internal/consts"
"path/filepath"
"github.com/pelletier/go-toml/v2"
)
// DefaultConfigTOML returns configTOML struct with all default values and create all directorys
func DefaultConfigTOML() (*ConfigTOML, error) {
var config ConfigTOML
_, err := os.Stat(consts.DefaultCache_d)
if err != nil {
if os.IsNotExist(err) {
err := os.MkdirAll(consts.DefaultCache_d, 0666)
if err != nil {
return nil, err
}
}
}
_, err = os.Stat(consts.DefaultCache_d)
if err != nil {
if os.IsNotExist(err) {
err := os.MkdirAll(consts.DefaultData_d, 0644)
if err != nil {
return nil, err
}
}
}
config.Config.Cache_d = consts.DefaultCache_d
config.Config.Data_d = consts.DefaultData_d
config.Config.HttpPort = consts.DefaultHttpPort
config.Config.Bin_d = consts.DefaultBin_d
config.Config.StorePackages = true
return &config, nil
}
// GetConfigTOML return settings values
func GetConfigTOML() (*ConfigTOML, error) {
f, err := os.Open(filepath.Join(consts.DefaultLinux_d, "config.toml"))
if err != nil {
return nil, err
}
decoder := toml.NewDecoder(f)
var config ConfigTOML
if err := decoder.Decode(&config); err != nil {
return nil, err
}
return &config, nil
}

View File

@@ -1,39 +0,0 @@
package configs
/*
type Manifest struct {
Package struct {
Name string `toml:"name"`
Id string `toml:"id"`
Version string `toml:"version"`
Description string `toml:"description"`
Dependencies map[string]string `toml:"dependencies"`
Author string `toml:"author"`
Architeture string `toml:"architeture"`
Os string `toml:"os"`
PacakgeType string `toml:"type"`
GitUrl string `toml:"giturl,omitempty"`
Branch string `toml:"gitbranch,omitempty"`
} `toml:"Package"`
Build struct {
BuildDependencies map[string]string `toml:"dependencies"`
}
Hooks struct {
Fetch string `toml:"fetch,omitempty"`
Install string `toml:"install"`
Remove string `toml:"remove"`
Build string `toml:"build"`
} `toml:"Hooks"`
}
*/
type ConfigTOML struct {
Config struct {
HttpPort int `toml:"httpPort"`
Cache_d string `toml:"cache_d"`
Data_d string `toml:"data_d"`
Bin_d string `toml:"bin_d"`
StorePackages bool `toml:"store_packages"`
} `toml:"Config"`
}

View File

@@ -1,55 +0,0 @@
CREATE TABLE packages (
id TEXT NOT NULL UNIQUE PRIMARY KEY,
query_name TEXT NOT NULL,
version TEXT NOT NULL,
serial INTEGER NOT NULL,
description TEXT NOT NULL,
image_url TEXT NOT NULL,
package_url TEXT NOT NULL,
public_key BLOB NOT NULL,
signature BLOB NOT NULL,
author TEXT NOT NULL,
author_verified INTEGER NOT NULL DEFAULT 0,
arch TEXT NOT NULL,
os TEXT NOT NULL,
size INTEGER NOT NULL DEFAULT 0,
UNIQUE(query_name, version),
UNIQUE(query_name, serial)
);
CREATE TABLE package_dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
version_constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
);
CREATE INDEX index_dependency_name ON package_dependencies(dependency_name);
CREATE TABLE IF NOT EXISTS packages (
query_name TEXT NOT NULL UNIQUE PRIMARY KEY,
id TEXT NOT NULL UNIQUE,
version TEXT NOT NULL,
dependencies TEXT NOT NULL DEFAULT '',
description TEXT NOT NULL,
package_d TEXT NOT NULL,
filename TEXT NOT NULL,
os TEXT NOT NULL,
arch TEXT NOT NULL,
in_cache INTEGER NOT NULL DEFAULT 1,
serial INTEGER NOT NULL,
UNIQUE(query_name, version),
UNIQUE(query_name, serial)
);
CREATE TABLE IF NOT EXISTS build_dependencies (
id TEXT PRIMARY KEY,
dir TEXT NOT NULL DEFAULT "/dev/null"
uses INTEGER NOT NULL DEFAULT 0
);

61
doc/internal.db.sql Normal file
View File

@@ -0,0 +1,61 @@
CREATE TABLE installed_packges(
name TEXT NOT NULL,
id TEXT PRIMARY KEY,
version TEXT NOT NULL,
serial INTEGER NOT NULL,
maintainer TEXT NOT NULL,
verified INTEGER NOT NULL DEFAULT 0,
description TEXT NOT NULL,
upload_time TEXT NOT NULL,
installed_time TEXT NOT NULL,
public_key BLOB NOT NULL,
signature BLOB NOT NULL,
image BLOB,
UNIQUE(name, signature),
UNIQUE(name, version),
UNIQUE(name, serial)
)
CREATE TABLE package_files(
package_id TEXT PRIMARY KEY,
filepath TEXT NOT NULL,
is_dir INTEGER NOT NULL DEFAULT 0,
UNIQUE(package_id, filepath)
)
CREATE TABLE dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
)
CREATE TABLE build_dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
)
CREATE TABLE conflicts(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
)
CREATE TABLE package_flags(
package_id TEXT NOT NULL,
flag TEXT NOT NULL,
name TEXT NOT NULL,
path TEXT NOT NULL,
)

41
doc/source.db.sql Normal file
View File

@@ -0,0 +1,41 @@
CREATE TABLE packges(
name TEXT NOT NULL,
id TEXT PRIMARY KEY,
version TEXT NOT NULL,
serial INTEGER NOT NULL,
maintainer TEXT NOT NULL,
verified INTEGER NOT NULL DEFAULT 0,
description TEXT NOT NULL,
upload_time TEXT NOT NULL,
UNIQUE(name, signature),
UNIQUE(name, version),
UNIQUE(name, serial)
)
CREATE TABLE dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
)
CREATE TABLE build_dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
)
CREATE TABLE conflicts(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
)

74
go.mod
View File

@@ -1,68 +1,56 @@
module packets module github.com/roboogg133/packets
go 1.25.1 go 1.25.3
require github.com/yuin/gopher-lua v1.1.1
require ( require (
github.com/gin-gonic/gin v1.11.0 github.com/charmbracelet/bubbles v0.21.0
github.com/go-git/go-git/v6 v6.0.0-20251021092831-91c33c9361ce github.com/charmbracelet/bubbletea v1.3.10
github.com/klauspost/compress v1.18.0 github.com/charmbracelet/lipgloss v1.1.0
github.com/go-git/go-git/v6 v6.0.0-20251029213217-0bbfc0875edd
github.com/klauspost/compress v1.18.1
github.com/mattn/go-sqlite3 v1.14.32
github.com/pelletier/go-toml/v2 v2.2.4 github.com/pelletier/go-toml/v2 v2.2.4
github.com/spf13/afero v1.15.0 github.com/pierrec/lz4/v4 v4.1.22
github.com/spf13/cobra v1.10.1 github.com/spf13/cobra v1.10.1
github.com/yuin/gopher-lua v1.1.1 github.com/ulikunitz/xz v0.5.15
golang.org/x/net v0.46.0
modernc.org/sqlite v1.38.2
) )
require ( require (
github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect
github.com/bytedance/sonic v1.14.0 // indirect github.com/atotto/clipboard v0.1.4 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/x/ansi v0.10.1 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/cloudflare/circl v1.6.1 // indirect github.com/cloudflare/circl v1.6.1 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/cyphar/filepath-securejoin v0.5.0 // indirect github.com/cyphar/filepath-securejoin v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-git/gcfg/v2 v2.0.2 // indirect github.com/go-git/gcfg/v2 v2.0.2 // indirect
github.com/go-git/go-billy/v6 v6.0.0-20251016063423-4289a4e54aa4 // indirect github.com/go-git/go-billy/v6 v6.0.0-20251022185412-61e52df296a5 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.27.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v1.4.0 // indirect github.com/kevinburke/ssh_config v1.4.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/mattn/go-localereader v0.0.1 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/pjbgf/sha1cd v0.5.0 // indirect github.com/pjbgf/sha1cd v0.5.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/quic-go/quic-go v0.54.0 // indirect github.com/sahilm/fuzzy v0.1.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/sergi/go-diff v1.4.0 // indirect github.com/sergi/go-diff v1.4.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/pflag v1.0.9 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/ugorji/go/codec v1.3.0 // indirect
go.uber.org/mock v0.5.0 // indirect
golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.43.0 // indirect golang.org/x/crypto v0.43.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect golang.org/x/net v0.46.0 // indirect
golang.org/x/mod v0.28.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect golang.org/x/text v0.30.0 // indirect
golang.org/x/tools v0.37.0 // indirect
google.golang.org/protobuf v1.36.9 // indirect
modernc.org/libc v1.66.3 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
) )

171
go.sum
View File

@@ -6,138 +6,120 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 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 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cyphar/filepath-securejoin v0.5.0 h1:hIAhkRBMQ8nIeuVwcAoymp7MY4oherZdAxD+m0u9zaw= github.com/cyphar/filepath-securejoin v0.5.0 h1:hIAhkRBMQ8nIeuVwcAoymp7MY4oherZdAxD+m0u9zaw=
github.com/cyphar/filepath-securejoin v0.5.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/cyphar/filepath-securejoin v0.5.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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 v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-git/gcfg/v2 v2.0.2 h1:MY5SIIfTGGEMhdA7d7JePuVVxtKL7Hp+ApGDJAJ7dpo= github.com/go-git/gcfg/v2 v2.0.2 h1:MY5SIIfTGGEMhdA7d7JePuVVxtKL7Hp+ApGDJAJ7dpo=
github.com/go-git/gcfg/v2 v2.0.2/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs= github.com/go-git/gcfg/v2 v2.0.2/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs=
github.com/go-git/go-billy/v6 v6.0.0-20251016063423-4289a4e54aa4 h1:xQLkKmWcw9n5CUkl//bKQB7SPWQbaoKSVnHXH9V8sg8= github.com/go-git/go-billy/v6 v6.0.0-20251022185412-61e52df296a5 h1:9nXOQ3HupDEerUXxiPrw3olFy/jHGZ3O3DyM/o6ejdc=
github.com/go-git/go-billy/v6 v6.0.0-20251016063423-4289a4e54aa4/go.mod h1:TpCYxdQ0tWZkrnAkd7yqK+z1C8RKcyjcaYAJNAcnUnM= github.com/go-git/go-billy/v6 v6.0.0-20251022185412-61e52df296a5/go.mod h1:TpCYxdQ0tWZkrnAkd7yqK+z1C8RKcyjcaYAJNAcnUnM=
github.com/go-git/go-git-fixtures/v5 v5.1.1 h1:OH8i1ojV9bWfr0ZfasfpgtUXQHQyVS8HXik/V1C099w= github.com/go-git/go-git-fixtures/v5 v5.1.1 h1:OH8i1ojV9bWfr0ZfasfpgtUXQHQyVS8HXik/V1C099w=
github.com/go-git/go-git-fixtures/v5 v5.1.1/go.mod h1:Altk43lx3b1ks+dVoAG2300o5WWUnktvfY3VI6bcaXU= github.com/go-git/go-git-fixtures/v5 v5.1.1/go.mod h1:Altk43lx3b1ks+dVoAG2300o5WWUnktvfY3VI6bcaXU=
github.com/go-git/go-git/v6 v6.0.0-20251021092831-91c33c9361ce h1:DFvDcCiFZk2yDXVreC9+B+SAZYHH2RssMmtR2zBwANE= github.com/go-git/go-git/v6 v6.0.0-20251029213217-0bbfc0875edd h1:pn6+tR4O8McyqEr2MbQwqcySovpG8jDd11F/jQ6aAfA=
github.com/go-git/go-git/v6 v6.0.0-20251021092831-91c33c9361ce/go.mod h1:xtOWa43AoQlsqYogmpf0MnjBJHKPL2/3teh4fmZ/k+Y= github.com/go-git/go-git/v6 v6.0.0-20251029213217-0bbfc0875edd/go.mod h1:z9pQiXCfyOZIs/8qa5zmozzbcsDPtGN91UD7+qeX3hk=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ= github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
@@ -145,40 +127,9 @@ golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM=
modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ=
modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek=
modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

View File

@@ -1,80 +0,0 @@
package build
import (
"packets/internal/packet"
utils_lua "packets/internal/utils/lua"
lua "github.com/yuin/gopher-lua"
)
func (container Container) ExecutePrepare(packetLua packet.PacketLua, L *lua.LState) error {
if packetLua.Prepare == nil {
return nil
}
gitTable := L.NewTable()
gitTable.RawSetString("clone", L.NewFunction(utils_lua.LGitClone))
gitTable.RawSetString("checkout", L.NewFunction(utils_lua.LGitCheckout))
gitTable.RawSetString("pull", L.NewFunction(utils_lua.LGitPUll))
containerTable := L.NewTable()
containerTable.RawSetString("dir", L.NewFunction(container.lDir))
L.SetGlobal("git", gitTable)
L.Push(packetLua.Prepare)
L.Push(containerTable)
return L.PCall(1, 0, nil)
}
func (container Container) ExecuteBuild(packetLua packet.PacketLua, L *lua.LState) error {
if packetLua.Build == nil {
return nil
}
osObject := L.GetGlobal("os").(*lua.LTable)
ioObject := L.GetGlobal("io").(*lua.LTable)
OnlyContainerOS := L.NewTable()
OnlyContainerOS.RawSetString("copy", L.NewFunction(container.lCopy))
OnlyContainerOS.RawSetString("mkdir", L.NewFunction(container.lMkdir))
OnlyContainerOS.RawSetString("rename", L.NewFunction(container.lRename))
OnlyContainerOS.RawSetString("remove", L.NewFunction(container.lRemove))
OnlyContainerOS.RawSetString("execute", L.NewFunction(container.lexecute))
OnlyContainerOS.RawSetString("open", L.NewFunction(container.lOpen))
OnlyContainerIO := L.NewTable()
OnlyContainerIO.RawSetString("popen", L.NewFunction(container.lpopen))
L.SetGlobal("io", OnlyContainerIO)
L.SetGlobal("os", OnlyContainerOS)
L.Push(packetLua.Build)
err := L.PCall(0, 0, nil)
if err != nil {
return err
}
L.SetGlobal("os", osObject)
L.SetGlobal("io", ioObject)
return nil
}
func (container Container) ExecuteInstall(packetLua packet.PacketLua, L *lua.LState) error {
containerTable := L.NewTable()
containerTable.RawSetString("dir", L.NewFunction(container.lDir))
L.Push(packetLua.Install)
L.Push(containerTable)
return L.PCall(1, 0, nil)
}

View File

@@ -1,167 +0,0 @@
package build
import (
"archive/tar"
"bytes"
"fmt"
"io"
"log"
"os"
"packets/internal/packet"
"packets/internal/utils"
utils_lua "packets/internal/utils/lua"
"path/filepath"
"strings"
"sync"
"github.com/klauspost/compress/zstd"
)
func (container Container) installPackage(file []byte, destDir string) error {
manifest, err := packet.ReadPacketFromFile(bytes.NewReader(file))
if err != nil {
return err
}
zstdReader, err := zstd.NewReader(bytes.NewReader(file))
if err != nil {
return err
}
defer zstdReader.Close()
tarReader := tar.NewReader(zstdReader)
uid, err := utils.GetPacketsUID()
if err != nil {
return err
}
for {
hdr, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
rel := filepath.Clean(hdr.Name)
if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
continue
}
if err := os.MkdirAll(filepath.Join(container.Root, destDir), 0775); err != nil {
return err
}
if err := os.Chown(filepath.Join(container.Root, destDir), uid, 0); err != nil {
return err
}
absPath := filepath.Join(filepath.Join(container.Root, destDir), rel)
switch hdr.Typeflag {
case tar.TypeDir:
err = os.MkdirAll(absPath, os.FileMode(hdr.Mode))
if err != nil {
return err
}
if err := os.Chown(absPath, uid, 0); err != nil {
return err
}
case tar.TypeReg:
err = os.MkdirAll(filepath.Dir(absPath), 0775)
if err != nil {
return err
}
out, err := os.Create(absPath)
if err != nil {
return err
}
_, err = io.Copy(out, tarReader)
out.Close()
if err != nil {
return err
}
err = os.Chmod(absPath, os.FileMode(0775))
if err != nil {
return err
}
if filepath.Base(hdr.Name) == "Packet.lua" {
err = os.Chmod(absPath, os.FileMode(0755))
if err != nil {
return err
}
} else {
if err := os.Chown(absPath, uid, 0); err != nil {
return err
}
}
}
}
L, err := utils_lua.GetSandBox()
if err != nil {
return err
}
bootstrapcontainer, err := NewContainer(manifest)
if err != nil {
return err
}
os.Chdir(destDir)
if err := bootstrapcontainer.ExecutePrepare(manifest, &L); err != nil {
return fmt.Errorf("error executing prepare: %s", err)
}
if err := bootstrapcontainer.ExecuteBuild(manifest, &L); err != nil {
return fmt.Errorf("error executing build: %s", err)
}
if err := utils.ChangeToNoPermission(); err != nil {
return fmt.Errorf("error changing to packet user: %s", err)
}
if err := bootstrapcontainer.ExecuteInstall(manifest, &L); err != nil {
return fmt.Errorf("error executing build: %s", err)
}
if err := utils.ElevatePermission(); err != nil {
return fmt.Errorf("error changing to root: %s", err)
}
return nil
}
func (container Container) asyncFullInstallDependencie(dep string, storePackages bool, installPath string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf(" downloading %s \n", dep)
p, err := utils.GetPackage(dep)
if err != nil {
log.Fatal(err)
}
fmt.Printf(" installing %s \n", dep)
if err := container.installPackage(p.PackageF, installPath); err != nil {
log.Fatal(err)
}
if storePackages {
_, err := p.Write()
if err != nil {
log.Fatal(err)
return
}
}
}

View File

@@ -1,224 +0,0 @@
package build
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
utils_lua "packets/internal/utils/lua"
"github.com/spf13/afero"
lua "github.com/yuin/gopher-lua"
)
func (container Container) lRemove(L *lua.LState) int {
filename := L.CheckString(1)
err := container.FS.RemoveAll(filename)
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func (container Container) lRename(L *lua.LState) int {
oldname := L.CheckString(1)
newname := L.CheckString(2)
if err := container.FS.Rename(oldname, newname); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func (container Container) lCopy(L *lua.LState) int {
oldname := L.CheckString(1)
newname := L.CheckString(2)
if err := container.copyContainer(oldname, newname); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func modeFlags(mode string) int {
switch mode {
case "r", "rb":
return os.O_RDONLY
case "w", "wb":
return os.O_CREATE | os.O_WRONLY | os.O_TRUNC
case "a", "ab":
return os.O_CREATE | os.O_WRONLY | os.O_APPEND
case "r+", "r+b", "rb+", "br+":
return os.O_RDWR
case "w+", "w+b", "wb+", "bw+":
return os.O_CREATE | os.O_RDWR | os.O_TRUNC
case "a+", "a+b", "ab+", "ba+":
return os.O_CREATE | os.O_RDWR | os.O_APPEND
default:
return os.O_RDONLY
}
}
func (container Container) lOpen(L *lua.LState) int {
path := L.CheckString(1)
mode := L.OptString(2, "r")
file, err := container.FS.OpenFile(path, modeFlags(mode), 0o644)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
ud := L.NewUserData()
ud.Value = file
L.SetMetatable(ud, L.GetTypeMetatable("file"))
L.Push(ud)
L.Push(lua.LNil)
return 2
}
func (container Container) lMkdir(L *lua.LState) int {
path := L.CheckString(1)
perm := L.CheckInt(2)
if err := container.FS.MkdirAll(path, os.FileMode(perm)); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func (container Container) lexecute(L *lua.LState) int {
cmdString := L.CheckString(1)
cmdSlice := strings.Fields(cmdString)
files, err := afero.ReadDir(container.FS, BinDir)
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString("exit"))
L.Push(lua.LNumber(127))
return 3
}
for _, file := range files {
if !file.IsDir() && file.Name() == cmdSlice[0] {
err := exec.Command(cmdSlice[0], cmdSlice[1:]...).Run()
if err != nil {
if errr := err.(*exec.ExitError); errr != nil {
L.Push(lua.LFalse)
if err.(*exec.ExitError).Exited() {
L.Push(lua.LString("exit"))
} else {
L.Push(lua.LString("signal"))
}
L.Push(lua.LNumber(err.(*exec.ExitError).ExitCode()))
return 3
}
}
L.Push(lua.LTrue)
L.Push(lua.LString("exit"))
L.Push(lua.LNumber(0))
}
}
L.Push(lua.LFalse)
L.Push(lua.LString("exit"))
L.Push(lua.LNumber(127))
return 3
}
func (container Container) lpopen(L *lua.LState) int {
cmdString := L.CheckString(1)
mode := L.CheckString(2)
cmdSlice := strings.Fields(cmdString)
files, err := afero.ReadDir(container.FS, BinDir)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString("can't find executable"))
return 2
}
for _, file := range files {
if !file.IsDir() && file.Name() == cmdSlice[0] {
cmd := exec.Command(cmdSlice[0], cmdSlice[1:]...)
output, _ := cmd.CombinedOutput()
switch mode {
case "r":
ud := L.NewUserData()
ud.Value = string(output)
L.SetMetatable(ud, L.GetTypeMetatable("file"))
L.Push(ud)
L.Push(lua.LNil)
case "w":
ud := L.NewUserData()
ud.Value = string(output)
os.Stdout.Write(output)
L.SetMetatable(ud, L.GetTypeMetatable("file"))
L.Push(ud)
L.Push(lua.LNil)
default:
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprintf("%s: Invalid argument", cmdString)))
}
}
}
L.Push(lua.LNil)
L.Push(lua.LString("can't find any executable"))
return 2
}
func (container Container) lDir(L *lua.LState) int {
dir := L.CheckString(1)
L.Push(lua.LString(filepath.Join(container.Root, filepath.Clean(dir))))
return 1
}
func (container Container) GetLuaState() {
L := lua.NewState()
osObject := L.GetGlobal("os").(*lua.LTable)
ioObject := L.GetGlobal("io").(*lua.LTable)
L.SetGlobal("path_join", L.NewFunction(utils_lua.Ljoin))
osObject.RawSetString("remove", L.NewFunction(container.lRemove))
osObject.RawSetString("rename", L.NewFunction(container.lRename))
osObject.RawSetString("copy", L.NewFunction(container.lCopy))
osObject.RawSetString("mkdir", L.NewFunction(container.lMkdir))
ioObject.RawSetString("popen", L.NewFunction(container.lpopen))
ioObject.RawSetString("open", L.NewFunction(container.lOpen))
container.LuaState = *L
}

View File

@@ -1,183 +0,0 @@
package build
import (
"database/sql"
"encoding/base64"
"encoding/json"
"io"
"os"
"packets/internal/consts"
"packets/internal/packet"
"path/filepath"
_ "modernc.org/sqlite"
"github.com/spf13/afero"
lua "github.com/yuin/gopher-lua"
)
type Container struct {
BuildID BuildID
Root string
FS afero.Fs
LuaState lua.LState
Manifest packet.PacketLua
uses int
DeleteAfter bool
}
func NewContainer(manifest packet.PacketLua) (Container, error) {
var container Container
var err error
container.BuildID, err = getBuildId(manifest.BuildDependencies)
if err != nil {
return Container{}, err
}
baseFs := afero.NewOsFs()
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
return Container{}, err
}
if err := db.QueryRow("SELECT uses, dir FROM build_dependencies WHERE id = ? ", container.BuildID).Scan(&container.uses, container.Root); err != nil {
db.Close()
return Container{}, err
}
db.Close()
if container.Root != "/dev/null" {
if _, err := os.Stat(container.Root); err != nil {
if os.IsNotExist(err) {
if err := container.createNew(); err != nil {
return Container{}, err
}
}
}
} else {
container.DeleteAfter = true
if err := container.createNew(); err != nil {
return Container{}, err
}
}
container.GetLuaState()
fileSystem := afero.NewBasePathFs(baseFs, container.Root)
container.Manifest = manifest
container.FS = fileSystem
if err := container.FS.MkdirAll(BinDir, 0777); err != nil {
return Container{}, err
}
if err := container.FS.MkdirAll("/etc/packets", 0777); err != nil {
return Container{}, err
}
if err := afero.Symlinker.SymlinkIfPossible(container.FS.(afero.Symlinker), BinDir, SymLinkBinDir); err != nil {
return Container{}, err
}
return container, nil
}
func (container Container) CopyHostToContainer(src string, dest string) error {
stats, err := os.Stat(src)
if err != nil {
return err
}
if stats.IsDir() {
files, err := os.ReadDir(src)
if err != nil {
return err
}
if err := container.FS.MkdirAll(dest, 0755); err != nil {
return err
}
for _, file := range files {
srcPath := filepath.Join(src, file.Name())
destPath := filepath.Join(dest, file.Name())
if file.IsDir() {
if err := container.CopyHostToContainer(srcPath, destPath); err != nil {
return err
}
continue
}
if err := container.copySingleFile(srcPath, destPath); err != nil {
return err
}
}
} else {
if err := container.copySingleFile(src, dest); err != nil {
return err
}
}
return nil
}
func (container Container) copySingleFile(source string, destination string) error {
src, err := os.Open(source)
if err != nil {
return err
}
defer src.Close()
stats, err := src.Stat()
if err != nil {
return err
}
if err := container.FS.MkdirAll(filepath.Dir(destination), 0755); err != nil {
return err
}
dst, err := container.FS.Create(destination)
if err != nil {
return err
}
defer dst.Close()
if _, err := io.Copy(dst, src); err != nil {
return err
}
if err := container.FS.Chmod(destination, stats.Mode()); err != nil {
return err
}
return nil
}
func getBuildId(buildDependencies map[string]string) (BuildID, error) {
blobs, err := json.Marshal(buildDependencies)
if err != nil {
return "", err
}
return BuildID(base64.StdEncoding.EncodeToString(blobs)), nil
}
func (container Container) saveBuild() error {
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
return err
}
defer db.Close()
buildID := container.BuildID
var exists bool
if err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM build_dependencies WHERE id = ?)", buildID).Scan(exists); err != nil {
return err
}
if exists {
_, err := db.Exec("UPDATE FROM build_dependencies WHERE id = ? SET uses = uses + 1", buildID)
return err
}
_, err = db.Exec("INSERT INTO build_dependencies (id) VALUES (?)", buildID)
return err
}

View File

@@ -1,45 +0,0 @@
package build
import (
"os"
"packets/configs"
"packets/internal/consts"
"packets/internal/utils"
"path/filepath"
"sync"
_ "modernc.org/sqlite"
)
func (container Container) createNew() error {
if err := os.MkdirAll(filepath.Join(consts.BuildImagesDir, string(container.BuildID)), 0775); err != nil {
return err
}
packetsuid, err := utils.GetPacketsUID()
if err != nil {
return err
}
if err := os.Chown(filepath.Join(consts.BuildImagesDir, string(container.BuildID)), packetsuid, 0); err != nil {
return err
}
dependencies, err := utils.ResolvDependencies(container.Manifest.BuildDependencies)
if err != nil {
return err
}
cfg, err := configs.GetConfigTOML()
if err != nil {
return err
}
var wg sync.WaitGroup
for _, depn := range dependencies {
wg.Add(1)
go container.asyncFullInstallDependencie(depn, cfg.Config.StorePackages, depn, &wg)
}
wg.Wait()
container.Root = filepath.Join(consts.BuildImagesDir, string(container.BuildID))
container.saveBuild()
return nil
}

View File

@@ -1,8 +0,0 @@
package build
const (
BinDir = "/usr/bin"
SymLinkBinDir = "/bin"
)
type BuildID string // Json dependencies encoded to base64 stdEncoding

View File

@@ -1,79 +0,0 @@
package build
import (
"io"
"path/filepath"
"github.com/spf13/afero"
)
func (container Container) copyContainer(src string, dest string) error {
stats, err := container.FS.Stat(src)
if err != nil {
return err
}
if stats.IsDir() {
files, err := afero.ReadDir(container.FS, src)
if err != nil {
return err
}
if err := container.FS.MkdirAll(dest, 0755); err != nil {
return err
}
for _, file := range files {
srcPath := filepath.Join(src, file.Name())
destPath := filepath.Join(dest, file.Name())
if file.IsDir() {
if err := container.CopyHostToContainer(srcPath, destPath); err != nil {
return err
}
continue
}
if err := container.copySingleFileLtoL(srcPath, destPath); err != nil {
return err
}
}
} else {
if err := container.copySingleFileLtoL(src, dest); err != nil {
return err
}
}
return nil
}
func (container Container) copySingleFileLtoL(source string, destination string) error {
src, err := container.FS.Open(source)
if err != nil {
return err
}
defer src.Close()
stats, err := src.Stat()
if err != nil {
return err
}
if err := container.FS.MkdirAll(filepath.Dir(destination), 0755); err != nil {
return err
}
dst, err := container.FS.Create(destination)
if err != nil {
return err
}
defer dst.Close()
if _, err := io.Copy(dst, src); err != nil {
return err
}
if err := container.FS.Chmod(destination, stats.Mode()); err != nil {
return err
}
return nil
}

View File

@@ -1,44 +0,0 @@
package consts
import "time"
const (
DefaultLinux_d = "/etc/packets"
DefaultCache_d = "/var/cache/packets"
DefaultHttpPort = 9123
DefaultBin_d = "/usr/local/bin"
DefaultData_d = "/opt/packets"
LANDeadline = 2 * time.Second
IndexDB = "/etc/packets/index.db"
InstalledDB = "/etc/packets/installed.db"
BuildImagesDir = "/etc/packets/temp"
DefaultSyncUrl = "https://servidordomal.fun/index.db"
)
const InstalledDatabaseSchema = `CREATE TABLE IF NOT EXISTS packages (
query_name TEXT NOT NULL UNIQUE PRIMARY KEY,
id TEXT NOT NULL UNIQUE,
version TEXT NOT NULL,
dependencies TEXT NOT NULL DEFAULT '',
description TEXT NOT NULL,
package_d TEXT NOT NULL,
filename TEXT NOT NULL,
os TEXT NOT NULL,
arch TEXT NOT NULL,
in_cache INTEGER NOT NULL DEFAULT 1,
serial INTEGER NOT NULL,
UNIQUE(query_name, version),
UNIQUE(query_name, serial)
);
CREATE TABLE package_dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
version_constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
);
CREATE INDEX index_dependency_name ON package_dependencies(dependency_name);
`

View File

@@ -1,11 +0,0 @@
package errors_packets
import "errors"
var (
ErrResponseNot200OK = errors.New("the request is not 200, download failed")
ErrCantFindPacketDotLua = errors.New("can't find manifest.toml when trying to read the packagefile")
ErrInvalidSignature = errors.New("the signature is invalid")
ErrNotInstalled = errors.New("the package isn't installed")
ErrAlredyUpToDate = errors.New("alredy up to date")
)

View File

@@ -0,0 +1,195 @@
package lua
import (
"fmt"
"log"
"os"
"path/filepath"
"strconv"
lua "github.com/yuin/gopher-lua"
)
func LRemove(L *lua.LState) int {
filename := L.CheckString(1)
err := os.RemoveAll(filename)
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LRename(L *lua.LState) int {
oldname := L.CheckString(1)
newname := L.CheckString(2)
if err := os.Rename(oldname, newname); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func LCopy(L *lua.LState) int {
oldname := L.CheckString(1)
newname := L.CheckString(2)
_ = os.MkdirAll(filepath.Dir(newname), 0755)
if err := copyDir(oldname, newname); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LSymlink(L *lua.LState) int {
fileName := L.CheckString(1)
destination := L.CheckString(2)
_ = os.RemoveAll(destination)
if err := os.Symlink(fileName, destination); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func Ljoin(L *lua.LState) int {
n := L.GetTop()
parts := make([]string, 0, n)
for i := 1; i <= n; i++ {
val := L.Get(i)
parts = append(parts, val.String())
}
result := filepath.Join(parts...)
L.Push(lua.LString(result))
return 1
}
func LMkdir(L *lua.LState) int {
path := L.CheckString(1)
perm := L.CheckInt(2)
modeStr := strconv.Itoa(perm)
modeUint, err := strconv.ParseUint(modeStr, 8, 32)
if err != nil {
fmt.Println("Error parsing mode:", err)
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
if err := os.MkdirAll(path, os.FileMode(modeUint)); err != nil {
fmt.Println("Error creating directory:", err)
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LError(L *lua.LState) int {
n := L.GetTop()
parts := make([]any, 0, n)
for i := 1; i <= n; i++ {
val := L.Get(i)
parts = append(parts, val.String())
}
llogger().Panic(parts...)
return 0
}
func LSetEnv(L *lua.LState) int {
env := L.CheckString(1)
value := L.CheckString(2)
os.Setenv(env, value)
return 0
}
func LCD(L *lua.LState) int {
dir := L.CheckString(1)
if err := os.Chdir(dir); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LChmod(L *lua.LState) int {
f := L.CheckString(1)
mode := L.CheckInt(2)
modeStr := strconv.Itoa(mode)
modeUint, err := strconv.ParseUint(modeStr, 8, 32)
if err != nil {
fmt.Println("Error parsing mode:", err)
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
if err := os.Chmod(f, os.FileMode(modeUint)); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
type Flag struct {
Name string
Path string
FlagType string
}
type Flags struct {
Flags []Flag
}
func (f *Flags) LSetFlag(L *lua.LState) int {
flagtype := L.CheckString(1)
name := L.CheckString(2)
flagPath := L.CheckString(3)
f.Flags = append(f.Flags, Flag{
Name: name,
Path: flagPath,
FlagType: flagtype,
})
return 0
}
func llogger() *log.Logger { return log.New(os.Stderr, "script error: ", 0) }

95
internal/lua/utils.go Normal file
View File

@@ -0,0 +1,95 @@
package lua
import (
"io"
"os"
"path/filepath"
)
func copyDir(src string, dest string) error {
if stats, err := os.Stat(src); err != nil {
return err
} else {
if stats.IsDir() {
files, err := os.ReadDir(src)
if err != nil {
return err
}
if err := os.MkdirAll(dest, 0755); err != nil {
return err
}
for _, file := range files {
if file.IsDir() {
copyDir(filepath.Join(src, file.Name()), filepath.Join(dest, file.Name()))
continue
}
srcFile := filepath.Join(src, file.Name())
f, err := os.Create(filepath.Join(dest, file.Name()))
if err != nil {
return err
}
defer f.Close()
opennedSrcFile, err := os.Open(srcFile)
if err != nil {
return err
}
defer opennedSrcFile.Close()
if _, err := io.Copy(f, opennedSrcFile); err != nil {
return err
}
}
} else {
if err := copyFile(src, dest); err != nil {
return err
}
}
}
return nil
}
func copyFile(source string, destination string) error {
src, err := os.Open(source)
if err != nil {
return err
}
defer src.Close()
status, err := src.Stat()
if err != nil {
return err
}
err = os.MkdirAll(filepath.Dir(destination), 0o755)
if err != nil {
return err
}
dst, err := os.Create(destination)
if err != nil {
if !os.IsExist(err) {
dst, err = os.Open(destination)
if err != nil {
return err
}
} else {
return err
}
}
defer dst.Close()
if err := dst.Chmod(status.Mode()); err != nil {
return err
}
_, err = io.Copy(dst, src)
if err != nil {
return err
}
return nil
}

View File

@@ -1,55 +0,0 @@
package packet
import lua "github.com/yuin/gopher-lua"
func getStringFromTable(table *lua.LTable, key string) string {
value := table.RawGetString(key)
if value.Type() == lua.LTString {
return value.String()
}
return ""
}
func getStringArrayFromTable(L *lua.LState, table *lua.LTable, key string) []string {
value := table.RawGetString(key)
if value.Type() != lua.LTTable {
return []string{}
}
arrayTable := value.(*lua.LTable)
var result []string
arrayTable.ForEach(func(_, value lua.LValue) {
if value.Type() == lua.LTString {
result = append(result, value.String())
}
})
return result
}
func getFunctionFromTable(table *lua.LTable, key string) *lua.LFunction {
value := table.RawGetString(key)
if value.Type() == lua.LTFunction {
return value.(*lua.LFunction)
}
return nil
}
func getDependenciesFromTable(L *lua.LState, table *lua.LTable, key string) map[string]string {
value := table.RawGetString(key)
if value.Type() != lua.LTTable {
return map[string]string{}
}
depsTable := value.(*lua.LTable)
dependencies := make(map[string]string)
depsTable.ForEach(func(key, value lua.LValue) {
if key.Type() == lua.LTString && value.Type() == lua.LTString {
dependencies[key.String()] = value.String()
}
})
return dependencies
}

View File

@@ -1,139 +0,0 @@
package packet
import (
"archive/tar"
"fmt"
"io"
"packets/configs"
errors_packets "packets/internal/errors"
"path/filepath"
"runtime"
"github.com/klauspost/compress/zstd"
lua "github.com/yuin/gopher-lua"
)
type PacketLua struct {
Name string
Id string
Version string
Description string
Dependencies map[string]string
Author string
Architetures []string
Os []string
PkgType string
GitUrl string
GitBranch string
BuildDependencies map[string]string
Prepare *lua.LFunction
Build *lua.LFunction
Install *lua.LFunction
Remove *lua.LFunction
}
// ReadPacket read a Packet.lua and alredy set global vars
func ReadPacket(f []byte) (PacketLua, error) {
cfg, err := configs.GetConfigTOML()
if err != nil {
return PacketLua{}, err
}
L := lua.NewState()
defer L.Close()
osObject := L.GetGlobal("os").(*lua.LTable)
ioObject := L.GetGlobal("io").(*lua.LTable)
L.SetGlobal("os", lua.LNil)
L.SetGlobal("io", lua.LNil)
if err := L.DoString(string(f)); err != nil {
return PacketLua{}, err
}
L.SetGlobal("os", osObject)
L.SetGlobal("io", ioObject)
L.SetGlobal("BIN_DIR", lua.LString(cfg.Config.Bin_d))
L.SetGlobal("ARCH", lua.LString(runtime.GOARCH))
L.SetGlobal("OS", lua.LString(runtime.GOOS))
tableLua := L.Get(-1)
if tableLua.Type() != lua.LTTable {
return PacketLua{}, fmt.Errorf("invalid Packet.lua format: the file do not return a table")
}
table := tableLua.(*lua.LTable)
pkgTableLua := table.RawGetString("package")
if pkgTableLua.Type() != lua.LTTable {
return PacketLua{}, fmt.Errorf("invalid Packet.lua format: can't find package table")
}
pkgTable := pkgTableLua.(*lua.LTable)
packetLua := &PacketLua{
Name: getStringFromTable(pkgTable, "name"),
Id: getStringFromTable(pkgTable, "id"),
Version: getStringFromTable(pkgTable, "version"),
Author: getStringFromTable(pkgTable, "author"),
Description: getStringFromTable(pkgTable, "description"),
PkgType: getStringFromTable(pkgTable, "type"),
Dependencies: getDependenciesFromTable(L, pkgTable, "dependencies"),
BuildDependencies: getDependenciesFromTable(L, pkgTable, "build_dependencies"),
GitUrl: getStringFromTable(pkgTable, "git_url"),
GitBranch: getStringFromTable(pkgTable, "git_branch"),
Prepare: getFunctionFromTable(pkgTable, "prepare"),
Build: getFunctionFromTable(pkgTable, "build"),
Install: getFunctionFromTable(pkgTable, "install"),
Remove: getFunctionFromTable(pkgTable, "remove"),
}
if packetLua.Install == nil || packetLua.Remove == nil {
return PacketLua{}, fmt.Errorf("install or remove function is not valid")
}
return *packetLua, nil
}
func (packetLua PacketLua) ExecuteRemove(L *lua.LState) error {
L.Push(packetLua.Remove)
return L.PCall(0, 0, nil)
}
func ReadPacketFromFile(file io.Reader) (PacketLua, error) {
zstdReader, err := zstd.NewReader(file)
if err != nil {
return PacketLua{}, err
}
defer zstdReader.Close()
tarReader := tar.NewReader(zstdReader)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return PacketLua{}, err
}
if filepath.Base(header.Name) == "Packet.lua" {
packageLuaBlob, err := io.ReadAll(tarReader)
if err != nil {
return PacketLua{}, err
}
return ReadPacket(packageLuaBlob)
}
}
return PacketLua{}, errors_packets.ErrCantFindPacketDotLua
}

View File

@@ -1 +0,0 @@
package packet

View File

@@ -1,80 +0,0 @@
package utils
import (
"fmt"
"net"
"packets/internal/consts"
"strconv"
"strings"
"time"
"golang.org/x/net/ipv4"
)
type Peer struct {
IP net.IP
Port int
}
func BroadcastAddr(ip net.IP, mask net.IPMask) net.IP {
b := make(net.IP, len(ip))
for i := range ip {
b[i] = ip[i] | ^mask[i]
}
return b
}
func AskLAN(filename string) ([]Peer, error) {
var peers []Peer
query := []byte("Q:" + filename)
pc, err := net.ListenPacket("udp", ":0")
if err != nil {
return []Peer{}, err
}
defer pc.Close()
if pconn := ipv4.NewPacketConn(pc); pconn != nil {
_ = pconn.SetTTL(1)
}
ifaces, _ := net.Interfaces()
for _, ifc := range ifaces {
if ifc.Flags&net.FlagUp == 0 || ifc.Flags&net.FlagLoopback != 0 {
continue
}
addrs, _ := ifc.Addrs()
for _, a := range addrs {
ipnet, ok := a.(*net.IPNet)
if !ok || ipnet.IP.To4() == nil {
continue
}
bcast := BroadcastAddr(ipnet.IP.To4(), ipnet.Mask)
dst := &net.UDPAddr{IP: bcast, Port: 1333}
_, err = pc.WriteTo(query, dst)
if err != nil {
fmt.Printf(":: (%s) can't send to %s: %s\n", ifc.Name, bcast, err.Error())
}
}
}
_ = pc.SetDeadline(time.Now().Add(consts.LANDeadline))
buf := make([]byte, 1500)
for {
n, addr, err := pc.ReadFrom(buf)
if err != nil {
break
}
msg := string(buf[:n])
if strings.HasPrefix(msg, "H:"+filename) {
parts := strings.Split(msg, ":")
port, _ := strconv.Atoi(parts[2])
peers = append(peers, Peer{IP: addr.(*net.UDPAddr).IP, Port: port})
}
}
return peers, nil
}

View File

@@ -1,127 +0,0 @@
package utils_lua
import (
"fmt"
"os"
"github.com/go-git/go-git/v6"
"github.com/go-git/go-git/v6/plumbing"
lua "github.com/yuin/gopher-lua"
)
func LGitClone(L *lua.LState) int {
uri := L.CheckString(1)
output := L.CheckString(2)
depth := 1
if L.GetTop() > 2 {
depth = L.CheckInt(3)
}
_, err := git.PlainClone(output, &git.CloneOptions{
URL: uri,
Progress: os.Stdout,
Depth: depth,
})
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LGitCheckout(L *lua.LState) int {
dir := L.CheckString(1)
branchorid := L.CheckString(2)
repo, err := git.PlainOpen(dir)
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
worktree, err := repo.Worktree()
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
if err := tryCheckout(*worktree, branchorid); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LGitPUll(L *lua.LState) int {
dir := L.CheckString(1)
depth := 1
if L.GetTop() > 1 {
depth = L.CheckInt(2)
}
repo, err := git.PlainOpen(dir)
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
worktree, err := repo.Worktree()
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
if err := worktree.Pull(&git.PullOptions{Depth: depth}); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func tryCheckout(worktree git.Worktree, reference string) error {
err := worktree.Checkout(&git.CheckoutOptions{
Branch: plumbing.ReferenceName(reference),
})
if err == nil {
return nil
}
err = worktree.Checkout(&git.CheckoutOptions{
Branch: plumbing.ReferenceName("refs/heads/" + reference),
})
if err == nil {
return nil
}
err = worktree.Checkout(&git.CheckoutOptions{
Branch: plumbing.ReferenceName("refs/tags/" + reference),
})
if err == nil {
return nil
}
hash := plumbing.NewHash(reference)
err = worktree.Checkout(&git.CheckoutOptions{
Hash: hash,
})
if err == nil {
return nil
}
return fmt.Errorf("cannot checkout '%s' as branch, tag, or commit", reference)
}

View File

@@ -1,32 +0,0 @@
package utils_lua
import (
"packets/configs"
lua "github.com/yuin/gopher-lua"
)
func GetSandBox() (lua.LState, error) {
cfg, err := configs.GetConfigTOML()
if err != nil {
return *lua.NewState(), err
}
L := lua.NewState()
osObject := L.GetGlobal("os").(*lua.LTable)
L.SetGlobal("SAFE_MODE", lua.LTrue)
L.SetGlobal("BIN_DIR", lua.LString(cfg.Config.Bin_d))
L.SetGlobal("path_join", L.NewFunction(Ljoin))
osObject.RawSetString("remove", L.NewFunction(LSafeRemove))
osObject.RawSetString("rename", L.NewFunction(LSafeRename))
osObject.RawSetString("copy", L.NewFunction(LSafeCopy))
osObject.RawSetString("symlink", L.NewFunction(LSymlink))
osObject.RawSetString("mkdir", L.NewFunction(LMkdir))
//ioObject.RawSetString("open", L.NewFunction(LOpen))
return *L, nil
}

View File

@@ -1,260 +0,0 @@
package utils_lua
import (
"fmt"
"log"
"os"
"packets/configs"
"packets/internal/consts"
"packets/internal/utils"
"path/filepath"
"strings"
"github.com/pelletier/go-toml/v2"
lua "github.com/yuin/gopher-lua"
)
func IsSafe(str string) bool {
s, err := filepath.EvalSymlinks(filepath.Clean(str))
if err != nil {
s = filepath.Clean(str)
}
var cfg configs.ConfigTOML
f, err := os.Open(filepath.Join(consts.DefaultLinux_d, "config.toml"))
if err != nil {
log.Println("error here opening config.toml")
return false
}
defer f.Close()
decoder := toml.NewDecoder(f)
if err := decoder.Decode(&cfg); err != nil {
log.Println("error decoding")
return false
}
if strings.HasPrefix(s, cfg.Config.Data_d) || strings.HasPrefix(s, cfg.Config.Bin_d) {
return true
} else if strings.Contains(s, ".ssh") {
return false
} else if strings.HasPrefix(s, "/etc") {
return false
} else if strings.HasPrefix(s, "/usr") || strings.HasPrefix(s, "/bin") {
fmt.Println(s, "está dentro de usr")
return strings.HasPrefix(s, "/usr/share")
} else if strings.HasPrefix(s, "/var/mail") {
return false
} else if strings.HasPrefix(s, "/proc") {
return false
} else if strings.HasPrefix(s, "/sys") {
return false
} else if strings.HasPrefix(s, "/var/run") || strings.HasPrefix(s, "/run") {
return false
} else if strings.HasPrefix(s, "/tmp") {
return false
} else if strings.HasPrefix(s, "/dev") {
return false
} else if strings.HasPrefix(s, "/boot") {
return false
} else if strings.HasPrefix(s, "/home") {
if strings.Contains(s, "/Pictures") || strings.Contains(s, "/Videos") || strings.Contains(s, "/Documents") || strings.Contains(s, "/Downloads") {
return false
}
} else if strings.HasPrefix(s, "/lib") || strings.HasPrefix(s, "/lib64") || strings.HasPrefix(s, "/var/lib64") || strings.HasPrefix(s, "/lib") {
return false
} else if strings.HasPrefix(s, "/sbin") {
return false
} else if strings.HasPrefix(s, "/srv") {
return false
} else if strings.HasPrefix(s, "/mnt") {
return false
} else if strings.HasPrefix(s, "/media") {
return false
} else if strings.HasPrefix(s, "/snap") {
return false
}
return true
}
// lua functions
func LSafeRemove(L *lua.LState) int {
filename := L.CheckString(1)
fmt.Printf(" remove %s\n", filename)
err := os.RemoveAll(filename)
if err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LSafeRename(L *lua.LState) int {
oldname := L.CheckString(1)
newname := L.CheckString(2)
fmt.Printf(" move %s -> %s\n", oldname, newname)
if err := os.Rename(oldname, newname); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func LSafeCopy(L *lua.LState) int {
oldname := L.CheckString(1)
newname := L.CheckString(2)
fmt.Printf(" copy %s -> %s\n", oldname, newname)
if err := utils.CopyDir(oldname, newname); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LSymlink(L *lua.LState) int {
fileName := L.CheckString(1)
destination := L.CheckString(2)
fmt.Printf(" symlink %s -> %s\n", fileName, destination)
_ = os.RemoveAll(destination)
if err := os.Symlink(fileName, destination); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func modeFlags(mode string) int {
switch mode {
case "r", "rb":
return os.O_RDONLY
case "w", "wb":
return os.O_CREATE | os.O_WRONLY | os.O_TRUNC
case "a", "ab":
return os.O_CREATE | os.O_WRONLY | os.O_APPEND
case "r+", "r+b", "rb+", "br+":
return os.O_RDWR
case "w+", "w+b", "wb+", "bw+":
return os.O_CREATE | os.O_RDWR | os.O_TRUNC
case "a+", "a+b", "ab+", "ba+":
return os.O_CREATE | os.O_RDWR | os.O_APPEND
default:
return os.O_RDONLY
}
}
/*
func LOpen(L *lua.LState) int {
path := L.CheckString(1)
mode := L.OptString(2, "r")
file, err := os.OpenFile(path, modeFlags(mode), 0644)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
ud := L.NewUserData()
ud.Value = file
L.SetMetatable(ud, L.GetTypeMetatable("file"))
L.Push(ud)
L.Push(lua.LNil)
return 2
}
*/
func Ljoin(L *lua.LState) int {
n := L.GetTop()
parts := make([]string, 0, n)
for i := 1; i <= n; i++ {
val := L.Get(i)
parts = append(parts, val.String())
}
result := filepath.Join(parts...)
L.Push(lua.LString(result))
return 1
}
func LMkdir(L *lua.LState) int {
path := L.CheckString(1)
perm := L.CheckInt(2)
fmt.Printf(" mkdir %s \n", path)
/*
if !IsSafe(path) {
L.Push(lua.LFalse)
L.Push(lua.LString("unsafe filepath"))
return 2
}
*/
if err := os.MkdirAll(path, os.FileMode(perm)); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LError(L *lua.LState) int {
n := L.GetTop()
parts := make([]any, 0, n)
for i := 1; i <= n; i++ {
val := L.Get(i)
parts = append(parts, val.String())
}
llogger().Panic(parts...)
return 0
}
func llogger() *log.Logger { return log.New(os.Stderr, " script error: ", 0) }

View File

@@ -1,479 +0,0 @@
package utils
import (
"crypto/ed25519"
"database/sql"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
"syscall"
"packets/internal/consts"
errors_packets "packets/internal/errors"
"packets/internal/packet"
)
type Package struct {
PackageF []byte
Version string
ImageUrl string
QueryName string
Description string
Author string
AuthorVerified bool
OS string
Arch string
Filename string
Size int64
Dependencies map[string]string
Manifest packet.PacketLua
Signature []byte
PublicKey ed25519.PublicKey
Serial int
}
func GetFileHTTP(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
return nil, errors_packets.ErrResponseNot200OK
}
fileBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return fileBytes, nil
}
// CopyDir copies a directory from source to destination
func CopyDir(src string, dest string) error {
if stats, err := os.Stat(src); err != nil {
return err
} else {
if stats.IsDir() {
files, err := os.ReadDir(src)
if err != nil {
return err
}
if err := os.MkdirAll(dest, 0o755); err != nil {
return err
}
for _, file := range files {
if file.IsDir() {
CopyDir(filepath.Join(src, file.Name()), filepath.Join(dest, file.Name()))
continue
}
srcFile := filepath.Join(src, file.Name())
f, err := os.Create(filepath.Join(dest, file.Name()))
if err != nil {
return err
}
defer f.Close()
opennedSrcFile, err := os.Open(srcFile)
if err != nil {
return err
}
defer opennedSrcFile.Close()
if _, err := io.Copy(f, opennedSrcFile); err != nil {
return err
}
}
} else {
if err := CopyFile(src, dest); err != nil {
return err
}
}
}
return nil
}
// CopyFile copies a file from source to destination
func CopyFile(source string, destination string) error {
src, err := os.Open(source)
if err != nil {
return err
}
defer src.Close()
status, err := src.Stat()
if err != nil {
return err
}
err = os.MkdirAll(filepath.Dir(destination), 0o755)
if err != nil {
return err
}
dst, err := os.Create(destination)
if err != nil {
if !os.IsExist(err) {
dst, err = os.Open(destination)
if err != nil {
return err
}
} else {
return err
}
}
defer dst.Close()
if err := dst.Chmod(status.Mode()); err != nil {
return err
}
_, err = io.Copy(dst, src)
if err != nil {
return err
}
return nil
}
// Write writes the package file to the cache directory and returns the path to it
func (p *Package) Write() (string, error) {
if err := os.WriteFile(filepath.Join(consts.DefaultCache_d, p.Filename), p.PackageF, 0o644); err != nil {
_ = os.Remove(filepath.Join(consts.DefaultCache_d, p.Filename))
return "", err
}
return filepath.Join(consts.DefaultCache_d, p.Filename), nil
}
func (p *Package) AddToInstalledDB(inCache int, packagePath string) error {
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
return err
}
defer db.Close()
var success bool
defer func() {
if !success {
_, err := db.Exec("DELETE FROM packages WHERE id = ?", p.Manifest.Id)
if err != nil {
log.Println("failed to rollback package addition:", err)
}
}
}()
_, err = db.Exec(`
INSERT INTO packages (
query_name, id, version, description,
serial, package_d, filename, os, arch, in_cache
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
p.QueryName,
p.Manifest.Id,
p.Version,
p.Description,
p.Serial,
packagePath,
p.Filename,
p.OS,
p.Arch,
inCache,
)
if err != nil {
return err
}
for depnName, versionConstraint := range p.Dependencies {
_, err = db.Exec("INSERT INTO package_dependencies (package_id, dependency_name, version_constraint) VALUES (?, ?, ?)", p.Manifest.Id, depnName, versionConstraint)
}
success = true
return err
}
func CheckIfPackageInstalled(name string) (bool, error) {
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
return false, err
}
defer db.Close()
if strings.Contains(name, "@") {
name = strings.SplitN(name, "@", 2)[0]
}
var exists bool
err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM packages WHERE query_name = ?)", name).Scan(&exists)
if err != nil {
return false, err
}
return exists, nil
}
func GetDependencies(db *sql.DB, id string) (map[string]string, error) {
rows, err := db.Query("SELECT dependency_name, version_constraint FROM package_dependencies WHERE package_id = ?", id)
if err != nil {
return map[string]string{}, err
}
defer rows.Close()
dependencies := make(map[string]string)
for rows.Next() {
var a, versionConstraint string
if err := rows.Scan(&a, &versionConstraint); err != nil {
return map[string]string{}, err
}
dependencies[a] = versionConstraint
}
return dependencies, nil
}
func ResolvDependencies(depnList map[string]string) ([]string, error) {
db, err := sql.Open("sqlite", consts.IndexDB)
if err != nil {
return []string{}, err
}
defer db.Close()
var resolved []string
for dependencieName, constraint := range depnList {
var filter, order string
value := strings.TrimLeft(constraint, "<>=")
switch {
case strings.HasPrefix(constraint, ">"):
filter = fmt.Sprintf("AND serial > %s", value)
order = "ORDER BY serial DESC LIMIT 1"
case strings.HasPrefix(constraint, "<="):
filter = fmt.Sprintf("AND serial <= %s", value)
order = "ORDER BY serial ASC LIMIT 1"
case strings.HasPrefix(constraint, "<"):
filter = fmt.Sprintf("AND serial < %s", value)
order = "ORDER BY serial ASC LIMIT 1"
case strings.HasPrefix(constraint, "="):
filter = fmt.Sprintf("AND serial = %s", value)
order = ""
}
var packageId string
err := db.QueryRow(fmt.Sprintf("SELECT id FROM packages WHERE query_name = ? %s %s", filter, order), dependencieName).Scan(&packageId)
if err != nil {
if err == sql.ErrNoRows {
continue
}
return []string{}, err
}
resolved = append(resolved, packageId)
dp, err := GetDependencies(db, packageId)
if err != nil {
return resolved, err
}
depn, err := ResolvDependencies(dp)
if err != nil {
return resolved, err
}
resolved = append(resolved, depn...)
}
return resolved, nil
}
func RemoveFromInstalledDB(id string) error {
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
return err
}
if _, err = db.Exec("DELETE FROM packages WHERE id = ? OR query_name = ?", id, id); err != nil {
return err
}
return nil
}
// GetPackage retrieves package information from the index database and downloads the package file
func GetPackage(id string) (Package, error) {
var this Package
this.Dependencies = make(map[string]string)
var peers []Peer
db, err := sql.Open("sqlite", consts.IndexDB)
if err != nil {
return this, err
}
defer db.Close()
var packageUrl string
err = db.QueryRow("SELECT query_name, version, package_url, image_url, description, author, author_verified, os, arch, signature, public_key, serial, size FROM packages WHERE id = ?", id).
Scan(
&this.QueryName,
&this.Version,
&packageUrl,
&this.ImageUrl,
&this.Description,
&this.Author,
&this.AuthorVerified,
&this.OS,
&this.Arch,
&this.Signature,
&this.PublicKey,
&this.Serial,
&this.Size,
)
if err != nil {
return Package{}, err
}
rows, err := db.Query("SELECT dependency_name, version_constraint FROM package_dependencies WHERE package_id = ?", id)
if err != nil {
return Package{}, err
}
defer rows.Close()
for rows.Next() {
var a, vConstraint string
if err := rows.Scan(&a, &vConstraint); err != nil {
return Package{}, err
}
this.Dependencies[a] = vConstraint
}
filename := path.Base(packageUrl)
this.Filename = filename
dirEntry, err := os.ReadDir(consts.DefaultCache_d)
if err != nil {
return Package{}, err
}
for _, v := range dirEntry {
if v.Name() == filename {
this.PackageF, err = os.ReadFile(filepath.Join(consts.DefaultCache_d, filename))
if err != nil {
break
}
goto skipping
}
}
peers, err = AskLAN(filename)
if err != nil {
return Package{}, err
}
if len(peers) == 0 {
fmt.Printf(":: Pulling from %s\n", packageUrl)
this.PackageF, err = GetFileHTTP(packageUrl)
if err != nil {
return Package{}, err
}
} else {
var totalerrors int = 0
for _, peer := range peers {
fmt.Printf(":: Pulling from local network (%s)\n", peer.IP)
this.PackageF, err = GetFileHTTP(fmt.Sprintf("http://%s:%d/%s", peer.IP, peer.Port, filename))
if err == nil {
break
} else {
totalerrors++
}
}
if totalerrors == len(peers) {
this.PackageF, err = GetFileHTTP(packageUrl)
if err != nil {
return Package{}, err
}
}
}
skipping:
this.Manifest, err = packet.ReadPacket(this.PackageF)
if err != nil {
return Package{}, err
}
if !ed25519.Verify(this.PublicKey, this.PackageF, this.Signature) {
return Package{}, errors_packets.ErrInvalidSignature
}
return this, nil
}
func GetPacketsUID() (int, error) {
_ = exec.Command("useradd", "-M", "-N", "-r", "-s", "/bin/false", "-d", "/var/lib/packets", "packets").Run()
cmd := exec.Command("id", "-u", "packets")
out, err := cmd.CombinedOutput()
if err != nil {
return -1, err
}
s := strings.TrimSpace(string(out))
uid, err := strconv.Atoi(s)
if err != nil {
return -1, err
}
return uid, nil
}
func ChangeToNoPermission() error {
uid, err := GetPacketsUID()
if err != nil {
return err
}
_ = os.Chown("/var/lib/packets", uid, 0)
return syscall.Setresuid(0, uid, 0)
}
func ElevatePermission() error { return syscall.Setresuid(0, 0, 0) }
func getFileHTTP(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
return nil, errors_packets.ErrResponseNot200OK
}
fileBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return fileBytes, nil
}

View File

@@ -0,0 +1,14 @@
package dependencysolve
import "github.com/roboogg133/packets/pkg/packet.lua.d"
type InstallInstruction struct {
Build []string
Install []string
Conflict []string
}
func ResolveDependencies(dependencies packet.PkgDependencies) InstallInstruction {
// Implementation goes here
return InstallInstruction{}
}

102
pkg/install/main.go Normal file
View File

@@ -0,0 +1,102 @@
package install
import (
"io"
"os"
"path/filepath"
"strings"
)
type BasicFileStatus struct {
Filepath string
PermMode os.FileMode
IsDir bool
}
func GetPackageFiles(packetDir string) ([]BasicFileStatus, error) {
return walkAll(packetDir)
}
func walkAll(dirToWalk string) ([]BasicFileStatus, error) {
var filesSlice []BasicFileStatus
files, err := os.ReadDir(dirToWalk)
if err != nil {
return []BasicFileStatus{}, err
}
for _, v := range files {
basicStat := &BasicFileStatus{
Filepath: filepath.Join(dirToWalk, v.Name()),
PermMode: v.Type().Perm(),
IsDir: v.IsDir(),
}
filesSlice = append(filesSlice, *basicStat)
if v.IsDir() {
tmp, err := walkAll(filepath.Join(dirToWalk, v.Name()))
if err != nil {
return []BasicFileStatus{}, err
}
filesSlice = append(filesSlice, tmp...)
}
}
return filesSlice, nil
}
func InstallFiles(files []BasicFileStatus, packetDir string) error {
for _, v := range files {
sysPath, _ := strings.CutPrefix(v.Filepath, packetDir)
if v.IsDir {
if err := os.MkdirAll(sysPath, v.PermMode.Perm()); err != nil {
return err
}
} else {
if err := copyFile(v.Filepath, sysPath); err != nil {
return err
}
}
}
return nil
}
func copyFile(source string, destination string) error {
src, err := os.Open(source)
if err != nil {
return err
}
defer src.Close()
status, err := src.Stat()
if err != nil {
return err
}
err = os.MkdirAll(filepath.Dir(destination), 0755)
if err != nil {
return err
}
dst, err := os.Create(destination)
if err != nil {
if !os.IsExist(err) {
dst, err = os.Open(destination)
if err != nil {
return err
}
} else {
return err
}
}
defer dst.Close()
if err := dst.Chmod(status.Mode()); err != nil {
return err
}
_, err = io.Copy(dst, src)
if err != nil {
return err
}
return nil
}

View File

@@ -1,80 +0,0 @@
package packets
import (
"fmt"
"net"
"packets/internal/consts"
"strconv"
"strings"
"time"
"golang.org/x/net/ipv4"
)
type Peer struct {
IP net.IP
Port int
}
func BroadcastAddr(ip net.IP, mask net.IPMask) net.IP {
b := make(net.IP, len(ip))
for i := range ip {
b[i] = ip[i] | ^mask[i]
}
return b
}
func AskLAN(filename string) ([]Peer, error) {
var peers []Peer
query := []byte("Q:" + filename)
pc, err := net.ListenPacket("udp", ":0")
if err != nil {
return []Peer{}, err
}
defer pc.Close()
if pconn := ipv4.NewPacketConn(pc); pconn != nil {
_ = pconn.SetTTL(1)
}
ifaces, _ := net.Interfaces()
for _, ifc := range ifaces {
if ifc.Flags&net.FlagUp == 0 || ifc.Flags&net.FlagLoopback != 0 {
continue
}
addrs, _ := ifc.Addrs()
for _, a := range addrs {
ipnet, ok := a.(*net.IPNet)
if !ok || ipnet.IP.To4() == nil {
continue
}
bcast := BroadcastAddr(ipnet.IP.To4(), ipnet.Mask)
dst := &net.UDPAddr{IP: bcast, Port: 1333}
_, err = pc.WriteTo(query, dst)
if err != nil {
fmt.Printf(":: (%s) can't send to %s: %s\n", ifc.Name, bcast, err.Error())
}
}
}
_ = pc.SetDeadline(time.Now().Add(consts.LANDeadline))
buf := make([]byte, 1500)
for {
n, addr, err := pc.ReadFrom(buf)
if err != nil {
break
}
msg := string(buf[:n])
if strings.HasPrefix(msg, "H:"+filename) {
parts := strings.Split(msg, ":")
port, _ := strconv.Atoi(parts[2])
peers = append(peers, Peer{IP: addr.(*net.UDPAddr).IP, Port: port})
}
}
return peers, nil
}

View File

@@ -1,304 +0,0 @@
package packets
import (
"archive/tar"
"bytes"
"crypto/ed25519"
"database/sql"
"fmt"
"io"
"log"
"net/http"
"os"
"packets/internal/build"
"packets/internal/consts"
errors_packets "packets/internal/errors"
"packets/internal/packet"
"packets/internal/utils"
"path"
utils_lua "packets/internal/utils/lua"
"path/filepath"
"strings"
"github.com/klauspost/compress/zstd"
_ "modernc.org/sqlite"
)
type Package struct {
PackageF []byte
Version string
ImageUrl string
QueryName string
Description string
Author string
AuthorVerified bool
OS string
Arch string
Filename string
Size int64
Dependencies map[string]string
Signature []byte
PublicKey ed25519.PublicKey
Serial int
Manifest packet.PacketLua
}
// Install exctract and fully install from a package file ( tar.zst )
func InstallPackage(file []byte, destDir string) error {
manifest, err := packet.ReadPacketFromFile(bytes.NewReader(file))
if err != nil {
return err
}
zstdReader, err := zstd.NewReader(bytes.NewReader(file))
if err != nil {
return err
}
defer zstdReader.Close()
tarReader := tar.NewReader(zstdReader)
uid, err := utils.GetPacketsUID()
if err != nil {
return err
}
for {
hdr, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
rel := filepath.Clean(hdr.Name)
if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
continue
}
if err := os.MkdirAll(destDir, 0775); err != nil {
return err
}
if err := os.Chown(destDir, uid, 0); err != nil {
return err
}
absPath := filepath.Join(destDir, rel)
switch hdr.Typeflag {
case tar.TypeDir:
err = os.MkdirAll(absPath, os.FileMode(hdr.Mode))
if err != nil {
return err
}
if err := os.Chown(absPath, uid, 0); err != nil {
return err
}
case tar.TypeReg:
err = os.MkdirAll(filepath.Dir(absPath), 0775)
if err != nil {
return err
}
out, err := os.Create(absPath)
if err != nil {
return err
}
_, err = io.Copy(out, tarReader)
out.Close()
if err != nil {
return err
}
err = os.Chmod(absPath, os.FileMode(0775))
if err != nil {
return err
}
if filepath.Base(hdr.Name) == "Packet.lua" {
err = os.Chmod(absPath, os.FileMode(0755))
if err != nil {
return err
}
} else {
if err := os.Chown(absPath, uid, 0); err != nil {
return err
}
}
}
}
L, err := utils_lua.GetSandBox()
if err != nil {
return err
}
bootstrapcontainer, err := build.NewContainer(manifest)
if err != nil {
return err
}
os.Chdir(destDir)
if err := bootstrapcontainer.ExecutePrepare(manifest, &L); err != nil {
return fmt.Errorf("error executing prepare: %s", err)
}
if err := bootstrapcontainer.ExecuteBuild(manifest, &L); err != nil {
return fmt.Errorf("error executing build: %s", err)
}
if err := utils.ChangeToNoPermission(); err != nil {
return fmt.Errorf("error changing to packet user: %s", err)
}
if err := bootstrapcontainer.ExecuteInstall(manifest, &L); err != nil {
return fmt.Errorf("error executing build: %s", err)
}
if err := utils.ElevatePermission(); err != nil {
return fmt.Errorf("error changing to root: %s", err)
}
return nil
}
func GetPackage(id string) (Package, error) {
var this Package
this.Dependencies = make(map[string]string)
var peers []Peer
db, err := sql.Open("sqlite", consts.IndexDB)
if err != nil {
return this, err
}
defer db.Close()
var packageUrl string
err = db.QueryRow("SELECT query_name, version, package_url, image_url, description, author, author_verified, os, arch, signature, public_key, serial, size FROM packages WHERE id = ?", id).
Scan(
&this.QueryName,
&this.Version,
&packageUrl,
&this.ImageUrl,
&this.Description,
&this.Author,
&this.AuthorVerified,
&this.OS,
&this.Arch,
&this.Signature,
&this.PublicKey,
&this.Serial,
&this.Size,
)
if err != nil {
return Package{}, err
}
rows, err := db.Query("SELECT dependency_name, version_constraint FROM package_dependencies WHERE package_id = ?", id)
if err != nil {
return Package{}, err
}
defer rows.Close()
for rows.Next() {
var a, vConstraint string
if err := rows.Scan(&a, &vConstraint); err != nil {
return Package{}, err
}
this.Dependencies[a] = vConstraint
}
filename := path.Base(packageUrl)
this.Filename = filename
dirEntry, err := os.ReadDir(consts.DefaultCache_d)
if err != nil {
return Package{}, err
}
for _, v := range dirEntry {
if v.Name() == filename {
this.PackageF, err = os.ReadFile(filepath.Join(consts.DefaultCache_d, filename))
if err != nil {
break
}
goto skipping
}
}
peers, err = AskLAN(filename)
if err != nil {
return Package{}, err
}
if len(peers) == 0 {
fmt.Printf(":: Pulling from %s\n", packageUrl)
this.PackageF, err = getFileHTTP(packageUrl)
if err != nil {
return Package{}, err
}
} else {
var totalerrors int = 0
for _, peer := range peers {
fmt.Printf(":: Pulling from local network (%s)\n", peer.IP)
this.PackageF, err = getFileHTTP(fmt.Sprintf("http://%s:%d/%s", peer.IP, peer.Port, filename))
if err == nil {
break
} else {
totalerrors++
}
}
if totalerrors == len(peers) {
this.PackageF, err = getFileHTTP(packageUrl)
if err != nil {
return Package{}, err
}
}
}
skipping:
reader := bytes.NewReader(this.PackageF)
this.Manifest, err = packet.ReadPacketFromFile(reader)
if err != nil {
return Package{}, err
}
if !ed25519.Verify(this.PublicKey, this.PackageF, this.Signature) {
return Package{}, errors_packets.ErrInvalidSignature
}
return this, nil
}
func getFileHTTP(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
return nil, errors_packets.ErrResponseNot200OK
}
fileBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return fileBytes, nil
}

View File

@@ -0,0 +1,354 @@
package packet
import (
"strings"
lua "github.com/yuin/gopher-lua"
)
func getStringFromTable(table *lua.LTable, key string) string {
value := table.RawGetString(key)
if value.Type() == lua.LTString {
return value.String()
}
return ""
}
func getIntFromTable(table *lua.LTable, key string) int {
value := table.RawGetString(key)
if value.Type() == lua.LTNumber {
if num, ok := value.(lua.LNumber); ok {
return int(num)
}
}
return -133
}
func getStringArrayFromTable(table *lua.LTable, key string) []string {
value := table.RawGetString(key)
if value.Type() != lua.LTTable {
return []string{}
}
arrayTable := value.(*lua.LTable)
var result []string
arrayTable.ForEach(func(_, value lua.LValue) {
if value.Type() == lua.LTString {
result = append(result, value.String())
}
})
return result
}
func getFunctionFromTable(table *lua.LTable, key string) *lua.LFunction {
value := table.RawGetString(key)
if value.Type() == lua.LTFunction {
return value.(*lua.LFunction)
}
return nil
}
type version struct {
Name string
Constraint VersionConstraint
}
func getDependenciesFromTable(table *lua.LTable, key string) *PkgDependencies {
value := table.RawGetString(key)
if value.Type() != lua.LTTable {
return &PkgDependencies{}
}
var pkgDeps PkgDependencies
depnTable := value.(*lua.LTable)
pkgDeps.RuntimeDependencies = depsParse(depnTable, "runtime")
pkgDeps.BuildDependencies = depsParse(depnTable, "build")
pkgDeps.Conflicts = depsParse(depnTable, "conflicts")
return &pkgDeps
}
func getSourcesFromTable(table *lua.LTable, key string) *[]Source {
value := table.RawGetString(key)
if value.Type() != lua.LTTable {
return nil
}
var srcList []Source
srcTable := value.(*lua.LTable)
srcTable.ForEach(func(_, value lua.LValue) {
if value.Type() == lua.LTTable {
src := value.(*lua.LTable)
var srcInfo Source
method := src.RawGetString("method")
if method.Type() == lua.LTString {
srcInfo.Method = method.String()
}
url := src.RawGetString("url")
if url.Type() == lua.LTString {
srcInfo.Url = url.String()
}
switchlabel:
switch srcInfo.Method {
case "GET":
var getSpecs GETSpecs
getSpecs.SHA256 = new([]string)
sha256sumL := src.RawGetString("sha256")
if sha256sumL.Type() == lua.LTTable {
shatable := sha256sumL.(*lua.LTable)
shatable.ForEach(func(_, value lua.LValue) {
if value.Type() == lua.LTString {
*getSpecs.SHA256 = append(*getSpecs.SHA256, value.String())
}
})
}
headersLT := src.RawGetString("headers")
if headersLT.Type() == lua.LTTable {
headers := headersLT.(*lua.LTable)
tmpMap := make(map[string]string)
headers.ForEach(func(headerKey, value lua.LValue) {
if value.Type() == lua.LTString {
tmpMap[headerKey.String()] = value.String()
}
})
getSpecs.Headers = &tmpMap
}
srcInfo.Specs = getSpecs
break switchlabel
case "git":
var gitSpecs GitSpecs
branchL := src.RawGetString("branch")
if branchL.Type() == lua.LTString {
gitSpecs.Branch = branchL.String()
}
tagL := src.RawGetString("tag")
if tagL.Type() == lua.LTString {
*gitSpecs.Tag = tagL.String()
}
srcInfo.Specs = gitSpecs
break switchlabel
case "POST":
var postSpecs POSTSpecs
sha256sumL := src.RawGetString("sha256")
if sha256sumL.Type() == lua.LTTable {
shatable := sha256sumL.(*lua.LTable)
shatable.ForEach(func(_, value lua.LValue) {
if value.Type() == lua.LTString {
*postSpecs.SHA256 = append(*postSpecs.SHA256, value.String())
}
})
}
headersLT := src.RawGetString("headers")
if headersLT.Type() == lua.LTTable {
headers := headersLT.(*lua.LTable)
tmpMap := make(map[string]string)
headers.ForEach(func(headerKey, value lua.LValue) {
if value.Type() == lua.LTString {
tmpMap[headerKey.String()] = value.String()
}
})
postSpecs.Headers = &tmpMap
}
bodyLt := src.RawGetString("body")
if bodyLt.Type() == lua.LTString {
*postSpecs.Body = bodyLt.String()
}
srcInfo.Specs = postSpecs
break switchlabel
}
srcList = append(srcList, srcInfo)
}
})
return &srcList
}
func getPlataformsFromTable(table *lua.LTable, key string) *map[OperationalSystem]Plataform {
value := table.RawGetString(key)
if value.Type() != lua.LTTable {
return nil
}
tmpMap := make(map[OperationalSystem]Plataform)
plataform := value.(*lua.LTable)
plataform.ForEach(func(osString, value lua.LValue) {
if value.Type() != lua.LTTable {
return
}
var plat Plataform
plat.Architetures = getStringArrayFromTable(value.(*lua.LTable), "arch")
plat.Name = osString.String()
plat.Sources = getSourcesFromTable(value.(*lua.LTable), "sources")
plat.Dependencies = getDependenciesFromTable(value.(*lua.LTable), "dependencies")
tmpMap[OperationalSystem(osString.String())] = plat
})
if len(tmpMap) == 0 {
return nil
}
return &tmpMap
}
func depsParse(depnTable *lua.LTable, key string) *map[string]*VersionConstraint {
if runLTable := depnTable.RawGetString(key); runLTable.Type() == lua.LTTable {
runtimeTable := runLTable.(*lua.LTable)
mapTemp := make(map[string]*VersionConstraint)
var found bool
runtimeTable.ForEach(func(_, value lua.LValue) {
if value.Type() == lua.LTString {
version := parseVersionString(value.String())
mapTemp[version.Name] = &version.Constraint
found = true
}
})
if !found {
return nil
} else {
return &mapTemp
}
}
return nil
}
func parseVersionString(s string) version {
// >=go@1.25.3 | <=go@1.25.3 | go | >go@1.25.3 | <go@1.25.3 | go@1.25.3
if strings.ContainsAny(s, "@") {
slice := strings.Split(s, "@")
switch {
case !strings.ContainsAny(s, "<=>"):
return version{
Name: slice[0],
Constraint: VersionConstraint(slice[1]),
}
case s[0] == '>' && s[1] == '=':
return version{
Name: slice[0][2:],
Constraint: VersionConstraint(">=" + slice[1]),
}
case s[0] == '<' && s[1] == '=':
return version{
Name: slice[0][2:],
Constraint: VersionConstraint("<=" + slice[1]),
}
case s[0] == '>' && s[1] != '=':
return version{
Name: slice[0][1:],
Constraint: VersionConstraint(">" + slice[1]),
}
case s[0] == '<' && s[1] != '=':
return version{
Name: slice[0][1:],
Constraint: VersionConstraint("<" + slice[1]),
}
}
} else if !strings.ContainsAny(s, "@=<>") {
return version{
Name: s,
Constraint: VersionConstraint(0x000),
}
}
return version{}
}
func normalizeArch(arch string) string {
switch arch {
case "386":
return "i686"
case "amd64":
return "x86_64"
case "amd64p32":
return "x86_64"
case "arm":
return "arm"
case "arm64":
return "aarch64"
case "arm64be":
return "aarch64_be"
case "armbe":
return "armbe"
case "loong64":
return "loongarch64"
case "mips":
return "mips"
case "mips64":
return "mips64"
case "mips64le":
return "mips64el"
case "mips64p32":
return "mips64"
case "mips64p32le":
return "mips64el"
case "mipsle":
return "mipsel"
case "ppc":
return "powerpc"
case "ppc64":
return "ppc64"
case "ppc64le":
return "ppc64le"
case "riscv":
return "riscv"
case "riscv64":
return "riscv64"
case "s390":
return "s390"
case "s390x":
return "s390x"
case "sparc":
return "sparc"
case "sparc64":
return "sparc64"
case "wasm":
return "wasm"
default:
return arch
}
}

View File

@@ -0,0 +1,33 @@
package packet
import "path/filepath"
type Config struct {
BinDir string
PacketDir string
SourcesDir string
RootDir string
}
const defaultBinDir = "/usr/bin"
func checkConfig(cfg *Config) *Config {
if cfg == nil {
bin := defaultBinDir
return &Config{
BinDir: bin,
}
}
switch {
case cfg.BinDir == "":
return &Config{
BinDir: defaultBinDir,
}
case cfg.PacketDir == "":
cfg.PacketDir = filepath.Join("/tmp", randStringBytes(12))
}
return cfg
}

390
pkg/packet.lua.d/main.go Normal file
View File

@@ -0,0 +1,390 @@
package packet
import (
"archive/tar"
"bytes"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"runtime"
"slices"
"time"
"github.com/go-git/go-git/v6"
"github.com/go-git/go-git/v6/plumbing"
"github.com/klauspost/compress/zstd"
lua_utils "github.com/roboogg133/packets/internal/lua"
lua "github.com/yuin/gopher-lua"
)
type OperationalSystem string
type PacketLua struct {
Name string
Version string
Maintainer string
Description string
Serial int
Page string
License []string
Plataforms *map[OperationalSystem]Plataform
GlobalSources *[]Source
GlobalDependencies *PkgDependencies
Flags []lua_utils.Flag
Build *lua.LFunction
Install *lua.LFunction
LuaState *lua.LState
}
type Source struct {
Method string
Url string
Specs any
}
type VersionConstraint string
type PkgDependencies struct {
RuntimeDependencies *map[string]*VersionConstraint
BuildDependencies *map[string]*VersionConstraint
Conflicts *map[string]*VersionConstraint
}
type Plataform struct {
Name string
Architetures []string
Sources *[]Source
Dependencies *PkgDependencies
}
type GitSpecs struct {
Branch string
Tag *string
}
type POSTSpecs struct {
SHA256 *[]string
Body *string
Headers *map[string]string
}
type GETSpecs struct {
SHA256 *[]string
Headers *map[string]string
}
var ErrCantFindPacketDotLua = errors.New("can't find Packet.lua in .tar.zst file")
var ErrFileDontReturnTable = errors.New("invalid Packet.lua format: the file do not return a table")
var ErrCannotFindPackageTable = errors.New("invalid Packet.lua format: can't find package table")
var ErrInstallFunctionDoesNotExist = errors.New("can not find install()")
var ErrSha256Sum = errors.New("false checksum")
// ReadPacket read a Packet.lua and alredy set global vars
func ReadPacket(f []byte, cfg *Config) (PacketLua, error) {
cfg = checkConfig(cfg)
L := lua.NewState()
L.SetGlobal("error", L.NewFunction(lua_utils.LError))
osObject := L.GetGlobal("os").(*lua.LTable)
ioObject := L.GetGlobal("io").(*lua.LTable)
L.SetGlobal("os", lua.LNil)
L.SetGlobal("io", lua.LNil)
L.SetGlobal("BIN_DIR", lua.LString(cfg.BinDir))
L.SetGlobal("CURRENT_ARCH", lua.LString(runtime.GOARCH))
L.SetGlobal("CURRENT_ARCH_NORMALIZED", lua.LString(normalizeArch(runtime.GOARCH)))
L.SetGlobal("CURRENT_PLATAFORM", lua.LString(runtime.GOOS))
var newFlags lua_utils.Flags
L.SetGlobal("setflags", L.NewFunction(newFlags.LSetFlag))
L.SetGlobal("pathjoin", L.NewFunction(lua_utils.Ljoin))
if err := L.DoString(string(f)); err != nil {
return PacketLua{}, err
}
L.SetGlobal("os", osObject)
L.SetGlobal("io", ioObject)
tableLua := L.Get(-1)
if tableLua.Type() != lua.LTTable {
return PacketLua{}, ErrFileDontReturnTable
}
table := tableLua.(*lua.LTable)
pkgTableLua := table.RawGetString("package")
if pkgTableLua.Type() != lua.LTTable {
return PacketLua{}, ErrCannotFindPackageTable
}
pkgTable := pkgTableLua.(*lua.LTable)
packetLua := &PacketLua{
Name: getStringFromTable(pkgTable, "name"),
Version: getStringFromTable(pkgTable, "version"),
Maintainer: getStringFromTable(pkgTable, "maintainer"),
Description: getStringFromTable(pkgTable, "description"),
Serial: getIntFromTable(pkgTable, "serial"),
Page: getStringFromTable(pkgTable, "pageurl"),
License: getStringArrayFromTable(pkgTable, "LICENSE"),
Plataforms: getPlataformsFromTable(pkgTable, "plataforms"),
GlobalDependencies: getDependenciesFromTable(pkgTable, "build_dependencies"),
GlobalSources: getSourcesFromTable(pkgTable, "sources"),
Build: getFunctionFromTable(table, "build"),
Install: getFunctionFromTable(table, "install"),
}
packetLua.Flags = append(packetLua.Flags, newFlags.Flags...)
packetLua.LuaState = L
if packetLua.Install == nil {
return PacketLua{}, ErrInstallFunctionDoesNotExist
}
return *packetLua, nil
}
func ReadPacketFromZSTDF(file io.Reader, cfg *Config) (PacketLua, error) {
cfg = checkConfig(cfg)
zstdReader, err := zstd.NewReader(file)
if err != nil {
return PacketLua{}, err
}
defer zstdReader.Close()
tarReader := tar.NewReader(zstdReader)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return PacketLua{}, err
}
if filepath.Base(header.Name) == "Packet.lua" {
packageLuaBlob, err := io.ReadAll(tarReader)
if err != nil {
return PacketLua{}, err
}
return ReadPacket(packageLuaBlob, cfg)
}
}
return PacketLua{}, ErrCantFindPacketDotLua
}
// GetSource returns file []byte if method is "GET" or "POST", if is "git" returns *git.CloneOptions{}
func GetSource(url, method string, info any, tryAttempts int) (any, error) {
switch method {
case "GET":
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
specs := info.(GETSpecs)
if specs.Headers != nil {
for k, v := range *specs.Headers {
req.Header.Set(k, v)
}
}
client := http.Client{Timeout: 5 * time.Minute}
var resp *http.Response
for range tryAttempts {
resp, err = client.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
break
}
resp.Body.Close()
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if !verifySHA256(*specs.SHA256, data) {
return nil, ErrSha256Sum
}
return data, nil
case "POST":
specs := info.(POSTSpecs)
var body *bytes.Reader
if specs.Body != nil {
body = bytes.NewReader([]byte(*specs.Body))
} else {
body = nil
}
req, err := http.NewRequest("POST", url, body)
if err != nil {
return nil, err
}
if specs.Headers != nil {
for k, v := range *specs.Headers {
req.Header.Set(k, v)
}
}
client := http.Client{Timeout: 5 * time.Minute}
var resp *http.Response
for range tryAttempts {
resp, err = client.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
break
}
resp.Body.Close()
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if !verifySHA256(*specs.SHA256, data) {
return nil, ErrSha256Sum
}
return data, nil
case "git":
specs := info.(GitSpecs)
if specs.Tag == nil {
return &git.CloneOptions{
URL: url,
SingleBranch: true,
ReferenceName: plumbing.NewBranchReferenceName(specs.Branch),
Depth: 1,
}, nil
} else {
return &git.CloneOptions{
URL: url,
SingleBranch: true,
ReferenceName: plumbing.NewTagReferenceName(*specs.Tag),
Depth: 1,
}, nil
}
}
return nil, fmt.Errorf("invalid method")
}
func verifySHA256(checksum []string, src []byte) bool {
check := sha256.Sum256(src)
return slices.Contains(checksum, hex.EncodeToString(check[:]))
}
func (pkg *PacketLua) ExecuteBuild(cfg *Config) {
L := pkg.LuaState
L.SetGlobal("error", L.NewFunction(lua_utils.LError))
osObject := L.GetGlobal("os").(*lua.LTable)
osObject.RawSetString("chdir", L.NewFunction(lua_utils.LCD))
osObject.RawSetString("setenv", L.NewFunction(lua_utils.LSetEnv))
osObject.RawSetString("copy", L.NewFunction(lua_utils.LCopy))
osObject.RawSetString("mkdir", L.NewFunction(lua_utils.LMkdir))
osObject.RawSetString("remove", L.NewFunction(lua_utils.LRemove))
osObject.RawSetString("rename", L.NewFunction(lua_utils.LRename))
osObject.RawSetString("symlink", L.NewFunction(lua_utils.LSymlink))
osObject.RawSetString("chmod", L.NewFunction(lua_utils.LChmod))
L.SetGlobal("BIN_DIR", lua.LString(cfg.BinDir))
L.SetGlobal("CURRENT_ARCH", lua.LString(runtime.GOARCH))
L.SetGlobal("CURRENT_ARCH_NORMALIZED", lua.LString(normalizeArch(runtime.GOARCH)))
L.SetGlobal("CURRENT_PLATAFORM", lua.LString(runtime.GOOS))
L.SetGlobal("SOURCESDIR", lua.LString(cfg.SourcesDir))
L.SetGlobal("PACKETDIR", lua.LString(cfg.PacketDir))
var newFlags lua_utils.Flags
L.SetGlobal("setflags", L.NewFunction(newFlags.LSetFlag))
L.SetGlobal("pathjoin", L.NewFunction(lua_utils.Ljoin))
os.Chdir(cfg.RootDir)
os.Setenv("PATH", os.Getenv("PATH")+":"+cfg.BinDir)
L.Push(pkg.Build)
L.Call(0, 0)
pkg.Flags = append(pkg.Flags, newFlags.Flags...)
}
func (pkg *PacketLua) ExecuteInstall(cfg *Config) {
L := pkg.LuaState
defer L.Close()
L.SetGlobal("error", L.NewFunction(lua_utils.LError))
osObject := L.GetGlobal("os").(*lua.LTable)
osObject.RawSetString("chdir", L.NewFunction(lua_utils.LCD))
osObject.RawSetString("setenv", L.NewFunction(lua_utils.LSetEnv))
osObject.RawSetString("copy", L.NewFunction(lua_utils.LCopy))
osObject.RawSetString("mkdir", L.NewFunction(lua_utils.LMkdir))
osObject.RawSetString("remove", L.NewFunction(lua_utils.LRemove))
osObject.RawSetString("rename", L.NewFunction(lua_utils.LRename))
osObject.RawSetString("symlink", L.NewFunction(lua_utils.LSymlink))
osObject.RawSetString("chmod", L.NewFunction(lua_utils.LChmod))
L.SetGlobal("BIN_DIR", lua.LString(cfg.BinDir))
L.SetGlobal("CURRENT_ARCH", lua.LString(runtime.GOARCH))
L.SetGlobal("CURRENT_ARCH_NORMALIZED", lua.LString(normalizeArch(runtime.GOARCH)))
L.SetGlobal("CURRENT_PLATAFORM", lua.LString(runtime.GOOS))
L.SetGlobal("SOURCESDIR", lua.LString(cfg.SourcesDir))
L.SetGlobal("PACKETDIR", lua.LString(cfg.PacketDir))
var newFlags lua_utils.Flags
L.SetGlobal("setflags", L.NewFunction(newFlags.LSetFlag))
L.SetGlobal("pathjoin", L.NewFunction(lua_utils.Ljoin))
os.Chdir(cfg.RootDir)
os.Setenv("PATH", os.Getenv("PATH")+":"+cfg.BinDir)
L.Push(pkg.Install)
L.Call(0, 0)
pkg.Flags = append(pkg.Flags, newFlags.Flags...)
}

65
pkg/packet.lua.d/utils.go Normal file
View File

@@ -0,0 +1,65 @@
package packet
import (
"math/rand"
"strings"
)
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$%!@%&*()-=+[]{}:;.,1234567890"
func randStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
type PackageID struct {
ID string
}
func (id PackageID) Name() string {
return strings.SplitAfter(id.ID, "@")[0]
}
func (id PackageID) Version() string {
return strings.SplitAfter(id.ID, "@")[1]
}
func NewId(id string) PackageID {
var ID PackageID
ID.ID = id
return ID
}
func (pkg PacketLua) IsValid() bool {
var a, b int
for _, v := range *pkg.Plataforms {
for _, src := range *v.Sources {
a++
if src.Method == "git" {
if src.Specs.(GitSpecs).Branch == "" && src.Specs.(GitSpecs).Tag == nil {
return false
}
}
}
b += len(v.Architetures)
}
a += len(*pkg.GlobalSources)
if a < 1 || len(*pkg.Plataforms) > b {
return false
}
switch {
case pkg.Serial == -133:
return false
case pkg.Description == "" || pkg.Maintainer == "" || pkg.Name == "" || pkg.Version == "":
return false
}
return true
}

67
test/bat/Packet.lua Normal file
View File

@@ -0,0 +1,67 @@
return {
package = {
name = "bat-bin", -- required
version = "0.26.0", -- required
maintainer = "robogg133", -- required
description = "A cat(1) clone with syntax highlighting and Git integration.", -- required
serial = 0,
LICENSE = {"APACHE", "MIT"},
pageurl = "https://github.com/sharkdp/bat"
plataforms = {
windows = {
arch = { "amd64" },
sources = {
{
url = "https://github.com/sharkdp/bat/releases/download/v0.26.0/bat-v0.26.0-" ..
CURRENT_ARCH_NORMALIZED .. "-pc-windows-msvc.zip",
method = "GET",
sha256 = { "a8a6862f14698b45e101b0932c69bc47a007f4c0456f3a129fdcef54d443d501" }
}
},
dependencies = {
build = {},
runtime = {},
conflicts = {}
}
},
linux = {
arch = { "amd64" },
sources = {
{
url = "https://github.com/sharkdp/bat/releases/download/v0.26.0/bat-v0.26.0-" ..
CURRENT_ARCH_NORMALIZED .. "-unknown-linux-gnu.tar.gz",
method = "GET",
sha256 = { "7efed0c768fae36f18ddbbb4a38f5c4b64db7c55a170dfc89fd380805809a44b" }
}
},
dependencies = {
build = {},
runtime = {},
conflicts = {}
}
}
},
sources = {}
},
build = function()
end,
install = function()
os.chdir(pathjoin(SOURCESDIR, "bat-v0.26.0-" .. CURRENT_ARCH_NORMALIZED .. "-unknown-linux-gnu"))
os.chmod("bat", 755)
local suc, errmsg = os.copy("bat", pathjoin(PACKETDIR, BIN_DIR, "bat"))
if not suc then
error("failed to copy bat: " .. errmsg)
end
os.copy("bat.1", pathjoin(PACKETDIR, "/usr/share/man/man1/bat.1"))
setflags("man", "manual", "/usr/share/man/man1/bat.1")
end,
}

65
test/go/Packet.lua Normal file
View File

@@ -0,0 +1,65 @@
return {
package = {
name = "go",
version = "1.25.3",
maintainer = "robogg133",
description = "A cat(1) clone with syntax highlighting and Git integration.",
serial = 0,
plataforms = {
windows = {
arch = { "amd64" },
sources = {
{
url = "https://github.com/sharkdp/bat/releases/download/v0.26.0/bat-v0.26.0-" ..
CURRENT_ARCH_NORMALIZED .. "-pc-windows-msvc.zip",
method = "GET",
sha256 = "a8a6862f14698b45e101b0932c69bc47a007f4c0456f3a129fdcef54d443d501"
}
},
dependencies = {
build = {},
runtime = {},
conflicts = {}
}
},
linux = {
arch = { "amd64" },
sources = {
{
url = "https://github.com/sharkdp/bat/releases/download/v0.26.0/bat-v0.26.0-" ..
CURRENT_ARCH_NORMALIZED .. "-unknown-linux-gnu.tar.gz",
method = "GET",
sha256 = "7efed0c768fae36f18ddbbb4a38f5c4b64db7c55a170dfc89fd380805809a44b"
}
},
dependencies = {
build = {},
runtime = {},
conflicts = {}
}
}
},
sources = {}
},
build = function()
end,
install = function()
os.chdir(pathjoin(SOURCESDIR, "bat-v0.26.0-" .. CURRENT_ARCH_NORMALIZED .. "-unknown-linux-gnu"))
os.chmod("bat", 755)
local suc, errmsg = os.copy("bat", pathjoin(PACKETDIR, BIN_DIR, "bat"))
if not suc then
error("failed to copy bat: " .. errmsg)
end
os.copy("bat.1", pathjoin(PACKETDIR, "/usr/share/man/man1/bat.1"))
setflags("man", "manual", "/usr/share/man/man1/bat.1")
end,
}

127
test/nginx/Packet.lua Normal file
View File

@@ -0,0 +1,127 @@
-- https://nginx.org/download/nginx-1.29.3.tar.gz
return {
package = {
name = "nginx",
version = "1.29.3",
maintainer = "robogg133",
description =
[[nginx ("engine x") is an HTTP web server, reverse proxy, content cache, load balancer, TCP/UDP proxy server, and mail proxy server. Originally written by Igor Sysoev and distributed under the 2-clause BSD License. Enterprise distributions, commercial support and training are available from F5, Inc.]],
serial = 0,
plataforms = {
windows = {
arch = { "amd64" },
sources = {
{
url = "https://nginx.org/download/nginx-1.29.3.zip",
method = "GET",
sha256 = { "afa2fde9fdf0ac64b91a17dcd34100ac557a3ff8e6154eeb0eeae7aa8e5bbc2d" }
}
},
dependencies = {
build = {
"cc",
"cmake",
"make"
},
runtime = {},
conflicts = {}
}
},
linux = {
arch = { "amd64" },
sources = {
{
url = "https://nginx.org/download/nginx-1.29.3.tar.gz",
method = "GET",
sha256 = { "9befcced12ee09c2f4e1385d7e8e21c91f1a5a63b196f78f897c2d044b8c9312" }
}
},
dependencies = {
build = {
"cc",
"cmake",
"make"
},
runtime = {},
conflicts = {}
}
}
},
sources = {}
},
build = function()
local uncompressedname = "nginx-1.29.3"
os.chdir(pathjoin(SOURCESDIR, uncompressedname))
os.chmod("configure", 0755)
os.execute("./configure --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --sbin-path=" ..
pathjoin(BIN_DIR, "nginx"))
print("Build progress: executing Make...")
local handle = io.popen("make", "r")
local _ = handle:read("*a")
local success, reason, exitcode = handle:close()
if not success then
error("make failed with code " .. tostring(exitcode) .. ": " .. tostring(reason))
end
print("Build progress: Make completed!")
end,
install = function()
local uncompressedname = "nginx-1.29.3"
os.copy("nginx.service", pathjoin(PACKETDIR, "/etc/systemd/system/nginx.service"))
os.chdir(pathjoin(SOURCESDIR, uncompressedname))
os.chmod("objs/nginx", 755)
os.copy("objs/nginx", pathjoin(PACKETDIR, BIN_DIR, "nginx"))
os.mkdir(pathjoin(PACKETDIR, "/usr/local/nginx"), 755)
os.mkdir(pathjoin(PACKETDIR, "/etc/nginx"), 755)
os.copy("conf/koi-win", pathjoin(PACKETDIR, "/etc/nginx/koi-win"))
os.copy("conf/koi-utf", pathjoin(PACKETDIR, "/etc/nginx/koi-utf"))
os.copy("conf/win-utf", pathjoin(PACKETDIR, "/etc/nginx/win-utf"))
os.copy("conf/mime.types", pathjoin(PACKETDIR, "/etc/nginx/mime.types"))
os.copy("conf/mime.types", pathjoin(PACKETDIR, "/etc/nginx/mime.types.default"))
os.copy("conf/fastcgi_params", pathjoin(PACKETDIR, "/etc/nginx/fastcgi_params"))
os.copy("conf/fastcgi_params", pathjoin(PACKETDIR, "/etc/nginx/fastcgi_params.default"))
os.copy("conf/fastcgi.conf", pathjoin(PACKETDIR, "/etc/nginx/fastcgi.conf"))
os.copy("conf/fastcgi.conf", pathjoin(PACKETDIR, "/etc/nginx/fastcgi.conf.default"))
os.copy("conf/uwsgi_params", pathjoin(PACKETDIR, "/etc/nginx/uwsgi_params"))
os.copy("conf/uwsgi_params", pathjoin(PACKETDIR, "/etc/nginx/uwsgi_params.default"))
os.copy("conf/scgi_params", pathjoin(PACKETDIR, "/etc/nginx/scgi_params"))
os.copy("conf/scgi_params", pathjoin(PACKETDIR, "/etc/nginx/scgi_params.default"))
os.copy("conf/nginx.conf", pathjoin(PACKETDIR, "/etc/nginx/nginx.conf"))
os.copy("conf/nginx.conf", pathjoin(PACKETDIR, "/etc/nginx/nginx.conf.default"))
os.copy("html", pathjoin(PACKETDIR, "/usr/share/nginx/html"))
os.copy("LICENSE", pathjoin(PACKETDIR, "/usr/share/licenses/nginx/LICENSE"))
os.copy("man/nginx.8", pathjoin(PACKETDIR, "/usr/share/man/man8/nginx.8"))
os.mkdir(pathjoin(PACKETDIR, "/etc/nginx/logs"), 755)
setflags("bin", "nginx", pathjoin(BIN_DIR, "nginx"))
setflags("config", "main", "/etc/nginx/nginx.conf")
setflags("config", "sites-available", "/etc/nginx/sites-available")
setflags("config", "sites-enabled", "/etc/nginx/sites-enabled")
setflags("man", "nginx.8", "/usr/share/man/man8/nginx.8")
setflags("license", "license", "/usr/share/licenses/nginx/LICENSE")
setflags("systemd", "nginx.service", "/etc/systemd/system/nginx.service")
end,
}

20
test/nginx/nginx.service Normal file
View File

@@ -0,0 +1,20 @@
[Unit]
Description=nginx web server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PrivateDevices=yes
PrivateTmp=true
SyslogLevel=err
ExecStart=/usr/bin/nginx
ExecReload=/usr/bin/nginx -s reload
Restart=on-failure
KillMode=mixed
KillSignal=SIGQUIT
TimeoutStopSec=5
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,40 @@
return {
package = {
name = "utctimerightnow", -- required
version = "0.1.0", -- required
maintainer = "robogg133", -- required
description = "shows utc time", -- required
serial = 0, -- required
dependencies = {
build = { "go" },
runtime = {},
conflicts = {}
},
sources = { --optional
{
url = "https://git.opentty.xyz/robogg133/utctimerightnow.git", -- required
method = "git", -- required
branch = "main" -- required
-- tag = ""
}
}
},
build = function()
-- os.setenv("GOPATH", pathjoin(SOURCESDIR, "gopath"))
os.chdir(pathjoin(SOURCESDIR, "utctimerightnow"))
os.execute('go build -trimpath -ldflags="-s -w" -o utctimerightnow main.go')
os.chmod("utctimerightnow", 777)
end,
install = function() -- required
os.copy(pathjoin(SOURCESDIR, "utctimerightnow", "utctimerightnow"),
pathjoin(PACKETDIR, BIN_DIR, "utctimerightnow"))
os.copy(pathjoin(SOURCESDIR, "utctimerightnow", "LICENSE"),
pathjoin(PACKETDIR, "/usr/share/licenses/utctimerightnow/LICENSE"))
end,
}