Beispiel #1
0
    def __init__(self, pid) :
        '''Intitate the whole class and create the object.'''

        self.pid            = pid
        self.tools          = Tools()
        self.rapumaHome     = os.environ.get('RAPUMA_BASE')
        self.userHome       = os.environ.get('RAPUMA_USER')
        self.user           = UserConfig(self.rapumaHome, self.userHome)
        self.userConfig     = self.user.userConfig
        self.projectConfig     = Config(pid).projectConfig
        self.projHome       = None
        self.local          = None

        self.finishInit()

        # Log messages for this module
        self.errorCodes     = {
            'EDIT-000' : ['MSG', 'Messages for editing project and setting files.'],
            'EDIT-005' : ['MSG', 'Unassigned error message ID.'],
            'EDIT-010' : ['ERR', 'The component [<<1>>] has multiple subcomponents and cannot be opened for editing. Please work with the individual subcomponents.'],
            'EDIT-020' : ['ERR', 'Working text file [<<1>>] not found.'],
            'EDIT-030' : ['ERR', 'No files found to edit with the commands supplied.'],
            'EDIT-040' : ['MSG', 'Component files for [<<1>>] have been opened in your file editor.'],

            '0000' : ['MSG', 'Placeholder message'],
        }
Beispiel #2
0
    def __init__(self, pid, gid = None, projectConfig = None) :
        '''Intitate the whole class and create the object.'''

        self.pid                    = pid
        self.tools                  = Tools()
        self.user                   = UserConfig()
        self.userConfig             = self.user.userConfig
        if projectConfig :
            self.projectConfig      = projectConfig
        else :
            self.proj_config        = Config(self.pid)
            self.proj_config.getProjectConfig()
            self.projectConfig      = self.proj_config.projectConfig
        self.local                  = ProjLocal(pid, gid, self.projectConfig)
        self.log                    = ProjLog(pid)

        # Log messages for this module
        self.errorCodes     = {
            '0000' : ['MSG', 'Placeholder message'],
            'XPRT-000' : ['MSG', 'Messages for export issues (probably only in project.py)'],
            'XPRT-005' : ['MSG', 'Unassigned error message ID.'],
            'XPRT-010' : ['ERR', 'Export file name could not be formed with available configuration information.'],
            'XPRT-020' : ['ERR', 'Unable to export: [<<1>>].'],
            'XPRT-030' : ['MSG', 'Files exported to [<<1>>].'],
            'XPRT-040' : ['MSG', 'Beginning export, please wait...'],
            'XPRT-050' : ['MSG', 'Unassigned error message ID.'],

            '1210' : ['MSG', 'Processes completed successfully on: [<<1>>] by [<<2>>]'],
            '1220' : ['ERR', 'Processes for [<<1>>] failed. Script [<<2>>] returned this error: [<<3>>]'],
            '1240' : ['MSG', 'Component group preprocessing [<<1>>] for group [<<2>>].'],
            '1260' : ['ERR', 'Installed the default component preprocessing script. Editing will be required for it to work with your project.'],
            '1265' : ['LOG', 'Component preprocessing script is already installed.'],

        }
Beispiel #3
0
    def __init__(self) :
        '''Intitate the whole class and create the object.'''

#        import pdb; pdb.set_trace()

        self.rapumaHome         = os.environ.get('RAPUMA_BASE')
        self.defaultUserHome    = os.environ.get('RAPUMA_USER')
        self.userConfFileName   = 'rapuma.conf'
        self.tools              = Tools()

        # Point to the right user config either server or desktop
        # The RAPUMA_USER setting should have the right path from
        # the mother script (rapuma)
        self.userConfFile       = os.path.join(self.defaultUserHome, self.userConfFileName)

        # Check to see if the file is there, then read it in and break it into
        # sections. If it fails, scream really loud!
        rapumaXMLDefaults = os.path.join(self.rapumaHome, 'config', 'rapuma.xml')
        if os.path.exists(rapumaXMLDefaults) :
            self.tools.sysXmlConfig = self.tools.xml_to_section(rapumaXMLDefaults)
        else :
            raise IOError, "Can't open " + rapumaXMLDefaults

        # Now make the users local rapuma.conf file if it isn't there
        if not os.path.isfile(self.userConfFile) :
            self.initUserHome()

        # Load the system.conf file into an object
        self.userConfig = ConfigObj(self.userConfFile, encoding='utf-8')

        # Log messages for this module
        self.errorCodes     = {
            '0000' : ['MSG', 'Placeholder message'],
        }
Beispiel #4
0
    def __init__(self, pid, gid = None) :
        '''Intitate the whole class and create the object.'''

