Kiln » TortoiseHg » TortoiseHg
Clone URL:  
Pushed to one repository · View In Graph Contained in 1.9, 1.9.1, and 1.9.2

purge: move from hglib to hgqt, turn into a dialog and thg command

Gives user more control over details, but gives up detailed file lists since
we sweep through the repo to discover the actual deletion list.

Changeset e3dd535bfb22

Parent 7eec1b8e76c3

by Steve Borho

Changes to 4 files · Browse files at e3dd535bfb22 Showing diff from parent 7eec1b8e76c3 Diff from another changeset...

Change 1 of 1 Show Entire File tortoisehg/​hgqt/​purge.py Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
@@ -0,0 +1,126 @@
+# status.py - working copy browser +# +# Copyright 2010 Steve Borho <steve@borho.org> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import os +import stat + +from mercurial import cmdutil + +from tortoisehg.util import hglib +from tortoisehg.hgqt.i18n import _ +from tortoisehg.hgqt import qtlib + +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +def purge(repo, ignored, unknown, delfolders, keephg): + directories = [] + failures = [] + + def remove(remove_func, name): + try: + if keephg and name.startswith('.hg'): + return + remove_func(repo.wjoin(name)) + except EnvironmentError: + failures.append(name) + + def removefile(path): + try: + os.remove(path) + except OSError: + # read-only files cannot be unlinked under Windows + s = os.stat(path) + if (s.st_mode & stat.S_IWRITE) != 0: + raise + os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE) + os.remove(path) + + match = cmdutil.match(repo, [], {}) + match.dir = directories.append + status = repo.status(match=match, ignored=ignored, unknown=unknown) + + for f in sorted(status[4] + status[5]): + remove(removefile, f) + + if delfolders: + for f in sorted(directories, reverse=True): + if not os.listdir(repo.wjoin(f)): + remove(os.rmdir, f) + return failures + + +class PurgeDialog(QDialog): + def __init__(self, repo, unknown, ignored, parent): + QDialog.__init__(self, parent) + self.setLayout(QVBoxLayout()) + if unknown: + cb = QCheckBox(_('Delete %d unknown files') % len(unknown)) + cb.setChecked(True) + self.layout().addWidget(cb) + self.ucb = cb + if ignored: + cb = QCheckBox(_('Delete %d ignored files') % len(ignored)) + cb.setChecked(True) + self.layout().addWidget(cb) + self.icb = cb + self.foldercb = QCheckBox(_('Delete empty folders')) + self.foldercb.setChecked(True) + self.layout().addWidget(self.foldercb) + self.hgfilecb = QCheckBox(_('Preserve files beginning with .hg')) + self.hgfilecb.setChecked(True) + self.layout().addWidget(self.hgfilecb) + self.files = (unknown, ignored) + + BB = QDialogButtonBox + bb = QDialogButtonBox(BB.Ok|BB.Cancel) + bb.accepted.connect(self.accept) + bb.rejected.connect(self.reject) + self.bb = bb + self.layout().addWidget(bb) + + self.setWindowTitle('%s - purge' % repo.displayname) + self.repo = repo + + def accept(self): + U, I = self.files + unknown = len(U) and self.ucb.isChecked() + ignored = len(I) and self.icb.isChecked() + delf = self.foldercb.isChecked() + keep = self.hgfilecb.isChecked() + + if not (unknown or ignored or delf): + QDialog.accept(self) + return + if not qtlib.QuestionMsgBox(_('Confirm file deletions'), + _('Are you sure you want to delete these files and/or folders?')): + return + + failures = purge(self.repo, ignored, unknown, delf, keep) + if failures: + qtlib.InfoMsgBox(_('Deletion failures'), + _('Unable to delete %d files or folders') % len(failures), self) + QDialog.accept(self) + +def run(ui, *pats, **opts): + from tortoisehg.hgqt import thgrepo + from tortoisehg.util import paths + try: + repo = thgrepo.repository(ui, path=paths.find_root()) + wctx = repo[None] + wctx.status(ignored=True, unknown=True) + except Exception, e: + qtlib.InfoMsgBox(_('Repository Error'), + _('Unable to query unrevisioned files\n') + + hglib.tounicode(str(e))) + return None + U, I = wctx.unknown(), wctx.ignored() + if not U and not I: + qtlib.InfoMsgBox(_('No unrevisioned files'), + _('There are no purgable unrevisioned files')) + return None + return PurgeDialog(repo, U, I, None)
 
11
12
13
14
 
15
16
17
 
19
20
21
22
 
23
24
25
 
331
332
333
334
 
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
 
 
 
 
372
373
374
 
11
12
13
 
14
15
16
17
 
19
20
21
 
22
23
24
25
 
331
332
333
 
