Started adding support for Mercurial sub-repositories.

Sat, 16 Jun 2012 18:28:31 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 16 Jun 2012 18:28:31 +0200
changeset 1905
7ad9161c5293
parent 1902
73ac8bcb984d
child 1906
8487f9c2533b

Started adding support for Mercurial sub-repositories.

Plugins/VcsPlugins/vcsMercurial/HgAddSubrepositoryDialog.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/HgAddSubrepositoryDialog.ui file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/ProjectHelper.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/hg.py file | annotate | diff | comparison | revisions
eric5.e4p file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/HgAddSubrepositoryDialog.py	Sat Jun 16 18:28:31 2012 +0200
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to add a subrepository.
+"""
+
+import os
+
+from PyQt4.QtCore import pyqtSlot
+from PyQt4.QtGui import QDialog, QDialogButtonBox
+
+from E5Gui import E5FileDialog, E5MessageBox
+
+import Utilities
+
+from .Ui_HgAddSubrepositoryDialog import Ui_HgAddSubrepositoryDialog
+
+
+class HgAddSubrepositoryDialog(QDialog, Ui_HgAddSubrepositoryDialog):
+    """
+    Class implementing a dialog to add a subrepository.
+    """
+    def __init__(self, projectPath, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        self.__ok = self.buttonBox.button(QDialogButtonBox.Ok)
+        self.__ok.setEnabled(False)
+        
+        self.__projectPath = projectPath
+        
+        self.typeCombo.addItem("Mercurial", "hg")
+        self.typeCombo.addItem("GIT", "git")
+        self.typeCombo.addItem("Subversion", "svn")
+    
+    def __updateOk(self):
+        """
+        Private slot to update the state of the OK button.
+        """
+        path = self.pathEdit.text()
+        url = self.urlEdit.text()
+        
+        self.__ok.setEnabled(
+            path != "" and
+            not os.path.isabs(path) and
+            url != ""
+        )
+    
+    @pyqtSlot(str)
+    def on_pathEdit_textChanged(self, p0):
+        """
+        Private slot to handle the update of the path.
+        
+        @param p0 text of the path edit (string)
+        """
+        self.__updateOk()
+    
+    @pyqtSlot(str)
+    def on_urlEdit_textChanged(self, p0):
+        """
+        Private slot to handle the update of the URL.
+        
+        @param p0 text of the URL edit (string)
+        """
+        self.__updateOk()
+    
+    @pyqtSlot()
+    def on_pathButton_clicked(self):
+        """
+        Private slot to handle the path selection via a directory selection dialog.
+        """
+        path = E5FileDialog.getExistingDirectory(
+            self,
+            self.trUtf8("Add Subrepository"),
+            os.path.join(self.__projectPath, self.pathEdit.text()),
+            E5FileDialog.Options(E5FileDialog.Option(0)))
+        
+        if path:
+            if path.startswith(self.__projectPath):
+                path = path.replace(self.__projectPath, "")[1:]
+                self.pathEdit.setText(Utilities.toNativeSeparators(path))
+            else:
+                E5MessageBox.critical(self,
+                    self.trUtf8("Add Subrepository"),
+                    self.trUtf8("""The subrepository path must be inside the project."""))
+                return
+    
+    def getData(self):
+        """
+        Public method to get the data.
+        
+        @return tuple containing the relative path within the project, the subrepository
+            type and the subrepository URL (string, string, string)
+        """
+        return (
+            self.pathEdit.text(),
+            self.typeCombo.itemData(self.typeCombo.currentIndex()),
+            self.urlEdit.text()
+        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/HgAddSubrepositoryDialog.ui	Sat Jun 16 18:28:31 2012 +0200
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HgAddSubrepositoryDialog</class>
+ <widget class="QDialog" name="HgAddSubrepositoryDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>550</width>
+    <height>135</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Add Subrepository</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>&amp;Path within Project:</string>
+     </property>
+     <property name="buddy">
+      <cstring>pathEdit</cstring>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLineEdit" name="pathEdit">
+       <property name="toolTip">
+        <string>Enter the path of the subrepository relative to the project</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="pathButton">
+       <property name="toolTip">
+        <string>Select the path of the subrepository with a directory selection dialog</string>
+       </property>
+       <property name="text">
+        <string notr="true">...</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>&amp;Type:</string>
+     </property>
+     <property name="buddy">
+      <cstring>typeCombo</cstring>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QComboBox" name="typeCombo">
+       <property name="toolTip">
+        <string>Select the type of the subrepository</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item row="2" column="0">
+    <widget class="QLabel" name="label_3">
+     <property name="text">
+      <string>&amp;URL:</string>
+     </property>
+     <property name="buddy">
+      <cstring>urlEdit</cstring>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="QLineEdit" name="urlEdit">
+     <property name="toolTip">
+      <string>Enter the URL of the subrepository</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>pathEdit</tabstop>
+  <tabstop>pathButton</tabstop>
+  <tabstop>typeCombo</tabstop>
+  <tabstop>urlEdit</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>HgAddSubrepositoryDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>HgAddSubrepositoryDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- a/Plugins/VcsPlugins/vcsMercurial/ProjectHelper.py	Sat Jun 16 13:38:45 2012 +0200
+++ b/Plugins/VcsPlugins/vcsMercurial/ProjectHelper.py	Sat Jun 16 18:28:31 2012 +0200
@@ -74,6 +74,14 @@
         for extension in self.__extensions.values():
             extension.setObjects(vcsObject, projectObject)
     
+    def getProject(self):
+        """
+        Public method to get a reference to the project object.
+        
+        @return reference to the project object (Project)
+        """
+        return self.project
+    
     def getActions(self):
         """
         Public method to get a list of all actions.
