def importLayer(self): params = [ Parameter("layer", "Layer to add", "", VECTOR, ""), Parameter("message", "Commit message", "", STRING, "") ] ret = openParametersDialog(params, "Add layer") if ret is not None: if ret["layer"] is None: return if isGeogigLayer(ret["layer"]): raise GeogigError("Selected layer is already a Geogig layer") if GEOGIGID_FIELD in [ f.name().lower() for f in ret["layer"].fields() ]: raise GeogigError("Selected layer has a 'geogigid' field") msg = ret["message"] or "Added layer '{}'".format( ret["layer"].name()) self.server.addLayer(self.user, self.repo, ret["layer"], "master", msg) saveStyleFromQgisLayer(ret["layer"], self.server, self.user, self.repo) self.refreshContent() iface.messageBar().pushMessage("Add layer", "Layer correctly imported", level=Qgis.Info, duration=5)
def onLayersLoaded(layers): global _geogigLayers for layer in layers: if GeogigLiveLayer.GEOGIG_URL in layer.customPropertyKeys(): #geogig layer that is part of a project geogigLayer = addGeogigLayerFromLayer(layer) if geogigLayer: _geogigLayers.append(geogigLayer) if not geogigLayer.isValid(): item = QgsProject.instance().layerTreeRoot().findLayer(geogigLayer.layer.id()) item.setItemVisibilityCheckedRecursive(False) raise GeogigError("Could not populate layer with Geogig server data") else: #let's see if it's a geogig layer in a geopackage file path = geogig.geopkgtools.simplifyGeoPKGFname(layer.source()) if path.endswith("gpkg"): url = geogig.geopkgtools.getMetadataValue(path, GeogigLiveLayer.GEOGIG_URL) if url is not None: rect = layer.extent() extent = [rect.xMinimum(), rect.yMinimum(), rect.xMaximum(), rect.yMaximum()] layer.setCustomProperty(GeogigLiveLayer.GEOGIG_URL, url) layer.setCustomProperty(GeogigLiveLayer.GEOGIG_USER, geogig.geopkgtools.getMetadataValue(path, GeogigLiveLayer.GEOGIG_USER)) layer.setCustomProperty(GeogigLiveLayer.GEOGIG_REPO, geogig.geopkgtools.getMetadataValue(path, GeogigLiveLayer.GEOGIG_REPO)) layer.setCustomProperty(GeogigLiveLayer.GEOGIG_LAYER, geogig.geopkgtools.getMetadataValue(path, GeogigLiveLayer.GEOGIG_LAYER)) layer.setCustomProperty(GeogigLiveLayer.GEOGIG_COMMITID, geogig.geopkgtools.getMetadataValue(path, GeogigLiveLayer.GEOGIG_COMMITID)) layer.setCustomProperty(GeogigLiveLayer.GEOGIG_EXTENT, extent) layer.setCustomProperty(GeogigLiveLayer.GEOGIG_LAYERCLASS, GeogigGpkgLayer.__name__) geogigLayer = addGeogigLayerFromLayer(layer) if geogigLayer: _geogigLayers.append(geogigLayer) if not geogigLayer.isValid(): item = QgsProject.instance().layerTreeRoot().findLayer(geogigLayer.layer.id()) item.setItemVisibilityCheckedRecursive(False) raise GeogigError("Could not populate layer with Geogig server data")
def __init__(self, geogiglayer, fid): super(VersionViewerDialog, self).__init__(iface.mainWindow()) self.geogiglayer = geogiglayer self.fid = fid self.layer = None self.setupUi(self) self.listWidget.itemClicked.connect(self.commitClicked) horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(0) horizontalLayout.setMargin(0) self.mapCanvas = QgsMapCanvas() self.mapCanvas.setCanvasColor(Qt.white) horizontalLayout.addWidget(self.mapCanvas) self.mapWidget.setLayout(horizontalLayout) self.panTool = QgsMapToolPan(self.mapCanvas) self.mapCanvas.setMapTool(self.panTool) path = geogiglayer.layername + "/" + fid ids, commits = geogiglayer.server.log(geogiglayer.user, geogiglayer.repo, "master", path) if commits: for commit in commits.values(): item = CommitListItem(commit, geogiglayer, fid) self.listWidget.addItem(item) else: raise GeogigError("The selected feature is not versioned yet")
def addGeogigLayer(server, user, repo, layername, commitid, live, parent = None): if live: layer = GeogigLiveLayer(server, user, repo, layername, commitid) else: parent = parent or iface.mainWindow() if parent == iface: parent = iface.mainWindow() dlg = ExtentDialog(parent) dlg.exec_() if dlg.ok: extent = dlg.extent if extent is not None: extentRect = QgsRectangle(extent[0],extent[1], extent[2],extent[3]) projectCrs = QgsProject.instance().crs() layerCrs = server.layerCrs(user, repo, layername, commitid) extentRect = xform(extentRect, projectCrs,layerCrs) extent = [extentRect.xMinimum(),extentRect.yMinimum(), extentRect.xMaximum(), extentRect.yMaximum()] layer = GeogigGpkgLayer(server, user, repo, layername, commitid, extent=extent) else: return False # no action - they said "cancel" _geogigLayers.append(layer) if live and not layer.isValid(): # layer will not be valid/invalid until downloaded -- will do check then raise GeogigError("Could not populate layer with Geogig server data. See log for details", "Error connecting to server") return True
def saveChanges(self): changesFile = self._changesFile() if changesFile is None: if self.hasLocalChanges(): raise GeogigError( "Cannot save local changes. Project must be saved first.") else: return deletedGigIds = self.deletedFeatures modifiedFeatures = list(self.layer.getFeatures(self.modifiedFeatures)) addedFeatures = list(self.layer.getFeatures(self.addedFeatures)) if self.hasLocalChanges(): with open(changesFile, "wb") as f: f.write(struct.pack( 'i', len(deletedGigIds))) # write int - # of deleted for gigid in deletedGigIds: s = gigid.encode() f.write(struct.pack('i', len(s))) #len f.write(s) f.write(struct.pack( 'i', len(modifiedFeatures))) # write int - # of mod if len(modifiedFeatures) > 0: writer = FeatureWriter(modifiedFeatures) f.write(writer.asBytes()) f.write(bytes([0])) # separator f.write(struct.pack( 'i', len(addedFeatures))) # write int - # of mod if len(addedFeatures) > 0: writer = FeatureWriter(addedFeatures) f.write(writer.asBytes()) elif os.path.exists(changesFile): os.remove(changesFile)
def createRepo(self, user, repo): user = cleanseUserName(user) repo = cleanseRepoName(repo) repos = self.reposForUser(user) if repo in [r["identity"] for r in repos]: raise GeogigError("A repository with that name already exists for the specified user") self.connector.post("repos/{}/{}".format(user, repo),json={}) self.repoCreated.emit(user, repo)
def _diffPR(self, user, repo, layerName, prID): user = cleanseUserName(user) repo = cleanseRepoName(repo) prID = cleansePRId(prID) layerName = cleanseLayerName(layerName) q = QueryForLayerProto(self.connector) try: return q.queryDiffPR(user, repo, layerName, prID) except HTTPError as ee: raise except Exception as e: raise GeogigError("Error getting diff from server", str(e))
def forkRepo(self, user, repo, name): user = cleanseUserName(user) repo = cleanseRepoName(repo) name = cleanseRepoName(name) repos = self.reposForUser(self.connector.user) if name in [r["identity"] for r in repos]: raise GeogigError("A repository with that name already exists for the current user") query = {"forkName": name} taskId = self.connector.post("repos/{}/{}/forks".format(user, repo), params=query)["id"] self.waitForTask(taskId, "Forking repository") self.repoForked.emit(user, repo, name)
def checkCanCommit(self): if self.server.connector.user != self.user: raise GeogigError("You logged in with a different user. Features were not commited and will be kept in the Geogig edit buffer") try: headid = self.server.commitidForBranch(self.user, self.repo, "master") except GeogigAuthException: raise GeogigError("You are not logged in. Features were not commited and will be kept in the Geogig edit buffer") except GeogigError: raise GeogigError("Cannot connect to server. Features were not commited and will be kept in the Geogig edit buffer") if self.commitid=="HEAD": return # by definition, up to date if headid != self.commitid: filteredIds = [f[GEOGIGID_FIELD] for f in self.layer.getFeatures(QgsFeatureRequest(self.modifiedFeatures))] filteredIds.extend(self.deletedFeatures) featureFilter = {"featureIds": filteredIds} diff = self.server.diff(self.user, self.repo, self.layername, headid, self.commitid, featureFilter) if diff: conflicts = solveConflicts(self, diff) if not conflicts: raise GeogigError("Conflicts were not solved. Features were not commited to the repo.")
def diff(self, user, repo, layer, refspec, oldRef, featureFilter=None, returnAsIterator=False, oldRefUser=None, oldRefRepoName=None): user = cleanseUserName(user) repo = cleanseRepoName(repo) layer = cleanseLayerName(layer) refspec = cleanseRefSpec(refspec) oldRef = cleanseRefSpec(oldRef) q = QueryForLayerProto(self.connector) try: return q.queryDiff(user, repo, layer, refspec, oldRef, featureFilter, returnAsIterator=returnAsIterator, oldRefUser=oldRefUser, oldRefRepoName=oldRefRepoName) except: try: #might be a deleted layer. We try to compute the diff in reversed order of commits if oldRefRepoName is None: diff = q.queryDiff(user, repo, layer, oldRef, refspec, featureFilter) else: diff = q.queryDiff(oldRefUser, oldRefRepoName, layer, oldRef, refspec, featureFilter, oldRefUser=user, oldRefRepoName=repo) def invert(d): d['geogig.changeType'] = 2 d['old'] = d['new'] d['new'] = None return d inverted = [invert(d) for d in diff] return inverted except Exception as e: raise GeogigError("Error getting diff from server", str(e))
def syncBranch(self, user, repo, parentUser, parentRepo, transactionid, branch="master", parentBranch="master", commitMessage=""): user = cleanseUserName(user) repo = cleanseRepoName(repo) parentUser = cleanseUserName(parentUser) parentRepo = cleanseRepoName(parentRepo) branch = cleanseBranchName(branch) parentBranch = cleanseBranchName(parentBranch) transactionid = cleanseTransactionId(transactionid) headers = {"geogig-transaction-id": transactionid} pullArgs = { "remote_repo_owner": parentUser, "remote_repo_name": parentRepo, "remote_repo_head": parentBranch, "commit_message": commitMessage } ret = self.connector.post("repos/{}/{}/branches/{}/sync".format( user, repo, branch), json=pullArgs, headers=headers) taskId = ret["id"] ret = self.waitForTask(taskId, "Processing changes in server") layers = self.layers(user, repo) q = QueryForLayerProto(self.connector) result = {} conflictsFound = False for layerName in layers: try: conflicts = q.queryConflict(user, repo, layerName, transactionid) conflicts2 = {} if conflicts: conflictsFound = True for conflict in conflicts: conflicts2[conflict["ID"]] = {} conflicts2[conflict["ID"]]["origin"] = conflict["ancestor"] conflicts2[conflict["ID"]]["local"] = conflict["theirs"] conflicts2[conflict["ID"]]["remote"] = conflict["ours"] result[layerName] = conflicts2 except Exception as e: raise GeogigError("Error getting diff from server", str(e)) if conflictsFound: return result return []
def addNewServer(self): params = [ Parameter("url", "URL", "", STRING, "http://localhost:8181"), Parameter("name", "Name", "", STRING, "") ] urls = [] for i in range(self.childCount()): serverItem = self.child(i) urls.append(serverItem.url) ret = openParametersDialog(params, "New server") if ret is not None: url = ret["url"] url = url + "/" if not url.endswith("/") else url if url in urls: raise GeogigError("A server item with that url already exists") item = ServerItem(url, ret["name"]) self.addChild(item) servers = _servers() servers[ret["name"]] = url _saveServers(servers)
def populate(self): try: preloadedData = RepoDataPreloader(self.server).data self.usersItem = UsersItem(self.server, preloadedData=preloadedData) self.addChild(self.usersItem) except ConnectionError: raise GeogigError( "Connection error. Server not available or might not be a GeoGig server." ) try: self.myUserItem = UserItem( self.connector.user, self.server, preloadedData=preloadedData["userRepos"][self.connector.user]) self.myUserItem.setText(0, "My repos") self.myUserItem.setIcon(0, repoIcon) self.addChild(self.myUserItem) self.myUserItem.setExpanded(True) except: pass self.setExpanded(True)