@@ -0,0 +1,216 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"strings"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"runtime"
|
||||
"errors"
|
||||
"github.com/go-ini/ini"
|
||||
"io"
|
||||
)
|
||||
|
||||
var VERSION string = "1.3.6"
|
||||
|
||||
func packageName(name string) string {
|
||||
if index := strings.Index(name, "_"); index != -1 {
|
||||
name = name[:index]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
type DeleteObj struct {
|
||||
Filename string
|
||||
DistroName string
|
||||
Arch string
|
||||
}
|
||||
|
||||
var (
|
||||
mutex sync.RWMutex
|
||||
configFile = flag.String("c", "conf.ini", "config file location")
|
||||
flagShowVersion = flag.Bool("version", false, "Show deb-simple version")
|
||||
conf = Conf{}
|
||||
pgpEntity *openpgp.Entity
|
||||
)
|
||||
|
||||
func Start() {
|
||||
flag.Parse()
|
||||
|
||||
if *flagShowVersion {
|
||||
fmt.Printf("deb-simple %s (%s)\n", VERSION, runtime.Version())
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
file, err := ioutil.ReadFile(*configFile)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln("unable to read config file, exiting...")
|
||||
}
|
||||
|
||||
if err := ini.MapTo(&conf, file); err != nil {
|
||||
log.Fatalln("unable to marshal config file, exiting...", err)
|
||||
}
|
||||
|
||||
if err := createDirs(conf); err != nil {
|
||||
log.Println(err)
|
||||
log.Fatalln("error creating directory structure, exiting")
|
||||
}
|
||||
|
||||
if err := setupPgp(conf); err != nil {
|
||||
log.Println(err)
|
||||
log.Fatalln("error loading pgp key, exiting")
|
||||
}
|
||||
|
||||
log.Println("Indexing packages...")
|
||||
|
||||
for _, dist := range conf.Repo.DistroNames() {
|
||||
if err := loadCache(dist); err != nil {
|
||||
log.Println("Unable to load cached data for", dist, "- reindexing")
|
||||
distro := &Distro{Name: dist, Architectures: make(map[string]map[string]*PackageFile)}
|
||||
|
||||
go scanInitialPackages(conf, distro)
|
||||
|
||||
distros[dist] = distro
|
||||
}
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir(conf.Repo.Root))))
|
||||
mux.HandleFunc("/rescan", rescanHandler)
|
||||
mux.HandleFunc("/upload", uploadHandler)
|
||||
mux.HandleFunc("/delete", deleteHandler)
|
||||
|
||||
bind := fmt.Sprintf(":%d", conf.Http.Port)
|
||||
|
||||
if conf.Http.SSL {
|
||||
log.Println("running with SSL enabled")
|
||||
log.Fatalln(http.ListenAndServeTLS(bind, conf.Http.SSLCert, conf.Http.SSLKey, mux))
|
||||
} else {
|
||||
log.Println("running without SSL enabled")
|
||||
log.Fatalln(http.ListenAndServe(bind, mux))
|
||||
}
|
||||
}
|
||||
|
||||
func scanInitialPackages(config Conf, dist *Distro) {
|
||||
for _, arch := range config.Repo.ArchitectureNames() {
|
||||
files, err := buildPackageList(config, dist.Name, arch)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to load packages:", err)
|
||||
}
|
||||
|
||||
dist.Architectures[arch] = files
|
||||
|
||||
log.Println("Generating packages file for", dist.Name, arch)
|
||||
createPackagesCached(config, dist.Name, arch, files)
|
||||
}
|
||||
|
||||
log.Println("Generating Release for", dist.Name)
|
||||
createRelease(config, dist.Name)
|
||||
|
||||
saveCache(dist)
|
||||
}
|
||||
|
||||
func setupPgp(config Conf) error {
|
||||
if config.PGP.Key == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
secretKey, err := os.Open(config.PGP.Key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open private key ring file: %s", err)
|
||||
}
|
||||
defer secretKey.Close()
|
||||
|
||||
entitylist, err := openpgp.ReadKeyRing(secretKey)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read key ring: %s", err)
|
||||
}
|
||||
|
||||
if len(entitylist) < 1 {
|
||||
return errors.New("no keys in key ring")
|
||||
}
|
||||
|
||||
pgpEntity = entitylist[0]
|
||||
|
||||
passphrase := []byte(config.PGP.Passphrase)
|
||||
|
||||
if err := pgpEntity.PrivateKey.Decrypt(passphrase); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, subkey := range pgpEntity.Subkeys {
|
||||
err := subkey.PrivateKey.Decrypt(passphrase)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createDirs(config Conf) error {
|
||||
for _, distro := range config.Repo.DistroNames() {
|
||||
for _, arch := range config.Repo.ArchitectureNames() {
|
||||
if _, err := os.Stat(config.ArchPath(distro, arch)); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.Printf("Directory for %s (%s) does not exist, creating", distro, arch)
|
||||
if err := os.MkdirAll(config.ArchPath(distro, arch), 0755); err != nil {
|
||||
return fmt.Errorf("error creating directory for %s (%s): %s", distro, arch, err)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("error inspecting %s (%s): %s", distro, arch, err)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(config.PoolPath(distro, arch)); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.Printf("Directory for %s (%s) does not exist, creating", distro, arch)
|
||||
if err := os.MkdirAll(config.PoolPath(distro, arch), 0755); err != nil {
|
||||
return fmt.Errorf("error creating directory for %s (%s): %s", distro, arch, err)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("error inspecting %s (%s): %s", distro, arch, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stripPrefix(str, prefix string) string {
|
||||
if strings.Index(str, prefix) == 0 {
|
||||
return strings.TrimLeft(str[len(prefix):], "/")
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func copyFile(oldPath, newPath string) error {
|
||||
old, err := os.Open(oldPath)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer old.Close()
|
||||
|
||||
n, err := os.Create(newPath)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer n.Close()
|
||||
|
||||
_, err = io.Copy(n, old)
|
||||
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user