Title: Script not working with changing proj structure
Tags: linux;bash;shell;go;sh
Question: I have the following file ```make.sh``` which is working on the following project:

```myapp
   utils
      run.go
      auth.go
   server.go
   make.sh
```

When I run this script it creates the expected tar and everything is working!

```#!/bin/sh
go get ./...

rm -r /tmp/myapp
rm /tmp/myapp.tar.gz
mkdir /tmp/myapp
go build -o /tmp/myapp/myapp_mac
env GOOS=windows GOARH=amd64 go build -o /tmp/myapp/myapp_win64.exe
env GOOS=linux GOARCH=amd64 go build -o /tmp/myapp/myapp
cp -R ./resources /tmp/myapp/
cd /tmp
tar -czf myapp.tar.gz myapp
```

Now I needed to change the project structure to the following:

```myapp
  make.sh
  src
    utils
       run.go
       auth.go
     server
       server.go
```

Now when I run the ‘make.sh’ it I got an error:

```can't load package: package myapp: no Go files in /Users/i023333/go/src/myapp
```

Any idea how to adapt it?

I try to put the ```make.sh``` inside the ```server folder``` as is and it create the tar but its not valid…any idea what should I change the script here to adopt to the new project structure? 

EDIT1

Before the structure which is generated is like following

```tmp 
  myapp
    myapp
    myapp_mac
    myapp_win64.exe
  myapp.tar.gz
```

After trying the script in the answer of ```Charles Duffy``` I got the following 

```tmp 
  myapp
    myapp
    myapp_mac
    myapp_win64.exe
```

The tar file is missing, any idea ?

Comment: @Flimzy - can you show how please ?

Comment: @Flimzy - Its not related to the code at all it just packaging , the code doesn't change it exactly the same , just the project structure changed

Comment: @Flimzy - this is the reason that I've tried to move the script to the `server ` folder and it working but I suspect it doesnt watch the `utils` folder and the go files there ....

Comment: @CharlesDuffy - Do you mean just remove the word `env`?

Comment: btw, the `env` is completely needless. `GOOS=windows GOARH=amd64 go build -o /tmp/myapp/myapp_win64.exe` would do exactly the same thing (setting GOOS and GOARCH environment variables only for the duration of the individual command).

Comment: And btw, storing files with hardcoded names in `/tmp` is an actively dangerous practice -- someone else who creates a `/tmp/myapp` symlink or directory of symlinks can force your code to overwrite files that you have permission to but they don't.

Comment: Yes, I mean exactly that. Won't fix anything, but it removes one tiny bit of unnecessary inefficiency.

Comment: BTW, where is `resources`? It isn't shown in either your old or new directory listings, and it's relevant to the script.

Comment: Sorry, the problem, as made plain by the error message, is that there is no go source in your project directory `myapp`  now. You can't compile nothing.  Try compiling `myapp/util` instead.

Here is the accepted answer: To change your script, add the line:

```cd src/server || exit
```

...before any action which needs to care about the source. Thus:

```#!/bin/sh
cd src/server || exit        # <--- ADD THIS LINE
go get ./... || exit

rm -rf /tmp/myapp      # aside: using hardcoded names in /tmp is a Really Bad Idea.
rm -f /tmp/myapp.tar.gz
mkdir -p /tmp/myapp
go build -o /tmp/myapp/myapp_mac || exit
GOOS=windows GOARH=amd64 go build -o /tmp/myapp/myapp_win64.exe || exit
GOOS=linux GOARCH=amd64 go build -o /tmp/myapp/myapp || exit
cp -R ./resources /tmp/myapp/ || exit
cd /tmp || exit
tar -czf /tmp/myapp.tar.gz myapp
```



That said, I would suggest instead writing this as:

```#!/bin/bash
basedir=$(cd -- "${BASH_SOURCE%/*}" &amp;&amp; pwd) || exit

rm -rf -- "$basedir/build" || exit
mkdir -p -- "$basedir/"{build,dist} || exit

build() (cd src/server &amp;&amp; GOOS=$1 GOARCH=$2 exec go build -o "$basedir/build/$3")

build darwin  amd64 myapp_mac   || exit
build linux   amd64 myapp       || exit
build windows amd64 myapp_win64 || exit

if [[ -d "$basedir/resources" ]]; then
  cp -PR -- "$basedir/resources/." "$basedir/build/resources" || exit
fi

tar -czf "$basedir/dist/myapp.tar.gz" -C "$basedir/build" .
```

Note:


We're operating relative to the script's location, so it works even if run from a different directory (you can run ```./myapp/build```, and it'll set ```builddir``` to the path to ```./myapp```).
We're not using ```/tmp``` (if we wanted to do so safely, then we'd have something like ```builddir=$(mktemp -t -d myapp-build.XXXXXX)```, and then ```rm -rf "$builddir"``` at the end).
We're using a ```#!/bin/bash``` shebang, which permits extensions such as ```[[ ]]``` and ```$BASH_SOURCE```, instead of ```#!/bin/sh```.
Repeated operations are encapsulated in a function.
We always die on errors we don't expect (which includes failing to copy ```resources``` if ```resources``` doesn't exist), but don't die on errors we do expect (such as filing to copy ```resources``` because it doesn't exist).
The exit status of the script is always the exit status of the last command, so there's no need for explicit error handling there.


