From ab2d937d04238fb95374e9ea1f838e8e8dba2ac9 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 25 Apr 2019 09:30:20 -0700 Subject: [PATCH] Initial commit. this is an attempt to make a simple GUI for people to image the pinebook Signed-off-by: Jeff Carr --- .gitignore | 1 + Makefile | 22 +++++++ config.go | 98 ++++++++++++++++++++++++++++++ config.yml | 27 +++++++++ main.go | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 322 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 config.go create mode 100644 config.yml create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c8ad734 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +pinebook-imager diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1a099e8 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +all: + go install + +build-verbose: + go build -x -work + +# simple sortcut to push all git changes +push: + git pull + git add --all + -git commit -a -s + git push + +# should update every go dependancy (?) +update: + git pull + go get -v -t -u ./... + +gaper: + # 'gaper' is a simple and smart golang tool that just rebuilds every time you change a file + # go get -u github.com/maxcnunes/gaper + gaper diff --git a/config.go b/config.go new file mode 100644 index 0000000..1dfeb2c --- /dev/null +++ b/config.go @@ -0,0 +1,98 @@ +package main + +/* + This simply parses the command line arguments using the default golang + package called 'flag'. This can be used as a simple template to parse + command line arguments in other programs. + + It puts everything in the 'config' package which I think is a good + wrapper around the 'flags' package and doesn't need a whole mess of + global variables +*/ + +import "log" +import "os" +import "flag" +import "fmt" +import "github.com/gookit/config" +import "github.com/gookit/config/yaml" +import "github.com/davecgh/go-spew/spew" + +var customUsage = func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0]) + flag.PrintDefaults() + + fmt.Println("") + fmt.Println("EXAMPLES:") + fmt.Println("") + fmt.Println(os.Args[0] + "--hostname test.hostname.wit.com") + fmt.Println("") +} + +func parseFlags() { + var version string + var race bool + var hostname string + var width int + var height int + + flag.StringVar (&version, "version", "v0.1", "Set compiled in version string") + + flag.StringVar (&hostname, "hostname", "localhost", "Your full hostname") + flag.IntVar (&width, "width", 400, "Width of the Window") + flag.IntVar (&height, "height", 600, "Height of the Window") + + flag.BoolVar (&race, "race", race, "Use race detector") + + // Set the output if something fails to stdout rather than stderr + flag.CommandLine.SetOutput(os.Stdout) + + flag.Usage = customUsage + flag.Parse() + + if flag.Parsed() { + log.Println("flag.Parse() worked") + } else { + log.Println("flag.Parse() failed") + } + + config.Set("width", width) + config.Set("height", height) + config.Set("hostname", hostname) +} + +func parseConfig() { + config.WithOptions(config.ParseEnv) + parseFlags() + + config.LoadOSEnv([]string{"MAIL"}) + config.LoadOSEnv([]string{"USER"}) + config.LoadOSEnv([]string{"BUILDDEBUG"}) + +/* + urls := flag.Args() + log.Println("flag.Aargs() = ", urls) + + for _, addr := range flag.Args() { + log.Println("GET %s", addr) + } +*/ + + // add driver for support yaml content + config.AddDriver(yaml.Driver) + config.LoadFiles("config.yml") + + map1 := config.StringMap("dists") + spew.Dump(map1) + for name, vars := range config.StringMap("dists") { + log.Println("name =", name) + log.Println("vars =", vars) + } + +/* + for _, addr := range config.Strings("dists") { + log.Println("addr =", addr) + } +*/ + +} diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..d1b24a8 --- /dev/null +++ b/config.yml @@ -0,0 +1,27 @@ +name: app2 +debug: false +baseKey: value2 +shell: ${SHELL} +envKey1: ${NotExist|defValue} + +map1: + key: val2 + key2: val20 + +arr1: + - lo + - wifi0 + - docker0 + +dists: + Debian x32: + size: 12378 + url: http://mirrors.wit.com/wit/pinebook/debian.img.gz + Armbian: + size: 12378 + Manjaro: + size: 12378 + Android: + size: 12378 + bob: + size: 12378 diff --git a/main.go b/main.go new file mode 100644 index 0000000..83c07ed --- /dev/null +++ b/main.go @@ -0,0 +1,174 @@ +package main + +import "log" +import "reflect" +import "os" + +import "github.com/gookit/config" +import "github.com/andlabs/ui" +import "github.com/davecgh/go-spew/spew" + +import "git.wit.com/jcarr/shell" + +var mainwin *ui.Window +var mydrive string + +func rsync(mybut *ui.Button) { + log.Println("rsync() mybut =", reflect.ValueOf(mybut).Elem()) + + if _, err := os.Stat("/mnt/sdcard/lost+found/"); !os.IsNotExist(err) { + log.Println("run rsync here") + shell.Script(` + rsync -av --progress --inplace /home/pinebook/factory/FACTORY-IMAGER-ROOTFS/ /mnt/sdcard/ + umount /mnt/sdcard + `) + ui.MsgBox(mainwin, "The sdcard is finished", "") + } else { + log.Println("partition is not mounted") + ui.MsgBoxError(mainwin, "The partition is not mounted at /mnt/sdcard", "") + } +} + +func dd(mybut *ui.Button) { + if _, err := os.Stat("/mnt/factory-image/lost+found/"); os.IsNotExist(err) { + shell.Run("mkdir /mnt/factory-image/") + shell.Run("mount /dev/sdb2 /mnt/factory-image/") + } + if _, err := os.Stat("/mnt/factory-image/lost+found/"); os.IsNotExist(err) { + log.Println("partition is not mounted") + ui.MsgBoxError(mainwin, "The partition is not mounted at /mnt/sdcard", "") + return + } + + shell.Script("dd if=/home/pinebook/factory/factory-2019-01-20 of=/mnt/factory-image/factory-2019-01-20 status=progress oflag=sync"); + + ui.MsgBox(mainwin, "The sdcard is finished", "") +} + +// select the dev entry to partition and format +// for example: /dev/mtdblock0 or /dev/sdc +func selectDrive(mybox *ui.Combobox) { + spew.Dump(mybox.Visible()) + spew.Dump(mybox.Selected()) + spew.Dump(mybox.ControlBase) + // spew.Dump(box.ControlBase.Parent) + spew.Dump(mybox) + log.Println("selected = ", mybox.Selected()) + if (mybox.Selected() == 1) { + mydrive = "/dev/sdb" + } +} + +func format(mybut *ui.Button) { + log.Println("format() mybut =", reflect.ValueOf(mybut).Elem()) + log.Println("format and mount here") + + shell.Script(` + parted -s /dev/sdb mklabel msdos + parted -s /dev/sdb mkpart primary ext4 1MiB 8GB + parted -s /dev/sdb mkpart primary ext4 8GB 32GB + sleep 1 + mkfs.ext4 /dev/sdb1 + mkfs.ext4 /dev/sdb2 + e2label /dev/sdb1 root + e2label /dev/sdb2 factory-image + mount /dev/sdb1 /mnt/sdcard/ + pwd + dd if=../u-boot/u-boot-sunxi-with-spl.bin of=/dev/sdb status=progress oflag=sync bs=1K seek=8 + `) +} + +func addButton(vbox *ui.Box, label string, click func(*ui.Button)) { + hbox := ui.NewHorizontalBox() + hbox.SetPadded(true) + + // look up translation here for 'label' + button := ui.NewButton(label) + hbox.Append(button, false) + button.OnClicked(click) + + vbox.Append(hbox, false) +} + +func addGroupBox(hbox *ui.Box, name string) *ui.Box { + groupDrive := ui.NewGroup(name) + groupDrive.SetMargined(true) + + vbox := ui.NewVerticalBox() + vbox.SetPadded(true) + + groupDrive.SetChild(vbox) + hbox.Append(groupDrive, true) + + log.Println("groupDrive =", reflect.TypeOf(groupDrive)) + + vbox.SetPadded(true) + return vbox +} + +func makeBurnSDcardPage() *ui.Box { + hbox := ui.NewVerticalBox() + hbox.SetPadded(true) + + vbox := addGroupBox(hbox, "Select Distribution") + + cbox := ui.NewCombobox() + for name, vars := range config.StringMap("dists") { + log.Println("name =", name) + log.Println("vars =", vars) + cbox.Append(name) + } + cbox.OnSelected(selectDrive) + vbox.Append(cbox, false) + + vbox2 := addGroupBox(hbox, "Select the Image") + + addButton(vbox2, "Download", format) + addButton(vbox2, "Burn file to eMMC", dd) + addButton(vbox2, "md5sum", rsync) + + return hbox +} + +func getHardwareBox() *ui.Box { + hbox := ui.NewVerticalBox() + hbox.SetPadded(true) + + vbox := addGroupBox(hbox, "Hardware Info") + + addButton(vbox, "something", format) + + return hbox +} + +func setupUI() { + mainwin = ui.NewWindow("Pinebook eMMC Imager", config.Int("width"), config.Int("height"), false) + + mainwin.OnClosing(func(*ui.Window) bool { + ui.Quit() + return true + }) + + ui.OnShouldQuit(func() bool { + mainwin.Destroy() + return true + }) + + tab := ui.NewTab() + mainwin.SetChild(tab) + mainwin.SetMargined(true) + + tab.Append("Burn eMMC", makeBurnSDcardPage()) + tab.SetMargined(0, true) // 0 here means tab 0 + + tab.Append("Hardware", getHardwareBox()) + tab.SetMargined(1, true) // 1 here means tab 1 + + mainwin.Show() +} + +func main() { + parseConfig() + + ui.Main(setupUI) +}