Skip to content

Commit

Permalink
Implemented clone and merge of example contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
MitchPierias committed May 26, 2019
1 parent 9159138 commit 4d8867e
Showing 1 changed file with 110 additions and 63 deletions.
173 changes: 110 additions & 63 deletions src/project/projectManager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import * as colors from 'colors';
import * as path from 'path';
import * as mkdirpCallback from 'mkdirp';
import axios from 'axios';
import {
readFile as readFileCallback,
writeFile as writeFileCallback,
exists as existsCallback,
readdir as readdirCallback,
readdir as readdirCallback
} from 'fs';
import { ncp as ncpCallback } from 'ncp';
import * as rimrafCallback from 'rimraf';
import { promisify } from 'util';
import { ConfigManager, LamingtonConfig } from './../configManager';
import * as spinner from './../cli/logIndicator';
Expand All @@ -18,17 +21,31 @@ const mkdirp = promisify(mkdirpCallback);
const writeFile = promisify(writeFileCallback);
const readFile = promisify(readFileCallback);
const readdir = promisify(readdirCallback);
const rimraf = promisify(rimrafCallback);
const ncp = promisify(ncpCallback);

/** Default encoding */
const ENCODING = 'utf8';

/** Recommended Lamington package scripts */
const DEFAULT_SCRIPTS = {
build: 'lamington build',
test: 'lamington test',
}

/** Required project dependencies */
const DEFAULT_DEV_DEPENDENCIES = {
lamington: 'latest',
};

