<commit_before>import json
import utils as utils
import xbmcvfs
import xbmc
import xbmcgui

class BackupSetManager:
    jsonFile = xbmc.translatePath(utils.data_dir() + "custom_paths.json")
    paths = None
    
    def __init__(self):
        self.paths = {}
        
        #try and read in the custom file
        self._readFile()

    def addSet(self,aSet):
        self.paths[aSet['name']] = {'root':aSet['root'],'dirs':[{"type":"include","path":aSet['root'],'recurse':True}]}

        #save the file
        self._writeFile()

    def updateSet(self,name,aSet):
        self.paths[name] = aSet

        #save the file
        self._writeFile()

    def deleteSet(self,index):
        #match the index to a key
        keys = self.getSets()

        #delete this set
        del self.paths[keys[index]]

        #save the file
        self._writeFile()
    
    def getSets(self):
        #list all current sets by name
        keys = self.paths.keys()
        keys.sort()

        return keys

    def getSet(self,index):
        keys = self.getSets();

        #return the set at this index
        return {'name':keys[index],'set':self.paths[keys[index]]}

    def validateSetName(self,name):
        return (name not in self.getSets())

    def _writeFile(self):
        #create the custom file
        aFile = xbmcvfs.File(self.jsonFile,'w')
        aFile.write(json.dumps(self.paths))
        aFile.close()
    
    def _readFile(self):
        
        if(xbmcvfs.exists(self.jsonFile)):

            #read in the custom file
            aFile = xbmcvfs.File(self.jsonFile)

            #load custom dirs
            self.paths = json.loads(aFile.read())
            aFile.close()
        else:
            #write a blank file
            self._writeFile()

class AdvancedBackupEditor:
    dialog = None

    def __init__(self):
        self.dialog = xbmcgui.Dialog()

    def _cleanPath(self,root,path):
        return path[len(root)-1:]

    def _validatePath(self,root,path):
        return path.startswith(root)

    def createSet(self):
        backupSet = None
    
        name = self.dialog.input(utils.getString(30110),defaultt='Backup Set')

        if(name != None):

            #give a choice to start in home or enter a root path
            enterHome = self.dialog.yesno(utils.getString(30111),line1=utils.getString(30112) + " - " + utils.getString(30114),line2=utils.getString(30113) + " - " + utils.getString(30115),nolabel=utils.getString(30112),yeslabel=utils.getString(30113))

            rootFolder = 'special://home'
            if(enterHome):
                rootFolder = self.dialog.input(utils.getString(30116),defaultt=rootFolder)

                #direcotry has to end in slash
                if(rootFolder[:-1] != '/'):
                    rootFolder = rootFolder + '/'

                #check that this path even exists
                if(not xbmcvfs.exists(xbmc.translatePath(rootFolder))):
                    self.dialog.ok(utils.getString(30117),utils.getString(30118),rootFolder)
                    return None
            else:
                #select path to start set
                rootFolder = self.dialog.browse(type=0,heading=utils.getString(30119),shares='files',defaultt=rootFolder)

            backupSet = {'name':name,'root':rootFolder}
    
        return backupSet

    def editSet(self,name,backupSet):
        optionSelected = ''
        rootPath = backupSet['root']
        utils.log(rootPath)
        while(optionSelected != -1):
            options = [xbmcgui.ListItem(utils.getString(30120),"Exclude a specific folder from this backup set"),xbmcgui.ListItem(utils.getString(30135),"Include a specific folder to this backup set"),xbmcgui.ListItem(rootPath,utils.getString(30121))]

            for aDir in backupSet['dirs']:
                if(aDir['type'] == 'exclude'):
                    options.append(xbmcgui.ListItem(self._cleanPath(rootPath,aDir['path']),"%s: %s" % ("Type",utils.getString(30129))))
                elif(aDir['type'] == 'include'):
                    options.append(xbmcgui.ListItem(self._cleanPath(rootPath,aDir['path']),"%s: %s | %s: %s" % ("Type",utils.getString(30134),"Recursive",str(aDir['recurse']))))

            optionSelected = self.dialog.select(utils.getString(30122) + ' ' +  name,options,useDetails=True)

            if(optionSelected == 0 or optionSelected == 1):
                #add a folder, will equal root if cancel is hit
                addFolder = self.dialog.browse(type=0,heading=utils.getString(30120),shares='files',defaultt=backupSet['root'])
                
                if(addFolder.startswith(rootPath)):
                    
                    if(not any(addFolder == aDir['path'] for aDir in backupSet['dirs'])):
                        #cannot add root as an exclusion
                        if(optionSelected == 0 and addFolder != backupSet['root']):
                            backupSet['dirs'].append({"path":addFolder,"type":"exclude"})
                        elif(optionSelected == 1):
                            #can add root as inclusion
                            backupSet['dirs'].append({"path":addFolder,"type":"include","recurse":True})
                    else:
                        #this path is already part of another include/exclude rule
                        self.dialog.ok(utils.getString(30117),utils.getString(30137),addFolder)
                else:
                    #folder must be under root folder
                    self.dialog.ok(utils.getString(30117), utils.getString(30136),rootPath)
            elif(optionSelected == 2):
                self.dialog.ok(utils.getString(30121),utils.getString(30130),backupSet['root'])
            elif(optionSelected > 2):
                
                if(self.dialog.yesno(heading=utils.getString(30123),line1=utils.getString(30128))):
                    #remove folder
                    del backupSet['dirs'][optionSelected - 3]

        return backupSet<commit_msg>added ability to toggle recursion of sub folders<commit_after>import json
