Merge pull request #8 from rohanthewiz/master

Update README for GOPATH limitation
diff --git a/alldocs.go b/alldocs.go
index 85e106b..bb5e889 100644
--- a/alldocs.go
+++ b/alldocs.go
@@ -62,6 +62,8 @@
 Flags:
 	-precaire
 		allow the use of insecure protocols.
+	-connections
+		count of parallel download connections.
 
 Update a local dependency
 
diff --git a/rebuild.go b/rebuild.go
index 9d4b0fa..87f13cd 100644
--- a/rebuild.go
+++ b/rebuild.go
@@ -6,16 +6,20 @@
 	"log"
 	"os"
 	"path/filepath"
+	"sync"
+	"sync/atomic"
 
 	"github.com/FiloSottile/gvt/gbvendor"
 )
 
 var (
-	rbInsecure bool // Allow the use of insecure protocols
+	rbInsecure    bool // Allow the use of insecure protocols
+	rbConnections uint // Count of concurrent download connections
 )
 
 func addRebuildFlags(fs *flag.FlagSet) {
 	fs.BoolVar(&rbInsecure, "precaire", false, "allow the use of insecure protocols")
+	fs.UintVar(&rbConnections, "connections", 8, "count of parallel download connections")
 }
 
 var cmdRebuild = &Command{
@@ -36,6 +40,8 @@
 Flags:
 	-precaire
 		allow the use of insecure protocols.
+	-connections
+		count of parallel download connections.
 `,
 	Run: func(args []string) error {
 		switch len(args) {
@@ -54,35 +60,63 @@
 		return fmt.Errorf("could not load manifest: %v", err)
 	}
 
-	for _, dep := range m.Dependencies {
-		dst := filepath.Join(vendorDir(), dep.Importpath)
-		if _, err := os.Stat(dst); err == nil {
-			if err := vendor.RemoveAll(dst); err != nil {
-				// TODO need to apply vendor.cleanpath here too
-				return fmt.Errorf("dependency could not be deleted: %v", err)
+	var errors uint32
+	var wg sync.WaitGroup
+	depC := make(chan vendor.Dependency)
+	for i := 0; i < int(rbConnections); i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			for d := range depC {
+				if err := downloadDependency(d); err != nil {
+					log.Printf("%s: %v", d.Importpath, err)
+					atomic.AddUint32(&errors, 1)
+				}
 			}
-		}
+		}()
+	}
 
-		log.Printf("fetching %s", dep.Importpath)
+	for _, dep := range m.Dependencies {
+		depC <- dep
+	}
+	close(depC)
+	wg.Wait()
 
-		repo, _, err := vendor.DeduceRemoteRepo(dep.Importpath, rbInsecure)
-		if err != nil {
-			return err
-		}
+	if errors > 0 {
+		return fmt.Errorf("failed to fetch %d dependencies", errors)
+	}
 
-		wc, err := repo.Checkout("", "", dep.Revision)
-		if err != nil {
-			return err
-		}
+	return nil
+}
 
-		src := filepath.Join(wc.Dir(), dep.Path)
-		if err := vendor.Copypath(dst, src); err != nil {
-			return err
+func downloadDependency(dep vendor.Dependency) error {
+	dst := filepath.Join(vendorDir(), dep.Importpath)
+	if _, err := os.Stat(dst); err == nil {
+		if err := vendor.RemoveAll(dst); err != nil {
+			// TODO need to apply vendor.cleanpath here too
+			return fmt.Errorf("dependency could not be deleted: %v", err)
 		}
+	}
 
-		if err := wc.Destroy(); err != nil {
-			return err
-		}
+	log.Printf("fetching %s", dep.Importpath)
+
+	repo, _, err := vendor.DeduceRemoteRepo(dep.Importpath, rbInsecure)
+	if err != nil {
+		return err
+	}
+
+	wc, err := repo.Checkout("", "", dep.Revision)
+	if err != nil {
+		return err
+	}
+
+	src := filepath.Join(wc.Dir(), dep.Path)
+	if err := vendor.Copypath(dst, src); err != nil {
+		return err
+	}
+
+	if err := wc.Destroy(); err != nil {
+		return err
 	}
 
 	return nil