package ui import ( "log" "os" "time" "bytes" "context" "errors" "fmt" "io" "io/ioutil" "net/http" "path/filepath" "github.com/codeclysm/extract" "github.com/gotk3/gotk3/glib" "varia.zone/hui/internal/conf" "varia.zone/hui/internal/model" ) // PostInitSpinner handles UI tasks after Hugo is downloaded. func PostInitSpinner(m *model.Model) error { if err := SwitchStackPage(m, conf.EmptyStackPage); err != nil { return err } if err := ShowSiteButtons(m); err != nil { return err } return nil } // Initialise initialises the program. func Initialise(m *model.Model) error { msg := "Downloading Hugo... this could take a minute..." if err := SwitchStackPage(m, conf.BusyStackPage, msg); err != nil { return err } go func() { if err := initialise(m.User.HomeDir); err != nil { glib.IdleAdd(func() bool { if err := ShowErrDialog(m, err); err != nil { log.Fatal(fmt.Errorf("main: unable to show error dialog: %s", err)) } return false }) } }() go func() { for { if _, err := os.Stat(conf.HugoBinPath(m.User.HomeDir)); err == nil { break } time.Sleep(1) } glib.IdleAdd(func() bool { if err := PostInitSpinner(m); err != nil { if err := ShowErrDialog(m, err); err != nil { log.Fatal(fmt.Errorf("main: unable to show error dialog: %s", err)) } } return false }) }() return nil } // initialise deals with initial setup functionality. func initialise(homeDir string) error { if err := createDirectories(homeDir); err != nil { return err } if err := downloadHugo(homeDir); err != nil { return err } return nil } // httpGetFile downloads a file from the internet. func httpGetFile(filepath, url string) error { out, err := os.Create(filepath) if err != nil { return fmt.Errorf("httpGetFile: unable to create '%s': %s", filepath, err) } defer out.Close() resp, err := http.Get(url) if err != nil { return fmt.Errorf("httpGetFile: unable to HTTP GET '%s'", url) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("httpGetFile: HTTP GET response code %v for '%s'", resp.StatusCode, url) } _, err = io.Copy(out, resp.Body) if err != nil { return fmt.Errorf("httpGetFile: unable to copy HTTP GET response to disk: %s", err) } return nil } // downloadHugo downloads Hugo. func downloadHugo(homeDir string) error { hugoTarPath := filepath.Join(conf.HugoDir(homeDir), fmt.Sprintf("hugo-%s.tar.gz", conf.HugoVersion)) if _, err := os.Stat(conf.HugoBinPath(homeDir)); err == nil { return nil } else if errors.Is(err, os.ErrNotExist) { if err := httpGetFile(hugoTarPath, conf.HugoReleaseURL); err != nil { return err } } fpath, err := ioutil.ReadFile(hugoTarPath) if err != nil { return fmt.Errorf("downloadHugo: unable to read file '%s': %s", hugoTarPath, err) } if err := extract.Gz(context.TODO(), bytes.NewBuffer(fpath), conf.HugoDir(homeDir), nil); err != nil { return fmt.Errorf("downloadHugo: unable to extract file '%s': %s", hugoTarPath, err) } return nil } // createDirectories creates all necessary application directories. func createDirectories(homeDir string) error { paths := []string{ conf.DataDir(homeDir), conf.HugoDir(homeDir), conf.SitesDir(homeDir), } for _, fpath := range paths { if _, err := os.Stat(fpath); err != nil && os.IsNotExist(err) { if err := os.Mkdir(fpath, 0764); err != nil { return fmt.Errorf("createDirectories: unable to create '%s': %s", fpath, err) } } } return nil }