func (src *GCSSource) Type() string {
	return src.TableBase
}
Type returns a string for use in metrics and logs.
package storage
import (
	"archive/tar"
	"compress/gzip"
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
	"cloud.google.com/go/civil"
	gcs "cloud.google.com/go/storage"
	"google.golang.org/api/option"
	"github.com/googleapis/google-cloud-go-testing/storage/stiface"
	"github.com/m-lab/etl/etl"
	"github.com/m-lab/etl/factory"
	"github.com/m-lab/etl/metrics"
)
var ErrOversizeFile = errors.New("Oversize file")
type TarReader interface {
	Next() (*tar.Header, error)
	Read(b []byte) (int, error)
}
type GCSSource struct {
	FilePath      string
	Size          int64
	TarReader                    
	io.Closer                    
	RetryBaseTime time.Duration  
	TableBase     string         
	PathDate      civil.Date     
}
func (src *GCSSource) nextHeader(trial int) (*tar.Header, bool, error) {
	h, err := src.Next()
	if err != nil {
		if err == io.EOF {
			return nil, false, err
		} else if strings.Contains(err.Error(), "unexpected EOF") {
			metrics.GCSRetryCount.WithLabelValues(
				src.TableBase, "nextHeader", strconv.Itoa(trial), "unexpected EOF").Inc()
		} else {
			metrics.GCSRetryCount.WithLabelValues(
				src.TableBase, "nextHeader", strconv.Itoa(trial), "other").Inc()
		}
		log.Printf("ERROR: nextHeader: %v\n", err)
	}
	return h, true, err
}
func (src *GCSSource) nextData(h *tar.Header, trial int) ([]byte, bool, error) {
	var data []byte
	var err error
	var phase string
	if strings.HasSuffix(strings.ToLower(h.Name), "gz") {
		var zipReader *gzip.Reader
		zipReader, err = gzip.NewReader(src)
		if err != nil {
			if err == io.EOF {
				return nil, false, err
			}
			metrics.GCSRetryCount.WithLabelValues(
				src.TableBase, "open zip", strconv.Itoa(trial), "zipReaderError").Inc()
			log.Printf("ERROR: zipReader(%d): %v in file %s\n", trial, err, h.Name)
			return nil, true, err
		}
		defer zipReader.Close()
		phase = "nextData zip"
		data, err = ioutil.ReadAll(zipReader)
	} else {
		phase = "nextData"
		data, err = ioutil.ReadAll(src)
	}
	if err != nil {
		if strings.Contains(err.Error(), "stream error") {
			metrics.GCSRetryCount.WithLabelValues(
				src.TableBase, phase, strconv.Itoa(trial), "stream error").Inc()
		} else if strings.Contains(err.Error(), "unexpected EOF") {
			metrics.GCSRetryCount.WithLabelValues(
				src.TableBase, phase, strconv.Itoa(trial), "unexpected EOF").Inc()
		} else {
			metrics.GCSRetryCount.WithLabelValues(
				src.TableBase, phase, strconv.Itoa(trial), "other error").Inc()
		}
		log.Printf("ERROR: nextData:%d [%s] %s (%d bytes) from %s\n", trial, err, h.Name, h.Size, src.FilePath)
		return nil, true, err
	}
	return data, false, nil
}