예제 #1
0
파일: build.go 프로젝트: kpsmith/gopherjs
func (s *Session) BuildPackage(pkg *PackageData) error {
	s.Packages[pkg.ImportPath] = pkg
	if pkg.ImportPath == "unsafe" {
		return nil
	}

	if pkg.PkgObj != "" {
		var fileInfo os.FileInfo
		gopherjsBinary, err := osext.Executable()
		if err == nil {
			fileInfo, err = os.Stat(gopherjsBinary)
			if err == nil {
				pkg.SrcModTime = fileInfo.ModTime()
			}
		}
		if err != nil {
			os.Stderr.WriteString("Could not get GopherJS binary's modification timestamp. Please report issue.\n")
			pkg.SrcModTime = time.Now()
		}

		for _, importedPkgPath := range pkg.Imports {
			ignored := true
			for _, pos := range pkg.ImportPos[importedPkgPath] {
				importFile := filepath.Base(pos.Filename)
				for _, file := range pkg.GoFiles {
					if importFile == file {
						ignored = false
						break
					}
				}
				if !ignored {
					break
				}
			}
			if importedPkgPath == "unsafe" || ignored {
				continue
			}
			_, err := s.ImportPackage(importedPkgPath)
			if err != nil {
				return err
			}
			impModeTime := s.Packages[importedPkgPath].SrcModTime
			if impModeTime.After(pkg.SrcModTime) {
				pkg.SrcModTime = impModeTime
			}
		}

		for _, name := range pkg.GoFiles {
			fileInfo, err := os.Stat(filepath.Join(pkg.Dir, name))
			if err != nil {
				return err
			}
			if fileInfo.ModTime().After(pkg.SrcModTime) {
				pkg.SrcModTime = fileInfo.ModTime()
			}
		}

		pkgObjFileInfo, err := os.Stat(pkg.PkgObj)
		if err == nil && !pkg.SrcModTime.After(pkgObjFileInfo.ModTime()) {
			// package object is up to date, load from disk if library
			pkg.UpToDate = true
			if pkg.IsCommand() {
				return nil
			}

			objFile, err := ioutil.ReadFile(pkg.PkgObj)
			if err != nil {
				return err
			}

			pkg.Archive, err = compiler.UnmarshalArchive(pkg.PkgObj, pkg.ImportPath, objFile, s.ImportContext)
			if err != nil {
				return err
			}

			return nil
		}
	}

	fileSet := token.NewFileSet()
	files, err := Parse(pkg.Package, fileSet)
	if err != nil {
		return err
	}
	pkg.Archive, err = compiler.Compile(pkg.ImportPath, files, fileSet, s.ImportContext, s.options.Minify)
	if err != nil {
		return err
	}

	if s.options.Verbose {
		fmt.Println(pkg.ImportPath)
	}

	if pkg.PkgObj == "" || pkg.IsCommand() {
		return nil
	}

	if err := s.writeLibraryPackage(pkg, pkg.PkgObj); err != nil {
		if strings.HasPrefix(pkg.PkgObj, s.options.GOROOT) {
			// fall back to first GOPATH workspace
			firstGopathWorkspace := filepath.SplitList(s.options.GOPATH)[0]
			if err := s.writeLibraryPackage(pkg, filepath.Join(firstGopathWorkspace, pkg.PkgObj[len(s.options.GOROOT):])); err != nil {
				return err
			}
			return nil
		}
		return err
	}

	return nil
}
예제 #2
0
func control(scope *angularjs.Scope) {
	scope.Set("code", initCode)
	// scope.Set("showGenerated", false)
	// scope.Set("generated", `(generated code will be shown here after clicking "Run")`)

	packages := make(map[string]*compiler.Archive)
	var pkgsToLoad []string
	importContext := compiler.NewImportContext(
		func(path string) (*compiler.Archive, error) {
			if pkg, found := packages[path]; found {
				return pkg, nil
			}
			pkgsToLoad = append(pkgsToLoad, path)
			return &compiler.Archive{}, nil
		},
	)
	fileSet := token.NewFileSet()
	pkgsReceived := 0

	setupEnvironment(scope)

	var run func(bool)
	run = func(loadOnly bool) {
		output = nil
		scope.Set("output", output)
		pkgsToLoad = nil

		file, err := parser.ParseFile(fileSet, "prog.go",
			getCode(), parser.ParseComments,
		)
		if err != nil {
			if list, ok := err.(scanner.ErrorList); ok {
				for _, entry := range list {
					output = append(output, errErrLine(entry))
				}
				scope.Set("output", output)
				return
			}
			scope.Set("output", []Line{errErrLine(err)})
			return
		}

		mainPkg, err := compiler.Compile("main",
			[]*ast.File{file}, fileSet,
			importContext, false,
		)
		packages["main"] = mainPkg
		if err != nil && len(pkgsToLoad) == 0 {
			if list, ok := err.(compiler.ErrorList); ok {
				output := make([]Line, 0)
				for _, entry := range list {
					output = append(output, errErrLine(entry))
				}
				scope.Set("output", output)
				return
			}
			scope.Set("output", []Line{errErrLine(err)})
			return
		}

		var allPkgs []*compiler.Archive
		if len(pkgsToLoad) == 0 {
			for _, depPath := range mainPkg.Dependencies {
				dep, _ := importContext.Import(string(depPath))
				allPkgs = append(allPkgs, dep)
			}
			allPkgs = append(allPkgs, mainPkg)
		}

		if len(pkgsToLoad) != 0 {
			pkgsReceived = 0
			for _, p := range pkgsToLoad {
				path := p

				req := js.Global.Get("XMLHttpRequest").New()
				req.Call("open", "GET", "pkg/"+path+".a", true)
				req.Set("responseType", "arraybuffer")
				req.Set("onload", func() {
					if req.Get("status").Int() != 200 {

						f := func() {
							emsg := fmt.Sprintf("cannot load package \"%s\"", path)
							scope.Set("output", []Line{errLine(emsg)})
						}
						scope.Apply(f)
						return
					}

					data := js.Global.Get("Uint8Array").New(req.Get("response")).Interface().([]byte)
					packages[path], err = compiler.UnmarshalArchive(
						path+".a", path, []byte(data), importContext,
					)
					if err != nil {
						scope.Apply(func() {
							scope.Set("output", []Line{errErrLine(err)})
						})
						return
					}
					pkgsReceived++
					if pkgsReceived == len(pkgsToLoad) {
						run(loadOnly)
					}
				})
				req.Call("send")
			}
			return
		}

		if loadOnly {
			return
		}

		mainPkgCode := bytes.NewBuffer(nil)
		compiler.WritePkgCode(packages["main"], false,
			&compiler.SourceMapFilter{Writer: mainPkgCode},
		)
		// scope.Set("generated", mainPkgCode.String())

		jsCode := bytes.NewBuffer(nil)
		jsCode.WriteString("try{\n")
		compiler.WriteProgramCode(allPkgs, importContext,
			&compiler.SourceMapFilter{Writer: jsCode},
		)
		jsCode.WriteString("} catch (err) {\ngoPanicHandler(err.message);\n}\n")
		js.Global.Call("eval", js.InternalObject(jsCode.String()))
	}

	scope.Set("run", run)
	run(true)

	scope.Set("format", func() {
		out, err := format.Source(getCode())
		if err != nil {
			scope.Set("output", []Line{errErrLine(err)})
			return
		}

		setCode(string(out))
		scope.Set("output", []Line{})
	})
}