<commit_before>package paths

import (
	"archive/zip"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"testing"

	. "github.com/VonC/godbg"
	. "github.com/smartystreets/goconvey/convey"
)

func TestArchive(t *testing.T) {

	Convey("Tests for Uncompress", t, func() {

		testHas7 = false
		Convey("Uncompress fails if p is a folder", func() {
			p := NewPath(".")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip '.\' for '<nil>'
'read .\: The handle is invalid.'`)
		})

		Convey("Uncompress fails if p is a non-existing file", func() {
			p := NewPath("xxx")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'xxx' for '<nil>'
'open xxx: The system cannot find the file specified.'`)
		})

		Convey("Uncompress fails if p is not a zip file", func() {
			p := NewPath("paths.go")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'paths.go' for '<nil>'
'zip: not a valid zip file'`)
		})

		Convey("cloneZipItem can fail on a particular item", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			testmkd = true
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while mkdir for zip element: 'testzip'`)
			testmkd = false
		})

		Convey("cloneZipItem can fail on opening a particular item file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fzipfileopen = testfzipfileopen
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while checking if zip element is a file: 'testzip/'
'Error (Open) zip.File for 'testzip/''`)
			fzipfileopen = ifzipfileopen
		})

		Convey("cloneZipItem can fail on creating a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			foscreate = testfoscreate
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while creating zip element to '.\testzip\a.txt' from 'testzip/a.txt'
err='Error (Create) zip element '.\testzip\a.txt''`)
			foscreate = ifoscreate
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on copying a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fiocopy = testfiocopy
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while copying zip element to '.\testzip\a.txt' from 'testzip/a.txt'
err='Error (io.Copy) zip element'`)
			fiocopy = ifiocopy
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			foscloseze = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `      [func] (cloneZipItem) (*Path.Uncompress) (func)
        Error while closing zip element '.\testzip\a.txt'
err='Error (Close) closing zip element '.\testzip\a.txt''`)
			foscloseze = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing a zip file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fosclose = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `      [func] (cloneZipItem) (*Path.Uncompress) (func)
        Error while closing zip file 'testzip/'
err='Error (Close) closing zip element 'testzip/''`)
			fosclose = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing zip archive file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fosclosearc = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [func] (*Path.Uncompress) (func)
      Error while closing zip archive 'testzip.zip'
err='Error (Close) closing zip element 'testzip.zip''`)
			fosclosearc = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem of a valid zip archives succeed", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeTrue)
			So(NoOutput(), ShouldBeTrue)
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})

	})

	Convey("Tests for Uncompress 7z", t, func() {

		p := NewPath("testzip.zip")
		folder := NewPath(".")
		So(check7z(), ShouldBeNil)
		Convey("fcmd should not be empty", func() {
			SetBuffers(nil)
			So(fcmd, ShouldBeEmpty)
			fc := cmd7z()
			So(fc, ShouldBeEmpty)
			defaultcmd = "7z/7z.exe"
			fc = cmd7z()
			So(fc, ShouldEndWith, `VonC\senvgo\paths\7z\7z.exe`)
			defaultcmd = "test/peazip/latest/res/7z/7z.exe"
			fcmd = ""
		})

		Convey("uncompress7z is false if destination folder is empty", func() {
			SetBuffers(nil)
			b := p.uncompress7z(nil, nil, "test", false)
			So(b, ShouldBeFalse)
		})

		Convey("uncompress7z is false if fcmd is empty", func() {
			SetBuffers(nil)
			fcmd = ""
			defaultcmd = "test/peazip/latest/res/7z/7z.exe"
			b := p.uncompress7z(folder, nil, "test", false)
			So(b, ShouldBeFalse)
			So(fcmd, ShouldBeEmpty)
			defaultcmd = "7z/7z.exe"
		})

		Convey("Uncompress can uncompress an archive, respecting its directory structure", func() {
			SetBuffers(nil)
			testHas7 = true
			up := NewPath("tt.zip")
			b := up.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			err := ErrString()
			So(err, ShouldNotBeEmpty)
			err = strings.Replace(err, NewPath(".").Abs().String(), "", -1)
			So(err, ShouldEqualNL, `    [*Path.uncompress7z] (*Path.Uncompress) (func)
      Unzip: 'tt.zip' => 7zU...
/C 7z\7z.exe x -aoa -o -pdefault -sccUTF-8 tt.zip
    [*Path.uncompress7z] (*Path.Uncompress) (func)
      Error invoking 7ZU '[/C 7z\7z.exe x -aoa -o -pdefault -sccUTF-8 tt.zip]'
''
7-Zip [64] 9.22 beta  Copyright (c) 1999-2011 Igor Pavlov  2011-04-18

Error:
cannot find archive
' exit status 2'
/C 7z\7z.exe x -aoa -o -pdefault -sccUTF-8 tt.zip`)
			testHas7 = false
		})

		Convey("Uncompress can uncompress an archive, respecting its directory structure", func() {
			SetBuffers(nil)
			testHas7 = true
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeTrue)
			So(NewPath("testzip/a.txt").Exists(), ShouldBeTrue)
			So(NewPath("testzip/c/abcd.txt").Exists(), ShouldBeTrue)
			testHas7 = false
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})

		Convey("Uncompress can uncompress an archive, all in one folder", func() {
			SetBuffers(nil)
			testHas7 = true
			dest := NewPath("testzip")
			So(dest.MkdirAll(), ShouldBeTrue)
			b := p.uncompress7z(dest, nil, "extract", true)
			So(b, ShouldBeTrue)
			So(NewPath("testzip/a.txt").Exists(), ShouldBeTrue)
			So(NewPath("testzip/abcd.txt").Exists(), ShouldBeTrue)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldNotBeEmpty)
			testHas7 = false
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})

		Convey("Uncompress can extract a file of an archive", func() {
			SetBuffers(nil)
			testHas7 = true
			dest := NewPath("testzip")
			// Let's *not* create the destination folder: a file extract from an archive creates it
			b := p.uncompress7z(dest, NewPath("testzip/a.txt"), "extract file", true)
			So(b, ShouldBeTrue)
			b = p.uncompress7z(dest, NewPath("testzip/c/abcd.txt"), "extract file", true)
			So(b, ShouldBeTrue)
			So(NewPath("testzip/a.txt").Exists(), ShouldBeTrue)
			So(NewPath("testzip/b.txt").Exists(), ShouldBeFalse)
			So(NewPath("testzip/abcd.txt").Exists(), ShouldBeTrue)
			So(NewPath("testzip/c/abcd.txt").Exists(), ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldNotBeEmpty)
			testHas7 = false
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})
	})
}

func check7z() error {
	p := NewPath("7z/7z.exe")
	if p.Exists() {
		return nil
	}
	cmdStr := "git submodule update --init"
	out, err := exec.Command("cmd", "/c", cmdStr).Output()
	Perrdbgf("Init 7z '%v", string(out))
	return err
}

func testfzipfileopen(f *zip.File) (rc io.ReadCloser, err error) {
	return nil, fmt.Errorf("Error (Open) zip.File for '%s'", f.Name)
}
func testfoscreate(name string) (file *os.File, err error) {
	return nil, fmt.Errorf("Error (Create) zip element '%s'", name)
}
func testfiocopy(dst io.Writer, src io.Reader) (written int64, err error) {
	return 0, fmt.Errorf("Error (io.Copy) zip element")
}
func testfosclose(f io.ReadCloser, name string) (err error) {
	ifosclose(f, name)
	return fmt.Errorf("Error (Close) closing zip element '%v'", name)
}

/*
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo a> testzip\a.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo ab> testzip\b.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip\c
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo abcd> testzip\c\abcd.txt
http://askubuntu.com/questions/58889/how-can-i-create-a-zip-archive-of-a-whole-directory-via-terminal-without-hidden
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>zip -r testzip.zip testzip
  adding: testzip/ (164 bytes security) (stored 0%)
  adding: testzip/a.txt (164 bytes security) (stored 0%)
  adding: testzip/b.txt (164 bytes security) (stored 0%)
  adding: testzip/c/ (164 bytes security) (stored 0%)
  adding: testzip/c/abcd.txt (164 bytes security) (stored 0%)
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>testzip.zip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>rm -Rf testzip
*/
<commit_msg>Fix Paths Uncompress test title<commit_after>package paths

import (
	"archive/zip"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"testing"

	. "github.com/VonC/godbg"
	. "github.com/smartystreets/goconvey/convey"
)