import utils as utils
import xbmcvfs
import xbmc
import xbmcgui

class BackupSetManager:
    jsonFile = xbmc.translatePath(utils.data_dir() + "custom_paths.json")
    paths = None
    
    def __init__(self):
        self.paths = {}
        
        #try and read in the custom file
        self._readFile()

    def addSet(self,aSet):
        self.paths[aSet['name']] = {'root':aSet['root'],'dirs':[{"type":"include","path":aSet['root'],'recurse':True}]}

        #save the file
        self._writeFile()

    def updateSet(self,name,aSet):
        self.paths[name] = aSet

        #save the file
        self._writeFile()

    def deleteSet(self,index):
        #match the index to a key
        keys = self.getSets()

        #delete this set
        del self.paths[keys[index]]

        #save the file
        self._writeFile()
    
    def getSets(self):
        #list all current sets by name
        keys = self.paths.keys()
        keys.sort()

        return keys

    def getSet(self,index):
        keys = self.getSets();

        #return the set at this index
        return {'name':keys[index],'set':self.paths[keys[index]]}

    def validateSetName(self,name):
        return (name not in self.getSets())

    def _writeFile(self):
        #create the custom file
        aFile = xbmcvfs.File(self.jsonFile,'w')
        aFile.write(json.dumps(self.paths))
        aFile.close()
    
    def _readFile(self):
        
        if(xbmcvfs.exists(self.jsonFile)):

            #read in the custom file
            aFile = xbmcvfs.File(self.jsonFile)

            #load custom dirs
            self.paths = json.loads(aFile.read())
            aFile.close()
        else:
            #write a blank file
            self._writeFile()

