Example #1
0
    def package_import(self, pack: str):
        """
        Import opsi package file into development folder and open it, if successful

        :param pack: package file path
        """
        self.logger.debug("Importing package")

        if self._active_project:
            if not self.project_close():
                return

            self.reset_state()

        # extract product id from package path
        file = Helper.get_file_from_path(pack)
        product = file[:file.rfind(
            "_"
        )]  # remove everything behind product name (version, file extension, etc.)
        project = Helper.concat_path_native(ConfigHandler.cfg.dev_dir, product)

        # import
        try:
            self.startup.hide_me()
            self.do_import(pack)
        except:
            self.logger.error("Package import unsuccessful!")
        else:
            # open
            try:
                self.project_load(project)
            except:
                self.logger.err("Imported package could not be opened!")
Example #2
0
    def package_import(self, pack: str):
        """
        Import opsi package file into development folder and open it, if successful

        :param pack: package file path
        """
        self.logger.debug("Importing package")

        if self._active_project:
            if not self.project_close():
                return

            self.reset_state()

        # extract product id from package path
        file = Helper.get_file_from_path(pack)
        product = file[:file.rfind("_")]  # remove everything behind product name (version, file extension, etc.)
        project = Helper.concat_path_native(ConfigHandler.cfg.dev_dir, product)

        # import
        try:
            self.startup.hide_me()
            self.do_import(pack)
        except:
            self.logger.error("Package import unsuccessful!")
        else:
            # open
            try:
                self.project_load(project)
            except:
                self.logger.err("Imported package could not be opened!")
Example #3
0
 def create_project_paths(self, base):
     for elem in oPB.BASE_FOLDERS:
         try:
             path = Path(Helper.concat_path_native(base, elem))
             if not path.exists():
                 path.mkdir(parents=True)
         except OSError:
             raise
Example #4
0
 def create_project_paths(self, base):
     for elem in oPB.BASE_FOLDERS:
         try:
             path = Path(Helper.concat_path_native(base, elem))
             if not path.exists():
                 path.mkdir(parents=True)
         except OSError:
             raise
Example #5
0
    def __init__(self, parent=None, applangprefix=""):
        """
        Constructor of Translator class

        :param parent: parent, mostly qApp
        :param applangprefix: application language file prefix
        """

        if Translator.cfg is None:
            Translator.cfg = self

            Translator.cfg._parent = parent

            super().__init__(Translator.cfg._parent)

            Translator.cfg._qt_local_path = None
            Translator.cfg._app_locale_path = None
            Translator.cfg._syslocale = None
            Translator.cfg._current_lang = "en"
            Translator.cfg.applangprefix = applangprefix

            Translator.cfg._combobox = None
            Translator.cfg._dialog = None

            # different translators
            Translator.cfg.translator_qt = None
            Translator.cfg.translator_qtbase = None
            Translator.cfg.translator_qthelp = None
            Translator.cfg.translator_qtmm = None
            Translator.cfg.translator_qtwebengine = None
            Translator.cfg.translator_app = None

            pyqt_path = os.path.dirname(PyQt5.__file__)

            if platform.system() == "Windows":
                Translator.cfg._qt_locale_path = Helper.concat_path_native(
                    pyqt_path, "Qt\\translations")
            else:
                if os.path.isdir("/usr/share/qt5/translations/"):
                    Translator.cfg._qt_locale_path = "/usr/share/qt5/translations/"

                else:
                    # we assume, that library plugin path is sibling to translations path
                    # so let's find the plugins and construct translations path
                    lib_dirs = qApp.libraryPaths()

                    for d in lib_dirs:
                        l = os.path.join(d, "../translations")
                        if os.path.isdir(l):
                            Translator.cfg._qt_locale_path = l
                            break

            Translator.cfg._app_locale_path = ":locale/"
            Translator.cfg._syslocale = QtCore.QLocale().system().name()[:2]
