Skip to content

Instantly share code, notes, and snippets.

@alecthegeek
Last active September 3, 2015 18:18
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alecthegeek/3a48bb2bd3aa52a20306 to your computer and use it in GitHub Desktop.
Save alecthegeek/3a48bb2bd3aa52a20306 to your computer and use it in GitHub Desktop.
Set up a "standard" go project workspace with support for 3rdparty modules, version control repo and a template main package
# Install all the Go tools and godep tool
# Location of gobin is based on installation by OS X Homebrew
sudo -u admin GOPATH=/tmp GOBIN=/usr/local/opt/go/bin go get -u golang.org/x/tools/cmd/...
sudo -u admin GOPATH=/tmp GOBIN=/usr/local/opt/go/bin go get -u github.com/tools/godep
#! /usr/bin/env bash
# Create a "standard" Go Lang package directory
COPYRIGHTYEAR=$(date +%Y) # This year
AUTHOR="Alec Clews"
AUTHOR_EMAIL=alecclews@gmail.com
USR_NAME="alecthegeek" # Default
LOCATION=$PWD # Default
# Must pass at least the project name and a remote repo organisation
while getopts "n:w:" CURROPTFLAG ; do
case $CURROPTFLAG in
w) LOCATION=$OPTARG ;;
n) PACKAGE_NAME=$OPTARG ;;
h) echo $(basename $0) '-n <name> [-w <Location>]' >&2
echo '-W optional location of package dir, defaults to $PWD' >&2
exit 0;;
*) echo Invalid argument -$CURROPTFLAG >&2 ; exit 1;;
esac
done
if [[ -z "$PACKAGE_NAME" ]] ; then
echo 'Error: Must supply minimum of package name -n <name>'
exit 1
fi
mkdir -p $LOCATION/$PACKAGE_NAME
cat << EOF > $LOCATION/$PACKAGE_NAME/${PACKAGE_NAME}.go
// Brief one line overview of package
package $PACKAGE_NAME
import "fmt"
func $(echo $PACKAGE_NAME|gsed -e 's/.*/\u&/')() {
fmt.Printf("Hello, world.\n")
}
EOF
cat << EOF > $LOCATION/$PACKAGE_NAME/${PACKAGE_NAME}_test.go
// Test Suite for $PACKAGE_NAME
package $PACKAGE_NAME
import "testing"
func Test$(echo $PACKAGE_NAME|gsed -e 's/.*/\u&/')(t *testing.T) {
t.Error("No Test Defined")
}
EOF
cat << EOF > $LOCATION/$PACKAGE_NAME/README.md
# NAME
$PACKAGE_NAME - <One line description of package's purpose>
# VERSION
This documentation refers to $PACKAGE_NAME version 0.0.1
# SYNOPSIS
\`\`\`import "$REPO_URL/$USR_NAME/$ProjectName/$PACKAGE_NAME"\`\`\`
# Brief but working code example(s) here showing the most common usage(s)
# This section will be as far as many users bother reading
# so make it as educational and exemplary as possible.
# DESCRIPTION
A full description of the package and its features.
May include numerous subsections (i.e. =head2, =head3, etc.)
# FUNCTIONS
A separate section listing the public components of the package's interface.
These consist of functions that are exported,
# DIAGNOSTICS
A list of every error and warning message that the package can generate
(even the ones that will "never happen"), with a full explanation of each
problem, one or more likely causes, and any suggested remedies.
# CONFIGURATION AND ENVIRONMENT
A full explanation of any configuration system(s) used by the package,
including the names and locations of any configuration files, and the
meaning of any environment variables or properties that can be set. These
descriptions must also include details of any configuration language used.
# DEPENDENCIES
A list of all the other packages that this package relies upon, including any
restrictions on versions.
# INCOMPATIBILITIES
A list of any packages that this package cannot be used in conjunction with.
This may be due to name conflicts in the interface.
# BUGS AND LIMITATIONS
A list of known problems with the package, together with some indication
whether they are likely to be fixed in an upcoming release.
Also a list of restrictions on the features the package does provide:
data types that cannot be handled, performance issues and the circumstances
in which they may arise, practical limitations on the size of data sets,
special cases that are not (yet) handled, etc.
The initial template usually just has:
There are no known bugs in this package.
Please report problems to <Maintainer name(s)> (<contact address>)
Patches are welcome.
# AUTHOR
$AUTHOR <$AUTHOR_EMAIL>
# LICENCE AND COPYRIGHT
Copyright (c) $COPYRIGHTYEAR <$AUTHOR> (<$AUTHOR_EMAIL>). All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
EOF
#! /usr/bin/env bash
# Create a "standard" Go Lang workspace
# Assumes you use direnv (http://direnv.net/)
# and git
# Based on material at
# http://blog.tideland.biz/2013-07-09-go-environment-setup,
# https://stackoverflow.com/questions/9985559/organizing-a-multiple-file-go-project
# http://zduck.com/2014/go-project-structure-and-dependencies/
# http://blog.lazywei.com/2014/02/23/godir-with-direnv-for-golang-projects/
# http://shop.oreilly.com/product/9780596001735.do
COPYRIGHTYEAR=$(date +%Y) # This year
AUTHOR="Alec Clews"
AUTHOR_EMAIL=alecclews@gmail.com
projectLocation=$HOME/AlecProjects # Where all the projects are located
USR_NAME="alecthegeek" # Default
#while getopts "hbgclu:m:p:L:" CURROPTFLAG ; do # For the future
# -c => Google Code, -l => Launchpad -L <license>
# Must pass at least the project name and a remote repo organisation
while getopts "hbgu:m:p:" CURROPTFLAG ; do
case $CURROPTFLAG in
b) REPO_URL=bitbucket.org ;;
g) REPO_URL=github.com ;;
u) USR_NAME=$OPTARG ;;
m) if [[ -z "$PackageName" ]] ; then
PackageName=$OPTARG
else
PackageName=$PackageName" $OPTARG"
fi ;;
p) ProjectName=$OPTARG ;;
h) echo $(basename $0) '-b|-g -u <UserName> -m <PackageName> -p <ProjectName>' >&2
echo '-b => bitbucket -g => github' >&2
exit 0;;
*) echo Invalid argument -$CURROPTFLAG >&2 ; exit 1;;
esac
done
if [[ -z "$ProjectName" || -z "$REPO_URL" ]] ; then
echo 'Please rerun with -g|-b and -p <ProjectName> options at a minumum. -h for help' >&2
exit 1
fi
mypkgbase="$REPO_URL/$USR_NAME/$ProjectName"
if [ -e $projectLocation/$ProjectName ] ; then
echo Project $ProjectName already exists, please fix and rerun. >&2
exit 1
fi
if [[ -n "$PackageName" ]] ; then
for i in $PackageName ; do
if [[ -e "$projectLocation/$ProjectName/own/src/$mypkgbase/src/$PackageName/$i" ]] ; then
echo Package $i already exists, please fix and rerun. >&2
exit 1
fi
done
importList="import (
$(echo $PackageName|tr -s '[:space:]' '\n'|gsed -e 's/^\(.\+\)$/\t"'$REPO_URL'\/'$USR_NAME'\/'$ProjectName'\/\1"/g')
)"
fi
echo Setting up project $ProjectName, with a package\(s\) \"$PackageName\"
mkdir -p $projectLocation/$ProjectName/own/src/$mypkgbase/{main_app,lib} # Only required for main NB Directory should not be called main
mkdir -p $projectLocation/$ProjectName/_3rdparty/{src,pkg,bin}
echo "export GOPATH=\"\$PWD/_3rdparty:\$PWD/own\"" > $projectLocation/$ProjectName/.envrc
echo "export GOBIN=\"\$PWD/own/bin\"" >> $projectLocation/$ProjectName/.envrc
echo "PATH=\"\$GOBIN:\$PATH\"" >> $projectLocation/$ProjectName/.envrc
direnv allow $projectLocation/$ProjectName/
GIT_DIR=$projectLocation/$ProjectName/own/src/$mypkgbase/.git git init
GIT_DIR=$projectLocation/$ProjectName/own/src/$mypkgbase/.git git config user.email $AUTHOR_EMAIL
GIT_DIR=$projectLocation/$ProjectName/own/src/$mypkgbase/.git git config user.name "$AUTHOR"
# Assume we need a main app
# Header based on Damian Conway's Perl Best Practices. Too complicated perhpas?
# But it's easy to delete unwanted detail
cat << EOF > $projectLocation/$ProjectName/own/src/$mypkgbase/README.md
# NAME
$ProjectName - <One line description of application's purpose>
# VERSION
This documentation refers to $ProjectName version 0.0.1
# USAGE
# Brief working invocation example(s) here showing the most common usage(s)
To build this program \`go install main_app/${ProjectName}.go\`
# This section will be as far as many users ever read
# so make it as educational and exemplary as possible.
# REQUIRED ARGUMENTS
A complete list of every argument that must appear on the command line.
when the application is invoked, explaining what each of them does, any
restrictions on where each one may appear (i.e. flags that must appear
before or after filenames), and how the various arguments and options
may interact (e.g. mutual exclusions, required combinations, etc.)
If all of the application's arguments are optional this section
may be omitted entirely.
# OPTIONS
A complete list of every available option with which the application
can be invoked, explaining what each does, and listing any restrictions,
or interactions.
If the application has no options this section may be omitted entirely.
# DESCRIPTION
A full description of the application and its features.
May include numerous subsections (i.e. =head2, =head3, etc.)
# DIAGNOSTICS
A list of every error and warning message that the application can generate
(even the ones that will "never happen"), with a full explanation of each
problem, one or more likely causes, and any suggested remedies. If the
application generates exit status codes (e.g. under Unix) then list the exit
status associated with each error.
# CONFIGURATION AND ENVIRONMENT
A full explanation of any configuration system(s) used by the application,
including the names and locations of any configuration files, and the
meaning of any environment variables or properties that can be set. These
descriptions must also include details of any configuration language used
# DEPENDENCIES
# INCOMPATIBILITIES
# BUGS AND LIMITATIONS
# AUTHOR
$AUTHOR <$AUTHOR_EMAIL>
# LICENCE AND COPYRIGHT
Copyright (c) $COPYRIGHTYEAR <$AUTHOR> (<$AUTHOR_EMAIL>). All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
EOF
cat << EOF > $projectLocation/$ProjectName/own/src/$mypkgbase/main_app/$ProjectName.go
// Brief one line overview of application
package main
import "fmt"
$importList
func main() {
fmt.Printf("Hello, world.\n")
}
EOF
wget http://www.gnu.org/licenses/gpl-3.0.txt -O $projectLocation/$ProjectName/own/src/$mypkgbase/LICENSE.txt
# Setup multiple packages
if [[ -n "$PackageName" ]] ; then
for i in $PackageName ; do
go-package -w $projectLocation/$ProjectName/own/src/$mypkgbase -n $i
done
fi
@alecthegeek
Copy link
Author

So far this works well. Obviously all the predefined values are based on how my directories are laid out.

Based on http://blog.tideland.biz/2013-07-09-go-environment-setup and various other setups

@alecthegeek
Copy link
Author

Now sets up $GOBIN, $PATH, a git repo and a template main

@alecthegeek
Copy link
Author

Layout as suggested at http://stackoverflow.com/a/20188012

Bug Fixes for GOBIN and PATH setting in .envrc

Create template test file

I think this is beginning to look final, unless I see better suggestions on project layout

@alecthegeek
Copy link
Author

Fixed a couple of bugs, discovered this approach was simpler than other approaches, make some other simplifications, added more templates

@alecthegeek
Copy link
Author

Added some command line options

@alecthegeek
Copy link
Author

Added support for location independent direnv settings. You can now freely move project directories

@alecthegeek
Copy link
Author

It's now split into two scripts so that new packages can be created in the current directory by the go-package script.

Also tidied up a bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment