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

feat(gnovm): packages loader #2932

Draft
wants to merge 154 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
154 commits
Select commit Hold shift + click to select a range
01b0719
copy over from gnoutil pr
thehowl May 26, 2024
232834c
remove util_test
thehowl May 26, 2024
f378217
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/gno-r…
thehowl May 26, 2024
8afeacf
linter fixes
thehowl May 26, 2024
808061d
tmp: gno list
n0izn0iz Oct 7, 2024
2c5d604
tmp
n0izn0iz Oct 7, 2024
dfc0881
tmp: working
n0izn0iz Oct 9, 2024
a35050c
chore: merge remote-tracking branch 'origin/master' into dev/morgan/g…
n0izn0iz Oct 10, 2024
7c7165f
feat: match mapping
n0izn0iz Oct 10, 2024
1c3a830
fix: test and lint
n0izn0iz Oct 10, 2024
f95e4bb
fix: partially fix transpile
n0izn0iz Oct 10, 2024
2d990e5
tmp: support loaded pkgs in test store
n0izn0iz Oct 10, 2024
6995485
tmp: better Module info
n0izn0iz Oct 11, 2024
fb8d518
tmp: follow go resolver logic
n0izn0iz Oct 11, 2024
1c51509
fix: resolver usage in test
n0izn0iz Oct 11, 2024
da65417
chore: mod tidy
n0izn0iz Oct 11, 2024
4a8401a
chore: ignore draft
n0izn0iz Oct 11, 2024
e792771
chore: rename importer -> packages like go, break import cycle and mo…
n0izn0iz Oct 11, 2024
08fbd84
chore: lint and fmt
n0izn0iz Oct 11, 2024
f93a221
Update gnovm/pkg/packages/download.go
n0izn0iz Oct 11, 2024
53c5770
chore: revert merge fails
n0izn0iz Oct 11, 2024
457b0c9
chore: add package and module struct fields comments
n0izn0iz Oct 11, 2024
59a752a
chore: go -> gno
n0izn0iz Oct 11, 2024
e648305
fix: use io instead of os
n0izn0iz Oct 11, 2024
0123512
chore: explicit args
n0izn0iz Oct 11, 2024
d266b8e
chore: improve comment
n0izn0iz Oct 11, 2024
ac435c2
fix: break import cycle
n0izn0iz Oct 21, 2024
178706f
chore: merge remote-tracking branch 'origin/master' into gno-resolver
n0izn0iz Oct 21, 2024
9fbe83c
chore: linter
n0izn0iz Oct 22, 2024
d78fb90
chore: reuse helper
n0izn0iz Oct 22, 2024
f7b6df7
chore: merge remote-tracking branch 'origin/master' into gno-resolver
n0izn0iz Oct 22, 2024
6f2330e
tmp: use gno.work and add back mod files
n0izn0iz Oct 28, 2024
2d9fc96
chore: merge remote-tracking branch 'origin/master' into gno-resolver
n0izn0iz Oct 28, 2024
b8bf790
fix: prevent import cycles in stdlibs
n0izn0iz Dec 8, 2024
fd7bbc4
fix: remove import cycles
n0izn0iz Dec 8, 2024
9be6649
chore: improve cycle detector
n0izn0iz Dec 9, 2024
b7ba5a9
chore: inject match string to break import cycle
n0izn0iz Dec 9, 2024
920c49b
Merge branch 'master' into forbid-import-cycle
n0izn0iz Dec 9, 2024
c45a741
chore: revert fuzz move
n0izn0iz Dec 9, 2024
360aa64
chore: fuzztesting -> testing
n0izn0iz Dec 9, 2024
d7c3d10
chore: regen
n0izn0iz Dec 9, 2024
c69fc43
Merge branch 'master' into forbid-import-cycle
n0izn0iz Dec 9, 2024
096f8cd
fix: strconv tests
n0izn0iz Dec 9, 2024
4517f0f
Merge branch 'master' into forbid-import-cycle
n0izn0iz Dec 9, 2024
ced3475
fix: math/rand, some math/bits, strings
n0izn0iz Dec 10, 2024
eff15b0
fix: typo
n0izn0iz Dec 10, 2024
761ef83
chore: rename var
n0izn0iz Dec 10, 2024
ee265f5
fix: don't hide self imports
n0izn0iz Dec 10, 2024
401d4e3
Merge branch 'master' into forbid-import-cycle
n0izn0iz Dec 10, 2024
0a05f85
chore: add test case for self import
n0izn0iz Dec 10, 2024
d9f4d3a
chore: make genstd consider test files
n0izn0iz Dec 10, 2024
c6728c5
chore: make genstd consider test files
n0izn0iz Dec 10, 2024
4374a39
fix(genstd): allow native injections in all packages and regen
n0izn0iz Dec 10, 2024
284e56b
tmp
n0izn0iz Dec 11, 2024
6c5d83e
feat: categorize imports
n0izn0iz Dec 11, 2024
d05c43b
Merge branch 'master' into imports-map
n0izn0iz Dec 11, 2024
702e3d9
Merge branch 'master' into imports-map
n0izn0iz Dec 11, 2024
1d17b9f
Merge branch 'master' into imports-map
n0izn0iz Dec 13, 2024
c4d82dc
Merge branch 'master' into imports-map
n0izn0iz Dec 17, 2024
27bb085
Merge branch 'master' into imports-map
n0izn0iz Dec 18, 2024
3e04787
chore: Merge remote-tracking branch 'origin/master' into imports-map
n0izn0iz Dec 19, 2024
a0dd0d8
chore: move code for easier review
n0izn0iz Dec 19, 2024
d2d043e
chore: pass fset to GetFileKind
n0izn0iz Dec 19, 2024
efda22d
fix: usage of packages.Imports
n0izn0iz Dec 19, 2024
fcd66a5
chore: don't expose SortImports
n0izn0iz Dec 19, 2024
37d96ce
chore: error msg with loc
n0izn0iz Dec 19, 2024
e591002
Merge branch 'master' into imports-map
n0izn0iz Dec 19, 2024
315b37f
Merge branch 'master' into imports-map
n0izn0iz Dec 19, 2024
cd91edb
Merge branch 'master' into imports-map
n0izn0iz Dec 20, 2024
c0998d7
chore: nit
n0izn0iz Dec 21, 2024
41ddaa6
chore: revert merge fail
n0izn0iz Dec 21, 2024
4cfda1e
chore: FileKindCompiled -> FileKindPackageSource
n0izn0iz Dec 21, 2024
2100a57
chore: FileKindXtest -> FilKindXTest
n0izn0iz Dec 21, 2024
0be8c69
chore: add FileKind doc
n0izn0iz Dec 21, 2024
1fcf4e3
Merge branch 'master' into imports-map
n0izn0iz Dec 21, 2024
3973f84
chore: Merge branch 'imports-map' into forbid-import-cycle
n0izn0iz Dec 22, 2024
5c7e31b
fix: nocycles binary after upgrade
n0izn0iz Dec 23, 2024
479145b
Merge branch 'master' into forbid-import-cycle
n0izn0iz Dec 23, 2024
35aca6d
chore: use new util to split imports
n0izn0iz Dec 23, 2024
22f1589
feat: correctly check cycles
n0izn0iz Dec 23, 2024
5c4208f
chore: improve explainers
n0izn0iz Dec 23, 2024
64beee7
feat: embed cycle test in actual test
n0izn0iz Dec 23, 2024
5a8beef
chore: don't panic in test
n0izn0iz Dec 23, 2024
a3fc750
Merge branch 'master' into forbid-import-cycle
n0izn0iz Dec 23, 2024
39def3e
chore: improve comment
n0izn0iz Dec 23, 2024
1f7d1fc
chore: improve doc
n0izn0iz Dec 23, 2024
0ebf4f5
Merge branch 'master' into imports-map
n0izn0iz Dec 25, 2024
7c11caa
chore: revert pkg change
Dec 25, 2024
f7c34e0
chore: refacto test
Dec 25, 2024
f01b564
chore: refacto test 2
Dec 25, 2024
8ae5f73
chore: remove dev artifact
Dec 25, 2024
65fdad5
chore: revert genstd changes
Dec 25, 2024
f9e8c94
chore: revert genstd changes
Dec 25, 2024
d5ee04e
chore: revert comments changes
Dec 25, 2024
bf7ff6f
chore: revert more comment changes
Dec 25, 2024
8c7959a
chore: protect bits error values
Dec 25, 2024
57a2d6b
chore: revert multi_test changes
Dec 25, 2024
5c95bd1
chore: revert unneeded math rand changes
Dec 25, 2024
d98eea9
chore: remove uneeded change
Dec 25, 2024
288351b
chore: only implement matchString in testing context
Dec 25, 2024
4692891
chore: improve comment
Dec 25, 2024
6c06b7f
chore: regen
Dec 25, 2024
e720c60
chore: add comment about overlay imports
Dec 25, 2024
0490b9e
Merge branch 'master' into imports-map
n0izn0iz Jan 3, 2025
2945568
chore: Merge remote-tracking branch 'origin/master' into imports-map
n0izn0iz Jan 6, 2025
31983c8
Merge branch 'master' into imports-map
n0izn0iz Jan 7, 2025
44444c0
chore: Merge branch 'imports-map' into forbid-import-cycle
n0izn0iz Jan 7, 2025
13a5e72
Merge branch 'master' into forbid-import-cycle
n0izn0iz Jan 7, 2025
7c5baf3
chore: Merge branch 'forbid-import-cycle' into gno-resolver
n0izn0iz Jan 7, 2025
b012a33
fix: build
n0izn0iz Jan 7, 2025
c428052
feat: working gno list
n0izn0iz Jan 8, 2025
68b2453
feat: improve
n0izn0iz Jan 8, 2025
fd2917f
chore: remove dev artifact
n0izn0iz Jan 8, 2025
4908939
chore: remove impossible case
n0izn0iz Jan 8, 2025
bb3057e
chore: revert unneeded changes
n0izn0iz Jan 8, 2025
74ebf0c
feat: inject util + consistent naming
n0izn0iz Jan 8, 2025
6c69bed
chore: simplify condition
n0izn0iz Jan 8, 2025
10701c4
chore: explicit log name
n0izn0iz Jan 8, 2025
0e98114
chore: remove dev artifact
n0izn0iz Jan 8, 2025
b6d9007
chore: remove merge fail
n0izn0iz Jan 8, 2025
edba346
chore: remove merge fail
n0izn0iz Jan 8, 2025
78b60ed
chore: remove old pkg loader
n0izn0iz Jan 8, 2025
4104372
chore: node loadconfig
n0izn0iz Jan 8, 2025
0a85338
feat: run gnoland genesis pkg loading in self-contained mode
n0izn0iz Jan 8, 2025
f5b7afc
fix: gnodev tests
n0izn0iz Jan 8, 2025
fba50a7
fix: go fmt and lint
n0izn0iz Jan 8, 2025
5f4610f
Merge branch 'master' into gno-resolver
n0izn0iz Jan 8, 2025
b760e36
fix: gnodev and gnogenesis
n0izn0iz Jan 8, 2025
ceb039b
fix: testing loader paths
n0izn0iz Jan 8, 2025
c7edab0
fix: ignore stdlibs and allow name override
n0izn0iz Jan 8, 2025
82b7ef8
chore: don't override name if not requested
n0izn0iz Jan 8, 2025
9d6b2d8
chore: skip stdlibs and package with no import paths in txs
n0izn0iz Jan 8, 2025
1405da2
chore: fix lint
n0izn0iz Jan 8, 2025
7bb33b2
tmp
n0izn0iz Jan 8, 2025
c95d2bf
fix: linter errors locations
n0izn0iz Jan 8, 2025
6d6ee0d
feat: single file pattern support + misc bugs
n0izn0iz Jan 8, 2025
c5754b5
chore: fmt and lint go
n0izn0iz Jan 8, 2025
a73ba04
fix: don't ignore files without valid package clause
n0izn0iz Jan 8, 2025
cef59f3
fix: mod why
n0izn0iz Jan 8, 2025
b73027b
fix: pass all tests except transpile
n0izn0iz Jan 8, 2025
5b5386f
tmp
n0izn0iz Jan 9, 2025
07375f8
fix: always use relative paths for files in pkgs
n0izn0iz Jan 9, 2025
95963dc
chore: revert transpile changes
n0izn0iz Jan 9, 2025
43c95d4
chore: Merge remote-tracking branch 'origin/master' into forbid-impor…
n0izn0iz Jan 9, 2025
6e1a134
chore: remove merge artifact
n0izn0iz Jan 9, 2025
6f6bb36
chore: Merge branch 'forbid-import-cycle' into gno-resolver
n0izn0iz Jan 9, 2025
1d67048
fix: sort
n0izn0iz Jan 10, 2025
c0eacfb
chore: fix debugger
n0izn0iz Jan 10, 2025
740e3e3
feat: detect stdlibs
n0izn0iz Jan 10, 2025
7523824
chore: Merge remote-tracking branch 'origin/master' into gno-resolver
n0izn0iz Jan 10, 2025
9380f1c
fix: gnodev, gnogensis
n0izn0iz Jan 10, 2025
2f9c35a
chore: lint and fmt
n0izn0iz Jan 10, 2025
85c800a
chore: generate
n0izn0iz Jan 10, 2025
5b06874
test: gnodev
n0izn0iz Jan 10, 2025
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: 1 addition & 1 deletion .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
with:
go-version: ${{ matrix.goversion }}
- run: go install -v ./gnovm/cmd/gno
- run: go run ./gnovm/cmd/gno transpile -v --gobuild ./examples
- run: go run ./gnovm/cmd/gno transpile -v --gobuild ./examples/...
test:
strategy:
fail-fast: false
Expand Down
14 changes: 8 additions & 6 deletions contribs/gnodev/pkg/dev/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot"
"github.com/gnolang/gno/gno.land/pkg/integration"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
"github.com/gnolang/gno/gnovm/pkg/packages"
"github.com/gnolang/gno/tm2/pkg/amino"
tmcfg "github.com/gnolang/gno/tm2/pkg/bft/config"
"github.com/gnolang/gno/tm2/pkg/bft/node"
Expand Down Expand Up @@ -44,6 +44,7 @@ type NodeConfig struct {
MaxGasPerBlock int64
ChainID string
ChainDomain string
LoadConfig *packages.LoadConfig
}

