From b6c82f073f772455f71c86697a0a2ab172c8636c Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 10:17:44 +0000 Subject: [PATCH 01/16] Added new script command --- cmd/script.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 cmd/script.go diff --git a/cmd/script.go b/cmd/script.go new file mode 100644 index 00000000..a4a6058c --- /dev/null +++ b/cmd/script.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/smira/commander" +) + +func makeCmdScript() *commander.Command { + return &commander.Command{ + UsageLine: "script", + Short: "runs aptly scripts", + Subcommands: []*commander.Command{ + makeCmdScriptRun(), + }, + } +} From df06dc356ba3716b386f35a2e27881279a19122a Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 10:19:58 +0000 Subject: [PATCH 02/16] Added script cmd in cmd.go --- cmd/cmd.go | 1 + cmd/script.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 0246d493..bcccff9e 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -57,6 +57,7 @@ package environment to new version.`, makeCmdGraph(), makeCmdMirror(), makeCmdRepo(), + makeCmdScript(), makeCmdServe(), makeCmdSnapshot(), makeCmdPublish(), diff --git a/cmd/script.go b/cmd/script.go index a4a6058c..c3e6e513 100644 --- a/cmd/script.go +++ b/cmd/script.go @@ -7,7 +7,7 @@ import ( func makeCmdScript() *commander.Command { return &commander.Command{ UsageLine: "script", - Short: "runs aptly scripts", + Short: "run aptly scripts", Subcommands: []*commander.Command{ makeCmdScriptRun(), }, From 1f2ddca32bd314e412aad9bb305f5f46add5db3c Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 11:36:15 +0000 Subject: [PATCH 03/16] Add switchContext function to context.go --- cmd/context.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmd/context.go b/cmd/context.go index 58d322af..d316897f 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -40,6 +40,7 @@ type AptlyContext struct { } var context *AptlyContext +var savedContext *AptlyContext // Check interface var _ aptly.PublishedStorageProvider = &AptlyContext{} @@ -60,6 +61,13 @@ func Fatal(err error) { panic(&FatalError{ReturnCode: returnCode, Message: err.Error()}) } +func switchContext() { + + savedContext = context + context = savedContext + +} + // Config loads and returns current configuration func (context *AptlyContext) Config() *utils.ConfigStructure { if !context.configLoaded { From cdd34b47592c47399f1cf571ab3e24c634248085 Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 11:38:17 +0000 Subject: [PATCH 04/16] Added panicked attribute to context.go This attribute is set to false during initalisation, and it's set to true when error arises. --- cmd/context.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/context.go b/cmd/context.go index d316897f..b3af5b23 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -24,6 +24,7 @@ import ( type AptlyContext struct { flags *flag.FlagSet configLoaded bool + panicked bool progress aptly.Progress downloader aptly.Downloader @@ -58,6 +59,7 @@ func Fatal(err error) { if err == commander.ErrFlagError || err == commander.ErrCommandError { returnCode = 2 } + context.panicked = true panic(&FatalError{ReturnCode: returnCode, Message: err.Error()}) } @@ -273,6 +275,7 @@ func InitContext(flags *flag.FlagSet) error { context = &AptlyContext{ flags: flags, + panicked: false, dependencyOptions: -1, publishedStorages: map[string]aptly.PublishedStorage{}, } From b2779d7a88ee8c14c1606d2b362d0e6ac817ca95 Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 11:40:03 +0000 Subject: [PATCH 05/16] Go-shellwords added to Gomfile This packages allows us to parse shell commands. Useful for script_run.go (later added) --- Gomfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Gomfile b/Gomfile index 25920026..6d72587d 100644 --- a/Gomfile +++ b/Gomfile @@ -4,6 +4,7 @@ gom 'code.google.com/p/gographviz', :commit => '454bc64fdfa2' gom 'code.google.com/p/mxk/go1/flowcontrol', :commit => '5ff2502e2556' gom 'code.google.com/p/snappy-go/snappy', :commit => '12e4b4183793' gom 'github.com/cheggaaa/pb', :commit => '74be7a1388046f374ac36e93d46f5d56e856f827' +gom 'github.com/mattn/go-shellwords', :commit => 'c7ca6f94add751566a61cf2199e1de78d4c3eee4' gom 'github.com/mitchellh/goamz/s3', :commit => '55f224c07975fddef9d2116600c664e30df3d594' gom 'github.com/mkrautz/goar', :commit => '36eb5f3452b1283a211fa35bc00c646fd0db5c4b' gom 'github.com/smira/commander', :commit => 'f408b00e68d5d6e21b9f18bd310978dafc604e47' From 3c7696ef7e0af23135114ca21a1535aa630c152a Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 11:44:24 +0000 Subject: [PATCH 06/16] Refactored main.go The main function - whuch runs aptly commands - has been taken out from main.go and included to the cmd package. This is useful for the aptly script run command, which should use that behaviour. --- cmd/run.go | 42 ++++++++++++++++++++++++++++++++++++++++++ main.go | 30 +----------------------------- 2 files changed, 43 insertions(+), 29 deletions(-) create mode 100644 cmd/run.go diff --git a/cmd/run.go b/cmd/run.go new file mode 100644 index 00000000..56ed777f --- /dev/null +++ b/cmd/run.go @@ -0,0 +1,42 @@ +package cmd + +import ( + "fmt" + "os" +) + +func Run(cmd_args []string, exitOnPanic bool) { + + defer func() { + if r := recover(); r != nil { + fatal, ok := r.(*FatalError) + if !ok { + panic(r) + } + fmt.Println("ERROR:", fatal.Message) + if exitOnPanic { + os.Exit(fatal.ReturnCode) + } + } + }() + + command := RootCommand() + + flags, args, err := command.ParseFlags(cmd_args) + if err != nil { + Fatal(err) + } + + err = InitContext(flags) + if err != nil { + Fatal(err) + } + + defer ShutdownContext() + + err = command.Dispatch(args) + if err != nil { + Fatal(err) + } + +} diff --git a/main.go b/main.go index 8bb4bc91..2165ad19 100644 --- a/main.go +++ b/main.go @@ -1,38 +1,10 @@ package main import ( - "fmt" "github.com/smira/aptly/cmd" "os" ) func main() { - defer func() { - if r := recover(); r != nil { - fatal, ok := r.(*cmd.FatalError) - if !ok { - panic(r) - } - fmt.Println("ERROR:", fatal.Message) - os.Exit(fatal.ReturnCode) - } - }() - - command := cmd.RootCommand() - - flags, args, err := command.ParseFlags(os.Args[1:]) - if err != nil { - cmd.Fatal(err) - } - - err = cmd.InitContext(flags) - if err != nil { - cmd.Fatal(err) - } - defer cmd.ShutdownContext() - - err = command.Dispatch(args) - if err != nil { - cmd.Fatal(err) - } + cmd.Run(os.Args[1:], true) } From 18e3ed5d6405eae0bac8175790c15c63792c7554 Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 13:18:03 +0000 Subject: [PATCH 07/16] aptly script run implementation This new aptly command will allow to run multiple commands within a single aptly command, running in a single thread. The commands can be included in a text file or added to the aptly script run command in one line, separated by comas ','. If one command returns an error, then all the subsequent commands will be skipped. Each command output will appear on the console within coloured strings, clearly stating which command is running and the start and the end of the received output. --- cmd/script_run.go | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 cmd/script_run.go diff --git a/cmd/script_run.go b/cmd/script_run.go new file mode 100644 index 00000000..324491f4 --- /dev/null +++ b/cmd/script_run.go @@ -0,0 +1,151 @@ +package cmd + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/mattn/go-shellwords" + "github.com/smira/commander" + "github.com/wsxiaoys/terminal/color" +) + +func aptlyScriptRun(cmd *commander.Command, args []string) error { + + var err error + var cmd_list [][]string + + if len(args) == 0 { + var text string + cmd_args := []string{} + + fmt.Println("One command per line and press enter when finished.") + + reader := bufio.NewReader(os.Stdin) + for { + fmt.Printf("> ") + text, _ = reader.ReadString('\n') + if text == "\n" { + break + } else { + text = strings.TrimSpace(text) + "," + parsed_args, _ := shellwords.Parse(text) + cmd_args = append(cmd_args, parsed_args...) + } + } + + if len(cmd_args) == 0 { + return fmt.Errorf("Nothing entered. Exiting...\n") + } + + cmd_list = formatCommands(cmd_args) + + } else if len(args) == 1 { + var text string + cmd_args := []string{} + + if finfo, err := os.Stat(args[0]); os.IsNotExist(err) || finfo.IsDir() { + return fmt.Errorf("No such file, %s\n", args[0]) + } + + fmt.Println("Reading file...\n") + + file, err := os.Open(args[0]) + + if err != nil { + return err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + text = strings.TrimSpace(scanner.Text()) + "," + parsed_args, _ := shellwords.Parse(text) + cmd_args = append(cmd_args, parsed_args...) + } + + if err = scanner.Err(); err != nil { + return err + } + + if len(cmd_args) == 0 { + return fmt.Errorf("The file is empty. Exiting...\n") + } + + cmd_list = formatCommands(cmd_args) + + } else if len(args) > 1 { + cmd_list = formatCommands(args) + } + + switchContext() + + for i, command := range cmd_list { + + if !context.panicked { + color.Printf("@g%d) [Running]: %s@!\n", (i + 1), strings.Join(command, " ")) + color.Println("\n@yBegin command output: ----------------------------\n@!") + Run(command, false) + color.Println("\n@yEnd command output: ------------------------------\n@!") + + } else { + color.Printf("@r%d) [Skipping]: %s@!\n", (i + 1), strings.Join(command, " ")) + } + + } + + if context.panicked { + err = fmt.Errorf("At least one command has reported an error\n") + } + + switchContext() + + return err +} + +func formatCommands(args []string) [][]string { + + var cmd []string + var cmd_array [][]string + + for _, s := range args { + if s_trimmed := strings.TrimRight(s, ","); s_trimmed != s { + cmd = append(cmd, s_trimmed) + cmd_array = append(cmd_array, cmd) + cmd = []string{} + } else { + cmd = append(cmd, s) + } + } + + if len(cmd) > 0 { + cmd_array = append(cmd_array, cmd) + } + + return cmd_array +} + +func makeCmdScriptRun() *commander.Command { + cmd := &commander.Command{ + Run: aptlyScriptRun, + UsageLine: "run | , , ...", + Short: "run aptly scripts", + Long: ` +Command runs multiple aptly commands in one single aptly thread. + +Example: + + $ aptly script run + > repo create local + > repo add local pkg1 + > publish repo local + > serve + > + +`, + } + + return cmd +} From 005cee572ed041c0690e5f0c76fbeaa0ebec59bb Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 14:14:56 +0000 Subject: [PATCH 08/16] Aptly script has now become aptly task It makes more sense. Multiple lines of aptly commands can now be called 'aptly tasks' which could potentially be automated, in the future? --- cmd/cmd.go | 2 +- cmd/{script.go => task.go} | 8 ++++---- cmd/{script_run.go => task_run.go} | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) rename cmd/{script.go => task.go} (51%) rename cmd/{script_run.go => task_run.go} (90%) diff --git a/cmd/cmd.go b/cmd/cmd.go index bcccff9e..8f4729f5 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -57,9 +57,9 @@ package environment to new version.`, makeCmdGraph(), makeCmdMirror(), makeCmdRepo(), - makeCmdScript(), makeCmdServe(), makeCmdSnapshot(), + makeCmdTask(), makeCmdPublish(), makeCmdVersion(), }, diff --git a/cmd/script.go b/cmd/task.go similarity index 51% rename from cmd/script.go rename to cmd/task.go index c3e6e513..07d79de5 100644 --- a/cmd/script.go +++ b/cmd/task.go @@ -4,12 +4,12 @@ import ( "github.com/smira/commander" ) -func makeCmdScript() *commander.Command { +func makeCmdTask() *commander.Command { return &commander.Command{ - UsageLine: "script", - Short: "run aptly scripts", + UsageLine: "task", + Short: "manage aptly tasks", Subcommands: []*commander.Command{ - makeCmdScriptRun(), + makeCmdTaskRun(), }, } } diff --git a/cmd/script_run.go b/cmd/task_run.go similarity index 90% rename from cmd/script_run.go rename to cmd/task_run.go index 324491f4..c04ee3f9 100644 --- a/cmd/script_run.go +++ b/cmd/task_run.go @@ -11,7 +11,7 @@ import ( "github.com/wsxiaoys/terminal/color" ) -func aptlyScriptRun(cmd *commander.Command, args []string) error { +func aptlyTaskRun(cmd *commander.Command, args []string) error { var err error var cmd_list [][]string @@ -127,17 +127,17 @@ func formatCommands(args []string) [][]string { return cmd_array } -func makeCmdScriptRun() *commander.Command { +func makeCmdTaskRun() *commander.Command { cmd := &commander.Command{ - Run: aptlyScriptRun, + Run: aptlyTaskRun, UsageLine: "run | , , ...", - Short: "run aptly scripts", + Short: "run aptly tasks", Long: ` -Command runs multiple aptly commands in one single aptly thread. +Command helps origanise multiple aptly commands in one single aptly task, running as single thread. Example: - $ aptly script run + $ aptly task run > repo create local > repo add local pkg1 > publish repo local From dfc1f27d4c02fae8110aa4a34453b38893355265 Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 14:18:35 +0000 Subject: [PATCH 09/16] Better wording for task run message. --- cmd/task_run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/task_run.go b/cmd/task_run.go index c04ee3f9..8945f9ab 100644 --- a/cmd/task_run.go +++ b/cmd/task_run.go @@ -20,7 +20,7 @@ func aptlyTaskRun(cmd *commander.Command, args []string) error { var text string cmd_args := []string{} - fmt.Println("One command per line and press enter when finished.") + fmt.Println("Please enter one command per line and leave one blank when finished.") reader := bufio.NewReader(os.Stdin) for { From 0c09bdedaa6a9f903317390f7d16d3d034d3f115 Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 14:22:04 +0000 Subject: [PATCH 10/16] Fixed t03_help:MainTest failing due to new cmd --- system/t03_help/MainTest_gold | 1 + 1 file changed, 1 insertion(+) diff --git a/system/t03_help/MainTest_gold b/system/t03_help/MainTest_gold index 96676be4..e354f726 100644 --- a/system/t03_help/MainTest_gold +++ b/system/t03_help/MainTest_gold @@ -9,6 +9,7 @@ Commands: repo manage local package repositories serve HTTP serve published repositories snapshot manage snapshots of repositories + task manage aptly tasks version display version Use "aptly help " for more information about a command. From 6ff601f4a25e7522ce0d9b666ec87b3351818748 Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 14:33:36 +0000 Subject: [PATCH 11/16] Making sure context is initialised before using it Now checkong context is not nil before setting panicked = true --- cmd/context.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/context.go b/cmd/context.go index b3af5b23..db7cd220 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -59,7 +59,9 @@ func Fatal(err error) { if err == commander.ErrFlagError || err == commander.ErrCommandError { returnCode = 2 } - context.panicked = true + if context != nil { + context.panicked = true + } panic(&FatalError{ReturnCode: returnCode, Message: err.Error()}) } From b59471ad359b089956f35ddf76f1ecc16fb6fd24 Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 15:11:14 +0000 Subject: [PATCH 12/16] Added RunTask acceptance tests Added a basic RunTask test to test the functionality of the new aptly task run command. More to come... --- system/t10_task/RunTask1Test_gold | 34 +++++++++++++++++++++++++++++++ system/t10_task/__init__.py | 5 +++++ system/t10_task/run.py | 9 ++++++++ 3 files changed, 48 insertions(+) create mode 100644 system/t10_task/RunTask1Test_gold create mode 100644 system/t10_task/__init__.py create mode 100644 system/t10_task/run.py diff --git a/system/t10_task/RunTask1Test_gold b/system/t10_task/RunTask1Test_gold new file mode 100644 index 00000000..3134ad6b --- /dev/null +++ b/system/t10_task/RunTask1Test_gold @@ -0,0 +1,34 @@ +1) [Running]: repo list + +Begin command output: ---------------------------- +  +No local repositories found, create one with `aptly repo create ...`. + +End command output: ------------------------------ +  +2) [Running]: repo create local + +Begin command output: ---------------------------- +  + +Local repo [local] successfully added. +You can run 'aptly repo add local ...' to add packages to repository. + +End command output: ------------------------------ +  +3) [Running]: repo drop local + +Begin command output: ---------------------------- +  +Local repo `local` has been removed. + +End command output: ------------------------------ +  +4) [Running]: version + +Begin command output: ---------------------------- +  +aptly version: 0.8~dev + +End command output: ------------------------------ +  diff --git a/system/t10_task/__init__.py b/system/t10_task/__init__.py new file mode 100644 index 00000000..00d32dc8 --- /dev/null +++ b/system/t10_task/__init__.py @@ -0,0 +1,5 @@ +""" +Test aptly task run +""" + +from .run import * diff --git a/system/t10_task/run.py b/system/t10_task/run.py new file mode 100644 index 00000000..0633ff15 --- /dev/null +++ b/system/t10_task/run.py @@ -0,0 +1,9 @@ +from lib import BaseTest + + +class RunTask1Test(BaseTest): + """ + output should match + """ + + runCmd = "aptly task run repo list, repo create local, repo drop local, version" From 91ff904ac4466ccb71f25375866d409f86c30f1c Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 22:13:24 +0000 Subject: [PATCH 13/16] Adding filename flag to specify task run filename. Just realised commands can not have any subcommands and therefore consist of single words (for example serve or version). Hence I can't assume that if len(args)==1 then the user has entered the filename. I have created the filename flag so the user is forced to specify it when they wish to run aptly tasks from files. --- cmd/task_run.go | 63 +++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/cmd/task_run.go b/cmd/task_run.go index 8945f9ab..fc8db977 100644 --- a/cmd/task_run.go +++ b/cmd/task_run.go @@ -16,42 +16,17 @@ func aptlyTaskRun(cmd *commander.Command, args []string) error { var err error var cmd_list [][]string - if len(args) == 0 { + if filename := cmd.Flag.Lookup("filename").Value.Get().(string); filename != "" { var text string cmd_args := []string{} - fmt.Println("Please enter one command per line and leave one blank when finished.") - - reader := bufio.NewReader(os.Stdin) - for { - fmt.Printf("> ") - text, _ = reader.ReadString('\n') - if text == "\n" { - break - } else { - text = strings.TrimSpace(text) + "," - parsed_args, _ := shellwords.Parse(text) - cmd_args = append(cmd_args, parsed_args...) - } - } - - if len(cmd_args) == 0 { - return fmt.Errorf("Nothing entered. Exiting...\n") - } - - cmd_list = formatCommands(cmd_args) - - } else if len(args) == 1 { - var text string - cmd_args := []string{} - - if finfo, err := os.Stat(args[0]); os.IsNotExist(err) || finfo.IsDir() { - return fmt.Errorf("No such file, %s\n", args[0]) + if finfo, err := os.Stat(filename); os.IsNotExist(err) || finfo.IsDir() { + return fmt.Errorf("No such file, %s\n", filename) } fmt.Println("Reading file...\n") - file, err := os.Open(args[0]) + file, err := os.Open(filename) if err != nil { return err @@ -76,7 +51,32 @@ func aptlyTaskRun(cmd *commander.Command, args []string) error { cmd_list = formatCommands(cmd_args) - } else if len(args) > 1 { + } else if len(args) == 0 { + var text string + cmd_args := []string{} + + fmt.Println("Please enter one command per line and leave one blank when finished.") + + reader := bufio.NewReader(os.Stdin) + for { + fmt.Printf("> ") + text, _ = reader.ReadString('\n') + if text == "\n" { + break + } else { + text = strings.TrimSpace(text) + "," + parsed_args, _ := shellwords.Parse(text) + cmd_args = append(cmd_args, parsed_args...) + } + } + + if len(cmd_args) == 0 { + return fmt.Errorf("Nothing entered. Exiting...\n") + } + + cmd_list = formatCommands(cmd_args) + + } else { cmd_list = formatCommands(args) } @@ -130,7 +130,7 @@ func formatCommands(args []string) [][]string { func makeCmdTaskRun() *commander.Command { cmd := &commander.Command{ Run: aptlyTaskRun, - UsageLine: "run | , , ...", + UsageLine: "run -filename= | , , ...", Short: "run aptly tasks", Long: ` Command helps origanise multiple aptly commands in one single aptly task, running as single thread. @@ -147,5 +147,6 @@ Example: `, } + cmd.Flag.String("filename", "", "specifies the filename that contains the commands to run") return cmd } From 72e54aa3d1e4392c2f4fd1b5342e90b24b3f6a11 Mon Sep 17 00:00:00 2001 From: Simon Aquino Date: Sat, 16 Aug 2014 23:32:38 +0000 Subject: [PATCH 14/16] Fixed a bug with the context switching The context switching wasn't really happening. Now the issue is fixed. --- cmd/context.go | 4 +++- cmd/task_run.go | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/context.go b/cmd/context.go index db7cd220..a426a233 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -42,6 +42,7 @@ type AptlyContext struct { var context *AptlyContext var savedContext *AptlyContext +var tempContext *AptlyContext // Check interface var _ aptly.PublishedStorageProvider = &AptlyContext{} @@ -67,8 +68,9 @@ func Fatal(err error) { func switchContext() { - savedContext = context + tempContext = context context = savedContext + savedContext = tempContext } diff --git a/cmd/task_run.go b/cmd/task_run.go index fc8db977..a61be962 100644 --- a/cmd/task_run.go +++ b/cmd/task_run.go @@ -84,7 +84,7 @@ func aptlyTaskRun(cmd *commander.Command, args []string) error { for i, command := range cmd_list { - if !context.panicked { + if context == nil || !context.panicked { color.Printf("@g%d) [Running]: %s@!\n", (i + 1), strings.Join(command, " ")) color.Println("\n@yBegin command output: ----------------------------\n@!") Run(command, false) @@ -95,7 +95,6 @@ func aptlyTaskRun(cmd *commander.Command, args []string) error { } } - if context.panicked { err = fmt.Errorf("At least one command has reported an error\n") } From 39a1f0ec2d4fba50b69cf4051a030110cf09f2d7 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 25 Aug 2014 21:22:55 +0400 Subject: [PATCH 15/16] Use go1.3.1. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bf949649..f4a22dc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: go go: - 1.2.1 - - 1.3 + - 1.3.1 - tip env: From 68e600974d0900bf35e963c072d4d16d3db5d5fe Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 25 Aug 2014 22:05:02 +0400 Subject: [PATCH 16/16] Refactoring: remove context switching, another way to catch panics, colored output. #96 --- cmd/context.go | 55 ++++++++++++++++++------------- cmd/run.go | 33 ++++++++++--------- cmd/task_run.go | 27 +++++++-------- main.go | 2 +- system/t10_task/RunTask1Test_gold | 40 +++++++++------------- 5 files changed, 80 insertions(+), 77 deletions(-) diff --git a/cmd/context.go b/cmd/context.go index a426a233..2af73773 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -22,9 +22,8 @@ import ( // AptlyContext is a common context shared by all commands type AptlyContext struct { - flags *flag.FlagSet - configLoaded bool - panicked bool + flags, globalFlags *flag.FlagSet + configLoaded bool progress aptly.Progress downloader aptly.Downloader @@ -41,8 +40,6 @@ type AptlyContext struct { } var context *AptlyContext -var savedContext *AptlyContext -var tempContext *AptlyContext // Check interface var _ aptly.PublishedStorageProvider = &AptlyContext{} @@ -60,26 +57,15 @@ func Fatal(err error) { if err == commander.ErrFlagError || err == commander.ErrCommandError { returnCode = 2 } - if context != nil { - context.panicked = true - } panic(&FatalError{ReturnCode: returnCode, Message: err.Error()}) } -func switchContext() { - - tempContext = context - context = savedContext - savedContext = tempContext - -} - // Config loads and returns current configuration func (context *AptlyContext) Config() *utils.ConfigStructure { if !context.configLoaded { var err error - configLocation := context.flags.Lookup("config").Value.String() + configLocation := context.globalFlags.Lookup("config").Value.String() if configLocation != "" { err = utils.LoadConfig(configLocation, &utils.Config) @@ -118,16 +104,16 @@ func (context *AptlyContext) Config() *utils.ConfigStructure { func (context *AptlyContext) DependencyOptions() int { if context.dependencyOptions == -1 { context.dependencyOptions = 0 - if context.Config().DepFollowSuggests || context.flags.Lookup("dep-follow-suggests").Value.Get().(bool) { + if context.Config().DepFollowSuggests || context.globalFlags.Lookup("dep-follow-suggests").Value.Get().(bool) { context.dependencyOptions |= deb.DepFollowSuggests } - if context.Config().DepFollowRecommends || context.flags.Lookup("dep-follow-recommends").Value.Get().(bool) { + if context.Config().DepFollowRecommends || context.globalFlags.Lookup("dep-follow-recommends").Value.Get().(bool) { context.dependencyOptions |= deb.DepFollowRecommends } - if context.Config().DepFollowAllVariants || context.flags.Lookup("dep-follow-all-variants").Value.Get().(bool) { + if context.Config().DepFollowAllVariants || context.globalFlags.Lookup("dep-follow-all-variants").Value.Get().(bool) { context.dependencyOptions |= deb.DepFollowAllVariants } - if context.Config().DepFollowSource || context.flags.Lookup("dep-follow-source").Value.Get().(bool) { + if context.Config().DepFollowSource || context.globalFlags.Lookup("dep-follow-source").Value.Get().(bool) { context.dependencyOptions |= deb.DepFollowSource } } @@ -139,7 +125,7 @@ func (context *AptlyContext) DependencyOptions() int { func (context *AptlyContext) ArchitecturesList() []string { if context.architecturesList == nil { context.architecturesList = context.Config().Architectures - optionArchitectures := context.flags.Lookup("architectures").Value.String() + optionArchitectures := context.globalFlags.Lookup("architectures").Value.String() if optionArchitectures != "" { context.architecturesList = strings.Split(optionArchitectures, ",") } @@ -244,6 +230,10 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto return publishedStorage } +func (context *AptlyContext) UpdateFlags(flags *flag.FlagSet) { + context.flags = flags +} + // ShutdownContext shuts context down func ShutdownContext() { if aptly.EnableDebug { @@ -264,12 +254,27 @@ func ShutdownContext() { } if context.database != nil { context.database.Close() + context.database = nil } if context.downloader != nil { context.downloader.Shutdown() + context.downloader = nil } if context.progress != nil { context.progress.Shutdown() + context.progress = nil + } +} + +// CleanupContext does partial shutdown of context +func CleanupContext() { + if context.downloader != nil { + context.downloader.Shutdown() + context.downloader = nil + } + if context.progress != nil { + context.progress.Shutdown() + context.progress = nil } } @@ -277,9 +282,13 @@ func ShutdownContext() { func InitContext(flags *flag.FlagSet) error { var err error + if context != nil { + panic("context already initialized") + } + context = &AptlyContext{ flags: flags, - panicked: false, + globalFlags: flags, dependencyOptions: -1, publishedStorages: map[string]aptly.PublishedStorage{}, } diff --git a/cmd/run.go b/cmd/run.go index 56ed777f..2d05db85 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -2,11 +2,10 @@ package cmd import ( "fmt" - "os" + "github.com/smira/commander" ) -func Run(cmd_args []string, exitOnPanic bool) { - +func Run(cmd *commander.Command, cmd_args []string, initContext bool) (returnCode int) { defer func() { if r := recover(); r != nil { fatal, ok := r.(*FatalError) @@ -14,29 +13,31 @@ func Run(cmd_args []string, exitOnPanic bool) { panic(r) } fmt.Println("ERROR:", fatal.Message) - if exitOnPanic { - os.Exit(fatal.ReturnCode) - } + returnCode = fatal.ReturnCode } }() - command := RootCommand() + returnCode = 0 - flags, args, err := command.ParseFlags(cmd_args) + flags, args, err := cmd.ParseFlags(cmd_args) if err != nil { Fatal(err) } - err = InitContext(flags) - if err != nil { - Fatal(err) - } - - defer ShutdownContext() - - err = command.Dispatch(args) + if initContext { + err = InitContext(flags) + if err != nil { + Fatal(err) + } + defer ShutdownContext() + } + + context.UpdateFlags(flags) + + err = cmd.Dispatch(args) if err != nil { Fatal(err) } + return } diff --git a/cmd/task_run.go b/cmd/task_run.go index a61be962..4e016c66 100644 --- a/cmd/task_run.go +++ b/cmd/task_run.go @@ -8,7 +8,6 @@ import ( "github.com/mattn/go-shellwords" "github.com/smira/commander" - "github.com/wsxiaoys/terminal/color" ) func aptlyTaskRun(cmd *commander.Command, args []string) error { @@ -80,27 +79,29 @@ func aptlyTaskRun(cmd *commander.Command, args []string) error { cmd_list = formatCommands(args) } - switchContext() + commandErrored := false for i, command := range cmd_list { + if !commandErrored { + context.Progress().ColoredPrintf("@g%d) [Running]: %s@!", (i + 1), strings.Join(command, " ")) + context.Progress().ColoredPrintf("\n@yBegin command output: ----------------------------@!") + context.Progress().Flush() - if context == nil || !context.panicked { - color.Printf("@g%d) [Running]: %s@!\n", (i + 1), strings.Join(command, " ")) - color.Println("\n@yBegin command output: ----------------------------\n@!") - Run(command, false) - color.Println("\n@yEnd command output: ------------------------------\n@!") - + returnCode := Run(RootCommand(), command, false) + if returnCode != 0 { + commandErrored = true + } + context.Progress().ColoredPrintf("\n@yEnd command output: ------------------------------@!") + CleanupContext() } else { - color.Printf("@r%d) [Skipping]: %s@!\n", (i + 1), strings.Join(command, " ")) + context.Progress().ColoredPrintf("@r%d) [Skipping]: %s@!", (i + 1), strings.Join(command, " ")) } - } - if context.panicked { + + if commandErrored { err = fmt.Errorf("At least one command has reported an error\n") } - switchContext() - return err } diff --git a/main.go b/main.go index 2165ad19..47d3b690 100644 --- a/main.go +++ b/main.go @@ -6,5 +6,5 @@ import ( ) func main() { - cmd.Run(os.Args[1:], true) + os.Exit(cmd.Run(cmd.RootCommand(), os.Args[1:], true)) } diff --git a/system/t10_task/RunTask1Test_gold b/system/t10_task/RunTask1Test_gold index 3134ad6b..57f0cfa7 100644 --- a/system/t10_task/RunTask1Test_gold +++ b/system/t10_task/RunTask1Test_gold @@ -1,34 +1,26 @@ -1) [Running]: repo list - -Begin command output: ---------------------------- -  +1) [Running]: repo list + +Begin command output: ---------------------------- No local repositories found, create one with `aptly repo create ...`. -End command output: ------------------------------ -  -2) [Running]: repo create local - -Begin command output: ---------------------------- -  +End command output: ------------------------------ +2) [Running]: repo create local + +Begin command output: ---------------------------- Local repo [local] successfully added. You can run 'aptly repo add local ...' to add packages to repository. -End command output: ------------------------------ -  -3) [Running]: repo drop local - -Begin command output: ---------------------------- -  +End command output: ------------------------------ Local repo `local` has been removed. +3) [Running]: repo drop local -End command output: ------------------------------ -  -4) [Running]: version - -Begin command output: ---------------------------- -  +Begin command output: ---------------------------- + +End command output: ------------------------------ aptly version: 0.8~dev +4) [Running]: version -End command output: ------------------------------ -  +Begin command output: ---------------------------- + +End command output: ------------------------------