mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-31 09:41:46 +00:00
2e9e479912
* fix(manager/pixi): support optional channel options * Review feedback Co-authored-by: Michael Kriese <michael.kriese@gmx.de> * fix(pixi): import number coercion utility --------- Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
179 lines
4.3 KiB
TypeScript
179 lines
4.3 KiB
TypeScript
import { isString } from '@sindresorhus/is';
|
|
import { z } from 'zod/v4';
|
|
|
|
import { logger } from '../../../logger/index.ts';
|
|
import { coerceArray } from '../../../util/array.ts';
|
|
import { getSiblingFileName, localPathExists } from '../../../util/fs/index.ts';
|
|
import { coerceNumber } from '../../../util/number.ts';
|
|
import { Result } from '../../../util/result.ts';
|
|
import {
|
|
ensureTrailingSlash,
|
|
isHttpUrl,
|
|
joinUrlParts,
|
|
} from '../../../util/url.ts';
|
|
import { defaultRegistryUrl as defaultCondaRegistryApi } from '../../datasource/conda/common.ts';
|
|
import type { RegistryStrategy } from '../../datasource/index.ts';
|
|
import type { PackageFileContent } from '../types.ts';
|
|
import {
|
|
type Channels,
|
|
type PixiConfig,
|
|
PixiFile,
|
|
type PixiPackageDependency,
|
|
PixiPyProject,
|
|
} from './schema.ts';
|
|
|
|
export function getUserPixiConfig(
|
|
content: string,
|
|
packageFile: string,
|
|
): null | PixiConfig {
|
|
if (
|
|
packageFile === 'pyproject.toml' ||
|
|
packageFile.endsWith('/pyproject.toml')
|
|
) {
|
|
const { val, err } = Result.parse(content, PixiPyProject).unwrap();
|
|
if (err) {
|
|
logger.debug({ packageFile, err }, `error parsing ${packageFile}`);
|
|
return null;
|
|
}
|
|
|
|
return val.tool?.pixi ?? null;
|
|
}
|
|
|
|
if (packageFile === 'pixi.toml' || packageFile.endsWith('/pixi.toml')) {
|
|
const { val, err } = Result.parse(content, PixiFile).unwrap();
|
|
if (err) {
|
|
logger.debug({ packageFile, err }, `error parsing ${packageFile}`);
|
|
return null;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
const { val, err } = Result.parse(
|
|
content,
|
|
z.union([PixiFile, PixiPyProject.transform((p) => p.tool?.pixi)]),
|
|
).unwrap();
|
|
|
|
if (err) {
|
|
logger.debug({ packageFile, err }, `error parsing ${packageFile}`);
|
|
return null;
|
|
}
|
|
return val ?? null;
|
|
}
|
|
|
|
export async function extractPackageFile(
|
|
content: string,
|
|
packageFile: string,
|
|
): Promise<PackageFileContent | null> {
|
|
logger.trace(`pixi.extractPackageFile(${packageFile})`);
|
|
|
|
const val = getUserPixiConfig(content, packageFile);
|
|
if (!val) {
|
|
return null;
|
|
}
|
|
|
|
const lockfileName = getSiblingFileName(packageFile, 'pixi.lock');
|
|
const lockFiles: string[] = [];
|
|
if (await localPathExists(lockfileName)) {
|
|
lockFiles.push(lockfileName);
|
|
}
|
|
|
|
const project = val.project;
|
|
|
|
const channelPriority = project['channel-priority'];
|
|
|
|
let registryStrategy: RegistryStrategy | undefined;
|
|
|
|
if (channelPriority === 'disabled') {
|
|
registryStrategy = 'merge';
|
|
}
|
|
|
|
// resolve channels and build registry urls for each channel with order
|
|
const conda: PixiPackageDependency[] = [];
|
|
|
|
for (const item of val.conda) {
|
|
conda.push(
|
|
addRegistryUrls({
|
|
...item,
|
|
channels: project.channels,
|
|
registryStrategy,
|
|
}),
|
|
);
|
|
}
|
|
|
|
for (const item of val.feature.conda) {
|
|
conda.push(
|
|
addRegistryUrls({
|
|
...item,
|
|
registryStrategy,
|
|
channels: [...coerceArray(item.channels), ...project.channels],
|
|
}),
|
|
);
|
|
}
|
|
|
|
return {
|
|
lockFiles,
|
|
deps: [conda, val.pypi, val.feature.pypi].flat(),
|
|
};
|
|
}
|
|
|
|
function addRegistryUrls(item: PixiPackageDependency): PixiPackageDependency {
|
|
const channels = orderChannels(item.channels);
|
|
|
|
if (item.channel) {
|
|
return {
|
|
...item,
|
|
channels,
|
|
registryUrls: [channelToRegistryUrl(item.channel)],
|
|
};
|
|
}
|
|
|
|
if (channels.length === 0) {
|
|
return {
|
|
...item,
|
|
channels,
|
|
skipStage: 'extract',
|
|
skipReason: 'unknown-registry',
|
|
};
|
|
}
|
|
|
|
const registryUrls: string[] = [];
|
|
for (const channel of channels) {
|
|
registryUrls.push(channelToRegistryUrl(channel));
|
|
}
|
|
|
|
return {
|
|
...item,
|
|
channels,
|
|
registryUrls,
|
|
};
|
|
}
|
|
|
|
function channelToRegistryUrl(channel: string): string {
|
|
if (isHttpUrl(channel)) {
|
|
return ensureTrailingSlash(channel);
|
|
}
|
|
|
|
return ensureTrailingSlash(joinUrlParts(defaultCondaRegistryApi, channel));
|
|
}
|
|
|
|
function orderChannels(channels: Channels = []): string[] {
|
|
return channels
|
|
.map((channel, index) => {
|
|
if (isString(channel)) {
|
|
return { channel, priority: 0, index };
|
|
}
|
|
|
|
return { ...channel, priority: coerceNumber(channel.priority), index };
|
|
})
|
|
.toSorted((a, b) => {
|
|
// first based on priority then based on index
|
|
if (a.priority !== b.priority) {
|
|
return b.priority - a.priority;
|
|
}
|
|
|
|
return a.index - b.index;
|
|
})
|
|
.map((c) => c.channel);
|
|
}
|