Skip to content

Instantly share code, notes, and snippets.

@barelyhuman
Created December 13, 2024 13:44
Show Gist options
  • Save barelyhuman/478ea13409de454ebfd37cb8106fe9ae to your computer and use it in GitHub Desktop.
Save barelyhuman/478ea13409de454ebfd37cb8106fe9ae to your computer and use it in GitHub Desktop.
[For reference] simpler npm registry package resolver and downloader
package main
import (
"archive/tar"
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
const registry = "https://registry.npmjs.com/"
const nodeModulesDir = "node_modules"
type PackageJSON struct {
Name string `json:"name"`
DevDependencies DepDefinition `json:"devDependencies"`
Dependencies DepDefinition `json:"dependencies"`
}
type PackageMeta struct {
Name string `json:"name"`
Versions map[string]Version
DistTags map[string]string `json:"dist-tags"`
}
type DepDefinition map[string]string
type DistDef struct {
Tarball string `json:"tarball"`
}
type Version struct {
Name string `json:"name"`
DevDependencies DepDefinition `json:"devDependencies"`
Dependencies DepDefinition `json:"dependencies"`
Dist DistDef `json:"dist"`
}
func main() {
start := time.Now()
done := make(chan bool)
basePkg, _ := readPackageJSON("package.json")
resolved := map[string]bool{}
os.MkdirAll(nodeModulesDir, os.ModePerm)
go func() {
resolveDeps(basePkg.Dependencies, resolved, "node_modules")
done <- true
}()
go func() {
resolveDeps(basePkg.DevDependencies, resolved, "node_modules")
done <- true
}()
<-done
<-done
fmt.Println("Downloaded\n\n")
updateTerminalLog("\nFinished in %v\n", time.Since(start))
}
func getPkgMeta(pkgName string) Version {
pkgPath, _ := url.JoinPath(registry, pkgName)
resp, err := http.Get(pkgPath)
if err != nil {
log.Printf("failed to download %v", pkgPath)
return Version{}
}
defer resp.Body.Close()
buf, _ := io.ReadAll(resp.Body)
pm := PackageMeta{}
if err = json.Unmarshal(buf, &pm); err != nil {
panic(err)
}
latestTag := pm.DistTags["latest"]
versionInfo := pm.Versions[latestTag]
return versionInfo
}
func resolveDeps(deps DepDefinition, resolved map[string]bool, parentPath string) {
var wg sync.WaitGroup
for depName := range deps {
if resolved[depName] {
continue
}
wg.Add(2)
pkg := getPkgMeta(depName)
go func() {
resolved[depName] = true
resolveDeps(pkg.Dependencies, resolved, filepath.Join(parentPath, depName, "node_modules"))
wg.Done()
}()
go func() {
downloadPkg(depName, pkg.Dist.Tarball, filepath.Join(parentPath, depName))
wg.Done()
}()
}
wg.Wait()
}
func downloadPkg(pkgName string, link string, downloadTo string) {
updateTerminalLog("Downloading %v", pkgName)
baseOutPath := filepath.Join(downloadTo)
tarFilePath := filepath.Join(pkgName + ".tar.gz")
os.MkdirAll(baseOutPath, os.ModePerm)
resp, err := http.Get(link)
if err != nil {
return
}
defer resp.Body.Close()
memBuffer := bytes.Buffer{}
defer memBuffer.Reset()
zr, err := gzip.NewReader(resp.Body)
if err != nil {
log.Fatal(err)
}
defer zr.Close()
// Just output the data for the example.
if _, err := io.Copy(&memBuffer, zr); err != nil {
log.Fatal(err)
}
tr := tar.NewReader(&memBuffer)
for {
hdr, err := tr.Next()
if err == io.EOF {
break // End of archive
}
if err != nil {
log.Fatal(err)
}
outfilePath := filepath.Join(baseOutPath, strings.Replace(hdr.Name, "package/", "./", 1))
outFileDir := filepath.Dir(outfilePath)
os.MkdirAll(outFileDir, os.ModePerm)
out, _ := os.Create(outfilePath)
defer out.Close()
if _, err := io.Copy(out, tr); err != nil {
continue
}
}
os.Remove(tarFilePath)
updateTerminalLog("Downloading %v ... done", pkgName)
}
func readPackageJSON(path string) (result PackageJSON, err error) {
fileData, err := os.ReadFile(path)
if err != nil {
return
}
if err = json.Unmarshal(fileData, &result); err != nil {
return
}
return
}
func updateTerminalLog(msg string, interfaces ...any) {
fmt.Printf("\033[1A\033[K")
fmt.Printf(msg+"\n", interfaces...)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment