From 9a538130eef9a65a74256053a316d82af6b4b9e5 Mon Sep 17 00:00:00 2001 From: masnn Date: Tue, 13 Apr 2021 17:49:58 +0000 Subject: [PATCH] use findFile() api --- .eslintrc.yaml | 67 ++++++++++---------- build/start.ts | 2 +- build/utils.ts | 3 +- packages/geoip/lib.ts | 4 +- packages/hydrojudge/src/check.ts | 6 +- packages/hydrojudge/src/judge/interactive.ts | 6 +- packages/hydrooj/package.json | 1 + packages/hydrooj/src/options.ts | 10 +-- packages/ui-default/backendlib/template.js | 7 +- packages/utils/lib/utils.ts | 51 ++++++++++++++- 10 files changed, 105 insertions(+), 52 deletions(-) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 7a862735..c8d796d6 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -7,52 +7,55 @@ globals: Atomics: readonly SharedArrayBuffer: readonly BigInt: readonly -parser: '@typescript-eslint/parser' +parser: "@typescript-eslint/parser" plugins: - - '@typescript-eslint' + - "@typescript-eslint" rules: - '@typescript-eslint/dot-notation': off - '@typescript-eslint/no-implied-eval': off - '@typescript-eslint/no-throw-literal': off - '@typescript-eslint/return-await': off + "@typescript-eslint/dot-notation": 0 + "@typescript-eslint/no-implied-eval": 0 + "@typescript-eslint/no-throw-literal": 0 + "@typescript-eslint/return-await": 0 - '@typescript-eslint/indent': + "@typescript-eslint/indent": - warn - 4 - '@typescript-eslint/lines-between-class-members': + "@typescript-eslint/lines-between-class-members": - error - always - exceptAfterSingleLine: true - '@typescript-eslint/naming-convention': off - '@typescript-eslint/no-redeclare': off + "@typescript-eslint/naming-convention": 0 + "@typescript-eslint/no-redeclare": 0 - class-methods-use-this: off - global-require: off - guard-for-in: off - implicit-arrow-linebreak: off - import/no-cycle: off - import/no-extraneous-dependencies: off - import/no-named-as-default: off - import/prefer-default-export: off - max-classes-per-file: off + class-methods-use-this: 0 + global-require: 0 + guard-for-in: 0 + implicit-arrow-linebreak: 0 + import/no-cycle: 0 + import/no-extraneous-dependencies: 0 + import/no-named-as-default: 0 + import/prefer-default-export: 0 + max-classes-per-file: 0 max-len: - warn - 150 - no-bitwise: off - no-console: off - no-continue: off - no-extend-native: off - no-multi-assign: off - no-nested-ternary: off - no-param-reassign: off - no-plusplus: off - no-restricted-syntax: off - no-return-await: off - no-underscore-dangle: off - prefer-destructuring: off + no-bitwise: 0 + no-console: 0 + no-continue: 0 + no-extend-native: 0 + no-empty: + - warn + - allowEmptyCatch: true + no-multi-assign: 0 + no-nested-ternary: 0 + no-param-reassign: 0 + no-plusplus: 0 + no-restricted-syntax: 0 + no-return-await: 0 + no-underscore-dangle: 0 + prefer-destructuring: 0 settings: import/parsers: - '@typescript-eslint/parser': + "@typescript-eslint/parser": - .ts - .js - .jsx diff --git a/build/start.ts b/build/start.ts index f506ccfc..ac6aaf5a 100644 --- a/build/start.ts +++ b/build/start.ts @@ -19,7 +19,7 @@ if (!cluster.isMaster) { fs.ensureDirSync(path.resolve(os.homedir(), '.hydro')); const addonPath = path.resolve(os.homedir(), '.hydro', 'addon.json'); let addons = filter( - fs.readdirSync(path.resolve(__dirname, '../packages')), + fs.readdirSync(path.resolve(process.cwd(), 'packages')), (i) => i !== 'hydrooj', ).map((i) => `@hydrooj/${i}`); fs.writeFileSync(addonPath, JSON.stringify(addons, null, 2)); diff --git a/build/utils.ts b/build/utils.ts index c14d099b..f3748161 100644 --- a/build/utils.ts +++ b/build/utils.ts @@ -1,10 +1,9 @@ /* eslint-disable no-console */ /* eslint-disable import/no-extraneous-dependencies */ -import path from 'path'; import globby from 'globby'; import spawn from 'cross-spawn'; -export const cwd = path.resolve(__dirname, '..'); +export const cwd = process.cwd(); export function getWorkspaces() { return globby(require('../package').workspaces, { diff --git a/packages/geoip/lib.ts b/packages/geoip/lib.ts index 1371e978..4e3ee86f 100644 --- a/packages/geoip/lib.ts +++ b/packages/geoip/lib.ts @@ -1,9 +1,9 @@ import 'hydrooj'; import fs from 'fs'; -import path from 'path'; import { Reader } from 'maxmind'; +import { findFileSync } from '@hydrooj/utils/lib/utils'; -const buffer = fs.readFileSync(path.resolve(__dirname, 'GeoLite2-City.mmdb')); +const buffer = fs.readFileSync(findFileSync('@hydrooj/geoip/GeoLite2-City.mmdb')); const reader = new Reader(buffer); export interface Result { diff --git a/packages/hydrojudge/src/check.ts b/packages/hydrojudge/src/check.ts index c1674716..81ca0939 100644 --- a/packages/hydrojudge/src/check.ts +++ b/packages/hydrojudge/src/check.ts @@ -1,10 +1,12 @@ import fs from 'fs-extra'; -import { resolve } from 'path'; +import { findFileSync } from '@hydrooj/utils/lib/utils'; import checkers from './checkers'; import compile from './compile'; import { SystemError } from './error'; import { parseFilename } from './utils'; +const testlibSrc = findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h'); + export async function check(config): Promise<[number, number, string]> { if (!checkers[config.checker_type]) throw new SystemError(`未知比较器类型:${config.checker_type}`); const { @@ -24,7 +26,7 @@ export async function check(config): Promise<[number, number, string]> { export async function compileChecker(checkerType: string, checker: string, copyIn: any) { if (!checkers[checkerType]) throw new SystemError('Unknown checker type {0}.', [checkerType]); - if (checkerType === 'testlib') copyIn['testlib.h'] = { src: resolve(__dirname, '../vendor/testlib/testlib.h') }; + if (checkerType === 'testlib') copyIn['testlib.h'] = { src: testlibSrc }; const file = await fs.readFile(checker); // TODO cache compiled checker return await compile(parseFilename(checker).split('.')[1], file.toString(), 'checker', copyIn); diff --git a/packages/hydrojudge/src/judge/interactive.ts b/packages/hydrojudge/src/judge/interactive.ts index 47711f89..a976d674 100644 --- a/packages/hydrojudge/src/judge/interactive.ts +++ b/packages/hydrojudge/src/judge/interactive.ts @@ -1,14 +1,14 @@ import Queue from 'p-queue'; import fs from 'fs-extra'; -import { resolve } from 'path'; import * as STATUS from '../status'; import { parse } from '../testlib'; -import { parseFilename } from '../utils'; +import { findFileSync, parseFilename } from '../utils'; import { run } from '../sandbox'; import compile from '../compile'; import signals from '../signals'; import { getConfig } from '../config'; +const testlibSrc = findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h'); const Score = { sum: (a, b) => (a + b), max: Math.max, @@ -19,7 +19,7 @@ function judgeCase(c) { return async (ctx, ctxSubtask) => { ctx.executeInteractor.copyIn.in = c.input ? { src: c.input } : { content: '' }; ctx.executeInteractor.copyIn.out = c.output ? { src: c.output } : { content: '' }; - ctx.executeInteractor.copyIn['testlib.h'] = { src: resolve(__dirname, '../../vendor/testlib/testlib.h') }; + ctx.executeInteractor.copyIn['testlib.h'] = { src: testlibSrc }; const [{ code, time_usage_ms, memory_usage_kb }, resInteractor] = await run([ { execute: ctx.executeUser.execute.replace(/\$\{name\}/g, 'code'), diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 94beae1f..de94e32d 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -43,6 +43,7 @@ "@types/inquirer": "^7.3.1", "@types/js-yaml": "^4.0.0", "@types/koa": "^2.13.1", + "@types/koa-compress": "^4.0.1", "@types/koa-router": "^7.4.1", "@types/koa-static-cache": "^5.1.0", "@types/lodash": "^4.14.168", diff --git a/packages/hydrooj/src/options.ts b/packages/hydrooj/src/options.ts index 80f71fe4..9f314a71 100644 --- a/packages/hydrooj/src/options.ts +++ b/packages/hydrooj/src/options.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; +import { findFileSync } from '@hydrooj/utils/lib/utils'; import { Logger } from './logger'; const logger = new Logger('options'); @@ -13,13 +14,8 @@ export = function load() { process.env[line.split('=')[0]] = line.split('=')[1]; } } - - let f = path.resolve(process.cwd(), 'config.json'); - if (!fs.existsSync(f)) f = path.resolve(__dirname, 'config.json'); - if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.config', 'hydro', 'config.json'); - if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.hydro', 'config.json'); - if (!fs.existsSync(f)) f = path.resolve('/config/config.json'); - if (!fs.existsSync(f)) return null; + const f = findFileSync('config.json', false); + if (!f) return null; let result: any = {}; try { result = JSON.parse(fs.readFileSync(f).toString()); diff --git a/packages/ui-default/backendlib/template.js b/packages/ui-default/backendlib/template.js index ac215946..4ea3d0c9 100644 --- a/packages/ui-default/backendlib/template.js +++ b/packages/ui-default/backendlib/template.js @@ -6,6 +6,7 @@ const nunjucks = require('nunjucks'); const { filter } = require('lodash'); const { argv } = require('yargs'); const Xss = require('xss'); +const { findFileSync } = require('@hydrooj/utils/lib/utils'); const markdown = require('./markdown'); const { misc, buildContent } = global.Hydro.lib; @@ -76,6 +77,9 @@ const xss = new Xss.FilterXSS({ }, }); +if (argv.template && argv.template !== 'string') argv.template = findFileSync('@hydrooj/ui-default/templates'); +else argv.template = findFileSync(argv.template); + class Loader extends nunjucks.Loader { // eslint-disable-next-line class-methods-use-this getSource(name) { @@ -88,8 +92,7 @@ class Loader extends nunjucks.Loader { }; } let fullpath = null; - if (typeof argv.template !== 'string') argv.template = path.resolve(__dirname, '..', 'templates'); - const p = path.resolve(process.cwd(), argv.template, name); + const p = path.resolve(argv.template, name); if (fs.existsSync(p)) fullpath = p; if (!fullpath) { if (global.Hydro.ui.template[name]) { diff --git a/packages/utils/lib/utils.ts b/packages/utils/lib/utils.ts index 19713302..47fbe09d 100644 --- a/packages/utils/lib/utils.ts +++ b/packages/utils/lib/utils.ts @@ -1,5 +1,6 @@ import path, { sep } from 'path'; -import fs from 'fs'; +import fs from 'fs-extra'; +import os from 'os'; import { Duplex } from 'stream'; import { ObjectID } from 'bson'; import { isMoment } from 'moment'; @@ -305,6 +306,54 @@ export function changeErrorType(err: Error, Err: any) { return e; } +export async function findFile(pathname: string, doThrow = true) { + if (await fs.pathExists(path.resolve(pathname))) return path.resolve(pathname); + if (await fs.pathExists(path.resolve(process.cwd(), pathname))) return path.resolve(process.cwd(), pathname); + if (await fs.pathExists(path.resolve(__dirname, pathname))) return path.resolve(__dirname, pathname); + try { + return require.resolve(pathname); + } catch (e) { } + if (pathname.includes('/')) { + const eles = pathname.split('/'); + let pkg = eles.shift(); + if (pkg.startsWith('@')) pkg = `${pkg}/${eles.shift()}`; + const rest = eles.join('/'); + try { + const p = require.resolve(pkg); + if (await fs.pathExists(path.resolve(p, rest))) return path.resolve(p, rest); + } catch (e) { } + } + if (await fs.pathExists(path.resolve(os.homedir(), pathname))) return path.resolve(__dirname, pathname); + if (await fs.pathExists(path.resolve(os.homedir(), '.hydro', pathname))) return path.resolve(__dirname, pathname); + if (await fs.pathExists(path.resolve(os.homedir(), '.config', 'hydro', pathname))) return path.resolve(__dirname, pathname); + if (doThrow) throw new Error(`File ${pathname} not found`); + return null; +} + +export function findFileSync(pathname: string, doThrow = true) { + if (fs.pathExistsSync(path.resolve(pathname))) return path.resolve(pathname); + if (fs.pathExistsSync(path.resolve(process.cwd(), pathname))) return path.resolve(process.cwd(), pathname); + if (fs.pathExistsSync(path.resolve(__dirname, pathname))) return path.resolve(__dirname, pathname); + try { + return require.resolve(pathname); + } catch (e) { } + if (pathname.includes('/')) { + const eles = pathname.split('/'); + let pkg = eles.shift(); + if (pkg.startsWith('@')) pkg = `${pkg}/${eles.shift()}`; + const rest = eles.join('/'); + try { + const p = require.resolve(pkg); + if (fs.pathExistsSync(path.resolve(p, rest))) return path.resolve(p, rest); + } catch (e) { } + } + if (fs.pathExistsSync(path.resolve(os.homedir(), pathname))) return path.resolve(__dirname, pathname); + if (fs.pathExistsSync(path.resolve(os.homedir(), '.hydro', pathname))) return path.resolve(__dirname, pathname); + if (fs.pathExistsSync(path.resolve(os.homedir(), '.config', 'hydro', pathname))) return path.resolve(__dirname, pathname); + if (doThrow) throw new Error(`File ${pathname} not found`); + return null; +} + export async function retry(func: Function, ...args: any[]): Promise; export async function retry(times: number, func: Function, ...args: any[]): Promise; // eslint-disable-next-line consistent-return