You are not logged in Log in Join
You are here: Home » Members » Marc's Zope Page » load_site.py » View File

Log in
Name

Password

 

load_site.py

File details
Size
20 K
File type
text/x-python

File contents

##############################################################################
# 
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
# 
# Copyright (c) Digital Creations.  All rights reserved.
# 
# This license has been certified as Open Source(tm).
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1. Redistributions in source code must retain the above copyright
#    notice, this list of conditions, and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions, and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
# 
# 3. Digital Creations requests that attribution be given to Zope
#    in any manner possible. Zope includes a "Powered by Zope"
#    button that is installed by default. While it is not a license
#    violation to remove this button, it is requested that the
#    attribution remain. A significant investment has been put
#    into Zope, and this effort will continue if the Zope community
#    continues to grow. This is one way to assure that growth.
# 
# 4. All advertising materials and documentation mentioning
#    features derived from or use of this software must display
#    the following acknowledgement:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    In the event that the product being advertised includes an
#    intact Zope distribution (with copyright and license included)
#    then this clause is waived.
# 
# 5. Names associated with Zope or Digital Creations must not be used to
#    endorse or promote products derived from this software without
#    prior written permission from Digital Creations.
# 
# 6. Modified redistributions of any form whatsoever must retain
#    the following acknowledgment:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    Intact (re-)distributions of any official Zope release do not
#    require an external acknowledgement.
# 
# 7. Modifications are encouraged but must be packaged separately as
#    patches to official Zope releases.  Distributions that do not
#    clearly separate the patches from the original work must be clearly
#    labeled as unofficial distributions.  Modifications which do not
#    carry the name Zope may be packaged in any form, as long as they
#    conform to all of the clauses above.
# 
# 
# Disclaimer
# 
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#   SUCH DAMAGE.
# 
# 
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations.  Specific
# attributions are listed in the accompanying credits file.
# 
##############################################################################
#
#
# Marc Lindahl (http://www.zope.org/Members/bowerymarc) 7/14/01
#
# added options to replace files or directories
# added option to use Audio object
# refactored image and audio file handling (still extensions based)
# imroved error handling
# use quote() to deal with filnames with spaces in them
# 
# 
##############################################################################
"""Load a Zope site from a collection of files or directories
"""

usage=""" [options] url file .....

    where options are:
            
      -r
      
         Replace files (individually) that exist using manage_upload.
         Otherwise it will skip existing files.
         
      -R
      
         Replace existing directories (deletes and re-adds, deleting anything
         in the existing directory).
         
      -a
       
         Use Audio objects for any files ending in ['mp3', 'mpa', 'mp2', 'mp1', 'ra', 'rm', 'wav', 'aiff']
        
      -A
      
         Delete and re-Add files as audio objects if ending in ['mp3', 'mpa', 'mp2', 'mp1', 'ra', 'rm', 'wav', 'aiff']

      -D

         For HTML documents, replace the start of the content, up to
         and including the opening body tag with a DTML var tag that
         inserts the standard header. Also replace the closing body
         and html tag with a DTML var tag that inserts the standard
         footer.

      -I

         For each index.html, add an index_html that redirects.

      -p path

         Path to ZPublisher.  If not provided, load_site will
         make an attempt to figure it out.

      -u user:password

         Credentials

      -v

         Run in verbose mode.

      -9

         Use *old* zope method names.
"""

import sys, getopt, os, string
from urllib import quote, quote_plus
ServerError=''
verbose=0
old=0
doctor=0
index_html=0
replaceDirs=0
replaceFiles=0
useAudio=0
readdAudio=0
audioTypes = ['mp3', 'mpa', 'mp2', 'mp1', 'ra', 'rm', 'wav', 'aiff']
imageTypes = ['gif', 'jpg', 'png', 'jpeg', 'psd', 'tif', 'tiff']

def main():
    user, password = 'superuser', '123'
    opts, args = getopt.getopt(sys.argv[1:], 'p:u:DIv9RrAa')
    global verbose
    global old
    global doctor
    global index_html
    global replaceDirs
    global replaceFiles
    global useAudio
    global readdAudio
    global audioTypes
    global imageTypes
    havepath=None
    for o, v in opts:
        if o=='-p':
            d, f = os.path.split(v)
            if f=='ZPublisher': sys.path.insert(0,d)
            else: sys.path.insert(0,v)
            havepath=1
        elif o=='-u':
            v = string.split(v,':')
            user, password = v[0], string.join(v[1:],':')
        elif o=='-D': doctor=1
        elif o=='-I': index_html=1
        elif o=='-v': verbose=1
        elif o=='-9': old=1
        elif o=='-R': replaceDirs=1
        elif o=='-r': replaceFiles=1
        elif o=='-a': useAudio=1
        elif o=='-A': readdAudio=1

    if not args:
        print sys.argv[0]+usage
        sys.exit(1)

    if not havepath:
        here=os.path.split(sys.argv[0])[0]
        if os.path.exists(os.path.join(here,'ZPublisher')):
            sys.path.insert(0,here)
        else:
            here=os.path.split(here)[0]
            here=os.path.join(here,'lib','python')
            if os.path.exists(os.path.join(here,'ZPublisher')):
                sys.path.insert(0,here)
        

    url=args[0]
    files=args[1:]

    import ZPublisher.Client
    global ServerError
    ServerError=ZPublisher.Client.ServerError
    object=ZPublisher.Client.Object(url, username=user, password=password)

         
    for f in files: upload_file(object, f)

def call(f, *args, **kw):
    # Call a function ignoring redirect bci errors.
    try: apply(f,args, kw)
    except ServerError, v:
        if str(v)[:1] != '3':
            raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

def upload_file(object, f):
    if os.path.isdir(f): 
        return upload_dir(object, f)
    dir, name = os.path.split(f)
    root, ext = os.path.splitext(name)
    if ext in ('file', 'dir'): 
        ext=''
    else:
        ext=string.lower(ext)
        if ext and ext[0] in '.': ext=ext[1:]
    #check for special file types with their own special add methods
    if ext:
        if ext in imageTypes:
            if verbose: print 'upload_image', f
            return upload_image(object, f)
        elif (useAudio or readdAudio) and (ext in audioTypes):     
            if verbose: print 'upload_audio', f
            return upload_audio(object, f)
        elif globals().has_key('upload_'+ext):
            if verbose: print 'upload_'+ext, f
            return globals()['upload_'+ext](object, f)

        
    if verbose: 
        print 'upload_file', f, ext
    if replaceFiles and object_already_exists(object, name):
        try:
           if verbose: print '   updating...'
           o=object.__class__(object.url+'/'+quote(name),
                username=object.username,
                password=object.password)
           call(o.manage_upload, file=open(f,'rb'))
        except:
            if verbose: print 'update file failed'
    else:
        if object_already_exists(object, name):
            if verbose: print '   file already exists'
        else:    
            try:
                call(object.manage_addFile, id=name, file=open(f,'rb'))
            except:
                if verbose: print 'addFile failed'

def upload_dir(object, f):
    if verbose: print 'upload_dir', f
    dir, name = os.path.split(f)
    if object_already_exists(object, name):
        if replaceDirs:
            try:
                call(object.manage_delete)
            except:
                if verbose: print 'delete before addFolder failed'
            try:
                call(object.manage_addFolder, id=name)
            except:
                if verbose: print 'addFolder (replace) failed'
        else:
            if verbose: print '   '+name + ' directory exists'                
    else:  
        try:
            call(object.manage_addFolder, id=name)
        except:
            if verbose: print 'addFolder failed'
            
    #this is how the heirarchy is walked inside zope.
    object=object.__class__(object.url+'/'+quote(name),
                            username=object.username,
                            password=object.password)
    for n in os.listdir(f):
        upload_file(object, os.path.join(f,n))

# ----- phd -----
# Modified by Oleg Broytmann <[email protected]>

from sgmllib import SGMLParser

def join_attrs(attrs):
   attr_list = []
   for attrname, value in attrs:
      attr_list.append('%s="%s"' % (attrname, string.strip(value)))

   if attr_list:
      s = " " + string.join(attr_list, " ")
   else:
      s = ""

   return s


class HeadParser(SGMLParser):
   def __init__(self):
      SGMLParser.__init__(self)

      self.seen_starthead = 0
      self.seen_endhead   = 0
      self.seen_startbody = 0

      self.head = ""
      self.title = ""
      self.accumulator = ""


   def handle_data(self, data):
      if data:
         self.accumulator = self.accumulator + data

   def handle_charref(self, ref):
       self.handle_data("&#%s;" % ref)

   def handle_entityref(self, ref):
       self.handle_data("&%s;" % ref)

   def handle_comment(self, data):
      if data:
         self.accumulator = self.accumulator + "<!--%s-->" % data


   def start_head(self, attrs):
      if not self.seen_starthead:
         self.seen_starthead = 1
         self.head = ""
         self.title = ""
         self.accumulator = ""

   def end_head(self):
      if not self.seen_endhead:
         self.seen_endhead = 1
         self.head = self.head + self.accumulator
         self.accumulator = ""


   def start_title(self, attrs):
      self.head = self.head + self.accumulator
      self.accumulator = ""

   def end_title(self):
      self.title = self.accumulator
      self.accumulator = ""


   def start_body(self, attrs):
      if not self.seen_startbody:
         self.seen_startbody = 1
         self.accumulator = ""

   def end_body(self): pass # Do not put </BODY> and </HTML>
   def end_html(self): pass # into output stream


   # Pass other tags unmodified
   def unknown_starttag(self, tag, attrs):
      self.accumulator = self.accumulator + "<%s%s>" % (string.upper(tag), join_attrs(attrs))

   def unknown_endtag(self, tag):
      self.accumulator = self.accumulator + "</%s>" % string.upper(tag)



def parse_html(infile):
   parser = HeadParser()

   while 1:
      line = infile.readline()
      if not line: break
      parser.feed(line)

   parser.close()
   infile.close()

   return (string.strip(parser.title), string.strip(parser.head),
           string.strip(parser.accumulator))


def upload_html(object, f):
    dir, name = os.path.split(f)
    f=open(f)

    if doctor:
        title, head, body = parse_html(f)
        if old:
            body = ("<!--#var standard_html_header-->\n\n" +
                    body + "\n\n<!--#var standard_html_footer-->")
        else:
            body = ("<dtml-var standard_html_header>\n\n" +
                    body + "\n\n<dtml-var standard_html_footer>")

    else:
        if old: f=f.read()
        title, head, body = '', '', f

    if old:
        if replaceFiles and object_already_exists(object, name):
            try:
                if verbose: print '   updating...'
                o=object.__class__(object.url+'/'+quote(name),
                        username=object.username,
                        password=object.password)
                call(o.manage_upload, title=title, file=body)
            except:
                if verbose: print 'update Document failed'
        else:
            try:    
                call(object.manage_addDocument, id=name, file=body)
            except:
                if verbose: print 'addDocument failed'
        if index_html and name in ('index.html', 'index.htm') and not object_already_exists(object, name):
            try:    
                call(object.manage_addDocument, id='index_html',
                     file=('<!--#raise Redirect-->'
                           '<!--#var URL1-->/%s'
                           '<!--#/raise-->' % name
                           ))
            except:
                if verbose: print 'add index_html redirect failed'
    else:
        if replaceFiles and object_already_exists(object, name):
            try:
                if verbose: print '   updating...'
                o=object.__class__(object.url+'/'+quote(name),
                        username=object.username,
                        password=object.password)
                call(o.manage_upload, title=title, file=body)
            except:
                if verbose: print 'update HTMLfile failed'
        else:
            try:    
                call(object.manage_addDTMLDocument, id=name, title=title, file=body)
            except:
                if verbose: print 'addDTMLDocument failed'
                
        if index_html and name in ('index.html', 'index.htm') and not object_already_exists(object, name):
            try:    
                call(object.manage_addDTMLMethod, id='index_html',
                     file=('<dtml-raise Redirect>'
                           '<dtml-var URL1>/%s'
                           '</dtml-raise>' % name
                           ))
            except:
                if verbose: print 'add index_html redirect failed'

    # Now add META and other tags as property
    if head:
      object=object.__class__(object.url+'/'+quote(name),
                            username=object.username,
                            password=object.password)
      try:    
          call(object.manage_addProperty,
               id="loadsite-head", type="text", value=head)
      except:
          if verbose: print 'addProperty loadsite-head failed'