class AdvancedBackupEditor:
    dialog = None

    def __init__(self):
        self.dialog = xbmcgui.Dialog()

    def _cleanPath(self,root,path):
        return path[len(root)-1:]

    def _validatePath(self,root,path):
        return path.startswith(root)

    def createSet(self):
        backupSet = None
    
        name = self.dialog.input(utils.getString(30110),defaultt='Backup Set')

        if(name != None):

            #give a choice to start in home or enter a root path
            enterHome = self.dialog.yesno(utils.getString(30111),line1=utils.getString(30112) + " - " + utils.getString(30114),line2=utils.getString(30113) + " - " + utils.getString(30115),nolabel=utils.getString(30112),yeslabel=utils.getString(30113))

            rootFolder = 'special://home'
            if(enterHome):
                rootFolder = self.dialog.input(utils.getString(30116),defaultt=rootFolder)

                #direcotry has to end in slash
                if(rootFolder[:-1] != '/'):
                    rootFolder = rootFolder + '/'

                #check that this path even exists
                if(not xbmcvfs.exists(xbmc.translatePath(rootFolder))):
                    self.dialog.ok(utils.getString(30117),utils.getString(30118),rootFolder)
                    return None
            else:
                #select path to start set
                rootFolder = self.dialog.browse(type=0,heading=utils.getString(30119),shares='files',defaultt=rootFolder)

            backupSet = {'name':name,'root':rootFolder}
    
        return backupSet

    def editSet(self,name,backupSet):
        optionSelected = ''
        rootPath = backupSet['root']
        utils.log(rootPath)
        while(optionSelected != -1):
            options = [xbmcgui.ListItem(utils.getString(30120),"Exclude a specific folder from this backup set"),xbmcgui.ListItem(utils.getString(30135),"Include a specific folder to this backup set"),xbmcgui.ListItem(rootPath,utils.getString(30121))]

            for aDir in backupSet['dirs']:
                if(aDir['type'] == 'exclude'):
                    options.append(xbmcgui.ListItem(self._cleanPath(rootPath,aDir['path']),"%s: %s" % ("Type",utils.getString(30129))))
                elif(aDir['type'] == 'include'):
                    options.append(xbmcgui.ListItem(self._cleanPath(rootPath,aDir['path']),"%s: %s | %s: %s" % ("Type",utils.getString(30134),"Include Sub Folders",str(aDir['recurse']))))

            optionSelected = self.dialog.select(utils.getString(30122) + ' ' +  name,options,useDetails=True)

            if(optionSelected == 0 or optionSelected == 1):
                #add a folder, will equal root if cancel is hit
                addFolder = self.dialog.browse(type=0,heading=utils.getString(30120),shares='files',defaultt=backupSet['root'])
                
                if(addFolder.startswith(rootPath)):
                    
                    if(not any(addFolder == aDir['path'] for aDir in backupSet['dirs'])):
                        #cannot add root as an exclusion
                        if(optionSelected == 0 and addFolder != backupSet['root']):
                            backupSet['dirs'].append({"path":addFolder,"type":"exclude"})
                        elif(optionSelected == 1):
                            #can add root as inclusion
                            backupSet['dirs'].append({"path":addFolder,"type":"include","recurse":True})
                    else:
                        #this path is already part of another include/exclude rule
                        self.dialog.ok(utils.getString(30117),utils.getString(30137),addFolder)
                else:
                    #folder must be under root folder
                    self.dialog.ok(utils.getString(30117), utils.getString(30136),rootPath)
            elif(optionSelected == 2):
                self.dialog.ok(utils.getString(30121),utils.getString(30130),backupSet['root'])
            elif(optionSelected > 2):
                
                cOptions = ['Delete']
                if(backupSet['dirs'][optionSelected - 3]['type'] == 'include'):
                    cOptions.append('Toggle Sub Folders')
                    
                contextOption = self.dialog.contextmenu(cOptions)
                
                if(contextOption == 0):
                    if(self.dialog.yesno(heading=utils.getString(30123),line1=utils.getString(30128))):
                        #remove folder
                        del backupSet['dirs'][optionSelected - 3]
                elif(contextOption == 1 and backupSet['dirs'][optionSelected - 3]['type'] == 'include'):
                    #toggle if this folder should be recursive
                    backupSet['dirs'][optionSelected - 3]['recurse'] = not backupSet['dirs'][optionSelected - 3]['recurse']

        return backupSet
{'fraction_non_alphanumeric': 0.12463424278370898, 'fraction_numerical': 0.024199288256227757, 'mean_word_length': 2.094958394517866, 'pattern_counts': {'":': 14, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '906349', 'n_tokens_mistral': 3824, 'n_tokens_neox': 3507, 'n_words': 696}