func TestArchive(t *testing.T) {

	Convey("Tests for Uncompress", t, func() {

		testHas7 = false
		Convey("Uncompress fails if p is a folder", func() {
			p := NewPath(".")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip '.\' for '<nil>'
'read .\: The handle is invalid.'`)
		})

		Convey("Uncompress fails if p is a non-existing file", func() {
			p := NewPath("xxx")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'xxx' for '<nil>'
'open xxx: The system cannot find the file specified.'`)
		})

		Convey("Uncompress fails if p is not a zip file", func() {
			p := NewPath("paths.go")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'paths.go' for '<nil>'
'zip: not a valid zip file'`)
		})

		Convey("cloneZipItem can fail on a particular item", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			testmkd = true
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while mkdir for zip element: 'testzip'`)
			testmkd = false
		})

		Convey("cloneZipItem can fail on opening a particular item file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fzipfileopen = testfzipfileopen
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while checking if zip element is a file: 'testzip/'
'Error (Open) zip.File for 'testzip/''`)
			fzipfileopen = ifzipfileopen
		})

		Convey("cloneZipItem can fail on creating a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			foscreate = testfoscreate
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while creating zip element to '.\testzip\a.txt' from 'testzip/a.txt'
err='Error (Create) zip element '.\testzip\a.txt''`)
			foscreate = ifoscreate
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on copying a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fiocopy = testfiocopy
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while copying zip element to '.\testzip\a.txt' from 'testzip/a.txt'
err='Error (io.Copy) zip element'`)
			fiocopy = ifiocopy
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			foscloseze = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `      [func] (cloneZipItem) (*Path.Uncompress) (func)
        Error while closing zip element '.\testzip\a.txt'
err='Error (Close) closing zip element '.\testzip\a.txt''`)
			foscloseze = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing a zip file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fosclose = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `      [func] (cloneZipItem) (*Path.Uncompress) (func)
        Error while closing zip file 'testzip/'
err='Error (Close) closing zip element 'testzip/''`)
			fosclose = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing zip archive file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fosclosearc = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [func] (*Path.Uncompress) (func)
      Error while closing zip archive 'testzip.zip'
err='Error (Close) closing zip element 'testzip.zip''`)
			fosclosearc = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem of a valid zip archives succeed", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeTrue)
			So(NoOutput(), ShouldBeTrue)
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})

	})

	Convey("Tests for Uncompress 7z", t, func() {

		p := NewPath("testzip.zip")
		folder := NewPath(".")
		So(check7z(), ShouldBeNil)
		Convey("fcmd should not be empty", func() {
			SetBuffers(nil)
			So(fcmd, ShouldBeEmpty)
			fc := cmd7z()
			So(fc, ShouldBeEmpty)
			defaultcmd = "7z/7z.exe"
			fc = cmd7z()
			So(fc, ShouldEndWith, `VonC\senvgo\paths\7z\7z.exe`)
			defaultcmd = "test/peazip/latest/res/7z/7z.exe"
			fcmd = ""
		})

		Convey("uncompress7z is false if destination folder is empty", func() {
			SetBuffers(nil)
			b := p.uncompress7z(nil, nil, "test", false)
			So(b, ShouldBeFalse)
		})

		Convey("uncompress7z is false if fcmd is empty", func() {
			SetBuffers(nil)
			fcmd = ""
			defaultcmd = "test/peazip/latest/res/7z/7z.exe"
			b := p.uncompress7z(folder, nil, "test", false)
			So(b, ShouldBeFalse)
			So(fcmd, ShouldBeEmpty)
			defaultcmd = "7z/7z.exe"
		})

		Convey("Uncompress fails if archive does not exist", func() {
			SetBuffers(nil)
			testHas7 = true
			up := NewPath("tt.zip")
			b := up.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			err := ErrString()
			So(err, ShouldNotBeEmpty)
			err = strings.Replace(err, NewPath(".").Abs().String(), "", -1)
			So(err, ShouldEqualNL, `    [*Path.uncompress7z] (*Path.Uncompress) (func)
      Unzip: 'tt.zip' => 7zU...
/C 7z\7z.exe x -aoa -o -pdefault -sccUTF-8 tt.zip
    [*Path.uncompress7z] (*Path.Uncompress) (func)
      Error invoking 7ZU '[/C 7z\7z.exe x -aoa -o -pdefault -sccUTF-8 tt.zip]'
''
7-Zip [64] 9.22 beta  Copyright (c) 1999-2011 Igor Pavlov  2011-04-18

Error:
cannot find archive
' exit status 2'
/C 7z\7z.exe x -aoa -o -pdefault -sccUTF-8 tt.zip`)
			testHas7 = false
		})

		Convey("Uncompress can uncompress an archive, respecting its directory structure", func() {
			SetBuffers(nil)
			testHas7 = true
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeTrue)
			So(NewPath("testzip/a.txt").Exists(), ShouldBeTrue)
			So(NewPath("testzip/c/abcd.txt").Exists(), ShouldBeTrue)
			testHas7 = false
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})

		Convey("Uncompress can uncompress an archive, all in one folder", func() {
			SetBuffers(nil)
			testHas7 = true
			dest := NewPath("testzip")
			So(dest.MkdirAll(), ShouldBeTrue)
			b := p.uncompress7z(dest, nil, "extract", true)
			So(b, ShouldBeTrue)
			So(NewPath("testzip/a.txt").Exists(), ShouldBeTrue)
			So(NewPath("testzip/abcd.txt").Exists(), ShouldBeTrue)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldNotBeEmpty)
			testHas7 = false
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})

		Convey("Uncompress can extract a file of an archive", func() {
			SetBuffers(nil)
			testHas7 = true
			dest := NewPath("testzip")
			// Let's *not* create the destination folder: a file extract from an archive creates it
			b := p.uncompress7z(dest, NewPath("testzip/a.txt"), "extract file", true)
			So(b, ShouldBeTrue)
			b = p.uncompress7z(dest, NewPath("testzip/c/abcd.txt"), "extract file", true)
			So(b, ShouldBeTrue)
			So(NewPath("testzip/a.txt").Exists(), ShouldBeTrue)
			So(NewPath("testzip/b.txt").Exists(), ShouldBeFalse)
			So(NewPath("testzip/abcd.txt").Exists(), ShouldBeTrue)
			So(NewPath("testzip/c/abcd.txt").Exists(), ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldNotBeEmpty)
			testHas7 = false
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})
	})
}

func check7z() error {
	p := NewPath("7z/7z.exe")
	if p.Exists() {
		return nil
	}
	cmdStr := "git submodule update --init"
	out, err := exec.Command("cmd", "/c", cmdStr).Output()
	Perrdbgf("Init 7z '%v", string(out))
	return err
}

func testfzipfileopen(f *zip.File) (rc io.ReadCloser, err error) {
	return nil, fmt.Errorf("Error (Open) zip.File for '%s'", f.Name)
}
func testfoscreate(name string) (file *os.File, err error) {
	return nil, fmt.Errorf("Error (Create) zip element '%s'", name)
}
func testfiocopy(dst io.Writer, src io.Reader) (written int64, err error) {
	return 0, fmt.Errorf("Error (io.Copy) zip element")
}
func testfosclose(f io.ReadCloser, name string) (err error) {
	ifosclose(f, name)
	return fmt.Errorf("Error (Close) closing zip element '%v'", name)
}

/*
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo a> testzip\a.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo ab> testzip\b.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip\c
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo abcd> testzip\c\abcd.txt
http://askubuntu.com/questions/58889/how-can-i-create-a-zip-archive-of-a-whole-directory-via-terminal-without-hidden
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>zip -r testzip.zip testzip
  adding: testzip/ (164 bytes security) (stored 0%)
  adding: testzip/a.txt (164 bytes security) (stored 0%)
  adding: testzip/b.txt (164 bytes security) (stored 0%)
  adding: testzip/c/ (164 bytes security) (stored 0%)
  adding: testzip/c/abcd.txt (164 bytes security) (stored 0%)
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>testzip.zip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>rm -Rf testzip
*/
<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

// Package framework sets up the test framework needed to run the end-to-end
// tests on Kubernetes.
package framework

import (
	habclient "github.com/habitat-sh/habitat-operator/pkg/client/clientset/versioned/typed/habitat/v1beta1"

	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

const (
	TestNs = "testing"
)

type Framework struct {
	Image      string
	KubeClient kubernetes.Interface
	Client     *rest.RESTClient
	ExternalIP string
}

// Setup sets up the test framework.
func Setup(image, kubeconfig, externalIP string) (*Framework, error) {
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
	if err != nil {
		return nil, err
	}

	apiclientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	cl, _, err := habclient.NewClient(config)
	if err != nil {
		return nil, err
	}

	f := &Framework{
		Image:      image,
		KubeClient: apiclientset,
		Client:     cl,
		ExternalIP: externalIP,
	}

	// Create a new Kubernetes namespace for testing purposes.
	_, err = f.KubeClient.CoreV1().Namespaces().Create(&apiv1.Namespace{
		ObjectMeta: metav1.ObjectMeta{
			Name: TestNs,
		},
	})
	if err != nil {
		return nil, err
	}

	if err = f.setupOperator(); err != nil {
		return nil, err
	}

	return f, nil
}

func (f *Framework) setupOperator() error {
	// Setup RBAC for operator.
	err := f.createRBAC()
	if err != nil {
		return err
	}

	// Get Habitat operator deployment from examples.
	d, err := ConvertDeployment("resources/operator/deployment.yml")
	if err != nil {
		return err
	}

	// Override image with the one passed to the tests.
	d.Spec.Template.Spec.Containers[0].Image = f.Image

	// Create deployment for the Habitat operator.
	_, err = f.KubeClient.AppsV1beta1().Deployments(TestNs).Create(d)
	if err != nil {
		return err
	}

	f.WaitForResources("name", d.ObjectMeta.Name, 1)

	return nil
}
<commit_msg>e2e/v1beta1: Fix test invocation<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

// Package framework sets up the test framework needed to run the end-to-end
// tests on Kubernetes.
package framework

import (
	habclient "github.com/habitat-sh/habitat-operator/pkg/client/clientset/versioned/typed/habitat/v1beta1"

	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
)

const (
	TestNs = "testing"
)

type Framework struct {
	Image      string
	KubeClient kubernetes.Interface
	Client     habclient.HabitatInterface
	ExternalIP string
}

// Setup sets up the test framework.
func Setup(image, kubeconfig, externalIP string) (*Framework, error) {
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
	if err != nil {
		return nil, err
	}

	apiclientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	cl, err := habclient.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	f := &Framework{
		Image:      image,
		KubeClient: apiclientset,
		Client:     cl.Habitats(TestNs),
		ExternalIP: externalIP,
	}

	// Create a new Kubernetes namespace for testing purposes.
	_, err = f.KubeClient.CoreV1().Namespaces().Create(&apiv1.Namespace{
		ObjectMeta: metav1.ObjectMeta{
			Name: TestNs,
		},
	})
	if err != nil {
		return nil, err
	}

	if err = f.setupOperator(); err != nil {
		return nil, err
	}

	return f, nil
}

func (f *Framework) setupOperator() error {
	// Setup RBAC for operator.
	err := f.createRBAC()
	if err != nil {
		return err
	}

	// Get Habitat operator deployment from examples.
	d, err := ConvertDeployment("resources/operator/deployment.yml")
	if err != nil {
		return err
	}

	// Override image with the one passed to the tests.
	d.Spec.Template.Spec.Containers[0].Image = f.Image

	// Create deployment for the Habitat operator.
	_, err = f.KubeClient.AppsV1beta1().Deployments(TestNs).Create(d)
	if err != nil {
		return err
	}

	f.WaitForResources("name", d.ObjectMeta.Name, 1)

	return nil
}
<|endoftext|>


<commit_before><commit_msg>still learning<commit_after>package main

import "fmt"

func MoveZero(nums List)  {
	for i := nums.Front(); i != nil; i = i.Next() {
		fmt.Print(i)
	}
}

func main() {
	MoveZero([1,2,3,4,5])
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package networkingcommon

import (
	"github.com/juju/errors"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/network"
	providercommon "github.com/juju/juju/provider/common"
	"github.com/juju/juju/state"
)

// NOTE:  All of the following code is only tested with a feature test.

// subnetShim forwards and adapts state.Subnets methods to BackingSubnet.
type subnetShim struct {
	BackingSubnet
	subnet *state.Subnet
}

func (s *subnetShim) CIDR() string {
	return s.subnet.CIDR()
}

func (s *subnetShim) VLANTag() int {
	return s.subnet.VLANTag()
}

func (s *subnetShim) ProviderId() network.Id {
	return s.subnet.ProviderId()
}

func (s *subnetShim) AvailabilityZones() []string {
	// TODO(dimitern): Add multiple zones to state.Subnet.
	return []string{s.subnet.AvailabilityZone()}
}

func (s *subnetShim) Life() params.Life {
	return params.Life(s.subnet.Life().String())
}

func (s *subnetShim) Status() string {
	// TODO(dimitern): This should happen in a cleaner way.
	if s.Life() != params.Alive {
		return "terminating"
	}
	return "in-use"
}

func (s *subnetShim) SpaceName() string {
	return s.subnet.SpaceName()
}

// spaceShim forwards and adapts state.Space methods to BackingSpace.
type spaceShim struct {
	BackingSpace
	space *state.Space
}

func (s *spaceShim) Name() string {
	return s.space.Name()
}

func (s *spaceShim) Subnets() ([]BackingSubnet, error) {
	results, err := s.space.Subnets()
	if err != nil {
		return nil, errors.Trace(err)
	}
	subnets := make([]BackingSubnet, len(results))
	for i, result := range results {
		subnets[i] = &subnetShim{subnet: result}
	}
	return subnets, nil
}

func NewStateShim(st *state.State) *stateShim {
	return &stateShim{st: st}
}

// stateShim forwards and adapts state.State methods to Backing
// method.
type stateShim struct {
	NetworkBacking
	st *state.State
}

func (s *stateShim) EnvironConfig() (*config.Config, error) {
	return s.st.EnvironConfig()
}

func (s *stateShim) AddSpace(name string, providerId network.Id, subnetIds []string, public bool) error {
	_, err := s.st.AddSpace(name, providerId, subnetIds, public)
	return err
}

func (s *stateShim) AllSpaces() ([]BackingSpace, error) {
	// TODO(dimitern): Make this ListSpaces() instead.
	results, err := s.st.AllSpaces()
	if err != nil {
		return nil, errors.Trace(err)
	}
	spaces := make([]BackingSpace, len(results))
	for i, result := range results {
		spaces[i] = &spaceShim{space: result}
	}
	return spaces, nil
}

func (s *stateShim) AddSubnet(info BackingSubnetInfo) (BackingSubnet, error) {
	// TODO(dimitern): Add multiple AZs per subnet in state.
	var firstZone string
	if len(info.AvailabilityZones) > 0 {
		firstZone = info.AvailabilityZones[0]
	}
	_, err := s.st.AddSubnet(state.SubnetInfo{
		CIDR:             info.CIDR,
		VLANTag:          info.VLANTag,
		ProviderId:       info.ProviderId,
		AvailabilityZone: firstZone,
		SpaceName:        info.SpaceName,
	})
	return nil, err // Drop the first result, as it's unused.
}

func (s *stateShim) AllSubnets() ([]BackingSubnet, error) {
	results, err := s.st.AllSubnets()
	if err != nil {
		return nil, errors.Trace(err)
	}
	subnets := make([]BackingSubnet, len(results))
	for i, result := range results {
		subnets[i] = &subnetShim{subnet: result}
	}
	return subnets, nil
}

type availZoneShim struct{}

func (availZoneShim) Name() string    { return "not-set" }
func (availZoneShim) Available() bool { return true }

func (s *stateShim) AvailabilityZones() ([]providercommon.AvailabilityZone, error) {
	// TODO(dimitern): Fix this to get them from state when available!
	return nil, nil
}

func (s *stateShim) SetAvailabilityZones(zones []providercommon.AvailabilityZone) error {
	return nil
}
<commit_msg>Remove whitespace<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package networkingcommon

import (
	"github.com/juju/errors"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/network"
	providercommon "github.com/juju/juju/provider/common"
	"github.com/juju/juju/state"
)

// NOTE: All of the following code is only tested with a feature test.

// subnetShim forwards and adapts state.Subnets methods to BackingSubnet.
type subnetShim struct {
	BackingSubnet
	subnet *state.Subnet
}

func (s *subnetShim) CIDR() string {
	return s.subnet.CIDR()
}

func (s *subnetShim) VLANTag() int {
	return s.subnet.VLANTag()
}

func (s *subnetShim) ProviderId() network.Id {
	return s.subnet.ProviderId()
}

func (s *subnetShim) AvailabilityZones() []string {
	// TODO(dimitern): Add multiple zones to state.Subnet.
	return []string{s.subnet.AvailabilityZone()}
}

func (s *subnetShim) Life() params.Life {
	return params.Life(s.subnet.Life().String())
}

func (s *subnetShim) Status() string {
	// TODO(dimitern): This should happen in a cleaner way.
	if s.Life() != params.Alive {
		return "terminating"
	}
	return "in-use"
}

func (s *subnetShim) SpaceName() string {
	return s.subnet.SpaceName()
}

// spaceShim forwards and adapts state.Space methods to BackingSpace.
type spaceShim struct {
	BackingSpace
	space *state.Space
}

func (s *spaceShim) Name() string {
	return s.space.Name()
}

func (s *spaceShim) Subnets() ([]BackingSubnet, error) {
	results, err := s.space.Subnets()
	if err != nil {
		return nil, errors.Trace(err)
	}
	subnets := make([]BackingSubnet, len(results))
	for i, result := range results {
		subnets[i] = &subnetShim{subnet: result}
	}
	return subnets, nil
}

func NewStateShim(st *state.State) *stateShim {
	return &stateShim{st: st}
}

// stateShim forwards and adapts state.State methods to Backing
// method.
type stateShim struct {
	NetworkBacking
	st *state.State
}

func (s *stateShim) EnvironConfig() (*config.Config, error) {
	return s.st.EnvironConfig()
}

func (s *stateShim) AddSpace(name string, providerId network.Id, subnetIds []string, public bool) error {
	_, err := s.st.AddSpace(name, providerId, subnetIds, public)
	return err
}

func (s *stateShim) AllSpaces() ([]BackingSpace, error) {
	// TODO(dimitern): Make this ListSpaces() instead.
	results, err := s.st.AllSpaces()
	if err != nil {
		return nil, errors.Trace(err)
	}
	spaces := make([]BackingSpace, len(results))
	for i, result := range results {
		spaces[i] = &spaceShim{space: result}
	}
	return spaces, nil
}

func (s *stateShim) AddSubnet(info BackingSubnetInfo) (BackingSubnet, error) {
	// TODO(dimitern): Add multiple AZs per subnet in state.
	var firstZone string
	if len(info.AvailabilityZones) > 0 {
		firstZone = info.AvailabilityZones[0]
	}
	_, err := s.st.AddSubnet(state.SubnetInfo{
		CIDR:             info.CIDR,
		VLANTag:          info.VLANTag,
		ProviderId:       info.ProviderId,
		AvailabilityZone: firstZone,
		SpaceName:        info.SpaceName,
	})
	return nil, err // Drop the first result, as it's unused.
}

func (s *stateShim) AllSubnets() ([]BackingSubnet, error) {
	results, err := s.st.AllSubnets()
	if err != nil {
		return nil, errors.Trace(err)
	}
	subnets := make([]BackingSubnet, len(results))
	for i, result := range results {
		subnets[i] = &subnetShim{subnet: result}
	}
	return subnets, nil
}

type availZoneShim struct{}

func (availZoneShim) Name() string    { return "not-set" }
func (availZoneShim) Available() bool { return true }

func (s *stateShim) AvailabilityZones() ([]providercommon.AvailabilityZone, error) {
	// TODO(dimitern): Fix this to get them from state when available!
	return nil, nil
}

func (s *stateShim) SetAvailabilityZones(zones []providercommon.AvailabilityZone) error {
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
	"math"

	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/num"
	"github.com/cpmech/gosl/plt"
)

func main() {

	// y(x) function
	yx := func(x float64) float64 {
		return math.Pow(x, 3.0) - 0.165*math.Pow(x, 2.0) + 3.993e-4
	}

	// range: be sure to enclose root
	xa, xb := 0.0, 0.11

	// initialise solver
	solver := num.NewBrent(yx, nil)

	// solve
	xo := solver.Root(xa, xb)

	// output
	yo := yx(xo)
	io.Pf("\n")
	io.Pf("x      = %v\n", xo)
	io.Pf("f(x)   = %v\n", yo)
	io.Pf("nfeval = %v\n", solver.NFeval)
	io.Pf("niter. = %v\n", solver.It)

	// plotting
	npts := 101
	X := make([]float64, npts)
	Y := make([]float64, npts)
	for i := 0; i < npts; i++ {
		X[i] = xa + float64(i)*(xb-xa)/float64(npts-1)
		Y[i] = yx(X[i])
	}
	plt.Reset(false, nil)
	plt.AxHline(0, nil)
	plt.Plot(X, Y, &plt.A{C: "g"})
	plt.PlotOne(xo, yo, &plt.A{C: "r", M: "."})
	plt.Gll("x", "y(x)", nil)
	plt.Save("/tmp/gosl", "num_brent01")
}
<commit_msg>Fix example<commit_after>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
	"math"

	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/num"
	"github.com/cpmech/gosl/plt"
)

func main() {

	// y(x) function
	yx := func(x float64) float64 {
		return math.Pow(x, 3.0) - 0.165*math.Pow(x, 2.0) + 3.993e-4
	}

	// range: be sure to enclose root
	xa, xb := 0.0, 0.11

	// initialise solver
	solver := num.NewBrent(yx, nil)

	// solve
	xo := solver.Root(xa, xb)

	// output
	yo := yx(xo)
	io.Pf("\n")
	io.Pf("x      = %v\n", xo)
	io.Pf("f(x)   = %v\n", yo)
	io.Pf("nfeval = %v\n", solver.NumFeval)
	io.Pf("niter. = %v\n", solver.NumIter)

	// plotting
	npts := 101
	X := make([]float64, npts)
	Y := make([]float64, npts)
	for i := 0; i < npts; i++ {
		X[i] = xa + float64(i)*(xb-xa)/float64(npts-1)
		Y[i] = yx(X[i])
	}
	plt.Reset(false, nil)
	plt.AxHline(0, nil)
	plt.Plot(X, Y, &plt.A{C: "g"})
	plt.PlotOne(xo, yo, &plt.A{C: "r", M: "."})
	plt.Gll("x", "y(x)", nil)
	plt.Save("/tmp/gosl", "num_brent01")
}
<|endoftext|>


<commit_before>package oauth_fb

import (
	"code.google.com/p/goauth2/oauth"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

type FBAuth struct {
	oauth.Config
	Token *oauth.Token
}

type Graph struct {
	AccessToken string
}

type Item struct {
	Id   string `json:"id"`
	Name string `json:"name"`
}

type Profile struct {
	Id                  string  `json:"id"`
	Username            string  `json:"username"`
	Name                string  `json:"name"`
	FirstName           string  `json:"first_name"`
	LastName            string  `json:"last_name"`
	Link                string  `json:"link"`
	Gender              string  `json:"gender"`
	Timezone            float32 `json:"timezone"`
	Locale              string  `json:"locale"`
	Verified            bool    `json:"verified"`
	UpdatedTime         string  `json:"updated_time"`
	Hometown            Item    `json:"hometown"`
	Location            Item    `json:"location"`
	Sports              []Item  `json:"sports"`
	FavoriteTeams       []Item  `json:"favourite_teams"`
	Languages           []Item  `json:"languages"`
	InspirationalPeople []Item  `json:"inspirational_people"`
}

const GraphHost = "graph.facebook.com"

func Init(client_id, client_secret, redirect_url string, options map[string]string) *FBAuth {
	fba := new(FBAuth)
	fba.ClientId = client_id
	fba.ClientSecret = client_secret
	fba.RedirectURL = redirect_url
	fba.AuthURL = "https://graph.facebook.com/oauth/authorize"
	fba.TokenURL = "https://graph.facebook.com/oauth/access_token"

	return fba
}

func (fba *FBAuth) LoginURL() string {
	// demo is a random string to prevent cross site requests
	return fba.AuthCodeURL("demo")
}

func (fba *FBAuth) Authorize(code string) (string, error) {
	t := &oauth.Transport{Config: &fba.Config}
	tok, err := t.Exchange(code)
	fba.Token = tok
	if err != nil {
		fmt.Println("Error in getting token")
	}

	return fba.AccessToken(), err
}

func (fba *FBAuth) AccessToken() string {
	var token string
	if fba.Token != nil {
		token = fba.Token.AccessToken
	}
	return token
}

func (g *Graph) getRequestUri(path string) string {
	var uri url.URL
	query := url.Values{"access_token": {g.AccessToken}}.Encode()

	uri.Host = GraphHost
	uri.Path = path
	uri.Scheme = "https"
	uri.RawQuery = query

	return uri.String()
}

func (g *Graph) GetObject(object string) (*Profile, error) {
	var profile Profile
	resp, err := http.Get(g.getRequestUri(object))

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	err = json.NewDecoder(resp.Body).Decode(&profile)
	return &profile, nil
}
<commit_msg>Added method to get connections like photos, posts, friends<commit_after>package oauth_fb

import (
	"code.google.com/p/goauth2/oauth"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

type FBAuth struct {
	oauth.Config
	Token *oauth.Token
}

type Graph struct {
	AccessToken string
}

type Item struct {
	Id   string `json:"id"`
	Name string `json:"name"`
}

type Data struct {
	Data []Item `json:"data"`
}

type Profile struct {
	Id                  string  `json:"id"`
	Username            string  `json:"username"`
	Name                string  `json:"name"`
	FirstName           string  `json:"first_name"`
	LastName            string  `json:"last_name"`
	Link                string  `json:"link"`
	Gender              string  `json:"gender"`
	Timezone            float32 `json:"timezone"`
	Locale              string  `json:"locale"`
	Verified            bool    `json:"verified"`
	UpdatedTime         string  `json:"updated_time"`
	Hometown            Item    `json:"hometown"`
	Location            Item    `json:"location"`
	Sports              []Item  `json:"sports"`
	FavoriteTeams       []Item  `json:"favourite_teams"`
	Languages           []Item  `json:"languages"`
	InspirationalPeople []Item  `json:"inspirational_people"`
}

const GraphHost = "graph.facebook.com"

func Init(client_id, client_secret, redirect_url string, options map[string]string) *FBAuth {
	fba := new(FBAuth)
	fba.ClientId = client_id
	fba.ClientSecret = client_secret
	fba.RedirectURL = redirect_url
	fba.AuthURL = "https://graph.facebook.com/oauth/authorize"
	fba.TokenURL = "https://graph.facebook.com/oauth/access_token"

	return fba
}

func (fba *FBAuth) LoginURL() string {
	// demo is a random string to prevent cross site requests
	return fba.AuthCodeURL("demo")
}

func (fba *FBAuth) Authorize(code string) (string, error) {
	t := &oauth.Transport{Config: &fba.Config}
	tok, err := t.Exchange(code)
	fba.Token = tok
	if err != nil {
		fmt.Println("Error in getting token")
	}

	return fba.AccessToken(), err
}

func (fba *FBAuth) AccessToken() string {
	var token string
	if fba.Token != nil {
		token = fba.Token.AccessToken
	}
	return token
}

func (g *Graph) getRequestUri(path string) string {
	var uri url.URL
	query := url.Values{"access_token": {g.AccessToken}}.Encode()

	uri.Host = GraphHost
	uri.Path = path
	uri.Scheme = "https"
	uri.RawQuery = query

	return uri.String()
}

func (g *Graph) GetObject(object string) (*Profile, error) {
	var profile Profile
	resp, err := http.Get(g.getRequestUri(object))

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	err = json.NewDecoder(resp.Body).Decode(&profile)

	return &profile, nil
}

func (g *Graph) GetConnections(path string) ([]Item, error) {
	var data Data
	resp, err := http.Get(g.getRequestUri(path))

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	err = json.NewDecoder(resp.Body).Decode(&data)

	return data.Data, nil
}
<|endoftext|>


<commit_before>// Package pastebin is a simple modern and powerful pastebin service
package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	duration "github.com/channelmeter/iso8601duration"
	// uniuri is used for easy random string generation
	"github.com/dchest/uniuri"
	// pygments is used for syntax highlighting
	"github.com/ewhal/pygments"
	// mysql driver
	_ "github.com/go-sql-driver/mysql"
	// mux is used for url routing
	"github.com/gorilla/mux"
)

type Configuration struct {
	// ADDRESS that pastebin will return links for
	Address string
	// LENGTH of paste id
	Length int
	// PORT that pastebin will listen on
	Port string
	// USERNAME for database
	Username string
	// PASS database password
	Password string
	// NAME database name
	Name string
}

var configuration Configuration

// DATABASE connection String
var DATABASE string

// Template pages
var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

// Response API struct
type Response struct {
	SUCCESS bool   `json:"success"`
	STATUS  string `json:"status"`
	ID      string `json:"id"`
	TITLE   string `json:"title"`
	SHA1    string `json:"sha1"`
	URL     string `json:"url"`
	SIZE    int    `json:"size"`
	DELKEY  string `json:"delkey"`
}

// Page generation struct
type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

// check error handling function
func Check(err error) {
	if err != nil {
		log.Println(err)
	}
}

// GenerateName uses uniuri to generate a random string that isn't in the
// database
func GenerateName() string {
	// use uniuri to generate random string
	id := uniuri.NewLen(configuration.Length)

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()
	// query database if id exists and if it does call generateName again
	query, err := db.Query("select id from pastebin where id=?", id)
	if err != sql.ErrNoRows {
		for query.Next() {
			GenerateName()
		}
	}

	return id

}

// Sha1 hashes paste into a sha1 hash
func Sha1(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

// DurationFromExpiry takes the expiry in string format and returns the duration
// that the paste will exist for
func DurationFromExpiry(expiry string) time.Duration {
	if expiry == "" {
		expiry = "P20Y"
	}
	dura, err := duration.FromString(expiry) // dura is time.Duration type
	Check(err)

	duration := dura.ToDuration()

	return duration
}

// Save function handles the saving of each paste.
// raw string is the raw paste input
// lang string is the user specified language for syntax highlighting
// title string user customized title
// expiry string duration that the paste will exist for
// Returns Response struct
func Save(raw string, lang string, title string, expiry string) Response {

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()

	// hash paste data and query database to see if paste exists
	sha := Sha1(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin where hash=?", sha)

	if err != sql.ErrNoRows {
		for query.Next() {
			var id, title, hash, paste, delkey string
			err := query.Scan(&id, &title, &hash, &paste, &delkey)
			Check(err)
			url := configuration.Address + "/p/" + id
			return Response{true, "saved", id, title, hash, url, len(paste), delkey}
		}
	}
	id := GenerateName()
	url := configuration.Address + "/p/" + id
	if lang != "" {
		url += "/" + lang
	}

	const timeFormat = "2006-01-02 15:04:05"
	expiryTime := time.Now().Add(DurationFromExpiry(expiry)).Format(timeFormat)

	delKey := uniuri.NewLen(40)
	dataEscaped := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	Check(err)
	if title == "" {
		title = id
	}
	_, err = stmt.Exec(id, html.EscapeString(title), sha, dataEscaped, delKey, expiryTime)
	Check(err)

	return Response{true, "saved", id, title, sha, url, len(dataEscaped), delKey}
}

// DelHandler checks to see if delkey and pasteid exist in the database.
// if both exist and are correct the paste will be removed.
func DelHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["pasteId"]
	delkey := r.FormValue("delkey")

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()

	stmt, err := db.Prepare("delete from pastebin where delkey=? and id=?")
	Check(err)

	res, err := stmt.Exec(html.EscapeString(delkey), html.EscapeString(id))
	Check(err)

	_, err = res.RowsAffected()
	if err != sql.ErrNoRows {
		w.Header().Set("Content-Type", "application/json")
		b := Response{STATUS: "DELETED " + id}
		err := json.NewEncoder(w).Encode(b)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

// SaveHandler Handles saving pastes and outputing responses
func SaveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		b := Save(paste, lang, title, expiry)

		switch output {
		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

		}
	}

}

// Highlight uses user specified input to call pygments library to highlight the
// paste
func Highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

// GetPaste takes pasteid and language
// queries the database and returns paste data
func GetPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()
	var title, s string
	var expiry string
	err = db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	Check(err)
	if time.Now().Format("2006-01-02 15:04:05") >= expiry {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		Check(err)
		_, err = stmt.Exec(param1)
		Check(err)
		return "Error invalid paste", ""
	}

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	}
	if lang != "" {
		high, err := Highlight(s, lang)
		Check(err)
		return high, html.UnescapeString(title)
	}
	return html.UnescapeString(s), html.UnescapeString(title)
}

// APIHandler handles get requests of pastes
func APIHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]

	b, _ := GetPaste(paste, "")
	w.Header().Set("Content-Type", "application/json")
	err := json.NewEncoder(w).Encode(b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

}

