From def3c333323e8b36ecf54110875d1b17e5a0376b Mon Sep 17 00:00:00 2001
From: Henrique Dias <hacdias@gmail.com>
Date: Sun, 21 Feb 2016 11:51:31 +0000
Subject: [PATCH] update install script

---
 config/config.go     |  23 +------
 insthugo/insthugo.go | 151 +++++++++++++++++++++++++++++++------------
 2 files changed, 112 insertions(+), 62 deletions(-)

diff --git a/config/config.go b/config/config.go
index 35211f7b..23b4bce6 100644
--- a/config/config.go
+++ b/config/config.go
@@ -1,11 +1,6 @@
 package config
 
 import (
-	"log"
-	"os"
-	"os/user"
-	"path/filepath"
-	"runtime"
 	"strings"
 
 	"github.com/hacdias/caddy-hugo/insthugo"
@@ -23,28 +18,12 @@ type Config struct {
 
 // ParseHugo parses the configuration file
 func ParseHugo(c *setup.Controller) (*Config, error) {
-	// First check if Hugo is installed
-	user, err := user.Current()
-
-	if err != nil {
-		log.Fatal(err)
-	}
-
 	conf := &Config{
 		Public: strings.Replace(c.Root, "./", "", -1),
 		Path:   "./",
-		Hugo:   user.HomeDir + "/.caddy/bin/hugo",
 	}
 
-	if runtime.GOOS == "windows" {
-		conf.Hugo += ".exe"
-	}
-
-	conf.Hugo = filepath.Clean(conf.Hugo)
-
-	if _, err := os.Stat(conf.Hugo); os.IsNotExist(err) {
-		insthugo.Install()
-	}
+	conf.Hugo = insthugo.Install()
 
 	for c.Next() {
 		args := c.RemainingArgs()
diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go
index b3c050a7..642ac595 100644
--- a/insthugo/insthugo.go
+++ b/insthugo/insthugo.go
@@ -3,8 +3,11 @@ package insthugo
 import (
 	"archive/zip"
 	"compress/gzip"
+	"crypto/sha256"
+	"encoding/hex"
 	"fmt"
 	"io"
+	"log"
 	"net/http"
 	"os"
 	"os/user"
@@ -13,99 +16,157 @@ import (
 	"strings"
 )
 
-const version = "0.15"
+const (
+	version = "0.15"
+	baseurl = "https://github.com/spf13/hugo/releases/download/v" + version + "/"
+)
+
+var (
+	usr        user.User
+	tempfiles  []string
+	filename   = "hugo_" + version + "_" + runtime.GOOS + "_" + runtime.GOARCH
+	sha256Hash = map[string]string{
+		"hugo_0.15_darwin_386.zip":              "",
+		"hugo_0.15_darwin_amd64.zip":            "",
+		"hugo_0.15_dragonfly_amd64.zip":         "",
+		"hugo_0.15_freebsd_386.zip":             "",
+		"hugo_0.15_freebsd_amd64.zip":           "",
+		"hugo_0.15_freebsd_arm.zip":             "",
+		"hugo_0.15_linux_386.tar.gz":            "",
+		"hugo_0.15_linux_amd64.tar.gz":          "",
+		"hugo_0.15_linux_arm.tar.gz":            "",
+		"hugo_0.15_netbsd_386.zip":              "",
+		"hugo_0.15_netbsd_amd64.zip":            "",
+		"hugo_0.15_netbsd_arm.zip":              "",
+		"hugo_0.15_openbsd_386.zip":             "",
+		"hugo_0.15_openbsd_amd64.zip":           "",
+		"hugo_0.15_windows_386_32-bit-only.zip": "0a72f9a1a929f36c0e52fb1c6272b4d37a2bd1a6bd19ce57a6e7b6803b434756",
+		"hugo_0.15_windows_amd64.zip":           "9f03602e48ae2199e06431d7436fb3b9464538c0d44aac9a76eb98e1d4d5d727",
+	}
+)
 
 // Install installs Hugo
-func Install() error {
-	// Sets the base url from where to download
-	baseurl := "https://github.com/spf13/hugo/releases/download/v" + version + "/"
+func Install() string {
+	usr, err := user.Current()
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(-1)
+	}
 
-	// The default filename
-	filename := "hugo_" + version + "_" + runtime.GOOS + "_" + runtime.GOARCH
+	caddy := filepath.Clean(usr.HomeDir + "/.caddy/")
+	bin := filepath.Clean(caddy + "/bin")
+	temp := filepath.Clean(caddy + "/temp")
+	hugo := filepath.Clean(bin + "/hugo")
 
 	switch runtime.GOOS {
-	case "darwin", "windows":
+	case "darwin":
+		filename += ".zip"
+	case "windows":
 		// At least for v0.15 version
-		if runtime.GOOS == "windows" && runtime.GOARCH == "386" {
+		if runtime.GOARCH == "386" {
 			filename += "32-bit-only"
 		}
 
 		filename += ".zip"
+		hugo += ".exe"
 	default:
 		filename += ".tar.gz"
 	}
 
-	// Gets the current user home directory and creates the .caddy dir
-	user, err := user.Current()
-	if err != nil {
-		return err
+	// Check if Hugo is already installed
+	if _, err := os.Stat(hugo); err == nil {
+		return hugo
 	}
 
-	path := user.HomeDir + "/.caddy/"
-	bin := path + "bin/"
-	temp := path + "temp/"
+	fmt.Println("Unable to find Hugo on " + caddy)
 
-	err = os.MkdirAll(path, 0666)
+	err = os.MkdirAll(caddy, 0666)
 	err = os.Mkdir(bin, 0666)
 	err = os.Mkdir(temp, 0666)
-	if err != nil {
-		return err
+
+	if !os.IsExist(err) {
+		fmt.Println(err)
+		os.Exit(-1)
 	}
 
-	tempfile := temp + filename
+	tempfile := temp + "/" + filename
 
 	// Create the file
+	tempfiles = append(tempfiles, tempfile)
 	out, err := os.Create(tempfile)
 	if err != nil {
-		return err
+		clean()
+		fmt.Println(err)
+		os.Exit(-1)
 	}
 	defer out.Close()
 
-	fmt.Println("Downloading Hugo...")
+	fmt.Print("Downloading Hugo from GitHub releases... ")
 
 	// Get the data
 	resp, err := http.Get(baseurl + filename)
 	if err != nil {
-		return err
+		fmt.Println("An error ocurred while downloading. If this error persists, try downloading Hugo from \"https://github.com/spf13/hugo/releases/\" and put the executable in " + bin + " and rename it to 'hugo' or 'hugo.exe' if you're on Windows.")
+		fmt.Println(err)
+		os.Exit(-1)
 	}
 	defer resp.Body.Close()
 
 	// Writer the body to file
 	_, err = io.Copy(out, resp.Body)
 	if err != nil {
-		return err
+		fmt.Println(err)
+		os.Exit(-1)
 	}
 
-	fmt.Println("Checking SHA256...")
-	// TODO: check sha256
+	fmt.Println("downloaded.")
+	fmt.Print("Checking SHA256...")
 
-	fmt.Println("Unziping...")
+	hasher := sha256.New()
+	f, err := os.Open(tempfile)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer f.Close()
+	if _, err := io.Copy(hasher, f); err != nil {
+		log.Fatal(err)
+	}
+
+	if hex.EncodeToString(hasher.Sum(nil)) != sha256Hash[filename] {
+		fmt.Println("can't verify SHA256.")
+		os.Exit(-1)
+	}
+
+	fmt.Println("checked!")
+	fmt.Print("Unziping... ")
 
 	// Unzip or Ungzip the file
 	switch runtime.GOOS {
 	case "darwin", "windows":
-		unzip(temp+filename, bin)
+		err = unzip(tempfile, bin)
 	default:
-		ungzip(temp+filename, bin)
+		err = ungzip(tempfile, bin)
 	}
 
-	fmt.Println("Removing temporary files...")
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(-1)
+	}
 
-	// Removes the temporary file and other files
-	os.Remove(tempfile)
-	os.Remove(bin + "README.md")
-	os.Remove(bin + "LICENSE.md")
+	fmt.Println("done.")
+
+	tempfiles = append(tempfiles, bin+"README.md", bin+"LICENSE.md")
+	clean()
+
+	ftorename := bin + strings.Replace(filename, ".tar.gz", "", 1)
 
 	if runtime.GOOS == "windows" {
-		os.Rename(bin+strings.Replace(filename, ".zip", ".exe", 1), bin+"hugo.exe")
-
-		fmt.Println("Hugo installed at " + filepath.Clean(bin) + "\\hugo.exe")
-		return nil
+		ftorename = bin + strings.Replace(filename, ".zip", ".exe", 1)
 	}
 
-	os.Rename(bin+strings.Replace(filename, ".tar.gz", "", 1), bin+"hugo")
-	fmt.Println("Hugo installed at " + filepath.Clean(bin) + "/hugo")
-	return nil
+	os.Rename(ftorename, hugo)
+	fmt.Println("Hugo installed at " + hugo)
+	return hugo
 }
 
 func unzip(archive, target string) error {
@@ -168,3 +229,13 @@ func ungzip(source, target string) error {
 	_, err = io.Copy(writer, archive)
 	return err
 }
+
+func clean() {
+	fmt.Print("Removing temporary files... ")
+
+	for _, file := range tempfiles {
+		os.Remove(file)
+	}
+
+	fmt.Println("done.")
+}