GitLabGroovy
import org.gitlab.api.*;
import org.gitlab.api.http.*;
import org.gitlab.api.models.*;
import groovy.json.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.Calendar;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import org.apache.velocity.tools.generic.EscapeTool;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.codec.binary.Base64;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.xpn.xwiki.doc.XWikiDocument;
@SuppressWarnings("GrUnnecessarySemicolon")
public class GitLabGroovy {
def xwiki;
def context;
def services;
def logger;
def gitlabapi;
def gitlabproject;
def prjname = "";
def prjdesc = "";
def prjversion = "";
def contribVersion = "";
def xmlVersion = "";
def gitlaburl = "";
def repuser = "";
def repname = "";
def reppath = "";
def repsrcpath = "src/main/resources";
def repbranch = "";
def defaultspace = "";
def configdoc;
def savedlist = "";
def repository = null;
def username = "";
def email = "";
def token = "";
def defaultDate = "";
Boolean removeDates;
String license;
String parentDefinitionStrategy;
String defaultLanguageDefinitionStrategy;
def defaultUser = "";
def status = new HashMap();
def DEFAULTAUTHOR = "xwiki:XWiki.Admin";
public setXWiki(xwiki, context, services) {
this.xwiki = xwiki;
this.context = context;
this.services = services;
this.logger = services.logging.getLogger(this.getClass().getCanonicalName());
}
public hasProgrammingRights() {
return xwiki.hasProgrammingRights();
}
public setGitLabConfig(page) {
this.configdoc = xwiki.getDocument(page)
this.prjname = configdoc.getValue("name");
this.prjdesc = configdoc.getValue("description");
this.prjversion = configdoc.getValue("version");
this.contribVersion = configdoc.getValue("contribVersion");
this.xmlVersion = configdoc.getValue("xarXmlVersion");
this.gitlaburl = configdoc.getValue("gitlab_url");
this.repuser = configdoc.getValue("repository_user");
this.repname = configdoc.getValue("repository_name");
this.reppath = configdoc.getValue("repository_path");
this.repbranch = (StringUtils.isBlank(configdoc.getValue("repository_branch"))) ? "master" : configdoc.getValue("repository_branch");
this.defaultspace = configdoc.getValue("defaultspace");
this.savedlist = configdoc.getValue("savedlist");
this.defaultDate = configdoc.getValue("defaultdate");
this.removeDates = configdoc.getValue("removeDates");
this.license = configdoc.getValue("license");
this.parentDefinitionStrategy = (configdoc.getValue("parentDefinitionStrategy") != null) ? configdoc.getValue("parentDefinitionStrategy") : "";
this.defaultLanguageDefinitionStrategy = (configdoc.getValue("defaultLanguageDefinitionStrategy") != null) ? configdoc.getValue("defaultLanguageDefinitionStrategy") : "";
this.defaultUser = configdoc.getValue("defaultuser");
this.status = getStatus(configdoc.getValue("status"));
if (contribVersion==null || contribVersion=="")
contribVersion = "8.4"
if (xmlVersion==null || xmlVersion=="")
xmlVersion = "1.1"
def authobj = configdoc.getObject("GitLab.Code.GitLabAuthClass", "contextuser", context.user)
if (authobj && authobj.getProperty("token").property.value != '') {
this.token = authobj.getProperty("token").property.value
} else {
Attempt to load a token defined on the user profile
def userProfileDoc = xwiki.getDocument(context.user);
userProfileDoc.use('GitLab.Code.GitLabAuthProfileClass');
def userProfileToken = userProfileDoc.getValue('token');
if (userProfileToken != '') {
this.token = userProfileToken;
}
}
Basic authentication
Create a GitLabApi instance to communicate with your GitLab server
gitlabapi = GitlabAPI.connect(gitlaburl, token)
gitlabproject = gitlabapi.getProject(repuser, repname)
logger.debug("Project: ${gitlabproject}")
return (gitlabproject==null) ? null : "";
}
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] : "", "gitlabversion" : (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.gitlabversion}\n";
}
only save if changed
if (status!=configdoc.getValue("status")) {
configdoc.set("status", sstatus);
configdoc.save();
}
}
public getDefaultSpace() {
return this.defaultspace;
}
public getSavedList() {
return (this.savedlist==null) ? "" : this.savedlist;
}
public getFilePath(pagedoc, nested) {
get page
def filePath = getSourcePath() + ((nested) ? pagedoc.getSpace().replaceAll("[.]","/") : pagedoc.getSpace()) + "/" + pagedoc.documentReference.name;
def language = pagedoc.getLanguage();
if (language!=null&&language!="")
filePath += "." + language;
filePath += ".xml"
return filePath;
}
public getStatusPath(pagedoc) {
get page
def filePath = pagedoc.getSpace() + "/" + pagedoc.documentReference.name;
def language = pagedoc.getLanguage();
if (language!=null&&language!="")
filePath += "." + language;
return filePath;
}
public cleanXML(gitlabcontent, withFormat) {
def newdoc = new XWikiDocument();
newdoc.fromXML(gitlabcontent.replaceAll("\r",""));
return getXML(newdoc.newDocument(context.getContext()), withFormat);
}
public String getFileContentAsString(sha, withFormat) {
/* def dservice = new DataService(gitlabclient);
def blob = dservice.getBlob(repository, sha);
def gitlabcontent = new String(Base64.decodeBase64(blob.content.getBytes()), "UTF-8");
if (withFormat)
return cleanXML(gitlabcontent, true);
return gitlabcontent;
*/
}
/*
public String getFileContentAsString(String space, String page, String language) {
get page
def filePath = space + "/" + page;
if (language!=null&&language!="")
filePath += "." + language;
filePath += ".xml"
return "";
}
*/
public getPOMFile() {
def escapetool = new EscapeTool();
def samplePOM = xwiki.getDocument("GitLab.Code.SamplePOM").getContent();
samplePOM = samplePOM.replaceAll("PRJNAME", prjname.toLowerCase().replaceAll(" ", "-"))
samplePOM = samplePOM.replaceAll("PRJPNAME", prjname)
samplePOM = samplePOM.replaceAll("PRJDESC", escapetool.xml(prjdesc))
samplePOM = samplePOM.replaceAll("PRJVERSION", prjversion)
samplePOM = samplePOM.replaceAll("CONTRIBVERSION", contribVersion)
samplePOM = samplePOM.replaceAll("XMLVERSION", xmlVersion)
samplePOM = samplePOM.replaceAll("REPOSITORY_NAME", repname)
samplePOM = samplePOM.replaceAll("REPOSITORY_USER", repuser)
samplePOM = samplePOM.replaceAll("USERNAME", username)
return samplePOM;
}
public getXML(pagedoc, boolean withFormat) {
def clonedDoc = pagedoc.document.clone();
boolean isTranslationDocument = false;
if ((this.parentDefinitionStrategy.isBlank() || this.parentDefinitionStrategy.equals("setDefault")) && clonedDoc.getParent().isBlank()) {
clonedDoc.setParent(clonedDoc.getSpace() + ".WebHome");
}
If the cloned document is a translation, we won't be able to know directly if it has a TranslationDocumentClass ; the quick and dirty way to check it is to get the default document.
if (xwiki.getDocument(clonedDoc.getFullName()).getObject("XWiki.TranslationDocumentClass")) {
if (clonedDoc.getSyntaxId()!="plain/1.0") {
clonedDoc.setSyntaxId("plain/1.0");
}
if (!clonedDoc.isHidden()) {
clonedDoc.setHidden(true);
}
isTranslationDocument = true;
}
remove Tag object
if (clonedDoc.getObject("XWiki.TagClass")) {
clonedDoc.removeObject(clonedDoc.getObject("XWiki.TagClass"));
}
remove all gitlab authentication classes so that we don't commit passwords
for (object in clonedDoc.getObjects("GitLab.Code.GitLabAuthClass")) {
clonedDoc.removeObject(object);
}
remove all gitlab authentication classes so that we don't commit passwords
for (object in clonedDoc.getObjects("GitLabCode.GitLabConfigClass")) {
object.set("status", "", context.getContext())
}
if (withFormat) {
clonedDoc.setCreator(DEFAULTAUTHOR);
clonedDoc.setContentAuthor(DEFAULTAUTHOR);
clonedDoc.setAuthor(DEFAULTAUTHOR);
} else 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");
}
Update attachment dates
for (xa in clonedDoc.getAttachmentList()) {
xa.setVersion("1.1");
if (defaultDate && defaultDate!="") {
xa.setDate(defaultDate);
}
if (withFormat) {
xa.setAuthor(DEFAULTAUTHOR);
} else if (defaultUser && defaultUser!="") {
xa.setAuthor(defaultUser);
}
}
clonedDoc.setComment("");
clonedDoc.setMinorEdit(false);
def c = clonedDoc.toXML(true, false, true, false, context.getContext())
def c2 = c.trim().replaceAll("[\r]","");
return (withFormat) ? format(c2, "", isTranslationDocument) : c2;
}
/
- Creates a new file in the repository
* - @param branchName The name of a repository branch
- @param commitMsg The commit message
- @param actions The actions to send
- @throws IOException on gitlab api call error
*/
public gitLabCommits(String branchName, String commitMsg, Object actions) throws IOException {
String tailUrl = gitlabproject.URL + "/" + gitlabproject.getId() + "/repository/commits";
GitlabHTTPRequestor requestor = gitlabapi.dispatch();
def req = requestor
.with("branch", branchName)
.with("commit_message", commitMsg)
.with("actions", actions);
logger.trace("JSON: " + JsonOutput.toJson(req.data));
return req.to(tailUrl, GitlabCommit.class);
}
public commitFiles(pagelist, message, pom) {
def srcPath = getSourcePath();
def newSpaces = new ArrayList();
def newPages = new ArrayList();
def currentPageData = new HashMap();
def pagesBySpace = new HashMap();
def pagename2 = "";
we need to list entries to see if we create or update
def entriesKeySet = getEntries("").keySet();
for (pagename in pagelist) {
separate the language particle at the end of the page name from the page fullname. The pagename is of form <docfullname>.<doclanguage>
def languageSeparator = pagename.lastIndexOf('.');
if (languageSeparator < 0) {
def pagefullname = pagename;
}
def pagefullname = pagename.substring(0, languageSeparator);
def lang = pagename.substring(languageSeparator + 1);
def pagedoc = xwiki.getDocument(pagefullname);
make sure we get the right translations
if (lang!=null && lang!="") {
pagedoc = pagedoc.getTranslatedDocument(lang);
}
def space = pagedoc.getSpace();
def page = pagedoc.documentReference.name;
def language = pagedoc.getLanguage();
def pageList = pagesBySpace.get(space);
if (pageList==null) {
pageList = new ArrayList();
pagesBySpace.put(space, pageList);
}
pageList.add(pagedoc);
}
def committedPages = new ArrayList();
def commitInfo = null;
def actions = []
def gitlabEntries = getEntries("");
try {
for (space in pagesBySpace.keySet()) {
loop on each page
for (pagedoc in pagesBySpace.get(space)) {
pagename2 = pagedoc.getFullName();
def page = pagedoc.documentReference.name;
def language = pagedoc.getLanguage();
find page Path
def result = findPage(gitlabEntries, pagedoc);
def entry = result.entry;
def filePath = result.filePath;
def newXML = getXML(pagedoc, true);
def newData = newXML.getBytes();
def action = [:];
action.action = (entry!=null) ? "update" : "create";
action.file_path = filePath;
action.content = newXML;
adding the page
actions.add(action);
if (!newPages.contains(filePath)) {
def oldData = currentPageData.get(filePath);
updating status to check for changes
committedPages.add(getStatusPath(pagedoc));
def pageStatus = status.get(getStatusPath(pagedoc));
if (pageStatus==null)
pageStatus = [ "xwikiversion" : "", "xwikihash" : "", "gitlabversion" : ""];
status.put(getStatusPath(pagedoc), pageStatus);
pageStatus.xwikiversion = "${pagedoc.getVersion()}";
pageStatus.xwikihash = "${newXML.hashCode()}";
}
}
}
} catch (Throwable e) {
e.printStackTrace();
logger.debug("error preparing commit on page ${pagename2}: " + e.getMessage());
return null;
} finally {
}
Adding pom in commit
if (pom=="1") {
def action = [:];
try {
gitlabapi.getRepositoryFile(gitlabproject, "pom.xml", repbranch)
action.action = "update"
} catch(e) {
action.action = "create"
}
action.file_path = "pom.xml";
action.content = getPOMFile();
actions.add(action);
logger.debug("Added pom.xml to commit");
}
now real commit
def newCommit = gitLabCommits(repbranch, message, actions);
logger.debug("Created commit: " + newCommit);
we need to save the status
saveStatus();
return "${gitlaburl}${repuser}/${repname}/tree/${newCommit.id}";
}
public getChangedPages(String spaces) {
return getChangedPages(spaces, "");
}
public findPage(entries, pagedoc) {
def filePath = getFilePath(pagedoc, false);
logger.debug("Check ${filePath} in entries");
def entry = entries.get(filePath);
if (entry==null) {
filePath = getFilePath(pagedoc, true);
logger.debug("Check ${filePath} in entries");
entry = entries.get(filePath);
}
return [ entry : entry, filePath : filePath ];
}
protected checkPage(page, pagedoc, changedMap, samePages, gitlabEntries) {
def wikicontent = getXML(pagedoc, true);
def wikihash = (wikicontent==null) ? "" : "${wikicontent.hashCode()}";
def wikicontent_unformatted = getXML(pagedoc, false);
def result = findPage(gitlabEntries, pagedoc);
def entry = result.entry;
def filePath = result.filePath;
logger.debug("Check ${filePath} ${wikihash}");
if (entry==null || !wikihash.equals(entry.gitlabhash) || !wikihash.equals(entry.gitlabhash_unformatted)) {
def pageStatus = getPageStatus(getStatusPath(pagedoc));
if (pageStatus==null) {
pageStatus = [ "xwikiversion" : pagedoc.getVersion(), "xwikihash" : "", "gitlabversion" : "", "gitlabsha" : (entry==null) ? "" : entry.gitlabsha ];
status.put(getStatusPath(pagedoc), pageStatus);
}
pageStatus.filePath = filePath;
pageStatus.page = page;
pageStatus.fullname = pagedoc.fullName;
pageStatus.language = pagedoc.language
pageStatus.status = "";
pageStatus.gitlabsha = (entry==null) ? "" : entry.gitlabsha;
logger.debug("Checking page ${page} version ${pagedoc.getVersion()} pageStatus ${pageStatus} ${wikihash}")
if the documents match after formatting but the pure gitlab content is different then display it as 'F' (content is equivalent except formatting).
if (entry!=null && wikihash.equals(entry.gitlabhash)) {
pageStatus.status = "F";
} else if (entry==null && !pagedoc.isNew()) {
pageStatus.status = "A";
} else if (pageStatus.xwikihash=="") {
def gitlabsha = (entry==null) ? "" : entry.gitlabsha;
if (gitlabsha=="")
pageStatus.status = "A";
else
pageStatus.status = "?";
} else if (pagedoc.getVersion().equals(pageStatus.xwikiversion)) {
version has not changed in the wikia
def whash = "${wikicontent.hashCode()}";
if the recorded hash is the same then we have a modified version in GitLab
otherwise it's a bad state so it's a conflict
if (whash == pageStatus.xwikihash)
pageStatus.status = "U";
else
pageStatus.status = "C";
} else {
def gitlabsha = (entry==null) ? "" : entry.gitlabsha;
if (gitlabsha=="")
pageStatus.status = "A";
else if(pageStatus.gitlabsha==gitlabsha)
pageStatus.status = "M";
else
pageStatus.status = "C";
}
we do not check the parent anymore because we force it's value as we cannot edit it
verify Invalid parents
if (pagedoc.getParent()=="")
pageStatus.status += " - Empty Parent"
verify default language
if (pagedoc.getLanguage()=="") {
if (pagedoc.getDefaultLanguage()!="" && pagedoc.getTranslationList().size()==0)
pageStatus.status += " - Default language should be empty"
}
changedMap.put(page, pageStatus)
} else {
samePages.add(filePath);
def pageStatus = getPageStatus(getStatusPath(pagedoc));
if (pageStatus==null) {
pageStatus = [ "xwikiversion" : "", "xwikihash" : "", "gitlabversion" : "", "gitlabsha" : "" ];
status.put(getStatusPath(pagedoc), pageStatus);
}
pageStatus.xwikiversion = pagedoc.getVersion();
pageStatus.xwikihash = wikicontent.hashCode();
if (entry!=null) {
pageStatus.gitlabversion = entry.gitlabversion;
pageStatus.gitlabsha = entry.gitlabsha;
}
}
}
public containsSpace(spaceName, spaceList) {
for (item in spaceList) {
if (spaceName.startsWith(item))
return true;
}
return false;
}
public getChangedPages(String spaces, String savedlist) {
def changedMap = new TreeMap();
def gitlabEntries = getEntries(spaces);
def spaceList = null;
def samePages = new ArrayList();
def list;
if (!savedlist || savedlist=="") {
spaceList = Arrays.asList(StringUtils.split(spaces," ,"));
def joinList = [];
for (space in spaceList) {
joinList.add("doc.fullName like '${space}%'")
}
def whereSpace = StringUtils.join(joinList, " or ");
def sql = "select distinct doc.fullName from XWikiDocument as doc where ${whereSpace}";
logger.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, gitlabEntries);
if (pagedoc.isNew()) {
logger.debug("GitLabApp: error reading page ${pagedoc.fullName} which should exist");
}
def transList = null
try {
transList = pagedoc.getTranslationList();
} catch (Exception e) {
System.out.println("Exception getting trans list of ${pagedoc.fullName} store ${pagedoc.store}: " + e.getMessage());
e.printStackTrace();
transList = [];
}
for (trans in transList) {
def tpagedoc = pagedoc.getTranslatedDocument(trans);
checkPage(page + "." + tpagedoc.language, tpagedoc, changedMap, samePages, gitlabEntries);
}
}
if (spaceList!=null) {
for (filePath in gitlabEntries.keySet()) {
def entry = gitlabEntries.get(filePath);
def i0 = getSourcePath().size()
def i1 = filePath.lastIndexOf("/");
def i2 = filePath.indexOf(".xml");
def spaceName = (i1==-1) ? filePath : filePath.substring(i0, i1);
spaceName = spaceName.replaceAll("/", ".")
def page = (i2==-1) ? filePath : filePath.substring(i1+1, i2);
def language = "";
def pageName = page;
if (page.contains(".")) {
def i3 = page.indexOf(".");
language = page.substring(i3+1);
pageName = page.substring(0, i3);
}
logger.debug("SpaceName: ${spaceName} SpaceList: ${spaceList} SamePages: ${samePages} FilePath: ${filePath} Page: ${spaceName}.${page}")
if (containsSpace(spaceName, spaceList)&&!samePages.contains(filePath)&&!changedMap.keySet().contains(spaceName + "." + page)) {
changedMap.put(spaceName + "." + pageName, [ "fullname" : "${spaceName}.${pageName}", "language" : language, "status" : "N", "xwikiversion" : "", "gitlabsha" : entry.gitlabsha ])
logger.debug("Adding page ${spaceName}.${page}")
} else {
if (!containsSpace(spaceName, spaceList))
logger.debug("${spaceName} not in ${spaceList}")
if (samePages.contains(filePath))
logger.debug("${filePath} already in list")
if (changedMap.keySet().contains(spaceName + "." + page))
logger.debug("${spaceName}.${page} already in list")
}
}
}
saveStatus if changed
saveStatus();
return changedMap;
}
public updatePages(pageList, spaces) {
def changedMap = new TreeMap();
def gitlabEntries = getEntries(spaces);
for (pageobj in pageList) {
def page = pageobj.page;
def sha = pageobj.sha;
logger.debug("Ready to update: ${page} ${sha}");
separate the language particle at the end of the page name from the page fullname. The pagename is of form <docfullname>.<doclanguage>
def languageSeparator = page.lastIndexOf('.');
if (languageSeparator < 0) {
def pagefullname = page;
}
def pagefullname = page.substring(0, languageSeparator);
def lang = page.substring(languageSeparator + 1);
def pagedoc = xwiki.getDocument(pagefullname);
if (lang!=null && lang!="") {
pagedoc = pagedoc.getTranslatedDocument(lang);
}
def wikicontent = getXML(pagedoc, true);
def result = findPage(gitlabEntries, pagedoc);
def entry = result.entry;
def filePath = result.filePath;
def gitlabversion = (entry==null) ? "" : entry.gitlabversion;
def gitlabcontent = (entry==null) ? "" : entry.gitlabcontent;
logger.debug("Ready to update: ${filePath}");
if (!wikicontent.equals(gitlabcontent) && gitlabcontent!=null && gitlabcontent!="") {
def pageStatus = getPageStatus(getStatusPath(pagedoc));
if (pageStatus==null) {
pageStatus = [ "xwikiversion" : pagedoc.getVersion(), "xwikihash" : "", "gitlabversion" : "" ];
}
pageStatus.filePath = filePath;
pageStatus.page = pagefullname;
pageStatus.status = "";
updating XWiki document from GitLab
changedMap.put(pagefullname, pageStatus);
def archive = pagedoc.document.getDocumentArchive(context.getContext());
def version = pagedoc.document.getRCSVersion();
def newdoc = new XWikiDocument();
newdoc.fromXML(gitlabcontent);
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);
}
Go through each object change between the previous and the new document in order to identify
objects that have been removed. We will need to explicitely mark them to be removed when
saving newdoc
newdoc.getObjectDiff(pagedoc.getDocument(), newdoc, context.getContext()).each{ diff ->
diff.each{ diffElement ->
if (diffElement.getAction().equals("object-removed")) {
def removedObject = pagedoc.getObject(diffElement.getClassName(), diffElement.getNumber());
if (removedObject != null) {
newdoc.addXObjectToRemove(removedObject.getXWikiObject());
}
}
}
}
saving document
xwiki.getXWiki().saveDocument(newdoc, "Updated from GitLab", 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, true);
pageStatus.xwikiversion = pagedoc.getVersion();
pageStatus.xwikihash = "${newwikicontent.hashCode()}";
pageStatus.gitlabversion = gitlabversion;
}
}
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 = "";
str += "${prefix}page${sep}language${sep}version${sep}isnew${sep}hash${sep}gitlabpath${sep}gitlabversion${sep}gitlabhash${sep}isdiff\n"
while (spaceIterator.hasNext()) {
def space = entry.getName().toString();
Collection pageEntries = repository.getDir(space, -1, null, (Collection) null);
Iterator pageIterator = null;
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, true);
def baos = new ByteArrayOutputStream();
logger.debug("reading file: ${space}/${fileName}")
repository.getFile(space + "/" + fileName, -1, fileProperties, baos);
def gitlabcontent = new String(baos.toByteArray())
def version = (pagedoc==null) ? "" : pagedoc.getVersion();
def hash = (pagexml==null) ? "" : pagexml.hashCode();
def gitlabversion = pageEntry.getRevision().toString();
def gitlabhash = (gitlabcontent==null) ? "" : gitlabcontent.hashCode();
def isdiff = !pagexml.equals(gitlabcontent)
if (!updatedonly || !isdiff)
str += "${prefix}${pageName}${sep}${pagedoc.getLanguage()}${sep}${version}${sep}${pagedoc.isNew()}${sep}${hash}${sep}${space}/${fileName}${sep}${gitlabversion}${sep}${gitlabhash}${sep}${isdiff}\n"
}
}
return str;
}
public getBasePath() {
def basepath = reppath;
if (basepath.startsWith("/"))
basepath = srcpath.substring(1);
if (basepath=="")
return "";
else if (basepath.endsWith("/"))
return basepath;
else
return basepath + "/";
}
public getSourcePath() {
def srcpath = getBasePath();
if (repsrcpath==""||repsrcpath=="/"||repsrcpath==".")
return srcpath;
else if (repsrcpath.startsWith("/"))
srcpath = srcpath + repsrcpath.substring(0);
else
srcpath = srcpath + repsrcpath;
if (srcpath=="")
return "";
else if (srcpath.endsWith("/"))
return srcpath
else
return srcpath + "/";
}
public matchSpace(path, spaces) {
if (spaces==null)
return true;
for (space in spaces.split(",")) {
if (path.startsWith(space.replaceAll("[.]", "/"))) {
return true;
}
}
return false;
}
public getEntries(String spaces) {
def entries = new HashMap();
def tree = gitlabapi.getRepositoryTree(gitlabproject, "", repbranch, true);
def srcPath = getSourcePath();
for (file in tree) {
if (file.type=="blob") {
if (file.path.startsWith(srcPath)) {
def file2 = gitlabapi.getRepositoryFile(gitlabproject, file.path, repbranch)
def gitlabcontent = new String(Base64.decodeBase64(file2.content.getBytes()), "UTF-8");
calculate the hash before formatting
def gitlabhash_unformatted = (gitlabcontent==null) ? "" : gitlabcontent.hashCode();
gitlabcontent = cleanXML(gitlabcontent, true);
def gitlabhash = (gitlabcontent==null) ? "" : gitlabcontent.hashCode();
def gitlabversion = 0;
entries.put(file.path, [ "gitlabversion" : gitlabversion, "gitlabsha" : file.id, "gitlabhash" : "${gitlabhash}", "gitlabhash_unformatted" : "${gitlabhash_unformatted}", "gitlabcontent" : gitlabcontent ]);
logger.debug("Adding: ${file.path}");
}
}
}
logger.debug("Entries: ${entries}")
return entries;
}
public getXMLForDiff(pagedoc, filePath, withFormat) {
def file2 = gitlabapi.getRepositoryFile(gitlabproject, filePath, repbranch)
def gitlabxml = new String(Base64.decodeBase64(file2.content.getBytes()), "UTF-8");
if (withFormat)
gitlabxml = cleanXML(gitlabxml, true);
logger.debug("Gitlab hash " + gitlabxml.hashCode())
def xml = getXML(pagedoc, true);
logger.debug("XWiki hash " + xml.hashCode())
if (pagedoc.isNew() && gitlabxml == null)
return "Document does not exist";
if (pagedoc.isNew())
return "Document does not exist in the wiki"
if (gitlabxml==null)
return "Document does not exist in GitLab"
remove attachment content from xml
gitlabxml = gitlabxml.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 [gitlabxml, xml];
}
public showXMLDiff(pagedoc, filePath, withFormat) {
def file2 = gitlabapi.getRepositoryFile(gitlabproject, filePath, repbranch)
def gitlabxml = new String(Base64.decodeBase64(file2.content.getBytes()), "UTF-8");
if (withFormat)
gitlabxml = cleanXML(gitlabxml, true);
logger.debug("Gitlab hash " + gitlabxml.hashCode())
def xml = getXML(pagedoc, true);
logger.debug("XWiki hash " + xml.hashCode())
if (pagedoc.isNew() && gitlabxml == null)
return "Document does not exist";
if (pagedoc.isNew())
return "Document does not exist in the wiki"
if (gitlabxml==null)
return "Document does not exist in GitLab"
remove attachment content from xml
gitlabxml = gitlabxml.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(gitlabxml, xml, false);
}
Adding class and method to perform indentation and cleanup
public class XWikiXMLWriter extends XMLWriter
{
/
- True if we use an output format.
*/
private boolean useFormat;
/
- @param output the stream where to write the XML
- @throws UnsupportedEncodingException in case encoding issue
*/
public XWikiXMLWriter(OutputStream output) throws UnsupportedEncodingException
{
super(output);
}
/
- @param output the stream where to write the XML
- @param format the style to use when outputting the XML
- @throws UnsupportedEncodingException in case encoding issue
*/
public XWikiXMLWriter(OutputStream output, OutputFormat format) throws UnsupportedEncodingException
{
super(output, format);
this.useFormat = true;
}
@Override
protected void writeComment(String text) throws IOException
{
super.writeComment(text);
Add a new line after the license declaration
if (text.contains("See the NOTICE file distributed with this work for additional")) {
println();
}
}
@Override
protected void writeNodeText(Node node) throws IOException
{
if (this.useFormat && node.getText().trim().length() == 0) {
Check if parent node contains non text nodes
boolean containsNonTextNode = false;
for (Object object : node.getParent().content()) {
Node objectNode = (Node) object;
if (objectNode.getNodeType() != Node.TEXT_NODE) {
containsNonTextNode = true;
break;
}
}
if (containsNonTextNode) {
Don't do anything, i.e. don't print the current text node
} else {
super.writeNodeText(node);
}
} else {
super.writeNodeText(node);
}
}
@Override
protected void writePrintln() throws IOException
{
We need to reimplement this method because of a bug (bad logic) in the original writePrintln() which checks
the last output char to decide whether to print a NL or not:
...3</a></b> > ...3</a>\n</b>
but> ...3\n</a></b>
...3\n</a></b>
and
...3\n</a>\n</b> > ...3\n</a></b>
if (this.useFormat) {
println();
writer.write(getOutputFormat().getLineSeparator());
}
}
}
formats the XWiki XML including indentation
def String format(String data, String defaultLanguage, boolean isTranslationDocument) throws Exception
{
def sr = new StringReader(data);
SAXReader reader = new SAXReader();
Document domdoc = reader.read(sr);
Node rnode = domdoc.getRootElement();
if (rnode !=null) {
Node node = rnode.element("author");
if (node != null) {
node.setText(DEFAULTAUTHOR);
}
node = rnode.element("contentAuthor");
if (node != null) {
node.setText(DEFAULTAUTHOR);
}
node = rnode.element("creator");
if (node != null) {
node.setText(DEFAULTAUTHOR);
}
node = rnode.element("originalMetadataAuthor");
if (node != null) {
node.setText(DEFAULTAUTHOR);
}
}
if (this.removeDates) {
this.logger.debug("Removing dates from generated XML ...");
removeNodes("xwikidoc/creationDate", domdoc);
removeNodes("xwikidoc/date", domdoc);
removeNodes("xwikidoc/contentUpdateDate", domdoc);
removeNodes("xwikidocattachment/date", domdoc);
}
if (this.parentDefinitionStrategy.equals("remove")) {
removeNodes("xwikidoc/parent", domdoc);
}
if (this.defaultLanguageDefinitionStrategy.equals("alwaysBlank")
|| (!isTranslationDocument && this.defaultLanguageDefinitionStrategy.equals("blankIfNotTranslation"))) {
Node node = rnode.selectSingleNode("defaultLanguage/text()");
if (node != null) {
node.detach();
}
}
def baos = new ByteArrayOutputStream()
XMLWriter w;
OutputFormat format = new OutputFormat(" ", true, "UTF-8");
format.setExpandEmptyElements(false);
w = new XWikiXMLWriter(baos, format);
w.write(domdoc);
w.close();
def result = baos.toString();
Adding license header
def xmlHeader = """<?xml version="${this.xmlVersion}" encoding="UTF-8"?>"""
if (this.license != null && !this.license.isBlank() && xwiki.exists(this.license)) {
String licenseContent = xwiki.getDocument(this.license).getContent();
result = result.replaceAll("(<.xml .*>)", xmlHeader + "\n\n" + licenseContent);
} else {
result = result.replaceAll("(<.xml .*>)", xmlHeader);
}
return result.replaceAll("\r","");
}
/
- Remove the nodes found with the xpath expression.
- Copied from FormatMojo in xwiki-commons-tool-xar-plugin
* - @param xpathExpression the xpath expression of the nodes
- @param domdoc The DOM document
*/
private void removeNodes(String xpathExpression, Document domdoc)
{
List<Node> nodes = domdoc.selectNodes(xpathExpression);
for (Node node : nodes) {
node.detach();
}
}
}