// PasteHandler handles the generation of paste pages with the links
func PasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]

	s, title := GetPaste(paste, lang)

	// button links
	link := configuration.Address + "/raw/" + paste
	download := configuration.Address + "/download/" + paste
	clone := configuration.Address + "/clone/" + paste
	// Page struct
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     configuration.Address,
		Download: download,
		Clone:    clone,
	}
	if lang == "" {

		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), p.Title, p.Title, s, p.Home, p.Download, p.Raw, p.Clone)

	}
}

// CloneHandler handles generating the clone pages
func CloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]

	s, title := GetPaste(paste, "")

	// Page links
	link := configuration.Address + "/raw/" + paste
	download := configuration.Address + "/download/" + paste
	clone := configuration.Address + "/clone/" + paste

	// Clone page struct
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     configuration.Address,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

// DownloadHandler forces downloads of selected pastes
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := GetPaste(paste, "")

	// Set header to an attachment so browser will automatically download it
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}

// RawHandler displays the pastes in text/plain format
func RawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := GetPaste(paste, "")

	w.Header().Set("Content-Type", "text/plain; charset=UTF-8; imeanit=yes")
	// simply write string to browser
	io.WriteString(w, s)

}

// RootHandler handles generating the root page
func RootHandler(w http.ResponseWriter, r *http.Request) {
	err := templates.ExecuteTemplate(w, "index.html", &Page{})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func main() {
	file, err := os.Open("config.json")
	if err != nil {
		panic(err)
	}
	decoder := json.NewDecoder(file)
	configuration := Configuration{}
	err = decoder.Decode(&configuration)
	if err != nil {
		panic(err)
	}

	DATABASE = configuration.Username + ":" + configuration.Password + "@/" + configuration.Name + "?charset=utf8"
	// create new mux router
	router := mux.NewRouter()

	// serverside rending stuff
	router.HandleFunc("/p/{pasteId}", PasteHandler).Methods("GET")
	router.HandleFunc("/raw/{pasteId}", RawHandler).Methods("GET")
	router.HandleFunc("/p/{pasteId}/{lang}", PasteHandler).Methods("GET")
	router.HandleFunc("/clone/{pasteId}", CloneHandler).Methods("GET")
	router.HandleFunc("/download/{pasteId}", DownloadHandler).Methods("GET")
	// api
	router.HandleFunc("/api", SaveHandler).Methods("POST")
	router.HandleFunc("/api/{output}", SaveHandler).Methods("POST")
	router.HandleFunc("/api/{pasteid}", APIHandler).Methods("GET")
	router.HandleFunc("/api/{pasteId}", DelHandler).Methods("DELETE")
	router.HandleFunc("/", RootHandler)
	err = http.ListenAndServe(configuration.Port, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Remove unneeded variable<commit_after>// Package pastebin is a simple modern and powerful pastebin service
package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	duration "github.com/channelmeter/iso8601duration"
	// uniuri is used for easy random string generation
	"github.com/dchest/uniuri"
	// pygments is used for syntax highlighting
	"github.com/ewhal/pygments"
	// mysql driver
	_ "github.com/go-sql-driver/mysql"
	// mux is used for url routing
	"github.com/gorilla/mux"
)

type Configuration struct {
	// ADDRESS that pastebin will return links for
	Address string
	// LENGTH of paste id
	Length int
	// PORT that pastebin will listen on
	Port string
	// USERNAME for database
	Username string
	// PASS database password
	Password string
	// NAME database name
	Name string
}

var configuration Configuration

// DATABASE connection String
var DATABASE string

// Template pages
var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

// Response API struct
type Response struct {
	SUCCESS bool   `json:"success"`
	STATUS  string `json:"status"`
	ID      string `json:"id"`
	TITLE   string `json:"title"`
	SHA1    string `json:"sha1"`
	URL     string `json:"url"`
	SIZE    int    `json:"size"`
	DELKEY  string `json:"delkey"`
}

// Page generation struct
type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

// check error handling function
func Check(err error) {
	if err != nil {
		log.Println(err)
	}
}

// GenerateName uses uniuri to generate a random string that isn't in the
// database
func GenerateName() string {
	// use uniuri to generate random string
	id := uniuri.NewLen(configuration.Length)

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()
	// query database if id exists and if it does call generateName again
	_, err = db.Query("select id from pastebin where id=?", id)
	if err != sql.ErrNoRows {
		GenerateName()
	}

	return id

}

// Sha1 hashes paste into a sha1 hash
func Sha1(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

// DurationFromExpiry takes the expiry in string format and returns the duration
// that the paste will exist for
func DurationFromExpiry(expiry string) time.Duration {
	if expiry == "" {
		expiry = "P20Y"
	}
	dura, err := duration.FromString(expiry) // dura is time.Duration type
	Check(err)

	duration := dura.ToDuration()

	return duration
}

// Save function handles the saving of each paste.
// raw string is the raw paste input
// lang string is the user specified language for syntax highlighting
// title string user customized title
// expiry string duration that the paste will exist for
// Returns Response struct
func Save(raw string, lang string, title string, expiry string) Response {

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()

	// hash paste data and query database to see if paste exists
	sha := Sha1(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin where hash=?", sha)

	if err != sql.ErrNoRows {
		for query.Next() {
			var id, title, hash, paste, delkey string
			err := query.Scan(&id, &title, &hash, &paste, &delkey)
			Check(err)
			url := configuration.Address + "/p/" + id
			return Response{true, "saved", id, title, hash, url, len(paste), delkey}
		}
	}
	id := GenerateName()
	url := configuration.Address + "/p/" + id
	if lang != "" {
		url += "/" + lang
	}

	const timeFormat = "2006-01-02 15:04:05"
	expiryTime := time.Now().Add(DurationFromExpiry(expiry)).Format(timeFormat)

	delKey := uniuri.NewLen(40)
	dataEscaped := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	Check(err)
	if title == "" {
		title = id
	}
	_, err = stmt.Exec(id, html.EscapeString(title), sha, dataEscaped, delKey, expiryTime)
	Check(err)

	return Response{true, "saved", id, title, sha, url, len(dataEscaped), delKey}
}

// DelHandler checks to see if delkey and pasteid exist in the database.
// if both exist and are correct the paste will be removed.
func DelHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["pasteId"]
	delkey := r.FormValue("delkey")

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()

	stmt, err := db.Prepare("delete from pastebin where delkey=? and id=?")
	Check(err)

	res, err := stmt.Exec(html.EscapeString(delkey), html.EscapeString(id))
	Check(err)

	_, err = res.RowsAffected()
	if err != sql.ErrNoRows {
		w.Header().Set("Content-Type", "application/json")
		b := Response{STATUS: "DELETED " + id}
		err := json.NewEncoder(w).Encode(b)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

// SaveHandler Handles saving pastes and outputing responses
func SaveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		b := Save(paste, lang, title, expiry)

		switch output {
		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

		}
	}

}

// Highlight uses user specified input to call pygments library to highlight the
// paste
func Highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

// GetPaste takes pasteid and language
// queries the database and returns paste data
func GetPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()
	var title, s string
	var expiry string
	err = db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	Check(err)
	if time.Now().Format("2006-01-02 15:04:05") >= expiry {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		Check(err)
		_, err = stmt.Exec(param1)
		Check(err)
		return "Error invalid paste", ""
	}

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	}
	if lang != "" {
		high, err := Highlight(s, lang)
		Check(err)
		return high, html.UnescapeString(title)
	}
	return html.UnescapeString(s), html.UnescapeString(title)
}

// APIHandler handles get requests of pastes
func APIHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]

	b, _ := GetPaste(paste, "")
	w.Header().Set("Content-Type", "application/json")
	err := json.NewEncoder(w).Encode(b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

}

