package planr import ( "os" "log" "path" "path/filepath" ) // Standard Directories: // // Planr relies on a standard directory structure to resolve paths to source code // These directories can be overridden via environmental variables // // Directories: // - `.` root directory // - `src` contains source code // - `planr` contains test metadata (also called configuration directory) // - `planr/rubric` contains test case configuration // - `planr/tests` contains source code for test cases // - `planr/build` contains all files written during the build process (ephemeral) // Env overrides const ( ENV_CONFIG_DIR="PLANR_PLANR_DIR" ENV_SRC_DIR="ENV_SRC_DIR" ENV_BUILD_DIR="PLANR_BUILD_DIR" ) // Try these search directories var CONFIG_SEARCH_DIRS = [2] string { "planr", ".planr", } // Path are relative to the "planr" project config directory const ( DEFAULT_PATH_SRC="../src" DEFAULT_PATH_BUILD="build" DEFAULT_PATH_RUBRIC="rubric" DEFAULT_PATH_TESTS="tests" ) type DirConfig struct { src string config string build string // Config falls back to the config found in the parent directory if the env variable hasn't been overridden pdFallback string } func dieDirAbsent(name, path string) { if !directoryExists(path) { log.Fatalf("Could not find %s directory tried %s", name, path) } } func dirFromEnv(name, env string) *string { if dir, isSet := os.LookupEnv(env); isSet { dieDirAbsent(name, dir) return &dir } return nil } func (c *DirConfig) SetSrcDir(srcDir string) { dieDirAbsent("src", srcDir) c.src = srcDir } func (c *DirConfig) SetConfigDir(configDir string) { dieDirAbsent("planr (config)", configDir) c.config = configDir } func (c *DirConfig) SetBuildDir(buildDir string) { dieDirAbsent("build", buildDir) c.build = buildDir } func (c *DirConfig) SetConfigDirFromTree(cdir string) { var configDir string found := traverseUp(cdir, func (path string) bool { for _, dir := range CONFIG_SEARCH_DIRS { configDir = filepath.Join(path, dir) if directoryExists(configDir) { return true } } return false }); if found { c.pdFallback = configDir } } func (c DirConfig) ConfigDir() string { if c.config != "" { return c.config } if dir := dirFromEnv("config", ENV_CONFIG_DIR); dir != nil { c.config = *dir return c.config } if c.pdFallback == "" { log.Fatal("Could not find planr directory"); } c.config = c.pdFallback; return c.config } func (c DirConfig) SrcDir() string { if c.src != "" { return c.src } if dir := dirFromEnv("src", ENV_SRC_DIR); dir != nil { c.src = *dir return c.src } // set path relative to config dir := c.ConfigDir() return path.Join(dir, DEFAULT_PATH_SRC) } func (c DirConfig) BuildDir() string { if c.src != "" { return c.src } if dir := dirFromEnv("build", ENV_BUILD_DIR); dir != nil { c.build = *dir return c.build } dir := c.ConfigDir() return path.Join(dir, DEFAULT_PATH_BUILD) } func (c DirConfig) CleanBuildDir() { build := c.BuildDir() if err := os.RemoveAll(build); err != nil { log.Fatalf("Cannot build directory %v\n", err) } if err := os.Remove(build); err != nil { log.Fatalf("Could not remove build directory %v\n", err) } } func (c DirConfig) MkBuildDir() { build := c.BuildDir() if err := os.Mkdir(build, 0755); err != nil { log.Fatalf("Could not create build directory %v\n", err) } } func (c DirConfig) RubricDir() string { rubric := path.Join(c.ConfigDir(), "rubric") dieDirAbsent("rubric", rubric) return rubric } func (c DirConfig) TestsDir() string { tests := path.Join(c.ConfigDir(), "tests") dieDirAbsent("tests", tests) return tests }