From 9e135967cb205637790ab934db8c2139424d2a8e Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 20 Feb 2016 11:31:59 +0000 Subject: [PATCH 01/18] call hugo as external command --- config/config.go | 1 - hugo.go | 29 +++++++++++++++-------------- utils/utils.go | 17 +++++++++++------ 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/config/config.go b/config/config.go index 20332902..ba8a817c 100644 --- a/config/config.go +++ b/config/config.go @@ -55,6 +55,5 @@ func ParseHugo(c *setup.Controller) (*Config, error) { } } - conf.Args = append([]string{"--source", conf.Path}, conf.Args...) return conf, nil } diff --git a/hugo.go b/hugo.go index 9d0b679c..c1736cc2 100644 --- a/hugo.go +++ b/hugo.go @@ -21,39 +21,40 @@ import ( "github.com/hacdias/caddy-hugo/utils" "github.com/mholt/caddy/caddy/setup" "github.com/mholt/caddy/middleware" - "github.com/spf13/cobra" - "github.com/spf13/hugo/commands" ) // Setup is the init function of Caddy plugins and it configures the whole // middleware thing. func Setup(c *setup.Controller) (middleware.Middleware, error) { + // TODO: install Hugo first? + config, _ := config.ParseHugo(c) // Checks if there is an Hugo website in the path that is provided. // If not, a new website will be created. - create := false + create := true - if _, err := os.Stat(config.Path + "config.yaml"); os.IsNotExist(err) { - create = true + if _, err := os.Stat(config.Path + "config.yaml"); err == nil { + create = false } - if _, err := os.Stat(config.Path + "config.json"); os.IsNotExist(err) { - create = true + if _, err := os.Stat(config.Path + "config.json"); err == nil { + create = false } - if _, err := os.Stat(config.Path + "config.toml"); os.IsNotExist(err) { - create = true + if _, err := os.Stat(config.Path + "config.toml"); err == nil { + create = false } if create { - cmd := &cobra.Command{} - cmd.Flags().Bool("force", true, "") - commands.NewSite(cmd, []string{config.Path}) + err := utils.RunCommand("hugo", []string{"new", "site", config.Path, "--force"}, ".") + if err != nil { + log.Panic(err) + } } // Generates the Hugo website for the first time the plugin is activated. - utils.Run(config) + go utils.Run(config) return func(next middleware.Handler) middleware.Handler { return &CaddyHugo{Next: next, Config: config} @@ -139,7 +140,7 @@ func (h CaddyHugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error // Whenever the header "X-Regenerate" is true, the website should be // regenerated. Used in edit and settings, for example. if r.Header.Get("X-Regenerate") == "true" { - utils.Run(h.Config) + go utils.Run(h.Config) } if err != nil { diff --git a/utils/utils.go b/utils/utils.go index bd9388f4..3f719bf2 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "os" + "os/exec" "reflect" "strings" "text/template" @@ -13,8 +14,6 @@ import ( "github.com/hacdias/caddy-hugo/assets" "github.com/hacdias/caddy-hugo/config" - "github.com/spf13/hugo/commands" - "github.com/spf13/viper" ) // CanBeEdited checks if the extension of a file is supported by the editor @@ -168,14 +167,20 @@ func ParseComponents(r *http.Request) []string { func Run(c *config.Config) { os.RemoveAll(c.Path + "public") - commands.MainSite = nil - viper.Reset() - commands.HugoCmd.ParseFlags(c.Args) - if err := commands.HugoCmd.RunE(nil, nil); err != nil { + if err := RunCommand("hugo", c.Args, c.Path); err != nil { log.Panic(err) } } +// RunCommand executes an external command +func RunCommand(command string, args []string, path string) error { + cmd := exec.Command(command, args...) + cmd.Dir = path + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + return cmd.Run() +} + var splitCapitalizeExceptions = map[string]string{ "youtube": "YouTube", "github": "GitHub", From 5fd7adec7a0e20d881725ac5ef8b2d5ee0b8a3cc Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 20 Feb 2016 12:04:12 +0000 Subject: [PATCH 02/18] close #47 --- browse/post.go | 57 ++++++++++++++++-------------------------------- config/config.go | 2 +- editor/post.go | 2 +- hugo.go | 4 ++-- utils/utils.go | 22 ++++++++++++++++++- 5 files changed, 44 insertions(+), 43 deletions(-) diff --git a/browse/post.go b/browse/post.go index 0c56cd7e..cbad12ba 100644 --- a/browse/post.go +++ b/browse/post.go @@ -49,51 +49,32 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) filename = strings.TrimSuffix(filename, "/") filename = c.Path + r.URL.Path + filename - // Check if the archetype is defined - if info["archetype"] != "" { - // Sanitize the archetype path + url := "/admin/edit/" + filename + + if strings.HasPrefix(filename, c.Path+"content/") && + (strings.HasSuffix(filename, ".md") || strings.HasSuffix(filename, ".markdown")) { + + filename = strings.Replace(filename, c.Path+"content/", "", 1) + args := []string{"new", filename} archetype := info["archetype"].(string) - archetype = strings.Replace(archetype, "/archetypes", "", 1) - archetype = strings.Replace(archetype, "archetypes", "", 1) - archetype = strings.TrimPrefix(archetype, "/") - archetype = strings.TrimSuffix(archetype, "/") - archetype = c.Path + "archetypes/" + archetype - // Check if the archetype ending with .markdown exists - if _, err := os.Stat(archetype + ".markdown"); err == nil { - err = utils.CopyFile(archetype+".markdown", filename) - if err != nil { - return http.StatusInternalServerError, err - } - - w.Header().Set("Location", "/admin/edit/"+filename) - w.Header().Set("Content-Type", "application/json") - w.Write([]byte("{}")) - return 201, nil + if archetype != "" { + args = append(args, "--kind", archetype) } - // Check if the archetype ending with .md exists - if _, err := os.Stat(archetype + ".md"); err == nil { - err = utils.CopyFile(archetype+".md", filename) - if err != nil { - return http.StatusInternalServerError, err - } - - w.Header().Set("Location", "/admin/edit/"+filename) - w.Header().Set("Content-Type", "application/json") - w.Write([]byte("{}")) - return 201, nil + if err := utils.RunCommand("hugo", args, c.Path); err != nil { + return http.StatusInternalServerError, err } + } else { + wf, err := os.Create(filename) + if err != nil { + return http.StatusInternalServerError, err + } + + defer wf.Close() } - wf, err := os.Create(filename) - if err != nil { - return http.StatusInternalServerError, err - } - - defer wf.Close() - - w.Header().Set("Location", "/admin/edit/"+filename) + w.Header().Set("Location", url) w.Header().Set("Content-Type", "application/json") w.Write([]byte("{}")) return http.StatusOK, nil diff --git a/config/config.go b/config/config.go index ba8a817c..bc177057 100644 --- a/config/config.go +++ b/config/config.go @@ -50,7 +50,7 @@ func ParseHugo(c *setup.Controller) (*Config, error) { value = c.Val() } - conf.Args = append(conf.Args, key, value) + conf.Args = append(conf.Args, key+"="+value) } } } diff --git a/editor/post.go b/editor/post.go index abba119d..0f6f1207 100644 --- a/editor/post.go +++ b/editor/post.go @@ -144,7 +144,7 @@ func parseCompleteFile(r *http.Request, c *config.Config, rawFile map[string]int return } - utils.Run(c) + go utils.Run(c, false) }) scheduler.Start() } diff --git a/hugo.go b/hugo.go index c1736cc2..a82da5e5 100644 --- a/hugo.go +++ b/hugo.go @@ -54,7 +54,7 @@ func Setup(c *setup.Controller) (middleware.Middleware, error) { } // Generates the Hugo website for the first time the plugin is activated. - go utils.Run(config) + go utils.Run(config, true) return func(next middleware.Handler) middleware.Handler { return &CaddyHugo{Next: next, Config: config} @@ -140,7 +140,7 @@ func (h CaddyHugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error // Whenever the header "X-Regenerate" is true, the website should be // regenerated. Used in edit and settings, for example. if r.Header.Get("X-Regenerate") == "true" { - go utils.Run(h.Config) + go utils.Run(h.Config, false) } if err != nil { diff --git a/utils/utils.go b/utils/utils.go index 3f719bf2..4a8d9cb1 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -164,9 +164,20 @@ func ParseComponents(r *http.Request) []string { } // Run is used to run the static website generator -func Run(c *config.Config) { +func Run(c *config.Config, force bool) { os.RemoveAll(c.Path + "public") + // Prevent running if watching is enabled + if b, pos := stringInSlice("--watch", c.Args); b && !force { + if len(c.Args) > pos && c.Args[pos+1] != "false" { + return + } + + if len(c.Args) == pos+1 { + return + } + } + if err := RunCommand("hugo", c.Args, c.Path); err != nil { log.Panic(err) } @@ -181,6 +192,15 @@ func RunCommand(command string, args []string, path string) error { return cmd.Run() } +func stringInSlice(a string, list []string) (bool, int) { + for i, b := range list { + if b == a { + return true, i + } + } + return false, 0 +} + var splitCapitalizeExceptions = map[string]string{ "youtube": "YouTube", "github": "GitHub", From 6bcae605f228e9d04eff2abd520625635660eb83 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 20 Feb 2016 12:04:38 +0000 Subject: [PATCH 03/18] close #45 --- hugo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugo.go b/hugo.go index a82da5e5..9a7f930d 100644 --- a/hugo.go +++ b/hugo.go @@ -26,7 +26,7 @@ import ( // Setup is the init function of Caddy plugins and it configures the whole // middleware thing. func Setup(c *setup.Controller) (middleware.Middleware, error) { - // TODO: install Hugo first? + // TODO: install Hugo first? add script config, _ := config.ParseHugo(c) From e8874fabf1951609a7db81ad11686a41f97b8927 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 20 Feb 2016 22:31:46 +0000 Subject: [PATCH 04/18] script to install Hugo - missing sha256 --- config/config.go | 24 ++++++ hugo.go | 2 - insthugo/insthugo.go | 170 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 insthugo/insthugo.go diff --git a/config/config.go b/config/config.go index bc177057..8776fa45 100644 --- a/config/config.go +++ b/config/config.go @@ -1,8 +1,14 @@ package config import ( + "fmt" + "log" + "os" + "os/user" + "runtime" "strings" + "github.com/hacdias/caddy-hugo/insthugo" "github.com/mholt/caddy/caddy/setup" ) @@ -12,13 +18,31 @@ type Config struct { Path string // Hugo files path Styles string // Admin styles path Args []string // Hugo arguments + Hugo string // Hugo executable path } // 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" + } + + if _, err := os.Stat(conf.Hugo); os.IsNotExist(err) { + fmt.Print("hey") + insthugo.Install() } for c.Next() { diff --git a/hugo.go b/hugo.go index 9a7f930d..0fb11db0 100644 --- a/hugo.go +++ b/hugo.go @@ -26,8 +26,6 @@ import ( // Setup is the init function of Caddy plugins and it configures the whole // middleware thing. func Setup(c *setup.Controller) (middleware.Middleware, error) { - // TODO: install Hugo first? add script - config, _ := config.ParseHugo(c) // Checks if there is an Hugo website in the path that is provided. diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go new file mode 100644 index 00000000..b3c050a7 --- /dev/null +++ b/insthugo/insthugo.go @@ -0,0 +1,170 @@ +package insthugo + +import ( + "archive/zip" + "compress/gzip" + "fmt" + "io" + "net/http" + "os" + "os/user" + "path/filepath" + "runtime" + "strings" +) + +const version = "0.15" + +// Install installs Hugo +func Install() error { + // Sets the base url from where to download + baseurl := "https://github.com/spf13/hugo/releases/download/v" + version + "/" + + // The default filename + filename := "hugo_" + version + "_" + runtime.GOOS + "_" + runtime.GOARCH + + switch runtime.GOOS { + case "darwin", "windows": + // At least for v0.15 version + if runtime.GOOS == "windows" && runtime.GOARCH == "386" { + filename += "32-bit-only" + } + + filename += ".zip" + default: + filename += ".tar.gz" + } + + // Gets the current user home directory and creates the .caddy dir + user, err := user.Current() + if err != nil { + return err + } + + path := user.HomeDir + "/.caddy/" + bin := path + "bin/" + temp := path + "temp/" + + err = os.MkdirAll(path, 0666) + err = os.Mkdir(bin, 0666) + err = os.Mkdir(temp, 0666) + if err != nil { + return err + } + + tempfile := temp + filename + + // Create the file + out, err := os.Create(tempfile) + if err != nil { + return err + } + defer out.Close() + + fmt.Println("Downloading Hugo...") + + // Get the data + resp, err := http.Get(baseurl + filename) + if err != nil { + return err + } + defer resp.Body.Close() + + // Writer the body to file + _, err = io.Copy(out, resp.Body) + if err != nil { + return err + } + + fmt.Println("Checking SHA256...") + // TODO: check sha256 + + fmt.Println("Unziping...") + + // Unzip or Ungzip the file + switch runtime.GOOS { + case "darwin", "windows": + unzip(temp+filename, bin) + default: + ungzip(temp+filename, bin) + } + + fmt.Println("Removing temporary files...") + + // Removes the temporary file and other files + os.Remove(tempfile) + os.Remove(bin + "README.md") + os.Remove(bin + "LICENSE.md") + + 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 + } + + os.Rename(bin+strings.Replace(filename, ".tar.gz", "", 1), bin+"hugo") + fmt.Println("Hugo installed at " + filepath.Clean(bin) + "/hugo") + return nil +} + +func unzip(archive, target string) error { + reader, err := zip.OpenReader(archive) + if err != nil { + return err + } + + if err := os.MkdirAll(target, 0755); err != nil { + return err + } + + for _, file := range reader.File { + path := filepath.Join(target, file.Name) + if file.FileInfo().IsDir() { + os.MkdirAll(path, file.Mode()) + continue + } + + fileReader, err := file.Open() + if err != nil { + return err + } + defer fileReader.Close() + + targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) + if err != nil { + return err + } + defer targetFile.Close() + + if _, err := io.Copy(targetFile, fileReader); err != nil { + return err + } + } + + return nil +} + +func ungzip(source, target string) error { + reader, err := os.Open(source) + if err != nil { + return err + } + defer reader.Close() + + archive, err := gzip.NewReader(reader) + if err != nil { + return err + } + defer archive.Close() + + target = filepath.Join(target, archive.Name) + writer, err := os.Create(target) + if err != nil { + return err + } + defer writer.Close() + + _, err = io.Copy(writer, archive) + return err +} From 454c59e8a36e70bb6054b9f30925b6e5f7011c6e Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 20 Feb 2016 22:33:10 +0000 Subject: [PATCH 05/18] update Hugo calls --- browse/post.go | 2 +- config/config.go | 5 +++-- hugo.go | 2 +- utils/utils.go | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/browse/post.go b/browse/post.go index cbad12ba..305a3d8f 100644 --- a/browse/post.go +++ b/browse/post.go @@ -62,7 +62,7 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) args = append(args, "--kind", archetype) } - if err := utils.RunCommand("hugo", args, c.Path); err != nil { + if err := utils.RunCommand(c.Hugo, args, c.Path); err != nil { return http.StatusInternalServerError, err } } else { diff --git a/config/config.go b/config/config.go index 8776fa45..35211f7b 100644 --- a/config/config.go +++ b/config/config.go @@ -1,10 +1,10 @@ package config import ( - "fmt" "log" "os" "os/user" + "path/filepath" "runtime" "strings" @@ -40,8 +40,9 @@ func ParseHugo(c *setup.Controller) (*Config, error) { conf.Hugo += ".exe" } + conf.Hugo = filepath.Clean(conf.Hugo) + if _, err := os.Stat(conf.Hugo); os.IsNotExist(err) { - fmt.Print("hey") insthugo.Install() } diff --git a/hugo.go b/hugo.go index 0fb11db0..001d0cb5 100644 --- a/hugo.go +++ b/hugo.go @@ -45,7 +45,7 @@ func Setup(c *setup.Controller) (middleware.Middleware, error) { } if create { - err := utils.RunCommand("hugo", []string{"new", "site", config.Path, "--force"}, ".") + err := utils.RunCommand(config.Hugo, []string{"new", "site", config.Path, "--force"}, ".") if err != nil { log.Panic(err) } diff --git a/utils/utils.go b/utils/utils.go index 4a8d9cb1..5f2f7cf6 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -178,7 +178,7 @@ func Run(c *config.Config, force bool) { } } - if err := RunCommand("hugo", c.Args, c.Path); err != nil { + if err := RunCommand(c.Hugo, c.Args, c.Path); err != nil { log.Panic(err) } } From def3c333323e8b36ecf54110875d1b17e5a0376b Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 21 Feb 2016 11:51:31 +0000 Subject: [PATCH 06/18] 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.") +} From 69dc0be7ed8915742d28a0252e53839158fd21d8 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 21 Feb 2016 11:55:11 +0000 Subject: [PATCH 07/18] fix bug --- insthugo/insthugo.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index 642ac595..c3f5124f 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -26,7 +26,7 @@ var ( tempfiles []string filename = "hugo_" + version + "_" + runtime.GOOS + "_" + runtime.GOARCH sha256Hash = map[string]string{ - "hugo_0.15_darwin_386.zip": "", + "hugo_0.15_darwin_386.zip": "f9b7353f9b64e7aece5f7981e5aa97dc4b31974ce76251edc070e77691bc03e2", "hugo_0.15_darwin_amd64.zip": "", "hugo_0.15_dragonfly_amd64.zip": "", "hugo_0.15_freebsd_386.zip": "", @@ -155,13 +155,13 @@ func Install() string { fmt.Println("done.") - tempfiles = append(tempfiles, bin+"README.md", bin+"LICENSE.md") + tempfiles = append(tempfiles, bin+"/README.md", bin+"/LICENSE.md") clean() - ftorename := bin + strings.Replace(filename, ".tar.gz", "", 1) + ftorename := bin + "/" + strings.Replace(filename, ".tar.gz", "", 1) if runtime.GOOS == "windows" { - ftorename = bin + strings.Replace(filename, ".zip", ".exe", 1) + ftorename = bin + "/" + strings.Replace(filename, ".zip", ".exe", 1) } os.Rename(ftorename, hugo) From 1ceca4ed7a0c5998b76dc41121ea475ee9a96e70 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 21 Feb 2016 20:09:16 +0000 Subject: [PATCH 08/18] add all sha256 --- insthugo/insthugo.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index c3f5124f..a91aca14 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -27,19 +27,19 @@ var ( filename = "hugo_" + version + "_" + runtime.GOOS + "_" + runtime.GOARCH sha256Hash = map[string]string{ "hugo_0.15_darwin_386.zip": "f9b7353f9b64e7aece5f7981e5aa97dc4b31974ce76251edc070e77691bc03e2", - "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_darwin_amd64.zip": "aeecd6a12d86ab920f5b04e9486474bbe478dc246cdc2242799849b84c61c6f1", + "hugo_0.15_dragonfly_amd64.zip": "e380343789f2b2e0c366c8e1eeb251ccd90eea53dac191ff85d8177b130e53bc", + "hugo_0.15_freebsd_386.zip": "98f9210bfa3dcb48bd154879ea1cfe1b0ed8a3d891fdeacbdb4c3fc69b72aac4", + "hugo_0.15_freebsd_amd64.zip": "aa6a3028899e76e6920b9b5a64c29e14017ae34120efa67276e614e3a69cb100", + "hugo_0.15_freebsd_arm.zip": "de52e1b07caf778bdc3bdb07f39119cd5a1739c8822ebe311cd4f667c43588ac", + "hugo_0.15_linux_386.tar.gz": "af28c4cbb16db765535113f361a38b2249c634ce2d3798dcf5b795de6e4b7ecf", + "hugo_0.15_linux_amd64.tar.gz": "32a6335bd76f72867efdec9306a8a7eb7b9498a2e0478105efa96c1febadb09b", + "hugo_0.15_linux_arm.tar.gz": "886dd1a843c057a46c541011183dd558469250580e81450eedbd1a4d041e9234", + "hugo_0.15_netbsd_386.zip": "6245f5db16b33a09466f149d5b7b68a7899d6d624903de9e7e70c4b6ea869a72", + "hugo_0.15_netbsd_amd64.zip": "103ea8d81d2a3d707c05e3dd68c98fcf8146ddd36b49bf0e65d9874cee230c88", + "hugo_0.15_netbsd_arm.zip": "9c9b5cf4ea3b6169be1b5fc924251a247d9c140dd8a45aa5175031878585ff0a", + "hugo_0.15_openbsd_386.zip": "81dfdb3048a27a61b249650241fe4e8da1eda31a3a7311c615eb419f1cdd06b1", + "hugo_0.15_openbsd_amd64.zip": "e7447cde0dd7628b05b25b86938018774d8db8156ab1330b364e0e2c6501ad87", "hugo_0.15_windows_386_32-bit-only.zip": "0a72f9a1a929f36c0e52fb1c6272b4d37a2bd1a6bd19ce57a6e7b6803b434756", "hugo_0.15_windows_amd64.zip": "9f03602e48ae2199e06431d7436fb3b9464538c0d44aac9a76eb98e1d4d5d727", } From a3c9fc2545ddc214229af00cd6eb0f0c7cecd60d Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 21 Feb 2016 20:15:07 +0000 Subject: [PATCH 09/18] update license --- LICENSE.md | 214 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 197 insertions(+), 17 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 19fd5dc3..5e0fd33c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,21 +1,201 @@ -The MIT License (MIT) +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ -Copyright (c) 2015 - 2016 Henrique Dias +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +1. Definitions. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "{}" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright {yyyy} {name of copyright owner} + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. From 7a929b736c09e44b6905dcd74422db79fea74ca9 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Mon, 22 Feb 2016 21:21:01 +0000 Subject: [PATCH 10/18] update file perm --- insthugo/insthugo.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index a91aca14..7640f3a9 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -80,9 +80,9 @@ func Install() string { fmt.Println("Unable to find Hugo on " + caddy) - err = os.MkdirAll(caddy, 0666) - err = os.Mkdir(bin, 0666) - err = os.Mkdir(temp, 0666) + err = os.MkdirAll(caddy, 0774) + err = os.Mkdir(bin, 0774) + err = os.Mkdir(temp, 0774) if !os.IsExist(err) { fmt.Println(err) @@ -94,6 +94,7 @@ func Install() string { // Create the file tempfiles = append(tempfiles, tempfile) out, err := os.Create(tempfile) + out.Chmod(0774) if err != nil { clean() fmt.Println(err) From b30079509d59c4f3e8bf316f29d7ffd1c9acf5a5 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Mon, 22 Feb 2016 21:30:38 +0000 Subject: [PATCH 11/18] update --- insthugo/insthugo.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index 7640f3a9..46a069cc 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -84,13 +84,10 @@ func Install() string { err = os.Mkdir(bin, 0774) err = os.Mkdir(temp, 0774) - if !os.IsExist(err) { - fmt.Println(err) - os.Exit(-1) - } - tempfile := temp + "/" + filename + fmt.Print("Downloading Hugo from GitHub releases... ") + // Create the file tempfiles = append(tempfiles, tempfile) out, err := os.Create(tempfile) @@ -102,8 +99,6 @@ func Install() string { } defer out.Close() - fmt.Print("Downloading Hugo from GitHub releases... ") - // Get the data resp, err := http.Get(baseurl + filename) if err != nil { From 1da6363db711a04871f63e295be3b66dd2190b09 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Mon, 22 Feb 2016 21:34:52 +0000 Subject: [PATCH 12/18] darwin patch --- insthugo/insthugo.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index 46a069cc..f5278204 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -156,6 +156,10 @@ func Install() string { ftorename := bin + "/" + strings.Replace(filename, ".tar.gz", "", 1) + if runtime.GOOS == "darwin" { + ftorename = bin + "/" + strings.Replace(filename, ".zip", "", 1) + } + if runtime.GOOS == "windows" { ftorename = bin + "/" + strings.Replace(filename, ".zip", ".exe", 1) } From e9b13f961bda8fd474ddd0e8ed2f607b55d2f2f7 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Mon, 22 Feb 2016 21:37:47 +0000 Subject: [PATCH 13/18] update install script --- insthugo/insthugo.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index f5278204..f2f8d24f 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -154,17 +154,24 @@ func Install() string { tempfiles = append(tempfiles, bin+"/README.md", bin+"/LICENSE.md") clean() - ftorename := bin + "/" + strings.Replace(filename, ".tar.gz", "", 1) + ftorename := bin + "/" - if runtime.GOOS == "darwin" { - ftorename = bin + "/" + strings.Replace(filename, ".zip", "", 1) + switch runtime.GOOS { + case "darwin": + ftorename += strings.Replace(filename, ".zip", "", 1) + case "windows": + ftorename += strings.Replace(filename, ".zip", ".exe", 1) + default: + ftorename += strings.Replace(filename, ".tar.gz", "", 1) } - if runtime.GOOS == "windows" { - ftorename = bin + "/" + strings.Replace(filename, ".zip", ".exe", 1) + err = os.Rename(ftorename, hugo) + + if err != nil { + fmt.Println(err) + os.Exit(-1) } - os.Rename(ftorename, hugo) fmt.Println("Hugo installed at " + hugo) return hugo } From e7369b17b5bef42948bd4602fbe47cb81812519e Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Mon, 22 Feb 2016 21:49:09 +0000 Subject: [PATCH 14/18] update filepath Joins --- insthugo/insthugo.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index f2f8d24f..f82c0ba7 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -53,10 +53,10 @@ func Install() string { os.Exit(-1) } - caddy := filepath.Clean(usr.HomeDir + "/.caddy/") - bin := filepath.Clean(caddy + "/bin") - temp := filepath.Clean(caddy + "/temp") - hugo := filepath.Clean(bin + "/hugo") + caddy := filepath.Join(usr.HomeDir, ".caddy") + bin := filepath.Join(caddy, "bin") + temp := filepath.Join(caddy, "temp") + hugo := filepath.Join(bin, "hugo") switch runtime.GOOS { case "darwin": @@ -84,7 +84,7 @@ func Install() string { err = os.Mkdir(bin, 0774) err = os.Mkdir(temp, 0774) - tempfile := temp + "/" + filename + tempfile := filepath.Join(temp, filename) fmt.Print("Downloading Hugo from GitHub releases... ") @@ -151,7 +151,7 @@ func Install() string { fmt.Println("done.") - tempfiles = append(tempfiles, bin+"/README.md", bin+"/LICENSE.md") + tempfiles = append(tempfiles, filepath.Join(bin, "README.md"), filepath.Join(bin, "LICENSE.md")) clean() ftorename := bin + "/" From 2c5d6f3d4eb467a8c818480f7f692a39e1db5b82 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 23 Feb 2016 20:16:56 +0000 Subject: [PATCH 15/18] improvements on installHugo script --- config/config.go | 2 +- insthugo/insthugo.go | 164 +++++++++++++++++++++++-------------------- 2 files changed, 90 insertions(+), 76 deletions(-) diff --git a/config/config.go b/config/config.go index 23b4bce6..45a2906e 100644 --- a/config/config.go +++ b/config/config.go @@ -23,7 +23,7 @@ func ParseHugo(c *setup.Controller) (*Config, error) { Path: "./", } - conf.Hugo = insthugo.Install() + conf.Hugo = insthugo.GetPath() for c.Next() { args := c.RemainingArgs() diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index f82c0ba7..3f7c24e7 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -13,7 +13,6 @@ import ( "os/user" "path/filepath" "runtime" - "strings" ) const ( @@ -22,10 +21,8 @@ const ( ) var ( - usr user.User - tempfiles []string - filename = "hugo_" + version + "_" + runtime.GOOS + "_" + runtime.GOARCH - sha256Hash = map[string]string{ + caddy, bin, temp, hugo, tempfile, zipname, exename string + sha256Hash = map[string]string{ "hugo_0.15_darwin_386.zip": "f9b7353f9b64e7aece5f7981e5aa97dc4b31974ce76251edc070e77691bc03e2", "hugo_0.15_darwin_amd64.zip": "aeecd6a12d86ab920f5b04e9486474bbe478dc246cdc2242799849b84c61c6f1", "hugo_0.15_dragonfly_amd64.zip": "e380343789f2b2e0c366c8e1eeb251ccd90eea53dac191ff85d8177b130e53bc", @@ -45,51 +42,109 @@ var ( } ) -// Install installs Hugo -func Install() string { +// GetPath retrives the Hugo path for the user or install it if it's not found +func GetPath() string { + initializeVariables() + + /* // Check if Hugo is already on $PATH + if hugo, err := exec.LookPath("hugo"); err == nil { + return hugo + } */ + + // Check if Hugo is on $HOME/.caddy/bin + if _, err := os.Stat(hugo); err == nil { + return hugo + } + + fmt.Println("Unable to find Hugo on your computer.") + + // Create the neccessary folders + os.MkdirAll(caddy, 0774) + os.Mkdir(bin, 0774) + os.Mkdir(temp, 0774) + + downloadHugo() + checkSHA256() + + fmt.Print("Unziping... ") + + var err error + + // Unzip or Ungzip the file + switch runtime.GOOS { + case "darwin", "windows": + err = unzip(tempfile, temp) + default: + err = ungzip(tempfile, temp) + } + + if err != nil { + fmt.Println(err) + os.Exit(-1) + } + + fmt.Println("done.") + + var exetorename string + + err = filepath.Walk(temp, func(path string, f os.FileInfo, err error) error { + if f.Name() == exename { + exetorename = path + } + + return nil + }) + + err = os.Rename(exetorename, hugo) + + if err != nil { + fmt.Println(err) + os.Exit(-1) + } + + fmt.Println("Hugo installed at " + hugo) + clean() + return hugo +} + +func initializeVariables() { + exename = "hugo_" + version + "_" + runtime.GOOS + "_" + runtime.GOARCH + zipname = exename + usr, err := user.Current() if err != nil { fmt.Println(err) os.Exit(-1) } - caddy := filepath.Join(usr.HomeDir, ".caddy") - bin := filepath.Join(caddy, "bin") - temp := filepath.Join(caddy, "temp") - hugo := filepath.Join(bin, "hugo") + caddy = filepath.Join(usr.HomeDir, ".caddy") + bin = filepath.Join(caddy, "bin") + temp = filepath.Join(caddy, "temp") + hugo = filepath.Join(bin, "hugo") switch runtime.GOOS { case "darwin": - filename += ".zip" + zipname += ".zip" case "windows": // At least for v0.15 version if runtime.GOARCH == "386" { - filename += "32-bit-only" + zipname += "32-bit-only" } - filename += ".zip" + zipname += ".zip" + exename += ".exe" hugo += ".exe" default: - filename += ".tar.gz" + zipname += ".tar.gz" } +} - // Check if Hugo is already installed - if _, err := os.Stat(hugo); err == nil { - return hugo - } - - fmt.Println("Unable to find Hugo on " + caddy) - - err = os.MkdirAll(caddy, 0774) - err = os.Mkdir(bin, 0774) - err = os.Mkdir(temp, 0774) - - tempfile := filepath.Join(temp, filename) +func downloadHugo() { + tempfile = filepath.Join(temp, zipname) fmt.Print("Downloading Hugo from GitHub releases... ") // Create the file - tempfiles = append(tempfiles, tempfile) out, err := os.Create(tempfile) out.Chmod(0774) if err != nil { @@ -100,7 +155,7 @@ func Install() string { defer out.Close() // Get the data - resp, err := http.Get(baseurl + filename) + resp, err := http.Get(baseurl + zipname) if err != nil { 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) @@ -116,6 +171,9 @@ func Install() string { } fmt.Println("downloaded.") +} + +func checkSHA256() { fmt.Print("Checking SHA256...") hasher := sha256.New() @@ -128,52 +186,12 @@ func Install() string { log.Fatal(err) } - if hex.EncodeToString(hasher.Sum(nil)) != sha256Hash[filename] { + if hex.EncodeToString(hasher.Sum(nil)) != sha256Hash[zipname] { 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": - err = unzip(tempfile, bin) - default: - err = ungzip(tempfile, bin) - } - - if err != nil { - fmt.Println(err) - os.Exit(-1) - } - - fmt.Println("done.") - - tempfiles = append(tempfiles, filepath.Join(bin, "README.md"), filepath.Join(bin, "LICENSE.md")) - clean() - - ftorename := bin + "/" - - switch runtime.GOOS { - case "darwin": - ftorename += strings.Replace(filename, ".zip", "", 1) - case "windows": - ftorename += strings.Replace(filename, ".zip", ".exe", 1) - default: - ftorename += strings.Replace(filename, ".tar.gz", "", 1) - } - - err = os.Rename(ftorename, hugo) - - if err != nil { - fmt.Println(err) - os.Exit(-1) - } - - fmt.Println("Hugo installed at " + hugo) - return hugo } func unzip(archive, target string) error { @@ -239,10 +257,6 @@ func ungzip(source, target string) error { func clean() { fmt.Print("Removing temporary files... ") - - for _, file := range tempfiles { - os.Remove(file) - } - + os.RemoveAll(temp) fmt.Println("done.") } From b873605bad6b4f5623487735595b7f2221482d3b Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 23 Feb 2016 20:30:17 +0000 Subject: [PATCH 16/18] uncomment if --- insthugo/insthugo.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index 3f7c24e7..19f68bfe 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -10,6 +10,7 @@ import ( "log" "net/http" "os" + "os/exec" "os/user" "path/filepath" "runtime" @@ -46,10 +47,10 @@ var ( func GetPath() string { initializeVariables() - /* // Check if Hugo is already on $PATH - if hugo, err := exec.LookPath("hugo"); err == nil { - return hugo - } */ + // Check if Hugo is already on $PATH + if hugo, err := exec.LookPath("hugo"); err == nil { + return hugo + } // Check if Hugo is on $HOME/.caddy/bin if _, err := os.Stat(hugo); err == nil { From 6140e6ca1f285ae3210b2f5f876cfe52158d4bc9 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 25 Feb 2016 19:22:40 +0000 Subject: [PATCH 17/18] fix OS X unzipping --- insthugo/insthugo.go | 71 ++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/insthugo/insthugo.go b/insthugo/insthugo.go index 19f68bfe..36da229a 100644 --- a/insthugo/insthugo.go +++ b/insthugo/insthugo.go @@ -195,38 +195,63 @@ func checkSHA256() { fmt.Println("checked!") } -func unzip(archive, target string) error { - reader, err := zip.OpenReader(archive) +func unzip(src, dest string) error { + r, err := zip.OpenReader(src) if err != nil { return err } + defer func() { + if err := r.Close(); err != nil { + panic(err) + } + }() - if err := os.MkdirAll(target, 0755); err != nil { - return err + os.MkdirAll(dest, 0755) + + // Closure to address file descriptors issue with all the deferred .Close() methods + extractAndWriteFile := func(f *zip.File) error { + rc, err := f.Open() + if err != nil { + return err + } + defer func() { + if err := rc.Close(); err != nil { + panic(err) + } + }() + + path := filepath.Join(dest, f.Name) + + if f.FileInfo().IsDir() { + os.MkdirAll(path, f.Mode()) + } else { + if _, err := os.Stat(filepath.Dir(path)); os.IsNotExist(err) { + os.MkdirAll(filepath.Dir(path), 0755) + } + + f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + defer func() { + if err := f.Close(); err != nil { + panic(err) + } + }() + _, err = io.Copy(f, rc) + + if err != nil { + return err + } + } + return nil } - for _, file := range reader.File { - path := filepath.Join(target, file.Name) - if file.FileInfo().IsDir() { - os.MkdirAll(path, file.Mode()) - continue - } - - fileReader, err := file.Open() + for _, f := range r.File { + err := extractAndWriteFile(f) if err != nil { return err } - defer fileReader.Close() - - targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) - if err != nil { - return err - } - defer targetFile.Close() - - if _, err := io.Copy(targetFile, fileReader); err != nil { - return err - } } return nil From aa319618928a03afeb6d6794955a55d4fb6796d9 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 25 Feb 2016 20:02:06 +0000 Subject: [PATCH 18/18] fix #55 --- assets/js/app.min.js | 2 +- assets/js/plugins.min.js | 10 +++++----- assets/src/js/browse.js | 2 +- browse/post.go | 23 +++++++++++++++++------ 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/assets/js/app.min.js b/assets/js/app.min.js index da15855d..2adeea8b 100644 --- a/assets/js/app.min.js +++ b/assets/js/app.min.js @@ -1 +1 @@ -$(document).ready(function(){$("#logout").click(function(a){return a.preventDefault(),$.ajax({type:"GET",url:"/admin",async:!1,username:"username",password:"password",headers:{Authorization:"Basic xxx"}}).fail(function(){window.location="/"}),!1}),$(document).pjax("a[data-pjax]","#content")}),$(document).on("ready pjax:end",function(){function a(){this.style.height="5px",this.style.height=this.scrollHeight+"px"}return $("#content").off(),document.title=document.getElementById("site-title").innerHTML,$("textarea").each(a),$("textarea").keyup(a),$(window).resize(function(){$("textarea").each(a)}),$("main").hasClass("browse")&&$(document).trigger("page:browse"),$(".editor")[0]&&$(document).trigger("page:editor"),!1}),$(document).on("page:browse",function(){var a="#foreground",b=new Object;b.selector="form#delete",b.form=$(b.selector),b.row="",b.button="",b.url="",$("#content").on("click",".delete",function(c){return c.preventDefault(),b.button=$(this),b.row=$(this).parent().parent(),$(a).fadeIn(200),b.url=b.row.find(".filename").text(),b.form.find("span").text(b.url),b.form.fadeIn(200),!1}),$("#content").on("submit",b.selector,function(c){return c.preventDefault(),$.ajax({type:"DELETE",url:b.button.data("file")}).done(function(c){$(a).fadeOut(200),b.form.fadeOut(200),b.row.fadeOut(200),notification({text:b.button.data("message"),type:"success",timeout:5e3})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("change",'input[type="file"]',function(a){a.preventDefault(),files=a.target.files;var b=new FormData;return $.each(files,function(a,c){b.append(a,c)}),$.ajax({url:window.location.pathname,type:"POST",data:b,cache:!1,dataType:"json",headers:{"X-Upload":"true"},processData:!1,contentType:!1}).done(function(a){notification({text:"File(s) uploaded successfully.",type:"success",timeout:5e3}),$.pjax({url:window.location.pathname,container:"#content"})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("click","#upload",function(a){return a.preventDefault(),$('.actions input[type="file"]').click(),!1});var c=new Object;c.selector="form#new",c.form=$(c.selector),c.input=c.selector+' input[type="text"]',c.button="",c.url="",$("#content").on("click",".new",function(b){return b.preventDefault(),c.button=$(this),$(a).fadeIn(200),c.form.fadeIn(200),!1}),$("#content").on("keypress",c.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(c.form).submit(),!1):void 0}),$("#content").on("submit",c.selector,function(a){a.preventDefault();var b=c.form.find('input[type="text"]').val(),d=b.split(":"),e="",f="";if(""==b)return notification({text:"You have to write something. If you want to close the box, click the button again.",type:"warning",timeout:5e3}),!1;if(1==d.length)e=b;else{if(2!=d.length)return notification({text:"Hmm... I don't understand you. Try writing something like 'name[:archetype]'.",type:"error"}),!1;e=d[0],f=d[1]}var g='{"filename": "'+e+'", "archetype": "'+f+'"}';return $.ajax({type:"POST",url:window.location.pathname,data:g,dataType:"json",encode:!0}).done(function(a){notification({text:"File created successfully.",type:"success",timeout:5e3}),$.pjax({url:window.location.pathname.replace("browse","edit")+e,container:"#content"})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1});var d=new Object;d.selector="form#rename",d.form=$(d.selector),d.input=d.selector+' input[type="text"]',d.button="",d.url="",$("#content").on("click",".rename",function(b){return b.preventDefault(),d.button=$(this),$(a).fadeIn(200),d.url=$(this).parent().parent().find(".filename").text(),d.form.fadeIn(200),d.form.find("span").text(d.url),d.form.find('input[type="text"]').val(d.url),!1}),$("#content").on("keypress",d.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(d.form).submit(),!1):void 0}),$("#content").on("submit",d.selector,function(a){a.preventDefault();var b=d.form.find('input[type="text"]').val();if(""===b)return!1;"/"!=b.substring(0,1)&&(b=window.location.pathname.replace("/admin/browse/","")+"/"+b);var c='{"filename": "'+b+'"}';return $.ajax({type:"PUT",url:d.url,data:c,dataType:"json",encode:!0}).done(function(a){$.pjax({url:window.location.pathname,container:"#content"}),notification({text:d.button.data("message"),type:"success",timeout:5e3})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("click",".close",function(b){return b.preventDefault(),$(this).parent().parent().fadeOut(200),$(a).click(),!1}),$("#content").on("click",a,function(e){return e.preventDefault(),$(a).fadeOut(200),c.form.fadeOut(200),d.form.fadeOut(200),b.form.fadeOut(200),!1})}),$(document).on("page:editor",function(){var a=$(".editor"),b=$("#editor-preview"),c=$("#editor-source");if(a.hasClass("complete")&&$("#content").on("keyup","#site-title",function(){$(".frontmatter #title").val($(this).val())}),!a.hasClass("frontmatter-only")){var d=$("#editor-source").data("mode"),e=$('textarea[name="content"]').hide(),f=ace.edit("editor-source");f.getSession().setMode("ace/mode/"+d),f.getSession().setValue(e.val()),f.getSession().on("change",function(){e.val(f.getSession().getValue())}),f.setOptions({wrap:!0,maxLines:1/0,theme:"ace/theme/github",showPrintMargin:!1,fontSize:"1em",minLines:20}),$("#content").on("click","#see-source",function(a){a.preventDefault(),b.hide(),c.fadeIn(),$(this).addClass("active"),$("#see-preview").removeClass("active"),$("#see-preview").data("previewing","false")}),$("#content").on("click","#see-preview",function(a){if(a.preventDefault(),"true"==$(this).data("previewing"))b.hide(),c.fadeIn(),$(this).removeClass("active"),$("#see-source").addClass("active"),$(this).data("previewing","false");else{var d=new showdown.Converter,e=f.getValue(),g=d.makeHtml(e);c.hide(),b.html(g).fadeIn(),$(this).addClass("active"),$("#see-source").removeClass("active"),$(this).data("previewing","true")}return!1})}$("#content").on("keypress","input",function(a){return 13==a.keyCode?(a.preventDefault(),$('input[value="Save"]').focus().click(),!1):void 0}),$("#content").on("submit","form",function(d){d.preventDefault(),a.hasClass("frontmatter-only")||(b.html("").fadeOut(),$("#see-preview").data("previewing","false"),c.fadeIn());var e=JSON.stringify($(this).serializeJSON()),f=$(this).find("input[type=submit]:focus");return $.ajax({type:"POST",url:window.location,data:e,headers:{"X-Regenerate":f.data("regenerate"),"X-Schedule":f.data("schedule"),"X-Content-Type":f.data("type")},dataType:"json",encode:!0,contentType:"application/json; charset=utf-8"}).done(function(a){notification({text:f.data("message"),type:"success",timeout:5e3})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("click",".add",function(a){if(a.preventDefault(),defaultID="lorem-ipsum-sin-dolor-amet",newItem=$("#"+defaultID),newItem.length&&newItem.remove(),block=$(this).parent().parent(),blockType=block.data("type"),blockID=block.attr("id"),"array"==blockType&&(newID=blockID+"[]",input=blockID,input=input.replace(/\[/,"\\["),input=input.replace(/\]/,"\\]"),block.append('
div").length+'" data-type="array-item">
'),console.log("New array item added.")),block.is("div")&&block.hasClass("frontmatter")&&(block=$(".blocks"),blockType="object"),"object"==blockType){if(block.append('
'),newItem=$("#"+defaultID),newItem.html(''),field=$("#name-"+defaultID),!document.cookie.replace(/(?:(?:^|.*;\s*)placeholdertip\s*\=\s*([^;]*).*$)|^.*$/,"$1")){var b=new Date;b.setDate(b.getDate()+365),document.cookie="placeholdertip=true; expires="+b.toUTCString+"; path=/",notification({text:'Write the field name and then press enter. If you want to create an array or an object, end the name with ":array" or ":object".',type:"information"})}$(field).keypress(function(a){return 13==a.which?(a.preventDefault(),value=field.val(),""==value?(newItem.remove(),!1):(elements=value.split(":"),elements.length>2?(notification({text:"Invalid syntax. It must be 'name[:type]'.",type:"error"}),!1):2==elements.length&&"array"!=elements[1]&&"object"!=elements[1]?(notification({text:"Only arrays and objects are allowed.",type:"error"}),!1):(field.remove(),"undefined"==typeof blockID?blockID=elements[0]:blockID=blockID+"["+elements[0]+"]",1==elements.length?(newItem.attr("id","block-"+blockID),newItem.append('
'),newItem.prepend(' ')):(type="","array"==elements[1]?type="array":type="object",template='

${elements[0]}

',template=template.replace("${blockID}",blockID),template=template.replace("${elements[0]}",elements[0]),template=template.replace("${type}",type),newItem.after(template),newItem.remove(),console.log('"'+blockID+'" block of type "'+type+'" added.')),!1))):void 0})}return!1}),$("#content").on("click",".delete",function(a){return a.preventDefault(),button=$(this),name=button.parent().parent().attr("for")||button.parent().parent().attr("id")||button.parent().parent().parent().attr("id"),name=name.replace(/\[/,"\\["),name=name.replace(/\]/,"\\]"),console.log(name),$('label[for="'+name+'"]').fadeOut().remove(),$("#"+name).fadeOut().remove(),!1})}),$.noty.themes.admin={name:"admin",helpers:{},modal:{css:{position:"fixed",width:"100%",height:"100%",backgroundColor:"#000",zIndex:1e4,opacity:.6,display:"none",left:0,top:0}}},$.noty.defaults={layout:"topRight",theme:"admin",dismissQueue:!0,animation:{open:"animated bounceInRight",close:"animated fadeOut",easing:"swing",speed:500},timeout:!1,force:!1,modal:!1,maxVisible:5,killer:!1,closeWith:["click"],callback:{onShow:function(){},afterShow:function(){},onClose:function(){},afterClose:function(){},onCloseClick:function(){}},buttons:!1},notification=function(a){var b;switch(a.type){case"success":b='';break;case"error":b='';break;case"warning":b='';break;case"information":b='';break;default:b=''}var c={template:'
'+b+'
'};if(a=$.extend({},c,a),noty(a),!document.cookie.replace(/(?:(?:^|.*;\s*)stickynoties\s*\=\s*([^;]*).*$)|^.*$/,"$1")&&!a.timeout){var d=new Date;d.setDate(d.getDate()+365),document.cookie="stickynoties=true; expires="+d.toUTCString+"; path=/",notification({text:"Some notifications are sticky. If it doesn't go away, click to dismiss it.",type:"information"})}}; \ No newline at end of file +$(document).ready(function(){$("#logout").click(function(a){return a.preventDefault(),$.ajax({type:"GET",url:"/admin",async:!1,username:"username",password:"password",headers:{Authorization:"Basic xxx"}}).fail(function(){window.location="/"}),!1}),$(document).pjax("a[data-pjax]","#content")}),$(document).on("ready pjax:end",function(){function a(){this.style.height="5px",this.style.height=this.scrollHeight+"px"}return $("#content").off(),document.title=document.getElementById("site-title").innerHTML,$("textarea").each(a),$("textarea").keyup(a),$(window).resize(function(){$("textarea").each(a)}),$("main").hasClass("browse")&&$(document).trigger("page:browse"),$(".editor")[0]&&$(document).trigger("page:editor"),!1}),$(document).on("page:browse",function(){var a="#foreground",b=new Object;b.selector="form#delete",b.form=$(b.selector),b.row="",b.button="",b.url="",$("#content").on("click",".delete",function(c){return c.preventDefault(),b.button=$(this),b.row=$(this).parent().parent(),$(a).fadeIn(200),b.url=b.row.find(".filename").text(),b.form.find("span").text(b.url),b.form.fadeIn(200),!1}),$("#content").on("submit",b.selector,function(c){return c.preventDefault(),$.ajax({type:"DELETE",url:b.button.data("file")}).done(function(c){$(a).fadeOut(200),b.form.fadeOut(200),b.row.fadeOut(200),notification({text:b.button.data("message"),type:"success",timeout:5e3})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("change",'input[type="file"]',function(a){a.preventDefault(),files=a.target.files;var b=new FormData;return $.each(files,function(a,c){b.append(a,c)}),$.ajax({url:window.location.pathname,type:"POST",data:b,cache:!1,dataType:"json",headers:{"X-Upload":"true"},processData:!1,contentType:!1}).done(function(a){notification({text:"File(s) uploaded successfully.",type:"success",timeout:5e3}),$.pjax({url:window.location.pathname,container:"#content"})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("click","#upload",function(a){return a.preventDefault(),$('.actions input[type="file"]').click(),!1});var c=new Object;c.selector="form#new",c.form=$(c.selector),c.input=c.selector+' input[type="text"]',c.button="",c.url="",$("#content").on("click",".new",function(b){return b.preventDefault(),c.button=$(this),$(a).fadeIn(200),c.form.fadeIn(200),!1}),$("#content").on("keypress",c.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(c.form).submit(),!1):void 0}),$("#content").on("submit",c.selector,function(a){a.preventDefault();var b=c.form.find('input[type="text"]').val(),d=b.split(":"),e="",f="";if(""==b)return notification({text:"You have to write something. If you want to close the box, click the button again.",type:"warning",timeout:5e3}),!1;if(1==d.length)e=b;else{if(2!=d.length)return notification({text:"Hmm... I don't understand you. Try writing something like 'name[:archetype]'.",type:"error"}),!1;e=d[0],f=d[1]}var g='{"filename": "'+e+'", "archetype": "'+f+'"}';return $.ajax({type:"POST",url:window.location.pathname,data:g,dataType:"json",encode:!0}).done(function(a){notification({text:"File created successfully.",type:"success",timeout:5e3}),$.pjax({url:a.Location,container:"#content"})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1});var d=new Object;d.selector="form#rename",d.form=$(d.selector),d.input=d.selector+' input[type="text"]',d.button="",d.url="",$("#content").on("click",".rename",function(b){return b.preventDefault(),d.button=$(this),$(a).fadeIn(200),d.url=$(this).parent().parent().find(".filename").text(),d.form.fadeIn(200),d.form.find("span").text(d.url),d.form.find('input[type="text"]').val(d.url),!1}),$("#content").on("keypress",d.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(d.form).submit(),!1):void 0}),$("#content").on("submit",d.selector,function(a){a.preventDefault();var b=d.form.find('input[type="text"]').val();if(""===b)return!1;"/"!=b.substring(0,1)&&(b=window.location.pathname.replace("/admin/browse/","")+"/"+b);var c='{"filename": "'+b+'"}';return $.ajax({type:"PUT",url:d.url,data:c,dataType:"json",encode:!0}).done(function(a){$.pjax({url:window.location.pathname,container:"#content"}),notification({text:d.button.data("message"),type:"success",timeout:5e3})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("click",".close",function(b){return b.preventDefault(),$(this).parent().parent().fadeOut(200),$(a).click(),!1}),$("#content").on("click",a,function(e){return e.preventDefault(),$(a).fadeOut(200),c.form.fadeOut(200),d.form.fadeOut(200),b.form.fadeOut(200),!1})}),$(document).on("page:editor",function(){var a=$(".editor"),b=$("#editor-preview"),c=$("#editor-source");if(a.hasClass("complete")&&$("#content").on("keyup","#site-title",function(){$(".frontmatter #title").val($(this).val())}),!a.hasClass("frontmatter-only")){var d=$("#editor-source").data("mode"),e=$('textarea[name="content"]').hide(),f=ace.edit("editor-source");f.getSession().setMode("ace/mode/"+d),f.getSession().setValue(e.val()),f.getSession().on("change",function(){e.val(f.getSession().getValue())}),f.setOptions({wrap:!0,maxLines:1/0,theme:"ace/theme/github",showPrintMargin:!1,fontSize:"1em",minLines:20}),$("#content").on("click","#see-source",function(a){a.preventDefault(),b.hide(),c.fadeIn(),$(this).addClass("active"),$("#see-preview").removeClass("active"),$("#see-preview").data("previewing","false")}),$("#content").on("click","#see-preview",function(a){if(a.preventDefault(),"true"==$(this).data("previewing"))b.hide(),c.fadeIn(),$(this).removeClass("active"),$("#see-source").addClass("active"),$(this).data("previewing","false");else{var d=new showdown.Converter,e=f.getValue(),g=d.makeHtml(e);c.hide(),b.html(g).fadeIn(),$(this).addClass("active"),$("#see-source").removeClass("active"),$(this).data("previewing","true")}return!1})}$("#content").on("keypress","input",function(a){return 13==a.keyCode?(a.preventDefault(),$('input[value="Save"]').focus().click(),!1):void 0}),$("#content").on("submit","form",function(d){d.preventDefault(),a.hasClass("frontmatter-only")||(b.html("").fadeOut(),$("#see-preview").data("previewing","false"),c.fadeIn());var e=JSON.stringify($(this).serializeJSON()),f=$(this).find("input[type=submit]:focus");return $.ajax({type:"POST",url:window.location,data:e,headers:{"X-Regenerate":f.data("regenerate"),"X-Schedule":f.data("schedule"),"X-Content-Type":f.data("type")},dataType:"json",encode:!0,contentType:"application/json; charset=utf-8"}).done(function(a){notification({text:f.data("message"),type:"success",timeout:5e3})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("click",".add",function(a){if(a.preventDefault(),defaultID="lorem-ipsum-sin-dolor-amet",newItem=$("#"+defaultID),newItem.length&&newItem.remove(),block=$(this).parent().parent(),blockType=block.data("type"),blockID=block.attr("id"),"array"==blockType&&(newID=blockID+"[]",input=blockID,input=input.replace(/\[/,"\\["),input=input.replace(/\]/,"\\]"),block.append('
div").length+'" data-type="array-item">
'),console.log("New array item added.")),block.is("div")&&block.hasClass("frontmatter")&&(block=$(".blocks"),blockType="object"),"object"==blockType){if(block.append('
'),newItem=$("#"+defaultID),newItem.html(''),field=$("#name-"+defaultID),!document.cookie.replace(/(?:(?:^|.*;\s*)placeholdertip\s*\=\s*([^;]*).*$)|^.*$/,"$1")){var b=new Date;b.setDate(b.getDate()+365),document.cookie="placeholdertip=true; expires="+b.toUTCString+"; path=/",notification({text:'Write the field name and then press enter. If you want to create an array or an object, end the name with ":array" or ":object".',type:"information"})}$(field).keypress(function(a){return 13==a.which?(a.preventDefault(),value=field.val(),""==value?(newItem.remove(),!1):(elements=value.split(":"),elements.length>2?(notification({text:"Invalid syntax. It must be 'name[:type]'.",type:"error"}),!1):2==elements.length&&"array"!=elements[1]&&"object"!=elements[1]?(notification({text:"Only arrays and objects are allowed.",type:"error"}),!1):(field.remove(),"undefined"==typeof blockID?blockID=elements[0]:blockID=blockID+"["+elements[0]+"]",1==elements.length?(newItem.attr("id","block-"+blockID),newItem.append('
'),newItem.prepend(' ')):(type="","array"==elements[1]?type="array":type="object",template='

