mirror of
https://github.com/digarok/Appy.git
synced 2024-12-21 18:29:26 +00:00
commit initial version
This commit is contained in:
parent
b3e7261fb2
commit
95e5685072
55
README.md
Normal file
55
README.md
Normal file
@ -0,0 +1,55 @@
|
||||
# Appy
|
||||
|
||||
Local project builder for emulator disk images
|
||||
|
||||
## Getting Started
|
||||
|
||||
Install Appy then create an `appy.yaml` project definition file.
|
||||
|
||||
Run Appy to assemble, build, and run your source. Or do all 3 with:
|
||||
```
|
||||
appy brun
|
||||
```
|
||||
|
||||
### What this solves
|
||||
|
||||
We often need to assemble projects locally, but that is only part of the equation for people writing project to run under emulation.
|
||||
|
||||
The second step is taking our assembled binaries, and combining them with any other assets, data files, operating system files, et cetera, into a single disk image for use with an emulator.
|
||||
|
||||
Often this is handled by a set of scripts the author has locally in the projects. However this leads to problems when collaborating with other people or building pipelines.
|
||||
|
||||
Problem 1: You need to not only provide the scripts, but also the build tools they use, at the correct version.
|
||||
|
||||
Problem 2: The scripts often contain bespoke logic for things like handling filetypes or where to place files on the disk image.
|
||||
|
||||
Appy abstracts the tools away from a script mindset, and into a project mindset. Currently the tool paths are hardcoded but next versions will include dynamic tool providers, including vendoring from internet sources!
|
||||
|
||||
## The project file
|
||||
|
||||
Currently it uses an `appy.yaml` file in the current project directory.
|
||||
|
||||
### Running Appy
|
||||
|
||||
Appy has a verb command structure (sorta like git) for executing the various functions.
|
||||
|
||||
Invoke like: `appy command`
|
||||
|
||||
Commands:
|
||||
```
|
||||
$ appy asm # assemble all files
|
||||
|
||||
$ appy disk # create all disk images and add all files
|
||||
|
||||
$ appy run # launch an emulator
|
||||
|
||||
$ appy build # assemble files and make disk, aka 'asm'+'disk'
|
||||
|
||||
$ appy brun # assemble files, make disk, and launch emulator
|
||||
# aka 'asm'+'disk'+'run'
|
||||
```
|
||||
|
||||
### Version Notes
|
||||
This is an early experimental version not intended for public use.
|
||||
|
||||
Versioning from external sources and custom tool paths not yet implemented but all core functionality exists.
|
13
appy.yaml
Normal file
13
appy.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
assemble: [testsrc/sp.s, testsrc/pc.s]
|
||||
disks:
|
||||
- name: mydiskimage
|
||||
file: mydiskimage800.2mg
|
||||
size: 800KB
|
||||
files:
|
||||
- input: ../PRODOS.2.4.2/PRODOS
|
||||
output: /mydiskimage
|
||||
- input: testsrc/sp.s
|
||||
output: /mydiskimage
|
||||
- input: ../modsearch/potential/eclipse.ntp
|
||||
output: /mydiskimage
|
||||
ftaux: #B30000
|
22
cmd/asm.go
Normal file
22
cmd/asm.go
Normal file
@ -0,0 +1,22 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/digarok/appy/core"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// 'appy asm' command
|
||||
var asmCmd = &cobra.Command{
|
||||
Use: "asm",
|
||||
Short: "Assemble the source files in your project",
|
||||
Long: `This will run your 6502/65816 assembler, such as Merlin32,
|
||||
against all of the files specified for assembly in your project.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
core.Assemble()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(asmCmd)
|
||||
}
|
27
cmd/brun.go
Normal file
27
cmd/brun.go
Normal file
@ -0,0 +1,27 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/digarok/appy/core"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// brunCmd represents the brun command
|
||||
var brunCmd = &cobra.Command{
|
||||
Use: "brun",
|
||||
Short: "A brief description of your command",
|
||||
Long: `A longer description that spans multiple lines and likely contains examples
|
||||
and usage of using your command. For example:
|
||||
|
||||
Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
to quickly create a Cobra application.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
core.Assemble()
|
||||
core.BuildDisk()
|
||||
core.Run()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(brunCmd)
|
||||
}
|
22
cmd/build.go
Normal file
22
cmd/build.go
Normal file
@ -0,0 +1,22 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/digarok/appy/core"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// buildCmd represents the build command
|
||||
var buildCmd = &cobra.Command{
|
||||
Use: "build",
|
||||
Short: "This is the equivalent of 'asm' and 'disk' in a single command.",
|
||||
Long: `This will first assemble your files and then build the disk
|
||||
image(s) specified in your project file.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
core.Assemble()
|
||||
core.BuildDisk()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(buildCmd)
|
||||
}
|
22
cmd/disk.go
Normal file
22
cmd/disk.go
Normal file
@ -0,0 +1,22 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/digarok/appy/core"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// 'appy disk' command
|
||||
var diskCmd = &cobra.Command{
|
||||
Use: "disk",
|
||||
Short: "Create disk images from your project",
|
||||
Long: `This will launch a disk creation utility (CADIUS), and
|
||||
create the disk images with the files as specified by
|
||||
your project configuration file.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
core.BuildDisk()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(diskCmd)
|
||||
}
|
85
cmd/root.go
Normal file
85
cmd/root.go
Normal file
@ -0,0 +1,85 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/digarok/appy/core/project"
|
||||
)
|
||||
|
||||
var cfgFile string
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "appy",
|
||||
Short: "A happy little Apple II project application.",
|
||||
Long: `This will assemble your source files, and build your disk images,
|
||||
and let you run them in an Apple II emulator in a single command. For example:
|
||||
|
||||
|
||||
./appy run # this will do everything!
|
||||
|
||||
|
||||
`,
|
||||
// Uncomment the following line if your bare application
|
||||
// has an action associated with it:
|
||||
// Run: func(cmd *cobra.Command, args []string) { },
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
// fmt.Println("root.Execute()")
|
||||
cobra.CheckErr(rootCmd.Execute())
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
// fmt.Println("root.init()")
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.appy.yaml)")
|
||||
|
||||
// Cobra also supports local flags, which will only run
|
||||
// when this action is called directly.
|
||||
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
func initConfig() {
|
||||
// fmt.Println("root.initConfig()")
|
||||
|
||||
if cfgFile != "" {
|
||||
// Use config file from the flag.
|
||||
viper.SetConfigFile(cfgFile)
|
||||
} else {
|
||||
viper.SetConfigName("appy")
|
||||
|
||||
// Typically look in the current path for the project config.
|
||||
viper.AddConfigPath(".")
|
||||
// Find home directory.
|
||||
home, err := homedir.Dir()
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".appy" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
|
||||
}
|
||||
|
||||
viper.AutomaticEnv() // read in environment variables that match
|
||||
|
||||
// If a config file is found, read it in.
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, "Error loading config:", err)
|
||||
}
|
||||
project.SelfConfigure()
|
||||
// project.Id()
|
||||
}
|
25
cmd/run.go
Normal file
25
cmd/run.go
Normal file
@ -0,0 +1,25 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/digarok/appy/core"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// runCmd represents the run command
|
||||
var runCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "A brief description of your command",
|
||||
Long: `A longer description that spans multiple lines and likely contains examples
|
||||
and usage of using your command. For example:
|
||||
|
||||
Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
to quickly create a Cobra application.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
core.Run()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(runCmd)
|
||||
}
|
32
core/assembler.go
Normal file
32
core/assembler.go
Normal file
@ -0,0 +1,32 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var filesToAssemble []string
|
||||
|
||||
const Merlin32Path = "/usr/local/bin/merlin32"
|
||||
|
||||
func Assemble() {
|
||||
//fmt.Println("asm called")
|
||||
filesToAssemble = viper.GetViper().GetStringSlice("assemble")
|
||||
|
||||
//fmt.Fprintln(os.Stderr, "HEY", filesToAssemble)
|
||||
|
||||
for _, filename := range filesToAssemble {
|
||||
fmt.Printf("Assembling %v\n", filename)
|
||||
|
||||
cmd := exec.Command(Merlin32Path, "-V", filename)
|
||||
|
||||
err := cmd.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
46
core/diskbuilder.go
Normal file
46
core/diskbuilder.go
Normal file
@ -0,0 +1,46 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
|
||||
"github.com/digarok/appy/core/project"
|
||||
)
|
||||
|
||||
const CadiusPath = "/usr/local/bin/cadius"
|
||||
|
||||
func CreateDisk(name string, file string, size string) {
|
||||
fmt.Printf("Creating Disk: \"%s\" -> %s \tSize: %s\n", name, file, size)
|
||||
|
||||
cmd := exec.Command(CadiusPath, "CREATEVOLUME", file, name, size)
|
||||
|
||||
err := cmd.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func AddFiles(disk project.Disk) {
|
||||
fmt.Printf("Add files to: \"%s\"\n", disk.Name)
|
||||
for _, file := range disk.Files {
|
||||
// fmt.Printf("%s ADDFILE %s %s %s\n", CadiusPath, disk.File, file.Output, file.Input)
|
||||
fmt.Printf(" Adding file: -----> %s\n", file.Input)
|
||||
cmd := exec.Command(CadiusPath, "ADDFILE", disk.File, file.Output, file.Input)
|
||||
err := cmd.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BuildDisk() {
|
||||
var p = project.AppyProj
|
||||
for _, disk := range p.Disks {
|
||||
CreateDisk(disk.Name, disk.File, disk.Size)
|
||||
AddFiles(disk)
|
||||
}
|
||||
}
|
39
core/project/project.go
Normal file
39
core/project/project.go
Normal file
@ -0,0 +1,39 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Project struct {
|
||||
name string
|
||||
Disks []Disk
|
||||
}
|
||||
|
||||
type Disk struct {
|
||||
Name string
|
||||
File string
|
||||
Size string
|
||||
Files []File
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Input string
|
||||
Output string
|
||||
}
|
||||
|
||||
var AppyProj Project
|
||||
|
||||
func SelfConfigure() {
|
||||
AppyProj.name = "Selfie"
|
||||
err := viper.Unmarshal(&AppyProj)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to decode into struct, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Id() {
|
||||
fmt.Println("HI FROM:", AppyProj.name)
|
||||
}
|
22
core/runner.go
Normal file
22
core/runner.go
Normal file
@ -0,0 +1,22 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
const emulatorPath = "gsplus"
|
||||
|
||||
func Run() {
|
||||
fmt.Println("Running an emulator")
|
||||
|
||||
cmd := exec.Command(emulatorPath)
|
||||
|
||||
err := cmd.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
9
go.mod
Normal file
9
go.mod
Normal file
@ -0,0 +1,9 @@
|
||||
module github.com/digarok/appy
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/spf13/cobra v1.1.3 // indirect
|
||||
github.com/spf13/viper v1.7.1 // indirect
|
||||
)
|
22
main.go
Normal file
22
main.go
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright © 2021 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package main
|
||||
|
||||
import "github.com/digarok/appy/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
2
testsrc/pc.s
Normal file
2
testsrc/pc.s
Normal file
@ -0,0 +1,2 @@
|
||||
org $300
|
||||
rts
|
2
testsrc/sp.s
Normal file
2
testsrc/sp.s
Normal file
@ -0,0 +1,2 @@
|
||||
org $2000
|
||||
rts
|
Loading…
Reference in New Issue
Block a user