// PasteHandler handles the generation of paste pages with the links
func PasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]

	s, title := GetPaste(paste, lang)

	// button links
	link := configuration.Address + "/raw/" + paste
	download := configuration.Address + "/download/" + paste
	clone := configuration.Address + "/clone/" + paste
	// Page struct
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     configuration.Address,
		Download: download,
		Clone:    clone,
	}
	if lang == "" {

		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), p.Title, p.Title, s, p.Home, p.Download, p.Raw, p.Clone)

	}
}

// CloneHandler handles generating the clone pages
func CloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]

	s, title := GetPaste(paste, "")

	// Page links
	link := configuration.Address + "/raw/" + paste
	download := configuration.Address + "/download/" + paste
	clone := configuration.Address + "/clone/" + paste

	// Clone page struct
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     configuration.Address,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

// DownloadHandler forces downloads of selected pastes
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := GetPaste(paste, "")

	// Set header to an attachment so browser will automatically download it
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}

// RawHandler displays the pastes in text/plain format
func RawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := GetPaste(paste, "")

	w.Header().Set("Content-Type", "text/plain; charset=UTF-8; imeanit=yes")
	// simply write string to browser
	io.WriteString(w, s)

}

// RootHandler handles generating the root page
func RootHandler(w http.ResponseWriter, r *http.Request) {
	err := templates.ExecuteTemplate(w, "index.html", &Page{})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func main() {
	file, err := os.Open("config.json")
	if err != nil {
		panic(err)
	}
	decoder := json.NewDecoder(file)
	configuration := Configuration{}
	err = decoder.Decode(&configuration)
	if err != nil {
		panic(err)
	}

	DATABASE = configuration.Username + ":" + configuration.Password + "@/" + configuration.Name + "?charset=utf8"
	// create new mux router
	router := mux.NewRouter()

	// serverside rending stuff
	router.HandleFunc("/p/{pasteId}", PasteHandler).Methods("GET")
	router.HandleFunc("/raw/{pasteId}", RawHandler).Methods("GET")
	router.HandleFunc("/p/{pasteId}/{lang}", PasteHandler).Methods("GET")
	router.HandleFunc("/clone/{pasteId}", CloneHandler).Methods("GET")
	router.HandleFunc("/download/{pasteId}", DownloadHandler).Methods("GET")
	// api
	router.HandleFunc("/api", SaveHandler).Methods("POST")
	router.HandleFunc("/api/{output}", SaveHandler).Methods("POST")
	router.HandleFunc("/api/{pasteid}", APIHandler).Methods("GET")
	router.HandleFunc("/api/{pasteId}", DelHandler).Methods("DELETE")
	router.HandleFunc("/", RootHandler)
	err = http.ListenAndServe(configuration.Port, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>// Copyright 2015 The Serulian Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package es5

// Note: nativenew is based on http://www.bennadel.com/blog/2291-invoking-a-native-javascript-constructor-using-call-or-apply.htm
// Note: toType is based on https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
// Note: uuid generation from https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript

// runtimeTemplate contains all the necessary code for wrapping generated modules into a complete Serulian
// runtime bundle.
const runtimeTemplate = `
this.Serulian = (function($global) {
  var $__currentScriptSrc = null;
  if (typeof document === 'object') {
    $__currentScriptSrc = document.currentScript.src;
  }

  $global.__serulian_internal = {
    'autoNominalWrap': function(k, v) {
      if (v == null) {
        return v;
      }

      var typeName = $t.toType(v);
      switch (typeName) {
        case 'object':
          if (k != '') {
            return $t.nominalwrap(v, $a.mapping($t.any));
          }
          break;

        case 'array':
          return $t.nominalwrap(v, $a.slice($t.any));

        case 'boolean':
          return $t.nominalwrap(v, $a.bool);

        case 'string':
          return $t.nominalwrap(v, $a.string);

        case 'number':
          if (Math.ceil(v) == v) {
            return $t.nominalwrap(v, $a.int);
          }

          return $t.nominalwrap(v, $a.float64);
      }

      return v;
    }
  };

  var $g = {};
  var $a = {};
  var $w = {};

  var $t = {
    'toType': function(obj) {
      return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
    },

    'any': new Function("return function any() {};")(),

    'cast': function(value, type) {
      // TODO: implement cast checking.
      return value
    },

    'uuid': function() {
        var buf = new Uint16Array(8);
        crypto.getRandomValues(buf);
        var S4 = function(num) {
            var ret = num.toString(16);
            while(ret.length < 4){
                ret = "0"+ret;
            }
            return ret;
        };
        return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
    },

    'nativenew': function(type) {
      return function () {
        var newInstance = Object.create(type.prototype);
        newInstance = type.apply(newInstance, arguments) || newInstance;
        return newInstance;
      };
    },

    'nominalroot': function(instance) {
      if (instance.$wrapped) {
        return instance.$wrapped;
      }

      return instance;
    },

    'nominalwrap': function(instance, type) {
      return type.new(instance)
    },

    'nominalunwrap': function(instance) {
      return instance.$wrapped;
    },

    'workerwrap': function(methodId, f) {
      $w[methodId] = f;

      // If already inside a worker, return a function to execute asynchronously locally.
      if (!$__currentScriptSrc) {
        return function() {
          var promise = new Promise(function(resolve, reject) {
            $global.setTimeout(function() {
              f().then(function(value) {
                resolve(value);
              }).catch(function(value) {
                reject(value);
              });
            }, 0);
          });
          return promise;
        };
      }

      // Otherwise return a function to execute via a worker.
      return function() {
         var args = Array.prototype.slice.call(arguments);
         var token = $t.uuid();

         var promise = new Promise(function(resolve, reject) {
           var worker = new Worker($__currentScriptSrc + "?__serulian_async_token=" + token);
           worker.onmessage = function(e) {
              if (!e.isTrusted) {
                worker.terminate();
                return;
              }

              var data = e.data;
              if (data['token'] != token) {
                return;
              }

              if (data['result']) {
                resolve(data['result']);
              } else {
                reject(data['reject']);
              }

              worker.terminate();
           };

           worker.postMessage({
            'action': 'invoke',
            'arguments': args,
            'method': methodId,
            'token': token
           });
         });
         return promise;
      };
    },

    'property': function(getter, opt_setter) {
      var f = function() {
        if (arguments.length == 1) {
          return opt_setter.apply(this, arguments);
        } else {
          return getter.apply(this, arguments);
        }
      };

      f.$property = true;
      return f;
    },

    'dynamicaccess': function(obj, name) {
      if (obj == null || obj[name] == null) {
        return null;
      }

      var value = obj[name];
      if (typeof value == 'function' && value.$property) {
        return $promise.wrap(function() {
          return value.apply(obj, arguments);
        });
      }

      return value
    },

    'nullcompare': function(first, second) {
      return first == null ? second : first;
    },

  	'sm': function(caller) {
  		return {
        resources: {},
  			current: 0,
  			next: caller,

        pushr: function(value, name) {
          this.resources[name] = value;
        },

        popr: function(names) {
          var promises = [];

          for (var i = 0; i < arguments.length; ++i) {
            var name = arguments[i];
            if (this.resources[name]) {
              promises.push(this.resources[name].Release());
              delete this.resources[name];
            }
          }

          if (promises.length > 0) {
            return $promise.all(promises);
          } else {
            return $promise.resolve(null);
          }
        },

        popall: function() {
          for (var name in this.resources) {
            if (this.resources.hasOwnProperty(name)) {
              this.resources[name].Release();
            }
          }
        }
  		};
  	}
  };

  var $promise = {
  	'build': function(statemachine) {
  		return new Promise(function(resolve, reject) {
        statemachine.resolve = function(value) {
          statemachine.popall();
          statemachine.current = -1;
          resolve(value);
        };

        statemachine.reject = function(value) {
          statemachine.popall();
          statemachine.current = -1;
          reject(value);
        };

  			var continueFunc = function() {
  				if (statemachine.current < 0) {
  					return;
  				}

  				statemachine.next(callFunc);
			  };

        var callFunc = function() {
    			continueFunc();
          if (statemachine.current < 0) {
            statemachine.resolve(null);
          }
        };

        callFunc();
  		});
  	},

  	'all': function(promises) {
  		return Promise.all(promises);
  	},

  	'empty': function() {
  		return new Promise(function() {
  			resolve();
  		});
  	},

    'resolve': function(value) {
      return Promise.resolve(value);
    },

  	'wrap': function(func) {
  		return Promise.resolve(func());
  	},

    'translate': function(prom) {
       if (!prom.Then) {
         return prom;
       }

       return {
          'then': function() {
             return prom.Then.apply(prom, arguments);
          },
          'catch': function() {
             return prom.Catch.apply(prom, arguments);
          }
       };
    }
  };

  var moduleInits = [];

  var $module = function(name, creator) {
  	var module = {};

    var parts = name.split('.');
    var current = $g;
    for (var i = 0; i < parts.length - 1; ++i) {
      if (!current[parts[i]]) {
        current[parts[i]] = {};
      }
      current = current[parts[i]]
    }

    current[parts[parts.length - 1]] = module;

  	module.$init = function(cpromise) {
  	  moduleInits.push(cpromise);
  	};

    module.$newtypebuilder = function(kind) {
      return function(name, hasGenerics, alias, creator) {
        var buildType = function(n, args) {
          var tpe = new Function("return function " + n + "() {};")();
          creator.apply(tpe, args || []);

          if (kind == 'type') {
            tpe.prototype.toJSON = function() {
              return $t.nominalunwrap(this);
            };
          } else if (kind == 'struct') {
            // Stringify.
            tpe.prototype.Stringify = function(T) {
              var $this = this;
              return function() {
                // Special case JSON, as it uses an internal method.
                if (T == $a['$json']) {
                  return $promise.resolve(JSON.stringify($this.data));
                }

                return T.Get().then(function(resolved) {
                  return resolved.Stringify($t.any)($this.data);
                });
              };
            };

            // Parse.
            tpe.Parse = function(T) {
              return function(value) {
                // TODO: Validate the struct.

                // Special case JSON for performance, as it uses an internal method.
                if (T == $a['$json']) {
                  var created = new tpe();
                  created.data = JSON.parse($t.nominalunwrap(value));
                  return $promise.resolve(created);
                }

                return T.Get().then(function(resolved) {
                  return (resolved.Parse($t.any)(value)).then(function(parsed) {
                    var created = new tpe();
                    // TODO: *efficiently* unwrap internal nominal types.
                    created.data = JSON.parse(JSON.stringify($t.nominalunwrap(parsed)));
                    return $promise.resolve(created);
                  });
                });
              };
            };
          }

          return tpe;
        };

        if (hasGenerics) {
          module[name] = function(__genericargs) {
            var fullName = name;
            for (var i = 0; i < arguments.length; ++i) {
              fullName = fullName + '_' + arguments[i].name;
            }

            return buildType(fullName, arguments);
          };
        } else {
          module[name] = buildType(name);
        }

        if (alias) {
          $a[alias] = module[name];
        }
      };
    };

    module.$struct = module.$newtypebuilder('struct');
  	module.$class = module.$newtypebuilder('class');
  	module.$interface = module.$newtypebuilder('interface');
    module.$type = module.$newtypebuilder('type');

  	creator.call(module)
  };

  {{ range $idx, $kv := .Iter }}
  	{{ $kv.Value }}
  {{ end }}

  $g.executeWorkerMethod = function(token) {
    $global.onmessage = function(e) {
      if (!e.isTrusted) {
        $global.close();
        return;
      }

      var data = e.data;
      if (data['token'] != token) {
        throw Error('Invalid token')
        $global.close();
      }

      switch (data['action']) {
        case 'invoke':
          var methodId = data['method'];
          var arguments = data['arguments'];
          var method = $w[methodId];

          method.apply(null, arguments).then(function(result) {
            $global.postMessage({
              'result': result,
              'token': token
            });
            $global.close();
          }).catch(function(reject) {
            $global.postMessage({
              'reject': reject,
              'token': token
            });
            $global.close();
          });
          break
      }
    };
  };

  return $promise.all(moduleInits).then(function() {
  	return $g;
  });
})(this)

// Handle web-worker calls.
if (typeof importScripts === 'function') {
  var runWorker = function() {
    var search = location.search;
    if (!search || search[0] != '?') {
      return;
    }

    var searchPairs = search.substr(1).split('&')
    if (searchPairs.length < 1) {
      return;
    }

    for (var i = 0; i < searchPairs.length; ++i) {
      var pair = searchPairs[i].split('=');
      if (pair[0] == '__serulian_async_token') {
        this.Serulian.then(function(global) {
          global.executeWorkerMethod(pair[1]);
        });
        return;
      }
    }

    close();
  };
  runWorker();
}
`
<commit_msg>Ensure that nominals are only ever one level deep<commit_after>// Copyright 2015 The Serulian Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package es5

// Note: nativenew is based on http://www.bennadel.com/blog/2291-invoking-a-native-javascript-constructor-using-call-or-apply.htm
// Note: toType is based on https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
// Note: uuid generation from https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript

// runtimeTemplate contains all the necessary code for wrapping generated modules into a complete Serulian
// runtime bundle.
const runtimeTemplate = `
this.Serulian = (function($global) {
  var $__currentScriptSrc = null;
  if (typeof document === 'object') {
    $__currentScriptSrc = document.currentScript.src;
  }

  $global.__serulian_internal = {
    'autoNominalWrap': function(k, v) {
      if (v == null) {
        return v;
      }

      var typeName = $t.toType(v);
      switch (typeName) {
        case 'object':
          if (k != '') {
            return $t.nominalwrap(v, $a.mapping($t.any));
          }
          break;

        case 'array':
          return $t.nominalwrap(v, $a.slice($t.any));

        case 'boolean':
          return $t.nominalwrap(v, $a.bool);

        case 'string':
          return $t.nominalwrap(v, $a.string);

        case 'number':
          if (Math.ceil(v) == v) {
            return $t.nominalwrap(v, $a.int);
          }

          return $t.nominalwrap(v, $a.float64);
      }

      return v;
    }
  };

  var $g = {};
  var $a = {};
  var $w = {};

  var $t = {
    'toType': function(obj) {
      return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
    },

    'any': new Function("return function any() {};")(),

    'cast': function(value, type) {
      // TODO: implement cast checking.
      return value
    },

    'uuid': function() {
        var buf = new Uint16Array(8);
        crypto.getRandomValues(buf);
        var S4 = function(num) {
            var ret = num.toString(16);
            while(ret.length < 4){
                ret = "0"+ret;
            }
            return ret;
        };
        return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
    },

    'nativenew': function(type) {
      return function () {
        var newInstance = Object.create(type.prototype);
        newInstance = type.apply(newInstance, arguments) || newInstance;
        return newInstance;
      };
    },

    'nominalroot': function(instance) {
      if (instance.$wrapped) {
        return instance.$wrapped;
      }

      return instance;
    },

    'nominalwrap': function(instance, type) {
      return type.new($t.nominalroot(instance))
    },

    'nominalunwrap': function(instance) {
      return instance.$wrapped;
    },

    'workerwrap': function(methodId, f) {
      $w[methodId] = f;

      // If already inside a worker, return a function to execute asynchronously locally.
      if (!$__currentScriptSrc) {
        return function() {
          var promise = new Promise(function(resolve, reject) {
            $global.setTimeout(function() {
              f().then(function(value) {
                resolve(value);
              }).catch(function(value) {
                reject(value);
              });
            }, 0);
          });
          return promise;
        };
      }

      // Otherwise return a function to execute via a worker.
      return function() {
         var args = Array.prototype.slice.call(arguments);
         var token = $t.uuid();

         var promise = new Promise(function(resolve, reject) {
           var worker = new Worker($__currentScriptSrc + "?__serulian_async_token=" + token);
           worker.onmessage = function(e) {
              if (!e.isTrusted) {
                worker.terminate();
                return;
              }

              var data = e.data;
              if (data['token'] != token) {
                return;
              }

              if (data['result']) {
                resolve(data['result']);
              } else {
                reject(data['reject']);
              }

              worker.terminate();
           };

           worker.postMessage({
            'action': 'invoke',
            'arguments': args,
            'method': methodId,
            'token': token
           });
         });
         return promise;
      };
    },

    'property': function(getter, opt_setter) {
      var f = function() {
        if (arguments.length == 1) {
          return opt_setter.apply(this, arguments);
        } else {
          return getter.apply(this, arguments);
        }
      };

      f.$property = true;
      return f;
    },

    'dynamicaccess': function(obj, name) {
      if (obj == null || obj[name] == null) {
        return null;
      }

      var value = obj[name];
      if (typeof value == 'function' && value.$property) {
        return $promise.wrap(function() {
          return value.apply(obj, arguments);
        });
      }

      return value
    },

    'nullcompare': function(first, second) {
      return first == null ? second : first;
    },

  	'sm': function(caller) {
  		return {
        resources: {},
  			current: 0,
  			next: caller,

        pushr: function(value, name) {
          this.resources[name] = value;
        },

        popr: function(names) {
          var promises = [];

          for (var i = 0; i < arguments.length; ++i) {
            var name = arguments[i];
            if (this.resources[name]) {
              promises.push(this.resources[name].Release());
              delete this.resources[name];
            }
          }

          if (promises.length > 0) {
            return $promise.all(promises);
          } else {
            return $promise.resolve(null);
          }
        },

        popall: function() {
          for (var name in this.resources) {
            if (this.resources.hasOwnProperty(name)) {
              this.resources[name].Release();
            }
          }
        }
  		};
  	}
  };

  var $promise = {
  	'build': function(statemachine) {
  		return new Promise(function(resolve, reject) {
        statemachine.resolve = function(value) {
          statemachine.popall();
          statemachine.current = -1;
          resolve(value);
        };

        statemachine.reject = function(value) {
          statemachine.popall();
          statemachine.current = -1;
          reject(value);
        };

  			var continueFunc = function() {
  				if (statemachine.current < 0) {
  					return;
  				}

  				statemachine.next(callFunc);
			  };

        var callFunc = function() {
    			continueFunc();
          if (statemachine.current < 0) {
            statemachine.resolve(null);
          }
        };

        callFunc();
  		});
  	},

  	'all': function(promises) {
  		return Promise.all(promises);
  	},

  	'empty': function() {
  		return new Promise(function() {
  			resolve();
  		});
  	},

    'resolve': function(value) {
      return Promise.resolve(value);
    },

  	'wrap': function(func) {
  		return Promise.resolve(func());
  	},

    'translate': function(prom) {
       if (!prom.Then) {
         return prom;
       }

       return {
          'then': function() {
             return prom.Then.apply(prom, arguments);
          },
          'catch': function() {
             return prom.Catch.apply(prom, arguments);
          }
       };
    }
  };

  var moduleInits = [];

  var $module = function(name, creator) {
  	var module = {};

    var parts = name.split('.');
    var current = $g;
    for (var i = 0; i < parts.length - 1; ++i) {
      if (!current[parts[i]]) {
        current[parts[i]] = {};
      }
      current = current[parts[i]]
    }

    current[parts[parts.length - 1]] = module;

  	module.$init = function(cpromise) {
  	  moduleInits.push(cpromise);
  	};

    module.$newtypebuilder = function(kind) {
      return function(name, hasGenerics, alias, creator) {
        var buildType = function(n, args) {
          var tpe = new Function("return function " + n + "() {};")();
          creator.apply(tpe, args || []);

          if (kind == 'type') {
            tpe.prototype.toJSON = function() {
              return $t.nominalunwrap(this);
            };
          } else if (kind == 'struct') {
            // Stringify.
            tpe.prototype.Stringify = function(T) {
              var $this = this;
              return function() {
                // Special case JSON, as it uses an internal method.
                if (T == $a['$json']) {
                  return $promise.resolve(JSON.stringify($this.data));
                }

                return T.Get().then(function(resolved) {
                  return resolved.Stringify($t.any)($this.data);
                });
              };
            };

            // Parse.
            tpe.Parse = function(T) {
              return function(value) {
                // TODO: Validate the struct.

                // Special case JSON for performance, as it uses an internal method.
                if (T == $a['$json']) {
                  var created = new tpe();
                  created.data = JSON.parse($t.nominalunwrap(value));
                  return $promise.resolve(created);
                }

                return T.Get().then(function(resolved) {
                  return (resolved.Parse($t.any)(value)).then(function(parsed) {
                    var created = new tpe();
                    // TODO: *efficiently* unwrap internal nominal types.
                    created.data = JSON.parse(JSON.stringify($t.nominalunwrap(parsed)));
                    return $promise.resolve(created);
                  });
                });
              };
            };
          }

          return tpe;
        };

        if (hasGenerics) {
          module[name] = function(__genericargs) {
            var fullName = name;
            for (var i = 0; i < arguments.length; ++i) {
              fullName = fullName + '_' + arguments[i].name;
            }

            return buildType(fullName, arguments);
          };
        } else {
          module[name] = buildType(name);
        }

        if (alias) {
          $a[alias] = module[name];
        }
      };
    };

    module.$struct = module.$newtypebuilder('struct');
  	module.$class = module.$newtypebuilder('class');
  	module.$interface = module.$newtypebuilder('interface');
    module.$type = module.$newtypebuilder('type');

  	creator.call(module)
  };

  {{ range $idx, $kv := .Iter }}
  	{{ $kv.Value }}
  {{ end }}

  $g.executeWorkerMethod = function(token) {
    $global.onmessage = function(e) {
      if (!e.isTrusted) {
        $global.close();
        return;
      }

      var data = e.data;
      if (data['token'] != token) {
        throw Error('Invalid token')
        $global.close();
      }

      switch (data['action']) {
        case 'invoke':
          var methodId = data['method'];
          var arguments = data['arguments'];
          var method = $w[methodId];

          method.apply(null, arguments).then(function(result) {
            $global.postMessage({
              'result': result,
              'token': token
            });
            $global.close();
          }).catch(function(reject) {
            $global.postMessage({
              'reject': reject,
              'token': token
            });
            $global.close();
          });
          break
      }
    };
  };

  return $promise.all(moduleInits).then(function() {
  	return $g;
  });
})(this)

// Handle web-worker calls.
if (typeof importScripts === 'function') {
  var runWorker = function() {
    var search = location.search;
    if (!search || search[0] != '?') {
      return;
    }

    var searchPairs = search.substr(1).split('&')
    if (searchPairs.length < 1) {
      return;
    }

    for (var i = 0; i < searchPairs.length; ++i) {
      var pair = searchPairs[i].split('=');
      if (pair[0] == '__serulian_async_token') {
        this.Serulian.then(function(global) {
          global.executeWorkerMethod(pair[1]);
        });
        return;
      }
    }

    close();
  };
  runWorker();
}
`
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"
	"text/template"
	"time"

	"github.com/MaxCDN/go-maxcdn"
	"github.com/codegangsta/cli"
	"gopkg.in/yaml.v1"
)

var start time.Time
var config Config

func init() {
	// Override cli's default help template
	cli.AppHelpTemplate = `Usage: {{.Name}} [arguments...]
Options:
   {{range .Flags}}{{.}}
   {{end}}

'alias', 'token' 'secret' and/or 'zone' can be set via exporting them
to your environment and ALIAS, TOKEN, SECRET and/or ZONE.

Additionally, they can be set in a YAML configuration via the
config option. 'host' can also be set via configuration, but not
environment.

Precedence is argument > environment > configuration.

WARNING:
    Default configuration path works for *nix systems only and
    replies on the 'HOME' environment variable. For Windows, please
    supply a full path.

Sample configuration:

    ---
    alias: YOUR_ALIAS
    token: YOUR_TOKEN
    secret: YOUR_SECRET
    zone: YOUR_ZONE_ID

`

	app := cli.NewApp()

	app.Name = "maxpurge"
	app.Version = "1.0.1"

	cli.HelpPrinter = helpPrinter
	cli.VersionPrinter = versionPrinter

	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "config, c", Value: "~/.maxcdn.yml", Usage: "yaml file containing all required args"},
		cli.StringFlag{Name: "alias, a", Value: "", Usage: "[required] consumer alias"},
		cli.StringFlag{Name: "token, t", Value: "", Usage: "[required] consumer token"},
		cli.StringFlag{Name: "secret, s", Value: "", Usage: "[required] consumer secret"},
		cli.IntSliceFlag{Name: "zone, z", Value: new(cli.IntSlice), Usage: "[required] zone to be purged"},
		cli.StringSliceFlag{Name: "file, f", Value: new(cli.StringSlice), Usage: "cached file to be purged"},
		cli.StringFlag{Name: "host, H", Value: "", Usage: "override default API host"},
		cli.BoolFlag{Name: "verbose", Usage: "display verbose http transport information"},
	}

	app.Action = func(c *cli.Context) {
		// Precedence
		// 1. CLI Argument
		// 2. Environment (when applicable)
		// 3. Configuration

		config, _ = LoadConfig(c.String("config"))

		if v := c.String("alias"); v != "" {
			config.Alias = v
		} else if v := os.Getenv("ALIAS"); v != "" {
			config.Alias = v
		}

		if v := c.String("token"); v != "" {
			config.Token = v
		} else if v := os.Getenv("TOKEN"); v != "" {
			config.Token = v
		}

		if v := c.String("secret"); v != "" {
			config.Secret = v
		} else if v := os.Getenv("SECRET"); v != "" {
			config.Secret = v
		}

		if v := c.IntSlice("zone"); len(v) != 0 {
			config.Zones = v
		} else if v := os.Getenv("ZONE"); v != "" {
			zones := strings.Split(v, ",")
			for i, z := range zones {
				n, err := strconv.ParseInt(strings.TrimSpace(z), 0, 64)
				check(err)

				config.Zones[i] = int(n)
			}
		}

		config.Files = c.StringSlice("file")
		config.Verbose = c.Bool("verbose")

		if v := config.Validate(); v != "" {
			fmt.Printf("argument error:\n%s\n", v)
			cli.ShowAppHelp(c)
		}

		if v := c.String("host"); v != "" {
			config.Host = v
		}
		// handle host override
		if config.Host != "" {
			maxcdn.APIHost = config.Host
		}
	}

	app.Run(os.Args)

	start = time.Now()
}

