Ejemplo n.º 1
0
	def OnSave(self, event=None):
		# Get data to write to control file
		control = self.GetCtrlInfo()

		save_dialog = GetFileSaveDialog(GetMainWindow(), GT(u'Save Control Information'))
		save_dialog.SetFilename(u'control')

		if ShowDialog(save_dialog):
			# Be sure not to strip trailing newline (dpkg is picky)
			WriteFile(save_dialog.GetPath(), control, noStrip=u'\n')
Ejemplo n.º 2
0
def UpdateDistNamesCache(unstable=True, obsolete=False, generic=False):
    global FILE_distnames

    debian_distnames = _get_debian_distnames(unstable, obsolete, generic)
    ubuntu_distnames = _get_ubuntu_distnames(unstable, obsolete)
    mint_distnames = _get_mint_distnames()

    section_debian = u'[DEBIAN]\n{}'.format(u'\n'.join(debian_distnames))
    section_ubuntu = u'[UBUNTU]\n{}'.format(u'\n'.join(ubuntu_distnames))
    section_mint = u'[LINUX MINT]\n{}'.format(u'\n'.join(mint_distnames))

    return WriteFile(
        FILE_distnames, u'\n\n'.join(
            (section_debian, section_ubuntu, section_mint)))
Ejemplo n.º 3
0
        def SaveIt(path):
            # Gather data from different pages
            data = (
                GetPage(pgid.CONTROL).GetSaveData(),
                GetPage(pgid.FILES).GetSaveData(),
                GetPage(pgid.SCRIPTS).GetSaveData(),
                GetPage(pgid.CHANGELOG).GetSaveData(),
                GetPage(pgid.COPYRIGHT).GetSaveData(),
                GetPage(pgid.MENU).GetSaveData(),
                GetPage(pgid.BUILD).GetSaveData(),
            )

            # Create a backup of the project
            overwrite = False
            if os.path.isfile(path):
                backup = u'{}.backup'.format(path)
                shutil.copy(path, backup)
                overwrite = True

            # This try statement can be removed when unicode support is enabled
            try:
                WriteFile(
                    path, u'[DEBREATE-{}]\n{}'.format(VERSION_string,
                                                      u'\n'.join(data)))

                if overwrite:
                    os.remove(backup)

            except UnicodeEncodeError:
                detail1 = GT(
                    u'Unfortunately Debreate does not support unicode yet.')
                detail2 = GT(
                    u'Remove any non-ASCII characters from your project.')

                ShowErrorDialog(GT(u'Save failed'),
                                u'{}\n{}'.format(detail1, detail2),
                                title=GT(u'Unicode Error'))

                if overwrite:
                    os.remove(path)
                    # Restore project backup
                    shutil.move(backup, path)
Ejemplo n.º 4
0
    def OnExportLauncher(self, event=None):
        Logger.Debug(__name__, u'Export launcher ...')

        # Get data to write to control file
        menu_data = self.GetLauncherInfo().encode(u'utf-8')

        dia = wx.FileDialog(GetMainWindow(),
                            GT(u'Save Launcher'),
                            os.getcwd(),
                            style=wx.FD_SAVE | wx.FD_CHANGE_DIR
                            | wx.FD_OVERWRITE_PROMPT)

        if ShowDialog(dia):
            path = dia.GetPath()

            # Create a backup file
            overwrite = False
            if os.path.isfile(path):
                backup = u'{}.backup'.format(path)
                shutil.copy(path, backup)
                overwrite = True

            try:
                WriteFile(path, menu_data)

                if overwrite:
                    os.remove(backup)

            except UnicodeEncodeError:
                detail1 = GT(
                    u'Unfortunately Debreate does not support unicode yet.')
                detail2 = GT(
                    u'Remove any non-ASCII characters from your project.')

                ShowErrorDialog(GT(u'Save failed'),
                                u'{}\n{}'.format(detail1, detail2),
                                title=GT(u'Unicode Error'))

                os.remove(path)
                # Restore from backup
                shutil.move(backup, path)