func DefaultNodeConfig(rootdir, domain string) *NodeConfig {
Expand All @@ -70,6 +71,7 @@ func DefaultNodeConfig(rootdir, domain string) *NodeConfig {
TMConfig: tmc,
SkipFailingGenesisTxs: true,
MaxGasPerBlock: 10_000_000_000,
LoadConfig: &packages.LoadConfig{Deps: true},
}
}

Expand Down Expand Up @@ -98,7 +100,7 @@ type Node struct {
var DefaultFee = std.NewFee(50000, std.MustParseCoin(ugnot.ValueString(1000000)))

func NewDevNode(ctx context.Context, cfg *NodeConfig) (*Node, error) {
mpkgs, err := NewPackagesMap(cfg.PackagesPathList)
mpkgs, err := NewPackagesMap(cfg.LoadConfig, cfg.PackagesPathList)
if err != nil {
return nil, fmt.Errorf("unable map pkgs list: %w", err)
}
Expand Down Expand Up @@ -140,7 +142,7 @@ func (n *Node) Close() error {
return n.Node.Stop()
}

func (n *Node) ListPkgs() []gnomod.Pkg {
func (n *Node) ListPkgs() []*packages.Package {
n.muNode.RLock()
defer n.muNode.RUnlock()

Expand Down Expand Up @@ -240,20 +242,20 @@ func (n *Node) updatePackages(paths ...string) error {
}

// List all packages from target path
pkgslist, err := gnomod.ListPkgs(abspath)
pkgslist, err := packages.Load(n.config.LoadConfig, filepath.Join(abspath, "..."))
if err != nil {
return fmt.Errorf("failed to list gno packages for %q: %w", path, err)
}

// Update or add package in the current known list.
for _, pkg := range pkgslist {
n.pkgs[pkg.Dir] = Package{
Pkg: pkg,
Package: pkg,
Creator: deployer,
Deposit: deposit,
}

n.logger.Debug("pkgs update", "name", pkg.Name, "path", pkg.Dir)
n.logger.Debug("pkgs update", "name", pkg.ImportPath, "path", pkg.Dir)
}

pkgsUpdated += len(pkgslist)
Expand Down
2 changes: 1 addition & 1 deletion contribs/gnodev/pkg/dev/node_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func Render(_ string) string { return strconv.Itoa(value) }

// Call NewDevNode with no package should work
node, emitter := newTestingDevNode(t, counterPkg)
assert.Len(t, node.ListPkgs(), 1)
assert.Len(t, node.ListPkgs(), 23)

// Test rendering
render, err := testingRenderRealm(t, node, testCounterRealm)
Expand Down
1 change: 0 additions & 1 deletion contribs/gnodev/pkg/dev/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,6 @@ func newTestingDevNodeWithConfig(t *testing.T, cfg *NodeConfig) (*Node, *mock.Se

node, err := NewDevNode(ctx, cfg)
require.NoError(t, err)
assert.Len(t, node.ListPkgs(), len(cfg.PackagesPathList))

t.Cleanup(func() {
node.Close()
Expand Down
24 changes: 14 additions & 10 deletions contribs/gnodev/pkg/dev/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"github.com/gnolang/gno/contribs/gnodev/pkg/address"
"github.com/gnolang/gno/gno.land/pkg/gnoland"
vmm "github.com/gnolang/gno/gno.land/pkg/sdk/vm"
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
"github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/pkg/packages"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/std"
)
Expand Down Expand Up @@ -63,7 +63,7 @@ func ResolvePackagePathQuery(bk *address.Book, path string) (PackagePath, error)
}

type Package struct {
gnomod.Pkg
*packages.Package
Creator crypto.Address
Deposit std.Coins
}
Expand All @@ -75,7 +75,7 @@ var (
ErrEmptyDepositPackage = errors.New("no deposit specified for package")
)

func NewPackagesMap(ppaths []PackagePath) (PackagesMap, error) {
func NewPackagesMap(cfg *packages.LoadConfig, ppaths []PackagePath) (PackagesMap, error) {
pkgs := make(map[string]Package)
for _, ppath := range ppaths {
if ppath.Creator.IsZero() {
Expand All @@ -88,7 +88,7 @@ func NewPackagesMap(ppaths []PackagePath) (PackagesMap, error) {
}

// list all packages from target path
pkgslist, err := gnomod.ListPkgs(abspath)
pkgslist, err := packages.Load(cfg, filepath.Join(abspath, "..."))
if err != nil {
return nil, fmt.Errorf("listing gno packages: %w", err)
}
Expand All @@ -102,7 +102,7 @@ func NewPackagesMap(ppaths []PackagePath) (PackagesMap, error) {
continue // skip
}
pkgs[pkg.Dir] = Package{
Pkg: pkg,
Package: pkg,
Creator: ppath.Creator,
Deposit: ppath.Deposit,
}
Expand All @@ -112,10 +112,10 @@ func NewPackagesMap(ppaths []PackagePath) (PackagesMap, error) {
return pkgs, nil
}

func (pm PackagesMap) toList() gnomod.PkgList {
list := make([]gnomod.Pkg, 0, len(pm))
func (pm PackagesMap) toList() packages.PkgList {
list := make([]*packages.Package, 0, len(pm))
for _, pkg := range pm {
list = append(list, pkg.Pkg)
list = append(list, pkg.Package)
}
return list
}
Expand All @@ -132,13 +132,17 @@ func (pm PackagesMap) Load(fee std.Fee, start time.Time) ([]gnoland.TxWithMetada

metatxs := make([]gnoland.TxWithMetadata, 0, len(nonDraft))
for _, modPkg := range nonDraft {
if modPkg.ImportPath == "" || gnolang.IsStdlib(modPkg.ImportPath) {
continue
}

pkg := pm[modPkg.Dir]
if pkg.Creator.IsZero() {
return nil, fmt.Errorf("no creator set for %q", pkg.Dir)
}

// Open files in directory as MemPackage.
memPkg := gno.MustReadMemPackage(modPkg.Dir, modPkg.Name)
memPkg := gnolang.MustReadMemPackage(modPkg.Dir, modPkg.ImportPath)
if err := memPkg.Validate(); err != nil {
return nil, fmt.Errorf("invalid package: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions contribs/gnodev/pkg/watcher/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (

emitter "github.com/gnolang/gno/contribs/gnodev/pkg/emitter"
events "github.com/gnolang/gno/contribs/gnodev/pkg/events"
"github.com/gnolang/gno/gnovm/pkg/packages"

"github.com/fsnotify/fsnotify"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
)

type PackageWatcher struct {
Expand Down Expand Up @@ -118,7 +118,7 @@ func (p *PackageWatcher) Stop() {
// Packages are sorted by their length in descending order to facilitate easier
// and more efficient matching with corresponding paths. The longest paths are
// compared first.
func (p *PackageWatcher) AddPackages(pkgs ...gnomod.Pkg) error {
func (p *PackageWatcher) AddPackages(pkgs ...*packages.Package) error {
for _, pkg := range pkgs {
dir := pkg.Dir

Expand Down
7 changes: 4 additions & 3 deletions contribs/gnogenesis/internal/txs/txs_add_packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (
"fmt"
"os"

"github.com/gnolang/gno/tm2/pkg/crypto/keys"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot"
"github.com/gnolang/gno/gnovm/pkg/packages"
"github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/keys"
"github.com/gnolang/gno/tm2/pkg/std"
)

Expand Down Expand Up @@ -125,7 +125,8 @@ func execTxsAddPackages(
parsedTxs := make([]gnoland.TxWithMetadata, 0)
for _, path := range args {
// Generate transactions from the packages (recursively)
txs, err := gnoland.LoadPackagesFromDir(path, creator, genesisDeployFee)
loadCfg := &packages.LoadConfig{IO: io, Deps: true}
txs, err := gnoland.LoadPackagesFromDir(loadCfg, path, creator, genesisDeployFee)
if err != nil {
return fmt.Errorf("unable to load txs from directory, %w", err)
}
Expand Down
16 changes: 8 additions & 8 deletions examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,29 @@ GOIMPORTS_FLAGS ?= $(GOFMT_FLAGS)
GOTEST_FLAGS ?= -v -p 1 -timeout=30m

# Official packages (non-overridable): more reliable and tested modules, distinct from the experimentation area.
OFFICIAL_PACKAGES = ./gno.land/p
OFFICIAL_PACKAGES += ./gno.land/r/demo
OFFICIAL_PACKAGES += ./gno.land/r/gnoland
OFFICIAL_PACKAGES += ./gno.land/r/sys
OFFICIAL_PACKAGES += ./gno.land/r/gov
OFFICIAL_PACKAGES = ./gno.land/p/...
OFFICIAL_PACKAGES += ./gno.land/r/demo/...
OFFICIAL_PACKAGES += ./gno.land/r/gnoland/...
OFFICIAL_PACKAGES += ./gno.land/r/sys/...
OFFICIAL_PACKAGES += ./gno.land/r/gov/...

########################################
# Dev tools
.PHONY: transpile
transpile:
go run ../gnovm/cmd/gno transpile -v .
go run ../gnovm/cmd/gno transpile -v ./...

.PHONY: build
build:
go run ../gnovm/cmd/gno transpile -v --gobuild .
go run ../gnovm/cmd/gno transpile -v --gobuild ./...

.PHONY: test
test:
go run ../gnovm/cmd/gno test -v ./...

.PHONY: lint
lint:
go run ../gnovm/cmd/gno lint -v $(OFFICIAL_PACKAGES)
go run ../gnovm/cmd/gno lint --root-examples -v $(OFFICIAL_PACKAGES)

.PHONY: test.sync
test.sync:
Expand Down
2 changes: 1 addition & 1 deletion examples/gno.land/p/moul/md/md_test.gno
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package md
package md_test

import (
"testing"
Expand Down
2 changes: 1 addition & 1 deletion examples/gno.land/r/gnoland/faucet/faucet_test.gno
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package faucet
package faucet_test

import (
"std"
Expand Down
117 changes: 117 additions & 0 deletions examples/no_cycles_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package examples_test

import (
"fmt"
"path/filepath"
"slices"
"strings"
"testing"

"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/gnovm/pkg/packages"
"github.com/stretchr/testify/require"
)

var injectedTestingLibs = []string{"encoding/json", "fmt", "os", "internal/os_test"}

// TestNoCycles checks that there is no import cycles in stdlibs and non-draft examples
func TestNoCycles(t *testing.T) {
// find examples and stdlibs
cfg := &packages.LoadConfig{SelfContained: true, Deps: true}
pkgs, err := packages.Load(cfg, filepath.Join(gnoenv.RootDir(), "examples", "..."))
require.NoError(t, err)

// detect cycles
visited := make(map[string]bool)
for _, p := range pkgs {
if p.Draft {
continue
}
require.NoError(t, detectCycles(p, pkgs, visited))
}
}

// detectCycles detects import cycles
//
// We need to check
// 3 kinds of nodes
//
// - normal pkg: compiled source
//
// - xtest pkg: external test source (include xtests and filetests), can be treated as their own package
//
// - test pkg: embedded test sources,
// these should not have their corresponding normal package in their dependencies tree
//
// The tricky thing is that we need to split test sources and normal source
// while not considering them as distincitive packages.
// Otherwise we will have false positive for example if we have these edges:
//
// - foo_pkg/foo_test.go imports bar_pkg
//
// - bar_pkg/bar_test.go import foo_pkg
//
// In go, the above example is allowed
// but the following is not
//
// - foo_pkg/foo.go imports bar_pkg
//
// - bar_pkg/bar_test.go imports foo_pkg
func detectCycles(root *packages.Package, pkgs []*packages.Package, visited map[string]bool) error {
// check cycles in package's sources
stack := []string{}
if err := visitPackage(root, pkgs, visited, stack); err != nil {
return fmt.Errorf("pkgsrc import: %w", err)
}
// check cycles in external tests' dependencies we might have missed
if err := visitImports([]packages.FileKind{packages.FileKindXTest, packages.FileKindFiletest}, root, pkgs, visited, stack); err != nil {
return fmt.Errorf("xtest import: %w", err)
}

// check cycles in tests' imports by marking the current package as visited while visiting the tests' imports
// we also consider PackageSource imports here because tests can call package code
visited = map[string]bool{root.ImportPath: true}
stack = []string{root.ImportPath}
if err := visitImports([]packages.FileKind{packages.FileKindPackageSource, packages.FileKindTest}, root, pkgs, visited, stack); err != nil {
return fmt.Errorf("test import: %w", err)
}

return nil
}

// visitImports resolves and visits imports by kinds
func visitImports(kinds []packages.FileKind, root *packages.Package, pkgs []*packages.Package, visited map[string]bool, stack []string) error {
for _, imp := range root.Imports.Merge(kinds...) {
if slices.Contains(injectedTestingLibs, imp) {
continue
}
idx := slices.IndexFunc(pkgs, func(p *packages.Package) bool { return p.ImportPath == imp })
if idx == -1 {
return fmt.Errorf("import %q not found for %q tests", imp, root.ImportPath)
}
if err := visitPackage(pkgs[idx], pkgs, visited, stack); err != nil {
return fmt.Errorf("test import error: %w", err)
}
}

return nil
}

// visitNode visits a package and its imports recursively. It only considers imports in PackageSource
func visitPackage(pkg *packages.Package, pkgs []*packages.Package, visited map[string]bool, stack []string) error {
if slices.Contains(stack, pkg.ImportPath) {
return fmt.Errorf("cycle detected: %s -> %s", strings.Join(stack, " -> "), pkg.ImportPath)
}
if visited[pkg.ImportPath] {
return nil
}

visited[pkg.ImportPath] = true
stack = append(stack, pkg.ImportPath)

if err := visitImports([]packages.FileKind{packages.FileKindPackageSource}, pkg, pkgs, visited, stack); err != nil {
return err
}

return nil
}
Loading
Loading