func main() {
	max := maxcdn.NewMaxCDN(config.Alias, config.Token, config.Secret)
	max.Verbose = config.Verbose

	var response []*maxcdn.Response
	var err error
	var successful bool

	if len(config.Files) != 0 {
		var resps []*maxcdn.Response
		for _, zone := range config.Zones {
			resps, err = max.PurgeFiles(zone, config.Files)
			response = append(response, resps...)
		}
		successful = len(response) == (len(config.Files) * len(config.Zones))
	} else {
		response, err = max.PurgeZones(config.Zones)
		successful = (len(response) == len(config.Zones))
	}
	check(err)

	if successful {
		fmt.Printf("Purge successful after: %v.\n", time.Since(start))
	} else {
		check(fmt.Errorf("error: one or more of your purges did not succeed"))
	}
}

func check(err error) {
	if err != nil {
		fmt.Printf("%v\n\nPurge failed after %v.\n", err, time.Since(start))
		os.Exit(2)
	}
}

// Replace cli's default help printer with cli's default help printer
// plus an exit at the end.
func helpPrinter(templ string, data interface{}) {
	w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
	t := template.Must(template.New("help").Parse(templ))
	err := t.Execute(w, data)
	if err != nil {
		panic(err)
	}
	w.Flush()
	os.Exit(0)
}

