Wednesday, November 26, 2014

How to Install Any Version of Node and NPM on OSX

Summary

Have the need to downgrade your Node and NPM installations?

If so, here's how I downgraded node from v0.10.33 to v0.10.26 and npm from 2.1.9 to 1.3.6.

Run these commands


sudo rm -rf /usr/local/lib/node_modules
echo prefix=~/.node >> ~/.npmrc
brew uninstall node
cd /usr/local
brew versions node|grep 0.10.26   # << this shows the git commit id (bae051d)
git checkout 0901e77 Library/Formula/node.rb
brew unlink node
brew install node
curl -L https://www.npmjs.org/install.sh|pbcopy
# This is when I created the install-npm-1.3.6.sh file
chmod +x install-npm-1.3.6.sh
install-npm-1.3.6.sh
ln -s `which npm` $HOME/.node/bin/npm


Created install-npm-1.3.6.sh File

Replace "latest" text with "1.3.6"

#!/bin/sh

# A word about this shell script:
#
# It must work everywhere, including on systems that lack
# a /bin/bash, map 'sh' to ksh, ksh97, bash, ash, or zsh,
# and potentially have either a posix shell or bourne
# shell living at /bin/sh.
#
# See this helpful document on writing portable shell scripts:
# http://www.gnu.org/s/hello/manual/autoconf/Portable-Shell.html
#
# The only shell it won't ever work on is cmd.exe.

if [ "x$0" = "xsh" ]; then
  # run as curl | sh
  # on some systems, you can just do cat>npm-install.sh
  # which is a bit cuter.  But on others, &1 is already closed,
  # so catting to another script file won't do anything.
  curl -s https://www.npmjs.org/install.sh > npm-install-$$.sh
  sh npm-install-$$.sh
  ret=$?
  rm npm-install-$$.sh
  exit $ret
fi

# See what "npm_config_*" things there are in the env,
# and make them permanent.
# If this fails, it's not such a big deal.
configures="`env | grep 'npm_config_' | sed -e 's|^npm_config_||g'`"

npm_config_loglevel="error"
if [ "x$npm_debug" = "x" ]; then
  (exit 0)
else
  echo "Running in debug mode."
  echo "Note that this requires bash or zsh."
  set -o xtrace
  set -o pipefail
  npm_config_loglevel="verbose"
fi
export npm_config_loglevel

# make sure that node exists
node=`which node 2>&1`
ret=$?
if [ $ret -eq 0 ] && [ -x "$node" ]; then
  (exit 0)
else
  echo "npm cannot be installed without node.js." >&2
  echo "Install node first, and then try again." >&2
  echo "" >&2
  echo "Maybe node is installed, but not in the PATH?" >&2
  echo "Note that running as sudo can change envs." >&2
  echo ""
  echo "PATH=$PATH" >&2
  exit $ret
fi

# set the temp dir
TMP="${TMPDIR}"
if [ "x$TMP" = "x" ]; then
  TMP="/tmp"
fi
TMP="${TMP}/npm.$$"
rm -rf "$TMP" || true
mkdir "$TMP"
if [ $? -ne 0 ]; then
  echo "failed to mkdir $TMP" >&2
  exit 1
fi

BACK="$PWD"

ret=0
tar="${TAR}"
if [ -z "$tar" ]; then
  tar="${npm_config_tar}"
fi
if [ -z "$tar" ]; then
  tar=`which tar 2>&1`
  ret=$?
fi

if [ $ret -eq 0 ] && [ -x "$tar" ]; then
  echo "tar=$tar"
  echo "version:"
  $tar --version
  ret=$?
fi

if [ $ret -eq 0 ]; then
  (exit 0)
else
  echo "No suitable tar program found."
  exit 1
fi



# Try to find a suitable make
# If the MAKE environment var is set, use that.
# otherwise, try to find gmake, and then make.
# If no make is found, then just execute the necessary commands.

# XXX For some reason, make is building all the docs every time.  This
# is an annoying source of bugs. Figure out why this happens.
MAKE=NOMAKE