Ejemplo n.º 5
0
def WriteConfig(k_name, k_value, conf=default_config, sectLabel=None):
    conf_dir = os.path.dirname(conf)

    if not os.path.isdir(conf_dir):
        if os.path.exists(conf_dir):
            print(u'{}: {}: {}'.format(
                GT(u'Error'),
                GT(u'Cannot create config directory, file exists'), conf_dir))
            return ConfCode.ERR_WRITE

        os.makedirs(conf_dir)

    # Only write pre-defined keys
    if k_name not in default_config_values:
        print(u'{}: {}: {}'.format(GT(u'Error'),
                                   GT(u'Configuration key not found'), k_name))
        return ConfCode.KEY_NOT_DEFINED

    # Make sure we are writing the correct type
    k_value = default_config_values[k_name][0](k_value)

    if k_value == None:
        print(u'{}: {}: {}'.format(
            GT(u'Error'), GT(u'Wrong value type for configuration key'),
            k_name))
        return ConfCode.WRONG_TYPE

    # tuple is the only type we need to format
    if isinstance(k_value, tuple):
        k_value = u'{},{}'.format(GS(k_value[0]), GS(k_value[1]))

    else:
        k_value = GS(k_value)

    conf_text = wx.EmptyString

    # Save current config to buffer
    if os.path.exists(conf):
        if not os.path.isfile(conf):
            print(u'{}: {}: {}'.format(
                GT(u'Error'),
                GT(u'Cannot open config for writing, directory exists'), conf))
            return ConfCode.ERR_WRITE

        conf_text = ReadFile(conf)

        # FIXME: ReadFile returns None type if config file exists but is empty
        if conf_text == None:
            conf_text = u''

    else:
        conf_text = u'[CONFIG-{}.{}]'.format(GS(config_version[0]),
                                             GS(config_version[1]))

    conf_lines = conf_text.split(u'\n')

    key_exists = False
    for L in conf_lines:
        l_index = conf_lines.index(L)
        if u'=' in L:
            key = L.split(u'=')[0]

            if k_name == key:
                key_exists = True

                conf_lines[l_index] = u'{}={}'.format(k_name, k_value)

    if not key_exists:
        conf_lines.append(u'{}={}'.format(k_name, k_value))

    conf_text = u'\n'.join(conf_lines)

    if TextIsEmpty(conf_text):
        print(u'{}: {}'.format(GT(u'Warning'),
                               GT(u'Not writing empty text to configuration')))
        return ConfCode.ERR_WRITE

    # Actual writing to configuration
    WriteFile(conf, conf_text)

    if os.path.isfile(conf):
        return ConfCode.SUCCESS

    return ConfCode.ERR_WRITE
Ejemplo n.º 6
0
def WriteMD5(stage_dir, parent=None):
    CMD_md5sum = GetExecutable(u'md5sum')

    # Show an error if the 'md5sum' command does not exist
    # This is only a failsafe & should never actually occur
    if not CMD_md5sum:
        if not parent:
            parent = GetMainWindow()

        md5_label = GetField(pgid.BUILD, chkid.MD5).GetLabel()

        err_msg1 = GT(u'The "md5sum" command was not found on the system.')
        err_msg2 = GT(u'Uncheck the "{}" box.').format(md5_label)
        err_msg3 = GT(
            u'Please report this error to one of the following addresses:')
        err_url1 = u'https://github.com/AntumDeluge/debreate/issues'
        err_url2 = u'https://sourceforge.net/p/debreate/bugs/'

        Logger.Error(
            __name__,
            u'{} {} {}\n\t{}\n\t{}'.format(err_msg1, err_msg2, err_msg3,
                                           err_url1, err_url2))

        md5_error = ErrorDialog(parent,
                                text=u'{}\n{}\n\n{}'.format(
                                    err_msg1, err_msg2, err_msg3))
        md5_error.AddURL(err_url1)
        md5_error.AddURL(err_url2)
        md5_error.ShowModal()

        return None

    temp_list = []
    md5_list = []  # Final list used to write the md5sum file
    for ROOT, DIRS, FILES in os.walk(stage_dir):
        # Ignore the 'DEBIAN' directory
        if os.path.basename(ROOT) == u'DEBIAN':
            continue

        for F in FILES:
            F = u'{}/{}'.format(ROOT, F)

            md5 = GetCommandOutput(CMD_md5sum, (u'-t', F))

            Logger.Debug(__name__,
                         u'WriteMD5: GetCommandOutput: {}'.format(md5))

            temp_list.append(md5)

    for item in temp_list:
        # Remove [stage_dir] from the path name in the md5sum so that it has a
        # true unix path
        # e.g., instead of "/myfolder_temp/usr/local/bin", "/usr/local/bin"
        sum_split = item.split(u'{}/'.format(stage_dir))
        sum_join = u''.join(sum_split)
        md5_list.append(sum_join)

    # Create the md5sums file in the "DEBIAN" directory
    # NOTE: lintian ignores the last character of the file, so should end with newline character (\n)
    return WriteFile(u'{}/DEBIAN/md5sums'.format(stage_dir),
                     u'{}\n'.format(u'\n'.join(md5_list)), u'\n')
