func (c *cli) CmdScan(args ...string) error { cmd := SubCmd("scan", "[IDENTIFIER]", "(Re-)Scan a mirror") enable := cmd.Bool("enable", false, "Enable the mirror automatically if the scan is successful") all := cmd.Bool("all", false, "Scan all mirrors at once") ftp := cmd.Bool("ftp", false, "Force a scan using FTP") rsync := cmd.Bool("rsync", false, "Force a scan using rsync") if err := cmd.Parse(args); err != nil { return nil } if !*all && cmd.NArg() != 1 || *all && cmd.NArg() != 0 { cmd.Usage() return nil } r := database.NewRedis() conn, err := r.Connect() if err != nil { log.Fatal("Redis: ", err) } defer conn.Close() // Check if the local repository has been scanned already exists, err := redis.Bool(conn.Do("EXISTS", "FILES")) if err != nil { return err } if !exists { fmt.Fprintf(os.Stderr, "Local repository not yet indexed.\nYou should run 'refresh' first!\n") os.Exit(-1) } var list []string if *all == true { list, err = redis.Strings(conn.Do("LRANGE", "MIRRORS", "0", "-1")) if err != nil { return errors.New("Cannot fetch the list of mirrors") } } else { list, err = c.matchMirror(cmd.Arg(0)) if err != nil { return err } if len(list) == 0 { fmt.Fprintf(os.Stderr, "No match for %s\n", cmd.Arg(0)) return nil } else if len(list) > 1 { for _, e := range list { fmt.Fprintf(os.Stderr, "%s\n", e) } return nil } } for _, id := range list { key := fmt.Sprintf("MIRROR_%s", id) m, err := redis.Values(conn.Do("HGETALL", key)) if err != nil { fmt.Fprintf(os.Stderr, "Cannot fetch mirror details: %s\n", err) return err } var mirror mirrors.Mirror err = redis.ScanStruct(m, &mirror) if err != nil { return err } log.Noticef("Scanning %s...", id) err = NoSyncMethod if *rsync == true || *ftp == true { // Use the requested protocol if *rsync == true && mirror.RsyncURL != "" { err = scan.Scan(scan.RSYNC, r, mirror.RsyncURL, id, nil) } else if *ftp == true && mirror.FtpURL != "" { err = scan.Scan(scan.FTP, r, mirror.FtpURL, id, nil) } } else { // Use rsync (if applicable) and fallback to FTP if mirror.RsyncURL != "" { err = scan.Scan(scan.RSYNC, r, mirror.RsyncURL, id, nil) } if err != nil && mirror.FtpURL != "" { err = scan.Scan(scan.FTP, r, mirror.FtpURL, id, nil) } } if err != nil { log.Errorf("Scanning %s failed: %s", id, err.Error()) } // Finally enable the mirror if requested if err == nil && *enable == true { if err := mirrors.EnableMirror(r, id); err != nil { log.Fatal("Couldn't enable the mirror: ", err) } fmt.Println("Mirror enabled successfully") } } return nil }
// Main sync loop // TODO merge with the monitorLoop? func (m *Monitor) syncLoop() { m.wg.Add(1) defer m.wg.Done() for { select { case <-m.stop: return case k := <-m.syncChan: m.mapLock.Lock() mirror := m.mirrors[k] m.mapLock.Unlock() conn := m.redis.Get() scanning, err := scan.IsScanning(conn, k) if err != nil { conn.Close() if !database.RedisIsLoading(err) { log.Warningf("syncloop: %s", err.Error()) } goto unlock } else if scanning { // A scan is already in progress on another node conn.Close() goto unlock } conn.Close() log.Debugf("Scanning %s", k) err = cli.NoSyncMethod // First try to scan with rsync if mirror.RsyncURL != "" { err = scan.Scan(scan.RSYNC, m.redis, mirror.RsyncURL, k, m.stop) } // If it failed or rsync wasn't supported // fallback to FTP if err != nil && err != scan.ScanAborted && mirror.FtpURL != "" { err = scan.Scan(scan.FTP, m.redis, mirror.FtpURL, k, m.stop) } if err == scan.ScanInProgress { log.Warningf("%-30.30s Scan already in progress", k) goto unlock } if mirror.Up == false { select { case m.healthCheckChan <- k: default: } } unlock: m.mapLock.Lock() if _, ok := m.mirrors[k]; ok { m.mirrors[k].scanning = false } m.mapLock.Unlock() } } }