// 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 { return revel.Walk(srcDir, 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(srcDir):], 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 }) }
func mustTarGzDir(destFilename, srcDir string) string { zipFile, err := os.Create(destFilename) panicOnError(err, "Failed to create archive") defer zipFile.Close() gzipWriter := gzip.NewWriter(zipFile) defer gzipWriter.Close() tarWriter := tar.NewWriter(gzipWriter) defer tarWriter.Close() revel.Walk(srcDir, func(srcPath string, info os.FileInfo, err error) error { if info.IsDir() { return nil } srcFile, err := os.Open(srcPath) panicOnError(err, "Failed to read source file") defer srcFile.Close() err = tarWriter.WriteHeader(&tar.Header{ Name: strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator)), Size: info.Size(), Mode: int64(info.Mode()), ModTime: info.ModTime(), }) panicOnError(err, "Failed to write tar entry header") _, err = io.Copy(tarWriter, srcFile) panicOnError(err, "Failed to copy") return nil }) return zipFile.Name() }
// Parse the app controllers directory and return a list of the controller types found. // Returns a CompileError if the parsing fails. func ProcessSource(roots []string) (*SourceInfo, *revel.Error) { var ( srcInfo *SourceInfo compileError *revel.Error ) for _, root := range roots { rootImportPath := importPathFromPath(root) if rootImportPath == "" { revel.WARN.Println("Skipping code path", root) continue } // Start walking the directory tree. _ = revel.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { log.Println("Error scanning app source:", err) return nil } if !info.IsDir() || info.Name() == "tmp" { return nil } // Get the import path of the package. pkgImportPath := rootImportPath if root != path { pkgImportPath = rootImportPath + "/" + filepath.ToSlash(path[len(root)+1:]) } // Parse files within the path. var pkgs map[string]*ast.Package fset := token.NewFileSet() pkgs, err = parser.ParseDir(fset, path, func(f os.FileInfo) bool { return !f.IsDir() && !strings.HasPrefix(f.Name(), ".") && strings.HasSuffix(f.Name(), ".go") }, 0) if err != nil { if errList, ok := err.(scanner.ErrorList); ok { var pos token.Position = errList[0].Pos compileError = &revel.Error{ SourceType: ".go source", Title: "Go Compilation Error", Path: pos.Filename, Description: errList[0].Msg, Line: pos.Line, Column: pos.Column, SourceLines: revel.MustReadLines(pos.Filename), } errorLink := revel.Config.StringDefault("error.link", "") if errorLink != "" { compileError.SetLink(errorLink) } return compileError } ast.Print(nil, err) log.Fatalf("Failed to parse dir: %s", err) } // Skip "main" packages. delete(pkgs, "main") // If there is no code in this directory, skip it. if len(pkgs) == 0 { return nil } // There should be only one package in this directory. if len(pkgs) > 1 { log.Println("Most unexpected! Multiple packages in a single directory:", pkgs) } var pkg *ast.Package for _, v := range pkgs { pkg = v } srcInfo = appendSourceInfo(srcInfo, processPackage(fset, pkgImportPath, path, pkg)) return nil }) } return srcInfo, compileError }