Ejemplo n.º 7
0
    def Build(self, task_list, build_path, filename):
        # Declare this here in case of error before progress dialog created
        build_progress = None

        try:
            # Other mandatory tasks that will be processed
            mandatory_tasks = (
                u'stage',
                u'install_size',
                u'control',
                u'build',
            )

            # Add other mandatory tasks
            for T in mandatory_tasks:
                task_list[T] = None

            task_count = len(task_list)

            # Add each file for updating progress dialog
            if u'files' in task_list:
                task_count += len(task_list[u'files'])

            # Add each script for updating progress dialog
            if u'scripts' in task_list:
                task_count += len(task_list[u'scripts'])

            if DebugEnabled():
                task_msg = GT(u'Total tasks: {}').format(task_count)
                print(u'DEBUG: [{}] {}'.format(__name__, task_msg))
                for T in task_list:
                    print(u'\t{}'.format(T))

            create_changelog = u'changelog' in task_list
            create_copyright = u'copyright' in task_list

            pg_control = GetPage(pgid.CONTROL)
            pg_menu = GetPage(pgid.MENU)

            stage_dir = u'{}/{}__dbp__'.format(build_path, filename)

            if os.path.isdir(u'{}/DEBIAN'.format(stage_dir)):
                try:
                    shutil.rmtree(stage_dir)

                except OSError:
                    ShowErrorDialog(
                        GT(u'Could not free stage directory: {}').format(
                            stage_dir),
                        title=GT(u'Cannot Continue'))

                    return (dbrerrno.EEXIST, None)

            # Actual path to new .deb
            deb = u'"{}/{}.deb"'.format(build_path, filename)

            progress = 0

            task_msg = GT(u'Preparing build tree')
            Logger.Debug(__name__, task_msg)

            wx.Yield()
            build_progress = ProgressDialog(
                GetMainWindow(),
                GT(u'Building'),
                task_msg,
                maximum=task_count,
                style=PD_DEFAULT_STYLE | wx.PD_ELAPSED_TIME
                | wx.PD_ESTIMATED_TIME | wx.PD_CAN_ABORT)

            DIR_debian = ConcatPaths((stage_dir, u'DEBIAN'))

            # Make a fresh build tree
            os.makedirs(DIR_debian)
            progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            def UpdateProgress(current_task, message=None):
                task_eval = u'{} / {}'.format(current_task, task_count)

                if message:
                    Logger.Debug(__name__,
                                 u'{} ({})'.format(message, task_eval))

                    wx.Yield()
                    build_progress.Update(current_task, message)

                    return

                wx.Yield()
                build_progress.Update(current_task)

            # *** Files *** #
            if u'files' in task_list:
                UpdateProgress(progress, GT(u'Copying files'))

                no_follow_link = GetField(GetPage(pgid.FILES),
                                          chkid.SYMLINK).IsChecked()

                # TODO: move this into a file functions module
                def _copy(f_src, f_tgt, exe=False):
                    # NOTE: Python 3 appears to have follow_symlinks option for shutil.copy
                    # FIXME: copying nested symbolic link may not work

                    if os.path.isdir(f_src):
                        if os.path.islink(f_src) and no_follow_link:
                            Logger.Debug(
                                __name__,
                                u'Adding directory symbolic link to stage: {}'.
                                format(f_tgt))

                            os.symlink(os.readlink(f_src), f_tgt)
                        else:
                            Logger.Debug(
                                __name__,
                                u'Adding directory to stage: {}'.format(f_tgt))

                            shutil.copytree(f_src, f_tgt)
                            os.chmod(f_tgt, 0o0755)
                    elif os.path.isfile(f_src):
                        if os.path.islink(f_src) and no_follow_link:
                            Logger.Debug(
                                __name__,
                                u'Adding file symbolic link to stage: {}'.
                                format(f_tgt))

                            os.symlink(os.readlink(f_src), f_tgt)
                        else:
                            if exe:
                                Logger.Debug(
                                    __name__,
                                    u'Adding executable to stage: {}'.format(
                                        f_tgt))
                            else:
                                Logger.Debug(
                                    __name__,
                                    u'Adding file to stage: {}'.format(f_tgt))

                            shutil.copy(f_src, f_tgt)

                            # Set FILE permissions
                            if exe:
                                os.chmod(f_tgt, 0o0755)

                            else:
                                os.chmod(f_tgt, 0o0644)

                files_data = task_list[u'files']
                for FILE in files_data:
                    file_defs = FILE.split(u' -> ')

                    source_file = file_defs[0]
                    target_file = u'{}{}/{}'.format(stage_dir, file_defs[2],
                                                    file_defs[1])
                    target_dir = os.path.dirname(target_file)

                    if not os.path.isdir(target_dir):
                        os.makedirs(target_dir)

                    # Remove asteriks from exectuables
                    exe = False
                    if source_file[-1] == u'*':
                        exe = True
                        source_file = source_file[:-1]

                    _copy(
                        source_file,
                        u'{}/{}'.format(target_dir,
                                        os.path.basename(source_file)), exe)

                    # Individual files
                    progress += 1
                    UpdateProgress(progress)

                # Entire file task
                progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # *** Strip files ***#
            # FIXME: Needs only be run if 'files' step is used
            if u'strip' in task_list:
                UpdateProgress(progress, GT(u'Stripping binaries'))

                for ROOT, DIRS, FILES in os.walk(stage_dir):  #@UnusedVariable
                    for F in FILES:
                        # Don't check files in DEBIAN directory
                        if ROOT != DIR_debian:
                            F = ConcatPaths((ROOT, F))

                            if FileUnstripped(F):
                                Logger.Debug(__name__,
                                             u'Unstripped file: {}'.format(F))

                                # FIXME: Strip command should be set as class member?
                                ExecuteCommand(GetExecutable(u'strip'), F)

                progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            package = GetField(pg_control, inputid.PACKAGE).GetValue()

            # Make sure that the directory is available in which to place documentation
            if create_changelog or create_copyright:
                doc_dir = u'{}/usr/share/doc/{}'.format(stage_dir, package)
                if not os.path.isdir(doc_dir):
                    os.makedirs(doc_dir)

            # *** Changelog *** #
            if create_changelog:
                UpdateProgress(progress, GT(u'Creating changelog'))

                # If changelog will be installed to default directory
                changelog_target = task_list[u'changelog'][0]
                if changelog_target == u'STANDARD':
                    changelog_target = ConcatPaths(
                        (u'{}/usr/share/doc'.format(stage_dir), package))

                else:
                    changelog_target = ConcatPaths(
                        (stage_dir, changelog_target))

                if not os.path.isdir(changelog_target):
                    os.makedirs(changelog_target)

                WriteFile(u'{}/changelog'.format(changelog_target),
                          task_list[u'changelog'][1])

                CMD_gzip = GetExecutable(u'gzip')

                if CMD_gzip:
                    UpdateProgress(progress, GT(u'Compressing changelog'))
                    c = u'{} -n --best "{}/changelog"'.format(
                        CMD_gzip, changelog_target)
                    clog_status = commands.getstatusoutput(c.encode(u'utf-8'))
                    if clog_status[0]:
                        ShowErrorDialog(GT(u'Could not compress changelog'),
                                        clog_status[1],
                                        warn=True,
                                        title=GT(u'Warning'))

                progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # *** Copyright *** #
            if create_copyright:
                UpdateProgress(progress, GT(u'Creating copyright'))

                WriteFile(
                    u'{}/usr/share/doc/{}/copyright'.format(
                        stage_dir, package), task_list[u'copyright'])

                progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # Characters that should not be in filenames
            invalid_chars = (u' ', u'/')

            # *** Menu launcher *** #
            if u'launcher' in task_list:
                UpdateProgress(progress, GT(u'Creating menu launcher'))

                # This might be changed later to set a custom directory
                menu_dir = u'{}/usr/share/applications'.format(stage_dir)

                menu_filename = pg_menu.GetOutputFilename()

                # Remove invalid characters from filename
                for char in invalid_chars:
                    menu_filename = menu_filename.replace(char, u'_')

                if not os.path.isdir(menu_dir):
                    os.makedirs(menu_dir)

                WriteFile(u'{}/{}.desktop'.format(menu_dir, menu_filename),
                          task_list[u'launcher'])

                progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # *** md5sums file *** #
            # Good practice to create hashes before populating DEBIAN directory
            if u'md5sums' in task_list:
                UpdateProgress(progress, GT(u'Creating md5sums'))

                if not WriteMD5(stage_dir, parent=build_progress):
                    # Couldn't call md5sum command
                    build_progress.Cancel()

                progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # *** Scripts *** #
            if u'scripts' in task_list:
                UpdateProgress(progress, GT(u'Creating scripts'))

                scripts = task_list[u'scripts']
                for SCRIPT in scripts:
                    script_name = SCRIPT
                    script_text = scripts[SCRIPT]

                    script_filename = ConcatPaths(
                        (stage_dir, u'DEBIAN', script_name))

                    WriteFile(script_filename, script_text)

                    # Make sure scipt path is wrapped in quotes to avoid whitespace errors
                    os.chmod(script_filename, 0755)
                    os.system((u'chmod +x "{}"'.format(script_filename)))

                    # Individual scripts
                    progress += 1
                    UpdateProgress(progress)

                # Entire script task
                progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # *** Control file *** #
            UpdateProgress(progress, GT(u'Getting installed size'))

            # Get installed-size
            installed_size = os.popen(
                (u'du -hsk "{}"'.format(stage_dir))).readlines()
            installed_size = installed_size[0].split(u'\t')
            installed_size = installed_size[0]

            # Insert Installed-Size into control file
            control_data = pg_control.Get().split(u'\n')
            control_data.insert(2,
                                u'Installed-Size: {}'.format(installed_size))

            progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # Create final control file
            UpdateProgress(progress, GT(u'Creating control file'))

            # dpkg fails if there is no newline at end of file
            control_data = u'\n'.join(control_data).strip(u'\n')
            # Ensure there is only one empty trailing newline
            # Two '\n' to show physical empty line, but not required
            # Perhaps because string is not null terminated???
            control_data = u'{}\n\n'.format(control_data)

            WriteFile(u'{}/DEBIAN/control'.format(stage_dir),
                      control_data,
                      noStrip=u'\n')

            progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # *** Final build *** #
            UpdateProgress(progress, GT(u'Running dpkg'))

            working_dir = os.path.split(stage_dir)[0]
            c_tree = os.path.split(stage_dir)[1]
            deb_package = u'{}.deb'.format(filename)

            # Move the working directory becuase dpkg seems to have problems with spaces in path
            os.chdir(working_dir)

            # HACK to fix file/dir permissions
            for ROOT, DIRS, FILES in os.walk(stage_dir):
                for D in DIRS:
                    D = u'{}/{}'.format(ROOT, D)
                    os.chmod(D, 0o0755)
                for F in FILES:
                    F = u'{}/{}'.format(ROOT, F)
                    if os.access(F, os.X_OK):
                        os.chmod(F, 0o0755)
                    else:
                        os.chmod(F, 0o0644)

            # FIXME: Should check for working fakeroot & dpkg-deb executables
            build_status = commands.getstatusoutput(
                (u'{} {} -b "{}" "{}"'.format(GetExecutable(u'fakeroot'),
                                              GetExecutable(u'dpkg-deb'),
                                              c_tree, deb_package)))

            progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # *** Delete staged directory *** #
            if u'rmstage' in task_list:
                UpdateProgress(progress, GT(u'Removing temp directory'))

                try:
                    shutil.rmtree(stage_dir)

                except OSError:
                    ShowErrorDialog(GT(
                        u'An error occurred when trying to delete the build tree'
                    ),
                                    parent=build_progress)

                progress += 1

            if build_progress.WasCancelled():
                build_progress.Destroy()
                return (dbrerrno.ECNCLD, None)

            # *** ERROR CHECK
            if u'lintian' in task_list:
                UpdateProgress(progress, GT(u'Checking package for errors'))

                # FIXME: Should be set as class memeber?
                CMD_lintian = GetExecutable(u'lintian')
                errors = commands.getoutput((u'{} {}'.format(CMD_lintian,
                                                             deb)))

                if errors != wx.EmptyString:
                    e1 = GT(u'Lintian found some issues with the package.')
                    e2 = GT(u'Details saved to {}').format(filename)

                    WriteFile(u'{}/{}.lintian'.format(build_path, filename),
                              errors)

                    DetailedMessageDialog(build_progress,
                                          GT(u'Lintian Errors'),
                                          ICON_INFORMATION,
                                          u'{}\n{}.lintian'.format(e1, e2),
                                          errors).ShowModal()

                progress += 1

            # Close progress dialog
            wx.Yield()
            build_progress.Update(progress)
            build_progress.Destroy()

            # Build completed successfullly
            if not build_status[0]:
                return (dbrerrno.SUCCESS, deb_package)

            if PY_VER_MAJ <= 2:
                # Unicode decoder has trouble with certain characters. Replace any
                # non-decodable characters with � (0xFFFD).
                build_output = list(build_status[1])

                # String & unicode string incompatibilities
                index = 0
                for C in build_output:
                    try:
                        GS(C)

                    except UnicodeDecodeError:
                        build_output[index] = u'�'

                    index += 1

                build_status = (build_status[0], u''.join(build_output))

            # Build failed
            return (build_status[0], build_status[1])

        except:
            if build_progress:
                build_progress.Destroy()

            return (dbrerrno.EUNKNOWN, traceback.format_exc())