Default runtime now checks out code on demand (#1563)
* Default runtime now checks out code on demand * Go mod tidy
This commit is contained in:
parent
692b27578c
commit
ff8ad7d4ca
3
go.mod
3
go.mod
@ -22,6 +22,7 @@ require (
|
||||
github.com/fsouza/go-dockerclient v1.6.0
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-acme/lego/v3 v3.3.0
|
||||
github.com/go-git/go-git/v5 v5.0.0
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee
|
||||
github.com/gobwas/pool v0.2.0 // indirect
|
||||
@ -61,7 +62,7 @@ require (
|
||||
go.etcd.io/bbolt v1.3.4
|
||||
go.uber.org/zap v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1
|
||||
google.golang.org/grpc v1.26.0
|
||||
|
27
go.sum
27
go.sum
@ -101,6 +101,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -146,6 +147,14 @@ github.com/go-acme/lego/v3 v3.3.0 h1:6BePZsOiYA4/w+M7QDytxQtMfCipMPGnWAHs9pWks98
|
||||
github.com/go-acme/lego/v3 v3.3.0/go.mod h1:iGSY2vQrvQs3WezicSB/oVbO2eCrD88dpWPwb1qLqu0=
|
||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
|
||||
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
|
||||
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
@ -263,6 +272,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
@ -317,6 +328,8 @@ github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1t
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249 h1:Pr5gZa2VcmktVwq0lyC39MsN5tz356vC/pQHKvq+QBo=
|
||||
github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
|
||||
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
|
||||
@ -385,6 +398,8 @@ github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
@ -456,6 +471,7 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@ -500,8 +516,8 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0 h1:MsuvTghUPjX762sGLnGsxC3HM0B5r83wEtYcYR8/vRs=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -539,6 +555,8 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPT
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
@ -612,6 +630,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
@ -639,6 +660,8 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/hpcloud/tail"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/runtime/local/git"
|
||||
)
|
||||
|
||||
type runtime struct {
|
||||
@ -52,6 +53,21 @@ func NewRuntime(opts ...Option) Runtime {
|
||||
}
|
||||
}
|
||||
|
||||
// @todo move this to runtime default
|
||||
func (r *runtime) checkoutSourceIfNeeded(s *Service) error {
|
||||
source, err := git.ParseSourceLocal("", s.Source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
source.Ref = s.Version
|
||||
err = git.CheckoutSource(os.TempDir(), source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Source = source.FullPath
|
||||
return nil
|
||||
}
|
||||
|
||||
// Init initializes runtime options
|
||||
func (r *runtime) Init(opts ...Option) error {
|
||||
r.Lock()
|
||||
@ -193,6 +209,7 @@ func serviceKey(s *Service) string {
|
||||
|
||||
// Create creates a new service which is then started by runtime
|
||||
func (r *runtime) Create(s *Service, opts ...CreateOption) error {
|
||||
r.checkoutSourceIfNeeded(s)
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
@ -336,6 +353,7 @@ func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) {
|
||||
|
||||
// Update attemps to update the service
|
||||
func (r *runtime) Update(s *Service, opts ...UpdateOption) error {
|
||||
r.checkoutSourceIfNeeded(s)
|
||||
r.Lock()
|
||||
service, ok := r.services[serviceKey(s)]
|
||||
r.Unlock()
|
||||
|
333
runtime/local/git/git.go
Normal file
333
runtime/local/git/git.go
Normal file
@ -0,0 +1,333 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
type Gitter interface {
|
||||
Clone(repo string) error
|
||||
FetchAll(repo string) error
|
||||
Checkout(repo, branchOrCommit string) error
|
||||
RepoDir(repo string) string
|
||||
}
|
||||
|
||||
type libGitter struct {
|
||||
folder string
|
||||
}
|
||||
|
||||
func (g libGitter) Clone(repo string) error {
|
||||
fold := filepath.Join(g.folder, dirifyRepo(repo))
|
||||
exists, err := pathExists(fold)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return nil
|
||||
}
|
||||
_, err = git.PlainClone(fold, false, &git.CloneOptions{
|
||||
URL: repo,
|
||||
Progress: os.Stdout,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (g libGitter) FetchAll(repo string) error {
|
||||
repos, err := git.PlainOpen(filepath.Join(g.folder, dirifyRepo(repo)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remotes, err := repos.Remotes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = remotes[0].Fetch(&git.FetchOptions{
|
||||
RefSpecs: []config.RefSpec{"refs/*:refs/*", "HEAD:refs/heads/HEAD"},
|
||||
Progress: os.Stdout,
|
||||
Depth: 1,
|
||||
})
|
||||
if err != nil && err != git.NoErrAlreadyUpToDate {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g libGitter) Checkout(repo, branchOrCommit string) error {
|
||||
if branchOrCommit == "latest" {
|
||||
branchOrCommit = "master"
|
||||
}
|
||||
repos, err := git.PlainOpen(filepath.Join(g.folder, dirifyRepo(repo)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
worktree, err := repos.Worktree()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isCommit := func(s string) bool {
|
||||
return strings.ContainsAny(s, "0123456789") && len(s) == 40
|
||||
}
|
||||
if isCommit(branchOrCommit) {
|
||||
err = worktree.Checkout(&git.CheckoutOptions{
|
||||
Hash: plumbing.NewHash(branchOrCommit),
|
||||
Force: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = worktree.Checkout(&git.CheckoutOptions{
|
||||
Branch: plumbing.NewBranchReferenceName(branchOrCommit),
|
||||
Force: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g libGitter) RepoDir(repo string) string {
|
||||
return filepath.Join(g.folder, dirifyRepo(repo))
|
||||
}
|
||||
|
||||
type binaryGitter struct {
|
||||
folder string
|
||||
}
|
||||
|
||||
func (g binaryGitter) Clone(repo string) error {
|
||||
fold := filepath.Join(g.folder, dirifyRepo(repo))
|
||||
exists, err := pathExists(fold)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return nil
|
||||
}
|
||||
cmd := exec.Command("git", "clone", repo, ".")
|
||||
|
||||
err = os.MkdirAll(fold, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Dir = fold
|
||||
_, err = cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (g binaryGitter) FetchAll(repo string) error {
|
||||
cmd := exec.Command("git", "fetch", "--all")
|
||||
cmd.Dir = filepath.Join(g.folder, dirifyRepo(repo))
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (g binaryGitter) Checkout(repo, branchOrCommit string) error {
|
||||
if branchOrCommit == "latest" {
|
||||
branchOrCommit = "master"
|
||||
}
|
||||
cmd := exec.Command("git", "checkout", "-f", branchOrCommit)
|
||||
cmd.Dir = filepath.Join(g.folder, dirifyRepo(repo))
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g binaryGitter) RepoDir(repo string) string {
|
||||
return filepath.Join(g.folder, dirifyRepo(repo))
|
||||
}
|
||||
|
||||
func NewGitter(folder string) Gitter {
|
||||
if commandExists("git") {
|
||||
return binaryGitter{folder}
|
||||
}
|
||||
return libGitter{folder}
|
||||
}
|
||||
|
||||
func commandExists(cmd string) bool {
|
||||
_, err := exec.LookPath(cmd)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func dirifyRepo(s string) string {
|
||||
s = strings.ReplaceAll(s, "https://", "")
|
||||
s = strings.ReplaceAll(s, "/", "-")
|
||||
return s
|
||||
}
|
||||
|
||||
// exists returns whether the given file or directory exists
|
||||
func pathExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
// GetRepoRoot determines the repo root from a full path.
|
||||
// Returns empty string and no error if not found
|
||||
func GetRepoRoot(fullPath string) (string, error) {
|
||||
// traverse parent directories
|
||||
prev := fullPath
|
||||
for {
|
||||
current := prev
|
||||
exists, err := pathExists(filepath.Join(current, ".git"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if exists {
|
||||
return current, nil
|
||||
}
|
||||
prev = filepath.Dir(current)
|
||||
// reached top level, see:
|
||||
// https://play.golang.org/p/rDgVdk3suzb
|
||||
if current == prev {
|
||||
break
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
const defaultRepo = "github.com/micro/services"
|
||||
|
||||
// Source is not just git related @todo move
|
||||
type Source struct {
|
||||
// is it a local folder intended for a local runtime?
|
||||
Local bool
|
||||
// absolute path to service folder in local mode
|
||||
FullPath string
|
||||
// path of folder to repo root
|
||||
// be it local or github repo
|
||||
Folder string
|
||||
// github ref
|
||||
Ref string
|
||||
// for cloning purposes
|
||||
// blank for local
|
||||
Repo string
|
||||
// dir to repo root
|
||||
// blank for non local
|
||||
LocalRepoRoot string
|
||||
}
|
||||
|
||||
// Name to be passed to RPC call runtime.Create Update Delete
|
||||
// eg: `helloworld/api`, `crufter/myrepo/helloworld/api`, `localfolder`
|
||||
func (s *Source) RuntimeName() string {
|
||||
if s.Repo == "github.com/micro/services" || s.Repo == "" {
|
||||
return s.Folder
|
||||
}
|
||||
return fmt.Sprintf("%v/%v", strings.ReplaceAll(s.Repo, "github.com/", ""), s.Folder)
|
||||
}
|
||||
|
||||
// Source to be passed to RPC call runtime.Create Update Delete
|
||||
// eg: `helloworld`, `github.com/crufter/myrepo/helloworld`, `/path/to/localrepo/localfolder`
|
||||
func (s *Source) RuntimeSource() string {
|
||||
if s.Local {
|
||||
return s.FullPath
|
||||
}
|
||||
if s.Repo == "github.com/micro/services" || s.Repo == "" {
|
||||
return s.Folder
|
||||
}
|
||||
return fmt.Sprintf("%v/%v", s.Repo, s.Folder)
|
||||
}
|
||||
|
||||
// ParseSource parses a `micro run/update/kill` source.
|
||||
func ParseSource(source string) (*Source, error) {
|
||||
// If github is not present, we got a shorthand for `micro/services`
|
||||
if !strings.Contains(source, "github.com") {
|
||||
source = "github.com/micro/services/" + source
|
||||
}
|
||||
if !strings.Contains(source, "@") {
|
||||
source += "@latest"
|
||||
}
|
||||
ret := &Source{}
|
||||
refs := strings.Split(source, "@")
|
||||
ret.Ref = refs[1]
|
||||
parts := strings.Split(refs[0], "/")
|
||||
ret.Repo = strings.Join(parts[0:3], "/")
|
||||
if len(parts) > 1 {
|
||||
ret.Folder = strings.Join(parts[3:], "/")
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ParseSourceLocal detects and handles local pathes too
|
||||
// workdir should be used only from the CLI @todo better interface for this function
|
||||
func ParseSourceLocal(workDir, source string) (*Source, error) {
|
||||
var localFullPath string
|
||||
if len(workDir) > 0 {
|
||||
localFullPath = filepath.Join(workDir, source)
|
||||
} else {
|
||||
localFullPath = source
|
||||
}
|
||||
if exists, err := pathExists(localFullPath); err == nil && exists {
|
||||
localRepoRoot, err := GetRepoRoot(localFullPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
folder := strings.ReplaceAll(localFullPath, localRepoRoot+string(filepath.Separator), "")
|
||||
return &Source{
|
||||
Local: true,
|
||||
Folder: folder,
|
||||
FullPath: localFullPath,
|
||||
LocalRepoRoot: localRepoRoot,
|
||||
Ref: "latest", // @todo consider extracting branch from git here
|
||||
}, nil
|
||||
}
|
||||
return ParseSource(source)
|
||||
}
|
||||
|
||||
// CheckoutSource for the local runtime server
|
||||
// folder is the folder to check out the source code to
|
||||
// Modifies source path to set it to checked out repo absolute path locally.
|
||||
func CheckoutSource(folder string, source *Source) error {
|
||||
// if it's a local folder, do nothing
|
||||
if exists, err := pathExists(source.FullPath); err == nil && exists {
|
||||
return nil
|
||||
}
|
||||
gitter := NewGitter(folder)
|
||||
repo := source.Repo
|
||||
if !strings.Contains(repo, "https://") {
|
||||
repo = "https://" + repo
|
||||
}
|
||||
// Always clone, it's idempotent and only clones if needed
|
||||
err := gitter.Clone(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
source.FullPath = filepath.Join(gitter.RepoDir(source.Repo), source.Folder)
|
||||
return gitter.Checkout(repo, source.Ref)
|
||||
}
|
||||
|
||||
// code below is not used yet
|
||||
|
||||
var nameExtractRegexp = regexp.MustCompile(`((micro|web)\.Name\(")(.*)("\))`)
|
||||
|
||||
func extractServiceName(fileContent []byte) string {
|
||||
hits := nameExtractRegexp.FindAll(fileContent, 1)
|
||||
if len(hits) == 0 {
|
||||
return ""
|
||||
}
|
||||
hit := string(hits[0])
|
||||
return strings.Split(hit, "\"")[1]
|
||||
}
|
95
runtime/local/git/git_test.go
Normal file
95
runtime/local/git/git_test.go
Normal file
@ -0,0 +1,95 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
type parseCase struct {
|
||||
url string
|
||||
expected *Source
|
||||
}
|
||||
|
||||
func TestParseSource(t *testing.T) {
|
||||
cases := []parseCase{
|
||||
{
|
||||
url: "helloworld",
|
||||
expected: &Source{
|
||||
Repo: "github.com/micro/services",
|
||||
Folder: "helloworld",
|
||||
Ref: "latest",
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "github.com/micro/services/helloworld",
|
||||
expected: &Source{
|
||||
Repo: "github.com/micro/services",
|
||||
Folder: "helloworld",
|
||||
Ref: "latest",
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "github.com/micro/services/helloworld@v1.12.1",
|
||||
expected: &Source{
|
||||
Repo: "github.com/micro/services",
|
||||
Folder: "helloworld",
|
||||
Ref: "v1.12.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "github.com/micro/services/helloworld@branchname",
|
||||
expected: &Source{
|
||||
Repo: "github.com/micro/services",
|
||||
Folder: "helloworld",
|
||||
Ref: "branchname",
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "github.com/crufter/reponame/helloworld@branchname",
|
||||
expected: &Source{
|
||||
Repo: "github.com/crufter/reponame",
|
||||
Folder: "helloworld",
|
||||
Ref: "branchname",
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
result, err := ParseSource(c.url)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed case %v: %v", i, err)
|
||||
}
|
||||
if result.Folder != c.expected.Folder {
|
||||
t.Fatalf("Folder does not match for '%v', expected '%v', got '%v'", i, c.expected.Folder, result.Folder)
|
||||
}
|
||||
if result.Repo != c.expected.Repo {
|
||||
t.Fatalf("Repo address does not match for '%v', expected '%v', got '%v'", i, c.expected.Repo, result.Repo)
|
||||
}
|
||||
if result.Ref != c.expected.Ref {
|
||||
t.Fatalf("Ref does not match for '%v', expected '%v', got '%v'", i, c.expected.Ref, result.Ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type nameCase struct {
|
||||
fileContent string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestServiceNameExtract(t *testing.T) {
|
||||
cases := []nameCase{
|
||||
{
|
||||
fileContent: `func main() {
|
||||
// New Service
|
||||
service := micro.NewService(
|
||||
micro.Name("go.micro.service.helloworld"),
|
||||
micro.Version("latest"),
|
||||
)`,
|
||||
expected: "go.micro.service.helloworld",
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
result := extractServiceName([]byte(c.fileContent))
|
||||
if result != c.expected {
|
||||
t.Fatalf("Case %v, expected: %v, got: %v", i, c.expected, result)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user