Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
* upstream/main:
  Add CRAN package registry (go-gitea#22331)
  • Loading branch information
zjjhot committed May 22, 2023
2 parents 6791aa3 + cdb088c commit ade0372
Show file tree
Hide file tree
Showing 23 changed files with 1,212 additions and 2 deletions.
2 changes: 2 additions & 0 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2420,6 +2420,8 @@ LEVEL = Info
;LIMIT_SIZE_CONDA = -1
;; Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_CONTAINER = -1
;; Maximum size of a CRAN upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_CRAN = -1
;; Maximum size of a Debian upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_DEBIAN = -1
;; Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
- `LIMIT_SIZE_CONAN`: **-1**: Maximum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
- `LIMIT_SIZE_CONDA`: **-1**: Maximum size of a Conda upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
- `LIMIT_SIZE_CONTAINER`: **-1**: Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
- `LIMIT_SIZE_CRAN`: **-1**: Maximum size of a CRAN upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
- `LIMIT_SIZE_DEBIAN`: **-1**: Maximum size of a Debian upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
- `LIMIT_SIZE_GENERIC`: **-1**: Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
- `LIMIT_SIZE_GO`: **-1**: Maximum size of a Go upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
Expand Down
93 changes: 93 additions & 0 deletions docs/content/doc/usage/packages/cran.en-us.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
date: "2023-01-01T00:00:00+00:00"
title: "CRAN Packages Repository"
slug: "cran"
draft: false
toc: false
menu:
sidebar:
parent: "packages"
name: "CRAN"
weight: 35
identifier: "cran"
---

# CRAN Packages Repository

Publish [R](https://www.r-project.org/) packages to a [CRAN](https://cran.r-project.org/)-like registry for your user or organization.

**Table of Contents**

{{< toc >}}

## Requirements

To work with the CRAN package registry, you need to install [R](https://cran.r-project.org/).

## Configuring the package registry

To register the package registry you need to add it to `Rprofile.site`, either on the system-level, user-level (`~/.Rprofile`) or project-level:

```
options("repos" = c(getOption("repos"), c(gitea="https://gitea.example.com/api/packages/{owner}/cran")))
```

| Parameter | Description |
| --------- | ----------- |
| `owner` | The owner of the package. |

If you need to provide credentials, you may embed them as part of the url (`https://user:password@gitea.example.com/...`).

## Publish a package

To publish a R package, perform a HTTP `PUT` operation with the package content in the request body.

Source packages:

```
PUT https://gitea.example.com/api/packages/{owner}/cran/src
```

| Parameter | Description |
| --------- | ----------- |
| `owner` | The owner of the package. |

Binary packages:

```
PUT https://gitea.example.com/api/packages/{owner}/cran/bin?platform={platform}&rversion={rversion}
```

| Parameter | Description |
| ---------- | ----------- |
| `owner` | The owner of the package. |
| `platform` | The name of the platform. |
| `rversion` | The R version of the binary. |

For example:

```shell
curl --user your_username:your_password_or_token \
--upload-file path/to/package.zip \
https://gitea.example.com/api/packages/testuser/cran/bin?platform=windows&rversion=4.2
```

You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.

## Install a package

To install a R package from the package registry, execute the following command:

```shell
install.packages("{package_name}")
```

| Parameter | Description |
| -------------- | ----------- |
| `package_name` | The package name. |

For example:

```shell
install.packages("testpackage")
```
1 change: 1 addition & 0 deletions docs/content/doc/usage/packages/overview.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The following package managers are currently supported:
| [Conan]({{< relref "doc/usage/packages/conan.en-us.md" >}}) | C++ | `conan` |
| [Conda]({{< relref "doc/usage/packages/conda.en-us.md" >}}) | - | `conda` |
| [Container]({{< relref "doc/usage/packages/container.en-us.md" >}}) | - | any OCI compliant client |
| [CRAN]({{< relref "doc/usage/packages/cran.en-us.md" >}}) | R | - |
| [Debian]({{< relref "doc/usage/packages/debian.en-us.md" >}}) | - | `apt` |
| [Generic]({{< relref "doc/usage/packages/generic.en-us.md" >}}) | - | any HTTP client |
| [Go]({{< relref "doc/usage/packages/go.en-us.md" >}}) | Go | `go` |
Expand Down
90 changes: 90 additions & 0 deletions models/packages/cran/search.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package cran

import (
"context"
"strconv"
"strings"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/packages"
cran_module "code.gitea.io/gitea/modules/packages/cran"

"xorm.io/builder"
)

type SearchOptions struct {
OwnerID int64
FileType string
Platform string
RVersion string
Filename string
}

func (opts *SearchOptions) toConds() builder.Cond {
var cond builder.Cond = builder.Eq{
"package.type": packages.TypeCran,
"package.owner_id": opts.OwnerID,
"package_version.is_internal": false,
}

if opts.Filename != "" {
cond = cond.And(builder.Eq{"package_file.lower_name": strings.ToLower(opts.Filename)})
}

var propsCond builder.Cond = builder.Eq{
"package_property.ref_type": packages.PropertyTypeFile,
}
propsCond = propsCond.And(builder.Expr("package_property.ref_id = package_file.id"))

count := 1
propsCondBlock := builder.Eq{"package_property.name": cran_module.PropertyType}.And(builder.Eq{"package_property.value": opts.FileType})

if opts.Platform != "" {
count += 2
propsCondBlock = propsCondBlock.
Or(builder.Eq{"package_property.name": cran_module.PropertyPlatform}.And(builder.Eq{"package_property.value": opts.Platform})).
Or(builder.Eq{"package_property.name": cran_module.PropertyRVersion}.And(builder.Eq{"package_property.value": opts.RVersion}))
}

propsCond = propsCond.And(propsCondBlock)

cond = cond.And(builder.Eq{
strconv.Itoa(count): builder.Select("COUNT(*)").Where(propsCond).From("package_property"),
})

return cond
}

func SearchLatestVersions(ctx context.Context, opts *SearchOptions) ([]*packages.PackageVersion, error) {
sess := db.GetEngine(ctx).
Table("package_version").
Select("package_version.*").
Join("LEFT", "package_version pv2", builder.Expr("package_version.package_id = pv2.package_id AND pv2.is_internal = ? AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))", false)).
Join("INNER", "package", "package.id = package_version.package_id").
Join("INNER", "package_file", "package_file.version_id = package_version.id").
Where(opts.toConds().And(builder.Expr("pv2.id IS NULL"))).
Asc("package.name")

pvs := make([]*packages.PackageVersion, 0, 10)
return pvs, sess.Find(&pvs)
}

func SearchFile(ctx context.Context, opts *SearchOptions) (*packages.PackageFile, error) {
sess := db.GetEngine(ctx).
Table("package_version").
Select("package_file.*").
Join("INNER", "package", "package.id = package_version.package_id").
Join("INNER", "package_file", "package_file.version_id = package_version.id").
Where(opts.toConds())

pf := &packages.PackageFile{}
if has, err := sess.Get(pf); err != nil {
return nil, err
} else if !has {
return nil, packages.ErrPackageFileNotExist
}
return pf, nil
}
3 changes: 3 additions & 0 deletions models/packages/descriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/packages/conan"
"code.gitea.io/gitea/modules/packages/conda"
"code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/packages/cran"
"code.gitea.io/gitea/modules/packages/debian"
"code.gitea.io/gitea/modules/packages/helm"
"code.gitea.io/gitea/modules/packages/maven"
Expand Down Expand Up @@ -151,6 +152,8 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
metadata = &conda.VersionMetadata{}
case TypeContainer:
metadata = &container.Metadata{}
case TypeCran:
metadata = &cran.Metadata{}
case TypeDebian:
metadata = &debian.Metadata{}
case TypeGeneric:
Expand Down
6 changes: 6 additions & 0 deletions models/packages/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
TypeConan Type = "conan"
TypeConda Type = "conda"
TypeContainer Type = "container"
TypeCran Type = "cran"
TypeDebian Type = "debian"
TypeGeneric Type = "generic"
TypeGo Type = "go"
Expand All @@ -60,6 +61,7 @@ var TypeList = []Type{
TypeConan,
TypeConda,
TypeContainer,
TypeCran,
TypeDebian,
TypeGeneric,
TypeGo,
Expand Down Expand Up @@ -92,6 +94,8 @@ func (pt Type) Name() string {
return "Conda"
case TypeContainer:
return "Container"
case TypeCran:
return "CRAN"
case TypeDebian:
return "Debian"
case TypeGeneric:
Expand Down Expand Up @@ -139,6 +143,8 @@ func (pt Type) SVGName() string {
return "gitea-conda"
case TypeContainer:
return "octicon-container"
case TypeCran:
return "gitea-cran"
case TypeDebian:
return "gitea-debian"
case TypeGeneric:
Expand Down
Loading

0 comments on commit ade0372

Please sign in to comment.