Example #6
0
    def __init__(self, parent = None, applangprefix = ""):
        """
        Constructor of Translator class

        :param parent: parent, mostly qApp
        :param applangprefix: application language file prefix
        """

        if Translator.cfg is None:
            Translator.cfg = self

            Translator.cfg._parent = parent

            super().__init__(Translator.cfg._parent)

            Translator.cfg._qt_local_path = None
            Translator.cfg._app_locale_path = None
            Translator.cfg._syslocale = None
            Translator.cfg._current_lang = "en"
            Translator.cfg.applangprefix = applangprefix

            Translator.cfg._combobox = None
            Translator.cfg._dialog = None

            # different translators
            Translator.cfg.translator_qt = None
            Translator.cfg.translator_qtbase = None
            Translator.cfg.translator_qthelp = None
            Translator.cfg.translator_qtmm = None
            Translator.cfg.translator_qtwebengine = None
            Translator.cfg.translator_app = None

            pyqt_path = os.path.dirname(PyQt5.__file__)

            if platform.system() == "Windows":
                Translator.cfg._qt_locale_path = Helper.concat_path_native(pyqt_path, "Qt\\translations")
            else:
                if os.path.isdir("/usr/share/qt5/translations/"):
                    Translator.cfg._qt_locale_path = "/usr/share/qt5/translations/"

                else:
                    # we assume, that library plugin path is sibling to translations path
                    # so let's find the plugins and construct translations path
                    lib_dirs = qApp.libraryPaths()

                    for d in lib_dirs:
                        l = os.path.join(d, "../translations")
                        if os.path.isdir(l):
                            Translator.cfg._qt_locale_path = l
                            break

            Translator.cfg._app_locale_path = ":locale/"
            Translator.cfg._syslocale = QtCore.QLocale().system().name()[:2]
Example #7
0
    def validate(self, p_str, p_int):
        """
        Validator method

        :param p_str: script full pathname to validate
        :param p_int: (not used)

        :return: tuple(QValidator.state, p_str, p_int)
        """
        if p_str == "":
            return ScriptFileValidator.Intermediate, p_str, p_int
        if os.path.exists(Helper.concat_path_native(self._parent.lblPacketFolder.text().replace('\\','/') + "/CLIENT_DATA/", p_str)):
            return ScriptFileValidator.Acceptable, p_str, p_int
        else:
            return ScriptFileValidator.Invalid, p_str, p_int
Example #8
0
    def select_keyfile(self):
        """SSH keyfile selector dialog"""
        self.logger.debug("Select SSH keyfile dialog")

        ext = "Private key file (" + (" ").join(["*." + x for x in oPB.KEYFILE_EXT]) + ")"  # generate file extension selection string for dialog

        script = QFileDialog.getOpenFileName(self, translate("SettingsDialog", "Choose keyfile"),
                                            ConfigHandler.cfg.dev_dir, ext)

        if not script == ("", ""):
            self.logger.debug("Selected SSH keyfile: " + script[0])
            self.inpKeyFile.setText(Helper.concat_path_native(script[0], ""))
            self.dataChanged.emit()
        else:
            self.logger.debug("Dialog aborted.")
Example #9
0
    def select_dev_dir(self):
        """Development directory selector dialog"""
        self.logger.debug("Select development directory")
        directory = QFileDialog.getExistingDirectory(self, translate("SettingsDialog", "Select development folder"),
                                                     ConfigHandler.cfg.dev_dir, QFileDialog.ShowDirsOnly)

        if not directory == "":
            self.logger.info("Chosen directory: " + directory)
            value = Helper.concat_path_native(directory, "")
            if value[-1:] == "/" or value[-1:] == '\\':
                value = value[:-1]
            self.inpDevFolder.setText(value)
            self.inpLocalShareBase.setText(value)
            self.dataChanged.emit()
        else:
            self.logger.debug("Dialog aborted.")
Example #10
0
    def run_command_line(self):
        """Process project action via command line"""
        self.logger.info("Project given via command line: " + self.args.path)
        if os.path.isabs(self.args.path):
            project = self.args.path
        else:
            project = Helper.concat_path_native(ConfigHandler.cfg.dev_dir, self.args.path)

        # load project
        self.load_backend(project)

        # stop if something happened
        if oPB.EXITCODE != oPB.RET_OK:
            return

        # first, set rights
        if self.args.setrights is True:
            self.do_setrights()
            # wait a short moment for disk flushing
            sleep(0.5)

        # stop if something happened
        if oPB.EXITCODE != oPB.RET_OK:
            return

        # build project
        if self.args.build_mode is not None:
            self.logger.info("Command line: build")
            self.do_build()
            # wait a short moment for disk flushing
            sleep(0.5)

        # stop if something happened
        if oPB.EXITCODE != oPB.RET_OK:
            return

        # install / install+setup / uninstall
        try:
            self.logger.info("Command line: " + self.args.packetaction[0])
            if self.args.packetaction[0] == "install":
                self.do_install(depot = ConfigHandler.cfg.opsi_server)
            if self.args.packetaction[0] == "instsetup":
                self.do_installsetup(depot = ConfigHandler.cfg.opsi_server)
            if self.args.packetaction[0] == "uninstall":
                self.do_uninstall(depot = ConfigHandler.cfg.opsi_server)
        except:
            pass
Example #11
0
    def run_command_line(self):
        """Process project action via command line"""
        self.logger.info("Project given via command line: " + self.args.path)
        if os.path.isabs(self.args.path):
            project = self.args.path
        else:
            project = Helper.concat_path_native(ConfigHandler.cfg.dev_dir, self.args.path)

        # load project
        self.load_backend(project)

        # stop if something happened
        if oPB.EXITCODE != oPB.RET_OK:
            return

        # first, set rights
        if self.args.setrights is True:
            self.do_setrights()
            # wait a short moment for disk flushing
            sleep(0.5)

        # stop if something happened
        if oPB.EXITCODE != oPB.RET_OK:
            return

        # build project
        if self.args.build_mode is not None:
            self.logger.info("Command line: build")
            self.do_build()
            # wait a short moment for disk flushing
            sleep(0.5)

        # stop if something happened
        if oPB.EXITCODE != oPB.RET_OK:
            return

        # install / install+setup / uninstall
        try:
            self.logger.info("Command line: " + self.args.packetaction[0])
            if self.args.packetaction[0] == "install":
                self.do_install(depot = ConfigHandler.cfg.opsi_server)
            if self.args.packetaction[0] == "instsetup":
                self.do_installsetup(depot = ConfigHandler.cfg.opsi_server)
            if self.args.packetaction[0] == "uninstall":
                self.do_uninstall(depot = ConfigHandler.cfg.opsi_server)
        except:
            pass
Example #12
0
    def select_dev_dir(self):
        """Development directory selector dialog"""
        self.logger.debug("Select development directory")
        directory = QFileDialog.getExistingDirectory(
            self, translate("SettingsDialog", "Select development folder"),
            ConfigHandler.cfg.dev_dir, QFileDialog.ShowDirsOnly)

        if not directory == "":
            self.logger.info("Chosen directory: " + directory)
            value = Helper.concat_path_native(directory, "")
            if value[-1:] == "/" or value[-1:] == '\\':
                value = value[:-1]
            self.inpDevFolder.setText(value)
            self.inpLocalShareBase.setText(value)
            self.dataChanged.emit()
        else:
            self.logger.debug("Dialog aborted.")
Example #13
0
    def validate(self, p_str, p_int):
        """
        Validator method

        :param p_str: script full pathname to validate
        :param p_int: (not used)

        :return: tuple(QValidator.state, p_str, p_int)
        """
        if p_str == "":
            return ScriptFileValidator.Intermediate, p_str, p_int
        if os.path.exists(
                Helper.concat_path_native(
                    self._parent.lblPacketFolder.text().replace('\\', '/') +
                    "/CLIENT_DATA/", p_str)):
            return ScriptFileValidator.Acceptable, p_str, p_int
        else:
            return ScriptFileValidator.Invalid, p_str, p_int
Example #14
0
    def select_externaleditor(self):
        """External editor selector dialog"""
        self.logger.debug("Select scripteditor dialog")

        if platform.system() != "Windows":
            ext = "Program (" + (" ").join(["*." + x for x in oPB.PRG_EXT]) + ")"  # generate file extension selection string for dialog
        else:
            ext = "Any (*)"

        script = QFileDialog.getOpenFileName(self, translate("SettingsDialog", "Choose Scripteditor"),
                                            ConfigHandler.cfg.dev_dir, ext)

        if not script == ("", ""):
            self.logger.debug("Selected Scripeditor: " + script[0])
            self.inpExternalEditor.setText(Helper.concat_path_native(script[0], ""))
            self.dataChanged.emit()
        else:
            self.logger.debug("Dialog aborted.")
Example #15
0
    def select_keyfile(self):
        """SSH keyfile selector dialog"""
        self.logger.debug("Select SSH keyfile dialog")

        ext = "Private key file (" + (" ").join([
            "*." + x for x in oPB.KEYFILE_EXT
        ]) + ")"  # generate file extension selection string for dialog

        script = QFileDialog.getOpenFileName(
            self, translate("SettingsDialog", "Choose keyfile"),
            ConfigHandler.cfg.dev_dir, ext)

        if not script == ("", ""):
            self.logger.debug("Selected SSH keyfile: " + script[0])
            self.inpKeyFile.setText(Helper.concat_path_native(script[0], ""))
            self.dataChanged.emit()
        else:
            self.logger.debug("Dialog aborted.")
Example #16
0
    def load_backend(self, project_name):
        """Load project data."""
        # itemChanged signal has to be disconnected temporarily, because
        # if not, dataChanged would be set after loading
        self.logger.info("Load project: " + project_name)

        self._dataLoaded = None

        self.controlData.load_data(Helper.concat_path_native(ConfigHandler.cfg.dev_dir, project_name))

        while self._dataLoaded is None: # _dataLoaded has to be True or False
            pass

        if not self._dataLoaded:
            self.logger.error("Backend data could not be loaded.")
            self.logger.debug("Set exitcode RET_EOPEN")
            oPB.EXITCODE = oPB.RET_EOPEN
            self.msgbox(translate("baseController", "Project could not be loaded!"), oPB.MsgEnum.MS_ERR)
        else:
            self.logger.info("Backend data loaded")
            self.msgbox(translate("mainController", "Project loaded successfully!"), oPB.MsgEnum.MS_STAT)
Example #17
0
    def load_backend(self, project_name):
        """Load project data."""
        # itemChanged signal has to be disconnected temporarily, because
        # if not, dataChanged would be set after loading
        self.logger.info("Load project: " + project_name)

        self._dataLoaded = None

        self.controlData.load_data(Helper.concat_path_native(ConfigHandler.cfg.dev_dir, project_name))

        while self._dataLoaded is None: # _dataLoaded has to be True or False
            pass

        if not self._dataLoaded:
            self.logger.error("Backend data could not be loaded.")
            self.logger.debug("Set exitcode RET_EOPEN")
            oPB.EXITCODE = oPB.RET_EOPEN
            self.msgbox(translate("baseController", "Project could not be loaded!"), oPB.MsgEnum.MS_ERR)
        else:
            self.logger.info("Backend data loaded")
            self.msgbox(translate("baseController", "Project loaded successfully!"), oPB.MsgEnum.MS_STAT)
Example #18
0
    def select_externaleditor(self):
        """External editor selector dialog"""
        self.logger.debug("Select scripteditor dialog")

        if platform.system() != "Windows":
            ext = "Program (" + (" ").join([
                "*." + x for x in oPB.PRG_EXT
            ]) + ")"  # generate file extension selection string for dialog
        else:
            ext = "Any (*)"

        script = QFileDialog.getOpenFileName(
            self, translate("SettingsDialog", "Choose Scripteditor"),
            ConfigHandler.cfg.dev_dir, ext)

        if not script == ("", ""):
            self.logger.debug("Selected Scripeditor: " + script[0])
            self.inpExternalEditor.setText(
                Helper.concat_path_native(script[0], ""))
            self.dataChanged.emit()
        else:
            self.logger.debug("Dialog aborted.")
Example #19
0
    def select_logfile(self):
        """Logfile selector dialog"""
        self.logger.debug("Select log file dialog")

        """
        ext = "Log (*.log)"  # generate file extension selection string for dialog

        script = QFileDialog.getOpenFileName(self, translate("SettingsDialog", "Choose folder for logfile"),
                                             ConfigHandler.cfg.log_file, ext)

        if not script == ("", ""):
            self.logger.debug("Selected Logile: " + script[0])
        """

        directory = QFileDialog.getExistingDirectory(self, translate("SettingsDialog", "Select logfile folder"),
                                                     ConfigHandler.cfg.dev_dir, QFileDialog.ShowDirsOnly)

        if not directory == "":
            self.logger.info("Chosen directory: " + directory)
            self.inpLogFile.setText(Helper.concat_path_native(directory, "opb-session.log"))
            self.dataChanged.emit()
        else:
            self.logger.debug("Dialog aborted.")
Example #20
0
    def select_script_dialog(self, script_type, setvalue = True):
        """
        Opens a dialog to select a script file or clear field content

        :param script_type: field type identifier (setup, uninstall, update, always, once, custom, userlogin)
        :param setvalue: set new value = True, empty field only = False
        """
        self.logger.debug("Select script dialog")

        ext = "Scripts (" + " ".join(["*." + x for x in oPB.SCRIPT_EXT]) + ")"  # generate file extension selection string for dialog

        if setvalue:
            if self.lblPacketFolder.text() == "":
                script = QFileDialog.getOpenFileName(self, translate("MainWindow", "Choose script"),
                                                     ConfigHandler.cfg.dev_dir, ext)
            else:
                script = QFileDialog.getOpenFileName(self, translate("MainWindow", "Choose script"),
                                                     Helper.concat_path_native(self.lblPacketFolder.text(), "CLIENT_DATA"), ext)

            if not script == ("", ""):
                self._parent.set_selected_script(script[0], script_type)
        else:
            self._parent.set_selected_script("", script_type)
