aboutsummaryrefslogtreecommitdiff
path: root/content/appengine-gopath.article
diff options
context:
space:
mode:
Diffstat (limited to 'content/appengine-gopath.article')
-rw-r--r--content/appengine-gopath.article157
1 files changed, 157 insertions, 0 deletions
diff --git a/content/appengine-gopath.article b/content/appengine-gopath.article
new file mode 100644
index 0000000..d9f995b
--- /dev/null
+++ b/content/appengine-gopath.article
@@ -0,0 +1,157 @@
+# The App Engine SDK and workspaces (GOPATH)
+9 Jan 2013
+Tags: appengine, tools, gopath
+Summary: App Engine SDK 1.7.4 adds support for GOPATH-style workspaces.
+OldURL: /the-app-engine-sdk-and-workspaces-gopath
+
+Andrew Gerrand
+
+## Introduction
+
+When we released Go 1 we introduced the [go tool](https://golang.org/cmd/go/) and,
+with it, the concept of workspaces.
+Workspaces (specified by the GOPATH environment variable) are a convention
+for organizing code that simplifies fetching,
+building, and installing Go packages.
+If you're not familiar with workspaces, please read [this article](https://golang.org/doc/code.html)
+or watch [this screencast](http://www.youtube.com/watch?v=XCsL89YtqCs) before reading on.
+
+Until recently, the tools in the App Engine SDK were not aware of workspaces.
+Without workspaces the "[go get](https://golang.org/cmd/go/#hdr-Download_and_install_packages_and_dependencies)"
+command cannot function,
+and so app authors had to install and update their app dependencies manually. It was a pain.
+
+This has all changed with version 1.7.4 of the App Engine SDK.
+The [dev\_appserver](https://developers.google.com/appengine/docs/go/tools/devserver)
+and [appcfg](https://developers.google.com/appengine/docs/go/tools/uploadinganapp)
+tools are now workspace-aware.
+When running locally or uploading an app,
+these tools now search for dependencies in the workspaces specified by the
+GOPATH environment variable.
+This means you can now use "go get" while building App Engine apps,
+and switch between normal Go programs and App Engine apps without changing
+your environment or habits.
+
+For example, let's say you want to build an app that uses OAuth 2.0 to authenticate
+with a remote service.
+A popular OAuth 2.0 library for Go is the [oauth2](https://godoc.org/golang.org/x/oauth2) package,
+which you can install to your workspace with this command:
+
+ go get golang.org/x/oauth2
+
+When writing your App Engine app, import the oauth package just as you would in a regular Go program:
+
+ import "golang.org/x/oauth2"
+
+Now, whether running your app with the dev\_appserver or deploying it with appcfg,
+the tools will find the oauth package in your workspace. It just works.
+
+## Hybrid stand-alone/App Engine apps
+
+The Go App Engine SDK builds on Go's standard [net/http](https://golang.org/pkg/net/http/)
+package to serve web requests and,
+as a result, many Go web servers can be run on App Engine with only a few changes.
+For example, [godoc](https://golang.org/cmd/godoc/) is included in the
+Go distribution as a stand-alone program,
+but it can also run as an App Engine app (godoc serves [golang.org](https://golang.org/) from App Engine).
+
+But wouldn't it be nice if you could write a program that is both a stand-alone
+web server and an App Engine app? By using [build constraints](https://golang.org/pkg/go/build/#hdr-Build_Constraints), you can.
+
+Build constraints are line comments that determine whether a file should
+be included in a package.
+They are most often used in code that handles a variety of operating systems
+or processor architectures.
+For instance, the [path/filepath](https://golang.org/pkg/path/filepath/)
+package includes the file [symlink.go](https://golang.org/src/pkg/path/filepath/symlink.go),
+which specifies a build constraint to ensure that it is not built on Windows
+systems (which do not have symbolic links):
+
+ // +build !windows
+
+The App Engine SDK introduces a new build constraint term: "appengine". Files that specify
+
+ // +build appengine
+
+will be built by the App Engine SDK and ignored by the go tool. Conversely, files that specify
+
+ // +build !appengine
+
+are ignored by the App Engine SDK, while the go tool will happily build them.
+
+The [goprotobuf](http://code.google.com/p/goprotobuf/) library uses this
+mechanism to provide two implementations of a key part of its encode/decode machinery:
+[pointer\_unsafe.go](http://code.google.com/p/goprotobuf/source/browse/proto/pointer_unsafe.go)
+is the faster version that cannot be used on App Engine because it uses
+the [unsafe package](https://golang.org/pkg/unsafe/),
+while [pointer\_reflect.go](http://code.google.com/p/goprotobuf/source/browse/proto/pointer_reflect.go)
+is a slower version that avoids unsafe by using the [reflect package](https://golang.org/pkg/reflect/) instead.
+
+Let's take a simple Go web server and turn it into a hybrid app. This is main.go:
+
+ package main
+
+ import (
+ "fmt"
+ "net/http"
+ )
+
+ func main() {
+ http.HandleFunc("/", handler)
+ http.ListenAndServe("localhost:8080", nil)
+ }
+
+ func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprint(w, "Hello!")
+ }
+
+Build this with the go tool and you'll get a stand-alone web server executable.
+
+The App Engine infrastructure provides its own main function that runs its
+equivalent to ListenAndServe.
+To convert main.go to an App Engine app, drop the call to ListenAndServe
+and register the handler in an init function (which runs before main). This is app.go:
+
+ package main
+
+ import (
+ "fmt"
+ "net/http"
+ )
+
+ func init() {
+ http.HandleFunc("/", handler)
+ }
+
+ func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprint(w, "Hello!")
+ }
+
+To make this a hybrid app, we need to split it into an App Engine-specific part,
+an stand-alone binary-specific part, and the parts common to both versions.
+In this case, there is no App Engine-specific part,
+so we split it into just two files:
+
+app.go specifies and registers the handler function.
+It is identical to the code listing above,
+and requires no build constraints as it should be included in all versions of the program.
+
+main.go runs the web server. It includes the "!appengine" build constraint,
+as it must only included when building the stand-alone binary.
+
+ // +build !appengine
+
+ package main
+
+ import "net/http"
+
+ func main() {
+ http.ListenAndServe("localhost:8080", nil)
+ }
+
+To see a more complex hybrid app, take a look at the [present tool](https://godoc.org/golang.org/x/tools/present).
+
+## Conclusions
+
+We hope these changes will make it easier to work on apps with external dependencies,
+and to maintain code bases that contain both stand-alone programs and App Engine apps.