1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2014 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4#
5
6"""
7Module implementing the largefiles extension interface.
8"""
9
10import os
11
12from PyQt5.QtCore import QTimer
13from PyQt5.QtWidgets import QDialog
14
15from E5Gui.E5Application import e5App
16from E5Gui import E5MessageBox
17
18from ..HgExtension import HgExtension
19from ..HgDialog import HgDialog
20from ..HgClient import HgClient
21
22
23class Largefiles(HgExtension):
24    """
25    Class implementing the largefiles extension interface.
26    """
27    def __init__(self, vcs):
28        """
29        Constructor
30
31        @param vcs reference to the Mercurial vcs object
32        """
33        super().__init__(vcs)
34
35    def hgLfconvert(self, direction, projectFile):
36        """
37        Public slot to convert the repository format of the current project.
38
39        @param direction direction of the conversion (string, one of
40            'largefiles' or 'normal')
41        @param projectFile file name of the current project file (string)
42        @exception ValueError raised to indicate a bad value for the
43            'direction' parameter.
44        """
45        if direction not in ["largefiles", "normal"]:
46            raise ValueError("Bad value for 'direction' parameter.")
47
48        projectDir = os.path.dirname(projectFile)
49
50        from .LfConvertDataDialog import LfConvertDataDialog
51        dlg = LfConvertDataDialog(projectDir, direction)
52        if dlg.exec() == QDialog.DialogCode.Accepted:
53            newName, minSize, patterns = dlg.getData()
54            newProjectFile = os.path.join(
55                newName, os.path.basename(projectFile))
56
57            # step 1: convert the current project to new project
58            args = self.vcs.initCommand("lfconvert")
59            if direction == 'normal':
60                args.append('--to-normal')
61            else:
62                args.append("--size")
63                args.append(str(minSize))
64            args.append(projectDir)
65            args.append(newName)
66            if direction == 'largefiles' and patterns:
67                args.extend(patterns)
68
69            dia = HgDialog(self.tr('Convert Project - Converting'), self.vcs)
70            res = dia.startProcess(args)
71            if res:
72                dia.exec()
73                res = dia.normalExit() and os.path.isdir(
74                    os.path.join(newName, self.vcs.adminDir))
75
76            # step 2: create working directory contents
77            if res:
78                # step 2.1: start a command server client for the new repo
79                client = HgClient(newName, "utf-8", self.vcs)
80                ok, err = client.startServer()
81                if not ok:
82                    E5MessageBox.warning(
83                        None,
84                        self.tr("Mercurial Command Server"),
85                        self.tr(
86                            """<p>The Mercurial Command Server could not be"""
87                            """ started.</p><p>Reason: {0}</p>""").format(err))
88                    return
89
90                # step 2.2: create working directory contents
91                args = self.vcs.initCommand("update")
92                args.append("--verbose")
93                dia = HgDialog(self.tr('Convert Project - Extracting'),
94                               self.vcs, client=client)
95                res = dia.startProcess(args)
96                if res:
97                    dia.exec()
98                    res = dia.normalExit() and os.path.isfile(newProjectFile)
99
100                # step 2.3: stop the command server client for the new repo
101                client.stopServer()
102
103            # step 3: close current project and open new one
104            if res:
105                if direction == 'largefiles':
106                    self.vcs.hgEditConfig(
107                        repoName=newName,
108                        largefilesData={"minsize": minSize,
109                                        "pattern": patterns}
110                    )
111                else:
112                    self.vcs.hgEditConfig(
113                        repoName=newName,
114                        withLargefiles=False
115                    )
116                QTimer.singleShot(
117                    0, lambda: e5App().getObject("Project").openProject(
118                        newProjectFile))
119
120    def hgAdd(self, names, mode):
121        """
122        Public method used to add a file to the Mercurial repository.
123
124        @param names file name(s) to be added (string or list of string)
125        @param mode add mode (string one of 'normal' or 'large')
126        """
127        args = self.vcs.initCommand("add")
128        args.append("-v")
129        if mode == "large":
130            args.append("--large")
131        else:
132            args.append("--normal")
133
134        if isinstance(names, list):
135            self.vcs.addArguments(args, names)
136        else:
137            args.append(names)
138
139        dia = HgDialog(
140            self.tr('Adding files to the Mercurial repository'),
141            self.vcs)
142        res = dia.startProcess(args)
143        if res:
144            dia.exec()
145
146    def hgLfPull(self, revisions=None):
147        """
148        Public method to pull missing large files into the local repository.
149
150        @param revisions list of revisions to pull (list of string)
151        """
152        revs = []
153        if revisions:
154            revs = revisions
155        else:
156            from .LfRevisionsInputDialog import LfRevisionsInputDialog
157            dlg = LfRevisionsInputDialog()
158            if dlg.exec() == QDialog.DialogCode.Accepted:
159                revs = dlg.getRevisions()
160
161        if revs:
162            args = self.vcs.initCommand("lfpull")
163            args.append("-v")
164            for rev in revs:
165                args.append("--rev")
166                args.append(rev)
167
168            dia = HgDialog(self.tr("Pulling large files"), self.vcs)
169            res = dia.startProcess(args)
170            if res:
171                dia.exec()
172
173    def hgLfVerify(self, mode):
174        """
175        Public method to verify large files integrity.
176
177        @param mode verify mode (string; one of 'large', 'lfa' or 'lfc')
178        """
179        args = self.vcs.initCommand("verify")
180        if mode == "large":
181            args.append("--large")
182        elif mode == "lfa":
183            args.append("--lfa")
184        elif mode == "lfc":
185            args.append("--lfc")
186        else:
187            return
188
189        dia = HgDialog(
190            self.tr('Verifying the integrity of large files'),
191            self.vcs)
192        res = dia.startProcess(args)
193        if res:
194            dia.exec()
195