if [ "x$MAKE" = "x" ]; then
  make=`which gmake 2>&1`
  if [ $? -eq 0 ] && [ -x "$make" ]; then
    (exit 0)
  else
    make=`which make 2>&1`
    if [ $? -eq 0 ] && [ -x "$make" ]; then
      (exit 0)
    else
      make=NOMAKE
    fi
  fi
else
  make="$MAKE"
fi

if [ -x "$make" ]; then
  (exit 0)
else
  # echo "Installing without make. This may fail." >&2
  make=NOMAKE
fi

# If there's no bash, then don't even try to clean
if [ -x "/bin/bash" ]; then
  (exit 0)
else
  clean="no"
fi

node_version=`"$node" --version 2>&1`
ret=$?
if [ $ret -ne 0 ]; then
  echo "You need node to run this program." >&2
  echo "node --version reports: $node_version" >&2
  echo "with exit code = $ret" >&2
  echo "Please install node before continuing." >&2
  exit $ret
fi

t="${npm_install}"
if [ -z "$t" ]; then
  # switch based on node version.
  # note that we can only use strict sh-compatible patterns here.
  case $node_version in
    0.[01234567].* | v0.[01234567].*)
      echo "You are using an outdated and unsupported version of" >&2
      echo "node ($node_version).  Please update node and try again." >&2
      exit 99
      ;;
    *)
      echo "install npm@1.3.6"
      t="1.3.6"
      ;;
  esac
fi

# need to echo "" after, because Posix sed doesn't treat EOF
# as an implied end of line.
url=`(curl -SsL https://registry.npmjs.org/npm/$t; echo "") \
     | sed -e 's/^.*tarball":"//' \
     | sed -e 's/".*$//'`

ret=$?
if [ "x$url" = "x" ]; then
  ret=125
  # try without the -e arg to sed.
  url=`(curl -SsL https://registry.npmjs.org/npm/$t; echo "") \
       | sed 's/^.*tarball":"//' \
       | sed 's/".*$//'`
  ret=$?
  if [ "x$url" = "x" ]; then
    ret=125
  fi
fi
if [ $ret -ne 0 ]; then
  echo "Failed to get tarball url for npm/$t" >&2
  exit $ret
fi


echo "fetching: $url" >&2

