summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <m.shulhan@gmail.com>2020-06-04 02:50:57 +0700
committerShulhan <m.shulhan@gmail.com>2020-06-04 02:50:57 +0700
commit8b9e8bdc0fa7c9c4bb4024567d562af558385e1e (patch)
tree65b47a25f2c07aa0ed616aacc947917face41014
parent9bf6863448581351232dcdc5aa06a50907542f60 (diff)
downloadawwan-8b9e8bdc0fa7c9c4bb4024567d562af558385e1e.tar.xz
all: add magic command "#require:"
Magic word `#require:` will ensure that the next statement will always executed when its skipped with start number. For example, given following script with line number 1: #require: 2: echo a 3: echo b 4: #require: 5: echo c ``` executing `awwan local script.aww 3`, will always execute line number 2 `echo a`, but not line number 5 (because its before line start 3).
-rw-r--r--CHANGELOG.adoc21
-rw-r--r--README.adoc110
-rw-r--r--README.md78
-rw-r--r--awwan.go1
-rw-r--r--command.go30
-rw-r--r--script.go16
6 files changed, 244 insertions, 12 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index db58a89..ab5972c 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -1,6 +1,25 @@
= Changelog for awwan
-== awwan 0.1.1 (2020.06.xx)
+== awwan 0.2.0 (2020.06.xx)
+
+=== New features
+
+* all: add magic command "#require:"
+
+Magic word `#require:` will ensure that the next statement will always
+executed when its skipped with start number.
+For example, given following script with line number
+
+ 1: #require:
+ 2: echo a
+ 3: echo b
+ 4: #require:
+ 5: echo c
+```
+
+executing `awwan local script.aww 3`, will always execute line
+number 2 `echo a`, but not line number 5 (because its before line start 3).
+
=== Enhancements
diff --git a/README.adoc b/README.adoc
index f69a268..8a740ab 100644
--- a/README.adoc
+++ b/README.adoc
@@ -85,8 +85,23 @@ $ awwan play cloud/myserver/script.aww 5 -
The awwan script is similar to shell script.
Each line started with '#' is a comment, except for special, magic words.
-There are three magic words in the script: `#get:`, `#get!`, `#put:`, and
-`#put!`.
+There are five magic words in the script: `#require:`, `#get:`, `#get!`,
+`#put:`, and `#put!`.
+
+Magic word `#require:` will ensure that the next statement will always
+executed when its skipped with start number.
+For example, given following script with line number
+
+```
+1: #require:
+2: echo a
+3: echo b
+4: #require:
+5: echo c
+```
+
+executing `awwan local script.aww 3`, will always execute line number 2 `echo
+a`, but not line number 5 (because its before line start 3).
Magic word `#get:` will copy file from remote server to your local file
system.
@@ -226,21 +241,29 @@ that match with "development" in current ".ssh/config" or in "~/.ssh/config".
== EXAMPLE
+To give you the taste of the idea, I will show you an example using the
+working directory $WORKDIR as our base directory.
+
Let say that we have the working remote server named "myserver" at IP address
-"1.2.3.4" using username "arch" on port "2222" in the current ".ssh/config"
-file
+"1.2.3.4" using username "arch" on port "2222".
+
+In the $WORKDIR, create directory ".ssh" and "config" file,
----
+$ mkdir -p .ssh
+$ cat > .ssh/config <<EOF
Host myserver
Hostname 1.2.3.4
User arch
Port 2222
- IdentityFile ~/.ssh/id_rsa
+ IdentityFile .ssh/myserver
+EOF
----
-and the environment file "awwan.env"
+Still in the $WORKDIR, create the environment file "awwan.env"
----
+$ cat > awwan.env <<EOF
[all]
user = arch
host = myserver
@@ -248,26 +271,38 @@ host = myserver
[whitelist "ip"]
alpha = 1.2.3.4/32
beta = 2.3.4.5/32
+EOF
----
-and script file "test.aww",
+Inside the $WORKDIR we create the directory that match with our server name
+and a script file "test.aww",
----
+$ mkdir -p myserver
+$ cat > myserver/test.aww <<EOF
echo {{.Val "all::host"}}`
#put: {{.ScriptDir}}/test /tmp/
cat /tmp/test
+EOF
----
and a template file "test",
----
+$ cat > myserver/test <<EOF
Hi {{.Val "all::user"}}!
+EOF
----
-When executed, it will print the following output to terminal,
+When executed from start to end like these,
----
$ awwan play myserver/test.aww 1 -
+----
+
+it will print the following output to terminal,
+
+----
>>> arch@1.2.3.4:2222: 1: echo myserver
myserver
@@ -275,7 +310,6 @@ test 100% 9 0.4KB/s 00
>>> arch@1.2.3.4:2222: 3: cat /tmp/test
Hi arch!
-
----
That's it.
@@ -355,6 +389,64 @@ Any keys that are duplicate will be merged and the last one will overwrite the
previous one.
+=== Use case of magic command `#require:`
+
+The magic command `#require:` is added to prevent running local command using
+different project or configuration.
+
+The use case was derived from experience with `gcloud` and `kubectl` commands.
+When you have more than one projects in GCP, you need to make sure that the
+command that you run is using correct configuration.
+
+Here is the example of deploying Cloud Functions using local awwan script,
+
+```
+1: #require:
+2: gcloud config configurations activate {{.Val "gcloud::config"}}
+3:
+4: ## Create PubSub topic.
+5:
+6: gcloud pubsub topics create {{.Val "CloudFunctions:log2slack:pubsub_topic"}}
+7:
+8: ## Create Logger Sink to Route the log to PubSub topic.
+9:
+10: gcloud logging sinks create {{.Val "CloudFunctions:log2slack:pubsub_topic"}} \
+11: pubsub.googleapis.com/projects/{{.Val "gcloud::project"}}/topics/{{.Val "CloudFunctions:log2slack:pubsub_topic"}} \
+12: --log-filter=severity>=WARNING
+13:
+14: ## Create Cloud Functions to forward log to Slack.
+15:
+16: gcloud functions deploy Log2Slack \
+17: --source {{.ScriptDir}} \
+18: --entry-point Log2Slack \
+19: --runtime go113 \
+20: --trigger-topic {{.Val "CloudFunctions:log2slack:pubsub_topic"}} \
+21: --set-env-vars SLACK_WEBHOOK_URL={{.Val "slack::slack_webhook_url"}} \
+22: --ingress-settings internal-only \
+23: --max-instances=5
+24:
+25: ## Test the chains by publishing a message to Topic...
+26:
+27: gcloud pubsub topics \
+28: publish {{.Val "CloudFunctions:log2slack:pubsub_topic"}} \
+29: --message='Hello World!'
+```
+
+When executing statement at line number 6, 10, 16 or 27 we need to make sure
+that it always using the correct environment "gcloud::config",
+
+
+```
+$ awwan local awwan/playground/CloudFunctions/log2slack/local.deploy.aww 27
+2020/06/04 01:48:38 >>> loading "/xxx//awwan.env" ...
+2020/06/04 01:48:38 >>> loading "/xxx/awwan/dev/awwan.env" ...
+2020/06/04 01:48:38 --- require 2: gcloud config configurations activate dev
+
+Activated [dev].
+2020/06/04 01:48:38 >>> local 29: gcloud pubsub topics publish logs
+--message='Hello World!'
+```
+
== BUGS
Shell pipe "|", "<", or ">" does not work in the script, yet.
diff --git a/README.md b/README.md
index 7a16dac..7d2fe5e 100644
--- a/README.md
+++ b/README.md
@@ -78,8 +78,23 @@ $ awwan play cloud/myserver/script.aww 5 -
The awwan script is similar to shell script.
Each line started with '#' is a comment, except for special, magic words.
-There are three magic words in the script: `#get:`, `#get!`, `#put:`, and
-`#put!`.
+There are five magic words in the script: `#require:`, `#get:`, `#get!`,
+`#put:`, and `#put!`.
+
+Magic word `#require:` will ensure that the next statement will always
+executed when its skipped with start number.
+For example, given following script with line number
+
+```
+1: #require:
+2: echo a
+3: echo b
+4: #require:
+5: echo c
+```
+
+executing `awwan local script.aww 3`, will always execute line number 2 `echo
+a`, but not line number 5 (because its before line start 3).
Magic word `#get:` will copy file from remote server to your local file
system.
@@ -367,6 +382,65 @@ Any keys that are duplicate will be merged and the last one will overwrite the
previous one.
+### Use case of magic command `#require:`
+
+The magic command `#require:` is added to prevent running local command using
+different project or configuration.
+
+The use case was derived from experience with `gcloud` and `kubectl` commands.
+When you have more than one projects in GCP, you need to make sure that the
+command that you run is using correct configuration.
+
+Here is the example of deploying Cloud Functions using local awwan script,
+
+```
+1: #require:
+2: gcloud config configurations activate {{.Val "gcloud::config"}}
+3:
+4: ## Create PubSub topic.
+5:
+6: gcloud pubsub topics create {{.Val "CloudFunctions:log2slack:pubsub_topic"}}
+7:
+8: ## Create Logger Sink to Route the log to PubSub topic.
+9:
+10: gcloud logging sinks create {{.Val "CloudFunctions:log2slack:pubsub_topic"}} \
+11: pubsub.googleapis.com/projects/{{.Val "gcloud::project"}}/topics/{{.Val "CloudFunctions:log2slack:pubsub_topic"}} \
+12: --log-filter=severity>=WARNING
+13:
+14: ## Create Cloud Functions to forward log to Slack.
+15:
+16: gcloud functions deploy Log2Slack \
+17: --source {{.ScriptDir}} \
+18: --entry-point Log2Slack \
+19: --runtime go113 \
+20: --trigger-topic {{.Val "CloudFunctions:log2slack:pubsub_topic"}} \
+21: --set-env-vars SLACK_WEBHOOK_URL={{.Val "slack::slack_webhook_url"}} \
+22: --ingress-settings internal-only \
+23: --max-instances=5
+24:
+25: ## Test the chains by publishing a message to Topic...
+26:
+27: gcloud pubsub topics \
+28: publish {{.Val "CloudFunctions:log2slack:pubsub_topic"}} \
+29: --message='Hello World!'
+```
+
+When executing statement at line number 6, 10, 16 or 27 we need to make sure
+that it always using the correct environment "gcloud::config",
+
+```
+$ awwan local awwan/playground/CloudFunctions/log2slack/local.deploy.aww 27
+2020/06/04 01:48:38 >>> loading "/xxx//awwan.env" ...
+2020/06/04 01:48:38 >>> loading "/xxx/awwan/dev/awwan.env" ...
+2020/06/04 01:48:38 --- require 2: gcloud config configurations activate dev
+
+Activated [dev].
+2020/06/04 01:48:38 >>> local 29: gcloud pubsub topics publish logs
+--message='Hello World!'
+```
+
+
+
## BUGS
Shell pipe "|", "<", or ">" does not work in the script, yet.
diff --git a/awwan.go b/awwan.go
index 9db0b74..af16608 100644
--- a/awwan.go
+++ b/awwan.go
@@ -18,4 +18,5 @@ var (
cmdMagicPut = []byte("#put:")
cmdMagicSudoGet = []byte("#get!")
cmdMagicSudoPut = []byte("#put!")
+ cmdMagicRequire = []byte("#require:")
)
diff --git a/command.go b/command.go
index f116a5b..d2f9634 100644
--- a/command.go
+++ b/command.go
@@ -106,6 +106,11 @@ func (cmd *Command) doPlay() {
}
}()
+ err = cmd.executeRequires()
+ if err != nil {
+ log.Fatal(err)
+ }
+
cmd.executeScript()
}
@@ -125,6 +130,10 @@ func (cmd *Command) doLocal() {
}
}()
+ err = cmd.executeRequires()
+ if err != nil {
+ log.Fatal(err)
+ }
cmd.executeLocalScript()
}
@@ -297,6 +306,27 @@ func (cmd *Command) executeLocalScript() {
}
}
+//
+// executeRequires run the #require: statements.
+//
+func (cmd *Command) executeRequires() (err error) {
+ for x := 0; x < cmd.env.scriptStart; x++ {
+ stmt := cmd.script.requires[x]
+ if len(stmt) == 0 {
+ continue
+ }
+
+ log.Printf("--- require %d: %s\n\n", x, stmt)
+
+ err = exec.Run(string(stmt), os.Stdout, os.Stderr)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
func (cmd *Command) executeScript() {
for x := cmd.env.scriptStart; x <= cmd.env.scriptEnd; x++ {
stmt := cmd.script.Statements[x]
diff --git a/script.go b/script.go
index 4180c3e..5660050 100644
--- a/script.go
+++ b/script.go
@@ -17,6 +17,7 @@ import (
// script define the content of ".aww" file, line by line.
//
type script struct {
+ requires [][]byte
Statements [][]byte
}
@@ -37,6 +38,8 @@ func newScript(env *Environment, path string) *script {
env.scriptEnd = len(s.Statements) - 1
}
+ s.parseMagicRequire()
+
return s
}
@@ -115,3 +118,16 @@ func (s *script) join() {
x = y
}
}
+
+func (s *script) parseMagicRequire() {
+ s.requires = make([][]byte, len(s.Statements))
+
+ for x, stmt := range s.Statements {
+ if !bytes.HasPrefix(stmt, cmdMagicRequire) {
+ continue
+ }
+ if len(s.Statements) > x+1 {
+ s.requires[x+1] = bytes.TrimSpace(s.Statements[x+1])
+ }
+ }
+}