Commits (5)
......@@ -266,14 +266,15 @@
(defun xclip-working ()
"Quick Check to see if X is working."
(if (getenv "DISPLAY")
(if (runs-and-exits-zero "xset" "q")
;; this xset test is a bit flakey
;; (if (runs-and-exits-zero "xset" "q")
;; Using xclip to set an invalid selection is as lightly intrusive
;; check I could come up with, and not overwriting anything
;; however it seems to hang
;; (if (runs-and-exits-zero "xclip" "-selection" "unused")
;; 'true)
;; )
(defun populate-x-clipboard ()
......@@ -292,11 +293,9 @@
;; As we start on other OSes, we'll need to copy this differently
(if (xclip-working)
(with-current-buffer (get-buffer-create "start-tmate-command")
(insert-for-yank "You will need to copy this manually:\n\n")
(with-current-buffer (get-buffer-create "start-tmate-command" )
(insert-for-yank "You will need to copy this manually:\n\n" )
;; needs to be global, so it's availabel to the other buffer
(setq tmate-command start-tmate-command)
......@@ -306,6 +305,20 @@
(switch-to-buffer "start-tmate-command")
(y-or-n-p "Have you Pasted?")
;; https://www.wisdomandwonder.com/article/10630/how-fast-can-you-tangle-in-org-mode
(setq help/default-gc-cons-threshold gc-cons-threshold)
(defun help/set-gc-cons-threshold (&optional multiplier notify)
"Set `gc-cons-threshold' either to its default value or a
`multiplier' thereof."
(let* ((new-multiplier (or multiplier 1))
(new-threshold (* help/default-gc-cons-threshold
(setq gc-cons-threshold new-threshold)
(when notify (message "Setting `gc-cons-threshold' to %s"
(defun help/double-gc-cons-threshold () "Double `gc-cons-threshold'." (help/set-gc-cons-threshold 2))
(add-hook 'org-babel-pre-tangle-hook #'help/double-gc-cons-threshold)
(add-hook 'org-babel-post-tangle-hook #'help/set-gc-cons-threshold)
;; (gui-select-text (concat "rm -fi " socket "; ssh -tAX " ssh-user "@" ssh-host " -L " socket ":" socket " " start-tmate-over-ssh-command))
;; (edebug-trace "TRACING socket:%S" socket)
;; (edebug-trace "TRACING org-babel-header-args:tmate %S" org-babel-header-args:emacs-lisp)
......@@ -327,3 +340,6 @@
;; https://www.emacswiki.org/emacs/AutomaticFileHeaders #templates / updates etc
;; ^^ based on https://www.emacswiki.org/emacs/download/header2.el
;; ;; https://stackoverflow.com/questions/13228001/org-mode-nested-properties
;; https://www.reddit.com/r/emacs/comments/4154bu/how_to_get_orgmode_to_recognize_markdownstyle/
;; ^^ https://www.reddit.com/r/emacs/comments/4154bu/how_to_get_orgmode_to_recognize_markdownstyle/cz0bb45/
# -*- eval: (setq-local default-directory "~/gqlgen-todos"); -*-
# -*- eval: (setq-local compile-command "go run server/server.go"; -*-
# -*- github-username: "hh"; -*-
# -*- compile-command: "go run server/server.go"; -*-
* [[https://gqlgen.com/getting-started/][Building GraphQL servers in golang - gqlgen]]
:header-args:tmate+: :session session:gqlgen
** [[https://gqlgen.com/getting-started/#setup-project][Setup Project]]
#+BEGIN_SRC tmate
export GITHUB_USER=hh
cd ~/
rm -rfi ~/gqlgen-todos/
#+BEGIN_SRC tmate :dir ~/
mkdir gqlgen-todos
cd gqlgen-todos
go mod init github.com/$GITHUB_USER/gqlgen-todos
** [[https://gqlgen.com/getting-started/#building-the-server][Building the server]]
#+BEGIN_SRC graphql :tangle (concat default-directory "/schema.graphql")
type Todo {
id: ID!
text: String!
done: Boolean!
user: User!
type User {
id: ID!
name: String!
type Query {
todos: [Todo!]!
input NewTodo {
text: String!
userId: String!
type Mutation {
createTodo(input: NewTodo!): Todo!
** [[https://gqlgen.com/getting-started/#create-the-project-skeleton][Create the project skeleton]]
#+BEGIN_SRC tmate
go run github.com/99designs/gqlgen init
This has created an empty skeleton with all files you need:
- [[file:gqlgen.yml][gqlgen.yml]] The gqlgen config file, knobs for controlling the generated code.
- [[file:generated.go][generated.go]] The GraphQL execution runtime, the bulk of the generated code.
- [[file:models_gen.go][models_gen.go]] Generated models required to build the graph. Often you will override these with your own models. Still very useful for input types.
- [[file:resolver.go][resolver.go]] This is where your application code lives. generated.go will call into this to get the data the user has requested.
- [[file:server/server.go][server/server.go]] This is a minimal entry point that sets up an http.Handler to the generated GraphQL server.
** [[https://gqlgen.com/getting-started/#create-the-database-models][Create the database modules]]
#+BEGIN_SRC golang :tangle (concat default-directory "/todo.go")
package gqlgen_todos
type Todo struct {
ID string
Text string
Done bool
UserID string
Add to [[file:gqlgen.yml][gqlgen.yml]]
#+BEGIN_SRC yaml :tangle (concat default-directory "/gqlgen-models-to-add.yml")
model: github.com/hh/gqlgen-todos.Todo
#+BEGIN_SRC tmate
cat gqlgen-models-to-add.yml >> gqlgen.yml
go run github.com/99designs/gqlgen
** [[https://gqlgen.com/getting-started/#implement-the-resolvers][Implement the resolvers]]
[[file:generated.go::func%20NewExecutableSchema][generated.go NewExecutableSchema]]
Notice the [[file:generated.go::User%20func(childComplexity%20int)%20int][TodoResolver.User]] method?
For any missing models (like NewTodo) gqlgen will generate a go struct.
** [[https://gqlgen.com/getting-started/#write-the-resolvers][Write the resolvers]]
#+BEGIN_SRC tmate
rm resolver.go
go run github.com/99designs/gqlgen
#+BEGIN_SRC go :tangle (concat default-directory "/resolver.go")
package gqlgen_todos
import (
context "context"
type Resolver struct {
todos []Todo
func (r *Resolver) Mutation() MutationResolver {
return &mutationResolver{r}
func (r *Resolver) Query() QueryResolver {
return &queryResolver{r}
func (r *Resolver) Todo() TodoResolver {
return &todoResolver{r}
type mutationResolver struct{ *Resolver }
func (r *mutationResolver) CreateTodo(ctx context.Context, input NewTodo) (*Todo, error) {
todo := &Todo{
Text: input.Text,
ID: fmt.Sprintf("T%d", rand.Int()),
UserID: input.UserID,
r.todos = append(r.todos, *todo)
return todo, nil
type queryResolver struct{ *Resolver }
func (r *queryResolver) Todos(ctx context.Context) ([]Todo, error) {
return r.todos, nil
type todoResolver struct{ *Resolver }
func (r *todoResolver) User(ctx context.Context, obj *Todo) (*User, error) {
return &User{ID: obj.UserID, Name: "user " + obj.UserID}, nil
** errors
locally: [[file:resolver.go::17][resolver.go::17]]
./resolver.go:17:24: cannot use &queryResolver literal (type *queryResolver) as type QueryResolver in return argument:
*queryResolver does not implement QueryResolver (wrong type for Todos method)
have Todos(context.Context) ([]Todo, error)
want Todos(context.Context) ([]*Todo, error)
Compilation exited abnormally with code 2 at Sun May 19 06:47:30
The following block can be use to stop the server and bring in the logs:
#+BEGIN_SRC elisp
(with-current-buffer (get-buffer "*compilation*")
(buffer-substring 0 5)
#+BEGIN_SRC shell
pkill -P $(pgrep -f server/server.go)
#+BEGIN_SRC shell :async
go run server/server.go
) 2>&1
echo $?
# github.com/hh/gqlgen-todos
./resolver.go:17:24: cannot use &queryResolver literal (type *queryResolver) as type QueryResolver in return argument:
,*queryResolver does not implement QueryResolver (wrong type for Todos method)
have Todos(context.Context) ([]Todo, error)
want Todos(context.Context) ([]*Todo, error)
then open http://localhost:8080 in a browser. here are some queries to try:
TODO: Skewer and org mode might be very interesting at this point.
Mainly for populating that left query side.
#+BEGIN_SRC elisp
(setq-local compile-command "go run server/server.go ")
* My Environment
** environ
#+BEGIN_SRC shell
go version
go version go1.12.3 linux/amd64
** go env
#+BEGIN_SRC shell
go env
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build045453696=/tmp/go-build -gno-record-gcc-switches"
* checkout code
#+BEGIN_SRC elisp :results none
(setq-local src-dir "~/src/k8s")
(setq-local src-repo "git@github.com:kubernetes/kubernetes.git")
#+BEGIN_SRC elisp :results none
(setq-local src-dir "~/src/graphql")
(setq-local src-repo "git@github.com:graphql/graphql-js.git")
#+BEGIN_SRC elisp :results none
(setq-local src-dir "~/src/graphql-js")
(setq-local src-repo "git@github.com:graphql/graphql-js.git")
#+BEGIN_SRC elisp :results none
(delete-directory src-dir t)
Clone the repository!
Might be nice to be notified when it's finished cloning and open magit-status
#+BEGIN_SRC elisp :results none
(magit-clone-regular src-repo src-dir "--progress")
;; might be nice to delay here until the clone is done
(when (file-directory-p src-dir)
(display-buffer (magit-status-setup-buffer src-dir)))
This hack borrowed from:
#+BEGIN_SRC elisp :results silent
(setq-local project-to-switch src-dir)
(let ((default-directory project-to-switch))
(let (
(funcall projectile-project-name-function
(funcall 'projectile-find-file)))
* Poke around
......@@ -5,7 +5,8 @@ BASE=$(basename $orgfile)
tmate -S /tmp/${USER}.${BASE}.iisocket new-session \
-A -s $USER -n emacs \
"tmate wait tmate-ready \
&& TMATE_CONNECT=\$(tmate display -p '#{tmate_ssh} # ${USER}.${BASE} # $(date) # #{tmate_web}') \
\$(tmate display gp '#{tmate_ssh} # ${USER}.${BASE} # $(date) # #{tmate_web}') \
; echo \$TMATE_CONNECT \
; (echo \$TMATE_CONNECT | xclip -i -sel p -f | xclip -i -sel c )2>/dev/null \
; echo Share the above with your friends and hit enter here when done? \