Browse Source

提交代码,解决冲突。

Signed-off-by: zouap <zouap@pcl.ac.cn>
tags/v1.22.3.2^2
zouap 3 years ago
parent
commit
78ce5f5e1b
100 changed files with 27104 additions and 769 deletions
  1. +3
    -0
      README.md
  2. +0
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/.keep
  3. +0
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/.keep 3
  4. +2317
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css
  5. BIN
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.eot
  6. +1
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.glyph.json
  7. +2319
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.less
  8. +6835
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.svg
  9. +11356
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.symbol.svg
  10. BIN
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.ttf
  11. BIN
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.woff
  12. BIN
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.woff2
  13. +157
    -16
      custom/public/css/git.openi.css
  14. +13
    -0
      custom/public/swiper/swiper-bundle.min.css
  15. +14
    -0
      custom/public/swiper/swiper-bundle.min.js
  16. +3
    -1
      go.mod
  17. +9
    -41
      go.sum
  18. +19
    -0
      models/action.go
  19. +13
    -0
      models/attachment.go
  20. +44
    -4
      models/cloudbrain.go
  21. +13
    -0
      models/error.go
  22. +8
    -0
      models/models.go
  23. +51
    -0
      models/repo.go
  24. +163
    -0
      models/repo_tag.go
  25. +5
    -2
      models/repo_watch.go
  26. +134
    -53
      models/user_business_analysis.go
  27. +267
    -0
      models/user_business_struct.go
  28. +4
    -0
      modules/auth/org.go
  29. +148
    -12
      modules/cloudbrain/cloudbrain.go
  30. +6
    -0
      modules/context/context.go
  31. +8
    -0
      modules/context/repo.go
  32. +13
    -16
      modules/modelarts/modelarts.go
  33. +3
    -3
      modules/modelarts/resty.go
  34. +10
    -2
      modules/repository/elk_pagedata.go
  35. +24
    -8
      modules/setting/setting.go
  36. +4
    -0
      modules/storage/local.go
  37. +28
    -0
      modules/storage/minio.go
  38. +1
    -0
      modules/storage/storage.go
  39. +10
    -0
      modules/util/util.go
  40. +46
    -1
      options/locale/locale_en-US.ini
  41. +48
    -1
      options/locale/locale_zh-CN.ini
  42. +5
    -0
      package-lock.json
  43. +1
    -0
      package.json
  44. +442
    -0
      public/home/home.js
  45. +13
    -10
      routers/actionnotification.go
  46. +8
    -2
      routers/api/v1/api.go
  47. +6
    -11
      routers/api/v1/repo/modelarts.go
  48. +48
    -9
      routers/home.go
  49. +87
    -0
      routers/notice/notice.go
  50. +8
    -0
      routers/org/home.go
  51. +90
    -0
      routers/org/tag.go
  52. +49
    -7
      routers/repo/ai_model_manage.go
  53. +52
    -8
      routers/repo/blame.go
  54. +158
    -79
      routers/repo/cloudbrain.go
  55. +5
    -0
      routers/repo/issue.go
  56. +160
    -74
      routers/repo/modelarts.go
  57. +126
    -0
      routers/repo/user_data_analysis.go
  58. +13
    -7
      routers/routes/routes.go
  59. +1
    -2
      services/repository/repository.go
  60. +5
    -0
      services/socketwrap/client.go
  61. +46
    -11
      services/socketwrap/clientManager.go
  62. +7
    -0
      templates/base/footer_content.tmpl
  63. +6
    -0
      templates/base/footer_content_fluid.tmpl
  64. +44
    -2
      templates/base/head.tmpl
  65. +43
    -0
      templates/base/head_fluid.tmpl
  66. +13
    -10
      templates/base/head_home.tmpl
  67. +10
    -0
      templates/base/head_navbar.tmpl
  68. +8
    -0
      templates/base/head_navbar_fluid.tmpl
  69. +8
    -0
      templates/base/head_navbar_home.tmpl
  70. +8
    -0
      templates/base/head_navbar_pro.tmpl
  71. +44
    -0
      templates/base/head_pro.tmpl
  72. +1
    -1
      templates/base/paginate.tmpl
  73. +13
    -13
      templates/explore/repo_list.tmpl
  74. +1
    -1
      templates/explore/repo_orgtop.tmpl
  75. +1
    -0
      templates/explore/repo_search.tmpl
  76. +132
    -192
      templates/home.tmpl
  77. +5
    -4
      templates/org/home.tmpl
  78. +3
    -2
      templates/org/member/members.tmpl
  79. +37
    -5
      templates/org/navber.tmpl
  80. +319
    -0
      templates/org/select_pro.tmpl
  81. +3
    -3
      templates/org/team/teams.tmpl
  82. +20
    -3
      templates/repo/cloudbrain/new.tmpl
  83. +147
    -46
      templates/repo/debugjob/index.tmpl
  84. +3
    -3
      templates/repo/header.tmpl
  85. +1
    -0
      templates/repo/issue/list.tmpl
  86. +6
    -24
      templates/repo/modelarts/trainjob/index.tmpl
  87. +142
    -8
      templates/repo/modelarts/trainjob/show.tmpl
  88. +18
    -6
      templates/repo/modelmanage/index.tmpl
  89. +265
    -66
      templates/repo/modelmanage/showinfo.tmpl
  90. +12
    -0
      vendor/github.com/elliotchance/orderedmap/.editorconfig
  91. +1
    -0
      vendor/github.com/elliotchance/orderedmap/.gitignore
  92. +9
    -0
      vendor/github.com/elliotchance/orderedmap/.travis.yml
  93. +21
    -0
      vendor/github.com/elliotchance/orderedmap/LICENSE
  94. +102
    -0
      vendor/github.com/elliotchance/orderedmap/README.md
  95. +33
    -0
      vendor/github.com/elliotchance/orderedmap/element.go
  96. +5
    -0
      vendor/github.com/elliotchance/orderedmap/go.mod
  97. +15
    -0
      vendor/github.com/elliotchance/orderedmap/go.sum
  98. +150
    -0
      vendor/github.com/elliotchance/orderedmap/orderedmap.go
  99. +9
    -0
      vendor/github.com/patrickmn/go-cache/CONTRIBUTORS
  100. +19
    -0
      vendor/github.com/patrickmn/go-cache/LICENSE

+ 3
- 0
README.md View File