334
335
336
337
338
339
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
342
343
344
345
346
347
@@ -11,7 +11,7 @@
 import binascii  import os   -from tortoisehg.util import shlib, hglib, purge +from tortoisehg.util import shlib, hglib    from tortoisehg.hgqt.i18n import _  from tortoisehg.hgqt.qtlib import geticon, getfont, QuestionMsgBox, InfoMsgBox @@ -19,7 +19,7 @@
 from tortoisehg.hgqt.repomodel import HgRepoListModel  from tortoisehg.hgqt.quickbar import FindInGraphlogQuickBar  from tortoisehg.hgqt import cmdui, update, tag, backout, merge, visdiff -from tortoisehg.hgqt import archive, thgimport, thgstrip, run, thgrepo +from tortoisehg.hgqt import archive, thgimport, thgstrip, run, thgrepo, purge    from tortoisehg.hgqt.thread import DataWrapper  from tortoisehg.hgqt.repoview import HgRepoView @@ -331,44 +331,17 @@
  except Exception, e:   InfoMsgBox(_('Repository Error'),   _('Unable to query unrevisioned files\n') + - hglib.tounicode(e)) + hglib.tounicode(str(e)))   return   U, I = wctx.unknown(), wctx.ignored()   if not U and not I:   InfoMsgBox(_('No unrevisioned files'),   _('There are no purgable unrevisioned files'))   return - elif not U: - if not QuestionMsgBox(_('Purge ignored files'), - _('Purge (delete) all %d ignored files?') % len(I)): - return - dels = I - else: - res = CustomPrompt(_('Purge unrevisioned files'), - _('%d unknown files\n' - '%d files ignored by .hgignore filter\n' - 'Purge unknown, ignored, or both?') % (len(U), len(I)), self, - (_('&Unknown'), _('&Ignored'), _('&Both'), _('Cancel')), - 0, 3, U+I).run() - if res == 3: - return - elif res == 2: - dels = U+I - elif res == 1: - dels = I - else: - dels = U - res = CustomPrompt(_('Confirm file deletions'), - _('Are you sure you want to delete these %d files?') % - len(dels), self, (_('&Yes'), _('&No')), 1, 1, dels).run() - if res == 1: - return - - failures = purge.purge(self.repo, dels) - if failures: - CustomPrompt(_('Deletion failures'), - _('Unable to delete %d files or folders') % - len(failures), self, (_('&Ok'),), 0, 0, failures).run() + dlg = purge.PurgeDialog(self.repo, U, I, self) + dlg.setWindowFlags(Qt.Sheet) + dlg.setWindowModality(Qt.WindowModal) + dlg.exec_()     def create_models(self):   self.repomodel = HgRepoListModel(self.repo)
 
513
514
515
 
 
 
 
 
516
517
518
 
915
916
917
 
918
919
920
 
513
514
515
516
517
518
519
520
521
522
523
 
920
921
922
923
924
925
926
@@ -513,6 +513,11 @@
  #from tortoisehg.hgqt.chunkselect import run   qtrun(run, ui, *pats, **opts)   +def purge(ui, *pats, **opts): + """purge unknown and/or ignore files from repository""" + from tortoisehg.hgqt.purge import run + qtrun(run, ui, *pats, **opts) +  def remove(ui, *pats, **opts):   """remove selected files"""   from tortoisehg.hgqt.quickop import run @@ -915,6 +920,7 @@
  _('thg tag [-f] [-l] [-m TEXT] [-r REV] [NAME]')),   "test": (test, [], _('thg test')),   "help": (help_, [], _('thg help [COMMAND]')), + "^purge": (purge, [], _('thg purge')),   "^update|checkout|co":   (update,   [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
Change 1 of 1 Show Entire File tortoisehg/​util/​purge.py Stacked
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
@@ -1,48 +0,0 @@
-# purge.py - deleted specified files from given repository -# -# Copyright 2010 Steve Borho <steve@borho.org> -# -# This software may be used and distributed according to the terms of the -# GNU General Public License version 2, incorporated herein by reference. - -import os -import stat - -from mercurial import cmdutil - -# Heavily influenced by Mercurial's purge extension - -def purge(repo, files): - directories = [] - failures = [] - - def remove(remove_func, name): - try: - remove_func(repo.wjoin(name)) - except EnvironmentError: - failures.append(name) - - def removefile(path): - try: - os.remove(path) - except OSError: - # read-only files cannot be unlinked under Windows - s = os.stat(path) - if (s.st_mode & stat.S_IWRITE) != 0: - raise - os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE) - os.remove(path) - - match = cmdutil.match(repo, [], {}) - match.dir = directories.append - status = repo.status(match=match, ignored=True, unknown=True) - - for f in sorted(status[4] + status[5]): - if f in files: - remove(removefile, f) - - for f in sorted(directories, reverse=True): - if not os.listdir(repo.wjoin(f)): - remove(os.rmdir, f) - - return failures