162 lines
3.2 KiB
Go
162 lines
3.2 KiB
Go
|
package spm
|
||
|
|
||
|
import (
|
||
|
"archive/tar"
|
||
|
"compress/gzip"
|
||
|
"io"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
)
|
||
|
|
||
|
func DecompressToTemp(filePath string) (string, error) {
|
||
|
UpdateProgress(0, "Decompressing package")
|
||
|
tempDir, err := os.MkdirTemp("", "spm_decompress")
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
file, err := os.Open(filePath)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
defer file.Close()
|
||
|
|
||
|
gzr, err := gzip.NewReader(file)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
defer gzr.Close()
|
||
|
|
||
|
tarReader := tar.NewReader(gzr)
|
||
|
var totalFiles, processedFiles int
|
||
|
// Count total files
|
||
|
for {
|
||
|
_, err := tarReader.Next()
|
||
|
if err == io.EOF {
|
||
|
break
|
||
|
}
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
totalFiles++
|
||
|
}
|
||
|
|
||
|
file.Seek(0, io.SeekStart)
|
||
|
gzr.Reset(file)
|
||
|
tarReader = tar.NewReader(gzr)
|
||
|
|
||
|
for {
|
||
|
header, err := tarReader.Next()
|
||
|
if err == io.EOF {
|
||
|
break
|
||
|
}
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
targetPath := filepath.Join(tempDir, header.Name)
|
||
|
switch header.Typeflag {
|
||
|
case tar.TypeDir:
|
||
|
if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
case tar.TypeReg:
|
||
|
outFile, err := os.Create(targetPath)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
outFile.Close()
|
||
|
}
|
||
|
|
||
|
processedFiles++
|
||
|
UpdateProgress(int(float64(processedFiles)/float64(totalFiles)*100), "Decompressing package")
|
||
|
}
|
||
|
|
||
|
UpdateProgress(100, "Package decompressed")
|
||
|
return tempDir, nil
|
||
|
}
|
||
|
|
||
|
func MoveFilesToInstallDir(tempDir, installDir string) error {
|
||
|
// Count total files to copy
|
||
|
var totalFiles, copiedFiles int
|
||
|
err := filepath.Walk(tempDir, func(path string, info os.FileInfo, err error) error {
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if !info.IsDir() {
|
||
|
totalFiles++
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Copy files and track progress
|
||
|
err = filepath.Walk(tempDir, func(path string, info os.FileInfo, err error) error {
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
relPath, err := filepath.Rel(tempDir, path)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
targetPath := filepath.Join(installDir, relPath)
|
||
|
if info.IsDir() {
|
||
|
// Create directories in the install directory
|
||
|
if err := os.MkdirAll(targetPath, os.ModePerm); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
} else {
|
||
|
// Copy files to the install directory
|
||
|
if err := copyFile(path, targetPath); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
copiedFiles++
|
||
|
UpdateProgress(int(float64(copiedFiles)/float64(totalFiles)*100), "Copying files to install directory")
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Clean up temporary directory
|
||
|
UpdateProgress(100, "Cleaning up temporary files")
|
||
|
return os.RemoveAll(tempDir)
|
||
|
}
|
||
|
|
||
|
// copyFile copies the contents of the source file to the destination file.
|
||
|
func copyFile(src, dst string) error {
|
||
|
sourceFile, err := os.Open(src)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer sourceFile.Close()
|
||
|
|
||
|
// Create the destination file
|
||
|
destinationFile, err := os.Create(dst)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer destinationFile.Close()
|
||
|
|
||
|
// Copy the file content
|
||
|
if _, err := io.Copy(destinationFile, sourceFile); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Preserve file permissions
|
||
|
info, err := sourceFile.Stat()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return os.Chmod(dst, info.Mode())
|
||
|
}
|