diff --git a/README.md b/README.md index 5eff29d..f1d7e16 100644 --- a/README.md +++ b/README.md @@ -235,17 +235,13 @@ $ nix-amer -p apt-get myserver.build _myserver.build_ ``` -[ comment starts with opening brackets '[' - -[aliases] -alias sshd /etc/ssh/sshd_config +# [pre] is executed before launching everything else +[pre] +install nginx ssh sslh alias nginx /etc/nginx/nginx.conf +alias sshd /etc/ssh/sshd_config alias sslh /etc/default/sslh -[install packages] -install nginx ssh -install sslh - [nginx] set nginx@http.gzip off service enable nginx diff --git a/internal/buildfile/reader.go b/internal/buildfile/reader.go index 6f0ea9e..cb09559 100644 --- a/internal/buildfile/reader.go +++ b/internal/buildfile/reader.go @@ -9,6 +9,7 @@ import ( "io" "regexp" "strings" + "sync" "time" ) @@ -125,10 +126,18 @@ func (r *Reader) Execute() error { // return fmt.Errorf("cannot upgrade | %s", err) // } refresh := make(chan bool, 1) + wg := new(sync.WaitGroup) + wgstatus := new(sync.WaitGroup) - // 1. create status table + // 1. create status table + extract [pre] section if one table := make([]tableSection, 0) + index := make(map[string]int, 0) + + var pre *[]instruction.T = nil + var preTable *tableSection = nil + for secname, sec := range r.Content { + tableSec := tableSection{ name: secname, instructions: make([]execStatus, len(*sec), len(*sec)+1), @@ -137,39 +146,69 @@ func (r *Reader) Execute() error { // for each instruction for i, inst := range *sec { tableSec.instructions[i].name = inst.Raw() - tableSec.instructions[i].start = time.Now() } table = append(table, tableSec) - go execSection(sec, *r.Context, refresh, &table[len(table)-1]) + index[secname] = len(table) - 1 + + // [pre] section + if secname == "pre" { + pre = sec + preTable = &tableSec + } + + // add one section + wg.Add(len(*sec)) } - // 2. create status updater - go status(refresh, table) - time.Sleep(time.Second * 10) + // 2. launch status updater + wgstatus.Add(1) + go status(table, refresh, wgstatus) + + // 3. launch [pre] (it set) + if pre != nil { + execSection(pre, *r.Context, preTable, refresh, wg) + time.Sleep(time.Second * 2) + } + + // 4. launch each other section + for secname, sec := range r.Content { + // do not launch pre again + if secname == "pre" { + continue + } + i, ok := index[secname] + if !ok { + continue + } + go execSection(sec, *r.Context, &table[i], refresh, wg) + } + + wg.Wait() close(refresh) + wgstatus.Wait() return nil } -func execSection(section *[]instruction.T, ctx instruction.ExecutionContext, refresher chan<- bool, tsec *tableSection) { +func execSection(section *[]instruction.T, ctx instruction.ExecutionContext, tsec *tableSection, refresher chan<- bool, wg *sync.WaitGroup) { for i, inst := range *section { + tsec.instructions[i].start = time.Now() _, err := inst.Exec(ctx) tsec.instructions[i].stop = time.Now() tsec.instructions[i].stopped = true tsec.instructions[i].err = err refresher <- true + wg.Done() } } -func status(refresher chan bool, table []tableSection) { - fmt.Printf("status\n") - remain := false +func status(table []tableSection, refresher <-chan bool, wg *sync.WaitGroup) { - for <-refresher { + for opened := true; true; _, opened = <-refresher { // 1. clean screen fmt.Printf("\033[H\033[2J") @@ -185,7 +224,6 @@ func status(refresher chan bool, table []tableSection) { if !inst.stopped { clifmt.Align(fmt.Sprintf("(%d) %s", i, clifmt.Color(0, inst.name))) fmt.Printf("%s\n", clifmt.Color(33, "processing")) - remain = true continue } @@ -201,11 +239,12 @@ func status(refresher chan bool, table []tableSection) { } } - // 4. close refresher if no remaining task - if !remain { + if !opened { break } } + wg.Done() + }