gnolang / gno

Gno: An interpreted, stack-based Go virtual machine to build succinct and composable apps + Gno.land: a blockchain for timeless code and fair open-source
https://gno.land/
Other
873 stars 354 forks source link

[chain] Unable to deploy module with a single top-level `gno.mod`, with multiple sub-packages without `gno.mod`s #2141

Open zivkovicmilos opened 3 months ago

zivkovicmilos commented 3 months ago

Unable to deploy module with a single top-level gno.mod, with multiple sub-packages without gno.mods

Description

Gno currently does not support deploying a Gno module (with a single top-level gno.mod) and multiple sub-packages, which a super common Go library structure:

.
└── bug/
    ├── gno.mod
    ├── a.gno
    ├── b/
    │   └── b.gno
    └── c/
        └── c.gno

Instead, to deploy this package to the chain, each subfolder requires its own gno.mod, even though this is a perfectly normal scenario and structure in standard Go.

Top level gno.mod:

module gno.land/r/demo/bug

a.gno:

package packagea

import (
    "gno.land/r/demo/bug/packageb"
    "gno.land/r/demo/bug/packagec"
)

var (
    bee = packageb.New()
    cee = packagec.New()
)

func CallAllSubs() {
    bee.Call()
    cee.Call()
}

b/b.gno:

package packageb

type B struct {
}

func New() *B {
    return &B{}
}

func (b *B) Call() {
    // something
}

c/c.gno:

package packagec

type C struct {
}

func New() *C {
    return &C{}
}

func (c *C) Call() {
    // something
}

Your environment

Steps to reproduce

Expected behavior

The package should be deployed, even though each sub-package does not have a gno.mod

Actual behavior

Each sub-package (folder) requires its own gno.mod, and these need to be referenced in the top-level gno.mod

Logs

Running gno lint --v .:

gno lint --v .
Linting "./."...
a.gno:1: unknown import path gno.land/r/demo/bug/packageb (code=2).
Linting "./b"...
./b: missing 'gno.mod' file (code=1).
Linting "./c"...
./c: missing 'gno.mod' file (code=1).

Gnodev:

Node        ┃ E unable to deliver tx
            ┃   err=
            ┃   │ invalid gno package; type check errors:
            ┃   │ a.gno:4:2: could not import gno.land/r/demo/bug/packageb (import not found: gno.land/r/demo/bug/packageb)
            ┃   │ a.gno:5:2: could not import gno.land/r/demo/bug/packagec (import not found: gno.land/r/demo/bug/packagec)
            ┃  err="msg:0,success:false,log:--= Error =--"

Proposed solution

Not sure what would be the solution right off the bat.

Adding individual gno.mods to each sub-folder (package), and running gno mod tidy from the top-level directory (which adds the requirements) fixes the problem, but this shouldn't need to happen in the first place

cc @ajnavarro @gfanton @moul

moul commented 3 months ago

I suggest we adapt our communication and guidelines to distinguish between p/ and r/ more clearly:

Sure, here's an improved version of that text:

For example, you can have r/manfred/myapp, a stateful app with banker and Render, that includes p/avl (a pure dependency). It can also import r/manfred/myapp/myhelpers, which is stateless and does not use banker, making it more like a package but not pure. Additionally, you can have r/manfred/myapp/admin, a realm where you centralize all your admin features to keep the top-level realm cleaner.

On other Gno-powered chains, this distinction might not be necessary, but on the Gno.land blockchain, we offer both source-code hosting (p/) and app deployment (r/).

We should update Gnoweb to reflect these differences in interfaces:

This means you can have a single gno.mod file in an external repo like https://github.com/moul/my-gno-app containing the top-level realm (the index of your app) and subfolders that can be sub-realms with data or just sub-packages that are technically realms but not using any realm features (persistency, banker, etc.).

It also means that I or someone else might want to import r/manfred/myapp/myhelpers, which is possible from r/. In such cases, it could be beneficial to add a "fork" feature that assists in converting this folder into a pure package. This would involve spending some time to make it more useful for developers by improving documentation, adding unit tests, or enhancing the API.

cc @leohhhn @zivkovicmilos @thehowl @alexiscolin