Example #21
0
    def select_logfile(self):
        """Logfile selector dialog"""
        self.logger.debug("Select log file dialog")
        """
        ext = "Log (*.log)"  # generate file extension selection string for dialog

        script = QFileDialog.getOpenFileName(self, translate("SettingsDialog", "Choose folder for logfile"),
                                             ConfigHandler.cfg.log_file, ext)

        if not script == ("", ""):
            self.logger.debug("Selected Logile: " + script[0])
        """

        directory = QFileDialog.getExistingDirectory(
            self, translate("SettingsDialog", "Select logfile folder"),
            ConfigHandler.cfg.dev_dir, QFileDialog.ShowDirsOnly)

        if not directory == "":
            self.logger.info("Chosen directory: " + directory)
            self.inpLogFile.setText(
                Helper.concat_path_native(directory, "opb-session.log"))
            self.dataChanged.emit()
        else:
            self.logger.debug("Dialog aborted.")
Example #22
0
    def open_scripteditor(self):
        """Open script editor after double click on tree view item"""

        self.logger.debug("Start scripteditor")

        idx = self.treeView.currentIndex()
        if idx.isValid():
            sibling = idx.sibling(idx.row(), idx.column() + 1)
            item = self.model.itemFromIndex(sibling)
            script = item.text()

        if "(External)" in script:
            self._parent.msgbox(
                translate(
                    "MainWindow",
                    "Sorry! You cannot edit a script outside the project folder!"
                ), oPB.MsgEnum.MS_ERR, self)
            return

        if ConfigHandler.cfg.editor_intern == "True":
            self._parent.msgbox(
                translate(
                    "MainWindow",
                    "Internal editor not available at the moment. Use external editor instead!"
                ), oPB.MsgEnum.MS_ALWAYS, self)
            self._parentUi.actionSettings.trigger()
            return

        if os.path.exists(ConfigHandler.cfg.scripteditor):
            path = Helper.concat_path_native(
                self._parentUi.lblPacketFolder.text(), "CLIENT_DATA")

            path = Helper.concat_path_native(path, script)

            self.logger.debug("Opening script: " + path)
            cmd = [ConfigHandler.cfg.scripteditor]
            if (ConfigHandler.cfg.editor_options).strip() != "":
                for part in (ConfigHandler.cfg.editor_options).split():
                    cmd.append(part)
                if ConfigHandler.cfg.editor_attachdirect == "True":
                    cmd[-1] = cmd[-1] + path
                else:
                    cmd.append(path)
            else:
                cmd.append(path)

            self.logger.debug("Executing subprocess: " + str(cmd))
            proc = subprocess.Popen(cmd,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE,
                                    universal_newlines=True)
            outs, errs = proc.communicate()
            self.logger.info(outs)
            self.logger.error(errs)
            if proc.returncode != 0:
                self._parent.msgbox(
                    translate(
                        "MainWindow",
                        "Editor startup did not cleanup correctly.\n\nThe following message(s) returned:"
                    ) + "\n\nStandard Out:\n" + outs + "\n\nStandard Err:\n" +
                    errs, oPB.MsgEnum.MS_WARN, self)

        else:
            self._parent.msgbox(
                translate(
                    "MainWindow", "Editor not found:" + " " +
                    ConfigHandler.cfg.scripteditor), oPB.MsgEnum.MS_ERR, self)
Example #23
0
    def project_copy(self, project_folder):
        """
        Copies current project data to new project destination

        :param destination: destination for copied project
        """

        dest_data = ""
        val = 0

        def sizeof_fmt(num, suffix='B'):
            for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
                if abs(num) < 1024.0:
                    return "%3.1f%s%s" % (num, unit, suffix)
                num /= 1024.0
            return "%.1f%s%s" % (num, 'Yi', suffix)

        def copy2_(src, dst):
            self.logger.debug("Copying to destination file: " + str(dst))
            self.msgbox("CLIENT_DATA: " + str(dst).replace(dest_data, ""), oPB.MsgEnum.MS_STAT)
            self.progressChanged.emit(val)
            shutil.copy2(src,dst)

        def countFiles(directory):
            files = []
            total_size = 0
            if os.path.isdir(directory):
                for path, dirs, filenames in os.walk(directory):
                    files.extend(filenames)
                    for f in filenames:
                        fp = os.path.join(path, f)
                        total_size += os.path.getsize(fp)

            return len(files), total_size

        def copyDirectory(src, dest):
            self.logger.info("Copying files")
            self.logger.debug("Source: " + src)
            self.logger.debug("Destination:" + dest)
            if os.path.exists(dest):
                shutil.rmtree(dest)
            try:
                shutil.copytree(src, dest, copy_function=copy2_)
            # Directories are the same
            except shutil.Error as e:
                self.logger.error('Directory not copied. Error: %s' % e)
            # Any error saying that the directory doesn't exist
            except OSError as e:
                self.logger.error('Directory not copied. Error: %s' % e)

        self.logger.info("Create new project from current: " + project_folder)

        # create new control object as copy

        if os.path.exists(Helper.concat_path_native(project_folder, "CLIENT_DATA")):
            self.logger.error("CLIENT_DATA subdirectory in destination folder detected. This is not allowed for security reason!")
            self.msgbox(translate("mainController", "CLIENT_DATA subdirectory in destination folder detected. This is not allowed for security reason!"),
                        oPB.MsgEnum.MS_ERR)
            return

        newControl = deepcopy(self.controlData)
        self.create_project_paths(project_folder)
        project_name = PurePath(project_folder).name.replace(" ","_")
        newControl.id = project_name
        newControl.projectfolder = project_folder

        # add changelog entry for this copy process
        text = "Project copied from: " + self.controlData.packagename
        newentry = ChangelogEntry(newControl.id)
        newentry.version = "(" + newControl.productversion + "-" + newControl.packageversion + ")"
        newentry.status = oPB.CHLOG_STATI[0]
        newentry.urgency = oPB.CHLOG_BLOCKMARKER + oPB.CHLOG_URGENCIES[0]
        newentry.text = "\n" + text + changelog_footer()
        newControl.changelog_append(newentry)

        try:
            self.processingStarted.emit()

            newControl.save_data()
            self.logger.debug("New control data saved.")

            dest_data = Helper.concat_path_native(newControl.projectfolder, "CLIENT_DATA")
            total, total_size = countFiles(Helper.concat_path_native(self.controlData.projectfolder, "CLIENT_DATA"))
            val = 100 / total

            reply = self.msgbox(translate("mainController", "Copy files now? This can't be canceled.") + "\n\nTotal: " +  str(total) + "\n" + sizeof_fmt(total_size),
                                oPB.MsgEnum.MS_QUEST_YESNO)
            if reply is True:
                copyDirectory(Helper.concat_path_native(self.controlData.projectfolder, "CLIENT_DATA"),
                              Helper.concat_path_native(newControl.projectfolder, "CLIENT_DATA")
                              )
                self.logger.debug("Files copied.")

            self.processingEnded.emit(True)

            # close current project an re-open clone
            if not self.project_close():
                return

            self.project_load(project_name)
        except:
            self.logger.error("Project could not be copied and re-opened.")