// Replace cli's default version printer with cli's default version printer
// plus an exit at the end.
func versionPrinter(c *cli.Context) {
	fmt.Printf("%v version %v\n", c.App.Name, c.App.Version)
	os.Exit(0)
}

/*
 * Config file handlers
 */

type Config struct {
	Host    string `yaml: host,omitempty`
	Alias   string `yaml: alias,omitempty`
	Token   string `yaml: token,omitempty`
	Secret  string `yaml: secret,omitempty`
	Zones   []int  `yaml: secret,omitempty`
	Files   []string
	Verbose bool
}

func LoadConfig(file string) (c Config, e error) {
	// TODO: this is unix only, look at fixing for windows
	file = strings.Replace(file, "~", os.Getenv("HOME"), 1)

	c = Config{}
	if data, err := ioutil.ReadFile(file); err == nil {
		e = yaml.Unmarshal(data, &c)
	}

	return
}

func (c *Config) Validate() (out string) {
	if c.Alias == "" {
		out += "- missing alias value\n"
	}

	if c.Token == "" {
		out += "- missing token value\n"
	}

	if c.Secret == "" {
		out += "- missing secret value\n"
	}

	if len(c.Zones) == 0 {
		out += "- missing zones value\n"
	}

	return
}
<commit_msg>Fixing help issue. Version bump.<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"
	"text/template"
	"time"

	"github.com/MaxCDN/go-maxcdn"
	"github.com/codegangsta/cli"
	"gopkg.in/yaml.v1"
)

