mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 10:25:52 +02:00
refactor(cosy): cosy directory structure
This commit is contained in:
parent
40ca44d183
commit
9d62b3ef03
10 changed files with 333 additions and 92 deletions
|
@ -29,6 +29,7 @@ type Ctx[T any] struct {
|
|||
transformer func(*T) any
|
||||
permanentlyDelete bool
|
||||
SelectedFields []string
|
||||
itemKey string
|
||||
}
|
||||
|
||||
func Core[T any](c *gin.Context) *Ctx[T] {
|
||||
|
@ -37,51 +38,26 @@ func Core[T any](c *gin.Context) *Ctx[T] {
|
|||
gormScopes: make([]func(tx *gorm.DB) *gorm.DB, 0),
|
||||
beforeExecuteHookFunc: make([]func(ctx *Ctx[T]), 0),
|
||||
beforeDecodeHookFunc: make([]func(ctx *Ctx[T]), 0),
|
||||
itemKey: "`id`",
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetItemKey(key string) *Ctx[T] {
|
||||
c.itemKey = key
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetValidRules(rules gin.H) *Ctx[T] {
|
||||
c.rules = rules
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) BeforeDecodeHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
|
||||
c.beforeDecodeHookFunc = append(c.beforeDecodeHookFunc, hook...)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) BeforeExecuteHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
|
||||
c.beforeExecuteHookFunc = append(c.beforeExecuteHookFunc, hook...)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) ExecutedHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
|
||||
c.executedHookFunc = append(c.executedHookFunc, hook...)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetPreloads(args ...string) *Ctx[T] {
|
||||
c.preloads = append(c.preloads, args...)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) beforeExecuteHook() {
|
||||
if len(c.beforeExecuteHookFunc) > 0 {
|
||||
for _, v := range c.beforeExecuteHookFunc {
|
||||
v(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) beforeDecodeHook() {
|
||||
if len(c.beforeDecodeHookFunc) > 0 {
|
||||
for _, v := range c.beforeDecodeHookFunc {
|
||||
v(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) validate() (errs gin.H) {
|
||||
c.Payload = make(gin.H)
|
||||
|
||||
|
@ -128,13 +104,3 @@ func (c *Ctx[T]) AbortWithError(err error) {
|
|||
func (c *Ctx[T]) Abort() {
|
||||
c.abort = true
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) PermanentlyDelete() *Ctx[T] {
|
||||
c.permanentlyDelete = true
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) GormScope(hook func(tx *gorm.DB) *gorm.DB) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, hook)
|
||||
return c
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
func (c *Ctx[T]) PermanentlyDelete() *Ctx[T] {
|
||||
c.permanentlyDelete = true
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) Destroy() {
|
||||
if c.abort {
|
||||
return
|
||||
|
|
207
api/cosy/filter.go
Normal file
207
api/cosy/filter.go
Normal file
|
@ -0,0 +1,207 @@
|
|||
package cosy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/0xJacky/Nginx-UI/internal/logger"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (c *Ctx[T]) SetFussy(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return QueryToFussySearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetFussyKeys(value string, keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return QueryToFussyKeysSearch(c.ctx, tx, value, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetEqual(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return QueryToEqualSearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetIn(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return QueryToInSearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetOrFussy(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return QueryToOrFussySearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetOrEqual(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return QueryToOrEqualSearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetOrIn(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return QueryToOrInSearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func QueryToInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
|
||||
for _, v := range keys {
|
||||
queryArray := c.QueryArray(v + "[]")
|
||||
if len(queryArray) == 0 {
|
||||
queryArray = c.QueryArray(v)
|
||||
}
|
||||
if len(queryArray) > 0 {
|
||||
var sb strings.Builder
|
||||
|
||||
_, err := fmt.Fprintf(&sb, "`%s` IN ?", v)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
db = db.Where(sb.String(), queryArray)
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func QueryToEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
|
||||
for _, v := range keys {
|
||||
if c.Query(v) != "" {
|
||||
var sb strings.Builder
|
||||
|
||||
_, err := fmt.Fprintf(&sb, "`%s` = ?", v)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
db = db.Where(sb.String(), c.Query(v))
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func QueryToFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
|
||||
for _, v := range keys {
|
||||
if c.Query(v) != "" {
|
||||
var sb strings.Builder
|
||||
|
||||
_, err := fmt.Fprintf(&sb, "`%s` LIKE ?", v)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
var sbValue strings.Builder
|
||||
|
||||
_, err = fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v))
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
db = db.Where(sb.String(), sbValue.String())
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func QueryToFussyKeysSearch(c *gin.Context, db *gorm.DB, value string, keys ...string) *gorm.DB {
|
||||
if c.Query(value) == "" {
|
||||
return db
|
||||
}
|
||||
|
||||
var condition *gorm.DB
|
||||
for i, v := range keys {
|
||||
sb := v + " LIKE ?"
|
||||
sv := "%" + c.Query(value) + "%"
|
||||
|
||||
switch i {
|
||||
case 0:
|
||||
condition = db.Where(db.Where(sb, sv))
|
||||
default:
|
||||
condition = condition.Or(sb, sv)
|
||||
}
|
||||
}
|
||||
|
||||
return db.Where(condition)
|
||||
}
|
||||
|
||||
func QueryToOrInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
|
||||
for _, v := range keys {
|
||||
queryArray := c.QueryArray(v + "[]")
|
||||
if len(queryArray) == 0 {
|
||||
queryArray = c.QueryArray(v)
|
||||
}
|
||||
if len(queryArray) > 0 {
|
||||
var sb strings.Builder
|
||||
|
||||
_, err := fmt.Fprintf(&sb, "`%s` IN ?", v)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
db = db.Or(sb.String(), queryArray)
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func QueryToOrEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
|
||||
for _, v := range keys {
|
||||
if c.Query(v) != "" {
|
||||
var sb strings.Builder
|
||||
|
||||
_, err := fmt.Fprintf(&sb, "`%s` = ?", v)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
db = db.Or(sb.String(), c.Query(v))
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func QueryToOrFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
|
||||
for _, v := range keys {
|
||||
if c.Query(v) != "" {
|
||||
var sb strings.Builder
|
||||
|
||||
_, err := fmt.Fprintf(&sb, "`%s` LIKE ?", v)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
var sbValue strings.Builder
|
||||
|
||||
_, err = fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v))
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
db = db.Or(sb.String(), sbValue.String())
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
39
api/cosy/hook.go
Normal file
39
api/cosy/hook.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package cosy
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
func (c *Ctx[T]) GormScope(hook func(tx *gorm.DB) *gorm.DB) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, hook)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) beforeExecuteHook() {
|
||||
if len(c.beforeExecuteHookFunc) > 0 {
|
||||
for _, v := range c.beforeExecuteHookFunc {
|
||||
v(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) beforeDecodeHook() {
|
||||
if len(c.beforeDecodeHookFunc) > 0 {
|
||||
for _, v := range c.beforeDecodeHookFunc {
|
||||
v(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) BeforeDecodeHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
|
||||
c.beforeDecodeHookFunc = append(c.beforeDecodeHookFunc, hook...)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) BeforeExecuteHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
|
||||
c.beforeExecuteHookFunc = append(c.beforeExecuteHookFunc, hook...)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) ExecutedHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
|
||||
c.executedHookFunc = append(c.executedHookFunc, hook...)
|
||||
return c
|
||||
}
|
|
@ -4,58 +4,39 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/internal/logger"
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/cast"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (c *Ctx[T]) SetFussy(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return model.QueryToFussySearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
func GetPagingParams(c *gin.Context) (page, offset, pageSize int) {
|
||||
page = cast.ToInt(c.Query("page"))
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize = settings.ServerSettings.PageSize
|
||||
reqPageSize := c.Query("page_size")
|
||||
if reqPageSize != "" {
|
||||
pageSize = cast.ToInt(reqPageSize)
|
||||
}
|
||||
offset = (page - 1) * pageSize
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetFussyKeys(value string, keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return model.QueryToFussyKeysSearch(c.ctx, tx, value, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
func (c *Ctx[T]) combineStdSelectorRequest() {
|
||||
var StdSelectorInitParams struct {
|
||||
ID []int `json:"id"`
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetEqual(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return model.QueryToEqualSearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
if err := c.ctx.ShouldBindJSON(&StdSelectorInitParams); err != nil {
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetIn(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return model.QueryToInSearch(c.ctx, tx, keys...)
|
||||
c.GormScope(func(tx *gorm.DB) *gorm.DB {
|
||||
return tx.Where(c.itemKey+" IN ?", StdSelectorInitParams.ID)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetOrFussy(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return model.QueryToOrFussySearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetOrEqual(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return model.QueryToOrEqualSearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) SetOrIn(keys ...string) *Ctx[T] {
|
||||
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
|
||||
return model.QueryToOrInSearch(c.ctx, tx, keys...)
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) result() (*gorm.DB, bool) {
|
||||
|
@ -72,7 +53,7 @@ func (c *Ctx[T]) result() (*gorm.DB, bool) {
|
|||
var dbModel T
|
||||
result := model.UseDB()
|
||||
|
||||
if c.ctx.Query("trash") == "true" {
|
||||
if cast.ToBool(c.ctx.Query("trash")) {
|
||||
stmt := &gorm.Statement{DB: model.UseDB()}
|
||||
err := stmt.Parse(&dbModel)
|
||||
if err != nil {
|
||||
|
@ -84,6 +65,8 @@ func (c *Ctx[T]) result() (*gorm.DB, bool) {
|
|||
|
||||
result = result.Model(&dbModel)
|
||||
|
||||
c.combineStdSelectorRequest()
|
||||
|
||||
if len(c.gormScopes) > 0 {
|
||||
result = result.Scopes(c.gormScopes...)
|
||||
}
|
||||
|
@ -97,7 +80,7 @@ func (c *Ctx[T]) ListAllData() ([]*T, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
result = result.Scopes(model.SortOrder(c.ctx))
|
||||
result = result.Scopes(c.SortOrder())
|
||||
models := make([]*T, 0)
|
||||
result.Find(&models)
|
||||
return models, true
|
||||
|
@ -109,7 +92,7 @@ func (c *Ctx[T]) PagingListData() (*model.DataList, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
result = result.Scopes(model.OrderAndPaginate(c.ctx))
|
||||
result = result.Scopes(c.OrderAndPaginate())
|
||||
data := &model.DataList{}
|
||||
if c.scan == nil {
|
||||
models := make([]*T, 0)
|
||||
|
|
39
api/cosy/sort.go
Normal file
39
api/cosy/sort.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package cosy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (c *Ctx[T]) SortOrder() func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
sort := c.ctx.DefaultQuery("order", "desc")
|
||||
order := fmt.Sprintf("%s %s", DefaultQuery(c.ctx, "sort_by", c.itemKey), sort)
|
||||
return db.Order(order)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Ctx[T]) OrderAndPaginate() func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
sort := c.ctx.DefaultQuery("order", "desc")
|
||||
|
||||
order := fmt.Sprintf("%s %s", DefaultQuery(c.ctx, "sort_by", c.itemKey), sort)
|
||||
db = db.Order(order)
|
||||
|
||||
_, offset, pageSize := GetPagingParams(c.ctx)
|
||||
|
||||
return db.Offset(offset).Limit(pageSize)
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultValue(c *gin.Context, key string, defaultValue any) any {
|
||||
if value, ok := c.Get(key); ok {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func DefaultQuery(c *gin.Context, key string, defaultValue any) string {
|
||||
return c.DefaultQuery(key, DefaultValue(c, key, defaultValue).(string))
|
||||
}
|
|
@ -28,6 +28,8 @@ func (c *Ctx[T]) Modify() {
|
|||
return
|
||||
}
|
||||
|
||||
var dbModel T
|
||||
|
||||
db := model.UseDB()
|
||||
|
||||
result := db
|
||||
|
@ -35,7 +37,7 @@ func (c *Ctx[T]) Modify() {
|
|||
result = result.Scopes(c.gormScopes...)
|
||||
}
|
||||
|
||||
err := result.Session(&gorm.Session{}).First(&c.Model, id).Error
|
||||
err := result.Session(&gorm.Session{}).First(&dbModel, id).Error
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithError(err)
|
||||
|
@ -65,7 +67,7 @@ func (c *Ctx[T]) Modify() {
|
|||
return
|
||||
}
|
||||
|
||||
err = db.Model(&c.Model).Select(selectedFields).Updates(&c.Model).Error
|
||||
err = db.Model(&dbModel).Select(selectedFields).Updates(&c.Model).Error
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithError(err)
|
||||
|
@ -85,6 +87,6 @@ func (c *Ctx[T]) Modify() {
|
|||
if c.nextHandler != nil {
|
||||
(*c.nextHandler)(c.ctx)
|
||||
} else {
|
||||
c.ctx.JSON(http.StatusOK, c.Model)
|
||||
c.ctx.JSON(http.StatusOK, dbModel)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
"@vitejs/plugin-vue": "^4.5.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"@vue/compiler-sfc": "^3.3.10",
|
||||
"ace-builds": "^1.31.2",
|
||||
"ace-builds": "^1.32.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
|
|
2
app/pnpm-lock.yaml
generated
2
app/pnpm-lock.yaml
generated
|
@ -122,7 +122,7 @@ devDependencies:
|
|||
specifier: ^0.4.0
|
||||
version: 0.4.0
|
||||
ace-builds:
|
||||
specifier: ^1.31.2
|
||||
specifier: ^1.32.0
|
||||
version: 1.32.0
|
||||
autoprefixer:
|
||||
specifier: ^10.4.16
|
||||
|
|
|
@ -18,7 +18,7 @@ RUN set -x \
|
|||
&& curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
|
||||
| tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \
|
||||
&& echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
|
||||
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
|
||||
https://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
|
||||
| tee /etc/apt/sources.list.d/nginx.list
|
||||
|
||||
RUN echo "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" | tee /etc/apt/preferences.d/99nginx \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue