1
0
Fork 0
mirror of https://github.com/dilllxd/gitfolio.git synced 2024-08-14 22:28:09 +00:00

Cli feature (#29)

* Move all cli options to single bin file, export fns from each file instead

* Make username/title required in cli itself

* fix username not being parsed, set desc separately

* read outDir from env var, defaults to dist

* set outDir env var in cli to cwd

* Move default configs to default dir

* handle blog.json not existing

* fix assets path

* make build function async

* update clean command

* added defaults to CLI
This commit is contained in:
Rohit Gohri 2019-05-23 10:30:49 +05:30 committed by imfunny
parent 2ec61a9132
commit e62e4c05b3
10 changed files with 169 additions and 99 deletions

View file

@ -50,6 +50,7 @@
},800); },800);
},1500); },1500);
$.getJSON("blog.json", function(blog){ $.getJSON("blog.json", function(blog){
blog = blog || [];
if(blog.length == 0){ if(blog.length == 0){
return document.getElementById("blog_section").style.display = "none"; return document.getElementById("blog_section").style.display = "none";
} }
@ -68,6 +69,8 @@
</a> </a>
`); `);
} }
}).fail(function(){
return document.getElementById("blog_section").style.display = "none";
}); });
</script> </script>
</body> </body>

44
bin/gitfolio.js Normal file
View file

