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

Add class to work with a Universe of contracts #78

Merged
merged 2 commits into from
Jan 10, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from './types/types';
import Contract from './contract';
import Blueprint from './blueprint';
import Universe from './universe';
import { buildTemplate } from './partials';
import { parse as parseCardinality } from './cardinality';

Expand All @@ -25,6 +26,7 @@ export {
BlueprintObject,
Contract,
Blueprint,
Universe,
buildTemplate,
parseCardinality,
};
Expand Down
99 changes: 99 additions & 0 deletions lib/universe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import path from 'path';
import { promises as fs } from 'fs';
import type { Stats } from 'fs';

import Contract from './contract';
import { UNIVERSE } from './types/types';

/**
* @summary recursively find all files under the directory that match the given filter
* @function
* @memberof module:universe
*
* @param dir - base directory to start the search
* @param filter - filtering function to indicate that a file should be selected
*/
async function findFiles(
dir: string,
filter: (filePath: string, stat: Stats) => boolean = () => true,
): Promise<string[]> {
const allFiles = await fs.readdir(dir, { recursive: true });
const filePaths: string[] = [];
for (const fileName of allFiles) {
const filePath = path.join(dir, fileName);
const stat = await fs.stat(filePath);
if (!stat.isDirectory() && filter(filePath, stat)) {
filePaths.push(filePath);
}
}

return filePaths;
}

interface FromFsOptions {
/**
* Additional filters to apply to json files when loading a universe from FS
*/
filter: (filePath: string, stat: Stats) => boolean;

/**
* Only load the canonical version of the contract and ignore
* aliases
*/
canonicalOnly: boolean;
}

export class Universe extends Contract {
constructor() {
super({ type: UNIVERSE });
}

/**
* @summary recursively looks up all json files under a directory and adds them
* to the universe
* @function
* @static
* @name module:contrato.Universe.fromFs
* @public
*
* @param dir full path of the directory to load
* @param options additional configuration for the search and build process
*
*/
static async fromFs(
dir: string,
{ filter = () => true, canonicalOnly = false }: Partial<FromFsOptions> = {},
): Promise<Universe> {
const allFiles = await findFiles(
dir,
(filePath, stat) =>
path.extname(filePath) === '.json' && filter(filePath, stat),
);

const { default: pMap } = await import('p-map');

const universe = new Universe();
const children = (
await pMap(
allFiles,
async (file) => {
const contents = await fs.readFile(file, { encoding: 'utf8' });
let source = JSON.parse(contents);
if (canonicalOnly) {
// Ignore aliases
const { aliases, ...obj } = source;
source = obj;
}
return Contract.build(source);
},
{ concurrency: 10 },
)
).flat();

universe.addChildren(children);

return universe;
}
}

