Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ filter.xml
# Mac
.DS_Store

work/
work/
migrate_chipCopy.groovy
Binary file added libs/commons-lang3-3.12.0.jar
Binary file not shown.
190 changes: 102 additions & 88 deletions migrate.groovy
Original file line number Diff line number Diff line change
@@ -1,19 +1,4 @@
#!/usr/bin/env groovy
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
* Migration script for migrating legacy content using an AEM Content Package
* See: https://github.com/PerficientDigital/AEM-Migration-Script
Expand Down Expand Up @@ -137,7 +122,7 @@ void processPages(File source, File jcrRoot) {
def template = templates[pageData['Template']]
assert template : "Template ${pageData['Template']} not found!"

def sourceFile = new File(pageData['Source Path'],source)
def sourceFile = new File(source, pageData['Source Path'])
assert sourceFile.exists() : "Source file ${sourceFile} not found!"

println "Using template ${pageData['Template']} for ${sourceFile}"
Expand All @@ -151,11 +136,12 @@ void processPages(File source, File jcrRoot) {
template.renderPage(pageData, inXml, outXml, replacements)

println 'Creating parent folder...'
def targetFile = new File("${pageData['New Path']}${File.separator}.content.xml",jcrRoot)
targetFile.getParentFile().mkdirs()
def targetFile = new File(jcrRoot.toString(), "${pageData['New Path'].toString()}${File.separator}.content.xml".toString())
targetFile.parentFile.mkdirs()

println "Writing results to $targetFile"
targetFile.write(writer.toString(),ENCODING)

migrated++
} else {
println 'No action required...'
Expand All @@ -166,124 +152,152 @@ void processPages(File source, File jcrRoot) {
println "${count} pages processed and ${migrated} migrated in ${TimeCategory.minus(new Date(), start)}"
}

void processFiles(File source, File jcrRoot){

def contentXml = '''<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/" xmlns:tiff="http://ns.adobe.com/tiff/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dam="http://www.day.com/dam/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="dam:Asset">
<jcr:content
jcr:primaryType="dam:AssetContent">
<metadata
jcr:primaryType="nt:unstructured"/>
<related jcr:primaryType="nt:unstructured"/>
</jcr:content>
</jcr:root>
'''
def tika = new Tika()
def files = new File("work${File.separator}config${File.separator}file-mappings.csv")
def count = 0
def migrated = 0
println 'Processing files...'
for (fileData in parseCsv(files.getText(ENCODING), separator: SEPARATOR)) {
def assetRoot = new File(fileData['Target'], jcrRoot)
def sourceFile = new File(fileData['Source'], source)
def mimeType = tika.detect(sourceFile)

def processFiles(sourceDir, targetDir) {
def sourcePath = sourceDir.toPath()
def targetPath = targetDir.toPath()

Files.walk(sourcePath).forEach { sourceFile ->
def targetFile = targetPath.resolve(sourcePath.relativize(sourceFile))

if (Files.isDirectory(sourceFile)) {
Files.createDirectories(targetFile)
} else {
Files.createDirectories(targetFile.getParent())
Files.copy(sourceFile, targetFile, StandardCopyOption.REPLACE_EXISTING)
}

println "Copying ${sourceFile} to ${targetFile}"
}
}

void processFile(File sourceFile, File assetRoot, Tika tika) {
if (sourceFile.isDirectory()) {
def targetDir = new File(assetRoot, sourceFile.name)
targetDir.mkdirs()

for (file in sourceFile.listFiles()) {
def targetFile = new File(targetDir, file.name)
processFile(file, targetFile, tika)
}
} else {
// Process the file
def mimeType = "application/octet-stream" // Default MIME type for directories

println "Processing Source: ${sourceFile} Target: ${assetRoot}"


if (sourceFile.isFile()) {
try {
mimeType = tika.detect(sourceFile)
} catch (FileNotFoundException e) {
// Handle file not found exception
println "File not found: ${sourceFile}"
return
}
}

println 'Creating original.dir XML...'
def writer = new StringWriter()
def originalDirXml = new MarkupBuilder(writer)
originalDirXml.'jcr:root'('xmlns:jcr':'http://www.jcp.org/jcr/1.0','xmlns:nt':'http://www.jcp.org/jcr/nt/1.0','jcr:primaryType':'nt:file'){
'jcr:content'('jcr:mimeType': mimeType, 'jcr:primaryType': 'nt:resource')
}
def originalDir = new File("_jcr_content${File.separator}renditions${File.separator}original.dir${File.separator}.content.xml",assetRoot)
originalDir.getParentFile().mkdirs()
originalDir.newWriter().withWriter { w ->
w << writer.toString()
}

def originalDirPath = assetRoot.getAbsolutePath() + File.separator + "_jcr_content" + File.separator + "renditions" + File.separator + "original.dir"
def originalDir = new File(originalDirPath)
originalDir.mkdirs()
def contentXmlFile = new File(originalDir, ".content.xml")
println "Writing results to $contentXmlFile"
contentXmlFile.write(writer.toString(), ENCODING)

println 'Copying original file...'
Files.copy(sourceFile.toPath(), new File("_jcr_content${File.separator}renditions${File.separator}original",assetRoot).toPath(),StandardCopyOption.REPLACE_EXISTING,StandardCopyOption.COPY_ATTRIBUTES)

println 'Writing .content.xml...'
new File('.content.xml',assetRoot).newWriter().withWriter { w ->
w << contentXml
}
def targetFile = new File(assetRoot, sourceFile.name)
Files.copy(sourceFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
}

def configDir = new File(args[0])
assert configDir.exists()
def newConfigDir = new File(args[0])
assert newConfigDir.exists()
println 'Copying configuration to work dir...'
def workConfig = new File("work${File.separator}config")
if(!workConfig.exists()){
workConfig.mkdirs()
def workConfigDir = new File("work${File.separator}config")
if (!workConfigDir.exists()) {
workConfigDir.mkdirs()
}
configDir.eachFile (FileType.FILES) { file ->
Files.copy(file.toPath(), new File(workConfig.getAbsolutePath()+File.separator+file.getName()).toPath(),StandardCopyOption.REPLACE_EXISTING,StandardCopyOption.COPY_ATTRIBUTES)
newConfigDir.eachFile { file ->
def destFile = new File(workConfigDir.getAbsolutePath() + File.separator + file.name)
def inputFile = new File(file.absolutePath)
def outputFile = new File(destFile.absolutePath)

outputFile.parentFile.mkdirs()

inputFile.withInputStream { inputStream ->
outputFile.withOutputStream { outputStream ->
outputStream << inputStream
}
}
}


def base = new File('work')
def source = new File('source',base)
def source = new File(base,'source')
println "Using source: ${source}"
def target = new File('target',base)
def jcrRoot = new File('jcr_root',target)
def target = new File(base,'target')
def jcrRoot = new File(target, 'jcr_root')
println "Using target: ${target}"

println 'Clearing target...'
target.deleteDir();
target.mkdir();

processPages(source,jcrRoot)
processFiles(source,jcrRoot)
processFiles(new File("work${File.separator}source"), new File("work${File.separator}target${File.separator}jcr_root${File.separator}content${File.separator}dam"))

println 'Updating filter.xml...'
def vlt = new File("META-INF${File.separator}vault",target)
def vlt = new File("work/target/META-INF/vault")
vlt.mkdirs()
if(batch?.trim()){
if (batch?.trim()) {
def writer = new StringWriter()
def filterXml = new MarkupBuilder(writer)
def pageFile = new File("work${File.separator}config${File.separator}page-mappings.csv")
filterXml.'workspaceFilter'('version':'1.0'){

def pageFile = new File("work/config/page-mappings.csv")

filterXml.workspaceFilter(version: '1.0') {
for (pageData in parseCsv(pageFile.getText(ENCODING), separator: SEPARATOR)) {
if(batch.equals(pageData['Batch']) && 'Remove' != pageData[0] && 'Missing' != pageData[0]){
'filter'('root':pageData['New Path']){
'include'('pattern':pageData['New Path'])
'include'('pattern':"${pageData['New Path']}/jcr:content.*")
if ('Remove' != pageData[0] && 'Missing' != pageData[0]) {
filterXml.filter(root: pageData['New Path']) {
include(pattern: pageData['New Path'])
include(pattern: "${pageData['New Path']}/jcr:content.*")
}
}
}
for (fileData in parseCsv(new File("work${File.separator}config${File.separator}file-mappings.csv").getText(ENCODING), separator: SEPARATOR)) {
if(batch.equals(fileData['Batch']) && 'Remove' != fileData[0] && 'Missing' != fileData[0]){
'filter'('root':fileData['Target']){
'include'('pattern':fileData['Target'])
'include'('pattern':"${fileData['Target']}/jcr:content.*")
for (fileData in parseCsv(new File("work/config/file-mappings.csv").getText(ENCODING), separator: SEPARATOR)) {
if ('Remove' != fileData[0] && 'Missing' != fileData[0]) {
filterXml.filter(root: fileData['Target']) {
include(pattern: fileData['Target'])
include(pattern: "${fileData['Target']}/jcr:content.*")
}
}
}
}
new File('filter.xml',vlt) << writer.toString()
new File(vlt, 'filter.xml').withWriter { fileWriter ->
fileWriter << writer.toString()
}
} else {
def filter = new File('filter.xml',workConfig)
def filter = new File('work/config/filter.xml')
assert filter.exists()
Files.copy(filter.toPath(), new File('filter.xml',vlt).toPath(),StandardCopyOption.REPLACE_EXISTING,StandardCopyOption.COPY_ATTRIBUTES)
Files.copy(filter.toPath(), new File(vlt, 'filter.xml').toPath(), StandardCopyOption.REPLACE_EXISTING)
}

def now = new Date().format("yyyy-MM-dd-HH-mm-ss")
println 'Updating properties.xml...'
def propertiesXml = new File('properties.xml',workConfig)
def propertiesXml = new File(workConfigDir, 'properties.xml')
assert propertiesXml.exists()
new File('properties.xml',vlt) << propertiesXml.getText().replace('${version}',now).replace('${name}',"migrated-content-${configDir.getName()}")
new File(vlt, 'properties.xml') << propertiesXml.getText().replace('${version}',now).replace('${name}',"migrated-content-${workConfigDir.getName()}")

println 'Creating package...'
def ant = new AntBuilder()
ant.zip(destfile: "${base.getAbsolutePath()}${File.separator}migrated-content-${configDir.getName()}-${now}.zip", basedir: target)
ant.zip(destfile: "${base.getAbsolutePath()}${File.separator}migrated-content-${workConfigDir.getName()}-${now}.zip", basedir: target)

println "Package saved to: work${File.separator}migrated-content-${configDir.getName()}-${now}.zip"
println "Package saved to: work${File.separator}migrated-content-${workConfigDir.getName()}-${now}.zip"

println "Content migrated in ${TimeCategory.minus(new Date(), start)}"

println "Package created successfully!!!"
println "Package created successfully!!!"
67 changes: 67 additions & 0 deletions templates/.commons.groovy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import groovy.xml.slurpersupport.GPathResult
import groovy.xml.MarkupBuilder


Map component(String resourceType) {
return component(resourceType, [:])
}

Map component(String resourceType, Map properties) {
def p = unstructured()
p['sling:resourceType']=resourceType
properties.each{ k, v -> p[k] = v }
return p
}

Map pageProperties(Object pageData, GPathResult inXml, String template){
pageProperties(pageData, inXml, template, null)
}

Map pageProperties(Object pageData, GPathResult inXml, String template, String resourceType, Map replacements){
def pageProperties = [:]
pageProperties['jcr:primaryType']='cq:PageContent'
def pageTitle = inXml.metadata.title.toString()
if (pageTitle.isEmpty())
pageTitle = inXml.title.toString()
pageProperties['jcr:title'] = pageTitle

pageProperties['cq:contextHubPath'] = '/etc/cloudsettings/default/contexthub'
pageProperties['cq:contextHubSegmentsPath'] = '/etc/segmentation/contexthub'
pageProperties['cq:template'] = template
pageProperties['sling:resourceType'] = resourceType
pageProperties['legacyPath'] = pageData['Source Path']
pageProperties['migrationBatch'] = pageData['Batch']

def description = inXml.metadata.description.toString()
if (description.isEmpty())
description = inXml.description.toString()
if(description?.trim()) {
pageProperties['jcr:description'] = description
}
return pageProperties
}

String replace(String source, Map replacements){
replacements.each{ k, v ->
if(source.contains(k)){
source = source.replace(k,v)
}
}
return source
}

Map rootProperties() {
def p = [:]
p['xmlns:cq']='http://www.day.com/jcr/cq/1.0'
p['xmlns:jcr']='http://www.jcp.org/jcr/1.0'
p['xmlns:nt']='http://www.jcp.org/jcr/nt/1.0'
p['xmlns:sling']='http://sling.apache.org/jcr/sling/1.0'
p['jcr:primaryType']='cq:Page'
return p
}

Map unstructured() {
def p = [:]
p['jcr:primaryType']='nt:unstructured'
return p
}
2 changes: 1 addition & 1 deletion templates/content.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ void renderPage(Object pageData, GPathResult inXml, MarkupBuilder outXml, Map re

GroovyShell shell = new GroovyShell()
def commons = shell.parse(new File('templates/.commons.groovy').text)
def pageProperties = commons.pageProperties(pageData, inXml, '/conf/sample/settings/wcm/templates/content-page','sample/components/structure/page', replacements)
def pageProperties = commons.pageProperties(pageData, inXml, '/conf/core-components-examples/settings/wcm/templates/content-page','sample/components/structure/page', replacements)

outXml.'jcr:root'(commons.rootProperties()) {
'jcr:content'(pageProperties) {
Expand Down
20 changes: 20 additions & 0 deletions templates/content.groovy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import groovy.xml.slurpersupport.GPathResult
import groovy.xml.MarkupBuilder

void renderPage(Object pageData, GPathResult inXml, MarkupBuilder outXml, Map replacements){

GroovyShell shell = new GroovyShell()
def commons = shell.parse(new File('templates/.commons.groovy').text)
def pageProperties = commons.pageProperties(pageData, inXml, '/conf/sample/settings/wcm/templates/content-page','sample/components/structure/page', replacements)

outXml.'jcr:root'(commons.rootProperties()) {
'jcr:content'(pageProperties) {
'root'(commons.component('wcm/foundation/components/responsivegrid')){
'responsivegrid'(commons.component('wcm/foundation/components/responsivegrid')){
'title'(commons.component('sample/components/content/title', ['fontSize': 'h1', 'header': inXml.metadata.title.toString()]))
'text'(commons.component('sample/components/content/text', ['textIsRich': true, 'text': inXml.content.toString()]))
}
}
}
}
}
20 changes: 20 additions & 0 deletions templates/post.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import groovy.xml.slurpersupport.GPathResult
import groovy.xml.MarkupBuilder

void renderPage(Object pageData, GPathResult inXml, MarkupBuilder outXml, Map replacements){

GroovyShell shell = new GroovyShell()
def commons = shell.parse(new File('templates/.commons.groovy').text)
def pageProperties = commons.pageProperties(pageData, inXml, '/conf/sample/settings/wcm/templates/content-page','/apps/core/wcm/components/structure/page', replacements)

outXml.'jcr:root'(commons.rootProperties()) {
'jcr:content'(pageProperties) {
'root'(commons.component('wcm/foundation/components/responsivegrid')){
'responsivegrid'(commons.component('wcm/foundation/components/responsivegrid')){
'title'(commons.component('/apps/core/wcm/components/content/title', ['fontSize': 'h1', 'header': inXml.metadata.title.toString()]))
'text'(commons.component('/apps/core/wcm/components/content/text', ['textIsRich': true, 'text': inXml.content.toString()]))
}
}
}
}
}
Loading