#        import pdb; pdb.set_trace()

        self.pid                        = pid
        self.gid                        = gid
        self.local                      = ProjLocal(pid, gid)
        self.tools                      = Tools()
        self.proj_config                = Config(pid, gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getLayoutConfig()
        self.layoutConfig               = self.proj_config.layoutConfig
        self.user                       = UserConfig()
        self.userConfig                 = self.user.userConfig
        self.log                        = ProjLog(pid)

        # to [px] is 72/25.4 
        self.mmToPx                     = 72 / 25.4
        # page width [px]
        self.paperPxWidth               = round(self.mmToPx * float(self.layoutConfig['PageLayout']['pageWidth']),1)
        # page height [px]
        self.paperPxHeight              = round(self.mmToPx * float(self.layoutConfig['PageLayout']['pageHeight']),1)

        # Log messages for this module
        self.errorCodes     = {

            '0000' : ['MSG', 'Placeholder message'],
            '1310' : ['WRN', 'Failed to add diagnostic component: [<<1>>] with error: [<<2>>]']

        }
Beispiel #5
0
    def __init__(self, pid) :
        '''Intitate the whole class and create the object.'''

        self.pid                            = pid
        self.log                            = ProjLog(self.pid)
        self.tools                          = Tools()
        self.user                           = UserConfig()
        self.config                         = Config(pid)
        self.local                          = ProjLocal(self.pid)
        self.userConfig                     = self.user.userConfig
        self.config.getProjectConfig()
        self.projectConfig                  = self.config.projectConfig
        if self.userConfig['System']['textDifferentialViewerCommand'] == '' :
            self.diffViewCmd                = None
        else :
            self.diffViewCmd                = self.userConfig['System']['textDifferentialViewerCommand']
            # Make sure the diff view command is a list
            if type(self.diffViewCmd) != list :
                self.diffViewCmd            = [self.userConfig['System']['textDifferentialViewerCommand']]

        # Log messages for this module
        self.errorCodes     = {
            '0210' : ['WRN', 'File does not exist: [<<1>>] compare cannot be done.'],
            '0280' : ['ERR', 'Failed to compare files with error: [<<1>>]'],
            '0285' : ['ERR', 'Cannot compare component [<<1>>] because a coresponding subcomponent could not be found.'],
            '0290' : ['ERR', 'Compare test type: [<<1>>] is not valid.'],
            '0295' : ['MSG', 'Comparing: [<<1>>] with parent: [<<2>>] Close the viewer to return to the terminal prompt.'],
            '0220' : ['MSG', 'Comparison not needed, files seem to be the same.'],
            '0300' : ['WRN', 'Files are different but visual compare is not enabled.']
        }
Beispiel #6
0
    def __init__(self, project, cfg, parent = None) :
        '''Initialize this class.'''

        self.project = project
        self.cfg = cfg
        self.parent = parent or project
        self.managers = {}
        self.tools = Tools()
Beispiel #7
0
    def __init__(self, project, cfg) :
        super(Pdf, self).__init__(project, cfg)

#        import pdb; pdb.set_trace()

        # Set values for this manager
        self.pid                    = project.projectIDCode
        self.gid                    = project.gid
        self.cType                  = 'pdf'
        self.Ctype                  = self.cType.capitalize()
        self.project                = project
        self.local                  = project.local
        self.tools                  = Tools()
        self.proj_config            = Config(self.pid, self.gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getAdjustmentConfig()
        self.projectConfig          = self.proj_config.projectConfig
        self.log                    = project.log
        self.cfg                    = cfg
        self.mType                  = project.projectMediaIDCode
        self.renderer               = project.projectConfig['CompTypes'][self.Ctype]['renderer']
        self.compSource             = project.projectConfig['CompTypes'][self.Ctype]['compSource']

        # Get the comp settings
        self.compSettings           = project.projectConfig['CompTypes'][self.Ctype]

        # Build a tuple of managers this component type needs to use
        self.pdfManagers = ('fixed', self.renderer)

        # Init the general managers
        for self.mType in self.pdfManagers :
            self.project.createManager(self.mType)

        # Create the internal ref names we use in this module
        self.text                   = self.project.managers[self.cType + '_Fixed']
        # File names

        # Folder paths
        self.projScriptFolder       = self.local.projScriptFolder
        self.projComponentFolder    = self.local.projComponentFolder
        self.gidFolder              = os.path.join(self.projComponentFolder, self.gid)
        # File names with folder paths
        self.rapumaXmlCompConfig    = os.path.join(self.project.local.rapumaConfigFolder, self.xmlConfFile)

        # Get persistant values from the config if there are any
        newSectionSettings = self.tools.getPersistantSettings(self.projectConfig['CompTypes'][self.Ctype], self.rapumaXmlCompConfig)
        if newSectionSettings != self.projectConfig['CompTypes'][self.Ctype] :
            self.projectConfig['CompTypes'][self.Ctype] = newSectionSettings
        # Set them here
        for k, v in self.compSettings.iteritems() :
            setattr(self, k, v)

        # Module Error Codes
        self.errorCodes     = {

            '0000' : ['MSG', 'Messages for the PDF module.'],

        }
Beispiel #8
0
    def __init__(self, pid) :
        '''Intitate the whole class and create the object.'''

        self.pid            = pid
        self.tools          = Tools()
        self.user           = UserConfig()
        self.userConfig     = self.user.userConfig
        self.local          = ProjLocal(pid)
        self.log            = ProjLog(pid)
        self.projData       = ProjData(pid)
Beispiel #9
0
class Group (object) :

    # Shared values
    xmlConfFile     = 'group.xml'

    def __init__(self, project, cfg, parent = None) :
        '''Initialize this class.'''

        self.project = project
        self.cfg = cfg
        self.parent = parent or project
        self.managers = {}
        self.tools = Tools()


    def render(self) :
        '''Render a group.'''

        self.tools.terminal("Warning: Calling dummy rendering in the group class.")
Beispiel #10
0
    def __init__(self, pid) :
        '''Do the primary initialization for this manager.'''

        self.tools              = Tools()
        self.pid                = pid
        self.rapumaHome         = os.environ.get('RAPUMA_BASE')
        self.userHome           = os.environ.get('RAPUMA_USER')
        self.user               = UserConfig()
        self.userConfig         = self.user.userConfig
        self.local              = ProjLocal(pid)
Beispiel #11
0
class Fixed (Manager) :

    # Shared values
    xmlConfFile     = 'fixed.xml'

    def __init__(self, project, cfg, cType) :
        '''Do the primary initialization for this manager.'''

        super(Fixed, self).__init__(project, cfg)

        # Set values for this manager
        self.gid                    = project.gid
        self.pid                    = project.projectIDCode
        self.tools                  = Tools()
        self.project                = project
        self.projectConfig          = project.projectConfig
        self.cfg                    = cfg
        self.cType                  = cType
        self.Ctype                  = cType.capitalize()
        self.log                    = project.log
        self.manager                = self.cType + '_Fixed'
        self.managers               = project.managers
        self.rapumaXmlTextConfig    = os.path.join(self.project.local.rapumaConfigFolder, self.xmlConfFile)

#        import pdb; pdb.set_trace()

        # Get persistant values from the config if there are any
        newSectionSettings = self.tools.getPersistantSettings(self.project.projectConfig['Managers'][self.manager], self.rapumaXmlTextConfig)
        if newSectionSettings != self.project.projectConfig['Managers'][self.manager] :
            self.project.projectConfig['Managers'][self.manager] = newSectionSettings
            self.tools.writeConfFile(self.project.projectConfig)

        self.compSettings = self.project.projectConfig['Managers'][self.manager]

        for k, v in self.compSettings.iteritems() :
            setattr(self, k, v)

        # Log messages for this module
        self.errorCodes     = {

            '0000' : ['MSG', 'Placeholder message'],

        }
Beispiel #12
0
    def __init__(self, layoutConfig) :
        '''Do the primary initialization for this class.'''

        self.tools                          = Tools()
        self.layoutConfig                   = layoutConfig

        # Log messages for this module
        self.errorCodes     = {

            '0000' : ['MSG', 'Placeholder message'],

        }
Beispiel #13
0
    def __init__(self, pid) :
        '''Do the primary initialization for this class.'''

        self.pid                            = pid
        self.tools                          = Tools()
        self.user                           = UserConfig()
        self.log                            = ProjLog(pid)
        self.userConfig                     = self.user.userConfig
        self.proj_config                    = Config(pid)
        self.proj_config.getProjectConfig()
        self.projectConfig                  = self.proj_config.projectConfig
        self.proj_config.getFontConfig()
        self.fontConfig                     = self.proj_config.fontConfig
        self.local                          = ProjLocal(pid, self.projectConfig)

        # Load all font settings for use in this module
        if self.fontConfig :
            for k, v in self.fontConfig['GeneralSettings'].iteritems() :
                setattr(self, k, v)

        # Log messages for this module
        self.errorCodes     = {
            'FONT-000' : ['MSG', 'Font module messages'],
            'FONT-005' : ['MSG', 'FONT-005 - Unassigned error message ID.'],
            'FONT-015' : ['MSG', 'FONT-015 - Unassigned error message ID.'],
            'FONT-020' : ['ERR', 'Failed to find font setting in ParaTExt project (.ssf file). A primary font must be set before this component can be successfully rendered.'],
            'FONT-025' : ['ERR', 'No source editor was found for this project. Please enter this setting before continuing.'],
            'FONT-042' : ['MSG', 'The [<<1>>] font setup information was added to project config'],
            'FONT-050' : ['ERR', 'Halt! [<<1>>] not found. - font.copyInFont()'],
            'FONT-070' : ['LOG', 'Copied the [<<1>>] font file into the project. - proj_font.copyInFont()'],
            'FONT-100' : ['ERR', 'This function has not been implemented yet!.  - proj_font.setGlyphMap()'],

            '0010' : ['LOG', 'Wrote out new font configuration (font.__init__())'],

            '1220' : ['ERR', 'The Font bundle file [<<1>>] could not be found. Process halted.'],
            '1235' : ['MSG', 'Font [<<1>>] has been installed into the project.'],
            '1237' : ['MSG', 'Font [<<1>>] has been updated.'],
            '1240' : ['ERR', 'Font bundle file [<<1>>] not found.'],
            '1241' : ['ERR', 'Font bundle [<<1>>] not found.'],
            '1245' : ['LOG', '<<1>> font setup information added to project config'],
            '1250' : ['ERR', 'The [<<1>>] font is apparently part of this project. Please remove before trying to re-add this font.'],
            '1260' : ['MSG', 'The <<1>> font bundle has been copied into the project font folder.'],
            '1262' : ['LOG', 'The <<1>> font bundle already exsits in the font folder.'],
            '1265' : ['ERR', 'Failed to extract the [<<1>>] font bundle into the project. Font install process failed.'],
            '1267' : ['LOG', 'The <<1>> font bundle has been copied into the project font folder.'],
            '1280' : ['MSG', 'Failed to install the font: [<<1>>] into the project.'],
            '1370' : ['LOG', 'Removed [<<1>>] font name from project component type: [<<2>>].'],
            '1380' : ['MSG', 'Removed the [<<1>>] font from the project.'],
            '1382' : ['MSG', 'Force switch was set (-f). This process has completely removed the [<<1>>] font and settings from the project. - proj_font.removeFont()'],
            '1390' : ['LOG', 'Removed the [<<1>>] font package.'],
            '1395' : ['MSG', 'Could not remove the [<<1>>] font package. It may be used by another group. Use force (-f) to remove the package from the font folder.']

        }
Beispiel #14
0
    def __init__(self, pid, gid=None) :
        '''Do the primary initialization for this class.'''

        self.pid                            = pid
        self.gid                            = gid
        self.user                           = UserConfig()
        self.userConfig                     = self.user.userConfig
        self.projHome                       = os.path.join(os.path.expanduser(self.userConfig['Resources']['projects']), self.pid)
        self.local                          = ProjLocal(pid, gid)
        self.tools                          = Tools()
        self.log                            = ProjLog(pid)
        # Create config placeholders
        self.projectConfig                  = None
        self.adjustmentConfig               = None
        self.layoutConfig                   = None
        self.illustrationConfig             = None
        self.fontConfig                     = None
        self.macroConfig                    = None

        # Log messages for this module
        self.errorCodes     = {
            '3100' : ['ERR', 'Macro package: [<<1>>] already exists in the project. Use force (-f) to reinstall.'],
            '3200' : ['ERR', 'Failed to install macro package: [<<1>>]'],
            '3300' : ['MSG', 'Install macro package: [<<1>>], Reinitialized [<<2>>]'],
            '3310' : ['ERR', 'Failed to copy [<<1>>] to folder [<<2>>].'],
            '3400' : ['MSG', 'Force set to True. Removed macro package configuration file: [<<1>>]'],
            '3500' : ['MSG', 'Removed macro package [<<1>>] folder and all files contained.'],
            '3600' : ['MSG', 'Updated macro package [<<1>>]'],
            '3650' : ['ERR', 'Failed to updated macro package [<<1>>]']
        }

        # Test for gid before trying to finish the init

#        import pdb; pdb.set_trace()

        if gid :
            if not self.projectConfig :
                self.getProjectConfig()
            # We need to skip over this if the group doesn't exist
            try :
                # Reinitialize local
                self.cType                      = self.projectConfig['Groups'][gid]['cType']
                self.Ctype                      = self.cType.capitalize()
                self.local                      = ProjLocal(pid, gid, self.cType)
            except :
                self.cType                      = None
                self.Ctype                      = None
        else :
            self.cType                      = None
            self.Ctype                      = None
Beispiel #15
0
    def __init__(self, pid, gid) :
        '''Do the primary initialization for this class.'''

        self.pid                        = pid
        self.gid                        = gid
        self.tools                      = Tools()
        self.local                      = ProjLocal(pid)
        self.user                       = UserConfig()
        self.userConfig                 = self.user.userConfig
        self.proj_config                = Config(pid, gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getLayoutConfig()
        self.proj_config.getIllustrationConfig()
        self.projectConfig              = self.proj_config.projectConfig
        self.layoutConfig               = self.proj_config.layoutConfig
        self.illustrationConfig         = self.proj_config.illustrationConfig
        self.cType                      = self.projectConfig['Groups'][gid]['cType']
        self.Ctype                      = self.cType.capitalize()
        self.log                        = ProjLog(pid)
        self.backgroundTypes            = ['watermark', 'lines']

        # Folder paths
        self.projComponentFolder        = self.local.projComponentFolder
        self.projIllustrationFolder     = self.local.projIllustrationFolder
        self.projConfFolder             = self.local.projConfFolder

        # Log messages for this module
        self.errorCodes     = {

            '0000' : ['MSG', 'Placeholder message'],
            '0010' : ['ERR', 'Component type [<<1>>] not recognized!'],
            '0210' : ['WRN', 'Cannot copy [<<1>>] into the project Illustration folder. File already exists. Please use remove or update commands if the file needs to be replaced.'],
            '0220' : ['MSG', 'Copied [<<1>>] into the project Illustration folder.'],
            '0230' : ['ERR', 'Failed to Copy [<<1>>] into the project Illustration folder.'],
            '0240' : ['MSG', 'Illustration add operation complete!'],
            '0265' : ['LOG', 'Piclist file for [<<1>>] has been created.'],
            '0270' : ['WRN', 'Illustration file [<<1>>] not found in Illustration folder.'],
            '0280' : ['ERR', 'There was a problem trying to import the illustration file(s). A possible cause could be that there was no \\fig markers in the source imported into the project. I\'m just say\'n.'],

            '1010' : ['MSG', 'Removed illustration file [<<1>>] from project Illustration folder.'],
            '1020' : ['LOG', 'Request to removed illustration file [<<1>>] from project Illustration folder. File not found. Operation not complete'],
            '1030' : ['MSG', 'Illustration remove operation complete!'],

            '2010' : ['MSG', 'Updated illustration file [<<1>>] in project Illustration folder.'],
            '2020' : ['ERR', 'Update failed, file [<<1>>] not found in project Illustration folder. Use add illustration command to install the illustration.'],
            '2030' : ['ERR', 'Update failed on file [<<1>>]. Copy proceedure failed.'],
            '2040' : ['MSG', 'Illustration update operation complete!']

        }
Beispiel #16
0
    def __init__(self, project, cfg, cType) :
        '''Do the primary initialization for this manager.'''

        super(Text, self).__init__(project, cfg)

        # Set values for this manager
        self.gid                    = project.gid
        self.pid                    = project.projectIDCode
        self.tools                  = Tools()
        self.project                = project
        self.projectConfig          = project.projectConfig
        self.cfg                    = cfg
        self.cType                  = cType
        self.Ctype                  = cType.capitalize()
        self.log                    = project.log
        self.manager                = self.cType + '_Text'
        self.managers               = project.managers
        self.rapumaXmlTextConfig    = os.path.join(self.project.local.rapumaConfigFolder, self.xmlConfFile)

#        import pdb; pdb.set_trace()

        # Get persistant values from the config if there are any
        newSectionSettings = self.tools.getPersistantSettings(self.project.projectConfig['Managers'][self.manager], self.rapumaXmlTextConfig)
        if newSectionSettings != self.project.projectConfig['Managers'][self.manager] :
            self.project.projectConfig['Managers'][self.manager] = newSectionSettings
            self.tools.writeConfFile(self.project.projectConfig)

        self.compSettings = self.project.projectConfig['Managers'][self.manager]

        for k, v in self.compSettings.iteritems() :
            setattr(self, k, v)

        # Log messages for this module
        self.errorCodes     = {

            'TEXT-000' : ['MSG', 'Text module messages'],
            'TEXT-005' : ['ERR', 'Component type [<<1>>] is not supported by the text manager.'],
            'TEXT-015' : ['MSG', 'TEXT-015 - Unassigned error message ID.'],
            'TEXT-030' : ['LOG', 'Copied [<<1>>] to [<<2>>] in project.'],
            'TEXT-040' : ['WRN', 'The [<<1>>] component is locked. It must be unlocked before any modifications can be made.'],
            'TEXT-050' : ['LOG', 'Working text file for [<<1>>] has been completed.'],
            'TEXT-055' : ['ERR', 'TEXT-055 - Unassigned error message ID.'],
            'TEXT-080' : ['LOG', 'Validating text using the [<<1>>] style file.'],
            'TEXT-150' : ['MSG', 'USFM file: [<<1>>] is valid.'],
            'TEXT-160' : ['ERR', 'Unable to complete working text installation for [<<1>>]. May require \"force\" (-f).'],

            '0000' : ['MSG', 'Placeholder message'],

        }
Beispiel #17
0
    def __init__(self, pid) :
        '''Intitate the whole class and create the object.'''

        self.pid                    = pid
        self.tools                  = Tools()
        self.user                   = UserConfig()
        self.userConfig             = self.user.userConfig
        self.projHome               = os.path.join(os.environ['RAPUMA_PROJECTS'], self.pid)
        self.local                  = ProjLocal(self.pid)
        self.proj_config            = Config(pid)
        self.proj_config.getProjectConfig()
        self.projectConfig          = self.proj_config.projectConfig
        self.projectMediaIDCode     = self.projectConfig['ProjectInfo']['projectMediaIDCode']

        # Log messages for this module
        self.errorCodes     = {
            '0000' : ['MSG', 'Placeholder message'],
        }
Beispiel #18
0
    def __init__(self, pid, gid = None) :
        '''Intitate the whole class and create the object.'''

        self.pid            = pid
        self.gid            = gid
        self.tools          = Tools()
        self.user           = UserConfig()
        self.userConfig     = self.user.userConfig
        self.local          = ProjLocal(pid)
        self.log            = ProjLog(pid)
        self.projHome       = os.path.join(os.path.expanduser(self.userConfig['Resources']['projects']), self.pid)
        self.projList       = self.tools.getProjIdList(os.path.expanduser(self.userConfig['Resources']['projects']))

        # Log messages for this module
        self.errorCodes     = {

            '1220' : ['LOG', 'Project [<<1>>] already registered in the system.'],
            '1240' : ['ERR', 'Could not find/open the Project configuration file for [<<1>>]. Project could not be registered!'],

            '3410' : ['LOG', 'Backup file cull skipping: [<<1>>] Not a recognized Rapuma backup file name format.'],
            '3510' : ['ERR', 'The path (or name) given is not valid: [<<1>>].'],
            '3530' : ['MSG', 'Project backup: [<<1>>] has been restored to: [<<2>>]. A backup of the orginal project remains and must be manually removed.'],
            '3550' : ['ERR', 'Project backup version request: [<<1>>] exceeds the maxium number which could be in storage which is: [<<2>>]. Request an earlier (lesser) version.'],
            '3610' : ['ERR', 'The [<<1>>]. project is not registered. No backup was done.'],
            '3620' : ['ERR', 'The path to the backup folder is not valid [<<1>>]. Please try again.'],
            '3622' : ['ERR', 'The path to the backup folder is not set. Please set it and try again.'],
            '3625' : ['ERR', 'The path given to the backup folder is not valid [<<1>>]. Please set the system backup path.'],
            '3630' : ['MSG', 'Backup for [<<1>>] created and saved to: [<<2>>]'],

            '4110' : ['MSG', 'Completed merging data.'],
            '4120' : ['MSG', 'No files updated.'],
            '4130' : ['MSG', 'Added: <<1>> file(s).'],
            '4140' : ['MSG', 'Updated: <<1>> file(s)'],
            '4150' : ['WRN', 'The project data in: [<<1>>] will be replaced with the data from: [<<2>>].'],

            '4210' : ['MSG', 'Completed pulling/restoring data from the cloud.'],
            '4220' : ['ERR', 'Cannot resolve path: [<<1>>]'],
            '4250' : ['ERR', 'The cloud project [<<1>>] you want to pull from is owned by [<<2>>]. Use force (-f) to pull the project and change the local owner ID.'],
            '4260' : ['ERR', 'The local project [<<1>>] is newer than the cloud copy. If you seriously want to overwrite it, use force (-f) to do so.'],
            '4270' : ['MSG', 'Restored the project [<<1>>] from the cloud copy. Local copy is owned by [<<2>>].'],

        }
Beispiel #19
0
    def __init__(self):
        """Intitate the whole class and create the object."""

        self.rapumaHome = os.environ.get("RAPUMA_BASE")
        self.defaultUserHome = os.environ.get("RAPUMA_USER")
        self.userConfFileName = "rapuma.conf"
        self.tools = Tools()

        # Point to the right user config
        # Look for a web installation first, if not go to default
        # Note that a slash is put before var as it is off of root
        # That kind of stops this from being cross-platform
        rapumaWebConfig = os.path.join("/var", "lib", "rapuma", "config", self.userConfFileName)
        defaultConfig = os.path.join(self.defaultUserHome, self.userConfFileName)
        if os.path.exists(rapumaWebConfig):
            self.userConfFile = rapumaWebConfig
        else:
            self.userConfFile = defaultConfig

        # Check to see if the file is there, then read it in and break it into
        # sections. If it fails, scream really loud!
        rapumaXMLDefaults = os.path.join(self.rapumaHome, "config", "rapuma.xml")
        if os.path.exists(rapumaXMLDefaults):
            self.tools.sysXmlConfig = self.tools.xml_to_section(rapumaXMLDefaults)
        else:
            raise IOError, "Can't open " + rapumaXMLDefaults

        #        import pdb; pdb.set_trace()

        # Now make the users local rapuma.conf file if it isn't there
        if not os.path.exists(self.userConfFile):
            self.initUserHome()

        # Load the Rapuma conf file into an object
        self.userConfig = ConfigObj(self.userConfFile, encoding="utf-8")

        # Initialize the user's home folders, like resources, etc
        self.makeHomeFolders()

        # Log messages for this module
        self.errorCodes = {"0000": ["MSG", "Placeholder message"]}
Beispiel #20
0
    def __init__(self, pid, cType, gid=None):
        """Do the primary initialization for this class."""

        self.pid = pid
        self.gid = gid
        self.cType = cType
        self.user = UserConfig()
        self.userConfig = self.user.userConfig
        self.projHome = os.path.join(os.path.expanduser(self.userConfig["Resources"]["projects"]), self.pid)
        self.local = ProjLocal(pid, gid, cType)

        #        import pdb; pdb.set_trace()

        self.proj_config = Config(pid)
        self.proj_config.getProjectConfig()
        self.projectConfig = self.proj_config.projectConfig
        self.layoutConfig = self.proj_config.layoutConfig
        self.tools = Tools()
        self.log = ProjLog(pid)
        # Create config placeholders
        self.layoutConfig = None
        self.illustrationConfig = None
        self.macroConfig = self.tools.loadConfig(self.local.macroConfFile, self.local.macroConfXmlFile)

        # Log messages for this module
        self.errorCodes = {
            "3010": ["ERR", "No macro package is registered for the [<<1>>] component type."],
            "3020": ["ERR", "Cannot update! No macro package is registered for the [<<1>>] component type."],
            "3050": ["ERR", "Macro package file not found: [<<1>>]"],
            "3100": [
                "ERR",
                "Macro package: [<<1>>] already exists in the project. I am not allowed to copy over an existing package.",
            ],
            "3200": ["ERR", "Failed to install macro package: [<<1>>]"],
            "3300": ["MSG", "Installed macro package: [<<1>>], Reinitialized [<<2>>]"],
            "3310": ["ERR", "Failed to copy [<<1>>] to folder [<<2>>]."],
            "3400": ["MSG", "Removed macro package configuration settings for: [<<1>>] from the macro.conf file."],
            "3500": ["MSG", "Removed macro package [<<1>>] folder and all files contained."],
            "3600": ["MSG", "Updated component type [<<1>>] with macro package [<<2>>]"],
            "3650": ["ERR", "Failed to updated macro package [<<1>>]"],
        }
Beispiel #21
0
    def __init__(self, pid, cType, gid=None) :
        '''Do the primary initialization for this class.'''

        self.pid                            = pid
        self.gid                            = gid
        self.cType                          = cType
        self.user                           = UserConfig()
        self.userConfig                     = self.user.userConfig
        self.projHome                       = os.path.join(os.path.expanduser(os.environ['RAPUMA_PROJECTS']), self.pid)
        self.local                          = ProjLocal(pid, gid, cType)


#        import pdb; pdb.set_trace()


        self.proj_config                    = Config(pid)
        self.proj_config.getProjectConfig()
        self.projectConfig                  = self.proj_config.projectConfig
        self.layoutConfig                   = self.proj_config.layoutConfig
        self.tools                          = Tools()
        self.log                            = ProjLog(pid)
        # Create config placeholders
        self.layoutConfig                   = None
        self.illustrationConfig             = None
        self.macroConfig                    = self.tools.loadConfig(self.local.macroConfFile, self.local.macroConfXmlFile)

        # Log messages for this module
        self.errorCodes     = {
            '3010' : ['ERR', 'No macro package is registered for the [<<1>>] component type.'],
            '3020' : ['ERR', 'Cannot update! No macro package is registered for the [<<1>>] component type.'],
            '3050' : ['ERR', 'Macro package file not found: [<<1>>]'],
            '3100' : ['ERR', 'Macro package: [<<1>>] already exists in the project. I am not allowed to copy over an existing package.'],
            '3200' : ['ERR', 'Failed to install macro package: [<<1>>]'],
            '3300' : ['MSG', 'Installed macro package: [<<1>>], Reinitialized [<<2>>]'],
            '3310' : ['ERR', 'Failed to copy [<<1>>] to folder [<<2>>].'],
            '3400' : ['MSG', 'Removed macro package configuration settings for: [<<1>>] from the macro.conf file.'],
            '3500' : ['MSG', 'Removed macro package [<<1>>] folder and all files contained.'],
            '3600' : ['MSG', 'Updated component type [<<1>>] with macro package [<<2>>]'],
            '3650' : ['ERR', 'Failed to updated macro package [<<1>>]']
        }
Beispiel #22
0
    def __init__(self, pid, gid) :
        '''Do the primary initialization for this class.'''

        self.pid                        = pid
        self.gid                        = gid
        self.tools                      = Tools()
        self.local                      = ProjLocal(pid)
        self.user                       = UserConfig()
        self.userConfig                 = self.user.userConfig
        self.proj_config                = Config(pid, gid)
        self.proj_config.getProjectConfig()
        self.projectConfig              = self.proj_config.projectConfig
        self.cType                      = self.projectConfig['Groups'][gid]['cType']
        self.Ctype                      = self.cType.capitalize()
        self.log                        = ProjLog(pid)



        # Log messages for this module
        self.errorCodes     = {

            '0000' : ['MSG', 'Placeholder message'],

            '1010' : ['MSG', 'Script install process for [<<1>>] Succeeded.'],
            '1020' : ['ERR', 'Script install process for [<<1>>] failed.'],
            '1030' : ['ERR', 'Script type [<<1>>] not supported.'],
            '1040' : ['ERR', 'Script install cannot proceed for [<<1>>] because this script already exists in the project. You must remove it first before you can add another script.'],

            '2010' : ['MSG', 'Script remove process for [<<1>>] Succeeded.'],
            '2020' : ['ERR', 'Script remove process for [<<1>>] failed.'],

            '4210' : ['MSG', 'Processes completed successfully on: [<<1>>] by [<<2>>]'],
            '4220' : ['ERR', 'Processes for [<<1>>] failed. Script [<<2>>] returned this error: [<<3>>]'],
            '4260' : ['ERR', 'Installed the default component preprocessing script. Editing will be required for it to work with your project.'],
            '4265' : ['LOG', 'Component preprocessing script is already installed.'],
            '4310' : ['ERR', 'Script is an unrecognized type: [<<1>>] Cannot continue with installation.']


        }
Beispiel #23
0
    def __init__(self, pid) :
        '''Do the primary initialization for this manager.'''

        self.pid                = pid
        self.tools              = Tools()
        self.user               = UserConfig()
        self.userConfig         = self.user.userConfig
        self.config             = Config(pid)
        self.pg_back            = ProjBackground(self.pid)
        self.config.getProjectConfig()
        self.config.getLayoutConfig()
        self.projectConfig      = self.config.projectConfig
        self.layoutConfig       = self.config.layoutConfig
        self.useBackground      = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useBackground'])
        self.useDocInfo         = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useDocInfo'])
        self.projHome           = os.path.join(self.userConfig['Resources']['projects'], self.pid)
        self.local              = ProjLocal(self.pid)
        self.log                = ProjLog(self.pid)
        self.pdfViewerCmd       = self.userConfig['System']['pdfViewerCommand']


        # Log messages for this module
        self.errorCodes     = {
            '0205' : ['MSG', 'Unassigned message.'],
            '0210' : ['MSG', 'No contents are specified for binding.'],
            '0215' : ['ERR', 'Failed to bind contents into the [<<1>>] fille. Got error: [<<2>>]'],
            '0220' : ['ERR', 'Could not copy [<<1>>] temp file to [<<2>>] saved binding file.'],
            '0230' : ['MSG', 'Completed proccessing on the [<<1>>] binding file.'],
            '0235' : ['ERR', 'Failed to complete proccessing on the [<<1>>] binding file.'],
            '0240' : ['LOG', 'Recorded [<<1>>] rendered pages in the [<<2>>] binding file.'],
            '0260' : ['ERR', 'PDF viewer failed with this error: [<<1>>]'],
            '0265' : ['ERR', 'Rendered file not found: <<1>>'],
            '0270' : ['WRN', 'PDF viewing is disabled.'],
            '0280' : ['ERR', 'GS PDF file merge failed with this error: [<<1>>]'],
            '0300' : ['MSG', 'File binding operation in process, please wait...']

        }
Beispiel #24
0
    def __init__(self, pid, gid = None) :
        '''Intitate the whole class and create the object.'''

#        import pdb; pdb.set_trace()

        self.pid                        = pid
        self.gid                        = gid
        self.local                      = ProjLocal(pid, gid)
        self.tools                      = Tools()
        self.proj_config                = Config(pid, gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getLayoutConfig()
        self.projectConfig              = self.proj_config.projectConfig
        self.layoutConfig               = self.proj_config.layoutConfig
        self.log                        = ProjLog(pid)
        self.user                       = UserConfig()
        self.userConfig                 = self.user.userConfig
        self.projHome                   = os.path.join(os.environ['RAPUMA_PROJECTS'], self.pid)
        self.mmToPx                     = 72 / 25.4
        # For debugging purposes a switch can be set here for verbose
        # message output via the terminal
        self.debugMode                  = self.tools.str2bool(self.userConfig['System']['debugging'])

        # Log messages for this module
        self.errorCodes     = {

            '0000' : ['MSG', 'Placeholder message'],
            '1110' : ['MSG', 'File exsits: [<<1>>]. Use \"force\" to remove it.'],
            '1280' : ['ERR', 'Failed to merge background file with command: [<<1>>]. This is the error: [<<2>>]'],
            '1290' : ['ERR', 'Failed to convert background file [<<1>>]. Error: [<<2>>] The command was: [<<3>>]'],
            '1300' : ['MSG', 'Background merge operation in process, please wait...'],
            '1305' : ['MSG', 'Adding document information, please wait...'],
            '1310' : ['WRN', 'Failed to add background component: [<<1>>] with error: [<<2>>]'],
            '1320' : ['MSG', 'New background created.']

        }
Beispiel #25
0
class Template (object) :

    def __init__(self, pid) :
        '''Intitate the whole class and create the object.'''

        self.pid            = pid
        self.tools          = Tools()
        self.user           = UserConfig()
        self.userConfig     = self.user.userConfig
        self.local          = ProjLocal(pid)
        self.log            = ProjLog(pid)
        self.projData       = ProjData(pid)


    def projectToTemplate (self, tid = None) :
        '''Preserve critical project information in a template. The pid is the project
        that the template will be bassed from. The template will go in the template lib.'''

        # Set needed vals
        if not tid :
            tid             = self.pid
        tempDir             = os.path.join(tempfile.mkdtemp(), tid)
        target              = os.path.join(self.local.userLibTemplate, tid + '.zip')

        # Make a temp copy of the project that we can manipulate
        shutil.copytree(self.local.projHome, tempDir)

        # Now make the config files generic for use with any project
        tc = ConfigObj(os.path.join(tempDir, 'Config', 'project.conf'), encoding='utf-8')
        tc['ProjectInfo']['projectTitle']               = ''
        tc['ProjectInfo']['projectIDCode']              = ''
        tc['ProjectInfo']['projectCreateDate']          = ''
        tc['ProjectInfo']['projectCreateDate']          = ''
        # Remove unnecessary folders
        needNot = ['Component', 'Deliverable', 'Illustration']
        for f in needNot :
            fld = os.path.join(tempDir, f)
            if os.path.exists(fld) :
                shutil.rmtree(fld)
        # Remove unnecessary config files
        needNot = ['adjustment', 'illustration']
        for f in needNot :
            fl = os.path.join(tempDir, 'Config', f + '.conf')
            if os.path.exists(fl) :
                os.remove(fl)
        # Remove unnecessary project config stuff
        needNot = ['Groups', 'Backup']
        for s in needNot :
            if tc.has_key(s) :
                del tc[s]
        # Write out the new template project config file
        tc.filename = os.path.join(tempDir, 'Config', 'project.conf')
        tc.write()

        # Kill the log file
        os.remove(os.path.join(tempDir, 'rapuma.log'))

        # Exclude files
        excludeFiles = self.projData.makeExcludeFileList(source)

        # Zip it up using the above params
        root_len = len(tempDir)
        with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as myzip :
            sys.stdout.write('Creating template')
            sys.stdout.flush()
            for root, dirs, files in os.walk(tempDir):
                # Chop off the part of the path we do not need to store
                zip_root = os.path.abspath(root)[root_len:]
                for f in files:
                    if f[-1] == '~' :
                        continue
                    elif f in excludeFiles :
                        continue
                    elif f.rfind('.') != -1 :
                        fullpath = os.path.join(root, f)
                        zip_name = os.path.join(zip_root, f)
                        sys.stdout.write('.')
                        sys.stdout.flush()
                        myzip.write(fullpath, zip_name, zipfile.ZIP_DEFLATED)

            # Add space for next message
            sys.stdout.write('\n')

        # Remove the temp project dir we made
        self.tools.terminal('\nCompleted creating template: ' + target + '\n')


    def templateToProject (self, targetDir = None, source = None) :
        '''Create a new project based on the provided template ID. If a path to
        the template is not provided it will look in the users template lib. A PID
        must be provided. That is checked with the system. If the same PID is
        found in the system, it must be removed before reruning this function. If
        a non-default location is needed, a target path must be provided.'''

#        import pdb; pdb.set_trace()

        # Set a default target path
        projHome = os.path.join(self.local.projParentDefaultFolder, self.pid)
        # See if we can build a better target path
        if targetDir != '' :
            projHome = os.path.join(targetDir, self.pid)
        elif self.local.projHome :
            projHome = os.path.join(self.local.projHome, self.pid)

#        self.tools.dieNow()

        # Test to see if the project already exists
        if self.pid in self.projList :
            self.tools.terminal('\nError: Project ID [' + self.pid + '] is already exists on this system. Use the remove command to remove it.')
            self.tools.dieNow()
        # Test for source template file
        if not source :
            source = os.path.join(self.local.userLibTemplate, self.pid + '.zip')
            if not os.path.exists(source) :
                self.tools.terminal('\nError: No template can be found for [' + self.pid + ']\n')
                self.tools.dieNow()

        # Unzip the template in place to start the new project
        with zipfile.ZipFile(source, 'r') as myzip :
            myzip.extractall(projHome)

        # Peek into the project
        pc = ConfigObj(os.path.join(projHome, 'Config', 'project.conf'), encoding='utf-8')
        pc['ProjectInfo']['projectCreateDate']         = self.tools.tStamp()
        pc['ProjectInfo']['projectIDCode']             = self.pid
        pc.filename                                    = os.path.join(projHome, 'Config', 'project.conf')
        pc.write()

        # Get the media type from the newly placed project for registration
        projectMediaIDCode = pc['ProjectInfo']['projectMediaIDCode']

        # Reset the local settings
        self.local = ProjLocal(self.pid)

        # Create any folders that might be needed
        for fld in self.local.projFolders :
            folder = os.path.join(self.local.projHome, fld)
            if not os.path.exists(folder) :
                os.makedirs(folder)

        # Report what happened
        self.tools.terminal('A new project [' + self.pid + '] has been created based on the [' + self.tools.fName(source) + '] template.')
Beispiel #26
0
class ProjData (object) :

    def __init__(self, pid, gid = None) :
        '''Intitate the whole class and create the object.'''

        self.pid            = pid
        self.gid            = gid
        self.tools          = Tools()
        self.user           = UserConfig()
        self.userConfig     = self.user.userConfig
        self.local          = ProjLocal(pid)
        self.log            = ProjLog(pid)
        self.projHome       = os.path.join(os.path.expanduser(self.userConfig['Resources']['projects']), self.pid)
        self.projList       = self.tools.getProjIdList(os.path.expanduser(self.userConfig['Resources']['projects']))

        # Log messages for this module
        self.errorCodes     = {

            '1220' : ['LOG', 'Project [<<1>>] already registered in the system.'],
            '1240' : ['ERR', 'Could not find/open the Project configuration file for [<<1>>]. Project could not be registered!'],

            '3410' : ['LOG', 'Backup file cull skipping: [<<1>>] Not a recognized Rapuma backup file name format.'],
            '3510' : ['ERR', 'The path (or name) given is not valid: [<<1>>].'],
            '3530' : ['MSG', 'Project backup: [<<1>>] has been restored to: [<<2>>]. A backup of the orginal project remains and must be manually removed.'],
            '3550' : ['ERR', 'Project backup version request: [<<1>>] exceeds the maxium number which could be in storage which is: [<<2>>]. Request an earlier (lesser) version.'],
            '3610' : ['ERR', 'The [<<1>>]. project is not registered. No backup was done.'],
            '3620' : ['ERR', 'The path to the backup folder is not valid [<<1>>]. Please try again.'],
            '3622' : ['ERR', 'The path to the backup folder is not set. Please set it and try again.'],
            '3625' : ['ERR', 'The path given to the backup folder is not valid [<<1>>]. Please set the system backup path.'],
            '3630' : ['MSG', 'Backup for [<<1>>] created and saved to: [<<2>>]'],

            '4110' : ['MSG', 'Completed merging data.'],
            '4120' : ['MSG', 'No files updated.'],
            '4130' : ['MSG', 'Added: <<1>> file(s).'],
            '4140' : ['MSG', 'Updated: <<1>> file(s)'],
            '4150' : ['WRN', 'The project data in: [<<1>>] will be replaced with the data from: [<<2>>].'],

            '4210' : ['MSG', 'Completed pulling/restoring data from the cloud.'],
            '4220' : ['ERR', 'Cannot resolve path: [<<1>>]'],
            '4250' : ['ERR', 'The cloud project [<<1>>] you want to pull from is owned by [<<2>>]. Use force (-f) to pull the project and change the local owner ID.'],
            '4260' : ['ERR', 'The local project [<<1>>] is newer than the cloud copy. If you seriously want to overwrite it, use force (-f) to do so.'],
            '4270' : ['MSG', 'Restored the project [<<1>>] from the cloud copy. Local copy is owned by [<<2>>].'],

        }


###############################################################################
############################## General Functions ##############################
###############################################################################
####################### Error Code Block Series = 1000 ########################
###############################################################################



###############################################################################
########################## Archive Project Functions ##########################
###############################################################################
####################### Error Code Block Series = 2000 ########################
###############################################################################

    def makeExcludeFileList (self, source) :
        '''Return a list of files that are not necessary to be included in a backup
        template or an archive. These will be all auto-generated files that containe system-
        specific paths, etc.'''

        excludeFiles        = []
        excludeTypes        = ['delayed', 'log', 'notepages', 'parlocs', 'pdf', 'tex', 'piclist', 'adj', 'zip']
        excludeFolders      = ['Draft', 'Final', 'HelperScript', 'Proof']

        # Process the excluded folders
        for root, dirs, files in os.walk(source) :
            for fileName in files :
                if os.path.basename(root) in excludeFolders :
                    excludeFiles.append(os.path.join(root, fileName))
                else :
                    # Get rid of edited backup files
                    if fileName[-1] == '~' :
                        excludeFiles.append(os.path.join(root, fileName))
                        continue
                    ext = os.path.splitext(fileName)[1][1:]
                    if ext in excludeTypes :
                        # A special indicator for file we want to keep
                        if fileName.find('-ext.') > 0 :
                            continue

        return excludeFiles

# FIXME: Should archiveProject() use self.pid instead of explicitly passing in a pid?
    def archiveProject (self, pid, path = None) :
        '''Archive a project. Send the compressed archive file to the user-specified
        archive folder. If none is specified, put the archive in cwd. If a valid
        path is specified, send it to that location. Like backup, this too will
        overwrite any existing file of the same name. The difference is that this
        will also disable the project so it cannot be accesses by Rapuma. When a
        project is archived, all work should cease on the project.'''

        # Make a private project object just for archiving
        aProject = Project(pid, self.gid)
        # Set some paths and file names
        archName = aProject.projectIDCode + '.rapuma'
        userArchives = self.userConfig['Resources']['archive']
        archTarget = ''
        if path :
            path = self.tools.resolvePath(path)
            if os.path.isdir(path) :
                archTarget = os.path.join(path, archName)
            else :
                self.tools.terminal('\nError: The path given is not valid: [' + path + ']\n')
                self.tools.dieNow()
        elif os.path.isdir(userArchives) :
            archTarget = os.path.join(userArchives, archName)
        elif os.path.isdir(os.path.dirname(aProject.local.projHome)) :
            # Default to the dir just above the project
            archTarget = os.path.dirname(aProject.local.projHome)
        else :
            self.tools.terminal('\nError: Cannot resolve a path to create the archive file!\n')
            self.tools.dieNow()

        # Get a list of files we don't want
        excludeFiles = self.makeExcludeFileList(source)

        self.zipUpProject(archTarget, excludeFiles)

        # Rename the source dir to indicate it was archived
        bakArchProjDir = aProject.local.projHome + '(archived)'
        if os.path.isdir(bakArchProjDir) :
            self.tools.terminal('\nError: Cannot complete archival process!\n')
            self.tools.terminal('\nAnother archived version of this project exsits with the folder name of: ' + self.tools.fName(bakArchProjDir) + '\n')
            self.tools.terminal('\nPlease remove or rename it and then repete the process.\n')
            self.tools.dieNow()
        else :
            os.rename(aProject.local.projHome, bakArchProjDir)

        # Finish here
        self.tools.terminal('Archive for [' + pid + '] created and saved to: ' + archTarget + '\n')


    def zipUpProject (self, target, excludeFiles = None) :
        '''Zip up a project and deposit it to target location. Be sure to strip
        out all all auto-created, user-specific files that could mess up a
        transfer to another system. This goes for archives and backups'''

#        import pdb; pdb.set_trace()

        # In case an exclude list is not given
        if not excludeFiles :
            excludeFiles = []

        # Do the zip magic here
        root_len = len(self.local.projHome)
        with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as myzip :
            sys.stdout.write('Backing up files')
            sys.stdout.flush()
            for root, dirs, files in os.walk(self.local.projHome) :
                # Chop off the part of the path we do not need to store
                zip_root = os.path.abspath(root)[root_len:]
                for f in files :
                    if os.path.join(root, f) in excludeFiles :
                        continue
                    if not f[-1] == '~' :
                        fn, fx = os.path.splitext(f)
                        fullpath = os.path.join(root, f)
                        zip_name = os.path.join(zip_root, f)
                        sys.stdout.write('.')
                        sys.stdout.flush()
                        myzip.write(fullpath, zip_name, zipfile.ZIP_DEFLATED)
            # Add a space before the next message
            print '\n'

# FIXME: Should restoreArchive() use self.pid instead of explicitly passing in a pid?
    def restoreArchive (self, pid, targetPath, sourcePath = None) :
        '''Restore a project from the user specified storage area or sourcePath if 
        specified. Use targetPath to specify where the project will be restored.
        Rapuma will register the project there.'''

        # Check to see if the user included the extension
        try :
            pid.split('.')[1] == 'rapuma'
            archName = pid
            pid = pid.split('.')[0]
        except :
            archName = pid + '.rapuma'

        archSource = ''
        archTarget = ''
        userArchives = ''

        # First look for the archive that is to be restored
        if sourcePath :
            if os.path.isdir(sourcePath) :
                archSource = os.path.join(sourcePath, archName)
        elif os.path.isdir(self.userConfig['Resources']['archive']) :
            userArchives = self.userConfig['Resources']['archive']
            archSource = os.path.join(userArchives, archName)
        else :
            self.tools.terminal('\nError: The path (or name) given is not valid: [' + archSource + ']\n')
            self.tools.dieNow()

        # Now set the target params
        if targetPath :
            if not os.path.isdir(targetPath) :
                self.tools.terminal('\nError: The path given is not valid: [' + targetPath + ']\n')
                self.tools.dieNow()
            else :
                archTarget = os.path.join(targetPath, pid)

        # If we made it this far, extract the archive
        with zipfile.ZipFile(archSource, 'r') as myzip :
            myzip.extractall(archTarget)

        # Permission for executables is lost in the zip, fix it here
        for folder in ['Scripts', os.path.join('Macros', 'User')] :
            self.tools.fixExecutables(os.path.join(archTarget, folder))

# FIXME: This will need some work 

        # Add project to local Rapuma project registry
        # To do this we need to open up the restored project config file
        # and pull out some settings.
        local       = ProjLocal(pid)
        pc          = Config(pid)
        log         = ProjLog(pid)
        aProject    = Project(pid, self.gid)
    #    import pdb; pdb.set_trace()

        # Finish here
        self.tools.terminal('\nRapuma archive [' + pid + '] has been restored to: ' + archTarget + '\n')


###############################################################################
########################### Backup Project Functions ##########################
###############################################################################
####################### Error Code Block Series = 3000 ########################
###############################################################################

    def cullBackups (self, maxBak, bakDir) :
        '''Remove any excess backups from the backup folder in
        this project.'''

        # Get number of maximum backups to store
        maxStoreBackups = int(maxBak)
        if not maxStoreBackups or maxStoreBackups == 0 :
            maxStoreBackups = 1

        # Build the cullList
        cullList = []
        files = os.listdir(bakDir)
        for f in files :
            try :
                cullList.append(int(f.split('.')[0]))
            except :
                self.log.writeToLog(self.errorCodes['3410'], [f])
        # Remove oldest file(s)
        while len(cullList) > maxStoreBackups :
            fn = min(cullList)
            cullList.remove(min(cullList))
            os.remove(os.path.join(bakDir, str(fn) + '.zip'))


    def backupProject (self, targetPath=None) :
        '''Backup a project. Send the compressed backup file with a date-stamp
        file name to the user-specified backup folder. If a target path is 
        specified, put the archive there but use the PID in the name. If other
        backups with the same name exist there, increment with a number.'''

        # First see if this is even a valid project
        if self.pid not in self.projList :
            self.log.writeToLog(self.errorCodes['3610'], [self.pid])

        # Set some paths and file names
        if not targetPath :
            # Now check for a valid location to backup to
            if self.local.userLibBackup == '' :
                self.log.writeToLog(self.errorCodes['3622'])
            elif not os.path.exists(self.local.userLibBackup) :
                self.log.writeToLog(self.errorCodes['3620'], [self.local.userLibBackup])
            projBackupFolder    = os.path.join(self.local.userLibBackup, self.pid)
            backupTarget        = os.path.join(projBackupFolder, self.tools.fullFileTimeStamp() + '.zip')
        else :
            projBackupFolder    = self.tools.resolvePath(targetPath)
            # Now check for a valid target path
            if not os.path.exists(projBackupFolder) :
                self.log.writeToLog(self.errorCodes['3625'], [targetPath])
            backupTarget        = self.tools.incrementFileName(os.path.join(projBackupFolder, self.pid + '.zip'))

        # Make sure the dir is there
        if not os.path.exists(projBackupFolder) :
            os.makedirs(projBackupFolder)

#        import pdb; pdb.set_trace()

        # Zip up but use a list of files we don't want
        self.zipUpProject(backupTarget, self.makeExcludeFileList(source))

        # Cull out any excess backups
        if not targetPath :
            self.cullBackups(self.userConfig['System']['maxStoreBackups'], projBackupFolder)

        # Finish here
        pc = Config(self.pid)
        pc.getProjectConfig()
        pc.projectConfig['Backup']['lastBackup'] = self.tools.fullFileTimeStamp()
        self.tools.writeConfFile(pc.projectConfig)
        self.log.writeToLog(self.errorCodes['3630'], [self.pid,backupTarget])
        return True


    def backupRestore (self, backup, target = None) :
        '''Restore a backup to the current or specified project.'''

#        import pdb; pdb.set_trace()

        if not target :
            target = self.local.projHome

        # Now remove the orginal
        if os.path.exists(target) :
            shutil.rmtree(target)
        # Create an empty folder to restore to
        os.makedirs(target)

        # If we made it this far, extract the archive
        with zipfile.ZipFile(backup, 'r') as myzip :
            myzip.extractall(target)
        return True


#    def restoreLocalBackup (self, bakFile) :
#        '''Restore from a project backup. As a project may have multiple backups in
#        its backup folder, the user will need to provide a number from 1 to n (n being
#        the number of backups in the folder, 1 being the most recent and n being the
#        oldest). If no number is provided, 1, (the most recent) will be restored.'''

#        # Adjust bNum if needed
#        maxBak = int(self.userConfig['System']['maxStoreBackups'])
#        if not bNum :
#            bNum = 0
#        else :
#            bNum = int(bNum)
#            if bNum <= 0 :
#                bNum = 0
#            elif bNum > maxBak :
#                self.log.writeToLog(self.errorCodes['3550'], [str(bNum), str(maxBak)])
#            else :
#                bNum = bNum-1

#        # Get vals we need
#        projHome            = self.getProjHome()
#        projBackupFolder    = self.tools.resolvePath(os.path.join(self.userConfig['Resources']['backup'], self.pid))

#        # Get the archive file name
#        files = os.listdir(projBackupFolder)
#        fns = []
#        for f in files :
#            fns.append(int(f.split('.')[0]))
#        # Sort the list, last (latest) first
#        fns.sort(reverse=True)
#        # Make file path/name
#        backup = os.path.join(projBackupFolder, str(fns[bNum]) + '.zip')
#        if not os.path.exists(backup) :
#            self.log.writeToLog(self.errorCodes['3510'], [backup])

#        # Restore the backup
#        self.backupRestore(backup, projHome)

#        # Permission for executables is lost in the zip, fix them here
#        self.tools.fixExecutables(projHome)

#        # Add helper scripts if needed
#        if self.tools.str2bool(self.userConfig['System']['autoHelperScripts']) :
#            ProjCommander(self.pid).updateScripts()

#        # Finish here (We will leave the project backup in place)
#        self.log.writeToLog(self.errorCodes['3530'], [self.tools.fName(backup),projHome])


    def restoreExternalBackup (self, source, target = None, force = False) :
        '''Restore a non-existant project from an external backup to a target folder.
        If no target is provided the project will be installed in the default project
        folder. The source path and ZIP file must be valid'''

        # Get/make the (localized) project home reference
        projHome = self.getProjHome(target)

#        import pdb; pdb.set_trace()

        # Create the source backup file name
#        source = os.path.join(source, self.pid + '.zip')

# FIXME: This needs some review and rework

        # Restore the backup
        if self.backupRestore(source, projHome) :

            # Permission for executables is lost in the zip, fix them here
            self.tools.fixExecutables(projHome)

            # If this is a new project we will need to register it now
            self.registerProject(projHome)

            # Add helper scripts if needed
            if self.tools.str2bool(self.userConfig['System']['autoHelperScripts']) :
                ProjCommander(self.pid).updateScripts()

            # Finish here (We will leave the backup-backup in place)
            self.tools.terminal('\nRapuma backup [' + self.pid + '] has been restored to: ' + projHome + '\n')
            
            return True


###############################################################################
############################ Cloud Backup Functions ###########################
###############################################################################
####################### Error Code Block Series = 4000 ########################
###############################################################################


    def isNewerThanCloud (self, cloud, projectConfig) :
        '''Compare time stamps between the cloud and the local project.
        Return True if the local project is newer or the same age as
        the copy in the cloud. Return True if the project does not
        exist in the local copy of the cloud.'''

        # First see if it exists
        cConfig = self.getConfig(cloud)
        if not cConfig :
            return True
        elif not cConfig.has_key('Backup') :
            return True
        elif not cConfig['Backup'].has_key('lastCloudPush') :
            return True
        # Check local for key
        if not projectConfig.has_key('Backup') :
            return False
        elif not projectConfig['Backup'].has_key('lastCloudPush') :
            return False
        # Compare if we made it this far
        cStamp = cConfig['Backup']['lastCloudPush']
        lStamp = projectConfig['Backup']['lastCloudPush']
        if lStamp >= cStamp :
            return True


    def isNewerThanLocal (self, cloud, projectConfig) :
        '''Compare time stamps between the cloud and the local project.
        Return True if the cloud project is newer or the same age as
        the local copy. Return True if the project does not exist in
        as a local copy.'''

        # First see if the local exists
        if not projectConfig :
            return True

        # See if cloud is there and up-to-date
        cloudConfig = self.getConfig(cloud)
        if not cloudConfig :
            return False

        # Compare if we made it this far
        cStamp = cloudConfig['Backup']['lastCloudPush']
        # It is possible the local has never been pushed
        # If that is the case, local is assumed older
        try :
            pStamp = projectConfig['Backup']['lastCloudPush']
        except :
            return False
        if cStamp >= pStamp :
            return True


    def getConfig (self, projHome) :
        '''Return a valid config object from cloud project.'''

#        import pdb; pdb.set_trace()

        projectConfigFile = os.path.join(projHome, 'Config', 'project.conf')
        if os.path.exists(projectConfigFile) :
            return ConfigObj(projectConfigFile, encoding='utf-8')


    def getCloudOwner (self, cloud) :
        '''Return the owner of a specified cloud project.'''

        try :
            return self.getConfig(cloud)['Backup']['ownerID']
        except :
            return None


    def getLocalOwner (self) :
        '''Return the owner of a specified cloud project.'''

        return self.userConfig['System']['userID']


    def sameOwner (self, cloud) :
        '''Return True if the owner of a given cloud is the same as
        the system user. Also return True if the cloud owner is not
        present.'''

        # First check for existence
        if not self.getCloudOwner(cloud) :
            return True
        # Compare if we made it to this point
        if self.getCloudOwner(cloud) == self.getLocalOwner() :
            return True


    def setCloudPushTime (self, projectConfig) :
        '''Set/reset the lastPush time stamp setting.'''

        projectConfig['Backup']['lastCloudPush'] = self.tools.fullFileTimeStamp()
        self.tools.writeConfFile(projectConfig)


    def buyCloud (self, projectConfig) :
        '''Change the ownership on a project in the cloud by assigning
        your userID to the local project cloudOwnerID. Then, using force
        the next time the project is pushed to the cloud, you will own it.'''

        projOwnerID = self.userConfig['System']['userID']
        projectConfig['Backup']['ownerID'] = projOwnerID
        self.tools.writeConfFile(projectConfig)


    def buyLocal (self, projectConfig) :
        '''Change the ownership on a local project by assigning your
        userID to it.'''

        projOwnerID = self.userConfig['System']['userID']
        projectConfig['Backup']['ownerID'] = projOwnerID
        self.tools.writeConfFile(projectConfig)


    def replaceProject (self, source, target) :
        '''This will completly replace an existing project (target)
        with data from another project (source). This assumes
        source and target are valid.'''

        # We simply just get rid of the target before doing a merge
        shutil.rmtree(target)
        self.log.writeToLog(self.errorCodes['4150'], [target, source])
        self.mergeProjects(source, target)


    def mergeProjects(self, source, target) :
        '''This will merge two Rapuma projects and try to preserve
        data in the target that is newer than the source. This assumes
        target and source are valid.'''
        
        # Get a list of files we do not want
        excludeFiles        = self.makeExcludeFileList(source)

        # Get a total list of files from the project
        cn = 0
        cr = 0
        # Add space for output message
        sys.stdout.write('\n')
        sys.stdout.write('Merging files from: ' + source + ' to: ' + target)
        sys.stdout.flush()
        for folder, subs, files in os.walk(source):
            for fileName in files:
                # Do not include any backup files we find
                if fileName[-1] == '~' :
                    continue
                if os.path.join(folder, fileName) not in excludeFiles :
                    if not os.path.isdir(folder.replace(source, target)) :
                        os.makedirs(folder.replace(source, target))
                    targetFile = os.path.join(folder, fileName).replace(source, target)
                    sourceFile = os.path.join(folder, fileName)
                    if not os.path.isfile(targetFile) :
                        sys.stdout.write('.')
                        sys.stdout.flush()
                        shutil.copy(sourceFile, targetFile)
                        cn +=1
                    # Otherwise if the cloud file is older than
                    # the project file, refresh it
                    elif self.tools.isOlder(targetFile, sourceFile) :
                        if os.path.isfile(targetFile) :
                            os.remove(targetFile)
                        sys.stdout.write('.')
                        sys.stdout.flush()
                        shutil.copy(sourceFile, targetFile)
                        cr +=1
        # Add space for next message
        sys.stdout.write('\n')


        # Report what happened
        self.log.writeToLog(self.errorCodes['4110'])
        if cn == 0 and cr == 0 :
            self.log.writeToLog(self.errorCodes['4120'])
        else :
            if cn > 0 :
                self.log.writeToLog(self.errorCodes['4130'], [str(cn)])
            if cr > 0 :
                self.log.writeToLog(self.errorCodes['4140'], [str(cr)])

        return True


    def getProjHome (self, tPath = None) :
        '''Return a project home path by checking to see what the best path
        might be. Provided path gets first dibs, then '''

        if tPath :
            if os.path.isfile(tPath) :
                return self.local.projHome
            elif self.tools.resolvePath(tPath) :
                tPath = self.tools.resolvePath(tPath)
                lastFolder = os.path.basename(tPath)
                if lastFolder == self.pid :
                    return tPath
                else :
                    return os.path.join(tPath, self.pid)
            else :
                self.log.writeToLog(self.errorCodes['4220'], [tPath])
        elif self.local.projHome :
            return self.local.projHome
        else :
            return self.tools.resolvePath(os.path.join(self.userConfig['Resources']['projects'], self.pid))
Beispiel #27
0
    def __init__(self, project, cfg, cType) :
        '''Do the primary initialization for this manager.'''

        super(Xetex, self).__init__(project, cfg)

#        import pdb; pdb.set_trace()

        # Create all the values we can right now for this manager.
        # Others will be created at run time when we know the cid.
        self.tools                  = Tools()
        self.project                = project
        self.local                  = project.local
        self.log                    = project.log
        self.cfg                    = cfg
        self.pid                    = project.projectIDCode
        self.gid                    = project.gid
        self.cType                  = cType
        self.Ctype                  = cType.capitalize()
        self.mType                  = project.projectMediaIDCode
        self.renderer               = 'xetex'
        self.manager                = self.cType + '_' + self.renderer.capitalize()
        self.managers               = project.managers
        self.pg_back                = ProjBackground(self.pid, self.gid)
        self.fmt_diagnose           = ProjDiagnose(self.pid, self.gid)
        self.proj_config            = Config(self.pid, self.gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getLayoutConfig()
        self.proj_config.getFontConfig()
        self.proj_config.getMacroConfig()
        # Bring in some manager objects we will need
        self.proj_font              = ProjFont(self.pid)
        self.proj_illustration      = ProjIllustration(self.pid, self.gid)
        self.proj_hyphenation       = ProjHyphenation(self.pid, self.gid)
        self.usfmData               = UsfmData()
        self.cidChapNumDict         = self.usfmData.cidChapNumDict()
        self.cidPtIdDict            = self.usfmData.cidPtIdDict()
        # Get config objs
        self.projectConfig          = self.proj_config.projectConfig
        self.layoutConfig           = self.proj_config.layoutConfig
        self.fontConfig             = self.proj_config.fontConfig
        self.macroConfig            = self.proj_config.macroConfig
        self.userConfig             = self.project.userConfig
        self.macPackId              = self.projectConfig['CompTypes'][self.Ctype]['macroPackage']
        # Some config settings

        self.pdfViewerCmd           = self.tools.getPdfViewerCommand(self.userConfig, self.projectConfig)
        self.sourceEditor           = self.projectConfig['CompTypes'][self.Ctype]['sourceEditor']
        self.useBackground          = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useBackground'])
        self.useDiagnostic          = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useDiagnostic'])
        self.useDocInfo             = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useDocInfo'])

        # Get settings for this component
        self.managerSettings = self.projectConfig['Managers'][self.manager]
        for k, v in self.managerSettings.iteritems() :
            if v == 'True' or v == 'False' :
                setattr(self, k, self.tools.str2bool(v))
            else :
                setattr(self, k, v)

        # Set some Booleans (this comes after persistant values are set)
        # Setting hyphenation is a 2 step process, first check global, then group
        self.useHyphenation         = False
        if self.tools.str2bool(self.projectConfig['ProjectInfo']['hyphenationOn']) :
            if self.tools.str2bool(self.projectConfig['Groups'][self.gid]['useHyphenation']) :
                self.useHyphenation = True
                
        # In case the macro is not installed we need to skip over this
        try :
            self.chapNumOffSingChap     = self.tools.str2bool(self.macroConfig['Macros'][self.macPackId]['ChapterVerse']['omitChapterNumberOnSingleChapterBook'])
        except :
            self.chapNumOffSingChap     = None
        # Make any dependent folders if needed
        if not os.path.isdir(self.local.projGidFolder) :
            os.makedirs(self.local.projGidFolder)

        # Record some error codes
        # FIXME: much more needs to be done with this
        self.xetexErrorCodes =  {
            0   : 'Rendering succeful.',
            256 : 'Something really awful happened.'
                                }

        # Log messages for this module
        self.errorCodes     = {

            '1005' : ['ERR', 'PDF viewer failed with error: [<<1>>]'],
            '1010' : ['ERR', 'Style file [<<1>>] could not be created.'],
            '1040' : ['LOG', 'Created: [<<1>>]'],

            '0420' : ['WRN', 'TeX settings file has been frozen for debugging purposes.'],
            '0440' : ['LOG', 'Created: [<<1>>]'],
            '0460' : ['LOG', 'Settings changed in [<<1>>], [<<2>>] needed to be recreated.'],
            '0465' : ['LOG', 'File: [<<1>>] missing, created a new one.'],
            '0470' : ['ERR', 'Macro package [<<1>>] is not recognized by the system.'],

            '0600' : ['MSG', '<<1>> cannot be viewed, PDF viewer turned off.'],
            '0610' : ['LOG', 'Recorded [<<1>>] rendered pages in the [<<2>>] group.'],
            '0615' : ['ERR', 'XeTeX failed to execute with error: <<1>>'],
            '0617' : ['ERR', 'XeTeX failed to execute with this error: [<<1>>]'],
            '0620' : ['DBG', 'xetex command in <<1>>: <<2>> <<3>>'],
            '0625' : ['MSG', 'Rendering of [<<1>>] successful.'],
            '0630' : ['ERR', 'Rendering [<<1>>] was unsuccessful. <<2>> (<<3>>)'],
            '0635' : ['ERR', 'XeTeX error code [<<1>>] not understood by Rapuma.'],
            '0650' : ['ERR', 'Component type [<<1>>] not supported!'],
            '0690' : ['MSG', 'Dependent files unchanged, rerendering of [<<1>>] un-necessary.'],
            '0695' : ['MSG', 'Routing <<1>> to PDF viewer.'],
            '0700' : ['ERR', 'Rendered file not found: <<1>>'],
            '0710' : ['WRN', 'PDF viewing is disabled.'],
            '0720' : ['MSG', 'Saved rendered file to: [<<1>>]'],
            '0730' : ['ERR', 'Failed to save rendered file to: [<<1>>]'],

            '1000' : ['WRN', 'XeTeX debugging is set to [<<1>>]. These are the paths XeTeX is seeing: [<<2>>]'],
            '1090' : ['ERR', 'Invalid value [<<1>>] used for XeTeX debugging. Must use an integer of 0, 1, 2, 4, 8, 16, or 32']

        }
Beispiel #28
0
class Xetex (Manager) :

    # Shared values
    xmlConfFile     = 'xetex.xml'

    def __init__(self, project, cfg, cType) :
        '''Do the primary initialization for this manager.'''

        super(Xetex, self).__init__(project, cfg)

#        import pdb; pdb.set_trace()

        # Create all the values we can right now for this manager.
        # Others will be created at run time when we know the cid.
        self.tools                  = Tools()
        self.project                = project
        self.local                  = project.local
        self.log                    = project.log
        self.cfg                    = cfg
        self.pid                    = project.projectIDCode
        self.gid                    = project.gid
        self.cType                  = cType
        self.Ctype                  = cType.capitalize()
        self.mType                  = project.projectMediaIDCode
        self.renderer               = 'xetex'
        self.manager                = self.cType + '_' + self.renderer.capitalize()
        self.managers               = project.managers
        self.pg_back                = ProjBackground(self.pid, self.gid)
        self.fmt_diagnose           = ProjDiagnose(self.pid, self.gid)
        self.proj_config            = Config(self.pid, self.gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getLayoutConfig()
        self.proj_config.getFontConfig()
        self.proj_config.getMacroConfig()
        # Bring in some manager objects we will need
        self.proj_font              = ProjFont(self.pid)
        self.proj_illustration      = ProjIllustration(self.pid, self.gid)
        self.proj_hyphenation       = ProjHyphenation(self.pid, self.gid)
        self.usfmData               = UsfmData()
        self.cidChapNumDict         = self.usfmData.cidChapNumDict()
        self.cidPtIdDict            = self.usfmData.cidPtIdDict()
        # Get config objs
        self.projectConfig          = self.proj_config.projectConfig
        self.layoutConfig           = self.proj_config.layoutConfig
        self.fontConfig             = self.proj_config.fontConfig
        self.macroConfig            = self.proj_config.macroConfig
        self.userConfig             = self.project.userConfig
        self.macPackId              = self.projectConfig['CompTypes'][self.Ctype]['macroPackage']
        # Some config settings

        self.pdfViewerCmd           = self.tools.getPdfViewerCommand(self.userConfig, self.projectConfig)
        self.sourceEditor           = self.projectConfig['CompTypes'][self.Ctype]['sourceEditor']
        self.useBackground          = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useBackground'])
        self.useDiagnostic          = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useDiagnostic'])
        self.useDocInfo             = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useDocInfo'])

        # Get settings for this component
        self.managerSettings = self.projectConfig['Managers'][self.manager]
        for k, v in self.managerSettings.iteritems() :
            if v == 'True' or v == 'False' :
                setattr(self, k, self.tools.str2bool(v))
            else :
                setattr(self, k, v)

        # Set some Booleans (this comes after persistant values are set)
        # Setting hyphenation is a 2 step process, first check global, then group
        self.useHyphenation         = False
        if self.tools.str2bool(self.projectConfig['ProjectInfo']['hyphenationOn']) :
            if self.tools.str2bool(self.projectConfig['Groups'][self.gid]['useHyphenation']) :
                self.useHyphenation = True
                
        # In case the macro is not installed we need to skip over this
        try :
            self.chapNumOffSingChap     = self.tools.str2bool(self.macroConfig['Macros'][self.macPackId]['ChapterVerse']['omitChapterNumberOnSingleChapterBook'])
        except :
            self.chapNumOffSingChap     = None
        # Make any dependent folders if needed
        if not os.path.isdir(self.local.projGidFolder) :
            os.makedirs(self.local.projGidFolder)

        # Record some error codes
        # FIXME: much more needs to be done with this
        self.xetexErrorCodes =  {
            0   : 'Rendering succeful.',
            256 : 'Something really awful happened.'
                                }

        # Log messages for this module
        self.errorCodes     = {

            '1005' : ['ERR', 'PDF viewer failed with error: [<<1>>]'],
            '1010' : ['ERR', 'Style file [<<1>>] could not be created.'],
            '1040' : ['LOG', 'Created: [<<1>>]'],

            '0420' : ['WRN', 'TeX settings file has been frozen for debugging purposes.'],
            '0440' : ['LOG', 'Created: [<<1>>]'],
            '0460' : ['LOG', 'Settings changed in [<<1>>], [<<2>>] needed to be recreated.'],
            '0465' : ['LOG', 'File: [<<1>>] missing, created a new one.'],
            '0470' : ['ERR', 'Macro package [<<1>>] is not recognized by the system.'],

            '0600' : ['MSG', '<<1>> cannot be viewed, PDF viewer turned off.'],
            '0610' : ['LOG', 'Recorded [<<1>>] rendered pages in the [<<2>>] group.'],
            '0615' : ['ERR', 'XeTeX failed to execute with error: <<1>>'],
            '0617' : ['ERR', 'XeTeX failed to execute with this error: [<<1>>]'],
            '0620' : ['DBG', 'xetex command in <<1>>: <<2>> <<3>>'],
            '0625' : ['MSG', 'Rendering of [<<1>>] successful.'],
            '0630' : ['ERR', 'Rendering [<<1>>] was unsuccessful. <<2>> (<<3>>)'],
            '0635' : ['ERR', 'XeTeX error code [<<1>>] not understood by Rapuma.'],
            '0650' : ['ERR', 'Component type [<<1>>] not supported!'],
            '0690' : ['MSG', 'Dependent files unchanged, rerendering of [<<1>>] un-necessary.'],
            '0695' : ['MSG', 'Routing <<1>> to PDF viewer.'],
            '0700' : ['ERR', 'Rendered file not found: <<1>>'],
            '0710' : ['WRN', 'PDF viewing is disabled.'],
            '0720' : ['MSG', 'Saved rendered file to: [<<1>>]'],
            '0730' : ['ERR', 'Failed to save rendered file to: [<<1>>]'],

            '1000' : ['WRN', 'XeTeX debugging is set to [<<1>>]. These are the paths XeTeX is seeing: [<<2>>]'],
            '1090' : ['ERR', 'Invalid value [<<1>>] used for XeTeX debugging. Must use an integer of 0, 1, 2, 4, 8, 16, or 32']

        }

        # FIXME: It would be good if we could do a check for dependent files here


###############################################################################
############################ Manager Level Functions ##########################
###############################################################################
######################## Error Code Block Series = 1000 #######################
###############################################################################

    def checkStartPageNumber (self) :
        '''Adjust page number for the current group. The current logic is
        if there is no number in the startPageNumber setting, we can put
        one in there as a suggestion. If there is already one there, the
        user will be responsible for seeing that it is correct.'''

#        import pdb; pdb.set_trace()

        try :
            # Simply try to return anything that is in the field
            cStrPgNo = self.projectConfig['Groups'][self.gid]['startPageNumber']
            if cStrPgNo != '' :
                return cStrPgNo
        except :
            # If nothing is there, we'll make a suggestion
            pGrp = str(self.projectConfig['Groups'][self.gid]['precedingGroup'])
            if pGrp == 'None' :
                self.projectConfig['Groups'][self.gid]['startPageNumber'] = 1
                self.tools.writeConfFile(self.projectConfig)
                return '1'
            else :
                # Calculate the suggested number based on the preceeding group
                try :
                    cStrPgNo    = str(self.projectConfig['Groups'][self.gid]['startPageNumber'])
                except :
                    cStrPgNo    = 1
                    self.projectConfig['Groups'][self.gid]['startPageNumber'] = 1
                try :
                    pGrpPgs     = int(self.projectConfig['Groups'][pGrp]['totalPages'])
                    pGrpStrPgNo = int(self.projectConfig['Groups'][pGrp]['startPageNumber'])
                except :
                    # FIXME: Maybe this could go out and find out exactly how many pages were in the preceeding group
                    pGrpPgs     = 1
                    pGrpStrPgNo = 1
                    self.projectConfig['Groups'][pGrp]['totalPages'] = 1
                    self.projectConfig['Groups'][pGrp]['startPageNumber'] = 1
                # Whether this is right or wrong set it the way it is
                self.projectConfig['Groups'][self.gid]['startPageNumber'] = (pGrpStrPgNo + pGrpPgs)
                self.tools.writeConfFile(self.projectConfig)
                return self.projectConfig['Groups'][pGrp]['startPageNumber']


    def makeExtFile (self, fileName, description) :
        '''Generic function to create an extension file if one does not already exist.'''

        if not os.path.exists(fileName) :
            with codecs.open(fileName, "w", encoding='utf_8') as writeObject :
                writeObject.write(self.tools.makeFileHeader(fileName, description, False))
            self.log.writeToLog(self.errorCodes['1040'], [self.tools.fName(fileName)])
            return True


    def makeCmpExtTexFileOn (self, fileName) :
        '''Create a component TeX extention macro "on" file for a specified component. A matching "off"
        file will be created as well.'''

        description = 'This is a component (on) TeX macro extension file which may override any macros \
        which were loaded for this rendering process. This file is read just before the component \
        working file. After the component is rendered, the accompanying off TeX file will be \
        loaded which will turn off any modified macro commands that this TeX file has set. The \
        user must edit this file in order for it to work right.'

        return self.makeExtFile(fileName, description)


    def makeCmpExtTexFileOff (self, fileName) :
        '''Create a component TeX extention macro "off" file for a specified component. This is to
        match the "on" file that was created.'''

        description = 'This is a component (off) style extension file which overrides the settings \
        that were loaded for this rendering process just prior to loading the component working \
        file. The commands in this style file will off-set the "on" settings causing the macro to \
        render as it did before the "on" styles were loaded. The user must edit this file for it \
        to work properly.'

        return self.makeExtFile(fileName, description)


    def makeCmpExtStyFileOn (self, fileName) :
        '''Create a component style extentions "on" file for a specified component. A matching "off"
        file will be created as well.'''

        description = 'This is a component (on) style extension file which overrides any settings \
        which were loaded for this rendering process. This file is read just before the component \
        working file. After the component is rendered, the accompanying off style file will be \
        loaded which will turn off any modified style commands that this style file has set. The \
        user must edit this file in order for it to work right.'

        return self.makeExtFile(fileName, description)


    def makeCmpExtStyFileOff (self, fileName) :
        '''Create a component style extentions "off" file for a specified component. This is to
        match the "on" file that was created.'''

        description = 'This is a component (off) style extension file which overrides the settings \
        that were loaded for this rendering process just prior to loading the component working \
        file. The commands in this style file will off-set the "on" settings causing the macro to \
        render as it did before the "on" styles were loaded. The user must edit this file for it \
        to work properly.'

        return self.makeExtFile(fileName, description)


    def makeGrpExtTexFile (self) :
        '''Create a group TeX extentions file for a specified group.'''

        description = 'This is the group TeX extention macro file which overrides settings in \
        the global TeX extension macro file.'

        return self.makeExtFile(self.local.grpExtTexFile, description)


    def makeGrpExtStyFile (self) :
        '''Create a group Style extentions file to a specified group.'''

        description = 'This is the group style extention file which overrides settings in \
        the main default component extentions settings style file.'

        return self.makeExtFile(self.local.grpExtStyFile, description)


###############################################################################
############################# DEPENDENCY FUNCTIONS ############################
###############################################################################
######################## Error Code Block Series = 0400 #######################
###############################################################################


    def makeSettingsTexFile (self) :
        '''Create the primary TeX settings file.'''

#        import pdb; pdb.set_trace()

        description = 'This is the primary TeX settings file for the ' + self.gid + ' group. \
        It is auto-generated so editing can be a rather futile exercise. This is unless you \
        set freezeTexSettings to True in the XeTeX manager configuration of the project.conf \
        file. Doing that will prevent the file from being remade. However, no configuration \
        changes will be reflected in the static settings file. Use this with care.'

        # Setting for internal testing
        outputTest = False

        # Check for freezeTexSettings in project.conf
        if self.projectConfig['Managers'][self.cType + '_Xetex'].has_key('freezeTexSettings') and \
                self.tools.str2bool(self.projectConfig['Managers'][self.cType + '_Xetex']['freezeTexSettings']) :
            self.log.writeToLog(self.errorCodes['0420'])
            return False

        def appendLine(line, realVal) :
            '''Use this to shorten the code and look for listy things.'''
            if type(line) == list :
                for s in line :
                    linesOut.append(self.proj_config.processNestedPlaceholders(s, realVal))
            else :
                linesOut.append(self.proj_config.processNestedPlaceholders(line, realVal))

        # Open a fresh settings file
        with codecs.open(self.local.macSettingsFile, "w", encoding='utf_8') as writeObject :
            writeObject.write(self.tools.makeFileHeader(self.local.macSettingsFileName, description))
            # Build a dictionary from the default XML settings file
            # Create a dict that contains only the data we need here
            macPackDict = self.tools.xmlFileToDict(self.local.macPackConfXmlFile)

            for sections in macPackDict['root']['section'] :
                for section in sections :
                    secItem = sections[section]
                    linesOut = []
                    if type(secItem) is list :
                        if outputTest :
                            print sections['sectionID']
                        linesOut.append('% ' + sections['sectionID'].upper())
                        for setting in secItem :
                            for k in setting.keys() :
                                if k == 'texCode' :
                                    if outputTest :
                                        print '\t', setting['key']
                                    realVal = self.macroConfig['Macros'][self.macPackId][sections['sectionID']][setting['key']]
                                    # Test any boolDepends that this setting might have
                                    if setting.has_key('boolDepend') :
                                        result = []
                                        if type(setting['boolDepend']) == list :
                                            for i in setting['boolDepend'] :
                                                result.append(self.affirm(i))
                                        else :
                                            result.append(self.affirm(setting['boolDepend']))
                                        # If 'None' didn't end up in the list, that means
                                        # every bool tested good so we can output the line
                                        if None not in result :
                                            if outputTest :
                                                print '\t', setting.get(k)
                                            appendLine(setting['texCode'], realVal)
                                    # Normal setting output
                                    elif setting.get(k) :
                                        if setting.get(k) != None :
                                            # We filter out zero values here (But what if we need one of them?)
                                            if not self.proj_config.processNestedPlaceholders(realVal) == '0' :
                                                if outputTest :
                                                    print '\t', setting.get(k)
                                                appendLine(setting['texCode'], realVal)

                    # Only write out sections that have something in them
                    if len(linesOut) > 1 :
                        writeObject.write('\n')
                        for line in linesOut :
                            writeObject.write(line + '\n')


            # Continue here with injecting the font settings which are guided by
            # the config file because the XML source(s) could vary
            writeObject.write('\n% INSTALLED FONTS\n')
            installedFonts = self.fontConfig['Fonts'].keys()
            cTypeFont = self.projectConfig['CompTypes'][self.cType.capitalize()]['fontName']
            for font in installedFonts :
                if font == cTypeFont :
                    # Output the primary font
                    for key in self.fontConfig['Fonts'][font]['TexMapping']['PrimaryFont'].keys() :
                        writeObject.write(self.proj_config.processNestedPlaceholders(self.fontConfig['Fonts'][font]['TexMapping']['PrimaryFont'][key]) + '\n')
                    # Output the seconday settings as well for this font
                    for key in self.fontConfig['Fonts'][font]['TexMapping']['SecondaryFont'].keys() :
                        writeObject.write(self.proj_config.processNestedPlaceholders(self.fontConfig['Fonts'][font]['TexMapping']['SecondaryFont'][key]) + '\n')
                else :
                    # There can only be one primary font, this is not it
                    for key in self.fontConfig['Fonts'][font]['TexMapping']['SecondaryFont'].keys() :
                        writeObject.write(self.proj_config.processNestedPlaceholders(self.fontConfig['Fonts'][font]['TexMapping']['SecondaryFont'][key]) + '\n')

                writeObject.write('\n')

            # Die here if testing
            if outputTest :
                self.tools.dieNow()
            # Report finished if not
            return True


    def affirm (self, boolDependInfo) :
        '''Affirm by returning True if the actual bool matches its
        state setting. Returning 'None' will cause a setting to be skipped.'''


        realBool = self.returnConfRefValue(boolDependInfo['#text']).lower()
        if boolDependInfo['@state'].lower() == realBool.lower() :
            return True


    def returnConfRefValue (self, ref) :
        '''Return the value of a given config reference. The ref syntax is
        as follows: [config:configObj|section|key]. This should be able to
        recuse as deep as necessary.'''

#        import pdb; pdb.set_trace()

        ref = ref.lstrip('[').rstrip(']')
        (holderType, holderKey) = ref.split(':', 1)
        if holderType.lower() == 'config' :
            val = holderKey.split('|')
            dct = ['self.' + val[0]]
            val.remove(val[0])
            for i in val :
                i = self.proj_config.processNestedPlaceholders(i, '')
                dct.append('["' + i + '"]')

            return eval(''.join(dct))


    def makeGidTexFile (self, cidList) :
        '''Create the main gid TeX control file.'''

        description = 'This is the group TeX control file. XeTeX will \
            read this file to get all of links to other instructions (macros) \
            needed to render the group, or a component of a group.'

        # Since a render run could contain any number of components
        # in any order, we will remake this file on every run. No need
        # for dependency checking
        if os.path.exists(self.local.gidTexFile) :
            os.remove(self.local.gidTexFile)

        # Create the main TeX settings file (made on every run)
        self.makeSettingsTexFile()

        # Start writing out the gid.tex file. Check/make dependencies as we go.
        # If we fail to make a dependency it will die and report during that process.
        # We bring in each element in the order necessary
        with codecs.open(self.local.gidTexFile, "w", encoding='utf_8') as gidTexObject :
            # Write out the file header
            gidTexObject.write(self.tools.makeFileHeader(self.local.gidTexFileName, description))
            # First bring in the main macro file
            gidTexObject.write('\\input \"' + self.local.primaryMacroFile + '\"\n')
            # Check for a preStyle extension file and load if it is there
            if os.path.exists(self.local.preStyTexExtFile) :
                gidTexObject.write('\\input \"' + self.local.preStyTexExtFile + '\"\n')
            ########
            # FIXME? To avoid problems with the usfmTex marginalverses macro code, we bring
            # in the stylesheets now. Will this cause any problems with other macPacks?
            ########
            # Load style files (default and extention come with the package)
            gidTexObject.write('\\stylesheet{' + self.local.defaultStyFile + '}\n')
            # Load the global style extensions
            gidTexObject.write('\\stylesheet{' + self.local.glbExtStyFile + '}\n')
            # Load the group style extensions (if needed)
            if self.projectConfig['Groups'][self.gid].has_key('useGrpStyOverride') and self.tools.str2bool(self.projectConfig['Groups'][self.gid]['useGrpStyOverride']) :
                self.makeGrpExtStyFile()
                gidTexObject.write('\\stylesheet{' + self.local.grpExtStyFile + '}\n')
            # Load the settings (usfmTex: if marginalverses, load code in this)
            gidTexObject.write('\\input \"' + self.local.macSettingsFile + '\"\n')
            # Load the TeX macro extensions for this macro package
            gidTexObject.write('\\input \"' + self.local.extTexFile + '\"\n')
            # Load the group TeX macro extensions (if needed)
            if self.projectConfig['Groups'][self.gid].has_key('useGrpTexOverride') and self.tools.str2bool(self.projectConfig['Groups'][self.gid]['useGrpTexOverride']) :
                self.makeGrpExtTexFile()
                gidTexObject.write('\\input \"' + self.local.grpExtTexFile + '\"\n')
            # Load hyphenation data if needed
            if self.useHyphenation :
                # This is the main hyphenation settings file, this must be loaded first
                gidTexObject.write('\\input \"' + self.proj_hyphenation.projHyphSetTexFile + '\"\n')
                # This is the character definition file for hyphenation, this should be loaded second
                gidTexObject.write('\\input \"' + self.proj_hyphenation.projHyphCharTexFile + '\"\n')
                # This is the exception words list (all the hyphenated words), this is loaded last
                gidTexObject.write('\\input \"' + self.proj_hyphenation.projHyphExcTexFile + '\"\n')
            # If this is less than a full group render, just go with default pg num (1)
            if cidList == self.projectConfig['Groups'][self.gid]['cidList'] :
                # Check if this setting is there
                startPageNumber = self.checkStartPageNumber()
                if startPageNumber > 1 :
                    gidTexObject.write('\\pageno = ' + str(startPageNumber) + '\n')
            # Insert Document properties and x1a compliant info if needed
            gidTexObject.write(self.makeXoneACompliant())
            # Now add in each of the components
            for cid in cidList :
                # Output files and commands for usfm cType
                if self.cType == 'usfm' :
                    cidSource       = os.path.join(self.local.projComponentFolder, cid, self.project.groups[self.gid].makeFileNameWithExt(cid))
                    cidTexFileOn    = os.path.join(self.local.projTexFolder, self.gid + '-' + cid + '-On-ext.tex')
                    cidTexFileOff   = os.path.join(self.local.projTexFolder, self.gid + '-' + cid + '-Off-ext.tex')
                    cidStyFileOn    = os.path.join(self.local.projStyleFolder, self.gid + '-' + cid + '-On-ext.sty')
                    cidStyFileOff   = os.path.join(self.local.projStyleFolder, self.gid + '-' + cid + '-Off-ext.sty')
                    # Check to see if a TeX macro override is needed
                    if self.projectConfig['Groups'][self.gid].has_key('compTexOverrideList') and cid in self.projectConfig['Groups'][self.gid]['compTexOverrideList'] :
                        self.makeCmpExtTexFileOn(cidTexFileOn)
                        gidTexObject.write('\\input \"' + cidTexFileOn + '\"\n')
                    # Check to see if a style override is needed (if so create "on" file)
                    if self.projectConfig['Groups'][self.gid].has_key('compStyOverrideList') and cid in self.projectConfig['Groups'][self.gid]['compStyOverrideList'] :
                        self.makeCmpExtStyFileOn(cidStyFileOn)
                        gidTexObject.write('\\stylesheet{' + cidStyFileOn + '}\n')
                    # Check for short books add omit statement
                    if self.chapNumOffSingChap and self.cidChapNumDict[cid] == 1 :
                        gidTexObject.write('\\OmitChapterNumbertrue\n') 
                    # Add the working file here
                    gidTexObject.write('\\ptxfile{' + cidSource + '}\n')
                    # Check again for short books turn off omit statement
                    if self.chapNumOffSingChap and self.cidChapNumDict[cid] == 1 :
                        gidTexObject.write('\\OmitChapterNumberfalse\n') 
                    # Check for for style override and add the "Off" style file here
                    if self.projectConfig['Groups'][self.gid].has_key('compStyOverrideList') and cid in self.projectConfig['Groups'][self.gid]['compStyOverrideList'] :
                        self.makeCmpExtStyFileOn(cidStyFileOff)
                        gidTexObject.write('\\stylesheet{' + cidStyFileOff + '}\n')
                    # Check for for TeX macro override and add the "Off" TeX file here
                    if self.projectConfig['Groups'][self.gid].has_key('compTexOverrideList') and cid in self.projectConfig['Groups'][self.gid]['compTexOverrideList'] :
                        self.makeCmpExtTexFileOff(cidTexFileOff)
                        gidTexObject.write('\\input \"' + cidTexFileOff + '\"\n')
                else :
                    self.log.writeToLog(self.errorCodes['0650'], [self.cType])

            # This can only hapen once in the whole process, this marks the end
            gidTexObject.write('\\bye\n')

        return True


    def makeXoneACompliant (self) :
        '''Insert the necessary TeX code into the header to give the
        appearance of being PDF x1-a compliant. If the feature is turned
        off then it will only inject relevant document properties that
        are good to have included no mater what. XeTeX output is x1-a
        for the most part, it just doesn't brag about it. The output
        here mostly works. :-) '''

#        import pdb; pdb.set_trace()
        
        allLines = ''
        # Set some of the vars for the output
        title = self.projectConfig['ProjectInfo']['projectTitle']
        subject = self.projectConfig['ProjectInfo']['projectDescription']
        author = ''.join(self.projectConfig['ProjectInfo']['translators'])
        creator = ''.join(self.projectConfig['ProjectInfo']['typesetters'])
        # I don't think this next bit is not right, what does +7 mean anyway?
        # It works for CDT time anyway, which I thought was -6
        offSet = "+07\'00\'"
        # To get the date stamp right, we strip out all the non-number
        # characters so we are left with: yyyymmddhhmmss
        comp = self.projectConfig['ProjectInfo']['projectCreateDate'].replace('-', '').replace(':', '').replace(' ', '')
        cDate = 'D:' + comp + offSet
        mDate = 'D:' + self.tools.fullFileTimeStamp() + offSet
        lines = [   
                    '\special{pdf:docinfo<<',
                    '/Title(' + title + ')%',
                    '/Subject(' + subject + ')%',
                    '/Author(' + author + ')%',
                    '/Creator(' + creator + ')%',
                    '/CreationDate(' + cDate + ')%',
                    '/ModDate(' + mDate + ')%',
                    '/Producer(XeTeX with Rapuma)%',
                    '/Trapped /False',
                    '/GTS_PDFXVersion(PDF/X-1:2003)%',
                    '/GTS_PDFXConformance(PDF/X-1a:2003)%',
                    '>> }'
                ]
        # Add PDF header declairations for PDF X1-A:2003 compliance (default is True)
        if self.tools.str2bool(self.layoutConfig['DocumentFeatures']['pdfX1a']) :
            icc = os.path.join(self.local.rapumaConfigFolder, 'ps_cmyk.icc')
            # Now create the insert line list
            xtralines =  [   '\special{pdf:fstream @OBJCVR (' + icc + ')}',
                                '\special{pdf:put @OBJCVR <</N 4>>}',
                                '%\special{pdf:close @OBJCVR}',
                                '\special{pdf:docview <<',
                                '/OutputIntents [ <<',
                                '/Type/OutputIndent',
                                '/S/GTS_PDFX',
                                '/OutputCondition (An Unknown print device)',
                                '/OutputConditionIdentifier (Custom)',
                                '/DestOutputProfile @OBJCVR',
                                '/RegistryName (http://www.color.og)',
                                '>> ] >>}'
                        ]
            lines = lines + xtralines

        # Whatever our output, process the lines
        for l in lines : 
            allLines = allLines + l + ' \n'

        return allLines


###############################################################################
################################# Main Function ###############################
###############################################################################
######################## Error Code Block Series = 0600 #######################
###############################################################################

    def run (self, gid, cidList, pgRange, override, save) :
        '''This will check all the dependencies for a group and then
        use XeTeX to render the whole group or a subset of components
        and even a page range in a single component.'''

#        import pdb; pdb.set_trace()

        # There must be a cidList. If one was not passed, default to
        # the group list
        cidListSubFileName      = ''
        saveFile                = ''
        saveFileName            = ''
        if not cidList :
            cidList = self.projectConfig['Groups'][gid]['cidList']
        else :
            # If there is a cidList, create an alternate ouput name.
            # This is so if the file is saved it will have a unique
            # name. the name needs to be ordered by ###-cid-gid.
            # We need to do this sooner than later.
            if len(cidList) > 1 :
                cidListSubFileName = '-'.join(cidList)
            else :
                cid = cidList[0]
                # Add a filler character to the ID
                cnid = "{:0>3}".format(self.cidPtIdDict[cid])
                cidListSubFileName = cnid + '-' + cid

        # Create, if necessary, the gid.tex file
        # First, go through and make/update any dependency files
        self.makeSettingsTexFile()
        # Now make the gid main setting file
        self.makeGidTexFile(cidList)
        # Dynamically create a dependency list for the render process
        # Note: gidTexFile is remade on every run, do not test against that file
        dep = [self.local.extTexFile, self.local.projectConfFile, self.local.layoutConfFile, 
                self.local.macroConfFile, self.local.illustrationConfFile, ]
        # Add component dependency files
        for cid in cidList :
            cidUsfm = self.project.groups[gid].getCidPath(cid)
            cidIlls = self.proj_illustration.getCidPiclistFile(cid)
            for f in [cidUsfm, cidIlls] :
                if os.path.exists(f) :
                    dep.append(f)
            # Treat adjustment file separate
            if self.cType == 'usfm' :
                cidAdj = self.project.groups[gid].getCidAdjPath(cid)
                if os.path.exists(cidAdj) :
                    dep.append(cidAdj)

        # Call the renderer
        # Create the environment that XeTeX will use. This will be temporarily set
        # by subprocess.call() just before XeTeX is run.
        texInputsLine = self.project.local.projHome + ':' \
                        + self.local.projStyleFolder + ':' \
                        + self.local.projTexFolder + ':' \
                        + self.local.projMacPackFolder + ':' \
                        + self.local.projMacroFolder + ':' \
                        + self.local.projGidFolder + ':.'

        # Create the environment dictionary that will be fed into subprocess.call()
        #envDict = dict(os.environ)
        envDict={}
        # These are project environment vars
        envDict['TEXINPUTS'] = texInputsLine
        # These are XeTeX environment vars that are run if the internal (fast) version
        # of XeTeX is being run, which is the default. If runExternalXetex is set to
        # False, the following special environment vars will be run. If set to true,
        # an external version of XeTeX, provided it is installed, will run with its own
        # environment vars set elsewhere
        runExternal = self.tools.str2bool(self.projectConfig['Managers'][self.cType + '_Xetex'].get('runExternalXetex', ''))
        if not runExternal :
            envDict['PATH'] = os.path.join(self.local.rapumaXetexFolder, 'bin', 'x86_64-linux')
            envDict['TEXMFCNF'] = os.path.join(self.local.rapumaXetexFolder, 'texmf-local', 'web2c')
            envDict['TEXFORMATS'] = os.path.join(self.local.rapumaXetexFolder, 'texmf-local', 'web2c', 'xetex')
            # To help with debugging the following hook has been added. This is not
            # something the user would ever use. It is only for developer diagnostics.
            # for infomation on what integers can be used refer to this URL:
            # http://www.dcs.ed.ac.uk/home/latex/Informatics/Obsolete/html/kpathsea/kpathsea.html
            debugXetex = self.projectConfig['Managers'][self.cType + '_Xetex'].get('debugKpse', None)
            if debugXetex :
                try :
                    if int(debugXetex) > 0 :
                        envDict['KPATHSEA_DEBUG'] = debugXetex
                        self.log.writeToLog(self.errorCodes['1000'], [str(debugXetex), str(envDict)])
                except :
                    self.log.writeToLog(self.errorCodes['1090'], [debugXetex])
        else :
            envDict.update(os.environ)

        # Create the XeTeX command argument list that subprocess.call() will run with
        # the environment vars we set above
        cmds = ['xetex', '-output-directory=' + self.local.projGidFolder, self.local.gidTexFile]

        # For debugging purposes, output the following DBG message
        if self.projectConfig['Managers'][self.cType + '_Xetex'].has_key('freezeTexSettings') and \
                self.tools.str2bool(self.projectConfig['Managers'][self.cType + '_Xetex']['freezeTexSettings']) :
            self.log.writeToLog(self.errorCodes['0620'], [os.getcwd(), str(envDict), " ".join(cmds)])

        # Run the XeTeX and collect the return code for analysis
        try :
            rCode = subprocess.call(cmds, env = envDict)
            # Analyse the return code
            if rCode == int(0) :
                self.log.writeToLog(self.errorCodes['0625'], [self.local.gidTexFileName])
            elif rCode in self.xetexErrorCodes :
                self.log.writeToLog(self.errorCodes['0630'], [self.local.gidTexFileName, self.xetexErrorCodes[rCode], str(rCode)])
            else :
                self.log.writeToLog(self.errorCodes['0635'], [str(rCode)])
        except Exception as e :
            # If subprocess fails it might be because XeTeX did not execute
            # we will try to report back something useful
            self.log.writeToLog(self.errorCodes['0615'], [str(e)])

        # Collect the page count and record in group (Write out at the end of the opp.)
        self.projectConfig['Groups'][gid]['totalPages'] = str(PdfFileReader(open(self.local.gidPdfFile)).getNumPages())
        # Write out any changes made to the project.conf file that happened during this opp.
        self.tools.writeConfFile(self.projectConfig)

        # Pull out pages if requested (use the same file for output)
        if pgRange :
            self.tools.pdftkPullPages(self.local.gidPdfFile, self.local.gidPdfFile, pgRange)

        # The gidPdfFile is the residue of the last render and if approved, can be
        # used for the binding process. In regard to saving and file naming, the
        # gidPdfFile will be copied but never renamed. It must remain intact.

        # If the user wants to save this file or use a custom name, do that now
        if save and not override :
            saveFileName = self.pid + '_' + gid
            if cidListSubFileName :
                saveFileName = saveFileName + '_' + cidListSubFileName
            if pgRange :
                saveFileName = saveFileName + '_pg(' + pgRange + ')'
            # Add date stamp
            saveFileName = saveFileName + '_' + self.tools.ymd()
            # Add render file extention
            saveFileName = saveFileName + '.pdf'
            # Save this to the Deliverable folder (Make sure there is one)
            if not os.path.isdir(self.local.projDeliverableFolder) :
                os.makedirs(self.local.projDeliverableFolder)
            # Final file name and path
            saveFile = os.path.join(self.local.projDeliverableFolder, saveFileName)
            # Copy, no news is good news
            if shutil.copy(self.local.gidPdfFile, saveFile) :
                self.log.writeToLog(self.errorCodes['0730'], [saveFileName])
            else :
                self.log.writeToLog(self.errorCodes['0720'], [saveFileName])            

        # If given, the override file name becomes the file name 
        if override :
            saveFile = override
            # With shutil.copy(), no news is good news
            if shutil.copy(self.local.gidPdfFile, saveFile) :
                self.log.writeToLog(self.errorCodes['0730'], [saveFileName])
            else :
                self.log.writeToLog(self.errorCodes['0720'], [saveFileName])

        # Once we know the file is successfully generated, add a background if defined
        viewFile = ''
        if self.useBackground :
            if saveFile :
                viewFile = self.pg_back.addBackground(saveFile)
            else :
                viewFile = self.pg_back.addBackground(self.local.gidPdfFile)
                
        # Add a timestamp and doc info if requested in addition to background
        if self.useDocInfo :
            if saveFile :
                if os.path.isfile(viewFile) :
                    viewFile = self.pg_back.addDocInfo(viewFile)
                else :
                    viewFile = self.pg_back.addDocInfo(saveFile)
            else :
                if os.path.isfile(viewFile) :
                    viewFile = self.pg_back.addDocInfo(viewFile)
                else :
                    viewFile = self.pg_back.addDocInfo(self.local.gidPdfFile)

        # Add a diagnostic layer to the rendered output. Normally this is
        # not used with a normal background layer
        if self.useDiagnostic :
            if saveFile :
                viewFile = self.fmt_diagnose.addTransparency(saveFile)
            else :
                viewFile = self.fmt_diagnose.addTransparency(self.local.gidPdfFile)

        # To avoid confusion with file names, if this is a saved file,
        # and it has a background, we need to remove the original, non-
        # background file (remembering originals are kept in the group
        # Component folder), then rename the -view version to whatever
        # the saved name should be
        if save or override :
            if os.path.isfile(saveFile) and os.path.isfile(viewFile) :
                # First remove
                os.remove(saveFile)
                # Next rename
                os.rename(viewFile, saveFile)

        ##### Viewing #####
        # First get the right file name to view
        if saveFile :
            # If there was a saveFile, that will be the viewFile
            viewFile = saveFile
        else :
            # The view file in this case is just temporary
            if not os.path.isfile(viewFile) :
                viewFile = self.local.gidPdfFile.replace(gid + '.pdf', gid + '-view.pdf')
                shutil.copy(self.local.gidPdfFile, viewFile)

        # Now view it
        if os.path.isfile(viewFile) :
            if self.pdfViewerCmd :
                # Add the file to the viewer command
                self.pdfViewerCmd.append(viewFile)
                # Run the XeTeX and collect the return code for analysis
                try :
                    subprocess.Popen(self.pdfViewerCmd)
                    return True
                except Exception as e :
                    # If we don't succeed, we should probably quite here
                    self.log.writeToLog(self.errorCodes['1005'], [str(e)])
            else :
                self.log.writeToLog(self.errorCodes['0710'])
        else :
            self.log.writeToLog(self.errorCodes['0700'], [self.tools.fName(viewFile)])
            
        # If we made it this far, return True
        return True
Beispiel #29
0
    def __init__(self, project, cfg, cType) :
        '''Do the primary initialization for this manager.'''

        super(Pdftk, self).__init__(project, cfg)

#        import pdb; pdb.set_trace()

        # Create all the values we can right now for this manager.
        # Others will be created at run time when we know the cid.
        self.tools                  = Tools()
        self.project                = project
        self.local                  = project.local
        self.log                    = project.log
        self.cfg                    = cfg
        self.pid                    = project.projectIDCode
        self.gid                    = project.gid
        self.cType                  = cType
        self.Ctype                  = cType.capitalize()
        self.mType                  = project.projectMediaIDCode
        self.renderer               = 'pdftk'
        self.manager                = self.cType + '_' + self.renderer.capitalize()
        self.managers               = project.managers
        self.pg_back                = ProjBackground(self.pid, self.gid)
        self.fmt_diagnose           = ProjDiagnose(self.pid, self.gid)
        self.proj_config            = Config(self.pid, self.gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getLayoutConfig()
        # Get config objs
        self.projectConfig          = self.proj_config.projectConfig
        self.layoutConfig           = self.proj_config.layoutConfig
        self.userConfig             = self.project.userConfig
        # Some config settings
        self.pdfViewerCmd           = self.tools.getPdfViewerCommand(self.userConfig, self.projectConfig)
        self.useBackground          = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useBackground'])
        self.useDocInfo             = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useDocInfo'])

        # Get settings for this component
        self.managerSettings = self.projectConfig['Managers'][self.manager]
        for k, v in self.managerSettings.iteritems() :
            if v == 'True' or v == 'False' :
                setattr(self, k, self.tools.str2bool(v))
            else :
                setattr(self, k, v)

        # Make any dependent folders if needed
        if not os.path.isdir(self.local.projGidFolder) :
            os.makedirs(self.local.projGidFolder)


        # Log messages for this module
        self.errorCodes     = {

            '0000' : ['MSG', 'Messages for the pdftk module.'],

            '5010' : ['ERR', 'Subprocess failed with this error: <<1>>'],
            '5020' : ['MSG', 'PDF merge was successful. Output = <<1>>'],
            '5200' : ['ERR', 'Rendered file not found: <<1>>'],
            '5210' : ['WRN', 'PDF viewing is disabled.'],
            '5720' : ['MSG', 'Saved rendered file to: [<<1>>]'],
            '5730' : ['ERR', 'Failed to save rendered file to: [<<1>>]']

        }
Beispiel #30
0
class Pdftk (Manager) :

    # Shared values
    xmlConfFile     = 'pdftk.xml'

    def __init__(self, project, cfg, cType) :
        '''Do the primary initialization for this manager.'''

        super(Pdftk, self).__init__(project, cfg)

#        import pdb; pdb.set_trace()

        # Create all the values we can right now for this manager.
        # Others will be created at run time when we know the cid.
        self.tools                  = Tools()
        self.project                = project
        self.local                  = project.local
        self.log                    = project.log
        self.cfg                    = cfg
        self.pid                    = project.projectIDCode
        self.gid                    = project.gid
        self.cType                  = cType
        self.Ctype                  = cType.capitalize()
        self.mType                  = project.projectMediaIDCode
        self.renderer               = 'pdftk'
        self.manager                = self.cType + '_' + self.renderer.capitalize()
        self.managers               = project.managers
        self.pg_back                = ProjBackground(self.pid, self.gid)
        self.fmt_diagnose           = ProjDiagnose(self.pid, self.gid)
        self.proj_config            = Config(self.pid, self.gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getLayoutConfig()
        # Get config objs
        self.projectConfig          = self.proj_config.projectConfig
        self.layoutConfig           = self.proj_config.layoutConfig
        self.userConfig             = self.project.userConfig
        # Some config settings
        self.pdfViewerCmd           = self.tools.getPdfViewerCommand(self.userConfig, self.projectConfig)
        self.useBackground          = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useBackground'])
        self.useDocInfo             = self.tools.str2bool(self.layoutConfig['DocumentFeatures']['useDocInfo'])

        # Get settings for this component
        self.managerSettings = self.projectConfig['Managers'][self.manager]
        for k, v in self.managerSettings.iteritems() :
            if v == 'True' or v == 'False' :
                setattr(self, k, self.tools.str2bool(v))
            else :
                setattr(self, k, v)

        # Make any dependent folders if needed
        if not os.path.isdir(self.local.projGidFolder) :
            os.makedirs(self.local.projGidFolder)


        # Log messages for this module
        self.errorCodes     = {

            '0000' : ['MSG', 'Messages for the pdftk module.'],

            '5010' : ['ERR', 'Subprocess failed with this error: <<1>>'],
            '5020' : ['MSG', 'PDF merge was successful. Output = <<1>>'],
            '5200' : ['ERR', 'Rendered file not found: <<1>>'],
            '5210' : ['WRN', 'PDF viewing is disabled.'],
            '5720' : ['MSG', 'Saved rendered file to: [<<1>>]'],
            '5730' : ['ERR', 'Failed to save rendered file to: [<<1>>]']

        }


###############################################################################
############################ Manager Level Functions ##########################
###############################################################################
######################## Error Code Block Series = 1000 #######################
###############################################################################

    def sourceListFromCidList (self, cidList) :
        '''Return a sourceList derived from a given cidList.'''

        sourceList = []
        for cid in cidList :
            sourceList.append(self.sourceFromCid(cid))

        return sourceList

    def sourceFromCid (self, cid) :
        '''Return the full path with file name derived from a valid cid.'''
        
        return os.path.join(self.local.projComponentFolder, cid, cid + '.pdf')


###############################################################################
################################# Main Function ###############################
###############################################################################
######################## Error Code Block Series = 5000 #######################
###############################################################################

    def run (self, gid, cidList, pgRange, override, save) :
        '''This will check all the dependencies for a group and then
        use pdftk to "render" the whole group or a subset of components
        and even a page range in a single component.'''

#        import pdb; pdb.set_trace()

        # There must be a cidList. If one was not passed, default to
        # the group list
        cidListSubFileName      = ''
        saveFile                = ''
        saveFileName            = ''
        viewFile                = ''
        if not cidList :
            cidList = self.projectConfig['Groups'][gid]['cidList']

        # Make a list of files that pdftk will merge together
        sourceList = self.sourceListFromCidList(cidList)
                
        # Merge the files
        cmd = ['pdftk'] + sourceList + ['cat', 'output', self.local.gidPdfFile]

#        import pdb; pdb.set_trace()

        # No return from pdftk is good, we can continue on
        if not subprocess.call(cmd) : 
            # Collect the page count and record in group (Write out at the end of the opp.)
            self.projectConfig['Groups'][gid]['totalPages'] = str(PdfFileReader(open(self.local.gidPdfFile)).getNumPages())
            # Write out any changes made to the project.conf file that happened during this opp.
            self.tools.writeConfFile(self.projectConfig)

            # Pull out pages if requested (use the same file for output)
            if pgRange :
                self.tools.pdftkPullPages(self.local.gidPdfFile, self.local.gidPdfFile, pgRange)

            # The gidPdfFile is the residue of the last render and if approved, can be
            # used for the binding process. In regard to saving and file naming, the
            # gidPdfFile will be copied but never renamed. It must remain intact.

            # If the user wants to save this file or use a custom name, do that now
            if save and not override :
                saveFileName = self.pid + '_' + gid
                if cidListSubFileName :
                    saveFileName = saveFileName + '_' + cidListSubFileName
                if pgRange :
                    saveFileName = saveFileName + '_pg(' + pgRange + ')'
                # Add date stamp
                saveFileName = saveFileName + '_' + self.tools.ymd()
                # Add render file extention
                saveFileName = saveFileName + '.pdf'
                # Save this to the Deliverable folder (Make sure there is one)
                if not os.path.isdir(self.local.projDeliverableFolder) :
                    os.makedirs(self.local.projDeliverableFolder)
                # Final file name and path
                saveFile = os.path.join(self.local.projDeliverableFolder, saveFileName)
                # Copy, no news is good news
                if shutil.copy(self.local.gidPdfFile, saveFile) :
                    self.log.writeToLog(self.errorCodes['5730'], [saveFileName])
                else :
                    self.log.writeToLog(self.errorCodes['5720'], [saveFileName])            

            # If given, the override file name becomes the file name 
            if override :
                saveFile = override
                # With shutil.copy(), no news is good news
                if shutil.copy(self.local.gidPdfFile, saveFile) :
                    self.log.writeToLog(self.errorCodes['5730'], [saveFileName])
                else :
                    self.log.writeToLog(self.errorCodes['5720'], [saveFileName])

            # Once we know the file is successfully generated, add a background if defined
            if self.useBackground :
                if saveFile :
                    viewFile = self.pg_back.addBackground(saveFile)
                else :
                    viewFile = self.pg_back.addBackground(self.local.gidPdfFile)
                    
            # Add a timestamp and doc info if requested in addition to background
            if self.useDocInfo :
                if saveFile :
                    if os.path.isfile(viewFile) :
                        viewFile = self.pg_back.addDocInfo(viewFile)
                    else :
                        viewFile = self.pg_back.addDocInfo(saveFile)
                else :
                    if os.path.isfile(viewFile) :
                        viewFile = self.pg_back.addDocInfo(viewFile)
                    else :
                        viewFile = self.pg_back.addDocInfo(self.local.gidPdfFile)

            # To avoid confusion with file names, if this is a saved file,
            # and it has a background, we need to remove the original, non-
            # background file (remembering originals are kept in the group
            # Component folder), then rename the -view version to whatever
            # the saved name should be
            if save or override :
                if os.path.isfile(saveFile) and os.path.isfile(viewFile) :
                    # First remove
                    os.remove(saveFile)
                    # Next rename
                    os.rename(viewFile, saveFile)

            ##### Viewing #####
            # First get the right file name to view
            if saveFile :
                # If there was a saveFile, that will be the viewFile
                viewFile = saveFile
                self.log.writeToLog(self.errorCodes['5020'], [saveFile])
            else :
                # The view file in this case is just temporary
                if not os.path.isfile(viewFile) :
                    viewFile = self.local.gidPdfFile.replace(gid + '.pdf', gid + '-view.pdf')
                    shutil.copy(self.local.gidPdfFile, viewFile)
                    self.log.writeToLog(self.errorCodes['5020'], [self.tools.fName(viewFile)])

            if os.path.isfile(viewFile) :
                if self.pdfViewerCmd :
                    # Add the file to the viewer command
                    self.pdfViewerCmd.append(viewFile)
                    # Run the XeTeX and collect the return code for analysis
                    try :
                        subprocess.Popen(self.pdfViewerCmd)
                        return True
                    except Exception as e :
                        # If we don't succeed, we should probably quite here
                        self.log.writeToLog(self.errorCodes['5010'], [str(e)])
                else :
                    self.log.writeToLog(self.errorCodes['5210'])
            else :
                self.log.writeToLog(self.errorCodes['5200'], [self.tools.fName(viewFile)])
                
            # If we made it this far, return True
            return True