def _do_gp(self, path): self._logger.info("Pulling git repository: %s", path) gitHandler = GitHandler(self._logger) retCode, _pOut, pErr = gitHandler.pull(path) if retCode != 0: if pErr: self._logger.error(u"Error pulling git repository. Stderr: %s", pErr.decode("utf-8")) else: self._logger.error("Error pulling git repository.")
def __init__(self, parent, logger): super(AddRepoDialog, self).__init__(parent) self.logger = logger self._canAutoUpdate = False self._closeable = True self._path = None self._gitHandler = GitHandler(logger)
def _checkAllRepositories(self): from PyQt4.QtCore import Qt from plugin_repositories.plugin_repositories_gui import PluginRepositoriesGUI model = self._ui.getTable().model() outdated = set() upToDate = {} gh = GitHandler(self.logger) for row in xrange(model.rowCount()): path = convert_string(model.item(row, PluginRepositoriesGUI.PATH_COLUMN).data(Qt.DisplayRole).toString()) if gh.hasGit(path): needsPull, reason = gh.needsPull(True, path) if needsPull: outdated.add(path) else: upToDate[path] = reason return outdated, upToDate
class GitUpdateHandler(AppUpdateHandler): """Used if Lunchinator is run directly from git.""" def __init__(self, logger): super(GitUpdateHandler, self).__init__(logger) self._gitHandler = GitHandler(logger) @classmethod def appliesToConfiguration(cls, logger): gh = GitHandler(logger) return gh.hasGit() def activate(self): AppUpdateHandler.activate(self) if self.canCheckForUpdate(): self.checkForUpdate() def _getInitialStatus(self): return "Not checked." def getInstalledVersion(self): return get_settings().get_commit_count() def canCheckForUpdate(self): return lunchinator_has_gui() @loggingFunc def checkForUpdate(self): self._setStatus("Checking for update...") from lunchinator.callables import AsyncCall AsyncCall(getValidQtParent(), self.logger, self._gitHandler.needsPull, self._checkUpdateSuccess, self._checkUpdateError)(returnReason=True) @loggingFunc def _checkUpdateSuccess(self, tup): needsPull, reason = tup if needsPull: self._setStatus("Repository can be updated to version %s." % self._gitHandler.getRemoteCommitCount()) self._installReady() else: self._setStatus(u"No update: " + reason) @loggingFunc def _checkUpdateError(self, msg=None): st = u"Checking for update failed" if msg: st += u": " + msg self._setStatus(st, True) def prepareInstallation(self, commands): commands.addGitPull(get_settings().get_main_package_path())
def get_version(self): if self._version == None: try: version_file = self.get_resource("version") with contextlib.closing(open(version_file, "r")) as vfh: self._version = vfh.read().strip() self._commit_count = self._version.split(".")[-1] except Exception: from lunchinator.git import GitHandler gh = GitHandler(getCoreLogger()) if gh.hasGit(): commit_count = gh.getCommitCount() if commit_count: self._commit_count = commit_count self._version = commit_count else: getCoreLogger().error("Error reading/parsing version file") self._version = u"unknown.unknown" self._commit_count = "unknown" return self._version
def __init__(self, logger, parent): super(PluginRepositoriesGUI, self).__init__(parent) self.logger = logger self._gitHandler = GitHandler(logger) layout = QVBoxLayout(self) self._reposTable = QTreeView(self) self._reposTable.setIndentation(0) self._reposTable.header().setStretchLastSection(False) self._reposModel = QStandardItemModel(self._reposTable) self._initModel() self._reposTable.setModel(self._reposModel) self._reposTable.setSelectionMode(QTreeView.ExtendedSelection) self._reposTable.selectionModel().selectionChanged.connect(self._selectionChanged) layout.addWidget(self._reposTable) buttonLayout = QHBoxLayout() addButton = QPushButton("Add...") addButton.clicked.connect(self.addRepository) self._removeButton = QPushButton("Remove") self._removeButton.setEnabled(False) self._removeButton.clicked.connect(self._removeSelected) refreshButton = QPushButton("Check Status") refreshButton.clicked.connect(self.checkForUpdates) buttonLayout.addWidget(addButton) buttonLayout.addWidget(self._removeButton) buttonLayout.addWidget(refreshButton) layout.addLayout(buttonLayout) self._statusWidget = QWidget(self) self._statusWidget.setVisible(False) statusLayout = QHBoxLayout(self._statusWidget) statusLayout.setContentsMargins(0, 0, 0, 0) self._statusLabel = QLabel(self) statusLayout.addWidget(self._statusLabel) layout.addWidget(self._statusWidget)
class AddRepoDialog(ErrorMessageDialog): _WORKING_COPY = 0 _CLONE_URL = 1 def __init__(self, parent, logger): super(AddRepoDialog, self).__init__(parent) self.logger = logger self._canAutoUpdate = False self._closeable = True self._path = None self._gitHandler = GitHandler(logger) def _createPathPage(self): try: from PyQt4.QtGui import QCommonStyle style = QCommonStyle() except: style = None w = QWidget(self) layout = QVBoxLayout(w) inputWidget = QWidget(self) inputLayout = QHBoxLayout(inputWidget) inputLayout.setContentsMargins(0, 0, 0, 0) inputLayout.addWidget(QLabel("Path:", self)) self._pathEdit = QLineEdit(self) if hasattr(self._pathEdit, "setPlaceholderText"): self._pathEdit.setPlaceholderText(u"Directory Path") inputLayout.addWidget(self._pathEdit, 1) browseButton = QPushButton(self) browseButton.setAutoDefault(False) if style != None: browseIcon = style.standardIcon(QStyle.SP_DirOpenIcon) else: browseIcon = None if browseIcon and not browseIcon.isNull(): browseButton.setIcon(browseIcon) else: browseButton.setText("Browse...") browseButton.clicked.connect(self._browse) inputLayout.addWidget(browseButton, 0, Qt.AlignHCenter) layout.addWidget(inputWidget, 0) return w, layout def _createURLPage(self): w = QWidget(self) layout = QVBoxLayout(w) inputWidget = QWidget(self) inputLayout = QHBoxLayout(inputWidget) inputLayout.setContentsMargins(0, 0, 0, 0) inputLayout.addWidget(QLabel("URL:", self)) self._urlEdit = QLineEdit(self) if hasattr(self._urlEdit, "setPlaceholderText"): self._urlEdit.setPlaceholderText(u"Git URL (HTTPS/SSH)") inputLayout.addWidget(self._urlEdit, 1) layout.addWidget(inputWidget, 0) return w, layout def _addPropertyWidgets(self, layout, autoUpdateEnabled): propertiesLayout = QHBoxLayout() propertiesLayout.setContentsMargins(0, 0, 0, 0) activeCheckBox = QCheckBox("Active", self) activeCheckBox.setChecked(True) propertiesLayout.addWidget(activeCheckBox) self._activeBoxes.append(activeCheckBox) autoUpdateCheckBox = QCheckBox("Auto Update", self) autoUpdateCheckBox.setEnabled(autoUpdateEnabled) propertiesLayout.addWidget(autoUpdateCheckBox, 1, Qt.AlignLeft) self._autoUpdateBoxes.append(autoUpdateCheckBox) layout.addLayout(propertiesLayout) def _initInputUI(self, dialogLayout): self.setWindowTitle(u"Add Plugin Repository") self._tabs = QTabWidget(self) self._activeBoxes = [] self._autoUpdateBoxes = [] w, layout = self._createPathPage() self._addPropertyWidgets(layout, False) self._tabs.addTab(w, "Working Copy") w, layout = self._createURLPage() self._addPropertyWidgets(layout, True) self._tabs.addTab(w, "Clone URL") dialogLayout.addWidget(self._tabs) def _autoUpdateChanged(self, newState): self._autoUpdate = newState == Qt.Checked @loggingSlot() def _browse(self): fd = QFileDialog(self) fd.setOptions(QFileDialog.ShowDirsOnly) fd.setFileMode(QFileDialog.Directory) fd.exec_() if fd.result() == QDialog.Accepted: path = fd.selectedFiles()[0] self._setPath(path) def _checkPath(self): self._canAutoUpdate = self._gitHandler.hasGit(self.getPath()) box = self._autoUpdateBoxes[self._WORKING_COPY] if not self._canAutoUpdate: box.setChecked(False) if box.isEnabled() != self._canAutoUpdate: box.setEnabled(self._canAutoUpdate) return True return False def _setPath(self, path): self._pathEdit.setText(path) self._checkPath() def getPath(self): if self._path is not None: return self._path return convert_string(self._pathEdit.text()) def isRepositoryActive(self): return self._activeBoxes[self._tabs.currentIndex()].checkState() == Qt.Checked def isAutoUpdateEnabled(self): return self._autoUpdateBoxes[self._tabs.currentIndex()].checkState() == Qt.Checked def canAutoUpdate(self): return self._tabs.currentIndex() == self._CLONE_URL or self._canAutoUpdate def _setWorking(self, w): self._closeable = not w self._tabs.setEnabled(not w) self._setButtonsEnabled(not w) @loggingSlot() def _checkOK(self): if self._tabs.currentIndex() == self._WORKING_COPY: if not os.path.isdir(self.getPath()): self._error("The given path does not exist or is not a directory.") elif not self._checkPath(): # no change to properties widget -> accept self._path = self.getPath() self.accept() else: self._info(u"Cloning repository...") self._setWorking(True) url = convert_string(self._urlEdit.text()) AsyncCall(self, self.logger, self._checkAndClone, self._cloneSuccess, self._cloneError)(url) def closeEvent(self, event): if self._closeable: event.accept() else: event.ignore() def _checkAndClone(self, url): if not self._gitHandler.isGitURL(url): raise ValueError(u"The given URL does not exist or is no Git repository.") targetDir = get_settings().get_config(self._gitHandler.extractRepositoryNameFromURL(url)) targetDir = getUniquePath(targetDir) self._gitHandler.clone(url, targetDir) return targetDir @loggingSlot(object) def _cloneSuccess(self, path): self._setWorking(False) self.setResult(self.Accepted) self._path = path self.close() @loggingSlot(object) def _cloneError(self, msg): self._setWorking(False) self._error(msg)
class PluginRepositoriesGUI(QWidget): PATH_COLUMN = 1 ACTIVE_COLUMN = 0 AUTO_UPDATE_COLUMN = 2 STATUS_COLUMN = 3 addRepository = pyqtSignal() checkForUpdates = pyqtSignal() def __init__(self, logger, parent): super(PluginRepositoriesGUI, self).__init__(parent) self.logger = logger self._gitHandler = GitHandler(logger) layout = QVBoxLayout(self) self._reposTable = QTreeView(self) self._reposTable.setIndentation(0) self._reposTable.header().setStretchLastSection(False) self._reposModel = QStandardItemModel(self._reposTable) self._initModel() self._reposTable.setModel(self._reposModel) self._reposTable.setSelectionMode(QTreeView.ExtendedSelection) self._reposTable.selectionModel().selectionChanged.connect(self._selectionChanged) layout.addWidget(self._reposTable) buttonLayout = QHBoxLayout() addButton = QPushButton("Add...") addButton.clicked.connect(self.addRepository) self._removeButton = QPushButton("Remove") self._removeButton.setEnabled(False) self._removeButton.clicked.connect(self._removeSelected) refreshButton = QPushButton("Check Status") refreshButton.clicked.connect(self.checkForUpdates) buttonLayout.addWidget(addButton) buttonLayout.addWidget(self._removeButton) buttonLayout.addWidget(refreshButton) layout.addLayout(buttonLayout) self._statusWidget = QWidget(self) self._statusWidget.setVisible(False) statusLayout = QHBoxLayout(self._statusWidget) statusLayout.setContentsMargins(0, 0, 0, 0) self._statusLabel = QLabel(self) statusLayout.addWidget(self._statusLabel) layout.addWidget(self._statusWidget) def clear(self): self._initModel() def _updateStatusItem(self, item, path, outdated=None, upToDate=None): # first check fresh results, then the ones from repositories if upToDate and path in upToDate: item.setText(upToDate[path]) if upToDate[path] == GitHandler.UP_TO_DATE_REASON: item.setData(QColor(0, 255, 0), Qt.DecorationRole) else: item.setData(QColor(255, 0, 0), Qt.DecorationRole) elif outdated and path in outdated: item.setText("Repository can be updated") item.setData(QColor(255, 215, 0), Qt.DecorationRole) elif get_settings().get_plugin_repositories().isUpToDate(path): item.setText("No updates (for details, check status)") item.setData(QColor(0, 255, 0), Qt.DecorationRole) elif get_settings().get_plugin_repositories().isOutdated(path): item.setText("Repository can be updated") item.setData(QColor(255, 215, 0), Qt.DecorationRole) else: item.setData(None, Qt.DecorationRole) def updateStatusItems(self, outdated=None, upToDate=None): for row in xrange(self._reposModel.rowCount()): path = convert_string(self._reposModel.item(row, self.PATH_COLUMN).data(Qt.DisplayRole).toString()) self._updateStatusItem(self._reposModel.item(row, self.STATUS_COLUMN), path, outdated, upToDate) def _initModel(self): from PyQt4.QtCore import QStringList self._reposModel.clear() stringList = QStringList([u"Active", u"Path", u"Auto Update", u"Status"]) self._reposModel.setColumnCount(stringList.count()) self._reposModel.setHorizontalHeaderLabels(stringList) def appendRepository(self, path, active, autoUpdate, canAutoUpdate = None): activeItem = QStandardItem() activeItem.setEditable(False) activeItem.setCheckState(Qt.Checked if active else Qt.Unchecked) activeItem.setCheckable(True) pathItem = QStandardItem() pathItem.setData(path, Qt.DisplayRole) pathItem.setEditable(False) autoUpdateItem = QStandardItem() autoUpdateItem.setEditable(False) if canAutoUpdate == None: canAutoUpdate = self._gitHandler.hasGit(path) if canAutoUpdate: autoUpdateItem.setCheckState(Qt.Checked if autoUpdate else Qt.Unchecked) autoUpdateItem.setCheckable(True) statusItem = QStandardItem() self._updateStatusItem(statusItem, path) self._reposModel.appendRow([activeItem, pathItem, autoUpdateItem, statusItem]) def resizeColumns(self): self._reposTable.resizeColumnToContents(self.ACTIVE_COLUMN) self._reposTable.resizeColumnToContents(self.AUTO_UPDATE_COLUMN) self._reposTable.header().setResizeMode(self.PATH_COLUMN, QHeaderView.Stretch) self._reposTable.header().setResizeMode(self.STATUS_COLUMN, QHeaderView.ResizeToContents) def getTable(self): return self._reposTable @loggingSlot(QItemSelection, QItemSelection) def _selectionChanged(self, _sel, _desel): selection = self._reposTable.selectionModel().selectedRows() self._removeButton.setEnabled(len(selection) > 0) @loggingSlot() def _removeSelected(self): selection = self._reposTable.selectionModel().selectedRows() for index in selection: self._reposTable.model().removeRow(index.row()) def setStatus(self, msg, _progress=False): if msg: self._statusLabel.setText(msg) self._statusWidget.setVisible(True) else: self._statusWidget.setVisible(False)
def __init__(self, logger): super(GitUpdateHandler, self).__init__(logger) self._gitHandler = GitHandler(logger)
def appliesToConfiguration(cls, logger): gh = GitHandler(logger) return gh.hasGit()