2014-07-16 13:50:38 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
2016-11-29 17:40:18 +00:00
|
|
|
"log"
|
2014-07-16 13:50:38 +00:00
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path"
|
2016-11-29 16:52:07 +00:00
|
|
|
"sync"
|
2015-05-21 15:14:05 +00:00
|
|
|
|
|
|
|
"github.com/BurntSushi/toml"
|
2014-07-16 13:50:38 +00:00
|
|
|
)
|
|
|
|
|
2016-11-29 16:52:07 +00:00
|
|
|
var (
|
2016-11-29 19:25:45 +00:00
|
|
|
flSyncDir = flag.String("dir", "", "directory to sync to (this flag overrides the syncDir in the configuration file)")
|
2016-11-29 16:52:07 +00:00
|
|
|
flConfigFile = flag.String("c", path.Join(os.Getenv("HOME"), ".slackware-sync.toml"), "config file for the sync")
|
|
|
|
flThreads = flag.Int("t", 1, "threads to fetch with")
|
|
|
|
flQuiet = flag.Bool("q", false, "less output")
|
|
|
|
)
|
|
|
|
|
2014-07-16 13:50:38 +00:00
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
|
|
|
var config GeneralConfig
|
2016-11-29 17:40:18 +00:00
|
|
|
if _, err := toml.DecodeFile(*flConfigFile, &config); err != nil {
|
|
|
|
log.Fatal(err)
|
2014-07-16 13:50:38 +00:00
|
|
|
}
|
|
|
|
|
2015-05-21 15:14:05 +00:00
|
|
|
if len(*flSyncDir) > 0 {
|
|
|
|
config.SyncDir = *flSyncDir
|
|
|
|
}
|
2016-11-29 16:52:07 +00:00
|
|
|
if *flThreads > 1 {
|
|
|
|
config.Threads = *flThreads
|
|
|
|
}
|
2015-05-21 15:14:05 +00:00
|
|
|
|
2016-11-29 19:25:45 +00:00
|
|
|
if _, err := EnsureDirExists(config.SyncDir); err != nil {
|
2016-11-29 17:40:18 +00:00
|
|
|
log.Fatal(err)
|
2014-07-16 13:50:38 +00:00
|
|
|
}
|
|
|
|
|
2016-11-29 16:52:07 +00:00
|
|
|
workers := make(chan int, config.Threads)
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
for name, mirror := range config.Mirrors {
|
2014-07-16 13:50:38 +00:00
|
|
|
if !mirror.Enabled {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
uri, err := url.Parse(mirror.URL)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
dest := path.Join(config.SyncDir, uri.Host, uri.Path)
|
2016-11-29 17:40:18 +00:00
|
|
|
if _, err = EnsureDirExists(dest); err != nil {
|
2014-07-16 13:50:38 +00:00
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-11-29 16:52:07 +00:00
|
|
|
wg.Add(1)
|
|
|
|
rsyncFunc := func() {
|
2016-11-29 17:40:18 +00:00
|
|
|
if config.Threads > 1 {
|
2016-11-29 16:52:07 +00:00
|
|
|
workers <- 1
|
|
|
|
}
|
|
|
|
defer func() {
|
2016-11-29 17:40:18 +00:00
|
|
|
if config.Threads > 1 {
|
2016-11-29 16:52:07 +00:00
|
|
|
<-workers
|
|
|
|
}
|
|
|
|
wg.Done()
|
|
|
|
}()
|
2016-11-29 19:25:45 +00:00
|
|
|
args := []string{
|
|
|
|
"-avPHS",
|
|
|
|
"--delete",
|
|
|
|
}
|
|
|
|
if mirror.LinkDest != "" {
|
|
|
|
if linkDestMirror, ok := config.Mirrors[mirror.LinkDest]; ok {
|
|
|
|
if linkDestURL, err := url.Parse(linkDestMirror.URL); err == nil {
|
|
|
|
linkDest := path.Join(config.SyncDir, linkDestURL.Host, linkDestURL.Path)
|
|
|
|
args = append(args, "--link-dest="+linkDest+"/")
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(os.Stderr, "linkDest URL %q does not parse: %s", mirror.LinkDest, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
args = append(args, uri.String())
|
|
|
|
args = append(args, dest+"/")
|
|
|
|
//fmt.Println("rsync", strings.Join(args, " "))
|
|
|
|
cmd := exec.Command("rsync", args...)
|
2016-11-29 16:52:07 +00:00
|
|
|
cmd.Stderr = os.Stderr // we'll want to see errors, regardless
|
|
|
|
if !*flQuiet {
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
}
|
2014-07-16 13:50:38 +00:00
|
|
|
|
2016-11-29 17:40:18 +00:00
|
|
|
if err = cmd.Run(); err != nil {
|
2016-11-29 16:52:07 +00:00
|
|
|
fmt.Fprintf(os.Stderr, "%q: %s", name, err)
|
|
|
|
}
|
|
|
|
}
|
2016-11-29 17:40:18 +00:00
|
|
|
if config.Threads > 1 {
|
2016-11-29 16:52:07 +00:00
|
|
|
go rsyncFunc()
|
|
|
|
} else {
|
|
|
|
rsyncFunc()
|
2015-05-21 15:14:05 +00:00
|
|
|
}
|
2014-07-16 13:50:38 +00:00
|
|
|
}
|
2016-11-29 16:52:07 +00:00
|
|
|
wg.Wait()
|
2014-07-16 13:50:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func EnsureDirExists(path string) (os.FileInfo, error) {
|
|
|
|
stat, err := os.Stat(path)
|
|
|
|
if err != nil {
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
return stat, err
|
|
|
|
}
|
|
|
|
if err = os.MkdirAll(path, 0755); err != nil {
|
|
|
|
return stat, err
|
|
|
|
}
|
|
|
|
if stat, err = os.Stat(path); err != nil {
|
|
|
|
return stat, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return stat, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type GeneralConfig struct {
|
2016-11-29 16:52:07 +00:00
|
|
|
Threads int `toml:"threads"`
|
2016-11-29 19:25:45 +00:00
|
|
|
SyncDir string `toml:"syncDir"`
|
2014-07-16 13:50:38 +00:00
|
|
|
Mirrors map[string]Mirror
|
|
|
|
}
|
|
|
|
|
|
|
|
type Mirror struct {
|
2016-11-29 19:25:45 +00:00
|
|
|
Title string `toml:"title"`
|
|
|
|
URL string `toml:"url"`
|
|
|
|
Enabled bool `toml:"enabled"`
|
|
|
|
LinkDest string `toml:"linkDest"`
|
2014-07-16 13:50:38 +00:00
|
|
|
}
|