commit 7c7b6c436d2f0d3b3bd23f27da04a30b1ec6517c Author: CapCreeperGR Date: Mon Mar 25 09:41:59 2024 +0200 Initial Commit diff --git a/config.go b/config.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/config.go @@ -0,0 +1 @@ +package main diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4563329 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module bpm + +go 1.22 diff --git a/main.go b/main.go new file mode 100644 index 0000000..4f3d82e --- /dev/null +++ b/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "log" +) + +/* ---BPM | Bubble Package Manager--- */ +/* Made By CapCreeperGR */ +/* A simple-to-use package manager */ +/* ---------------------------------- */ + +var rootDir string = "/" + +func main() { + fmt.Printf("Running %s %s\n", getKernel(), getArch()) + //_, err := readPackage("test_hello_package/hello.bpm") + err := installPackage("test_hello_package/hello.bpm", rootDir) + if err != nil { + log.Fatalf("Could not read package\nError: %s\n", err) + } + pkgs, err := getInstalledPackages(rootDir) + if err != nil { + log.Fatalf("Could not get installed Packages!\nError: %s\n", err) + } + for _, pkg := range pkgs { + fmt.Println(pkg) + } + fmt.Println(getPackageFiles("hello")) +} diff --git a/package_utils.go b/package_utils.go new file mode 100644 index 0000000..bf37d11 --- /dev/null +++ b/package_utils.go @@ -0,0 +1,237 @@ +package main + +import ( + "archive/tar" + "bufio" + "compress/gzip" + "errors" + "io" + "os" + "path" + "slices" + "strconv" + "strings" +) + +type packageInfo struct { + name string + description string + version string + depends []string + provides []string +} + +func readPackage(filename string) (*packageInfo, error) { + if _, err := os.Stat(filename); os.IsNotExist(err) { + return nil, err + } + file, err := os.Open(filename) + if err != nil { + return nil, err + } + archive, err := gzip.NewReader(file) + if err != nil { + return nil, err + } + tr := tar.NewReader(archive) + for { + header, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + if header.Name == "pkg.info" { + bs, _ := io.ReadAll(tr) + err := file.Close() + if err != nil { + return nil, err + } + pkgInfo, err := readPackageInfo(string(bs)) + if err != nil { + return nil, err + } + return pkgInfo, nil + } + } + return nil, errors.New("pkg.info not found in archive") +} + +func readPackageInfo(contents string) (*packageInfo, error) { + pkgInfo := packageInfo{} + lines := strings.Split(contents, "\n") + for num, line := range lines { + split := strings.SplitN(line, ":", 2) + if len(split) != 2 { + return nil, errors.New("invalid pkg.info format at line " + strconv.Itoa(num)) + } + split[0] = strings.Trim(split[0], " ") + split[1] = strings.Trim(split[1], " ") + switch split[0] { + case "name": + pkgInfo.name = split[1] + case "description": + pkgInfo.description = split[1] + case "version": + pkgInfo.version = split[1] + } + } + return &pkgInfo, nil +} + +func createInfoFile(pkgInfo packageInfo) string { + ret := "" + ret = ret + "name: " + pkgInfo.name + "\n" + ret = ret + "description: " + pkgInfo.description + "\n" + ret = ret + "version: " + pkgInfo.version + "\n" + return ret +} + +func installPackage(filename, installDir string) error { + if _, err := os.Stat(filename); os.IsNotExist(err) { + return err + } + file, err := os.Open(filename) + if err != nil { + return err + } + archive, err := gzip.NewReader(file) + if err != nil { + return err + } + tr := tar.NewReader(archive) + var files []string + var pkgInfo *packageInfo + for { + header, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + if header.Name == "pkg.info" { + bs, _ := io.ReadAll(tr) + if err != nil { + return err + } + pkgInfo, err = readPackageInfo(string(bs)) + if err != nil { + return err + } + } + if strings.HasPrefix(header.Name, "files/") && header.Name != "files/" { + extractFilename := path.Join(installDir, strings.TrimPrefix(header.Name, "files/")) + switch header.Typeflag { + case tar.TypeDir: + files = append(files, strings.TrimPrefix(header.Name, "files/")) + if err := os.Mkdir(extractFilename, 0755); err != nil && !os.IsExist(err) { + return err + } + case tar.TypeReg: + outFile, err := os.Create(extractFilename) + files = append(files, strings.TrimPrefix(header.Name, "files/")) + if err != nil { + return err + } + if _, err := io.Copy(outFile, tr); err != nil { + return err + } + if err := os.Chmod(extractFilename, header.FileInfo().Mode()); err != nil { + return err + } + err = outFile.Close() + if err != nil { + return err + } + default: + return errors.New("ExtractTarGz: uknown type: " + strconv.Itoa(int(header.Typeflag)) + " in " + extractFilename) + } + } + } + if pkgInfo == nil { + return errors.New("pkg.info not found in archive") + } + slices.Sort(files) + slices.Reverse(files) + + dataDir := path.Join(installDir, "var/lib/bpm/installed/") + err = os.MkdirAll(dataDir, 755) + if err != nil { + return err + } + pkgDir := path.Join(dataDir, pkgInfo.name) + err = os.RemoveAll(pkgDir) + if err != nil { + return err + } + err = os.Mkdir(pkgDir, 755) + if err != nil { + return err + } + + f, err := os.Create(path.Join(pkgDir, "files")) + if err != nil { + return err + } + for _, line := range files { + _, err := f.WriteString(line + "\n") + if err != nil { + return err + } + } + f.Close() + + f, err = os.Create(path.Join(pkgDir, "info")) + if err != nil { + return err + } + _, err = f.WriteString(createInfoFile(*pkgInfo)) + if err != nil { + return err + } + f.Close() + + archive.Close() + file.Close() + return nil +} + +func getInstalledPackages(rootDir string) ([]string, error) { + dataDir := path.Join(rootDir, "var/lib/bpm/installed/") + items, err := os.ReadDir(dataDir) + if os.IsNotExist(err) { + return nil, nil + } + if err != nil { + return nil, err + } + var ret []string + for _, item := range items { + ret = append(ret, item.Name()) + } + return ret, nil +} + +func getPackageFiles(pkg string) []string { + var ret []string + dataDir := path.Join(rootDir, "var/lib/bpm/installed/") + pkgDir := path.Join(dataDir, pkg) + files := path.Join(pkgDir, "files") + if _, err := os.Stat(dataDir); os.IsNotExist(err) { + return nil + } + if _, err := os.Stat(pkgDir); os.IsNotExist(err) { + return nil + } + file, err := os.Open(files) + if err != nil { + return nil + } + scanner := bufio.NewScanner(file) + for scanner.Scan() { + ret = append(ret, scanner.Text()) + } + return ret +} diff --git a/test_hello_package/files/usr/bin/hello b/test_hello_package/files/usr/bin/hello new file mode 100755 index 0000000..c9dee84 Binary files /dev/null and b/test_hello_package/files/usr/bin/hello differ diff --git a/test_hello_package/hello.bpm b/test_hello_package/hello.bpm new file mode 100644 index 0000000..f25da83 Binary files /dev/null and b/test_hello_package/hello.bpm differ diff --git a/test_hello_package/pkg.info b/test_hello_package/pkg.info new file mode 100644 index 0000000..38616ec --- /dev/null +++ b/test_hello_package/pkg.info @@ -0,0 +1,3 @@ +name: hello +description: A simple hello world program +version: 1.0 \ No newline at end of file diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..fc1a6b5 --- /dev/null +++ b/utils.go @@ -0,0 +1,29 @@ +package main + +import "syscall" + +func getArch() string { + u := syscall.Utsname{} + err := syscall.Uname(&u) + if err != nil { + return "unknown" + } + return byteArrayToString(u.Machine[:]) +} + +func getKernel() string { + u := syscall.Utsname{} + err := syscall.Uname(&u) + if err != nil { + return "unknown" + } + return byteArrayToString(u.Sysname[:]) + " " + byteArrayToString(u.Release[:]) +} + +func byteArrayToString(bs []int8) string { + b := make([]byte, len(bs)) + for i, v := range bs { + b[i] = byte(v) + } + return string(b) +}