@@ -864,6 +872,21 @@
         ))
         self.hgGraftContinueAct.triggered[()].connect(self.__hgGraftContinue)
         self.actions.append(self.hgGraftContinueAct)
+        
+        self.hgAddSubrepoAct = E5Action(
+                self.trUtf8('Add'),
+                UI.PixmapCache.getIcon("vcsAdd.png"),
+                self.trUtf8('Add'),
+                0, 0, self, 'mercurial_add_subrepo')
+        self.hgAddSubrepoAct.setStatusTip(self.trUtf8(
+            'Add a subrepository'
+        ))
+        self.hgAddSubrepoAct.setWhatsThis(self.trUtf8(
+            """<b>Add</b>"""
+            """<p>Add a subrepository to the project.</p>"""
+        ))
+        self.hgAddSubrepoAct.triggered[()].connect(self.__hgAddSubrepository)
+        self.actions.append(self.hgAddSubrepoAct)
     
     def initMenu(self, menu):
         """
@@ -946,6 +969,13 @@
         else:
             graftMenu = None
         
+        if self.vcs.version >= (1, 8):
+            subrepoMenu = QMenu(self.trUtf8("Sub-Repository"), menu)
+            subrepoMenu.setTearOffEnabled(True)
+            subrepoMenu.addAction(self.hgAddSubrepoAct)
+        else:
+            subrepoMenu = None
+        
         act = menu.addAction(
             UI.PixmapCache.getIcon(
                 os.path.join("VcsPlugins", "vcsMercurial", "icons", "mercurial.png")),
@@ -999,6 +1029,9 @@
         menu.addSeparator()
         menu.addAction(self.vcsSwitchAct)
         menu.addSeparator()
+        if subrepoMenu is not None:
+            menu.addMenu(subrepoMenu)
+            menu.addSeparator()
         menu.addMenu(bisectMenu)
         menu.addSeparator()
         menu.addAction(self.vcsCleanupAct)
@@ -1349,3 +1382,9 @@
                 yesDefault=True)
             if res:
                 self.project.reopenProject()
+    
+    def __hgAddSubrepository(self):
+        """
+        Private slot used to add a sub-repository.
+        """
+        self.vcs.hgAddSubrepository()
--- a/Plugins/VcsPlugins/vcsMercurial/hg.py	Sat Jun 16 13:38:45 2012 +0200
+++ b/Plugins/VcsPlugins/vcsMercurial/hg.py	Sat Jun 16 18:28:31 2012 +0200
@@ -52,6 +52,7 @@
 from .HgExportDialog import HgExportDialog
 from .HgPhaseDialog import HgPhaseDialog
 from .HgGraftDialog import HgGraftDialog
+from .HgAddSubrepositoryDialog import HgAddSubrepositoryDialog
 
 from .BookmarksExtension.bookmarks import Bookmarks
 from .QueuesExtension.queues import Queues
@@ -315,6 +316,7 @@
         
         if status:
             status = self.hgCreateIgnoreFile(projectDir)
+            # TODO: only call this, if the file is not present
             
             if status:
                 args = []
@@ -2628,6 +2630,89 @@
         return res
     
     ############################################################################
+    ## Methods to deal with subrepositories are below.
+    ############################################################################
+    
+    def getHgSubPath(self):
+        """
+        Public method to get the path to the .hgsub file containing the definitions
+        of subrepositories.
+        
+        @return full path of the .hgsub file (string)
+        """
+        ppath = self.__projectHelper.getProject().getProjectPath()
+        return os.path.join(ppath, ".hgsub")
+    
+    def hasSubrepositories(self):
+        """
+        Public method to check, if the project might have subrepositories.
+        
+        @return flag indicating the existence of subrepositories (boolean)
+        """
+        hgsub = self.getHgSubPath()
+        return os.path.isfile(hgsub) and os.stat(hgsub).st_size > 0
+    
+    def hgAddSubrepository(self):
+        """
+        Public method to add a subrepository.
+        """
+        ppath = self.__projectHelper.getProject().getProjectPath()
+        hgsub = self.getHgSubPath()
+        dlg = HgAddSubrepositoryDialog(ppath)
+        if dlg.exec_() == QDialog.Accepted:
+            relPath, subrepoType, subrepoUrl = dlg.getData()
+            if subrepoType == "hg":
+                url = subrepoUrl
+            else:
+                url = "[{0}]{1}".format(subrepoType, subrepoUrl)
+            entry = "{0} = {1}\n".format(relPath, url)
+            
+            contents = []
+            if os.path.isfile(hgsub):
+                # file exists; check, if such an entry exists already
+                needsAdd = False
+                try:
+                    f = open(hgsub, "r")
+                    contents = f.readlines()
+                    f.close()
+                except IOError as err:
+                    E5MessageBox.critical(self.__ui,
+                        self.trUtf8("Add Subrepository"),
+                        self.trUtf8("""<p>The subrepositories file .hgsub could not"""
+                                    """ be read.</p><p>Reason: {0}</p>""")
+                                    .format(str(err)))
+                    return
+                
+                if entry in contents:
+                    E5MessageBox.critical(self.__ui,
+                        self.trUtf8("Add Subrepository"),
+                        self.trUtf8("""<p>The subrepositories file .hgsub already"""
+                                    """ contains an entry <b>{0}</b>. Aborting...</p>""")
+                                    .format(entry))
+                    return
+            else:
+                needsAdd = True
+            
+            if contents and not contents[-1].endswith("\n"):
+                contents[-1] = contents[-1] + "\n"
+            contents.append(entry)
+            try:
+                f = open(hgsub, "w")
+                f.writelines(contents)
+                f.close()
+            except IOError as err:
+                E5MessageBox.critical(self.__ui,
+                    self.trUtf8("Add Subrepository"),
+                    self.trUtf8("""<p>The subrepositories file .hgsub could not"""
+                                """ be written to.</p><p>Reason: {0}</p>""")
+                                .format(str(err)))
+                return
+            
+            if needsAdd:
+                self.vcsAdd(hgsub)
+                self.__projectHelper.getProject().appendFile(hgsub)
+    
+    ############################################################################
     ## Methods to handle extensions are below.
     ############################################################################
     
--- a/eric5.e4p	Sat Jun 16 13:38:45 2012 +0200
+++ b/eric5.e4p	Sat Jun 16 18:28:31 2012 +0200
@@ -1014,6 +1014,7 @@
     <Source>UI/SearchWidget.py</Source>
     <Source>Plugins/VcsPlugins/vcsPySvn/SvnChangeListsDialog.py</Source>
     <Source>Plugins/VcsPlugins/vcsSubversion/SvnChangeListsDialog.py</Source>
+    <Source>Plugins/VcsPlugins/vcsMercurial/HgAddSubrepositoryDialog.py</Source>
   </Sources>
   <Forms>
     <Form>PyUnit/UnittestDialog.ui</Form>
@@ -1305,6 +1306,7 @@
     <Form>Helpviewer/SiteInfo/SiteInfoNoSslDialog.ui</Form>
     <Form>Plugins/VcsPlugins/vcsPySvn/SvnChangeListsDialog.ui</Form>
     <Form>Plugins/VcsPlugins/vcsSubversion/SvnChangeListsDialog.ui</Form>
+    <Form>Plugins/VcsPlugins/vcsMercurial/HgAddSubrepositoryDialog.ui</Form>
   </Forms>
   <Translations>
     <Translation>i18n/eric5_cs.qm</Translation>

eric ide

mercurial