]> TLD Linux GIT Repositories - tld-ftp-admin.git/blob - bin/pfa-checktree
- non-integer releases are ok in TLD
[tld-ftp-admin.git] / bin / pfa-checktree
1 #!/usr/bin/env python3
2 # vi: encoding=utf-8 ts=8 sts=4 sw=4 et
3
4 from __future__ import print_function
5
6 import sys, os
7 sys.path.insert(0, os.environ['HOME']+'/tld-ftp-admin/modules')
8 import ftptree
9 ftptree.quietmode=True
10 from common import checkdir
11 import ftpio
12 import config
13 cval=config.value
14
15 import curses
16
17 if len(sys.argv) != 3:
18     print("ERR: wrong number of arguments")
19     print("check-tree.py srctree dsttree")
20     sys.exit(1)
21
22 checkdir(sys.argv[1])
23
24 ftpio.connect('check-tree')
25
26 if not ftpio.lock(sys.argv[1], True):
27     print("ERR: %s tree already locked" % sys.argv[1])
28     sys.exit(1)
29
30 if not ftpio.lock(sys.argv[2], True):
31     ftpio.unlock(sys.argv[1])
32     print("ERR: %s tree already locked" % sys.argv[2])
33     sys.exit(1)
34
35 srctree=ftptree.FtpTree(sys.argv[1], loadall=True)
36 dsttree=ftptree.FtpTree(sys.argv[2])
37
38 srctree.checktree(dsttree)
39
40 # We've loaded all interesting info, so we can continue without locks
41 ftpio.unlock(sys.argv[1])
42 ftpio.unlock(sys.argv[2])
43
44 # The list(set(list)) cast is a fancy way to remove dups from a list
45 names=sorted(list(set([pkg.name for pkg in srctree.values()])))
46
47 pkgtree={}
48
49 for n in names:
50     pkgtree[n]=[]
51
52 for pkg in srctree.values():
53     pkgtree[pkg.name].append(pkg)
54
55 for key in pkgtree.keys():
56     pkgtree[key]=sorted(pkgtree[key], reverse=True)
57
58 for pkg in srctree.values():
59     pkg.marked4movingpool=pkgtree[pkg.name]
60
61 pkglist=[]
62
63 for key in sorted(pkgtree.keys()):
64     pkglist=pkglist+pkgtree[key]
65
66 DoQuit="OMG!"
67
68 class Screen:
69     def __init__(self, srctreename, dsttreename, elements):
70         self.srctree=srctreename
71         self.dsttree=dsttreename
72         self.elements=elements
73         self.pkglistselected=0
74         self.pkgliststartpad=0
75         self.win2startpad=0
76         self.window=1
77         try:
78             # initial
79             self.screen=curses.initscr()
80             self.screen.keypad(1)
81             curses.start_color()
82             curses.noecho()
83             curses.cbreak()
84             curses.meta(1)
85             curses.curs_set(0)
86
87              # Without this refresh(), nothing will show up before first getch()
88             self.screen.refresh()
89
90             self.__init_colors()
91             self.__init_windows()
92             self.__bind_keys()
93
94             try:
95                 # Main loop
96                 while True:
97                     if self.window==1: #pkglist
98                         self.__redraw_pkglist()
99                         self.__redraw_statusbox()
100                     elif self.window==2: 
101                         pass
102                     curses.doupdate()
103                     self.__handle_input()
104             except DoQuit:
105                 pass
106         finally:
107             curses.echo()
108             curses.nocbreak()
109             curses.curs_set(1)
110             curses.endwin()
111
112     def __bind_keys(self):
113         self.globalkeys=(('qQ', 'quit'), ('KEY_RESIZE', 'resize'),
114                 ('KEY_CLOSE', 'quit'))
115         self.perwindowkeys=[(), ()]
116         self.perwindowkeys[0]=(('k', 'move_up'), ('J', 'move_pgdown'),
117                 ('K', 'move_pgup'), (' ', 'mark'), ('j', 'move_down'),
118                 ('KEY_DOWN', 'move_down'), ('KEY_UP', 'move_up'),
119                 ('KEY_HOME', 'move_home'), ('KEY_END', 'move_end'),
120                 ('KEY_NPAGE', 'move_pgdown'), ('KEY_PPAGE', 'move_pgup'))
121                 
122
123     def __init_colors(self):
124         curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_CYAN)
125         self.COLOR_TITLEBAR=curses.color_pair(1)
126         curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE)
127         self.COLOR_STANDARD=curses.color_pair(2)
128         curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLUE)
129         self.COLOR_ERROR=curses.color_pair(3)
130         curses.init_pair(4, curses.COLOR_YELLOW, curses.COLOR_BLUE)
131         self.COLOR_WARNING=curses.color_pair(4)
132         curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_RED)
133         self.COLOR_ERRORMSG=curses.color_pair(5)
134         curses.init_pair(6, curses.COLOR_WHITE, curses.COLOR_YELLOW)
135         self.COLOR_WARNINGMSG=curses.color_pair(6)
136         curses.init_pair(7, curses.COLOR_BLACK, curses.COLOR_WHITE)
137         self.COLOR_WHITEBG=curses.color_pair(7)
138
139     def __init_windows(self):
140         self.__set_screen_coordinates()
141
142         # Titlebar
143         self.titlebar = curses.newpad(1, 200)
144         self.titlebar.bkgdset(ord(' '), self.COLOR_TITLEBAR)
145         self.__redraw_titlebar()
146
147         # Pkg list pad
148         self.pkglist = curses.newpad(len(self.elements), 200)
149         self.pkglist.bkgdset(ord(' '), self.COLOR_STANDARD)
150         self.pkglist.clrtobot()
151
152         # Status bar
153         self.statusbar = curses.newpad(1, 200)
154
155         # Pkg status box
156         self.statusbox = curses.newpad(5, 200)
157         self.statusbox.bkgdset(ord(' '), self.COLOR_STANDARD)
158         self.statusbox.clrtobot()
159         self.__redraw_statusbox()
160
161     def __set_screen_coordinates(self):
162         self.scr_h, self.scr_w = self.screen.getmaxyx()
163         self.pad_h = self.scr_h-5
164         self.sbar_y = self.scr_h-4
165         self.sbox_y = self.scr_h-3
166
167     def __redraw_titlebar(self):
168         self.titlebar.clrtobot()
169 #        self.titlebar.addstr(0, self.scr_w-14, "tld-ftp-admin")
170         self.titlebar.addstr(0, 1, 'Window #%s' % self.window)
171         tmp="%s => %s" % (self.srctree, self.dsttree)
172         self.titlebar.addstr(0, int(self.scr_w/2-len(tmp)/2)-1, tmp)
173         self.titlebar.addstr(0, self.scr_w-20, "Press 'h' for help.")
174         self.titlebar.noutrefresh(0, 0, 0, 0, 1, self.scr_w-1)
175
176     def __redraw_statusbox(self):
177         self.statusbox.erase()
178         pkg=self.elements[self.pkglistselected]
179         i=0
180         for error in pkg.errors:
181             self.statusbox.bkgdset(ord(' '), self.COLOR_ERRORMSG)
182             self.statusbox.addstr(i, 0, 'ERR: '+error, curses.A_BOLD)
183             self.statusbox.bkgdset(ord(' '), self.COLOR_STANDARD)
184             i+=1
185         for warning in pkg.warnings:
186             self.statusbox.bkgdset(ord(' '), self.COLOR_WARNINGMSG)
187             self.statusbox.addstr(i, 0, 'WARN: '+warning, curses.A_BOLD)
188             self.statusbox.bkgdset(ord(' '), self.COLOR_STANDARD)
189             i+=1
190         self.statusbox.noutrefresh(0,0,self.sbox_y,0,self.scr_h-1,self.scr_w-1)
191
192     def __redraw_pkglist(self):
193         # Safety in case there's a bug somewhere
194         if self.pkgliststartpad>len(self.elements)-self.pad_h:
195             self.pkgliststartpad=len(self.elements)-self.pad_h
196         if self.pkgliststartpad<0:
197             self.pkgliststartpad=0
198
199         self.pkglist.erase()
200         for i in range(len(self.elements)):
201             if self.elements[i].marked4moving:
202                 if self.elements[i].warnings:
203                     self.pkglist.bkgdset(ord(' '), self.COLOR_WARNINGMSG)
204                     self.pkglist.addstr(i, 0, '+', curses.A_BOLD)
205                 else:
206                     self.pkglist.bkgdset(ord(' '), self.COLOR_WHITEBG)
207                     self.pkglist.addstr(i, 0, '+')
208
209             if self.elements[i].errors:
210                 self.pkglist.bkgdset(ord(' '), self.COLOR_ERROR)
211             elif self.elements[i].warnings:
212                 self.pkglist.bkgdset(ord(' '), self.COLOR_WARNING)
213             else:
214                 self.pkglist.bkgdset(ord(' '), self.COLOR_STANDARD)
215             if i == self.pkglistselected:
216                 self.pkglist.addstr(i, 2, repr(self.elements[i]), curses.A_REVERSE)
217             else:
218                 self.pkglist.addstr(i, 2, repr(self.elements[i]), curses.A_BOLD)
219             self.pkglist.bkgdset(ord(' '), self.COLOR_STANDARD)
220         self.pkglist.noutrefresh(self.pkgliststartpad,0,1,0,self.pad_h,self.scr_w-1)
221
222     def __do_resize(self):
223         self.__set_screen_coordinates()
224         self.__redraw_titlebar()
225         self.__redraw_statusbox()
226
227     def __do_move_down(self):
228         if 0 <= self.pkglistselected < len(self.elements)-1:
229             self.pkglistselected+=1
230             if (self.pkgliststartpad!=len(self.elements)-self.pad_h and
231                 self.pad_h-(self.pkglistselected-self.pkgliststartpad)<5):
232                 self.pkgliststartpad+=1
233
234     def __do_move_up(self):
235         if 0 < self.pkglistselected <= len(self.elements)-1:
236             self.pkglistselected-=1
237             if self.pkgliststartpad!=0 and self.pkglistselected-self.pkgliststartpad<4:
238                 self.pkgliststartpad-=1
239
240     def __do_move_home(self):
241         self.pkglistselected=0
242         self.pkgliststartpad=0
243
244     def __do_move_end(self):
245         self.pkglistselected=len(self.elements)-1
246         self.pkgliststartpad=len(self.elements)-self.pad_h
247
248     def __do_move_pgdown(self):
249         self.pkglistselected+=self.pad_h
250         if self.pkglistselected >= len(self.elements):
251             self.pkglistselected = len(self.elements)-1
252         self.pkgliststartpad+=self.pad_h
253         if self.pkgliststartpad > len(self.elements)-self.pad_h:
254             self.pkgliststartpad=len(self.elements)-self.pad_h
255
256     def __do_move_pgup(self):
257         self.pkglistselected-=self.pad_h
258         if self.pkglistselected < 0:
259             self.pkglistselected = 0
260         self.pkgliststartpad-=self.pad_h
261         if self.pkgliststartpad < 0:
262             self.pkgliststartpad = 0
263
264     def __do_quit(self):
265         raise DoQuit()
266
267     def __do_mark(self):
268         pkg=self.elements[self.pkglistselected]
269         if pkg.errors:
270             return
271         elif pkg.marked4moving:
272             pkg.unmark4moving()
273         else:
274             pkg.mark4moving()
275
276     def __handle_input(self):
277         key=self.screen.getch()
278         if key==27:
279             # Switch window
280             metakey=self.screen.getch()
281             if 0<metakey<256:
282                 c=chr(metakey)
283                 if c=='1':
284                     self.window=1
285                 elif c=='2':
286                     self.window=2
287         elif 0<key<256:
288             c=chr(key)
289             for bind in self.globalkeys+self.perwindowkeys[self.window-1]:
290                 if not bind[0].startswith('KEY_') and c in bind[0]:
291                     exec 'self._Screen__do_%s()' % bind[1]
292
293         else:
294 #            self.elements[0]=repr(key)
295             for bind in self.globalkeys+self.perwindowkeys[self.window-1]:
296                 if bind[0].startswith('KEY_'):
297                     if key == getattr(curses, bind[0]):
298                         exec 'self._Screen__do_%s()' % bind[1]
299
300 s = Screen(sys.argv[1], sys.argv[2], pkglist)
301