mirror of
https://github.com/EnumeratedDev/bpm.git
synced 2026-09-16 10:36:12 +00:00
Transitioned to a PKGBUILD-like format for source.sh files
Changed license from GPL3 to MIT
This commit is contained in:
+486
-359
@@ -369,381 +369,516 @@ func CreateInfoFile(pkgInfo PackageInfo, keepSourceFields bool) string {
|
||||
return ret
|
||||
}
|
||||
|
||||
func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTempDir bool) error {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
return err
|
||||
func extractPackage(pkgInfo *PackageInfo, filename, rootDir string) (error, []string) {
|
||||
var files []string
|
||||
if !IsPackageInstalled(pkgInfo.Name, rootDir) {
|
||||
err := ExecutePackageScripts(filename, rootDir, Install, false)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
} else {
|
||||
err := ExecutePackageScripts(filename, rootDir, Update, false)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
seenHardlinks := make(map[string]string)
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
return err, nil
|
||||
}
|
||||
archive, err := gzip.NewReader(file)
|
||||
if err != nil {
|
||||
return err
|
||||
return err, nil
|
||||
}
|
||||
tr := tar.NewReader(archive)
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if strings.HasPrefix(header.Name, "files/") && header.Name != "files/" {
|
||||
trimmedName := strings.TrimPrefix(header.Name, "files/")
|
||||
extractFilename := path.Join(rootDir, trimmedName)
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
files = append(files, strings.TrimPrefix(header.Name, "files/"))
|
||||
if err := os.Mkdir(extractFilename, 0755); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err, nil
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Creating Directory: " + extractFilename)
|
||||
}
|
||||
case tar.TypeReg:
|
||||
if _, err := os.Stat(extractFilename); err == nil {
|
||||
if slices.Contains(pkgInfo.Keep, trimmedName) {
|
||||
fmt.Println("Skipping File: " + extractFilename + "(File is configured to be kept during installs/updates)")
|
||||
files = append(files, trimmedName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err, nil
|
||||
}
|
||||
outFile, err := os.Create(extractFilename)
|
||||
fmt.Println("Creating File: " + extractFilename)
|
||||
files = append(files, strings.TrimPrefix(header.Name, "files/"))
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if _, err := io.Copy(outFile, tr); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if err := os.Chmod(extractFilename, header.FileInfo().Mode()); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
err = outFile.Close()
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
case tar.TypeSymlink:
|
||||
fmt.Println("Creating Symlink: " + extractFilename + " -> " + header.Linkname)
|
||||
files = append(files, strings.TrimPrefix(header.Name, "files/"))
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err, nil
|
||||
}
|
||||
err = os.Symlink(header.Linkname, extractFilename)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
case tar.TypeLink:
|
||||
fmt.Println("Detected Hard Link: " + extractFilename + " -> " + path.Join(rootDir, strings.TrimPrefix(header.Linkname, "files/")))
|
||||
files = append(files, strings.TrimPrefix(header.Name, "files/"))
|
||||
seenHardlinks[extractFilename] = path.Join(strings.TrimPrefix(header.Linkname, "files/"))
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err, nil
|
||||
}
|
||||
default:
|
||||
return errors.New("ExtractTarGz: unknown type: " + strconv.Itoa(int(header.Typeflag)) + " in " + extractFilename), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
for extractFilename, destination := range seenHardlinks {
|
||||
fmt.Println("Creating Hard Link: " + extractFilename + " -> " + path.Join(rootDir, destination))
|
||||
err := os.Link(path.Join(rootDir, destination), extractFilename)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
defer archive.Close()
|
||||
defer file.Close()
|
||||
return nil, files
|
||||
}
|
||||
|
||||
func compilePackage(pkgInfo *PackageInfo, filename, rootDir string, binaryPkgFromSrc, keepTempDir bool) (error, []string) {
|
||||
var files []string
|
||||
if !IsPackageInstalled(pkgInfo.Name, rootDir) {
|
||||
err := ExecutePackageScripts(filename, rootDir, Install, false)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
} else {
|
||||
err := ExecutePackageScripts(filename, rootDir, Update, false)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
//seenHardlinks := make(map[string]string)
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
archive, err := gzip.NewReader(file)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
tr := tar.NewReader(archive)
|
||||
|
||||
temp := "/var/tmp/bpm_source-" + pkgInfo.Name
|
||||
err = os.RemoveAll(temp)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
err = os.Mkdir(temp, 0755)
|
||||
fmt.Println("Creating temp directory at: " + temp)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if strings.HasPrefix(header.Name, "source-files/") && header.Name != "source-files/" {
|
||||
extractFilename := path.Join(temp, strings.TrimPrefix(header.Name, "source-files/"))
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.Mkdir(extractFilename, 0755); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err, nil
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Creating Directory: " + extractFilename)
|
||||
}
|
||||
case tar.TypeReg:
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err, nil
|
||||
}
|
||||
outFile, err := os.Create(extractFilename)
|
||||
fmt.Println("Creating File: " + extractFilename)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if _, err := io.Copy(outFile, tr); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if err := os.Chmod(extractFilename, header.FileInfo().Mode()); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
err = outFile.Close()
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
case tar.TypeSymlink:
|
||||
fmt.Println("Skipping symlink (Bundling symlinks in source packages is not supported)")
|
||||
case tar.TypeLink:
|
||||
fmt.Println("Skipping hard link (Bundling hard links in source packages is not supported)")
|
||||
default:
|
||||
return errors.New("ExtractTarGz: unknown type: " + strconv.Itoa(int(header.Typeflag)) + " in " + extractFilename), nil
|
||||
}
|
||||
}
|
||||
if header.Name == "source.sh" {
|
||||
bs, err := io.ReadAll(tr)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
err = os.WriteFile(path.Join(temp, "source.sh"), bs, 0644)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path.Join(temp, "source.sh")); os.IsNotExist(err) {
|
||||
return errors.New("source.sh file could not be found in the temporary build directory"), nil
|
||||
}
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
fmt.Println("Running source.sh file...")
|
||||
if !IsPackageInstalled(pkgInfo.Name, rootDir) {
|
||||
err = ExecutePackageScripts(filename, rootDir, Install, false)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
} else {
|
||||
err = ExecutePackageScripts(filename, rootDir, Update, false)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
bs, err := os.ReadFile(path.Join(temp, "source.sh"))
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
hasPackageFunc := false
|
||||
compatMode := false
|
||||
if strings.Contains(string(bs), "package()") {
|
||||
hasPackageFunc = true
|
||||
}
|
||||
if !hasPackageFunc {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print("This package does not seem to have the required 'package' function\nThe source.sh file may have been created for an older BPM version\nWould you like to run the script in compatibility mode (Not Recommended)? [Y\\n] ")
|
||||
text, _ := reader.ReadString('\n')
|
||||
if strings.TrimSpace(strings.ToLower(text)) != "y" && strings.TrimSpace(strings.ToLower(text)) != "yes" {
|
||||
return errors.New("could not find required 'package' function in source.sh"), nil
|
||||
}
|
||||
compatMode = true
|
||||
}
|
||||
|
||||
runScript := `
|
||||
cd "$BPM_WORKDIR"
|
||||
source "source.sh"
|
||||
if [[ $(type -t prepare) == function ]]; then
|
||||
echo "Running prepare() function..."
|
||||
export -f prepare
|
||||
bash -e -c prepare
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to run prepare() function in source.sh"
|
||||
fi
|
||||
fi
|
||||
cd "$BPM_SOURCE"
|
||||
if [[ $(type -t build) == function ]]; then
|
||||
echo "Running build() function..."
|
||||
export -f build
|
||||
bash -e -c build
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to run build() function in source.sh"
|
||||
fi
|
||||
fi
|
||||
cd "$BPM_SOURCE"
|
||||
if [[ $(type -t check) == function ]]; then
|
||||
echo "Running check() function..."
|
||||
export -f check
|
||||
bash -e -c check
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to run check() function in source.sh"
|
||||
fi
|
||||
fi
|
||||
if ! [[ $(type -t package) == function ]]; then
|
||||
echo "Failed to locate package() function in source.sh"
|
||||
exit 1
|
||||
fi
|
||||
echo "Running package() function..."
|
||||
export -f package
|
||||
bash -e -c package
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to run package() function in source.sh"
|
||||
fi
|
||||
`
|
||||
|
||||
err = os.WriteFile(path.Join(temp, "run.sh"), []byte(runScript), 0644)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("/bin/bash", "-e", "run.sh")
|
||||
cmd.Dir = temp
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
if compatMode {
|
||||
cmd = exec.Command("/bin/bash", "-e", "source.sh")
|
||||
cmd.Dir = temp
|
||||
cmd.Env = os.Environ()
|
||||
} else {
|
||||
err := os.Mkdir(path.Join(temp, "source"), 755)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
err = os.Mkdir(path.Join(temp, "output"), 755)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
cmd.Env = append(cmd.Env, "BPM_WORKDIR="+temp)
|
||||
cmd.Env = append(cmd.Env, "BPM_SOURCE="+path.Join(temp, "source"))
|
||||
cmd.Env = append(cmd.Env, "BPM_OUTPUT="+path.Join(temp, "output"))
|
||||
}
|
||||
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_ROOT=%s", rootDir))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_NAME=%s", pkgInfo.Name))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DESC=%s", pkgInfo.Description))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_VERSION=%s", pkgInfo.Version))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_URL=%s", pkgInfo.Url))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_ARCH=%s", pkgInfo.Arch))
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
depends := make([]string, len(pkgInfo.Depends))
|
||||
copy(depends, pkgInfo.Depends)
|
||||
for i := 0; i < len(depends); i++ {
|
||||
depends[i] = fmt.Sprintf("\"%s\"", depends[i])
|
||||
}
|
||||
makeDepends := make([]string, len(pkgInfo.MakeDepends))
|
||||
copy(makeDepends, pkgInfo.MakeDepends)
|
||||
for i := 0; i < len(makeDepends); i++ {
|
||||
makeDepends[i] = fmt.Sprintf("\"%s\"", makeDepends[i])
|
||||
}
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DEPENDS=(%s)", strings.Join(depends, " ")))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_MAKE_DEPENDS=(%s)", strings.Join(makeDepends, " ")))
|
||||
cmd.Env = append(cmd.Env, "BPM_PKG_TYPE=source")
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if _, err := os.Stat(path.Join(temp, "output/")); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return errors.New("output directory not be found at " + path.Join(temp, "output/")), nil
|
||||
}
|
||||
return err, nil
|
||||
}
|
||||
if dir, _ := os.ReadDir(path.Join(temp, "output/")); len(dir) == 0 {
|
||||
return errors.New("output directory is empty"), nil
|
||||
}
|
||||
fmt.Println("Copying all files...")
|
||||
err = filepath.WalkDir(path.Join(temp, "/output/"), func(fullpath string, d fs.DirEntry, err error) error {
|
||||
relFilename, err := filepath.Rel(path.Join(temp, "/output/"), fullpath)
|
||||
if relFilename == "." {
|
||||
return nil
|
||||
}
|
||||
extractFilename := path.Join(rootDir, relFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.Type() == os.ModeDir {
|
||||
files = append(files, relFilename+"/")
|
||||
if err := os.Mkdir(extractFilename, 0755); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Creating Directory: " + extractFilename)
|
||||
}
|
||||
} else if d.Type().IsRegular() {
|
||||
if _, err := os.Stat(extractFilename); err == nil {
|
||||
if slices.Contains(pkgInfo.Keep, relFilename) {
|
||||
fmt.Println("Skipping File: " + extractFilename + "(File is configured to be kept during installs/updates)")
|
||||
files = append(files, relFilename)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
outFile, err := os.Create(extractFilename)
|
||||
fmt.Println("Creating File: " + extractFilename)
|
||||
files = append(files, relFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Open(fullpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(outFile, f); err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := os.Stat(fullpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Chmod(extractFilename, info.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
err = outFile.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if d.Type() == os.ModeSymlink {
|
||||
link, err := os.Readlink(fullpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Creating Symlink: "+extractFilename, " -> "+link)
|
||||
files = append(files, relFilename)
|
||||
err = os.Symlink(link, extractFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if binaryPkgFromSrc {
|
||||
compiledDir := path.Join(rootDir, "var/lib/bpm/compiled/")
|
||||
err = os.MkdirAll(compiledDir, 755)
|
||||
compiledInfo := PackageInfo{}
|
||||
compiledInfo = *pkgInfo
|
||||
compiledInfo.Type = "binary"
|
||||
compiledInfo.Arch = GetArch()
|
||||
err = os.WriteFile(path.Join(compiledDir, "pkg.info"), []byte(CreateInfoFile(compiledInfo, false)), 0644)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
scripts, err := ReadPackageScripts(filename)
|
||||
for key, val := range scripts {
|
||||
err = os.WriteFile(path.Join(compiledDir, key), []byte(val), 0644)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
sed := fmt.Sprintf("s/%s/files/", strings.Replace(strings.TrimPrefix(path.Join(temp, "/output/"), "/"), "/", `\/`, -1))
|
||||
cmd := exec.Command("/usr/bin/tar", "-czvf", compiledInfo.Name+"-"+compiledInfo.Version+".bpm", "pkg.info", path.Join(temp, "/output/"), "--transform", sed)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Dir = compiledDir
|
||||
fmt.Printf("running command: %s %s\n", cmd.Path, strings.Join(cmd.Args, " "))
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
err = os.Remove(path.Join(compiledDir, "pkg.info"))
|
||||
for key := range scripts {
|
||||
err = os.Remove(path.Join(compiledDir, key))
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
if !keepTempDir {
|
||||
err := os.RemoveAll(temp)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return errors.New("no output files for source package. Cancelling package installation"), nil
|
||||
}
|
||||
|
||||
defer archive.Close()
|
||||
defer file.Close()
|
||||
return nil, files
|
||||
}
|
||||
|
||||
func InstallPackage(filename, rootDir string, force, binaryPkgFromSrc, keepTempDir bool) error {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
var oldFiles []string
|
||||
var files []string
|
||||
pkgInfo, err := ReadPackage(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
packageInstalled := IsPackageInstalled(pkgInfo.Name, installDir)
|
||||
packageInstalled := IsPackageInstalled(pkgInfo.Name, rootDir)
|
||||
if packageInstalled {
|
||||
oldFiles = GetPackageFiles(pkgInfo.Name, installDir)
|
||||
oldFiles = GetPackageFiles(pkgInfo.Name, rootDir)
|
||||
}
|
||||
if !force {
|
||||
if pkgInfo.Arch != "any" && pkgInfo.Arch != GetArch() {
|
||||
return errors.New("cannot install a package with a different architecture")
|
||||
}
|
||||
if unresolved := CheckDependencies(pkgInfo, installDir); len(unresolved) != 0 {
|
||||
if unresolved := CheckDependencies(pkgInfo, rootDir); len(unresolved) != 0 {
|
||||
return errors.New("Could not resolve all dependencies. Missing " + strings.Join(unresolved, ", "))
|
||||
}
|
||||
}
|
||||
if pkgInfo.Type == "binary" {
|
||||
if !packageInstalled {
|
||||
err = ExecutePackageScripts(filename, installDir, Install, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = ExecutePackageScripts(filename, installDir, Update, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
seenHardlinks := make(map[string]string)
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasPrefix(header.Name, "files/") && header.Name != "files/" {
|
||||
trimmedName := strings.TrimPrefix(header.Name, "files/")
|
||||
extractFilename := path.Join(installDir, trimmedName)
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
files = append(files, strings.TrimPrefix(header.Name, "files/"))
|
||||
if err := os.Mkdir(extractFilename, 0755); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Creating Directory: " + extractFilename)
|
||||
}
|
||||
case tar.TypeReg:
|
||||
if _, err := os.Stat(extractFilename); err == nil {
|
||||
if slices.Contains(pkgInfo.Keep, trimmedName) {
|
||||
fmt.Println("Skipping File: " + extractFilename + "(File is configured to be kept during installs/updates)")
|
||||
files = append(files, trimmedName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
outFile, err := os.Create(extractFilename)
|
||||
fmt.Println("Creating File: " + 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
|
||||
}
|
||||
case tar.TypeSymlink:
|
||||
fmt.Println("Creating Symlink: " + extractFilename + " -> " + header.Linkname)
|
||||
files = append(files, strings.TrimPrefix(header.Name, "files/"))
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
err = os.Symlink(header.Linkname, extractFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case tar.TypeLink:
|
||||
fmt.Println("Detected Hard Link: " + extractFilename + " -> " + path.Join(installDir, strings.TrimPrefix(header.Linkname, "files/")))
|
||||
files = append(files, strings.TrimPrefix(header.Name, "files/"))
|
||||
seenHardlinks[extractFilename] = path.Join(strings.TrimPrefix(header.Linkname, "files/"))
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("ExtractTarGz: unknown type: " + strconv.Itoa(int(header.Typeflag)) + " in " + extractFilename)
|
||||
}
|
||||
}
|
||||
}
|
||||
for extractFilename, destination := range seenHardlinks {
|
||||
fmt.Println("Creating Hard Link: " + extractFilename + " -> " + path.Join(installDir, destination))
|
||||
err := os.Link(path.Join(installDir, destination), extractFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err, i := extractPackage(pkgInfo, filename, rootDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
files = i
|
||||
} else if pkgInfo.Type == "source" {
|
||||
temp := "/var/tmp/bpm_source-" + pkgInfo.Name
|
||||
err = os.RemoveAll(temp)
|
||||
err, i := compilePackage(pkgInfo, filename, rootDir, binaryPkgFromSrc, keepTempDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Mkdir(temp, 0755)
|
||||
fmt.Println("Creating temp directory at: " + temp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasPrefix(header.Name, "source-files/") && header.Name != "source-files/" {
|
||||
extractFilename := path.Join(temp, strings.TrimPrefix(header.Name, "source-files/"))
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.Mkdir(extractFilename, 0755); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Creating Directory: " + extractFilename)
|
||||
}
|
||||
case tar.TypeReg:
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
outFile, err := os.Create(extractFilename)
|
||||
fmt.Println("Creating File: " + extractFilename)
|
||||
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
|
||||
}
|
||||
case tar.TypeSymlink:
|
||||
fmt.Println("Skipping symlink (Bundling symlinks in source packages is not supported)")
|
||||
case tar.TypeLink:
|
||||
fmt.Println("Skipping hard link (Bundling hard links in source packages is not supported)")
|
||||
default:
|
||||
return errors.New("ExtractTarGz: unknown type: " + strconv.Itoa(int(header.Typeflag)) + " in " + extractFilename)
|
||||
}
|
||||
}
|
||||
if header.Name == "source.sh" {
|
||||
bs, err := io.ReadAll(tr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(path.Join(temp, "source.sh"), bs, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path.Join(temp, "source.sh")); os.IsNotExist(err) {
|
||||
return errors.New("source.sh file could not be found in the temporary build directory")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Running source.sh file...")
|
||||
if !packageInstalled {
|
||||
err = ExecutePackageScripts(filename, installDir, Install, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = ExecutePackageScripts(filename, installDir, Update, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cmd := exec.Command("/bin/bash", "-e", "source.sh")
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Dir = temp
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_ROOT=%s", installDir))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_NAME=%s", pkgInfo.Name))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DESC=%s", pkgInfo.Description))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_VERSION=%s", pkgInfo.Version))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_URL=%s", pkgInfo.Url))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_ARCH=%s", pkgInfo.Arch))
|
||||
depends := make([]string, len(pkgInfo.Depends))
|
||||
copy(depends, pkgInfo.Depends)
|
||||
for i := 0; i < len(depends); i++ {
|
||||
depends[i] = fmt.Sprintf("\"%s\"", depends[i])
|
||||
}
|
||||
makeDepends := make([]string, len(pkgInfo.MakeDepends))
|
||||
copy(makeDepends, pkgInfo.MakeDepends)
|
||||
for i := 0; i < len(makeDepends); i++ {
|
||||
makeDepends[i] = fmt.Sprintf("\"%s\"", makeDepends[i])
|
||||
}
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DEPENDS=(%s)", strings.Join(depends, " ")))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_MAKE_DEPENDS=(%s)", strings.Join(makeDepends, " ")))
|
||||
cmd.Env = append(cmd.Env, "BPM_PKG_TYPE=source")
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := os.Stat(path.Join(temp, "/output/")); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return errors.New("Output directory not be found at " + path.Join(temp, "/output/"))
|
||||
}
|
||||
return err
|
||||
}
|
||||
fmt.Println("Copying all files...")
|
||||
err = filepath.WalkDir(path.Join(temp, "/output/"), func(fullpath string, d fs.DirEntry, err error) error {
|
||||
relFilename, err := filepath.Rel(path.Join(temp, "/output/"), fullpath)
|
||||
if relFilename == "." {
|
||||
return nil
|
||||
}
|
||||
extractFilename := path.Join(installDir, relFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.Type() == os.ModeDir {
|
||||
files = append(files, relFilename+"/")
|
||||
if err := os.Mkdir(extractFilename, 0755); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Creating Directory: " + extractFilename)
|
||||
}
|
||||
} else if d.Type().IsRegular() {
|
||||
if _, err := os.Stat(extractFilename); err == nil {
|
||||
if slices.Contains(pkgInfo.Keep, relFilename) {
|
||||
fmt.Println("Skipping File: " + extractFilename + "(File is configured to be kept during installs/updates)")
|
||||
files = append(files, relFilename)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
outFile, err := os.Create(extractFilename)
|
||||
fmt.Println("Creating File: " + extractFilename)
|
||||
files = append(files, relFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Open(fullpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(outFile, f); err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := os.Stat(fullpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Chmod(extractFilename, info.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
err = outFile.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if d.Type() == os.ModeSymlink {
|
||||
link, err := os.Readlink(fullpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Creating Symlink: "+extractFilename, " -> "+link)
|
||||
files = append(files, relFilename)
|
||||
err = os.Symlink(link, extractFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if binaryPkgFromSrc {
|
||||
compiledDir := path.Join(installDir, "var/lib/bpm/compiled/")
|
||||
err = os.MkdirAll(compiledDir, 755)
|
||||
compiledInfo := PackageInfo{}
|
||||
compiledInfo = *pkgInfo
|
||||
compiledInfo.Type = "binary"
|
||||
compiledInfo.Arch = GetArch()
|
||||
err = os.WriteFile(path.Join(compiledDir, "pkg.info"), []byte(CreateInfoFile(compiledInfo, false)), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scripts, err := ReadPackageScripts(filename)
|
||||
for key, val := range scripts {
|
||||
err = os.WriteFile(path.Join(compiledDir, key), []byte(val), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
sed := fmt.Sprintf("s/%s/files/", strings.Replace(strings.TrimPrefix(path.Join(temp, "/output/"), "/"), "/", `\/`, -1))
|
||||
cmd := exec.Command("/usr/bin/tar", "-czvf", compiledInfo.Name+"-"+compiledInfo.Version+".bpm", "pkg.info", path.Join(temp, "/output/"), "--transform", sed)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Dir = compiledDir
|
||||
fmt.Printf("running command: %s %s\n", cmd.Path, strings.Join(cmd.Args, " "))
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Remove(path.Join(compiledDir, "pkg.info"))
|
||||
for key := range scripts {
|
||||
err = os.Remove(path.Join(compiledDir, key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !keepTempDir {
|
||||
err := os.RemoveAll(temp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return errors.New("no output files for source package. Cancelling package installation")
|
||||
}
|
||||
files = i
|
||||
} else {
|
||||
return errors.New("Unknown package type: " + pkgInfo.Type)
|
||||
}
|
||||
@@ -754,7 +889,7 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe
|
||||
return slices.Contains(files, f)
|
||||
})
|
||||
|
||||
installedDir := path.Join(installDir, "var/lib/bpm/installed/")
|
||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||
err = os.MkdirAll(installedDir, 755)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -820,19 +955,11 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe
|
||||
}
|
||||
}
|
||||
|
||||
err = archive.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(filesDiff) != 0 {
|
||||
fmt.Println("Removing obsolete files")
|
||||
var symlinks []string
|
||||
for _, f := range filesDiff {
|
||||
f = path.Join(installDir, f)
|
||||
f = path.Join(rootDir, f)
|
||||
lstat, err := os.Lstat(f)
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
@@ -874,7 +1001,7 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe
|
||||
removals = 0
|
||||
for i := len(symlinks) - 1; i >= 0; i-- {
|
||||
f := symlinks[i]
|
||||
f = path.Join(installDir, f)
|
||||
f = path.Join(rootDir, f)
|
||||
_, err := os.Lstat(f)
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
@@ -896,12 +1023,12 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe
|
||||
}
|
||||
}
|
||||
if !packageInstalled {
|
||||
err = ExecutePackageScripts(filename, installDir, Install, true)
|
||||
err = ExecutePackageScripts(filename, rootDir, Install, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = ExecutePackageScripts(filename, installDir, Update, true)
|
||||
err = ExecutePackageScripts(filename, rootDir, Update, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user