spacepaste

  1.  
  2. #!/usr/bin/env python
  3. # -*- coding: utf-8 -*-
  4. '''Build a list of mirrors for pacman'''
  5. # Release : 1.5.1
  6. # Date : 28 March 2014
  7. # Authors : Esclapion, philm
  8. import argparse, datetime, getopt, os, signal, sys, time, urllib.request
  9. from sys import *
  10. path.append("/usr/lib/pacman-mirrors")
  11. from operator import itemgetter
  12. from decimal import *
  13. import os
  14. # Global initializations
  15. # ======================
  16. path_conf = "/etc/pacman-mirrors.conf"
  17. datenow = datetime.datetime.utcnow()
  18. serverList = []
  19. nbServer = 0 # Global count of servers available
  20. nbServerResp = 0 # Number of servers responding
  21. nbServerGood = 0 # Number of servers sinced < 4h
  22. generate = False # Generate new mirrorlist
  23. interactive = False # Use the gui for custom mirrorlist
  24. method = "rank" # Use generation method
  25. branch = "stable" # Use branch name
  26. onlyCountry=[] # Use only mirrors from country[,country,...]
  27. mirrorlistsDir="/etc/pacman.d/mirrors" # Use path as mirrorlist directory
  28. outputMirrorList = "/etc/pacman.d/mirrorlist" # Specify output file
  29. maxWaitTime = 2 # Server maximum waiting time (seconds)
  30. arch = os.uname().machine # i686 or X86_64
  31. def alarm_handler(signum, frame):
  32. raise TimeoutError("Ici")
  33. def timeOut(timeout):
  34. signal.signal(signal.SIGALRM, alarm_handler)
  35. signal.alarm(timeout) # produce SIGALRM in `timeout` seconds
  36. # Parse the file "pacman-mirrors.conf"
  37. # ====================================
  38. try :
  39. fi = open(path_conf, "r")
  40. except :
  41. print("\n Error : cannot open file", path_conf, "\n")
  42. exit(1)
  43. while 1 :
  44. line = fi.readline()
  45. if line == "" :
  46. break
  47. line = line.strip()
  48. if line == "" :
  49. continue
  50. if line[0] == '#' or line[0] == '\n' :
  51. continue
  52. i = line.find("=")
  53. if i == -1 :
  54. continue
  55. snom = line[0:i]
  56. i = i + 1
  57. j = len(line)
  58. if line[i] == '"' :
  59. i = i + 1
  60. if line[j -1] == '"' :
  61. j = j - 1
  62. sval = line[i:j]
  63. if snom == "Branch" : # Branch Pacman should use
  64. branch=sval
  65. elif snom == "OnlyCountry" : # Specify to use only mirrors from specific countries
  66. onlyCountry = sval.split(',')
  67. elif snom == "MirrorlistsDir" : # Input mirrorlist directory
  68. pathMirrors = sval + "/"
  69. elif snom == "OutputMirrorlist" : # Output mirrorlist
  70. outputMirrorList = sval
  71. #
  72. # Read the arguments of the command line
  73. # ======================================
  74. parser = argparse.ArgumentParser()
  75. parser.add_argument("-g", "--generate", help="generate new mirrorlist",
  76. action="store_true")
  77. parser.add_argument("-m", "--method", help="use generation method",
  78. type=str, choices=["rank", "random"])
  79. parser.add_argument("-b", "--branch", help="use branch name",
  80. type=str, choices=["stable", "testing", "unstable"])
  81. parser.add_argument("-c", "--country", help="use only mirrors from country[,country,...]",
  82. type=str)
  83. parser.add_argument("-d", "--mirror_dir", help="use path as mirrorlist directory",
  84. type=str)
  85. parser.add_argument("-o", "--output", help="specify output file",
  86. type=str)
  87. parser.add_argument("-t", "--timeout", help="server maximum waiting time (seconds)",
  88. type=int)
  89. if os.path.exists('/usr/lib/python3.4/site-packages/gi/overrides/Gtk.py') :
  90. parser.add_argument("-i", "--interactive", help="interactively generate a custom mirrorlist",
  91. action="store_true")
  92. parser.add_argument("-v", "--version", help="print the pacman-mirrors version",
  93. action="store_true")
  94. args = parser.parse_args()
  95. if len(sys.argv) == 1 :
  96. parser.print_help()
  97. exit(0)
  98. if args.generate :
  99. generate = args.generate
  100. if args.method :
  101. method = args.method
  102. if args.branch :
  103. branch = args.branch
  104. if args.country :
  105. onlyCountry = args.country.split(",")
  106. if onlyCountry == ["all"] :
  107. path = "/etc/pacman-mirrors.conf"
  108. try :
  109. fconf = open(path, "r")
  110. except :
  111. print("\n^GError : can't open file {0}.\n".format(path))
  112. exit(1)
  113. buf = fconf.read().split('\n')
  114. fconf.close()
  115. while buf[-1:] == [''] :
  116. del buf[-1:]
  117. try :
  118. fconf = open(path, "w")
  119. except :
  120. print("\n^GError : can't open file {0}.\n".format(path))
  121. exit(1)
  122. for line in buf :
  123. if "OnlyCountry" in line :
  124. fconf.write("#OnlyCountry=Custom\n")
  125. else :
  126. fconf.write(line + "\n")
  127. fconf.close
  128. try :
  129. os.remove(mirrorlistsDir + "/Custom")
  130. except :
  131. pass
  132. onlyCountry = []
  133. if args.mirror_dir :
  134. mirrorlistsDir = args.mirror_dir
  135. if args.output :
  136. if args.output[0] == '/' :
  137. outputMirrorList = args.output
  138. else :
  139. outputMirrorList = os.getcwd() + "/" + args.output
  140. if os.path.exists('/usr/lib/python3.4/site-packages/gi/overrides/Gtk.py') :
  141. if args.interactive :
  142. interactive = args.interactive
  143. else :
  144. interactive = False
  145. if args.timeout :
  146. maxWaitTime = args.timeout
  147. if args.version :
  148. print("pacman-mirrors 1.5")
  149. exit(0)
  150. try :
  151. os.chdir(mirrorlistsDir)
  152. except :
  153. print("\nError : Cannot change directory to", mirrorlistsDir, "\n")
  154. exit(1)
  155. listeDir = os.listdir(mirrorlistsDir)
  156. listeDir.sort()
  157. for i in onlyCountry :
  158. if i not in listeDir :
  159. print("\nError : unknown country", i)
  160. print("\nAvailable countries are :", listeDir, "\n")
  161. exit(1)
  162. if os.getuid() != 0 :
  163. print("\nError : must be root.\n")
  164. exit(1)
  165. # Main loop
  166. # =========
  167. if method == "rank" :
  168. print(":: Querying servers, this may take some time...")
  169. listeSer=[]
  170. for country in listeDir :
  171. if len(onlyCountry) != 0 and country not in onlyCountry :
  172. continue
  173. print(country)
  174. curCountry = country
  175. fi = open(country, "r")
  176. while 1 :
  177. s = fi.readline()
  178. if s == '' :
  179. break
  180. if s[0] == '[' :
  181. curCountry = s[1:-2]
  182. continue
  183. if s[0] != 'S' :
  184. continue
  185. urlServer = s[9:-1]
  186. urlServer = urlServer.replace("$branch", branch)
  187. # Add the server to the list, also if bad
  188. serverList.append([curCountry, "99.99", "99:99", urlServer, 0, False])
  189. # Country, response time, last sync, url, quality level
  190. nbServer = nbServer + 1
  191. if method == "random" :
  192. print("->", urlServer)
  193. continue
  194. print("-> .....", urlServer, end='')
  195. sys.stdout.flush()
  196. j = urlServer.find(branch)
  197. url = urlServer[0:j] + "state"
  198. start = time.time()
  199. try :
  200. furl = urllib.request.urlopen(url, timeout=maxWaitTime)
  201. except :
  202. print("\r-> Error!")
  203. continue
  204. timeOut(maxWaitTime)
  205. try :
  206. resp = furl.read()
  207. d = resp.find(b"date=")
  208. signal.alarm(0) # cancel alarm
  209. except :
  210. print("\r-> Error2!")
  211. furl.close()
  212. continue
  213. elapsed = round((time.time() - start), 3)
  214. nbServerResp = nbServerResp + 1 # The server responds ..
  215. date = resp[d+5:d+24].decode('utf-8')
  216. selapsed = "{:6.4}".format(Decimal(elapsed).quantize(Decimal('.001')))
  217. print("\r->", selapsed, sep="")
  218. sys.stdout.flush()
  219. serverList[nbServer - 1][1] = selapsed # - response time
  220. serverList[nbServer - 1][4] = 1
  221. try :
  222. date2 = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S" )
  223. except :
  224. print('Wrong date format in "state" file. Server skipped.')
  225. continue
  226. sec = (datenow - date2).seconds
  227. min = int(sec / 60)
  228. hr = int (min /60)
  229. min = min - hr * 60
  230. if hr < 4 :
  231. nbServerGood = nbServerGood + 1 # ...and was recently synced (< 4h)
  232. serverList[nbServer - 1][4] = 2
  233. datesync = '{}:{}'.format(hr, str(min).zfill(2))
  234. serverList[nbServer - 1][2] = datesync # - last sync
  235. furl.close()
  236. fi.close()
  237. # break
  238. #
  239. # Build the file "mirrorlist"
  240. # ===========================
  241. serverList = sorted(serverList, key=itemgetter(1))
  242. if interactive :
  243. from pacman_mirrors_gui import chooseMirrors
  244. finished = False
  245. for item in serverList :
  246. item[3] = item[3].replace("/" + branch + "/", "/$branch/")
  247. while not finished :
  248. chooseMirrors(True, serverList)
  249. customList = []
  250. for elem in serverList :
  251. if elem[5] :
  252. customList.append(elem)
  253. if len(customList) == 0 :
  254. continue
  255. finished = chooseMirrors(False, customList)
  256. path = mirrorlistsDir + "/Custom"
  257. try :
  258. fcust = open(path, "w")
  259. except :
  260. print("\n^GError : can't create file {0}.\n".format(path))
  261. exit(1)
  262. fcust.write("##\n")
  263. fcust.write("## Pacman Mirrorlist\n")
  264. fcust.write("##\n\n")
  265. for elem in customList :
  266. fcust.write("[" + elem[0] + "]\n")
  267. fcust.write("Server = " + elem[3] + "\n")
  268. fcust.close()
  269. path = "/etc/pacman-mirrors.conf"
  270. try :
  271. fconf = open(path, "r")
  272. except :
  273. print("\n^GError : can't open file {0}.\n".format(path))
  274. exit(1)
  275. buf = fconf.read().split('\n')
  276. fconf.close()
  277. while buf[-1:] == [''] :
  278. del buf[-1:]
  279. try :
  280. fconf = open(path, "w")
  281. except :
  282. print("\n^GError : can't open file {0}.\n".format(path))
  283. exit(1)
  284. for line in buf :
  285. if "OnlyCountry" in line :
  286. fconf.write("OnlyCountry=Custom\n")
  287. else :
  288. fconf.write(line + "\n")
  289. fconf.close
  290. try :
  291. fo = open(outputMirrorList, "w")
  292. except :
  293. print("\nError : cannot create", outputMirrorList)
  294. exit(1)
  295. fo.write("##\n")
  296. fo.write("## Manjaro Linux repository mirrorlist\n")
  297. fo.write("## Generated on ")
  298. fo.write(datetime.datetime.now().strftime("%d %B %Y %H:%M"))
  299. fo.write("\n##\n")
  300. fo.write("## Use pacman-mirrors to modify\n")
  301. fo.write("##\n\n")
  302. print("\nCustom List")
  303. print("-----------\n")
  304. for server in customList :
  305. server[3] = server[3].replace("$branch", branch)
  306. print("-> {0} :".format(server[0]), server[3])
  307. fo.write("\n## Location : ")
  308. fo.write(server[0])
  309. if method == "rank" :
  310. fo.write("\n## Time :")
  311. fo.write(server[1])
  312. fo.write("\n## Last Sync : ")
  313. fo.write(server[2])
  314. fo.write("\nServer = ")
  315. fo.write(server[3])
  316. fo.write("\n")
  317. print("\n:: Generated and saved '{}' Custom list.".format(outputMirrorList))
  318. else :
  319. try :
  320. fo = open(outputMirrorList, "w")
  321. except :
  322. print("\nError : cannot create", outputMirrorList)
  323. exit(1)
  324. fo.write("##\n")
  325. fo.write("## Manjaro Linux repository mirrorlist\n")
  326. fo.write("## Generated on ")
  327. fo.write(datetime.datetime.now().strftime("%d %B %Y %H:%M"))
  328. fo.write("\n##\n")
  329. fo.write("## Use pacman-mirrors to modify\n")
  330. fo.write("##\n\n")
  331. if nbServerGood >= 3 : # Avoid an empty mirrorlist
  332. level = 2
  333. elif nbServerResp >= 3 :
  334. level = 1
  335. else :
  336. level = 0
  337. if nbServer == 0 :
  338. print("\nError : no server available !\n")
  339. for server in serverList :
  340. if server[4] < level :
  341. continue
  342. fo.write("\n## Location : ")
  343. fo.write(server[0])
  344. if method == "rank" :
  345. fo.write("\n## Time :")
  346. fo.write(server[1])
  347. fo.write("\n## Last Sync : ")
  348. fo.write(server[2])
  349. fo.write("\nServer = ")
  350. fo.write(server[3])
  351. fo.write("\n")
  352. print(":: Generated and saved '{}' mirrorlist.".format(outputMirrorList))
  353.