mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2024-06-15 19:17:34 -04:00
reworked paths package
the location of the configuration directory now depends on how the binary is built. release versions of the binary will look for the gopher2600 directory in the user's os configuration directory. non-release versions will look for the .gopher2600 directory in the CWD. paths.ResourcePath() will create the paths that don't exist paths.ResourcePath() now clearly differentiates paths and files added build target to the Makefile; disabled release target for now
This commit is contained in:
parent
299db2277e
commit
4534da0db6
7
Makefile
7
Makefile
|
@ -12,8 +12,13 @@ clean:
|
|||
@echo "removing binary and profiling files"
|
||||
@rm -f gopher2600 cpu.profile mem.profile debug.cpu.profile debug.mem.profile
|
||||
|
||||
build:
|
||||
go build -gcflags '-c 3 -B -+ -wb=false'
|
||||
|
||||
release:
|
||||
go build -gcflags '-c 3 -B -+ -wb=false' .
|
||||
@#go build -gcflags '-c 3 -B -+ -wb=false' -tags release
|
||||
@echo "use 'make build' for now. the release target will"
|
||||
@echo "reappear in a future commit."
|
||||
|
||||
profile:
|
||||
go build -gcflags '-c 3 -B -+ -wb=false' .
|
||||
|
|
|
@ -71,7 +71,7 @@ const (
|
|||
DatabaseFileUnavailable = "database error: cannot open database (%v)"
|
||||
|
||||
// regression
|
||||
RegressionError = "regression test error: %v"
|
||||
RegressionError = "regression error: %v"
|
||||
RegressionDigestError = "digest entry: %v"
|
||||
RegressionPlaybackError = "playback entry: %v"
|
||||
|
||||
|
@ -82,8 +82,7 @@ const (
|
|||
SetupTelevisionError = "tv setup: %v"
|
||||
|
||||
// patch
|
||||
PatchError = "patch error: %v"
|
||||
PatchFileError = "patch error: patch file not found (%v)"
|
||||
PatchError = "patch error: %v"
|
||||
|
||||
// symbols
|
||||
SymbolsFileError = "symbols error: error processing symbols file: %v"
|
||||
|
|
|
@ -106,7 +106,7 @@ func play(md *modalflag.Modes) error {
|
|||
|
||||
p, err := md.Parse()
|
||||
if p != modalflag.ParseContinue {
|
||||
return err
|
||||
return errors.New(errors.PlayError, err)
|
||||
}
|
||||
|
||||
switch len(md.RemainingArgs()) {
|
||||
|
@ -160,15 +160,20 @@ func play(md *modalflag.Modes) error {
|
|||
func debug(md *modalflag.Modes) error {
|
||||
md.NewMode()
|
||||
|
||||
defInitScript, err := paths.ResourcePath("", defaultInitScript)
|
||||
if err != nil {
|
||||
return errors.New(errors.DebuggerError, err)
|
||||
}
|
||||
|
||||
cartFormat := md.AddString("cartformat", "AUTO", "force use of cartridge format")
|
||||
spec := md.AddString("tv", "AUTO", "television specification: NTSC, PAL")
|
||||
termType := md.AddString("term", "COLOR", "terminal type to use in debug mode: COLOR, PLAIN")
|
||||
initScript := md.AddString("initscript", paths.ResourcePath(defaultInitScript), "script to run on debugger start")
|
||||
initScript := md.AddString("initscript", defInitScript, "script to run on debugger start")
|
||||
profile := md.AddBool("profile", false, "run debugger through cpu profiler")
|
||||
|
||||
p, err := md.Parse()
|
||||
if p != modalflag.ParseContinue {
|
||||
return err
|
||||
return errors.New(errors.DebuggerError, err)
|
||||
}
|
||||
|
||||
tv, err := television.NewTelevision(*spec)
|
||||
|
@ -246,7 +251,7 @@ func disasm(md *modalflag.Modes) error {
|
|||
|
||||
p, err := md.Parse()
|
||||
if p != modalflag.ParseContinue {
|
||||
return err
|
||||
return errors.New(errors.DisassemblyError, err)
|
||||
}
|
||||
|
||||
switch len(md.RemainingArgs()) {
|
||||
|
@ -290,7 +295,7 @@ func perform(md *modalflag.Modes) error {
|
|||
|
||||
p, err := md.Parse()
|
||||
if p != modalflag.ParseContinue {
|
||||
return err
|
||||
return errors.New(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
switch len(md.RemainingArgs()) {
|
||||
|
@ -304,24 +309,24 @@ func perform(md *modalflag.Modes) error {
|
|||
|
||||
tv, err := television.NewTelevision(*spec)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.New(errors.PerformanceError, err)
|
||||
}
|
||||
defer tv.End()
|
||||
|
||||
if *display {
|
||||
scr, err := sdlplay.NewSdlPlay(tv, float32(*scaling))
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.New(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
err = scr.(gui.GUI).SetFeature(gui.ReqSetVisibility, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.New(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
err = scr.(gui.GUI).SetFeature(gui.ReqSetFPSCap, *fpscap)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.New(errors.PerformanceError, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,7 +354,7 @@ func regress(md *modalflag.Modes) error {
|
|||
|
||||
p, err := md.Parse()
|
||||
if p != modalflag.ParseContinue {
|
||||
return err
|
||||
return errors.New(errors.RegressionError, err)
|
||||
}
|
||||
|
||||
switch md.Mode() {
|
||||
|
@ -442,7 +447,7 @@ func regressAdd(md *modalflag.Modes) error {
|
|||
|
||||
p, err := md.Parse()
|
||||
if p != modalflag.ParseContinue {
|
||||
return err
|
||||
return errors.New(errors.RegressionError, err)
|
||||
}
|
||||
|
||||
switch len(md.RemainingArgs()) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package patch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopher2600/errors"
|
||||
"gopher2600/hardware/memory/cartridge"
|
||||
"gopher2600/paths"
|
||||
|
@ -42,13 +43,16 @@ const pokeLineSeparator = ":"
|
|||
func CartridgeMemory(mem *cartridge.Cartridge, patchFile string) (bool, error) {
|
||||
var err error
|
||||
|
||||
p := paths.ResourcePath(patchPath, patchFile)
|
||||
p, err := paths.ResourcePath(patchPath, patchFile)
|
||||
if err != nil {
|
||||
return false, errors.New(errors.PatchError, err)
|
||||
}
|
||||
|
||||
f, err := os.Open(p)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *os.PathError:
|
||||
return false, errors.New(errors.PatchFileError, p)
|
||||
return false, errors.New(errors.PatchError, fmt.Sprintf("patch file not found (%s)", p))
|
||||
}
|
||||
return false, errors.New(errors.PatchError, err)
|
||||
}
|
||||
|
|
27
paths/dev_path.go
Normal file
27
paths/dev_path.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
// +build !release
|
||||
|
||||
package paths
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
const gopherConfigDir = ".gopher2600"
|
||||
|
||||
// the non-release version of getBasePath looks for and if necessary creates
|
||||
// the gopherConfigDir (and child directories) in the current working
|
||||
// directory
|
||||
func getBasePath(subPth string) (string, error) {
|
||||
pth := path.Join(gopherConfigDir, subPth)
|
||||
|
||||
if _, err := os.Stat(pth); err == nil {
|
||||
return pth, nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(pth, 0700); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return pth, nil
|
||||
}
|
27
paths/doc.go
27
paths/doc.go
|
@ -17,21 +17,24 @@
|
|||
// git repository, are also covered by the licence, even when this
|
||||
// notice is not present ***
|
||||
|
||||
// Package paths contains functions to prepare paths to gopher2600 resources.
|
||||
// Package paths contains functions to prepare paths for gopher2600 resources.
|
||||
//
|
||||
// The ResourcePath() function modifies the supplied resource string such that
|
||||
// it is prepended with the appropriate config directory. For example, the
|
||||
// following will return the path to a cartridge patch.
|
||||
// The ResourcePath() function returns the correct path to the resource
|
||||
// directory/file specified in the arguments. The result of ResourcePath
|
||||
// depends on the build tag used to compile the program.
|
||||
//
|
||||
// d := paths.ResourcePath("patches", "ET")
|
||||
// For "release" tagged builds, the correct path is one rooted in the user's
|
||||
// configuration directory. On modern Linux systems that would be something
|
||||
// like:
|
||||
//
|
||||
// The policy of ResourcePath() is simple: if the base resource path, currently
|
||||
// defined to be ".gopher2600", is present in the program's current directory
|
||||
// then that is the base path that will used. If it is not preseent not, then
|
||||
// the user's config directory is used. The package uses os.UserConfigDir()
|
||||
// from go standard library for this.
|
||||
// /home/user/.config/gopher2600/
|
||||
//
|
||||
// In the example above, on a modern Linux system, the path returned will be:
|
||||
// For "non-release" tagged builds, the correct path is rooted in the current
|
||||
// working directory:
|
||||
//
|
||||
// /home/user/.config/gopher2600/patches/ET
|
||||
// ./.gopher2600
|
||||
//
|
||||
// The reason for this is simple. During development, it is more convenient to
|
||||
// have the config directory close to hand. For release binaries meanwhile, the
|
||||
// config directory should be somewhere the user expects.
|
||||
package paths
|
||||
|
|
|
@ -20,44 +20,27 @@
|
|||
package paths
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// the base path for all resources. note that we don't use this value directly
|
||||
// except in the getBasePath() function. that function should be used instead.
|
||||
const baseResourcePath = ".gopher2600"
|
||||
|
||||
// ResourcePath returns the resource string (representing the resource to be
|
||||
// loaded) prepended with operating system specific details.
|
||||
func ResourcePath(resource ...string) string {
|
||||
var p []string
|
||||
|
||||
p = make([]string, 0, len(resource)+1)
|
||||
p = append(p, getBasePath())
|
||||
p = append(p, resource...)
|
||||
|
||||
return path.Join(p...)
|
||||
}
|
||||
|
||||
// getBasePath() returns baseResourcePath with the user's home directory
|
||||
// prepended if it the unadorned baseResourcePath cannot be found in the
|
||||
// current directory.
|
||||
// loaded) prepended with OS/build specific paths.
|
||||
//
|
||||
// note that we're not checking for the existance of the resource requested by
|
||||
// the caller, or even the existance of 'baseResourcePath' in the home
|
||||
// directory.
|
||||
// The function takes care of creation of all folders necessary to reach the
|
||||
// end of sub-path. It does not otherwise touch or create the file.
|
||||
//
|
||||
// note: this is a UNIX thing. there's no real reason why any other OS should
|
||||
// implement this.
|
||||
func getBasePath() string {
|
||||
if _, err := os.Stat(baseResourcePath); err == nil {
|
||||
return baseResourcePath
|
||||
}
|
||||
// Either subPth or file can be empty, depending on context.
|
||||
func ResourcePath(subPth string, file string) (string, error) {
|
||||
var pth []string
|
||||
|
||||
home, err := os.UserConfigDir()
|
||||
basePath, err := getBasePath(subPth)
|
||||
if err != nil {
|
||||
return baseResourcePath
|
||||
return "", err
|
||||
}
|
||||
return path.Join(home, baseResourcePath[1:])
|
||||
|
||||
pth = make([]string, 0)
|
||||
pth = append(pth, basePath)
|
||||
pth = append(pth, file)
|
||||
|
||||
return path.Join(pth...), nil
|
||||
}
|
||||
|
|
33
paths/release_path.go
Normal file
33
paths/release_path.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
// +build release
|
||||
|
||||
package paths
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
const gopherConfigDir = "gopher2600"
|
||||
|
||||
// the release version of getBasePath looks for and if necessary creates the
|
||||
// gopherConfigDir (and child directories) in the User's configuration
|
||||
// directory, which is dependent on the host OS (see os.UserConfigDir()
|
||||
// documentation for details)
|
||||
func getBasePath(subPth string) (string, error) {
|
||||
cnf, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
pth := path.Join(cnf, gopherConfigDir, subPth)
|
||||
|
||||
if _, err := os.Stat(pth); err == nil {
|
||||
return pth, nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(pth, 0700); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return pth, nil
|
||||
}
|
|
@ -234,7 +234,10 @@ func (reg *DigestRegression) regress(newRegression bool, output io.Writer, msg s
|
|||
|
||||
if reg.State {
|
||||
// create a unique filename
|
||||
reg.stateFile = uniqueFilename("state", reg.CartLoad)
|
||||
reg.stateFile, err = uniqueFilename("state", reg.CartLoad)
|
||||
if err != nil {
|
||||
return false, "", errors.New(errors.RegressionDigestError, err)
|
||||
}
|
||||
|
||||
// check that the filename is unique
|
||||
nf, _ := os.Open(reg.stateFile)
|
||||
|
|
|
@ -193,7 +193,10 @@ func (reg *PlaybackRegression) regress(newRegression bool, output io.Writer, msg
|
|||
// regressionScripts directory
|
||||
if newRegression {
|
||||
// create a unique filename
|
||||
newScript := uniqueFilename("playback", plb.CartLoad)
|
||||
newScript, err := uniqueFilename("playback", plb.CartLoad)
|
||||
if err != nil {
|
||||
return false, "", errors.New(errors.RegressionPlaybackError, err)
|
||||
}
|
||||
|
||||
// check that the filename is unique
|
||||
nf, _ := os.Open(newScript)
|
||||
|
|
|
@ -27,7 +27,6 @@ import (
|
|||
"gopher2600/paths"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
@ -65,10 +64,10 @@ func initDBSession(db *database.Session) error {
|
|||
}
|
||||
|
||||
// make sure regression script directory exists
|
||||
if err := os.MkdirAll(paths.ResourcePath(regressionScripts), 0755); err != nil {
|
||||
msg := fmt.Sprintf("regression script directory: %s", err)
|
||||
return errors.New(errors.RegressionError, msg)
|
||||
}
|
||||
// if err := os.MkdirAll(paths.ResourcePath(regressionScripts), 0755); err != nil {
|
||||
// msg := fmt.Sprintf("regression script directory: %s", err)
|
||||
// return errors.New(errors.RegressionError, msg)
|
||||
// }
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -79,7 +78,12 @@ func RegressList(output io.Writer) error {
|
|||
return errors.New(errors.PanicError, "RegressList()", "io.Writer should not be nil (use a nopWriter)")
|
||||
}
|
||||
|
||||
db, err := database.StartSession(paths.ResourcePath(regressionDBFile), database.ActivityReading, initDBSession)
|
||||
dbPth, err := paths.ResourcePath("", regressionDBFile)
|
||||
if err != nil {
|
||||
return errors.New(errors.RegressionError, err)
|
||||
}
|
||||
|
||||
db, err := database.StartSession(dbPth, database.ActivityReading, initDBSession)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -99,7 +103,12 @@ func RegressAdd(output io.Writer, reg Regressor) error {
|
|||
return errors.New(errors.PanicError, "RegressAdd()", "io.Writer should not be nil (use nopWriter)")
|
||||
}
|
||||
|
||||
db, err := database.StartSession(paths.ResourcePath(regressionDBFile), database.ActivityCreating, initDBSession)
|
||||
dbPth, err := paths.ResourcePath("", regressionDBFile)
|
||||
if err != nil {
|
||||
return errors.New(errors.RegressionError, err)
|
||||
}
|
||||
|
||||
db, err := database.StartSession(dbPth, database.ActivityCreating, initDBSession)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -129,7 +138,12 @@ func RegressDelete(output io.Writer, confirmation io.Reader, key string) error {
|
|||
return errors.New(errors.RegressionError, msg)
|
||||
}
|
||||
|
||||
db, err := database.StartSession(paths.ResourcePath(regressionDBFile), database.ActivityModifying, initDBSession)
|
||||
dbPth, err := paths.ResourcePath("", regressionDBFile)
|
||||
if err != nil {
|
||||
return errors.New(errors.RegressionError, err)
|
||||
}
|
||||
|
||||
db, err := database.StartSession(dbPth, database.ActivityModifying, initDBSession)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -179,7 +193,12 @@ func RegressRunTests(output io.Writer, verbose bool, failOnError bool, filterKey
|
|||
return errors.New(errors.PanicError, "RegressRunEntries()", "io.Writer should not be nil (use nopWriter)")
|
||||
}
|
||||
|
||||
db, err := database.StartSession(paths.ResourcePath(regressionDBFile), database.ActivityReading, initDBSession)
|
||||
dbPth, err := paths.ResourcePath("", regressionDBFile)
|
||||
if err != nil {
|
||||
return errors.New(errors.RegressionError, err)
|
||||
}
|
||||
|
||||
db, err := database.StartSession(dbPth, database.ActivityReading, initDBSession)
|
||||
if err != nil {
|
||||
return errors.New(errors.RegressionError, err)
|
||||
}
|
||||
|
|
|
@ -22,15 +22,22 @@ package regression
|
|||
import (
|
||||
"fmt"
|
||||
"gopher2600/cartridgeloader"
|
||||
"gopher2600/errors"
|
||||
"gopher2600/paths"
|
||||
"time"
|
||||
)
|
||||
|
||||
// create a unique filename from a CatridgeLoader instance. used when saving
|
||||
// scripts into regressionScripts directory
|
||||
func uniqueFilename(prepend string, cartload cartridgeloader.Loader) string {
|
||||
func uniqueFilename(prepend string, cartload cartridgeloader.Loader) (string, error) {
|
||||
n := time.Now()
|
||||
timestamp := fmt.Sprintf("%04d%02d%02d_%02d%02d%02d", n.Year(), n.Month(), n.Day(), n.Hour(), n.Minute(), n.Second())
|
||||
newScript := fmt.Sprintf("%s_%s_%s", prepend, cartload.ShortName(), timestamp)
|
||||
return paths.ResourcePath(regressionScripts, newScript)
|
||||
|
||||
scrPth, err := paths.ResourcePath(regressionScripts, newScript)
|
||||
if err != nil {
|
||||
return "", errors.New(errors.RegressionError, err)
|
||||
}
|
||||
|
||||
return scrPth, nil
|
||||
}
|
||||
|
|
|
@ -70,7 +70,12 @@ func AttachCartridge(vcs *hardware.VCS, cartload cartridgeloader.Loader) error {
|
|||
return err
|
||||
}
|
||||
|
||||
db, err := database.StartSession(paths.ResourcePath(setupDBFile), database.ActivityReading, initDBSession)
|
||||
dbPth, err := paths.ResourcePath("", setupDBFile)
|
||||
if err != nil {
|
||||
return errors.New(errors.SetupError, err)
|
||||
}
|
||||
|
||||
db, err := database.StartSession(dbPth, database.ActivityReading, initDBSession)
|
||||
if err != nil {
|
||||
if errors.Is(err, errors.DatabaseFileUnavailable) {
|
||||
// silently ignore absence of setup database
|
||||
|
|
Loading…
Reference in a new issue