diff options
| author | huker667 <huker@tuta.io> | 2026-03-25 14:41:05 +0300 |
|---|---|---|
| committer | huker667 <huker@tuta.io> | 2026-03-25 14:41:05 +0300 |
| commit | 4ff821beed2565e84c9c8d0ac774fa678da1f10f (patch) | |
| tree | 22c9e3762fc174a733bbf4c9605f4ed60239fda4 /package/package.go | |
| download | qulay-4ff821beed2565e84c9c8d0ac774fa678da1f10f.tar.gz qulay-4ff821beed2565e84c9c8d0ac774fa678da1f10f.tar.bz2 qulay-4ff821beed2565e84c9c8d0ac774fa678da1f10f.zip | |
init commit
Diffstat (limited to 'package/package.go')
| -rw-r--r-- | package/package.go | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/package/package.go b/package/package.go new file mode 100644 index 0000000..6372688 --- /dev/null +++ b/package/package.go @@ -0,0 +1,251 @@ +package pkg + +import ( + "fmt" + "bufio" + "math/rand" + "slices" + "strings" + "errors" + // "slices" + // "strconv" + "os" + "os/exec" + "path/filepath" + "qulay/database" + "qulay/helpers" + "qulay/config" + + "codeberg.org/UzbekLinux/uzbekdb-go" +) + +var _name string = filepath.Base(os.Args[0]) + +type Package struct { + Name string + Repo string + Data []interface{} +} + +func randStr(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = byte(rand.Intn(26) + 'a') + } + return string(b) +} + +func randomTempDir(destDir string) string { + tempDir := "qulay_" + randStr(10) + tempDirPath := filepath.Join(destDir, tempDir) + os.MkdirAll(tempDirPath, 0755) + return tempDirPath +} + +func readDepends(path string) []string { + dependsPath := filepath.Join(path, "depends") + dependsPath2 := filepath.Join(path, "depends.uz") + f, err := os.Open(dependsPath) + if err != nil { + f, err = os.Open(dependsPath2) + if err != nil { + return []string{} + } + } + defer f.Close() + var depends []string + scanner := bufio.NewScanner(f) + for scanner.Scan() { + depends = append(depends, scanner.Text()) + } + return depends +} + +func isNewFormat(path string) bool { + _, err := os.Stat(filepath.Join(path, "data")) + return !os.IsNotExist(err) +} + +func GetPackages(destDir string) []Package { + var found []Package + entries, _ := os.ReadDir(filepath.Join(destDir, paths.ReposDir)) + for _, e := range entries { + if !e.IsDir() { + continue + } + data, err := os.ReadFile(filepath.Join(destDir, paths.ReposDir, e.Name(), "pkgs.uz")) + if err != nil { + continue + } + pkgs, ok := uzbekdb.Loads(string(data), "map").(map[interface{}][]interface{}) + if !ok { + continue + } + for name, val := range pkgs { + found = append(found, Package{fmt.Sprintf("%v", name), e.Name(), val}) + } + } + slices.SortFunc(found, func(a, b Package) int { + if n := strings.Compare(a.Repo, b.Repo); n != 0 { + return n + } + return strings.Compare(a.Name, b.Name) + }) + return found +} + +func FindPackages(name string, destDir string) []Package { + var found []Package + var packages = GetPackages(destDir) + var splitName = false + var repo string + + if strings.Contains(name, "/") { + splitName = true + parts := strings.SplitN(name, "/", 2) + repo = parts[0] + name = parts[1] + } + + for _, e := range packages { + if splitName { + if e.Name == name && e.Repo == repo { + found = append(found, e) + } + } else { + if e.Name == name { + found = append(found, e) + } + } + } + return found +} + +func getPackage(name string, destDir string) (*Package, error) { + var pkgs []Package + var pkg Package + if strings.Contains(name, "/") { + parts := strings.SplitN(name, "/", 2) + repo := parts[0] + name = parts[1] + pkgs = FindPackages(repo + "/" + name, destDir) + if len(pkgs) == 0 { + return nil, errors.New("no packages found with name " + name + " in " + repo + " repository") + } else if len(pkgs) == 1 { + pkg = pkgs[0] + } else { + for _, pkg := range pkgs { + fmt.Printf("%s/%s - %v - %v\n", pkg.Repo, pkg.Name, pkg.Data[0], pkg.Data[1]) + } + return nil, errors.New("? found multiple packages with name " + name + " in " + repo + " repository") + } + } else { + pkgs = FindPackages(name, destDir) + if len(pkgs) == 0 { + return nil, errors.New("no packages found with name " + name + " in repositories") + } else if len(pkgs) > 1 { + for _, pkg := range pkgs { + fmt.Printf("%s/%s - %v - %v\n", pkg.Repo, pkg.Name, pkg.Data[0], pkg.Data[1]) + } + return nil, errors.New("found multiple packages with name " + name + " in repositories") + } else { + pkg = pkgs[0] + } + } + return &pkg, nil +} + +func Install(name string, args []string, destDir string) error { + // verbose := slices.Contains(args, ":v") + reinstall := slices.Contains(args, ":r") + disableDeps := slices.Contains(args, ":nd") + + pkg, err := getPackage(name, destDir) + if err != nil { + return err + } + + pkgPath := filepath.Join(destDir, paths.ReposDir, pkg.Repo, "packages", pkg.Name) + depends := readDepends(pkgPath) + if !disableDeps { + if len(depends) != 0 { + fmt.Println(helpers.ToString(len(depends)) + " depends for " + pkg.Repo + "/" + pkg.Name + ":") + for i, n := range depends { + if n == pkg.Name || n == pkg.Repo + "/" + pkg.Name { + return errors.New("broken depends in package " + n) + } + fmt.Printf("%v. %s - %v", i, n, database.GetPackageVersion(n, destDir)) + } + } + } + if slices.Contains(args, ":a") { + if !helpers.Ask("install " + pkg.Repo + "/" + pkg.Name + " with version " + helpers.ToString(pkg.Data[1])) { + return errors.New("canceled by user") + } + } + if !disableDeps { + for _, dep := range depends { + if !database.IsInstalled(dep, destDir) || reinstall { + err := Install(dep, args, destDir) + if err != nil { + return err + } + } + } + } + + if !isNewFormat(pkgPath) { + cmd := exec.Command("sh", "install.sh") + cmd.Dir = pkgPath + cmd.Env = os.Environ() + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + return err + } + } + + err = database.RegPackage(pkg.Repo + "/" + pkg.Name, helpers.ToString(pkg.Data[1]), destDir) + if err != nil { + return errors.New("failed to register package in installed database: " + err.Error()) + } + fmt.Println(":: " + pkg.Repo + "/" + pkg.Name + " (" + helpers.ToString(pkg.Data[1]) + ") installed") + return nil +} + +func Remove(name string, args []string, destDir string) error { + pkg, err := getPackage(name, destDir) + if err != nil { + return err + } + + if slices.Contains(args, ":a") { + if !helpers.Ask("remove " + pkg.Repo + "/" + pkg.Name + " with repo version " + helpers.ToString(pkg.Data[1]) + + " and local version " + database.GetPackageVersion(pkg.Repo + "/" + pkg.Name, destDir) + "?") { + return errors.New("canceled by user") + } + } + + pkgPath := filepath.Join(destDir, paths.ReposDir, pkg.Repo, "packages", pkg.Name) + + if !isNewFormat(pkgPath) { + cmd := exec.Command("sh", "remove.sh") + cmd.Dir = pkgPath + cmd.Env = os.Environ() + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + return err + } + } + + err = database.UnRegPackage(pkg.Repo + "/" + pkg.Name, destDir) + if err != nil { + return errors.New("failed to unregister package in installed database: " + err.Error()) + } + + fmt.Println(":: " + pkg.Repo + "/" + pkg.Name + " (" + database.GetPackageVersion(pkg.Repo + "/" + pkg.Name, destDir) + ") removed") + return nil +} |