SVNGroovy

Last modified by Support on 2011/02/03 10:37

import java.util.Collection;
import java.util.Iterator;
import org.apache.commons.lang.StringUtils;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.io.*;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
import com.xpn.xwiki.doc.XWikiDocument;

public class SVNLogReader {
    def xwiki;
    def context;
    def repurl = "";
    def defaultspace = "";
    def configdoc;
    def savedlist = "";
    def SVNRepository repository = null;
    def username = "";
    def password = "";
    def defaultDate = "";
    def defaultUser = "";
    def sdebug = "";
    def status = new HashMap();

    public setXWiki(xwiki, context) {
      this.xwiki = xwiki;
      this.context = context;
    }

    public hasProgrammingRights() {
      return xwiki.hasProgrammingRights();
    }

    public setSVNConfig(page) {
       this.configdoc = xwiki.getDocument(page)
       this.username = configdoc.getValue("username")
       this.password = configdoc.getObject("SVNCode.SVNConfigClass").getProperty("password").property.value
       this.repurl = configdoc.getValue("repository");
       this.defaultspace = configdoc.getValue("defaultspace");
       this.savedlist = configdoc.getValue("savedlist");
       this.defaultDate = configdoc.getValue("defaultdate");
       this.defaultUser = configdoc.getValue("defaultuser");
       this.status = getStatus(configdoc.getValue("status"));

       debug("Date:" + this.defaultDate);
    }

    public getStatus(status) {
       def smap = new HashMap();
       for (sline in StringUtils.split(status, "\r\n")) {
          def items = sline.split(";");
          smap.put(items[0], [ "xwikiversion" : (items.length>1) ? items[1] : "", "xwikihash" : (items.length>2) ? items[2] : "", "svnversion" : (items.length>3) ? items[3] : "" ])
       }
       return smap;
    }

    public getPageStatus(filePath) {
      return status.get(filePath);
    }

    public saveStatus() {
       def sstatus = "";
       for (key in status.keySet()) {
         def stat = status.get(key);
         sstatus += "${key};${stat.xwikiversion};${stat.xwikihash};${stat.svnversion}\n";
       }
       only save if changed
       if (status!=configdoc.getValue("status")) {
        configdoc.set("status", sstatus);
        configdoc.save();
       }
    }

    public debug(message) {
       sdebug += message + "\n";
       def cdate = new Date();
       System.out.println("${cdate}: ${message}");
    }

    public getDebug() {
       return this.sdebug;
    }
  
    public setRepository(rep) {
        this.repurl = rep;
    }

    public getDefaultSpace() {
        return this.defaultspace;
    }

    public getSavedList() {
        return (this.savedlist==null) ? "" : this.savedlist;
    }

    public getFilePath(pagedoc) {
       get page
        def filePath = pagedoc.getSpace() + "/" + pagedoc.getName();
        def language = pagedoc.getLanguage();
        if (language!=null&&language!="")
          filePath += "." + language;
        filePath += ".xml"
        return filePath;
    }

    public getStatusPath(pagedoc) {
       get page
        def filePath = pagedoc.getSpace() + "/" + pagedoc.getName();
        def language = pagedoc.getLanguage();
        if (language!=null&&language!="")
          filePath += "." + language;
        return filePath;
    }

    public boolean initRepository() {
        /*

  • initializes the library (it must be done before ever using the
  • library itself)
             */
            setupLibrary();

        try {
            /*

  • Creates an instance of SVNRepository to work with the repository.
  • All user's requests to the repository are relative to the
  • repository location used to create this SVNRepository.
  • SVNURL is a wrapper for URL strings that refer to repository locations.
                 */
                repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(repurl));
            } catch (SVNException svne) {
                /*
  • Perhaps a malformed URL is the cause of this exception
                 */
                debug("Error while creating an SVNRepository for location '"
                                + repurl + "': " + svne.getMessage());
                return false;
            }

            /*
  • User's authentication information (name/password) is provided via  an 
  • ISVNAuthenticationManager  instance.  SVNWCUtil  creates  a   default 
  • authentication manager given user's name and password.

  • Default authentication manager first attempts to use provided user name 
  • and password and then falls back to the credentials stored in the 
  • default Subversion credentials storage that is located in Subversion 
  • configuration area. If you'd like to use provided user name and password 
  • only you may use BasicAuthenticationManager class instead of default 
  • authentication manager:

  •  authManager = new BasicAuthenticationsManager(userName, userPassword);
  •  
  • You may also skip this point - anonymous access will be used.
             */
            ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(username, password);
            repository.setAuthenticationManager(authManager);

        try {
            /*

  • Checks up if the specified path/to/repository part of the URL
  • really corresponds to a directory. If doesn't the program exits.
  • SVNNodeKind is that one who says what is located at a path in a
  • revision. -1 means the latest revision.
                 */
                SVNNodeKind nodeKind = repository.checkPath("", -1);
                if (nodeKind == SVNNodeKind.NONE) {
                    debug("There is no entry at '" + repurl + "'.");
                    return false;
                } else if (nodeKind == SVNNodeKind.FILE) {
                    debug("The entry at '" + repurl + "' is a file while a directory was expected.");
                    return false;
                }
            } catch (SVNException svne) {
                debug("error while listing entries: " + svne.getMessage());
                return false;
            }
            return true;
         }
     

     public listFiles() {
        def str = ""
        try {
           /*

  • getRepositoryRoot() returns the actual root directory where the
  • repository was created. 'true' forces to connect to the repository 
  • if the root url is not cached yet.
                 */
                str += "Repository Root: " + repository.getRepositoryRoot(true).toString() + "\n";
                /*
  • getRepositoryUUID() returns Universal Unique IDentifier (UUID) of the 
  • repository. 'true' forces to connect to the repository 
  • if the UUID is not cached yet.
                 */
                str += "Repository UUID: " + repository.getRepositoryUUID(true).toString() + "\n";

            /*

  • Displays the repository tree at the current path - "" (what means
  • the path/to/repository directory)
                 */
                str += listEntries(repository, "");
                return str;
            } catch (SVNException svne) {
                debug("error while listing entries: " + svne.getMessage());
                return str;
            }
        }

    /*

  • Initializes the library to work with a repository via 
  • different protocols.
         */
        private static void setupLibrary() {
            /*
  • For using over http:// and https://
             */
            DAVRepositoryFactory.setup();
            /*
  • For using over svn:// and svn+xxx://
             */
            SVNRepositoryFactoryImpl.setup();
           
            /*
  • For using over file:///
             */
            FSRepositoryFactory.setup();
        }

    /*

  • Called recursively to obtain all entries that make up the repository tree
  • repository - an SVNRepository which interface is used to carry out the
  • request, in this case it's a request to get all entries in the directory
  • located at the path parameter;

  • path is a directory path relative to the repository location path (that
  • is a part of the URL used to create an SVNRepository instance);

  •      */
        public listEntries(SVNRepository repository, String path) throws SVNException {
            /*
  • Gets the contents of the directory specified by path at the latest
  • revision (for this purpose -1 is used here as the revision number to
  • mean HEAD-revision) getDir returns a Collection of SVNDirEntry
  • elements. SVNDirEntry represents information about the directory
  • entry. Here this information is used to get the entry name, the name
  • of the person who last changed this entry, the number of the revision
  • when it was last changed and the entry type to determine whether it's
  • a directory or a file. If it's a directory listEntries steps into a
  • next recursion to display the contents of this directory. The third
  • parameter of getDir is null and means that a user is not interested
  • in directory properties. The fourth one is null, too - the user
  • doesn't provide its own Collection instance and uses the one returned
  • by getDir.
             */
            def str = "";
            Collection entries = repository.getDir(path, -1, null,
                    (Collection) null);
            Iterator iterator = entries.iterator();
            while (iterator.hasNext()) {
                SVNDirEntry entry = (SVNDirEntry) iterator.next();
                str += entry.getDate().toString() + ": " + path + "/" + entry.getName().toString() + " " + entry.getRevision().toString() + " \n";
               /* str += "/" + (path.equals("") ? "" : path + "/")
                        + entry.getName().toString() + " (author: '" + entry.getAuthor().toString()
                        + "'; revision: " + entry.getRevision().toString() + "; date: " + entry.getDate().toString() + ")" + "\n";
               */
                /*
  • Checking up if the entry is a directory.
                 */
                if (entry.getKind() == SVNNodeKind.DIR) {
                    str += listEntries(repository, (path.equals("")) ? entry.getName().toString()
path + "/" + entry.getName().toString());
            }
        }
        return str;
    }

    public String getFileContentAsString(String space, String page, String language) {
      def c = getFileContent(space, page, language);
      if (c==null)
       return null;
     
      def str = new String(c);
      return str.trim();
    } 

    public byte[] getFileContent(String space, String page, String language) {
        get page
        def filePath = space + "/" + page;
        if (language!=null&&language!="")
          filePath += "." + language;
        filePath += ".xml"

        /*

  • This Map will be used to get the file properties. Each Map key is a
  • property name and the value associated with the key is the property
  • value.
             */
            SVNProperties fileProperties = new SVNProperties();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            /*

  • Checks up if the specified path really corresponds to a file. If
  • doesn't the program exits. SVNNodeKind is that one who says what is
  • located at a path in a revision. -1 means the latest revision.
                 */
                SVNNodeKind nodeKind = repository.checkPath(filePath, -1);
               
                if (nodeKind == SVNNodeKind.NONE) {
                    debug("There is no entry at '" + filePath + "'.");
                    return null;
                } else if (nodeKind == SVNNodeKind.DIR) {
                    debug("The entry at '" + repurl
                            + "' is a directory while a file was expected.");
                    return null;
                }
                /*
  • Gets the contents and properties of the file located at filePath
  • in the repository at the latest revision (which is meant by a
  • negative revision number).
                 */
                repository.getFile(filePath, -1, fileProperties, baos);

        } catch (SVNException svne) {
            System.err.println("error while fetching the file contents and properties: " + svne.getMessage());
            System.exit(1);
        }
        return baos.toByteArray();
    }

    public getXML(pagedoc) {
        def clonedDoc = pagedoc.document.clone();

        remove Tag object
        if (clonedDoc.getObject("XWiki.TagClass")) {
          clonedDoc.removeObject(clonedDoc.getObject("XWiki.TagClass"));
        }

        if (defaultUser && defaultUser!="") {
          clonedDoc.setCreator(defaultUser);
          clonedDoc.setContentAuthor(defaultUser);
          clonedDoc.setAuthor(defaultUser);
        } else {
          clonedDoc.setCreator(clonedDoc.getAuthor());
          clonedDoc.setContentAuthor(clonedDoc.getAuthor());
        }
    
        if (defaultDate && defaultDate!="") {
          clonedDoc.setCreationDate(defaultDate);
          clonedDoc.setContentUpdateDate(defaultDate);
          clonedDoc.setDate(defaultDate);
          clonedDoc.setVersion("1.1");
        } else {
          clonedDoc.setContentUpdateDate(clonedDoc.getDate())
          clonedDoc.setCreationDate(clonedDoc.getDate())
          clonedDoc.setVersion("1.1");
        }  

        clonedDoc.setComment("");
        clonedDoc.setMinorEdit(false);
        def c = clonedDoc.toXML(true, false, true, false, context.getContext())
        return c.trim().replaceAll("[\r]","");
    }

    public commitFile(pagedoc, message) {
        def c = getXML(pagedoc);
        return setFileContent(pagedoc.getSpace(), pagedoc.getName(), pagedoc.getLanguage(), c, message)
    }

    public commitFiles(pagelist, message) {
        def newSpaces = new ArrayList();
        def newPages = new ArrayList();

        def currentPageData = new HashMap();
        def pagesBySpace = new HashMap();

        def pagename2 = "";

        for (pagename in pagelist) {
           def pagedoc = xwiki.getDocument(pagename);
           make sure we get the right translations
           def lang = context.getRequest().get("${pagename}_language")
           if (lang!=null && lang!="")
             pagedoc = pagedoc.getTranslatedDocument(lang);
           def space = pagedoc.getSpace();
           def page = pagedoc.getName();
           def language = pagedoc.getLanguage();
           if (!newSpaces.contains(space)) {
               if (repository.checkPath(space, -1) == SVNNodeKind.NONE) {
                newSpaces.add(space);   
                debug("Adding to new spaces: ${space}")         
               }
           }      
          
           
get page
           def filePath = space + "/" + page;
           if (language!=null&&language!="")
                filePath += "." + language;
           filePath += ".xml"

           if (repository.checkPath(filePath, -1) == SVNNodeKind.NONE) {
                newPages.add(filePath);                 
                debug("Adding to new pages: ${filePath}")         
           } else {
                debug("Adding to updated pages: ${filePath}")         
                currentPageData.put(filePath, getFileContent(space, page, language))
           }

           def pageList = pagesBySpace.get(space);
           if (pageList==null) {
              pageList = new ArrayList();
              pagesBySpace.put(space, pageList);
           }
           pageList.add(pagedoc);
        }

        def editor = repository.getCommitEditor(message, null);
        def committedPages = new ArrayList();
        def commitInfo = null;

        try {
         /*

  • Always called first. Opens the current root directory. It  means  all
  • modifications will be applied to this directory until  a  next  entry
  • (located inside the root) is opened/added.

  • -1 - revision is HEAD (actually, for a comit  editor  this number  is 
  • irrelevant)
              */
             editor.openRoot(-1);

         for (space in pagesBySpace.keySet()) {
           start by creating the space if necessary and open it if not
           /*

  • Adds a new directory (in this  case - to the  root  directory  for 
  • which the SVNRepository was  created). 
  • Since this moment all changes will be applied to this new  directory.

  • dirPath is relative to the root directory.

  • copyFromPath (the 2nd parameter) is set to null and  copyFromRevision
  • (the 3rd) parameter is set to  -1  since  the  directory is not added 
  • with history (is not copied, in other words).
                */
                if (newSpaces.contains(space)) {      
                 editor.addDir(space, null, -1);
                } else {
                 editor.openDir(space, -1);
                }

            loop on each page
            for (pagedoc in pagesBySpace.get(space)) {  
              pagename2 = pagedoc.getFullName();
              def page = pagedoc.getName();
              def language = pagedoc.getLanguage();

              get page path
              def filePath = space + "/" + page;
              if (language!=null&&language!="")
                  filePath += "." + language;
              filePath += ".xml"

              def newXML = getXML(pagedoc);
              def newData = newXML.getBytes();

              if (newPages.contains(filePath)) {
                /*

  • Adds a new file to the just added  directory. The  file  path is also 
  • defined as relative to the root directory.
                     *
  • copyFromPath (the 2nd parameter) is set to null and  copyFromRevision
  • (the 3rd parameter) is set to -1 since  the file is  not  added  with 
  • history.
                     */
                     editor.addFile(filePath, null, -1);

                /*

  • The next steps are directed to applying delta to the  file  (that  is 
  • the full contents of the file in this case).
                     */
                    editor.applyTextDelta(filePath, null);
                    /*
  • Use delta generator utility class to generate and send delta

  • Note that you may use only 'target' data to generate delta when there is no 
  • access to the 'base' (previous) version of the file. However, using 'base' 
  • data will result in smaller network overhead.

  • SVNDeltaGenerator will call editor.textDeltaChunk(...) method for each generated 
  • "diff window" and then editor.textDeltaEnd(...) in the end of delta transmission.  
  • Number of diff windows depends on the file size. 

  •                  */
                    SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
                    String checksum = deltaGenerator.sendDelta(filePath, new ByteArrayInputStream(newData), editor, true);

                /*

  • Closes the new added file.
                     */
                    editor.closeFile(filePath, checksum);
                  } else {
                    def oldData = currentPageData.get(filePath);

                /*

  • Opens the file added in the previous commit.

  • filePath is also defined as a relative path to the root directory.
                     */
                    editor.openFile(filePath, -1);
           
                    /*
  • The next steps are directed to applying and writing the file delta.
                     */
                    editor.applyTextDelta(filePath, null);
           
                    /*
  • Use delta generator utility class to generate and send delta

  • Note that you may use only 'target' data to generate delta when there is no 
  • access to the 'base' (previous) version of the file. However, here we've got 'base' 
  • data, what in case of larger files results in smaller network overhead.

  • SVNDeltaGenerator will call editor.textDeltaChunk(...) method for each generated 
  • "diff window" and then editor.textDeltaEnd(...) in the end of delta transmission.  
  • Number of diff windows depends on the file size. 

  •                  */
                    SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
                    String checksum = deltaGenerator.sendDelta(filePath, new ByteArrayInputStream(oldData), 0, new ByteArrayInputStream(newData), editor, true);

                 /*

  • Closes the file.
                     */
                    editor.closeFile(filePath, checksum);

                updating status to check for changes
                committedPages.add(getStatusPath(pagedoc));
                def pageStatus = status.get(getStatusPath(pagedoc));
                if (pageStatus==null)
                 pageStatus = [ "xwikiversion" : "", "xwikihash" : "", "svnversion" : ""];
                status.put(getStatusPath(pagedoc), pageStatus);
                pageStatus.xwikiversion = "${pagedoc.getVersion()}";
                pageStatus.xwikihash = "${newXML.hashCode()}";
              }
            }

            close the space
            editor.closeDir();
         }

         close root dir
         editor.closeDir();
        } catch (Throwable e) {
            e.printStackTrace();
            debug("error preparing commit on page ${pagename2}: " + e.getMessage());
            return null;

        } finally {
           /*

  • This is the final point in all editor handling. Only now all that new
  • information previously described with the editor's methods is sent to
  • the server for committing. As a result the server sends the new
  • commit information.
                */
                try {
                  commitInfo = editor.closeEdit();  
                } catch (Throwable e) {
                 e.printStackTrace();
                 debug("error calling closeEdit: " + e.getMessage());
                 return null;
                }
             }

         we need to save the status
         def rev = commitInfo.getNewRevision();
         for (def pagepath in committedPages) {
           status.get(pagepath).svnversion = "${rev}";
         }
         saveStatus();
         return commitInfo;
    }

    public setFileContent(String space, String page, String language, String xml, String message) {
        def createDir = (repository.checkPath(space, -1) != SVNNodeKind.DIR);
        setFileContent(space, page, language, xml, message, createDir, true);
    }

    public setFileContent(String space, String page, String language, String xml, String message, boolean createDir) {
        get page
        def filePath = space + "/" + page;
        if (language!=null&&language!="")
          filePath += "." + language;
        filePath += ".xml"

        def c = getFileContentAsString(space, page, language);
        def changed = false;
        if (c==null || !c.equals(xml))
            changed = true;

        if (changed) {
          def editor = repository.getCommitEditor(message, null);
          def commitInfo = null;

          try {
           if (c==null) {
             page does not exist we need to add it
             debug("Ready to add file ${filePath} with createDir ${createDir}")
             addFile(editor, space, filePath, xml.getBytes(), createDir, true, true)
           } else {
             
content is different we can commit
             page does not exist we need to add it
             debug("Ready to update file ${filePath}")
             modifyFile(editor, space, filePath, c.getBytes(), xml.getBytes())
           }
          } catch (Throwable e) {
             e.printStackTrace();
             debug("error preparing commit: " + e.getMessage());
             return null;
          } finally {
           /*

  • This is the final point in all editor handling. Only now all that new
  • information previously described with the editor's methods is sent to
  • the server for committing. As a result the server sends the new
  • commit information.
                */
                try {
                  commitInfo = editor.closeEdit();  
                } catch (Throwable e) {
                 e.printStackTrace();
                 debug("error calling closeEdit: " + e.getMessage());
                 return null;
                }
              }
              return commitInfo;
            } else {
              content is the same. do not commit
              debug("content is the same. do not commit");
              return null;
            }
        }

    /*

  • This method performs commiting an addition of a  directory  containing  a
  • file.
         */
        private void addFile(ISVNEditor editor, String dirPath,
                String filePath, byte[] data, boolean createDir, boolean closeDir, boolean closeRootDir) throws SVNException {
            /*
  • Always called first. Opens the current root directory. It  means  all
  • modifications will be applied to this directory until  a  next  entry
  • (located inside the root) is opened/added.

  • -1 - revision is HEAD (actually, for a comit  editor  this number  is 
  • irrelevant)
             */
            editor.openRoot(-1);
            /*
  • Adds a new directory (in this  case - to the  root  directory  for 
  • which the SVNRepository was  created). 
  • Since this moment all changes will be applied to this new  directory.

  • dirPath is relative to the root directory.

  • copyFromPath (the 2nd parameter) is set to null and  copyFromRevision
  • (the 3rd) parameter is set to  -1  since  the  directory is not added 
  • with history (is not copied, in other words).
             */
             if (createDir) {      
              editor.addDir(dirPath, null, -1);
             } else {
              editor.openDir(dirPath, -1);
             }
            /*
  • Adds a new file to the just added  directory. The  file  path is also 
  • defined as relative to the root directory.
             *
  • copyFromPath (the 2nd parameter) is set to null and  copyFromRevision
  • (the 3rd parameter) is set to -1 since  the file is  not  added  with 
  • history.
             */
            editor.addFile(filePath, null, -1);
            /*
  • The next steps are directed to applying delta to the  file  (that  is 
  • the full contents of the file in this case).
             */
            editor.applyTextDelta(filePath, null);
            /*
  • Use delta generator utility class to generate and send delta

  • Note that you may use only 'target' data to generate delta when there is no 
  • access to the 'base' (previous) version of the file. However, using 'base' 
  • data will result in smaller network overhead.

  • SVNDeltaGenerator will call editor.textDeltaChunk(...) method for each generated 
  • "diff window" and then editor.textDeltaEnd(...) in the end of delta transmission.  
  • Number of diff windows depends on the file size. 

  •          */
            SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
            String checksum = deltaGenerator.sendDelta(filePath, new ByteArrayInputStream(data), editor, true);

        /*

  • Closes the new added file.
             */
            editor.closeFile(filePath, checksum);
            /*
  • Closes the new added directory.
             */
            if (closeDir)
             editor.closeDir();

        /*

  • Closes the root directory.
             */
            if (closeRootDir)
             editor.closeDir();
        }

    /*

  • This method performs committing file modifications.
         */
        private void modifyFile(ISVNEditor editor, String dirPath,
                String filePath, byte[] oldData, byte[] newData) throws SVNException {
            /*
  • Always called first. Opens the current root directory. It  means  all
  • modifications will be applied to this directory until  a  next  entry
  • (located inside the root) is opened/added.

  • -1 - revision is HEAD
             */
            editor.openRoot(-1);
            /*
  • Opens a next subdirectory (in this example program it's the directory
  • added  in  the  last  commit).  Since this moment all changes will be
  • applied to this directory.

  • dirPath is relative to the root directory.
  • -1 - revision is HEAD
             */
            editor.openDir(dirPath, -1);
            /*
  • Opens the file added in the previous commit.

  • filePath is also defined as a relative path to the root directory.
             */
            editor.openFile(filePath, -1);
           
            /*
  • The next steps are directed to applying and writing the file delta.
             */
            editor.applyTextDelta(filePath, null);
           
            /*
  • Use delta generator utility class to generate and send delta

  • Note that you may use only 'target' data to generate delta when there is no 
  • access to the 'base' (previous) version of the file. However, here we've got 'base' 
  • data, what in case of larger files results in smaller network overhead.

  • SVNDeltaGenerator will call editor.textDeltaChunk(...) method for each generated 
  • "diff window" and then editor.textDeltaEnd(...) in the end of delta transmission.  
  • Number of diff windows depends on the file size. 

  •          */
            SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
            String checksum = deltaGenerator.sendDelta(filePath, new ByteArrayInputStream(oldData), 0, new ByteArrayInputStream(newData), editor, true);

        /*

  • Closes the file.
             */
            editor.closeFile(filePath, checksum);

        /*

  • Closes the directory.
             */
            editor.closeDir();

        /*

  • Closes the root directory.
             */
            editor.closeDir();
        }

    /*

  • This method performs committing a deletion of a directory.
         */
        private void deleteDir(ISVNEditor editor, String dirPath) throws SVNException {
            /*
  • Always called first. Opens the current root directory. It  means  all
  • modifications will be applied to this directory until  a  next  entry
  • (located inside the root) is opened/added.

  • -1 - revision is HEAD
             */
            editor.openRoot(-1);
            /*
  • Deletes the subdirectory with all its contents.

  • dirPath is relative to the root directory.
             */
            editor.deleteEntry(dirPath, -1);
            /*
  • Closes the root directory.
             */
            editor.closeDir();
        }

    public getChangedPages(String spaces) {
        return getChangedPages(spaces, "");
    }

    protected checkPage(page, pagedoc, changedMap, samePages, svnEntries) {
           def wikicontent = getXML(pagedoc);
           def svncontent = getFileContentAsString(pagedoc.getSpace(), pagedoc.getName(), pagedoc.getLanguage())
           svncontent = (svncontent == null) ? null : svncontent.trim();
           if (!wikicontent.equals(svncontent)) {
            def filePath = getFilePath(pagedoc);
            def pageStatus = getPageStatus(getStatusPath(pagedoc));
            if (pageStatus==null) {
               pageStatus = [ "xwikiversion" : pagedoc.getVersion(), "xwikihash" : "", "svnversion" : "" ];
               status.put(getStatusPath(pagedoc), pageStatus);
            }
            pageStatus.filePath = filePath;
            pageStatus.page = page;
            pageStatus.fullname = pagedoc.fullName;
            pageStatus.language = pagedoc.language
            pageStatus.status = "";

            debug("Checking page ${page} version ${pagedoc.getVersion()} pageStatus ${pageStatus}")

            if (pageStatus.xwikihash=="") {
               def entry = svnEntries.get(filePath);
               def svnversion = (entry==null) ? "" : entry.svnversion;
               if (svnversion=="")
                pageStatus.status = "A";
               else
                pageStatus.status = "?";
            } else if (pagedoc.getVersion().equals(pageStatus.xwikiversion)) {
               version has not changed in the wiki
               def whash = "${wikicontent.hashCode()}";
               
if the recorded hash is the same then we have a modified version in SVN
               otherwise it's a bad state so it's a conflict
               if (whash == pageStatus.xwikihash)
                pageStatus.status = "U";
               else
                pageStatus.status = "C";
            } else {
               def entry = svnEntries.get(filePath);
               def svnversion = (entry==null) ? "" : entry.svnversion;
               if (svnversion=="")
                pageStatus.status = "A";
               else if(pageStatus.svnversion==svnversion)
                pageStatus.status = "M";
               else
                pageStatus.status = "C";
            }
            changedMap.put(page, pageStatus)
           } else {
             def filePath = getFilePath(pagedoc);
             samePages.add(filePath);
             def pageStatus = getPageStatus(getStatusPath(pagedoc));
             if (pageStatus==null) {
                pageStatus = [ "xwikiversion" : "", "xwikihash" : "", "svnversion" : "" ];
                status.put(getStatusPath(pagedoc), pageStatus);
             }   
             pageStatus.xwikiversion = pagedoc.getVersion();
             pageStatus.xwikihash = wikicontent.hashCode();
             pageStatus.svnversion = svnEntries.get(filePath).svnversion;
           }
    }

    public getChangedPages(String spaces, String savedlist) {
        def changedMap = new TreeMap();
        def svnEntries = getEntries();
        def spaceList = null;
        def samePages = new ArrayList();
        def list;

        if (!savedlist || savedlist=="") {
         spaceList = Arrays.asList(StringUtils.split(spaces," ,"));
         def sspaces = StringUtils.join(spaceList, "','");
         def sql = "select doc.fullName from XWikiDocument as doc where doc.space in ('${sspaces}')";
         debug("Searching for ${sql}");
         list = xwiki.search(sql)
        } else {
         list = StringUtils.split(xwiki.getDocument(savedlist).getValue("list"), "|");
        }

        for (page in list) {
           def pagedoc = xwiki.getDocument(page);
           checkPage(page, pagedoc, changedMap, samePages, svnEntries);
           for (trans in pagedoc.getTranslationList()) {
               def tpagedoc = pagedoc.getTranslatedDocument(trans);
               checkPage(page + ".fr", tpagedoc, changedMap, samePages, svnEntries);
           }
        }

        if (spaceList!=null) {
         for (entry in svnEntries.keySet()) {
             def i1 = entry.indexOf("/");
             def i2 = entry.indexOf(".xml");
             def spaceName = (i1==-1) ? entry : entry.substring(0, i1);
             def pageName = (i2==-1) ? entry : entry.substring(i1+1, i2);
             if (spaceList.contains(spaceName)&&!samePages.contains(entry)&&!changedMap.keySet().contains(spaceName + "." + pageName)) {
               changedMap.put(spaceName + "." + pageName, [ "status" : "N", "xwikiversion" : "", "svnversion" : svnEntries.get(entry).svnversion ])
             }
         }
        }
        saveStatus if changed
        saveStatus();
        return changedMap;
    }

    public updatePages(pageList) {
        def changedMap = new TreeMap();
        def svnEntries = getEntries();

        for (page in pageList) {
           def pagedoc = xwiki.getDocument(page);
           make sure we are getting the right translation
           def lang = context.getRequest().get("${page}_language")
           if (lang!=null && lang!="")
             pagedoc = pagedoc.getTranslatedDocument(lang);
           def wikicontent = getXML(pagedoc);
           def svncontent = getFileContentAsString(pagedoc.getSpace(), pagedoc.getName(), pagedoc.getLanguage())
           def svnversion = "";
           if (!wikicontent.equals(svncontent)) {
            def filePath = getFilePath(pagedoc);
            def pageStatus = getPageStatus(getStatusPath(pagedoc));
            if (pageStatus==null) {
               pageStatus = [ "xwikiversion" : pagedoc.getVersion(), "xwikihash" : "", "svnversion" : "" ];
            }
            pageStatus.filePath = filePath;
            pageStatus.page = page;
            pageStatus.status = "";

            debug("Checking page ${page} version ${pagedoc.getVersion()} pageStatus ${pageStatus}")
            def needUpdate = false
            def entry = svnEntries.get(filePath);
            svnversion = (entry==null) ? "" : entry.svnversion;

            if (pageStatus.xwikihash=="") {
               if (svnversion!="")
                needUpdate = true;
            } else if (pagedoc.getVersion().equals(pageStatus.xwikiversion)) {
                needUpdate = true;
            } else {
               if (svnversion!="")
                needUpdate = true
               else if(pageStatus.svnversion!=svnversion)
                needUpdate = true;
            }

            if (needUpdate) {
              updating XWiki document from SVN
              changedMap.put(page, pageStatus);
              def archive = pagedoc.document.getDocumentArchive(context.getContext());
              def version = pagedoc.document.getRCSVersion();

              def newdoc = new XWikiDocument();
              newdoc.fromXML(svncontent);
            
              check attachments that do not exist in updated pages and delete them to recycle bin
              for (xa in pagedoc.getAttachmentList()) {
                    if (!newdoc.getAttachment(xa.getFilename())) {
                       pagedoc.document.deleteAttachment(xa.attachment, true, context.getContext());
                    }
              }

              Make sure they are not marked dirty
              for (xa in newdoc.getAttachmentList()) {
                    xa.setMetaDataDirty(false);
                    xa.getAttachment_content().setContentDirty(false);
              }

              we need to make sure previous history is kept
              newdoc.setDocumentArchive(archive);

              we need to keep the creator if there was already a document
              if (pagedoc.getCreator()!=null)
               newdoc.setCreator(pagedoc.getCreator());

              set user and author to current user
              newdoc.setContentAuthor(context.getUser());
              newdoc.setAuthor(context.getUser());

              we need to make sure no version is added
              if (pagedoc.isNew()) {
                newdoc.setMetaDataDirty(true);
                newdoc.setContentDirty(true);
                newdoc.setRCSVersion(null);
              } else {
                newdoc.setMetaDataDirty(true);
                newdoc.setContentDirty(true);
              }

              saving document
              xwiki.getXWiki().saveDocument(newdoc, "Updated from SVN", context.getContext());

              saving attachments
              newdoc.saveAllAttachments(false, true, context.getContext());

              we need to force the saving the document archive.
              if (newdoc.getDocumentArchive() != null) {
                  xwiki.getXWiki().getVersioningStore().saveXWikiDocArchive(newdoc.getDocumentArchive(context.getContext()), true, context.getContext());
              }

              
reading the information to set the status
              def newpagedoc = xwiki.getDocument(pagedoc.getFullName());
              def newwikicontent = getXML(pagedoc);
              pageStatus.xwikiversion = pagedoc.getVersion();
              pageStatus.xwikihash = "${newwikicontent.hashCode()}";  
              pageStatus.svnversion = svnversion;    
            }
           }
        }
        saveStatus if changed
        saveStatus();
        return changedMap;
    }

    public exportPages(docname, pageList) {
        def export = xwiki.package
        export.setWithVersions(true)
        export.setWithVersions(false)
        export.setName(docname)
        for (page in pageList) {
            export.add(page, 0);
        }
        export.export();
    }

    public getModifiedFiles(rev) {
        return (getModifiedFiles("", rev, "10"));
    }

    public getModifiedFiles2(date, hour) {
        return (getModifiedFiles("", date, hour));
    }
   
    public getModifiedFiles2(dir, date, hour) {
    }

    public getModifiedFiles(dir, rev, max) {
    }

    public getRevisions(dir) {
    }
   
    public listFiles(dir, recursive) {
    }

    public getCommitStatus(prefix, sep, updatedonly) {
        def str = "";
        Collection spaceEntries = repository.getDir("", -1, null, (Collection) null);
        Iterator spaceIterator = spaceEntries.iterator();
        str += "${prefix}page${sep}language${sep}version${sep}isnew${sep}hash${sep}svnpath${sep}svnversion${sep}svnhash${sep}isdiff\n"
        while (spaceIterator.hasNext()) {
            SVNDirEntry entry = (SVNDirEntry) spaceIterator.next();
            if (entry.getKind() == SVNNodeKind.DIR) {
              def space = entry.getName().toString();
              Collection pageEntries = repository.getDir(space, -1, null, (Collection) null);
              Iterator pageIterator = pageEntries.iterator();
              while (pageIterator.hasNext()) {
                 def pageEntry = pageIterator.next();
                 def fileName = pageEntry.getName().toString();
                 def i1 = fileName.indexOf(".xml");
                 def pageName = (i1==-1) ? fileName : fileName.substring(0, i1);
                 pageName = space + "." + pageName;
                 def pagedoc = xwiki.getDocument(pageName);
                 def pagexml = getXML(pagedoc);

                 def fileProperties = new SVNProperties();
                 def baos = new ByteArrayOutputStream();
                 debug("reading file: ${space}/${fileName}")
                 repository.getFile(space + "/" + fileName, -1, fileProperties, baos);
                 def svncontent = new String(baos.toByteArray())

                 def version = (pagedoc==null) ? "" : pagedoc.getVersion();
                 def hash = (pagexml==null) ? "" : pagexml.hashCode();
                 def svnversion = pageEntry.getRevision().toString();
                 def svnhash = (svncontent==null) ? "" : svncontent.hashCode();

                 def isdiff = !pagexml.equals(svncontent)
                 if (!updatedonly || !isdiff)
                  str += "${prefix}${pageName}${sep}${pagedoc.getLanguage()}${sep}${version}${sep}${pagedoc.isNew()}${sep}${hash}${sep}${space}/${fileName}${sep}${svnversion}${sep}${svnhash}${sep}${isdiff}\n"
              }
            }
        }
        return str;
    }

    public getEntries() {
        def entries = new HashMap();
        Collection spaceEntries = repository.getDir("", -1, null, (Collection) null);
        Iterator spaceIterator = spaceEntries.iterator();
        while (spaceIterator.hasNext()) {
            SVNDirEntry entry = (SVNDirEntry) spaceIterator.next();
            if (entry.getKind() == SVNNodeKind.DIR) {
              def space = entry.getName().toString();
              Collection pageEntries = repository.getDir(space, -1, null, (Collection) null);
              Iterator pageIterator = pageEntries.iterator();
              while (pageIterator.hasNext()) {
                 def pageEntry = pageIterator.next();
                 def fileName = pageEntry.getName().toString();
                 def filePath = space + "/" + fileName;
                 def fileProperties = new SVNProperties();
                 def baos = new ByteArrayOutputStream();
                 debug("reading file: ${space}/${fileName}")
                 repository.getFile(filePath, -1, fileProperties, baos);
                 def svncontent = new String(baos.toByteArray())
                 def svnversion = pageEntry.getRevision().toString();
                 def svnhash = (svncontent==null) ? "" : svncontent.hashCode();

                 entries.put(filePath, [ "svnversion" : svnversion, "svnhash" : svnhash ]);
              }
            }
        }
        return entries;
    }

    public showXMLDiff(pagedoc) {
        def svnxml = getFileContentAsString(pagedoc.getSpace(), pagedoc.getName(), pagedoc.getLanguage());
        def xml = getXML(pagedoc);
        if (pagedoc.isNew() && svnxml == null)
         return "Document does not exist";
       
        if (pagedoc.isNew())
         return "Document does not exist in the wiki"

        if (svnxml==null)
         return "Document does not exist in SVN"
  
        remove attachment content from xml
        svnxml = svnxml.replaceAll("(?s)<attachment>(.*?)<content>(.*?)</content>(.*?)</attachment>", "<attachment>\$1<content></content>\$3</attachment>")
        xml = xml.replaceAll("(?s)<attachment>(.*?)<content>(.*?)</content>(.*?)</attachment>",
                      "<attachment>\$1<content></content>\$3</attachment>")
        return xwiki.diff.getDifferencesAsHTML(svnxml, xml, false);
    }

}

Tags:
Created by Administrator on 2009/12/31 23:00
   

Orphaned Pages

My Bulletin Boards