@ -0,0 +1,44 @@
#! /usr/bin/env node
/* Argument parser */
const program = require('commander');
process.env.OUT_DIR = process.env.OUT_DIR || process.cwd();
const {buildCommand} = require('../build');
const {updateCommand} = require('../update');
const {blogCommand} = require('../blog');
const {version} = require('../package.json');
program
.command('build <username>')
.description('Build site with your GitHub username. This will be used to customize your site')
.option('-t, --theme [theme]', 'specify a theme to use', 'light')
.option('-b, --background [background]', 'set the background image')
.option('-f, --fork', 'includes forks with repos')
.option('-s, --sort [sort]', 'set default sort for repository', 'created')
.option('-o, --order [order]', 'set default order on sort', 'asc')
.action(buildCommand)
program
.command('update')
.action(updateCommand);
program
.command('blog <title>')
.description('Create blog with specified title')
.option('-s, --subtitle [subtitle]', 'give blog a subtitle', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
.option('-p, --pagetitle [pagetitle]', 'give blog page a title')
.option('-f, --folder [folder]', 'give folder a title (use "-" instead of spaces)')
.action(blogCommand);
program.on('command:*', () => {
console.log('Unknown Command: ' + program.args.join(' '))
program.help()
});
program
.version(version, '-v --version')
.usage('<command> [options]')
.parse(process.argv);
if (program.args.length === 0) program.help();

51
blog.js
View file

@ -1,31 +1,23 @@
const program = require('commander');
const fs = require('fs'); const fs = require('fs');
const jsdom = require('jsdom').JSDOM, const jsdom = require('jsdom').JSDOM,
options = { options = {
resources: "usable" resources: "usable"
}; };
const {getBlog, outDir} = require('./utils');
program
.version('0.1.2')
.option('-t, --title [title]', 'give blog a title')
.option('-s, --subtitle [subtitle]', 'give blog a subtitle', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
.option('-p, --pagetitle [pagetitle]', 'give blog page a title')
.option('-f, --folder [folder]', 'give folder a title (use "-" instead of spaces)')
.parse(process.argv);
function createBlog(title, subtitle, pagetitle, folder) { function createBlog(title, subtitle, pagetitle, folder) {
// Checks to make sure this directory actually exists // Checks to make sure this directory actually exists
// and creates it if it doesn't // and creates it if it doesn't
if (!fs.existsSync(`./dist/blog/`)){ if (!fs.existsSync(`${outDir}/blog/`)){
fs.mkdirSync(`./dist/blog/`, { recursive: true }, err => {}); fs.mkdirSync(`${outDir}/blog/`, { recursive: true }, err => {});
} }
if (!fs.existsSync(`./dist/blog/${folder}`)){ if (!fs.existsSync(`${outDir}/blog/${folder}`)){
fs.mkdirSync(`./dist/blog/${folder}`, { recursive: true }); fs.mkdirSync(`${outDir}/blog/${folder}`, { recursive: true });
} }
fs.copyFile('./assets/blog/blogTemplate.html', `./dist/blog/${folder}/index.html`, (err) => { fs.copyFile(`${__dirname}/assets/blog/blogTemplate.html`, `${outDir}/blog/${folder}/index.html`, (err) => {
if (err) throw err; if (err) throw err;
jsdom.fromFile(`./dist/blog/${folder}/index.html`, options).then(function (dom) { jsdom.fromFile(`${outDir}/blog/${folder}/index.html`, options).then(function (dom) {
let window = dom.window, document = window.document; let window = dom.window, document = window.document;
var style = document.createElement("link"); var style = document.createElement("link");
style.setAttribute("rel","stylesheet") style.setAttribute("rel","stylesheet")
@ -36,7 +28,7 @@ function createBlog(title, subtitle, pagetitle, folder) {
document.getElementById("blog_title").textContent = title; document.getElementById("blog_title").textContent = title;
document.getElementById("blog_sub_title").textContent = subtitle; document.getElementById("blog_sub_title").textContent = subtitle;
fs.writeFile(`./dist/blog/${folder}/index.html`, '<!DOCTYPE html>'+window.document.documentElement.outerHTML, function (error){ fs.writeFile(`${outDir}/blog/${folder}/index.html`, '<!DOCTYPE html>'+window.document.documentElement.outerHTML, async function (error){
if (error) throw error; if (error) throw error;
var blog_data = { var blog_data = {
"url_title": pagetitle, "url_title": pagetitle,
@ -44,14 +36,11 @@ function createBlog(title, subtitle, pagetitle, folder) {
"sub_title": subtitle, "sub_title": subtitle,
"top_image": "https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450", "top_image": "https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450",
"visible": true } "visible": true }
fs.readFile("./dist/blog.json", function (err , data) { const old_blogs = await getBlog();
old_blogs.push(blog_data);
fs.writeFile(`${outDir}/blog.json`, JSON.stringify(old_blogs, null, ' '), function(err){
if (err) throw err; if (err) throw err;
var old_blogs = JSON.parse(data); console.log('Blog Created Successfully in "blog" folder.');
old_blogs.push(blog_data);
fs.writeFile('./dist/blog.json', JSON.stringify(old_blogs, null, ' '), function(err){
if (err) throw err;
console.log('Blog Created Successfully in "blog" folder.');
});
}); });
}); });
}).catch(function(error){ }).catch(function(error){
@ -60,18 +49,20 @@ function createBlog(title, subtitle, pagetitle, folder) {
}); });
} }
if (program.title) { function blogCommand(title, program) {
/* Check if build has been executed before blog this will prevent it from giving "link : index.css" error */ /* Check if build has been executed before blog this will prevent it from giving "link : index.css" error */
if (!fs.existsSync(`./dist/index.html`) || !fs.existsSync(`./dist/index.css`)){ if (!fs.existsSync(`${outDir}/index.html`) || !fs.existsSync(`${outDir}/index.css`)){
return console.log("You need to run build command before using blog one"); return console.log("You need to run build command before using blog one");
} }
if (!program.pagetitle) { if (!program.pagetitle) {
program.pagetitle = program.title; program.pagetitle = title;
} }
if (!program.folder) { if (!program.folder) {
program.folder = program.title; program.folder = title;
} }
createBlog(program.title, program.subtitle, program.pagetitle, program.folder); createBlog(title, program.subtitle, program.pagetitle, program.folder);
} else {
console.log("Provide a title to create a new blog");
} }
module.exports = {
blogCommand,
};

View file

@ -1,5 +1,3 @@
/* Argument parser */
const program = require('commander');
/* Filepath utilities */ /* Filepath utilities */
const path = require('path'); const path = require('path');
/* Promise library */ /* Promise library */
@ -9,22 +7,10 @@ const hbs = require('handlebars');
from callback-passed async functions */ from callback-passed async functions */
const fs = bluebird.promisifyAll(require('fs')); const fs = bluebird.promisifyAll(require('fs'));
const { updateHTML } = require('./populate'); const { updateHTML } = require('./populate');
const { getConfig, outDir } = require('./utils');
const assetDir = path.resolve(`${__dirname}/assets/`);
/* Specify the options the program uses */ const config = path.join(outDir, 'config.json');
program
.version('0.1.2')
.option('-n, --name [username]', 'your GitHub username. This will be used to customize your site')
.option('-t, --theme [theme]', 'specify a theme to use')
.option('-b, --background [background]', 'set the background image')
.option('-f, --fork', 'includes forks with repos')
.option('-s, --sort [sort]', 'set default sort for repository')
.option('-o, --order [order]', 'set default order on sort')
.parse(process.argv);
const config = './dist/config.json';
const assetDir = path.resolve('./assets/');
const outDir = path.resolve('./dist/');
/** /**
* Creates the stylesheet used by the site from a template stylesheet. * Creates the stylesheet used by the site from a template stylesheet.
@ -32,9 +18,12 @@ const outDir = path.resolve('./dist/');
* Theme styles are added to the new stylesheet depending on command line * Theme styles are added to the new stylesheet depending on command line
* arguments. * arguments.
*/ */
async function populateCSS() { async function populateCSS({
theme = 'light',
background = 'https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450',
} = {}) {
/* Get the theme the user requests. Defaults to 'light' */ /* Get the theme the user requests. Defaults to 'light' */
let theme = `${program.theme || 'light'}.css`; /* Site theme, defaults to 'light' */ theme = `${theme}.css`;
let template = path.resolve(assetDir, 'index.css'); let template = path.resolve(assetDir, 'index.css');
let stylesheet = path.join(outDir, 'index.css'); let stylesheet = path.join(outDir, 'index.css');
@ -58,41 +47,41 @@ async function populateCSS() {
themeSource = themeSource.toString('utf-8'); themeSource = themeSource.toString('utf-8');
let themeTemplate = hbs.compile(themeSource); let themeTemplate = hbs.compile(themeSource);
let styles = themeTemplate({ let styles = themeTemplate({
'background': `${program.background || 'https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450'}` 'background': `${background}`
}) })
/* Add the user-specified styles to the new stylesheet */ /* Add the user-specified styles to the new stylesheet */
await fs.appendFileAsync(stylesheet, styles); await fs.appendFileAsync(stylesheet, styles);
/* Update the config file with the user's theme choice */ /* Update the config file with the user's theme choice */
let data = await fs.readFileAsync(config); const data = await getConfig();
data = JSON.parse(data);
data[0].theme = theme; data[0].theme = theme;
await fs.writeFileAsync(config, JSON.stringify(data, null, ' ')); await fs.writeFileAsync(config, JSON.stringify(data, null, ' '));
} }
async function populateConfig(sort, order, includeFork) { async function populateConfig(sort, order, includeFork) {
let data = await fs.readFileAsync(config); const data = await getConfig();
data = JSON.parse(data);
data[0].sort = sort; data[0].sort = sort;
data[0].order = order; data[0].order = order;
data[0].includeFork = includeFork; data[0].includeFork = includeFork;
await fs.writeFileAsync(config, JSON.stringify(data, null, ' ')); await fs.writeFileAsync(config, JSON.stringify(data, null, ' '));
} }
populateCSS(); async function buildCommand(username, program) {
await populateCSS(program);
if (typeof program.name === 'string' && program.name.trim() !== '') {
let sort = program.sort ? program.sort : 'created'; let sort = program.sort ? program.sort : 'created';
let order = "asc"; let order = "asc";
let includeFork = false; let includeFork = false;
if(program.order){ if(program.order){
order = ('%s', program.order); order = ('%s', program.order);
} }
if(program.fork){ if(program.fork){
includeFork = true; includeFork = true;
} }
populateConfig(sort, order, includeFork); await populateConfig(sort, order, includeFork);
updateHTML(('%s', program.name), sort, order, includeFork); updateHTML(('%s', username), sort, order, includeFork);
} else {
console.error("Error: Please provide a GitHub username.");
} }
module.exports = {
buildCommand,
};

View file

@ -3,8 +3,10 @@
"version": "0.1.2", "version": "0.1.2",
"description": "portfolio website for showcasing your work", "description": "portfolio website for showcasing your work",
"main": "build.js", "main": "build.js",
"bin": "bin/gitfolio.js",
"scripts": { "scripts": {
"clean": "rm -f dist/index.*", "cli": "OUT_DIR='./dist' node bin/gitfolio.js",
"clean": "rm -rf ./dist/*",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"author": "imfunny", "author": "imfunny",

View file

@ -5,6 +5,7 @@ const jsdom = require('jsdom').JSDOM,
options = { options = {
resources: "usable" resources: "usable"
}; };
const { getConfig, outDir } = require('./utils');
function convertToEmoji(text) { function convertToEmoji(text) {
if (text == null) return; if (text == null) return;
@ -29,7 +30,7 @@ function convertToEmoji(text) {
module.exports.updateHTML = (username, sort, order, includeFork) => { module.exports.updateHTML = (username, sort, order, includeFork) => {
//add data to assets/index.html //add data to assets/index.html
jsdom.fromFile("./assets/index.html", options).then(function (dom) { jsdom.fromFile(`${__dirname}/assets/index.html`, options).then(function (dom) {
let window = dom.window, document = window.document; let window = dom.window, document = window.document;
(async () => { (async () => {
try { try {
@ -115,18 +116,15 @@ module.exports.updateHTML = (username, sort, order, includeFork) => {
<span style="display:${user.location == null || !user.location ? 'none' : 'block'};"><i class="fas fa-map-marker-alt"></i> &nbsp;&nbsp; ${user.location}</span> <span style="display:${user.location == null || !user.location ? 'none' : 'block'};"><i class="fas fa-map-marker-alt"></i> &nbsp;&nbsp; ${user.location}</span>
<span style="display:${user.hireable == false || !user.hireable ? 'none' : 'block'};"><i class="fas fa-user-tie"></i> &nbsp;&nbsp; Available for hire</span>`; <span style="display:${user.hireable == false || !user.hireable ? 'none' : 'block'};"><i class="fas fa-user-tie"></i> &nbsp;&nbsp; Available for hire</span>`;
//add data to config.json //add data to config.json
fs.readFile("./dist/config.json", function (err, data) { const data = await getConfig();
data[0].username = user.login;
data[0].name = user.name;
data[0].userimg = user.avatar_url;
fs.writeFile(`${outDir}/config.json`, JSON.stringify(data, null, ' '), function (err) {
if (err) throw err; if (err) throw err;
data = JSON.parse(data); console.log("Config file updated.");
data[0].username = user.login;
data[0].name = user.name;
data[0].userimg = user.avatar_url;
fs.writeFile('./dist/config.json', JSON.stringify(data, null, ' '), function (err) {
if (err) throw err;
console.log("Config file updated.");
});
}); });
fs.writeFile('dist/index.html', '<!DOCTYPE html>' + window.document.documentElement.outerHTML, function (error) { fs.writeFile(`${outDir}/index.html`, '<!DOCTYPE html>' + window.document.documentElement.outerHTML, function (error) {
if (error) throw error; if (error) throw error;
console.log("Build Complete"); console.log("Build Complete");
}); });

View file

@ -1,9 +1,9 @@
const fs = require('fs'); const fs = require('fs');
const {getConfig, outDir} = require('./utils');
const {updateHTML} = require('./populate'); const {updateHTML} = require('./populate');
fs.readFile("./dist/config.json", function (err , data) { async function updateCommand() {
if (err) throw err; const data = await getConfig();
data = JSON.parse(data);
var username = data[0].username; var username = data[0].username;
var sort = data[0].sort; var sort = data[0].sort;
var order = data[0].order; var order = data[0].order;
@ -13,4 +13,8 @@ fs.readFile("./dist/config.json", function (err , data) {
return; return;
} }
updateHTML(username, sort, order, includeFork); updateHTML(username, sort, order, includeFork);
}); }
module.exports = {
updateCommand,
};

39
utils.js Normal file
View file

@ -0,0 +1,39 @@
const path = require('path');
const bluebird = require('bluebird');
const fs = bluebird.promisifyAll(require('fs'));
const outDir = path.resolve(process.env.OUT_DIR || './dist/');
const configPath = path.join(outDir, 'config.json');
const blogPath = path.join(outDir, 'blog.json');
const defaultConfigPath = path.resolve(`${__dirname}/default/config.json`);
const defaultBlogPath = path.resolve(`${__dirname}/default/blog.json`);
/**
* Tries to read file from out dir,
* if not present returns default file contents
*/
async function getFileWithDefaults(file, defaultFile) {
try {
await fs.accessAsync(file, fs.constants.F_OK);
} catch (err) {
const defaultData = await fs.readFileAsync(defaultFile);
return JSON.parse(defaultData);
}
const data = await fs.readFileAsync(file);
return JSON.parse(data);
}
async function getConfig() {
return getFileWithDefaults(configPath, defaultConfigPath);
}
async function getBlog() {
return getFileWithDefaults(blogPath, defaultBlogPath);
}
module.exports = {
outDir,
getConfig,
getBlog,
};