diff --git a/cmd/chief/main.go b/cmd/chief/main.go index 5509658..86f65f0 100644 --- a/cmd/chief/main.go +++ b/cmd/chief/main.go @@ -12,6 +12,7 @@ import ( "github.com/urfave/cli" "github.com/blankon/irgsh-go/internal/config" + easypgp "github.com/blankon/irgsh-go/pkg/easygpg" artifactEndpoint "github.com/blankon/irgsh-go/internal/artifact/endpoint" artifactRepo "github.com/blankon/irgsh-go/internal/artifact/repo" @@ -62,9 +63,12 @@ func main() { } log.Println(irgshConfig.Chief.Workdir) + // EasyGPG + egpg := easypgp.EasyPGP{} + artifactHTTPEndpoint = artifactEndpoint.NewArtifactHTTPEndpoint( artifactService.NewArtifactService( - artifactRepo.NewFileRepo(irgshConfig.Chief.Workdir))) + artifactRepo.NewFileRepo(irgshConfig.Chief.Workdir, egpg))) app = cli.NewApp() app.Name = "irgsh-go" @@ -96,12 +100,14 @@ func main() { func serve() { http.HandleFunc("/", indexHandler) http.HandleFunc("/api/v1/artifacts", artifactHTTPEndpoint.GetArtifactListHandler) - http.HandleFunc("/api/v1/submit", PackageSubmitHandler) + http.HandleFunc("/api/v1/submit", artifactHTTPEndpoint.SubmitPackageHandler) http.HandleFunc("/api/v1/status", BuildStatusHandler) http.HandleFunc("/api/v1/artifact-upload", artifactUploadHandler()) http.HandleFunc("/api/v1/log-upload", logUploadHandler()) http.HandleFunc("/api/v1/build-iso", BuildISOHandler) + http.HandleFunc("/api/v2/submit", artifactHTTPEndpoint.SubmitPackageHandler) + artifactFs := http.FileServer(http.Dir(irgshConfig.Chief.Workdir + "/artifacts")) http.Handle("/artifacts/", http.StripPrefix("/artifacts/", artifactFs)) diff --git a/go.mod b/go.mod index 33c19e2..7a41148 100644 --- a/go.mod +++ b/go.mod @@ -3,24 +3,27 @@ module github.com/blankon/irgsh-go require ( github.com/BurntSushi/toml v0.3.1 // indirect github.com/RichardKnop/machinery v1.5.5 + github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/ghodss/yaml v1.0.0 github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect github.com/google/uuid v1.1.0 github.com/hpcloud/tail v1.0.0 github.com/imroc/req v0.2.3 - github.com/jinzhu/configor v1.0.0 - github.com/julienschmidt/httprouter v1.3.0 github.com/leodido/go-urn v1.1.0 // indirect github.com/manifoldco/promptui v0.3.2 - github.com/stretchr/testify v1.2.2 + github.com/nicksnyder/go-i18n v1.10.1 // indirect + github.com/stretchr/testify v1.4.0 github.com/urfave/cli v1.20.0 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + golang.org/x/tools v0.0.0-20200815165600-90abf76919f3 // indirect + gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v9 v9.27.0 gopkg.in/src-d/go-git.v4 v4.8.1 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - gopkg.in/yaml.v2 v2.2.1 - mvdan.cc/sh v2.6.4+incompatible // indirect ) go 1.13 diff --git a/go.sum b/go.sum index 6e15f6c..1e646a0 100644 --- a/go.sum +++ b/go.sum @@ -10,47 +10,66 @@ github.com/RichardKnop/machinery v1.5.5 h1:Z5Ge5nZasLcy6DyC1tevZFo9RmpMjQ4dQxKrR github.com/RichardKnop/machinery v1.5.5/go.mod h1:nZh5Q14McSl+er5moTFI5Tho1TjhAN2U0yWHEbh23Vk= github.com/RichardKnop/redsync v1.2.0 h1:gK35hR3zZkQigHKm8wOGb9MpJ9BsrW6MzxezwjTcHP0= github.com/RichardKnop/redsync v1.2.0/go.mod h1:9b8nBGAX3bE2uCfJGSnsDvF23mKyHTZzmvmj5FH3Tp0= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/gometalinter v2.0.11+incompatible h1:ENdXMllZNSVDTJUUVIzBW9CSEpntTrQa76iRsEFLX/M= github.com/alecthomas/gometalinter v2.0.11+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk= +github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4 h1:EBTWhcAX7rNQ80RLwLCpHZBBrJuzallFHnF+yMXo928= +github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/aws/aws-sdk-go v1.15.66 h1:c2ScQzjFUoD1pK+6GQzX8yMXwppIjP5Oy8ljMRr2cbo= github.com/aws/aws-sdk-go v1.15.66/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +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= github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo= github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1 h1:j3L6gSLQalDETeEg/Jg0mGY0/y/N6zI2xX1978P0Uqw= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3 h1:I4BOK3PBMjhWfQM2zPJKK7lOBGsrsvOB7kBELP33hiE= github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc h1:cJlkeAx1QYgO5N80aF5xRGstVsRQwgLR7uA2FnP1ZjY= github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -60,22 +79,20 @@ github.com/imroc/req v0.2.3/go.mod h1:J9FsaNHDTIVyW/b5r6/Df5qKEEEq2WzZKIgKSajd1A github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/configor v1.0.0 h1:F8ck+vczDAvSbsz77Mj8pttFZQJTFau1uJ3efJkHoYU= -github.com/jinzhu/configor v1.0.0/go.mod h1:xycrO0mK6seJRAHXsdyk54QgPJ20aQNpTGi5xv8jQg8= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM= github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +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/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= @@ -90,11 +107,16 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/nicksnyder/go-i18n v1.10.1 h1:isfg77E/aCD7+0lD/D00ebR2MV5vgeQ276WYyDaCRQc= +github.com/nicksnyder/go-i18n v1.10.1/go.mod h1:e4Di5xjP9oTVrC6y3C7C0HoSYXjSbhh/dU0eUV32nB4= github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/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= @@ -108,39 +130,71 @@ github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/streadway/amqp v0.0.0-20180806233856-70e15c650864 h1:Oj3PUEs+OUSYUpn35O+BE/ivHGirKixA3+vqA0Atu9A= github.com/streadway/amqp v0.0.0-20180806233856-70e15c650864/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stvp/tempredis v0.0.0-20160122230306-83f7aae7ea49 h1:aBiMfOQ47GCfoTbNcnVyph/dnUuTWN0rSqEKFq3T58Y= github.com/stvp/tempredis v0.0.0-20160122230306-83f7aae7ea49/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= +github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9 h1:vY5WqiEon0ZSTGM3ayVVi+twaHKHDFUVloaQ/wug9/c= github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9/go.mod h1:q+QjxYvZ+fpjMXqs+XEriussHjSYqeXVnAdSV1tkMYk= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro= github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +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/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 h1:x/bBzNauLQAlE3fLku/xy92Y8QwKX5HZymrMz2IiKFc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816 h1:mVFkLpejdFLXVUv9E42f3XJVfMdqd0IVLVIVLjZWn5o= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +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-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181031022657-8527f56f7107 h1:63fpDttzclb8owmRoxSaFNbnT1CG25L0Yvnhh9lU1SE= golang.org/x/oauth2 v0.0.0-20181031022657-8527f56f7107/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b h1:MQE+LT/ABUuuvEZ+YQAMSXindAdUh7slEmAkup74op4= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181122213734-04b5d21e00f1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200815165600-90abf76919f3 h1:0aScV/0rLmANzEYIhjCOi2pTvDyhZNduBUMD2q3iqs4= +golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181101000641-61ce27ee8154 h1:DqMjeNv3mOVIVXy5mVpZ+IY8VW9+1qAE1jsgNyMNB3Y= google.golang.org/api v0.0.0-20181101000641-61ce27ee8154/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= @@ -153,16 +207,22 @@ google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoA google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0 h1:dz5IJGuC2BB7qXR5AyHNwAUBhZscK2xVez7mznh72sY= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780 h1:CEBpW6C191eozfEuWdUmIAHn7lwlLxJ7HVdr2e2Tsrw= +gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA= 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/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.27.0 h1:wCg/0hk9RzcB0CYw8pYV6FiBYug1on0cpco9YZF8jqA= gopkg.in/go-playground/validator.v9 v9.27.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo= gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= +gopkg.in/src-d/go-git-fixtures.v3 v3.1.1 h1:XWW/s5W18RaJpmo1l0IYGqXKuJITWRFuA45iOf1dKJs= gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.8.1 h1:aAyBmkdE1QUUEHcP4YFCGKmsMQRAuRmUcPEQR7lOAa0= gopkg.in/src-d/go-git.v4 v4.8.1/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= @@ -172,6 +232,6 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= 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= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -mvdan.cc/sh v2.6.4+incompatible h1:eD6tDeh0pw+/TOTI1BBEryZ02rD2nMcFsgcvde7jffM= -mvdan.cc/sh v2.6.4+incompatible/go.mod h1:IeeQbZq+x2SUGBensq/jge5lLQbS3XT2ktyp3wrt4x8= diff --git a/internal/artifact/endpoint/artifact.go b/internal/artifact/endpoint/artifact.go index aa96f68..79ad27a 100644 --- a/internal/artifact/endpoint/artifact.go +++ b/internal/artifact/endpoint/artifact.go @@ -1,30 +1,12 @@ package endpoint -import ( - "net/http" - - service "github.com/blankon/irgsh-go/internal/artifact/service" - httputil "github.com/blankon/irgsh-go/pkg/httputil" -) - -// ArtifactHTTPEndpoint http endpoint for artifact -type ArtifactHTTPEndpoint struct { - service *service.ArtifactService +// SubmissionRequest request parameter +type SubmissionRequest struct { + Tarball string `json:"tarball"` } -// NewArtifactHTTPEndpoint returns new artifact instance -func NewArtifactHTTPEndpoint(service *service.ArtifactService) *ArtifactHTTPEndpoint { - return &ArtifactHTTPEndpoint{ - service: service, - } -} - -// GetArtifactListHandler get artifact -func (A *ArtifactHTTPEndpoint) GetArtifactListHandler(w http.ResponseWriter, r *http.Request) { - artifactList, err := A.service.GetArtifactList(1, 1) - if err != nil { - httputil.ResponseError("Can't get artifact", 500, w) - } - - httputil.ResponseJSON(artifactList, 200, w) +// SubmissionResponse response +type SubmissionResponse struct { + PipelineID string `json:"pipelineId"` + Jobs []string `json:"jobs"` } diff --git a/internal/artifact/endpoint/artifact_http.go b/internal/artifact/endpoint/artifact_http.go new file mode 100644 index 0000000..8fb2029 --- /dev/null +++ b/internal/artifact/endpoint/artifact_http.go @@ -0,0 +1,62 @@ +package endpoint + +import ( + "encoding/json" + "io/ioutil" + "net/http" + + service "github.com/blankon/irgsh-go/internal/artifact/service" + httputil "github.com/blankon/irgsh-go/pkg/httputil" +) + +// ArtifactHTTPEndpoint http endpoint for artifact +type ArtifactHTTPEndpoint struct { + service *service.ArtifactService +} + +// NewArtifactHTTPEndpoint returns new artifact instance +func NewArtifactHTTPEndpoint(service *service.ArtifactService) *ArtifactHTTPEndpoint { + return &ArtifactHTTPEndpoint{ + service: service, + } +} + +// GetArtifactListHandler get artifact +func (A *ArtifactHTTPEndpoint) GetArtifactListHandler(w http.ResponseWriter, r *http.Request) { + artifactList, err := A.service.GetArtifactList(1, 1) + if err != nil { + httputil.ResponseError("Can't get artifact", http.StatusInternalServerError, w) + } + + httputil.ResponseJSON(artifactList, http.StatusOK, w) +} + +// SubmitPackageHandler submit package +func (A *ArtifactHTTPEndpoint) SubmitPackageHandler(w http.ResponseWriter, r *http.Request) { + var requestParam SubmissionRequest + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + httputil.ResponseError("Can't read request body", http.StatusBadRequest, w) + } + defer r.Body.Close() + + err = json.Unmarshal(b, &requestParam) + if err != nil { + httputil.ResponseError("Can't read request body", http.StatusBadRequest, w) + } + + jobDetail, err := A.service.SubmitPackage(requestParam.Tarball) + if err != nil { + httputil.ResponseError("Can't complete the submission", http.StatusInternalServerError, w) + } + + httputil.ResponseJSON(submissionToSubmissionResponse(jobDetail), http.StatusOK, w) +} + +func submissionToSubmissionResponse(job service.Submission) SubmissionResponse { + return SubmissionResponse{ + PipelineID: job.PipelineID, + Jobs: job.Jobs, + } +} diff --git a/internal/artifact/model/artifact.go b/internal/artifact/model/artifact.go new file mode 100644 index 0000000..e993e05 --- /dev/null +++ b/internal/artifact/model/artifact.go @@ -0,0 +1,17 @@ +package model + +import "time" + +// Artifact represent artifact data +type Artifact struct { + Name string +} + +// Submission represent submission data +type Submission struct { + TaskUUID string `json:"taskUUID"` + Timestamp time.Time `json:"timestamp"` + SourceURL string `json:"sourceUrl"` + PackageURL string `json:"packageUrl"` + Tarball string `json:"tarball"` +} diff --git a/internal/artifact/repo/artifact.go b/internal/artifact/repo/artifact.go index fe6e8b1..cec6aef 100644 --- a/internal/artifact/repo/artifact.go +++ b/internal/artifact/repo/artifact.go @@ -1,19 +1,21 @@ package repo -//go:generate moq -out artifact_repo_moq.go . Repo +import ( + model "github.com/blankon/irgsh-go/internal/artifact/model" +) -// ArtifactModel represent artifact data -type ArtifactModel struct { - Name string -} +//go:generate moq -out artifact_repo_moq.go . Repo // ArtifactList list of artifacts type ArtifactList struct { TotalData int - Artifacts []ArtifactModel + Artifacts []model.Artifact } // Repo interface to operate with artifact type Repo interface { GetArtifactList(pageNum int64, rows int64) (ArtifactList, error) + PutTarballToFile(tarball *string, taskUUID string) error + ExtractSubmittedTarball(taskUUID string, deleteTarball bool) error + VerifyArtifact(taskUUID string) (bool, error) } diff --git a/internal/artifact/repo/artifact_repo_moq.go b/internal/artifact/repo/artifact_repo_moq.go index bb6f219..f82a3d4 100644 --- a/internal/artifact/repo/artifact_repo_moq.go +++ b/internal/artifact/repo/artifact_repo_moq.go @@ -7,10 +7,6 @@ import ( "sync" ) -var ( - lockRepoMockGetArtifactList sync.RWMutex -) - // Ensure, that RepoMock does implement Repo. // If this is not the case, regenerate this file with moq. var _ Repo = &RepoMock{} @@ -21,9 +17,18 @@ var _ Repo = &RepoMock{} // // // make and configure a mocked Repo // mockedRepo := &RepoMock{ +// ExtractSubmittedTarballFunc: func(taskUUID string, deleteTarball bool) error { +// panic("mock out the ExtractSubmittedTarball method") +// }, // GetArtifactListFunc: func(pageNum int64, rows int64) (ArtifactList, error) { // panic("mock out the GetArtifactList method") // }, +// PutTarballToFileFunc: func(tarball *string, taskUUID string) error { +// panic("mock out the PutTarballToFile method") +// }, +// VerifyArtifactFunc: func(taskUUID string) (bool, error) { +// panic("mock out the VerifyArtifact method") +// }, // } // // // use mockedRepo in code that requires Repo @@ -31,11 +36,27 @@ var _ Repo = &RepoMock{} // // } type RepoMock struct { + // ExtractSubmittedTarballFunc mocks the ExtractSubmittedTarball method. + ExtractSubmittedTarballFunc func(taskUUID string, deleteTarball bool) error + // GetArtifactListFunc mocks the GetArtifactList method. GetArtifactListFunc func(pageNum int64, rows int64) (ArtifactList, error) + // PutTarballToFileFunc mocks the PutTarballToFile method. + PutTarballToFileFunc func(tarball *string, taskUUID string) error + + // VerifyArtifactFunc mocks the VerifyArtifact method. + VerifyArtifactFunc func(taskUUID string) (bool, error) + // calls tracks calls to the methods. calls struct { + // ExtractSubmittedTarball holds details about calls to the ExtractSubmittedTarball method. + ExtractSubmittedTarball []struct { + // TaskUUID is the taskUUID argument value. + TaskUUID string + // DeleteTarball is the deleteTarball argument value. + DeleteTarball bool + } // GetArtifactList holds details about calls to the GetArtifactList method. GetArtifactList []struct { // PageNum is the pageNum argument value. @@ -43,7 +64,58 @@ type RepoMock struct { // Rows is the rows argument value. Rows int64 } + // PutTarballToFile holds details about calls to the PutTarballToFile method. + PutTarballToFile []struct { + // Tarball is the tarball argument value. + Tarball *string + // TaskUUID is the taskUUID argument value. + TaskUUID string + } + // VerifyArtifact holds details about calls to the VerifyArtifact method. + VerifyArtifact []struct { + // TaskUUID is the taskUUID argument value. + TaskUUID string + } } + lockExtractSubmittedTarball sync.RWMutex + lockGetArtifactList sync.RWMutex + lockPutTarballToFile sync.RWMutex + lockVerifyArtifact sync.RWMutex +} + +// ExtractSubmittedTarball calls ExtractSubmittedTarballFunc. +func (mock *RepoMock) ExtractSubmittedTarball(taskUUID string, deleteTarball bool) error { + if mock.ExtractSubmittedTarballFunc == nil { + panic("RepoMock.ExtractSubmittedTarballFunc: method is nil but Repo.ExtractSubmittedTarball was just called") + } + callInfo := struct { + TaskUUID string + DeleteTarball bool + }{ + TaskUUID: taskUUID, + DeleteTarball: deleteTarball, + } + mock.lockExtractSubmittedTarball.Lock() + mock.calls.ExtractSubmittedTarball = append(mock.calls.ExtractSubmittedTarball, callInfo) + mock.lockExtractSubmittedTarball.Unlock() + return mock.ExtractSubmittedTarballFunc(taskUUID, deleteTarball) +} + +// ExtractSubmittedTarballCalls gets all the calls that were made to ExtractSubmittedTarball. +// Check the length with: +// len(mockedRepo.ExtractSubmittedTarballCalls()) +func (mock *RepoMock) ExtractSubmittedTarballCalls() []struct { + TaskUUID string + DeleteTarball bool +} { + var calls []struct { + TaskUUID string + DeleteTarball bool + } + mock.lockExtractSubmittedTarball.RLock() + calls = mock.calls.ExtractSubmittedTarball + mock.lockExtractSubmittedTarball.RUnlock() + return calls } // GetArtifactList calls GetArtifactListFunc. @@ -58,9 +130,9 @@ func (mock *RepoMock) GetArtifactList(pageNum int64, rows int64) (ArtifactList, PageNum: pageNum, Rows: rows, } - lockRepoMockGetArtifactList.Lock() + mock.lockGetArtifactList.Lock() mock.calls.GetArtifactList = append(mock.calls.GetArtifactList, callInfo) - lockRepoMockGetArtifactList.Unlock() + mock.lockGetArtifactList.Unlock() return mock.GetArtifactListFunc(pageNum, rows) } @@ -75,8 +147,74 @@ func (mock *RepoMock) GetArtifactListCalls() []struct { PageNum int64 Rows int64 } - lockRepoMockGetArtifactList.RLock() + mock.lockGetArtifactList.RLock() calls = mock.calls.GetArtifactList - lockRepoMockGetArtifactList.RUnlock() + mock.lockGetArtifactList.RUnlock() + return calls +} + +// PutTarballToFile calls PutTarballToFileFunc. +func (mock *RepoMock) PutTarballToFile(tarball *string, taskUUID string) error { + if mock.PutTarballToFileFunc == nil { + panic("RepoMock.PutTarballToFileFunc: method is nil but Repo.PutTarballToFile was just called") + } + callInfo := struct { + Tarball *string + TaskUUID string + }{ + Tarball: tarball, + TaskUUID: taskUUID, + } + mock.lockPutTarballToFile.Lock() + mock.calls.PutTarballToFile = append(mock.calls.PutTarballToFile, callInfo) + mock.lockPutTarballToFile.Unlock() + return mock.PutTarballToFileFunc(tarball, taskUUID) +} + +// PutTarballToFileCalls gets all the calls that were made to PutTarballToFile. +// Check the length with: +// len(mockedRepo.PutTarballToFileCalls()) +func (mock *RepoMock) PutTarballToFileCalls() []struct { + Tarball *string + TaskUUID string +} { + var calls []struct { + Tarball *string + TaskUUID string + } + mock.lockPutTarballToFile.RLock() + calls = mock.calls.PutTarballToFile + mock.lockPutTarballToFile.RUnlock() + return calls +} + +// VerifyArtifact calls VerifyArtifactFunc. +func (mock *RepoMock) VerifyArtifact(taskUUID string) (bool, error) { + if mock.VerifyArtifactFunc == nil { + panic("RepoMock.VerifyArtifactFunc: method is nil but Repo.VerifyArtifact was just called") + } + callInfo := struct { + TaskUUID string + }{ + TaskUUID: taskUUID, + } + mock.lockVerifyArtifact.Lock() + mock.calls.VerifyArtifact = append(mock.calls.VerifyArtifact, callInfo) + mock.lockVerifyArtifact.Unlock() + return mock.VerifyArtifactFunc(taskUUID) +} + +// VerifyArtifactCalls gets all the calls that were made to VerifyArtifact. +// Check the length with: +// len(mockedRepo.VerifyArtifactCalls()) +func (mock *RepoMock) VerifyArtifactCalls() []struct { + TaskUUID string +} { + var calls []struct { + TaskUUID string + } + mock.lockVerifyArtifact.RLock() + calls = mock.calls.VerifyArtifact + mock.lockVerifyArtifact.RUnlock() return calls } diff --git a/internal/artifact/repo/file_impl.go b/internal/artifact/repo/file_impl.go index cf2b28a..2812466 100644 --- a/internal/artifact/repo/file_impl.go +++ b/internal/artifact/repo/file_impl.go @@ -1,19 +1,29 @@ package repo import ( + "encoding/base64" + "io/ioutil" + "os" "path/filepath" "strings" + + model "github.com/blankon/irgsh-go/internal/artifact/model" + + easypgp "github.com/blankon/irgsh-go/pkg/easygpg" + tar "github.com/blankon/irgsh-go/pkg/tar" ) // FileRepo interface with file system based artifact information type FileRepo struct { Workdir string + egpg easypgp.IEasyPGP } // NewFileRepo create new instance -func NewFileRepo(Workdir string) *FileRepo { +func NewFileRepo(Workdir string, egpg easypgp.IEasyPGP) *FileRepo { return &FileRepo{ Workdir: Workdir, + egpg: egpg, } } @@ -25,16 +35,64 @@ func (A *FileRepo) GetArtifactList(pageNum int64, rows int64) (artifactsList Art return } - artifactsList.Artifacts = []ArtifactModel{} + artifactsList.Artifacts = []model.Artifact{} for _, file := range files { - artifactsList.Artifacts = append(artifactsList.Artifacts, ArtifactModel{Name: getArtifactFilename(file)}) + artifactsList.Artifacts = append(artifactsList.Artifacts, model.Artifact{Name: getArtifactFilename(file)}) } artifactsList.TotalData = len(artifactsList.Artifacts) return } +// PutTarballToFile not it's just general function to write string of base64 to file +func (A *FileRepo) PutTarballToFile(tarball *string, taskUUID string) (err error) { + + // create artifact directory + submissionDir := A.generateSubmissionPath(taskUUID) + err = os.MkdirAll(submissionDir, 0744) + if err != nil { + return + } + + // write the tarball + filePath := submissionDir + "/" + taskUUID + ".tar.gz" + buff, err := base64.StdEncoding.DecodeString(*tarball) + if err != nil { + return + } + err = ioutil.WriteFile(filePath, buff, 0744) + if err != nil { + return + } + + return +} + +// ExtractSubmittedTarball extract tarball package +func (A *FileRepo) ExtractSubmittedTarball(taskUUID string, deleteTarball bool) (err error) { + submissionDir := A.generateSubmissionPath(taskUUID) + filePath := submissionDir + "/" + taskUUID + ".tar.gz" + + err = tar.ExtractTarball(filePath, submissionDir) + if err != nil { + return + } + + err = os.Remove(filePath) + + return +} + +// VerifyArtifact using provided signature +func (A *FileRepo) VerifyArtifact(taskUUID string) (ok bool, err error) { + artifactDir := A.generateSubmissionPath(taskUUID) + + ok, err = A.egpg.Verify(artifactDir, "*.dsc") + + return +} + func getArtifactFilename(filePath string) (fileName string) { path := strings.Split(filePath, "artifacts/") if len(path) > 1 { @@ -42,3 +100,8 @@ func getArtifactFilename(filePath string) (fileName string) { } return } + +func (A *FileRepo) generateSubmissionPath(taskUUID string) (path string) { + path = A.Workdir + "/submissions/" + taskUUID + return +} diff --git a/internal/artifact/repo/file_impl_test.go b/internal/artifact/repo/file_impl_test.go index 0296607..1304ef4 100644 --- a/internal/artifact/repo/file_impl_test.go +++ b/internal/artifact/repo/file_impl_test.go @@ -4,6 +4,8 @@ import ( "os" "reflect" "testing" + + model "github.com/blankon/irgsh-go/internal/artifact/model" ) func TestMain(m *testing.M) { @@ -15,7 +17,6 @@ func TestMain(m *testing.M) { file002.Close() exitVal := m.Run() - // time.Sleep(2 * time.Second) // clean up test directory os.RemoveAll("./artifacts") @@ -81,9 +82,9 @@ func TestFileRepo_GetArtifactList(t *testing.T) { }, wantArtifactsList: ArtifactList{ TotalData: 2, - Artifacts: []ArtifactModel{ - ArtifactModel{Name: "file001"}, - ArtifactModel{Name: "file002"}, + Artifacts: []model.Artifact{ + {Name: "file001"}, + {Name: "file002"}, }, }, }, @@ -104,3 +105,39 @@ func TestFileRepo_GetArtifactList(t *testing.T) { }) } } + +func TestFileRepo_generateSubmissionPath(t *testing.T) { + type fields struct { + Workdir string + } + type args struct { + taskUUID string + } + tests := []struct { + name string + fields fields + args args + wantPath string + }{ + { + name: "empty", + wantPath: "/submissions/", + }, + { + name: "complete", + fields: fields{Workdir: "/home/workingdir"}, + args: args{taskUUID: "randomnumberhere"}, + wantPath: "/home/workingdir/submissions/randomnumberhere", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + A := &FileRepo{ + Workdir: tt.fields.Workdir, + } + if gotPath := A.generateSubmissionPath(tt.args.taskUUID); gotPath != tt.wantPath { + t.Errorf("FileRepo.generateSubmissionPath() = %v, want %v", gotPath, tt.wantPath) + } + }) + } +} diff --git a/internal/artifact/service/artifact.go b/internal/artifact/service/artifact.go index fa80466..73f7bc5 100644 --- a/internal/artifact/service/artifact.go +++ b/internal/artifact/service/artifact.go @@ -1,18 +1,15 @@ package service import ( + "github.com/RichardKnop/machinery/v1" + artifactModel "github.com/blankon/irgsh-go/internal/artifact/model" artifactRepo "github.com/blankon/irgsh-go/internal/artifact/repo" ) -// ArtifactItem representation of artifact data -type ArtifactItem struct { - Name string `json:"name"` -} - // ArtifactList list of artifact type ArtifactList struct { TotalData int - Artifacts []ArtifactItem `json:"artifacts"` + Artifacts []artifactModel.Artifact `json:"artifacts"` } // Service interface for artifact service @@ -22,7 +19,8 @@ type Service interface { // ArtifactService implement service type ArtifactService struct { - repo artifactRepo.Repo + repo artifactRepo.Repo + machineryServer *machinery.Server } // NewArtifactService return artifact service instance @@ -41,10 +39,10 @@ func (A *ArtifactService) GetArtifactList(pageNum int64, rows int64) (list Artif } list.TotalData = alist.TotalData - list.Artifacts = []ArtifactItem{} + list.Artifacts = []artifactModel.Artifact{} for _, a := range alist.Artifacts { - list.Artifacts = append(list.Artifacts, ArtifactItem{Name: a.Name}) + list.Artifacts = append(list.Artifacts, artifactModel.Artifact{Name: a.Name}) } return diff --git a/internal/artifact/service/artifactSubmission.go b/internal/artifact/service/artifactSubmission.go new file mode 100644 index 0000000..a6626e2 --- /dev/null +++ b/internal/artifact/service/artifactSubmission.go @@ -0,0 +1,86 @@ +package service + +import ( + "encoding/json" + "errors" + "time" + + "github.com/RichardKnop/machinery/v1/tasks" + "github.com/google/uuid" + + artifactModel "github.com/blankon/irgsh-go/internal/artifact/model" +) + +// Submission job detail of the submission +type Submission struct { + PipelineID string + Jobs []string +} + +// SubmitPackage submit package +func (A *ArtifactService) SubmitPackage(tarball string) (submission Submission, err error) { + submittedJob := artifactModel.Submission{ + Timestamp: time.Now(), + } + + submittedJob.TaskUUID = generateSubmissionUUID(submittedJob.Timestamp) + + err = A.repo.PutTarballToFile(&tarball, submittedJob.TaskUUID) + if err != nil { + return submission, errors.New("Can't store tarball " + err.Error()) + } + + err = A.repo.ExtractSubmittedTarball(submittedJob.TaskUUID, true) + if err != nil { + return submission, errors.New("Can't extract tarball " + err.Error()) + } + + // verify the package signature + isVerified, err := A.repo.VerifyArtifact(submittedJob.TaskUUID) + if err != nil || !isVerified { + return submission, errors.New("Can't verify tarball") + } + + submission.PipelineID = submittedJob.TaskUUID + + // TODO : we haven't delete the tarball here + // still thinking how to structure the repo and service + + return +} + +func generateSubmissionUUID(timestamp time.Time) string { + return timestamp.Format("2006-01-02-150405") + "_" + uuid.New().String() +} + +// sendSubmitPackageTasks send task to the machinery +func (A *ArtifactService) sendSubmitPackageTasks(submittedJob artifactModel.Submission) (err error) { + buildTaskPayload, err := json.Marshal(submittedJob) + if err != nil { + return errors.New("Can't send chain " + err.Error()) + } + + buildTask := tasks.Signature{ + Name: "build", + UUID: submittedJob.TaskUUID, + Args: []tasks.Arg{ + { + Type: "string", + Value: string(buildTaskPayload), + }, + }, + } + + repoTask := tasks.Signature{ + Name: "repo", + UUID: submittedJob.TaskUUID, + } + + chain, _ := tasks.NewChain(&buildTask, &repoTask) + _, err = A.machineryServer.SendChain(chain) + if err != nil { + return errors.New("Can't send chain " + err.Error()) + } + + return +} diff --git a/internal/artifact/service/artifact_test.go b/internal/artifact/service/artifact_test.go index df16842..b6f57e2 100644 --- a/internal/artifact/service/artifact_test.go +++ b/internal/artifact/service/artifact_test.go @@ -3,78 +3,14 @@ package service import ( "fmt" "reflect" + "strings" "testing" + "time" + artifactModel "github.com/blankon/irgsh-go/internal/artifact/model" artifactRepo "github.com/blankon/irgsh-go/internal/artifact/repo" ) -// func TestArtifactService_GetArtifactList(t *testing.T) { -// type fields struct { -// repo artifactRepo.Repo -// } -// type args struct { -// pageNum int64 -// rows int64 -// } -// tests := []struct { -// name string -// fields fields -// args args -// wantItems []ArtifactItem -// wantErr bool -// }{ -// { -// name: "empty", -// fields: fields{ -// repo: &artifactRepo.RepoMock{ -// GetArtifactListFunc: func(pageNum int64, rows int64) (m []repo.ArtifactModel, e error) { -// return -// }, -// }, -// }, -// }, -// { -// name: "error", -// fields: fields{ -// repo: &artifactRepo.RepoMock{ -// GetArtifactListFunc: func(pageNum int64, rows int64) (m []repo.ArtifactModel, e error) { -// return m, fmt.Errorf("") -// }, -// }, -// }, -// wantErr: true, -// }, -// { -// name: "2 items", -// fields: fields{ -// repo: &artifactRepo.RepoMock{ -// GetArtifactListFunc: func(pageNum int64, rows int64) (m []repo.ArtifactModel, e error) { -// m = append(m, repo.ArtifactModel{Name: "test1"}) -// m = append(m, repo.ArtifactModel{Name: "test2"}) -// return -// }, -// }, -// }, -// wantItems: []ArtifactItem{ArtifactItem{Name: "test1"}, ArtifactItem{Name: "test2"}}, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// A := &ArtifactService{ -// repo: tt.fields.repo, -// } -// gotItems, err := A.GetArtifactList(tt.args.pageNum, tt.args.rows) -// if (err != nil) != tt.wantErr { -// t.Errorf("ArtifactService.GetArtifactList() error = %v, wantErr %v", err, tt.wantErr) -// return -// } -// if !reflect.DeepEqual(gotItems, tt.wantItems) { -// t.Errorf("ArtifactService.GetArtifactList() = %v, want %v", gotItems, tt.wantItems) -// } -// }) -// } -// } - func TestNewArtifactService(t *testing.T) { type args struct { repo artifactRepo.Repo @@ -122,7 +58,7 @@ func TestArtifactService_GetArtifactList(t *testing.T) { }, }, }, - wantArtifacts: ArtifactList{TotalData: 0, Artifacts: []ArtifactItem{}}, + wantArtifacts: ArtifactList{TotalData: 0, Artifacts: []artifactModel.Artifact{}}, }, { name: "error", @@ -140,8 +76,8 @@ func TestArtifactService_GetArtifactList(t *testing.T) { fields: fields{ repo: &artifactRepo.RepoMock{ GetArtifactListFunc: func(pageNum int64, rows int64) (l artifactRepo.ArtifactList, e error) { - l.Artifacts = append(l.Artifacts, artifactRepo.ArtifactModel{Name: "test1"}) - l.Artifacts = append(l.Artifacts, artifactRepo.ArtifactModel{Name: "test2"}) + l.Artifacts = append(l.Artifacts, artifactModel.Artifact{Name: "test1"}) + l.Artifacts = append(l.Artifacts, artifactModel.Artifact{Name: "test2"}) l.TotalData = 2 return }, @@ -149,7 +85,7 @@ func TestArtifactService_GetArtifactList(t *testing.T) { }, wantArtifacts: ArtifactList{ TotalData: 2, - Artifacts: []ArtifactItem{ArtifactItem{Name: "test1"}, ArtifactItem{Name: "test2"}}, + Artifacts: []artifactModel.Artifact{{Name: "test1"}, {Name: "test2"}}, }, }, } @@ -169,3 +105,28 @@ func TestArtifactService_GetArtifactList(t *testing.T) { }) } } + +func Test_generateSubmissionUUID(t *testing.T) { + type args struct { + timestamp time.Time + } + tests := []struct { + name string + args args + want string + }{ + { + name: "14 november 2020", + args: args{ + timestamp: time.Date(2020, 11, 14, 5, 0, 0, 0, time.Now().Location()), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := generateSubmissionUUID(tt.args.timestamp); !strings.HasPrefix(got, "2020-11-14-050000_") { + t.Errorf("generateSubmissionUUID() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/easygpg/gpg.go b/pkg/easygpg/gpg.go new file mode 100644 index 0000000..510b44c --- /dev/null +++ b/pkg/easygpg/gpg.go @@ -0,0 +1,37 @@ +package easypgp + +import ( + "bytes" + "errors" + "os/exec" +) + +// package EasyPGP provide ready to use gpg interface + +// IEasyPGP ... +type IEasyPGP interface { + Verify(dirPath, fileName string) (bool, error) +} + +const gpgCommand string = "gpg --verify " + +// EasyPGP provide easy to use gpg +type EasyPGP struct { +} + +// Verify provided signature +func (E EasyPGP) Verify(dirPath, fileName string) (ok bool, err error) { + var stdErr bytes.Buffer + cmd := exec.Command("sh", "-c", gpgCommand+fileName) + cmd.Dir = dirPath + cmd.Stderr = &stdErr + err = cmd.Run() + + if err != nil { + err = errors.New(stdErr.String()) + } else { + ok = true + } + + return +} diff --git a/pkg/easygpg/gpg_test.go b/pkg/easygpg/gpg_test.go new file mode 100644 index 0000000..30a8728 --- /dev/null +++ b/pkg/easygpg/gpg_test.go @@ -0,0 +1,44 @@ +package easypgp + +import "testing" + +func TestEasyPGP_Verify(t *testing.T) { + type fields struct { + gpgCmd string + } + type args struct { + dirPath string + fileName string + } + tests := []struct { + name string + fields fields + args args + wantOk bool + wantErr bool + }{ + { + name: "piko", + args: args{dirPath: "/home/gio/Downloads/", fileName: "piko.dsc"}, + wantOk: true, + }, + { + name: "wildcard", + args: args{dirPath: "/home/gio/Downloads/", fileName: "*.dsc"}, + wantOk: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + E := EasyPGP{} + gotOk, err := E.Verify(tt.args.dirPath, tt.args.fileName) + if (err != nil) != tt.wantErr { + t.Errorf("EasyPGP.Verify() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotOk != tt.wantOk { + t.Errorf("EasyPGP.Verify() = %v, want %v", gotOk, tt.wantOk) + } + }) + } +} diff --git a/pkg/tar/untar.go b/pkg/tar/untar.go new file mode 100644 index 0000000..c47cb2e --- /dev/null +++ b/pkg/tar/untar.go @@ -0,0 +1,162 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// copied from https://github.com/golang/build/blob/master/internal/untar/untar.go + +package tar + +import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" + "log" + "os" + "path" + "path/filepath" + "strings" + "time" +) + +// TODO(bradfitz): this was copied from x/build/cmd/buildlet/buildlet.go +// but there were some buildlet-specific bits in there, so the code is +// forked for now. Unfork and add some opts arguments here, so the +// buildlet can use this code somehow. + +// Untar reads the gzip-compressed tar file from r and writes it into dir. +func Untar(r io.Reader, dir string) error { + return untar(r, dir) +} + +func untar(r io.Reader, dir string) (err error) { + t0 := time.Now() + nFiles := 0 + madeDir := map[string]bool{} + defer func() { + td := time.Since(t0) + if err == nil { + log.Printf("extracted tarball into %s: %d files, %d dirs (%v)", dir, nFiles, len(madeDir), td) + } else { + log.Printf("error extracting tarball into %s after %d files, %d dirs, %v: %v", dir, nFiles, len(madeDir), td, err) + } + }() + zr, err := gzip.NewReader(r) + if err != nil { + return fmt.Errorf("requires gzip-compressed body: %v", err) + } + tr := tar.NewReader(zr) + loggedChtimesError := false + for { + f, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + log.Printf("tar reading error: %v", err) + return fmt.Errorf("tar error: %v", err) + } + if !validRelPath(f.Name) { + return fmt.Errorf("tar contained invalid name error %q", f.Name) + } + rel := filepath.FromSlash(f.Name) + abs := filepath.Join(dir, rel) + + fi := f.FileInfo() + mode := fi.Mode() + switch { + case mode.IsRegular(): + // Make the directory. This is redundant because it should + // already be made by a directory entry in the tar + // beforehand. Thus, don't check for errors; the next + // write will fail with the same error. + dir := filepath.Dir(abs) + if !madeDir[dir] { + if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil { + return err + } + madeDir[dir] = true + } + wf, err := os.OpenFile(abs, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm()) + if err != nil { + return err + } + n, err := io.Copy(wf, tr) + if closeErr := wf.Close(); closeErr != nil && err == nil { + err = closeErr + } + if err != nil { + return fmt.Errorf("error writing to %s: %v", abs, err) + } + if n != f.Size { + return fmt.Errorf("only wrote %d bytes to %s; expected %d", n, abs, f.Size) + } + modTime := f.ModTime + if modTime.After(t0) { + // Clamp modtimes at system time. See + // golang.org/issue/19062 when clock on + // buildlet was behind the gitmirror server + // doing the git-archive. + modTime = t0 + } + if !modTime.IsZero() { + if err := os.Chtimes(abs, modTime, modTime); err != nil && !loggedChtimesError { + // benign error. Gerrit doesn't even set the + // modtime in these, and we don't end up relying + // on it anywhere (the gomote push command relies + // on digests only), so this is a little pointless + // for now. + log.Printf("error changing modtime: %v (further Chtimes errors suppressed)", err) + loggedChtimesError = true // once is enough + } + } + nFiles++ + case mode.IsDir(): + if err := os.MkdirAll(abs, 0755); err != nil { + return err + } + madeDir[abs] = true + default: + return fmt.Errorf("tar file entry %s contained unsupported file type %v", f.Name, mode) + } + } + return nil +} + +func validRelativeDir(dir string) bool { + if strings.Contains(dir, `\`) || path.IsAbs(dir) { + return false + } + dir = path.Clean(dir) + if strings.HasPrefix(dir, "../") || strings.HasSuffix(dir, "/..") || dir == ".." { + return false + } + return true +} + +func validRelPath(p string) bool { + if p == "" || strings.Contains(p, `\`) || strings.HasPrefix(p, "/") || strings.Contains(p, "../") { + return false + } + return true +} + +// ExtractTarball the straighforward way to use untar (wejick) +func ExtractTarball(filePath, dir string) (err error) { + tarballFile, err := os.Open(filePath) + if err != nil { + return + } + defer tarballFile.Close() + + var tarballReader io.ReadCloser = tarballFile + + err = Untar(tarballReader, dir) + if err != nil { + return + } + + tarballReader.Close() + + return +}