github.com/anishathalye/periscope@v0.3.5/internal/periscope/periscope.go (about)

     1  // Copyright (c) Anish Athalye. Released under GPLv3.
     2  
     3  package periscope
     4  
     5  import (
     6  	"github.com/anishathalye/periscope/internal/db"
     7  	"github.com/anishathalye/periscope/internal/herror"
     8  
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"time"
    15  
    16  	"github.com/cheggaaa/pb/v3"
    17  	"github.com/spf13/afero"
    18  	"golang.org/x/term"
    19  )
    20  
    21  const dbDirectory = "periscope"
    22  const dbName = "periscope.sqlite"
    23  
    24  type Periscope struct {
    25  	fs        afero.Fs
    26  	realFs    bool
    27  	db        *db.Session
    28  	dbPath    string
    29  	outStream io.Writer
    30  	errStream io.Writer
    31  	options   *Options
    32  }
    33  
    34  type Options struct {
    35  	Debug bool
    36  }
    37  
    38  func dbPath() (string, herror.Interface) {
    39  	cacheDirRoot, err := os.UserCacheDir()
    40  	if err != nil {
    41  		return "", herror.Unlikely(err, "unable to determine cache directory", `
    42  Ensure that $HOME or $XDG_CACHE_HOME is set.
    43  		`)
    44  	}
    45  	cacheDir := filepath.Join(cacheDirRoot, dbDirectory)
    46  	err = os.MkdirAll(cacheDir, 0o755)
    47  	if err != nil {
    48  		return "", herror.Unlikely(err, fmt.Sprintf("unable to create cache directory '%s'", cacheDir), fmt.Sprintf(`
    49  Ensure that the user cache directory '%s' exists and is writable.
    50  		`, cacheDirRoot))
    51  	}
    52  	dbPath := filepath.Join(cacheDir, dbName)
    53  	return dbPath, nil
    54  }
    55  
    56  func New(options *Options) (*Periscope, herror.Interface) {
    57  	dbPath, err := dbPath()
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	db, err := db.New(dbPath, options.Debug)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	fs := afero.NewOsFs()
    66  	return &Periscope{
    67  		fs:        fs,
    68  		realFs:    true,
    69  		db:        db,
    70  		dbPath:    dbPath,
    71  		outStream: os.Stdout,
    72  		errStream: os.Stderr,
    73  		options:   options,
    74  	}, nil
    75  }
    76  
    77  func (ps *Periscope) progressBar(total int, template string) *pb.ProgressBar {
    78  	bar := pb.New(total)
    79  	bar.SetRefreshRate(25 * time.Millisecond)
    80  	bar.SetTemplateString(template)
    81  	bar.SetMaxWidth(99)
    82  	bar.Start()
    83  	if w, ok := ps.errStream.(*os.File); ok && term.IsTerminal(int(w.Fd())) {
    84  		bar.SetWriter(ps.errStream)
    85  	} else {
    86  		bar.SetWriter(ioutil.Discard)
    87  	}
    88  	return bar
    89  }