Comment for this answer: where should I do it and how should it solve the issue of the diffrent structure ?
Comment for this answer: HI Thanks , I've tried it and I got the following error `:rm: /tmp/myapp: No such file or directory
rm: /tmp/myapp.tar.gz: No such file or directory
can't load package: package myapp/src: no Go files in /Users/i023223/go/src/myapp/src`
Comment for this answer: Now it dont create the `tar` file in the tmp folder, any idea what could be wrong ? what I did is copy the `make.sh` to 'make1' file to the same place `root project` and execute it  exactly your code ...
Comment for this answer: the first to errors 'rm' is not critical I guess but the `no Go files...` is more imported how to overcome it ....?
Comment for this answer: Thanks 1+  , It now much better it create the folder myapp and there I can find 3 files as before but now the problem is that there is no `tar` file , its not generated , any idea why ?
Comment for this answer: Thanks Now its working ! I remove the exit from the cp ..., I can give the bounty in 1 hour and i'll do that :) . just last question . from a best practise point of view how would you write it ?  without hardcoded name etc.Thanks a lot sir!
Comment for this answer: Thanks Charles, it will be great if you add in the answer the "best practise" script , I want to learn from your example. thank you!
Comment for this answer: Thanks, I've test it exaclty as you write and when I put the new `make.sh` in the root folder it create `build` folder under the root folder but it's empty and I got in the terminal following error `tar: Failed to open './dist/myapp.tar.gz'
` any idea how to solve it ?
Comment for this answer: I remove the exit from the `cp` line and now it generate the tar in build folder   on the root project (also change the  `tar -czf "$basedir/build/appcontroller.tar.gz"`  to `build` instead `dist`) and the tar was created in size of 200kb instead 10 mb , i've no other idea , maybe you ?
Comment for this answer: Thanks a lot it's working :) last question , to make it work i've created the "dist" folder , if I dont do it it will not work. why?
Comment for this answer: The difference in the structure is that there's now a `src` directory, and that your code is moved into it. If you do this *before* running `go build`, then the build is now done in the directory with your source.
Comment for this answer: Ahh -- I misread the structure. That's... frankly, a bad choice of structures for Go; you should have one subdirectory, and thus one `main`, per utility.
Comment for this answer: That said, since the one thing you're compiling is the server, the first line needs to be `cd src/server || exit`, since that's the one piece you're actually compiling.
Comment for this answer: If I had to guess, I'd guess that the `cp` of `resources` is failing so it aborts at that step. But I can't fix it since **you haven't answered my question** about where the `resources` directory is in the new structure. (If there is none, remove that whole line). Also, if that *is* the problem, there would be an error; including that error would make it much easier to diagnose.
Comment for this answer: so, the usual thing is to have a `build/` directory under the top of your source directory, at the same level as `src/`; to put build products there, and have a `dist/` directory where you put distributable archives (like the tarball) that are produced by a build. If for some reason you don't want to do that, the best-practice way to create temporary directories is with `mktemp`, to get a new and unique one each time (and clean it up when you're done).
Comment for this answer: @RaynD, ...added.
Comment for this answer: `dist` was intentional. By convention, `build` is where immediate build products go, `dist` is where distributables go. You should be able to `rm -rf build` without deleting your tarballs. (Also, if you modify your script to get your version number, as by retriving it from `git`, then you can create `dist/myapp-${version}.tar.gz` and keep a library of built binaries from different versions).
Comment for this answer: As for the immediate issue, that's on account of `BASH_SOURCE` being relative rather than absolute; easily fixed (albeit inefficiently, on account of being on MacOS and not having GNU tools).
Comment for this answer: Also, the `|| exit` on the cp line is likewise intentional. You should fix whatever's causing `cp` to fail, not paper over the issue by ignoring the failure.
Comment for this answer: Oops -- that's a bug; added `dist` to the `mkdir`.

Here is another answer: Your script executes ```go build``` without specifying the packages it needs to compile. By default the ```go``` tool will look for Go source files in the current directory. There are no, since you have moved them elsewhere. 

Try adding the list of packages at the end of the ```go build``` command. And note, that package names should include the full path relative to the ```GOPATH``` directory.

See the documentation here.

Comment for this answer: Thanks but i've tried to move the `make.sh` to the `server` folder but it didint works ...not sure how it refer to the 'utils' folder in this case ..., can you please provide example of what your suggestion ?
Comment for this answer: Thanks a lot,  I did it already (otherwise I get complication error ) and it doesnt work , same issue.....any other idea?
Comment for this answer: Btw I not expert in bash scripts , I understand most of it ( didnt created by me...) but not sure about 3 things: 1.  `go get ./...` what does the ` ./...` path doing 2. `go build -o` what this exactly do 3. the env `env GOOS` why its needed at all ? Thanks a lot!!!
Comment for this answer: @H4xorPL - Thanks!
Comment for this answer: In `server.go` try to change to `import "myapp/src/utils"`

Here is another answer: this should do it I believe 

```#!/bin/sh
cd src/server
go get ./...

rm -rf /tmp/myapp
rm -f /tmp/myapp.tar.gz

mkdir -p /tmp/myapp          
go build -o /tmp/myapp/myapp_mac
env GOOS=windows GOARH=amd64 go build -o /tmp/myapp/myapp_win64.exe
env GOOS=linux GOARCH=amd64 go build -o /tmp/myapp/myapp

cd ../..
cp -R ./resources /tmp/myapp/

cd /tmp
tar -czf myapp.tar.gz myapp/
```


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 3, 'CommentCount': 9, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2017:00:11/23/17', 'FavoriteCount': 2.0, 'PostTypeId': 1, 'Tags': '<linux><bash><shell><go><sh>', 'Title': 'Script not working with changing proj structure', 'ViewCount': 172, 'id': 47458133, 'user_AboutMe': None, 'user_AccountId': None, 'user_DisplayName': None, 'user_Reputation': None, 'user_Views': None, 'user_id': None}}