Skip to content

Commit

Permalink
Fix regression in loading old index.yaml (#684)
Browse files Browse the repository at this point in the history
* Add regression test.

* Fix regression in loading old index.yaml, reported as microsoft/vcpkg-ce-catalog#33
  • Loading branch information
BillyONeal authored Aug 31, 2022
1 parent a55d274 commit a9fce49
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 44 deletions.
6 changes: 3 additions & 3 deletions ce/ce/registries/artifact-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { IdentityKey, IndexSchema, SemverKey, StringKey } from './indexer';


export class ArtifactIndex extends IndexSchema<MetadataFile, ArtifactIndex> {
id = new IdentityKey(this, (i) => i.id);
version = new SemverKey(this, (i) => new SemVer(i.version));
summary = new StringKey(this, (i) => i.summary);
id = new IdentityKey(this, (i) => i.id, ['IdentityKey/id', 'IdentityKey/info.id']);
version = new SemverKey(this, (i) => new SemVer(i.version), ['SemverKey/version', 'SemverKey/info.version']);
summary = new StringKey(this, (i) => i.summary, ['StringKey/summary', 'StringKey/info.summary']);
}
58 changes: 26 additions & 32 deletions ce/ce/registries/indexer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { strict } from 'assert';
import { Range, SemVer } from 'semver';
import BTree from 'sorted-btree';
import { i } from '../i18n';
import { isIterable } from '../util/checks';
import { intersect } from '../util/intersect';
import { entries, keys, ManyMap, Record } from '../util/linq';
Expand Down Expand Up @@ -89,26 +89,6 @@ export class Index<TGraph extends Object, TIndexSchema extends IndexSchema<TGrap
}
}

/** deconstructs a function declaration so that we can figure out the most logical path */
function deconstruct(accessor: string) {
const params = /\(?([^(=)]+)\)?=>/g.exec(accessor);
let names = ['i'];
if (params) {
names = params[1].split(',').map(each => each.trim());
}

// find the part that looks for the value
let path = names.slice(1);
const expression = /=>.*i\.(.*?)(;| |\n|$)/g.exec(accessor);
if (expression) {
path = expression[1].replace(/\[.*?\]/g, '').replace(/[^\w.]/g, '').replace(/\.+/g, '.').split('.');
}

strict.ok(path.length, 'Unable to deconstruct the path to the element');

return path;
}

/**
* A Key is a means to creating a searchable, sortable index
*/
Expand All @@ -124,7 +104,8 @@ abstract class Key<TGraph extends Object, TKey extends HasToString, TIndexSchema
protected values = new BTree<TKey, Set<number>>(undefined, this.compare);
protected words = new BTree<string, Set<number>>();
protected indexSchema: TIndexSchema;
protected path: Array<string>;
readonly identity: string;
readonly alternativeIdentities: Array<string>;

/** attaches a nested key in the index. */
with<TNestedKey extends Record<string, Key<TGraph, any, TIndexSchema>>>(nestedKey: TNestedKey): Key<TGraph, TKey, TIndexSchema> & TNestedKey {
Expand All @@ -134,11 +115,6 @@ abstract class Key<TGraph extends Object, TKey extends HasToString, TIndexSchema
return intersect(this, nestedKey);
}

/** returns the textual 'identity' of this key */
get identity() {
return `${this.constructor.name}/${this.path.join('.')}`;
}

/** persists the key to an object graph */
serialize() {
const result = <any>{
Expand Down Expand Up @@ -234,9 +210,16 @@ abstract class Key<TGraph extends Object, TKey extends HasToString, TIndexSchema
}

/** construct a Key */
constructor(indexSchema: IndexSchema<TGraph, TIndexSchema>, public accessor: (value: TGraph, ...args: Array<any>) => TKey | undefined | Array<TKey> | Iterable<TKey>) {
this.path = deconstruct(accessor.toString());
constructor(indexSchema: IndexSchema<TGraph, TIndexSchema>, public accessor: (value: TGraph, ...args: Array<any>) => TKey | undefined | Array<TKey> | Iterable<TKey>, protoIdentity: Array<string> | string) {
this.indexSchema = <TIndexSchema><unknown>indexSchema;
if (typeof protoIdentity === 'string') {
this.identity = protoIdentity;
this.alternativeIdentities = [protoIdentity];
} else {
this.identity = protoIdentity[0];
this.alternativeIdentities = protoIdentity;
}

this.indexSchema.mapOfKeyObjects.set(this.identity, this);
}

Expand Down Expand Up @@ -519,7 +502,7 @@ export abstract class IndexSchema<TGraph, TSelf extends IndexSchema<TGraph, any>
selectedElements?: Set<number>;

/**
* filter the selected elements down to an intersetction of the {selectedelements} ∩ {idsToKeep}
* filter the selected elements down to an intersection of the {selectedelements} ∩ {idsToKeep}
*
* @param idsToKeep the element ids to intersect with.
*/
Expand Down Expand Up @@ -557,7 +540,19 @@ export abstract class IndexSchema<TGraph, TSelf extends IndexSchema<TGraph, any>
*/
deserialize(content: any) {
for (const [key, impl] of this.mapOfKeyObjects.entries()) {
impl.deserialize(content[key]);
let anyMatches = false;
for (const maybeIdentity of impl.alternativeIdentities) {
const maybeKey = content[maybeIdentity];
if (maybeKey) {
impl.deserialize(maybeKey);
anyMatches = true;
break;
}
}

if (!anyMatches) {
throw new Error(i`Failed to deserialize index ${key}`);
}
}
}

Expand All @@ -572,4 +567,3 @@ export abstract class IndexSchema<TGraph, TSelf extends IndexSchema<TGraph, any>
constructor(public index: Index<TGraph, TSelf>) {
}
}

13 changes: 4 additions & 9 deletions ce/test/core/index-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


import { Index, IndexSchema, SemverKey, StringKey } from '@microsoft/vcpkg-ce/dist/registries/indexer';
import { keys, Record } from '@microsoft/vcpkg-ce/dist/util/linq';
import { Record } from '@microsoft/vcpkg-ce/dist/util/linq';
import { describe, it } from 'mocha';
import { SemVer } from 'semver';
import { SuiteLocal } from './SuiteLocal';
Expand All @@ -22,16 +22,11 @@ interface TestData {

/** An Index implementation for TestData */
class MyIndex extends IndexSchema<TestData, MyIndex> {
id = new StringKey(this, (i) => i.id);
version = new SemverKey(this, (i) => new SemVer(i.version));
description = new StringKey(this, (i) => i.description);

contacts = new StringKey(this, (i) => keys(i.contacts)).with({
email: new StringKey(this, (i, index: string) => i.contacts?.[index]?.email)
});
id = new StringKey(this, (i) => i.id, 'StringKey/info.id');
version = new SemverKey(this, (i) => new SemVer(i.version), 'SemverKey/info.version');
description = new StringKey(this, (i) => i.description, 'StringKey/info.description');
}


// sample test using decorators.
describe('Index Tests', () => {
it('Create index from some data', () => {
Expand Down
30 changes: 30 additions & 0 deletions ce/test/core/regression-tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { Session } from '@microsoft/vcpkg-ce/dist/session';
import { strict } from 'assert';
import { SuiteLocal } from './SuiteLocal';

async function testRegistry(session: Session, sha: string) {
const uri = `https://github.com/microsoft/vcpkg-ce-catalog/archive/${sha}.zip`;
const loaded = await session.loadRegistry(uri);
strict.ok(loaded);
await loaded.load();
}

describe('Regressions', () => {
const local = new SuiteLocal();

after(local.after.bind(local));

// These 2 registry loads ensure that we can process both the 'old' and 'new' index.yaml files
// regression discovered in https://github.com/microsoft/vcpkg-ce-catalog/pull/33

it('Loads 2ffbc04d6856a1d03c5de0ab94404f90636f7855 registry', async () => {
await testRegistry(local.session, '2ffbc04d6856a1d03c5de0ab94404f90636f7855');
});

it('Loads d471612be63b2fb506ab5f47122da460f5aa4d30 registry', async () => {
await testRegistry(local.session, 'd471612be63b2fb506ab5f47122da460f5aa4d30');
});
});

0 comments on commit a9fce49

Please sign in to comment.