# ----- /phd -----
    
upload_htm=upload_html

def upload_dtml(object, f):
    dir, name = os.path.split(f)
    f=open(f)
    
    if replaceFiles and object_already_exists(object, name):
        try:
            if verbose: print '   updating...'
            o=object.__class__(object.url+'/'+quote(name),
                    username=object.username,
                    password=object.password)
            call(o.manage_upload,  title=title, file=f)
        except:
            if verbose: print 'update dtml failed'
    else:
        try:
            if old:
                f=f.read()
                call(object.manage_addDocument, id=name, file=f)
            else:
                call(object.manage_addDTMLMethod, id=name, file=f)
        except:
            if verbose: print 'upload_dtml failed'
        

def upload_image(object, f):
    dir, name = os.path.split(f)
    if replaceFiles and object_already_exists(object, name):
        try:
            if verbose: print '   updating...'
            o=object.__class__(object.url+'/'+quote(name),
                    username=object.username,
                    password=object.password)
            call(o.manage_upload,  file=open(f,'rb'))
        except:
            if verbose: print 'update image failed'
    else:
        try:
            call(object.manage_addImage, id=name, file=open(f,'rb'))
        except:
            if verbose: print 'addImage failed'

def upload_audio(object, f):
    dir, name = os.path.split(f)
    objA=object.__class__(object.url+'/manage_addProduct/Audio',
                    username=object.username,
                    password=object.password)
    root, ext = os.path.splitext(name)
    if ext in ('file', 'dir'): 
        ext=''
    else:
        ext=string.lower(ext)
        if ext and ext[0] in '.': ext=ext[1:]
        
    #hack to force some kind of binary content type
    if ext[:2] == 'mp':
        ct = 'audio/mpeg'
    elif ext[:1] == 'r':
        ct = 'audio/x-pn-realaudio'
    else:
        ct = 'audio/x-'+ext
        
    if readdAudio:
        if object_already_exists(object, name):
            try:
                if verbose: print '   deleting old ' + name
                call(object.manage_delObjects, ids=[name])
            except:
                if verbose: print 'delete before addAudio failed'
        try:
            if verbose: print '   adding ' + name
            call(objA.manage_addAudio, id=name, file=open(f,'rb'))
            #hack to force some kind of binary content type
            o=object.__class__(object.url+'/'+quote(name),
                    username=object.username,
                    password=object.password)
            call(o.manage_edit, title=name, content_type=ct, description=ext+' file uploaded via load_site')
        except:
            if verbose: print 'addAudio failed'
    else:    
        if object_already_exists(object, name):
            if replaceFiles:
                try:
                    if verbose: print '   updating...'
                    o=object.__class__(object.url+'/'+quote(name),
                            username=object.username,
                            password=object.password)
                    call(o.manage_upload, file=open(f,'rb'))
                    call(o.manage_edit, title=name, content_type=ct, description=ext+' file uploaded via load_site')
                except:
                    if verbose: print 'update audio file failed'
            else:
                if verbose: print '   audio file '+name+' already exists, updating content_type only'
                try:
                    o=object.__class__(object.url+'/'+quote(name),
                            username=object.username,
                            password=object.password)
                    call(o.manage_edit, title=name, content_type=ct, description=ext+' file uploaded via load_site')
                except:
                    if verbose: print 'update audio file content_type failed'
        else:        
            try:
                call(objA.manage_addAudio, id=name, file=open(f,'rb'))
                #hack to force some kind of binary content type
                o=object.__class__(object.url+'/'+quote(name),
                        username=object.username,
                        password=object.password)
                call(o.manage_edit, title=name, content_type=ct, description=ext+' file uploaded via load_site')
            except:
                if verbose: print 'addAudio failed'

        
                
def object_already_exists(object, name):
    try:
        #call manage tab to see if object exists    
        object=object.__class__(object.url+'/'+quote(name),
                        username=object.username,
                        password=object.password)
        call(object.manage)
        if verbose: print '      '+name + ' exists'
        return 1
    except:
        if verbose: print '      '+name + ' doesnt exist'
        return 0

if __name__=='__main__': main()