Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(maven): Extract util functions from datasource index #9727

Merged
merged 2 commits into from Apr 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
115 changes: 8 additions & 107 deletions lib/datasource/maven/index.ts
@@ -1,5 +1,4 @@
import url from 'url';
import fs from 'fs-extra';
import pAll from 'p-all';
import { XmlDocument } from 'xmldoc';
import { logger } from '../../logger';
Expand All @@ -9,7 +8,14 @@ import * as mavenVersioning from '../../versioning/maven';
import { compare } from '../../versioning/maven/compare';
import type { GetReleasesConfig, Release, ReleaseResult } from '../types';
import { MAVEN_REPO } from './common';
import { downloadHttpProtocol, isHttpResourceExists } from './util';
import type { MavenDependency } from './types';
import {
downloadMavenXml,
getDependencyInfo,
getDependencyParts,
getMavenUrl,
isHttpResourceExists,
} from './util';

export { id } from './common';

Expand All @@ -18,93 +24,6 @@ export const defaultRegistryUrls = [MAVEN_REPO];
export const defaultVersioning = mavenVersioning.id;
export const registryStrategy = 'merge';

function containsPlaceholder(str: string): boolean {
return /\${.*?}/g.test(str);
}

async function downloadFileProtocol(pkgUrl: url.URL): Promise<string | null> {
const pkgPath = pkgUrl.toString().replace('file://', '');
if (!(await fs.exists(pkgPath))) {
return null;
}
return fs.readFile(pkgPath, 'utf8');
}

function getMavenUrl(
dependency: MavenDependency,
repoUrl: string,
path: string
): url.URL | null {
return new url.URL(`${dependency.dependencyUrl}/${path}`, repoUrl);
}

interface MavenXml {
authorization?: boolean;
xml?: XmlDocument;
}

async function downloadMavenXml(
pkgUrl: url.URL | null
): Promise<MavenXml | null> {
/* istanbul ignore if */
if (!pkgUrl) {
return {};
}
let rawContent: string;
let authorization: boolean;
switch (pkgUrl.protocol) {
case 'file:':
rawContent = await downloadFileProtocol(pkgUrl);
break;
case 'http:':
case 'https:':
({ authorization, body: rawContent } = await downloadHttpProtocol(
pkgUrl
));
break;
case 's3:':
logger.debug('Skipping s3 dependency');
return {};
default:
logger.debug({ url: pkgUrl.toString() }, `Unsupported Maven protocol`);
return {};
}

if (!rawContent) {
logger.debug(`Content is not found for Maven url: ${pkgUrl.toString()}`);
return {};
}

return { authorization, xml: new XmlDocument(rawContent) };
}

async function getDependencyInfo(
dependency: MavenDependency,
repoUrl: string,
version: string
): Promise<Partial<ReleaseResult>> {
const result: Partial<ReleaseResult> = {};
const path = `${version}/${dependency.name}-${version}.pom`;

const pomUrl = getMavenUrl(dependency, repoUrl, path);
const { xml: pomContent } = await downloadMavenXml(pomUrl);
if (!pomContent) {
return result;
}

const homepage = pomContent.valueWithPath('url');
if (homepage && !containsPlaceholder(homepage)) {
result.homepage = homepage;
}

const sourceUrl = pomContent.valueWithPath('scm.url');
if (sourceUrl && !containsPlaceholder(sourceUrl)) {
result.sourceUrl = sourceUrl.replace(/^scm:/, '');
}

return result;
}

function isStableVersion(x: string): boolean {
return mavenVersion.isStable(x);
}
Expand All @@ -121,24 +40,6 @@ function getLatestStableVersion(releases: Release[]): string | null {
return null;
}

interface MavenDependency {
display: string;
group?: string;
name?: string;
dependencyUrl: string;
}

function getDependencyParts(lookupName: string): MavenDependency {
const [group, name] = lookupName.split(':');
const dependencyUrl = `${group.replace(/\./g, '/')}/${name}`;
return {
display: lookupName,
group,
name,
dependencyUrl,
};
}

