func (input *runnerTarInput) Persist() error { f, err := input.factory.inputData.Open() if err != nil { return err } hasher := common.NewHashReader(f, sha1.New()) streamHash := fmt.Sprintf("%0x", hasher.Sum(nil)) uncompressedSize := hasher.Length() f.Close() f, err = input.factory.inputData.Open() if err != nil { return err } defer f.Close() return input.persistFromTarStream( f, "", uncompressedSize, streamHash, ) }
func (input *runnerBaseInput) persistFromTarStream( r io.Reader, compressionFormat string, uncompressedSize int64, streamHash string, ) error { tmpPath := fmt.Sprintf("%s.tmp", input.path) if err := os.MkdirAll(tmpPath, 0755); err != nil { return err } defer os.RemoveAll(tmpPath) input.Reserve(uncompressedSize) hasher := common.NewHashReader(r, sha1.New()) var uncompressedReader io.Reader if compressionFormat == "gzip" { gz, err := gzip.NewReader(hasher) if err != nil { return err } defer gz.Close() uncompressedReader = gz } else if compressionFormat == "bzip2" { uncompressedReader = bzip2.NewReader(hasher) } else { uncompressedReader = hasher } archive := tar.NewReader(uncompressedReader) sha1sumFile, err := os.Create(fmt.Sprintf("%s.sha1", input.path)) if err != nil { return err } defer sha1sumFile.Close() var size int64 = 0 for { hdr, err := archive.Next() if err == io.EOF { break } if err != nil { return err } filePath := path.Join(tmpPath, hdr.Name) if hdr.FileInfo().IsDir() { if err := os.MkdirAll(filePath, 0755); err != nil { return err } } else { if err := os.MkdirAll(path.Dir(filePath), 0755); err != nil { return err } fd, err := os.Create(filePath) if err != nil { return err } defer fd.Close() innerHasher := common.NewHashReader(archive, sha1.New()) if _, err := io.Copy(fd, innerHasher); err != nil { return err } _, err = fmt.Fprintf( sha1sumFile, "%0x *%s/%s\n", innerHasher.Sum(nil), input.Hash()[2:], hdr.Name, ) if err != nil { return err } size += hdr.Size } } if streamHash != fmt.Sprintf("%0x", hasher.Sum(nil)) { return errors.New(fmt.Sprintf( "hash mismatch: expected %s got %s", streamHash, fmt.Sprintf("%0x", hasher.Sum(nil)), )) } settingsFd, err := os.Open(path.Join(tmpPath, "settings.json")) if err != nil { return err } defer settingsFd.Close() decoder := json.NewDecoder(settingsFd) if err := decoder.Decode(input.Settings()); err != nil { return err } if err := os.Rename(tmpPath, input.path); err != nil { return err } input.Commit(size) return nil }