Skip to content

Instantly share code, notes, and snippets.

@lluchs
Created June 27, 2012 13:02
Show Gist options
  • Save lluchs/3003943 to your computer and use it in GitHub Desktop.
Save lluchs/3003943 to your computer and use it in GitHub Desktop.
Automatic github downloader
package main
import "io"
import "time"
func copySleep(dst io.Writer, src io.Reader, delay int, progress func(written int64)) (written int64, err error) {
// If the writer has a ReadFrom method, use it to do the copy.
// Avoids an allocation and a copy.
if rt, ok := dst.(io.ReaderFrom); ok {
return rt.ReadFrom(src)
}
// Similarly, if the reader has a WriteTo method, use it to do the copy.
if wt, ok := src.(io.WriterTo); ok {
return wt.WriteTo(dst)
}
buf := make([]byte, 32*1024)
for {
nr, er := src.Read(buf)
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
if nw > 0 {
written += int64(nw)
}
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er == io.EOF {
break
}
if er != nil {
err = er
break
}
progress(written)
time.Sleep(time.Duration(delay) * time.Millisecond)
}
return written, err
}
package main
import "log"
import "fmt"
import "os"
import "strings"
import "net/http"
import "io"
import "io/ioutil"
import "archive/zip"
// change me!
const Branch = "master"
const GithubURL = "http://github.com/lluchs/Clinfinity/zipball/"
const prefixPathLength = 25
const progressBarWidth = 50
func main() {
clifiPath := "."
branch := Branch
download := true
var r *zip.Reader
var err error
// The first parameter can either be an archive that will be extracted (suffix '.zip')
// or a branch name.
if len(os.Args) > 1 {
if strings.HasSuffix(os.Args[1], ".zip") {
log.Printf("Using specified archive %s", os.Args[1])
var rc *zip.ReadCloser
rc, err = zip.OpenReader(os.Args[1])
defer rc.Close()
r = &rc.Reader
download = false
} else {
branch = os.Args[1]
}
}
if download {
downloadFile := createTempFile()
defer func() {
// close and remove the file
name := downloadFile.Name()
downloadFile.Close()
os.Remove(name)
}()
log.Printf("Downloading branch %s...", branch)
length := downloadArchive(downloadFile, branch)
log.Print("Download complete.")
r, err = zip.NewReader(downloadFile, length)
}
if err != nil {
log.Fatal(err)
}
log.Print("Extracting archive...")
// remove relevant archives
os.RemoveAll(clifiPath + "/Clinfinity.c4d")
os.RemoveAll(clifiPath + "/Clinfinity.c4f")
// progress
var total, i int64 = int64(len(r.File)), 0
// loop over all files
for _, f := range r.File {
relPath := f.Name[prefixPathLength:]
// ignore files outside of relevant folders
if !strings.HasPrefix(relPath, "/Clinfinity") { continue }
// absolute file path
path := clifiPath + relPath
// create folders, if necessary
os.MkdirAll(basePath(path), 0644)
// don't do anything else with directories
if path[len(path) - 1] == '/' { continue }
// create file
dest, err := os.Create(path)
if err != nil {
log.Fatal(err)
}
// open file in zip archive
rc, err := f.Open()
if err != nil {
log.Fatal(err)
}
// copy file content
_, err = io.Copy(dest, rc)
if err != nil {
log.Fatal(err)
}
rc.Close()
dest.Close()
// progress indicator
i++
progressBar(i, total)
}
println()
log.Print("Done")
}
func createTempFile() *os.File {
// create temporary file
downloadFile, err := ioutil.TempFile("", "github-get")
if err != nil {
log.Fatal(err)
}
return downloadFile
}
func downloadArchive(file *os.File, branch string) int64 {
// download the specified branch
url := GithubURL + branch
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
progress := func(written int64) {
if resp.ContentLength != -1 {
progressBar(written, resp.ContentLength)
}
}
// read the response
written, err := copySleep(file, resp.Body, 10, progress)
if err != nil {
log.Fatal(err)
}
println()
return written
}
func basePath(path string) string {
lastSlash := strings.LastIndex(path, "/")
if lastSlash != -1 {
path = path[:lastSlash]
}
return path
}
func progressBar(current int64, total int64) {
bar := "["
percent := 100 * current / total
tokens := progressBarWidth * current / total
var i int64
for i = 0; i < progressBarWidth; i++ {
if i < tokens {
bar += "="
} else {
bar += " "
}
}
bar += "]"
fmt.Printf("\r%s %d%%\r", bar, percent)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment