#!/usr/bin/env python # -*- coding: utf-8 -*- '''Build a list of mirrors for pacman''' # Release : 1.5.1 # Date : 28 March 2014 # Authors : Esclapion, philm import argparse, datetime, getopt, os, signal, sys, time, urllib.request from sys import * path.append("/usr/lib/pacman-mirrors") from operator import itemgetter from decimal import * import os # Global initializations # ====================== path_conf = "/etc/pacman-mirrors.conf" datenow = datetime.datetime.utcnow() serverList = [] nbServer = 0 # Global count of servers available nbServerResp = 0 # Number of servers responding nbServerGood = 0 # Number of servers sinced < 4h generate = False # Generate new mirrorlist interactive = False # Use the gui for custom mirrorlist method = "rank" # Use generation method branch = "stable" # Use branch name onlyCountry=[] # Use only mirrors from country[,country,...] mirrorlistsDir="/etc/pacman.d/mirrors" # Use path as mirrorlist directory outputMirrorList = "/etc/pacman.d/mirrorlist" # Specify output file maxWaitTime = 2 # Server maximum waiting time (seconds) arch = os.uname().machine # i686 or X86_64 def alarm_handler(signum, frame): raise TimeoutError("Ici") def timeOut(timeout): signal.signal(signal.SIGALRM, alarm_handler) signal.alarm(timeout) # produce SIGALRM in `timeout` seconds # Parse the file "pacman-mirrors.conf" # ==================================== try : fi = open(path_conf, "r") except : print("\n Error : cannot open file", path_conf, "\n") exit(1) while 1 : line = fi.readline() if line == "" : break line = line.strip() if line == "" : continue if line[0] == '#' or line[0] == '\n' : continue i = line.find("=") if i == -1 : continue snom = line[0:i] i = i + 1 j = len(line) if line[i] == '"' : i = i + 1 if line[j -1] == '"' : j = j - 1 sval = line[i:j] if snom == "Branch" : # Branch Pacman should use branch=sval elif snom == "OnlyCountry" : # Specify to use only mirrors from specific countries onlyCountry = sval.split(',') elif snom == "MirrorlistsDir" : # Input mirrorlist directory pathMirrors = sval + "/" elif snom == "OutputMirrorlist" : # Output mirrorlist outputMirrorList = sval # # Read the arguments of the command line # ====================================== parser = argparse.ArgumentParser() parser.add_argument("-g", "--generate", help="generate new mirrorlist", action="store_true") parser.add_argument("-m", "--method", help="use generation method", type=str, choices=["rank", "random"]) parser.add_argument("-b", "--branch", help="use branch name", type=str, choices=["stable", "testing", "unstable"]) parser.add_argument("-c", "--country", help="use only mirrors from country[,country,...]", type=str) parser.add_argument("-d", "--mirror_dir", help="use path as mirrorlist directory", type=str) parser.add_argument("-o", "--output", help="specify output file", type=str) parser.add_argument("-t", "--timeout", help="server maximum waiting time (seconds)", type=int) if os.path.exists('/usr/lib/python3.4/site-packages/gi/overrides/Gtk.py') : parser.add_argument("-i", "--interactive", help="interactively generate a custom mirrorlist", action="store_true") parser.add_argument("-v", "--version", help="print the pacman-mirrors version", action="store_true") args = parser.parse_args() if len(sys.argv) == 1 : parser.print_help() exit(0) if args.generate : generate = args.generate if args.method : method = args.method if args.branch : branch = args.branch if args.country : onlyCountry = args.country.split(",") if onlyCountry == ["all"] : path = "/etc/pacman-mirrors.conf" try : fconf = open(path, "r") except : print("\n^GError : can't open file {0}.\n".format(path)) exit(1) buf = fconf.read().split('\n') fconf.close() while buf[-1:] == [''] : del buf[-1:] try : fconf = open(path, "w") except : print("\n^GError : can't open file {0}.\n".format(path)) exit(1) for line in buf : if "OnlyCountry" in line : fconf.write("#OnlyCountry=Custom\n") else : fconf.write(line + "\n") fconf.close try : os.remove(mirrorlistsDir + "/Custom") except : pass onlyCountry = [] if args.mirror_dir : mirrorlistsDir = args.mirror_dir if args.output : if args.output[0] == '/' : outputMirrorList = args.output else : outputMirrorList = os.getcwd() + "/" + args.output if os.path.exists('/usr/lib/python3.4/site-packages/gi/overrides/Gtk.py') : if args.interactive : interactive = args.interactive else : interactive = False if args.timeout : maxWaitTime = args.timeout if args.version : print("pacman-mirrors 1.5") exit(0) try : os.chdir(mirrorlistsDir) except : print("\nError : Cannot change directory to", mirrorlistsDir, "\n") exit(1) listeDir = os.listdir(mirrorlistsDir) listeDir.sort() for i in onlyCountry : if i not in listeDir : print("\nError : unknown country", i) print("\nAvailable countries are :", listeDir, "\n") exit(1) if os.getuid() != 0 : print("\nError : must be root.\n") exit(1) # Main loop # ========= if method == "rank" : print(":: Querying servers, this may take some time...") listeSer=[] for country in listeDir : if len(onlyCountry) != 0 and country not in onlyCountry : continue print(country) curCountry = country fi = open(country, "r") while 1 : s = fi.readline() if s == '' : break if s[0] == '[' : curCountry = s[1:-2] continue if s[0] != 'S' : continue urlServer = s[9:-1] urlServer = urlServer.replace("$branch", branch) # Add the server to the list, also if bad serverList.append([curCountry, "99.99", "99:99", urlServer, 0, False]) # Country, response time, last sync, url, quality level nbServer = nbServer + 1 if method == "random" : print("->", urlServer) continue print("-> .....", urlServer, end='') sys.stdout.flush() j = urlServer.find(branch) url = urlServer[0:j] + "state" start = time.time() try : furl = urllib.request.urlopen(url, timeout=maxWaitTime) except : print("\r-> Error!") continue timeOut(maxWaitTime) try : resp = furl.read() d = resp.find(b"date=") signal.alarm(0) # cancel alarm except : print("\r-> Error2!") furl.close() continue elapsed = round((time.time() - start), 3) nbServerResp = nbServerResp + 1 # The server responds .. date = resp[d+5:d+24].decode('utf-8') selapsed = "{:6.4}".format(Decimal(elapsed).quantize(Decimal('.001'))) print("\r->", selapsed, sep="") sys.stdout.flush() serverList[nbServer - 1][1] = selapsed # - response time serverList[nbServer - 1][4] = 1 try : date2 = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S" ) except : print('Wrong date format in "state" file. Server skipped.') continue sec = (datenow - date2).seconds min = int(sec / 60) hr = int (min /60) min = min - hr * 60 if hr < 4 : nbServerGood = nbServerGood + 1 # ...and was recently synced (< 4h) serverList[nbServer - 1][4] = 2 datesync = '{}:{}'.format(hr, str(min).zfill(2)) serverList[nbServer - 1][2] = datesync # - last sync furl.close() fi.close() # break # # Build the file "mirrorlist" # =========================== serverList = sorted(serverList, key=itemgetter(1)) if interactive : from pacman_mirrors_gui import chooseMirrors finished = False for item in serverList : item[3] = item[3].replace("/" + branch + "/", "/$branch/") while not finished : chooseMirrors(True, serverList) customList = [] for elem in serverList : if elem[5] : customList.append(elem) if len(customList) == 0 : continue finished = chooseMirrors(False, customList) path = mirrorlistsDir + "/Custom" try : fcust = open(path, "w") except : print("\n^GError : can't create file {0}.\n".format(path)) exit(1) fcust.write("##\n") fcust.write("## Pacman Mirrorlist\n") fcust.write("##\n\n") for elem in customList : fcust.write("[" + elem[0] + "]\n") fcust.write("Server = " + elem[3] + "\n") fcust.close() path = "/etc/pacman-mirrors.conf" try : fconf = open(path, "r") except : print("\n^GError : can't open file {0}.\n".format(path)) exit(1) buf = fconf.read().split('\n') fconf.close() while buf[-1:] == [''] : del buf[-1:] try : fconf = open(path, "w") except : print("\n^GError : can't open file {0}.\n".format(path)) exit(1) for line in buf : if "OnlyCountry" in line : fconf.write("OnlyCountry=Custom\n") else : fconf.write(line + "\n") fconf.close try : fo = open(outputMirrorList, "w") except : print("\nError : cannot create", outputMirrorList) exit(1) fo.write("##\n") fo.write("## Manjaro Linux repository mirrorlist\n") fo.write("## Generated on ") fo.write(datetime.datetime.now().strftime("%d %B %Y %H:%M")) fo.write("\n##\n") fo.write("## Use pacman-mirrors to modify\n") fo.write("##\n\n") print("\nCustom List") print("-----------\n") for server in customList : server[3] = server[3].replace("$branch", branch) print("-> {0} :".format(server[0]), server[3]) fo.write("\n## Location : ") fo.write(server[0]) if method == "rank" : fo.write("\n## Time :") fo.write(server[1]) fo.write("\n## Last Sync : ") fo.write(server[2]) fo.write("\nServer = ") fo.write(server[3]) fo.write("\n") print("\n:: Generated and saved '{}' Custom list.".format(outputMirrorList)) else : try : fo = open(outputMirrorList, "w") except : print("\nError : cannot create", outputMirrorList) exit(1) fo.write("##\n") fo.write("## Manjaro Linux repository mirrorlist\n") fo.write("## Generated on ") fo.write(datetime.datetime.now().strftime("%d %B %Y %H:%M")) fo.write("\n##\n") fo.write("## Use pacman-mirrors to modify\n") fo.write("##\n\n") if nbServerGood >= 3 : # Avoid an empty mirrorlist level = 2 elif nbServerResp >= 3 : level = 1 else : level = 0 if nbServer == 0 : print("\nError : no server available !\n") for server in serverList : if server[4] < level : continue fo.write("\n## Location : ") fo.write(server[0]) if method == "rank" : fo.write("\n## Time :") fo.write(server[1]) fo.write("\n## Last Sync : ") fo.write(server[2]) fo.write("\nServer = ") fo.write(server[3]) fo.write("\n") print(":: Generated and saved '{}' mirrorlist.".format(outputMirrorList))