diff --git a/Gomfile b/Gomfile index a8dc987d..9e5e5eac 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' diff --git a/cmd/cmd.go b/cmd/cmd.go index 0246d493..8f4729f5 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -59,6 +59,7 @@ package environment to new version.`, makeCmdRepo(), makeCmdServe(), makeCmdSnapshot(), + makeCmdTask(), makeCmdPublish(), makeCmdVersion(), }, diff --git a/cmd/context.go b/cmd/context.go index 58d322af..a426a233 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 @@ -40,6 +41,8 @@ type AptlyContext struct { } var context *AptlyContext +var savedContext *AptlyContext +var tempContext *AptlyContext // Check interface var _ aptly.PublishedStorageProvider = &AptlyContext{} @@ -57,9 +60,20 @@ 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 { @@ -265,6 +279,7 @@ func InitContext(flags *flag.FlagSet) error { context = &AptlyContext{ flags: flags, + panicked: false, dependencyOptions: -1, publishedStorages: map[string]aptly.PublishedStorage{}, } 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/cmd/task.go b/cmd/task.go new file mode 100644 index 00000000..07d79de5 --- /dev/null +++ b/cmd/task.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/smira/commander" +) + +func makeCmdTask() *commander.Command { + return &commander.Command{ + UsageLine: "task", + Short: "manage aptly tasks", + Subcommands: []*commander.Command{ + makeCmdTaskRun(), + }, + } +} diff --git a/cmd/task_run.go b/cmd/task_run.go new file mode 100644 index 00000000..a61be962 --- /dev/null +++ b/cmd/task_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 aptlyTaskRun(cmd *commander.Command, args []string) error { + + var err error + var cmd_list [][]string + + if filename := cmd.Flag.Lookup("filename").Value.Get().(string); filename != "" { + var text string + cmd_args := []string{} + + 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(filename) + + 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) == 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) + } + + switchContext() + + for i, command := range cmd_list { + + 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@!") + + } 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 makeCmdTaskRun() *commander.Command { + cmd := &commander.Command{ + Run: aptlyTaskRun, + UsageLine: "run -filename= | , , ...", + Short: "run aptly tasks", + Long: ` +Command helps origanise multiple aptly commands in one single aptly task, running as single thread. + +Example: + + $ aptly task run + > repo create local + > repo add local pkg1 + > publish repo local + > serve + > + +`, + } + + cmd.Flag.String("filename", "", "specifies the filename that contains the commands to run") + return cmd +} 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) } 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. 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"