/**
* Fetches and stores the latest EOS configuration images
* @author Mitch Pierias <github.com/MitchPierias>
*/
export class ProjectManager {

/** @hidden Reference to the local `package.json` file */
private static pkg: {
private static cache: {
scripts?: { [key: string]: string };
devDependencies?: { [key: string]: string };
};
Expand All @@ -38,34 +55,20 @@ export class ProjectManager {
* @author Mitch Pierias <github.com/MitchPierias>
*/
public static async initWithDefaults() {
let packageJson = '';
try {
packageJson = await readFile(path.join(process.cwd(), 'package.json'), ENCODING);
} catch (error) {
console.error();
console.error(
colors.red(
'Could not read project package.json file in this folder. Is this a node project folder?'
)
);
console.error();

process.exit(1);
}

ProjectManager.pkg = JSON.parse(packageJson);
await ProjectManager.cloneExampleProject();

await ProjectManager.loadExistingProject();

await ProjectManager.injectScripts();

await ProjectManager.configureDependencies();

await ProjectManager.createProjectStructure();

await ProjectManager.pullExampleProject();
await ProjectManager.createDirectoryIfMissing('.lamington');

await writeFile(
path.join(process.cwd(), 'package.json'),
JSON.stringify(ProjectManager.pkg, null, 4),
JSON.stringify(ProjectManager.cache, null, 4),
ENCODING
);

Expand All @@ -75,74 +78,118 @@ export class ProjectManager {
}

/**
* Configures the projects `package.json` scripts for a standard Lamington environment
* @note Should merge the scripts provided in the example project with existing
* Examines the current directory and loads any existing `package.json` file
* into this object cache state.
* @author Mitch Pierias <github.com/MitchPierias>
* @hidden
*/
private static async injectScripts() {
spinner.create('Adding scripts');
const { scripts } = ProjectManager.pkg;
const defaultScripts = {
build: 'lamington build',
test: 'lamington test',
};
ProjectManager.pkg.scripts = { ...defaultScripts, ...scripts };
spinner.end('Added scripts');
}
private static async loadExistingProject() {
let packageJson = '';
try {
packageJson = await readFile(path.join(process.cwd(), 'package.json'), ENCODING);
} catch (error) {
console.error();
console.error(
colors.red(
'Could not read project package.json file in this folder. Is this a node project folder?'
)
);
console.error();

private static async configureDependencies() {
spinner.create('Adding dependencies');
const { devDependencies } = ProjectManager.pkg;
const defaultDependencies = {
lamington: 'latest',
};
ProjectManager.pkg.devDependencies = { ...defaultDependencies, ...devDependencies };
spinner.end('Added recommended dependencies');
process.exit(1);
}

ProjectManager.cache = JSON.parse(packageJson);
}

/**
* Downloads the latest example Lamington project from GitHub
* Injects recommended Lamington scripts into the currently cached package data
* @author Mitch Pierias <github.com/MitchPierias>
* @hidden
*/
private static async pullExampleProject() {
const files = await readdir(path.join(process.cwd(), 'contracts'));
spinner.create('Pulling example project');

await sleep(1000);
if (files.length <= 0) {
spinner.end('Included example project');
} else {
spinner.end('Project contained contracts');
}
private static async injectScripts() {
spinner.create('Injecting recommended scripts');
const existingScripts = ProjectManager.cache.scripts || {};
ProjectManager.cache.scripts = { ...DEFAULT_SCRIPTS, ...existingScripts };
spinner.end('Added scripts');
}

/**
* Creates the standard directories and files for a Lamington project
* Injects the required project dependencies into the currently cached package data
* @author Mitch Pierias <github.com/MitchPierias>
* @hidden
*/
private static async createProjectStructure() {
spinner.create('Creating directory structure');
private static async configureDependencies() {
spinner.create('Adding Lamington dependencies');
const existingDependencies = ProjectManager.cache.devDependencies || {};
ProjectManager.cache.devDependencies = { ...DEFAULT_DEV_DEPENDENCIES, ...existingDependencies };
spinner.end('Added required dependencies');
}

/**
* Downloads the latest example Lamington project from GitHub
* @author Mitch Pierias <github.com/MitchPierias>
* @hidden
*/
private static async cloneExampleProject() {
// Notify cloning task begun
spinner.create('Pulling example project');
// Check for existing contract files
await ProjectManager.createDirectoryIfMissing('contracts');
const files = await readdir(path.join(process.cwd(), 'contracts'));
if (files.length > 0)
return spinner.end('Existing contracts found');
// Attempt clone and merge of example project
try {

await ProjectManager.createDirectoryIfMissing('.lamington');

spinner.end('Created directory structure');
const got = require('got');
const tar = require('tar');
const cloneUrl = `https://codeload.github.com/MitchPierias/EOSIO-Lamington-Boilerplate/tar.gz/master`;

spinner.update('Cloning example project')

return new Promise(async (resolve, reject) => {
// Ensure tmp directory exists and capture directory path
const tmpPath = await ProjectManager.createDirectoryIfMissing('__tmp__');
// Stream the repo clone and untar
got.stream(cloneUrl).pipe(tar.extract({
cwd: tmpPath,
strip:1
})).on('error', (error:Error) => {
reject(error);
}).on('end', async () => {
// Clone example repository into tmp
const clonedFiles = await readdir(tmpPath);
if (clonedFiles.length <= 0)
throw new Error(`No files cloned from repo ${cloneUrl}`);
// Merge example contracts into current project
await ncp(path.join(tmpPath, 'contracts'), path.join(process.cwd(), 'contracts'));
// Cleanup temporary directory
spinner.update('Cleaning temporary files');
await rimraf(tmpPath);
resolve(true);
});
});
} catch (error) {
spinner.fail('Failed to clone repository');
console.log(error)
}
}

/**
*
* Creates a new local directory if missing and returns the path
* @author Mitch Pierias <github.com/MitchPierias>
* @param dirName Directory to create
* @returns Path to local directory
* @private
*/
private static async createDirectoryIfMissing(dirName: string) {
// Escape if the directory exists
if (await exists(path.join(process.cwd(), dirName))) return;
// Create the new directory
await mkdirp(path.join(process.cwd(), dirName));
// Construct directory path
const dirPath = path.join(process.cwd(), dirName);
// Create directory if missing
if (!await exists(dirPath))
await mkdirp(path.join(process.cwd(), dirName));
// Return the directory name
return dirPath;
}
}

0 comments on commit 4d8867e

Please sign in to comment.