cd "$TMP" \
  && curl -SsL "$url" \
     | $tar -xzf - \
  && cd "$TMP"/* \
  && (ver=`"$node" bin/read-package-json.js package.json version`
      isnpm10=0
      if [ $ret -eq 0 ]; then
        if [ -d node_modules ]; then
          if "$node" node_modules/semver/bin/semver -v "$ver" -r "1"
          then
            isnpm10=1
          fi
        else
          if "$node" bin/semver -v "$ver" -r ">=1.0"; then
            isnpm10=1
          fi
        fi
      fi

      ret=0
      if [ $isnpm10 -eq 1 ] && [ -f "scripts/clean-old.sh" ]; then
        if [ "x$skipclean" = "x" ]; then
          (exit 0)
        else
          clean=no
        fi
        if [ "x$clean" = "xno" ] \
            || [ "x$clean" = "xn" ]; then
          echo "Skipping 0.x cruft clean" >&2
          ret=0
        elif [ "x$clean" = "xy" ] || [ "x$clean" = "xyes" ]; then
          NODE="$node" /bin/bash "scripts/clean-old.sh" "-y"
          ret=$?
        else
          NODE="$node" /bin/bash "scripts/clean-old.sh" &2
        exit $ret
      fi) \
  && (if [ "x$configures" = "x" ]; then
        (exit 0)
      else
        echo "./configure $configures"
        echo "$configures" > npmrc
      fi) \
  && (if [ "$make" = "NOMAKE" ]; then
        (exit 0)
      elif "$make" uninstall install; then
        (exit 0)
      else
        make="NOMAKE"
      fi
      if [ "$make" = "NOMAKE" ]; then
        "$node" cli.js rm npm -gf
        "$node" cli.js install -gf
      fi) \
  && cd "$BACK" \
  && rm -rf "$TMP" \
  && echo "It worked"

ret=$?
if [ $ret -ne 0 ]; then
  echo "It failed" >&2
fi
exit $ret

Check Your Downgraded Versions


$ node -v
v0.10.26
\$ npm -v
1.3.6

Notes

To get the correct version of node to checkout you'll need to do something like this:

brew versions node | grep 0.10.26


... and to get brew versions to work you may need to run this:

brew tap homebrew/boneyard


I do not advocate downgrading node and npm.

This was for example purposes.

Reverting Back to Latest Versions

Not sure why any one would want to remove such a useful command, but for the time being you can use the brew versions command to get the git command used to download a specific node version (0.10.33 in our case).

$ brew versions node | grep 0.10.33
Warning: brew-versions is unsupported and will be removed soon.
You should use the homebrew-versions tap instead:
  https://github.com/Homebrew/homebrew-versions

0.10.33  git checkout 4b9395f /usr/local/Library/Formula/node.rb


$ brew cleanup
$ brew cleanup --cache
$ cd /usr/local/Library/
$ git checkout 4b9395f /usr/local/Library/Formula/node.rb
$ brew install node


Notes

No other combination of brew commands would upgrade node from 0.10.26 to 0.10.33.

So, none of these had any other effect, other than keeping node at version 0.10.26:

$ brew uninstall node
$ brew upgrade
$ brew cleanup 
$ brew cleanup --cache
$ brew upgrade node


Verify Versions

Verify that both node and npm are back to the latest versions:

~ $ node -v
v0.10.33
~ $ npm -v
2.1.9


Share this article



This work is licensed under the Creative Commons Attribution 3.0 Unported License.

For All Git Repos, Ignore All of This

Summary

Are there files that you are always having to add to the .gitignore file for all of your git repositories?

If so, use this technique to create a global ignore file that is automatically applied to all of your git repos on you local workstation.

For all git repos, ignore all of this

First, create the file to contain the global git ignore patterns:

~/.gitignore_global


# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so

# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip

# Logs and databases #
######################
*.log
*.sql
*.sqlite

# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db
.idea
.metadata

/lex_ignore

Then, configure git to use the gitignore_global ignore patterns.

git config --global core.excludesfile ~/.gitignore_global


Share this article



This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Monday, November 17, 2014

Add Golang Bundle to TextMate

Summary

Want Go language syntax highlighting in TextMate v2?

Alan Quatermain's Textmate bundle

Run the following commands and you should be set...

mkdir -p ~/Library/Application\ Support/Avian/Bundles
cd ~/Library/Application\ Support/Avian/Bundles
git clone git://github.com/AlanQuatermain/go-tmbundle.git Go.tmbundle

Notes

This also works for TextMate 1.5.

References

https://github.com/AlanQuatermain/go-tmbundle https://github.com/rsms/Go.tmbundle

Share this article



This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Sunday, November 16, 2014

Upgrade PHP on OSX 10.10 (yosemite)

Summary

First, you need to upgrade your to the latest version of XCode and reinstall XCode client tools: xcode-select --install

Even then, you may run into problems upgrading PHP:

Problems Upgrading PHP


~ $ brew upgrade
==> Upgrading 2 outdated packages, with result:
gdal 1.11.1_2, php55 5.5.19
==> Upgrading gdal
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/gdal-1.11.1_2.yosemite.bottle.tar.gz
######################################################################## 100.0%
==> Pouring gdal-1.11.1_2.yosemite.bottle.tar.gz
🍺  /usr/local/Cellar/gdal/1.11.1_2: 229 files, 34M
==> Upgrading php55
==> Downloading https://www.php.net/get/php-5.5.19.tar.bz2/from/this/mirror
######################################################################## 100.0%
Error: Permission denied - /usr/local/Cellar/php55/5.5.19
~ $ brew doctor
Your system is ready to brew.

Problems Upgrading PHP

Run the following commands and you should be set...

$ sudo chmod -R g+w /Library/Caches/Homebrew
$ brew rm zlib
$ brew update && brew upgrade
$ brew install git
$ brew install openssl
$ brew install php56 --homebrew-apxs --with-apache --with-homebrew-curl --with-homebrew-openssl --with-phpdbg --with-tidy --without-snmp

References

http://lexsheehan.blogspot.com/2013/12/while-testing-new-async-infrastructure.html http://superuser.com/questions/550305/homebrew-install-problems-permission-denied-library-caches-homebrew-formula http://stackoverflow.com/questions/25149032/brew-install-php55-intl-fails-cant-install-composer

Share this article



This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Script to Install or Update Go on OSX

Summary

Here's a bash script to Install or Update Go on OSX.

update-go


#!/bin/bash
function goversion {
    go version|cut -d" " -f3|while read n; do echo "${n:2}"; done    
}
set -x
brew update
brew doctor
{ set +x; } &>/dev/null
echo "Current Go version: `goversion`"
echo ""
echo "Need to do what brew doctor suggested? (It's safe to rerun this command.)  CTRL+C to stop --or-- Enter to continue..."
read x

if [ "`goversion`" == "" ]; then
    brew install go 
    brew link --overwrite go
else
    brew upgrade go
    brew link go
fi
echo "New Go version: `goversion`"

# Following currently enables intellij Go plugin to use new Go version
function reset-idea-go-plugin {
    if [ "`which idea`" != "" ]; then
        printf "intellij is installed.  Now, updating its go plugin..."
        # Note: version numbers may change
        rm /usr/local/Cellar/go/1.2.2
        rm /usr/local/Cellar/go/1.3
        ln -s /usr/local/Cellar/go/1.3.3 /usr/local/Cellar/go/1.2.2
        echo "Done."
    fi
} 

reset-idea-go-plugin 2>/dev/null

Output


~ $ update-go
+ brew update
Already up-to-date.
+ brew doctor
Your system is ready to brew.
Current Go version: 1.3.3

Need to do what brew doctor suggested? (It's safe to rerun this command.)  CTRL+C to stop --or-- Enter to continue...

Error: go-1.3.3 already installed
Warning: Already linked: /usr/local/Cellar/go/1.3.3
To relink: brew unlink go && brew link go
New Go version: 1.3.3
intellij is installed.  Now, updating its go plugin...Done.
~ $

Notes

It's safe to rerun this script.

Assumes you're on a mac.

Assumes you have homebrew installed.

If you use the Go plugin in IntelliJ, this script will direct it to use the newly installed version of Golang.


References

http://blog.jetbrains.com/idea/2010/08/quickly-create-jar-artifact/

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Tuesday, November 4, 2014

Create Executable Jar from IntelliJ Java Project

Summary

  • Define Jar file Components
  • Build Jar file
  • Run command

Define Jar file Components

File | Project Structure...
Select Artifacts in left side under Project Settings
  • Click "+"
  • Select "jar"
  • Choose "From modules with dependencies"
  • Select the class with your executable main method.

Build Jar file

Build | Build Artifacts...
  • Under "Build Artifact", choose the jar file that you defined earlier
  • Under "Build", click "Build"
The jar file can be found in the /out/artifacts/_jar directory

Run command

If your project name is "ijtest" the command to execute your jar would look something like this:

$ java -jar /Users/lex/dev/java/ijtest/out/artifacts/ijtest_jar/ijtest.jar

Notes

You can pass parameters, too.

$ java -jar /Users/lex/dev/java/ijtest/out/artifacts/IJTest_jar/ij.jar --parm1=ONE --parm2=TWO


Troubleshooting

First, make sure you are running a recent version of InjelliJ.

I'm running InjelliJ Community Edition v14.0.2

Next, make sure the sdk you've configured in IntelliJ is consistent with the one you use on your console.

This is what happens when your IntelliJ JDK is version 1.7 but your java in your console is version 1.6...


~/dev/java $ java -jar /Users/lex/dev/java/ijtest/out/artifacts/ijtest_jar/ijtest.jar
Exception in thread "main" java.lang.UnsupportedClassVersionError: com/company/Main : Unsupported major.minor version 51.0
 at java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClassCond(ClassLoader.java:637)
 at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
 at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
 at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
 at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
~/dev/java $ java -version
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-466.1-11M4716)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-466.1, mixed mode)
~/dev/java $ find /Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home -name java
/Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home/bin/java
/Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home/jre/bin/java
~/dev/java $ /Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home/jre/bin/java  -jar /Users/lex/dev/java/ijtest/out/artifacts/ijtest_jar/ijtest.jar
~/dev/java $ /Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home/jre/bin/java  -jar /Users/lex/dev/java/ijtest/out/artifacts/ijtest_jar/ijtest.jar
hello, world!


Profit!

Here we run the jar, from the console, that I we just created using the steps outlined above...

~/dev/java/ijtest/out/artifacts/ijtest_jar $ ls -lrt
total 24
-rw-r--r--  1 lex  staff   968 Jan  5 22:56 ijtest.jar
drwx------  4 lex  staff   136 Jan  5 22:57 ijtest
-rw-r--r--@ 1 lex  staff  6148 Jan  5 22:57 .DS_Store
~/dev/java/ijtest/out/artifacts/ijtest_jar $ jar xf ./ijtest.jar
~/dev/java/ijtest/out/artifacts/ijtest_jar $ ls -lrt
total 24
drwxr-xr-x  3 lex  staff   102 Jan  5 22:56 com
drwxr-xr-x  3 lex  staff   102 Jan  5 22:56 META-INF
-rw-r--r--  1 lex  staff   968 Jan  5 22:56 ijtest.jar
drwx------  4 lex  staff   136 Jan  5 22:57 ijtest
-rw-r--r--@ 1 lex  staff  6148 Jan  5 22:57 .DS_Store
~/dev/java/ijtest/out/artifacts/ijtest_jar $ find .
.
./.DS_Store
./com
./com/company
./com/company/Main.class
./ijtest
./ijtest/com
./ijtest/com/company
./ijtest/com/company/Main.class
./ijtest/META-INF
./ijtest/META-INF/MANIFEST.MF
./ijtest.jar
./META-INF
./META-INF/MANIFEST.MF


Notice that all files exist in the jar file, including MANIFEST.MF.

References

http://blog.jetbrains.com/idea/2010/08/quickly-create-jar-artifact/

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Thursday, October 23, 2014

Prevent incorrectly-formatted Go code from being committed to Git

Problem

Even though Go is beautifully straightforward and blatantly obvious as to what is going on, there is still room for coding style differences.

And what happens when you're working in a multi-developer project not every developer uses the same coding styles?

Examples

  • Use TAB character rather than spaces
  • Use 2 spaces per TAB (v. 3 or 4 spaces)
  • Open brace on new line (v. at end of line)
  • etc...
...You get to experience needless merging and git diffs, that look like every line changed.

Enough of that nonsense... Just use the following pre-commit script to force each developer to run the standard gofmt against each source file before they git committed to git.

misc/git/pre-commit script

Simply create a file named pre-commit in your project's .git/hooks/ directory with the following contents:

pre-commit


#!/bin/sh
# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# git gofmt pre-commit hook
#
# To use, store as .git/hooks/pre-commit inside your repository and make sure
# it has execute permissions.
#
# This script does not handle file names that contain spaces.

gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
[ -z "$gofiles" ] && exit 0

unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0

# Some files are not gofmt'd. Print message and fail.

echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
 echo >&2 "  gofmt -w $PWD/$fn"
done

exit 1

Make it executable


$ chmod +x .git/hooks/pre-commit

See the pre-commit hook work

Add and extra TAB.

$ git diff
diff --git a/errors.go b/errors.go
index fc62d4c..dc3addf 100644
--- a/errors.go
+++ b/errors.go
@@ -15,8 +15,8 @@ 
     defaultErrMsg := "Oops! We had an issue with your request."
-    for _, errMsg := range optionalDefaultErrMsg {
-        defaultErrMsg = errMsg
+    if len(optionalDefaultErrMsg) > 0 {
+            defaultErrMsg = errMsg
     }

$ git add-commit 'Add extra TAB to break formatting'
Go files must be formatted with gofmt. Please run:
  gofmt -w /<PROJECT_DIRECTORY_HERE>/errors.go

See the pre-commit hook work

Run gofmt -w /<PROJECT_DIRECTORY_HERE>/errors.go and try again.

This time, your commit should work and your properly formatted file will be saved to your local git repo.

Notes

Since the file pre-commit file is in your .git/hooks directory, by default it will not get checked into your repo.

So, it's safe to use. No worries about an extra commit because you created the new pre-commit file.

Others on your team could rely only on their IDE to provide gofmt functionality (and choose not use this pre-commit hook).

But you can rest assured that all of your code will always be properly formatted before any push into the team git repo.

Configure gofmt Globally

Since git 2.9+ (2016-06-13), we can place our pre-commit file in a global git/hooks directory to configure all of our git repos to execute it.


$ git config --global core.hooksPath /path/to/global/git/hooks

Example

If you put your pre-commit script in $HOME/dev/global/.git/hooks/pre-commit then you can run the following command to configure git to run gofmt on the Go files that you want to commit to git:

$ git config --global core.hooksPath ~/dev/global/.git/hooks

Log for Configure gofmt Globally

Notes:

  • main.go has some formatting issues on the func main() line
  • We can build our Go app locally (with the formatting issues)
  • We are unable to commit our poorly formatted Go code to our local repository due to our core.hooksPath git configuration
  • After running gofmt -w we are able to commit our file and push it to the remote repo
  • The pre-commit script looks for Go files in your index, i.e., your local git staging area, and will only run if you are attempting to commit one or more .go files
  • See https://github.com/l3x/gofmt-demo.git


$ cat main.go
package main

import "fmt"

 func main()  {
 fmt.Println("formatting errors above")
}

$ gs
On branch master
Your branch is up-to-date with 'origin/master'.

Untracked files:
  (use "git add ..." to include in what will be committed)

 main.go

nothing added to commit but untracked files present (use "git add" to track)

$ git add .

$ go build

$ ll
total 4128
drwxr-xr-x   6 lex  staff      192 Mar 21 11:36 ./
drwxr-xr-x   3 lex  staff       96 Mar 21 11:34 ../
drwxr-xr-x  13 lex  staff      416 Mar 21 11:36 .git/
-rw-r--r--   1 lex  staff        0 Mar 21 11:34 README.md
-rwxr-xr-x   1 lex  staff  2106512 Mar 21 11:36 gofmt-demo*
-rw-r--r--   1 lex  staff       86 Mar 21 11:36 main.go

$ ./gofmt-demo
formatting errors above

$ cat main.go
package main

import "fmt"

 func main()  {
 fmt.Println("formatting errors above")
}

$ git commit -m 'demo use of global git precommit hook'
Go files must be formatted with gofmt. Please run:
  gofmt -w /Users/lex/tmp/20180321-113307/gofmt-demo/main.go

$ gofmt -w /Users/lex/tmp/20180321-113307/gofmt-demo/main.go

$ gs
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD ..." to unstage)

 new file:   main.go

Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

 modified:   main.go

Untracked files:
  (use "git add ..." to include in what will be committed)

 gofmt-demo

$ git add .

$ go build

$ ./gofmt-demo
formatting errors above

$ git commit -m 'demo use of global git precommit hook'
[master f024a20] demo use of global git precommit hook
 2 files changed, 7 insertions(+)
 create mode 100755 gofmt-demo
 create mode 100644 main.go

$ git push
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 737.15 KiB | 6.41 MiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To github.com:l3x/gofmt-demo.git
   6cff8f6..f024a20  master -> master

$ cat main.go
package main

import "fmt"

func main() {
 fmt.Println("formatting errors above")
}

References

http://blog.golang.org/go-fmt-your-code
https://golang.org/doc/effective_go.html

This work is licensed under the Creative Commons Attribution 3.0 Unported License.