Compare commits

...

21 Commits

Author SHA1 Message Date
Steve
236499f9e5 Merge pull request #192 from revel/hotfix-1
Added local import map to getControllerFunc lookup
2020-07-14 22:10:25 -07:00
notzippy@gmail.com
42e0e3bf2b Added local import map to getControllerFunc lookup 2020-07-14 21:46:37 -07:00
Steve
b0484c9279 Merge pull request #188 from revel/hotfix-1
Fixed issues with test cases and launching app using the run mode
2020-07-14 13:16:12 -07:00
notzippy@gmail.com
c7f4307a5d Changed the local code walker to include all go files in the base path, and not just the app path 2020-07-14 12:45:10 -07:00
notzippy@gmail.com
ebc9c73ba0 Modified run command so launching command would be properly treated 2020-07-13 22:35:22 -07:00
Steve
2e2f22ad7d remove go 1.12 test 2020-07-13 09:40:56 -07:00
Steve
357c382d96 Version compatible Check
Increase version compatibility to 1.0 - 1.9
2020-07-13 09:39:57 -07:00
notzippy@gmail.com
6ecc0a7c0a release v1.0.0 2020-07-11 22:57:36 -07:00
Steve
d8117a33d3 Merge pull request #186 from notzippy/go-mod
Removed version update from Revel
2020-06-06 07:50:58 -07:00
notzippy@gmail.com
6371373eb5 Removed version update
Version control is maintained through go.mod file
Modified harness to only kill the application if not responded after 60 seconds in windows
2020-06-06 07:49:10 -07:00
Steve
28ac65f1c1 Merge pull request #185 from notzippy/go-mod
Go mod updates
2020-05-19 02:42:57 -07:00
notzippy@gmail.com
5070fb8be0 Fixed issue with new and run flag
Updated tests to run final test in non gopath, with new name
2020-05-19 02:23:18 -07:00
notzippy@gmail.com
904cfa2995 Added some informational messages while download 2020-05-18 12:43:00 -07:00
notzippy@gmail.com
223bd3b7c0 Added manual scan on packages in app folder
This allows for source code generation. Packages in <application>/app folder are scanned manually as opposed to the `packages.Load` scan which will fast fail on compile error, and leave you with go files with no syntax.
2020-05-18 11:47:01 -07:00
notzippy@gmail.com
4987ee8319 Added verbose logging to building / testing a no-vendor app
Removed section which raises an error when examining packages, we dont need to check for errors on foreign packages since we are importing only a slice of the data
2020-05-17 05:58:28 -07:00
notzippy@gmail.com
4bab4409b9 Updated Revel command
Added a check to see if harness had already started, saves a recompile on load
Added check to source info for local import renames
Removed the go/build check for path and just check existence of the path
Formatting updates
2020-05-13 22:26:05 -07:00
notzippy@gmail.com
741f49236a Updated scanner
Removed scanning all the import statements, this is not needed
Added recursive scan for revel import path to pick up testunits
2020-05-08 15:41:20 -07:00
Steve
60b88a42c9 Merge pull request #180 from notzippy/go-mod
Initial commit to go mod
2020-05-03 21:47:09 -07:00
notzippy@gmail.com
49eef29bb5 Build and Historic build updates
Modified GOPATH to not modify build with go.mod
Updated go.mod to version 1.12
Updated harness to setup listener before killing process
Updated notvendored flag to --no-vendor
Updated command_config to ensure no-vendor can be build
Added additional checks in source path lookup
2020-05-03 13:39:48 -07:00
notzippy@gmail.com
9d3a554bec Updates
Updated NotVendored flag
Updated travis matrix
Updated build log
2020-04-29 22:01:28 -07:00
notzippy@gmail.com
36bd6b944a Corrected flags 2020-04-29 21:48:11 -07:00
23 changed files with 466 additions and 349 deletions

View File

@@ -1,15 +1,14 @@
language: go language: go
go: go:
- "1.12.x" - "1.13.x"
# - "1.13.x" - "1.14.x"
# - "1.14.x" - "tip"
# - "tip"
os: os:
# - osx - osx
- linux - linux
# - windows - windows
sudo: false sudo: false
@@ -19,22 +18,23 @@ branches:
- develop - develop
env: env:
# Setting environments variables
- GO111MODULE=on - GO111MODULE=on
install: install:
# Setting environments variables
- export PATH=$PATH:$HOME/gopath/bin - export PATH=$PATH:$HOME/gopath/bin
- export REVEL_BRANCH="develop" - export REVEL_BRANCH="develop"
- 'if [[ "$TRAVIS_BRANCH" == "master" ]]; then export REVEL_BRANCH="master"; fi' - 'if [[ "$TRAVIS_BRANCH" == "master" ]]; then export REVEL_BRANCH="master"; fi'
- 'echo "Travis branch: $TRAVIS_BRANCH, Revel dependency branch: $REVEL_BRANCH"' - 'echo "Travis branch: $TRAVIS_BRANCH, Revel dependency branch: $REVEL_BRANCH"'
#- git clone -b $REVEL_BRANCH git://github.com/revel/revel ../revel/
#- git clone -b $REVEL_BRANCH git://github.com/revel/modules ../modules/
# Since travis already checks out go build the commandline tool (revel) # Since travis already checks out go build the commandline tool (revel)
- go get -t -v github.com/revel/cmd/revel - mkdir $HOME/GOPATH_PROTECTED
- echo $GOPATH - export GOPATH=$HOME/GOPATH_PROTECTED
- echo $PATH - go build -o $HOME/gopath/bin/revel github.com/revel/cmd/revel
- pwd - pwd
- env
script: script:
- go test -v github.com/revel/cmd/revel/...
# Ensure the new-app flow works (plus the other commands). # Ensure the new-app flow works (plus the other commands).
#- revel version #- revel version
#- revel new my/testapp #- revel new my/testapp
@@ -46,23 +46,25 @@ script:
#- revel package my/testapp prod #- revel package my/testapp prod
# Ensure the new-app flow works (plus the other commands). # Ensure the new-app flow works (plus the other commands).
- revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v - revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 --package revelframework.com -v
- revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v - revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v
- revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v - revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v
- revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -t build/testapp2 - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v -t build/testapp2
- revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -t build/testapp2 -m prod - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v -t build/testapp2 -m prod
- revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v
- revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -m prod - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v -m prod
- revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 -V - export INITIALWD=$PWD
- revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 # Check build works with no-vendor flag
- revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 - cd $GOPATH
- revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -t build/testapp3 - export GO111MODULE=auto
- revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -t build/testapp3 -m prod - revel new -a my/testapp2 --no-vendor -v
- revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 - revel test -a my/testapp2 -v
- revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -m prod
- go test -v github.com/revel/cmd/revel/... # Check non verbose build, outside of GO path
- cd $INITIALWD
- revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp3 --package revelframework.com
- revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp3
matrix: matrix:
allow_failures: allow_failures:

