mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-21 00:52:55 +00:00
feat: add projectmanagement and pack
This commit is contained in:
160
src/common.ts
Normal file
160
src/common.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2018 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Api} from '@openstapps/gitlab-api';
|
||||
import {Project} from '@openstapps/gitlab-api/lib/types';
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {asyncPool} from 'async-pool-native/dist/async-pool';
|
||||
import {readFile, unlink, writeFile} from 'fs';
|
||||
import * as glob from 'glob';
|
||||
import {basename} from 'path';
|
||||
import {promisify} from 'util';
|
||||
import {PACK_IDENTIFIER} from './configuration';
|
||||
import {JavaScriptModule} from './pack/types';
|
||||
|
||||
/**
|
||||
* Instantiated logger
|
||||
*/
|
||||
export const logger = new Logger();
|
||||
|
||||
/**
|
||||
* Get projects for a list of groups
|
||||
*
|
||||
* @param api GitLab API to make requests with
|
||||
* @param groups List of groups
|
||||
*/
|
||||
export async function getProjects(api: Api, groups: number[]): Promise<Project[]> {
|
||||
logger.info('Fetching all projects for specified groups (' + groups.length + ')...');
|
||||
|
||||
const projectResults = await asyncPool(3, groups, (groupId) => {
|
||||
return api.getProjectsForGroup(groupId);
|
||||
});
|
||||
|
||||
const projects = flatten2dArray(projectResults);
|
||||
|
||||
logger.log('Fetched ' + projects.length + ' project(s).');
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten 2d array
|
||||
*
|
||||
* @param arr Flattened array
|
||||
*/
|
||||
export function flatten2dArray<T>(arr: T[][]): T[] {
|
||||
return [].concat.apply([], arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Promisified version of readFile
|
||||
*/
|
||||
export const readFilePromisified = promisify(readFile);
|
||||
/**
|
||||
* Promisified version of glob
|
||||
*/
|
||||
export const globPromisified = promisify(glob);
|
||||
/**
|
||||
* Promisified version of writeFile
|
||||
*/
|
||||
export const writeFilePromisified = promisify(writeFile);
|
||||
/**
|
||||
* Promisified version of unlink
|
||||
*/
|
||||
export const unlinkPromisified = promisify(unlink);
|
||||
|
||||
/**
|
||||
* Delete file if it exists and is packed by this script
|
||||
*
|
||||
* @param path Path to file to check/delete
|
||||
*/
|
||||
export async function deleteFileIfExistingAndPacked(path: string): Promise<void> {
|
||||
try {
|
||||
const buffer = await readFilePromisified(path);
|
||||
const content = buffer.toString();
|
||||
|
||||
// check if packed by this script
|
||||
if (content.indexOf(PACK_IDENTIFIER) === 0) {
|
||||
logger.log('Found `' + path + '` which is packed by this script. Deleting it...');
|
||||
return await unlinkPromisified(path);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all internal dependencies from the content of a module
|
||||
*
|
||||
* @param moduleContent Module content to analyze
|
||||
*/
|
||||
export function getAllInternalDependecies(moduleContent: string): string[] {
|
||||
// match all const <name> = require(<moduleName>);
|
||||
const requireLines =
|
||||
moduleContent.match(/^\s*(const|var) [a-z0-9_]* = require\("([^"]+)"\)|require\('([^']+)'\);$/gmi);
|
||||
|
||||
if (Array.isArray(requireLines)) {
|
||||
return requireLines.map((requireLine) => {
|
||||
const matches = requireLine.match(/require\("([^"]+)"\)|require\('([^']+)'\);$/i);
|
||||
|
||||
// previously matched require line does not contain a require?!
|
||||
if (matches === null) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
// return only the moduleName
|
||||
return matches[1];
|
||||
}).filter((moduleName) => {
|
||||
// filter out internal modules beginning with './' and not ending with '.json'
|
||||
return /^[.]{1,2}\/(?!.*\.json$).*$/i.test(moduleName);
|
||||
}).map((internalModuleName) => {
|
||||
// cut './' from the name
|
||||
return internalModuleName.substring(2);
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort modules by their dependencies
|
||||
*
|
||||
* @param modules Modules to sort
|
||||
*/
|
||||
export function topologicalSort(modules: JavaScriptModule[]): JavaScriptModule[] {
|
||||
const topoSort = require('toposort');
|
||||
|
||||
// vertices are modules, an edge from a to b means that b depends on a
|
||||
const edges: string[][] = [];
|
||||
const nodes: string[] = [];
|
||||
|
||||
// add all edges
|
||||
modules.forEach((module) => {
|
||||
module.dependencies.forEach((dependenciePath) => {
|
||||
// add edge from dependency to our module
|
||||
edges.push([basename(dependenciePath), module.name]);
|
||||
});
|
||||
|
||||
nodes.push(module.name);
|
||||
});
|
||||
|
||||
// sort graph and return as an array of sorted modules
|
||||
return topoSort.array(nodes, edges).map((moduleName: string) => {
|
||||
return modules.find((module) => {
|
||||
return module.name === moduleName;
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user