var start time.Time
var config Config

func init() {
	// Override cli's default help template
	cli.AppHelpTemplate = `Usage: {{.Name}} [arguments...]
Options:
   {{range .Flags}}{{.}}
   {{end}}

'alias', 'token' 'secret' and/or 'zone' can be set via exporting them
to your environment and ALIAS, TOKEN, SECRET and/or ZONE.

Additionally, they can be set in a YAML configuration via the
config option. 'host' can also be set via configuration, but not
environment.

Precedence is argument > environment > configuration.

WARNING:
    Default configuration path works for *nix systems only and
    replies on the 'HOME' environment variable. For Windows, please
    supply a full path.

Sample configuration:

    ---
    alias: YOUR_ALIAS
    token: YOUR_TOKEN
    secret: YOUR_SECRET
    zones:
        - ZONE_ID_1
        - ZONE_ID_2

`

	app := cli.NewApp()

	app.Name = "maxpurge"
	app.Version = "1.0.2"

	cli.HelpPrinter = helpPrinter
	cli.VersionPrinter = versionPrinter

	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "config, c", Value: "~/.maxcdn.yml", Usage: "yaml file containing all required args"},
		cli.StringFlag{Name: "alias, a", Value: "", Usage: "[required] consumer alias"},
		cli.StringFlag{Name: "token, t", Value: "", Usage: "[required] consumer token"},
		cli.StringFlag{Name: "secret, s", Value: "", Usage: "[required] consumer secret"},
		cli.IntSliceFlag{Name: "zone, z", Value: new(cli.IntSlice), Usage: "[required] zone to be purged"},
		cli.StringSliceFlag{Name: "file, f", Value: new(cli.StringSlice), Usage: "cached file to be purged"},
		cli.StringFlag{Name: "host, H", Value: "", Usage: "override default API host"},
		cli.BoolFlag{Name: "verbose", Usage: "display verbose http transport information"},
	}

	app.Action = func(c *cli.Context) {
		// Precedence
		// 1. CLI Argument
		// 2. Environment (when applicable)
		// 3. Configuration

		config, _ = LoadConfig(c.String("config"))

		if v := c.String("alias"); v != "" {
			config.Alias = v
		} else if v := os.Getenv("ALIAS"); v != "" {
			config.Alias = v
		}

		if v := c.String("token"); v != "" {
			config.Token = v
		} else if v := os.Getenv("TOKEN"); v != "" {
			config.Token = v
		}

		if v := c.String("secret"); v != "" {
			config.Secret = v
		} else if v := os.Getenv("SECRET"); v != "" {
			config.Secret = v
		}

		if v := c.IntSlice("zone"); len(v) != 0 {
			config.Zones = v
		} else if v := os.Getenv("ZONE"); v != "" {
			zones := strings.Split(v, ",")
			for i, z := range zones {
				n, err := strconv.ParseInt(strings.TrimSpace(z), 0, 64)
				check(err)

				config.Zones[i] = int(n)
			}
		}

		config.Files = c.StringSlice("file")
		config.Verbose = c.Bool("verbose")

		if v := config.Validate(); v != "" {
			fmt.Printf("argument error:\n%s\n", v)
			cli.ShowAppHelp(c)
		}

		if v := c.String("host"); v != "" {
			config.Host = v
		}
		// handle host override
		if config.Host != "" {
			maxcdn.APIHost = config.Host
		}
	}

	app.Run(os.Args)

	start = time.Now()
}

func main() {
	max := maxcdn.NewMaxCDN(config.Alias, config.Token, config.Secret)
	max.Verbose = config.Verbose

	var response []*maxcdn.Response
	var err error
	var successful bool

	if len(config.Files) != 0 {
		var resps []*maxcdn.Response
		for _, zone := range config.Zones {
			resps, err = max.PurgeFiles(zone, config.Files)
			response = append(response, resps...)
		}
		successful = len(response) == (len(config.Files) * len(config.Zones))
	} else {
		response, err = max.PurgeZones(config.Zones)
		successful = (len(response) == len(config.Zones))
	}
	check(err)

	if successful {
		fmt.Printf("Purge successful after: %v.\n", time.Since(start))
	} else {
		check(fmt.Errorf("error: one or more of your purges did not succeed"))
	}
}

func check(err error) {
	if err != nil {
		fmt.Printf("%v\n\nPurge failed after %v.\n", err, time.Since(start))
		os.Exit(2)
	}
}

// Replace cli's default help printer with cli's default help printer
// plus an exit at the end.
func helpPrinter(templ string, data interface{}) {
	w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
	t := template.Must(template.New("help").Parse(templ))
	err := t.Execute(w, data)
	if err != nil {
		panic(err)
	}
	w.Flush()
	os.Exit(0)
}

// Replace cli's default version printer with cli's default version printer
// plus an exit at the end.
func versionPrinter(c *cli.Context) {
	fmt.Printf("%v version %v\n", c.App.Name, c.App.Version)
	os.Exit(0)
}

/*
 * Config file handlers
 */

type Config struct {
	Host    string `yaml: host,omitempty`
	Alias   string `yaml: alias,omitempty`
	Token   string `yaml: token,omitempty`
	Secret  string `yaml: secret,omitempty`
	Zones   []int  `yaml: secret,omitempty`
	Files   []string
	Verbose bool
}

func LoadConfig(file string) (c Config, e error) {
	// TODO: this is unix only, look at fixing for windows
	file = strings.Replace(file, "~", os.Getenv("HOME"), 1)

	c = Config{}
	if data, err := ioutil.ReadFile(file); err == nil {
		e = yaml.Unmarshal(data, &c)
	}

	return
}

func (c *Config) Validate() (out string) {
	if c.Alias == "" {
		out += "- missing alias value\n"
	}

	if c.Token == "" {
		out += "- missing token value\n"
	}

	if c.Secret == "" {
		out += "- missing secret value\n"
	}

	if len(c.Zones) == 0 {
		out += "- missing zones value\n"
	}

	return
}
<|endoftext|>