revelとは
- The Revel Web Framework for Go
- Go言語製のウェブフレームワークのひとつ
読む場所
% cd $GOPATH/src/github.com/revel/cmd
revel new hoge/fuga
revel/new.go
var cmdNew = &Command{ UsageLine: "new [path] [skeleton]", Short: "create a skeleton Revel application", Long: `略`, } // Command structって何だ?
revel/rev.go
// Cribbed from the genius organization of the "go" command. type Command struct { Run func(args []string) UsageLine, Short, Long string } func (cmd *Command) Name() string // 各サブコマンドの定義と説明文と、あと名前へのgetterだけっぽい
revel/new.go
func init() { cmdNew.Run = newApp } // 関数リテラルで宣言したフィールドに関数オブジェクトそのまま詰めれるのか
revel/new.go
func newApp(args []string) { // check for proper args by count if len(args) == 0 { errorf("No import path given.\nRun 'revel help new' for usage.\n") } if len(args) > 2 { errorf("Too many arguments provided.\nRun 'revel help new' for usage.\n") } // バリデーションしてる // checking and setting go paths initGoPaths() // ん?なんだこれ // 中断して見に行く
同ファイル
// lookup and set Go related variables // var gopath, srcRoot, gocmd string // の決定 func initGoPaths() { // lookup go path // $GOPATHを取得し、無かったらエラー gopath = build.Default.GOPATH if gopath == "" { errorf("Abort: GOPATH environment variable is not set. " + "Please refer to http://golang.org/doc/code.html to configure your Go environment.") } // set go src path // filepath.SplitList // 取得した$GOPATHがたとえば:つなぎ複数だった場合に、その最初を使う // そこに"src"をつなげたものを、Goのsrcパスとして決定する srcRoot = filepath.Join(filepath.SplitList(gopath)[0], "src") // check for go executable // 上記は$GOPATH/srcの決定。 // 下記はwhich goの決定 var err error gocmd, err = exec.LookPath("go") if err != nil { errorf("Go executable not found in PATH.") } }
ひきつづき、同ファイルnewAppの続き
// checking and setting application
setApplicationPath(args)
// importPath, appPath, appName, basePath string と // revelPkg *build.Packageの決定 func setApplicationPath(args []string) { var err error importPath = args[0] // revel new hoge/fuga で渡すhoge/fugaは // 絶対パスではいけない件 if filepath.IsAbs(importPath) { errorf("Abort: '%s' looks like a directory. Please provide a Go import path instead.", importPath) } // $GOPATH/src/hoge/fugaが既に存在してたらエラー _, err = build.Import(importPath, "", build.FindOnly) if err == nil { errorf("Abort: Import path %s already exists.\n", importPath) } // そもそもrevelソースが無い? revelPkg, err = build.Import(revel.REVEL_IMPORT_PATH, "", build.FindOnly) if err != nil { errorf("Abort: Could not find Revel source code: %s\n", err) } // $GOPATH/src/hoge/fugaを決定 appPath = filepath.Join(srcRoot, filepath.FromSlash(importPath)) // アプリケーション名をfugaに決定 appName = filepath.Base(appPath) // 一個上のpath持っとく?なぜ? basePath = filepath.ToSlash(filepath.Dir(importPath)) if basePath == "." { // we need to remove the a single '.' when // the app is in the $GOROOT/src directory basePath = "" } else { // we need to append a '/' when the app is // is a subdirectory such as $GOROOT/src/path/to/revelapp basePath += "/" } }
つぎ、
// checking and setting skeleton
setSkeletonPath(args)
// skeltonPathを決定する func setSkeletonPath(args []string) { var err error if len(args) == 2 { // user specified // 利用するスケルトンをユーザが指定できる? // 中略 } else { // use the revel default // $GOPTH/src/github.com/revel/revel/skeltonになるハズ skeletonPath = filepath.Join(revelPkg.Dir, "skeleton") } }
さいご
// copy files to new app directory
copyNewAppFiles()
func copyNewAppFiles() { var err error // appPathでmkdir -pする err = os.MkdirAll(appPath, 0777) panicOnError(err, "Failed to create directory "+appPath) // mustCopyDir? 何ソレ? mustCopyDir(appPath, skeletonPath, map[string]interface{}{ // app.conf "AppName": appName, "BasePath": basePath, "Secret": generateSecret(), }) // Dotfiles are skipped by mustCopyDir, so we have to explicitly copy the .gitignore. gitignore := ".gitignore" mustCopyFile(filepath.Join(appPath, gitignore), filepath.Join(skeletonPath, gitignore)) }
revel/util.go
// copyDir copies a directory tree over to a new directory. Any files ending in // ".template" are treated as a Go template and rendered using the given data. // Additionally, the trailing ".template" is stripped from the file name. // Also, dot files and dot directories are skipped. func mustCopyDir(destDir, srcDir string, data map[string]interface{}) error { var fullSrcDir string // Handle symlinked directories. f, err := os.Lstat(srcDir) // このf.Mode()&os.ModeSymlinkっていう表記なんだ? // symlinkの扱い if err == nil && f.Mode()&os.ModeSymlink == os.ModeSymlink { fullSrcDir, err = os.Readlink(srcDir) if err != nil { panic(err) } } else { fullSrcDir = srcDir } // すべてのディレクトリ・ファイルについてCopyしてる return filepath.Walk(fullSrcDir, func(srcPath string, info os.FileInfo, err error) error { // Get the relative path from the source base, and the corresponding path in // the dest directory. relSrcPath := strings.TrimLeft(srcPath[len(fullSrcDir):], string(os.PathSeparator)) destPath := path.Join(destDir, relSrcPath) // Skip dot files and dot directories. if strings.HasPrefix(relSrcPath, ".") { if info.IsDir() { return filepath.SkipDir } return nil } // Create a subdirectory if necessary. if info.IsDir() { err := os.MkdirAll(path.Join(destDir, relSrcPath), 0777) if !os.IsExist(err) { panicOnError(err, "Failed to create directory") } return nil } // If this file ends in ".template", render it as a template. if strings.HasSuffix(relSrcPath, ".template") { mustRenderTemplate(destPath[:len(destPath)-len(".template")], srcPath, data) return nil } // Else, just copy it over. mustCopyFile(destPath, srcPath) return nil }) }
結局
revelパスにあるsekltonを、指定されたプロジェクトパスにcp -r
してるだけのような気がする。foo/bar
で指定したときのアプリケーションってbar
的な文字列ほとんど含んでないっけ?
調査
% revel new hoge/piyopiyo ~ ~ revel! http://revel.github.io ~ Your application is ready: /Users/otiai10/proj/go/src/hoge/piyopiyo You can run it with: revel run hoge/piyopiyo % % cd $GOPATH/src/hoge/piyopiyo % grep piyopiyo **/*.* conf/app.conf:app.name=piyopiyo %
なるほど、conf/app.conf以外にpiyopiyo
という名前は登場しない。ファイルパスだけがhoge/piyopiyo
という名前にひもづいてる状態。
mustCopyDir
にアプリ名などを与え、mustCopyDir
内で.template
を使ってapp.confをアプリ名仕様にしてる。
$GOPATH/src/github.com/revel/revel/skeleton/conf/app.conf.template
app.name={{ .AppName }}
app.secret={{ .Secret }}
http.addr=
http.port=9000
http.ssl=false
http.sslcert=
# 以下略
結論
- 基本的には
$GOPATH/src/github.com/revel/revel
というパスを決定し、そこのskelton
ディレクトリの内容を、revel new hoge
で指定された$GOPATH/src/hoge
ディレクトリにコピーしてるだけ(あとapp.confつくってるくらい)
っぽい
雑感
- 次は
run
コマンド読むよ