Created
November 17, 2020 22:27
-
-
Save spagettikod/f8e196c5f4e3d10fd5b346ccab186622 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"bytes" | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"os" | |
"strings" | |
) | |
type Extension struct { | |
UniqueID string | |
Version string | |
} | |
var ( | |
errLog = log.New(os.Stderr, "", 0) | |
infoLog *log.Logger | |
path string | |
dest string | |
verbose bool | |
) | |
func printUsage(msg string) { | |
if msg != "" { | |
fmt.Println(msg) | |
} | |
fmt.Println(` | |
Usage: dlvsix [OPTIONS] PATH DEST | |
Download Visual Studio Extensions. | |
Options: | |
-v Be more talkative`) | |
} | |
func (e Extension) Filename() string { | |
return fmt.Sprintf("%s.vsix", e.String()) | |
} | |
func (e Extension) String() string { | |
return fmt.Sprintf("%s-%s", e.UniqueID, e.Version) | |
} | |
func init() { | |
flag.BoolVar(&verbose, "v", false, "Be more talkative") | |
} | |
func isPlainText(data []byte) bool { | |
mime := http.DetectContentType(data) | |
return strings.Index(mime, "text/plain") == 0 | |
} | |
func isDir(p string) (bool, error) { | |
info, err := os.Stat(p) | |
if err != nil { | |
return false, err | |
} | |
return info.IsDir(), nil | |
} | |
func parse(data []byte, destFiles map[string]bool) (extensions []Extension, err error) { | |
buf := bytes.NewBuffer(data) | |
scanner := bufio.NewScanner(buf) | |
for scanner.Scan() { | |
line := strings.TrimSpace(scanner.Text()) | |
if strings.Index(line, "#") == 0 || len(line) == 0 { | |
continue | |
} | |
splitLine := strings.Split(line, " ") | |
ext := Extension{} | |
if len(splitLine) > 0 { | |
ext.UniqueID = splitLine[0] | |
if len(splitLine) == 2 { | |
ext.Version = splitLine[1] | |
} | |
if destFiles[ext.Filename()] { | |
infoLog.Printf(" extension '%s' already exist at destination, skipping", ext.String()) | |
} else { | |
extensions = append(extensions, ext) | |
infoLog.Printf(" extension '%s' has not been downloaded", ext.String()) | |
} | |
} | |
} | |
return extensions, scanner.Err() | |
} | |
func findExtensions(p string, destFiles map[string]bool) (extensions []Extension, err error) { | |
dir, err := isDir(p) | |
if err != nil { | |
return | |
} | |
if dir { | |
infoLog.Printf("found directory '%s'\n", p) | |
fis, err := ioutil.ReadDir(p) | |
if err != nil { | |
return extensions, err | |
} | |
for _, fi := range fis { | |
if !fi.IsDir() { | |
return findExtensions(fmt.Sprintf("%s%s%s", p, string(os.PathSeparator), fi.Name()), destFiles) | |
} | |
} | |
} else { | |
infoLog.Printf("found file '%s'\n", p) | |
data, err := ioutil.ReadFile(p) | |
if err != nil { | |
return extensions, err | |
} | |
if isPlainText(data) { | |
exts, err := parse(data, destFiles) | |
if err != nil { | |
return extensions, err | |
} | |
extensions = append(extensions, exts...) | |
} | |
} | |
return | |
} | |
func listDestFiles(dest string) (files map[string]bool, err error) { | |
if _, e := os.Stat(dest); os.IsNotExist(e) { | |
infoLog.Printf("destination directory '%s' not found, creating", dest) | |
os.Mkdir(dest, os.ModeDir|os.ModePerm) | |
} | |
fis, err := ioutil.ReadDir(dest) | |
if err != nil { | |
return | |
} | |
files = make(map[string]bool) | |
for _, fi := range fis { | |
files[fi.Name()] = true | |
} | |
return | |
} | |
func main() { | |
flag.Parse() | |
if verbose { | |
infoLog = log.New(os.Stdout, "", 0) | |
path = flag.Arg(0) | |
dest = flag.Arg(1) | |
log.New(os.Stdout, "", 0) | |
} else { | |
infoLog = log.New(ioutil.Discard, "", 0) | |
path = flag.Arg(0) | |
dest = flag.Arg(1) | |
} | |
if path == "" { | |
printUsage("missing path") | |
os.Exit(1) | |
} | |
if dest == "" { | |
printUsage("missing destination path") | |
os.Exit(1) | |
} | |
infoLog.Printf("searching path '%s' for extensions\n", path) | |
destFiles, err := listDestFiles(dest) | |
if err != nil { | |
errLog.Fatal(err) | |
} | |
extensions, err := findExtensions(path, destFiles) | |
if err != nil { | |
errLog.Fatal(err) | |
} | |
if len(extensions) == 0 { | |
errLog.Fatalf("no extensions found at path '%s'", path) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment