1
2 '''
3 # DESCRIPTION:
4 # Entropy Object Oriented Interface
5
6 Copyright (C) 2007-2009 Fabio Erculiani
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 '''
22
23 from __future__ import with_statement
24 import os
25 import shutil
26 import time
27 from entropy.exceptions import OnlineMirrorError, IncorrectParameter, \
28 ConnectionError, InvalidDataType
29 from entropy.output import red, darkgreen, bold, brown, blue, darkred, darkblue
30 from entropy.const import etpConst, etpSys
31 from entropy.i18n import _
32 from entropy.misc import RSS
33 from entropy.transceivers import FtpInterface
34 from entropy.db import dbapi2
35
37
38 import socket
39 import entropy.dump as dumpTools
40 import entropy.tools as entropyTools
41 - def __init__(self, ServerInstance, repo = None):
42
43 from entropy.server.interfaces.main import Server as MainServer
44 if not isinstance(ServerInstance, MainServer):
45 mytxt = _("entropy.server.interfaces.main.Server needed")
46 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,))
47
48 self.Entropy = ServerInstance
49 from entropy.transceivers import FtpServerHandler
50 self.FtpServerHandler = FtpServerHandler
51 from entropy.cache import EntropyCacher
52 self.Cacher = EntropyCacher()
53 self.sys_settings_plugin_id = \
54 etpConst['system_settings_plugins_ids']['server_plugin']
55 self.SystemSettings = self.Entropy.SystemSettings
56
57 mytxt = blue("%s:") % (_("Entropy Server Mirrors Interface loaded"),)
58 self.Entropy.updateProgress(
59 mytxt,
60 importance = 2,
61 type = "info",
62 header = red(" @@ ")
63 )
64 mytxt = _("mirror")
65 for mirror in self.Entropy.get_remote_mirrors(repo):
66 mirror = self.entropyTools.hide_ftp_password(mirror)
67 self.Entropy.updateProgress(
68 blue("%s: %s") % (mytxt, darkgreen(mirror),),
69 importance = 0,
70 type = "info",
71 header = brown(" # ")
72 )
73
74
75 - def lock_mirrors(self, lock = True, mirrors = None, repo = None):
76
77 if repo == None:
78 repo = self.Entropy.default_repository
79
80 if not mirrors:
81 mirrors = self.Entropy.get_remote_mirrors(repo)
82
83 issues = False
84 for uri in mirrors:
85
86 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
87
88 lock_text = _("unlocking")
89 if lock:
90 lock_text = _("locking")
91 self.Entropy.updateProgress(
92 "[repo:%s|%s] %s %s" % (
93 brown(repo),
94 darkgreen(crippled_uri),
95 bold(lock_text),
96 blue("%s...") % (_("mirror"),),
97 ),
98 importance = 1,
99 type = "info",
100 header = brown(" * "),
101 back = True
102 )
103
104 try:
105 ftp = FtpInterface(uri, self.Entropy)
106 except ConnectionError:
107 self.entropyTools.print_traceback()
108 return True
109 my_path = os.path.join(
110 self.Entropy.get_remote_database_relative_path(repo),
111 self.SystemSettings['repositories']['branch'])
112 ftp.set_cwd(my_path, dodir = True)
113
114 lock_file = etpConst['etpdatabaselockfile']
115 if lock and ftp.is_file_available(lock_file):
116 self.Entropy.updateProgress(
117 "[repo:%s|%s] %s" % (
118 brown(repo),
119 darkgreen(crippled_uri),
120 blue(_("mirror already locked")),
121 ),
122 importance = 1,
123 type = "info",
124 header = darkgreen(" * ")
125 )
126 ftp.close()
127 continue
128 elif not lock and not ftp.is_file_available(lock_file):
129 self.Entropy.updateProgress(
130 "[repo:%s|%s] %s" % (
131 brown(repo),
132 darkgreen(crippled_uri),
133 blue(_("mirror already unlocked")),
134 ),
135 importance = 1,
136 type = "info",
137 header = darkgreen(" * ")
138 )
139 ftp.close()
140 continue
141
142 if lock:
143 rc_lock = self.do_mirror_lock(uri, ftp, repo = repo)
144 else:
145 rc_lock = self.do_mirror_unlock(uri, ftp, repo = repo)
146 ftp.close()
147 if not rc_lock:
148 issues = True
149
150 if not issues:
151 db_taint_file = self.Entropy.get_local_database_taint_file(repo)
152 if os.path.isfile(db_taint_file):
153 os.remove(db_taint_file)
154
155 return issues
156
157
160
161
162
163
164 if mirrors == None:
165 mirrors = []
166
167 if repo == None:
168 repo = self.Entropy.default_repository
169
170 if not mirrors:
171 mirrors = self.Entropy.get_remote_mirrors(repo)
172
173 issues = False
174 for uri in mirrors:
175
176 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
177
178 lock_text = _("unlocking")
179 if lock:
180 lock_text = _("locking")
181 self.Entropy.updateProgress(
182 "[repo:%s|%s] %s %s..." % (
183 blue(repo),
184 red(crippled_uri),
185 bold(lock_text),
186 blue(_("mirror for download")),
187 ),
188 importance = 1,
189 type = "info",
190 header = red(" @@ "),
191 back = True
192 )
193
194 try:
195 ftp = FtpInterface(uri, self.Entropy)
196 except ConnectionError:
197 self.entropyTools.print_traceback()
198 return True
199 my_path = os.path.join(
200 self.Entropy.get_remote_database_relative_path(repo),
201 self.SystemSettings['repositories']['branch'])
202 ftp.set_cwd(my_path, dodir = True)
203
204 lock_file = etpConst['etpdatabasedownloadlockfile']
205
206 if lock and ftp.is_file_available(lock_file):
207 self.Entropy.updateProgress(
208 "[repo:%s|%s] %s" % (
209 blue(repo),
210 red(crippled_uri),
211 blue(_("mirror already locked for download")),
212 ),
213 importance = 1,
214 type = "info",
215 header = red(" @@ ")
216 )
217 ftp.close()
218 continue
219
220 elif not lock and not ftp.is_file_available(lock_file):
221 self.Entropy.updateProgress(
222 "[repo:%s|%s] %s" % (
223 blue(repo),
224 red(crippled_uri),
225 blue(_("mirror already unlocked for download")),
226 ),
227 importance = 1,
228 type = "info",
229 header = red(" @@ ")
230 )
231 ftp.close()
232 continue
233
234 if lock:
235 rc_lock = self.do_mirror_lock(uri, ftp, dblock = False,
236 repo = repo)
237 else:
238 rc_lock = self.do_mirror_unlock(uri, ftp, dblock = False,
239 repo = repo)
240 ftp.close()
241 if not rc_lock:
242 issues = True
243
244 return issues
245
246 - def do_mirror_lock(self, uri, ftp_connection = None, dblock = True,
247 repo = None):
248
249 if repo == None:
250 repo = self.Entropy.default_repository
251
252 my_path = os.path.join(
253 self.Entropy.get_remote_database_relative_path(repo),
254 self.SystemSettings['repositories']['branch'])
255 if not ftp_connection:
256 try:
257 ftp_connection = FtpInterface(uri, self.Entropy)
258 except ConnectionError:
259 self.entropyTools.print_traceback()
260 return False
261 ftp_connection.set_cwd(my_path, dodir = True)
262 else:
263 mycwd = ftp_connection.get_cwd()
264 if mycwd != my_path:
265 ftp_connection.set_basedir()
266 ftp_connection.set_cwd(my_path, dodir = True)
267
268 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
269 lock_string = u''
270
271 if dblock:
272 self.create_local_database_lockfile(repo)
273 lock_file = self.get_database_lockfile(repo)
274 else:
275
276 lock_string = _('for download')
277 self.create_local_database_download_lockfile(repo)
278 lock_file = self.get_database_download_lockfile(repo)
279
280 rc_upload = ftp_connection.upload_file(lock_file, ascii = True)
281 if rc_upload:
282 self.Entropy.updateProgress(
283 "[repo:%s|%s] %s %s" % (
284 blue(repo),
285 red(crippled_uri),
286 blue(_("mirror successfully locked")),
287 blue(lock_string),
288 ),
289 importance = 1,
290 type = "info",
291 header = red(" @@ ")
292 )
293 else:
294 self.Entropy.updateProgress(
295 "[repo:%s|%s] %s: %s - %s %s" % (
296 blue(repo),
297 red(crippled_uri),
298 blue("lock error"),
299 rc_upload,
300 blue(_("mirror not locked")),
301 blue(lock_string),
302 ),
303 importance = 1,
304 type = "error",
305 header = darkred(" * ")
306 )
307 self.remove_local_database_lockfile(repo)
308
309 return rc_upload
310
311
313
314 if repo == None:
315 repo = self.Entropy.default_repository
316
317 my_path = os.path.join(
318 self.Entropy.get_remote_database_relative_path(repo),
319 self.SystemSettings['repositories']['branch'])
320 if not ftp_connection:
321 try:
322 ftp_connection = FtpInterface(uri, self.Entropy)
323 except ConnectionError:
324 self.entropyTools.print_traceback()
325 return False
326 ftp_connection.set_cwd(my_path)
327 else:
328 mycwd = ftp_connection.get_cwd()
329 if mycwd != my_path:
330 ftp_connection.set_basedir()
331 ftp_connection.set_cwd(my_path)
332
333 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
334
335 if dblock:
336 dbfile = etpConst['etpdatabaselockfile']
337 else:
338 dbfile = etpConst['etpdatabasedownloadlockfile']
339 rc_delete = ftp_connection.delete_file(dbfile)
340 if rc_delete:
341 self.Entropy.updateProgress(
342 "[repo:%s|%s] %s" % (
343 blue(repo),
344 red(crippled_uri),
345 blue(_("mirror successfully unlocked")),
346 ),
347 importance = 1,
348 type = "info",
349 header = darkgreen(" * ")
350 )
351 if dblock:
352 self.remove_local_database_lockfile(repo)
353 else:
354 self.remove_local_database_download_lockfile(repo)
355 else:
356 self.Entropy.updateProgress(
357 "[repo:%s|%s] %s: %s - %s" % (
358 blue(repo),
359 red(crippled_uri),
360 blue(_("unlock error")),
361 rc_delete,
362 blue(_("mirror not unlocked")),
363 ),
364 importance = 1,
365 type = "error",
366 header = darkred(" * ")
367 )
368
369 return rc_delete
370
372 if repo == None:
373 repo = self.Entropy.default_repository
374 return os.path.join(self.Entropy.get_local_database_dir(repo),
375 etpConst['etpdatabaselockfile'])
376
378 if repo == None:
379 repo = self.Entropy.default_repository
380 return os.path.join(self.Entropy.get_local_database_dir(repo),
381 etpConst['etpdatabasedownloadlockfile'])
382
391
393 if repo == None:
394 repo = self.Entropy.default_repository
395 lock_file = self.get_database_lockfile(repo)
396 f_lock = open(lock_file, "w")
397 f_lock.write("database locked")
398 f_lock.flush()
399 f_lock.close()
400
402 if repo == None:
403 repo = self.Entropy.default_repository
404 lock_file = self.get_database_lockfile(repo)
405 if os.path.isfile(lock_file):
406 os.remove(lock_file)
407
409 if repo == None:
410 repo = self.Entropy.default_repository
411 lock_file = self.get_database_download_lockfile(repo)
412 if os.path.isfile(lock_file):
413 os.remove(lock_file)
414
416
417 if repo == None:
418 repo = self.Entropy.default_repository
419
420 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
421
422 tries = 0
423 while tries < 5:
424 tries += 1
425
426 pkg_to_join_path = '/'.join(pkg_relative_path.split('/')[2:])
427 pkg_to_join_dirpath = os.path.dirname(pkg_to_join_path)
428 pkgfile = os.path.basename(pkg_relative_path)
429
430 self.Entropy.updateProgress(
431 "[repo:%s|%s|#%s] %s: %s" % (
432 brown(repo),
433 darkgreen(crippled_uri),
434 brown(tries),
435 blue(_("connecting to download package")),
436 darkgreen(pkg_to_join_path),
437 ),
438 importance = 1,
439 type = "info",
440 header = darkgreen(" * "),
441 back = True
442 )
443
444 try:
445 ftp = FtpInterface(uri, self.Entropy)
446 except ConnectionError:
447 self.entropyTools.print_traceback()
448 return False
449 dirpath = os.path.join(
450 self.Entropy.get_remote_packages_relative_path(repo),
451 pkg_to_join_dirpath)
452 ftp.set_cwd(dirpath, dodir = True)
453
454 self.Entropy.updateProgress(
455 "[repo:%s|%s|#%s] %s: %s" % (
456 brown(repo),
457 darkgreen(crippled_uri),
458 brown(tries),
459 blue(_("downloading package")),
460 darkgreen(pkg_to_join_path),
461 ),
462 importance = 1,
463 type = "info",
464 header = darkgreen(" * ")
465 )
466
467 download_path = os.path.join(
468 self.Entropy.get_local_packages_directory(repo),
469 pkg_to_join_dirpath)
470 if (not os.path.isdir(download_path)) and \
471 (not os.access(download_path, os.R_OK)):
472 os.makedirs(download_path)
473 rc_download = ftp.download_file(pkgfile, download_path)
474 if not rc_download:
475 self.Entropy.updateProgress(
476 "[repo:%s|%s|#%s] %s: %s %s" % (
477 brown(repo),
478 darkgreen(crippled_uri),
479 brown(tries),
480 blue(_("package")),
481 darkgreen(pkg_to_join_path),
482 blue(_("does not exist")),
483 ),
484 importance = 1,
485 type = "error",
486 header = darkred(" !!! ")
487 )
488 ftp.close()
489 return rc_download
490
491 dbconn = self.Entropy.open_server_repository(read_only = True,
492 no_upload = True, repo = repo)
493 idpackage = dbconn.getIDPackageFromDownload(pkg_relative_path)
494 if idpackage == -1:
495 self.Entropy.updateProgress(
496 "[repo:%s|%s|#%s] %s: %s %s" % (
497 brown(repo),
498 darkgreen(crippled_uri),
499 brown(tries),
500 blue(_("package")),
501 darkgreen(pkgfile),
502 blue(_("is not listed in the repository !")),
503 ),
504 importance = 1,
505 type = "error",
506 header = darkred(" !!! ")
507 )
508 ftp.close()
509 return False
510
511 storedmd5 = dbconn.retrieveDigest(idpackage)
512 self.Entropy.updateProgress(
513 "[repo:%s|%s|#%s] %s: %s" % (
514 brown(repo),
515 darkgreen(crippled_uri),
516 brown(tries),
517 blue(_("verifying checksum of package")),
518 darkgreen(pkgfile),
519 ),
520 importance = 1,
521 type = "info",
522 header = darkgreen(" * "),
523 back = True
524 )
525
526 pkg_path = os.path.join(download_path, pkgfile)
527 md5check = self.entropyTools.compare_md5(pkg_path, storedmd5)
528 if md5check:
529 self.Entropy.updateProgress(
530 "[repo:%s|%s|#%s] %s: %s %s" % (
531 brown(repo),
532 darkgreen(crippled_uri),
533 brown(tries),
534 blue(_("package")),
535 darkgreen(pkgfile),
536 blue(_("downloaded successfully")),
537 ),
538 importance = 1,
539 type = "info",
540 header = darkgreen(" * ")
541 )
542 return True
543 else:
544 self.Entropy.updateProgress(
545 "[repo:%s|%s|#%s] %s: %s %s" % (
546 brown(repo),
547 darkgreen(crippled_uri),
548 brown(tries),
549 blue(_("package")),
550 darkgreen(pkgfile),
551 blue(_("checksum does not match. re-downloading...")),
552 ),
553 importance = 1,
554 type = "warning",
555 header = darkred(" * ")
556 )
557 if os.path.isfile(pkg_path):
558 os.remove(pkg_path)
559
560 continue
561
562
563 self.Entropy.updateProgress(
564 "[repo:%s|%s|#%s] %s: %s %s" % (
565 brown(repo),
566 darkgreen(crippled_uri),
567 brown(tries),
568 blue(_("package")),
569 darkgreen(pkgfile),
570 blue(_("seems broken. Consider to re-package it. Giving up!")),
571 ),
572 importance = 1,
573 type = "error",
574 header = darkred(" !!! ")
575 )
576 return False
577
578
580
581 if repo == None:
582 repo = self.Entropy.default_repository
583
584 if not mirrors:
585 mirrors = self.Entropy.get_remote_mirrors(repo)
586
587 data = []
588 for uri in mirrors:
589
590
591 ftp = FtpInterface(uri, self.Entropy)
592 try:
593 my_path = os.path.join(
594 self.Entropy.get_remote_database_relative_path(repo),
595 self.SystemSettings['repositories']['branch'])
596 ftp.set_cwd(my_path, dodir = True)
597 except ftp.ftplib.error_perm:
598 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
599 self.Entropy.updateProgress(
600 "[repo:%s|%s] %s !" % (
601 brown(repo),
602 darkgreen(crippled_uri),
603 blue(_("mirror has invalid directory structure")),
604 ),
605 importance = 1,
606 type = "warning",
607 header = darkred(" !!! ")
608 )
609 ftp.close()
610 continue
611 sys_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
612 db_format = sys_set['database_file_format']
613 cmethod = etpConst['etpdatabasecompressclasses'].get(db_format)
614 if cmethod == None:
615 raise InvalidDataType("InvalidDataType: %s." % (
616 _("Wrong database compression method passed"),
617 )
618 )
619 compressedfile = etpConst[cmethod[2]]
620
621 revision = 0
622 rc1 = ftp.is_file_available(compressedfile)
623 revfilename = os.path.basename(
624 self.Entropy.get_local_database_revision_file(repo))
625 rc2 = ftp.is_file_available(revfilename)
626 if rc1 and rc2:
627 revision_localtmppath = os.path.join(etpConst['packagestmpdir'],
628 revfilename)
629 dlcount = 5
630 while dlcount:
631 dled = ftp.download_file(revfilename,
632 etpConst['packagestmpdir'], True)
633 if dled:
634 break
635 dlcount -= 1
636
637 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
638 if os.access(revision_localtmppath, os.R_OK | os.F_OK):
639 f_rev = open(revision_localtmppath,"r")
640 try:
641 revision = int(f_rev.readline().strip())
642 except ValueError:
643 mytxt = _("mirror hasn't valid database revision file")
644 self.Entropy.updateProgress(
645 "[repo:%s|%s] %s: %s" % (
646 brown(repo),
647 darkgreen(crippled_uri),
648 blue(mytxt),
649 bold(revision),
650 ),
651 importance = 1,
652 type = "error",
653 header = darkred(" !!! ")
654 )
655 revision = 0
656 f_rev.close()
657 elif dlcount == 0:
658 self.Entropy.updateProgress(
659 "[repo:%s|%s] %s: %s" % (
660 brown(repo),
661 darkgreen(crippled_uri),
662 blue(_("unable to download repository revision")),
663 bold(revision),
664 ),
665 importance = 1,
666 type = "error",
667 header = darkred(" !!! ")
668 )
669 revision = 0
670 else:
671 self.Entropy.updateProgress(
672 "[repo:%s|%s] %s: %s" % (
673 brown(repo),
674 darkgreen(crippled_uri),
675 blue(_("mirror doesn't have valid revision file")),
676 bold(revision),
677 ),
678 importance = 1,
679 type = "error",
680 header = darkred(" !!! ")
681 )
682 revision = 0
683 if os.path.isfile(revision_localtmppath):
684 os.remove(revision_localtmppath)
685
686 info = [uri, revision]
687 data.append(info)
688 ftp.close()
689
690 return data
691
693 local_repo = repo
694 if local_repo == None:
695 local_repo = self.Entropy.default_repository
696 lock_file = self.get_database_lockfile(local_repo)
697 return os.path.isfile(lock_file)
698
722
724
725 if repo == None:
726 repo = self.Entropy.default_repository
727 mirrors = self.Entropy.get_remote_mirrors(repo)
728 rss_path = self.Entropy.get_local_database_notice_board_file(repo)
729 mytmpdir = self.entropyTools.get_random_temp_file()
730 os.makedirs(mytmpdir)
731
732 self.Entropy.updateProgress(
733 "[repo:%s] %s %s" % (
734 brown(repo),
735 blue(_("downloading notice board from mirrors to")),
736 red(rss_path),
737 ),
738 importance = 1,
739 type = "info",
740 header = blue(" @@ ")
741 )
742
743 downloaded = False
744 for uri in mirrors:
745 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
746 downloader = self.FtpServerHandler(
747 FtpInterface, self.Entropy, [uri],
748 [rss_path], download = True,
749 local_basedir = mytmpdir, critical_files = [rss_path],
750 repo = repo
751 )
752 errors, m_fine_uris, m_broken_uris = downloader.go()
753 if not errors:
754 self.Entropy.updateProgress(
755 "[repo:%s] %s: %s" % (
756 brown(repo),
757 blue(_("notice board downloaded successfully from")),
758 red(crippled_uri),
759 ),
760 importance = 1,
761 type = "info",
762 header = blue(" @@ ")
763 )
764 downloaded = True
765 break
766
767 if downloaded:
768 shutil.move(os.path.join(mytmpdir, os.path.basename(rss_path)),
769 rss_path)
770
771 return downloaded
772
774
775 if repo == None:
776 repo = self.Entropy.default_repository
777 mirrors = self.Entropy.get_remote_mirrors(repo)
778 rss_path = self.Entropy.get_local_database_notice_board_file(repo)
779
780 self.Entropy.updateProgress(
781 "[repo:%s] %s %s" % (
782 brown(repo),
783 blue(_("uploading notice board from")),
784 red(rss_path),
785 ),
786 importance = 1,
787 type = "info",
788 header = blue(" @@ ")
789 )
790
791 uploader = self.FtpServerHandler(
792 FtpInterface,
793 self.Entropy,
794 mirrors,
795 [rss_path],
796 critical_files = [rss_path],
797 repo = repo
798 )
799 errors, m_fine_uris, m_broken_uris = uploader.go()
800 if errors:
801 m_broken_uris = sorted(m_broken_uris)
802 m_broken_uris = [self.entropyTools.extract_ftp_host_from_uri(x) \
803 for x in m_broken_uris]
804 self.Entropy.updateProgress(
805 "[repo:%s] %s %s" % (
806 brown(repo),
807 blue(_("notice board upload failed on")),
808 red(', '.join(m_broken_uris)),
809 ),
810 importance = 1,
811 type = "info",
812 header = blue(" @@ ")
813 )
814 return False
815 self.Entropy.updateProgress(
816 "[repo:%s] %s" % (
817 brown(repo),
818 blue(_("notice board upload success")),
819 ),
820 importance = 1,
821 type = "info",
822 header = blue(" @@ ")
823 )
824 return True
825
826
843
853
855
856 rss_path = self.Entropy.get_local_database_notice_board_file(repo)
857 rss_title = "%s Notice Board" % (self.SystemSettings['system']['name'],)
858 rss_description = "Inform about important distribution activities."
859 if not (os.path.isfile(rss_path) and os.access(rss_path, os.R_OK)):
860 return 0
861 rss_main = RSS(rss_path, rss_title, rss_description)
862 data = rss_main.remove_entry(identifier)
863 rss_main.write_changes()
864 return data
865
867
868 product = self.SystemSettings['repositories']['product']
869
870 rss_path = self.Entropy.get_local_database_rss_file(repo)
871 rss_light_path = self.Entropy.get_local_database_rsslight_file(repo)
872 rss_dump_name = etpConst['rss-dump-name']
873 db_revision_path = self.Entropy.get_local_database_revision_file(repo)
874
875 rss_title = u"%s Online Repository Status" % (
876 self.SystemSettings['system']['name'],)
877 rss_description = \
878 u"Keep you updated on what's going on in the %s Repository." % (
879 self.SystemSettings['system']['name'],)
880
881 srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
882
883 rss_main = RSS(rss_path, rss_title, rss_description,
884 maxentries = srv_set['rss']['max_entries'])
885
886 db_actions = self.Cacher.pop(rss_dump_name)
887 if db_actions:
888 try:
889 f_rev = open(db_revision_path)
890 revision = f_rev.readline().strip()
891 f_rev.close()
892 except (IOError, OSError):
893 revision = u"N/A"
894 commitmessage = u''
895 if self.Entropy.rssMessages['commitmessage']:
896 commitmessage = u' :: ' + \
897 self.Entropy.rssMessages['commitmessage']
898
899 title = u": " + self.SystemSettings['system']['name'] + u" " + \
900 product[0].upper() + product[1:] + " " + \
901 self.SystemSettings['repositories']['branch'] + \
902 " :: Revision: " + revision + commitmessage
903
904 link = srv_set['rss']['base_url']
905
906 added_items = db_actions.get("added")
907
908 if added_items:
909 for atom in added_items:
910 mylink = link + "?search=" + atom.split("~")[0] + \
911 "&arch=" + etpConst['currentarch'] + "&product="+product
912 description = atom + ": " + added_items[atom]['description']
913 rss_main.add_item(title = "Added/Updated" + title,
914 link = mylink, description = description)
915 removed_items = db_actions.get("removed")
916
917 if removed_items:
918 for atom in removed_items:
919 description = atom + ": " + \
920 removed_items[atom]['description']
921 rss_main.add_item(title = "Removed" + title, link = link,
922 description = description)
923
924 light_items = db_actions.get('light')
925 if light_items:
926 rss_light = RSS(rss_light_path, rss_title, rss_description,
927 maxentries = srv_set['rss']['light_max_entries'])
928 for atom in light_items:
929 mylink = link + "?search=" + atom.split("~")[0] + \
930 "&arch=" + etpConst['currentarch'] + "&product=" + \
931 product
932 description = light_items[atom]['description']
933 rss_light.add_item(title = "[" + revision + "] " + atom,
934 link = mylink, description = description)
935 rss_light.write_changes()
936
937 rss_main.write_changes()
938 self.Entropy.rssMessages.clear()
939 self.dumpTools.removeobj(rss_dump_name)
940
941
942 - def dump_database_to_file(self, db_path, destination_path, opener,
943 exclude_tables = None, repo = None):
944
945 if not exclude_tables:
946 exclude_tables = []
947
948 f_out = opener(destination_path, "wb")
949 dbconn = self.Entropy.open_server_repository(db_path,
950 just_reading = True, repo = repo)
951 dbconn.doDatabaseExport(f_out, exclude_tables = exclude_tables)
952 self.Entropy.close_server_database(dbconn)
953 f_out.close()
954
956 mydigest = self.entropyTools.md5sum(file_path)
957 f_ck = open(checksum_path, "w")
958 mystring = "%s %s\n" % (mydigest, os.path.basename(file_path),)
959 f_ck.write(mystring)
960 f_ck.flush()
961 f_ck.close()
962
964 f_out = opener(destination_path, "wb")
965 f_in = open(file_path,"rb")
966 data = f_in.read(8192)
967 while data:
968 f_out.write(data)
969 data = f_in.read(8192)
970 f_in.close()
971 if hasattr(f_out,'flush'):
972 f_out.flush()
973 f_out.close()
974
975 - def get_files_to_sync(self, cmethod, download = False, repo = None,
976 disabled_eapis = None):
977
978 if disabled_eapis == None:
979 disabled_eapis = []
980
981 critical = []
982 extra_text_files = []
983 data = {}
984 data['database_revision_file'] = \
985 self.Entropy.get_local_database_revision_file(repo)
986 extra_text_files.append(data['database_revision_file'])
987 critical.append(data['database_revision_file'])
988
989 database_ts_file = self.Entropy.get_local_database_timestamp_file(repo)
990 if os.path.isfile(database_ts_file) or download:
991 data['database_timestamp_file'] = database_ts_file
992 if not download:
993 critical.append(database_ts_file)
994
995 database_package_mask_file = \
996 self.Entropy.get_local_database_mask_file(repo)
997 extra_text_files.append(database_package_mask_file)
998 if os.path.isfile(database_package_mask_file) or download:
999 data['database_package_mask_file'] = database_package_mask_file
1000 if not download:
1001 critical.append(data['database_package_mask_file'])
1002
1003 database_package_system_mask_file = \
1004 self.Entropy.get_local_database_system_mask_file(repo)
1005 extra_text_files.append(database_package_system_mask_file)
1006 if os.path.isfile(database_package_system_mask_file) or download:
1007 data['database_package_system_mask_file'] = \
1008 database_package_system_mask_file
1009 if not download:
1010 critical.append(data['database_package_system_mask_file'])
1011
1012 database_package_confl_tagged_file = \
1013 self.Entropy.get_local_database_confl_tagged_file(repo)
1014 extra_text_files.append(database_package_confl_tagged_file)
1015 if os.path.isfile(database_package_confl_tagged_file) or download:
1016 data['database_package_confl_tagged_file'] = \
1017 database_package_confl_tagged_file
1018 if not download:
1019 critical.append(data['database_package_confl_tagged_file'])
1020
1021 database_license_whitelist_file = \
1022 self.Entropy.get_local_database_licensewhitelist_file(repo)
1023 extra_text_files.append(database_license_whitelist_file)
1024 if os.path.isfile(database_license_whitelist_file) or download:
1025 data['database_license_whitelist_file'] = \
1026 database_license_whitelist_file
1027 if not download:
1028 critical.append(data['database_license_whitelist_file'])
1029
1030 exp_based_pkgs_removal_file = \
1031 self.Entropy.get_local_exp_based_pkgs_rm_whitelist_file(repo)
1032 extra_text_files.append(exp_based_pkgs_removal_file)
1033 if os.path.isfile(exp_based_pkgs_removal_file) or download:
1034 data['exp_based_pkgs_removal_file'] = exp_based_pkgs_removal_file
1035 if not download:
1036 critical.append(data['exp_based_pkgs_removal_file'])
1037
1038 database_rss_file = self.Entropy.get_local_database_rss_file(repo)
1039 if os.path.isfile(database_rss_file) or download:
1040 data['database_rss_file'] = database_rss_file
1041 if not download:
1042 critical.append(data['database_rss_file'])
1043 database_rss_light_file = \
1044 self.Entropy.get_local_database_rsslight_file(repo)
1045
1046 extra_text_files.append(database_rss_light_file)
1047 if os.path.isfile(database_rss_light_file) or download:
1048 data['database_rss_light_file'] = database_rss_light_file
1049 if not download:
1050 critical.append(data['database_rss_light_file'])
1051
1052
1053 if not download:
1054 if 3 not in disabled_eapis:
1055 data['metafiles_path'] = \
1056 self.Entropy.get_local_database_compressed_metafiles_file(
1057 repo)
1058 critical.append(data['metafiles_path'])
1059 if 2 not in disabled_eapis:
1060 data['dump_path'] = os.path.join(
1061 self.Entropy.get_local_database_dir(repo),
1062 etpConst[cmethod[3]])
1063 critical.append(data['dump_path'])
1064
1065 data['dump_path_digest'] = os.path.join(
1066 self.Entropy.get_local_database_dir(repo),
1067 etpConst[cmethod[4]])
1068 critical.append(data['dump_path_digest'])
1069
1070 data['dump_path_light'] = os.path.join(
1071 self.Entropy.get_local_database_dir(repo),
1072 etpConst[cmethod[5]])
1073 critical.append(data['dump_path_light'])
1074
1075 data['dump_path_digest_light'] = os.path.join(
1076 self.Entropy.get_local_database_dir(repo),
1077 etpConst[cmethod[6]])
1078 critical.append(data['dump_path_digest_light'])
1079
1080 data['database_path'] = \
1081 self.Entropy.get_local_database_file(repo)
1082 critical.append(data['database_path'])
1083
1084
1085 if 1 not in disabled_eapis:
1086 data['compressed_database_path'] = os.path.join(
1087 self.Entropy.get_local_database_dir(repo), etpConst[cmethod[2]])
1088 critical.append(data['compressed_database_path'])
1089 data['compressed_database_path_digest'] = os.path.join(
1090 self.Entropy.get_local_database_dir(repo),
1091 etpConst['etpdatabasehashfile']
1092 )
1093 critical.append(data['compressed_database_path_digest'])
1094
1095
1096 ssl_ca_cert = self.Entropy.get_local_database_ca_cert_file()
1097 extra_text_files.append(ssl_ca_cert)
1098 if os.path.isfile(ssl_ca_cert):
1099 data['ssl_ca_cert_file'] = ssl_ca_cert
1100 if not download:
1101 critical.append(ssl_ca_cert)
1102 ssl_server_cert = self.Entropy.get_local_database_server_cert_file()
1103 extra_text_files.append(ssl_server_cert)
1104 if os.path.isfile(ssl_server_cert):
1105 data['ssl_server_cert_file'] = ssl_server_cert
1106 if not download:
1107 critical.append(ssl_server_cert)
1108
1109
1110 spm_files = [
1111 (etpConst['spm']['global_make_conf'], "global_make_conf"),
1112 (etpConst['spm']['global_package_keywords'],
1113 "global_package_keywords"),
1114 (etpConst['spm']['global_package_use'], "global_package_use"),
1115 (etpConst['spm']['global_package_mask'], "global_package_mask"),
1116 (etpConst['spm']['global_package_unmask'], "global_package_unmask"),
1117 ]
1118 for myfile, myname in spm_files:
1119 if os.path.isfile(myfile) and os.access(myfile, os.R_OK):
1120 data[myname] = myfile
1121 extra_text_files.append(myfile)
1122
1123 make_profile = etpConst['spm']['global_make_profile']
1124 rnd_tmp_file = self.Entropy.entropyTools.get_random_temp_file()
1125 mytmpdir = os.path.dirname(rnd_tmp_file)
1126 mytmpfile = os.path.join(mytmpdir,
1127 etpConst['spm']['global_make_profile_link_name'])
1128 extra_text_files.append(mytmpfile)
1129
1130 if os.path.islink(make_profile):
1131 mylink = os.readlink(make_profile)
1132 f_mkp = open(mytmpfile,"w")
1133 f_mkp.write(mylink)
1134 f_mkp.flush()
1135 f_mkp.close()
1136 data['global_make_profile'] = mytmpfile
1137
1138 return data, critical, extra_text_files
1139
1141
1142 self.Entropy.updateProgress(
1143 "[repo:%s] %s:" % (
1144 brown(repo),
1145 blue(_("configured package sets")),
1146 ),
1147 importance = 0,
1148 type = "info",
1149 header = darkgreen(" * ")
1150 )
1151 sets_data = self.Entropy.package_set_list(matchRepo = repo)
1152 if not sets_data:
1153 self.Entropy.updateProgress(
1154 "%s" % (_("None configured"),),
1155 importance = 0,
1156 type = "info",
1157 header = brown(" # ")
1158 )
1159 return
1160 for s_repo, s_name, s_sets in sets_data:
1161 self.Entropy.updateProgress(
1162 blue("%s" % (s_name,)),
1163 importance = 0,
1164 type = "info",
1165 header = brown(" # ")
1166 )
1167
1169
1170 self.Entropy.updateProgress(
1171 "[repo:%s|%s|%s:%s] %s" % (
1172 brown(repo),
1173 darkgreen(crippled_uri),
1174 red("EAPI"),
1175 bold("3"),
1176 blue(_("preparing uncompressed database for the upload")),
1177 ),
1178 importance = 0,
1179 type = "info",
1180 header = darkgreen(" * ")
1181 )
1182 self.Entropy.updateProgress(
1183 "%s: %s" % (_("database path"), blue(database_path),),
1184 importance = 0,
1185 type = "info",
1186 header = brown(" # ")
1187 )
1188
1191
1192 if repo == None:
1193 repo = self.Entropy.default_repository
1194
1195 self.Entropy.updateProgress(
1196 "[repo:%s|%s|%s:%s] %s" % (
1197 brown(repo),
1198 darkgreen(crippled_uri),
1199 red("EAPI"),
1200 bold("2"),
1201 blue(_("creating compressed database dump + checksum")),
1202 ),
1203 importance = 0,
1204 type = "info",
1205 header = darkgreen(" * ")
1206 )
1207 self.Entropy.updateProgress(
1208 "%s: %s" % (_("database path"), blue(database_path),),
1209 importance = 0,
1210 type = "info",
1211 header = brown(" # ")
1212 )
1213 self.Entropy.updateProgress(
1214 "%s: %s" % (_("dump"), blue(upload_data['dump_path']),),
1215 importance = 0,
1216 type = "info",
1217 header = brown(" # ")
1218 )
1219 self.Entropy.updateProgress(
1220 "%s: %s" % (
1221 _("dump checksum"),
1222 blue(upload_data['dump_path_digest']),
1223 ),
1224 importance = 0,
1225 type = "info",
1226 header = brown(" # ")
1227 )
1228 self.Entropy.updateProgress(
1229 "%s: %s" % (
1230 _("dump light"),
1231 blue(upload_data['dump_path_light']),
1232 ),
1233 importance = 0,
1234 type = "info",
1235 header = brown(" # ")
1236 )
1237 self.Entropy.updateProgress(
1238 "%s: %s" % (
1239 _("dump light checksum"),
1240 blue(upload_data['dump_path_digest_light']),
1241 ),
1242 importance = 0,
1243 type = "info",
1244 header = brown(" # ")
1245 )
1246
1247 self.Entropy.updateProgress(
1248 "%s: %s" % (_("opener"), blue(str(cmethod[0])),),
1249 importance = 0,
1250 type = "info",
1251 header = brown(" # ")
1252 )
1253
1256
1257 self.Entropy.updateProgress(
1258 "[repo:%s|%s|%s:%s] %s" % (
1259 brown(repo),
1260 darkgreen(crippled_uri),
1261 red("EAPI"),
1262 bold("1"),
1263 blue(_("compressing database + checksum")),
1264 ),
1265 importance = 0,
1266 type = "info",
1267 header = darkgreen(" * "),
1268 back = True
1269 )
1270 self.Entropy.updateProgress(
1271 "%s: %s" % (_("database path"), blue(database_path),),
1272 importance = 0,
1273 type = "info",
1274 header = brown(" # ")
1275 )
1276 self.Entropy.updateProgress(
1277 "%s: %s" % (
1278 _("compressed database path"),
1279 blue(upload_data['compressed_database_path']),
1280 ),
1281 importance = 0,
1282 type = "info",
1283 header = brown(" # ")
1284 )
1285 self.Entropy.updateProgress(
1286 "%s: %s" % (
1287 _("compressed checksum"),
1288 blue(upload_data['compressed_database_path_digest']),
1289 ),
1290 importance = 0,
1291 type = "info",
1292 header = brown(" # ")
1293 )
1294 self.Entropy.updateProgress(
1295 "%s: %s" % (_("opener"), blue(str(cmethod[0])),),
1296 importance = 0,
1297 type = "info",
1298 header = brown(" # ")
1299 )
1300
1318
1320 bdir = ""
1321 for mydir in path_to_create.split("/"):
1322 bdir += "/"+mydir
1323 if not ftp_connection.is_file_available(bdir):
1324 try:
1325 ftp_connection.mkdir(bdir)
1326 except Exception, err:
1327 error = unicode(err)
1328 if (error.find("550") == -1) and \
1329 (error.find("File exist") == -1):
1330
1331 mytxt = "%s %s, %s: %s" % (
1332 _("cannot create mirror directory"),
1333 bdir,
1334 _("error"),
1335 err,
1336 )
1337 raise OnlineMirrorError("OnlineMirrorError: %s" % (
1338 mytxt,))
1339 raise
1340
1342
1343 if repo == None:
1344 repo = self.Entropy.default_repository
1345
1346 gave_up = False
1347 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
1348 try:
1349 ftp = FtpInterface(uri, self.Entropy)
1350 except ConnectionError:
1351 self.entropyTools.print_traceback()
1352 return True
1353 my_path = os.path.join(
1354 self.Entropy.get_remote_database_relative_path(repo),
1355 self.SystemSettings['repositories']['branch'])
1356 ftp.set_cwd(my_path, dodir = True)
1357
1358 lock_file = self.get_database_lockfile(repo)
1359 lock_filename = os.path.basename(lock_file)
1360 if not os.path.isfile(lock_file) and \
1361 ftp.is_file_available(lock_filename):
1362
1363 self.Entropy.updateProgress(
1364 "[repo:%s|%s|%s] %s, %s" % (
1365 brown(str(repo)),
1366 darkgreen(crippled_uri),
1367 red(_("locking")),
1368 darkblue(_("mirror already locked")),
1369 blue(_("waiting up to 2 minutes before giving up")),
1370 ),
1371 importance = 1,
1372 type = "warning",
1373 header = brown(" * "),
1374 back = True
1375 )
1376 unlocked = False
1377 count = 0
1378 while count < 120:
1379 count += 1
1380 time.sleep(1)
1381 if not ftp.is_file_available(os.path.basename(lock_file)):
1382 self.Entropy.updateProgress(
1383 red("[repo:%s|%s|%s] %s !" % (
1384 repo,
1385 crippled_uri,
1386 _("locking"),
1387 _("mirror unlocked"),
1388 )
1389 ),
1390 importance = 1,
1391 type = "info",
1392 header = darkgreen(" * ")
1393 )
1394 unlocked = True
1395 break
1396 if not unlocked:
1397 gave_up = True
1398
1399 ftp.close()
1400 return gave_up
1401
1410
1420
1422
1423 if repo == None:
1424 repo = self.Entropy.default_repository
1425 dbconn = self.Entropy.open_server_repository(read_only = False,
1426 no_upload = True, repo = repo)
1427
1428 srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
1429 server_repos = srv_set['repositories'].keys()
1430 all_actions = set()
1431 for myrepo in server_repos:
1432
1433
1434 if myrepo == etpConst['clientserverrepoid']:
1435 continue
1436
1437 mydbc = self.Entropy.open_server_repository(just_reading = True,
1438 repo = myrepo)
1439 actions = mydbc.listAllTreeUpdatesActions(no_ids_repos = True)
1440 for data in actions:
1441 all_actions.add(data)
1442 if not actions:
1443 continue
1444 backed_up_entries = dbconn.listAllTreeUpdatesActions()
1445 try:
1446
1447 dbconn.removeTreeUpdatesActions(repo)
1448 dbconn.insertTreeUpdatesActions(all_actions, repo)
1449 except dbapi2.Error, err:
1450 self.entropyTools.print_traceback()
1451 mytxt = "%s, %s: %s. %s" % (
1452 _("Troubles with treeupdates"),
1453 _("error"),
1454 err,
1455 _("Bumping old data back"),
1456 )
1457 self.Entropy.updateProgress(
1458 mytxt,
1459 importance = 1,
1460 type = "warning"
1461 )
1462
1463 dbconn.bumpTreeUpdatesActions(backed_up_entries)
1464
1465 dbconn.commitChanges()
1466 self.Entropy.close_server_database(dbconn)
1467
1468 - def upload_database(self, uris, lock_check = False, pretend = False,
1469 repo = None):
1470
1471 if repo == None:
1472 repo = self.Entropy.default_repository
1473
1474 srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
1475 if srv_set['rss']['enabled']:
1476 self.update_rss_feed(repo = repo)
1477
1478 upload_errors = False
1479 broken_uris = set()
1480 fine_uris = set()
1481
1482 disabled_eapis = sorted(srv_set['disabled_eapis'])
1483
1484 for uri in uris:
1485
1486 db_format = srv_set['database_file_format']
1487 cmethod = etpConst['etpdatabasecompressclasses'].get(db_format)
1488 if cmethod == None:
1489 raise InvalidDataType("InvalidDataType: %s." % (
1490 _("wrong database compression method passed"),
1491 )
1492 )
1493
1494 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
1495 database_path = self.Entropy.get_local_database_file(repo)
1496
1497 if disabled_eapis:
1498 self.Entropy.updateProgress(
1499 "[repo:%s|%s|%s] %s: %s" % (
1500 blue(repo),
1501 red(crippled_uri),
1502 darkgreen(_("upload")),
1503 darkred(_("disabled EAPI")),
1504 bold(', '.join(disabled_eapis)),
1505 ),
1506 importance = 1,
1507 type = "warning",
1508 header = darkgreen(" * ")
1509 )
1510
1511
1512 self.update_repository_timestamp(repo)
1513
1514 upload_data, critical, text_files = self.get_files_to_sync(cmethod,
1515 repo = repo, disabled_eapis = disabled_eapis)
1516
1517 if lock_check:
1518 given_up = self.mirror_lock_check(uri, repo = repo)
1519 if given_up:
1520 upload_errors = True
1521 broken_uris.add(uri)
1522 continue
1523
1524 self.lock_mirrors_for_download(True, [uri], repo = repo)
1525
1526 self.Entropy.updateProgress(
1527 "[repo:%s|%s|%s] %s" % (
1528 blue(repo),
1529 red(crippled_uri),
1530 darkgreen(_("upload")),
1531 darkgreen(_("preparing to upload database to mirror")),
1532 ),
1533 importance = 1,
1534 type = "info",
1535 header = darkgreen(" * ")
1536 )
1537
1538
1539 self._show_package_sets_messages(repo)
1540
1541 self.sync_database_treeupdates(repo)
1542 self.Entropy.update_database_package_sets(repo)
1543 self.Entropy.close_server_databases()
1544
1545
1546 old_dbpath = self.Entropy.get_local_database_file(repo)
1547 backup_dbpath = old_dbpath + ".up_backup"
1548 copy_back = False
1549 if not pretend:
1550 try:
1551 if os.access(backup_dbpath, os.R_OK | os.F_OK):
1552 os.remove(backup_dbpath)
1553 shutil.copy2(old_dbpath, backup_dbpath)
1554 copy_back = True
1555 except shutil.Error:
1556 copy_back = False
1557
1558 self.shrink_database_and_close(repo)
1559
1560
1561 if 3 not in disabled_eapis:
1562 self._create_metafiles_file(upload_data['metafiles_path'],
1563 text_files, repo)
1564 self._show_eapi3_upload_messages(crippled_uri, database_path,
1565 repo)
1566
1567
1568 if 2 not in disabled_eapis:
1569 self._show_eapi2_upload_messages(crippled_uri, database_path,
1570 upload_data, cmethod, repo)
1571
1572
1573 self.dump_database_to_file(database_path,
1574 upload_data['dump_path'], cmethod[0], repo = repo)
1575 self.create_file_checksum(upload_data['dump_path'],
1576 upload_data['dump_path_digest'])
1577
1578 self.dump_database_to_file(database_path,
1579 upload_data['dump_path_light'], cmethod[0],
1580 exclude_tables = ["content"], repo = repo)
1581 self.create_file_checksum(upload_data['dump_path_light'],
1582 upload_data['dump_path_digest_light'])
1583
1584
1585
1586 if 1 not in disabled_eapis:
1587 self._show_eapi1_upload_messages(crippled_uri, database_path,
1588 upload_data, cmethod, repo)
1589
1590 self.compress_file(database_path,
1591 upload_data['compressed_database_path'], cmethod[0])
1592 self.create_file_checksum(database_path,
1593 upload_data['compressed_database_path_digest'])
1594
1595 if not pretend:
1596
1597 uploader = self.FtpServerHandler(
1598 FtpInterface,
1599 self.Entropy,
1600 [uri],
1601 [upload_data[x] for x in upload_data],
1602 critical_files = critical,
1603 repo = repo
1604 )
1605 errors, m_fine_uris, m_broken_uris = uploader.go()
1606 if errors:
1607 my_broken_uris = sorted([
1608 (self.entropyTools.extract_ftp_host_from_uri(x[0]),
1609 x[1]) for x in m_broken_uris])
1610 self.Entropy.updateProgress(
1611 "[repo:%s|%s|%s] %s" % (
1612 repo,
1613 crippled_uri,
1614 _("errors"),
1615 _("upload failed, not unlocking and continuing"),
1616 ),
1617 importance = 0,
1618 type = "error",
1619 header = darkred(" !!! ")
1620 )
1621
1622 reason = my_broken_uris[0][1]
1623 self.Entropy.updateProgress(
1624 blue("%s: %s" % (_("reason"), reason,)),
1625 importance = 0,
1626 type = "error",
1627 header = blue(" # ")
1628 )
1629 upload_errors = True
1630 broken_uris |= m_broken_uris
1631 continue
1632
1633
1634 if copy_back and os.path.isfile(backup_dbpath):
1635 self.Entropy.close_server_databases()
1636 further_backup_dbpath = old_dbpath+".security_backup"
1637 if os.path.isfile(further_backup_dbpath):
1638 os.remove(further_backup_dbpath)
1639 shutil.copy2(old_dbpath, further_backup_dbpath)
1640 shutil.move(backup_dbpath, old_dbpath)
1641
1642
1643 self.lock_mirrors_for_download(False, [uri], repo = repo)
1644 fine_uris |= m_fine_uris
1645
1646 if not fine_uris:
1647 upload_errors = True
1648 return upload_errors, broken_uris, fine_uris
1649
1650
1651 - def download_database(self, uris, lock_check = False, pretend = False,
1652 repo = None):
1653
1654 if repo == None:
1655 repo = self.Entropy.default_repository
1656
1657 download_errors = False
1658 broken_uris = set()
1659 fine_uris = set()
1660 srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
1661 disabled_eapis = sorted(srv_set['disabled_eapis'])
1662
1663 for uri in uris:
1664
1665 db_format = srv_set['database_file_format']
1666 cmethod = etpConst['etpdatabasecompressclasses'].get(db_format)
1667 if cmethod == None:
1668 raise InvalidDataType("InvalidDataType: %s." % (
1669 _("wrong database compression method passed"),
1670 )
1671 )
1672
1673 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
1674 database_path = self.Entropy.get_local_database_file(repo)
1675 database_dir_path = os.path.dirname(
1676 self.Entropy.get_local_database_file(repo))
1677 download_data, critical, text_files = self.get_files_to_sync(
1678 cmethod, download = True,
1679 repo = repo, disabled_eapis = disabled_eapis)
1680 mytmpdir = self.entropyTools.get_random_temp_file()
1681 os.makedirs(mytmpdir)
1682
1683 self.Entropy.updateProgress(
1684 "[repo:%s|%s|%s] %s" % (
1685 brown(repo),
1686 darkgreen(crippled_uri),
1687 red(_("download")),
1688 blue(_("preparing to download database from mirror")),
1689 ),
1690 importance = 1,
1691 type = "info",
1692 header = darkgreen(" * ")
1693 )
1694 files_to_sync = sorted(download_data.keys())
1695 for myfile in files_to_sync:
1696 self.Entropy.updateProgress(
1697 "%s: %s" % (
1698 blue(_("download path")),
1699 brown(unicode(download_data[myfile])),
1700 ),
1701 importance = 0,
1702 type = "info",
1703 header = brown(" # ")
1704 )
1705
1706 if lock_check:
1707 given_up = self.mirror_lock_check(uri, repo = repo)
1708 if given_up:
1709 download_errors = True
1710 broken_uris.add(uri)
1711 continue
1712
1713
1714 self.lock_mirrors(True, [uri], repo = repo)
1715
1716 if not pretend:
1717
1718 downloader = self.FtpServerHandler(
1719 FtpInterface, self.Entropy, [uri],
1720 [download_data[x] for x in download_data], download = True,
1721 local_basedir = mytmpdir, critical_files = critical,
1722 repo = repo
1723 )
1724 errors, m_fine_uris, m_broken_uris = downloader.go()
1725 if errors:
1726 my_broken_uris = sorted([
1727 (self.entropyTools.extract_ftp_host_from_uri(x[0]),
1728 x[1]) for x in m_broken_uris])
1729 self.Entropy.updateProgress(
1730 "[repo:%s|%s|%s] %s" % (
1731 brown(repo),
1732 darkgreen(crippled_uri),
1733 red(_("errors")),
1734 blue(_("failed to download from mirror")),
1735 ),
1736 importance = 0,
1737 type = "error",
1738 header = darkred(" !!! ")
1739 )
1740
1741 reason = my_broken_uris[0][1]
1742 self.Entropy.updateProgress(
1743 blue("%s: %s" % (_("reason"), reason,)),
1744 importance = 0,
1745 type = "error",
1746 header = blue(" # ")
1747 )
1748 download_errors = True
1749 broken_uris |= m_broken_uris
1750 self.lock_mirrors(False, [uri], repo = repo)
1751 continue
1752
1753
1754
1755
1756
1757 if 1 not in disabled_eapis:
1758 compressed_db_filename = os.path.basename(
1759 download_data['compressed_database_path'])
1760 uncompressed_db_filename = os.path.basename(database_path)
1761 compressed_file = os.path.join(mytmpdir,
1762 compressed_db_filename)
1763 uncompressed_file = os.path.join(mytmpdir,
1764 uncompressed_db_filename)
1765 self.entropyTools.uncompress_file(compressed_file,
1766 uncompressed_file, cmethod[0])
1767
1768
1769 for myfile in os.listdir(mytmpdir):
1770 fromfile = os.path.join(mytmpdir, myfile)
1771 tofile = os.path.join(database_dir_path, myfile)
1772 shutil.move(fromfile, tofile)
1773 self.Entropy.ClientService.setup_default_file_perms(tofile)
1774
1775 if os.path.isdir(mytmpdir):
1776 shutil.rmtree(mytmpdir)
1777 if os.path.isdir(mytmpdir):
1778 os.rmdir(mytmpdir)
1779
1780
1781 fine_uris.add(uri)
1782 self.lock_mirrors(False, [uri], repo = repo)
1783
1784 return download_errors, fine_uris, broken_uris
1785
1787
1788 if repo == None:
1789 repo = self.Entropy.default_repository
1790
1791 remote_status = self.get_remote_databases_status(repo)
1792 local_revision = self.Entropy.get_local_database_revision(repo)
1793 upload_queue = []
1794 download_latest = ()
1795
1796
1797 if not [x for x in remote_status if x[1]]:
1798 upload_queue = remote_status[:]
1799 else:
1800 highest_remote_revision = max([x[1] for x in remote_status])
1801
1802 if local_revision < highest_remote_revision:
1803 for remote_item in remote_status:
1804 if remote_item[1] == highest_remote_revision:
1805 download_latest = x
1806 break
1807
1808 if download_latest:
1809 upload_queue = [x for x in remote_status if \
1810 (x[1] < highest_remote_revision)]
1811 else:
1812 upload_queue = [x for x in remote_status if \
1813 (x[1] < local_revision)]
1814
1815 return download_latest, upload_queue
1816
1817 - def sync_databases(self, no_upload = False, unlock_mirrors = False,
1818 repo = None):
1819
1820 if repo == None:
1821 repo = self.Entropy.default_repository
1822
1823 while 1:
1824
1825 db_locked = False
1826 if self.is_local_database_locked(repo):
1827 db_locked = True
1828
1829 lock_data = self.get_mirrors_lock(repo)
1830 mirrors_locked = [x for x in lock_data if x[1]]
1831
1832 if not mirrors_locked and db_locked:
1833
1834 mylock_file = self.get_database_lockfile(repo)
1835 if os.access(mylock_file, os.W_OK | os.F_OK):
1836 os.remove(mylock_file)
1837 continue
1838
1839 break
1840
1841 if mirrors_locked and not db_locked:
1842 mytxt = "%s, %s %s" % (
1843 _("Mirrors are locked, someone is working on the repository"),
1844 _("try again later"),
1845 "...",
1846 )
1847 raise OnlineMirrorError("OnlineMirrorError: %s" % (mytxt,))
1848
1849 download_latest, upload_queue = self.calculate_database_sync_queues(
1850 repo)
1851
1852 if not download_latest and not upload_queue:
1853 self.Entropy.updateProgress(
1854 "[repo:%s|%s] %s" % (
1855 brown(repo),
1856 red(_("sync")),
1857 blue(_("database already in sync")),
1858 ),
1859 importance = 1,
1860 type = "info",
1861 header = blue(" @@ ")
1862 )
1863 return 0, set(), set()
1864
1865 if download_latest:
1866 download_uri = download_latest[0]
1867 download_errors, fine_uris, broken_uris = self.download_database(
1868 [download_uri], repo = repo)
1869 if download_errors:
1870 self.Entropy.updateProgress(
1871 "[repo:%s|%s] %s: %s" % (
1872 brown(repo),
1873 red(_("sync")),
1874 blue(_("database sync failed")),
1875 red(_("download issues")),
1876 ),
1877 importance = 1,
1878 type = "error",
1879 header = darkred(" !!! ")
1880 )
1881 return 1, fine_uris, broken_uris
1882
1883 if upload_queue and not no_upload:
1884
1885 deps_not_found = self.Entropy.dependencies_test(repo = repo)
1886 if deps_not_found and not self.Entropy.community_repo:
1887 self.Entropy.updateProgress(
1888 "[repo:%s|%s] %s: %s" % (
1889 brown(repo),
1890 red(_("sync")),
1891 blue(_("database sync forbidden")),
1892 red(_("dependencies_test() reported errors")),
1893 ),
1894 importance = 1,
1895 type = "error",
1896 header = darkred(" !!! ")
1897 )
1898 return 3, set(), set()
1899
1900 problems = self.Entropy.check_config_file_updates()
1901 if problems:
1902 return 4, set(), set()
1903
1904 self.Entropy.updateProgress(
1905 "[repo:%s|%s] %s" % (
1906 brown(repo),
1907 red(_("config files")),
1908 blue(_("no configuration files to commit. All fine.")),
1909 ),
1910 importance = 1,
1911 type = "info",
1912 header = blue(" @@ "),
1913 back = True
1914 )
1915
1916 uris = [x[0] for x in upload_queue]
1917 errors, fine_uris, broken_uris = self.upload_database(uris,
1918 repo = repo)
1919 if errors:
1920 self.Entropy.updateProgress(
1921 "[repo:%s|%s] %s: %s" % (
1922 brown(repo),
1923 red(_("sync")),
1924 blue(_("database sync failed")),
1925 red(_("upload issues")),
1926 ),
1927 importance = 1,
1928 type = "error",
1929 header = darkred(" !!! ")
1930 )
1931 return 2, fine_uris, broken_uris
1932
1933
1934 self.Entropy.updateProgress(
1935 "[repo:%s|%s] %s" % (
1936 brown(repo),
1937 red(_("sync")),
1938 blue(_("database sync completed successfully")),
1939 ),
1940 importance = 1,
1941 type = "info",
1942 header = darkgreen(" * ")
1943 )
1944
1945 if unlock_mirrors:
1946 self.lock_mirrors(False, repo = repo)
1947 return 0, set(), set()
1948
1949
1951 upload_files = 0
1952 upload_packages = set()
1953 upload_dir = os.path.join(self.Entropy.get_local_upload_directory(repo),
1954 branch)
1955
1956 pkg_ext = etpConst['packagesext']
1957 pkg_md5_ext = etpConst['packagesmd5fileext']
1958 for package in os.listdir(upload_dir):
1959 if package.endswith(pkg_ext) or package.endswith(pkg_md5_ext):
1960 upload_packages.add(package)
1961 if package.endswith(pkg_ext):
1962 upload_files += 1
1963
1964 return upload_files, upload_packages
1965
1967 local_files = 0
1968 local_packages = set()
1969 packages_dir = os.path.join(
1970 self.Entropy.get_local_packages_directory(repo), branch)
1971
1972 if not os.path.isdir(packages_dir):
1973 os.makedirs(packages_dir)
1974
1975 pkg_ext = etpConst['packagesext']
1976 pkg_md5_ext = etpConst['packagesmd5fileext']
1977 for package in os.listdir(packages_dir):
1978 if package.endswith(pkg_ext) or package.endswith(pkg_md5_ext):
1979 local_packages.add(package)
1980 if package.endswith(pkg_ext):
1981 local_files += 1
1982
1983 return local_files, local_packages
1984
1985
1987 self.Entropy.updateProgress(
1988 "%s:" % (
1989 blue(_("Local statistics")),
1990 ),
1991 importance = 1,
1992 type = "info",
1993 header = red(" @@ ")
1994 )
1995 self.Entropy.updateProgress(
1996 red("%s:\t\t%s %s" % (
1997 blue(_("upload directory")),
1998 bold(str(upload_files)),
1999 red(_("files ready")),
2000 )
2001 ),
2002 importance = 0,
2003 type = "info",
2004 header = red(" @@ ")
2005 )
2006 self.Entropy.updateProgress(
2007 red("%s:\t\t%s %s" % (
2008 blue(_("packages directory")),
2009 bold(str(local_files)),
2010 red(_("files ready")),
2011 )
2012 ),
2013 importance = 0,
2014 type = "info",
2015 header = red(" @@ ")
2016 )
2017
2018 - def _show_sync_queues(self, upload, download, removal, copy, metainfo,
2019 branch):
2020
2021
2022 for package, size in upload:
2023 package = darkgreen(os.path.basename(package))
2024 size = blue(self.entropyTools.bytes_into_human(size))
2025 self.Entropy.updateProgress(
2026 "[branch:%s|%s] %s [%s]" % (
2027 brown(branch),
2028 blue(_("upload")),
2029 darkgreen(package),
2030 size,
2031 ),
2032 importance = 0,
2033 type = "info",
2034 header = red(" # ")
2035 )
2036 for package, size in download:
2037 package = darkred(os.path.basename(package))
2038 size = blue(self.entropyTools.bytes_into_human(size))
2039 self.Entropy.updateProgress(
2040 "[branch:%s|%s] %s [%s]" % (
2041 brown(branch),
2042 darkred(_("download")),
2043 blue(package),
2044 size,
2045 ),
2046 importance = 0,
2047 type = "info",
2048 header = red(" # ")
2049 )
2050 for package, size in copy:
2051 package = darkblue(os.path.basename(package))
2052 size = blue(self.entropyTools.bytes_into_human(size))
2053 self.Entropy.updateProgress(
2054 "[branch:%s|%s] %s [%s]" % (
2055 brown(branch),
2056 darkgreen(_("copy")),
2057 brown(package),
2058 size,
2059 ),
2060 importance = 0,
2061 type = "info",
2062 header = red(" # ")
2063 )
2064 for package, size in removal:
2065 package = brown(os.path.basename(package))
2066 size = blue(self.entropyTools.bytes_into_human(size))
2067 self.Entropy.updateProgress(
2068 "[branch:%s|%s] %s [%s]" % (
2069 brown(branch),
2070 red(_("remove")),
2071 red(package),
2072 size,
2073 ),
2074 importance = 0,
2075 type = "info",
2076 header = red(" # ")
2077 )
2078
2079 self.Entropy.updateProgress(
2080 "%s:\t\t\t%s" % (
2081 blue(_("Packages to be removed")),
2082 darkred(str(len(removal))),
2083 ),
2084 importance = 0,
2085 type = "info",
2086 header = blue(" @@ ")
2087 )
2088 self.Entropy.updateProgress(
2089 "%s:\t\t%s" % (
2090 darkgreen(_("Packages to be moved locally")),
2091 darkgreen(str(len(copy))),
2092 ),
2093 importance = 0,
2094 type = "info",
2095 header = blue(" @@ ")
2096 )
2097 self.Entropy.updateProgress(
2098 "%s:\t\t\t%s" % (
2099 bold(_("Packages to be uploaded")),
2100 bold(str(len(upload))),
2101 ),
2102 importance = 0,
2103 type = "info",
2104 header = blue(" @@ ")
2105 )
2106
2107 self.Entropy.updateProgress(
2108 "%s:\t\t\t%s" % (
2109 darkred(_("Total removal size")),
2110 darkred(
2111 self.entropyTools.bytes_into_human(metainfo['removal'])
2112 ),
2113 ),
2114 importance = 0,
2115 type = "info",
2116 header = blue(" @@ ")
2117 )
2118
2119 self.Entropy.updateProgress(
2120 "%s:\t\t\t%s" % (
2121 blue(_("Total upload size")),
2122 blue(self.entropyTools.bytes_into_human(metainfo['upload'])),
2123 ),
2124 importance = 0,
2125 type = "info",
2126 header = blue(" @@ ")
2127 )
2128 self.Entropy.updateProgress(
2129 "%s:\t\t\t%s" % (
2130 brown(_("Total download size")),
2131 brown(self.entropyTools.bytes_into_human(metainfo['download'])),
2132 ),
2133 importance = 0,
2134 type = "info",
2135 header = blue(" @@ ")
2136 )
2137
2138
2141
2142 remote_files = 0
2143 close_conn = False
2144 remote_packages_data = {}
2145
2146 my_path = os.path.join(
2147 self.Entropy.get_remote_packages_relative_path(repo), branch)
2148 if ftp_connection == None:
2149 close_conn = True
2150
2151 ftp_connection = FtpInterface(uri, self.Entropy)
2152 ftp_connection.set_cwd(my_path, dodir = True)
2153
2154 remote_packages = ftp_connection.list_dir()
2155 remote_packages_info = ftp_connection.get_raw_list()
2156 if close_conn:
2157 ftp_connection.close()
2158
2159 for tbz2 in remote_packages:
2160 if tbz2.endswith(etpConst['packagesext']):
2161 remote_files += 1
2162
2163 for remote_package in remote_packages_info:
2164 remote_packages_data[remote_package.split()[8]] = \
2165 int(remote_package.split()[4])
2166
2167 return remote_files, remote_packages, remote_packages_data
2168
2170
2171 if repo == None:
2172 repo = self.Entropy.default_repository
2173
2174 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
2175 upload_files, upload_packages = self.calculate_local_upload_files(
2176 branch, repo)
2177 local_files, local_packages = self.calculate_local_package_files(branch,
2178 repo)
2179 self._show_local_sync_stats(upload_files, local_files)
2180
2181 self.Entropy.updateProgress(
2182 "%s: %s" % (blue(_("Remote statistics for")), red(crippled_uri),),
2183 importance = 1,
2184 type = "info",
2185 header = red(" @@ ")
2186 )
2187 remote_files, remote_packages, remote_packages_data = \
2188 self.calculate_remote_package_files(uri, branch, repo = repo)
2189 self.Entropy.updateProgress(
2190 "%s:\t\t\t%s %s" % (
2191 blue(_("remote packages")),
2192 bold(str(remote_files)),
2193 red(_("files stored")),
2194 ),
2195 importance = 0,
2196 type = "info",
2197 header = red(" @@ ")
2198 )
2199
2200 mytxt = blue("%s ...") % (
2201 _("Calculating queues"),
2202 )
2203 self.Entropy.updateProgress(
2204 mytxt,
2205 importance = 1,
2206 type = "info",
2207 header = red(" @@ ")
2208 )
2209
2210 upload_queue, download_queue, removal_queue, fine_queue = \
2211 self.calculate_sync_queues(upload_packages, local_packages,
2212 remote_packages, remote_packages_data, branch, repo)
2213 return upload_queue, download_queue, removal_queue, fine_queue, \
2214 remote_packages_data
2215
2216 - def calculate_sync_queues(
2217 self,
2218 upload_packages,
2219 local_packages,
2220 remote_packages,
2221 remote_packages_data,
2222 branch,
2223 repo = None
2224 ):
2225
2226 upload_queue = set()
2227 download_queue = set()
2228 removal_queue = set()
2229 fine_queue = set()
2230
2231 for local_package in upload_packages:
2232 if local_package in remote_packages:
2233
2234 local_filepath = os.path.join(
2235 self.Entropy.get_local_upload_directory(repo), branch,
2236 local_package)
2237
2238 local_size = self.entropyTools.get_file_size(local_filepath)
2239 remote_size = remote_packages_data.get(local_package)
2240 if remote_size == None:
2241 remote_size = 0
2242 if (local_size != remote_size):
2243
2244 upload_queue.add(local_package)
2245 else:
2246
2247 fine_queue.add(local_package)
2248 else:
2249
2250 upload_queue.add(local_package)
2251
2252
2253
2254 for local_package in local_packages:
2255 if local_package in remote_packages:
2256 local_filepath = os.path.join(
2257 self.Entropy.get_local_packages_directory(repo), branch,
2258 local_package)
2259 local_size = self.entropyTools.get_file_size(local_filepath)
2260 remote_size = remote_packages_data.get(local_package)
2261 if remote_size == None:
2262 remote_size = 0
2263 if (local_size != remote_size) and (local_size != 0):
2264
2265 if local_package not in fine_queue:
2266 upload_queue.add(local_package)
2267 else:
2268
2269
2270 upload_queue.add(local_package)
2271
2272
2273 for remote_package in remote_packages:
2274 if remote_package in local_packages:
2275 local_filepath = os.path.join(
2276 self.Entropy.get_local_packages_directory(repo), branch,
2277 remote_package)
2278 local_size = self.entropyTools.get_file_size(local_filepath)
2279 remote_size = remote_packages_data.get(remote_package)
2280 if remote_size == None:
2281 remote_size = 0
2282 if (local_size != remote_size) and (local_size != 0):
2283
2284
2285
2286 if remote_package not in upload_queue:
2287
2288
2289
2290 removal_queue.add(remote_package)
2291
2292 download_queue.add(remote_package)
2293 else:
2294
2295
2296
2297 if not remote_package.endswith(".tmp"):
2298 download_queue.add(remote_package)
2299
2300
2301
2302 dbconn = self.Entropy.open_server_repository(just_reading = True,
2303 repo = repo)
2304 db_files = dbconn.listBranchPackagesTbz2(branch, do_sort = False,
2305 full_path = True)
2306 db_files = set([os.path.basename(x) for x in db_files if \
2307 (self.Entropy.get_branch_from_download_relative_uri(x) == branch)])
2308
2309 exclude = set()
2310 for myfile in download_queue:
2311 if myfile.endswith(etpConst['packagesext']):
2312 if myfile not in db_files:
2313 exclude.add(myfile)
2314 download_queue -= exclude
2315
2316 exclude = set()
2317 for myfile in upload_queue:
2318 if myfile.endswith(etpConst['packagesext']):
2319 if myfile not in db_files:
2320 exclude.add(myfile)
2321 upload_queue -= exclude
2322
2323 exclude = set()
2324 for myfile in download_queue:
2325 if myfile in upload_queue:
2326 exclude.add(myfile)
2327 download_queue -= exclude
2328
2329 return upload_queue, download_queue, removal_queue, fine_queue
2330
2331
2332 - def expand_queues(self, upload_queue, download_queue, removal_queue,
2333 remote_packages_data, branch, repo):
2334
2335 metainfo = {
2336 'removal': 0,
2337 'download': 0,
2338 'upload': 0,
2339 }
2340 removal = []
2341 download = []
2342 do_copy = []
2343 upload = []
2344
2345 for item in removal_queue:
2346 if not item.endswith(etpConst['packagesext']):
2347 continue
2348 local_filepath = os.path.join(
2349 self.Entropy.get_local_packages_directory(repo), branch, item)
2350 size = self.entropyTools.get_file_size(local_filepath)
2351 metainfo['removal'] += size
2352 removal.append((local_filepath, size))
2353
2354 for item in download_queue:
2355 if not item.endswith(etpConst['packagesext']):
2356 continue
2357 local_filepath = os.path.join(
2358 self.Entropy.get_local_upload_directory(repo), branch, item)
2359 if not os.path.isfile(local_filepath):
2360 size = remote_packages_data.get(item)
2361 if size == None:
2362 size = 0
2363 size = int(size)
2364 metainfo['removal'] += size
2365 download.append((local_filepath, size))
2366 else:
2367 size = self.entropyTools.get_file_size(local_filepath)
2368 do_copy.append((local_filepath, size))
2369
2370 for item in upload_queue:
2371 if not item.endswith(etpConst['packagesext']):
2372 continue
2373 local_filepath = os.path.join(
2374 self.Entropy.get_local_upload_directory(repo), branch, item)
2375 local_filepath_pkgs = os.path.join(
2376 self.Entropy.get_local_packages_directory(repo), branch, item)
2377 if os.path.isfile(local_filepath):
2378 size = self.entropyTools.get_file_size(local_filepath)
2379 upload.append((local_filepath, size))
2380 else:
2381 size = self.entropyTools.get_file_size(local_filepath_pkgs)
2382 upload.append((local_filepath_pkgs, size))
2383 metainfo['upload'] += size
2384
2385 return upload, download, removal, do_copy, metainfo
2386
2387
2389
2390 if repo == None:
2391 repo = self.Entropy.default_repository
2392
2393 for itemdata in removal_queue:
2394
2395 remove_filename = itemdata[0]
2396 remove_filepath = os.path.join(
2397 self.Entropy.get_local_packages_directory(repo), branch,
2398 remove_filename)
2399 remove_filepath_hash = remove_filepath + \
2400 etpConst['packagesmd5fileext']
2401 self.Entropy.updateProgress(
2402 "[repo:%s|%s|%s] %s: %s [%s]" % (
2403 brown(repo),
2404 red("sync"),
2405 brown(branch),
2406 blue(_("removing package+hash")),
2407 darkgreen(remove_filename),
2408 blue(self.entropyTools.bytes_into_human(itemdata[1])),
2409 ),
2410 importance = 0,
2411 type = "info",
2412 header = darkred(" * ")
2413 )
2414
2415 if os.path.isfile(remove_filepath):
2416 os.remove(remove_filepath)
2417 if os.path.isfile(remove_filepath_hash):
2418 os.remove(remove_filepath_hash)
2419
2420 self.Entropy.updateProgress(
2421 "[repo:%s|%s|%s] %s" % (
2422 brown(repo),
2423 red(_("sync")),
2424 brown(branch),
2425 blue(_("removal complete")),
2426 ),
2427 importance = 0,
2428 type = "info",
2429 header = darkred(" * ")
2430 )
2431
2432
2434
2435 if repo == None:
2436 repo = self.Entropy.default_repository
2437
2438 for itemdata in copy_queue:
2439
2440 from_file = itemdata[0]
2441 from_file_hash = from_file + etpConst['packagesmd5fileext']
2442 to_file = os.path.join(
2443 self.Entropy.get_local_packages_directory(repo), branch,
2444 os.path.basename(from_file))
2445 to_file_hash = to_file+etpConst['packagesmd5fileext']
2446 expiration_file = to_file+etpConst['packagesexpirationfileext']
2447 self.Entropy.updateProgress(
2448 "[repo:%s|%s|%s] %s: %s" % (
2449 brown(repo),
2450 red("sync"),
2451 brown(branch),
2452 blue(_("copying file+hash to repository")),
2453 darkgreen(from_file),
2454 ),
2455 importance = 0,
2456 type = "info",
2457 header = darkred(" * ")
2458 )
2459
2460 if not os.path.isdir(os.path.dirname(to_file)):
2461 os.makedirs(os.path.dirname(to_file))
2462
2463 shutil.copy2(from_file, to_file)
2464 if not os.path.isfile(from_file_hash):
2465 self.create_file_checksum(from_file, from_file_hash)
2466 shutil.copy2(from_file_hash, to_file_hash)
2467
2468
2469 if os.path.isfile(expiration_file):
2470 os.remove(expiration_file)
2471
2472
2474
2475 if repo == None:
2476 repo = self.Entropy.default_repository
2477
2478 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
2479 myqueue = []
2480 for itemdata in upload_queue:
2481 upload_item = itemdata[0]
2482 hash_file = upload_item + etpConst['packagesmd5fileext']
2483 if not os.path.isfile(hash_file):
2484 self.entropyTools.create_md5_file(upload_item)
2485 myqueue.append(hash_file)
2486 myqueue.append(upload_item)
2487
2488 ftp_basedir = os.path.join(
2489 self.Entropy.get_remote_packages_relative_path(repo), branch)
2490 uploader = self.FtpServerHandler(FtpInterface,
2491 self.Entropy, [uri], myqueue, critical_files = myqueue,
2492 use_handlers = True, ftp_basedir = ftp_basedir,
2493 handlers_data = {'branch': branch }, repo = repo)
2494 errors, m_fine_uris, m_broken_uris = uploader.go()
2495 if errors:
2496 my_broken_uris = [
2497 (self.entropyTools.extract_ftp_host_from_uri(x[0]), x[1]) for \
2498 x in m_broken_uris]
2499 reason = my_broken_uris[0][1]
2500 self.Entropy.updateProgress(
2501 "[branch:%s] %s: %s, %s: %s" % (
2502 brown(branch),
2503 blue(_("upload errors")),
2504 red(crippled_uri),
2505 blue(_("reason")),
2506 darkgreen(unicode(reason)),
2507 ),
2508 importance = 1,
2509 type = "error",
2510 header = darkred(" !!! ")
2511 )
2512 return errors, m_fine_uris, m_broken_uris
2513
2514 self.Entropy.updateProgress(
2515 "[branch:%s] %s: %s" % (
2516 brown(branch),
2517 blue(_("upload completed successfully")),
2518 red(crippled_uri),
2519 ),
2520 importance = 1,
2521 type = "info",
2522 header = blue(" @@ ")
2523 )
2524 return errors, m_fine_uris, m_broken_uris
2525
2526
2529
2530 if repo == None:
2531 repo = self.Entropy.default_repository
2532
2533 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
2534 myqueue = []
2535 for package in download_queue:
2536 hash_file = package + etpConst['packagesmd5fileext']
2537 myqueue.append(package)
2538 myqueue.append(hash_file)
2539
2540 ftp_basedir = os.path.join(
2541 self.Entropy.get_remote_packages_relative_path(repo), branch)
2542 local_basedir = os.path.join(
2543 self.Entropy.get_local_packages_directory(repo), branch)
2544 downloader = self.FtpServerHandler(
2545 FtpInterface, self.Entropy, [uri], myqueue,
2546 critical_files = myqueue, use_handlers = True,
2547 ftp_basedir = ftp_basedir, local_basedir = local_basedir,
2548 handlers_data = {'branch': branch }, download = True, repo = repo)
2549
2550 errors, m_fine_uris, m_broken_uris = downloader.go()
2551 if errors:
2552 my_broken_uris = [
2553 (self.entropyTools.extract_ftp_host_from_uri(x), y,) \
2554 for x, y in m_broken_uris]
2555 reason = my_broken_uris[0][1]
2556 self.Entropy.updateProgress(
2557 "[repo:%s|%s|%s] %s: %s, %s: %s" % (
2558 brown(repo),
2559 red(_("sync")),
2560 brown(branch),
2561 blue(_("download errors")),
2562 darkgreen(crippled_uri),
2563 blue(_("reason")),
2564 reason,
2565 ),
2566 importance = 1,
2567 type = "error",
2568 header = darkred(" !!! ")
2569 )
2570 return errors, m_fine_uris, m_broken_uris
2571
2572 self.Entropy.updateProgress(
2573 "[repo:%s|%s|%s] %s: %s" % (
2574 brown(repo),
2575 red(_("sync")),
2576 brown(branch),
2577 blue(_("download completed successfully")),
2578 darkgreen(crippled_uri),
2579 ),
2580 importance = 1,
2581 type = "info",
2582 header = darkgreen(" * ")
2583 )
2584 return errors, m_fine_uris, m_broken_uris
2585
2586
2587 - def sync_packages(self, ask = True, pretend = False, packages_check = False,
2588 repo = None):
2589
2590 if repo == None:
2591 repo = self.Entropy.default_repository
2592
2593 self.Entropy.updateProgress(
2594 "[repo:%s|%s] %s" % (
2595 repo,
2596 red(_("sync")),
2597 darkgreen(_("starting packages sync")),
2598 ),
2599 importance = 1,
2600 type = "info",
2601 header = red(" @@ "),
2602 back = True
2603 )
2604
2605 successfull_mirrors = set()
2606 broken_mirrors = set()
2607 check_data = ()
2608 mirrors_tainted = False
2609 mirror_errors = False
2610 mirrors_errors = False
2611
2612 for uri in self.Entropy.get_remote_mirrors(repo):
2613
2614 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
2615 mirror_errors = False
2616
2617 self.Entropy.updateProgress(
2618 "[repo:%s|%s|branch:%s] %s: %s" % (
2619 repo,
2620 red(_("sync")),
2621 brown(self.SystemSettings['repositories']['branch']),
2622 blue(_("packages sync")),
2623 bold(crippled_uri),
2624 ),
2625 importance = 1,
2626 type = "info",
2627 header = red(" @@ ")
2628 )
2629
2630 try:
2631 upload_queue, download_queue, removal_queue, fine_queue, \
2632 remote_packages_data = self.calculate_packages_to_sync(uri,
2633 self.SystemSettings['repositories']['branch'], repo)
2634 except self.socket.error, err:
2635 self.Entropy.updateProgress(
2636 "[repo:%s|%s|branch:%s] %s: %s, %s %s" % (
2637 repo,
2638 red(_("sync")),
2639 self.SystemSettings['repositories']['branch'],
2640 darkred(_("socket error")),
2641 err,
2642 darkred(_("on")),
2643 crippled_uri,
2644 ),
2645 importance = 1,
2646 type = "error",
2647 header = darkgreen(" * ")
2648 )
2649 continue
2650
2651 if (not upload_queue) and (not download_queue) and \
2652 (not removal_queue):
2653 self.Entropy.updateProgress(
2654 "[repo:%s|%s|branch:%s] %s: %s" % (
2655 repo,
2656 red(_("sync")),
2657 self.SystemSettings['repositories']['branch'],
2658 darkgreen(_("nothing to do on")),
2659 crippled_uri,
2660 ),
2661 importance = 1,
2662 type = "info",
2663 header = darkgreen(" * ")
2664 )
2665 successfull_mirrors.add(uri)
2666 continue
2667
2668 self.Entropy.updateProgress(
2669 "%s:" % (blue(_("Expanding queues")),),
2670 importance = 1,
2671 type = "info",
2672 header = red(" ** ")
2673 )
2674
2675 upload, download, removal, copy, metainfo = self.expand_queues(
2676 upload_queue,
2677 download_queue,
2678 removal_queue,
2679 remote_packages_data,
2680 self.SystemSettings['repositories']['branch'],
2681 repo
2682 )
2683 del upload_queue, download_queue, removal_queue, \
2684 remote_packages_data
2685 self._show_sync_queues(upload, download, removal, copy, metainfo,
2686 self.SystemSettings['repositories']['branch'])
2687
2688 if not len(upload)+len(download)+len(removal)+len(copy):
2689
2690 self.Entropy.updateProgress(
2691 "[repo:%s|%s|branch:%s] %s %s" % (
2692 self.Entropy.default_repository,
2693 red(_("sync")),
2694 self.SystemSettings['repositories']['branch'],
2695 blue(_("nothing to sync for")),
2696 crippled_uri,
2697 ),
2698 importance = 1,
2699 type = "info",
2700 header = darkgreen(" @@ ")
2701 )
2702
2703 successfull_mirrors.add(uri)
2704 continue
2705
2706 if pretend:
2707 successfull_mirrors.add(uri)
2708 continue
2709
2710 if ask:
2711 rc_sync = self.Entropy.askQuestion(
2712 _("Would you like to run the steps above ?"))
2713 if rc_sync == "No":
2714 continue
2715
2716 try:
2717
2718 if removal:
2719 self._sync_run_removal_queue(removal,
2720 self.SystemSettings['repositories']['branch'], repo)
2721
2722 if copy:
2723 self._sync_run_copy_queue(copy,
2724 self.SystemSettings['repositories']['branch'], repo)
2725
2726 if upload or download:
2727 mirrors_tainted = True
2728
2729 if upload:
2730 d_errors, m_fine_uris, \
2731 m_broken_uris = self._sync_run_upload_queue(
2732 uri, upload,
2733 self.SystemSettings['repositories']['branch'], repo)
2734
2735 if d_errors:
2736 mirror_errors = True
2737
2738 if download:
2739 my_downlist = [x[0] for x in download]
2740 d_errors, m_fine_uris, \
2741 m_broken_uris = self._sync_run_download_queue(
2742 uri, my_downlist,
2743 self.SystemSettings['repositories']['branch'], repo)
2744
2745 if d_errors:
2746 mirror_errors = True
2747 if not mirror_errors:
2748 successfull_mirrors.add(uri)
2749 else:
2750 mirrors_errors = True
2751
2752 except KeyboardInterrupt:
2753 self.Entropy.updateProgress(
2754 "[repo:%s|%s|branch:%s] %s" % (
2755 repo,
2756 red(_("sync")),
2757 self.SystemSettings['repositories']['branch'],
2758 darkgreen(_("keyboard interrupt !")),
2759 ),
2760 importance = 1,
2761 type = "info",
2762 header = darkgreen(" * ")
2763 )
2764 continue
2765
2766 except Exception, err:
2767
2768 self.entropyTools.print_traceback()
2769 mirrors_errors = True
2770 broken_mirrors.add(uri)
2771 self.Entropy.updateProgress(
2772 "[repo:%s|%s|branch:%s] %s: %s, %s: %s" % (
2773 repo,
2774 red(_("sync")),
2775 self.SystemSettings['repositories']['branch'],
2776 darkred(_("exception caught")),
2777 Exception,
2778 _("error"),
2779 err,
2780 ),
2781 importance = 1,
2782 type = "error",
2783 header = darkred(" !!! ")
2784 )
2785
2786 exc_txt = self.Entropy.entropyTools.print_exception(
2787 returndata = True)
2788 for line in exc_txt:
2789 self.Entropy.updateProgress(
2790 unicode(line),
2791 importance = 1,
2792 type = "error",
2793 header = darkred(": ")
2794 )
2795
2796 if len(successfull_mirrors) > 0:
2797 self.Entropy.updateProgress(
2798 "[repo:%s|%s|branch:%s] %s" % (
2799 repo,
2800 red(_("sync")),
2801 self.SystemSettings['repositories']['branch'],
2802 darkred(
2803 _("at least one mirror synced properly!")),
2804 ),
2805 importance = 1,
2806 type = "error",
2807 header = darkred(" !!! ")
2808 )
2809 continue
2810
2811
2812 if (len(successfull_mirrors) > 0) and not pretend:
2813 self.remove_expiration_files(
2814 self.SystemSettings['repositories']['branch'], repo)
2815
2816 if packages_check:
2817 check_data = self.Entropy.verify_local_packages([], ask = ask,
2818 repo = repo)
2819
2820 return mirrors_tainted, mirrors_errors, successfull_mirrors, \
2821 broken_mirrors, check_data
2822
2824
2825 if repo == None:
2826 repo = self.Entropy.default_repository
2827
2828 branch_dir = os.path.join(
2829 self.Entropy.get_local_upload_directory(repo), branch)
2830 branchcontent = os.listdir(branch_dir)
2831 for xfile in branchcontent:
2832 source = os.path.join(self.Entropy.get_local_upload_directory(repo),
2833 branch, xfile)
2834 destdir = os.path.join(
2835 self.Entropy.get_local_packages_directory(repo), branch)
2836 if not os.path.isdir(destdir):
2837 os.makedirs(destdir)
2838 dest = os.path.join(destdir, xfile)
2839 shutil.move(source, dest)
2840
2841 dest_expiration = dest + etpConst['packagesexpirationfileext']
2842 if os.path.isfile(dest_expiration):
2843 os.remove(dest_expiration)
2844
2845
2847
2848 pkg_path = os.path.join(
2849 self.Entropy.get_local_packages_directory(repo), branch,
2850 package_file)
2851 pkg_path += etpConst['packagesexpirationfileext']
2852 if not os.path.isfile(pkg_path):
2853 return False
2854
2855 srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
2856 mtime = self.entropyTools.get_file_unix_mtime(pkg_path)
2857 days = srv_set['packages_expiration_days']
2858 delta = int(days)*24*3600
2859 currmtime = time.time()
2860 file_delta = currmtime - mtime
2861
2862 if file_delta > delta:
2863 return True
2864 return False
2865
2868
2869 pkg_path = os.path.join(
2870 self.Entropy.get_local_packages_directory(repo), branch,
2871 package_file)
2872 pkg_path += etpConst['packagesexpirationfileext']
2873 if gentle and os.path.isfile(pkg_path):
2874 return
2875 f_exp = open(pkg_path,"w")
2876 f_exp.flush()
2877 f_exp.close()
2878
2879
2881
2882 dbconn = self.Entropy.open_server_repository(just_reading = True,
2883 repo = repo)
2884 database_bins = dbconn.listBranchPackagesTbz2(branch, do_sort = False,
2885 full_path = True)
2886 bins_dir = os.path.join(
2887 self.Entropy.get_local_packages_directory(repo), branch)
2888 repo_bins = set()
2889
2890 if os.path.isdir(bins_dir):
2891 repo_bins = os.listdir(bins_dir)
2892 repo_bins = set([
2893 os.path.join('packages', etpSys['arch'], branch, x) for x \
2894 in repo_bins if x.endswith(etpConst['packagesext'])])
2895 repo_bins -= database_bins
2896
2897 return set([os.path.basename(x) for x in repo_bins])
2898
2899
2900 - def tidy_mirrors(self, ask = True, pretend = False, repo = None):
2901
2902 if repo == None:
2903 repo = self.Entropy.default_repository
2904
2905 self.Entropy.updateProgress(
2906 "[repo:%s|%s|branch:%s] %s" % (
2907 brown(repo),
2908 red(_("tidy")),
2909 blue(self.SystemSettings['repositories']['branch']),
2910 blue(_("collecting expired packages")),
2911 ),
2912 importance = 1,
2913 type = "info",
2914 header = red(" @@ ")
2915 )
2916
2917 branch_data = {}
2918 errors = False
2919
2920 branch_data['errors'] = False
2921
2922 branch = self.SystemSettings['repositories']['branch']
2923 srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
2924 last_branch = srv_set['branches'][-1]
2925 if branch != last_branch:
2926 mytxt = _("not the latest branch, skipping tidy for consistence.")
2927 self.Entropy.updateProgress(
2928 "[branch:%s] %s" % (
2929 brown(branch),
2930 blue(mytxt),
2931 ),
2932 importance = 1,
2933 type = "info",
2934 header = blue(" @@ ")
2935 )
2936 branch_data['errors'] = True
2937 return True, branch_data
2938
2939 self.Entropy.updateProgress(
2940 "[branch:%s] %s" % (
2941 brown(branch),
2942 blue(_("collecting expired packages in the selected branches")),
2943 ),
2944 importance = 1,
2945 type = "info",
2946 header = blue(" @@ ")
2947 )
2948
2949
2950 expiring_packages = self.collect_expiring_packages(branch, repo)
2951
2952 removal = []
2953 for package in expiring_packages:
2954 expired = self.is_package_expired(package, branch, repo)
2955 if expired:
2956 removal.append(package)
2957 else:
2958 self.create_expiration_file(package, branch, repo,
2959 gentle = True)
2960
2961
2962 branch_data['removal'] = removal[:]
2963
2964 if not removal:
2965 self.Entropy.updateProgress(
2966 "[branch:%s] %s" % (
2967 brown(branch),
2968 blue(_("nothing to remove on this branch")),
2969 ),
2970 importance = 1,
2971 type = "info",
2972 header = blue(" @@ ")
2973 )
2974 return errors, branch_data
2975 else:
2976 self.Entropy.updateProgress(
2977 "[branch:%s] %s:" % (
2978 brown(branch),
2979 blue(_("these are the expired packages")),
2980 ),
2981 importance = 1,
2982 type = "info",
2983 header = blue(" @@ ")
2984 )
2985 for package in removal:
2986 self.Entropy.updateProgress(
2987 "[branch:%s] %s: %s" % (
2988 brown(branch),
2989 blue(_("remove")),
2990 darkgreen(package),
2991 ),
2992 importance = 1,
2993 type = "info",
2994 header = brown(" # ")
2995 )
2996
2997 if pretend:
2998 return errors, branch_data
2999
3000 if ask:
3001 rc_question = self.Entropy.askQuestion(
3002 _("Would you like to continue ?"))
3003 if rc_question == "No":
3004 return errors, branch_data
3005
3006 myqueue = []
3007 for package in removal:
3008 myqueue.append(package+etpConst['packagesmd5fileext'])
3009 myqueue.append(package)
3010
3011 ftp_basedir = os.path.join(
3012 self.Entropy.get_remote_packages_relative_path(repo), branch)
3013 for uri in self.Entropy.get_remote_mirrors(repo):
3014
3015 self.Entropy.updateProgress(
3016 "[branch:%s] %s..." % (
3017 brown(branch),
3018 blue(_("removing packages remotely")),
3019 ),
3020 importance = 1,
3021 type = "info",
3022 header = blue(" @@ ")
3023 )
3024
3025 crippled_uri = self.entropyTools.extract_ftp_host_from_uri(uri)
3026 destroyer = self.FtpServerHandler(
3027 FtpInterface,
3028 self.Entropy,
3029 [uri],
3030 myqueue,
3031 critical_files = [],
3032 ftp_basedir = ftp_basedir,
3033 remove = True,
3034 repo = repo
3035 )
3036 errors, m_fine_uris, m_broken_uris = destroyer.go()
3037 if errors:
3038 my_broken_uris = [
3039 (self.entropyTools.extract_ftp_host_from_uri(x[0]), x[1]) \
3040 for x in m_broken_uris]
3041
3042 reason = my_broken_uris[0][1]
3043 self.Entropy.updateProgress(
3044 "[branch:%s] %s: %s, %s: %s" % (
3045 brown(branch),
3046 blue(_("remove errors")),
3047 red(crippled_uri),
3048 blue(_("reason")),
3049 reason,
3050 ),
3051 importance = 1,
3052 type = "warning",
3053 header = brown(" !!! ")
3054 )
3055 branch_data['errors'] = True
3056 errors = True
3057
3058 self.Entropy.updateProgress(
3059 "[branch:%s] %s..." % (
3060 brown(branch),
3061 blue(_("removing packages locally")),
3062 ),
3063 importance = 1,
3064 type = "info",
3065 header = blue(" @@ ")
3066 )
3067
3068 branch_data['removed'] = set()
3069 for package in removal:
3070 package_path = os.path.join(
3071 self.Entropy.get_local_packages_directory(repo),
3072 branch, package)
3073 package_path_hash = package_path + \
3074 etpConst['packagesmd5fileext']
3075 package_path_expired = package_path + \
3076 etpConst['packagesexpirationfileext']
3077
3078 my_rm_list = (package_path_hash, package_path,
3079 package_path_expired)
3080 for myfile in my_rm_list:
3081 if os.path.isfile(myfile):
3082 self.Entropy.updateProgress(
3083 "[branch:%s] %s: %s" % (
3084 brown(branch),
3085 blue(_("removing")),
3086 darkgreen(myfile),
3087 ),
3088 importance = 1,
3089 type = "info",
3090 header = brown(" @@ ")
3091 )
3092 os.remove(myfile)
3093 branch_data['removed'].add(myfile)
3094
3095 return errors, branch_data
3096