Skip to content

Commit fb1f2c0

Browse files
authored
Feature/substreams (#991)
Co-authored-by: Matthieu Vachon <[email protected]>
1 parent 9a240cb commit fb1f2c0

File tree

12 files changed

+404
-213
lines changed

12 files changed

+404
-213
lines changed

src/command-helpers/compiler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const Compiler = require('../compiler')
66
// Helper function to construct a subgraph compiler
77
const createCompiler = (
88
manifest,
9-
{ ipfs, headers, outputDir, outputFormat, skipMigrations, blockIpfsMethods, protocol }
9+
{ ipfs, headers, outputDir, outputFormat, skipMigrations, blockIpfsMethods, protocol },
1010
) => {
1111
// Parse the IPFS URL
1212
let url

src/commands/build.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const { updateSubgraphNetwork } = require('../command-helpers/network')
66
const DataSourcesExtractor = require('../command-helpers/data-sources')
77
const Protocol = require('../protocols')
88

9+
let buildDebug = require('../debug')('graph-cli:build')
10+
911
const HELP = `
1012
${chalk.bold('graph build')} [options] ${chalk.bold('[<subgraph-manifest>]')}
1113
@@ -41,7 +43,7 @@ module.exports = {
4143
w,
4244
watch,
4345
network,
44-
networkFile
46+
networkFile,
4547
} = toolbox.parameters.options
4648

4749
// Support both short and long option variants
@@ -76,7 +78,7 @@ module.exports = {
7678
networkFile =
7779
networkFile !== undefined && networkFile !== ''
7880
? networkFile
79-
: filesystem.resolve("networks.json")
81+
: filesystem.resolve('networks.json')
8082

8183
// Show help text if requested
8284
if (help) {
@@ -95,7 +97,9 @@ module.exports = {
9597
return
9698
}
9799

98-
if (network && filesystem.exists(networkFile) !== "file") {
100+
buildDebug('Detected protocol "%s" (%o)', protocol.name, protocol)
101+
102+
if (network && filesystem.exists(networkFile) !== 'file') {
99103
print.error(`Network file '${networkFile}' does not exists or is not a file!`)
100104
process.exitCode = 1
101105
return

src/commands/codegen.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Options:
2121
-uc, --uncrashable-config <path> Directory for uncrashable config (default: ./uncrashable-config.yaml)
2222
`
2323

24+
let codegenDebug = require('../debug')('graph-cli:codegen')
25+
2426
module.exports = {
2527
description: 'Generates AssemblyScript types for a subgraph',
2628
run: async toolbox => {
@@ -54,6 +56,7 @@ module.exports = {
5456
;[manifest] = fixParameters(toolbox.parameters, {
5557
h,
5658
help,
59+
skipMigrations,
5760
w,
5861
watch,
5962
u,
@@ -65,6 +68,8 @@ module.exports = {
6568
return
6669
}
6770

71+
codegenDebug('Initialized codegen manifest: %o', manifest)
72+
6873
// Fall back to default values for options / parameters
6974
outputDir =
7075
outputDir !== undefined && outputDir !== ''

src/commands/init.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const availableNetworks = Protocol.availableNetworks()
2626

2727
const DEFAULT_EXAMPLE_SUBGRAPH = 'ethereum/gravatar'
2828

29+
let initDebug = require('../debug')('graph-cli:init')
30+
2931
const HELP = `
3032
${chalk.bold('graph init')} [options] [subgraph-name] [directory]
3133
@@ -170,10 +172,17 @@ const processInitForm = async (
170172
type: 'select',
171173
name: 'network',
172174
message: () => `${protocolInstance.displayName()} network`,
173-
choices: () =>
174-
availableNetworks
175+
choices: () => {
176+
initDebug(
177+
'Generating list of available networks for protocol "%s" (%M)',
178+
protocol,
179+
availableNetworks.get(protocol),
180+
)
181+
return availableNetworks
175182
.get(protocol) // Get networks related to the chosen protocol.
176-
.toArray(), // Needed because of gluegun. It can't even receive a JS iterable.
183+
.toArray() // Needed because of gluegun. It can't even receive a JS iterable.
184+
},
185+
177186
skip: fromExample !== undefined,
178187
initial: network || 'mainnet',
179188
result: value => {

src/compiler/index.js

Lines changed: 128 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const Subgraph = require('../subgraph')
1111
const Watcher = require('../watcher')
1212
const { applyMigrations } = require('../migrations')
1313
const asc = require('./asc')
14+
const SubstreamsSubgraph = require('../protocols/substreams/subgraph')
15+
16+
let compilerDebug = require('../debug')('graph-cli:compiler')
1417

1518
class Compiler {
1619
constructor(options) {
@@ -20,36 +23,38 @@ class Compiler {
2023
this.blockIpfsMethods = options.blockIpfsMethods
2124
this.libsDirs = []
2225

23-
for (
24-
let dir = path.resolve(this.sourceDir);
25-
// Terminate after the root dir or when we have found node_modules
26-
dir !== undefined;
27-
// Continue with the parent directory, terminate after the root dir
28-
dir = path.dirname(dir) === dir ? undefined : path.dirname(dir)
29-
) {
30-
if (fs.existsSync(path.join(dir, 'node_modules'))) {
31-
this.libsDirs.push(path.join(dir, 'node_modules'))
26+
if (options.protocol.name !== 'substreams') {
27+
for (
28+
let dir = path.resolve(this.sourceDir);
29+
// Terminate after the root dir or when we have found node_modules
30+
dir !== undefined;
31+
// Continue with the parent directory, terminate after the root dir
32+
dir = path.dirname(dir) === dir ? undefined : path.dirname(dir)
33+
) {
34+
if (fs.existsSync(path.join(dir, 'node_modules'))) {
35+
this.libsDirs.push(path.join(dir, 'node_modules'))
36+
}
3237
}
33-
}
3438

35-
if (this.libsDirs.length === 0) {
36-
throw Error(
37-
`could not locate \`node_modules\` in parent directories of subgraph manifest`,
38-
)
39-
}
39+
if (this.libsDirs.length === 0) {
40+
throw Error(
41+
`could not locate \`node_modules\` in parent directories of subgraph manifest`,
42+
)
43+
}
4044

41-
const globalsFile = path.join('@graphprotocol', 'graph-ts', 'global', 'global.ts')
42-
const globalsLib = this.libsDirs.find(item => {
43-
return fs.existsSync(path.join(item, globalsFile))
44-
})
45+
const globalsFile = path.join('@graphprotocol', 'graph-ts', 'global', 'global.ts')
46+
const globalsLib = this.libsDirs.find(item => {
47+
return fs.existsSync(path.join(item, globalsFile))
48+
})
4549

46-
if (!globalsLib) {
47-
throw Error(
48-
'Could not locate `@graphprotocol/graph-ts` package in parent directories of subgraph manifest.',
49-
)
50-
}
50+
if (!globalsLib) {
51+
throw Error(
52+
'Could not locate `@graphprotocol/graph-ts` package in parent directories of subgraph manifest.',
53+
)
54+
}
5155

52-
this.globalsFile = path.join(globalsLib, globalsFile)
56+
this.globalsFile = path.join(globalsLib, globalsFile)
57+
}
5358

5459
this.protocol = this.options.protocol
5560
this.ABI = this.protocol.getABI()
@@ -83,7 +88,10 @@ class Compiler {
8388
}
8489
let subgraph = await this.loadSubgraph()
8590
let compiledSubgraph = await this.compileSubgraph(subgraph)
86-
let localSubgraph = await this.writeSubgraphToOutputDirectory(compiledSubgraph)
91+
let localSubgraph = await this.writeSubgraphToOutputDirectory(
92+
this.options.protocol,
93+
compiledSubgraph,
94+
)
8795

8896
if (this.ipfs !== undefined) {
8997
let ipfsHash = await this.uploadSubgraphToIPFS(localSubgraph)
@@ -214,6 +222,7 @@ class Compiler {
214222
dataSources.map(dataSource =>
215223
dataSource.updateIn(['mapping', 'file'], mappingPath =>
216224
this._compileDataSourceMapping(
225+
this.protocol,
217226
dataSource,
218227
mappingPath,
219228
compiledFiles,
@@ -243,7 +252,11 @@ class Compiler {
243252
)
244253
}
245254

246-
_compileDataSourceMapping(dataSource, mappingPath, compiledFiles, spinner) {
255+
_compileDataSourceMapping(protocol, dataSource, mappingPath, compiledFiles, spinner) {
256+
if (protocol.name == 'substreams') {
257+
return
258+
}
259+
247260
try {
248261
let dataSourceName = dataSource.getIn(['name'])
249262

@@ -378,7 +391,7 @@ class Compiler {
378391
_validateMappingContent(filePath) {
379392
const data = fs.readFileSync(filePath)
380393
if (
381-
this.blockIpfsMethods &&
394+
this.blockIpfsMethods &&
382395
(data.includes('ipfs.cat') || data.includes('ipfs.map'))
383396
) {
384397
throw Error(`
@@ -389,7 +402,7 @@ class Compiler {
389402
}
390403
}
391404

392-
async writeSubgraphToOutputDirectory(subgraph) {
405+
async writeSubgraphToOutputDirectory(protocol, subgraph) {
393406
const displayDir = `${this.displayPath(this.options.outputDir)}${
394407
toolbox.filesystem.separator
395408
}`
@@ -437,6 +450,30 @@ class Compiler {
437450
)
438451
}
439452

453+
if (protocol.name == 'substreams') {
454+
updatedDataSource = updatedDataSource
455+
// Write data source ABIs to the output directory
456+
.updateIn(['source', 'package'], substreamsPackage =>
457+
substreamsPackage.update('file', packageFile => {
458+
packageFile = path.resolve(this.sourceDir, packageFile)
459+
let packageContent = fs.readFileSync(packageFile)
460+
461+
return path.relative(
462+
this.options.outputDir,
463+
this._writeSubgraphFile(
464+
packageFile,
465+
packageContent,
466+
this.sourceDir,
467+
this.subgraphDir(this.options.outputDir, dataSource),
468+
spinner,
469+
),
470+
)
471+
}),
472+
)
473+
474+
return updatedDataSource
475+
}
476+
440477
// The mapping file is already being written to the output
441478
// directory by the AssemblyScript compiler
442479
return updatedDataSource.updateIn(['mapping', 'file'], mappingFile =>
@@ -445,48 +482,48 @@ class Compiler {
445482
path.resolve(this.sourceDir, mappingFile),
446483
),
447484
)
448-
})
485+
}),
449486
)
450487

451488
// Copy template files and update their paths
452489
subgraph = subgraph.update('templates', templates =>
453490
templates === undefined
454491
? templates
455492
: templates.map(template => {
456-
let updatedTemplate = template
457-
458-
if (this.protocol.hasABIs()) {
459-
updatedTemplate = updatedTemplate
460-
// Write template ABIs to the output directory
461-
.updateIn(['mapping', 'abis'], abis =>
462-
abis.map(abi =>
463-
abi.update('file', abiFile => {
464-
abiFile = path.resolve(this.sourceDir, abiFile)
465-
let abiData = this.ABI.load(abi.get('name'), abiFile)
466-
return path.relative(
467-
this.options.outputDir,
468-
this._writeSubgraphFile(
469-
abiFile,
470-
JSON.stringify(abiData.data.toJS(), null, 2),
471-
this.sourceDir,
472-
this.subgraphDir(this.options.outputDir, template),
473-
spinner,
474-
),
475-
)
476-
}),
477-
),
478-
)
479-
}
480-
481-
// The mapping file is already being written to the output
482-
// directory by the AssemblyScript compiler
483-
return updatedTemplate.updateIn(['mapping', 'file'], mappingFile =>
484-
path.relative(
485-
this.options.outputDir,
486-
path.resolve(this.sourceDir, mappingFile),
487-
),
488-
)
489-
})
493+
let updatedTemplate = template
494+
495+
if (this.protocol.hasABIs()) {
496+
updatedTemplate = updatedTemplate
497+
// Write template ABIs to the output directory
498+
.updateIn(['mapping', 'abis'], abis =>
499+
abis.map(abi =>
500+
abi.update('file', abiFile => {
501+
abiFile = path.resolve(this.sourceDir, abiFile)
502+
let abiData = this.ABI.load(abi.get('name'), abiFile)
503+
return path.relative(
504+
this.options.outputDir,
505+
this._writeSubgraphFile(
506+
abiFile,
507+
JSON.stringify(abiData.data.toJS(), null, 2),
508+
this.sourceDir,
509+
this.subgraphDir(this.options.outputDir, template),
510+
spinner,
511+
),
512+
)
513+
}),
514+
),
515+
)
516+
}
517+
518+
// The mapping file is already being written to the output
519+
// directory by the AssemblyScript compiler
520+
return updatedTemplate.updateIn(['mapping', 'file'], mappingFile =>
521+
path.relative(
522+
this.options.outputDir,
523+
path.resolve(this.sourceDir, mappingFile),
524+
),
525+
)
526+
}),
490527
)
491528

492529
// Write the subgraph manifest itself
@@ -537,15 +574,28 @@ class Compiler {
537574
}
538575

539576
// Upload all mappings
540-
for (let [i, dataSource] of subgraph.get('dataSources').entries()) {
541-
updates.push({
542-
keyPath: ['dataSources', i, 'mapping', 'file'],
543-
value: await this._uploadFileToIPFS(
544-
dataSource.getIn(['mapping', 'file']),
545-
uploadedFiles,
546-
spinner,
547-
),
548-
})
577+
if (this.protocol.name !== 'substreams') {
578+
for (let [i, dataSource] of subgraph.get('dataSources').entries()) {
579+
updates.push({
580+
keyPath: ['dataSources', i, 'mapping', 'file'],
581+
value: await this._uploadFileToIPFS(
582+
dataSource.getIn(['mapping', 'file']),
583+
uploadedFiles,
584+
spinner,
585+
),
586+
})
587+
}
588+
} else {
589+
for (let [i, dataSource] of subgraph.get('dataSources').entries()) {
590+
updates.push({
591+
keyPath: ['dataSources', i, 'source', 'package', 'file'],
592+
value: await this._uploadFileToIPFS(
593+
dataSource.getIn(['source', 'package', 'file']),
594+
uploadedFiles,
595+
spinner,
596+
),
597+
})
598+
}
549599
}
550600

551601
for (let [i, template] of subgraph.get('templates', immutable.List()).entries()) {
@@ -584,6 +634,11 @@ class Compiler {
584634
}
585635

586636
async _uploadFileToIPFS(maybeRelativeFile, uploadedFiles, spinner) {
637+
compilerDebug(
638+
'Resolving IPFS file "%s" from output dir "%s"',
639+
maybeRelativeFile,
640+
this.options.outputDir,
641+
)
587642
let absoluteFile = path.resolve(this.options.outputDir, maybeRelativeFile)
588643
step(spinner, 'Add file to IPFS', this.displayPath(absoluteFile))
589644

0 commit comments

Comments
 (0)