Example #24
0
    def project_copy(self, project_folder):
        """
        Copies current project data to new project destination

        :param destination: destination for copied project
        """

        dest_data = ""
        val = 0

        def sizeof_fmt(num, suffix='B'):
            for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
                if abs(num) < 1024.0:
                    return "%3.1f%s%s" % (num, unit, suffix)
                num /= 1024.0
            return "%.1f%s%s" % (num, 'Yi', suffix)

        def copy2_(src, dst):
            self.logger.debug("Copying to destination file: " + str(dst))
            self.msgbox("CLIENT_DATA: " + str(dst).replace(dest_data, ""),
                        oPB.MsgEnum.MS_STAT)
            self.progressChanged.emit(val)
            shutil.copy2(src, dst)

        def countFiles(directory):
            files = []
            total_size = 0
            if os.path.isdir(directory):
                for path, dirs, filenames in os.walk(directory):
                    files.extend(filenames)
                    for f in filenames:
                        fp = os.path.join(path, f)
                        total_size += os.path.getsize(fp)

            return len(files), total_size

        def copyDirectory(src, dest):
            self.logger.info("Copying files")
            self.logger.debug("Source: " + src)
            self.logger.debug("Destination:" + dest)
            if os.path.exists(dest):
                shutil.rmtree(dest)
            try:
                shutil.copytree(src, dest, copy_function=copy2_)
            # Directories are the same
            except shutil.Error as e:
                self.logger.error('Directory not copied. Error: %s' % e)
            # Any error saying that the directory doesn't exist
            except OSError as e:
                self.logger.error('Directory not copied. Error: %s' % e)

        self.logger.info("Create new project from current: " + project_folder)

        # create new control object as copy

        if os.path.exists(
                Helper.concat_path_native(project_folder, "CLIENT_DATA")):
            self.logger.error(
                "CLIENT_DATA subdirectory in destination folder detected. This is not allowed for security reason!"
            )
            self.msgbox(
                translate(
                    "mainController",
                    "CLIENT_DATA subdirectory in destination folder detected. This is not allowed for security reason!"
                ), oPB.MsgEnum.MS_ERR)
            return

        newControl = deepcopy(self.controlData)
        self.create_project_paths(project_folder)
        project_name = PurePath(project_folder).name.replace(" ", "_")
        newControl.id = project_name
        newControl.projectfolder = project_folder

        # add changelog entry for this copy process
        text = "Project copied from: " + self.controlData.packagename
        newentry = ChangelogEntry(newControl.id)
        newentry.version = "(" + newControl.productversion + "-" + newControl.packageversion + ")"
        newentry.status = oPB.CHLOG_STATI[0]
        newentry.urgency = oPB.CHLOG_BLOCKMARKER + oPB.CHLOG_URGENCIES[0]
        newentry.text = "\n" + text + changelog_footer()
        newControl.changelog_append(newentry)

        try:
            self.processingStarted.emit()

            newControl.save_data()
            self.logger.debug("New control data saved.")

            dest_data = Helper.concat_path_native(newControl.projectfolder,
                                                  "CLIENT_DATA")
            total, total_size = countFiles(
                Helper.concat_path_native(self.controlData.projectfolder,
                                          "CLIENT_DATA"))
            val = 100 / total

            reply = self.msgbox(
                translate("mainController",
                          "Copy files now? This can't be canceled.") +
                "\n\nTotal: " + str(total) + "\n" + sizeof_fmt(total_size),
                oPB.MsgEnum.MS_QUEST_YESNO)
            if reply is True:
                copyDirectory(
                    Helper.concat_path_native(self.controlData.projectfolder,
                                              "CLIENT_DATA"),
                    Helper.concat_path_native(newControl.projectfolder,
                                              "CLIENT_DATA"))
                self.logger.debug("Files copied.")

            self.processingEnded.emit(True)

            # close current project an re-open clone
            if not self.project_close():
                return

            self.project_load(project_name)
        except:
            self.logger.error("Project could not be copied and re-opened.")
Example #25
0
    def create_bundle(self, prods=[]):
        self.logger.debug("Create bundle from selection")

        if prods:
            msg = "\n\n" + translate(
                "bundleController", "Chosen products:") + "\n\n" + ("\n").join(
                    [p for p in prods])
            reply = self._parent.msgbox(
                translate("bundleController", "Create product bundle now?") +
                msg, oPB.MsgEnum.MS_QUEST_YESNO)
            if reply is True:
                self.logger.debug("Selected product(s): " + str(prods))

                ok = False
                while not ok:
                    comment = "meta-"
                    accept = False
                    while comment == "" or accept == False:
                        (
                            comment, accept
                        ) = self._parent.msgbox(translate(
                            "bundleController",
                            "Please enter package name (allowed characters: a-z, A-Z, 0-9, ._-):"
                        ),
                                                oPB.MsgEnum.MS_QUEST_PHRASE,
                                                parent=self.ui,
                                                preload=comment)

                        # first test if cancel button was pressed
                        if not accept:
                            self._parent.msgbox(translate(
                                "bundleController",
                                "Package creation canceled!"),
                                                oPB.MsgEnum.MS_ALWAYS,
                                                parent=self.ui)
                            self.logger.debug(
                                "Package bundle creation canceled by the user."
                            )
                            self._parent.startup.show_()
                            return None

                        if ConfigHandler.cfg.age == "True":
                            test = re.match(oPB.OPB_PRODUCT_ID_REGEX_NEW,
                                            comment)
                        else:
                            test = re.match(oPB.OPB_PRODUCT_ID_REGEX_OLD,
                                            comment)

                        if not test:
                            self._parent.msgbox(translate(
                                "bundleController",
                                "Package name is no valid product id!"),
                                                oPB.MsgEnum.MS_ALWAYS,
                                                parent=self.ui)
                            accept = False

                    directory = Helper.concat_path_native(
                        ConfigHandler.cfg.dev_dir, comment)
                    self.logger.info("Chosen directory for new project: " +
                                     directory)
                    if os.path.exists(directory):
                        self._parent.msgbox(translate(
                            "bundleController",
                            "Package name already exists. Please choose another package name!"
                        ),
                                            oPB.MsgEnum.MS_ALWAYS,
                                            parent=self.ui)
                    else:
                        self._parent.project_create(directory)
                        for p in prods:
                            self._parent.add_setup_before_dependency(p)
                        self._parent.controlData.priority = -100
                        self._parent.controlData.setupScript = "dummy.opsiscript"
                        self._parent.controlData.create_script_stub(
                            self._parent.controlData.setupScript)
                        self._parent.save_backend()
                        ok = True
                        self.logger.debug("Package bundle creation finished.")
        else:
            self.logger.debug("Nothing selected.")
