dave / forky

A tool to automate forking and modifying codebases
8 stars 1 forks source link

Inject virtual "flag" package and replace calls #6

Open dave opened 6 years ago

dave commented 6 years ago

Same as https://github.com/dave/forky/issues/5 but for the flag package.

roscopecoltran commented 5 years ago

Hi Dave,

Hope you are all well again !

Parse package AST and repack codebases based on custom templates

Context

I have forked the amalgomate program which is go program, that programmatically combines the source code of separate stand-alone Go programs into a single combined program. It also provides a library and invocation mechanism for invoking the original programs from the combined program. Amalgomate can be used to create a single executable that combines the functionality of several stand-alone executables. This provides advantages such as reducing the over-all size, locking in versions, creating a single point of execution and allowing the program to implement logic that makes use of its component programs.

Goals

Parsing go packages with the forky/golib/dst combo and be able to match some user-defined declarations in order to repack/rebundle a unique package or some amalgomated packages.

Playground

I created some public playgrounds for making everybody's life easier but it won't work as play.jsgo.io's filesystem is not writable but you can test it locally. Link: https://play.jsgo.io/df0b88edb687b16597f41a33d6fd4a70b8799d23

Real-World Use cases

Repacking flags from native flags or most popular cli libs declarations

import ( "fmt" "os" "sort"

flogogen "cranepp/internal/github.com/TIBCOSoftware/flogo-cli/cmd/flogogen"
swaggable "cranepp/internal/github.com/artheus/swaggable"
wuzz "cranepp/internal/github.com/asciimoo/wuzz"
gotodo "cranepp/internal/github.com/asticode/go-astitodo/astitodo"
jargon "cranepp/internal/github.com/clipperhouse/jargon/cmd/jargon"
forky "cranepp/internal/github.com/dave/forky/forkgo"
gocmplx "cranepp/internal/github.com/drathier/gocmplx"
zoekt "cranepp/internal/github.com/google/zoekt/cmd/zoekt"
zoekt_git_index "cranepp/internal/github.com/google/zoekt/cmd/zoekt-git-index"
zoekt_index "cranepp/internal/github.com/google/zoekt/cmd/zoekt-index"
htcat "cranepp/internal/github.com/htcat/htcat/cmd/htcat"
autoreadme "cranepp/internal/github.com/jimmyfrasche/autoreadme"
doc2json "cranepp/internal/github.com/jimmyfrasche/doc2json"
mage "cranepp/internal/github.com/magefile/mage"
crane "cranepp/internal/github.com/michaelsauter/crane"
interfacer "cranepp/internal/github.com/orisano/impast/cmd/interfacer"
mocker "cranepp/internal/github.com/orisano/impast/cmd/mocker"
stuber "cranepp/internal/github.com/orisano/impast/cmd/stuber"
fgen "cranepp/internal/github.com/retgits/fgen"
fweb "cranepp/internal/github.com/retgits/flogowebhelper"
src_cli "cranepp/internal/github.com/sourcegraph/src-cli/cmd/src"
src_scan "cranepp/internal/github.com/sourcegraph/srcscan/cmd/srcscan"
zoekt_sg_indexer "cranepp/internal/github.com/sourcegraph/zoekt/cmd/zoekt-sourcegraph-indexserver"
jsonschema2go "cranepp/internal/github.com/taskcluster/jsonschema2go/jsonschema2go"
gomutate "cranepp/internal/github.com/zabawaba99/gomutate/cmd/gomutate"

)

var programs = map[string]func(){"autoreadme": func() { autoreadme.RepackedMain() }, "crane": func() { crane.RepackedMain() }, "doc2json": func() { doc2json.RepackedMain() }, "fgen": func() { fgen.RepackedMain() }, "flogogen": func() { flogogen.RepackedMain() }, "forky": func() { forky.RepackedMain() }, "fweb": func() { fweb.RepackedMain() }, "gocmplx": func() { gocmplx.RepackedMain() }, "gomutate": func() { gomutate.RepackedMain() }, "gotodo": func() { gotodo.RepackedMain() }, "htcat": func() { htcat.RepackedMain() }, "interfacer": func() { interfacer.RepackedMain() }, "jargon": func() { jargon.RepackedMain() }, "jsonschema2go": func() { jsonschema2go.RepackedMain() }, "mage": func() { mage.RepackedMain() }, "mocker": func() { mocker.RepackedMain() }, "src-cli": func() { src_cli.RepackedMain() }, "src-scan": func() { src_scan.RepackedMain() }, "stuber": func() { stuber.RepackedMain() }, "swaggable": func() { swaggable.RepackedMain() }, "wuzz": func() { wuzz.RepackedMain() }, "zoekt": func() { zoekt.RepackedMain() }, "zoekt-git-index": func() { zoekt_git_index.RepackedMain() }, "zoekt-index": func() { zoekt_index.RepackedMain() }, "zoekt-sg-indexer": func() { zoekt_sg_indexer.RepackedMain() }, }

func main() { if len(os.Args) < 2 { fmt.Println("Missing program argument. Valid values:", cmds()) os.Exit(1) }

programName := os.Args[1]
if _, ok := programs[programName]; !ok {
    fmt.Printf("Unknown program: \"%v\". Valid values: %v\n", programName, cmds())
    os.Exit(1)
}

os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
programs[programName]()

}

func cmds() []string { var cmds []string for key := range programs { cmds = append(cmds, key) } sort.Strings(cmds) return cmds }



#### **Go Plugins**
Another use cases could be for go plugins; parse/match a package ast tree and unmarshal go plugins into/from structs. eg .https://github.com/tcard/pluginunmarshal, 

#### **Flogo Components/Contribs from a go package**
- generate flogo contribs on the fly based on templates, erf. https://github.com/retgits/fgen/blob/master/gen/activity.go#L60
- Good example, would be to create alternative activity components like https://github.com/mmussett/flogo-components/tree/master/activity/transform but from https://github.com/agrison/go-tablib. We could match exported functions with their arguments and generate the component by casting types of inputs (ref. https://github.com/mmussett/flogo-components/blob/master/activity/transform/activity.go#L37-L38) 

## Epilogue :-)
Hope that it sounds clear to you as it is only to assist in repacking librairies or programs by mixing amalgomate features with forky/dst features.... The real plus for all things mentioned above, it is that you have a UI for quick playgrounds that could be generated/repacked with a common/unique codebase.

Cheers,
Rosco
dave commented 5 years ago

Awesome work Rosco!

roscopecoltran commented 5 years ago

Sorry for the post below, but I needed to unload all the thoughts that inspired me the jsgo project. ^^ Is there a better way to manage/share suggestions from your perspective ?!

Current state

Actually, I am stucked at the flag declaration parsing/matching; that's how I found your work as I was looking after ast rewriting/decorating tools.

So if you have any insights or suggestions, on how to use dst or forky for describing all list of matching patterns into a yaml/json file, that would be awesome. so I can automate some parts of the repacking or content generation.

Btw, I am sure that there is a way to define builtin patterns for some popular libs (cobra, urfave); so it could incrementally store/update patterns per package release versions (boltdb or badger stores should be enough). It can be validated/moderated/ranked with some ci related features. Also, a jsonschema2struct plugin would help for more interop-services repacking.

So for now, I finished to create an abstraction interface preparing/ensuring deps/generating/building/dockerizing an amalgomated libs/programs or a standalone package (dep managers handled are dep,glide and gb for now). But always without having an abstraction layer for flags.

My current codebase is inspired by the following:

Extra suggestions based on ast parsing/refactoring

  1. Refactor/Analyze go packages with builtin patterns/schemas for user-defined cli/web/shim/custom repacking
  2. Build and dockerize repacked programs with custom entrypoint
  3. Create Virtual File System for go-git.v4/go-billy.v4;
    • Would enable monolithic repos management like https://github.com/Microsoft/VFSForGit, and manage gopath with more advanced forking/branching features on a large scale.
    • Extend the jsgo package dropdown menu by abstracting branches and their contents; will allow custom build context and playgrounds/sandboxes
  4. Generate Admin Interface from repacked libs or programs

Interesting codebases

CLI Generators:

Read-Write git vfs:

Read-Only git vfs:

Index git-content:

Go Plugins

Database abstraction service

Advanced use case: jsgo+Typescript+go pkgs+generators

For example, in flogo, you can create golang plugins but also create custom/additional js component for the flogo webui (docker image).

Some codebases that would fit nicely with jsgo:

Flogo Web In Action

Sorry again for this long post, but before switching to something else, I had to save a draft of what jsgo inspired me recently.

Rosco

dave commented 5 years ago

This is all great stuff - thanks for dropping it in here.