${elements[0]}

',template=template.replace("${blockID}",blockID),template=template.replace("${elements[0]}",elements[0]),template=template.replace("${type}",type),newItem.after(template),newItem.remove(),console.log('"'+blockID+'" block of type "'+type+'" added.')),!1))):void 0})}return!1}),$("#content").on("click",".delete",function(a){return a.preventDefault(),button=$(this),name=button.parent().parent().attr("for")||button.parent().parent().attr("id")||button.parent().parent().parent().attr("id"),name=name.replace(/\[/,"\\["),name=name.replace(/\]/,"\\]"),console.log(name),$('label[for="'+name+'"]').fadeOut().remove(),$("#"+name).fadeOut().remove(),!1})}),$.noty.themes.admin={name:"admin",helpers:{},modal:{css:{position:"fixed",width:"100%",height:"100%",backgroundColor:"#000",zIndex:1e4,opacity:.6,display:"none",left:0,top:0}}},$.noty.defaults={layout:"topRight",theme:"admin",dismissQueue:!0,animation:{open:"animated bounceInRight",close:"animated fadeOut",easing:"swing",speed:500},timeout:!1,force:!1,modal:!1,maxVisible:5,killer:!1,closeWith:["click"],callback:{onShow:function(){},afterShow:function(){},onClose:function(){},afterClose:function(){},onCloseClick:function(){}},buttons:!1},notification=function(a){var b;switch(a.type){case"success":b='';break;case"error":b='';break;case"warning":b='';break;case"information":b='';break;default:b=''}var c={template:'
'+b+'
'};if(a=$.extend({},c,a),noty(a),!document.cookie.replace(/(?:(?:^|.*;\s*)stickynoties\s*\=\s*([^;]*).*$)|^.*$/,"$1")&&!a.timeout){var d=new Date;d.setDate(d.getDate()+365),document.cookie="stickynoties=true; expires="+d.toUTCString+"; path=/",notification({text:"Some notifications are sticky. If it doesn't go away, click to dismiss it.",type:"information"})}}; \ No newline at end of file diff --git a/assets/js/plugins.min.js b/assets/js/plugins.min.js index dec1108c..92073773 100644 --- a/assets/js/plugins.min.js +++ b/assets/js/plugins.min.js @@ -1,5 +1,5 @@ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){function c(a){var b=!!a&&"length"in a&&a.length,c=fa.type(a);return"function"===c||fa.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}function d(a,b,c){if(fa.isFunction(b))return fa.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return fa.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(pa.test(b))return fa.filter(b,a,c);b=fa.filter(b,a)}return fa.grep(a,function(a){return _.call(b,a)>-1!==c})}function e(a,b){for(;(a=a[b])&&1!==a.nodeType;);return a}function f(a){var b={};return fa.each(a.match(va)||[],function(a,c){b[c]=!0}),b}function g(){X.removeEventListener("DOMContentLoaded",g),a.removeEventListener("load",g),fa.ready()}function h(){this.expando=fa.expando+h.uid++}function i(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Ca,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:Ba.test(c)?fa.parseJSON(c):c}catch(e){}Aa.set(a,b,c)}else c=void 0;return c}function j(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return fa.css(a,b,"")},i=h(),j=c&&c[3]||(fa.cssNumber[b]?"":"px"),k=(fa.cssNumber[b]||"px"!==j&&+i)&&Ea.exec(fa.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,fa.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}function k(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&fa.nodeName(a,b)?fa.merge([a],c):c}function l(a,b){for(var c=0,d=a.length;d>c;c++)za.set(a[c],"globalEval",!b||za.get(b[c],"globalEval"))}function m(a,b,c,d,e){for(var f,g,h,i,j,m,n=b.createDocumentFragment(),o=[],p=0,q=a.length;q>p;p++)if(f=a[p],f||0===f)if("object"===fa.type(f))fa.merge(o,f.nodeType?[f]:f);else if(La.test(f)){for(g=g||n.appendChild(b.createElement("div")),h=(Ia.exec(f)||["",""])[1].toLowerCase(),i=Ka[h]||Ka._default,g.innerHTML=i[1]+fa.htmlPrefilter(f)+i[2],m=i[0];m--;)g=g.lastChild;fa.merge(o,g.childNodes),g=n.firstChild,g.textContent=""}else o.push(b.createTextNode(f));for(n.textContent="",p=0;f=o[p++];)if(d&&fa.inArray(f,d)>-1)e&&e.push(f);else if(j=fa.contains(f.ownerDocument,f),g=k(n.appendChild(f),"script"),j&&l(g),c)for(m=0;f=g[m++];)Ja.test(f.type||"")&&c.push(f);return n}function n(){return!0}function o(){return!1}function p(){try{return X.activeElement}catch(a){}}function q(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)q(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=o;else if(!e)return this;return 1===f&&(g=e,e=function(a){return fa().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=fa.guid++)),a.each(function(){fa.event.add(this,b,e,d,c)})}function r(a,b){return fa.nodeName(a,"table")&&fa.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function s(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function t(a){var b=Sa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function u(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(za.hasData(a)&&(f=za.access(a),g=za.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)fa.event.add(b,e,j[e][c])}Aa.hasData(a)&&(h=Aa.access(a),i=fa.extend({},h),Aa.set(b,i))}}function v(a,b){var c=b.nodeName.toLowerCase();"input"===c&&Ha.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}function w(a,b,c,d){b=Z.apply([],b);var e,f,g,h,i,j,l=0,n=a.length,o=n-1,p=b[0],q=fa.isFunction(p);if(q||n>1&&"string"==typeof p&&!da.checkClone&&Ra.test(p))return a.each(function(e){var f=a.eq(e);q&&(b[0]=p.call(this,e,f.html())),w(f,b,c,d)});if(n&&(e=m(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(g=fa.map(k(e,"script"),s),h=g.length;n>l;l++)i=e,l!==o&&(i=fa.clone(i,!0,!0),h&&fa.merge(g,k(i,"script"))),c.call(a[l],i,l);if(h)for(j=g[g.length-1].ownerDocument,fa.map(g,t),l=0;h>l;l++)i=g[l],Ja.test(i.type||"")&&!za.access(i,"globalEval")&&fa.contains(j,i)&&(i.src?fa._evalUrl&&fa._evalUrl(i.src):fa.globalEval(i.textContent.replace(Ta,"")))}return a}function x(a,b,c){for(var d,e=b?fa.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||fa.cleanData(k(d)),d.parentNode&&(c&&fa.contains(d.ownerDocument,d)&&l(k(d,"script")),d.parentNode.removeChild(d));return a}function y(a,b){var c=fa(b.createElement(a)).appendTo(b.body),d=fa.css(c[0],"display");return c.detach(),d}function z(a){var b=X,c=Va[a];return c||(c=y(a,b),"none"!==c&&c||(Ua=(Ua||fa("