@verdaccio/config
Version:
logger
179 lines (153 loc) • 5.25 kB
text/typescript
import buildDebug from 'debug';
import fs from 'fs';
import _ from 'lodash';
import path from 'path';
import { CHARACTER_ENCODING } from '@verdaccio/core';
import { fileExists, folderExists } from './config-utils';
const CONFIG_FILE = 'config.yaml';
const XDG = 'xdg';
const WIN = 'win';
const WIN32 = 'win32';
// eslint-disable-next-line
const pkgJSON = {
name: 'verdaccio',
};
export type SetupDirectory = {
path: string;
type: string;
};
const debug = buildDebug('verdaccio:config');
/**
* Find and get the first config file that match.
* @return {String} the config file path
*/
function findConfigFile(configPath?: string): string {
if (typeof configPath !== 'undefined') {
return path.resolve(configPath);
}
const configPaths: SetupDirectory[] = getConfigPaths();
debug('%o posible locations found', configPaths.length);
if (_.isEmpty(configPaths)) {
// this should never happens
throw new Error('no configuration files can be processed');
}
// find the first location that already exist
const primaryConf: SetupDirectory | void = _.find(configPaths, (configLocation: SetupDirectory) =>
fileExists(configLocation.path)
);
if (typeof primaryConf !== 'undefined') {
debug('previous location exist already %s', primaryConf?.path);
return primaryConf.path;
}
// @ts-ignore
return createConfigFile(_.head(configPaths)).path;
}
function createConfigFile(configLocation: SetupDirectory): SetupDirectory {
createConfigFolder(configLocation);
const defaultConfig = updateStorageLinks(configLocation, readDefaultConfig());
fs.writeFileSync(configLocation.path, defaultConfig);
return configLocation;
}
export function readDefaultConfig(): Buffer {
const pathDefaultConf: string = path.resolve(__dirname, 'conf/default.yaml');
try {
debug('default configuration file %s', pathDefaultConf);
fs.accessSync(pathDefaultConf, fs.constants.R_OK);
} catch {
throw new TypeError('configuration file does not have enough permissions for reading');
}
// @ts-ignore
return fs.readFileSync(pathDefaultConf, CHARACTER_ENCODING.UTF8);
}
function createConfigFolder(configLocation): void {
fs.mkdirSync(path.dirname(configLocation.path), { recursive: true });
debug(`Creating default config file in %o`, configLocation?.path);
}
function updateStorageLinks(configLocation, defaultConfig): string {
if (configLocation.type !== XDG) {
return defaultConfig;
}
// $XDG_DATA_HOME defines the base directory relative to which user specific data
// files should be stored, If $XDG_DATA_HOME is either not set or empty, a default
// equal to $HOME/.local/share should be used.
let dataDir =
process.env.XDG_DATA_HOME || path.join(process.env.HOME as string, '.local', 'share');
if (folderExists(dataDir)) {
debug(`previous storage located`);
debug(`update storage links to %s`, dataDir);
dataDir = path.resolve(path.join(dataDir, pkgJSON.name, 'storage'));
return defaultConfig.replace(/^storage: .\/storage$/m, `storage: ${dataDir}`);
}
debug(`could not find a previous storage location, skip override`);
return defaultConfig;
}
/**
* Return a list of configuration locations by platform.
* @returns
*/
function getConfigPaths(): SetupDirectory[] {
const listPaths: (SetupDirectory | void)[] = [
getXDGDirectory(),
getWindowsDirectory(),
getRelativeDefaultDirectory(),
getOldDirectory(),
];
return listPaths.reduce(function (acc, currentValue: SetupDirectory | void): SetupDirectory[] {
if (typeof currentValue !== 'undefined') {
debug('directory detected path %s for type %s', currentValue?.path, currentValue.type);
acc.push(currentValue);
}
return acc;
}, [] as SetupDirectory[]);
}
/**
* Get XDG_CONFIG_HOME or HOME location (usually unix)
* @returns
*/
const getXDGDirectory = (): SetupDirectory | void => {
const xDGConfigPath =
process.env.XDG_CONFIG_HOME || (process.env.HOME && path.join(process.env.HOME, '.config'));
if (xDGConfigPath && folderExists(xDGConfigPath)) {
debug('XDGConfig folder path %s', xDGConfigPath);
return {
path: path.join(xDGConfigPath, pkgJSON.name, CONFIG_FILE),
type: XDG,
};
}
};
/**
* Detect windows location, APPDATA
* usually something like C:\User\<Build User>\AppData\Local
* @returns
*/
const getWindowsDirectory = (): SetupDirectory | void => {
if (process.platform === WIN32 && process.env.APPDATA && folderExists(process.env.APPDATA)) {
debug('is windows appdata: %s', process.env.APPDATA);
return {
path: path.resolve(path.join(process.env.APPDATA, pkgJSON.name, CONFIG_FILE)),
type: WIN,
};
}
};
/**
* Return relative directory, this is the default.
* It will cretate config in your {currentLocation/verdaccio/config.yaml}
* @returns
*/
const getRelativeDefaultDirectory = (): SetupDirectory => {
return {
path: path.resolve(path.join('.', pkgJSON.name, CONFIG_FILE)),
type: 'def',
};
};
/**
* This should never happens, consider it DEPRECATED
* @returns
*/
const getOldDirectory = (): SetupDirectory => {
return {
path: path.resolve(path.join('.', CONFIG_FILE)),
type: 'old',
};
};
export { findConfigFile };