Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
ollama
Commits
2cc63468
Commit
2cc63468
authored
Aug 21, 2023
by
Michael Yang
Browse files
use url.URL
parent
8f827641
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
80 additions
and
55 deletions
+80
-55
server/auth.go
server/auth.go
+25
-18
server/download.go
server/download.go
+3
-2
server/images.go
server/images.go
+39
-30
server/modelpath.go
server/modelpath.go
+13
-5
No files found.
server/auth.go
View file @
2cc63468
...
@@ -12,8 +12,10 @@ import (
...
@@ -12,8 +12,10 @@ import (
"io"
"io"
"log"
"log"
"net/http"
"net/http"
"net/url"
"os"
"os"
"path"
"path"
"strconv"
"strings"
"strings"
"time"
"time"
...
@@ -43,21 +45,34 @@ func generateNonce(length int) (string, error) {
...
@@ -43,21 +45,34 @@ func generateNonce(length int) (string, error) {
return
base64
.
RawURLEncoding
.
EncodeToString
(
nonce
),
nil
return
base64
.
RawURLEncoding
.
EncodeToString
(
nonce
),
nil
}
}
func
(
r
AuthRedirect
)
URL
()
(
string
,
error
)
{
func
(
r
AuthRedirect
)
URL
()
(
*
url
.
URL
,
error
)
{
nonce
,
err
:=
generateNonce
(
16
)
redirectURL
,
err
:=
url
.
Parse
(
r
.
Realm
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
nil
,
err
}
}
scopes
:=
[]
string
{}
values
:=
redirectURL
.
Query
()
values
.
Add
(
"service"
,
r
.
Service
)
for
_
,
s
:=
range
strings
.
Split
(
r
.
Scope
,
" "
)
{
for
_
,
s
:=
range
strings
.
Split
(
r
.
Scope
,
" "
)
{
scopes
=
append
(
scopes
,
fmt
.
Sprintf
(
"scope
=%s
"
,
s
)
)
values
.
Add
(
"scope"
,
s
)
}
}
scopeStr
:=
strings
.
Join
(
scopes
,
"&"
)
return
fmt
.
Sprintf
(
"%s?service=%s&%s&ts=%d&nonce=%s"
,
r
.
Realm
,
r
.
Service
,
scopeStr
,
time
.
Now
()
.
Unix
(),
nonce
),
nil
values
.
Add
(
"ts"
,
strconv
.
FormatInt
(
time
.
Now
()
.
Unix
(),
10
))
nonce
,
err
:=
generateNonce
(
16
)
if
err
!=
nil
{
return
nil
,
err
}
values
.
Add
(
"nonce"
,
nonce
)
redirectURL
.
RawQuery
=
values
.
Encode
()
return
redirectURL
,
nil
}
}
func
getAuthToken
(
ctx
context
.
Context
,
redirData
AuthRedirect
,
regOpts
*
RegistryOptions
)
(
string
,
error
)
{
func
getAuthToken
(
ctx
context
.
Context
,
redirData
AuthRedirect
,
regOpts
*
RegistryOptions
)
(
string
,
error
)
{
url
,
err
:=
redirData
.
URL
()
redirectURL
,
err
:=
redirData
.
URL
()
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
""
,
err
}
}
...
@@ -77,18 +92,10 @@ func getAuthToken(ctx context.Context, redirData AuthRedirect, regOpts *Registry
...
@@ -77,18 +92,10 @@ func getAuthToken(ctx context.Context, redirData AuthRedirect, regOpts *Registry
s
:=
SignatureData
{
s
:=
SignatureData
{
Method
:
"GET"
,
Method
:
"GET"
,
Path
:
url
,
Path
:
redirectURL
.
String
()
,
Data
:
nil
,
Data
:
nil
,
}
}
if
!
strings
.
HasPrefix
(
s
.
Path
,
"http"
)
{
if
regOpts
.
Insecure
{
s
.
Path
=
"http://"
+
url
}
else
{
s
.
Path
=
"https://"
+
url
}
}
sig
,
err
:=
s
.
Sign
(
rawKey
)
sig
,
err
:=
s
.
Sign
(
rawKey
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
""
,
err
...
@@ -96,7 +103,7 @@ func getAuthToken(ctx context.Context, redirData AuthRedirect, regOpts *Registry
...
@@ -96,7 +103,7 @@ func getAuthToken(ctx context.Context, redirData AuthRedirect, regOpts *Registry
headers
:=
make
(
http
.
Header
)
headers
:=
make
(
http
.
Header
)
headers
.
Set
(
"Authorization"
,
sig
)
headers
.
Set
(
"Authorization"
,
sig
)
resp
,
err
:=
makeRequest
(
ctx
,
"GET"
,
url
,
headers
,
nil
,
regOpts
)
resp
,
err
:=
makeRequest
(
ctx
,
"GET"
,
redirectURL
,
headers
,
nil
,
regOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"couldn't get token: %q"
,
err
)
log
.
Printf
(
"couldn't get token: %q"
,
err
)
}
}
...
...
server/download.go
View file @
2cc63468
...
@@ -155,12 +155,13 @@ func doDownload(ctx context.Context, opts downloadOpts, f *FileDownload) error {
...
@@ -155,12 +155,13 @@ func doDownload(ctx context.Context, opts downloadOpts, f *FileDownload) error {
}
}
}
}
url
:=
fmt
.
Sprintf
(
"%s/v2/%s/blobs/%s"
,
opts
.
mp
.
Registry
,
opts
.
mp
.
GetNamespaceRepository
(),
f
.
Digest
)
requestURL
:=
opts
.
mp
.
BaseURL
()
requestURL
=
requestURL
.
JoinPath
(
"v2"
,
opts
.
mp
.
GetNamespaceRepository
(),
"blobs"
,
f
.
Digest
)
headers
:=
make
(
http
.
Header
)
headers
:=
make
(
http
.
Header
)
headers
.
Set
(
"Range"
,
fmt
.
Sprintf
(
"bytes=%d-"
,
size
))
headers
.
Set
(
"Range"
,
fmt
.
Sprintf
(
"bytes=%d-"
,
size
))
resp
,
err
:=
makeRequest
(
ctx
,
"GET"
,
url
,
headers
,
nil
,
opts
.
regOpts
)
resp
,
err
:=
makeRequest
(
ctx
,
"GET"
,
requestURL
,
headers
,
nil
,
opts
.
regOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"couldn't download blob: %v"
,
err
)
log
.
Printf
(
"couldn't download blob: %v"
,
err
)
return
fmt
.
Errorf
(
"%w: %w"
,
errDownload
,
err
)
return
fmt
.
Errorf
(
"%w: %w"
,
errDownload
,
err
)
...
...
server/images.go
View file @
2cc63468
...
@@ -12,6 +12,7 @@ import (
...
@@ -12,6 +12,7 @@ import (
"io"
"io"
"log"
"log"
"net/http"
"net/http"
"net/url"
"os"
"os"
"path"
"path"
"path/filepath"
"path/filepath"
...
@@ -961,8 +962,8 @@ func PushModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
...
@@ -961,8 +962,8 @@ func PushModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
return
err
return
err
}
}
if
strings
.
HasPrefix
(
path
.
Base
(
location
),
"sha256:"
)
{
if
strings
.
HasPrefix
(
path
.
Base
(
location
.
Path
),
"sha256:"
)
{
layer
.
Digest
=
path
.
Base
(
location
)
layer
.
Digest
=
path
.
Base
(
location
.
Path
)
fn
(
api
.
ProgressResponse
{
fn
(
api
.
ProgressResponse
{
Status
:
"using existing layer"
,
Status
:
"using existing layer"
,
Digest
:
layer
.
Digest
,
Digest
:
layer
.
Digest
,
...
@@ -979,7 +980,8 @@ func PushModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
...
@@ -979,7 +980,8 @@ func PushModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
}
}
fn
(
api
.
ProgressResponse
{
Status
:
"pushing manifest"
})
fn
(
api
.
ProgressResponse
{
Status
:
"pushing manifest"
})
url
:=
fmt
.
Sprintf
(
"%s/v2/%s/manifests/%s"
,
mp
.
Registry
,
mp
.
GetNamespaceRepository
(),
mp
.
Tag
)
requestURL
:=
mp
.
BaseURL
()
requestURL
=
requestURL
.
JoinPath
(
"v2"
,
mp
.
GetNamespaceRepository
(),
"manifests"
,
mp
.
Tag
)
manifestJSON
,
err
:=
json
.
Marshal
(
manifest
)
manifestJSON
,
err
:=
json
.
Marshal
(
manifest
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -988,7 +990,7 @@ func PushModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
...
@@ -988,7 +990,7 @@ func PushModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
headers
:=
make
(
http
.
Header
)
headers
:=
make
(
http
.
Header
)
headers
.
Set
(
"Content-Type"
,
"application/vnd.docker.distribution.manifest.v2+json"
)
headers
.
Set
(
"Content-Type"
,
"application/vnd.docker.distribution.manifest.v2+json"
)
resp
,
err
:=
makeRequestWithRetry
(
ctx
,
"PUT"
,
url
,
headers
,
bytes
.
NewReader
(
manifestJSON
),
regOpts
)
resp
,
err
:=
makeRequestWithRetry
(
ctx
,
"PUT"
,
requestURL
,
headers
,
bytes
.
NewReader
(
manifestJSON
),
regOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -1072,11 +1074,11 @@ func PullModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
...
@@ -1072,11 +1074,11 @@ func PullModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
}
}
func
pullModelManifest
(
ctx
context
.
Context
,
mp
ModelPath
,
regOpts
*
RegistryOptions
)
(
*
ManifestV2
,
error
)
{
func
pullModelManifest
(
ctx
context
.
Context
,
mp
ModelPath
,
regOpts
*
RegistryOptions
)
(
*
ManifestV2
,
error
)
{
url
:=
fmt
.
Sprintf
(
"%s/v2/%s/manifests/%s"
,
mp
.
Registry
,
mp
.
GetNamespaceRepository
(),
mp
.
Tag
)
requestURL
:=
mp
.
BaseURL
()
.
JoinPath
(
"v2"
,
mp
.
GetNamespaceRepository
(),
"manifests"
,
mp
.
Tag
)
headers
:=
make
(
http
.
Header
)
headers
:=
make
(
http
.
Header
)
headers
.
Set
(
"Accept"
,
"application/vnd.docker.distribution.manifest.v2+json"
)
headers
.
Set
(
"Accept"
,
"application/vnd.docker.distribution.manifest.v2+json"
)
resp
,
err
:=
makeRequest
(
ctx
,
"GET"
,
url
,
headers
,
nil
,
regOpts
)
resp
,
err
:=
makeRequest
(
ctx
,
"GET"
,
requestURL
,
headers
,
nil
,
regOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"couldn't get manifest: %v"
,
err
)
log
.
Printf
(
"couldn't get manifest: %v"
,
err
)
return
nil
,
err
return
nil
,
err
...
@@ -1137,33 +1139,38 @@ func GetSHA256Digest(r io.Reader) (string, int) {
...
@@ -1137,33 +1139,38 @@ func GetSHA256Digest(r io.Reader) (string, int) {
type
requestContextKey
string
type
requestContextKey
string
func
startUpload
(
ctx
context
.
Context
,
mp
ModelPath
,
layer
*
Layer
,
regOpts
*
RegistryOptions
)
(
string
,
error
)
{
func
startUpload
(
ctx
context
.
Context
,
mp
ModelPath
,
layer
*
Layer
,
regOpts
*
RegistryOptions
)
(
*
url
.
URL
,
error
)
{
url
:=
fmt
.
Sprintf
(
"%s/v2/%s/blobs/uploads/"
,
mp
.
Registry
,
mp
.
GetNamespaceRepository
())
requestURL
:=
mp
.
BaseURL
()
requestURL
=
requestURL
.
JoinPath
(
"v2"
,
mp
.
GetNamespaceRepository
(),
"blobs/uploads/"
)
if
layer
.
From
!=
""
{
if
layer
.
From
!=
""
{
url
=
fmt
.
Sprintf
(
"%s/v2/%s/blobs/uploads/?mount=%s&from=%s"
,
mp
.
Registry
,
mp
.
GetNamespaceRepository
(),
layer
.
Digest
,
layer
.
From
)
values
:=
requestURL
.
Query
()
values
.
Add
(
"mount"
,
layer
.
Digest
)
values
.
Add
(
"from"
,
layer
.
From
)
requestURL
.
RawQuery
=
values
.
Encode
()
}
}
resp
,
err
:=
makeRequestWithRetry
(
ctx
,
"POST"
,
url
,
nil
,
nil
,
regOpts
)
resp
,
err
:=
makeRequestWithRetry
(
ctx
,
"POST"
,
requestURL
,
nil
,
nil
,
regOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"couldn't start upload: %v"
,
err
)
log
.
Printf
(
"couldn't start upload: %v"
,
err
)
return
""
,
err
return
nil
,
err
}
}
defer
resp
.
Body
.
Close
()
defer
resp
.
Body
.
Close
()
// Extract UUID location from header
// Extract UUID location from header
location
:=
resp
.
Header
.
Get
(
"Location"
)
location
:=
resp
.
Header
.
Get
(
"Location"
)
if
location
==
""
{
if
location
==
""
{
return
""
,
fmt
.
Errorf
(
"location header is missing in response"
)
return
nil
,
fmt
.
Errorf
(
"location header is missing in response"
)
}
}
return
location
,
nil
return
url
.
Parse
(
location
)
}
}
// Function to check if a blob already exists in the Docker registry
// Function to check if a blob already exists in the Docker registry
func
checkBlobExistence
(
ctx
context
.
Context
,
mp
ModelPath
,
digest
string
,
regOpts
*
RegistryOptions
)
(
bool
,
error
)
{
func
checkBlobExistence
(
ctx
context
.
Context
,
mp
ModelPath
,
digest
string
,
regOpts
*
RegistryOptions
)
(
bool
,
error
)
{
url
:=
fmt
.
Sprintf
(
"%s/v2/%s/blobs/%s"
,
mp
.
Registry
,
mp
.
GetNamespaceRepository
(),
digest
)
requestURL
:=
mp
.
BaseURL
()
requestURL
=
requestURL
.
JoinPath
(
"v2"
,
mp
.
GetNamespaceRepository
(),
"blobs"
,
digest
)
resp
,
err
:=
makeRequest
(
ctx
,
"HEAD"
,
url
,
nil
,
nil
,
regOpts
)
resp
,
err
:=
makeRequest
(
ctx
,
"HEAD"
,
requestURL
,
nil
,
nil
,
regOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"couldn't check for blob: %v"
,
err
)
log
.
Printf
(
"couldn't check for blob: %v"
,
err
)
return
false
,
err
return
false
,
err
...
@@ -1174,7 +1181,7 @@ func checkBlobExistence(ctx context.Context, mp ModelPath, digest string, regOpt
...
@@ -1174,7 +1181,7 @@ func checkBlobExistence(ctx context.Context, mp ModelPath, digest string, regOpt
return
resp
.
StatusCode
==
http
.
StatusOK
,
nil
return
resp
.
StatusCode
==
http
.
StatusOK
,
nil
}
}
func
uploadBlobChunked
(
ctx
context
.
Context
,
mp
ModelPath
,
url
string
,
layer
*
Layer
,
regOpts
*
RegistryOptions
,
fn
func
(
api
.
ProgressResponse
))
error
{
func
uploadBlobChunked
(
ctx
context
.
Context
,
mp
ModelPath
,
requestURL
*
url
.
URL
,
layer
*
Layer
,
regOpts
*
RegistryOptions
,
fn
func
(
api
.
ProgressResponse
))
error
{
// TODO allow resumability
// TODO allow resumability
// TODO allow canceling uploads via DELETE
// TODO allow canceling uploads via DELETE
...
@@ -1204,7 +1211,7 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
...
@@ -1204,7 +1211,7 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
headers
.
Set
(
"Content-Type"
,
"application/octet-stream"
)
headers
.
Set
(
"Content-Type"
,
"application/octet-stream"
)
headers
.
Set
(
"Content-Length"
,
strconv
.
Itoa
(
int
(
chunk
)))
headers
.
Set
(
"Content-Length"
,
strconv
.
Itoa
(
int
(
chunk
)))
headers
.
Set
(
"Content-Range"
,
fmt
.
Sprintf
(
"%d-%d"
,
completed
,
completed
+
sectionReader
.
Size
()
-
1
))
headers
.
Set
(
"Content-Range"
,
fmt
.
Sprintf
(
"%d-%d"
,
completed
,
completed
+
sectionReader
.
Size
()
-
1
))
resp
,
err
:=
makeRequestWithRetry
(
ctx
,
"PATCH"
,
url
,
headers
,
sectionReader
,
regOpts
)
resp
,
err
:=
makeRequestWithRetry
(
ctx
,
"PATCH"
,
requestURL
,
headers
,
sectionReader
,
regOpts
)
if
err
!=
nil
&&
!
errors
.
Is
(
err
,
io
.
EOF
)
{
if
err
!=
nil
&&
!
errors
.
Is
(
err
,
io
.
EOF
)
{
fn
(
api
.
ProgressResponse
{
fn
(
api
.
ProgressResponse
{
Status
:
fmt
.
Sprintf
(
"error uploading chunk: %v"
,
err
),
Status
:
fmt
.
Sprintf
(
"error uploading chunk: %v"
,
err
),
...
@@ -1225,20 +1232,26 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
...
@@ -1225,20 +1232,26 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
Completed
:
int
(
completed
),
Completed
:
int
(
completed
),
})
})
url
=
resp
.
Header
.
Get
(
"Location"
)
requestURL
,
err
=
url
.
Parse
(
resp
.
Header
.
Get
(
"Location"
))
if
err
!=
nil
{
return
err
}
if
completed
>=
int64
(
layer
.
Size
)
{
if
completed
>=
int64
(
layer
.
Size
)
{
break
break
}
}
}
}
url
=
fmt
.
Sprintf
(
"%s&digest=%s"
,
url
,
layer
.
Digest
)
values
:=
requestURL
.
Query
()
values
.
Add
(
"digest"
,
layer
.
Digest
)
requestURL
.
RawQuery
=
values
.
Encode
()
headers
:=
make
(
http
.
Header
)
headers
:=
make
(
http
.
Header
)
headers
.
Set
(
"Content-Type"
,
"application/octet-stream"
)
headers
.
Set
(
"Content-Type"
,
"application/octet-stream"
)
headers
.
Set
(
"Content-Length"
,
"0"
)
headers
.
Set
(
"Content-Length"
,
"0"
)
// finish the upload
// finish the upload
resp
,
err
:=
makeRequest
(
ctx
,
"PUT"
,
url
,
headers
,
nil
,
regOpts
)
resp
,
err
:=
makeRequest
(
ctx
,
"PUT"
,
requestURL
,
headers
,
nil
,
regOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"couldn't finish upload: %v"
,
err
)
log
.
Printf
(
"couldn't finish upload: %v"
,
err
)
return
err
return
err
...
@@ -1252,10 +1265,10 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
...
@@ -1252,10 +1265,10 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
return
nil
return
nil
}
}
func
makeRequestWithRetry
(
ctx
context
.
Context
,
method
,
url
string
,
headers
http
.
Header
,
body
io
.
ReadSeeker
,
regOpts
*
RegistryOptions
)
(
*
http
.
Response
,
error
)
{
func
makeRequestWithRetry
(
ctx
context
.
Context
,
method
string
,
requestURL
*
url
.
URL
,
headers
http
.
Header
,
body
io
.
ReadSeeker
,
regOpts
*
RegistryOptions
)
(
*
http
.
Response
,
error
)
{
var
status
string
var
status
string
for
try
:=
0
;
try
<
MaxRetries
;
try
++
{
for
try
:=
0
;
try
<
MaxRetries
;
try
++
{
resp
,
err
:=
makeRequest
(
ctx
,
method
,
url
,
headers
,
body
,
regOpts
)
resp
,
err
:=
makeRequest
(
ctx
,
method
,
requestURL
,
headers
,
body
,
regOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"couldn't start upload: %v"
,
err
)
log
.
Printf
(
"couldn't start upload: %v"
,
err
)
return
nil
,
err
return
nil
,
err
...
@@ -1291,16 +1304,12 @@ func makeRequestWithRetry(ctx context.Context, method, url string, headers http.
...
@@ -1291,16 +1304,12 @@ func makeRequestWithRetry(ctx context.Context, method, url string, headers http.
return
nil
,
fmt
.
Errorf
(
"max retry exceeded: %v"
,
status
)
return
nil
,
fmt
.
Errorf
(
"max retry exceeded: %v"
,
status
)
}
}
func
makeRequest
(
ctx
context
.
Context
,
method
,
url
string
,
headers
http
.
Header
,
body
io
.
Reader
,
regOpts
*
RegistryOptions
)
(
*
http
.
Response
,
error
)
{
func
makeRequest
(
ctx
context
.
Context
,
method
string
,
requestURL
*
url
.
URL
,
headers
http
.
Header
,
body
io
.
Reader
,
regOpts
*
RegistryOptions
)
(
*
http
.
Response
,
error
)
{
if
!
strings
.
HasPrefix
(
url
,
"http"
)
{
if
requestURL
.
Scheme
!=
"http"
&&
regOpts
.
Insecure
{
if
regOpts
.
Insecure
{
requestURL
.
Scheme
=
"http"
url
=
"http://"
+
url
}
else
{
url
=
"https://"
+
url
}
}
}
req
,
err
:=
http
.
NewRequestWithContext
(
ctx
,
method
,
url
,
body
)
req
,
err
:=
http
.
NewRequestWithContext
(
ctx
,
method
,
requestURL
.
String
()
,
body
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
...
server/modelpath.go
View file @
2cc63468
...
@@ -3,6 +3,7 @@ package server
...
@@ -3,6 +3,7 @@ package server
import
(
import
(
"errors"
"errors"
"fmt"
"fmt"
"net/url"
"os"
"os"
"path/filepath"
"path/filepath"
"runtime"
"runtime"
...
@@ -39,13 +40,13 @@ func ParseModelPath(name string) ModelPath {
...
@@ -39,13 +40,13 @@ func ParseModelPath(name string) ModelPath {
Tag
:
DefaultTag
,
Tag
:
DefaultTag
,
}
}
parts
:=
strings
.
Spli
t
(
name
,
"://"
)
before
,
after
,
found
:=
strings
.
Cu
t
(
name
,
"://"
)
if
len
(
parts
)
>
1
{
if
found
{
mp
.
ProtocolScheme
=
parts
[
0
]
mp
.
ProtocolScheme
=
before
name
=
parts
[
1
]
name
=
after
}
}
parts
=
strings
.
Split
(
name
,
"/"
)
parts
:
=
strings
.
Split
(
name
,
"/"
)
switch
len
(
parts
)
{
switch
len
(
parts
)
{
case
3
:
case
3
:
mp
.
Registry
=
parts
[
0
]
mp
.
Registry
=
parts
[
0
]
...
@@ -100,6 +101,13 @@ func (mp ModelPath) GetManifestPath(createDir bool) (string, error) {
...
@@ -100,6 +101,13 @@ func (mp ModelPath) GetManifestPath(createDir bool) (string, error) {
return
path
,
nil
return
path
,
nil
}
}
func
(
mp
ModelPath
)
BaseURL
()
*
url
.
URL
{
return
&
url
.
URL
{
Scheme
:
mp
.
ProtocolScheme
,
Host
:
mp
.
Registry
,
}
}
func
GetManifestPath
()
(
string
,
error
)
{
func
GetManifestPath
()
(
string
,
error
)
{
home
,
err
:=
os
.
UserHomeDir
()
home
,
err
:=
os
.
UserHomeDir
()
if
err
!=
nil
{
if
err
!=
nil
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment