import java.time.LocalDateTime
import org.apache.commons.io.FileUtils
import java.time.format.DateTimeFormatter
import org.sonatype.nexus.scheduling.TaskConfiguration
import org.sonatype.nexus.scheduling.TaskScheduler
import org.sonatype.nexus.scheduling.TaskInfo
import org.sonatype.nexus.scheduling.schedule.Schedule
import java.util.concurrent.TimeUnit


/**
 * This groovy script is meant to be included in a schedulled task in nexus.
 * It will perform a full backup of your installation with the following steps.
 * 1- If <nexusBackupRotate> and <nexusBackupRotateFirst> are true, pre-rotate backup dirs keeping last <nexusBackupKeepRotations-1> backups (making room for current backup)
 * 2- Create a temporary nexus db-backup task to store db backup in <nexusBackupDirPath>/blob-backup-<YY-MM-dd>/db
 * 3- Start running the temporary task
 * 4- Copy all blobstores from <nexusDataDirPath>/blobs to <nexusBackupDirPath>/blob-backup-<YY-MM-dd>
 * 5- Eventually wait for the nexus temporary db-backup task to complete
 * 6- Delete the nexus temporary db-backup task
 * 7- If <nexusBackupRotate> is true and <nexusBackupRotateFirst> is false, post-rotate backup dirs keeping last <nexusBackupKeepRotations> backups
 */

nexusBackupDirPath = "{{ nexus_backup_dir }}"
nexusDataDirPath = "{{ nexus_data_dir }}"
nexusBackupRotate = Boolean.valueOf("{{ nexus_backup_rotate }}")
nexusBackupRotateFirst = Boolean.valueOf("{{ nexus_backup_rotate_first }}")
nexusBackupKeepRotations = "{{ nexus_backup_keep_rotations }}".toInteger()

backupDateString = LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd-HH-mm-ss'))
CurrentBackupDirPath = nexusBackupDirPath+'/blob-backup-'+backupDateString

/** Helper function to rotate backups */
def rotateBackup() {
    if (nexusBackupRotateFirst) {
        realKeep = nexusBackupKeepRotations - 1
        rotateMsg = "Pre-rotating"
    } else {
        realKeep = nexusBackupKeepRotations
        rotateMsg = "Post-rotating"
    }

    log.info("{} backups to keep only last {} backups", rotateMsg, nexusBackupKeepRotations.toString())
    backupDirs = []
    backupCounter = 0
    backupPattern = ~/blob-backup-.*/
    new File(nexusBackupDirPath).eachDirMatch(backupPattern) { dir ->
        backupDirs << dir
    }
    backupDirs.sort{ it.name }.reverse().each { dir ->
        backupCounter++
        if (backupCounter > realKeep) {
            log.info("Deleting backup {}", dir.name.toString())
            dir.deleteDir()
        }
    }
    if (backupCounter > realKeep) {
        backupDeleted =  backupCounter - realKeep
        log.info("Deleted a total of {} backup directories", backupDeleted)
    } else {
        log.info("There were no backup directories to delete")
    }
}

try {
    log.info("Backup directory is {}", CurrentBackupDirPath)

    /** pre backup rotation */
    if (nexusBackupRotate && nexusBackupRotateFirst) {
        rotateBackup()
    }

    log.info("Create a temporary task to backup nexus db in {}/db", CurrentBackupDirPath)
    TaskScheduler taskScheduler = container.lookup(TaskScheduler.class.getName())
    TaskConfiguration tempBackupTaskConfiguration = taskScheduler.createTaskConfigurationInstance('db.backup')
    tempBackupTaskConfiguration.setName('Temporary db.backup task')
    tempBackupTaskConfiguration.setString('location', CurrentBackupDirPath+'/db')
    Schedule schedule = taskScheduler.scheduleFactory.manual()
    TaskInfo tempBackupTask = taskScheduler.scheduleTask(tempBackupTaskConfiguration, schedule)

    log.info("Run the temporary db backup task")
    tempBackupTask.runNow()

    log.info("Copy the blobstores into {}", CurrentBackupDirPath)
    FileUtils.copyDirectory(new File(nexusDataDirPath+'/blobs'), new File(CurrentBackupDirPath))

    log.info("Wait for temporary db backup task to finish")
    while (tempBackupTask.currentState.getState().toString() != "WAITING") {
        TimeUnit.SECONDS.sleep(1)
    }
    log.info("Remove temporary task")
    tempBackupTask.remove()

    /** Post backup rotation */
    if (nexusBackupRotate && !nexusBackupRotateFirst) {
        rotateBackup()
    }

} catch (Exception e) {
    log.error(e.toString())
}