Example #26
0
    def open_scripteditor(self):
        """
        Open configured script editor.

        Method reaction depends on calling widget (self.sender())
        """
        self.logger.debug("Start scripteditor")

        if ConfigHandler.cfg.editor_intern == "True":
            self._parent.msgbox(translate("MainWindow", "Internal editor not available at the moment. Use external editor instead!"), oPB.MsgEnum.MS_ALWAYS, self)
            self.actionSettings.trigger()
            return

        if os.path.exists(ConfigHandler.cfg.scripteditor):
            path = Helper.concat_path_native(self.lblPacketFolder.text(), "CLIENT_DATA")
            if self.sender() == self.btnScrSetupEdit:
                if self.inpScrSetup.text().strip() == "":
                    script = "setup.opsiscript"
                else:
                    script = self.inpScrSetup.text()
            elif self.sender() == self.btnScrUninstallEdit:
                if self.inpScrUninstall.text().strip() == "":
                    script = "uninstall.opsiscript"
                else:
                    script = self.inpScrUninstall.text()
            elif self.sender() == self.btnScrUpdateEdit:
                if self.inpScrUpdate.text().strip() == "":
                    script = "update.opsiscript"
                else:
                    script = self.inpScrUpdate.text()
            elif self.sender() == self.btnScrAlwaysEdit:
                if self.inpScrAlways.text().strip() == "":
                    script = "always.opsiscript"
                else:
                    script = self.inpScrAlways.text()
            elif self.sender() == self.btnScrOnceEdit:
                if self.inpScrOnce.text().strip() == "":
                    script = "once.opsiscript"
                else:
                    script = self.inpScrOnce.text()
            elif self.sender() == self.btnScrCustomEdit:
                if self.inpScrCustom.text().strip() == "":
                    script = "custom.opsiscript"
                else:
                    script = self.inpScrCustom.text()
            elif self.sender() == self.btnScrUserLoginEdit:
                if self.inpScrUserLogin.text().strip() == "":
                    script = "userlogin.opsiscript"
                else:
                    script = self.inpScrUserLogin.text()
            elif self.sender() == self.actionScriptEditor:
                script = "new.opsiscript"

            # script editor from menu
            if path != "" and script != "":
                path = Helper.concat_path_native(path, script)

            self.logger.debug("Opening script: " + path)
            # construct calling array
            # first add basic scripteditor executable
            cmd = [ConfigHandler.cfg.scripteditor]
            # if there are options, split and append them
            if (ConfigHandler.cfg.editor_options).strip() != "":
                for part in (ConfigHandler.cfg.editor_options).split():
                    cmd.append(part)
                # if attach direct is true, combine last option with script file path
                if ConfigHandler.cfg.editor_attachdirect == "True":
                    cmd[-1] = cmd[-1] + path
                # or else, append as separate value to list
                else:
                    cmd.append(path)
            else:
                cmd.append(path)

            self.logger.debug("Executing subprocess: " + str(cmd))
            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
            outs, errs = proc.communicate()
            self.logger.info(outs)
            self.logger.error(errs)
            if proc.returncode != 0 and proc.returncode != 555:
                self._parent.msgbox(translate("MainWindow", "Editor did not exit as expected.\n\nThe following message(s) returned:") +
                                    "\n\nStandard Out:\n" + outs +
                                    "\nStandard Err:\n" + errs +
                                    "\n\nReturn code: " + str(proc.returncode),
                                    oPB.MsgEnum.MS_WARN, self)
        else:
            self._parent.msgbox(translate("MainWindow", "Editor not found:" + " " + ConfigHandler.cfg.scripteditor), oPB.MsgEnum.MS_ERR, self)