export default Universe;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"json-schema": "^0.4.0",
"lodash": "^4.17.19",
"object-hash": "^1.3.1",
"p-map": "^7.0.3",
"promised-handlebars": "^2.0.1",
"semver": "^5.7.1"
},
Expand Down
15 changes: 15 additions & 0 deletions tests/universe/contracts/arch.sw/aarch64/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"slug": "aarch64",
"version": "1",
"type": "arch.sw",
"name": "ARM v8",
"data": { "arch": "aarch64" },
"requires": [
{
"type": "hw.device-type",
"data": {
"arch": "aarch64"
}
}
]
}
15 changes: 15 additions & 0 deletions tests/universe/contracts/arch.sw/amd64/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"slug": "amd64",
"version": "1",
"type": "arch.sw",
"name": "Intel 64-bit (x86-64)",
"data": { "arch": "amd64" },
"requires": [
{
"type": "hw.device-type",
"data": {
"arch": "amd64"
}
}
]
}
15 changes: 15 additions & 0 deletions tests/universe/contracts/arch.sw/armv7hf/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"slug": "armv7hf",
"version": "1",
"type": "arch.sw",
"name": "ARM v7",
"data": { "arch": "armv7hf" },
"requires": [
{
"type": "hw.device-type",
"data": {
"arch": "armv7hf"
}
}
]
}
15 changes: 15 additions & 0 deletions tests/universe/contracts/arch.sw/rpi/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"slug": "rpi",
"version": "1",
"type": "arch.sw",
"name": "ARM v6",
"data": { "arch": "armv6hf" },
"requires": [
{
"type": "hw.device-type",
"data": {
"arch": "rpi"
}
}
]
}
29 changes: 29 additions & 0 deletions tests/universe/contracts/hw.device-type/intel-nuc/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"slug": "intel-nuc",
"version": "1",
"type": "hw.device-type",
"aliases": [
"nuc"
],
"name": "Intel NUC",
"data": {
"arch": "amd64",
"hdmi": true,
"led": false,
"connectivity": {
"bluetooth": true,
"wifi": true
},
"storage": {
"internal": true
},
"media": {
"defaultBoot": "internal",
"altBoot": [
"usb_mass_storage",
"network"
]
},
"is_private": false
}
}
24 changes: 24 additions & 0 deletions tests/universe/contracts/hw.device-type/jetson-nano/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"slug": "jetson-nano",
"version": "1",
"type": "hw.device-type",
"aliases": [],
"name": "Nvidia Jetson Nano SD-CARD",
"data": {
"arch": "aarch64",
"hdmi": true,
"led": false,
"connectivity": {
"bluetooth": false,
"wifi": false
},
"storage": {
"internal": false
},
"flashProtocol": "jetsonFlash",
"media": {
"defaultBoot": "sdcard"
},
"is_private": false
}
}
29 changes: 29 additions & 0 deletions tests/universe/contracts/hw.device-type/raspberry-pi/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"slug": "raspberry-pi",
"version": "1",
"type": "hw.device-type",
"aliases": [
"raspberrypi"
],
"name": "Raspberry Pi (v1 / Zero / Zero W)",
"data": {
"arch": "rpi",
"hdmi": true,
"led": true,
"connectivity": {
"bluetooth": true,
"wifi": true
},
"storage": {
"internal": false
},
"media": {
"defaultBoot": "sdcard",
"altBoot": [
"usb_mass_storage",
"network"
]
},
"is_private": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"slug": "raspberry-pi2",
"version": "1",
"type": "hw.device-type",
"aliases": [
"raspberrypi2"
],
"name": "Raspberry Pi 2",
"data": {
"arch": "armv7hf",
"hdmi": true,
"led": true,
"connectivity": {
"bluetooth": false,
"wifi": false
},
"storage": {
"internal": false
},
"media": {
"defaultBoot": "sdcard",
"altBoot": [
"usb_mass_storage",
"network"
]
},
"is_private": false
}
}
27 changes: 27 additions & 0 deletions tests/universe/contracts/hw.device-type/raspberrypi3/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"slug": "raspberrypi3",
"version": "1",
"type": "hw.device-type",
"aliases": [],
"name": "Raspberry Pi 3",
"data": {
"arch": "armv7hf",
"hdmi": true,
"led": true,
"connectivity": {
"bluetooth": true,
"wifi": true
},
"storage": {
"internal": false
},
"media": {
"defaultBoot": "sdcard",
"altBoot": [
"usb_mass_storage",
"network"
]
},
"is_private": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"slug": "raspberrypi4-64",
"version": "1",
"type": "hw.device-type",
"aliases": [],
"name": "Raspberry Pi 4 (using 64bit OS)",
"data": {
"arch": "aarch64",
"hdmi": true,
"led": true,
"connectivity": {
"bluetooth": true,
"wifi": true
},
"storage": {
"internal": false
},
"media": {
"defaultBoot": "sdcard",
"altBoot": [
"usb_mass_storage",
"network"
]
},
"is_private": false
}
}
Loading
Loading