7
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/revel/cmd module github.com/revel/cmd
go 1.13 go 1.12
require ( require (
github.com/BurntSushi/toml v0.3.1 // indirect github.com/BurntSushi/toml v0.3.1 // indirect
@@ -8,7 +8,7 @@ require (
github.com/fsnotify/fsnotify v1.4.7 github.com/fsnotify/fsnotify v1.4.7
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 // indirect github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 // indirect
github.com/jessevdk/go-flags v1.4.0 github.com/jessevdk/go-flags v1.4.0
github.com/mattn/go-colorable v0.1.4 github.com/mattn/go-colorable v0.1.6
github.com/myesui/uuid v1.0.0 // indirect github.com/myesui/uuid v1.0.0 // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/revel/config v0.21.0 github.com/revel/config v0.21.0
@@ -19,7 +19,8 @@ require (
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.4.0
github.com/twinj/uuid v1.0.0 // indirect github.com/twinj/uuid v1.0.0 // indirect
github.com/xeonx/timeago v1.0.0-rc4 // indirect github.com/xeonx/timeago v1.0.0-rc4 // indirect
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 // indirect
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
golang.org/x/tools v0.0.0-20200219054238-753a1d49df85 golang.org/x/tools v0.0.0-20200219054238-753a1d49df85
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 gopkg.in/fsnotify/fsnotify.v1 v1.4.7
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22

60
go.sum Normal file
View File

@@ -0,0 +1,60 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/agtorre/gocolorize v1.0.0 h1:TvGQd+fAqWQlDjQxSKe//Y6RaxK+RHpEU9X/zPmHW50=
github.com/agtorre/gocolorize v1.0.0/go.mod h1:cH6imfTkHVBRJhSOeSeEZhB4zqEYSq0sXuIyehgZMIY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 h1:KUDFlmBg2buRWNzIcwLlKvfcnujcHQRQ1As1LoaCLAM=
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/myesui/uuid v1.0.0/go.mod h1:2CDfNgU0LR8mIdO8vdWd8i9gWWxLlcoIGGpSNgafq84=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/revel/config v0.21.0 h1:Bw4iXLGAuD/Di2HEhPSOyDywrTlFIXUMbds91lXTtTU=
github.com/revel/config v0.21.0/go.mod h1:GT4a9px5kDGRqLizcw/md0QFErrhen76toz4qS3oIoI=
github.com/revel/log15 v2.11.20+incompatible h1:JkA4tbwIo/UGEMumY50zndKq816RQW3LQ0wIpRc+32U=
github.com/revel/log15 v2.11.20+incompatible/go.mod h1:l0WmLRs+IM1hBl4noJiBc2tZQiOgZyXzS1mdmFt+5Gc=
github.com/revel/modules v0.21.0/go.mod h1:UBlNmO9VGZo4j6Ptn2uC/26Iclefuic+V40jYRPBxQE=
github.com/revel/pathtree v0.0.0-20140121041023-41257a1839e9/go.mod h1:TmlwoRLDvgRjoTe6rbsxIaka/CulzYrgfef7iNJcEWY=
github.com/revel/revel v0.21.0/go.mod h1:VZWJnHjpDEtuGUuZJ2NO42XryitrtwsdVaJxfDeo5yc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY=
github.com/xeonx/timeago v1.0.0-rc4/go.mod h1:qDLrYEFynLO7y5Ho7w3GwgtYgpy5UfhcXIIQvMKVDkA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3rzIsrrXfAQBWnYfn+w=
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20200219054238-753a1d49df85 h1:XNHaQ2CZDl/SjEZlUXGh7+OQvfLuFgmk3oNWkCFfERE=
golang.org/x/tools v0.0.0-20200219054238-753a1d49df85/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/stack.v0 v0.0.0-20141108040640-9b43fcefddd0 h1:lMH45EKqD8Nf6LwoF+43YOKjOAEEHQRVgDyG8RCV4MU=
gopkg.in/stack.v0 v0.0.0-20141108040640-9b43fcefddd0/go.mod h1:kl/bNzW/jgTgUOCGDj3XPn9/Hbfhw6pjfBRUnaTioFQ=
gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -12,6 +12,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"time" "time"
"sync"
"github.com/revel/cmd/model" "github.com/revel/cmd/model"
"github.com/revel/cmd/utils" "github.com/revel/cmd/utils"
@@ -64,8 +65,8 @@ func NewAppCmd(binPath string, port int, runMode string, paths *model.RevelConta
func (cmd AppCmd) Start(c *model.CommandConfig) error { func (cmd AppCmd) Start(c *model.CommandConfig) error {
listeningWriter := &startupListeningWriter{os.Stdout, make(chan bool), c, &bytes.Buffer{}} listeningWriter := &startupListeningWriter{os.Stdout, make(chan bool), c, &bytes.Buffer{}}
cmd.Stdout = listeningWriter cmd.Stdout = listeningWriter
utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args, "dir", cmd.Dir, "env", cmd.Env)
utils.CmdInit(cmd.Cmd, !c.Vendored, c.AppPath) utils.CmdInit(cmd.Cmd, !c.Vendored, c.AppPath)
utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args, "dir", cmd.Dir, "env", cmd.Env)
if err := cmd.Cmd.Start(); err != nil { if err := cmd.Cmd.Start(); err != nil {
utils.Logger.Fatal("Error running:", "error", err) utils.Logger.Fatal("Error running:", "error", err)
} }
@@ -92,7 +93,8 @@ func (cmd AppCmd) Start(c *model.CommandConfig) error {
} }
// Run the app server inline. Never returns. // Run the app server inline. Never returns.
func (cmd AppCmd) Run() { func (cmd AppCmd) Run(c *model.CommandConfig) {
utils.CmdInit(cmd.Cmd, !c.Vendored, c.AppPath)
utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args) utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args)
if err := cmd.Cmd.Run(); err != nil { if err := cmd.Cmd.Run(); err != nil {
utils.Logger.Fatal("Error running:", "error", err) utils.Logger.Fatal("Error running:", "error", err)
@@ -105,33 +107,18 @@ func (cmd AppCmd) Kill() {
if cmd.Cmd != nil && (cmd.ProcessState == nil || !cmd.ProcessState.Exited()) { if cmd.Cmd != nil && (cmd.ProcessState == nil || !cmd.ProcessState.Exited()) {
// Windows appears to send the kill to all threads, shutting down the // Windows appears to send the kill to all threads, shutting down the
// server before this can, this check will ensure the process is still running // server before this can, this check will ensure the process is still running
if _, err := os.FindProcess(int(cmd.Process.Pid));err!=nil { if _, err := os.FindProcess(int(cmd.Process.Pid)); err != nil {
// Server has already exited // Server has already exited
utils.Logger.Info("Killing revel server pid", "pid", cmd.Process.Pid) utils.Logger.Info("Server not running revel server pid", "pid", cmd.Process.Pid)
return return
} }
// Send an interrupt signal to allow for a graceful shutdown // Wait for the shutdown channel
utils.Logger.Info("Killing revel server pid", "pid", cmd.Process.Pid) waitMutex := &sync.WaitGroup{}
var err error waitMutex.Add(1)
if runtime.GOOS == "windows" {
// os.Interrupt is not available on windows
err = cmd.Process.Signal(os.Kill)
} else {
err = cmd.Process.Signal(os.Interrupt)
}
if err != nil {
utils.Logger.Error(
"Revel app failed to kill process.",
"processid", cmd.Process.Pid,"error",err,
"killerror", cmd.Process.Kill())
return
}
// Wait for the shutdown
ch := make(chan bool, 1) ch := make(chan bool, 1)
go func() { go func() {
waitMutex.Done()
s, err := cmd.Process.Wait() s, err := cmd.Process.Wait()
defer func() { defer func() {
ch <- true ch <- true
@@ -143,6 +130,25 @@ func (cmd AppCmd) Kill() {
utils.Logger.Info("Revel App exited", "state", s.String()) utils.Logger.Info("Revel App exited", "state", s.String())
} }
}() }()
// Wait for the channel to begin waiting
waitMutex.Wait()
// Send an interrupt signal to allow for a graceful shutdown
utils.Logger.Info("Killing revel server pid", "pid", cmd.Process.Pid)
var err error
if runtime.GOOS != "windows" {
// os.Interrupt is not available on windows
err = cmd.Process.Signal(os.Interrupt)
}
if err != nil {
utils.Logger.Info(
"Revel app already exited.",
"processid", cmd.Process.Pid, "error", err,
"killerror", cmd.Process.Kill())
return
}
// Use a timer to ensure that the process exits // Use a timer to ensure that the process exits
utils.Logger.Info("Waiting to exit") utils.Logger.Info("Waiting to exit")

View File

@@ -102,28 +102,8 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err
utils.Logger.Fatal("Go executable not found in PATH.") utils.Logger.Fatal("Go executable not found in PATH.")
} }
// Detect if deps tool should be used (is there a vendor folder ?) // Binary path is a combination of target/app directory, app's import path and its name.
useVendor := utils.DirExists(filepath.Join(paths.BasePath, "vendor")) binName := filepath.Join("target", "app", paths.ImportPath, filepath.Base(paths.BasePath))
basePath := paths.BasePath
for !useVendor {
basePath = filepath.Dir(basePath)
found := false
// Check to see if we are still in the GOPATH
for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
if strings.HasPrefix(basePath, gopath) {
found = true
break
}
}
if !found {
break
} else {
useVendor = utils.DirExists(filepath.Join(basePath, "vendor"))
}
}
// Binary path is a combination of BasePath/target/app directory, app's import path and its name.
binName := filepath.Join(paths.BasePath, "target", "app", paths.ImportPath, filepath.Base(paths.BasePath))
// Change binary path for Windows build // Change binary path for Windows build
goos := runtime.GOOS goos := runtime.GOOS
@@ -149,7 +129,7 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err
goModCmd := exec.Command(goPath, append([]string{"mod"}, strings.Split(gomod, " ")...)...) goModCmd := exec.Command(goPath, append([]string{"mod"}, strings.Split(gomod, " ")...)...)
utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) utils.CmdInit(goModCmd, !c.Vendored, c.AppPath)
output, err := goModCmd.CombinedOutput() output, err := goModCmd.CombinedOutput()
utils.Logger.Infof("Gomod applied ", "output", string(output)) utils.Logger.Info("Gomod applied ", "output", string(output))
// If the build succeeded, we're done. // If the build succeeded, we're done.
if err != nil { if err != nil {
@@ -165,7 +145,7 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err
} }
buildTime := time.Now().UTC().Format(time.RFC3339) buildTime := time.Now().UTC().Format(time.RFC3339)
versionLinkerFlags := fmt.Sprintf("-X %s/app.AppVersion=%s -X %s/app.BuildTime=%s", versionLinkerFlags := fmt.Sprintf("-X '%s/app.AppVersion=%s' -X '%s/app.BuildTime=%s'",
paths.ImportPath, appVersion, paths.ImportPath, buildTime) paths.ImportPath, appVersion, paths.ImportPath, buildTime)
// Append any build flags specified, they will override existing flags // Append any build flags specified, they will override existing flags
@@ -478,7 +458,7 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.SourceEr
return compileError return compileError
} }
// RevelMainTemplate template for app/tmp/main.go // RevelMainTemplate template for app/tmp/run/run.go
const RevelRunTemplate = `// GENERATED CODE - DO NOT EDIT const RevelRunTemplate = `// GENERATED CODE - DO NOT EDIT
// This file is the run file for Revel. // This file is the run file for Revel.
// It registers all the controllers and provides details for the Revel server engine to // It registers all the controllers and provides details for the Revel server engine to

View File

@@ -16,6 +16,7 @@ package harness
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"time"
"go/build" "go/build"
"io" "io"
"net" "net"
@@ -56,6 +57,8 @@ type Harness struct {
paths *model.RevelContainer // The Revel container paths *model.RevelContainer // The Revel container
config *model.CommandConfig // The configuration config *model.CommandConfig // The configuration
runMode string // The runmode the harness is running in runMode string // The runmode the harness is running in
isError bool // True if harness is in error state
ranOnce bool // True app compiled once
} }
func (h *Harness) renderError(iw http.ResponseWriter, ir *http.Request, err error) { func (h *Harness) renderError(iw http.ResponseWriter, ir *http.Request, err error) {
@@ -202,6 +205,21 @@ func NewHarness(c *model.CommandConfig, paths *model.RevelContainer, runMode str
// Refresh method rebuilds the Revel application and run it on the given port. // Refresh method rebuilds the Revel application and run it on the given port.
// called by the watcher // called by the watcher
func (h *Harness) Refresh() (err *utils.SourceError) { func (h *Harness) Refresh() (err *utils.SourceError) {
t := time.Now();
fmt.Println("Changed detected, recompiling")
err = h.refresh()
if err!=nil && !h.ranOnce && h.useProxy {
addr := fmt.Sprintf("%s:%d", h.paths.HTTPAddr, h.paths.HTTPPort)
fmt.Printf("\nError compiling code, to view error details see proxy running on http://%s\n\n",addr)
}
h.ranOnce = true
fmt.Printf("\nTime to recompile %s\n",time.Now().Sub(t).String())
return
}
func (h *Harness) refresh() (err *utils.SourceError) {
// Allow only one thread to rebuild the process // Allow only one thread to rebuild the process
// If multiple requests to rebuild are queued only the last one is executed on // If multiple requests to rebuild are queued only the last one is executed on
// So before a build is started we wait for a second to determine if // So before a build is started we wait for a second to determine if
@@ -281,7 +299,8 @@ func (h *Harness) Run() {
paths = append(paths, h.paths.CodePaths...) paths = append(paths, h.paths.CodePaths...)
h.watcher = watcher.NewWatcher(h.paths, false) h.watcher = watcher.NewWatcher(h.paths, false)
h.watcher.Listen(h, paths...) h.watcher.Listen(h, paths...)
h.watcher.Notify() go h.Refresh()
// h.watcher.Notify()
if h.useProxy { if h.useProxy {
go func() { go func() {
@@ -292,6 +311,7 @@ func (h *Harness) Run() {
addr := fmt.Sprintf("%s:%d", h.paths.HTTPAddr, h.paths.HTTPPort) addr := fmt.Sprintf("%s:%d", h.paths.HTTPAddr, h.paths.HTTPPort)
utils.Logger.Infof("Proxy server is listening on %s", addr) utils.Logger.Infof("Proxy server is listening on %s", addr)
var err error var err error
if h.paths.HTTPSsl { if h.paths.HTTPSsl {
err = http.ListenAndServeTLS( err = http.ListenAndServeTLS(
@@ -308,10 +328,12 @@ func (h *Harness) Run() {
}() }()
} }
// Kill the app on signal.
// Make a new channel to listen for the interrupt event
ch := make(chan os.Signal) ch := make(chan os.Signal)
signal.Notify(ch, os.Interrupt, os.Kill) signal.Notify(ch, os.Interrupt, os.Kill)
<-ch <-ch
// Kill the app and exit
if h.app != nil { if h.app != nil {
h.app.Kill() h.app.Kill()
} }

View File

@@ -6,7 +6,7 @@ type (
ImportCommand ImportCommand
SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"` SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"`
Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"` Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"`
NotVendored bool `short:"V" long:"vendor" description:"True if project should not be configured with a go.mod"` NotVendored bool `long:"no-vendor" description:"True if project should not be configured with a go.mod, this requires you to have the project on the GOPATH, this is only compatible with go versions v1.12 or older"`
Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` Run bool `short:"r" long:"run" description:"True if you want to run the application right away"`
Callback func() error Callback func() error
} }

View File

@@ -2,7 +2,5 @@ package command
type ( type (
Version struct { Version struct {
ImportCommand ImportCommand
Update bool `short:"u" long:"update" description:"Update the framework and modules" required:"false"`
UpdateVersion string `long:"update-version" description:"Specify the version the revel and app will be switched to" required:"false"`
} }
) )

View File

@@ -41,14 +41,14 @@ type (
ImportPath string // The import path (relative to a GOPATH) ImportPath string // The import path (relative to a GOPATH)
GoPath string // The GoPath GoPath string // The GoPath
GoCmd string // The full path to the go executable GoCmd string // The full path to the go executable
SrcRoot string // The source root //SrcRoot string // The source root
AppPath string // The application path (absolute) AppPath string // The application path (absolute)
AppName string // The application name AppName string // The application name
HistoricBuildMode bool `long:"historic-build-mode" description:"If set the code is scanned using the original parsers, not the go.1.11+"` // True if debug is active HistoricBuildMode bool `long:"historic-build-mode" description:"If set the code is scanned using the original parsers, not the go.1.11+"` // True if debug is active
Vendored bool // True if the application is vendored Vendored bool // True if the application is vendored
PackageResolver func(pkgName string) error // a package resolver for the config PackageResolver func(pkgName string) error // a package resolver for the config
BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"` BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"`
GoModFlags []string `long:"gomod-flags" description:"These flags will execut go mod commands for each flag, this happens during the build process"` GoModFlags []string `long:"gomod-flags" description:"These flags will execute go mod commands for each flag, this happens during the build process"`
New command.New `command:"new"` New command.New `command:"new"`
Build command.Build `command:"build"` Build command.Build `command:"build"`
Run command.Run `command:"run"` Run command.Run `command:"run"`
@@ -143,7 +143,7 @@ func (c *CommandConfig) UpdateImportPath() error {
} }
func (c *CommandConfig) initAppFolder() (err error) { func (c *CommandConfig) initAppFolder() (err error) {
utils.Logger.Info("initAppFolder", "vendored", c.Vendored) utils.Logger.Info("initAppFolder", "vendored", c.Vendored, "build-gopath", build.Default.GOPATH, "gopath-env", os.Getenv("GOPATH"))
// check for go executable // check for go executable
c.GoCmd, err = exec.LookPath("go") c.GoCmd, err = exec.LookPath("go")
@@ -174,8 +174,10 @@ func (c *CommandConfig) initAppFolder() (err error) {
// Use app folder to read the go.mod if it exists and extract the package information // Use app folder to read the go.mod if it exists and extract the package information
goModFile := filepath.Join(appFolder, "go.mod") goModFile := filepath.Join(appFolder, "go.mod")
utils.Logger.Info("Checking gomod, extracting from file", "path", goModFile,"exists", utils.Exists(goModFile))
if utils.Exists(goModFile) { if utils.Exists(goModFile) {
c.Vendored = true c.Vendored = true
utils.Logger.Info("Found go mod, extracting from file", "path", goModFile)
file, err := ioutil.ReadFile(goModFile) file, err := ioutil.ReadFile(goModFile)
if err != nil { if err != nil {
return err return err
@@ -184,30 +186,17 @@ func (c *CommandConfig) initAppFolder() (err error) {
if strings.Index(line, "module ") == 0 { if strings.Index(line, "module ") == 0 {
c.ImportPath = strings.TrimSpace(strings.Split(line, "module")[1]) c.ImportPath = strings.TrimSpace(strings.Split(line, "module")[1])
c.AppPath = appFolder c.AppPath = appFolder
c.SrcRoot = appFolder //c.SrcRoot = appFolder
utils.Logger.Info("Set application path and package based on go mod", "path", c.AppPath, "sourceroot", c.SrcRoot) utils.Logger.Info("Set application path and package based on go mod", "path", c.AppPath)
return nil return nil
} }
} }
} // c.SrcRoot = appFolder
c.AppPath = appFolder
utils.Logger.Debug("Trying to set path based on gopath") } else if c.Index != NEW || (c.Index == NEW && c.New.NotVendored) {
// lookup go path workingDir, _ := os.Getwd()
c.GoPath = build.Default.GOPATH goPathList := filepath.SplitList(c.GoPath)
if c.GoPath == "" { bestpath := ""
utils.Logger.Fatal("Abort: GOPATH environment variable is not set. " +
"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
}
// revel/revel#1004 choose go path relative to current working directory
// What we want to do is to add the import to the end of the
// gopath, and discover which import exists - If none exist this is an error except in the case
// where we are dealing with new which is a special case where we will attempt to target the working directory first
workingDir, _ := os.Getwd()
goPathList := filepath.SplitList(c.GoPath)
bestpath := ""
if !c.Vendored {
for _, path := range goPathList { for _, path := range goPathList {
if c.Index == NEW { if c.Index == NEW {
// If the GOPATH is part of the working dir this is the most likely target // If the GOPATH is part of the working dir this is the most likely target
@@ -216,77 +205,59 @@ func (c *CommandConfig) initAppFolder() (err error) {
} }
} else { } else {
if utils.Exists(filepath.Join(path, "src", c.ImportPath)) { if utils.Exists(filepath.Join(path, "src", c.ImportPath)) {
c.SrcRoot = path bestpath = path
break break
} }
} }
} }
if len(c.SrcRoot) == 0 && len(bestpath) > 0 {
c.SrcRoot = bestpath utils.Logger.Info("Source root", "cwd", workingDir, "gopath", c.GoPath, "c.ImportPath", c.ImportPath, "bestpath", bestpath)
if len(bestpath) > 0 {
c.AppPath = filepath.Join(bestpath, "src", c.ImportPath)
} }
// Recalculate the appFolder because we are using a GOPATH
} else { } else {
c.SrcRoot = appFolder // This is new and not vendored, so the app path is the appFolder
c.AppPath = appFolder
} }
utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath", bestpath) utils.Logger.Info("Set application path", "path", c.AppPath, "vendored",c.Vendored, "importpath",c.ImportPath)
// If source root is empty and this isn't a version then skip it
if len(c.SrcRoot) == 0 {
if c.Index == NEW {
c.SrcRoot = c.New.ImportPath
} else {
if c.Index != VERSION {
utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.")
}
return nil
}
}
// set go src path
if c.Vendored {
c.AppPath = c.SrcRoot
} else {
c.SrcRoot = filepath.Join(c.SrcRoot, "src")
c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath))
}
utils.Logger.Info("Set application path", "path", c.AppPath)
return nil return nil
} }
// Used to initialize the package resolver // Used to initialize the package resolver
func (c *CommandConfig) InitPackageResolver() { func (c *CommandConfig) InitPackageResolver() {
c.initGoPaths()
utils.Logger.Info("InitPackageResolver", "useVendor", c.Vendored, "path", c.AppPath) utils.Logger.Info("InitPackageResolver", "useVendor", c.Vendored, "path", c.AppPath)
// This should get called when needed // This should get called when needed
c.PackageResolver = func(pkgName string) error { c.PackageResolver = func(pkgName string) error {
//useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor"))
//var getCmd *exec.Cmd
utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", c.Vendored) utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", c.Vendored)
var getCmd *exec.Cmd
print("Downloading related packages ...")
if c.Vendored { if c.Vendored {
goModCmd := exec.Command("go", "mod", "tidy") getCmd = exec.Command(c.GoCmd, "mod", "tidy")
utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) } else {
goModCmd.Run() utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName)
return nil getCmd = exec.Command(c.GoCmd, "get", "-u", pkgName)
} }
utils.CmdInit(getCmd, !c.Vendored, c.AppPath)
utils.Logger.Info("Go get command ", "exec", getCmd.Path, "dir", getCmd.Dir, "args", getCmd.Args, "env", getCmd.Env, "package", pkgName)
output, err := getCmd.CombinedOutput()
if err != nil {
utils.Logger.Error("Failed to import package", "error", err, "gopath", build.Default.GOPATH, "GO-ROOT", build.Default.GOROOT, "output", string(output))
}
println(" completed.")
return nil return nil
} }
} }
// lookup and set Go related variables // lookup and set Go related variables
func (c *CommandConfig) InitGoPathsOld() { func (c *CommandConfig) initGoPaths() {
utils.Logger.Info("InitGoPaths") utils.Logger.Info("InitGoPaths", "vendored", c.Vendored)
// lookup go path
c.GoPath = build.Default.GOPATH
if c.GoPath == "" {
utils.Logger.Fatal("Abort: GOPATH environment variable is not set. " +
"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
}
// check for go executable // check for go executable
var err error var err error
c.GoCmd, err = exec.LookPath("go") c.GoCmd, err = exec.LookPath("go")
@@ -294,50 +265,46 @@ func (c *CommandConfig) InitGoPathsOld() {
utils.Logger.Fatal("Go executable not found in PATH.") utils.Logger.Fatal("Go executable not found in PATH.")
} }
if c.Vendored {
return
}
// lookup go path
c.GoPath = build.Default.GOPATH
if c.GoPath == "" {
utils.Logger.Fatal("Abort: GOPATH environment variable is not set. " +
"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
}
return
//todo determine if the rest needs to happen
// revel/revel#1004 choose go path relative to current working directory // revel/revel#1004 choose go path relative to current working directory
// What we want to do is to add the import to the end of the // What we want to do is to add the import to the end of the
// gopath, and discover which import exists - If none exist this is an error except in the case // gopath, and discover which import exists - If none exist this is an error except in the case
// where we are dealing with new which is a special case where we will attempt to target the working directory first // where we are dealing with new which is a special case where we will attempt to target the working directory first
workingDir, _ := os.Getwd() /*
goPathList := filepath.SplitList(c.GoPath) // If source root is empty and this isn't a version then skip it
bestpath := "" if len(c.SrcRoot) == 0 {
for _, path := range goPathList { if c.Index == NEW {
if c.Index == NEW { c.SrcRoot = c.New.ImportPath
// If the GOPATH is part of the working dir this is the most likely target } else {
if strings.HasPrefix(workingDir, path) { if c.Index != VERSION {
bestpath = path utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.")
} }
} else { return
if utils.Exists(filepath.Join(path, "src", c.ImportPath)) {
c.SrcRoot = path
break
} }
} }
}
utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath", bestpath) // set go src path
if len(c.SrcRoot) == 0 && len(bestpath) > 0 { c.SrcRoot = filepath.Join(c.SrcRoot, "src")
c.SrcRoot = bestpath
}
// If source root is empty and this isn't a version then skip it c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath))
if len(c.SrcRoot) == 0 { utils.Logger.Info("Set application path", "path", c.AppPath)
if c.Index == NEW {
c.SrcRoot = c.New.ImportPath
} else {
if c.Index != VERSION {
utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.")
}
return
}
}
// set go src path */
c.SrcRoot = filepath.Join(c.SrcRoot, "src")
c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath))
utils.Logger.Info("Set application path", "path", c.AppPath)
} }
// Sets the versions on the command config // Sets the versions on the command config

View File

@@ -57,7 +57,6 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered
// Look through the embedded types to see if the current type is among them. // Look through the embedded types to see if the current type is among them.
for _, embeddedType := range spec.EmbeddedTypes { for _, embeddedType := range spec.EmbeddedTypes {
// If so, add this type's simple name to the nodeQueue, and its spec to // If so, add this type's simple name to the nodeQueue, and its spec to
// the filtered list. // the filtered list.
if typeSimpleName == embeddedType.String() { if typeSimpleName == embeddedType.String() {
@@ -111,6 +110,7 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered
// ControllerSpecs returns the all the controllers that embeds // ControllerSpecs returns the all the controllers that embeds
// `revel.Controller` // `revel.Controller`
func (s *SourceInfo) ControllerSpecs() []*TypeInfo { func (s *SourceInfo) ControllerSpecs() []*TypeInfo {
utils.Logger.Info("Scanning controller specifications for types ","typePath",RevelImportPath + ".Controller", "speclen",len(s.controllerSpecs))
if s.controllerSpecs == nil { if s.controllerSpecs == nil {
s.controllerSpecs = s.TypesThatEmbed(RevelImportPath + ".Controller", "controllers") s.controllerSpecs = s.TypesThatEmbed(RevelImportPath + ".Controller", "controllers")
} }

View File

@@ -21,7 +21,7 @@ type Version struct {
var frameworkCompatibleRangeList = [][]string{ var frameworkCompatibleRangeList = [][]string{
{"0.0.0", "0.20.0"}, // minimum Revel version to use with this version of the tool {"0.0.0", "0.20.0"}, // minimum Revel version to use with this version of the tool
{"0.19.99", "0.30.0"}, // Compatible with Framework V 0.19.99 - 0.30.0 {"0.19.99", "0.30.0"}, // Compatible with Framework V 0.19.99 - 0.30.0
{"1.0.0", "1.1.0"}, // Compatible with Framework V 1.0 - 1.1 {"1.0.0", "1.9.0"}, // Compatible with Framework V 1.0 - 1.9
} }
// Parses a version like v1.2.3a or 1.2 // Parses a version like v1.2.3a or 1.2

View File

@@ -8,6 +8,7 @@ import (
"go/token" "go/token"
"strings" "strings"
"path/filepath" "path/filepath"
"github.com/revel/cmd/logger"
) )
type ( type (
@@ -31,14 +32,21 @@ func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *m
strings.Contains(p.PkgPath, "/tests/") strings.Contains(p.PkgPath, "/tests/")
methodMap = map[string][]*model.MethodSpec{} methodMap = map[string][]*model.MethodSpec{}
) )
localImportMap := map[string]string{}
log := s.sourceProcessor.log.New("package", p.PkgPath)
log.Info("Processing package")
for _, tree := range p.Syntax { for _, tree := range p.Syntax {
for _, decl := range tree.Decls { for _, decl := range tree.Decls {
s.sourceProcessor.packageMap[p.PkgPath] = filepath.Dir(p.Fset.Position(decl.Pos()).Filename) s.sourceProcessor.packageMap[p.PkgPath] = filepath.Dir(p.Fset.Position(decl.Pos()).Filename)
//println("*** checking", p.Fset.Position(decl.Pos()).Filename) if !s.addImport(decl, p, localImportMap, log) {
continue
}
spec, found := s.getStructTypeDecl(decl, p.Fset) spec, found := s.getStructTypeDecl(decl, p.Fset)
//log.Info("Checking file","filename", p.Fset.Position(decl.Pos()).Filename,"found",found)
if found { if found {
if isController || isTest { if isController || isTest {
controllerSpec := s.getControllerSpec(spec, p) controllerSpec := s.getControllerSpec(spec, p, localImportMap)
sourceInfo.StructSpecs = append(sourceInfo.StructSpecs, controllerSpec) sourceInfo.StructSpecs = append(sourceInfo.StructSpecs, controllerSpec)
} }
} else { } else {
@@ -54,9 +62,9 @@ func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *m
funcDecl.Name.IsExported() && // be public funcDecl.Name.IsExported() && // be public
funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) == 1 { funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) == 1 {
// return one result // return one result
if m, receiver := s.getControllerFunc(funcDecl, p); m != nil { if m, receiver := s.getControllerFunc(funcDecl, p, localImportMap); m != nil {
methodMap[receiver] = append(methodMap[receiver], m) methodMap[receiver] = append(methodMap[receiver], m)
s.sourceProcessor.log.Info("Added method map to ", "receiver", receiver, "method", m.Name) log.Info("Added method map to ", "receiver", receiver, "method", m.Name)
} }
} }
// Check for validation // Check for validation
@@ -183,7 +191,7 @@ func (s *SourceInfoProcessor) getValidationParameter(funcDecl *ast.FuncDecl) *a
} }
return nil return nil
} }
func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl, p *packages.Package) (method *model.MethodSpec, recvTypeName string) { func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl, p *packages.Package, localImportMap map[string]string) (method *model.MethodSpec, recvTypeName string) {
selExpr, ok := funcDecl.Type.Results.List[0].Type.(*ast.SelectorExpr) selExpr, ok := funcDecl.Type.Results.List[0].Type.(*ast.SelectorExpr)
if !ok { if !ok {
return return
@@ -212,8 +220,11 @@ func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl, p *packa
importPath = p.PkgPath importPath = p.PkgPath
} else if typeExpr.PkgName != "" { } else if typeExpr.PkgName != "" {
var ok bool var ok bool
if importPath, ok = s.sourceProcessor.importMap[typeExpr.PkgName]; !ok { if importPath, ok = localImportMap[typeExpr.PkgName]; !ok {
utils.Logger.Fatalf("Failed to find import for arg of type: %s , %s", typeExpr.PkgName, typeExpr.TypeName("")) if importPath, ok = s.sourceProcessor.importMap[typeExpr.PkgName]; !ok {
utils.Logger.Error("Unable to find import", "importMap", s.sourceProcessor.importMap, "localimport", localImportMap)
utils.Logger.Fatalf("Failed to find import for arg of type: %s , %s", typeExpr.PkgName, typeExpr.TypeName(""))
}
} }
} }
method.Args = append(method.Args, &model.MethodArg{ method.Args = append(method.Args, &model.MethodArg{
@@ -271,7 +282,7 @@ func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl, p *packa
} }
return return
} }
func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.Package) (controllerSpec *model.TypeInfo) { func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.Package, localImportMap map[string]string) (controllerSpec *model.TypeInfo) {
structType := spec.Type.(*ast.StructType) structType := spec.Type.(*ast.StructType)
// At this point we know it's a type declaration for a struct. // At this point we know it's a type declaration for a struct.
@@ -282,6 +293,7 @@ func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.
ImportPath: p.PkgPath, ImportPath: p.PkgPath,
PackageName: p.Name, PackageName: p.Name,
} }
log := s.sourceProcessor.log.New("file", p.Fset.Position(spec.Pos()).Filename, "position", p.Fset.Position(spec.Pos()).Line)
for _, field := range structType.Fields.List { for _, field := range structType.Fields.List {
// If field.Names is set, it's not an embedded type. // If field.Names is set, it's not an embedded type.
if field.Names != nil { if field.Names != nil {
@@ -329,9 +341,12 @@ func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.
importPath = p.PkgPath importPath = p.PkgPath
} else { } else {
var ok bool var ok bool
if importPath, ok = s.sourceProcessor.importMap[pkgName]; !ok { if importPath, ok = localImportMap[pkgName]; !ok {
s.sourceProcessor.log.Error("Error: Failed to find import path for ", "package", pkgName, "type", typeName, "map", s.sourceProcessor.importMap) log.Debug("Debug: Unusual, failed to find package locally ", "package", pkgName, "type", typeName, "map", s.sourceProcessor.importMap, "usedin", )
continue if importPath, ok = s.sourceProcessor.importMap[pkgName]; !ok {
log.Error("Error: Failed to find import path for ", "package", pkgName, "type", typeName, "map", s.sourceProcessor.importMap, "usedin", )
continue
}
} }
} }
@@ -376,4 +391,37 @@ func (s *SourceInfoProcessor) getFuncName(funcDecl *ast.FuncDecl) string {
prefix += "." prefix += "."
} }
return prefix + funcDecl.Name.Name return prefix + funcDecl.Name.Name
}
func (s *SourceInfoProcessor) addImport(decl ast.Decl, p *packages.Package, localImportMap map[string]string, log logger.MultiLogger) (shouldContinue bool) {
shouldContinue = true
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
return
}
if genDecl.Tok == token.IMPORT {
shouldContinue = false
for _, spec := range genDecl.Specs {
importSpec := spec.(*ast.ImportSpec)
//fmt.Printf("*** import specification %#v\n", importSpec)
var pkgAlias string
if importSpec.Name != nil {
pkgAlias = importSpec.Name.Name
if pkgAlias == "_" {
continue
}
}
quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\""
fullPath := quotedPath[1 : len(quotedPath) - 1] // Remove the quotes
if pkgAlias == "" {
pkgAlias = fullPath
if index := strings.LastIndex(pkgAlias, "/"); index > 0 {
pkgAlias = pkgAlias[index + 1:]
}
}
localImportMap[pkgAlias] = fullPath
}
}
return
} }

View File

@@ -1,15 +1,17 @@
package parser2 package parser2
import ( import (
"go/ast"
"go/token"
"github.com/revel/cmd/model" "github.com/revel/cmd/model"
"golang.org/x/tools/go/packages" "golang.org/x/tools/go/packages"
"github.com/revel/cmd/utils" "github.com/revel/cmd/utils"
"errors" "go/parser"
"strings" "strings"
"github.com/revel/cmd/logger" "github.com/revel/cmd/logger"
"os"
"path/filepath"
"go/ast"
"go/token"
"go/scanner"
) )
type ( type (
@@ -33,10 +35,6 @@ func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.Sour
processor.log.Infof("From parsers : Structures:%d InitImports:%d ValidationKeys:%d %v", len(sourceInfo.StructSpecs), len(sourceInfo.InitImportPaths), len(sourceInfo.ValidationKeys), sourceInfo.PackageMap) processor.log.Infof("From parsers : Structures:%d InitImports:%d ValidationKeys:%d %v", len(sourceInfo.StructSpecs), len(sourceInfo.InitImportPaths), len(sourceInfo.ValidationKeys), sourceInfo.PackageMap)
} }
if false {
compileError = errors.New("Incompleted")
utils.Logger.Panic("Not implemented")
}
return return
} }
@@ -45,16 +43,20 @@ func NewSourceProcessor(revelContainer *model.RevelContainer) *SourceProcessor {
s.sourceInfoProcessor = NewSourceInfoProcessor(s) s.sourceInfoProcessor = NewSourceInfoProcessor(s)
return s return s
} }
func (s *SourceProcessor) parse() (compileError error) { func (s *SourceProcessor) parse() (compileError error) {
print("Parsing packages, (may require download if not cached)...")
if compileError = s.addPackages(); compileError != nil { if compileError = s.addPackages(); compileError != nil {
return return
} }
println(" Completed")
if compileError = s.addImportMap(); compileError != nil { if compileError = s.addImportMap(); compileError != nil {
return return
} }
if compileError = s.addSourceInfo(); compileError != nil { if compileError = s.addSourceInfo(); compileError != nil {
return return
} }
s.sourceInfo.PackageMap = map[string]string{} s.sourceInfo.PackageMap = map[string]string{}
getImportFromMap := func(packagePath string) string { getImportFromMap := func(packagePath string) string {
for path := range s.packageMap { for path := range s.packageMap {
@@ -73,11 +75,15 @@ func (s *SourceProcessor) parse() (compileError error) {
return return
} }
// Using the packages.Load function load all the packages and type specifications (forces compile).
// this sets the SourceProcessor.packageList []*packages.Package
func (s *SourceProcessor) addPackages() (err error) { func (s *SourceProcessor) addPackages() (err error) {
allPackages := []string{s.revelContainer.ImportPath + "/...", model.RevelImportPath} allPackages := []string{model.RevelImportPath + "/..."}
for _, module := range s.revelContainer.ModulePathMap { for _, module := range s.revelContainer.ModulePathMap {
allPackages = append(allPackages, module.ImportPath + "/...") // +"/app/controllers/...") allPackages = append(allPackages, module.ImportPath + "/...") // +"/app/controllers/...")
} }
s.log.Info("Reading packages", "packageList", allPackages)
//allPackages = []string{s.revelContainer.ImportPath + "/..."} //+"/app/controllers/..."} //allPackages = []string{s.revelContainer.ImportPath + "/..."} //+"/app/controllers/..."}
config := &packages.Config{ config := &packages.Config{
@@ -102,9 +108,117 @@ func (s *SourceProcessor) addPackages() (err error) {
Dir:s.revelContainer.AppPath, Dir:s.revelContainer.AppPath,
} }
s.packageList, err = packages.Load(config, allPackages...) s.packageList, err = packages.Load(config, allPackages...)
s.log.Info("Loaded packages ", "len results", len(s.packageList), "error", err) s.log.Info("Loaded modules ", "len results", len(s.packageList), "error", err)
// Now process the files in the aap source folder s.revelContainer.ImportPath + "/...",
err = utils.Walk(s.revelContainer.BasePath, s.processPath)
s.log.Info("Loaded apps and modules ", "len results", len(s.packageList), "error", err)
return return
} }
// This callback is used to build the packages for the "app" package. This allows us to
// parse the source files without doing a full compile on them
// This callback only processes folders, so any files passed to this will return a nil
func (s *SourceProcessor) processPath(path string, info os.FileInfo, err error) error {
if err != nil {
s.log.Error("Error scanning app source:", "error", err)
return nil
}
// Ignore files and folders not marked tmp (since those are generated)
if !info.IsDir() || info.Name() == "tmp" {
return nil
}
// Real work for processing the folder
pkgImportPath := s.revelContainer.ImportPath
appPath := s.revelContainer.BasePath
if appPath != path {
pkgImportPath = s.revelContainer.ImportPath + "/" + filepath.ToSlash(path[len(appPath) + 1:])
}
s.log.Info("Processing source package folder", "package", pkgImportPath, "path", path)
// Parse files within the path.
var pkgMap map[string]*ast.Package
fset := token.NewFileSet()
pkgMap, err = parser.ParseDir(
fset,
path,
func(f os.FileInfo) bool {
return !f.IsDir() && !strings.HasPrefix(f.Name(), ".") && strings.HasSuffix(f.Name(), ".go")
},
0)
if err != nil {
if errList, ok := err.(scanner.ErrorList); ok {
var pos = errList[0].Pos
newError := &utils.SourceError{
SourceType: ".go source",
Title: "Go Compilation Error",
Path: pos.Filename,
Description: errList[0].Msg,
Line: pos.Line,
Column: pos.Column,
SourceLines: utils.MustReadLines(pos.Filename),
}
errorLink := s.revelContainer.Config.StringDefault("error.link", "")
if errorLink != "" {
newError.SetLink(errorLink)
}
return newError
}
// This is exception, err already checked above. Here just a print
ast.Print(nil, err)
s.log.Fatal("Failed to parse dir", "error", err)
}
// Skip "main" packages.
delete(pkgMap, "main")
// Ignore packages that end with _test
// These cannot be included in source code that is not generated specifically as a test
for i := range pkgMap {
if len(i) > 6 {
if string(i[len(i) - 5:]) == "_test" {
delete(pkgMap, i)
}
}
}
// If there is no code in this directory, skip it.
if len(pkgMap) == 0 {
return nil
}
// There should be only one package in this directory.
if len(pkgMap) > 1 {
for i := range pkgMap {
println("Found duplicate packages in single directory ", i)
}
utils.Logger.Fatal("Most unexpected! Multiple packages in a single directory:", "packages", pkgMap)
}
// At this point there is only one package in the pkgs map,
p := &packages.Package{}
p.PkgPath = pkgImportPath
p.Fset = fset
for _, pkg := range pkgMap {
p.Name = pkg.Name
s.log.Info("Found package", "pkg.Name", pkg.Name, "p.Name", p.PkgPath)
for filename, astFile := range pkg.Files {
p.Syntax = append(p.Syntax, astFile)
p.GoFiles = append(p.GoFiles, filename)
}
}
s.packageList = append(s.packageList, p)
return nil
}
// This function is used to populate a map so that we can lookup controller embedded types in order to determine
// if a Struct inherits from from revel.Controller
func (s *SourceProcessor) addImportMap() (err error) { func (s *SourceProcessor) addImportMap() (err error) {
s.importMap = map[string]string{} s.importMap = map[string]string{}
s.packageMap = map[string]string{} s.packageMap = map[string]string{}
@@ -113,41 +227,11 @@ func (s *SourceProcessor) addImportMap() (err error) {
if len(p.Errors) > 0 { if len(p.Errors) > 0 {
// Generate a compile error // Generate a compile error
for _, e := range p.Errors { for _, e := range p.Errors {
if !strings.Contains(e.Msg, "fsnotify") { s.log.Info("While reading packages encountered import error ignoring ", "PkgPath", p.PkgPath, "error", e)
err = utils.NewCompileError("", "", e)
}
} }
} }
for _, tree := range p.Syntax { for _, tree := range p.Syntax {
for _, decl := range tree.Decls { s.importMap[tree.Name.Name] = p.PkgPath
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
continue
}
if genDecl.Tok == token.IMPORT {
for _, spec := range genDecl.Specs {
importSpec := spec.(*ast.ImportSpec)
//fmt.Printf("*** import specification %#v\n", importSpec)
var pkgAlias string
if importSpec.Name != nil {
pkgAlias = importSpec.Name.Name
if pkgAlias == "_" {
continue
}
}
quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\""
fullPath := quotedPath[1 : len(quotedPath) - 1] // Remove the quotes
if pkgAlias == "" {
pkgAlias = fullPath
if index := strings.LastIndex(pkgAlias, "/"); index > 0 {
pkgAlias = pkgAlias[index + 1:]
}
}
s.importMap[pkgAlias] = fullPath
}
}
}
} }
} }
return return
@@ -165,53 +249,3 @@ func (s *SourceProcessor) addSourceInfo() (err error) {
} }
return return
} }
// Add imports to the map from the source dir
//func addImports(imports map[string]string, decl ast.Decl, srcDir string) {
// genDecl, ok := decl.(*ast.GenDecl)
// if !ok {
// return
// }
//
// if genDecl.Tok != token.IMPORT {
// return
// }
//
// for _, spec := range genDecl.Specs {
// importSpec := spec.(*ast.ImportSpec)
// var pkgAlias string
// if importSpec.Name != nil {
// pkgAlias = importSpec.Name.Name
// if pkgAlias == "_" {
// continue
// }
// }
// quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\""
// fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes
//
// // If the package was not aliased (common case), we have to import it
// // to see what the package name is.
// // TODO: Can improve performance here a lot:
// // 1. Do not import everything over and over again. Keep a cache.
// // 2. Exempt the standard library; their directories always match the package name.
// // 3. Can use build.FindOnly and then use parser.ParseDir with mode PackageClauseOnly
// if pkgAlias == "" {
//
// utils.Logger.Debug("Reading from build", "path", fullPath, "srcPath", srcDir, "gopath", build.Default.GOPATH)
// pkg, err := build.Import(fullPath, srcDir, 0)
// if err != nil {
// // We expect this to happen for apps using reverse routing (since we
// // have not yet generated the routes). Don't log that.
// if !strings.HasSuffix(fullPath, "/app/routes") {
// utils.Logger.Warn("Could not find import:", "path", fullPath, "srcPath", srcDir, "error", err)
// }
// continue
// } else {
// utils.Logger.Debug("Found package in dir", "dir", pkg.Dir, "name", pkg.ImportPath)
// }
// pkgAlias = pkg.Name
// }
//
// imports[pkgAlias] = fullPath
// }
//}

View File

@@ -59,6 +59,7 @@ func updateBuildConfig(c *model.CommandConfig, args []string) bool {
// The main entry point to build application from command line // The main entry point to build application from command line
func buildApp(c *model.CommandConfig) (err error) { func buildApp(c *model.CommandConfig) (err error) {
appImportPath, destPath, mode := c.ImportPath, c.Build.TargetPath, DefaultRunMode appImportPath, destPath, mode := c.ImportPath, c.Build.TargetPath, DefaultRunMode
if len(c.Build.Mode) > 0 { if len(c.Build.Mode) > 0 {
mode = c.Build.Mode mode = c.Build.Mode
@@ -113,7 +114,7 @@ func buildCopyFiles(c *model.CommandConfig, app *harness.App, revel_paths *model
srcPath := filepath.Join(destPath, "src") srcPath := filepath.Join(destPath, "src")
destBinaryPath := filepath.Join(destPath, filepath.Base(app.BinaryPath)) destBinaryPath := filepath.Join(destPath, filepath.Base(app.BinaryPath))
tmpRevelPath := filepath.Join(srcPath, filepath.FromSlash(model.RevelImportPath)) tmpRevelPath := filepath.Join(srcPath, filepath.FromSlash(model.RevelImportPath))
if err = utils.CopyFile(destBinaryPath, app.BinaryPath); err != nil { if err = utils.CopyFile(destBinaryPath, filepath.Join(revel_paths.BasePath, app.BinaryPath)); err != nil {
return return
} }
utils.MustChmod(destBinaryPath, 0755) utils.MustChmod(destBinaryPath, 0755)

View File

@@ -72,7 +72,7 @@ func newApp(c *model.CommandConfig) (err error) {
// Check for an existing folder so we don't clobber it // Check for an existing folder so we don't clobber it
_, err = build.Import(c.ImportPath, "", build.FindOnly) _, err = build.Import(c.ImportPath, "", build.FindOnly)
if err == nil || !utils.Empty(c.AppPath) { if err == nil || !utils.Empty(c.AppPath) {
return utils.NewBuildError("Abort: Import path already exists.", "path", c.ImportPath) return utils.NewBuildError("Abort: Import path already exists.", "path", c.ImportPath, "apppath", c.AppPath)
} }
// checking and setting skeleton // checking and setting skeleton
@@ -112,6 +112,10 @@ func newApp(c *model.CommandConfig) (err error) {
fmt.Fprintln(os.Stdout, "Your application has been created in:\n ", c.AppPath) fmt.Fprintln(os.Stdout, "Your application has been created in:\n ", c.AppPath)
// Check to see if it should be run right off // Check to see if it should be run right off
if c.New.Run { if c.New.Run {
// Need to prep the run command
c.Run.ImportPath = c.ImportPath
updateRunConfig(c,nil)
c.UpdateImportPath()
runApp(c) runApp(c)
} else { } else {
fmt.Fprintln(os.Stdout, "\nYou can run it with:\n revel run -a ", c.ImportPath) fmt.Fprintln(os.Stdout, "\nYou can run it with:\n revel run -a ", c.ImportPath)
@@ -203,13 +207,13 @@ func setApplicationPath(c *model.CommandConfig) (err error) {
// revel/revel#1014 validate relative path, we cannot use built-in functions // revel/revel#1014 validate relative path, we cannot use built-in functions
// since Go import path is valid relative path too. // since Go import path is valid relative path too.
// so check basic part of the path, which is "." // so check basic part of the path, which is "."
if filepath.IsAbs(c.ImportPath) || strings.HasPrefix(c.ImportPath, ".") {
utils.Logger.Fatalf("Abort: '%s' looks like a directory. Please provide a Go import path instead.",
c.ImportPath)
}
// If we are running a vendored version of Revel we do not need to check for it. // If we are running a vendored version of Revel we do not need to check for it.
if !c.Vendored { if !c.Vendored {
if filepath.IsAbs(c.ImportPath) || strings.HasPrefix(c.ImportPath, ".") {
utils.Logger.Fatalf("Abort: '%s' looks like a directory. Please provide a Go import path instead.",
c.ImportPath)
}
_, err = build.Import(model.RevelImportPath, "", build.FindOnly) _, err = build.Import(model.RevelImportPath, "", build.FindOnly)
if err != nil { if err != nil {
//// Go get the revel project //// Go get the revel project

View File

@@ -18,6 +18,12 @@ func TestNew(t *testing.T) {
c := newApp("new-test", model.NEW, nil, a) c := newApp("new-test", model.NEW, nil, a)
a.Nil(main.Commands[model.NEW].RunWith(c), "New failed") a.Nil(main.Commands[model.NEW].RunWith(c), "New failed")
}) })
t.Run("New-NotVendoredmode", func(t *testing.T) {
a := assert.New(t)
c := newApp("new-notvendored", model.NEW, nil, a)
c.New.NotVendored = true
a.Nil(main.Commands[model.NEW].RunWith(c), "New failed")
})
t.Run("Path", func(t *testing.T) { t.Run("Path", func(t *testing.T) {
a := assert.New(t) a := assert.New(t)
c := newApp("new/test/a", model.NEW, nil, a) c := newApp("new/test/a", model.NEW, nil, a)

View File

@@ -91,6 +91,9 @@ func main() {
utils.InitLogger(wd, logger.LvlWarn) utils.InitLogger(wd, logger.LvlWarn)
} }
// Setup package resolver
c.InitPackageResolver()
if err := c.UpdateImportPath(); err != nil { if err := c.UpdateImportPath(); err != nil {
utils.Logger.Error(err.Error()) utils.Logger.Error(err.Error())
parser.WriteHelp(os.Stdout) parser.WriteHelp(os.Stdout)
@@ -100,12 +103,6 @@ func main() {
command := Commands[c.Index] command := Commands[c.Index]
println("Revel executing:", command.Short) println("Revel executing:", command.Short)
// Setting go paths
// c.InitGoPaths()
// Setup package resolver
c.InitPackageResolver()
if err := command.RunWith(c); err != nil { if err := command.RunWith(c); err != nil {
utils.Logger.Error("Unable to execute", "error", err) utils.Logger.Error("Unable to execute", "error", err)
os.Exit(1) os.Exit(1)

View File

@@ -11,9 +11,7 @@ import (
"github.com/revel/cmd/harness" "github.com/revel/cmd/harness"
"github.com/revel/cmd/model" "github.com/revel/cmd/model"
"github.com/revel/cmd/utils" "github.com/revel/cmd/utils"
"go/build"
"os" "os"
"path/filepath"
) )
var cmdRun = &Command{ var cmdRun = &Command{
@@ -116,10 +114,7 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool {
// Returns true if this is an absolute path or a relative gopath // Returns true if this is an absolute path or a relative gopath
func runIsImportPath(pathToCheck string) bool { func runIsImportPath(pathToCheck string) bool {
if _, err := build.Import(pathToCheck, "", build.FindOnly); err == nil { return utils.DirExists(pathToCheck)
return true
}
return filepath.IsAbs(pathToCheck)
} }
// Called to run the app // Called to run the app
@@ -167,6 +162,6 @@ func runApp(c *model.CommandConfig) (err error) {
if c.HistoricMode { if c.HistoricMode {
runMode = revel_path.RunMode runMode = revel_path.RunMode
} }
app.Cmd(runMode).Run() app.Cmd(runMode).Run(c)
return return
} }

View File

@@ -110,16 +110,6 @@ func (v *VersionCommand) doRepoCheck(updateLibs bool) (versionInfo string, needs
} }
// Only do an update on the first loop, and if specified to update // Only do an update on the first loop, and if specified to update
shouldUpdate := updateLibs && v.Command.Version.Update
if v.Command.Version.Update {
if localVersion == nil || (versonFromRepo != nil && versonFromRepo.Newer(localVersion)) {
needsUpdate = true
if shouldUpdate {
v.doUpdate(title, repo, localVersion, versonFromRepo)
v.updateLocalVersions()
}
}
}
versionInfo = versionInfo + v.outputVersion(title, repo, localVersion, versonFromRepo) versionInfo = versionInfo + v.outputVersion(title, repo, localVersion, versonFromRepo)
} }
return return
@@ -234,6 +224,10 @@ func (v *VersionCommand) updateLocalVersions() {
v.cmdVersion.BuildDate = cmd.BuildDate v.cmdVersion.BuildDate = cmd.BuildDate
v.cmdVersion.MinGoVersion = cmd.MinimumGoVersion v.cmdVersion.MinGoVersion = cmd.MinimumGoVersion
if v.Command.Version.ImportPath=="" {
return
}
pathMap, err := utils.FindSrcPaths(v.Command.AppPath, []string{model.RevelImportPath, model.RevelModulesImportPath}, v.Command.PackageResolver) pathMap, err := utils.FindSrcPaths(v.Command.AppPath, []string{model.RevelImportPath, model.RevelModulesImportPath}, v.Command.PackageResolver)
if err != nil { if err != nil {
utils.Logger.Warn("Unable to extract version information from Revel library", "path", pathMap[model.RevelImportPath], "error", err) utils.Logger.Warn("Unable to extract version information from Revel library", "path", pathMap[model.RevelImportPath], "error", err)

View File

@@ -34,8 +34,8 @@ func TestVersion(t *testing.T) {
a.Nil(main.Commands[model.VERSION].RunWith(c), "Failed to run version-test") a.Nil(main.Commands[model.VERSION].RunWith(c), "Failed to run version-test")
}) })
if !t.Failed() { if !t.Failed() {
if err := os.RemoveAll(gopath); err != nil { if err := os.RemoveAll(gopath); err != nil && err!=os.ErrNotExist {
a.Fail("Failed to remove test path") a.Fail("Failed to remove test path",err.Error())
} }
} }
} }

View File

@@ -203,7 +203,8 @@ func Walk(root string, walkFn filepath.WalkFunc) error {
return fsWalk(root, root, walkFn) return fsWalk(root, root, walkFn)
} }
// Walk the tree using the function // Walk the path tree using the function
// Every file found will call the function
func fsWalk(fname string, linkName string, walkFn filepath.WalkFunc) error { func fsWalk(fname string, linkName string, walkFn filepath.WalkFunc) error {
fsWalkFunc := func(path string, info os.FileInfo, err error) error { fsWalkFunc := func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
@@ -308,9 +309,13 @@ func Exists(filename string) bool {
// empty returns true if the given directory is empty. // empty returns true if the given directory is empty.
// the directory must exist. // the directory must exist.
func Empty(dirname string) bool { func Empty(dirname string) bool {
if !DirExists(dirname) {
return true
}
dir, err := os.Open(dirname) dir, err := os.Open(dirname)
if err != nil { if err != nil {
Logger.Infof("error opening directory: %s", err) Logger.Infof("error opening directory: %s", err)
return false
} }
defer func() { defer func() {
_ = dir.Close() _ = dir.Close()
@@ -322,7 +327,8 @@ func Empty(dirname string) bool {
// Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory // Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory
func FindSrcPaths(appPath string, packageList []string, packageResolver func(pkgName string) error) (sourcePathsmap map[string]string, err error) { func FindSrcPaths(appPath string, packageList []string, packageResolver func(pkgName string) error) (sourcePathsmap map[string]string, err error) {
sourcePathsmap, missingList, err := findSrcPaths(appPath, packageList) sourcePathsmap, missingList, err := findSrcPaths(appPath, packageList)
if err != nil && packageResolver != nil { if err != nil && packageResolver != nil || len(missingList) > 0 {
Logger.Info("Failed to find package, attempting to call resolver for missing packages", "missing packages", missingList)
for _, item := range missingList { for _, item := range missingList {
if err = packageResolver(item); err != nil { if err = packageResolver(item); err != nil {
return return
@@ -351,8 +357,10 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str
Dir:appPath, Dir:appPath,
} }
sourcePathsmap = map[string]string{} sourcePathsmap = map[string]string{}
Logger.Infof("Environment path %s root %s config env %s", os.Getenv("GOPATH"), os.Getenv("GOROOT"), config.Env)
pkgs, err := packages.Load(config, packagesList...) pkgs, err := packages.Load(config, packagesList...)
Logger.Infof("Environment path %s root %s config env %s", os.Getenv("GOPATH"), os.Getenv("GOROOT"), config.Env)
Logger.Info("Loaded packages ", "len results", len(pkgs), "error", err, "basedir", appPath) Logger.Info("Loaded packages ", "len results", len(pkgs), "error", err, "basedir", appPath)
for _, packageName := range packagesList { for _, packageName := range packagesList {
found := false found := false
@@ -361,12 +369,16 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str
log.Info("Found package", "package", pck.ID) log.Info("Found package", "package", pck.ID)
if pck.ID == packageName { if pck.ID == packageName {
if pck.Errors != nil && len(pck.Errors) > 0 { if pck.Errors != nil && len(pck.Errors) > 0 {
log.Info("Error ", "count", len(pck.Errors), "App Import Path", pck.ID, "errors", pck.Errors) log.Error("Error ", "count", len(pck.Errors), "App Import Path", pck.ID, "filesystem path", pck.PkgPath, "errors", pck.Errors)
// continue
} }
//a,_ := pck.MarshalJSON() //a,_ := pck.MarshalJSON()
log.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID, "apppath", appPath) log.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID, "apppath", appPath)
sourcePathsmap[packageName] = filepath.Dir(pck.GoFiles[0]) if len(pck.GoFiles) > 0 {
found = true sourcePathsmap[packageName] = filepath.Dir(pck.GoFiles[0])
found = true
}
} }
} }
if !found { if !found {
@@ -378,5 +390,6 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str
missingList = append(missingList, packageName) missingList = append(missingList, packageName)
} }
} }
return return
} }

View File

@@ -6,11 +6,11 @@ package cmd
const ( const (
// Version current Revel version // Version current Revel version
Version = "1.0.0-dev" Version = "1.0.0"
// BuildDate latest commit/release date // BuildDate latest commit/release date
BuildDate = "2018-10-30" BuildDate = "2020-07-11"
// MinimumGoVersion minimum required Go version for Revel // MinimumGoVersion minimum required Go version for Revel
MinimumGoVersion = ">= go1.8" MinimumGoVersion = ">= go1.12"
) )

View File

@@ -33,7 +33,7 @@ type DiscerningListener interface {
// Watcher allows listeners to register to be notified of changes under a given // Watcher allows listeners to register to be notified of changes under a given
// directory. // directory.
type Watcher struct { type Watcher struct {
// Parallel arrays of watcher/listener pairs. // Parallel arrays of watcher/listener pairs.
watchers []*fsnotify.Watcher watchers []*fsnotify.Watcher
listeners []Listener listeners []Listener
forceRefresh bool forceRefresh bool
@@ -42,8 +42,8 @@ type Watcher struct {
lastError int lastError int
notifyMutex sync.Mutex notifyMutex sync.Mutex
paths *model.RevelContainer paths *model.RevelContainer
refreshTimer *time.Timer // The timer to countdown the next refresh refreshTimer *time.Timer // The timer to countdown the next refresh
timerMutex *sync.Mutex // A mutex to prevent concurrent updates timerMutex *sync.Mutex // A mutex to prevent concurrent updates
refreshChannel chan *utils.SourceError refreshChannel chan *utils.SourceError
refreshChannelCount int refreshChannelCount int
refreshTimerMS time.Duration // The number of milliseconds between refreshing builds refreshTimerMS time.Duration // The number of milliseconds between refreshing builds
@@ -52,10 +52,10 @@ type Watcher struct {
// Creates a new watched based on the container // Creates a new watched based on the container
func NewWatcher(paths *model.RevelContainer, eagerRefresh bool) *Watcher { func NewWatcher(paths *model.RevelContainer, eagerRefresh bool) *Watcher {
return &Watcher{ return &Watcher{
forceRefresh: true, forceRefresh: false,
lastError: -1, lastError: -1,
paths: paths, paths: paths,
refreshTimerMS: time.Duration(paths.Config.IntDefault("watch.rebuild.delay", 10)), refreshTimerMS: time.Duration(paths.Config.IntDefault("watch.rebuild.delay", 1000)),
eagerRefresh: eagerRefresh || eagerRefresh: eagerRefresh ||
paths.DevMode && paths.DevMode &&
paths.Config.BoolDefault("watch", true) && paths.Config.BoolDefault("watch", true) &&
@@ -85,7 +85,7 @@ func (w *Watcher) Listen(listener Listener, roots ...string) {
for _, p := range roots { for _, p := range roots {
// is the directory / file a symlink? // is the directory / file a symlink?
f, err := os.Lstat(p) f, err := os.Lstat(p)
if err == nil && f.Mode()&os.ModeSymlink == os.ModeSymlink { if err == nil && f.Mode() & os.ModeSymlink == os.ModeSymlink {
var realPath string var realPath string
realPath, err = filepath.EvalSymlinks(p) realPath, err = filepath.EvalSymlinks(p)
if err != nil { if err != nil {
@@ -200,12 +200,13 @@ func (w *Watcher) Notify() *utils.SourceError {
case <-watcher.Errors: case <-watcher.Errors:
continue continue
default: default:
// No events left to pull // No events left to pull
} }
break break
} }
utils.Logger.Info("Watcher:Notify refresh state", "Current Index", i, " last error index", w.lastError) utils.Logger.Info("Watcher:Notify refresh state", "Current Index", i, " last error index", w.lastError,
"force", w.forceRefresh, "refresh", refresh, "lastError", w.lastError == i)
if w.forceRefresh || refresh || w.lastError == i { if w.forceRefresh || refresh || w.lastError == i {
var err *utils.SourceError var err *utils.SourceError
if w.serial { if w.serial {
@@ -285,22 +286,10 @@ func (w *Watcher) rebuildRequired(ev fsnotify.Event, listener Listener) bool {
} }
if dl, ok := listener.(DiscerningListener); ok { if dl, ok := listener.(DiscerningListener); ok {
if !dl.WatchFile(ev.Name) || ev.Op&fsnotify.Chmod == fsnotify.Chmod { if !dl.WatchFile(ev.Name) || ev.Op & fsnotify.Chmod == fsnotify.Chmod {
return false return false
} }
} }
return true return true
} }
/*
var WatchFilter = func(c *Controller, fc []Filter) {
if MainWatcher != nil {
err := MainWatcher.Notify()
if err != nil {
c.Result = c.RenderError(err)
return
}
}
fc[0](c, fc[1:])
}
*/