function extractVersions(metadata: XmlDocument): string[] {
const versions = metadata.descendantWithPath('versioning.versions');
const elements = versions?.childrenNamed('version');
Expand Down
13 changes: 13 additions & 0 deletions lib/datasource/maven/types.ts
@@ -0,0 +1,13 @@
import type { XmlDocument } from 'xmldoc';

export interface MavenDependency {
display: string;
group?: string;
name?: string;
dependencyUrl: string;
}

export interface MavenXml {
authorization?: boolean;
xml?: XmlDocument;
}
97 changes: 97 additions & 0 deletions lib/datasource/maven/util.ts
@@ -1,10 +1,14 @@
import url from 'url';
import fs from 'fs-extra';
import { XmlDocument } from 'xmldoc';
import { HOST_DISABLED } from '../../constants/error-messages';
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/errors/external-host-error';
import { Http, HttpResponse } from '../../util/http';

import type { ReleaseResult } from '../types';
import { MAVEN_REPO, id } from './common';
import type { MavenDependency, MavenXml } from './types';

const http: Record<string, Http> = {};

Expand Down Expand Up @@ -96,6 +100,14 @@ export async function downloadHttpProtocol(
}
}

async function downloadFileProtocol(pkgUrl: url.URL): Promise<string | null> {
const pkgPath = pkgUrl.toString().replace('file://', '');
if (!(await fs.exists(pkgPath))) {
return null;
}
return fs.readFile(pkgPath, 'utf8');
}

export async function isHttpResourceExists(
pkgUrl: url.URL | string,
hostType = id
Expand All @@ -119,3 +131,88 @@ export async function isHttpResourceExists(
return null;
}
}

function containsPlaceholder(str: string): boolean {
return /\${.*?}/g.test(str);
}

export function getMavenUrl(
dependency: MavenDependency,
repoUrl: string,
path: string
): url.URL | null {
return new url.URL(`${dependency.dependencyUrl}/${path}`, repoUrl);
}

export async function downloadMavenXml(
pkgUrl: url.URL | null
): Promise<MavenXml | null> {
/* istanbul ignore if */
if (!pkgUrl) {
return {};
}
let rawContent: string;
let authorization: boolean;
switch (pkgUrl.protocol) {
case 'file:':
rawContent = await downloadFileProtocol(pkgUrl);
break;
case 'http:':
case 'https:':
({ authorization, body: rawContent } = await downloadHttpProtocol(
pkgUrl
));
break;
case 's3:':
logger.debug('Skipping s3 dependency');
return {};
default:
logger.debug({ url: pkgUrl.toString() }, `Unsupported Maven protocol`);
return {};
}

if (!rawContent) {
logger.debug(`Content is not found for Maven url: ${pkgUrl.toString()}`);
return {};
}

return { authorization, xml: new XmlDocument(rawContent) };
}

export async function getDependencyInfo(
dependency: MavenDependency,
repoUrl: string,
version: string
): Promise<Partial<ReleaseResult>> {
const result: Partial<ReleaseResult> = {};
const path = `${version}/${dependency.name}-${version}.pom`;

const pomUrl = getMavenUrl(dependency, repoUrl, path);
const { xml: pomContent } = await downloadMavenXml(pomUrl);
if (!pomContent) {
return result;
}

const homepage = pomContent.valueWithPath('url');
if (homepage && !containsPlaceholder(homepage)) {
result.homepage = homepage;
}

const sourceUrl = pomContent.valueWithPath('scm.url');
if (sourceUrl && !containsPlaceholder(sourceUrl)) {
result.sourceUrl = sourceUrl.replace(/^scm:/, '');
}

return result;
}

export function getDependencyParts(lookupName: string): MavenDependency {
const [group, name] = lookupName.split(':');
const dependencyUrl = `${group.replace(/\./g, '/')}/${name}`;
return {
display: lookupName,
group,
name,
dependencyUrl,
};
}