11import express from 'express' ;
2- import fs from 'fs' ;
2+ import Promise from 'bluebird' ;
3+ import fs from 'fs-extra' ;
34import path from 'path' ;
45import { NotFoundError } from '/common/error' ;
5- import { exec } from 'child_process' ;
66import { GitHubApi } from '/apis' ;
7+ import { execute } from '/common/util' ;
78
89const router = express . Router ( ) ;
910
10- const getPath = ( ...args ) => path . resolve ( __dirname , '..' , 'public' , 'algorithms' , ...args ) ;
11- const createKey = name => name . toLowerCase ( ) . replace ( / / g, '-' ) ;
12- const list = dirPath => fs . readdirSync ( dirPath ) . filter ( fileName => ! fileName . startsWith ( '.' ) ) ;
11+ const repoPath = path . resolve ( __dirname , '..' , 'public' , 'algorithms' ) ;
12+ const getPath = ( ...args ) => path . resolve ( repoPath , ...args ) ;
1313
1414const cacheCategories = ( ) => {
1515 const allFiles = [ ] ;
16+
17+ const createKey = name => name . toLowerCase ( ) . replace ( / / g, '-' ) ;
18+ const list = dirPath => fs . readdirSync ( dirPath ) . filter ( fileName => ! fileName . startsWith ( '.' ) ) ;
19+
1620 const cacheCategory = categoryName => {
1721 const categoryKey = createKey ( categoryName ) ;
1822 const categoryPath = getPath ( categoryName ) ;
@@ -64,54 +68,53 @@ const cacheCategories = () => {
6468 return cacheCommitAuthors ( page + 1 , commitAuthors ) ;
6569 }
6670 } ) ;
67- const cacheContributors = ( commitAuthors , fileIndex = 0 ) => {
68- const file = allFiles [ fileIndex ] ;
69- if ( file ) {
70- const cwd = getPath ( ) ;
71- exec ( `git --no-pager log --follow --no-merges --format="%H" "${ file . path } "` , { cwd } , ( error , stdout , stderr ) => {
72- if ( ! error && ! stderr ) {
73- const output = stdout . toString ( ) . replace ( / \n $ / , '' ) ;
74- const shas = output . split ( '\n' ) . reverse ( ) ;
75- const contributors = [ ] ;
76- for ( const sha of shas ) {
77- const author = commitAuthors [ sha ] ;
78- if ( author && ! contributors . find ( contributor => contributor . login === author . login ) ) {
79- contributors . push ( author ) ;
80- }
71+ const cacheContributors = commitAuthors => Promise . each ( allFiles , file => {
72+ return execute ( `git --no-pager log --follow --no-merges --format="%H" "${ file . path } "` , getPath ( ) , { stdout : null } )
73+ . then ( stdout => {
74+ const output = stdout . toString ( ) . replace ( / \n $ / , '' ) ;
75+ const shas = output . split ( '\n' ) . reverse ( ) ;
76+ const contributors = [ ] ;
77+ for ( const sha of shas ) {
78+ const author = commitAuthors [ sha ] ;
79+ if ( author && ! contributors . find ( contributor => contributor . login === author . login ) ) {
80+ contributors . push ( author ) ;
8181 }
82- file . contributors = contributors ;
8382 }
84- cacheContributors ( commitAuthors , fileIndex + 1 ) ;
83+ file . contributors = contributors ;
8584 } ) ;
86- }
87- } ;
85+ } ) ;
8886 cacheCommitAuthors ( ) . then ( cacheContributors ) ;
8987
9088 return categories ;
9189} ;
92- const cachedCategories = cacheCategories ( ) ; // TODO: cache again when webhooked
93-
94- const getCategories = ( req , res , next ) => {
95- res . json ( { categories : cachedCategories } ) ;
96- } ;
9790
98- const getAlgorithm = ( req , res , next ) => {
99- const { categoryKey, algorithmKey } = req . params ;
91+ const downloadCategories = ( ) => (
92+ fs . pathExistsSync ( repoPath ) ?
93+ execute ( `git fetch && git reset --hard origin/master` , repoPath ) :
94+ execute ( `git clone [email protected] :algorithm-visualizer/algorithms ${ repoPath } ` , __dirname ) 95+ ) ;
10096
101- const category = cachedCategories . find ( category => category . key === categoryKey ) ;
102- if ( ! category ) return next ( new NotFoundError ( ) ) ;
103- const algorithm = category . algorithms . find ( algorithm => algorithm . key === algorithmKey ) ;
104- if ( ! algorithm ) return next ( new NotFoundError ( ) ) ;
97+ let categories = [ ] ; // TODO: download again when webhooked
98+ downloadCategories ( ) . then ( ( ) => categories = cacheCategories ( ) ) ;
10599
106- const titles = [ category . name , algorithm . name ] ;
107- const files = algorithm . files . map ( ( { name, content, contributors } ) => ( { name, content, contributors } ) ) ;
108- res . json ( { algorithm : { titles, files } } ) ;
109- } ;
110100
111101router . route ( '/' )
112- . get ( getCategories ) ;
102+ . get ( ( req , res , next ) => {
103+ res . json ( { categories } ) ;
104+ } ) ;
113105
114106router . route ( '/:categoryKey/:algorithmKey' )
115- . get ( getAlgorithm ) ;
107+ . get ( ( req , res , next ) => {
108+ const { categoryKey, algorithmKey } = req . params ;
109+
110+ const category = categories . find ( category => category . key === categoryKey ) ;
111+ if ( ! category ) return next ( new NotFoundError ( ) ) ;
112+ const algorithm = category . algorithms . find ( algorithm => algorithm . key === algorithmKey ) ;
113+ if ( ! algorithm ) return next ( new NotFoundError ( ) ) ;
114+
115+ const titles = [ category . name , algorithm . name ] ;
116+ const files = algorithm . files . map ( ( { name, content, contributors } ) => ( { name, content, contributors } ) ) ;
117+ res . json ( { algorithm : { titles, files } } ) ;
118+ } ) ;
116119
117120export default router ;
0 commit comments