func main() { // This turns off focus reporting mode that will print “^[[O” and “^[[I” // when the terminal window gets / loses focus // http://superuser.com/questions/931873/o-and-i-appearing-on-iterm2-when-focus-lost fmt.Print("\033[?1004l") ctx, cancel, err := process.Initialise(context.Background(), nil) if err != nil { fmt.Println(err) os.Exit(1) } env := envctx.FromContext(ctx) cmd := cmdctx.FromContext(ctx) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) signal.Notify(c, syscall.SIGTERM) go func() { <-c cancel() }() if err := process.GenerateAll(ctx, env.Path, map[string]bool{}); err != nil { fmt.Println(err.Error()) wgctx.WaitAndExit(ctx, 1) } if cmd.Validate { err := process.RunValidateCommand(ctx) if err != nil { if !cmd.Log { // in log mode, we have already written the output of the exec'ed ke command, // so we don't need to duplicate the error message. if v, ok := kerr.Source(err).(validate.ValidationCommandError); ok { fmt.Println(v.Description) wgctx.WaitAndExit(ctx, 4) // Exit code 4: validation error } fmt.Println(err.Error()) } wgctx.WaitAndExit(ctx, 1) } } if cmd.Edit { if err = server.Start(ctx, cancel); err != nil { fmt.Println(err.Error()) wgctx.WaitAndExit(ctx, 1) } } wgctx.WaitAndExit(ctx, 0) }
func scanForPackage(ctx context.Context, env *envctx.Env) (*system.Package, error) { localContext := envctx.NewContext(ctx, env) files := scanner.ScanDirToFiles(ctx, env.Dir, false) bytes := scanner.ScanFilesToBytes(ctx, files) for b := range bytes { if b.Err != nil { return nil, kerr.Wrap("GATNNQKNHY", b.Err, b.File) } o := &system.ObjectStub{} if err := system.Unmarshal(localContext, b.Bytes, o); err != nil { switch kerr.Source(err).(type) { case system.UnknownPackageError, system.UnknownTypeError: // don't return error default: return nil, kerr.Wrap("MTDCXBYBEJ", err, b.File) } } if o.Type == nil { return nil, kerr.New("MSNIGTIDIO", "%s has no type", b.File) } switch *o.Type { case *system.NewReference("kego.io/system", "package"): var i interface{} err := system.Unmarshal(localContext, b.Bytes, &i) if err != nil { switch kerr.Source(err).(type) { case system.UnknownPackageError, system.UnknownTypeError: // don't return error default: return nil, kerr.Wrap("XTEQCAYQJP", err) } } if pkg, ok := i.(*system.Package); ok { return pkg, nil } } } return nil, nil }
func root(ctx context.Context, w http.ResponseWriter, req *http.Request, auth auther.Auther) error { wgctx.Add(ctx, "root") defer wgctx.Done(ctx, "root") if b, err := static.Asset(req.URL.Path[1:]); err == nil { if strings.HasSuffix(req.URL.Path, ".css") { w.Header().Set("Content-Type", "text/css") } if err := writeWithTimeout(w, b); err != nil { return kerr.Wrap("PVPCXBIUJT", err) } return nil } path := req.URL.Path[1:] if strings.HasSuffix(path, "/") { path = path[0 : len(path)-1] } // use a new context with a blank sysctx for the duration of this function // to prevent caching ctx = sysctx.NewContext(ctx) scache := sysctx.FromContext(ctx) env, err := parser.ScanForEnv(ctx, path) if err != nil { if _, ok := kerr.Source(err).(gopackages.NotFoundError); ok { w.WriteHeader(404) return nil } return kerr.Wrap("ALINBMKDRP", err) } pcache, err := parser.Parse(ctx, path) if err != nil { return kerr.Wrap("HIHWJRPUKE", err) } if err := process.GenerateAll(ctx, env.Path, map[string]bool{}); err != nil { return kerr.Wrap("LVGHABDYNQ", err) } data := map[string]string{} for _, name := range pcache.Globals.Keys() { if g, ok := pcache.Globals.Get(name); ok { data[name] = g.File } } pkgBytes := pcache.PackageBytes pkgFilename := pcache.PackageFilename if pkgBytes == nil { b, err := system.Marshal(ctx, system.EmptyPackage()) if err != nil { return kerr.Wrap("OUBOTYGPKU", err) } pkgBytes = b pkgFilename = "package.ke.json" } imports := map[string]shared.ImportInfo{} var scan func(string) error scan = func(path string) error { if _, ok := imports[path]; ok { return nil } syspi, ok := scache.Get(path) if !ok { return kerr.New("VIGKIUPNCF", "%s not found in sys ctx", path) } info := shared.ImportInfo{ Path: path, Aliases: syspi.Aliases, Types: map[string]shared.TypeInfo{}, } for _, name := range syspi.Files.Keys() { if b, ok := syspi.Files.Get(name); ok { info.Types[name] = shared.TypeInfo{ File: b.File, Bytes: b.Bytes, } } } imports[path] = info for _, child := range syspi.Aliases { if err := scan(child); err != nil { return kerr.Wrap("NCULMUUUOT", err) } } return nil } // First we always import system if err := scan("kego.io/system"); err != nil { return kerr.Wrap("KRXSLOJKWV", err) } if err := scan(env.Path); err != nil { return kerr.Wrap("EELKQDCJGN", err) } info := shared.Info{ Path: env.Path, Aliases: env.Aliases, Data: data, Package: pkgBytes, PackageFilename: pkgFilename, Imports: imports, Hash: auth.Sign([]byte(env.Path)), } buf := bytes.NewBuffer([]byte{}) err = gob.NewEncoder(buf).Encode(info) if err != nil { return kerr.Wrap("OHBYTULHUQ", err) } base64EncodedString := base64.StdEncoding.EncodeToString(buf.Bytes()) attrib := base64EncodedString source := []byte(` <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/bootstrap/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="/split.css"> <link rel="stylesheet" href="/editors.css"> <link rel="stylesheet" href="/tree.css"> <script src="/jquery-2.2.4.min.js"></script> <script src="/jquery-ui/jquery-ui.min.js"></script> <script src="/split.min.js"></script> <script src="/bootstrap/js/bootstrap.min.js"></script> <link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo="> </head> <body id="body" info="` + attrib + `"></body> <script src="/` + env.Path + `/script.js"></script> </html>`) if err := writeWithTimeout(w, source); err != nil { return kerr.Wrap("ICJSAIMDRF", err) } return nil }
func TestReferenceUnmarshal(t *testing.T) { reset := func() *Reference { // Let's pre-load with some values so we check that when we // load a null value, we clear all the fields r := NewReference("a.b/c", "d") return r } r := reset() err := r.Unpack(envctx.Empty, Pack(nil), false) assert.IsError(t, err, "MOQVSKJXRB") r = reset() err = r.Unpack(envctx.Empty, Pack(1.0), false) assert.IsError(t, err, "RFLQSBPMYM") r = reset() err = r.Unpack(envctx.Empty, Pack("a.b/c:d"), false) assert.IsError(t, err, "MSXBLEIGVJ") assert.HasError(t, err, "KJSOXDESFD") p, ok := kerr.Source(err).(UnknownPackageError) assert.True(t, ok) assert.Equal(t, "a.b/c", p.UnknownPackage) ctx := tests.Context("").Alias("c", "a.b/c").Ctx() r = reset() err = r.Unpack(ctx, Pack("a.b/c:d"), false) require.NoError(t, err) assert.NotNil(t, r) assert.Equal(t, "a.b/c", r.Package) assert.Equal(t, "d", r.Name) assert.Equal(t, "a.b/c:d", r.Value()) r = reset() err = r.Unpack(ctx, Pack(map[string]interface{}{ "type": "system:reference", "value": "a.b/c:d", }), false) require.NoError(t, err) assert.NotNil(t, r) assert.Equal(t, "a.b/c", r.Package) assert.Equal(t, "d", r.Name) assert.Equal(t, "a.b/c:d", r.Value()) r = reset() err = r.Unpack(ctx, Pack("a.b/c:@d"), false) require.NoError(t, err) assert.NotNil(t, r) assert.Equal(t, "a.b/c", r.Package) assert.Equal(t, "@d", r.Name) assert.Equal(t, "a.b/c:@d", r.Value()) r = reset() err = r.Unpack(envctx.Empty, Pack("a:b"), false) assert.IsError(t, err, "MSXBLEIGVJ") assert.HasError(t, err, "DKKFLKDKYI") p, ok = kerr.Source(err).(UnknownPackageError) assert.True(t, ok) assert.Equal(t, "a", p.UnknownPackage) r = reset() err = r.UnmarshalInterface(envctx.Empty, 1) require.NoError(t, err) assert.Equal(t, *NewReference("", ""), *r) r = reset() err = r.UnmarshalInterface(envctx.Empty, "") require.NoError(t, err) assert.Equal(t, *NewReference("", ""), *r) r = reset() err = r.UnmarshalInterface(envctx.Empty, "a.b/c:d") assert.IsError(t, err, "ETLPLMMWCC") r = reset() err = r.UnmarshalInterface(tests.Context("a.b/c").Ctx(), "a.b/c:d") require.NoError(t, err) assert.Equal(t, *NewReference("a.b/c", "d"), *r) }
func TestRun(t *testing.T) { cb := tests.New().RealGopath() defer cb.Cleanup() path, dir := cb.TempPackage("d", map[string]string{ "a.yaml": ` type: system:type id: a fields: b: type: system:@string max-length: 5`, "d.go": `package d`, }) cb.Path(path).Dir(dir).Jauto().Wg().Sauto(parser.Parse) env := envctx.FromContext(cb.Ctx()) err := Generate(cb.Ctx(), env) require.NoError(t, err) b, err := ioutil.ReadFile(filepath.Join(dir, "generated.go")) require.NoError(t, err) assert.Contains(t, string(b), `pkg.Init(`) assert.Contains(t, string(b), `func() interface{} { return new(A) },`) assert.Contains(t, string(b), `func() interface{} { return new(ARule) },`) assert.Contains(t, string(b), `func() reflect.Type { return reflect.TypeOf((*AInterface)(nil)).Elem() },`) assert.Contains(t, string(b), fmt.Sprintf("%v", env.Hash)) err = RunValidateCommand(cb.Ctx()) require.NoError(t, err) file1, err := os.Stat(filepath.Join(dir, ".localke", "validate")) require.NoError(t, err) time1 := file1.ModTime() err = RunValidateCommand(cb.Ctx()) require.NoError(t, err) cb.TempFile("c.yaml", ` type: a id: c b: foo`) err = RunValidateCommand(cb.Ctx()) require.NoError(t, err) // should not rebuild validate command file2, err := os.Stat(filepath.Join(dir, ".localke", "validate")) require.NoError(t, err) time2 := file2.ModTime() assert.Equal(t, time1, time2) cb.TempFile("e.yaml", ` type: a id: e b: tooolong`) err = RunValidateCommand(cb.Ctx()) assert.IsError(t, err, "KFNIOHWCBT") assert.HasError(t, err, "ETWHPXTUVB") cb.TempFile("f.yaml", ` type: system:type id: f fields: a: type: system:@string`) // This loads the new system.Type into the system cache cb.Sauto(parser.Parse) // This generates a new generated.go err = Generate(cb.Ctx(), env) require.NoError(t, err) // This will re-run the build, but still return the validation error err = RunValidateCommand(cb.Ctx()) assert.IsError(t, err, "KFNIOHWCBT") assert.HasError(t, err, "ETWHPXTUVB") cb.RemoveTempFile("e.yaml") cb.TempFile("h.yaml", ` type: system:type id: h fields: a: type: system:@string`) // This loads the new system.Type into the system cache cb.Sauto(parser.Parse) // This generates a new generated.go err = Generate(cb.Ctx(), env) require.NoError(t, err) // This will re-run the build, but not return the validation error err = RunValidateCommand(cb.Ctx()) require.NoError(t, err) // should rebuild validate command file3, err := os.Stat(filepath.Join(dir, ".localke", "validate")) require.NoError(t, err) time3 := file3.ModTime() assert.NotEqual(t, time1, time3) cb.TempFile("g.yaml", ` type: system:type id: g fields: a: type: system:@string`) // We add a new type, but we haven't generated the struct, so it will fail with hash changed err = runValidateCommand(cb.Ctx(), false, false) assert.IsError(t, err, "DTTHRRJSSF") err = os.Remove(filepath.Join(dir, ".localke", "validate")) require.NoError(t, err) _, err = os.Stat(filepath.Join(dir, ".localke", "validate")) assert.True(t, os.IsNotExist(err)) err = runValidateCommand(cb.Ctx(), false, false) assert.IsError(t, err, "DTTHRRJSSF") _, ok := kerr.Source(err).(*os.PathError) assert.True(t, ok) }
func parse(ctx context.Context, path string, queue []string) (*sysctx.SysPackageInfo, error) { scache := sysctx.FromContext(ctx) cmd := cmdctx.FromContext(ctx) for _, q := range queue { if q == path { return nil, kerr.New("SCSCFJPPHD", "Circular import %v -> %v", queue, path) } } if _, found := scache.Get("kego.io/json"); !found { system.RegisterJsonTypes(ctx) } hash := &PackageHasher{Path: path, Aliases: map[string]string{}, Types: map[string]uint64{}, Exports: map[string]uint64{}} importPackage := func(importPath string, importAlias string) error { if _, found := scache.Get(importPath); !found { _, err := parse(ctx, importPath, append(queue, path)) if err != nil { return kerr.Wrap("RIARRSCMVE", err) } } hash.Aliases[importAlias] = importPath return nil } packageDirectoryExists := true _, err := packages.GetDirFromPackage(ctx, path) if err != nil { _, ok := kerr.Source(err).(gopackages.NotFoundError) if ok { packageDirectoryExists = false } } if !packageDirectoryExists || cmd.Update { if err := GoGet(ctx, path); err != nil { return nil, kerr.Wrap("SBALWXUPKN", err) } } env, err := ScanForEnv(ctx, path) if err != nil { return nil, kerr.Wrap("GJRHNGGWFD", err) } // Always scan the system package first if we don't have it already if path != "kego.io/system" { if err := importPackage("kego.io/system", "system"); err != nil { return nil, kerr.Wrap("ORRCDNUPOX", err) } } for aliasName, aliasPath := range env.Aliases { if aliasPath == "kego.io/system" || aliasName == "system" { return nil, kerr.New("EWMLNJDXKC", "Illegal import %s", aliasName) } if err := importPackage(aliasPath, aliasName); err != nil { return nil, kerr.Wrap("NOVMGYKHHI", err) } } pcache := scache.SetEnv(env) cmd.Printf("Parsing %s...", path) if err := scanForTypesAndExports(ctx, env, pcache, hash); err != nil { return nil, kerr.Wrap("VFUNPHUFHD", err) } cmd.Println(" OK.") h, err := hash.Hash() if err != nil { return nil, kerr.Wrap("MIODRYNEJQ", err) } env.Hash = h return pcache, nil }