mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-06-03 01:02:03 +03:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5285cd142 | ||
|
|
69482343ba | ||
|
|
d4639c2e61 | ||
|
|
b85ade9dd7 | ||
|
|
e191cb8aa3 | ||
|
|
e6bc75ce26 | ||
|
|
bc1df346f2 | ||
|
|
27c35321f0 | ||
|
|
7b99ba325b | ||
|
|
74763287fb | ||
|
|
737ff42d64 | ||
|
|
5656bd2d48 | ||
|
|
058c069394 | ||
|
|
926ec48d00 | ||
|
|
410e5353b2 | ||
|
|
bfb90406ed | ||
|
|
439cdce287 | ||
|
|
4e50c2a4b1 | ||
|
|
94c636ae61 | ||
|
|
f53b9a266e | ||
|
|
2476448032 | ||
|
|
a34cd742e3 | ||
|
|
39698196ac | ||
|
|
61432ced4f | ||
|
|
2ddd13c445 | ||
|
|
af6c4c5b3e | ||
|
|
d4012294bf | ||
|
|
4b04b0e855 | ||
|
|
1bec5019bf | ||
|
|
ec6b876baa | ||
|
|
7cee0d01ab | ||
|
|
dd3314d06b | ||
|
|
9c58b26265 | ||
|
|
83c26f47da | ||
|
|
8ed2f55600 | ||
|
|
b435317904 | ||
|
|
acb8aa8ca2 | ||
|
|
c55d6b8a6f | ||
|
|
a4039a254e | ||
|
|
85ed4b3026 | ||
|
|
5207a99692 | ||
|
|
d69527995d | ||
|
|
4b000ba2f7 | ||
|
|
1b302b77a0 | ||
|
|
a5b5c404ec | ||
|
|
6b97b0c6cd | ||
|
|
115dd43eee |
19
.github/workflows/testing.yml
vendored
Normal file
19
.github/workflows/testing.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: testing
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build and run Docker image
|
||||
run: |
|
||||
docker build -t gns3-gui-test .
|
||||
docker run gns3-gui-test
|
||||
21
.travis.yml
21
.travis.yml
@@ -1,21 +0,0 @@
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
notifications:
|
||||
email: false
|
||||
script:
|
||||
- docker build -t gns3-gui-test .
|
||||
- docker run gns3-gui-test
|
||||
before_deploy:
|
||||
- sudo pip install twine
|
||||
- sudo pip install urllib3[secure]
|
||||
deploy:
|
||||
provider: pypi
|
||||
edge:
|
||||
branch: v1.8.45
|
||||
user: noplay
|
||||
password:
|
||||
secure: FofcqlJjgqf2jaDaXpLHeigVoexbrOz3WwnDuiJpwJxeFUlPY8s2cQs/Bm+dzxzZaOaGiVE0A83v/Xa10yD5tflThHt4sqYJK3iQCinA7wgeAlDimB4xrWUNplfNJZ/Eod5Ssa++E02W+3i29PxpXY//mjCY7qDxaoxul1gnFJY=
|
||||
on:
|
||||
tags: true
|
||||
repo: GNS3/gns3-gui
|
||||
13
.whitesource
Normal file
13
.whitesource
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"scanSettings": {
|
||||
"configMode": "AUTO",
|
||||
"configExternalURL": "",
|
||||
"projectToken" : ""
|
||||
},
|
||||
"checkRunSettings": {
|
||||
"vulnerableCheckRunConclusionLevel": "failure"
|
||||
},
|
||||
"issueSettings": {
|
||||
"minSeverityLevel": "LOW"
|
||||
}
|
||||
}
|
||||
35
CHANGELOG
35
CHANGELOG
@@ -1,5 +1,40 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.15 07/10/2020
|
||||
|
||||
* Fix custom symbol not sent to remote controller when installing appliance
|
||||
|
||||
## 2.2.14 14/09/2020
|
||||
|
||||
* Improvements to add a new version of an appliance from wizard. Fixes #3002.
|
||||
|
||||
## 2.2.13 04/09/2020
|
||||
|
||||
* No changes
|
||||
|
||||
## 2.2.12 07/08/2020
|
||||
|
||||
* Downgrade psutil to version 5.6.7
|
||||
* Fix log shows the GUI command line without spaces between its arguments. Fixes #3026
|
||||
* Use server host is console host is equal to "0:0:0:0:0:0:0:0"
|
||||
* Remove VMware promotion.
|
||||
|
||||
## 2.2.11 09/07/2020
|
||||
|
||||
* Try to fix "Recent project" selection not working. Ref #3007
|
||||
* Fix debug entries shown twice in console window and double error messages with remote GNS3VM. Fixes #3010
|
||||
* Fix deprecation warning. Ref #3009
|
||||
* Fix tests on macOS. Ref #3009
|
||||
* Fix sentry SDK is configured twice.
|
||||
|
||||
## 2.2.10 18/06/2020
|
||||
|
||||
* New fix for multi-device selection/deselection not working as expected with right click. Fixes #2986
|
||||
* Optimize snap-to-grid code for drawing items. Fixes #2997
|
||||
* Move jsonschema 2.6.0 requirement in build repository.
|
||||
* Only use jsonschema 2.6.0 on Windows and macOS.
|
||||
* Disable default integrations for sentry sdk.
|
||||
|
||||
## 2.2.9 04/06/2020
|
||||
|
||||
* Fix GUI doesn't detect another GUI on macOS. Fixes #2994
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
# Run tests inside a container
|
||||
FROM ubuntu:18.04
|
||||
|
||||
MAINTAINER GNS3 Team
|
||||
|
||||
#ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y --force-yes python3.6 python3-pyqt5 python3-pip python3-pyqt5.qtsvg python3-pyqt5.qtwebsockets python3.6-dev xvfb
|
||||
RUN apt-get clean
|
||||
|
||||
|
||||
ADD dev-requirements.txt /dev-requirements.txt
|
||||
ADD requirements.txt /requirements.txt
|
||||
RUN pip3 install -r /dev-requirements.txt
|
||||
|
||||
|
||||
ADD . /src
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
CMD xvfb-run python3.6 -m pytest -vv
|
||||
|
||||
@@ -3,7 +3,6 @@ include AUTHORS
|
||||
include LICENSE
|
||||
include MANIFEST.in
|
||||
include requirements.txt
|
||||
include tox.ini
|
||||
recursive-include tests *
|
||||
recursive-include gns3 *
|
||||
recursive-include resources *
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
GNS3-gui
|
||||
========
|
||||
|
||||
.. image:: https://travis-ci.org/GNS3/gns3-gui.svg?branch=master
|
||||
:target: https://travis-ci.org/GNS3/gns3-gui
|
||||
.. image:: https://github.com/GNS3/gns3-gui/workflows/testing/badge.svg
|
||||
:target: https://github.com/GNS3/gns3-gui/actions?query=workflow%3Atesting
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/gns3-gui.svg
|
||||
:target: https://pypi.python.org/pypi/gns3-gui
|
||||
|
||||
.. image:: https://snyk.io/test/github/GNS3/gns3-gui/badge.svg
|
||||
:target: https://snyk.io/test/github/GNS3/gns3-gui
|
||||
|
||||
|
||||
GNS3 GUI repository.
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
-rrequirements.txt
|
||||
|
||||
pep8==1.7.0
|
||||
pytest==4.4.1
|
||||
pytest-pythonpath==0.7.3 # useful for running tests outside tox
|
||||
pytest-timeout==1.3.3
|
||||
pytest==5.4.3
|
||||
flake8==3.8.3
|
||||
pytest-timeout==1.4.1
|
||||
|
||||
@@ -223,17 +223,10 @@ class ConsoleCmd(cmd.Cmd):
|
||||
level = int(args[0])
|
||||
if level == 0:
|
||||
print("Deactivating debugging")
|
||||
for handler in root.handlers:
|
||||
if isinstance(handler, logging.StreamHandler):
|
||||
root.removeHandler(handler)
|
||||
root.setLevel(logging.INFO)
|
||||
else:
|
||||
root.addHandler(logging.StreamHandler(sys.stdout))
|
||||
if level == 1:
|
||||
print("Activating debugging")
|
||||
else:
|
||||
print("Activating full debugging")
|
||||
root.setLevel(logging.DEBUG)
|
||||
print("Activating debugging")
|
||||
root.setLevel(logging.DEBUG)
|
||||
from .main_window import MainWindow
|
||||
MainWindow.instance().setSettings({"debug_level": level})
|
||||
else:
|
||||
|
||||
@@ -51,7 +51,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://1a54ce2e5db84c5caa3bd1ad9ab5dd37:6fc7b3f8deca4a1ebf2f551b310e9b3f@o19455.ingest.sentry.io/38506"
|
||||
DSN = "https://5120f215040a4d0f8fea454f6baea6a4:3d447073ba874997a4f755ccdfd0f8ed@o19455.ingest.sentry.io/38506"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
@@ -78,12 +78,9 @@ class CrashReport:
|
||||
sentry_sdk.init(dsn=CrashReport.DSN,
|
||||
release=__version__,
|
||||
ca_certs=cacert,
|
||||
default_integrations=False,
|
||||
integrations=[sentry_logging])
|
||||
|
||||
sentry_sdk.init(dsn=CrashReport.DSN,
|
||||
release=__version__,
|
||||
ca_certs=cacert)
|
||||
|
||||
tags = {
|
||||
"os:name": platform.system(),
|
||||
"os:release": platform.release(),
|
||||
|
||||
@@ -475,8 +475,24 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
Allow user to create a new version of an appliance
|
||||
"""
|
||||
|
||||
new_version, ok = QtWidgets.QInputDialog.getText(self, "Creating a new version", "Create a new version for this appliance.\nPlease share your experience on the GNS3 community if this version works.\n\nVersion name:", QtWidgets.QLineEdit.Normal)
|
||||
current = self.uiApplianceVersionTreeWidget.currentItem()
|
||||
if current is None:
|
||||
QtWidgets.QMessageBox.critical(self.parent(), "Base version", "Please select a base version")
|
||||
return
|
||||
base_version = current.data(0, QtCore.Qt.UserRole)
|
||||
|
||||
new_version_name, ok = QtWidgets.QInputDialog.getText(self, "Creating a new version", "Create a new version for this appliance.\nPlease share your experience on the GNS3 community if this version works.\n\nVersion name:", QtWidgets.QLineEdit.Normal, base_version.get("name"))
|
||||
if ok:
|
||||
new_version = {"name": new_version_name}
|
||||
new_version["images"] = {}
|
||||
|
||||
for disk_type in base_version["images"]:
|
||||
base_filename = base_version["images"][disk_type]["filename"]
|
||||
filename, ok = QtWidgets.QInputDialog.getText(self, "Image", "Disk image filename for {}".format(disk_type), QtWidgets.QLineEdit.Normal, base_filename)
|
||||
if not ok:
|
||||
filename = base_filename
|
||||
new_version["images"][disk_type] = {"filename": filename, "version": new_version_name}
|
||||
|
||||
try:
|
||||
self._appliance.create_new_version(new_version)
|
||||
except ApplianceError as e:
|
||||
|
||||
@@ -237,13 +237,13 @@ class ProjectDialog(QtWidgets.QDialog, Ui_ProjectDialog):
|
||||
"""
|
||||
|
||||
menu = QtWidgets.QMenu()
|
||||
menu.triggered.connect(self._menuTriggeredSlot)
|
||||
if Controller.instance().isRemote():
|
||||
for action in self._main_window.recent_project_actions:
|
||||
menu.addAction(action)
|
||||
else:
|
||||
for action in self._main_window.recent_file_actions:
|
||||
menu.addAction(action)
|
||||
menu.triggered.connect(self._menuTriggeredSlot)
|
||||
menu.exec_(QtGui.QCursor.pos())
|
||||
|
||||
def _overwriteProjectCallback(self, result, error=False, **kwargs):
|
||||
|
||||
@@ -67,7 +67,6 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
|
||||
self.uiRefreshPushButton.clicked.connect(self._refreshVMListSlot)
|
||||
self.uiVmwareRadioButton.clicked.connect(self._listVMwareVMsSlot)
|
||||
self.uiVirtualBoxRadioButton.clicked.connect(self._listVirtualBoxVMsSlot)
|
||||
self.uiVMwareBannerButton.clicked.connect(self._VMwareBannerButtonClickedSlot)
|
||||
settings = parent.settings()
|
||||
self.uiShowCheckBox.setChecked(settings["hide_setup_wizard"])
|
||||
|
||||
@@ -94,11 +93,6 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
|
||||
self.uiLocalServerHostComboBox.addItem("::", "::") # all IPv6 addresses
|
||||
self.uiLocalServerHostComboBox.addItem("0.0.0.0", "0.0.0.0") # all IPv4 addresses
|
||||
|
||||
if sys.platform.startswith("darwin"):
|
||||
self.uiVMwareBannerButton.setIcon(QtGui.QIcon(":/images/vmware_fusion_banner.png"))
|
||||
else:
|
||||
self.uiVMwareBannerButton.setIcon(QtGui.QIcon(":/images/vmware_workstation_banner.png"))
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
self.uiLocalRadioButton.setChecked(True)
|
||||
self.uiLocalLabel.setText("Dependencies like Dynamips and Qemu must be manually installed")
|
||||
@@ -121,13 +115,6 @@ class SetupWizard(QtWidgets.QWizard, Ui_SetupWizard):
|
||||
|
||||
self.uiLocalServerPathLineEdit.setText(path)
|
||||
|
||||
def _VMwareBannerButtonClickedSlot(self):
|
||||
if sys.platform.startswith("darwin"):
|
||||
url = "http://send.onenetworkdirect.net/z/621395/CD225091/"
|
||||
else:
|
||||
url = "http://send.onenetworkdirect.net/z/616207/CD225091/"
|
||||
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url))
|
||||
|
||||
def _listVMwareVMsSlot(self):
|
||||
"""
|
||||
Slot to refresh the VMware VMs list.
|
||||
|
||||
@@ -527,13 +527,12 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
|
||||
if is_not_link and is_not_logo and not self._adding_link:
|
||||
if item and not sip.isdeleted(item):
|
||||
# Right clicking on a selected item must de-select all other items
|
||||
# excepting if CRTL is pressed
|
||||
item.setSelected(True)
|
||||
if not event.modifiers() & QtCore.Qt.ControlModifier:
|
||||
for it in self.scene().items():
|
||||
if item != it and it.isSelected():
|
||||
# Prevent right clicking on a selected item from de-selecting all other items
|
||||
if not item.isSelected():
|
||||
if not event.modifiers() & QtCore.Qt.ControlModifier:
|
||||
for it in self.scene().items():
|
||||
it.setSelected(False)
|
||||
item.setSelected(True)
|
||||
self._showDeviceContextualMenu(event.globalPos())
|
||||
# when more than one item is selected display the contextual menu even if mouse is not above an item
|
||||
elif len(self.scene().selectedItems()) > 1:
|
||||
@@ -755,6 +754,11 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
self.populateDeviceContextualMenu(menu)
|
||||
menu.exec_(pos)
|
||||
menu.clear()
|
||||
# Make sure to deselect all items.
|
||||
# This is to prevent a bug on Windows
|
||||
# see https://github.com/GNS3/gns3-gui/issues/2986
|
||||
for it in self.scene().items():
|
||||
it.setSelected(False)
|
||||
|
||||
def populateDeviceContextualMenu(self, menu):
|
||||
"""
|
||||
|
||||
@@ -212,14 +212,13 @@ class DrawingItem:
|
||||
self._project.delete("/drawings/" + self._id, None, body=self.__json__())
|
||||
|
||||
def itemChange(self, change, value):
|
||||
if change == QtWidgets.QGraphicsItem.ItemPositionHasChanged and self.isActive() and self._main_window.uiSnapToGridAction.isChecked():
|
||||
|
||||
if change == QtWidgets.QGraphicsItem.ItemPositionChange and self.isActive() and self._main_window.uiSnapToGridAction.isChecked():
|
||||
grid_size = self._graphics_view.drawingGridSize()
|
||||
mid_x = self.boundingRect().width() / 2
|
||||
tmp_x = (grid_size * round((self.x() + mid_x) / grid_size)) - mid_x
|
||||
value.setX((grid_size * round((value.x() + mid_x) / grid_size)) - mid_x)
|
||||
mid_y = self.boundingRect().height() / 2
|
||||
tmp_y = (grid_size * round((self.y() + mid_y) / grid_size)) - mid_y
|
||||
if tmp_x != self.x() and tmp_y != self.y():
|
||||
self.setPos(tmp_x, tmp_y)
|
||||
value.setY((grid_size * round((value.y()+mid_y)/grid_size)) - mid_y)
|
||||
|
||||
if change == QtWidgets.QGraphicsItem.ItemSelectedChange:
|
||||
if not value:
|
||||
|
||||
@@ -255,8 +255,7 @@ def main():
|
||||
current_year = datetime.date.today().year
|
||||
log.info("GNS3 GUI version {}".format(__version__))
|
||||
log.info("Copyright (c) 2007-{} GNS3 Technologies Inc.".format(current_year))
|
||||
|
||||
log.info("Application started with {}".format("".join(sys.argv)))
|
||||
log.info("Application started with {}".format(" ".join(sys.argv)))
|
||||
|
||||
# update the exception file path to have it in the same directory as the settings file.
|
||||
exception_file_path = os.path.join(LocalConfig.instance().configDirectory(), exception_file_path)
|
||||
|
||||
@@ -1185,8 +1185,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
|
||||
# restore debug level
|
||||
if self._settings["debug_level"]:
|
||||
print("Activating debugging (use command 'debug 0' to deactivate)")
|
||||
root = logging.getLogger()
|
||||
root.addHandler(logging.StreamHandler(sys.stdout))
|
||||
root.setLevel(logging.DEBUG)
|
||||
|
||||
# restore the style
|
||||
self._setStyle(self._settings.get("style"))
|
||||
|
||||
@@ -654,7 +654,7 @@ class Node(BaseNode):
|
||||
"""
|
||||
|
||||
host = self.settings()["console_host"]
|
||||
if host is None or host == "::" or host == "0.0.0.0":
|
||||
if host is None or host == "::" or host == "0.0.0.0" or host == "0:0:0:0:0:0:0:0":
|
||||
host = Controller.instance().host()
|
||||
return host
|
||||
|
||||
|
||||
@@ -115,10 +115,13 @@ class LogQMessageBox(QtWidgets.QMessageBox):
|
||||
show a stack trace when a critical message box is shown in debug mode
|
||||
"""
|
||||
@staticmethod
|
||||
def critical(parent, title, message, *args):
|
||||
def critical(parent, title, message, *args, show_stack_info=False):
|
||||
if message.startswith("QXcbConnection"): # Qt noise not relevant
|
||||
return
|
||||
LogQMessageBox._get_logger().critical(re.sub(r"<[^<]+?>", "", message), stack_info=LogQMessageBox.stack_info())
|
||||
stack_info = None
|
||||
if show_stack_info:
|
||||
stack_info = LogQMessageBox.stack_info()
|
||||
LogQMessageBox._get_logger().critical(re.sub(r"<[^<]+?>", "", message), stack_info=stack_info)
|
||||
if parent is False:
|
||||
# special case to display a QMessageBox before the main window is created.
|
||||
parent = None
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import json
|
||||
import copy
|
||||
import os
|
||||
import collections
|
||||
import collections.abc
|
||||
import jsonschema
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class ApplianceError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Appliance(collections.Mapping):
|
||||
class Appliance(collections.abc.Mapping):
|
||||
|
||||
def __init__(self, registry, path):
|
||||
"""
|
||||
@@ -115,22 +115,14 @@ class Appliance(collections.Mapping):
|
||||
if not found:
|
||||
raise ApplianceError("Broken appliance missing file {} for version {}".format(filename, version["name"]))
|
||||
|
||||
def create_new_version(self, version_name):
|
||||
def create_new_version(self, new_version):
|
||||
"""
|
||||
Duplicate a version in order to create a new version
|
||||
"""
|
||||
if 'versions' not in self._appliance.keys() or not self._appliance["versions"]:
|
||||
|
||||
if "versions" not in self._appliance.keys() or not self._appliance["versions"]:
|
||||
raise ApplianceError("Your appliance file doesn't contain any versions")
|
||||
|
||||
ref = self._appliance["versions"][0]
|
||||
new_version = {'name': version_name}
|
||||
new_version['images'] = {}
|
||||
|
||||
for disk_type in ref['images']:
|
||||
filename = ref['images'][disk_type]['filename']
|
||||
filename = filename.replace(ref['images'][disk_type]['version'], version_name)
|
||||
new_version['images'][disk_type] = {'filename': filename, 'version': version_name}
|
||||
self._appliance['versions'].append(new_version)
|
||||
self._appliance["versions"].append(new_version)
|
||||
|
||||
def search_images_for_version(self, version_name):
|
||||
"""
|
||||
|
||||
@@ -178,8 +178,9 @@ class ApplianceToTemplate:
|
||||
if symbol_id.startswith(":/symbols/"):
|
||||
return symbol_id
|
||||
|
||||
controller = Controller.instance()
|
||||
path = os.path.join(Config().symbols_dir, symbol_id)
|
||||
if os.path.exists(path):
|
||||
if not controller.isRemote() and os.path.exists(path):
|
||||
return os.path.basename(path)
|
||||
|
||||
if controller_symbols:
|
||||
@@ -197,7 +198,6 @@ class ApplianceToTemplate:
|
||||
url = "https://raw.githubusercontent.com/GNS3/gns3-registry/master/symbols/{}".format(symbol_id)
|
||||
try:
|
||||
self._downloadApplianceSymbol(url, path)
|
||||
controller = Controller.instance()
|
||||
controller.clearStaticCache()
|
||||
if controller.isRemote():
|
||||
controller.uploadSymbol(symbol_id, path)
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1081</width>
|
||||
<height>534</height>
|
||||
<width>1104</width>
|
||||
<height>665</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -234,33 +234,6 @@
|
||||
<string>In order to run the GNS3 VM you must first have VMware or VirtualBox installed and the GNS3 VM.ova imported with one of these software.</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiVirtualizationSoftwarLabel">
|
||||
<property name="text">
|
||||
<string>Virtualization software:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="4">
|
||||
<widget class="QPushButton" name="uiVMwareBannerButton">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../resources/resources.qrc">
|
||||
<normaloff>:/images/vmware_fusion_banner.png</normaloff>:/images/vmware_fusion_banner.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="uiVmwareRadioButton">
|
||||
<property name="toolTip">
|
||||
@@ -274,18 +247,12 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiVirtualizationSoftwarLabel">
|
||||
<property name="text">
|
||||
<string>Virtualization software:</string>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>317</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QRadioButton" name="uiVirtualBoxRadioButton">
|
||||
@@ -328,7 +295,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="3">
|
||||
<item row="6" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="uiVMListComboBox">
|
||||
@@ -349,7 +316,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="3">
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QSpinBox" name="uiCPUSpinBox">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
@@ -362,7 +329,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="3">
|
||||
<item row="10" column="0" colspan="2">
|
||||
<widget class="QSpinBox" name="uiRAMSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/setup_wizard.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.13.0
|
||||
# Created by: PyQt5 UI code generator 5.15.0
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
@@ -13,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
class Ui_SetupWizard(object):
|
||||
def setupUi(self, SetupWizard):
|
||||
SetupWizard.setObjectName("SetupWizard")
|
||||
SetupWizard.resize(1081, 534)
|
||||
SetupWizard.resize(1104, 665)
|
||||
SetupWizard.setModal(True)
|
||||
SetupWizard.setWizardStyle(QtWidgets.QWizard.ModernStyle)
|
||||
SetupWizard.setOptions(QtWidgets.QWizard.NoBackButtonOnStartPage)
|
||||
@@ -114,24 +115,13 @@ class Ui_SetupWizard(object):
|
||||
self.uiVMWizardPage.setObjectName("uiVMWizardPage")
|
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.uiVMWizardPage)
|
||||
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||
self.uiVirtualizationSoftwarLabel = QtWidgets.QLabel(self.uiVMWizardPage)
|
||||
self.uiVirtualizationSoftwarLabel.setObjectName("uiVirtualizationSoftwarLabel")
|
||||
self.gridLayout_3.addWidget(self.uiVirtualizationSoftwarLabel, 0, 0, 1, 1)
|
||||
self.uiVMwareBannerButton = QtWidgets.QPushButton(self.uiVMWizardPage)
|
||||
self.uiVMwareBannerButton.setText("")
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(":/images/vmware_fusion_banner.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.uiVMwareBannerButton.setIcon(icon)
|
||||
self.uiVMwareBannerButton.setIconSize(QtCore.QSize(300, 150))
|
||||
self.uiVMwareBannerButton.setFlat(True)
|
||||
self.uiVMwareBannerButton.setObjectName("uiVMwareBannerButton")
|
||||
self.gridLayout_3.addWidget(self.uiVMwareBannerButton, 0, 2, 4, 1)
|
||||
self.uiVmwareRadioButton = QtWidgets.QRadioButton(self.uiVMWizardPage)
|
||||
self.uiVmwareRadioButton.setChecked(True)
|
||||
self.uiVmwareRadioButton.setObjectName("uiVmwareRadioButton")
|
||||
self.gridLayout_3.addWidget(self.uiVmwareRadioButton, 1, 0, 1, 1)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(317, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.gridLayout_3.addItem(spacerItem1, 1, 1, 1, 1)
|
||||
self.uiVirtualizationSoftwarLabel = QtWidgets.QLabel(self.uiVMWizardPage)
|
||||
self.uiVirtualizationSoftwarLabel.setObjectName("uiVirtualizationSoftwarLabel")
|
||||
self.gridLayout_3.addWidget(self.uiVirtualizationSoftwarLabel, 0, 0, 1, 1)
|
||||
self.uiVirtualBoxRadioButton = QtWidgets.QRadioButton(self.uiVMWizardPage)
|
||||
self.uiVirtualBoxRadioButton.setObjectName("uiVirtualBoxRadioButton")
|
||||
self.gridLayout_3.addWidget(self.uiVirtualBoxRadioButton, 2, 0, 1, 1)
|
||||
@@ -161,13 +151,13 @@ class Ui_SetupWizard(object):
|
||||
self.uiRefreshPushButton = QtWidgets.QPushButton(self.uiVMWizardPage)
|
||||
self.uiRefreshPushButton.setObjectName("uiRefreshPushButton")
|
||||
self.horizontalLayout.addWidget(self.uiRefreshPushButton)
|
||||
self.gridLayout_3.addLayout(self.horizontalLayout, 6, 0, 1, 3)
|
||||
self.gridLayout_3.addLayout(self.horizontalLayout, 6, 0, 1, 2)
|
||||
self.uiCPUSpinBox = QtWidgets.QSpinBox(self.uiVMWizardPage)
|
||||
self.uiCPUSpinBox.setMinimum(1)
|
||||
self.uiCPUSpinBox.setMaximum(128)
|
||||
self.uiCPUSpinBox.setProperty("value", 1)
|
||||
self.uiCPUSpinBox.setObjectName("uiCPUSpinBox")
|
||||
self.gridLayout_3.addWidget(self.uiCPUSpinBox, 8, 0, 1, 3)
|
||||
self.gridLayout_3.addWidget(self.uiCPUSpinBox, 8, 0, 1, 2)
|
||||
self.uiRAMSpinBox = QtWidgets.QSpinBox(self.uiVMWizardPage)
|
||||
self.uiRAMSpinBox.setEnabled(True)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
@@ -180,7 +170,7 @@ class Ui_SetupWizard(object):
|
||||
self.uiRAMSpinBox.setSingleStep(512)
|
||||
self.uiRAMSpinBox.setProperty("value", 2048)
|
||||
self.uiRAMSpinBox.setObjectName("uiRAMSpinBox")
|
||||
self.gridLayout_3.addWidget(self.uiRAMSpinBox, 10, 0, 1, 3)
|
||||
self.gridLayout_3.addWidget(self.uiRAMSpinBox, 10, 0, 1, 2)
|
||||
SetupWizard.addPage(self.uiVMWizardPage)
|
||||
self.uiRemoteControllerWizardPage = QtWidgets.QWizardPage()
|
||||
self.uiRemoteControllerWizardPage.setObjectName("uiRemoteControllerWizardPage")
|
||||
@@ -260,9 +250,9 @@ class Ui_SetupWizard(object):
|
||||
self.uiLocalServerStatusWizardPage.setSubTitle(_translate("SetupWizard", "Validation of the configuration for the local server"))
|
||||
self.uiVMWizardPage.setTitle(_translate("SetupWizard", "GNS3 VM"))
|
||||
self.uiVMWizardPage.setSubTitle(_translate("SetupWizard", "In order to run the GNS3 VM you must first have VMware or VirtualBox installed and the GNS3 VM.ova imported with one of these software."))
|
||||
self.uiVirtualizationSoftwarLabel.setText(_translate("SetupWizard", "Virtualization software:"))
|
||||
self.uiVmwareRadioButton.setToolTip(_translate("SetupWizard", "VMware is recommended to run Qemu based appliances (required for KVM)."))
|
||||
self.uiVmwareRadioButton.setText(_translate("SetupWizard", "VMware (recommended)"))
|
||||
self.uiVirtualizationSoftwarLabel.setText(_translate("SetupWizard", "Virtualization software:"))
|
||||
self.uiVirtualBoxRadioButton.setToolTip(_translate("SetupWizard", "Use VirtualBox if you intend to only use Dynamips, IOU or VPCS."))
|
||||
self.uiVirtualBoxRadioButton.setText(_translate("SetupWizard", "VirtualBox"))
|
||||
self.uiVMNameLabel.setText(_translate("SetupWizard", "VM name:"))
|
||||
|
||||
@@ -23,10 +23,9 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "2.2.9"
|
||||
__version_info__ = (2, 2, 9, 0)
|
||||
__version__ = "2.2.15"
|
||||
__version_info__ = (2, 2, 15, 0)
|
||||
|
||||
# If it's a git checkout try to add the commit
|
||||
if "dev" in __version__:
|
||||
try:
|
||||
import os
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
-rrequirements.txt
|
||||
|
||||
#PyQt5==5.7
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
jsonschema==3.2.0; python_version >= '3.8' # pyup: ignore
|
||||
jsonschema==2.6.0; python_version < '3.8' # pyup: ignore
|
||||
jsonschema==3.2.0
|
||||
sentry-sdk>=0.14.4
|
||||
psutil==5.6.6
|
||||
psutil==5.6.7
|
||||
distro>=1.3.0
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 38 KiB |
@@ -326,8 +326,6 @@
|
||||
<file>charcoal_icons/filter-hover.svg</file>
|
||||
<file>charcoal_icons/filter-reset.svg</file>
|
||||
<file>charcoal_icons/filter-reset-hover.svg</file>
|
||||
<file>images/vmware_fusion_banner.png</file>
|
||||
<file>images/vmware_workstation_banner.png</file>
|
||||
<file>styles/charcoal.css</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo '
|
||||
_______ ________ _______ ______
|
||||
| \ | \| \ / \
|
||||
| $$$$$$$\| $$$$$$$$| $$$$$$$\| $$$$$$\
|
||||
| $$__/ $$| $$__ | $$__/ $$| $$__/ $$
|
||||
| $$ $$| $$ \ | $$ $$ >$$ $$
|
||||
| $$$$$$$ | $$$$$ | $$$$$$$ | $$$$$$
|
||||
| $$ | $$_____ | $$ | $$__/ $$
|
||||
| $$ | $$ \| $$ \$$ $$
|
||||
\$$ \$$$$$$$$ \$$ \$$$$$$
|
||||
|
||||
'
|
||||
|
||||
|
||||
find . -name '*.py' -exec autopep8 --in-place -v --aggressive --aggressive \{\} \;
|
||||
|
||||
echo "It's clean"
|
||||
12
setup.py
12
setup.py
@@ -24,7 +24,7 @@ if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 4)
|
||||
raise SystemExit("Python 3.4 or higher is required")
|
||||
|
||||
|
||||
class Tox(TestCommand):
|
||||
class PyTest(TestCommand):
|
||||
|
||||
def finalize_options(self):
|
||||
TestCommand.finalize_options(self)
|
||||
@@ -33,10 +33,10 @@ class Tox(TestCommand):
|
||||
|
||||
def run_tests(self):
|
||||
# import here, cause outside the eggs aren't loaded
|
||||
import tox
|
||||
errcode = tox.cmdline(self.test_args)
|
||||
sys.exit(errcode)
|
||||
import pytest
|
||||
|
||||
errcode = pytest.main(self.test_args)
|
||||
sys.exit(errcode)
|
||||
|
||||
if sys.platform.startswith('linux'):
|
||||
data_files = [
|
||||
@@ -61,8 +61,8 @@ setup(
|
||||
version=__import__("gns3").__version__,
|
||||
url="http://github.com/GNS3/gns3-gui",
|
||||
license="GNU General Public License v3 (GPLv3)",
|
||||
tests_require=["tox"],
|
||||
cmdclass={"test": Tox},
|
||||
tests_require=["pytest"],
|
||||
cmdclass={"test": PyTest},
|
||||
author="Jeremy Grossmann",
|
||||
author_email="package-maintainer@gns3.net",
|
||||
description="GNS3 graphical interface for the GNS3 server.",
|
||||
|
||||
@@ -171,8 +171,8 @@ def test_create_new_version():
|
||||
os.path.dirname(__file__), "appliances", "microcore-linux.gns3a")
|
||||
|
||||
a = Appliance(registry, appliance_path)
|
||||
|
||||
a.create_new_version("42.0")
|
||||
new_version = {'images': {'hda_disk_image': {'filename': 'linux-microcore-42.0.img', 'version': '42.0'}}, 'name': '42.0'}
|
||||
a.create_new_version(new_version)
|
||||
v = a['versions'][-1:][0]
|
||||
assert v == {
|
||||
'images':
|
||||
|
||||
@@ -22,6 +22,7 @@ import json
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from gns3.local_config import LocalConfig
|
||||
from gns3.version import __version_info__
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -119,16 +120,17 @@ def test_migrateOldConfigOSX(tmpdir):
|
||||
|
||||
local_config = LocalConfig()
|
||||
|
||||
assert os.path.exists(str(tmpdir / '.config' / 'GNS3'))
|
||||
assert os.path.exists(str(tmpdir / '.config' / 'GNS3' / 'hello'))
|
||||
version = "{}.{}".format(__version_info__[0], __version_info__[1])
|
||||
assert os.path.exists(str(tmpdir / '.config' / 'GNS3' / version))
|
||||
assert os.path.exists(str(tmpdir / '.config' / 'GNS3' / version / 'hello'))
|
||||
assert os.path.exists(str(tmpdir / '.config' / 'gns3.net'))
|
||||
|
||||
# It should migrate only one time
|
||||
open(str(tmpdir / '.config' / 'gns3.net' / 'world'), 'w+').close()
|
||||
|
||||
local_config._migrateOldConfigPath()
|
||||
assert os.path.exists(str(tmpdir / '.config' / 'GNS3' / 'hello'))
|
||||
assert not os.path.exists(str(tmpdir / '.config' / 'GNS3' / 'world'))
|
||||
assert os.path.exists(str(tmpdir / '.config' / 'GNS3' / version / 'hello'))
|
||||
assert not os.path.exists(str(tmpdir / '.config' / 'GNS3' / version / 'world'))
|
||||
|
||||
|
||||
def test_migrate13Config(tmpdir):
|
||||
|
||||
19
tox.ini
19
tox.ini
@@ -1,19 +0,0 @@
|
||||
[tox]
|
||||
envlist = py34
|
||||
|
||||
[testenv]
|
||||
sitepackages=True
|
||||
setenv = PYTHONPATH={toxinidir}
|
||||
commands = py.test
|
||||
|
||||
[pep8]
|
||||
ignore = E501,E402
|
||||
|
||||
[flake8]
|
||||
ignore = E265,E501
|
||||
exclude = tests/*,gns3/ui/*,./gns3/modules/*/ui
|
||||
|
||||
[pytest]
|
||||
python_paths = {toxinidir}
|
||||
norecursedirs = .tox
|
||||
timeout = 10
|
||||
Reference in New Issue
Block a user