-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
232 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
internal/extension-registry/installer/impl/bininstaller/tarinstaller/installer.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package tarinstaller | ||
|
||
import ( | ||
"github.com/ImSingee/kitty/internal/extension-registry/installer" | ||
"github.com/ImSingee/kitty/internal/extension-registry/installer/impl/bininstaller/indirect" | ||
eroptions "github.com/ImSingee/kitty/internal/extension-registry/options" | ||
) | ||
|
||
type Factory struct{} | ||
|
||
func (Factory) Key() string { | ||
return "dist-tar" | ||
} | ||
|
||
func (Factory) GetInstaller(o eroptions.AnyOptions) (installer.Installer, error) { | ||
return indirect.GetInstaller("tar", o) | ||
} |
17 changes: 17 additions & 0 deletions
17
internal/extension-registry/installer/impl/bininstaller/zipinstaller/installer.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package zipinstaller | ||
|
||
import ( | ||
"github.com/ImSingee/kitty/internal/extension-registry/installer" | ||
"github.com/ImSingee/kitty/internal/extension-registry/installer/impl/bininstaller/indirect" | ||
eroptions "github.com/ImSingee/kitty/internal/extension-registry/options" | ||
) | ||
|
||
type Factory struct{} | ||
|
||
func (Factory) Key() string { | ||
return "dist-zip" | ||
} | ||
|
||
func (Factory) GetInstaller(o eroptions.AnyOptions) (installer.Installer, error) { | ||
return indirect.GetInstaller("zip", o) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
package erutils | ||
|
||
import ( | ||
"archive/tar" | ||
"compress/gzip" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"io/fs" | ||
"log" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"runtime" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// Untar reads the tar file and writes it into dir. | ||
func Untar(filename string, dir string) error { | ||
f, err := os.Open(filename) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
|
||
return untar(filename, f, dir) | ||
} | ||
|
||
func untar(filename string, r io.Reader, dir string) (err error) { | ||
t0 := time.Now() | ||
nFiles := 0 | ||
madeDir := map[string]bool{} | ||
defer func() { | ||
td := time.Since(t0) | ||
if err == nil { | ||
log.Printf("extracted tarball into %s: %d files, %d dirs (%v)", dir, nFiles, len(madeDir), td) | ||
} else { | ||
log.Printf("error extracting tarball into %s after %d files, %d dirs, %v: %v", dir, nFiles, len(madeDir), td, err) | ||
} | ||
}() | ||
zr, err := decompress(filename, r) | ||
if err != nil { | ||
return fmt.Errorf("cannot detect compress type: %v", err) | ||
} | ||
tr := tar.NewReader(zr) | ||
loggedChtimesError := false | ||
for { | ||
f, err := tr.Next() | ||
if err == io.EOF { | ||
break | ||
} | ||
if err != nil { | ||
log.Printf("tar reading error: %v", err) | ||
return fmt.Errorf("tar error: %v", err) | ||
} | ||
if !validRelPath(f.Name) { | ||
return fmt.Errorf("tar contained invalid name error %q", f.Name) | ||
} | ||
rel := filepath.FromSlash(f.Name) | ||
abs := filepath.Join(dir, rel) | ||
|
||
mode := f.FileInfo().Mode() | ||
switch f.Typeflag { | ||
case tar.TypeReg: | ||
// Make the directory. This is redundant because it should | ||
// already be made by a directory entry in the tar | ||
// beforehand. Thus, don't check for errors; the next | ||
// write will fail with the same error. | ||
dir := filepath.Dir(abs) | ||
if !madeDir[dir] { | ||
if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil { | ||
return err | ||
} | ||
madeDir[dir] = true | ||
} | ||
if runtime.GOOS == "darwin" && mode&0111 != 0 { | ||
// The darwin kernel caches binary signatures | ||
// and SIGKILLs binaries with mismatched | ||
// signatures. Overwriting a binary with | ||
// O_TRUNC does not clear the cache, rendering | ||
// the new copy unusable. Removing the original | ||
// file first does clear the cache. See #54132. | ||
err := os.Remove(abs) | ||
if err != nil && !errors.Is(err, fs.ErrNotExist) { | ||
return err | ||
} | ||
} | ||
wf, err := os.OpenFile(abs, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm()) | ||
if err != nil { | ||
return err | ||
} | ||
n, err := io.Copy(wf, tr) | ||
if closeErr := wf.Close(); closeErr != nil && err == nil { | ||
err = closeErr | ||
} | ||
if err != nil { | ||
return fmt.Errorf("error writing to %s: %v", abs, err) | ||
} | ||
if n != f.Size { | ||
return fmt.Errorf("only wrote %d bytes to %s; expected %d", n, abs, f.Size) | ||
} | ||
modTime := f.ModTime | ||
if modTime.After(t0) { | ||
// Clamp modtimes at system time. See | ||
// golang.org/issue/19062 when clock on | ||
// buildlet was behind the gitmirror server | ||
// doing the git-archive. | ||
modTime = t0 | ||
} | ||
if !modTime.IsZero() { | ||
if err := os.Chtimes(abs, modTime, modTime); err != nil && !loggedChtimesError { | ||
// benign error. Gerrit doesn't even set the | ||
// modtime in these, and we don't end up relying | ||
// on it anywhere (the gomote push command relies | ||
// on digests only), so this is a little pointless | ||
// for now. | ||
log.Printf("error changing modtime: %v (further Chtimes errors suppressed)", err) | ||
loggedChtimesError = true // once is enough | ||
} | ||
} | ||
nFiles++ | ||
case tar.TypeDir: | ||
if err := os.MkdirAll(abs, 0755); err != nil { | ||
return err | ||
} | ||
madeDir[abs] = true | ||
case tar.TypeXGlobalHeader: | ||
// git archive generates these. Ignore them. | ||
default: | ||
return fmt.Errorf("tar file entry %s contained unsupported file type %v", f.Name, mode) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func decompress(filename string, archive io.Reader) (io.ReadCloser, error) { | ||
switch { | ||
case strings.HasSuffix(filename, ".tar.gz"): | ||
return gzip.NewReader(archive) | ||
case strings.HasSuffix(filename, ".tar"): | ||
return io.NopCloser(archive), nil | ||
default: | ||
return nil, fmt.Errorf("unknown archive format: %s", filename) | ||
} | ||
} | ||
|
||
func validRelativeDir(dir string) bool { | ||
if strings.Contains(dir, `\`) || path.IsAbs(dir) { | ||
return false | ||
} | ||
dir = path.Clean(dir) | ||
if strings.HasPrefix(dir, "../") || strings.HasSuffix(dir, "/..") || dir == ".." { | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
func validRelPath(p string) bool { | ||
if p == "" || strings.Contains(p, `\`) || strings.HasPrefix(p, "/") || strings.Contains(p, "../") { | ||
return false | ||
} | ||
return true | ||
} |