@@ -46,3 +46,6 @@
- 点击[这里](https://git.openi.org.cn/OpenI/aiforge/issues)在线提交问题(点击页面右上角绿色按钮**创建任务**) - 点击[这里](https://git.openi.org.cn/OpenI/aiforge/issues)在线提交问题(点击页面右上角绿色按钮**创建任务**)
- 加入微信群实时交流,获得进一步的支持 - 加入微信群实时交流,获得进一步的支持
<img src="https://git.openi.org.cn/OpenI/aiforge/wiki/raw/img/wechatgroup.jpg" width=200px /> <img src="https://git.openi.org.cn/OpenI/aiforge/wiki/raw/img/wechatgroup.jpg" width=200px />

## 启智社区小白训练营:
- 结合案例给大家详细讲解如何使用社区平台,帮助无技术背景的小白成长为启智社区达人 (https://git.openi.org.cn/zeizei/OpenI_Learning)

+ 0
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/.keep View File


+ 0
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/.keep 3 View File


+ 2317
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css
File diff suppressed because it is too large
View File


BIN
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.eot View File


+ 1
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.glyph.json
File diff suppressed because it is too large
View File


+ 2319
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.less
File diff suppressed because it is too large
View File


+ 6835
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.svg
File diff suppressed because it is too large
View File


+ 11356
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.symbol.svg
File diff suppressed because it is too large
View File


BIN
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.ttf View File


BIN
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.woff View File


BIN
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.woff2 View File


+ 157
- 16
custom/public/css/git.openi.css View File

@@ -24,11 +24,27 @@
.am-pt-20{ padding-top: 2.0rem !important;} .am-pt-20{ padding-top: 2.0rem !important;}
.am-pt-30{ padding-top: 3.0rem !important;} .am-pt-30{ padding-top: 3.0rem !important;}
.am-pl-30{ padding-left: 3.0rem !important;} .am-pl-30{ padding-left: 3.0rem !important;}
.am-pl-50{ padding-left: 5.0em !important;}
.am-ml-10{ margin-left: 1.0rem !important;}
.am-ml-30{ margin-left: 3.0rem !important;} .am-ml-30{ margin-left: 3.0rem !important;}
.am-pr-30{ padding-right: 3.0rem !important;} .am-pr-30{ padding-right: 3.0rem !important;}
.am-mr-30{ margin-right: 3.0rem !important;} .am-mr-30{ margin-right: 3.0rem !important;}
.am-lh-18{ line-height: 1.8em;} .am-lh-18{ line-height: 1.8em;}


.nowrap{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.nowrap-2 {
max-height: 2.837em;
line-height: 1.4285em;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}

.opacity5{ opacity:0.5;} .opacity5{ opacity:0.5;}
.radius15{ border-radius:1.5rem !important; } .radius15{ border-radius:1.5rem !important; }
.radius10{ border-radius:1.0rem !important; } .radius10{ border-radius:1.0rem !important; }
@@ -42,12 +58,15 @@
box-shadow: 0 2px 4px 0 rgba(34,36,38,.3); box-shadow: 0 2px 4px 0 rgba(34,36,38,.3);
} }


.ui.blue {
color: #0366d6;
}


.ui.secondary.hometop.segment{ .ui.secondary.hometop.segment{
background: #DFE9F0; background: #DFE9F0;
padding-top: 0; padding-top: 0;
border: none; border: none;
margin-bottom: 90px;
margin-bottom: 11em;
} }
.ui.secondary.hometop.segment #navbar{ .ui.secondary.hometop.segment #navbar{
z-index: 10; z-index: 10;
@@ -68,6 +87,7 @@
.homebanner{ .homebanner{
position: relative; position: relative;
padding: 100px 32px 80px; padding: 100px 32px 80px;
padding-bottom: 0;
z-index: 9; z-index: 9;
} }
.homebanner .ui.header .sub.header{ .homebanner .ui.header .sub.header{
@@ -75,10 +95,15 @@
} }
.bannerpic{ .bannerpic{
position: absolute; position: absolute;
right: 50px;
right: 0px;
bottom: -64px; bottom: -64px;
width: 560px; width: 560px;
z-index: 6;
}
.homebanner .ui.button{
font-weight: normal;
} }

.ui[class*="very padded"].segment.i-code{ .ui[class*="very padded"].segment.i-code{
padding-left: 6.0rem; padding-left: 6.0rem;
} }
@@ -115,25 +140,141 @@
.i-env .ui.cards>.card>.content{ .i-env .ui.cards>.card>.content{
border-top: none; border-top: none;
} }
.leftline01{

#homenews{
position: relative;
z-index: 9;
bottom: -6em;
}
#homenews > p{
color: #BBBBBB;
margin-left: 2.3em;
}
.homenews{
border-radius: 2em;
background-color: rgba(16, 16, 16, .9);
position: relative;
padding-left: 2.3em !important;
}
.homeorg, .homepro, .homemodel, .i-env{
position: relative;
padding-bottom: 5em;
}
.homenews::before{
content: '';
position: absolute; position: absolute;
left: 3.0rem;
left: 3em;
top: 0; top: 0;
bottom: 0; bottom: 0;
border-left: 2px solid #505559;
border-bottom: 2px solid #505559;
border-radius: 0 0 0 2.0rem;
width: 2.0rem;
background-color: rgba(105, 192, 255, .4);
width: 2px;
}
.homenews .time-since{
padding-left: 1em;
color: #888888;
}
.homenews a{
color: #69C0FF;
} }
.leftline02{
.homenews .ui.list>.item>.content{
color: #E8E8E8;
line-height: 1.8em;
width: calc(100% - 3.25em) !important;
}
.homenews .ui.list>.item{
padding: 0;
}
.newslist{
height: 325px;
overflow: hidden;
}

.leftline01, .leftline03, .leftline04{
position: absolute; position: absolute;
left: 5rem;
top: calc(-5.0rem - 2px);
border-top: 2px solid #505559;
border-right: 2px solid #505559;
border-radius: 0 2.0rem 0 0;
width: 17.5rem;
height: 6.0rem;
width: 5em;
border-radius: 0 0 0 4.0em;
border-left: 2px solid #3291F8;
border-bottom: 2px solid #3291F8;
top: -5em;
bottom: 0;
left: 2em;
z-index: 6;
}
.leftline02, .leftline02-2 {
position: absolute;
left: 7.0em;
top: -2px;
bottom: 2px;
height: auto;
border-top: 2px solid #3291F8;
border-right: 2px solid #3291F8;
border-bottom: 2px solid #3291F8;
border-radius: 0 4.0em 4.0em 0;
width: 10em;
z-index: 6;
}
.leftline03{
border-radius: 4.0em 0 0 0;
border-top: 2px solid #3291F8;
border-bottom:none;
top: -2.0em;
}
.leftline02-2{
border-color: rgba(105, 192, 255, .4);
width: 7em;
z-index: 5;
}
.leftline04{
border-radius: 0;
border-top: none;
border-bottom: none;
}

.homeorg-tit{
padding-left: 5em !important;
}
.homeorg-tit::after{
content: '';
position: absolute;
width: 1.6em;
height: 1.6em;
background-color: #FFF;
border: 2px solid #3291F8;
left: 2.3em;
top: 1.3em;
border-radius: 1em;
z-index: 9;
}
.homeorg-list .card{
background-image: linear-gradient(#FFF, #FFF 60%, #DFF0EF) !important;
box-shadow: none !important;
}
.homeorg-list .card .ui.small.header .content{
width: calc(100% - 3.25em);
}
.homepro-list{
position: relative;
z-index: 9;
padding: 1.0em 1.0em 3.0em;
overflow: hidden;
}
.homepro-list .ui.card{
border-radius: 15px;
background-color: #FFF;
box-shadow: 0px 5px 10px 0px rgba(105, 192, 255, 30);
border: 1px solid rgba(105, 192, 255, 40);
min-height: 10.8em;
}
.homepro-list .ui.card>.content>.header{
line-height: 40px !important;
}

.homepro-list .swiper-pagination-bullet-active{
width: 40px;
border-radius: 4px;
}
.i-env > div{
position: relative;
} }


@media only screen and (max-width: 767px) { @media only screen and (max-width: 767px) {


+ 13
- 0
custom/public/swiper/swiper-bundle.min.css
File diff suppressed because it is too large
View File


+ 14
- 0
custom/public/swiper/swiper-bundle.min.js
File diff suppressed because it is too large
View File


+ 3
- 1
go.mod View File

@@ -32,6 +32,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dustin/go-humanize v1.0.0 github.com/dustin/go-humanize v1.0.0
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 github.com/editorconfig/editorconfig-core-go/v2 v2.1.1
github.com/elliotchance/orderedmap v1.4.0
github.com/emirpasic/gods v1.12.0 github.com/emirpasic/gods v1.12.0
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
@@ -87,6 +88,7 @@ require (
github.com/niklasfasching/go-org v0.1.9 github.com/niklasfasching/go-org v0.1.9
github.com/oliamb/cutter v0.2.2 github.com/oliamb/cutter v0.2.2
github.com/olivere/elastic/v7 v7.0.9 github.com/olivere/elastic/v7 v7.0.9
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.2.0 github.com/pquerna/otp v1.2.0
github.com/prometheus/client_golang v1.1.0 github.com/prometheus/client_golang v1.1.0
@@ -99,7 +101,7 @@ require (
github.com/sergi/go-diff v1.1.0 github.com/sergi/go-diff v1.1.0
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
github.com/stretchr/testify v1.4.0
github.com/stretchr/testify v1.7.0
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect
github.com/tinylib/msgp v1.1.2 // indirect github.com/tinylib/msgp v1.1.2 // indirect
github.com/tstranex/u2f v1.0.0 github.com/tstranex/u2f v1.0.0


+ 9
- 41
go.sum View File

@@ -39,11 +39,9 @@ gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Y
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a h1:aOKEXkDTnh4euoH0so/THLXeHtQuqHmDPb1xEk6Ehok= gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a h1:aOKEXkDTnh4euoH0so/THLXeHtQuqHmDPb1xEk6Ehok=
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM=
gitea.com/macaron/macaron v1.3.3-0.20190803174002-53e005ff4827/go.mod h1:/rvxMjIkOq4BM8uPUb+VHuU02ZfAO6R4+wD//tiCiRw= gitea.com/macaron/macaron v1.3.3-0.20190803174002-53e005ff4827/go.mod h1:/rvxMjIkOq4BM8uPUb+VHuU02ZfAO6R4+wD//tiCiRw=
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA=
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs=
gitea.com/macaron/macaron v1.4.0 h1:FY1QDGqyuUzs21K6ChkbYbRUfwL7v2aUrhNEJ0IgsAw= gitea.com/macaron/macaron v1.4.0 h1:FY1QDGqyuUzs21K6ChkbYbRUfwL7v2aUrhNEJ0IgsAw=
gitea.com/macaron/macaron v1.4.0/go.mod h1:P7hfDbQjcW22lkYkXlxdRIfWOXxH2+K4EogN4Q0UlLY= gitea.com/macaron/macaron v1.4.0/go.mod h1:P7hfDbQjcW22lkYkXlxdRIfWOXxH2+K4EogN4Q0UlLY=
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705 h1:mvkQGAlON1Z6Y8pqa/+FpYIskk54mazuECUfZK5oTg0=
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705/go.mod h1:1ujH0jD6Ca4iK9NL0Q2a7fG2chvXx5hVa7hBfABwpkA= gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705/go.mod h1:1ujH0jD6Ca4iK9NL0Q2a7fG2chvXx5hVa7hBfABwpkA=
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d h1:XLww3CvnFZkXVwauN67fniDaIpIqsE+9KVcxlZKlvLU= gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d h1:XLww3CvnFZkXVwauN67fniDaIpIqsE+9KVcxlZKlvLU=
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d/go.mod h1:FanKy3WjWb5iw/iZBPk4ggoQT9FcM6bkBPvmDmsH6tY= gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d/go.mod h1:FanKy3WjWb5iw/iZBPk4ggoQT9FcM6bkBPvmDmsH6tY=
@@ -70,7 +68,6 @@ github.com/RichardKnop/machinery v1.6.9 h1:dQu1c7ENgPFrN9qWweEe7xDDvNYGSqEyprK0G
github.com/RichardKnop/machinery v1.6.9/go.mod h1:BO7MG/5tvdpgMVkOT8V94SEf8x8H8aceRzTt8Tx1IMc= github.com/RichardKnop/machinery v1.6.9/go.mod h1:BO7MG/5tvdpgMVkOT8V94SEf8x8H8aceRzTt8Tx1IMc=
github.com/RichardKnop/redsync v1.2.0 h1:gK35hR3zZkQigHKm8wOGb9MpJ9BsrW6MzxezwjTcHP0= github.com/RichardKnop/redsync v1.2.0 h1:gK35hR3zZkQigHKm8wOGb9MpJ9BsrW6MzxezwjTcHP0=
github.com/RichardKnop/redsync v1.2.0/go.mod h1:9b8nBGAX3bE2uCfJGSnsDvF23mKyHTZzmvmj5FH3Tp0= github.com/RichardKnop/redsync v1.2.0/go.mod h1:9b8nBGAX3bE2uCfJGSnsDvF23mKyHTZzmvmj5FH3Tp0=
github.com/RoaringBitmap/roaring v0.4.21 h1:WJ/zIlNX4wQZ9x8Ey33O1UaD9TCTakYsdLFSBcTwH+8=
github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RoaringBitmap/roaring v0.4.23 h1:gpyfd12QohbqhFO4NVDUdoPOCXsyahYRQhINmlHxKeo= github.com/RoaringBitmap/roaring v0.4.23 h1:gpyfd12QohbqhFO4NVDUdoPOCXsyahYRQhINmlHxKeo=
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
@@ -140,11 +137,9 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k= github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k=
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d h1:XMf4E1U+b9E3ElF0mjvfXZdflBRZz4gLp16nQ/QSHQM=
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 h1:vZryARwW4PSFXd9arwegEywvMTvPuXL3/oa+4L5NTe8= github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 h1:vZryARwW4PSFXd9arwegEywvMTvPuXL3/oa+4L5NTe8=
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b h1:bZ9rKU2/V8sY+NulSfxDOnXTWcs1rySqdF1sVepihvo=
github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 h1:0WMIDtuXCKEm4wtAJgAAXa/qtM5O9MariLwgHaRlYmk= github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 h1:0WMIDtuXCKEm4wtAJgAAXa/qtM5O9MariLwgHaRlYmk=
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
@@ -169,7 +164,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 h1:bpWCJ5MddHsv4Xtl3azkK89mZzd/vvut32mvAnKbyUA=
github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg= github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
@@ -185,8 +179,9 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 h1:mhPg/0hGebcpiiQLqJD2PWWyoHRLEdZ3sXKaEvT1EQU= github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 h1:mhPg/0hGebcpiiQLqJD2PWWyoHRLEdZ3sXKaEvT1EQU=
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1/go.mod h1:/LuhWJiQ9Gvo1DhVpa4ssm5qeg8rrztdtI7j/iCie2k= github.com/editorconfig/editorconfig-core-go/v2 v2.1.1/go.mod h1:/LuhWJiQ9Gvo1DhVpa4ssm5qeg8rrztdtI7j/iCie2k=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A=
github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a h1:M1bRpaZAn4GSsqu3hdK2R8H0AH9O6vqCTCbm2oAFGfE= github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a h1:M1bRpaZAn4GSsqu3hdK2R8H0AH9O6vqCTCbm2oAFGfE=
@@ -306,7 +301,6 @@ github.com/go-swagger/go-swagger v0.21.0 h1:AX9mdfzp6eJtUe92nFrWmbK7ocRgkCDPJs0F
github.com/go-swagger/go-swagger v0.21.0/go.mod h1:tDb8PdDVFcaE8EPXkMOsuxpL3UEPiwu1UDZar9Z/1RY= github.com/go-swagger/go-swagger v0.21.0/go.mod h1:tDb8PdDVFcaE8EPXkMOsuxpL3UEPiwu1UDZar9Z/1RY=
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0=
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
@@ -330,13 +324,11 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
@@ -349,7 +341,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -375,7 +366,6 @@ github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -406,7 +396,6 @@ github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVo
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY=
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
@@ -458,7 +447,6 @@ github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY=
github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.2 h1:Znfn6hXZAHaLPNnlqUYRrBSReFHYybslgv4PTiyz6P0= github.com/klauspost/compress v1.10.2 h1:Znfn6hXZAHaLPNnlqUYRrBSReFHYybslgv4PTiyz6P0=
github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
@@ -472,7 +460,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
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.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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@@ -545,7 +532,6 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA=
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
@@ -580,6 +566,8 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
@@ -588,7 +576,6 @@ github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -715,12 +702,13 @@ github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9 h1:wR6aLKdbJ5E8m+NZ
github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
@@ -731,7 +719,6 @@ github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
@@ -746,7 +733,6 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/unknwon/cae v1.0.0 h1:i39lOFaBXZxhGjQOy/RNbi8uzettCs6OQxpR0xXohGU= github.com/unknwon/cae v1.0.0 h1:i39lOFaBXZxhGjQOy/RNbi8uzettCs6OQxpR0xXohGU=
github.com/unknwon/cae v1.0.0/go.mod h1:QaSeRctcea9fK6piJpAMCCPKxzJ01+xFcr2k1m3WRPU= github.com/unknwon/cae v1.0.0/go.mod h1:QaSeRctcea9fK6piJpAMCCPKxzJ01+xFcr2k1m3WRPU=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
@@ -772,7 +758,6 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
github.com/yohcop/openid-go v1.0.0 h1:EciJ7ZLETHR3wOtxBvKXx9RV6eyHZpCaSZ1inbBaUXE= github.com/yohcop/openid-go v1.0.0 h1:EciJ7ZLETHR3wOtxBvKXx9RV6eyHZpCaSZ1inbBaUXE=
github.com/yohcop/openid-go v1.0.0/go.mod h1:/408xiwkeItSPJZSTPF7+VtZxPkPrRRpRNK2vjGh6yI= github.com/yohcop/openid-go v1.0.0/go.mod h1:/408xiwkeItSPJZSTPF7+VtZxPkPrRRpRNK2vjGh6yI=
github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.25 h1:isv+Q6HQAmmL2Ofcmg8QauBmDPlUUnSoNhEcC940Rds=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27 h1:nqDD4MMMQA0lmWq03Z2/myGPYLQoXtmi0rGVs95ntbo= github.com/yuin/goldmark v1.1.27 h1:nqDD4MMMQA0lmWq03Z2/myGPYLQoXtmi0rGVs95ntbo=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -813,16 +798,15 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R5r1BuKtfYqRqF0h/Cbh0=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -832,9 +816,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= 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/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -865,7 +847,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@@ -876,7 +857,6 @@ golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -915,13 +895,10 @@ golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190907184412-d223b2b6db03/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190907184412-d223b2b6db03/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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/sys v0.0.0-20200302150141-5c8b2ff67527/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/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -932,7 +909,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -955,14 +931,11 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200225230052-807dcd883420 h1:4RJNOV+2rLxMEfr6QIpC7GEv9MjD6ApGXTCLrNF9+eA=
golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ= golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ=
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -984,7 +957,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo=
google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
@@ -1016,7 +988,6 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY= google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
@@ -1027,7 +998,6 @@ gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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 h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1058,12 +1028,12 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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.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= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1078,13 +1048,11 @@ sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI= xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw= xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/xorm v0.8.0 h1:iALxgJrX8O00f8Jk22GbZwPmxJNgssV5Mv4uc2HL9PM=
xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY= xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
xorm.io/xorm v1.0.1 h1:/lITxpJtkZauNpdzj+L9CN/3OQxZaABrbergMcJu+Cw= xorm.io/xorm v1.0.1 h1:/lITxpJtkZauNpdzj+L9CN/3OQxZaABrbergMcJu+Cw=
xorm.io/xorm v1.0.1/go.mod h1:o4vnEsQ5V2F1/WK6w4XTwmiWJeGj82tqjAnHe44wVHY= xorm.io/xorm v1.0.1/go.mod h1:o4vnEsQ5V2F1/WK6w4XTwmiWJeGj82tqjAnHe44wVHY=

+ 19
- 0
models/action.go View File

@@ -346,6 +346,25 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
return actions, nil return actions, nil
} }


func GetLast20PublicFeeds() ([]*Action, error) {
cond := builder.NewCond()
cond = cond.And(builder.Eq{"is_private": false})
cond = cond.And(builder.Eq{"is_deleted": false})


actions := make([]*Action, 0, 20)

if err := x.Limit(20).Desc("id").Where(cond).Find(&actions); err != nil {
return nil, fmt.Errorf("Find: %v", err)
}

if err := ActionList(actions).LoadAttributes(); err != nil {
return nil, fmt.Errorf("LoadAttributes: %v", err)
}

return actions, nil
}

func GetUnTransformedActions() ([]*Action, error) { func GetUnTransformedActions() ([]*Action, error) {
actions := make([]*Action, 0, 10) actions := make([]*Action, 0, 10)
err := x.Where("op_type = ?", ActionCommitRepo). err := x.Where("op_type = ?", ActionCommitRepo).


+ 13
- 0
models/attachment.go View File

@@ -439,6 +439,19 @@ func GetModelArtsUserAttachments(userID int64) ([]*AttachmentUsername, error) {
return getModelArtsUserAttachments(x, userID) return getModelArtsUserAttachments(x, userID)
} }


func getModelArtsTrainAttachments(e Engine, userID int64) ([]*AttachmentUsername, error) {
attachments := make([]*AttachmentUsername, 0, 10)
if err := e.Table("attachment").Join("LEFT", "`user`", "attachment.uploader_id "+
"= `user`.id").Where("attachment.type = ? and (uploader_id= ? or is_private = ?) and attachment.decompress_state = ?", TypeCloudBrainTwo, userID, false, DecompressStateDone).Find(&attachments); err != nil {
return nil, err
}
return attachments, nil
}

func GetModelArtsTrainAttachments(userID int64) ([]*AttachmentUsername, error) {
return getModelArtsTrainAttachments(x, userID)
}

func CanDelAttachment(isSigned bool, user *User, attach *Attachment) bool { func CanDelAttachment(isSigned bool, user *User, attach *Attachment) bool {
if !isSigned { if !isSigned {
return false return false


+ 44
- 4
models/cloudbrain.go View File

@@ -19,6 +19,9 @@ type JobType string
type ModelArtsJobStatus string type ModelArtsJobStatus string


const ( const (
NPUResource = "NPU"
GPUResource = "CPU/GPU"

JobWaiting CloudbrainStatus = "WAITING" JobWaiting CloudbrainStatus = "WAITING"
JobStopped CloudbrainStatus = "STOPPED" JobStopped CloudbrainStatus = "STOPPED"
JobSucceeded CloudbrainStatus = "SUCCEEDED" JobSucceeded CloudbrainStatus = "SUCCEEDED"
@@ -88,6 +91,9 @@ type Cloudbrain struct {
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
Duration int64 Duration int64
TrainJobDuration string TrainJobDuration string
Image string //GPU镜像名称
GpuQueue string //GPU类型即GPU队列
ResourceSpecId int //GPU规格id
DeletedAt time.Time `xorm:"deleted"` DeletedAt time.Time `xorm:"deleted"`
CanDebug bool `xorm:"-"` CanDebug bool `xorm:"-"`
CanDel bool `xorm:"-"` CanDel bool `xorm:"-"`
@@ -204,6 +210,7 @@ type CloudbrainsOptions struct {
JobType string JobType string
VersionName string VersionName string
IsLatestVersion string IsLatestVersion string
JobTypeNot bool
} }


type TaskPod struct { type TaskPod struct {
@@ -888,9 +895,15 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
} }


if (opts.JobType) != "" { if (opts.JobType) != "" {
cond = cond.And(
builder.Eq{"cloudbrain.job_type": opts.JobType},
)
if opts.JobTypeNot {
cond = cond.And(
builder.Neq{"cloudbrain.job_type": opts.JobType},
)
} else {
cond = cond.And(
builder.Eq{"cloudbrain.job_type": opts.JobType},
)
}
} }


if (opts.IsLatestVersion) != "" { if (opts.IsLatestVersion) != "" {
@@ -962,7 +975,9 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) {
cond = cond.And( cond = cond.And(
builder.Eq{"Status": "COMPLETED"}, builder.Eq{"Status": "COMPLETED"},
) )

cond = cond.And(
builder.Eq{"job_type": "TRAIN"},
)
cloudbrains := make([]*CloudbrainInfo, 0) cloudbrains := make([]*CloudbrainInfo, 0)
if err := sess.Select("job_id,job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). if err := sess.Select("job_id,job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC").
Find(&cloudbrains); err != nil { Find(&cloudbrains); err != nil {
@@ -1195,3 +1210,28 @@ func GetCloudbrainTrainJobCountByUserID(userID int64) (int, error) {
And("job_type = ? and user_id = ? and type = ?", JobTypeTrain, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) And("job_type = ? and user_id = ? and type = ?", JobTypeTrain, userID, TypeCloudBrainTwo).Count(new(Cloudbrain))
return int(count), err return int(count), err
} }

func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) {
sess := x.NewSession()
defer sess.Close()

if err = sess.Begin(); err != nil {
return err
}

if _, err = sess.Delete(old); err != nil {
sess.Rollback()
return err
}

if _, err = sess.Insert(new); err != nil {
sess.Rollback()
return err
}

if err = sess.Commit(); err != nil {
return err
}

return nil
}

+ 13
- 0
models/error.go View File

@@ -1999,3 +1999,16 @@ func IsErrJobNotExist(err error) bool {
func (err ErrJobNotExist) Error() string { func (err ErrJobNotExist) Error() string {
return fmt.Sprintf("the job does not exist") return fmt.Sprintf("the job does not exist")
} }

type ErrTagNotExist struct {
TagID int64
}

func (err ErrTagNotExist) Error() string {
return fmt.Sprintf("the tag does not exist")
}

func IsErrTagNotExist(err error) bool {
_, ok := err.(ErrTagNotExist)
return ok
}

+ 8
- 0
models/models.go View File

@@ -134,6 +134,8 @@ func init() {
new(BlockChain), new(BlockChain),
new(RecommendOrg), new(RecommendOrg),
new(AiModelManage), new(AiModelManage),
new(OfficialTag),
new(OfficialTagRepos),
) )


tablesStatistic = append(tablesStatistic, tablesStatistic = append(tablesStatistic,
@@ -141,6 +143,12 @@ func init() {
new(SummaryStatistic), new(SummaryStatistic),
new(UserBusinessAnalysis), new(UserBusinessAnalysis),
new(UserBusinessAnalysisAll), new(UserBusinessAnalysisAll),
new(UserBusinessAnalysisCurrentYear),
new(UserBusinessAnalysisLast30Day),
new(UserBusinessAnalysisLastMonth),
new(UserBusinessAnalysisCurrentMonth),
new(UserBusinessAnalysisCurrentWeek),
new(UserBusinessAnalysisYesterday),
new(UserLoginLog), new(UserLoginLog),
) )




+ 51
- 0
models/repo.go View File

@@ -6,6 +6,7 @@
package models package models


import ( import (
"code.gitea.io/gitea/modules/git"
"context" "context"
"crypto/md5" "crypto/md5"
"errors" "errors"
@@ -2519,3 +2520,53 @@ func UpdateRepositoryCommitNum(repo *Repository) error {


return nil return nil
} }

type RepoFile struct {
CommitId string
Content []byte
}

// ReadLatestFileInRepo read latest version of file in repository
// return a RepoFile
func ReadLatestFileInRepo(userName, repoName, refName, treePath string) (*RepoFile, error) {
var err error
repoPath := RepoPath(userName, repoName)
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
log.Error("ReadLatestFileInRepo error when OpenRepository,error=%v", err)
return nil, err
}
commitID, err := gitRepo.GetBranchCommitID(refName)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBranchCommitID,error=%v", err)
return nil, err
}
commit, err := gitRepo.GetBranchCommit(refName)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBranchCommit,error=%v", err)
return nil, err
}

blob, err := commit.GetBlobByPath(treePath)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBlobByPath,error=%v", err)
return nil, err
}

reader, err := blob.DataAsync()
if err != nil {
return nil, err
}
defer func() {
if err = reader.Close(); err != nil {
log.Error("ReadLatestFileInRepo: Close: %v", err)
}
}()

buf := make([]byte, 1024)
n, _ := reader.Read(buf)
if n >= 0 {
buf = buf[:n]
}
return &RepoFile{CommitId: commitID, Content: buf}, nil
}

+ 163
- 0
models/repo_tag.go View File

@@ -0,0 +1,163 @@
package models

import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"fmt"
)

type OfficialTag struct {
ID int64 `xorm:"pk autoincr"`
Name string `xorm:"NOT NULL"`
Code string `xorm:"NOT NULL"`
Limit int `xorm:"NOT NULL default(-1)"`
Status int `xorm:"NOT NULL default(0)"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}

type OfficialTagRepos struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"NOT NULL INDEX"`
TagID int64 `xorm:"NOT NULL"`
RepoID int64 `xorm:"NOT NULL INDEX"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}

type TagReposBrief struct {
RepoID int64
RepoName string
TagID int64
}

type TagReposSelected struct {
RepoID int64
RepoName string
Selected bool
}

type TagsDetail struct {
TagId int64
TagName string
TagLimit int
RepoList []Repository
}

func GetTagByID(id int64) (*OfficialTag, error) {
r := &OfficialTag{
ID: id,
}
has, err := x.Get(r)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTagNotExist{0}
}
return r, nil
}

func UpdateTagReposByID(tagID, orgID int64, repoIdList []int64) error {
sess := x.NewSession()
defer sess.Close()

if err := sess.Begin(); err != nil {
return fmt.Errorf("UpdateTagReposByID[tagId: %d, orgID: %d,error:%v", tagID, orgID, err)
}
//delete old tag repos
r := &OfficialTagRepos{
TagID: tagID,
OrgID: orgID,
}
_, err := sess.Delete(r)
if err != nil {
return err
}

if len(repoIdList) == 0 {
return sess.Commit()
}

//add new tag repos
data := make([]*OfficialTagRepos, 0)
for _, repoId := range repoIdList {
data = append(data, &OfficialTagRepos{
OrgID: orgID,
TagID: tagID,
RepoID: repoId,
})
}
_, err = sess.Insert(&data)
if err != nil {
sess.Rollback()
return err
}
return sess.Commit()
}

func GetTagRepos(tagID, orgID int64) ([]TagReposSelected, error) {
t := make([]TagReposBrief, 0)
const SQLCmd = "select t1.id as repo_id,t1.name as repo_name,t2.id as tag_id from repository t1 left join official_tag_repos t2 on (t1.id = t2.repo_id and t2.tag_id = ?) where t1.owner_id = ? and t1.is_private = false order by t1.updated_unix desc"

if err := x.SQL(SQLCmd, tagID, orgID).Find(&t); err != nil {
return nil, err
}
r := make([]TagReposSelected, 0)
for _, v := range t {
selected := false
if v.TagID > 0 {
selected = true
}
r = append(r, TagReposSelected{
RepoID: v.RepoID,
RepoName: v.RepoName,
Selected: selected,
})
}
return r, nil
}

func GetAllOfficialTagRepos(orgID int64, isOwner bool) ([]TagsDetail, error) {
result := make([]TagsDetail, 0)
tags, err := GetAllOfficialTags()
if err != nil {
return nil, err
}
for _, tag := range tags {
repos, err := GetOfficialTagDetail(orgID, tag.ID)
if err != nil {
return nil, err
}
if len(repos) == 0 && !isOwner {
continue
}
result = append(result, TagsDetail{
TagId: tag.ID,
TagName: tag.Name,
TagLimit: tag.Limit,
RepoList: repos,
})
}
return result, nil
}

func GetOfficialTagDetail(orgID, tagId int64) ([]Repository, error) {
t := make([]Repository, 0)
const SQLCmd = "select t2.* from official_tag_repos t1 inner join repository t2 on t1.repo_id = t2.id where t1.org_id = ? and t1.tag_id=? order by t2.updated_unix desc"

if err := x.SQL(SQLCmd, orgID, tagId).Find(&t); err != nil {
return nil, err
}
return t, nil
}

func GetAllOfficialTags() ([]OfficialTag, error) {
//todo redis?
o := make([]OfficialTag, 0)
err := x.Where("status = ?", 0).OrderBy("updated_unix desc").Find(&o)
if err != nil {
log.Error("GetAllOfficialTags error,%v", err)
return nil, err
}
return o, nil
}

+ 5
- 2
models/repo_watch.go View File

@@ -280,13 +280,16 @@ func notifyWatchers(e Engine, actions ...*Action) error {
// NotifyWatchers creates batch of actions for every watcher. // NotifyWatchers creates batch of actions for every watcher.
func NotifyWatchers(actions ...*Action) error { func NotifyWatchers(actions ...*Action) error {


error := notifyWatchers(x, actions...)
producer(actions...) producer(actions...)
return notifyWatchers(x, actions...)
return error
} }


func producer(actions ...*Action) { func producer(actions ...*Action) {
for _, action := range actions { for _, action := range actions {
ActionChan <- action
if !action.IsPrivate{
ActionChan <- action
}
} }
} }




+ 134
- 53
models/user_business_analysis.go View File

@@ -10,10 +10,12 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder" "xorm.io/builder"
"xorm.io/xorm"
) )


const ( const (
Page_SIZE = 2000
PAGE_SIZE = 2000
BATCH_INSERT_SIZE = 50
) )


type UserBusinessAnalysisAll struct { type UserBusinessAnalysisAll struct {
@@ -163,14 +165,6 @@ func (ulist UserBusinessAnalysisList) Less(i, j int) bool {
return ulist[i].ID > ulist[j].ID return ulist[i].ID > ulist[j].ID
} }


type UserBusinessAnalysisAllList []*UserBusinessAnalysisAll

func (ulist UserBusinessAnalysisAllList) Swap(i, j int) { ulist[i], ulist[j] = ulist[j], ulist[i] }
func (ulist UserBusinessAnalysisAllList) Len() int { return len(ulist) }
func (ulist UserBusinessAnalysisAllList) Less(i, j int) bool {
return ulist[i].ID > ulist[j].ID
}

func getLastCountDate() int64 { func getLastCountDate() int64 {
statictisSess := xStatistic.NewSession() statictisSess := xStatistic.NewSession()
defer statictisSess.Close() defer statictisSess.Close()
@@ -189,6 +183,29 @@ func getLastCountDate() int64 {
return pageStartTime.Unix() return pageStartTime.Unix()
} }


func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, queryObj interface{}, userName string) ([]*UserBusinessAnalysisAll, int64) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
var cond = builder.NewCond()
if len(userName) > 0 {
cond = cond.And(
builder.Like{"name", userName},
)
}
allCount, err := statictisSess.Where(cond).Count(queryObj)
if err != nil {
log.Info("query error." + err.Error())
return nil, 0
}
log.Info("query return total:" + fmt.Sprint(allCount))
userBusinessAnalysisAllList := make([]*UserBusinessAnalysisAll, 0)
if err := statictisSess.Table(tableName).Where(cond).OrderBy("commit_count desc,id desc").Limit(pageSize, start).
Find(&userBusinessAnalysisAllList); err != nil {
return nil, 0
}
return userBusinessAnalysisAllList, allCount
}

func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusinessAnalysisAll, int64) { func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusinessAnalysisAll, int64) {
log.Info("query startTime =" + fmt.Sprint(opts.StartTime) + " endTime=" + fmt.Sprint(opts.EndTime) + " isAll=" + fmt.Sprint(opts.IsAll)) log.Info("query startTime =" + fmt.Sprint(opts.StartTime) + " endTime=" + fmt.Sprint(opts.EndTime) + " isAll=" + fmt.Sprint(opts.IsAll))


@@ -202,9 +219,9 @@ func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusi
} }
log.Info("query return total:" + fmt.Sprint(allCount)) log.Info("query return total:" + fmt.Sprint(allCount))


pageSize := 1000
pageSize := PAGE_SIZE
totalPage := int(allCount) / pageSize totalPage := int(allCount) / pageSize
userBusinessAnalysisReturnList := UserBusinessAnalysisAllList{}
userBusinessAnalysisReturnList := make([]*UserBusinessAnalysisAll, 0)
for i := 0; i <= int(totalPage); i++ { for i := 0; i <= int(totalPage); i++ {
userBusinessAnalysisAllList := make([]*UserBusinessAnalysisAll, 0) userBusinessAnalysisAllList := make([]*UserBusinessAnalysisAll, 0)
if err := statictisSess.Table("user_business_analysis_all").OrderBy("id desc").Limit(pageSize, i*pageSize). if err := statictisSess.Table("user_business_analysis_all").OrderBy("id desc").Limit(pageSize, i*pageSize).
@@ -217,7 +234,6 @@ func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusi
} }
} }


sort.Sort(userBusinessAnalysisReturnList)
log.Info("return size=" + fmt.Sprint(len(userBusinessAnalysisReturnList))) log.Info("return size=" + fmt.Sprint(len(userBusinessAnalysisReturnList)))
return userBusinessAnalysisReturnList, allCount return userBusinessAnalysisReturnList, allCount
} }
@@ -337,28 +353,24 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus
return userBusinessAnalysisReturnList, count return userBusinessAnalysisReturnList, count
} }


func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap map[string]*git.UserKPIStats) {

func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[string]*git.UserKPIStats, tableName string, pageStartTime time.Time, pageEndTime time.Time) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()


statictisSess := xStatistic.NewSession() statictisSess := xStatistic.NewSession()
defer statictisSess.Close() defer statictisSess.Close()
log.Info("truncate all data from table: user_business_analysis_all")
statictisSess.Exec("TRUNCATE TABLE user_business_analysis_all")
log.Info("truncate all data from table: " + tableName)
statictisSess.Exec("TRUNCATE TABLE " + tableName)


currentTimeNow := time.Now()

startTime := currentTimeNow.AddDate(0, 0, -1)

pageStartTime := time.Date(2021, 11, 5, 0, 0, 0, 0, currentTimeNow.Location())
log.Info("pageStartTime:" + pageStartTime.Format("2006-01-02 15:04:05")) log.Info("pageStartTime:" + pageStartTime.Format("2006-01-02 15:04:05"))
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
log.Info("pageEndTime time:" + pageEndTime.Format("2006-01-02 15:04:05")) log.Info("pageEndTime time:" + pageEndTime.Format("2006-01-02 15:04:05"))


start_unix := pageStartTime.Unix() start_unix := pageStartTime.Unix()
end_unix := pageEndTime.Unix() end_unix := pageEndTime.Unix()


currentTimeNow := time.Now()
startTime := currentTimeNow.AddDate(0, 0, -1)

CodeMergeCountMap := queryPullRequest(start_unix, end_unix) CodeMergeCountMap := queryPullRequest(start_unix, end_unix)
CommitCountMap := queryCommitAction(start_unix, end_unix, 5) CommitCountMap := queryCommitAction(start_unix, end_unix, 5)
IssueCountMap := queryCreateIssue(start_unix, end_unix) IssueCountMap := queryCreateIssue(start_unix, end_unix)
@@ -385,12 +397,14 @@ func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap ma
} }
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
insertCount := 0
dateRecordBatch := make([]UserBusinessAnalysisAll, 0)
for { for {
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
userList := make([]*User, 0) userList := make([]*User, 0)
sess.Find(&userList) sess.Find(&userList)
for i, userRecord := range userList {
log.Info("insert all static, i=" + fmt.Sprint(i) + " userName=" + userRecord.Name)
for _, userRecord := range userList {
var dateRecordAll UserBusinessAnalysisAll var dateRecordAll UserBusinessAnalysisAll
dateRecordAll.ID = userRecord.ID dateRecordAll.ID = userRecord.ID
dateRecordAll.Email = userRecord.Email dateRecordAll.Email = userRecord.Email
@@ -484,18 +498,85 @@ func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap ma
} }


dateRecordAll.CommitModelCount = 0 dateRecordAll.CommitModelCount = 0
_, err = statictisSess.Insert(&dateRecordAll)
if err != nil {
log.Info("insert all data failed." + err.Error())

dateRecordBatch = append(dateRecordBatch, dateRecordAll)
if len(dateRecordBatch) >= BATCH_INSERT_SIZE {
insertTable(dateRecordBatch, tableName, statictisSess)
insertCount += BATCH_INSERT_SIZE
if err != nil {
log.Info("insert all data failed." + err.Error())
}
dateRecordBatch = make([]UserBusinessAnalysisAll, 0)
} }
} }
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
} }
if len(dateRecordBatch) > 0 {
insertTable(dateRecordBatch, tableName, statictisSess)
insertCount += len(dateRecordBatch)
if err != nil {
log.Info("insert all data failed." + err.Error())
}
}

log.Info("refresh data finished.tableName=" + tableName + " total record:" + fmt.Sprint(insertCount))
}

func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, statictisSess *xorm.Session) {

insertBatchSql := "INSERT INTO public." + tableName +
"(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " +
"commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date) " +
"VALUES"

for i, record := range dateRecords {
insertBatchSql += "(" + fmt.Sprint(record.ID) + ", " + fmt.Sprint(record.CountDate) + ", " + fmt.Sprint(record.CodeMergeCount) + ", " + fmt.Sprint(record.CommitCount) +
", " + fmt.Sprint(record.IssueCount) + ", " + fmt.Sprint(record.CommentCount) + ", " + fmt.Sprint(record.FocusRepoCount) + ", " + fmt.Sprint(record.StarRepoCount) +
", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) +
", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) +
", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "')"
if i < (len(dateRecords) - 1) {
insertBatchSql += ","
}
}


statictisSess.Exec(insertBatchSql)
}

func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap map[string]*git.UserKPIStats) {
currentTimeNow := time.Now()
pageStartTime := time.Date(2021, 11, 5, 0, 0, 0, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_all", pageStartTime, pageEndTime)
log.Info("refresh all data finished.") log.Info("refresh all data finished.")

pageStartTime = time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_year", pageStartTime, pageEndTime)

thisMonth := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_month", thisMonth, pageEndTime)

offset := int(time.Monday - currentTimeNow.Weekday())
if offset > 0 {
offset = -6
}
pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_week", pageStartTime, pageEndTime)

pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -30)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_last30_day", pageStartTime, pageEndTime)

pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
pageEndTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_yesterday", pageStartTime, pageEndTime)

pageStartTime = thisMonth.AddDate(0, -1, 0)
pageEndTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_last_month", pageStartTime, pageEndTime)

} }


func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, endTime time.Time, isReCount bool) error { func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, endTime time.Time, isReCount bool) error {
@@ -550,7 +631,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
userList := make([]*User, 0) userList := make([]*User, 0)
sess.Find(&userList) sess.Find(&userList)


@@ -660,7 +741,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
} }
} }


indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -700,7 +781,7 @@ func querySolveIssue(start_unix int64, end_unix int64) map[int64]int {
issueAssigneesList := make([]*IssueAssignees, 0) issueAssigneesList := make([]*IssueAssignees, 0)
sess.Select("issue_assignees.*").Table("issue_assignees"). sess.Select("issue_assignees.*").Table("issue_assignees").
Join("inner", "issue", "issue.id=issue_assignees.issue_id"). Join("inner", "issue", "issue.id=issue_assignees.issue_id").
Where(cond).OrderBy("issue_assignees.id asc").Limit(Page_SIZE, int(indexTotal))
Where(cond).OrderBy("issue_assignees.id asc").Limit(PAGE_SIZE, int(indexTotal))


sess.Find(&issueAssigneesList) sess.Find(&issueAssigneesList)


@@ -712,7 +793,7 @@ func querySolveIssue(start_unix int64, end_unix int64) map[int64]int {
resultMap[issueAssigneesRecord.AssigneeID] += 1 resultMap[issueAssigneesRecord.AssigneeID] += 1
} }
} }
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -735,7 +816,7 @@ func queryPullRequest(start_unix int64, end_unix int64) map[int64]int {
indexTotal = 0 indexTotal = 0
for { for {
issueList := make([]*Issue, 0) issueList := make([]*Issue, 0)
sess.Select("issue.*").Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).OrderBy("issue.id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("issue.*").Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).OrderBy("issue.id asc").Limit(PAGE_SIZE, int(indexTotal))
sess.Find(&issueList) sess.Find(&issueList)
log.Info("query issue(PR) size=" + fmt.Sprint(len(issueList))) log.Info("query issue(PR) size=" + fmt.Sprint(len(issueList)))
for _, issueRecord := range issueList { for _, issueRecord := range issueList {
@@ -745,7 +826,7 @@ func queryPullRequest(start_unix int64, end_unix int64) map[int64]int {
resultMap[issueRecord.PosterID] += 1 resultMap[issueRecord.PosterID] += 1
} }
} }
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -768,7 +849,7 @@ func queryCommitAction(start_unix int64, end_unix int64, actionType int64) map[i
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
sess.Select("id,user_id,op_type,act_user_id").Table("action").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,op_type,act_user_id").Table("action").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
actionList := make([]*Action, 0) actionList := make([]*Action, 0)
sess.Find(&actionList) sess.Find(&actionList)


@@ -781,7 +862,7 @@ func queryCommitAction(start_unix int64, end_unix int64, actionType int64) map[i
} }
} }


indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -805,7 +886,7 @@ func queryCreateIssue(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
sess.Select("id,poster_id").Table("issue").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,poster_id").Table("issue").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
issueList := make([]*Issue, 0) issueList := make([]*Issue, 0)
sess.Find(&issueList) sess.Find(&issueList)
log.Info("query issue size=" + fmt.Sprint(len(issueList))) log.Info("query issue size=" + fmt.Sprint(len(issueList)))
@@ -816,7 +897,7 @@ func queryCreateIssue(start_unix int64, end_unix int64) map[int64]int {
resultMap[issueRecord.PosterID] += 1 resultMap[issueRecord.PosterID] += 1
} }
} }
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -839,7 +920,7 @@ func queryComment(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
sess.Select("id,type,poster_id").Table("comment").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,type,poster_id").Table("comment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
commentList := make([]*Comment, 0) commentList := make([]*Comment, 0)
sess.Find(&commentList) sess.Find(&commentList)
log.Info("query Comment size=" + fmt.Sprint(len(commentList))) log.Info("query Comment size=" + fmt.Sprint(len(commentList)))
@@ -850,7 +931,7 @@ func queryComment(start_unix int64, end_unix int64) map[int64]int {
resultMap[commentRecord.PosterID] += 1 resultMap[commentRecord.PosterID] += 1
} }
} }
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -875,7 +956,7 @@ func queryWatch(start_unix int64, end_unix int64) map[int64]int {
indexTotal = 0 indexTotal = 0
for { for {
watchList := make([]*Watch, 0) watchList := make([]*Watch, 0)
sess.Select("id,user_id,repo_id").Table("watch").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,repo_id").Table("watch").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
sess.Find(&watchList) sess.Find(&watchList)


log.Info("query Watch size=" + fmt.Sprint(len(watchList))) log.Info("query Watch size=" + fmt.Sprint(len(watchList)))
@@ -887,7 +968,7 @@ func queryWatch(start_unix int64, end_unix int64) map[int64]int {
} }
} }


indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -913,7 +994,7 @@ func queryStar(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
sess.Select("id,uid,repo_id").Table("star").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,uid,repo_id").Table("star").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
starList := make([]*Star, 0) starList := make([]*Star, 0)
sess.Find(&starList) sess.Find(&starList)


@@ -926,7 +1007,7 @@ func queryStar(start_unix int64, end_unix int64) map[int64]int {
} }
} }


indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -949,7 +1030,7 @@ func queryFollow(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
sess.Select("id,user_id,follow_id").Table("follow").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,follow_id").Table("follow").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
followList := make([]*Follow, 0) followList := make([]*Follow, 0)
sess.Find(&followList) sess.Find(&followList)


@@ -962,7 +1043,7 @@ func queryFollow(start_unix int64, end_unix int64) map[int64]int {
} }
} }


indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -985,7 +1066,7 @@ func queryDatasetSize(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
sess.Select("id,uploader_id,size").Table("attachment").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,uploader_id,size").Table("attachment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
attachmentList := make([]*Attachment, 0) attachmentList := make([]*Attachment, 0)
sess.Find(&attachmentList) sess.Find(&attachmentList)


@@ -998,7 +1079,7 @@ func queryDatasetSize(start_unix int64, end_unix int64) map[int64]int {
} }
} }


indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -1021,7 +1102,7 @@ func queryUserCreateRepo(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
sess.Select("id,owner_id,name").Table("repository").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,owner_id,name").Table("repository").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
repoList := make([]*Repository, 0) repoList := make([]*Repository, 0)
sess.Find(&repoList) sess.Find(&repoList)
log.Info("query Repository size=" + fmt.Sprint(len(repoList))) log.Info("query Repository size=" + fmt.Sprint(len(repoList)))
@@ -1032,7 +1113,7 @@ func queryUserCreateRepo(start_unix int64, end_unix int64) map[int64]int {
resultMap[repoRecord.OwnerID] += 1 resultMap[repoRecord.OwnerID] += 1
} }
} }
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }
@@ -1111,7 +1192,7 @@ func queryLoginCount(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
statictisSess.Select("id,u_id").Table("user_login_log").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
statictisSess.Select("id,u_id").Table("user_login_log").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
userLoginLogList := make([]*UserLoginLog, 0) userLoginLogList := make([]*UserLoginLog, 0)
statictisSess.Find(&userLoginLogList) statictisSess.Find(&userLoginLogList)
log.Info("query user login size=" + fmt.Sprint(len(userLoginLogList))) log.Info("query user login size=" + fmt.Sprint(len(userLoginLogList)))
@@ -1122,7 +1203,7 @@ func queryLoginCount(start_unix int64, end_unix int64) map[int64]int {
resultMap[loginRecord.UId] += 1 resultMap[loginRecord.UId] += 1
} }
} }
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
break break
} }


+ 267
- 0
models/user_business_struct.go View File

@@ -0,0 +1,267 @@
package models

import "code.gitea.io/gitea/modules/timeutil"

type UserBusinessAnalysisCurrentYear struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisLast30Day struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisLastMonth struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisCurrentMonth struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisCurrentWeek struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisYesterday struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

+ 4
- 0
modules/auth/org.go View File

@@ -70,3 +70,7 @@ type CreateTeamForm struct {
func (f *CreateTeamForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { func (f *CreateTeamForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale) return validate(errs, ctx.Data, f, ctx.Locale)
} }

type SubmitReposOfTagForm struct {
RepoList []int64
}

+ 148
- 12
modules/cloudbrain/cloudbrain.go View File

@@ -1,6 +1,8 @@
package cloudbrain package cloudbrain


import ( import (
"code.gitea.io/gitea/modules/storage"
"encoding/json"
"errors" "errors"
"strconv" "strconv"


@@ -80,7 +82,7 @@ func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) {
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")


job, err := models.GetCloudbrainByJobID(jobID) job, err := models.GetCloudbrainByJobID(jobID)
ctx.Cloudbrain = job
if !isAdminOrOwnerOrJobCreater(ctx, job, err) { if !isAdminOrOwnerOrJobCreater(ctx, job, err) {


ctx.NotFound(ctx.Req.URL.RequestURI(), nil) ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -92,6 +94,7 @@ func AdminOrJobCreaterRight(ctx *context.Context) {


var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
job, err := models.GetCloudbrainByJobID(jobID) job, err := models.GetCloudbrainByJobID(jobID)
ctx.Cloudbrain = job
if !isAdminOrJobCreater(ctx, job, err) { if !isAdminOrJobCreater(ctx, job, err) {


ctx.NotFound(ctx.Req.URL.RequestURI(), nil) ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -107,6 +110,9 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,
uuid uuid


var resourceSpec *models.ResourceSpec var resourceSpec *models.ResourceSpec
if ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
}
for _, spec := range ResourceSpecs.ResourceSpec { for _, spec := range ResourceSpecs.ResourceSpec {
if resourceSpecId == spec.Id { if resourceSpecId == spec.Id {
resourceSpec = spec resourceSpec = spec
@@ -185,25 +191,29 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,
}, },
}) })
if err != nil { if err != nil {
log.Error("CreateJob failed:", err.Error())
log.Error("CreateJob failed:", err.Error(), ctx.Data["MsgID"])
return err return err
} }
if jobResult.Code != Success { if jobResult.Code != Success {
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg)
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg, ctx.Data["MsgID"])
return errors.New(jobResult.Msg) return errors.New(jobResult.Msg)
} }


var jobID = jobResult.Payload["jobId"].(string) var jobID = jobResult.Payload["jobId"].(string)
err = models.CreateCloudbrain(&models.Cloudbrain{ err = models.CreateCloudbrain(&models.Cloudbrain{
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobID,
JobName: jobName,
SubTaskName: SubTaskName,
JobType: jobType,
Type: models.TypeCloudBrainOne,
Uuid: uuid,
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobID,
JobName: jobName,
SubTaskName: SubTaskName,
JobType: jobType,
Type: models.TypeCloudBrainOne,
Uuid: uuid,
Image: image,
GpuQueue: gpuQueue,
ResourceSpecId: resourceSpecId,
ComputeResource: models.GPUResource,
}) })


if err != nil { if err != nil {
@@ -212,3 +222,129 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,


return nil return nil
} }

func RestartTask(ctx *context.Context, task *models.Cloudbrain, newJobID *string) error {
dataActualPath := setting.Attachment.Minio.RealPath +
setting.Attachment.Minio.Bucket + "/" +
setting.Attachment.Minio.BasePath +
models.AttachmentRelativePath(task.Uuid) +
task.Uuid
jobName := task.JobName

var resourceSpec *models.ResourceSpec
if ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
}
for _, spec := range ResourceSpecs.ResourceSpec {
if task.ResourceSpecId == spec.Id {
resourceSpec = spec
}
}

if resourceSpec == nil {
log.Error("no such resourceSpecId(%d)", task.ResourceSpecId, ctx.Data["MsgID"])
return errors.New("no such resourceSpec")
}

jobResult, err := CreateJob(jobName, models.CreateJobParams{
JobName: jobName,
RetryCount: 1,
GpuType: task.GpuQueue,
Image: task.Image,
TaskRoles: []models.TaskRole{
{
Name: SubTaskName,
TaskNumber: 1,
MinSucceededTaskCount: 1,
MinFailedTaskCount: 1,
CPUNumber: resourceSpec.CpuNum,
GPUNumber: resourceSpec.GpuNum,
MemoryMB: resourceSpec.MemMiB,
ShmMB: resourceSpec.ShareMemMiB,
Command: Command,
NeedIBDevice: false,
IsMainRole: false,
UseNNI: false,
},
},
Volumes: []models.Volume{
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, CodeMountPath + "/"),
MountPath: CodeMountPath,
ReadOnly: false,
},
},
{
HostPath: models.StHostPath{
Path: dataActualPath,
MountPath: DataSetMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, ModelMountPath + "/"),
MountPath: ModelMountPath,
ReadOnly: false,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, BenchMarkMountPath + "/"),
MountPath: BenchMarkMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, Snn4imagenetMountPath + "/"),
MountPath: Snn4imagenetMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, BrainScoreMountPath + "/"),
MountPath: BrainScoreMountPath,
ReadOnly: true,
},
},
},
})
if err != nil {
log.Error("CreateJob failed:%v", err.Error(), ctx.Data["MsgID"])
return err
}
if jobResult.Code != Success {
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg, ctx.Data["MsgID"])
return errors.New(jobResult.Msg)
}

var jobID = jobResult.Payload["jobId"].(string)
newTask := &models.Cloudbrain{
Status: string(models.JobWaiting),
UserID: task.UserID,
RepoID: task.RepoID,
JobID: jobID,
JobName: task.JobName,
SubTaskName: task.SubTaskName,
JobType: task.JobType,
Type: task.Type,
Uuid: task.Uuid,
Image: task.Image,
GpuQueue: task.GpuQueue,
ResourceSpecId: task.ResourceSpecId,
ComputeResource: task.ComputeResource,
}

err = models.RestartCloudbrain(task, newTask)
if err != nil {
log.Error("RestartCloudbrain(%s) failed:%v", jobName, err.Error(), ctx.Data["MsgID"])
return err
}

*newJobID = jobID

return nil
}

+ 6
- 0
modules/context/context.go View File

@@ -6,6 +6,7 @@
package context package context


import ( import (
"code.gitea.io/gitea/routers/notice"
"html" "html"
"html/template" "html/template"
"io" "io"
@@ -46,6 +47,7 @@ type Context struct {


Repo *Repository Repo *Repository
Org *Organization Org *Organization
Cloudbrain *models.Cloudbrain
} }


// IsUserSiteAdmin returns true if current user is a site admin // IsUserSiteAdmin returns true if current user is a site admin
@@ -345,6 +347,10 @@ func Contexter() macaron.Handler {
ctx.Data["EnableSwagger"] = setting.API.EnableSwagger ctx.Data["EnableSwagger"] = setting.API.EnableSwagger
ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn


notice, _ := notice.GetNewestNotice()
if notice != nil {
ctx.Data["notice"] = *notice
}
c.Map(ctx) c.Map(ctx)
} }
} }

+ 8
- 0
modules/context/repo.go View File

@@ -11,6 +11,7 @@ import (
"net/url" "net/url"
"path" "path"
"strings" "strings"
"time"


"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/cache"
@@ -517,6 +518,7 @@ func RepoAssignment() macaron.Handler {
return return
} }


startTime := time.Now()
tags, err := ctx.Repo.GitRepo.GetTags() tags, err := ctx.Repo.GitRepo.GetTags()
if err != nil { if err != nil {
ctx.ServerError("GetTags", err) ctx.ServerError("GetTags", err)
@@ -524,11 +526,17 @@ func RepoAssignment() macaron.Handler {
} }
ctx.Data["Tags"] = tags ctx.Data["Tags"] = tags


duration := time.Since(startTime)
log.Info("GetTags cost: %v seconds", duration.Seconds())
brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 0)
if err != nil { if err != nil {
ctx.ServerError("GetBranches", err) ctx.ServerError("GetBranches", err)
return return
} }

duration = time.Since(startTime)
log.Info("GetBranches cost: %v seconds", duration.Seconds())

ctx.Data["Branches"] = brs ctx.Data["Branches"] = brs
ctx.Data["BranchesCount"] = len(brs) ctx.Data["BranchesCount"] = len(brs)




+ 13
- 16
modules/modelarts/modelarts.go View File

@@ -48,12 +48,8 @@ const (
PerPage = 10 PerPage = 10
IsLatestVersion = "1" IsLatestVersion = "1"
NotLatestVersion = "0" NotLatestVersion = "0"
// ComputeResource = "NPU"
NPUResource = "NPU"
GPUResource = "CPU/GPU"
AllResource = "all"
DebugType = -1
VersionCount = 1
DebugType = -1
VersionCount = 1


SortByCreateTime = "create_time" SortByCreateTime = "create_time"
ConfigTypeCustom = "custom" ConfigTypeCustom = "custom"
@@ -215,14 +211,15 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin
} }
err = models.CreateCloudbrain(&models.Cloudbrain{ err = models.CreateCloudbrain(&models.Cloudbrain{


Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID,
JobName: jobName,
JobType: string(models.JobTypeDebug),
Type: models.TypeCloudBrainTwo,
Uuid: uuid,
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID,
JobName: jobName,
JobType: string(models.JobTypeDebug),
Type: models.TypeCloudBrainTwo,
Uuid: uuid,
ComputeResource: models.NPUResource,
}) })


if err != nil { if err != nil {
@@ -277,7 +274,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error
DatasetName: attach.Name, DatasetName: attach.Name,
CommitID: req.CommitID, CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion, IsLatestVersion: req.IsLatestVersion,
ComputeResource: NPUResource,
ComputeResource: models.NPUResource,
EngineID: req.EngineID, EngineID: req.EngineID,
TrainUrl: req.TrainUrl, TrainUrl: req.TrainUrl,
BranchName: req.BranchName, BranchName: req.BranchName,
@@ -360,7 +357,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
CommitID: req.CommitID, CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion, IsLatestVersion: req.IsLatestVersion,
PreVersionName: req.PreVersionName, PreVersionName: req.PreVersionName,
ComputeResource: NPUResource,
ComputeResource: models.NPUResource,
EngineID: req.EngineID, EngineID: req.EngineID,
TrainUrl: req.TrainUrl, TrainUrl: req.TrainUrl,
BranchName: req.BranchName, BranchName: req.BranchName,


+ 3
- 3
modules/modelarts/resty.go View File

@@ -174,7 +174,7 @@ sendjob:
return &result, nil return &result, nil
} }


func StopJob(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) {
func ManageNotebook(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) {
checkSetting() checkSetting()
client := getRestyClient() client := getRestyClient()
var result models.NotebookActionResult var result models.NotebookActionResult
@@ -207,8 +207,8 @@ sendjob:
} }


if len(response.ErrorCode) != 0 { if len(response.ErrorCode) != 0 {
log.Error("StopJob failed(%s): %s", response.ErrorCode, response.ErrorMsg)
return &result, fmt.Errorf("StopJob failed(%s): %s", response.ErrorCode, response.ErrorMsg)
log.Error("ManageNotebook failed(%s): %s", response.ErrorCode, response.ErrorMsg)
return &result, fmt.Errorf("ManageNotebook failed(%s): %s", response.ErrorCode, response.ErrorMsg)
} }


return &result, nil return &result, nil


+ 10
- 2
modules/repository/elk_pagedata.go View File

@@ -21,7 +21,8 @@ type Fields struct {
Format string `json:"format"` Format string `json:"format"`
} }
type MatchPhrase struct { type MatchPhrase struct {
Message string `json:"message"`
Message string `json:"message,omitempty"`
TagName string `json:"tagName.keyword,omitempty"`
} }
type Should struct { type Should struct {
MatchPhrase MatchPhrase `json:"match_phrase"` MatchPhrase MatchPhrase `json:"match_phrase"`
@@ -144,7 +145,7 @@ func ProjectViewInit(User string, Project string, Gte string, Lte string) (proje
inputStruct.Batch[0].Request.Params.Body.Fields = make([]Fields, 1) inputStruct.Batch[0].Request.Params.Body.Fields = make([]Fields, 1)
inputStruct.Batch[0].Request.Params.Body.Fields[0].Field = setting.TimeField inputStruct.Batch[0].Request.Params.Body.Fields[0].Field = setting.TimeField
inputStruct.Batch[0].Request.Params.Body.Fields[0].Format = setting.ElkTimeFormat inputStruct.Batch[0].Request.Params.Body.Fields[0].Format = setting.ElkTimeFormat
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 3)
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 4)
//限定查询时间 //限定查询时间
var timeRange Range var timeRange Range
timeRange.Timestamptest.Gte = Gte timeRange.Timestamptest.Gte = Gte
@@ -159,6 +160,13 @@ func ProjectViewInit(User string, Project string, Gte string, Lte string) (proje
var projectName FilterMatchPhrase var projectName FilterMatchPhrase
projectName.ProjectName = Project projectName.ProjectName = Project
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[2].FilterMatchPhrase = &projectName inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[2].FilterMatchPhrase = &projectName
//限定页面
var bool Bool
bool.Should = make([]Should, len(setting.PROJECT_LIMIT_PAGES))
for i, pageName := range setting.PROJECT_LIMIT_PAGES {
bool.Should[i].MatchPhrase.TagName = pageName
}
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[3].Bool = &bool
return inputStruct return inputStruct
} }




+ 24
- 8
modules/setting/setting.go View File

@@ -435,8 +435,14 @@ var (


//home page //home page
RecommentRepoAddr string RecommentRepoAddr string

ESSearchURL string
ESSearchURL string
//notice config
UserNameOfNoticeRepo string
RepoNameOfNoticeRepo string
RefNameOfNoticeRepo string
TreePathOfNoticeRepo string
CacheTimeOutSecond int
CacheOn bool


//labelsystem config //labelsystem config
LabelTaskName string LabelTaskName string
@@ -510,12 +516,13 @@ var (
TrainJobFLAVORINFOS string TrainJobFLAVORINFOS string


//elk config //elk config
ElkUrl string
ElkUser string
ElkPassword string
Index string
TimeField string
ElkTimeFormat string
ElkUrl string
ElkUser string
ElkPassword string
Index string
TimeField string
ElkTimeFormat string
PROJECT_LIMIT_PAGES []string


//nginx proxy //nginx proxy
PROXYURL string PROXYURL string
@@ -1238,6 +1245,14 @@ func NewContext() {
RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/") RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/")
ESSearchURL = sec.Key("ESSearchURL").MustString("http://192.168.207.94:9200") ESSearchURL = sec.Key("ESSearchURL").MustString("http://192.168.207.94:9200")


sec = Cfg.Section("notice")
UserNameOfNoticeRepo = sec.Key("USER_NAME").MustString("OpenIOSSG")
RepoNameOfNoticeRepo = sec.Key("REPO_NAME").MustString("promote")
RefNameOfNoticeRepo = sec.Key("REF_NAME").MustString("master")
TreePathOfNoticeRepo = sec.Key("TREE_PATH").MustString("notice.json")
CacheTimeOutSecond = sec.Key("CACHE_TIME_OUT_SECOND").MustInt(60)
CacheOn = sec.Key("CACHE_ON").MustBool(true)

sec = Cfg.Section("cloudbrain") sec = Cfg.Section("cloudbrain")
CBAuthUser = sec.Key("USER").MustString("") CBAuthUser = sec.Key("USER").MustString("")
CBAuthPassword = sec.Key("PWD").MustString("") CBAuthPassword = sec.Key("PWD").MustString("")
@@ -1311,6 +1326,7 @@ func NewContext() {
Index = sec.Key("INDEX").MustString("") Index = sec.Key("INDEX").MustString("")
TimeField = sec.Key("TIMEFIELD").MustString(" @timestamptest") TimeField = sec.Key("TIMEFIELD").MustString(" @timestamptest")
ElkTimeFormat = sec.Key("ELKTIMEFORMAT").MustString("date_time") ElkTimeFormat = sec.Key("ELKTIMEFORMAT").MustString("date_time")
PROJECT_LIMIT_PAGES = strings.Split(sec.Key("project_limit_pages").MustString(""), ",")


SetRadarMapConfig() SetRadarMapConfig()




+ 4
- 0
modules/storage/local.go View File

@@ -80,3 +80,7 @@ func (l *LocalStorage) HasObject(path string) (bool, error) {
func (l *LocalStorage) UploadObject(fileName, filePath string) error { func (l *LocalStorage) UploadObject(fileName, filePath string) error {
return nil return nil
} }

func (l *LocalStorage) DeleteDir(dir string) error {
return nil
}

+ 28
- 0
modules/storage/minio.go View File

@@ -11,6 +11,9 @@ import (
"strings" "strings"
"time" "time"


"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"

"github.com/minio/minio-go" "github.com/minio/minio-go"
) )


@@ -76,6 +79,27 @@ func (m *MinioStorage) Delete(path string) error {
return m.client.RemoveObject(m.bucket, m.buildMinioPath(path)) return m.client.RemoveObject(m.bucket, m.buildMinioPath(path))
} }


// Delete delete a file
func (m *MinioStorage) DeleteDir(dir string) error {
objectsCh := make(chan string)

// Send object names that are needed to be removed to objectsCh
go func() {
defer close(objectsCh)
// List all objects from a bucket-name with a matching prefix.
for object := range m.client.ListObjects(m.bucket, dir, true, nil) {
if object.Err != nil {
log.Error("ListObjects failed:%v", object.Err)
}
objectsCh <- object.Key
}
}()

m.client.RemoveObjects(m.bucket, objectsCh)

return nil
}

//Get Presigned URL for get object //Get Presigned URL for get object
func (m *MinioStorage) PresignedGetURL(path string, fileName string) (string, error) { func (m *MinioStorage) PresignedGetURL(path string, fileName string) (string, error) {
// Set request parameters for content-disposition. // Set request parameters for content-disposition.
@@ -128,3 +152,7 @@ func (m *MinioStorage) UploadObject(fileName, filePath string) error {
_, err := m.client.FPutObject(m.bucket, fileName, filePath, minio.PutObjectOptions{}) _, err := m.client.FPutObject(m.bucket, fileName, filePath, minio.PutObjectOptions{})
return err return err
} }

func GetMinioPath(jobName, suffixPath string) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath
}

+ 1
- 0
modules/storage/storage.go View File

@@ -23,6 +23,7 @@ type ObjectStorage interface {
Save(path string, r io.Reader) (int64, error) Save(path string, r io.Reader) (int64, error)
Open(path string) (io.ReadCloser, error) Open(path string) (io.ReadCloser, error)
Delete(path string) error Delete(path string) error
DeleteDir(dir string) error
PresignedGetURL(path string, fileName string) (string, error) PresignedGetURL(path string, fileName string) (string, error)
PresignedPutURL(path string) (string, error) PresignedPutURL(path string) (string, error)
HasObject(path string) (bool, error) HasObject(path string) (bool, error)


+ 10
- 0
modules/util/util.go View File

@@ -6,6 +6,7 @@ package util


import ( import (
"bytes" "bytes"
"strconv"
"strings" "strings"
) )


@@ -100,3 +101,12 @@ func NormalizeEOL(input []byte) []byte {
} }
return tmp[:pos] return tmp[:pos]
} }

func AddZero(t int64) (m string) {
if t < 10 {
m = "0" + strconv.FormatInt(t, 10)
return m
} else {
return strconv.FormatInt(t, 10)
}
}

+ 46
- 1
options/locale/locale_en-US.ini View File

@@ -220,8 +220,40 @@ show_only_public = Showing only public
issues.in_your_repos = In your repositories issues.in_your_repos = In your repositories
contributors = Contributors contributors = Contributors


page_title=Explore Better AI
page_small_title=OpenI AI development cooperation platform
page_description=The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation
page_use=Use Now
page_only_dynamic=Show only open source project dynamics
page_recommend_org=Recommended organization
page_recommend_org_desc=These excellent organizations are using Qizhi AI to develop collaboration platforms; Your organization also wants to show here,
page_recommend_org_commit=Click here to submit
page_recommend_org_more=More organizations
page_recommend_repo=Recommended projects
page_recommend_repo_desc=Excellent AI project recommendation; Your project also wants to show here,
page_recommend_repo_commit=Click here to submit
page_recommend_repo_go=. Click here
page_recommend_repo_more=Project Square
page_dev_env=Collaborative development environment
page_dev_env_desc=The biggest difference between Qizhi AI collaborative development platform and traditional git platform is that it provides a collaborative development environment for AI development
page_dev_env_desc_title=Unified management of development elements
page_dev_env_desc_desc=The platform provides four elements of AI development: unified management of model code, data set, model and execution environment
page_dev_env_desc1_title=Data collaboration and sharing
page_dev_env_desc1_desc=By uploading data sets in the project, many project members cooperate to complete data preprocessing; You can also establish a better model with community developers by setting the data as a public dataset
page_dev_env_desc2_title=Model management and sharing
page_dev_env_desc2_desc=Associate the model with the code version, adjust the model in different ways based on the code history version, and save the results; The trained model can be open and shared, so that more people can use the model to test and give feedback
page_dev_env_desc3_title=One configuration, multiple use
page_dev_env_desc3_desc=Provide execution environment sharing, one-time configuration and multiple use, reduce the threshold of model development, and avoid spending repeated time configuring complex environments
page_dev_yunlao=PengCheng Cloudbrain open source collaboration
page_dev_yunlao_desc1=The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks
page_dev_yunlao_desc2=Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and shengteng processors
page_dev_yunlao_desc3=Developers can freely choose the corresponding computing resources according to the use requirements, and can test the adaptability, performance and stability of the model in different hardware environments
page_dev_yunlao_desc4=If your model needs more computing resources, you can also apply separately
page_dev_yunlao_apply=Separate apply

[explore] [explore]
repos = Repositories repos = Repositories
select_repos = Select the project
users = Users users = Users
organizations = Organizations organizations = Organizations
images = CloudImages images = CloudImages
@@ -234,6 +266,8 @@ org_no_results = No matching organizations found.
code_no_results = No source code matching your search term found. code_no_results = No source code matching your search term found.
code_search_results = Search results for '%s' code_search_results = Search results for '%s'
code_last_indexed_at = Last indexed %s code_last_indexed_at = Last indexed %s
save=save
cancel=cancel


[auth] [auth]
create_new_account = Register Account create_new_account = Register Account
@@ -421,7 +455,13 @@ static.openiindex=OpenI Index
static.registdate=Regist Date static.registdate=Regist Date
static.countdate=Count Date static.countdate=Count Date
static.all=All static.all=All

static.public.user_business_analysis_current_month=Current_Month
static.public.user_business_analysis_current_week=Current_Week
static.public.user_business_analysis_current_year=Current_Year
static.public.user_business_analysis_last30_day=Last_30_day
static.public.user_business_analysis_last_month=Last_Month
static.public.user_business_analysis_yesterday=Yesterday
static.public.user_business_analysis_all=All
[settings] [settings]
profile = Profile profile = Profile
account = Account account = Account
@@ -841,6 +881,7 @@ modelarts.current_version=Current version
modelarts.parent_version=Parent Version modelarts.parent_version=Parent Version
modelarts.run_version=Run Version modelarts.run_version=Run Version
modelarts.train_job.compute_node=Compute Node modelarts.train_job.compute_node=Compute Node
modelarts.create_model = Create Model




modelarts.train_job.basic_info=Basic Info modelarts.train_job.basic_info=Basic Info
@@ -900,6 +941,8 @@ model.manage.F1 = F1
model.manage.Precision = Precision model.manage.Precision = Precision
model.manage.Recall = Recall model.manage.Recall = Recall
model.manage.sava_model = Sava Model model.manage.sava_model = Sava Model
model.manage.model_manage = ModelManage
model.manage.model_accuracy = Model Accuracy


template.items = Template Items template.items = Template Items
template.git_content = Git Content (Default Branch) template.git_content = Git Content (Default Branch)
@@ -2654,3 +2697,5 @@ foot.member_news = Member news
foot.industry_advisory = Industry Advisory foot.industry_advisory = Industry Advisory
foot.help = help foot.help = help
foot.copyright= Copyright: New Generation Artificial Intelligence Open Source Open Platform (OpenI) foot.copyright= Copyright: New Generation Artificial Intelligence Open Source Open Platform (OpenI)
Platform_Tutorial=Platform Tutorial
foot.advice_feedback=advice feedback

+ 48
- 1
options/locale/locale_zh-CN.ini View File

@@ -222,8 +222,40 @@ issues.in_your_repos=属于该用户项目的


contributors=贡献者 contributors=贡献者


page_title=探索更好的AI
page_small_title=启智AI开发协作平台
page_description=面向AI领域的一站式协同开发环境,提供集代码开发、数据管理、模型调试、推理和评测为一体的AI开发流水线
page_use=立即使用
page_only_dynamic=仅展示开源项目动态
page_recommend_org=推荐组织
page_recommend_org_desc=这些优秀的组织正在使用启智AI开发协作平台;你的组织也想展示到这里,
page_recommend_org_commit=点此提交
page_recommend_org_more=更多组织
page_recommend_repo=推荐项目
page_recommend_repo_desc=优秀的AI项目推荐;你的项目也想展示到这里,
page_recommend_repo_commit=点此提交
page_recommend_repo_go=。进入
page_recommend_repo_more=项目广场
page_dev_env=协同开发环境
page_dev_env_desc=启智AI协作开发平台与传统git平台最大的不同就在于提供了面向AI开发的协同开发环境
page_dev_env_desc_title=开发要素统一管理
page_dev_env_desc_desc=平台提供了AI开发四大要素:模型代码、数据集、模型和执行环境的统一管理
page_dev_env_desc1_title=数据协同与共享
page_dev_env_desc1_desc=通过在项目中上传数据集,项目成员多人协作完成数据预处理;也可以通过将数据设置为公有数据集,与社区开发者共同建立更好的模型
page_dev_env_desc2_title=模型管理与共享
page_dev_env_desc2_desc=将模型与代码版本建立关联,可以基于代码历史版本,使用不同的方式调整模型,并将结果保存下来;训练好的模型可以开放共享,让更多人的使用模型测试并提出反馈
page_dev_env_desc3_title=一次配置,多次使用
page_dev_env_desc3_desc=提供执行环境共享,一次配置,多次使用,降低模型开发门槛,避免花费重复的时间配置复杂的环境
page_dev_yunlao=鹏城云脑开源协同
page_dev_yunlao_desc1=平台已经与鹏城云脑打通,可以利用鹏城云脑的丰富算力资源,完成AI开发任务
page_dev_yunlao_desc2=鹏城云脑现有AI算力100P FLOPS@FP16(每秒十亿亿次半精度浮点计算),主要硬件基础设施由搭载英伟达Tesla V100 的GPU服务器和搭载鲲鹏、昇腾处理器的Atlas 900 AI集群构成
page_dev_yunlao_desc3=开发者可以根据使用需求,自由选择相应计算资源,可以测试模型在不同硬件环境下的适配能力、性能、稳定性等
page_dev_yunlao_desc4=如果您的模型需要更多的计算资源,也可以单独申请
page_dev_yunlao_apply=单独申请

[explore] [explore]
repos=项目 repos=项目
select_repos=精选项目
users=用户 users=用户
organizations=组织 organizations=组织
images = 云脑镜像 images = 云脑镜像
@@ -238,6 +270,8 @@ org_no_results=未找到匹配的组织。
code_no_results=未找到与搜索字词匹配的源代码。 code_no_results=未找到与搜索字词匹配的源代码。
code_search_results=“%s” 的搜索结果是 code_search_results=“%s” 的搜索结果是
code_last_indexed_at=最后索引于 %s code_last_indexed_at=最后索引于 %s
save=保存
cancel=取消


[auth] [auth]
create_new_account=注册帐号 create_new_account=注册帐号
@@ -425,6 +459,13 @@ static.openiindex=OpenI指数
static.registdate=用户注册时间 static.registdate=用户注册时间
static.countdate=系统统计时间 static.countdate=系统统计时间
static.all=所有 static.all=所有
static.public.user_business_analysis_current_month=本月
static.public.user_business_analysis_current_week=本周
static.public.user_business_analysis_current_year=今年
static.public.user_business_analysis_last30_day=近30天
static.public.user_business_analysis_last_month=上月
static.public.user_business_analysis_yesterday=昨天
static.public.user_business_analysis_all=所有
[settings] [settings]
profile=个人信息 profile=个人信息
account=账号 account=账号
@@ -787,6 +828,7 @@ model_noright=无权限操作
model_rename=模型名称重复,请修改模型名称 model_rename=模型名称重复,请修改模型名称


debug=调试 debug=调试
debug_again=再次调试
stop=停止 stop=停止
delete=删除 delete=删除
model_download=模型下载 model_download=模型下载
@@ -845,6 +887,7 @@ modelarts.modify=修改
modelarts.current_version=当前版本 modelarts.current_version=当前版本
modelarts.parent_version=父版本 modelarts.parent_version=父版本
modelarts.run_version=运行版本 modelarts.run_version=运行版本
modelarts.create_model=创建模型






@@ -909,6 +952,8 @@ model.manage.F1 = F1值
model.manage.Precision = 精确率 model.manage.Precision = 精确率
model.manage.Recall = 召回率 model.manage.Recall = 召回率
model.manage.sava_model = 保存模型 model.manage.sava_model = 保存模型
model.manage.model_manage = 模型管理
model.manage.model_accuracy = 模型精度


template.items=模板选项 template.items=模板选项
template.git_content=Git数据(默认分支) template.git_content=Git数据(默认分支)
@@ -1424,7 +1469,7 @@ milestones.open_tab=%d 开启中
milestones.close_tab=%d 已关闭 milestones.close_tab=%d 已关闭
milestones.closed=于 %s关闭 milestones.closed=于 %s关闭
milestones.no_due_date=暂无截止日期 milestones.no_due_date=暂无截止日期
milestones.open=开启
milestones.open=开启
milestones.close=关闭 milestones.close=关闭
milestones.new_subheader=里程碑组织任务,合并请求和跟踪进度。 milestones.new_subheader=里程碑组织任务,合并请求和跟踪进度。
milestones.completeness=%d%% 完成 milestones.completeness=%d%% 完成
@@ -2661,3 +2706,5 @@ foot.member_news=成员动态
foot.industry_advisory=行业资讯 foot.industry_advisory=行业资讯
foot.help=帮助 foot.help=帮助
foot.copyright= 版权所有:新一代人工智能开源开放平台(OpenI) foot.copyright= 版权所有:新一代人工智能开源开放平台(OpenI)
Platform_Tutorial=新手指引
foot.advice_feedback = 意见反馈

+ 5
- 0
package-lock.json View File

@@ -11655,6 +11655,11 @@
"autolinker": "~0.28.0" "autolinker": "~0.28.0"
} }
}, },
"remixicon": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/remixicon/-/remixicon-2.5.0.tgz",
"integrity": "sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww=="
},
"remove-bom-buffer": { "remove-bom-buffer": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",


+ 1
- 0
package.json View File

@@ -42,6 +42,7 @@
"postcss-preset-env": "6.7.0", "postcss-preset-env": "6.7.0",
"postcss-safe-parser": "4.0.2", "postcss-safe-parser": "4.0.2",
"qs": "6.9.4", "qs": "6.9.4",
"remixicon": "2.5.0",
"spark-md5": "3.0.1", "spark-md5": "3.0.1",
"svg-sprite-loader": "5.0.0", "svg-sprite-loader": "5.0.0",
"svgo": "1.3.2", "svgo": "1.3.2",


+ 442
- 0
public/home/home.js View File

@@ -0,0 +1,442 @@

var token;
if(isEmpty(token)){
var meta = $("meta[name=_uid]");
if(!isEmpty(meta)){
token = meta.attr("content");
console.log("token is uid:" + token);
}
}

var swiperNewMessage = new Swiper(".newslist", {
direction: "vertical",
slidesPerView: 10,
loop: true,
autoplay: {
delay: 2500,
disableOnInteraction: false,
},
});
var swiperRepo = new Swiper(".homepro-list", {
slidesPerView: 3,
slidesPerColumn: 2,
slidesPerColumnFill:'row',
spaceBetween: 30,
pagination: {
el: ".swiper-pagination",
clickable: true,
},
autoplay: {
delay: 2500,
disableOnInteraction: false,
},
});

var output = document.getElementById("newmessage");
var socket = new WebSocket("ws://" + document.location.host + "/action/notification");

socket.onopen = function () {
console.log("message has connected.");
};

var messageQueue = [];
var maxSize = 20;
var html =document.documentElement;
var lang = html.attributes["lang"]
var isZh = true;
if(lang != null && lang.nodeValue =="en-US" ){
console.log("the language is " + lang.nodeValue);
isZh=false;
}else{
console.log("default lang=zh");
}

socket.onmessage = function (e) {
var data =JSON.parse(e.data)
console.log("recevie data=" + e.data)
var html = "";
if (data != null){
console.log("queue length=" + messageQueue.length);
if(messageQueue.length > maxSize){
delete messageQueue[0];
}else{
messageQueue.push(data);
}
var currentTime = new Date().getTime();
for(var i = 0; i < messageQueue.length; i++){
var record = messageQueue[i];
var recordPrefix = getMsg(record);
var actionName = getAction(record.OpType,isZh);
if(record.OpType == "6" || record.OpType == "10" || record.OpType == "12" || record.OpType == "13"){
html += recordPrefix + actionName;
html += " <a href=\"" + getIssueLink(record) + "\" rel=\"nofollow\">" + getIssueText(record) + "</a>"
}
else if(record.OpType == "7" || record.OpType == "11" || record.OpType == "14" || record.OpType == "15" || record.OpType == "22"
|| record.OpType == "23"){
html += recordPrefix + actionName;
html += " <a href=\"" + getPRLink(record) + "\" rel=\"nofollow\">" + getPRText(record) + "</a>"
}
else if(record.OpType == "1"){
html += recordPrefix + actionName;
html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepoLink(record) + "</a>"
}
else if(record.OpType == "9" || record.OpType == "5"){
branch = "<a href=\"" + getRepoLink(record) + "/src/branch/" + record.RefName + "\" rel=\"nofollow\">" + record.RefName + "</a>"
actionName = actionName.replace("{branch}",branch);
html += recordPrefix + actionName;
html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepoLink(record) + "</a>"
}else if(record.OpType == "17"){
actionName = actionName.replace("{deleteBranchName}",record.RefName);
var repoLink = "<a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepoLink(record) + "</a>"
actionName = actionName.replace("{repoName}",repoLink);
html += recordPrefix + actionName;
}
else if(record.OpType == "2"){
actionName = actionName.replace("{oldRepoName}",record.Content);
html += recordPrefix + actionName;
html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepoLink(record) + "</a>"
}
else{
continue;
}

if(record.Repo != null){
var time = getTime(record.CreatedUnix,currentTime);
html += " " + time;
}
html += "</div>";
html += "</div>";
}
/*
<div class="swiper-slide item">
<img class="ui avatar image" src="/user/avatar/zhoupzh/-1" alt="">
<div class="middle aligned content">
<a href="/zhoupzh" title="">zhoupzh</a> 合并了合并请求 <a href="/OpenI/aiforge/pulls/1168" rel="nofollow">OpenI/aiforge#1168</a><span class="time-since">22 分钟前</span>
</div>
</div>
*/

}
console.log("html=" + html)
output.innerHTML = html;
swiperNewMessage.updateSlides();
swiperNewMessage.updateProgress();
};

function getMsg(record){
var html ="";
html += "<div class=\"swiper-slide item\">";
html += " <img class=\"ui avatar image\" src=\"/user/avatar/" + record.ActUser.Name + "/-1\" alt=\"\">"
html += " <div class=\"middle aligned content nowrap\">"
html += " <a href=\"/" + record.ActUser.Name + "\" title=\"\">" + record.ActUser.Name + "</a>"
return html;
}

function getRepoLink(record){
return "/" + record.Repo.OwnerName + "/" + record.Repo.Name;
}
function getRepoLink(record){
return record.Repo.OwnerName + "/" + record.Repo.Name;
}

function getTime(UpdatedUnix,currentTime){
UpdatedUnix = UpdatedUnix;
currentTime = currentTime / 1000;
var timeEscSecond = currentTime - UpdatedUnix;
if( timeEscSecond < 0){
timeEscSecond = 1;
}
console.log("currentTime=" + currentTime + " updateUnix=" + UpdatedUnix);
var hours= Math.floor(timeEscSecond / 3600);
//计算相差分钟数
var leave2 = Math.floor(timeEscSecond % (3600)); //计算小时数后剩余的秒数
var minutes= Math.floor(leave2 / 60);//计算相差分钟数

var leave3=Math.floor(leave2 % 60); //计算分钟数后剩余的秒数
var seconds= leave3;

if(hours == 0 && minutes == 0){
return seconds + getRepoOrOrg(6,isZh);
}else{
if(hours > 0){
return hours + getRepoOrOrg(4,isZh);
}else{
return minutes + getRepoOrOrg(5,isZh);
}
}
}

function getPRLink(record){
return "/" + record.Repo.OwnerName + "/" + record.Repo.Name + "/pulls/" + getIssueId(record);
}
function getPRText(record){
return record.Repo.OwnerName + "/" + record.Repo.Name + "#" + getIssueId(record);
}

function getIssueLink(record){
return "/" + record.Repo.OwnerName + "/" + record.Repo.Name + "/issues/" + getIssueId(record);
}

function getIssueId(record){
var Id = "1";
if(!isEmpty(record.Comment) && !isEmpty(record.Comment.Issue)){
Id = record.Comment.Issue.Index;
}else{
if(!isEmpty(record.Content)){
var content = record.Content;
var index = content.indexOf("|");
if(index != -1){
Id = content.substring(0,index);
}
}
}
return Id;
}

function getIssueText(record){
return record.Repo.OwnerName + "/" + record.Repo.Name + "#" + getIssueId(record);
}

/*
ActionCreateRepo ActionType = iota + 1 // 1
ActionRenameRepo // 2
ActionStarRepo // 3
ActionWatchRepo // 4
ActionCommitRepo // 5
ActionCreateIssue // 6
ActionCreatePullRequest // 7
ActionTransferRepo // 8
ActionPushTag // 9
ActionCommentIssue // 10
ActionMergePullRequest // 11
ActionCloseIssue // 12
ActionReopenIssue // 13
ActionClosePullRequest // 14
ActionReopenPullRequest // 15
ActionDeleteTag // 16
ActionDeleteBranch // 17
ActionMirrorSyncPush // 18
ActionMirrorSyncCreate // 19
ActionMirrorSyncDelete // 20
ActionApprovePullRequest // 21
ActionRejectPullRequest // 22
ActionCommentPull // 23
*/

var actionNameZH={
"1":"创建了项目",
"2":"重命名项目 {oldRepoName} 为",
"5":"推送了 {branch} 分支的代码到",
"6":"创建了任务",
"7":"创建了合并请求",
"9":"推送了 {branch} 分支的代码到",
"10":"评论了任务",
"11":"合并了合并请求",
"12":"关闭了任务",
"13":"重新开启了任务",
"14":"关闭了合并请求",
"15":"重新开启了合并请求",
"17":"从 {repoName} 删除分支 {deleteBranchName}",
"22":"拒绝了合并请求",
"23":"评论了合并请求"
};

var actionNameEN={
"1":" created repository",
"2":" renamed repository from {oldRepoName} to ",
"5":" pushed to {branch} at",
"6":" opened issue",
"7":" created pull request",
"9":" pushed to {branch} at",
"10":" commented on issue",
"11":" merged pull request",
"12":" closed issue",
"13":" reopened issue",
"14":" closed pull request",
"15":" reopened pull request",
"17":" deleted branch {deleteBranchName} from {repoName}",
"22":" rejected pull request",
"23":" commented on pull request"
};

var repoAndOrgZH={
"1":"项目",
"2":"成员",
"3":"团队",
"4":"小时前",
"5":"分钟前",
"6":"秒前"
};

var repoAndOrgEN={
"1":"repository",
"2":"Members ",
"3":"Teams",
"4":" hours ago",
"5":" minutes ago",
"6":" seconds ago"
};


function getAction(opType,isZh){
if(isZh){
return actionNameZH[opType]
}else{
return actionNameEN[opType]
}
}

queryRecommendData();

function queryRecommendData(){
$.ajax({
type:"GET",
url:"/recommend/org",
headers: {
authorization:token,
},
dataType:"json",
async:false,
success:function(json){
console.log(json);
displayOrg(json);
},
error:function(response) {
console.log(response);
}
});

$.ajax({
type:"GET",
url:"/recommend/repo",
headers: {
authorization:token,
},
dataType:"json",
async:false,
success:function(json){
console.log(json);
displayRepo(json);
},
error:function(response) {
console.log(response);
}
});

}

/*
<div class="swiper-slide">
<div class="ui fluid card">
<div class="content">
<span class="right floated meta">
<i class="star icon"></i>276 <i class="star icon"></i>32
</span>
<img class="left floated mini ui image" src="/repo-avatars/278-a9f45e21b92b86dbf969c9f70dff1efc">
<a class="header nowrap" href="/OpenI/aiforge">aiforge </a>
<div class="description nowrap-2">
本项目是群体化方法与技术的开源实现案例,在基于Gitea的基础上,进一步支持社交化的协同开发、协同学习、协同研究等群体创新实践服务,特别是针对新一代人工智能技术特点,重点支持项目管理、git代码管理、大数据集存储管理与智能计算平台接入。
</div>
<div class="ui tags nowrap am-mt-10">
<a class="ui small label topic" href="/explore/repos?q=ai%e5%bc%80%e5%8f%91%e5%b7%a5%e5%85%b7&amp;topic=">ai开发工具</a>
<a class="ui small label topic" href="/explore/repos?q=openi&amp;topic=">openi</a>
<a class="ui small label topic" href="/explore/repos?q=golang&amp;topic=">golang</a>
<a class="ui small label topic" href="/explore/repos?q=git&amp;topic=">git</a>
<a class="ui small label topic" href="/explore/repos?q=pcl&amp;topic=">pcl</a>
</div>
</div>
</div>
</div>
*/
function displayRepo(json){
var orgRepo = document.getElementById("recommendrepo");
var html = "";
if (json != null && json.length > 0){
for(var i = 0; i < json.length;i++){
var record = json[i]
html += "<div class=\"swiper-slide\">";
html += " <div class=\"ui fluid card\">";
html += " <div class=\"content\">";
html += " <span class=\"right floated meta\">";
html += " <i class=\"ri-star-line\"></i>" + record["NumStars"] + "<i class=\"ri-git-branch-line am-ml-10\"></i>" + record["NumForks"];
html += " </span>";
html += " <img class=\"left floated mini ui image\" src=\"" + record["Avatar"] + "\">";
html += " <a class=\"header nowrap\" href=\"/" + record["OwnerName"] + "/" + record["Name"] + "\">" + record["Name"] +"</a>";
html += " <div class=\"description nowrap-2\">" + record["Description"] + " </div>";
html += " <div class=\"ui tags nowrap am-mt-10\">"
if(record["Topics"] != null){
for(var j = 0; j < record["Topics"].length; j++){
topic = record["Topics"][j];
url = "/explore/repos?q=" + (topic) + "&amp;topic="
html += "<a class=\"ui small label topic\" href=\"" + url + "\">" + topic + "</a>";
}
}
html += " </div>";
html += " </div>";
html += " </div>";
html += "</div>";
}
}
orgRepo.innerHTML = html;
swiperRepo.updateSlides();
swiperRepo.updateProgress();
}

/**
*
* <div class="column">
<div class="ui fluid card">
<div class="content">
<div class="ui small header">
<img class="ui image" src="/user/avatar/OpenI/-1">
<div class="content nowrap">
<a href="/OpenI">OpenI</a> 启智社区
<div class="sub header">39 项目 ・ 60 成员 ・ 23 团队</div>
</div>
</div>
</div>
</div>
</div>
*/

//var repoAndOrgZH = new Map([['1', "项目"], ['2', "成员"], ['3', "团队"]]);
//var repoAndOrgEN = new Map([['1', "Repository"], ['2', "Members"], ['3', "Teams"]]);


function getRepoOrOrg(key,isZhLang){
if(isZhLang){
return repoAndOrgZH[key];
}else{
return repoAndOrgEN[key];
}
}

function displayOrg(json){
var orgDiv = document.getElementById("recommendorg");
var html = "";
if (json != null && json.length > 0){
for(var i = 0; i < json.length;i++){
var record = json[i]
html += "<div class=\"column\">";
html += " <a href=\"/" + record["Name"] + "\" class=\"ui fluid card\">";
html += " <div class=\"content\">";
html += " <div class=\"ui small header\">";
html += " <img class=\"ui image\" src=\"" + record["Avatar"] + "\">";
html += " <div class=\"content nowrap\">";
html += " <span class=\"ui blue\">" + record["Name"] + "</span> " + record["FullName"];
html += " <div class=\"sub header\">" + record["NumRepos"] +" " + getRepoOrOrg(1,isZh) + " ・ " + record["NumMembers"] +" " + getRepoOrOrg(2,isZh) + " ・ " + record["NumTeams"] + " " + getRepoOrOrg(3,isZh) + "</div>";
html += " </div>";
html += " </div>";
html += " </div>";
html += " </a>";
html += "</div>";
}
}
orgDiv.innerHTML = html;
}

+ 13
- 10
routers/actionnotification.go View File

@@ -1,6 +1,8 @@
package routers package routers


import ( import (
"net/http"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@@ -11,6 +13,9 @@ import (
var upgrader = websocket.Upgrader{ var upgrader = websocket.Upgrader{
ReadBufferSize: 1024, ReadBufferSize: 1024,
WriteBufferSize: 1024, WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
} }


var SocketManager = socketwrap.NewClientsManager() var SocketManager = socketwrap.NewClientsManager()
@@ -24,7 +29,7 @@ func ActionNotification(ctx *context.Context) {
} }
client := &socketwrap.Client{Manager: SocketManager, Conn: conn, Send: make(chan *models.Action, 256)} client := &socketwrap.Client{Manager: SocketManager, Conn: conn, Send: make(chan *models.Action, 256)}


WriteLastTenActionsIfHave(conn)
WriteLastActionsIfHave(conn)


client.Manager.Register <- client client.Manager.Register <- client


@@ -32,22 +37,20 @@ func ActionNotification(ctx *context.Context) {


} }


func WriteLastTenActionsIfHave(conn *websocket.Conn) {
socketwrap.LastTenActionsQueue.Mutex.RLock()
func WriteLastActionsIfHave(conn *websocket.Conn) {
socketwrap.LastActionsQueue.Mutex.RLock()
{ {
size := socketwrap.LastTenActionsQueue.Queue.Len()
size := socketwrap.LastActionsQueue.Queue.Len()
if size > 0 { if size > 0 {
tempE := socketwrap.LastTenActionsQueue.Queue.Front()
conn.WriteJSON(tempE)
tempE := socketwrap.LastActionsQueue.Queue.Front()
conn.WriteJSON(tempE.Value)
for i := 1; i < size; i++ { for i := 1; i < size; i++ {
tempE = tempE.Next() tempE = tempE.Next()
conn.WriteJSON(tempE)
conn.WriteJSON(tempE.Value)


} }
} }


} }
socketwrap.LastTenActionsQueue.Mutex.RUnlock()
socketwrap.LastActionsQueue.Mutex.RUnlock()
} }



+ 8
- 2
routers/api/v1/api.go View File

@@ -524,7 +524,7 @@ func RegisterRoutes(m *macaron.Macaron) {
Get(notify.GetThread). Get(notify.GetThread).
Patch(notify.ReadThread) Patch(notify.ReadThread)
}, reqToken()) }, reqToken())
operationReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, OperationRequired: true}) operationReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, OperationRequired: true})
//Project board //Project board
m.Group("/projectboard", func() { m.Group("/projectboard", func() {
@@ -544,7 +544,13 @@ func RegisterRoutes(m *macaron.Macaron) {
}, operationReq) }, operationReq)


m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage) m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage)

m.Get("/query_user_current_month", operationReq, repo_ext.QueryUserStaticCurrentMonth)
m.Get("/query_user_current_week", operationReq, repo_ext.QueryUserStaticCurrentWeek)
m.Get("/query_user_current_year", operationReq, repo_ext.QueryUserStaticCurrentYear)
m.Get("/query_user_last30_day", operationReq, repo_ext.QueryUserStaticLast30Day)
m.Get("/query_user_last_month", operationReq, repo_ext.QueryUserStaticLastMonth)
m.Get("/query_user_yesterday", operationReq, repo_ext.QueryUserStaticYesterday)
m.Get("/query_user_all", operationReq, repo_ext.QueryUserStaticAll)
// Users // Users
m.Group("/users", func() { m.Group("/users", func() {
m.Get("/search", user.Search) m.Get("/search", user.Search)


+ 6
- 11
routers/api/v1/repo/modelarts.go View File

@@ -6,6 +6,7 @@
package repo package repo


import ( import (
"code.gitea.io/gitea/modules/util"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@@ -15,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts" "code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
routerRepo "code.gitea.io/gitea/routers/repo"
) )


func GetModelArtsNotebook(ctx *context.APIContext) { func GetModelArtsNotebook(ctx *context.APIContext) {
@@ -105,7 +107,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
job.TrainJobDuration = result.TrainJobDuration job.TrainJobDuration = result.TrainJobDuration


if result.Duration != 0 { if result.Duration != 0 {
job.TrainJobDuration = addZero(result.Duration/3600000) + ":" + addZero(result.Duration%3600000/60000) + ":" + addZero(result.Duration%60000/1000)
job.TrainJobDuration = util.AddZero(result.Duration/3600000) + ":" + util.AddZero(result.Duration%3600000/60000) + ":" + util.AddZero(result.Duration%60000/1000)


} else { } else {
job.TrainJobDuration = "00:00:00" job.TrainJobDuration = "00:00:00"
@@ -124,15 +126,6 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {


} }


func addZero(t int64) (m string) {
if t < 10 {
m = "0" + strconv.FormatInt(t, 10)
return m
} else {
return strconv.FormatInt(t, 10)
}
}

func TrainJobGetLog(ctx *context.APIContext) { func TrainJobGetLog(ctx *context.APIContext) {
var ( var (
err error err error
@@ -237,7 +230,7 @@ func DelTrainJobVersion(ctx *context.APIContext) {
JobID: jobID, JobID: jobID,
}) })
if err != nil { if err != nil {
ctx.ServerError("get VersionListCount faild", err)
ctx.ServerError("get VersionListCount failed", err)
return return
} }
if VersionListCount > 0 { if VersionListCount > 0 {
@@ -255,6 +248,8 @@ func DelTrainJobVersion(ctx *context.APIContext) {
return return
} }
} }
} else { //已删除该任务下的所有版本
routerRepo.DeleteJobStorage(task.JobName)
} }


ctx.JSON(http.StatusOK, map[string]interface{}{ ctx.JSON(http.StatusOK, map[string]interface{}{


+ 48
- 9
routers/home.go View File

@@ -44,9 +44,52 @@ const (
func Home(ctx *context.Context) { func Home(ctx *context.Context) {
ctx.Data["PageIsHome"] = true ctx.Data["PageIsHome"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
setRecommendURL(ctx)
ctx.HTML(200, tplHome) ctx.HTML(200, tplHome)
} }


func setRecommendURL(ctx *context.Context) {
addr := setting.RecommentRepoAddr[10:]
start := strings.Index(addr, "/")
end := strings.Index(addr, "raw")
if start != -1 && end != -1 {
ctx.Data["RecommendURL"] = addr[start:end]
} else {
ctx.Data["RecommendURL"] = setting.RecommentRepoAddr
}

ctx.Data["page_title"] = ctx.Tr("home.page_title")
ctx.Data["page_small_title"] = ctx.Tr("home.page_small_title")
ctx.Data["page_description"] = ctx.Tr("home.page_description")
ctx.Data["page_use"] = ctx.Tr("home.page_use")
ctx.Data["page_only_dynamic"] = ctx.Tr("home.page_only_dynamic")
ctx.Data["page_recommend_org"] = ctx.Tr("home.page_recommend_org")
ctx.Data["page_recommend_org_desc"] = ctx.Tr("home.page_recommend_org_desc")
ctx.Data["page_recommend_org_commit"] = ctx.Tr("home.page_recommend_org_commit")
ctx.Data["page_recommend_org_more"] = ctx.Tr("home.page_recommend_org_more")
ctx.Data["page_recommend_repo"] = ctx.Tr("home.page_recommend_repo")
ctx.Data["page_recommend_repo_desc"] = ctx.Tr("home.page_recommend_repo_desc")
ctx.Data["page_recommend_repo_commit"] = ctx.Tr("home.page_recommend_repo_commit")
ctx.Data["page_recommend_repo_go"] = ctx.Tr("home.page_recommend_repo_go")
ctx.Data["page_recommend_repo_more"] = ctx.Tr("home.page_recommend_repo_more")
ctx.Data["page_dev_env"] = ctx.Tr("home.page_dev_env")
ctx.Data["page_dev_env_desc"] = ctx.Tr("home.page_dev_env_desc")
ctx.Data["page_dev_env_desc_title"] = ctx.Tr("home.page_dev_env_desc_title")
ctx.Data["page_dev_env_desc_desc"] = ctx.Tr("home.page_dev_env_desc_desc")
ctx.Data["page_dev_env_desc1_title"] = ctx.Tr("home.page_dev_env_desc1_title")
ctx.Data["page_dev_env_desc1_desc"] = ctx.Tr("home.page_dev_env_desc1_desc")
ctx.Data["page_dev_env_desc2_title"] = ctx.Tr("home.page_dev_env_desc2_title")
ctx.Data["page_dev_env_desc2_desc"] = ctx.Tr("home.page_dev_env_desc2_desc")
ctx.Data["page_dev_env_desc3_title"] = ctx.Tr("home.page_dev_env_desc3_title")
ctx.Data["page_dev_env_desc3_desc"] = ctx.Tr("home.page_dev_env_desc3_desc")
ctx.Data["page_dev_yunlao"] = ctx.Tr("home.page_dev_yunlao")
ctx.Data["page_dev_yunlao_desc1"] = ctx.Tr("home.page_dev_yunlao_desc1")
ctx.Data["page_dev_yunlao_desc2"] = ctx.Tr("home.page_dev_yunlao_desc2")
ctx.Data["page_dev_yunlao_desc3"] = ctx.Tr("home.page_dev_yunlao_desc3")
ctx.Data["page_dev_yunlao_desc4"] = ctx.Tr("home.page_dev_yunlao_desc4")
ctx.Data["page_dev_yunlao_apply"] = ctx.Tr("home.page_dev_yunlao_apply")
}

func Dashboard(ctx *context.Context) { func Dashboard(ctx *context.Context) {
if ctx.IsSigned { if ctx.IsSigned {
if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm { if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
@@ -77,7 +120,7 @@ func Dashboard(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/login") ctx.Redirect(setting.AppSubURL + "/user/login")
return return
} }
setRecommendURL(ctx)
ctx.Data["PageIsHome"] = true ctx.Data["PageIsHome"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.HTML(200, tplHome) ctx.HTML(200, tplHome)
@@ -527,6 +570,8 @@ func RecommendOrgFromPromote(ctx *context.Context) {
if err == nil { if err == nil {
userMap := make(map[string]interface{}) userMap := make(map[string]interface{})
userMap["Name"] = user.Name userMap["Name"] = user.Name
userMap["Description"] = user.Description
userMap["FullName"] = user.FullName
userMap["ID"] = user.ID userMap["ID"] = user.ID
userMap["Avatar"] = user.RelAvatarLink() userMap["Avatar"] = user.RelAvatarLink()
userMap["NumRepos"] = user.NumRepos userMap["NumRepos"] = user.NumRepos
@@ -558,14 +603,8 @@ func recommendFromPromote(url string) ([]string, error) {
lines := strings.Split(allLineStr, "\n") lines := strings.Split(allLineStr, "\n")
result := make([]string, len(lines)) result := make([]string, len(lines))
for i, line := range lines { for i, line := range lines {

tmpIndex := strings.Index(line, ".")
log.Info("i=" + fmt.Sprint(i) + " line=" + line + " tmpIndex=" + fmt.Sprint(tmpIndex))
if tmpIndex == -1 {
result[i] = strings.Trim(line, " ")
} else {
result[i] = strings.Trim(line[tmpIndex+1:], " ")
}
log.Info("i=" + fmt.Sprint(i) + " line=" + line)
result[i] = strings.Trim(line, " ")
} }
return result, nil return result, nil
} }


+ 87
- 0
routers/notice/notice.go View File

@@ -0,0 +1,87 @@
package notice

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"encoding/json"
"github.com/patrickmn/go-cache"
"time"
)

var noticeCache = cache.New(2*time.Minute, 1*time.Minute)

const (
NOTICE_CACHE_KEY = "notice"
)

type Notice struct {
Title string
Link string
Visible int //0 invisible, 1 visible
CommitId string
}

var lock int32 = 0

func GetNewestNotice() (*Notice, error) {
defer func() {
if err := recover(); err != nil {
log.Error("recover error", err)
}
}()

var notice *Notice
var err error
if setting.CacheOn {
notice, err = getNewestNoticeFromCacheAndDisk()
} else {
notice, err = getNewestNoticeFromDisk()
}

if err != nil {
return nil, err
}
return notice, nil
}

func getNoticeTimeout() time.Duration {
return time.Duration(setting.CacheTimeOutSecond) * time.Second
}

func getNewestNoticeFromDisk() (*Notice, error) {
log.Debug("Get notice from disk")
repoFile, err := models.ReadLatestFileInRepo(setting.UserNameOfNoticeRepo, setting.RepoNameOfNoticeRepo, setting.RefNameOfNoticeRepo, setting.TreePathOfNoticeRepo)
if err != nil {
log.Error("GetNewestNotice failed, error=%v", err)
return nil, err
}
notice := &Notice{}
json.Unmarshal(repoFile.Content, notice)
if notice.Title == "" {
return nil, err
}
notice.CommitId = repoFile.CommitId
return notice, nil
}

func getNewestNoticeFromCacheAndDisk() (*Notice, error) {
v, success := noticeCache.Get(NOTICE_CACHE_KEY)
if success {
log.Debug("Get notice from cache,value = %v", v)
if v == nil {
return nil, nil
}
n := v.(*Notice)
return n, nil
}

notice, err := getNewestNoticeFromDisk()
if err != nil {
log.Error("GetNewestNotice failed, error=%v", err)
noticeCache.Set(NOTICE_CACHE_KEY, nil, 30*time.Second)
return nil, err
}
noticeCache.Set(NOTICE_CACHE_KEY, notice, getNoticeTimeout())
return notice, nil
}

+ 8
- 0
routers/org/home.go View File

@@ -130,5 +130,13 @@ func Home(ctx *context.Context) {
pager.SetDefaultParams(ctx) pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager ctx.Data["Page"] = pager


//find org tag info
tags, err := models.GetAllOfficialTagRepos(org.ID, ctx.Org.IsOwner)
if err != nil {
ctx.ServerError("GetAllOfficialTagRepos", err)
return
}

ctx.Data["tags"] = tags
ctx.HTML(200, tplOrgHome) ctx.HTML(200, tplOrgHome)
} }

+ 90
- 0
routers/org/tag.go View File

@@ -0,0 +1,90 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package org

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context"
"errors"
"strconv"
)

const DefaultOrgTagLimit = -1

// SubmitTags submit repos of org tag
func SubmitTags(ctx *context.Context, form auth.SubmitReposOfTagForm) {
if !ctx.Org.IsOwner {
ctx.ServerError("UpdateTagReposByID", errors.New("no access to submit tags"))
return
}
tag := getTagFromContext(ctx)
if ctx.Written() {
return
}
if tag.Limit != DefaultOrgTagLimit && len(form.RepoList) > tag.Limit {
ctx.ServerError("UpdateTagReposByID", errors.New("tags size over limit"))
return
}
err := models.UpdateTagReposByID(tag.ID, ctx.Org.Organization.ID, form.RepoList)
if err != nil {
ctx.ServerError("UpdateTagReposByID", err)
return
}

ctx.JSON(200, map[string]interface{}{
"code": "00",
"msg": "success",
})
}

// GetTagRepos get repos under org tag
func GetTagRepos(ctx *context.Context) {
if !ctx.Org.IsOwner {
ctx.ServerError("GetTagRepos", errors.New("no access to get tags"))
return
}
tag := getTagFromContext(ctx)
if ctx.Written() {
return
}

r, err := models.GetTagRepos(tag.ID, ctx.Org.Organization.ID)
if err != nil {
ctx.ServerError("GetTagRepos", err)
return
}

ctx.JSON(200, map[string]interface{}{
"code": "00",
"msg": "success",
"data": r,
})
}

// getTagFromContext finds out tag info From context.
func getTagFromContext(ctx *context.Context) *models.OfficialTag {
var tag *models.OfficialTag
var err error

tagIdStr := ctx.Query("tagId")
if len(tagIdStr) == 0 {
ctx.ServerError("GetTagInfo", errors.New("tag is not exist"))
return nil
}
tagId, _ := strconv.ParseInt(tagIdStr, 10, 32)
tag, err = models.GetTagByID(tagId)
if err != nil {
if models.IsErrTagNotExist(err) {
ctx.NotFound("GetTagInfo", err)
} else {
ctx.ServerError("GetTagInfo", err)
}
return nil
}

return tag
}

+ 49
- 7
routers/repo/ai_model_manage.go View File

@@ -99,6 +99,18 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
//udpate status and version count //udpate status and version count
models.ModifyModelNewProperty(lastNewModelId, MODEL_NOT_LATEST, 0) models.ModifyModelNewProperty(lastNewModelId, MODEL_NOT_LATEST, 0)
} }
var units []models.RepoUnit
var deleteUnitTypes []models.UnitType
units = append(units, models.RepoUnit{
RepoID: ctx.Repo.Repository.ID,
Type: models.UnitTypeModelManage,
Config: &models.ModelManageConfig{
EnableModelManage: true,
},
})
deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeModelManage)

models.UpdateRepositoryUnits(ctx.Repo.Repository, units, deleteUnitTypes)


log.Info("save model end.") log.Info("save model end.")


@@ -130,10 +142,13 @@ func SaveModel(ctx *context.Context) {
version := ctx.Query("Version") version := ctx.Query("Version")
label := ctx.Query("Label") label := ctx.Query("Label")
description := ctx.Query("Description") description := ctx.Query("Description")
trainTaskCreate := ctx.QueryBool("trainTaskCreate")


if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.ServerError("No right.", errors.New(ctx.Tr("repo.model_noright")))
return
if !trainTaskCreate {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.ServerError("No right.", errors.New(ctx.Tr("repo.model_noright")))
return
}
} }


if JobId == "" || VersionName == "" { if JobId == "" || VersionName == "" {
@@ -474,6 +489,23 @@ func ShowOneVersionOtherModel(ctx *context.Context) {


func ShowModelTemplate(ctx *context.Context) { func ShowModelTemplate(ctx *context.Context) {
ctx.Data["isModelManage"] = true ctx.Data["isModelManage"] = true
repoId := ctx.Repo.Repository.ID
Type := -1
_, count, _ := models.QueryModel(&models.AiModelQueryOptions{
ListOptions: models.ListOptions{
Page: 1,
PageSize: 2,
},
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
})
ctx.Data["MODEL_COUNT"] = count

_, trainCount, _ := models.QueryModelTrainJobList(repoId)
log.Info("query train count=" + fmt.Sprint(trainCount))

ctx.Data["TRAIN_COUNT"] = trainCount
ctx.HTML(200, tplModelManageIndex) ctx.HTML(200, tplModelManageIndex)
} }


@@ -626,7 +658,6 @@ func QueryModelListForPredict(ctx *context.Context) {


func QueryModelFileForPredict(ctx *context.Context) { func QueryModelFileForPredict(ctx *context.Context) {
id := ctx.Query("ID") id := ctx.Query("ID")
parentDir := ctx.Query("parentDir")
model, err := models.QueryModelById(id) model, err := models.QueryModelById(id)
if err != nil { if err != nil {
log.Error("no such model!", err.Error()) log.Error("no such model!", err.Error())
@@ -634,9 +665,20 @@ func QueryModelFileForPredict(ctx *context.Context) {
return return
} }
prefix := model.Path[len(setting.Bucket)+1:] prefix := model.Path[len(setting.Bucket)+1:]
if parentDir != "" {
prefix = prefix + parentDir
}
fileinfos, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix) fileinfos, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix)
ctx.JSON(http.StatusOK, fileinfos) ctx.JSON(http.StatusOK, fileinfos)
} }

func QueryOneLevelModelFile(ctx *context.Context) {
id := ctx.Query("ID")
parentDir := ctx.Query("parentDir")
model, err := models.QueryModelById(id)
if err != nil {
log.Error("no such model!", err.Error())
ctx.ServerError("no such model:", err)
return
}
prefix := model.Path[len(setting.Bucket)+1:]
fileinfos, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir)
ctx.JSON(http.StatusOK, fileinfos)
}

+ 52
- 8
routers/repo/blame.go View File

@@ -6,13 +6,6 @@ package repo


import ( import (
"bytes" "bytes"
"container/list"
"fmt"
"html"
gotemplate "html/template"
"net/url"
"strings"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@@ -22,6 +15,12 @@ import (
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"container/list"
"fmt"
"html"
gotemplate "html/template"
"net/url"
"strings"
) )


const ( const (
@@ -35,7 +34,52 @@ func RefBlame(ctx *context.Context) {
ctx.NotFound("Blame FileName", nil) ctx.NotFound("Blame FileName", nil)
return return
} }

//get repo contributors info
contributors, err := git.GetContributors(ctx.Repo.Repository.RepoPath(), ctx.Repo.BranchName)
if err == nil && contributors != nil {
var contributorInfos []*ContributorInfo
contributorInfoHash := make(map[string]*ContributorInfo)
count := 0
for _, c := range contributors {
if count >= 25 {
continue
}
if strings.Compare(c.Email, "") == 0 {
continue
}
// get user info from committer email
user, err := models.GetUserByActivateEmail(c.Email)
if err == nil {
// committer is system user, get info through user's primary email
if existedContributorInfo, ok := contributorInfoHash[user.Email]; ok {
// existed: same primary email, different committer name
existedContributorInfo.CommitCnt += c.CommitCnt
} else {
// new committer info
var newContributor = &ContributorInfo{
user, user.RelAvatarLink(), user.Name, user.Email, c.CommitCnt,
}
count++
contributorInfos = append(contributorInfos, newContributor)
contributorInfoHash[user.Email] = newContributor
}
} else {
// committer is not system user
if existedContributorInfo, ok := contributorInfoHash[c.Email]; ok {
// existed: same primary email, different committer name
existedContributorInfo.CommitCnt += c.CommitCnt
} else {
var newContributor = &ContributorInfo{
user, "", "", c.Email, c.CommitCnt,
}
count++
contributorInfos = append(contributorInfos, newContributor)
contributorInfoHash[c.Email] = newContributor
}
}
}
ctx.Data["ContributorInfo"] = contributorInfos
}
userName := ctx.Repo.Owner.Name userName := ctx.Repo.Owner.Name
repoName := ctx.Repo.Repository.Name repoName := ctx.Repo.Repository.Name
commitID := ctx.Repo.CommitID commitID := ctx.Repo.CommitID


+ 158
- 79
routers/repo/cloudbrain.go View File

@@ -14,18 +14,17 @@ import (
"strings" "strings"
"time" "time"


"code.gitea.io/gitea/modules/modelarts"

"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/storage"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cloudbrain" "code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/util"
) )


const ( const (
@@ -206,7 +205,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
} }
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
downloadCode(repo, codePath) downloadCode(repo, codePath)
uploadCodeToMinio(codePath+"/", jobName, "/code/")
uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/")


modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/" modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/"
mkModelPath(modelPath) mkModelPath(modelPath)
@@ -220,7 +219,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
gpuType = gpuInfo.Value gpuType = gpuInfo.Value
} }
} }
downloadRateCode(repo, jobName, setting.BenchmarkOwner, setting.BrainScoreName, benchmarkPath, form.BenchmarkCategory, gpuType)
downloadRateCode(repo, jobName, setting.BenchmarkOwner, setting.BenchmarkName, benchmarkPath, form.BenchmarkCategory, gpuType)
uploadCodeToMinio(benchmarkPath+"/", jobName, cloudbrain.BenchMarkMountPath+"/") uploadCodeToMinio(benchmarkPath+"/", jobName, cloudbrain.BenchMarkMountPath+"/")
} }


@@ -236,15 +235,79 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
uploadCodeToMinio(brainScorePath+"/", jobName, cloudbrain.BrainScoreMountPath+"/") uploadCodeToMinio(brainScorePath+"/", jobName, cloudbrain.BrainScoreMountPath+"/")
} }


err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, getMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
getMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), getMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
getMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, resourceSpecId)
err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, resourceSpecId)
if err != nil { if err != nil {
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form)
return return
} }
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func CloudBrainRestart(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
var resultCode = "0"
var errorMsg = ""
var status = string(models.JobWaiting)

task := ctx.Cloudbrain
for {
if task.Status != string(models.JobStopped) && task.Status != string(models.JobSucceeded) && task.Status != string(models.JobFailed) {
log.Error("the job(%s) is not stopped", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not stopped"
break
}

if task.Image == "" || task.GpuQueue == "" || task.Type != models.TypeCloudBrainOne {
log.Error("the job(%s) version is too old", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job's version is too old and can not be restarted"
break
}

if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin()) {
log.Error("the user has no right ro restart the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to restart the job"
break
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have already a running or waiting task, can not create more"
break
}
}

err = cloudbrain.RestartTask(ctx, task, &jobID)
if err != nil {
log.Error("RestartTask failed:%v", err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

break
}

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
} }


func CloudBrainShow(ctx *context.Context) { func CloudBrainShow(ctx *context.Context) {
@@ -296,46 +359,19 @@ func CloudBrainShow(ctx *context.Context) {
} }


func CloudBrainDebug(ctx *context.Context) { func CloudBrainDebug(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
if !ctx.IsSigned {
log.Error("the user has not signed in")
ctx.Error(http.StatusForbidden, "", "the user has not signed in")
return
}
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}

debugUrl := setting.DebugServerHost + "jpylab_" + task.JobID + "_" + task.SubTaskName
debugUrl := setting.DebugServerHost + "jpylab_" + ctx.Cloudbrain.JobID + "_" + ctx.Cloudbrain.SubTaskName
ctx.Redirect(debugUrl) ctx.Redirect(debugUrl)
} }


func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrainForm) { func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrainForm) {
var jobID = ctx.Params(":jobid")
if !ctx.IsSigned {
log.Error("the user has not signed in")
ctx.Error(http.StatusForbidden, "", "the user has not signed in")
return
}
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.JSON(200, map[string]string{
"result_code": "-1",
"error_msg": "GetCloudbrainByJobID failed",
})
return
}

err = cloudbrain.CommitImage(jobID, models.CommitImageParams{
Ip: task.ContainerIp,
TaskContainerId: task.ContainerID,
err := cloudbrain.CommitImage(ctx.Cloudbrain.JobID, models.CommitImageParams{
Ip: ctx.Cloudbrain.ContainerIp,
TaskContainerId: ctx.Cloudbrain.ContainerID,
ImageDescription: form.Description, ImageDescription: form.Description,
ImageTag: form.Tag, ImageTag: form.Tag,
}) })
if err != nil { if err != nil {
log.Error("CommitImage(%s) failed:%v", task.JobName, err.Error(), ctx.Data["msgID"])
log.Error("CommitImage(%s) failed:%v", ctx.Cloudbrain.JobName, err.Error(), ctx.Data["msgID"])
ctx.JSON(200, map[string]string{ ctx.JSON(200, map[string]string{
"result_code": "-1", "result_code": "-1",
"error_msg": "CommitImage failed", "error_msg": "CommitImage failed",
@@ -351,32 +387,46 @@ func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrain


func CloudBrainStop(ctx *context.Context) { func CloudBrainStop(ctx *context.Context) {
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
var resultCode = "0"
var errorMsg = ""
var status = ""


if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) {
log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"])
ctx.ServerError("the job has been stopped", errors.New("the job has been stopped"))
return
}
task := ctx.Cloudbrain
for {
if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) {
log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}


err = cloudbrain.StopJob(jobID)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["msgID"])
ctx.ServerError("StopJob failed", err)
return
}
err := cloudbrain.StopJob(jobID)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}


task.Status = string(models.JobStopped)
err = models.UpdateJob(task)
if err != nil {
ctx.ServerError("UpdateJob failed", err)
return
task.Status = string(models.JobStopped)
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

status = task.Status
break
} }
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
} }


func StopJobsByUserID(userID int64) { func StopJobsByUserID(userID int64) {
@@ -423,7 +473,7 @@ func StopJobs(cloudBrains []*models.Cloudbrain) {
Action: models.ActionStop, Action: models.ActionStop,
} }
err := retry(3, time.Second*30, func() error { err := retry(3, time.Second*30, func() error {
_, err := modelarts.StopJob(taskInfo.JobID, param)
_, err := modelarts.ManageNotebook(taskInfo.JobID, param)
return err return err
}) })
logErrorAndUpdateJobStatus(err, taskInfo) logErrorAndUpdateJobStatus(err, taskInfo)
@@ -460,12 +510,7 @@ func logErrorAndUpdateJobStatus(err error, taskInfo *models.Cloudbrain) {
} }


func CloudBrainDel(ctx *context.Context) { func CloudBrainDel(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
task := ctx.Cloudbrain


if task.Status != string(models.JobStopped) && task.Status != string(models.JobFailed) { if task.Status != string(models.JobStopped) && task.Status != string(models.JobFailed) {
log.Error("the job(%s) has not been stopped", task.JobName, ctx.Data["msgID"]) log.Error("the job(%s) has not been stopped", task.JobName, ctx.Data["msgID"])
@@ -473,12 +518,14 @@ func CloudBrainDel(ctx *context.Context) {
return return
} }


err = models.DeleteJob(task)
err := models.DeleteJob(task)
if err != nil { if err != nil {
ctx.ServerError("DeleteJob failed", err) ctx.ServerError("DeleteJob failed", err)
return return
} }
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

deleteJobStorage(task.JobName, models.TypeCloudBrainOne)
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
} }


func CloudBrainShowModels(ctx *context.Context) { func CloudBrainShowModels(ctx *context.Context) {
@@ -560,7 +607,7 @@ func getImages(ctx *context.Context, imageType string) {


func GetModelDirs(jobName string, parentDir string) (string, error) { func GetModelDirs(jobName string, parentDir string) (string, error) {
var req string var req string
modelActualPath := getMinioPath(jobName, cloudbrain.ModelMountPath+"/")
modelActualPath := storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/")
if parentDir == "" { if parentDir == "" {
req = "baseDir=" + modelActualPath req = "baseDir=" + modelActualPath
} else { } else {
@@ -570,10 +617,6 @@ func GetModelDirs(jobName string, parentDir string) (string, error) {
return getDirs(req) return getDirs(req)
} }


func getMinioPath(jobName, suffixPath string) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath
}

func CloudBrainDownloadModel(ctx *context.Context) { func CloudBrainDownloadModel(ctx *context.Context) {
parentDir := ctx.Query("parentDir") parentDir := ctx.Query("parentDir")
fileName := ctx.Query("fileName") fileName := ctx.Query("fileName")
@@ -756,6 +799,35 @@ func mkModelPath(modelPath string) error {
return nil return nil
} }


func deleteJobStorage(jobName string, cloudbrainType int) error {
//delete local
localJobPath := setting.JobPath + jobName
err := os.RemoveAll(localJobPath)
if err != nil {
log.Error("RemoveAll(%s) failed:%v", localJobPath, err)
}

//delete oss
if cloudbrainType == models.TypeCloudBrainOne {
dirPath := setting.CBCodePathPrefix + jobName + "/"
err = storage.Attachments.DeleteDir(dirPath)
if err != nil {
log.Error("DeleteDir(%s) failed:%v", localJobPath, err)
}
} else if cloudbrainType == models.TypeCloudBrainTwo {
//dirPath := setting.CodePathPrefix + jobName + "/"
//err = storage.ObsRemoveObject(setting.Bucket, dirPath)
//if err != nil {
// log.Error("ObsRemoveObject(%s) failed:%v", localJobPath, err)
//}
log.Info("no need to delete")
} else {
log.Error("cloudbrainType(%d) error", cloudbrainType)
}

return nil
}

func SyncCloudbrainStatus() { func SyncCloudbrainStatus() {
cloudBrains, err := models.GetCloudBrainUnStoppedJob() cloudBrains, err := models.GetCloudBrainUnStoppedJob()
if err != nil { if err != nil {
@@ -827,6 +899,13 @@ func SyncCloudbrainStatus() {
task.Duration = result.Duration task.Duration = result.Duration
task.TrainJobDuration = result.TrainJobDuration task.TrainJobDuration = result.TrainJobDuration


if result.Duration != 0 {
task.TrainJobDuration = util.AddZero(result.Duration/3600000) + ":" + util.AddZero(result.Duration%3600000/60000) + ":" + util.AddZero(result.Duration%60000/1000)

} else {
task.TrainJobDuration = "00:00:00"
}

err = models.UpdateJob(task) err = models.UpdateJob(task)
if err != nil { if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err) log.Error("UpdateJob(%s) failed:%v", task.JobName, err)


+ 5
- 0
routers/repo/issue.go View File

@@ -13,6 +13,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"time"


"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
@@ -336,6 +337,7 @@ func issues(ctx *context.Context, milestoneID int64, isPullOption util.OptionalB


// Issues render issues page // Issues render issues page
func Issues(ctx *context.Context) { func Issues(ctx *context.Context) {
startTime := time.Now()
isPullList := ctx.Params(":type") == "pulls" isPullList := ctx.Params(":type") == "pulls"
if isPullList { if isPullList {
MustAllowPulls(ctx) MustAllowPulls(ctx)
@@ -366,6 +368,9 @@ func Issues(ctx *context.Context) {


ctx.Data["CanWriteIssuesOrPulls"] = ctx.Repo.CanWriteIssuesOrPulls(isPullList) ctx.Data["CanWriteIssuesOrPulls"] = ctx.Repo.CanWriteIssuesOrPulls(isPullList)


duration := time.Since(startTime)
log.Info("Issues cost: %v seconds", duration.Seconds())

ctx.HTML(200, tplIssues) ctx.HTML(200, tplIssues)
} }




+ 160
- 74
routers/repo/modelarts.go View File

@@ -11,11 +11,10 @@ import (
"strings" "strings"
"time" "time"


"code.gitea.io/gitea/modules/cloudbrain"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@@ -42,6 +41,7 @@ const (


func DebugJobIndex(ctx *context.Context) { func DebugJobIndex(ctx *context.Context) {
debugListType := ctx.Query("debugListType") debugListType := ctx.Query("debugListType")
ctx.Data["ListType"] = debugListType
MustEnableCloudbrain(ctx) MustEnableCloudbrain(ctx)
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
page := ctx.QueryInt("page") page := ctx.QueryInt("page")
@@ -49,12 +49,9 @@ func DebugJobIndex(ctx *context.Context) {
page = 1 page = 1
} }
debugType := modelarts.DebugType debugType := modelarts.DebugType
jobType := string(models.JobTypeDebug)
if debugListType == modelarts.GPUResource {
if debugListType == models.GPUResource {
debugType = models.TypeCloudBrainOne debugType = models.TypeCloudBrainOne
jobType = ""
}
if debugListType == modelarts.NPUResource {
} else if debugListType == models.NPUResource {
debugType = models.TypeCloudBrainTwo debugType = models.TypeCloudBrainTwo
} }


@@ -63,9 +60,10 @@ func DebugJobIndex(ctx *context.Context) {
Page: page, Page: page,
PageSize: setting.UI.IssuePagingNum, PageSize: setting.UI.IssuePagingNum,
}, },
RepoID: repo.ID,
Type: debugType,
JobType: jobType,
RepoID: repo.ID,
Type: debugType,
JobTypeNot: true,
JobType: string(models.JobTypeTrain),
}) })
if err != nil { if err != nil {
ctx.ServerError("Get debugjob faild:", err) ctx.ServerError("Get debugjob faild:", err)
@@ -73,21 +71,13 @@ func DebugJobIndex(ctx *context.Context) {
} }


for i, task := range ciTasks { for i, task := range ciTasks {
if task.Cloudbrain.Type == models.TypeCloudBrainOne {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = modelarts.GPUResource
}
if task.Cloudbrain.Type == models.TypeCloudBrainTwo {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = modelarts.NPUResource
}

ciTasks[i].CanDebug = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
} }


pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "debugListType", "ListType")
ctx.Data["Page"] = pager ctx.Data["Page"] = pager
ctx.Data["PageIsCloudBrain"] = true ctx.Data["PageIsCloudBrain"] = true
ctx.Data["Tasks"] = ciTasks ctx.Data["Tasks"] = ciTasks
@@ -150,13 +140,27 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm)
return return
} }
} }
_, err = models.GetCloudbrainByName(jobName)
if err == nil {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("the job name did already exist", tplModelArtsNotebookNew, &form)
return
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplModelArtsNotebookNew, &form)
return
}
}


err = modelarts.GenerateTask(ctx, jobName, uuid, description, flavor) err = modelarts.GenerateTask(ctx, jobName, uuid, description, flavor)
if err != nil { if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form) ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form)
return return
} }
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
} }


func NotebookShow(ctx *context.Context) { func NotebookShow(ctx *context.Context) {
@@ -202,11 +206,6 @@ func NotebookShow(ctx *context.Context) {


func NotebookDebug(ctx *context.Context) { func NotebookDebug(ctx *context.Context) {
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
_, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}


result, err := modelarts.GetJob(jobID) result, err := modelarts.GetJob(jobID)
if err != nil { if err != nil {
@@ -232,55 +231,118 @@ func NotebookDebug(ctx *context.Context) {
ctx.Redirect(debugUrl) ctx.Redirect(debugUrl)
} }


func NotebookStop(ctx *context.Context) {
func NotebookManage(ctx *context.Context) {
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
log.Info(jobID)
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
var action = ctx.Params(":action")
var resultCode = "0"
var errorMsg = ""
var status = ""


if task.Status != string(models.JobRunning) {
log.Error("the job(%s) is not running", task.JobName)
ctx.ServerError("the job is not running", errors.New("the job is not running"))
return
}
for {
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}


param := models.NotebookAction{
Action: models.ActionStop,
}
res, err := modelarts.StopJob(jobID, param)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err.Error())
ctx.ServerError("StopJob failed", err)
return
}
if action == models.ActionStop {
if task.Status != string(models.ModelArtsRunning) {
log.Error("the job(%s) is not running", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not running"
break
}


task.Status = res.CurrentStatus
err = models.UpdateJob(task)
if err != nil {
ctx.ServerError("UpdateJob failed", err)
return
if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin() && !ctx.IsUserRepoOwner()) {
log.Error("the user has no right ro stop the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to stop the job"
break
}
} else if action == models.ActionRestart {
if task.Status != string(models.ModelArtsStopped) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsCreateFailed) {
log.Error("the job(%s) is not stopped", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not stopped"
break
}

if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin()) {
log.Error("the user has no right ro restart the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to restart the job"
break
}

count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have already a running or waiting task, can not create more"
break
}
}

action = models.ActionStart
} else {
log.Error("the action(%s) is illegal", action, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "非法操作"
break
}

param := models.NotebookAction{
Action: action,
}
res, err := modelarts.ManageNotebook(jobID, param)
if err != nil {
log.Error("ManageNotebook(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "启动失败"
break
}

task.Status = res.CurrentStatus
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

status = task.Status

break
} }
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
} }


func NotebookDel(ctx *context.Context) { func NotebookDel(ctx *context.Context) {
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
task := ctx.Cloudbrain


if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped){
if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped) {
log.Error("the job(%s) has not been stopped", task.JobName) log.Error("the job(%s) has not been stopped", task.JobName)
ctx.ServerError("the job has not been stopped", errors.New("the job has not been stopped")) ctx.ServerError("the job has not been stopped", errors.New("the job has not been stopped"))
return return
} }


_, err = modelarts.DelNotebook(jobID)
_, err := modelarts.DelNotebook(jobID)
if err != nil { if err != nil {
log.Error("DelJob(%s) failed:%v", task.JobName, err.Error()) log.Error("DelJob(%s) failed:%v", task.JobName, err.Error())
ctx.ServerError("DelJob failed", err) ctx.ServerError("DelJob failed", err)
@@ -293,7 +355,7 @@ func NotebookDel(ctx *context.Context) {
return return
} }


ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
} }


func TrainJobIndex(ctx *context.Context) { func TrainJobIndex(ctx *context.Context) {
@@ -312,6 +374,7 @@ func TrainJobIndex(ctx *context.Context) {
}, },
RepoID: repo.ID, RepoID: repo.ID,
Type: models.TypeCloudBrainTwo, Type: models.TypeCloudBrainTwo,
JobTypeNot: false,
JobType: string(models.JobTypeTrain), JobType: string(models.JobTypeTrain),
IsLatestVersion: modelarts.IsLatestVersion, IsLatestVersion: modelarts.IsLatestVersion,
}) })
@@ -323,6 +386,7 @@ func TrainJobIndex(ctx *context.Context) {
for i, task := range tasks { for i, task := range tasks {
tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)
tasks[i].ComputeResource = models.NPUResource
} }


pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
@@ -364,7 +428,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error {
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = jobName ctx.Data["job_name"] = jobName


attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil { if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err) ctx.ServerError("GetAllUserAttachments failed:", err)
return err return err
@@ -433,7 +497,7 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = jobName ctx.Data["job_name"] = jobName


attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil { if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err) ctx.ServerError("GetAllUserAttachments failed:", err)
return err return err
@@ -521,7 +585,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error {
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = task.JobName ctx.Data["job_name"] = task.JobName


attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil { if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err) ctx.ServerError("GetAllUserAttachments failed:", err)
return err return err
@@ -610,7 +674,7 @@ func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrai
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = task.JobName ctx.Data["job_name"] = task.JobName


attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil { if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err) ctx.ServerError("GetAllUserAttachments failed:", err)
return err return err
@@ -1192,6 +1256,10 @@ func paramCheckCreateTrainJob(form auth.CreateModelArtsTrainJobForm) error {
log.Error("the WorkServerNumber(%d) must be in (1,25)", form.WorkServerNumber) log.Error("the WorkServerNumber(%d) must be in (1,25)", form.WorkServerNumber)
return errors.New("计算节点数必须在1-25之间") return errors.New("计算节点数必须在1-25之间")
} }
if form.BranchName == "" {
log.Error("the branch must not be null!", form.BranchName)
return errors.New("代码分支不能为空!")
}


return nil return nil
} }
@@ -1352,19 +1420,19 @@ func TrainJobDel(ctx *context.Context) {
} }
} }


//删除存储
if len(VersionListTasks) > 0 {
DeleteJobStorage(VersionListTasks[0].JobName)
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job")
} }


func TrainJobStop(ctx *context.Context) { func TrainJobStop(ctx *context.Context) {
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error())
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil)
return
}
task := ctx.Cloudbrain


_, err = modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10))
_, err := modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10))
if err != nil { if err != nil {
log.Error("StopTrainJob(%s) failed:%v", task.JobName, err.Error()) log.Error("StopTrainJob(%s) failed:%v", task.JobName, err.Error())
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil) ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil)
@@ -1477,3 +1545,21 @@ func ModelDownload(ctx *context.Context) {
} }
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
} }

func DeleteJobStorage(jobName string) error {
//delete local
localJobPath := setting.JobPath + jobName
err := os.RemoveAll(localJobPath)
if err != nil {
log.Error("RemoveAll(%s) failed:%v", localJobPath, err)
}

//delete oss
dirPath := setting.CodePathPrefix + jobName + "/"
err = storage.ObsRemoveObject(setting.Bucket, dirPath)
if err != nil {
log.Error("ObsRemoveObject(%s) failed:%v", localJobPath, err)
}

return nil
}

+ 126
- 0
routers/repo/user_data_analysis.go View File

@@ -15,6 +15,132 @@ import (
"github.com/360EntSecGroup-Skylar/excelize/v2" "github.com/360EntSecGroup-Skylar/excelize/v2"
) )


const (
PAGE_SIZE = 2000
)

func queryUserDataPage(ctx *context.Context, tableName string, queryObj interface{}) {
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}
userName := ctx.Query("userName")
IsReturnFile := ctx.QueryBool("IsReturnFile")

if IsReturnFile {
//writer exec file.
xlsx := excelize.NewFile()
sheetName := ctx.Tr("user.static.sheetname")
index := xlsx.NewSheet(sheetName)
xlsx.DeleteSheet("Sheet1")
dataHeader := map[string]string{
"A1": ctx.Tr("user.static.id"),
"B1": ctx.Tr("user.static.name"),
"C1": ctx.Tr("user.static.codemergecount"),
"D1": ctx.Tr("user.static.commitcount"),
"E1": ctx.Tr("user.static.issuecount"),
"F1": ctx.Tr("user.static.commentcount"),
"G1": ctx.Tr("user.static.focusrepocount"),
"H1": ctx.Tr("user.static.starrepocount"),
"I1": ctx.Tr("user.static.logincount"),
"J1": ctx.Tr("user.static.watchedcount"),
"K1": ctx.Tr("user.static.commitcodesize"),
"L1": ctx.Tr("user.static.solveissuecount"),
"M1": ctx.Tr("user.static.encyclopediascount"),
"N1": ctx.Tr("user.static.createrepocount"),
"O1": ctx.Tr("user.static.openiindex"),
"P1": ctx.Tr("user.static.registdate"),
"Q1": ctx.Tr("user.static.countdate"),
}
for k, v := range dataHeader {
//设置单元格的值
xlsx.SetCellValue(sheetName, k, v)
}
_, count := models.QueryUserStaticDataByTableName(1, 1, tableName, queryObj, userName)
var indexTotal int64
indexTotal = 0
for {
re, _ := models.QueryUserStaticDataByTableName(int(indexTotal), PAGE_SIZE, tableName, queryObj, "")
log.Info("return count=" + fmt.Sprint(count))
for i, userRecord := range re {
rows := fmt.Sprint(i + 2)
xlsx.SetCellValue(sheetName, "A"+rows, userRecord.ID)
xlsx.SetCellValue(sheetName, "B"+rows, userRecord.Name)
xlsx.SetCellValue(sheetName, "C"+rows, userRecord.CodeMergeCount)
xlsx.SetCellValue(sheetName, "D"+rows, userRecord.CommitCount)
xlsx.SetCellValue(sheetName, "E"+rows, userRecord.IssueCount)
xlsx.SetCellValue(sheetName, "F"+rows, userRecord.CommentCount)
xlsx.SetCellValue(sheetName, "G"+rows, userRecord.FocusRepoCount)
xlsx.SetCellValue(sheetName, "H"+rows, userRecord.StarRepoCount)
xlsx.SetCellValue(sheetName, "I"+rows, userRecord.LoginCount)
xlsx.SetCellValue(sheetName, "J"+rows, userRecord.WatchedCount)
xlsx.SetCellValue(sheetName, "K"+rows, userRecord.CommitCodeSize)
xlsx.SetCellValue(sheetName, "L"+rows, userRecord.SolveIssueCount)
xlsx.SetCellValue(sheetName, "M"+rows, userRecord.EncyclopediasCount)
xlsx.SetCellValue(sheetName, "N"+rows, userRecord.CreateRepoCount)
xlsx.SetCellValue(sheetName, "O"+rows, fmt.Sprintf("%.2f", userRecord.OpenIIndex))

formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3])

formatTime = userRecord.DataDate
xlsx.SetCellValue(sheetName, "Q"+rows, formatTime+" 00:01")
}

//设置默认打开的表单
xlsx.SetActiveSheet(index)
filename := sheetName + "_" + ctx.Tr("user.static."+tableName) + ".xlsx"
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
if _, err := xlsx.WriteTo(ctx.Resp); err != nil {
log.Info("writer exel error." + err.Error())
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
} else {
re, count := models.QueryUserStaticDataByTableName((page-1)*pageSize, pageSize, tableName, queryObj, userName)
mapInterface := make(map[string]interface{})
mapInterface["data"] = re
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
}
}

func QueryUserStaticCurrentMonth(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth))
}

func QueryUserStaticCurrentWeek(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_week", new(models.UserBusinessAnalysisCurrentWeek))
}

func QueryUserStaticCurrentYear(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_year", new(models.UserBusinessAnalysisCurrentYear))
}

func QueryUserStaticLast30Day(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_last30_day", new(models.UserBusinessAnalysisLast30Day))
}

func QueryUserStaticLastMonth(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_last_month", new(models.UserBusinessAnalysisLastMonth))
}

func QueryUserStaticYesterday(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_yesterday", new(models.UserBusinessAnalysisYesterday))
}

func QueryUserStaticAll(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_all", new(models.UserBusinessAnalysisAll))
}

func QueryUserStaticDataPage(ctx *context.Context) { func QueryUserStaticDataPage(ctx *context.Context) {
startDate := ctx.Query("startDate") startDate := ctx.Query("startDate")
endDate := ctx.Query("endDate") endDate := ctx.Query("endDate")


+ 13
- 7
routers/routes/routes.go View File

@@ -628,6 +628,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/org", func() { m.Group("/org", func() {
m.Group("/:org", func() { m.Group("/:org", func() {
m.Get("/members", org.Members) m.Get("/members", org.Members)
m.Group("/org_tag", func() {
m.Get("/repo_list", org.GetTagRepos)
m.Post("/repo_submit", bindIgnErr(auth.SubmitReposOfTagForm{}), org.SubmitTags)
})
}, context.OrgAssignment()) }, context.OrgAssignment())
}) })
m.Group("/org", func() { m.Group("/org", func() {
@@ -965,20 +969,21 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/cloudbrain", func() { m.Group("/cloudbrain", func() {
m.Group("/:jobid", func() { m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow) m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow)
m.Get("/debug", reqRepoCloudBrainWriter, repo.CloudBrainDebug)
m.Post("/commit_image", cloudbrain.AdminOrOwnerOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage)
m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainDebug)
m.Post("/commit_image", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainStop) m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainStop)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDel) m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDel)
m.Post("/restart", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainRestart)
m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate) m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate)
m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels) m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels)
m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDownloadModel)
m.Get("/download_model", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainDownloadModel)
}) })
m.Get("/create", reqRepoCloudBrainWriter, repo.CloudBrainNew) m.Get("/create", reqRepoCloudBrainWriter, repo.CloudBrainNew)
m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate)
}, context.RepoRef()) }, context.RepoRef())
m.Group("/modelmanage", func() { m.Group("/modelmanage", func() {
m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel) m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel)
m.Post("/create_new_model", reqRepoModelManageWriter, repo.SaveNewNameModel)
m.Post("/create_new_model", repo.SaveNewNameModel)
m.Delete("/delete_model", repo.DeleteModel) m.Delete("/delete_model", repo.DeleteModel)
m.Put("/modify_model", repo.ModifyModelInfo) m.Put("/modify_model", repo.ModifyModelInfo)
m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate)
@@ -990,6 +995,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList) m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList)
m.Get("/query_model_for_predict", reqRepoCloudBrainReader, repo.QueryModelListForPredict) m.Get("/query_model_for_predict", reqRepoCloudBrainReader, repo.QueryModelListForPredict)
m.Get("/query_modelfile_for_predict", reqRepoCloudBrainReader, repo.QueryModelFileForPredict) m.Get("/query_modelfile_for_predict", reqRepoCloudBrainReader, repo.QueryModelFileForPredict)
m.Get("/query_onelevel_modelfile", reqRepoCloudBrainReader, repo.QueryOneLevelModelFile)
m.Group("/:ID", func() { m.Group("/:ID", func() {
m.Get("", repo.ShowSingleModel) m.Get("", repo.ShowSingleModel)
m.Get("/downloadsingle", repo.DownloadSingleModelFile) m.Get("/downloadsingle", repo.DownloadSingleModelFile)
@@ -1005,8 +1011,8 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/notebook", func() { m.Group("/notebook", func() {
m.Group("/:jobid", func() { m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.NotebookShow) m.Get("", reqRepoCloudBrainReader, repo.NotebookShow)
m.Get("/debug", reqRepoCloudBrainWriter, repo.NotebookDebug)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookStop)
m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.NotebookDebug)
m.Post("/:action", reqRepoCloudBrainWriter, repo.NotebookManage)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel) m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel)
}) })
m.Get("/create", reqRepoCloudBrainWriter, repo.NotebookNew) m.Get("/create", reqRepoCloudBrainWriter, repo.NotebookNew)
@@ -1019,7 +1025,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow) m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobStop) m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobStop)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobDel) m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobDel)
m.Get("/model_download", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.ModelDownload)
m.Get("/model_download", cloudbrain.AdminOrJobCreaterRight, repo.ModelDownload)
m.Get("/create_version", cloudbrain.AdminOrJobCreaterRight, repo.TrainJobNewVersion) m.Get("/create_version", cloudbrain.AdminOrJobCreaterRight, repo.TrainJobNewVersion)
m.Post("/create_version", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) m.Post("/create_version", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion)
}) })


+ 1
- 2
services/repository/repository.go View File

@@ -5,13 +5,12 @@
package repository package repository


import ( import (
"fmt"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification"
repo_module "code.gitea.io/gitea/modules/repository" repo_module "code.gitea.io/gitea/modules/repository"
pull_service "code.gitea.io/gitea/services/pull" pull_service "code.gitea.io/gitea/services/pull"
"fmt"
) )


// CreateRepository creates a repository for the user/organization. // CreateRepository creates a repository for the user/organization.


+ 5
- 0
services/socketwrap/client.go View File

@@ -14,6 +14,11 @@ type Client struct {
Send chan *models.Action Send chan *models.Action
} }


func (c *Client) Close() {
close(c.Send)
c.Conn.Close()
}

func (c *Client) WritePump() { func (c *Client) WritePump() {


defer func() { defer func() {


+ 46
- 11
services/socketwrap/clientManager.go View File

@@ -1,11 +1,17 @@
package socketwrap package socketwrap


import ( import (
"os"
"os/signal"
"syscall"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"github.com/elliotchance/orderedmap"
) )


type ClientsManager struct { type ClientsManager struct {
Clients map[*Client]bool
Clients *orderedmap.OrderedMap
Register chan *Client Register chan *Client
Unregister chan *Client Unregister chan *Client
} }
@@ -14,33 +20,62 @@ func NewClientsManager() *ClientsManager {
return &ClientsManager{ return &ClientsManager{
Register: make(chan *Client), Register: make(chan *Client),
Unregister: make(chan *Client), Unregister: make(chan *Client),
Clients: make(map[*Client]bool),
Clients: orderedmap.NewOrderedMap(),
} }
} }


var LastTenActionsQueue = NewSyncQueue(10)
const MaxClients = 100

var LastActionsQueue = NewSyncQueue(20)


func (h *ClientsManager) Run() { func (h *ClientsManager) Run() {
initActionQueue()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
var signalsReceived uint
for { for {
select { select {
case client := <-h.Register: case client := <-h.Register:
h.Clients[client] = true
h.Clients.Set(client, true)
if h.Clients.Len() > MaxClients {
h.Clients.Delete(h.Clients.Front().Key)
}

case client := <-h.Unregister: case client := <-h.Unregister:
if _, ok := h.Clients[client]; ok {
delete(h.Clients, client)
if _, ok := h.Clients.Get(client); ok {
h.Clients.Delete(client)
close(client.Send) close(client.Send)
} }
case message := <-models.ActionChan: case message := <-models.ActionChan:
LastTenActionsQueue.Push(message)
for client := range h.Clients {
LastActionsQueue.Push(message)
for _, client := range h.Clients.Keys() {
select { select {
case client.Send <- message:
case client.(*Client).Send <- message:
default: default:
close(client.Send)
delete(h.Clients, client)
close(client.(*Client).Send)
h.Clients.Delete(client)
}
}
case s := <-sig:
log.Info("received signal", s)
signalsReceived++
if signalsReceived < 2 {
for _, client := range h.Clients.Keys() {
h.Clients.Delete(client)
client.(*Client).Close()
} }
break

} }
}
}
}


func initActionQueue() {
actions, err := models.GetLast20PublicFeeds()
if err == nil {
for i := len(actions) - 1; i >= 0; i-- {
LastActionsQueue.Push(actions[i])
} }
} }
} }

+ 7
- 0
templates/base/footer_content.tmpl View File

@@ -26,7 +26,14 @@
{{end}} {{end}}
</div> </div>
</div> </div>
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="ui item" target="_blank">{{.i18n.Tr "custom.Platform_Tutorial"}}</a>
{{if .EnableSwagger}}<a href="/api/swagger" class="ui item">API</a>{{end}} {{if .EnableSwagger}}<a href="/api/swagger" class="ui item">API</a>{{end}}
{{if .IsSigned}}
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class="ui item" target="_blank">{{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{else}}
<a href="{{AppSubUrl}}/user/login" class="ui item">{{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{end}}

{{template "custom/extra_links_footer" .}} {{template "custom/extra_links_footer" .}}
</div> </div>
</div> </div>


+ 6
- 0
templates/base/footer_content_fluid.tmpl View File

@@ -26,7 +26,13 @@
{{end}} {{end}}
</div> </div>
</div> </div>
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="ui item" target="_blank">{{.i18n.Tr "custom.Platform_Tutorial"}}</a>
{{if .EnableSwagger}}<a href="/api/swagger" class="ui item">API</a>{{end}} {{if .EnableSwagger}}<a href="/api/swagger" class="ui item">API</a>{{end}}
{{if .IsSigned}}
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class="ui item" target="_blank">{{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{else}}
<a href="{{AppSubUrl}}/user/login" class="ui item">{{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{end}}
{{template "custom/extra_links_footer" .}} {{template "custom/extra_links_footer" .}}
</div> </div>
</div> </div>


+ 44
- 2
templates/base/head.tmpl View File

@@ -186,7 +186,6 @@ var _hmt = _hmt || [];
})(); })();
</script> </script>
<script src="/self/func.js" type="text/javascript"></script> <script src="/self/func.js" type="text/javascript"></script>

</head> </head>
<body> <body>
{{template "custom/body_outer_pre" .}} {{template "custom/body_outer_pre" .}}
@@ -195,14 +194,57 @@ var _hmt = _hmt || [];
<noscript>{{.i18n.Tr "enable_javascript"}}</noscript> <noscript>{{.i18n.Tr "enable_javascript"}}</noscript>


{{template "custom/body_inner_pre" .}} {{template "custom/body_inner_pre" .}}
{{if not .PageIsInstall}} {{if not .PageIsInstall}}
<div class="ui top secondary stackable main menu following bar dark"> <div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar" .}} {{template "base/head_navbar" .}}
</div><!-- end bar --> </div><!-- end bar -->
<div class="notic_content" id ="notic_content" >
<a href={{.notice.Link}} class="a_width">
<marquee behavior="scroll" direction="left">
{{.notice.Title}}
</marquee>
</a>
<i class="icon icon-octicon x_icon" onclick="closeNoice()">{{svg "octicon-x" 16}}</i>
</div>
{{end}} {{end}}
{{/* {{/*
</div> </div>
</body> </body>
</html> </html>
*/}} */}}

<script>
function closeNoice(){
document.getElementById("notic_content").style.display='none'
localStorage.setItem("isCloseNotice",true)
}
function isShowNotice(){
var current_notice = localStorage.getItem("notice")

if (current_notice != "{{.notice.CommitId}}"){
localStorage.setItem('notice',"{{.notice.CommitId}}");
isNewNotice=true;
localStorage.setItem("isCloseNotice",false)
}else{
isNewNotice=false;
}
if ("{{.notice.Visible}}"){
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{
isCloseNotice = localStorage.getItem("isCloseNotice")
if (JSON.parse(isCloseNotice)){
document.getElementById("notic_content").style.display='none'
}else{
document.getElementById("notic_content").style.display='block'
}

}
}else{
document.getElementById("notic_content").style.display='none'
}
}
isShowNotice();
</script>

+ 43
- 0
templates/base/head_fluid.tmpl View File

@@ -200,9 +200,52 @@ var _hmt = _hmt || [];
<div class="ui top secondary stackable main menu following bar dark"> <div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar_fluid" .}} {{template "base/head_navbar_fluid" .}}
</div><!-- end bar --> </div><!-- end bar -->
<div class="notic_content" id ="notic_content" >
<a href={{.notice.Link}} class="a_width">
<marquee behavior="scroll" direction="left">
{{.notice.Title}}
</marquee>
</a>
<i class="icon icon-octicon x_icon" onclick="closeNoice()">{{svg "octicon-x" 16}}</i>
</div>
{{end}} {{end}}
{{/* {{/*
</div> </div>
</body> </body>
</html> </html>
*/}} */}}

<script>
function closeNoice(){
document.getElementById("notic_content").style.display='none'
localStorage.setItem("isCloseNotice",true)
}
function isShowNotice(){
var current_notice = localStorage.getItem("notice")

if (current_notice != "{{.notice.CommitId}}"){
localStorage.setItem('notice',"{{.notice.CommitId}}");
isNewNotice=true;
localStorage.setItem("isCloseNotice",false)
}else{
isNewNotice=false;
}
if ("{{.notice.Visible}}"){
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{
isCloseNotice = localStorage.getItem("isCloseNotice")
if (JSON.parse(isCloseNotice)){
document.getElementById("notic_content").style.display='none'
}else{
document.getElementById("notic_content").style.display='block'
}

}
}else{
document.getElementById("notic_content").style.display='none'
}
}
isShowNotice();
</script>

+ 13
- 10
templates/base/head_home.tmpl View File

@@ -186,24 +186,27 @@ var _hmt = _hmt || [];
s.parentNode.insertBefore(hm, s); s.parentNode.insertBefore(hm, s);
})(); })();
</script> </script>
<script src="/self/func.js" type="text/javascript"></script>
<!--RemixIcon Fonts v2.5.0-->
<link rel="stylesheet" href="/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css">
<!-- Swiper -->
<link rel="stylesheet" href="/swiper/swiper-bundle.min.css">
<script src="/swiper/swiper-bundle.min.js"></script>
</head> </head>
<body> <body>
{{template "custom/body_outer_pre" .}} {{template "custom/body_outer_pre" .}}


<div class="full height"> <div class="full height">
<noscript>{{.i18n.Tr "enable_javascript"}}</noscript> <noscript>{{.i18n.Tr "enable_javascript"}}</noscript>
<div class="ui vertical masthead secondary hometop segment">
{{template "custom/body_inner_pre" .}}


{{if not .PageIsInstall}}
<div class="ui container">
<div class="ui top secondary stackable main menu following bar">
{{template "base/head_navbar_home" .}}
</div><!-- end bar -->
</div>
{{end}}
{{template "custom/body_inner_pre" .}}
{{if not .PageIsInstall}}
<div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar" .}}
</div><!-- end bar -->
{{end}}
{{/* {{/*
</div>
</div> </div>
</body> </body>
</html> </html>


+ 10
- 0
templates/base/head_navbar.tmpl View File

@@ -168,6 +168,14 @@
{{svg "octicon-question" 16}} {{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help --> {{.i18n.Tr "help"}}<!-- Help -->
</a--> </a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
{{if .IsAdmin}} {{if .IsAdmin}}
<div class="divider"></div> <div class="divider"></div>


@@ -213,4 +221,6 @@
</div><!-- end anonymous right menu --> </div><!-- end anonymous right menu -->


{{end}} {{end}}

</div> </div>


+ 8
- 0
templates/base/head_navbar_fluid.tmpl View File

@@ -166,6 +166,14 @@
{{svg "octicon-question" 16}} {{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help --> {{.i18n.Tr "help"}}<!-- Help -->
</a--> </a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
{{if .IsAdmin}} {{if .IsAdmin}}
<div class="divider"></div> <div class="divider"></div>




+ 8
- 0
templates/base/head_navbar_home.tmpl View File

@@ -148,6 +148,14 @@
{{svg "octicon-question" 16}} {{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help --> {{.i18n.Tr "help"}}<!-- Help -->
</a--> </a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
{{if .IsAdmin}} {{if .IsAdmin}}
<div class="divider"></div> <div class="divider"></div>




+ 8
- 0
templates/base/head_navbar_pro.tmpl View File

@@ -169,6 +169,14 @@
{{svg "octicon-question" 16}} {{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help --> {{.i18n.Tr "help"}}<!-- Help -->
</a--> </a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
{{if .IsAdmin}} {{if .IsAdmin}}
<div class="divider"></div> <div class="divider"></div>




+ 44
- 0
templates/base/head_pro.tmpl View File

@@ -200,9 +200,53 @@ var _hmt = _hmt || [];
<div class="ui top secondary stackable main menu following bar dark"> <div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar_pro" .}} {{template "base/head_navbar_pro" .}}
</div><!-- end bar --> </div><!-- end bar -->
<div class="notic_content" id ="notic_content" >
<a href={{.notice.Link}} class="a_width">
<marquee behavior="scroll" direction="left">
{{.notice.Title}}
</marquee>
</a>
<i class="icon icon-octicon x_icon" onclick="closeNoice()">{{svg "octicon-x" 16}}</i>
</div>
{{end}} {{end}}
{{/* {{/*
</div> </div>
</body> </body>
</html> </html>
*/}} */}}


<script>
function closeNoice(){
document.getElementById("notic_content").style.display='none'
localStorage.setItem("isCloseNotice",true)
}
function isShowNotice(){
var current_notice = localStorage.getItem("notice")

if (current_notice != "{{.notice.CommitId}}"){
localStorage.setItem('notice',"{{.notice.CommitId}}");
isNewNotice=true;
localStorage.setItem("isCloseNotice",false)
}else{
isNewNotice=false;
}
if ("{{.notice.Visible}}"){
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{
isCloseNotice = localStorage.getItem("isCloseNotice")
if (JSON.parse(isCloseNotice)){
document.getElementById("notic_content").style.display='none'
}else{
document.getElementById("notic_content").style.display='block'
}

}
}else{
document.getElementById("notic_content").style.display='none'
}
}
isShowNotice();
</script>

+ 1
- 1
templates/base/paginate.tmpl View File

@@ -1,7 +1,7 @@
{{$paginationLink := .Page.GetParams}} {{$paginationLink := .Page.GetParams}}
{{with .Page.Paginater}} {{with .Page.Paginater}}
{{if gt .TotalPages 1}} {{if gt .TotalPages 1}}
<div class="center page buttons">
<div class="center page buttons" style="margin: 0px auto 15px">
<div class="ui borderless pagination menu"> <div class="ui borderless pagination menu">
<a class="{{if .IsFirst}}disabled{{end}} item navigation" {{if not .IsFirst}}href="{{$.Link}}{{if $paginationLink}}?{{$paginationLink}}{{end}}"{{end}}><i class="angle double left icon"></i><span class="navigation_label">&nbsp;{{$.i18n.Tr "admin.first_page"}}</span></a> <a class="{{if .IsFirst}}disabled{{end}} item navigation" {{if not .IsFirst}}href="{{$.Link}}{{if $paginationLink}}?{{$paginationLink}}{{end}}"{{end}}><i class="angle double left icon"></i><span class="navigation_label">&nbsp;{{$.i18n.Tr "admin.first_page"}}</span></a>
<a class="{{if not .HasPrevious}}disabled{{end}} item navigation" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}{{if $paginationLink}}&{{$paginationLink}}{{end}}"{{end}}> <a class="{{if not .HasPrevious}}disabled{{end}} item navigation" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}{{if $paginationLink}}&{{$paginationLink}}{{end}}"{{end}}>


+ 13
- 13
templates/explore/repo_list.tmpl View File

@@ -40,20 +40,20 @@


<div class="ui secondary pointing tabular top attached borderless menu navbar"> <div class="ui secondary pointing tabular top attached borderless menu navbar">
{{if .PageIsExplore}} {{if .PageIsExplore}}
<a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=hot">
<a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=hot&tab={{$.TabName}}">
<svg class="svg octicon-repo" width="16" height="16" aria-hidden="true"> <svg class="svg octicon-repo" width="16" height="16" aria-hidden="true">
<use xlink:href="#octicon-repo" /> <use xlink:href="#octicon-repo" />
</svg> </svg>
热门{{.i18n.Tr "explore.repos"}} 热门{{.i18n.Tr "explore.repos"}}
</a> </a>
<a class="{{if eq .SortType "active"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=active">
<a class="{{if eq .SortType "active"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=active&tab={{$.TabName}}">
<svg class="svg octicon-inbox" width="16" height="16" aria-hidden="true"> <svg class="svg octicon-inbox" width="16" height="16" aria-hidden="true">
<use xlink:href="#octicon-inbox" /> <use xlink:href="#octicon-inbox" />
</svg> </svg>
活跃{{.i18n.Tr "explore.repos"}} 活跃{{.i18n.Tr "explore.repos"}}
</a> </a>
{{end}} {{end}}
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=recentupdate">
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=recentupdate&tab={{$.TabName}}">
<svg class="svg octicon-organization" width="16" height="16" aria-hidden="true"> <svg class="svg octicon-organization" width="16" height="16" aria-hidden="true">
<use xlink:href="#octicon-organization" /> <use xlink:href="#octicon-organization" />
</svg> {{.i18n.Tr "repo.issues.filter_sort.recentupdate"}} </svg> {{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}
@@ -67,16 +67,16 @@
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
</span> </span>
<div class="menu"> <div class="menu">
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a>
<a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a>
<a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a>
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a>
<a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a>
<a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a>
</div> </div>
</div> </div>
</div> </div>


+ 1
- 1
templates/explore/repo_orgtop.tmpl View File

@@ -59,7 +59,7 @@
</div> </div>
<div class="swiper-slide"> <div class="swiper-slide">
<div class="ui card"> <div class="ui card">
<a class="image" href="https://git.openi.org.cn/TensorLayer">
<a class="image" href="https://git.openi.org.cn/OpenI/TensorLayerX">
<img src="/img/org-tensorlayer@2x-80.jpg" alt="TensorLayer" title="TensorLayer"> <img src="/img/org-tensorlayer@2x-80.jpg" alt="TensorLayer" title="TensorLayer">
</a> </a>
</div> </div>


+ 1
- 0
templates/explore/repo_search.tmpl View File

@@ -10,6 +10,7 @@
<div class="ui fluid action input"> <div class="ui fluid action input">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus> <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
<input type="hidden" name="topic" value="{{$.Topic}}"> <input type="hidden" name="topic" value="{{$.Topic}}">
<input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}"> <input type="hidden" name="sort" value="{{$.SortType}}">
<button class="ui green button">{{.i18n.Tr "explore.search"}}</button> <button class="ui green button">{{.i18n.Tr "explore.search"}}</button>
</div> </div>


+ 132
- 192
templates/home.tmpl View File

@@ -1,221 +1,161 @@
{{template "base/head_home" .}} {{template "base/head_home" .}}
<div class="ui container homebanner">
<h1 class="ui header">
启智AI开发协作平台
<div class="sub header">
面向AI领域的一站式协同开发环境
</div>
</h1>
<p class="am-lh-18">免费私有代码仓库,免费计算资源,大容量数据存储,<br>多类型硬件环境(GPU、NPU),AI开发流水线(开发-调试-训练-迭代)</p>
{{if .IsSigned}}
<a class="circular ui secondary button" href="{{AppSubUrl}}/dashboard">立即使用 <i class="right arrow icon"></i></a>
{{else}}
<a class="circular ui secondary button" href="{{AppSubUrl}}/user/login">立即使用 <i class="right arrow icon"></i></a>
{{end}}
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div>
</div>
</div><!-- end segment -->

<div class="explore repositories">
<div class="ui sticky container">
<div class="ui secondary pointing fluid five item menu" style="background-color: #FFF;">
<a class="item" href="#first">代码</a>
<a class="item" href="#second">数据</a>
<a class="item" href="#third">AI流水线</a>
<a class="item" href="#fourth">协同开发</a>
<a class="item" href="#fifth">云脑协同</a>
</div>
</div>

<div id="railContent">
<a name="first"></a>
<div class="ui container am-mt-30 basic tab i-code active" style="position: relative;">
<div class="ui inverted very padded segment radius15 am-pl-30">
<div class="ui mobile reversed stackable grid am-pl-30">
<div class="six wide column">
<h2 class="ui huge blue header">代码管理</h2>
<p class="am-lh-18">在这里为你和你的团队创建项目,基于Git工具,提交记录或者回滚代码修改。<br>
不论是公开或者私有仓库,都可免费使用所有功能。<br>
尽情将你喜欢的代码都放在这里,仓库数量、存储容量不受限</p>
{{if .IsSigned}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/dashboard">立即使用 </a>
{{else}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/user/login">立即使用 </a>
{{end}}
</div>
<div class="ten wide column computer only i-code-pic am-pt-30">
<img class="ui fluid rounded image am-shadow-2 am-mt-10" src="/img/i-code-pic.jpg" style="position: absolute;">
<div class="ui vertical masthead secondary hometop segment">
<div class="ui container" style="position: relative;">
<div class="ui center homebanner">
<h1 class="ui huge header">
{{.page_title}}
<div class="sub header">
{{.page_small_title}}
</div> </div>
</div>
</h1>
<p class="ui am-lh-18">{{.page_description}}</p>
{{if .IsSigned}}
<a class="circular huge ui secondary button" href="{{AppSubUrl}}/dashboard">{{.page_use}} <i class="right arrow icon"></i></a>
{{else}}
<a class="circular huge ui secondary button" href="{{AppSubUrl}}/user/login">{{.page_use}} <i class="right arrow icon"></i></a>
{{end}}
</div> </div>
<div class="am-mt-30 am-pt-30 am-pl-30">
<div class="am-pl-30 am-pb-30">
<h2 class="ui huge header am-bw">协作开发</h2>
<p class="am-lh-18">鼓励通过创建合并请求(PR)的方式,更好的进行团队协作<br>
代码评审让每一次的代码修改得以二次确认,提高代码质量<br>
创建并指派任务(Issue),让每一个任务的进展有迹可循,规范管理<br>
被合并的PR,可获得奖励积分;积分总额可以显示出你在项目中的贡献度,也许有一天会有人愿意为此付费<br>
</p>
</div>
</div>
<div class="leftline01"></div>
</div>

<a name="second"></a>
<div class="ui basic tab active am-mt-30 bg-gray am-pt-30">
<div class="ui container i-data" style="position: relative;">
<div class="leftline02"></div>
<div class="ui stackable grid">
<div class="nine wide column">
<img class="ui centered medium rounded large image" src="/img/gitopeni-index-02.svg">
<div class="i-code-pic" style="margin-top: -4.0rem;">
<img class="ui fluid rounded image am-shadow-2" src="/img/i-data-pic.jpg">
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div>
<div id="homenews" class="ui container">
<p>* {{.page_only_dynamic}}</p>
<div class="ui grid">
<div class="twelve wide tablet ten wide computer column homenews">
<div class="newslist">
<div class="ui mini aligned list swiper-wrapper" id="newmessage">
</div>
</div> </div>
</div> </div>
<div class="seven wide column am-pt-30">
<h2 class="ui huge blue header">数据集管理</h2>
<p class="am-lh-18">
数据是重要的生产要素,AI开发更是离不开数据;<br>
- 数据与模型代码的协同,可在项目中上传关联的数据集;<br>
- 数据存储免费,不限制文件大小;<br>
- 数据可共享,标注清洗过的公开数据集,用户可设置为公有数据,供社区用户下载;
</p>
<div class="am-mt-30 am-pt-20"></div>
<h2 class="ui huge header">使用数据集</h2>
<p class="am-lh-18">
数据集可以直接用于训练或者推理任务中<br>
创建任务时选择对应的数据集,启动任务执行环境(Docker)后,即可在Docker内访问到你的代码和数据,就像在你本地执行一样
</p>
</div>
</div>
</div><!-- end homenews -->
</div>
</div><!-- end segment -->

<!--组织-->
<div class="ui container homeorg">
<div class="ui stackable grid">
<div class="sixteen wide tablet four wide computer column homeorg-tit">
<h2>{{.page_recommend_org}}</h2>
<p><span class="ui text grey">{{.page_recommend_org_desc}}</span><a href="{{.RecommendURL}}">{{.page_recommend_org_commit}}</a></p>
<a href="{{AppSubUrl}}/explore/organizations" class="circular ui primary basic button">{{.page_recommend_org_more}} <i class="arrow circle right icon"></i></a>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="ui stackable three column grid homeorg-list" id="recommendorg">
</div> </div>
</div> </div>
</div>
</div>
<div class="leftline01"></div>
</div>
<!--项目-->
<div class="ui container homepro">
<div class="leftline02"></div>
<div class="leftline02-2"></div>
<div class="ui center homepro-tit am-mb-20">
<h2>{{.page_recommend_repo}}</h2>
<p><span class="ui text grey">{{.page_recommend_repo_desc}}</span><a href="{{.RecommendURL}}">{{.page_recommend_repo_commit}}</a>{{.page_recommend_repo_go}}<a href="{{AppSubUrl}}/explore/">{{.page_recommend_repo_more}}</a></p>
</div>


<a name="third"></a>
<div class="ui basic tab active container am-mt-30 am-pt-30">
<h2 class="ui center aligned huge blue header am-pt-30">
AI流水线
<div class="sub header am-mt-10">提供集代码开发、数据管理、模型调试、推理和评测为一体的AI开发流水线</div>
</h2>
<div class="ui divider"></div>
<div class="ui centered grid">
<div class="fourteen wide column">
<div class="ui two column grid">
<div class="column">
<div class="ui small header">调试任务:</div>
<div class="ui bulleted list">
<div class="item">配置模型运行环境;</div>
<div class="item">可在线编辑和调试模型代码,并将改动更新至代码仓库;</div>
<div class="item">基于编辑好的脚本,开展模型评测任务;</div>
</div>
</div>
<div class="column">
<div class="ui small header">作业任务:</div>
<div class="ui bulleted list">
<div class="item">利用已配置好的模型运行环境;</div>
<div class="item">基于编辑好的脚本,一键运行,开展模型训练或模型推理任务;</div>
</div>
</div>
</div>
</div>
<div class="homepro-list">
<div class="swiper-wrapper" id="recommendrepo">
</div> </div>
<div class="ui divider"></div>
<img class="ui centered image" src="/img/develop.svg">
<div class="swiper-pagination"></div>
</div> </div>
</div>


<a name="fourth"></a>
<div class="ui basic tab active container am-mt-30 am-pt-30 i-env">
<h2 class="ui center aligned huge blue header am-pt-30">
协同开发环境
<div class="sub header am-mt-10">启智AI协作开发平台与传统git平台最大的不同就在于提供了面向AI开发的协同开发环境</div>
</h2>
<div class="ui four stackable cards am-mt-20">
<div class="card">
<div class="image">
<img src="/img/i-pic-01.svg">

<a name="fourth"></a>
<div class="ui container i-env">
<div class="ui center am-pb-30">
<div class="leftline03"></div>
<h2>{{.page_dev_env}}</h2>
<p><span class="ui text grey">{{.page_dev_env_desc}}</p>
</div>
<div class="ui four stackable cards">
<div class="card">
<div class="image">
<img src="/img/i-pic-01.svg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc_title}}</h3>
<div class="description">
{{.page_dev_env_desc_desc}}
</div> </div>
<div class="content">
<h3 class="ui centered header">开发要素统一管理</h3>
<div class="description">
平台提供了AI开发四大要素:模型代码、数据集、模型和执行环境的统一管理
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-02.svg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc1_title}}</h3>
<div class="description">
{{.page_dev_env_desc1_desc}}
</div> </div>
</div> </div>
</div>
<div class="card"> <div class="card">
<div class="image">
<img src="/img/i-pic-02.svg">
</div>
<div class="content">
<h3 class="ui centered header">数据协同与共享</h3>
<div class="description">
通过在项目中上传数据集,项目成员多人协作完成数据预处理;也可以通过将数据设置为公有数据集,与社区开发者共同建立更好的模型
</div>
</div>
<div class="image">
<img src="/img/i-pic-03.svg">
</div> </div>
<div class="card">
<div class="image">
<img src="/img/i-pic-03.svg">
</div>
<div class="content">
<h3 class="ui centered header">模型管理与共享</h3>
<div class="description">
将模型与代码版本建立关联,可以基于代码历史版本,使用不同的方式调整模型,并将结果保存下来;训练好的模型可以开放共享,让更多人的使用模型测试并提出反馈
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc2_title}}</h3>
<div class="description">
{{.page_dev_env_desc2_desc}}
</div> </div>
</div> </div>
<div class="card">
<div class="image">
<img src="/img/i-pic-04.svg">
</div>
<div class="content">
<h3 class="ui centered header">一次配置,多次使用</h3>
<div class="description">
提供执行环境共享,一次配置,多次使用,降低模型开发门槛,避免花费重复的时间配置复杂的环境
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-04.svg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc3_title}}</h3>
<div class="description">
{{.page_dev_env_desc3_desc}}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>


<a name="fifth"></a>
<div class="ui basic tab active container am-mt-30 am-pt-30">
<div class="ui very padded black inverted segment radius15">
<div class="ui stackable grid">
<div class="six wide column">
<img class="ui centered large image" src="/img/i-yunnao.svg">
</div>
<div class="ten wide column am-pt-30">
<h2 class="ui huge blue header">鹏城云脑开源协同</h2>
<p class="am-lh-18">
平台已经与鹏城云脑打通,可以利用鹏城云脑的丰富算力资源,完成AI开发任务<br>
鹏城云脑现有AI算力100P FLOPS@FP16(每秒十亿亿次半精度浮点计算),主要硬件基础设施由搭载英伟达Tesla V100 的GPU服务器和搭载鲲鹏、昇腾处理器的Atlas 900 AI集群构成<br>
开发者可以根据使用需求,自由选择相应计算资源,可以测试模型在不同硬件环境下的适配能力、性能、稳定性等<br>
如果您的模型需要更多的计算资源,也可以单独申请<br>
</p>
{{if .IsSigned}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/dashboard">立即使用 </a><a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">单独申请</a>
{{else}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/user/login">立即使用 </a><a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">单独申请</a>
{{end}}
</div>
<a name="fifth"></a>
<div class="ui container">
<div class="ui very padded inverted segment radius15">
<div class="ui stackable grid">
<div class="six wide column">
<img class="ui centered large image" src="/img/i-yunnao.svg">
</div>
<div class="ten wide column am-pt-30">
<h2 class="ui grey inverted header">{{.page_dev_yunlao}}</h2>
<p class="am-lh-18 ui text grey">
{{.page_dev_yunlao_desc1}}<br>
{{.page_dev_yunlao_desc2}}<br>
{{.page_dev_yunlao_desc3}}<br>
{{.page_dev_yunlao_desc4}}<br>
</p>
{{if .IsSigned}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/dashboard">{{.page_use}}</a>
{{else}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/user/login">{{.page_use}}</a>
{{end}}
<a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">{{.page_dev_yunlao_apply}}</a>
</div> </div>
</div> </div>
</div> </div>
<div class="am-mt-30"></div>

</div><!-- end railContent -->
</div>
<div class="am-mt-30"></div>
<script src="/self/js/jquery.min.js" type="text/javascript"></script>
<script src="/home/home.js?v={{MD5 AppVer}}" type="text/javascript"></script>


</div><!-- end explore -->
<script>
$('.menu .item')
.tab();
$('.ui.sticky')
.sticky({
context: '#railContent',
observeChanges: true,
})
.sticky('refresh');
</script>


{{template "base/footer" .}} {{template "base/footer" .}}

+ 5
- 4
templates/org/home.tmpl View File

@@ -20,10 +20,11 @@
</div> </div>


<div class="ui container"> <div class="ui container">
<div class="ui stackable grid">
{{template "org/navber" .}}
<div class="ui fourteen wide computer column">
{{template "org/navber" .}}
{{template "org/select_pro" .}}
<div class="ui stackable grid">
<div class="ui sixteen wide computer column">
<div class="ui mobile reversed stackable grid"> <div class="ui mobile reversed stackable grid">
<div class="ui ten wide tablet eleven wide computer column"> <div class="ui ten wide tablet eleven wide computer column">
{{if .CanCreateOrgRepo}} {{if .CanCreateOrgRepo}}


+ 3
- 2
templates/org/member/members.tmpl View File

@@ -3,10 +3,11 @@
{{template "org/header" .}} {{template "org/header" .}}
<div class="ui container"> <div class="ui container">
{{template "base/alert" .}} {{template "base/alert" .}}
{{template "org/navber" .}}
<div class="ui stackable grid"> <div class="ui stackable grid">
{{template "org/navber" .}}
<div class="ui fourteen wide computer column list">
<div class="ui sixteen wide computer column list">
{{ range .Members}} {{ range .Members}}
<div class="item ui grid"> <div class="item ui grid">
<div class="ui two wide column"> <div class="ui two wide column">


+ 37
- 5
templates/org/navber.tmpl View File

@@ -1,4 +1,4 @@
<div class="tablet only mobile only sixteen wide mobile sixteen wide tablet column row">
<!-- <div class="tablet only mobile only sixteen wide mobile sixteen wide tablet column row">
<div class="ui secondary pointing tabular top attached borderless menu navbar"> <div class="ui secondary pointing tabular top attached borderless menu navbar">
<a class="{{if $.PageIsOrgHome}}active{{end}} item" href="{{.HomeLink}}"> <a class="{{if $.PageIsOrgHome}}active{{end}} item" href="{{.HomeLink}}">
{{svg "octicon-home" 16}}&nbsp;{{$.i18n.Tr "org.home"}} {{svg "octicon-home" 16}}&nbsp;{{$.i18n.Tr "org.home"}}
@@ -12,10 +12,10 @@
</a> </a>
{{end}} {{end}}
</div> </div>
</div>
</div> -->
<!--平板、移动端--> <!--平板、移动端-->
<div class="computer only two wide computer column">
<!-- <div class="computer only two wide computer column">
<div class="ui grid"> <div class="ui grid">
<div class="sixteen wide column ui secondary sticky pointing tabular vertical menu"> <div class="sixteen wide column ui secondary sticky pointing tabular vertical menu">
{{with .Org}} {{with .Org}}
@@ -33,5 +33,37 @@
{{end}} {{end}}
</div> </div>
</div> </div>
</div>
<!--电脑、宽屏-->
</div> -->
<!--电脑、宽屏-->
<style>
.dis{
margin-bottom: 10px;
}
.active{
color:#0366D6 !important;
}
.mleft{
margin-left: 30% !important;
}
.mbom{
margin-bottom: 10px !important;
}
</style>

<div class="row">
<div class="ui secondary pointing tabular top attached borderless menu navbar mbom">
{{with .Org}}
<a class="{{if $.PageIsOrgHome}}active{{end}} item mleft" href="{{.HomeLink}}">
{{svg "octicon-home" 16}}&nbsp;{{$.i18n.Tr "org.home"}}
</a>
{{end}}
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members">
{{svg "octicon-organization" 16}}&nbsp;{{$.i18n.Tr "org.people"}}
</a>
{{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}}
<a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams">
{{svg "octicon-jersey" 16}}&nbsp;{{$.i18n.Tr "org.teams"}}
</a>
{{end}}
</div>
</div>

+ 319
- 0
templates/org/select_pro.tmpl View File

@@ -0,0 +1,319 @@
<style>
.text-right{
float:right !important;
}
.header{
font-weight:bold;
font-size: 18px;
font-family: SourceHanSansSC-medium;
}
.cor{
color:#0366D6 !important;
}
.header_card{
/* color:#003A8C !important; */
color:#0366D6 !important;
margin: 10px 0 0px 0;
height: 25px;
}
.marg{
margin: 0 5px !important;
}

.content_list{
max-height: 130px;
overflow: auto;
}
.Relist{
color:#0366D6 !important;
}
.descript_height{
color: #101010 !important;
margin: 10px 0;
height: 40px !important;
word-break:break-all;
line-height: 20px;
overflow: hidden;
/* overflow: hidden!important;
word-wrap:break-word!important; */


}

.tags_height{
height: 30px !important;
}
.full_height{
height: 100%;
}
.omit{
overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
/deep/ ui.checkbox input[type=checkbox]::after{
border: 1px solid #0366D6 !important;
}
.nowrap-2 {
/* height: 2.837em; */
/* line-height: 1.4285em; */
overflow: hidden;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}


</style>
<div class="ui stackable grid">
<div style="width: 100%;margin:15px 0;">
{{if .tags}}
<span class="header">
精选项目
</span>
<!-- {{.IsOrganizationOwner}} -->
{{if .IsOrganizationOwner}}
<a class="text-right" id="model" onclick="showcreate()" >{{svg "octicon-gear" 16}}自定义</a>
{{end}}
{{end}}
</div>
<div style="width: 100%;">
{{ range .tags}}
{{if eq .TagName "精选项目"}}
<div class="ui three cards" style="margin-bottom: 10px;">
{{ range .RepoList}}
<div class="card" >
<div class="extra full_height cor" >
<div class=" header header_card omit" >
<a class="header_card image poping up " href="{{.Link}}" data-content="{{.Name}}" data-position="top left" data-variation="tiny inverted"> {{.Name}}</a>
</div>
<div class='content descript_height nowrap-2'>
{{.Description}}
</div>
<div class="content " >
{{if .Topics }}
<div class=" tags " style="position: relative;">
{{range .Topics}}
{{if ne . "" }}<a style="max-width:100%;margin: 5px 0;display:inline-flex;" href="{{AppSubUrl}}/explore/repos?q={{.}}&topic={{$.Topic}}" ><span class="ui small label topic omit" >{{.}}</span></a>{{end}}
{{end}}
</div>
{{end}}
</div>
</div>
<div class=" extra " style="color:#888888;border-top: none !important">
<div class="ui mini right compact marg" >
<a class="item marg ">
{{svg "octicon-eye" 16}} {{.NumWatches}}
</a>
<a class="item marg">
{{svg "octicon-star" 16}} {{.NumStars}}
</a>
<a class="item marg">
{{svg "octicon-git-branch" 16}} {{.NumForks}}
</a>
</div>
</div>
</div>
{{end}}
</div>
{{end}}
{{end}}

</div>

</div>

<div class="ui modal">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">自定义精选项目</h4>
</div>
<div class="content content-padding" style="color: black;">
<p>最多可选9个公开项目</p>
<div class="ui search" >
<div class="ui input" style="width: 100%;">
<input type="text" id = 'search_selectPro' placeholder="Search ..." value = '' oninput="search()">
</div>
</div>
<div style="margin: 10px ;">
<div id ='org_list' style="margin-bottom: 20px;"class="content_list" >

</div>
</div>
<p id='recommend'></p>
<div class="inline field" style="margin-left: 37%;">
<div class="actions">
<button id="submitId" type="button" class="ui create_train_job green deny button" onclick="saveSeletedPro(1)">
{{.i18n.Tr "explore.save"}}
</button>
<button class="ui button cancel" >{{.i18n.Tr "explore.cancel"}}</button>
</div>
</div>
</div>

</div>

<script>
var data;
var filterData=[];
var num=0;

function showcreate(obj){
document.getElementById("search_selectPro").value=''
$('.ui.modal')
.modal({
centered: false,
onShow:function(){
$("#org_list").empty()
getPro(1)
},
onHide:function(){
}
})
.modal('show')
}
function getPro(typeTag){

$.ajax({
type:"GET",
url:"/org/{{.Org.Name}}/org_tag/repo_list?tagId="+typeTag,
dataType:"json",
async:false,
success:function(json){
data = json.data;
var n_length = data.length
pro_html = getHTML(data)
$("#org_list").append(pro_html)
// console.log('原始',data)
checkedNum(0)
}
});
}
function getHTML(data){
let pro_html=''
for (let i=0;i<data.length;i++){
if (data[i].Selected==true){
console.log("data[i]:",data[i])
pro_html += `<div class="ui checkbox" style="width: 33%;margin-bottom:10px" > <input type="checkbox" id = " ${i}" checked="" onclick="checkedNum(${i})" class="Relist" name ='select_pro_name' data-repoid="${data[i].RepoID}" data-reponame="${data[i].RepoName}" data-selected=${data[i].Selected} > <label class='omit image poping up' data-content=${data[i].RepoName}  data-position="top left " data-variation="mini"> ${data[i].RepoName}</label></div>`
pro_html += '</div>'
}
else{
pro_html += `<div class="ui checkbox" style="width: 33%;margin-bottom:10px" > <input type="checkbox" id = "${i}" onclick="checkedNum(${i})" class="Relist" name ='select_pro_name' data-repoid="${data[i].RepoID}" data-reponame="${data[i].RepoName}" data-selected= ${data[i].Selected}> <label class='omit image poping up' data-content=${data[i].RepoName}  data-position="top left " data-variation="mini"> ${data[i].RepoName} </label></div>`
pro_html += '</div>'
}
}
return pro_html
}
function saveSeletedPro(typeTag){
var saveData=[];
$('input[name="select_pro_name"]:checked').each(function(){
console.log('值',this.dataset.repoid)

saveData.push(parseInt(this.dataset.repoid));
})
if(saveData.length>9){
alert("最多可选9个,保存失败")
return
}
// saveData = getSelecteDataID();
// console.log("数据:",saveData)
$.ajax({
type:"POST",
url:"/org/{{.Org.Name}}/org_tag/repo_submit?tagId="+typeTag,
contentType:'application/json',
dataType:"json",
async:false,
data:JSON.stringify({'repoList':saveData
}),
success:function(res){
console.log('保存成功');
location.reload()

}
});
}

function getSelecteData(){
var selectedData=[];
$('input[name="select_pro_name"]:checked').each(function(){
// console.log(this)
// console.log('值',this.dataset.selected)

selectedData.push({"RepoID":parseInt(this.dataset.repoid),"RepoName":this.dataset.reponame,"Selected":JSON.parse(this.dataset.selected)});
})
return selectedData
}
function search(){
var selectedData = getSelecteData();
var searchValue = document.getElementById("search_selectPro").value;
filterData=[];
console.log("searchValue:",searchValue)
for (let i=0;i<data.length;i++){
var isInclude=false;
if(data[i].RepoName.toLowerCase().includes(searchValue.toLowerCase())){
filterData.push(data[i])
}
}
console.log("选中的值:",selectedData)
console.log("筛选包括选中的值:",filterData)
var showData=[];
for(i=0;i<selectedData.length;i++){
filterData =filterData.filter((item)=>{
return item.RepoID!=selectedData[i].RepoID
});
}
console.log("筛选后不包括选中的值:",filterData)
$("#org_list").empty()
if(searchValue!=""){
if (filterData.length!=0){
var pro_html = getHTML(selectedData);
console.log("selectedData_pro_html:",pro_html)
$("#org_list").append(pro_html)
pro_html= getHTML(filterData);
$("#org_list").append(pro_html)
}else{
var pro_html = getHTML(selectedData);
$("#org_list").append(pro_html)
}
}else{
var pro_html = getHTML(data);
$("#org_list").append(pro_html)
}
}

function checkedNum(id){

num=0;
var inputs = document.getElementsByName("select_pro_name")
for (var i=0;i<inputs.length;i++){
if(inputs[i].checked){
num++
if(num>9){
document.getElementById(id).checked=false
alert("选择超过9个,请重新选择!")
return
}
}
}

var show_num = 9-num;
document.getElementById("recommend").innerHTML="还能推荐"+show_num+"个"

}

</script>

+ 3
- 3
templates/org/team/teams.tmpl View File

@@ -3,12 +3,12 @@
{{template "org/header" .}} {{template "org/header" .}}
<div class="ui container"> <div class="ui container">
{{template "base/alert" .}} {{template "base/alert" .}}
{{template "org/navber" .}}
<div class="ui stackable grid"> <div class="ui stackable grid">
{{template "org/navber" .}}
<div class="ui fourteen wide computer column list">
<div class="ui sixteen wide computer column list">
<div class="ui two column grid"> <div class="ui two column grid">
{{range .Teams}} {{range .Teams}}
<div class="column"> <div class="column">


+ 20
- 3
templates/repo/cloudbrain/new.tmpl View File

@@ -93,6 +93,14 @@
display: none; display: none;
} }


.icons{
/* position: absolute !important;
right: 150px;
top: 14px;
z-index: 2; */
}


</style> </style>


<div id="mask"> <div id="mask">
@@ -182,9 +190,10 @@
</select> </select>
</div> </div>


<div class="inline required field">
<div class="inline required field" style="position: relative;">
<label>镜像</label> <label>镜像</label>
<input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image" required autofocus maxlength="254"> <input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image" required autofocus maxlength="254">
<i class="times circle outline icon icons" style="visibility: hidden;" onclick="clearValue()"></i>
<datalist class="ui search" id="cloudbrain_image" style='width:385px;' name="image"> <datalist class="ui search" id="cloudbrain_image" style='width:385px;' name="image">
{{range .images}} {{range .images}}
<option name="image" value="{{.Place}}">{{.PlaceView}}</option> <option name="image" value="{{.Place}}">{{.PlaceView}}</option>
@@ -261,9 +270,17 @@
<script> <script>
let form = document.getElementById('form_id'); let form = document.getElementById('form_id');


$('#messageInfo').css('display','none')
let inputs = document.querySelectorAll('input[list]');
inputs[0].addEventListener('change', function() {
$(".icon.icons").css("visibility","visible")
});


$('#messageInfo').css('display','none')
function clearValue(){
context=inputs[0]
context.value=''
$(".icon.icons").css("visibility","hidden")
}
form.onsubmit = function(e){ form.onsubmit = function(e){
let value_task = $("input[name='job_name']").val() let value_task = $("input[name='job_name']").val()
let value_image = $("input[name='image']").val() let value_image = $("input[name='image']").val()


+ 147
- 46
templates/repo/debugjob/index.tmpl View File

@@ -202,14 +202,17 @@
<div class="rect5"></div> <div class="rect5"></div>
</div> </div>
</div> </div>
<!-- 提示框 -->
<div class="alert"></div>


<div class="alert"></div>
<div class="repository release dataset-list view"> <div class="repository release dataset-list view">
{{template "repo/header" .}} {{template "repo/header" .}}
{{template "base/alert" .}}
<!-- 提示框 -->
<!-- 列表容器 --> <!-- 列表容器 -->
<div class="ui container"> <div class="ui container">
<div class="ui two column stackable grid ">
<div class="ui two column stackable grid">
<div class="column"> <div class="column">
<div class="ui blue small menu compact selectcloudbrain"> <div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> <a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
@@ -282,7 +285,7 @@
<div class="row"> <div class="row">
<!-- 任务名 --> <!-- 任务名 -->
<div class="four wide column"> <div class="four wide column">
<a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}' title="{{.JobName}}" style="font-size: 14px;">
<a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}' title="{{.JobName}}" style="font-size: 14px;">
<span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span> <span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span>
</a> </a>
</div> </div>
@@ -315,34 +318,49 @@
</a> </a>
{{end}} --> {{end}} -->
<!-- 调试 --> <!-- 调试 -->
{{if .CanDebug}}
{{if eq .ComputeResource "CPU/GPU"}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
<form id="debugAgainForm-{{.JobID}}">
{{$.CsrfTokenHtml}}
{{if .CanDebug}}
{{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}}
<a style="margin: 0 1rem;" id="model-debug-{{.JobID}}" class='ui basic {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick='debugAgain("{{.JobID}}","{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/")'>
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}} disabled {{else}}blue {{end}}button' onclick='debugAgain("{{.JobID}}","{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/")'>
{{$.i18n.Tr "repo.debug_again"}}
</a>
{{end}}
{{else}} {{else}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
{{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug_again"}}
</a>
{{end}}
{{end}} {{end}}
{{else}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug"}}
</a>
{{end}}
</form>
<!-- 停止 --> <!-- 停止 -->
<form id="stopForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;">
<form id="stopForm-{{.JobID}}" style="margin-left:-1px;">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
{{if .CanDel}} {{if .CanDel}}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{if eq .ComputeResource "CPU/GPU" }}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' onclick='stopDebug("{{.JobID}}","{{$.RepoLink}}/cloudbrain/{{.JobID}}/stop")'>
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' onclick='stopDebug("{{.JobID}}","{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/stop")'>
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}
{{else}} {{else}}
<a class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.stop"}} {{$.i18n.Tr "repo.stop"}}
</a> </a>
{{end}} {{end}}
<input type="hidden" name="debugListType" value="all">
</form> </form>
<!-- 删除 --> <!-- 删除 -->
<form id="delForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/del" method="post"> <form id="delForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/del" method="post">
@@ -384,6 +402,13 @@
<a class="ui basic disabled button">{{$.i18n.Tr "repo.download"}}</a> <a class="ui basic disabled button">{{$.i18n.Tr "repo.download"}}</a>
{{end}} {{end}}
</div> </div>
{{if and (ne .JobType "DEBUG") (eq .Cloudbrain.Type 0)}}
<div class="item" style="padding: 0 !important;">
<a class="ui basic blue button" href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/rate" target="_blank">
评分
</a>
</div>
{{end}}
</div> </div>
</div> </div>
@@ -463,10 +488,21 @@


<script> <script>
// 调试和评分新开窗口 // 调试和评分新开窗口
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;
let url={{.RepoLink}} let url={{.RepoLink}}
let getParam=location.search.split('?debugListType=').pop()
let getParam=getQueryVariable('debugListType')
let dropdownValue = getParam==='all'||getParam==='' ? '全部' : getParam let dropdownValue = getParam==='all'||getParam==='' ? '全部' : getParam
localStorage.setItem('all',location.href) localStorage.setItem('all',location.href)
function getQueryVariable(variable)
{
let query = window.location.search.substring(1);
let vars = query.split("&");
for (let i=0;i<vars.length;i++) {
let pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
function stop(obj) { function stop(obj) {
if (obj.style.color != "rgb(204, 204, 204)") { if (obj.style.color != "rgb(204, 204, 204)") {
obj.target = '_blank' obj.target = '_blank'
@@ -489,6 +525,7 @@
onApprove: function() { onApprove: function() {
document.getElementById(delId).submit() document.getElementById(delId).submit()
flag = true flag = true
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
}, },
onHidden: function() { onHidden: function() {
if (flag == false) { if (flag == false) {
@@ -499,7 +536,68 @@
.modal('show') .modal('show')
} }
} }
function debugAgain(JobID,debugUrl){
if($('#' + JobID+ '-text').text()==="RUNNING"){
window.open(debugUrl+'debug')
}else{
$.ajax({
type:"POST",
url:debugUrl+'restart',
data:$('#debugAgainForm-'+JobID).serialize(),
success:function(res){
if(res.result_code==="0"){
if(res.job_id!==JobID){
location.reload()
}else{
$('#' + JobID+'-icon').removeClass().addClass(res.status)
$('#' + JobID+ '-text').text(res.status)
$('#model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#model-delete-'+JobID).removeClass('blue').addClass('disabled')
$('#model-debug-'+JobID).text("调试").css("margin","0 1rem")
}
}else{
$('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut();
}
},
error :function(res){
console.log(res)


}
})
}
}
function stopDebug(JobID,stopUrl){
$.ajax({
type:"POST",
url:stopUrl,
data:$('#stopForm-'+JobID).serialize(),
success:function(res){
if(res.result_code==="0"){
$('#' + JobID+'-icon').removeClass().addClass(res.status)
$('#' + JobID+ '-text').text(res.status)
if(res.status==="STOPPED"){
$('#model-debug-'+JobID).removeClass('disabled').addClass('blue').text("再次调试").css("margin","0")
$('#model-image-'+JobID).removeClass('blue').addClass('disabled')
$('#stop-model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#model-delete-'+JobID).removeClass('disabled').addClass('blue')
}
else{
$('#model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#stop-model-debug-'+JobID).removeClass('blue').addClass('disabled')
}
}else{
$('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut();
}
},
error :function(res){
console.log(res)

}
})

}
// 加载任务状态 // 加载任务状态
var timeid = window.setInterval(loadJobStatus, 15000); var timeid = window.setInterval(loadJobStatus, 15000);
$(document).ready(loadJobStatus); $(document).ready(loadJobStatus);
@@ -508,8 +606,9 @@
const jobID = job.dataset.jobid; const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath; const repoPath = job.dataset.repopath;
const computeResource = job.dataset.resource const computeResource = job.dataset.resource
const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED']
const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED']
if (initArray.includes(job.textContent.trim())) { if (initArray.includes(job.textContent.trim())) {
return return
} }
const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain' const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain'
@@ -521,32 +620,30 @@
$('#' + jobID+ '-text').text(status) $('#' + jobID+ '-text').text(status)
} }
if(status==="RUNNING"){ if(status==="RUNNING"){
$('#model-debug-'+jobID).removeClass('disabled')
$('#model-debug-'+jobID).addClass('blue')
$('#model-image-'+jobID).removeClass('disabled')
$('#model-image-'+jobID).addClass('blue')
$('#model-debug-'+jobID).removeClass('disabled').addClass('blue').text('调试').css("margin","0 1rem")
$('#model-image-'+jobID).removeClass('disabled').addClass('blue')
} }
if(status!=="RUNNING"){ if(status!=="RUNNING"){
$('#model-debug-'+jobID).removeClass('blue')
$('#model-debug-'+jobID).addClass('disabled')
$('#model-image-'+jobID).removeClass('blue')
$('#model-image-'+jobID).addClass('disabled')

// $('#model-debug-'+jobID).removeClass('blue')
// $('#model-debug-'+jobID).addClass('disabled')
$('#model-image-'+jobID).removeClass('blue').addClass('disabled')
}
if(["CREATING","STOPPING","WAITING","STARTING"].includes(status)){
$('#model-debug-'+jobID).removeClass('blue').addClass('disabled')
}
if(['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED'].includes(status)){
$('#model-debug-'+jobID).removeClass('disabled').addClass('blue').text('再次调试').css("margin","0")
} }
if(["RUNNING","WAITING"].includes(status)){ if(["RUNNING","WAITING"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('disabled')
$('#stop-model-debug-'+jobID).addClass('blue')
$('#stop-model-debug-'+jobID).removeClass('disabled').addClass('blue')
} }
if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('blue')
$('#stop-model-debug-'+jobID).addClass('disabled')
if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED","SUCCEEDED"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('blue').addClass('disabled')
} }
if(status==="STOPPED" || status==="FAILED"|| status==="START_FAILED"){ if(status==="STOPPED" || status==="FAILED"|| status==="START_FAILED"){
$('#model-delete-'+jobID).removeClass('disabled')
$('#model-delete-'+jobID).addClass('blue')
$('#model-delete-'+jobID).removeClass('disabled').addClass('blue')
}else{ }else{
$('#model-delete-'+jobID).removeClass('blue')
$('#model-delete-'+jobID).addClass('disabled')
$('#model-delete-'+jobID).removeClass('blue').addClass('disabled')
} }
}).fail(function(err) { }).fail(function(err) {
console.log(err); console.log(err);
@@ -554,6 +651,7 @@
}); });
}; };
$(document).ready(function(){ $(document).ready(function(){
dropdownValue = dropdownValue==="CPU%2FGPU"? 'CPU/GPU' : dropdownValue
$('.default.text').text(dropdownValue) $('.default.text').text(dropdownValue)
$('.ui.dropdown') $('.ui.dropdown')
.dropdown({ .dropdown({
@@ -564,6 +662,12 @@
location.href = `${url}/debugjob?debugListType=${value}` location.href = `${url}/debugjob?debugListType=${value}`
} }
}) })
$('.message .close')
.on('click', function() {
$(this)
.closest('.message')
.transition('fade')
})
}) })
@@ -601,7 +705,6 @@
// 显示弹窗,弹出相应的信息 // 显示弹窗,弹出相应的信息
function showmask() { function showmask() {
var image_tag = !$('#image_tag').val() var image_tag = !$('#image_tag').val()
console.log("image_tag",image_tag)
if(image_tag){ if(image_tag){
return return
} }
@@ -612,8 +715,6 @@
var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML;  var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML; 
var json1 = JSON.parse(responseText) var json1 = JSON.parse(responseText)
$('#mask').css('display', 'none') $('#mask').css('display', 'none')
parent.location.href

if (json1.result_code === "0") { if (json1.result_code === "0") {
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut(); $('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
} else { } else {


+ 3
- 3
templates/repo/header.tmpl View File

@@ -51,7 +51,7 @@
</div> </div>
{{if not .IsBeingCreated}} {{if not .IsBeingCreated}}
<div class="repo-buttons"> <div class="repo-buttons">
<form method="post" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}">
<form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<div class="ui labeled button" tabindex="0"> <div class="ui labeled button" tabindex="0">
<button type="submit" class="ui compact basic button"> <button type="submit" class="ui compact basic button">
@@ -62,7 +62,7 @@
</a> </a>
</div> </div>
</form> </form>
<form method="post" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}">
<form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<div class="ui labeled button" tabindex="0"> <div class="ui labeled button" tabindex="0">
<button type="submit" class="ui compact basic button"> <button type="submit" class="ui compact basic button">
@@ -181,4 +181,4 @@
</div> </div>




<script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
<script src="{{StaticUrlPrefix}}/js/jquery.js?v={{MD5 AppVer}}"></script>

+ 1
- 0
templates/repo/issue/list.tmpl View File

@@ -4,6 +4,7 @@
} }
.ovfl{ .ovfl{
overflow-y:hidden !important; overflow-y:hidden !important;
min-width: 140px!important;
} }
</style> </style>
{{template "base/head" .}} {{template "base/head" .}}


+ 6
- 24
templates/repo/modelarts/trainjob/index.tmpl View File

@@ -121,7 +121,7 @@
</div> </div>
<!-- 任务运行时间 --> <!-- 任务运行时间 -->
<div class="two wide column text center padding0"> <div class="two wide column text center padding0">
<span style="font-size: 12px;" id="duration-{{.JobID}}"></span>
<span style="font-size: 12px;" id="duration-{{.JobID}}">{{.TrainJobDuration}}</span>
</div> </div>
<!-- 计算资源 --> <!-- 计算资源 -->
<div class="two wide column text center padding0"> <div class="two wide column text center padding0">
@@ -253,35 +253,18 @@
} }
} }


function loadJobDuration() {
$(".job-status").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const versionname = job.dataset.version
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
console.log(data)
const duration = data.JobDuration
const jobID = data.JobID
$('#duration-'+jobID).text(duration)
})
})
}
$(document).ready(loadJobDuration);
// 加载任务状态 // 加载任务状态
var timeid = window.setInterval(loadJobStatus, 15000); var timeid = window.setInterval(loadJobStatus, 15000);
$(document).ready(loadJobStatus); $(document).ready(loadJobStatus);
function loadJobStatus() { function loadJobStatus() {
$(".job-status").each((index, job) => { $(".job-status").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const jobID = job.dataset.jobid
const repoPath = job.dataset.repopath
const versionname = job.dataset.version const versionname = job.dataset.version
if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
|| job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
|| job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
return
const status_text = $(`#${jobID}-text`).text()
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'].includes(status_text)){
return
} }

$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { $.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
const jobID = data.JobID const jobID = data.JobID
const status = data.JobStatus const status = data.JobStatus
@@ -329,7 +312,6 @@
} }
} }
function stopVersion(version_name,jobID){ function stopVersion(version_name,jobID){
const url = '/api/v1/repos/{{$.RepoRelPath}}/modelarts/train-job/'+jobID+'/stop_version' const url = '/api/v1/repos/{{$.RepoRelPath}}/modelarts/train-job/'+jobID+'/stop_version'
$.post(url,{version_name:version_name},(data)=>{ $.post(url,{version_name:version_name},(data)=>{
if(data.StatusOK===0){ if(data.StatusOK===0){


+ 142
- 8
templates/repo/modelarts/trainjob/show.tmpl View File

@@ -161,6 +161,15 @@ td, th {
padding-top: 0.5rem ; padding-top: 0.5rem ;
} }
</style> </style>
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository"> <div class="repository">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="ui container"> <div class="ui container">
@@ -186,6 +195,12 @@ td, th {
<span class="accordion-panel-title-content"> <span class="accordion-panel-title-content">
<span> <span>
<div style="float: right;"> <div style="float: right;">
{{$.CsrfTokenHtml}}
{{if .CanModify}}
<a class="ti-action-menu-item" onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{else}}
<a class="ti-action-menu-item disabled">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{end}}
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
{{if .CanModify}} {{if .CanModify}}
<a class="ti-action-menu-item" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a> <a class="ti-action-menu-item" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a>
@@ -446,11 +461,66 @@ td, th {
</div> </div>
</div> </div>
</div> </div>
<!-- 创建模型 -->
<div id="newmodel">
<div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">导入新模型</h4>
</div>
<div class="content content-padding">
<form id="formId" method="POST" class="ui form">
<div class="ui error message">
</div>
{{$.CsrfTokenHtml}}
<input type="hidden" name="trainTaskCreate" value="true">

<div class="two inline fields ">
<div class="required ten wide field">
<label style="margin-left: -23px;">选择训练任务</label>
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required>
<input class="width83" id="JobName" readonly required>
</div>
<div class="required six widde field">
<label>版本</label>
<input class="width70" id="VersionName" name="VersionName" readonly required>
</div>
</div>
<div class="required inline field" id="modelname">
<label>模型名称</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
<div class="required inline field" id="verionname">
<label>模型版本</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
</div>
<div class="inline field">
<label>模型标签</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
<div class="inline field">
<label for="description">模型描述</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea>
</div>
<div class="inline field" style="margin-left: 75px;">
<button onclick="createModel()" id="submitId" type="button" class="ui create_train_job green button" style="position: absolute;">
{{.i18n.Tr "repo.model.manage.sava_model"}}
</button>
</div>
</form>
<div class="actions" style="display: inline-block;margin-left: 180px;">
<button class="ui button cancel" >{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
</div>
</div>
</div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}


<script> <script>
console.log({{.version_list_task}})
$('.menu .item').tab() $('.menu .item').tab()


$(document).ready(function(){ $(document).ready(function(){
@@ -480,7 +550,61 @@ td, th {
} }
let timeid = window.setInterval(loadJobStatus, 30000); let timeid = window.setInterval(loadJobStatus, 30000);
$(document).ready(loadJobStatus); $(document).ready(loadJobStatus);
function showcreate(obj){
$('.ui.modal.second')
.modal({
centered: false,
onShow:function(){
$('input[name="Version"]').addClass('model_disabled')
// $('input[name="JobId"]').text(obj.JobName)
$('#JobName').val(obj.JobName).addClass('model_disabled')
$('input[name="JobId"]').val(obj.JobID)
$('input[name="VersionName"]').val(obj.VersionName).addClass('model_disabled')
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"})
createModelName()
},
onHide:function(){
document.getElementById("formId").reset();
$('.ui.dimmer').css({"background-color":""})
$('.ui.error.message').text()
$('.ui.error.message').css('display','none')
}
})
.modal('show')
}
function createModel(){
let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model`
let data = $("#formId").serialize()
$("#mask").css({"display":"block","z-index":"9999"})
$.ajax({
url:url_href,
type:'POST',
data:data,
success:function(res){
location.href=`/${userName}/${repoPath}/modelmanage/show_model`
$('.ui.modal.second').modal('hide')
},
error: function(xhr){
// 隐藏 loading
// 只有请求不正常(状态码不为200)才会执行
$('.ui.error.message').text(xhr.responseText)
$('.ui.error.message').css('display','block')
},
complete:function(xhr){
$("#mask").css({"display":"none","z-index":"1"})
}
})
}
function createModelName(){
let repoName = location.pathname.split('/')[2]
let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4)
$('#name').val(modelName)
$('#version').val("0.0.1")
}
function renderSize(value){ function renderSize(value){
if(null==value||value==''){ if(null==value||value==''){
return "0 Bytes"; return "0 Bytes";
@@ -495,14 +619,19 @@ td, th {
} }
function loadJobStatus() { function loadJobStatus() {
$(".ui.accordion.border-according").each((index, job) => { $(".ui.accordion.border-according").each((index, job) => {
const jobID = job.dataset.jobid; const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath; const repoPath = job.dataset.repopath;
const versionname = job.dataset.version const versionname = job.dataset.version
if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
|| job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
|| job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
return
// ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED']
// if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
// || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
// || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
// return
// }
let status = $(`#${versionname}-status-span`).text()
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'].includes(status)){
return
} }
let stopArray=["KILLED","FAILED","START_FAILED","KILLING","COMPLETED"] let stopArray=["KILLED","FAILED","START_FAILED","KILLING","COMPLETED"]
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { $.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
@@ -663,7 +792,12 @@ td, th {
html += "</span>" html += "</span>"
html += "</td>" html += "</td>"
html += "<td class='message seven wide'>" html += "<td class='message seven wide'>"
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
if(data.Dirs[i].IsDir){
html += "<span class='truncate has-emoji'></span>"
}else{
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
}
html += "</td>" html += "</td>"


html += "<td class='text right age three wide'>" html += "<td class='text right age three wide'>"


+ 18
- 6
templates/repo/modelmanage/index.tmpl View File

@@ -17,16 +17,30 @@
<div class="repository release dataset-list view"> <div class="repository release dataset-list view">
{{template "repo/header" .}} {{template "repo/header" .}}
<!-- 列表容器 --> <!-- 列表容器 -->
<div class="ui container active loader" id="loadContainer">
<div class="ui container {{if ne $.MODEL_COUNT 0}}active loader {{end}}" id="loadContainer">
{{template "base/alert" .}} {{template "base/alert" .}}
<div class="ui two column stackable grid" style="display: none;">
<div class="ui two column stackable grid">
<div class="column"></div> <div class="column"></div>
<div class="column right aligned"> <div class="column right aligned">
<!-- --> <!-- -->
<a class="ui button {{if .Permission.CanWrite $.UnitTypeCloudBrain}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a> <a class="ui button {{if .Permission.CanWrite $.UnitTypeCloudBrain}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a>
</div> </div>
</div> </div>

{{if eq $.MODEL_COUNT 0}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过模型</div>
<div class="bgtask-content">
{{if $.RepoIsEmpty}}
<div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本;</a></div>
{{end}}
{{if eq $.TRAIN_COUNT 0}}
<div class="bgtask-content-txt">训练任务:您还没创建过训练任务,请先创建<a href="{{.RepoLink}}/modelarts/train-job">训练任务</a>。</div>
{{end}}
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div>
</div>
</div>
{{else}}
<!-- 中下列表展示区 --> <!-- 中下列表展示区 -->
<div class="ui grid" style="display: none;"> <div class="ui grid" style="display: none;">
<div class="row" style="padding-top: 0;"> <div class="row" style="padding-top: 0;">
@@ -38,6 +52,7 @@
</div> </div>
</div> </div>
</div> </div>
{{end}}


</div> </div>


@@ -89,7 +104,6 @@
<div class="menu" id="job-name"> <div class="menu" id="job-name">
</div> </div>
</div> </div>
</div> </div>
<div class="required six widde field"> <div class="required six widde field">
<label>版本</label> <label>版本</label>
@@ -103,7 +117,6 @@
</div> </div>
</div> </div>
</div> </div>

<div class="required inline field" id="modelname"> <div class="required inline field" id="modelname">
<label>模型名称</label> <label>模型名称</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')"> <input style="width: 45%;" id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
@@ -141,7 +154,6 @@
<script> <script>
let repolink = {{.RepoLink}} let repolink = {{.RepoLink}}
let repoId = {{$repository}} let repoId = {{$repository}}
let url_href = window.location.pathname.split('show_model')[0] + 'create_model'
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config;
$('input[name="_csrf"]').val(csrf) $('input[name="_csrf"]').val(csrf)




+ 265
- 66
templates/repo/modelmanage/showinfo.tmpl View File

@@ -69,7 +69,7 @@
<!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> --> <!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> -->
<div class="ui breadcrumb"> <div class="ui breadcrumb">
<a class="section" href="{{$.RepoLink}}/modelmanage/show_model"> <a class="section" href="{{$.RepoLink}}/modelmanage/show_model">
模型管理
{{$.i18n.Tr "repo.model.manage.model_manage"}}
</a> </a>
<div class="divider"> / </div> <div class="divider"> / </div>
<div class="active section">{{.name}}</div> <div class="active section">{{.name}}</div>
@@ -78,67 +78,121 @@
</select> </select>
</h4> </h4>
<div id="showInfo" style="border:1px solid #e2e2e2;padding: 20px 60px;margin-top:24px"> <div id="showInfo" style="border:1px solid #e2e2e2;padding: 20px 60px;margin-top:24px">
<div class="half-table">
<span class="model_header_text">基本信息</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">模型名称</td>
<td class="ti-text-form-content word-elipsis"><span id="ModelName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">版本</td>
<td class="ti-text-form-content word-elipsis"><span id="Version" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">标签</td>
<td class="ti-text-form-content">
<div id="Label" style="overflow: hidden;width: 95%;">
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item" data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item" data-tab="second">{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first">
<div class="half-table">
<span class="model_header_text">基本信息</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.model_name"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="ModelName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.version"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Version" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.migrate_items_labels"}}</td>
<td class="ti-text-form-content">
<div id="Label" style="overflow: hidden;width: 95%;">
</div>
</div>

</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">大小</td>
<td class="ti-text-form-content word-elipsis"><span id="Size" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">创建时间</td>
<td class="ti-text-form-content word-elipsis"><span id="CreateTime" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">模型描述</td>
<td class="ti-text-form-content" ><div id="edit-td" style="display:flex"><span id="Description" title="" class="iword-elipsis"></span><i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div></td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.model_size"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Size" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.createtime"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="CreateTime" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.description"}}</td>
<td class="ti-text-form-content" >
<div id="edit-td" style="display:flex">
<span id="Description" title="" class="iword-elipsis"></span>
<i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></i>
</div>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.code_version"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="CodeBranch" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.start_file"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="BootFile" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.train_dataset"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="DatasetName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Parameters" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="EngineName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.standard"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="FlavorName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.compute_node"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="WorkServerNumber" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div class="half-table">
<span class="model_header_text">{{$.i18n.Tr "repo.model.manage.model_accuracy"}}</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Accuracy"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Accuracy" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">F1</td>
<td class="ti-text-form-content word-elipsis"><span id="F1" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Precision"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Precision" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Recall"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Recall" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div style="clear: both;"></div>
</div> </div>
<div class="half-table">
<span class="model_header_text">模型精度</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">准确率</td>
<td class="ti-text-form-content word-elipsis"><span id="Accuracy" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">F1</td>
<td class="ti-text-form-content word-elipsis"><span id="F1" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">精确率</td>
<td class="ti-text-form-content word-elipsis"><span id="Precision" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">召回率</td>
<td class="ti-text-form-content word-elipsis"><span id="Recall" title=""></span></td>
</tr>
</tbody>
</table>
<div class="ui tab" data-tab="second">
<input type="hidden" name="model" value="-1">
<input type="hidden" name="modelback" value="-1">
<div class='ui breadcrumb model_file_bread' id='file_breadcrumb'>
<div class="active section"></div>
<div class="divider"> / </div>

</div>
<div id="dir_list">
</div>
</div> </div>
<div style="clear: both;"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -146,6 +200,9 @@
<script> <script>
let url = location.href.split('show_model')[0] let url = location.href.split('show_model')[0]
let ID = location.search.split('?name=').pop() let ID = location.search.split('?name=').pop()
$(document).ready(function(){
$('.secondary.menu .item').tab();
});
$(document).ready(loadInfo); $(document).ready(loadInfo);
function changeInfo(version){ function changeInfo(version){
$.get(`${url}show_model_info_api?name=${ID}`,(data)=>{ $.get(`${url}show_model_info_api?name=${ID}`,(data)=>{
@@ -155,7 +212,9 @@ function changeInfo(version){
let returnArray = [] let returnArray = []
returnArray = transObj(versionData) returnArray = transObj(versionData)
let [initObj,initModelAcc,id] = returnArray let [initObj,initModelAcc,id] = returnArray
editorCancel('','')
renderInfo(initObj,initModelAcc,id) renderInfo(initObj,initModelAcc,id)
loadModelFile(versionData[0].ID,versionData[0].Version,'','','init')
}) })
} }
function loadInfo(){ function loadInfo(){
@@ -172,11 +231,17 @@ function loadInfo(){
returnArray = transObj(data) returnArray = transObj(data)
let [initObj,initModelAcc,id] = returnArray let [initObj,initModelAcc,id] = returnArray
renderInfo(initObj,initModelAcc,id) renderInfo(initObj,initModelAcc,id)
loadModelFile(data[0].ID,data[0].Version,'','','init')
}) })
} }
function transObj(data){ function transObj(data){
let {ID,Name,Version,Label,Size,Description,CreatedUnix,Accuracy} = data[0]
let {ID,Name,Version,Label,Size,Description,CreatedUnix,Accuracy,CodeBranch,CodeCommitID,TrainTaskInfo} = data[0]
let modelAcc = JSON.parse(Accuracy) let modelAcc = JSON.parse(Accuracy)
TrainTaskInfo = JSON.parse(TrainTaskInfo)
// Parameters = JSON.parse(Parameters)
let {Parameters,EngineName} = TrainTaskInfo
Parameters = JSON.parse(Parameters)
Parameters = Parameters.parameter.length === 0 ? '--':Parameters.parameter
let size = tranSize(Size) let size = tranSize(Size)
let time = transTime(CreatedUnix) let time = transTime(CreatedUnix)
let initObj = { let initObj = {
@@ -186,6 +251,15 @@ function transObj(data){
Size:size, Size:size,
CreateTime:time, CreateTime:time,
Description:Description || '--', Description:Description || '--',
CodeBranch:CodeBranch || '--',
CodeCommitID:CodeCommitID || '--',
BootFile:TrainTaskInfo.BootFile || '--',
DatasetName:TrainTaskInfo.DatasetName || '--',
Parameters:TrainTaskInfo.Parameters || '--',
FlavorName:TrainTaskInfo.FlavorName || '--',
WorkServerNumber:TrainTaskInfo.WorkServerNumber || '--',
Parameters:Parameters,
EngineName:EngineName,
} }
let initModelAcc = { let initModelAcc = {
Accuracy: modelAcc.Accuracy || '--', Accuracy: modelAcc.Accuracy || '--',
@@ -221,15 +295,16 @@ function tranSize(value){
function editorFn(context){ function editorFn(context){
let id= context.dataset.id let id= context.dataset.id
let text = context.dataset.desc let text = context.dataset.desc
console.log(id,text)
$('#edit-td').replaceWith("<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;' id='edit-text'>"+text+"</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure(\"" + text + "\",\"" + id + "\")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel(\"" + text + "\",\"" + id + "\")'></i></div>");
let textValue = text.replace(/enter;/g,'\r\n')
$('#edit-td').replaceWith(`<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;white-space: nowrap;' id='edit-text'>${textValue}</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure("${text}","${id}")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel("${text}","${id}")'></i></div>`);
} }
function editorCancel(text,id){ function editorCancel(text,id){
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${text}" class="iword-elipsis">${text}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
let objkey = text.replace(/enter;/g,'\r\n')
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${objkey}" class="iword-elipsis">${objkey}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
} }
function editorSure(text,id){ function editorSure(text,id){
let description=$('#textarea-value').val() let description=$('#textarea-value').val()
let sourcetext = $('#textarea-value').val().replace(/\n/g,'enter;')
let data = { let data = {
ID:id, ID:id,
Description:description Description:description
@@ -239,16 +314,17 @@ function editorSure(text,id){
type:'PUT', type:'PUT',
data:data data:data
}).done((res)=>{ }).done((res)=>{
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${description}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${sourcetext}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
}) })
} }
function renderInfo(obj,accObj,id){ function renderInfo(obj,accObj,id){
for(let key in obj){ for(let key in obj){
if(key==="Description"){ if(key==="Description"){
let descriptionText=obj[key].replace(/\r\n|\n/g,'enter;')
$(`#${key}`).text(obj[key]) $(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key]) $(`#${key}`).attr("title",obj[key])
$('#edit-pencil').attr("data-id",id) $('#edit-pencil').attr("data-id",id)
$('#edit-pencil').attr("data-desc",obj[key])
$('#edit-pencil').attr("data-desc",descriptionText)
} }
else if(key==="Label"){ else if(key==="Label"){
$('#Label').empty() $('#Label').empty()
@@ -264,6 +340,25 @@ function renderInfo(obj,accObj,id){
$('#Label').append(html) $('#Label').append(html)
} }
} }
else if(key==="CodeCommitID"){
let codeCommit = obj[key].slice(0,10)
let html = `<a style="margin-left:1rem" class="ui label" title="${codeCommit}">${codeCommit}</a>`
$('#CodeBranch').append(html)

}
else if(key==="Parameters"){
if(obj[key]==='--'){
$(`#${key}`).text(obj[key])
}else{
const parameterArray = obj[key].map(element => {
let labelValue = `${element.label}=${element.value}`
return labelValue
});
const parameter = parameterArray.join('; ')
$(`#${key}`).text(parameter)
$(`#${key}`).attr("title",parameter)
}
}
else{ else{
$(`#${key}`).text(obj[key]) $(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key]) $(`#${key}`).attr("title",obj[key])
@@ -276,4 +371,108 @@ function renderInfo(obj,accObj,id){
} }
} }


function loadModelFile(ID,version_name,parents,filename,init){
$.get(`${url}query_onelevel_modelfile?ID=${ID}&parentDir=${parents}`, (data) => {
$('#dir_list').empty()
renderDir(data,ID,version_name)
if(init==="init"){
$('input[name=model]').val("")
$('input[name=modelback]').val(version_name)
$('#file_breadcrumb').empty()
let htmlBread = ""
htmlBread += `<div class='active section'>${version_name}</div>`
htmlBread += "<div class='divider'> / </div>"
$('#file_breadcrumb').append(htmlBread)
}else{
renderBrend(ID,version_name,parents,filename,init)
}
})
}
function renderSize(value){
if(null==value||value==''){
return "0 Bytes";
}
var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB");
var index=0;
var srcsize = parseFloat(value);
index=Math.floor(Math.log(srcsize)/Math.log(1024));
var size =srcsize/Math.pow(1024,index);
size=size.toFixed(2);//保留的小数位数
return size+unitArr[index];
}

function renderBrend(ID,version_name,parents,filename,init){
if(init=="folder"){
let htmlBrend = ""
let sectionName=$('#file_breadcrumb .active.section').text()
let parents1 = $('input[name=model]').val()
let filename1 = $('input[name=modelback]').val()
if(parents1===""){
$('#file_breadcrumb .active.section').replaceWith(`<a class='section' onclick="loadModelFile('${ID}','${version_name}','${parents1}','','init')">${sectionName}</a>`)
}else{
$('#file_breadcrumb .active.section').replaceWith(`<a class='section' onclick="loadModelFile('${ID}','${version_name}','${parents1}','${filename1}')">${sectionName}</a>`)
}
htmlBrend += `<div class='active section'>${filename}</div>`
htmlBrend += "<div class='divider'> / </div>"
$('#file_breadcrumb').append(htmlBrend)
$('input[name=model]').val(parents)
$('input[name=modelback]').val(filename)
}else{
$('input[name=model]').val(parents)
$('input[name=modelbac]').val(filename)
$('#file_breadcrumb a.section:contains(${filename})').nextAll().remove()
$('#file_breadcrumb a.section:contains(${filename})').replaceWith(`<div class='active section'>${filename}</div>`)
$('#file_breadcrumb div.section:contains(${filename})').append("<div class='divider'> / </div>")
}
}
function renderDir(data,ID,version_name){
let html=""
html += "<div class='ui grid' style='margin:0;'>"
html += "<div class='row' style='padding: 0;'>"
html += "<div class='ui sixteen wide column' style='padding:1rem;'>"
html += "<div class='dir list'>"
html += "<table id='repo-files-table' class='ui single line table pad20'>"
html += '<tbody>'
for(let i=0;i<data.length;i++){
let dirs_size = renderSize(data[i].Size)
html += "<tr>"
html += "<td class='name six wid'>"
html += "<span class='truncate'>"
html += "<span class='octicon octicon-file-directory'>"
html += "</span>"
if(data[i].IsDir){
html += `<a onclick="loadModelFile('${ID}','${version_name}','${data[i].ParenDir}','${data[i].FileName}','folder')">`
html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data[i].FileName + "</span>"
}else{
html += `<a href="${url}${ID}/downloadsingle?parentDir=${data[i].ParenDir}&fileName=${data[i].FileName}">`
html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data[i].FileName + "</span>"
}
html += '</a>'
html += "</span>"
html += "</td>"
html += "<td class='message seven wide'>"
if(data[i].IsDir){
html += "<span class='truncate has-emoji'></span>"
}else{
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
}
html += "</td>"

html += "<td class='text right age three wide'>"
html += "<span class='truncate has-emoji'>" + data[i].ModTime + "</span>"
html += "</td>"
html += "</tr>"
}
html += "</tbody>"
html += "</table>"
html += "</div>"
html += "</div>"
html += "</div>"
html += "</div>"
$('#dir_list').append(html)
}
</script> </script>

+ 12
- 0
vendor/github.com/elliotchance/orderedmap/.editorconfig View File

@@ -0,0 +1,12 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.go]
indent_style = tab
indent_size = 4
max_line_length = 80

+ 1
- 0
vendor/github.com/elliotchance/orderedmap/.gitignore View File

@@ -0,0 +1 @@
/.idea

+ 9
- 0
vendor/github.com/elliotchance/orderedmap/.travis.yml View File

@@ -0,0 +1,9 @@
language: go

go:
- 1.11.x
- 1.12.x
- master

script:
- env GO111MODULE=on go test

+ 21
- 0
vendor/github.com/elliotchance/orderedmap/LICENSE View File

@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 Elliot Chance

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 102
- 0
vendor/github.com/elliotchance/orderedmap/README.md View File

@@ -0,0 +1,102 @@
# 🔃 github.com/elliotchance/orderedmap [![GoDoc](https://godoc.org/github.com/elliotchance/orderedmap?status.svg)](https://godoc.org/github.com/elliotchance/orderedmap) [![Build Status](https://travis-ci.org/elliotchance/orderedmap.svg?branch=master)](https://travis-ci.org/elliotchance/orderedmap)

## Installation

```bash
go get -u github.com/elliotchance/orderedmap
```

## Basic Usage

An `*OrderedMap` is a high performance ordered map that maintains amortized O(1)
for `Set`, `Get`, `Delete` and `Len`:

```go
m := orderedmap.NewOrderedMap()

m.Set("foo", "bar")
m.Set("qux", 1.23)
m.Set(123, true)

m.Delete("qux")
```

Internally an `*OrderedMap` uses a combination of a map and linked list.

## Iterating

Be careful using `Keys()` as it will create a copy of all of the keys so it's
only suitable for a small number of items:

```go
for _, key := range m.Keys() {
value, _:= m.Get(key)
fmt.Println(key, value)
}
```

For larger maps you should use `Front()` or `Back()` to iterate per element:

```go
// Iterate through all elements from oldest to newest:
for el := m.Front(); el != nil; el = el.Next() {
fmt.Println(el.Key, el.Value)
}

// You can also use Back and Prev to iterate in reverse:
for el := m.Back(); el != nil; el = el.Prev() {
fmt.Println(el.Key, el.Value)
}
```

The iterator is safe to use bidirectionally, and will return `nil` once it goes
beyond the first or last item.

If the map is changing while the iteration is in-flight it may produce
unexpected behavior.

## Performance

CPU: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz

RAM: 8GB

System: Windows 10

```shell
$go test -benchmem -run=^$ github.com/elliotchance/orderedmap -bench BenchmarkAll
```

map[int]bool

| | map | orderedmap |
| ------- | ------------------- | ------------------- |
| set | 198 ns/op, 44 B/op | 722 ns/op, 211 B/op |
| get | 18 ns/op, 0 B/op | 37.3 ns/op, 0 B/op |
| delete | 888 ns/op, 211 B/op | 280 ns/op, 44 B/op |
| Iterate | 206 ns/op, 44 B/op | 693 ns/op, 259 B/op |

map[string]bool(PS : Use strconv.Itoa())

| | map | orderedmap |
| ----------- | ------------------- | ----------------------- |
| set | 421 ns/op, 86 B/op | 1048 ns/op, 243 B/op |
| get | 81.1 ns/op, 2 B/op | 97.8 ns/op, 2 B/op |
| delete | 737 ns/op, 122 B/op | 1188 ns/op, 251 B/op |
| Iterate all | 14706 ns/op, 1 B/op | 52671 ns/op, 16391 B/op |

Big map[int]bool (10000000 keys)

| | map | orderedmap |
| ----------- | -------------------------------- | ------------------------------- |
| set all | 1.834559 s/op, 423.9470291 MB/op | 7.5564667 s/op, 1784.1483 MB/op |
| get all | 2.6367878 s/op, 423.9698 MB/op | 9.0232475 s/op, 1784.1086 MB/op |
| Iterate all | 1.9526784 s/op, 423.9042 MB/op | 8.2495265 s/op, 1936.7619 MB/op |

Big map[string]bool (10000000 keys)

| | map | orderedmap |
| ----------- | --------------------------------- | ----------------------------------- |
| set all | 4.8893923 s/op, 921.33435 MB/op | 10.4405527 s/op, 2089.0144 MB/op |
| get all | 7.122791 s/op, 997.3802643 MB/op | 13.2613692 s/op, 2165.09521 MB/op |
| Iterate all | 5.1688922 s/op, 921.4619293 MB/op | 12.6623711 s/op, 2241.5272064 MB/op |

+ 33
- 0
vendor/github.com/elliotchance/orderedmap/element.go View File

@@ -0,0 +1,33 @@
package orderedmap

import "container/list"

type Element struct {
Key, Value interface{}

element *list.Element
}

func newElement(e *list.Element) *Element {
if e == nil {
return nil
}

element := e.Value.(*orderedMapElement)

return &Element{
element: e,
Key: element.key,
Value: element.value,
}
}

// Next returns the next element, or nil if it finished.
func (e *Element) Next() *Element {
return newElement(e.element.Next())
}

// Prev returns the previous element, or nil if it finished.
func (e *Element) Prev() *Element {
return newElement(e.element.Prev())
}

+ 5
- 0
vendor/github.com/elliotchance/orderedmap/go.mod View File

@@ -0,0 +1,5 @@
module github.com/elliotchance/orderedmap

go 1.12

require github.com/stretchr/testify v1.7.0

+ 15
- 0
vendor/github.com/elliotchance/orderedmap/go.sum View File

@@ -0,0 +1,15 @@
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
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.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 150
- 0
vendor/github.com/elliotchance/orderedmap/orderedmap.go View File

@@ -0,0 +1,150 @@
package orderedmap

import "container/list"

type orderedMapElement struct {
key, value interface{}
}

type OrderedMap struct {
kv map[interface{}]*list.Element
ll *list.List
}

func NewOrderedMap() *OrderedMap {
return &OrderedMap{
kv: make(map[interface{}]*list.Element),
ll: list.New(),
}
}

// Get returns the value for a key. If the key does not exist, the second return
// parameter will be false and the value will be nil.
func (m *OrderedMap) Get(key interface{}) (interface{}, bool) {
value, ok := m.kv[key]
if ok {
return value.Value.(*orderedMapElement).value, true
}

return nil, false
}

// Set will set (or replace) a value for a key. If the key was new, then true
// will be returned. The returned value will be false if the value was replaced
// (even if the value was the same).
func (m *OrderedMap) Set(key, value interface{}) bool {
_, didExist := m.kv[key]

if !didExist {
element := m.ll.PushBack(&orderedMapElement{key, value})
m.kv[key] = element
} else {
m.kv[key].Value.(*orderedMapElement).value = value
}

return !didExist
}

// GetOrDefault returns the value for a key. If the key does not exist, returns
// the default value instead.
func (m *OrderedMap) GetOrDefault(key, defaultValue interface{}) interface{} {
if value, ok := m.kv[key]; ok {
return value.Value.(*orderedMapElement).value
}

return defaultValue
}

// GetElement returns the element for a key. If the key does not exist, the
// pointer will be nil.
func (m *OrderedMap) GetElement(key interface{}) *Element {
value, ok := m.kv[key]
if ok {
element := value.Value.(*orderedMapElement)
return &Element{
element: value,
Key: element.key,
Value: element.value,
}
}

return nil
}

// Len returns the number of elements in the map.
func (m *OrderedMap) Len() int {
return len(m.kv)
}

// Keys returns all of the keys in the order they were inserted. If a key was
// replaced it will retain the same position. To ensure most recently set keys
// are always at the end you must always Delete before Set.
func (m *OrderedMap) Keys() (keys []interface{}) {
keys = make([]interface{}, m.Len())

element := m.ll.Front()
for i := 0; element != nil; i++ {
keys[i] = element.Value.(*orderedMapElement).key
element = element.Next()
}

return keys
}

// Delete will remove a key from the map. It will return true if the key was
// removed (the key did exist).
func (m *OrderedMap) Delete(key interface{}) (didDelete bool) {
element, ok := m.kv[key]
if ok {
m.ll.Remove(element)
delete(m.kv, key)
}

return ok
}

// Front will return the element that is the first (oldest Set element). If
// there are no elements this will return nil.
func (m *OrderedMap) Front() *Element {
front := m.ll.Front()
if front == nil {
return nil
}

element := front.Value.(*orderedMapElement)

return &Element{
element: front,
Key: element.key,
Value: element.value,
}
}

// Back will return the element that is the last (most recent Set element). If
// there are no elements this will return nil.
func (m *OrderedMap) Back() *Element {
back := m.ll.Back()
if back == nil {
return nil
}

element := back.Value.(*orderedMapElement)

return &Element{
element: back,
Key: element.key,
Value: element.value,
}
}

// Copy returns a new OrderedMap with the same elements.
// Using Copy while there are concurrent writes may mangle the result.
func (m *OrderedMap) Copy() *OrderedMap {
m2 := NewOrderedMap()

for el := m.Front(); el != nil; el = el.Next() {
m2.Set(el.Key, el.Value)
}

return m2
}

+ 9
- 0
vendor/github.com/patrickmn/go-cache/CONTRIBUTORS View File

@@ -0,0 +1,9 @@
This is a list of people who have contributed code to go-cache. They, or their
employers, are the copyright holders of the contributed code. Contributed code
is subject to the license restrictions listed in LICENSE (as they were when the
code was contributed.)

Dustin Sallings <dustin@spy.net>
Jason Mooberry <jasonmoo@me.com>
Sergey Shepelev <temotor@gmail.com>
Alex Edwards <ajmedwards@gmail.com>

+ 19
- 0
vendor/github.com/patrickmn/go-cache/LICENSE View File

@@ -0,0 +1,19 @@
Copyright (c) 2012-2017 Patrick Mylund Nielsen and the go-cache contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save