Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a custom plugin for packaging automation using rollup #373

Open
david-poindexter opened this issue May 5, 2024 · 0 comments
Open
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@david-poindexter
Copy link
Member

Is your feature request related to a problem?

Since gulp will no longer be used, we'll need to automate packaging using rollup.

Describe the solution you'd like

We'll need to develop a custom rollup plugin for this feature. We will use the following from the DNN 10 theme Aperture as inspiration.

import { Plugin } from 'rollup';
import * as fs from 'fs';
import * as path from 'path';
import { glob } from 'glob';
import { Zip } from 'zip-lib';

interface RollupPluginDnnPackageOptions
{
    name: string;
    version: string;
    destinationDirectory: string;
};

type RollupPluginDnnPackage = (dnnPackageOptions: RollupPluginDnnPackageOptions) => Plugin;

function ensureEmptyDirectory(dirPath: string): void {
    // Ensure that the directory exists
    if (!fs.existsSync(dirPath)) {
        // Directory does not exist, create it
        fs.mkdirSync(dirPath, { recursive: true });
    }

    // Directory exists, empty it
    const files = fs.readdirSync(dirPath);

    for (const file of files) {
        const currentPath = path.join(dirPath, file);
        if (fs.lstatSync(currentPath).isDirectory()) {
            // Recursive call for directories
            ensureEmptyDirectory(currentPath);
            // After emptying the subdirectory, remove it
            fs.rmdirSync(currentPath);
        } else {
            // Delete file
            fs.unlinkSync(currentPath);
        }
    }
}

function copyFileToPath(src: string, dest: string): void {
    // Ensure that the destination directory exists
    const dir = path.dirname(dest);
    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }

    // Now that we know the directory exists, copy the file
    fs.copyFileSync(src, dest);
}

const dnnPackage: RollupPluginDnnPackage = (dnnPackageOptions) =>
{
    return {
        name: 'rollup-plugin-dnn-package',
        async writeBundle(options, _bundle)
        {
            const skinDist = options.dir as string;
            const containersDist = skinDist.replace('/Skins/', '/Containers/');
            const artifactsDir = "./artifacts";
            ensureEmptyDirectory(artifactsDir);
            const stagingDir = `${artifactsDir}/staging`;
            ensureEmptyDirectory(stagingDir);
            
            // Skin resources
            var skinResources = await glob(
                [
                    `${skinDist}/css/**/*`,
                    `${skinDist}/fonts/**/*`,
                    `${skinDist}/js/**/*`,
                    `${skinDist}/menus/**/*`,
                    `${skinDist}/patials/**/*`,
                    `${skinDist}/**/*.ascx`,
                    `${skinDist}/**/*.xml`,
                    `${skinDist}/**/*.png`,
                ],
                { nodir: true }
            );
            skinResources.forEach((skinResource) => {
                const relativePath = path.relative(skinDist, skinResource).replace(/\\/g, '/');
                const targetPath = path.resolve(`${stagingDir}/skinResources/${relativePath}`);
                copyFileToPath(skinResource, targetPath);
            });
            let zip = new Zip();
            zip.addFolder(`${stagingDir}/skinResources`);
            await zip.archive(`${stagingDir}/skin.zip`)
            fs.rmSync(`${stagingDir}/skinResources`, { recursive: true, force: true });

            // Container resources
            var containerResources = await glob(
                [
                    `${containersDist}/**/*`,
                ],
                { nodir: true }
            );
            containerResources.forEach((containerResource) => {
                const relativePath = path.relative(containersDist, containerResource).replace(/\\/g, '/');
                const targetPath = path.resolve(`${stagingDir}/containerResources/${relativePath}`);
                copyFileToPath(containerResource, targetPath);
            });
            zip = new Zip();
            zip.addFolder(`${stagingDir}/containerResources`);
            await zip.archive(`${stagingDir}/container.zip`);
            fs.rmSync(`${stagingDir}/containerResources`, { recursive: true, force: true });

            // Root files
            var rootResources = await glob(
                [
                    `${skinDist}/*.png`,
                    `${skinDist}/LICENSE`,
                    `${skinDist}/*.txt`,
                    `${skinDist}/*.dnn`,
                ],
                { nodir: true }
            );
            rootResources.forEach((rootResource) => {
                const relativePath = path.relative(skinDist, rootResource).replace(/\\/g, '/');
                const targetPath = path.resolve(`${stagingDir}/${relativePath}`);
                copyFileToPath(rootResource, targetPath);
            });

            // Package ZIP
            zip = new Zip();
            zip.addFolder(stagingDir);
            var packageName = `${dnnPackageOptions.name}_${dnnPackageOptions.version}_install.zip`;
            var packagePath = `${artifactsDir}/${packageName}`;
            await zip.archive(packagePath);
            fs.rmSync(stagingDir, { recursive: true, force: true });

            var skinInstallPath = `${path.resolve(dnnPackageOptions.destinationDirectory)}`;
            console.log(`Copying ${packageName} to ${skinInstallPath}`);
            fs.copyFileSync(
                packagePath,
                `${skinInstallPath}/${packageName}`);
            fs.rmSync(artifactsDir, { recursive: true, force: true });
        },
    };
}

export default dnnPackage;

Describe alternatives you've considered

n/a

Additional context

n/a

@david-poindexter david-poindexter added the enhancement New feature or request label May 5, 2024
@david-poindexter david-poindexter added this to the 4.0.0 milestone May 5, 2024
@david-poindexter david-poindexter self-assigned this May 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant