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

(ts) Runtime de-globalling (step 3) #6758

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3afe810
modernize dev-shell
Nov 6, 2020
a908f48
tweaks
Nov 6, 2020
a093036
law of Demeter
Nov 6, 2020
193c1a7
remove storageService
Nov 12, 2020
4dad548
cleanups
Nov 12, 2020
09fd6b6
surgically remove static (global) runtime object
Nov 17, 2020
32e20ae
clean ups
Nov 18, 2020
1987f50
big runtime usage refactor
Nov 20, 2020
16a0961
cleanups
Nov 20, 2020
ab675d4
cleanups
Nov 20, 2020
328ac92
serious degloballing
Nov 26, 2020
4978ea0
repairs after unpleasant rebase
Dec 8, 2020
1900fe2
remove debugger statement
Dec 8, 2020
00505f1
sleuthing test failures
Dec 8, 2020
6a9f14d
Don't call idle immediately after closing StorageEndpoint
jblebrun Dec 8, 2020
9482eef
Refactors several classes to use injected StorageKeyManager instances…
csilvestrini Dec 8, 2020
7f2ea17
rename EntitySpecTest.kt to javatests/arcs/sdk/GeneratedEntityTest.kt
galganif Dec 8, 2020
7f5e9f6
Fix typo
csilvestrini Dec 8, 2020
2aff690
Tests for BaseHandle.kt
Dec 8, 2020
bdfdce5
Add missing strict deps for type aliases.
arcs-c3po Dec 8, 2020
b4bb177
rename ReferenceSpecTest.kt to javatests/arcs/sdk/GeneratedReferenceT…
galganif Dec 8, 2020
7ebf1f0
add support for inline schema field inside ordered list in fromLitera…
mariakleiner Dec 8, 2020
b81fbd2
Rename EntityHandleManager to HandleManagerImpl to reflect the actual…
yuangu-google Dec 8, 2020
d5242e8
Add more unit tests for DirectStore.
yuangu-google Dec 8, 2020
f1092db
Caching RawEntity hashCode to improve overhead.
alxmrs Dec 9, 2020
408388c
Add error message for CollectionHandle init (#6690)
SHeimlich Dec 9, 2020
0557c0b
Refactor mock helper methods from the Handle tests into testutil/
Dec 9, 2020
be944aa
Remove unused methods from EntityHandleManager and StorageProxy.
Dec 9, 2020
0e2bf53
Create showcase & showcase test for queries
Dec 9, 2020
c9f4166
Disable import ordering in ktlint (#6749)
csilvestrini Dec 10, 2020
75c791e
remove dead code
Dec 10, 2020
4b6bc47
Merge branch 'master' of github.com:PolymerLabs/arcs into dec-dev-she…
Dec 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 76 additions & 79 deletions shells/dev-shell/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,25 @@
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/

import './file-pane.js';
import './output-pane.js';
import '../configuration/whitelisted.js';
import '../lib/platform/loglevel-web.js';

import {Runtime} from '../../build/runtime/runtime.js';
import {RamDiskStorageDriverProvider} from '../../build/runtime/storage/drivers/ramdisk.js';
import {SimpleVolatileMemoryProvider} from '../../build/runtime/storage/drivers/volatile.js';
import {DirectStorageEndpointManager} from '../../build/runtime/storage/direct-storage-endpoint-manager.js';
import {Loader} from '../../build/platform/loader.js';
import {Arc} from '../../build/runtime/arc.js';
import {IdGenerator} from '../../build/runtime/id.js';
import {pecIndustry} from '../../build/platform/pec-industry-web.js';
import {Runtime} from '../../build/runtime/runtime.js';
import {RecipeResolver} from '../../build/runtime/recipe-resolver.js';
import {devtoolsArcInspectorFactory} from '../../build/devtools-connector/devtools-arc-inspector.js';
import {SlotComposer} from '../../build/runtime/slot-composer.js';
import {SlotObserver} from '../lib/xen-renderer.js';

import '../../build/services/random-service.js';

// how to reach arcs root from our URL/CWD
const root = '../..';
const urlMap = Runtime.mapFromRootPath(root);

// extra params for created arcs
const extraArcParams = {
inspectorFactory: devtoolsArcInspectorFactory
};

// import DOM node references
const {
Expand All @@ -41,21 +38,19 @@ const {
helpButton
} = window;

let memoryProvider;
init();

function init() {
memoryProvider = new SimpleVolatileMemoryProvider();
RamDiskStorageDriverProvider.register(memoryProvider);

// prepare ui
filePane.init(execute, toggleFilesButton, exportFilesButton);
executeButton.addEventListener('click', execute);
helpButton.addEventListener('click', showHelp);
popupContainer.addEventListener('click', () => popupContainer.style.display = 'none');

// scan window parameters
const params = new URLSearchParams(window.location.search);
// set logLevel
window.logLevel = (params.get('log') !== null) ? 1 : 0;

// seed manifest as requested
const manifestParam = params.get('m') || params.get('manifest');
if (manifestParam) {
filePane.seedManifest(manifestParam.split(';').map(m => `import '${m}'`));
Expand All @@ -76,101 +71,103 @@ recipe
h0: copy DataStore
P
data: reads h0`;

const exampleParticle = `\
defineParticle(({SimpleParticle, html, log}) => {
return class extends SimpleParticle {
get template() {
log(\`Add '?log' to the URL to enable particle logging\`);
return html\`<span>{{num}}</span> : <span>{{str}}</span>\`;
return \`<div style="padding: 8px;"><span>{{num}}</span> : <span>{{str}}</span></div>\`;
}
render({data}) {
return data ? {num: data.num, str: data.txt} : {};
}
};
});`;

filePane.seedExample(exampleManifest, exampleParticle);
}
}

function execute() {
wrappedExecute().catch(e => outputPane.showError('Unhandled exception', e.stack));
wrappedExecute().catch(e => {
outputPane.showError('Unhandled exception', e.stack);
console.error(e);
});
}

async function wrappedExecute() {
// clear ui
document.dispatchEvent(new Event('clear-arcs-explorer'));
outputPane.reset();

const loader = new Loader(urlMap, filePane.getFileMap());
// TODO(sjmiles): should be a static method
loader.flushCaches();

const pecFactory = pecIndustry(loader);

let manifest;
// establish a runtime using custom parameters
const runtime = new Runtime({rootPath: root, staticMap: filePane.getFileMap()});
runtime.loader.flushCaches();
// attempt to parse the context manifest
try {
const options = {loader, fileName: './manifest', throwImportErrors: true, memoryProvider};
manifest = await Runtime.parseManifest(filePane.getManifest(), options);
runtime.context = await runtime.parse(filePane.getManifest(), {fileName: './manifest', throwImportErrors: true});
} catch (e) {
outputPane.showError('Error in Manifest.parse', e);
return;
}

if (manifest.allRecipes.length == 0) {
// check for existence of recipes
if (runtime.context.allRecipes.length == 0) {
outputPane.showError('No recipes found in Manifest.parse');
}

// instantiate an arc for each recipe in context
let arcIndex = 1;
for (const recipe of manifest.allRecipes) {
const id = IdGenerator.newSession().newArcId('arc' + arcIndex++);
const arcPanel = outputPane.addArcPanel(id);
for (const recipe of runtime.context.allRecipes) {
createRecipeArc(recipe, runtime, arcIndex++);
}
}

const errors = new Map();
if (!recipe.normalize({errors})) {
arcPanel.showError('Error in recipe.normalize', [...errors.values()].join('\n'));
continue;
}
async function createRecipeArc(recipe, runtime, index) {
// ask runtime to assemble arc parameter boilerplate (argument is the arc name)
const params = runtime.buildArcParams(`arc${index}`);
// construct the arc
const arc = new Arc({...params, extraArcParams});
// establish a UI Surface
const arcPanel = outputPane.addArcPanel(params.id);
// attach a renderer (SlotObserver and a DOM node) to the composer
params.slotComposer.observeSlots(new SlotObserver(arcPanel.shadowRoot));
// attach arc to bespoke shell ui
arcPanel.attachArc(arc);
arc.arcPanel = arcPanel;
try {
normalizeRecipe(arc, recipe);
const resolvedRecipe = await resolveRecipe(arc, recipe);
await instantiateRecipe(arc, resolvedRecipe);
} catch (x) {
arcPanel.showError('recipe error', x);
return;
}
// display description
await arcPanel.arcInstantiated(await Runtime.getArcDescription(arc));
}

const slotComposer = new SlotComposer();
slotComposer.observeSlots(new SlotObserver(arcPanel.shadowRoot));

const arc = new Arc({
id,
context: manifest,
pecFactories: [pecFactory],
slotComposer,
loader,
storageManager: new DirectStorageEndpointManager(),
inspectorFactory: devtoolsArcInspectorFactory
});
arcPanel.attachArc(arc);

recipe.normalize();

let resolvedRecipe = null;
if (recipe.isResolved()) {
resolvedRecipe = recipe;
} else {
const resolver = new RecipeResolver(arc);
const options = {errors: new Map()};
resolvedRecipe = await resolver.resolve(recipe, options);
if (!resolvedRecipe) {
arcPanel.showError('Error in RecipeResolver', `${
[...options.errors.entries()].join('\n')
}.\n${recipe.toString()}`);
continue;
}
}
function normalizeRecipe(arc, recipe) {
const errors = new Map();
if (!recipe.normalize({errors})) {
throw `Error in recipe.normalize: ${[...errors.values()].join('\n')}`;
}
}

try {
await arc.instantiate(resolvedRecipe);
} catch (e) {
arcPanel.showError('Error in arc.instantiate', e);
continue;
async function resolveRecipe(arc, recipe) {
let resolved = recipe;
if (!recipe.isResolved()) {
const errors = new Map();
const resolver = new RecipeResolver(arc);
resolved = await resolver.resolve(recipe, {errors});
if (!resolved) {
throw `Error in RecipeResolver: ${[...errors.entries()].join('\n')}.\n${recipe.toString()}`;
}
const description = await Runtime.getArcDescription(arc);
await arcPanel.arcInstantiated(description);
}
return resolved;
}

async function instantiateRecipe(arc, recipe) {
try {
await arc.instantiate(recipe);
} catch (e) {
throw `Error in arc.instantiate: ${e}`;
}
}

Expand Down
61 changes: 26 additions & 35 deletions shells/tests/arcs/ts/runtime/arc-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,9 @@ import {handleForStoreInfo, CollectionEntityType} from '../../../../../build/run
import '../../../../lib/arcs-ui/dist/install-ui-classes.js';

describe('Arc', () => {
afterEach(() => {
Runtime.resetDrivers();
});

it('deserializing a serialized arc with a Transformation produces that arc', async () => {
const loader = new Loader();
const manifest = await Manifest.parse(`
const runtime = new Runtime();
runtime.context = await runtime.parse(`
import 'src/runtime/tests/artifacts/Common/Multiplexer.manifest'
import 'src/runtime/tests/artifacts/test-particles.manifest'

Expand All @@ -42,17 +38,15 @@ describe('Arc', () => {
annotation: consumes slot0
list: reads handle0

`, {loader, fileName: ''});
`);

const recipe = manifest.recipes[0];
const slotComposer = new SlotComposer();
const id = Id.fromString('test2');
const storageKey = new VolatileStorageKey(id, '');
const storageManager = new DirectStorageEndpointManager();
const arc = new Arc({id, storageKey, context: manifest, slotComposer, loader: new Loader(), storageManager});
const params = runtime.buildArcParams('test2');
const arc = new Arc(params);

const barType = manifest.findTypeByName('Bar') as EntityType;
const barType = runtime.context.findTypeByName('Bar') as EntityType;
let store = await arc.createStore(barType.collectionOf(), undefined, 'test:1');

const recipe = runtime.context.recipes[0];
recipe.handles[0].mapToStorage(store);

assert(recipe.normalize());
Expand All @@ -64,7 +58,8 @@ describe('Arc', () => {
const serialization = await arc.serialize();
arc.dispose();

const newArc = await Arc.deserialize({serialization, loader, slotComposer, fileName: './manifest.manifest', context: manifest, storageManager});
const {loader, context, slotComposer, storageManager, driverFactory} = params;
const newArc = await Arc.deserialize({serialization, loader, slotComposer, fileName: './manifest.manifest', context, storageManager, driverFactory});
await newArc.idle;
store = newArc.findStoreById(store.id) as StoreInfo<CollectionEntityType>;
const handle = await handleForStoreInfo(store, newArc);
Expand Down Expand Up @@ -123,7 +118,6 @@ describe('Arc', () => {
current = next;
}

const slotComposer = new SlotComposer();
const loader = new Loader(null, {
...sources,
'Z.js': `defineParticle(({UiParticle}) => {
Expand All @@ -132,7 +126,8 @@ describe('Arc', () => {
};
});`,
});
const context = await Manifest.parse(`
const runtime = new Runtime({loader});
runtime.context = await runtime.parse(`
particle A in 'A.js'
root: consumes Slot

Expand All @@ -141,20 +136,18 @@ describe('Arc', () => {
A
root: consumes root
`);
const id = IdGenerator.newSession().newArcId('arcid');
const storageManager = new DirectStorageEndpointManager();
const arc = new Arc({id, loader, slotComposer, context, storageManager});
const opts = runtime.buildArcParams('arcid');
const arc = new Arc(opts);

const [recipe] = arc.context.recipes;
recipe.normalize();
await arc.instantiate(recipe);
});

it('handles serialization/deserialization of empty arcs handles', async () => {
const id = ArcId.newForTest('test');
const loader = new Loader();

const manifest = await Manifest.parse(`
//const id = ArcId.newForTest('test');
const runtime = new Runtime();
runtime.context = await runtime.parse(`
schema FavoriteFood
food: Text

Expand All @@ -167,20 +160,20 @@ describe('Arc', () => {
foods: create #favoriteFoods
FavoriteFoodPicker
foods: foods
`, {loader, fileName: process.cwd() + '/input.manifest'});
`);

const storageKey = new VolatileStorageKey(id, '');
const storageManager = new DirectStorageEndpointManager();
const arc = new Arc({id, storageKey, loader: new Loader(), context: manifest, storageManager});
const opts = runtime.buildArcParams('test');
//opts.id = id;
const arc = new Arc(opts);
assert.isNotNull(arc);

const favoriteFoodClass = Entity.createEntityClass(manifest.findSchemaByName('FavoriteFood'), null);
const favoriteFoodClass = Entity.createEntityClass(runtime.context.findSchemaByName('FavoriteFood'), null);
assert.isNotNull(favoriteFoodClass);

const recipe = manifest.recipes[0];
const recipe = runtime.context.recipes[0];
assert.isNotNull(recipe);

const favoriteFoodType = manifest.findTypeByName('FavoriteFood');
const favoriteFoodType = runtime.context.findTypeByName('FavoriteFood');
assert.isNotNull(favoriteFoodType, 'FavoriteFood type is found');

const options = {errors: new Map()};
Expand All @@ -190,10 +183,8 @@ describe('Arc', () => {
await arc.instantiate(recipe);

const serialization = await arc.serialize();

const slotComposer = new SlotComposer();

const newArc = await Arc.deserialize({serialization, loader, slotComposer, context: manifest, fileName: 'foo.manifest', storageManager});
const {loader, slotComposer, context, storageManager, driverFactory} = opts;
const newArc = await Arc.deserialize({serialization, loader, slotComposer, context, fileName: 'foo.manifest', storageManager, driverFactory});
assert.strictEqual(newArc.stores.length, 1);
assert.strictEqual(newArc.activeRecipe.toString(), `@active\n${arc.activeRecipe.toString()}`);
assert.strictEqual(newArc.id.idTreeAsString(), 'test');
Expand Down
6 changes: 3 additions & 3 deletions shells/tests/arcs/ts/runtime/hotreload-integration-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import '../../../../lib/arcs-ui/dist/install-ui-classes.js';
describe('Hot Code Reload for JS Particle', async () => {
it('updates model and template', async () =>{
const context = await Manifest.parse(`
particle A in 'A.js'
particle A in './A.js'
root: consumes Slot

recipe
slot0: slot 'rootslotid-root'
A
root: consumes slot0`);
const loader = new Loader(null, {
'A.js': `defineParticle(({UiParticle}) => {
'./A.js': `defineParticle(({UiParticle}) => {
return class extends UiParticle {
get template() { return 'Hello <span>{{name}}</span>, old age: <span>{{age}}</span>'; }

Expand All @@ -49,7 +49,7 @@ describe('Hot Code Reload for JS Particle', async () => {
//assert.deepStrictEqual(slotConsumer.getRendering().model, {name: 'Jack', age: '10'});
//assert.deepStrictEqual(slotConsumer._content.template, `Hello <span>{{name}}</span>, old age: <span>{{age}}</span>`);

loader.staticMap['A.js'] = `defineParticle(({UiParticle}) => {
loader.staticMap['./A.js'] = `defineParticle(({UiParticle}) => {
return class extends UiParticle {
get template() { return 'Hello <span>{{name}}</span>, new age: <span>{{age}}</span>'; }

Expand Down
2 changes: 0 additions & 2 deletions shells/tests/arcs/ts/runtime/multiplexer-integration-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ describe('Multiplexer', () => {
const entity = Entity.identify(entityClass, '4', null);
await postsHandle2.add(entity);
await arc.idle;

Runtime.resetDrivers();
});

// TODO(sjmiles): probably should be in particles/tests/* because of Multiplexer.js
Expand Down
Loading