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
5ebcde15
"src/targets/vscode:/vscode.git/clone" did not exist on "b8b4630b4666bd3420227c4b580e7e1242771c50"
Unverified
Commit
5ebcde15
authored
Nov 21, 2023
by
Matt Williams
Committed by
GitHub
Nov 21, 2023
Browse files
Merge branch 'main' into install-instructions-archlinux
parents
e1cd3152
45206cb7
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
102 additions
and
174 deletions
+102
-174
progressbar/spinners.go
progressbar/spinners.go
+0
-80
scripts/build_docker.sh
scripts/build_docker.sh
+2
-0
scripts/push_docker.sh
scripts/push_docker.sh
+1
-0
server/download.go
server/download.go
+9
-10
server/images.go
server/images.go
+32
-46
server/routes.go
server/routes.go
+8
-8
server/upload.go
server/upload.go
+50
-30
No files found.
progressbar/spinners.go
deleted
100644 → 0
View file @
e1cd3152
package
progressbar
var
spinners
=
map
[
int
][]
string
{
0
:
{
"←"
,
"↖"
,
"↑"
,
"↗"
,
"→"
,
"↘"
,
"↓"
,
"↙"
},
1
:
{
"▁"
,
"▃"
,
"▄"
,
"▅"
,
"▆"
,
"▇"
,
"█"
,
"▇"
,
"▆"
,
"▅"
,
"▄"
,
"▃"
,
"▁"
},
2
:
{
"▖"
,
"▘"
,
"▝"
,
"▗"
},
3
:
{
"┤"
,
"┘"
,
"┴"
,
"└"
,
"├"
,
"┌"
,
"┬"
,
"┐"
},
4
:
{
"◢"
,
"◣"
,
"◤"
,
"◥"
},
5
:
{
"◰"
,
"◳"
,
"◲"
,
"◱"
},
6
:
{
"◴"
,
"◷"
,
"◶"
,
"◵"
},
7
:
{
"◐"
,
"◓"
,
"◑"
,
"◒"
},
8
:
{
"."
,
"o"
,
"O"
,
"@"
,
"*"
},
9
:
{
"|"
,
"/"
,
"-"
,
"
\\
"
},
10
:
{
"◡◡"
,
"⊙⊙"
,
"◠◠"
},
11
:
{
"⣾"
,
"⣽"
,
"⣻"
,
"⢿"
,
"⡿"
,
"⣟"
,
"⣯"
,
"⣷"
},
12
:
{
">))'>"
,
" >))'>"
,
" >))'>"
,
" >))'>"
,
" >))'>"
,
" <'((<"
,
" <'((<"
,
" <'((<"
},
13
:
{
"⠁"
,
"⠂"
,
"⠄"
,
"⡀"
,
"⢀"
,
"⠠"
,
"⠐"
,
"⠈"
},
14
:
{
"⠋"
,
"⠙"
,
"⠹"
,
"⠸"
,
"⠼"
,
"⠴"
,
"⠦"
,
"⠧"
,
"⠇"
,
"⠏"
},
15
:
{
"a"
,
"b"
,
"c"
,
"d"
,
"e"
,
"f"
,
"g"
,
"h"
,
"i"
,
"j"
,
"k"
,
"l"
,
"m"
,
"n"
,
"o"
,
"p"
,
"q"
,
"r"
,
"s"
,
"t"
,
"u"
,
"v"
,
"w"
,
"x"
,
"y"
,
"z"
},
16
:
{
"▉"
,
"▊"
,
"▋"
,
"▌"
,
"▍"
,
"▎"
,
"▏"
,
"▎"
,
"▍"
,
"▌"
,
"▋"
,
"▊"
,
"▉"
},
17
:
{
"■"
,
"□"
,
"▪"
,
"▫"
},
18
:
{
"←"
,
"↑"
,
"→"
,
"↓"
},
19
:
{
"╫"
,
"╪"
},
20
:
{
"⇐"
,
"⇖"
,
"⇑"
,
"⇗"
,
"⇒"
,
"⇘"
,
"⇓"
,
"⇙"
},
21
:
{
"⠁"
,
"⠁"
,
"⠉"
,
"⠙"
,
"⠚"
,
"⠒"
,
"⠂"
,
"⠂"
,
"⠒"
,
"⠲"
,
"⠴"
,
"⠤"
,
"⠄"
,
"⠄"
,
"⠤"
,
"⠠"
,
"⠠"
,
"⠤"
,
"⠦"
,
"⠖"
,
"⠒"
,
"⠐"
,
"⠐"
,
"⠒"
,
"⠓"
,
"⠋"
,
"⠉"
,
"⠈"
,
"⠈"
},
22
:
{
"⠈"
,
"⠉"
,
"⠋"
,
"⠓"
,
"⠒"
,
"⠐"
,
"⠐"
,
"⠒"
,
"⠖"
,
"⠦"
,
"⠤"
,
"⠠"
,
"⠠"
,
"⠤"
,
"⠦"
,
"⠖"
,
"⠒"
,
"⠐"
,
"⠐"
,
"⠒"
,
"⠓"
,
"⠋"
,
"⠉"
,
"⠈"
},
23
:
{
"⠁"
,
"⠉"
,
"⠙"
,
"⠚"
,
"⠒"
,
"⠂"
,
"⠂"
,
"⠒"
,
"⠲"
,
"⠴"
,
"⠤"
,
"⠄"
,
"⠄"
,
"⠤"
,
"⠴"
,
"⠲"
,
"⠒"
,
"⠂"
,
"⠂"
,
"⠒"
,
"⠚"
,
"⠙"
,
"⠉"
,
"⠁"
},
24
:
{
"⠋"
,
"⠙"
,
"⠚"
,
"⠒"
,
"⠂"
,
"⠂"
,
"⠒"
,
"⠲"
,
"⠴"
,
"⠦"
,
"⠖"
,
"⠒"
,
"⠐"
,
"⠐"
,
"⠒"
,
"⠓"
,
"⠋"
},
25
:
{
"ヲ"
,
"ァ"
,
"ィ"
,
"ゥ"
,
"ェ"
,
"ォ"
,
"ャ"
,
"ュ"
,
"ョ"
,
"ッ"
,
"ア"
,
"イ"
,
"ウ"
,
"エ"
,
"オ"
,
"カ"
,
"キ"
,
"ク"
,
"ケ"
,
"コ"
,
"サ"
,
"シ"
,
"ス"
,
"セ"
,
"ソ"
,
"タ"
,
"チ"
,
"ツ"
,
"テ"
,
"ト"
,
"ナ"
,
"ニ"
,
"ヌ"
,
"ネ"
,
"ノ"
,
"ハ"
,
"ヒ"
,
"フ"
,
"ヘ"
,
"ホ"
,
"マ"
,
"ミ"
,
"ム"
,
"メ"
,
"モ"
,
"ヤ"
,
"ユ"
,
"ヨ"
,
"ラ"
,
"リ"
,
"ル"
,
"レ"
,
"ロ"
,
"ワ"
,
"ン"
},
26
:
{
"."
,
".."
,
"..."
},
27
:
{
"▁"
,
"▂"
,
"▃"
,
"▄"
,
"▅"
,
"▆"
,
"▇"
,
"█"
,
"▉"
,
"▊"
,
"▋"
,
"▌"
,
"▍"
,
"▎"
,
"▏"
,
"▏"
,
"▎"
,
"▍"
,
"▌"
,
"▋"
,
"▊"
,
"▉"
,
"█"
,
"▇"
,
"▆"
,
"▅"
,
"▄"
,
"▃"
,
"▂"
,
"▁"
},
28
:
{
"."
,
"o"
,
"O"
,
"°"
,
"O"
,
"o"
,
"."
},
29
:
{
"+"
,
"x"
},
30
:
{
"v"
,
"<"
,
"^"
,
">"
},
31
:
{
">>--->"
,
" >>--->"
,
" >>--->"
,
" >>--->"
,
" >>--->"
,
" <---<<"
,
" <---<<"
,
" <---<<"
,
" <---<<"
,
"<---<<"
},
32
:
{
"|"
,
"||"
,
"|||"
,
"||||"
,
"|||||"
,
"|||||||"
,
"||||||||"
,
"|||||||"
,
"||||||"
,
"|||||"
,
"||||"
,
"|||"
,
"||"
,
"|"
},
33
:
{
"[ ]"
,
"[= ]"
,
"[== ]"
,
"[=== ]"
,
"[==== ]"
,
"[===== ]"
,
"[====== ]"
,
"[======= ]"
,
"[======== ]"
,
"[========= ]"
,
"[==========]"
},
34
:
{
"(*---------)"
,
"(-*--------)"
,
"(--*-------)"
,
"(---*------)"
,
"(----*-----)"
,
"(-----*----)"
,
"(------*---)"
,
"(-------*--)"
,
"(--------*-)"
,
"(---------*)"
},
35
:
{
"█▒▒▒▒▒▒▒▒▒"
,
"███▒▒▒▒▒▒▒"
,
"█████▒▒▒▒▒"
,
"███████▒▒▒"
,
"██████████"
},
36
:
{
"[ ]"
,
"[=> ]"
,
"[===> ]"
,
"[=====> ]"
,
"[======> ]"
,
"[========> ]"
,
"[==========> ]"
,
"[============> ]"
,
"[==============> ]"
,
"[================> ]"
,
"[==================> ]"
,
"[===================>]"
},
37
:
{
"ဝ"
,
"၀"
},
38
:
{
"▌"
,
"▀"
,
"▐▄"
},
39
:
{
"🌍"
,
"🌎"
,
"🌏"
},
40
:
{
"◜"
,
"◝"
,
"◞"
,
"◟"
},
41
:
{
"⬒"
,
"⬔"
,
"⬓"
,
"⬕"
},
42
:
{
"⬖"
,
"⬘"
,
"⬗"
,
"⬙"
},
43
:
{
"[>>> >]"
,
"[]>>>> []"
,
"[] >>>> []"
,
"[] >>>> []"
,
"[] >>>> []"
,
"[] >>>>[]"
,
"[>> >>]"
},
44
:
{
"♠"
,
"♣"
,
"♥"
,
"♦"
},
45
:
{
"➞"
,
"➟"
,
"➠"
,
"➡"
,
"➠"
,
"➟"
},
46
:
{
" | "
,
` \ `
,
"_ "
,
` \ `
,
" | "
,
" / "
,
" _"
,
" / "
},
47
:
{
" . . . ."
,
". . . ."
,
". . . ."
,
". . . ."
,
". . . . "
,
". . . . ."
},
48
:
{
" | "
,
" / "
,
" _ "
,
` \ `
,
" | "
,
` \ `
,
" _ "
,
" / "
},
49
:
{
"⎺"
,
"⎻"
,
"⎼"
,
"⎽"
,
"⎼"
,
"⎻"
},
50
:
{
"▹▹▹▹▹"
,
"▸▹▹▹▹"
,
"▹▸▹▹▹"
,
"▹▹▸▹▹"
,
"▹▹▹▸▹"
,
"▹▹▹▹▸"
},
51
:
{
"[ ]"
,
"[ =]"
,
"[ ==]"
,
"[ ===]"
,
"[====]"
,
"[=== ]"
,
"[== ]"
,
"[= ]"
},
52
:
{
"( ● )"
,
"( ● )"
,
"( ● )"
,
"( ● )"
,
"( ●)"
,
"( ● )"
,
"( ● )"
,
"( ● )"
,
"( ● )"
},
53
:
{
"✶"
,
"✸"
,
"✹"
,
"✺"
,
"✹"
,
"✷"
},
54
:
{
"▐|
\\
____________▌"
,
"▐_|
\\
___________▌"
,
"▐__|
\\
__________▌"
,
"▐___|
\\
_________▌"
,
"▐____|
\\
________▌"
,
"▐_____|
\\
_______▌"
,
"▐______|
\\
______▌"
,
"▐_______|
\\
_____▌"
,
"▐________|
\\
____▌"
,
"▐_________|
\\
___▌"
,
"▐__________|
\\
__▌"
,
"▐___________|
\\
_▌"
,
"▐____________|
\\
▌"
,
"▐____________/|▌"
,
"▐___________/|_▌"
,
"▐__________/|__▌"
,
"▐_________/|___▌"
,
"▐________/|____▌"
,
"▐_______/|_____▌"
,
"▐______/|______▌"
,
"▐_____/|_______▌"
,
"▐____/|________▌"
,
"▐___/|_________▌"
,
"▐__/|__________▌"
,
"▐_/|___________▌"
,
"▐/|____________▌"
},
55
:
{
"▐⠂ ▌"
,
"▐⠈ ▌"
,
"▐ ⠂ ▌"
,
"▐ ⠠ ▌"
,
"▐ ⡀ ▌"
,
"▐ ⠠ ▌"
,
"▐ ⠂ ▌"
,
"▐ ⠈ ▌"
,
"▐ ⠂ ▌"
,
"▐ ⠠ ▌"
,
"▐ ⡀ ▌"
,
"▐ ⠠ ▌"
,
"▐ ⠂ ▌"
,
"▐ ⠈ ▌"
,
"▐ ⠂▌"
,
"▐ ⠠▌"
,
"▐ ⡀▌"
,
"▐ ⠠ ▌"
,
"▐ ⠂ ▌"
,
"▐ ⠈ ▌"
,
"▐ ⠂ ▌"
,
"▐ ⠠ ▌"
,
"▐ ⡀ ▌"
,
"▐ ⠠ ▌"
,
"▐ ⠂ ▌"
,
"▐ ⠈ ▌"
,
"▐ ⠂ ▌"
,
"▐ ⠠ ▌"
,
"▐ ⡀ ▌"
,
"▐⠠ ▌"
},
56
:
{
"¿"
,
"?"
},
57
:
{
"⢹"
,
"⢺"
,
"⢼"
,
"⣸"
,
"⣇"
,
"⡧"
,
"⡗"
,
"⡏"
},
58
:
{
"⢄"
,
"⢂"
,
"⢁"
,
"⡁"
,
"⡈"
,
"⡐"
,
"⡠"
},
59
:
{
". "
,
".. "
,
"..."
,
" .."
,
" ."
,
" "
},
60
:
{
"."
,
"o"
,
"O"
,
"°"
,
"O"
,
"o"
,
"."
},
61
:
{
"▓"
,
"▒"
,
"░"
},
62
:
{
"▌"
,
"▀"
,
"▐"
,
"▄"
},
63
:
{
"⊶"
,
"⊷"
},
64
:
{
"▪"
,
"▫"
},
65
:
{
"□"
,
"■"
},
66
:
{
"▮"
,
"▯"
},
67
:
{
"-"
,
"="
,
"≡"
},
68
:
{
"d"
,
"q"
,
"p"
,
"b"
},
69
:
{
"∙∙∙"
,
"●∙∙"
,
"∙●∙"
,
"∙∙●"
,
"∙∙∙"
},
70
:
{
"🌑 "
,
"🌒 "
,
"🌓 "
,
"🌔 "
,
"🌕 "
,
"🌖 "
,
"🌗 "
,
"🌘 "
},
71
:
{
"☗"
,
"☖"
},
72
:
{
"⧇"
,
"⧆"
},
73
:
{
"◉"
,
"◎"
},
74
:
{
"㊂"
,
"㊀"
,
"㊁"
},
75
:
{
"⦾"
,
"⦿"
},
}
scripts/build_docker.sh
View file @
5ebcde15
...
...
@@ -10,6 +10,8 @@ docker buildx build \
--platform
=
linux/arm64,linux/amd64
\
--build-arg
=
VERSION
\
--build-arg
=
GOFLAGS
\
--cache-from
type
=
local
,src
=
.cache
\
--cache-to
type
=
local
,dest
=
.cache
\
-f
Dockerfile
\
-t
ollama
\
.
scripts/push_docker.sh
View file @
5ebcde15
...
...
@@ -10,6 +10,7 @@ docker buildx build \
--platform
=
linux/arm64,linux/amd64
\
--build-arg
=
VERSION
\
--build-arg
=
GOFLAGS
\
--cache-from
type
=
local
,src
=
.cache
\
-f
Dockerfile
\
-t
ollama/ollama
-t
ollama/ollama:
$VERSION
\
.
server/download.go
View file @
5ebcde15
...
...
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"log"
"math"
"net/http"
"net/url"
"os"
...
...
@@ -53,8 +54,8 @@ type blobDownloadPart struct {
const
(
numDownloadParts
=
64
minDownloadPartSize
int64
=
32
*
1000
*
1000
maxDownloadPartSize
int64
=
256
*
1000
*
1000
minDownloadPartSize
int64
=
100
*
format
.
MegaByte
maxDownloadPartSize
int64
=
1000
*
format
.
MegaByte
)
func
(
p
*
blobDownloadPart
)
Name
()
string
{
...
...
@@ -147,7 +148,6 @@ func (b *blobDownload) run(ctx context.Context, requestURL *url.URL, opts *Regis
continue
}
i
:=
i
g
.
Go
(
func
()
error
{
var
err
error
for
try
:=
0
;
try
<
maxRetries
;
try
++
{
...
...
@@ -158,12 +158,11 @@ func (b *blobDownload) run(ctx context.Context, requestURL *url.URL, opts *Regis
// return immediately if the context is canceled or the device is out of space
return
err
case
err
!=
nil
:
log
.
Printf
(
"%s part %d attempt %d failed: %v, retrying"
,
b
.
Digest
[
7
:
19
],
i
,
try
,
err
)
sleep
:=
time
.
Second
*
time
.
Duration
(
math
.
Pow
(
2
,
float64
(
try
)))
log
.
Printf
(
"%s part %d attempt %d failed: %v, retrying in %s"
,
b
.
Digest
[
7
:
19
],
part
.
N
,
try
,
err
,
sleep
)
time
.
Sleep
(
sleep
)
continue
default
:
if
try
>
0
{
log
.
Printf
(
"%s part %d completed after %d retries"
,
b
.
Digest
[
7
:
19
],
i
,
try
)
}
return
nil
}
}
...
...
@@ -285,7 +284,7 @@ func (b *blobDownload) Wait(ctx context.Context, fn func(api.ProgressResponse))
}
fn
(
api
.
ProgressResponse
{
Status
:
fmt
.
Sprintf
(
"
download
ing %s"
,
b
.
Digest
),
Status
:
fmt
.
Sprintf
(
"
pull
ing %s"
,
b
.
Digest
[
7
:
19
]
),
Digest
:
b
.
Digest
,
Total
:
b
.
Total
,
Completed
:
b
.
Completed
.
Load
(),
...
...
@@ -304,7 +303,7 @@ type downloadOpts struct {
fn
func
(
api
.
ProgressResponse
)
}
const
maxRetries
=
3
const
maxRetries
=
6
var
errMaxRetriesExceeded
=
errors
.
New
(
"max retries exceeded"
)
...
...
@@ -322,7 +321,7 @@ func downloadBlob(ctx context.Context, opts downloadOpts) error {
return
err
default
:
opts
.
fn
(
api
.
ProgressResponse
{
Status
:
fmt
.
Sprintf
(
"
download
ing %s"
,
opts
.
digest
),
Status
:
fmt
.
Sprintf
(
"
pull
ing %s"
,
opts
.
digest
[
7
:
19
]
),
Digest
:
opts
.
digest
,
Total
:
fi
.
Size
(),
Completed
:
fi
.
Size
(),
...
...
server/images.go
View file @
5ebcde15
...
...
@@ -228,26 +228,6 @@ func GetModel(name string) (*Model, error) {
return
model
,
nil
}
func
filenameWithPath
(
path
,
f
string
)
(
string
,
error
)
{
// if filePath starts with ~/, replace it with the user's home directory.
if
strings
.
HasPrefix
(
f
,
fmt
.
Sprintf
(
"~%s"
,
string
(
os
.
PathSeparator
)))
{
parts
:=
strings
.
Split
(
f
,
string
(
os
.
PathSeparator
))
home
,
err
:=
os
.
UserHomeDir
()
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to open file: %v"
,
err
)
}
f
=
filepath
.
Join
(
home
,
filepath
.
Join
(
parts
[
1
:
]
...
))
}
// if filePath is not an absolute path, make it relative to the modelfile path
if
!
filepath
.
IsAbs
(
f
)
{
f
=
filepath
.
Join
(
filepath
.
Dir
(
path
),
f
)
}
return
f
,
nil
}
func
realpath
(
p
string
)
string
{
abspath
,
err
:=
filepath
.
Abs
(
p
)
if
err
!=
nil
{
...
...
@@ -1146,43 +1126,49 @@ func GetSHA256Digest(r io.Reader) (string, int64) {
var
errUnauthorized
=
fmt
.
Errorf
(
"unauthorized"
)
func
makeRequestWithRetry
(
ctx
context
.
Context
,
method
string
,
requestURL
*
url
.
URL
,
headers
http
.
Header
,
body
io
.
ReadSeeker
,
regOpts
*
RegistryOptions
)
(
*
http
.
Response
,
error
)
{
lastErr
:=
errMaxRetriesExceeded
for
try
:=
0
;
try
<
maxRetries
;
try
++
{
resp
,
err
:=
makeRequest
(
ctx
,
method
,
requestURL
,
headers
,
body
,
regOpts
)
resp
,
err
:=
makeRequest
(
ctx
,
method
,
requestURL
,
headers
,
body
,
regOpts
)
if
err
!=
nil
{
if
!
errors
.
Is
(
err
,
context
.
Canceled
)
{
log
.
Printf
(
"request failed: %v"
,
err
)
}
return
nil
,
err
}
switch
{
case
resp
.
StatusCode
==
http
.
StatusUnauthorized
:
// Handle authentication error with one retry
auth
:=
resp
.
Header
.
Get
(
"www-authenticate"
)
authRedir
:=
ParseAuthRedirectString
(
auth
)
token
,
err
:=
getAuthToken
(
ctx
,
authRedir
)
if
err
!=
nil
{
log
.
Printf
(
"couldn't start upload: %v"
,
err
)
return
nil
,
err
}
switch
{
case
resp
.
StatusCode
==
http
.
StatusUnauthorized
:
auth
:=
resp
.
Header
.
Get
(
"www-authenticate"
)
authRedir
:=
ParseAuthRedirectString
(
auth
)
token
,
err
:=
getAuthToken
(
ctx
,
authRedir
)
regOpts
.
Token
=
token
if
body
!=
nil
{
_
,
err
=
body
.
Seek
(
0
,
io
.
SeekStart
)
if
err
!=
nil
{
return
nil
,
err
}
}
regOpts
.
Token
=
token
if
body
!=
nil
{
body
.
Seek
(
0
,
io
.
SeekStart
)
}
lastErr
=
errUnauthorized
case
resp
.
StatusCode
==
http
.
StatusNotFound
:
return
nil
,
os
.
ErrNotExist
case
resp
.
StatusCode
>=
http
.
StatusBadRequest
:
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"%d: %s"
,
resp
.
StatusCode
,
err
)
}
resp
,
err
:=
makeRequest
(
ctx
,
method
,
requestURL
,
headers
,
body
,
regOpts
)
if
resp
.
StatusCode
==
http
.
StatusUnauthorized
{
return
nil
,
errUnauthorized
}
return
nil
,
fmt
.
Errorf
(
"%d: %s"
,
resp
.
StatusCode
,
body
)
default
:
return
resp
,
nil
return
resp
,
err
case
resp
.
StatusCode
==
http
.
StatusNotFound
:
return
nil
,
os
.
ErrNotExist
case
resp
.
StatusCode
>=
http
.
StatusBadRequest
:
responseBody
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"%d: %s"
,
resp
.
StatusCode
,
err
)
}
return
nil
,
fmt
.
Errorf
(
"%d: %s"
,
resp
.
StatusCode
,
responseBody
)
}
return
nil
,
lastErr
return
resp
,
nil
}
func
makeRequest
(
ctx
context
.
Context
,
method
string
,
requestURL
*
url
.
URL
,
headers
http
.
Header
,
body
io
.
Reader
,
regOpts
*
RegistryOptions
)
(
*
http
.
Response
,
error
)
{
...
...
server/routes.go
View file @
5ebcde15
...
...
@@ -666,8 +666,14 @@ func HeadBlobHandler(c *gin.Context) {
}
func
CreateBlobHandler
(
c
*
gin
.
Context
)
{
targetPath
,
err
:=
GetBlobsPath
(
c
.
Param
(
"digest"
))
if
err
!=
nil
{
c
.
AbortWithStatusJSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
hash
:=
sha256
.
New
()
temp
,
err
:=
os
.
CreateTemp
(
""
,
c
.
Param
(
"digest"
))
temp
,
err
:=
os
.
CreateTemp
(
filepath
.
Dir
(
targetPath
)
,
c
.
Param
(
"digest"
)
+
"-"
)
if
err
!=
nil
{
c
.
AbortWithStatusJSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
...
...
@@ -690,12 +696,6 @@ func CreateBlobHandler(c *gin.Context) {
return
}
targetPath
,
err
:=
GetBlobsPath
(
c
.
Param
(
"digest"
))
if
err
!=
nil
{
c
.
AbortWithStatusJSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
if
err
:=
os
.
Rename
(
temp
.
Name
(),
targetPath
);
err
!=
nil
{
c
.
AbortWithStatusJSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
...
...
@@ -794,7 +794,7 @@ func Serve(ln net.Listener, allowOrigins []string) error {
if
runtime
.
GOOS
==
"linux"
{
// check compatibility to log warnings
if
_
,
err
:=
llm
.
CheckVRAM
();
err
!=
nil
{
log
.
Printf
(
"Warning: GPU support may not be enabled, check you have installed GPU drivers: %v"
,
err
)
log
.
Printf
(
err
.
Error
()
)
}
}
...
...
server/upload.go
View file @
5ebcde15
...
...
@@ -5,9 +5,9 @@ import (
"crypto/md5"
"errors"
"fmt"
"hash"
"io"
"log"
"math"
"net/http"
"net/url"
"os"
...
...
@@ -35,6 +35,8 @@ type blobUpload struct {
context
.
CancelFunc
file
*
os
.
File
done
bool
err
error
references
atomic
.
Int32
...
...
@@ -42,8 +44,8 @@ type blobUpload struct {
const
(
numUploadParts
=
64
minUploadPartSize
int64
=
95
*
1000
*
1000
maxUploadPartSize
int64
=
1000
*
1000
*
1000
minUploadPartSize
int64
=
100
*
format
.
MegaByte
maxUploadPartSize
int64
=
1000
*
format
.
MegaByte
)
func
(
b
*
blobUpload
)
Prepare
(
ctx
context
.
Context
,
requestURL
*
url
.
URL
,
opts
*
RegistryOptions
)
error
{
...
...
@@ -128,12 +130,12 @@ func (b *blobUpload) Run(ctx context.Context, opts *RegistryOptions) {
return
}
f
,
err
:
=
os
.
Open
(
p
)
b
.
file
,
err
=
os
.
Open
(
p
)
if
err
!=
nil
{
b
.
err
=
err
return
}
defer
f
.
Close
()
defer
b
.
file
.
Close
()
g
,
inner
:=
errgroup
.
WithContext
(
ctx
)
g
.
SetLimit
(
numUploadParts
)
...
...
@@ -145,7 +147,6 @@ func (b *blobUpload) Run(ctx context.Context, opts *RegistryOptions) {
g
.
Go
(
func
()
error
{
var
err
error
for
try
:=
0
;
try
<
maxRetries
;
try
++
{
part
.
ReadSeeker
=
io
.
NewSectionReader
(
f
,
part
.
Offset
,
part
.
Size
)
err
=
b
.
uploadChunk
(
inner
,
http
.
MethodPatch
,
requestURL
,
part
,
opts
)
switch
{
case
errors
.
Is
(
err
,
context
.
Canceled
)
:
...
...
@@ -153,7 +154,10 @@ func (b *blobUpload) Run(ctx context.Context, opts *RegistryOptions) {
case
errors
.
Is
(
err
,
errMaxRetriesExceeded
)
:
return
err
case
err
!=
nil
:
log
.
Printf
(
"%s part %d attempt %d failed: %v, retrying"
,
b
.
Digest
[
7
:
19
],
part
.
N
,
try
,
err
)
part
.
Reset
()
sleep
:=
time
.
Second
*
time
.
Duration
(
math
.
Pow
(
2
,
float64
(
try
)))
log
.
Printf
(
"%s part %d attempt %d failed: %v, retrying in %s"
,
b
.
Digest
[
7
:
19
],
part
.
N
,
try
,
err
,
sleep
)
time
.
Sleep
(
sleep
)
continue
}
...
...
@@ -173,8 +177,16 @@ func (b *blobUpload) Run(ctx context.Context, opts *RegistryOptions) {
requestURL
:=
<-
b
.
nextURL
var
sb
strings
.
Builder
// calculate md5 checksum and add it to the commit request
for
_
,
part
:=
range
b
.
Parts
{
sb
.
Write
(
part
.
Sum
(
nil
))
hash
:=
md5
.
New
()
if
_
,
err
:=
io
.
Copy
(
hash
,
io
.
NewSectionReader
(
b
.
file
,
part
.
Offset
,
part
.
Size
));
err
!=
nil
{
b
.
err
=
err
return
}
sb
.
Write
(
hash
.
Sum
(
nil
))
}
md5sum
:=
md5
.
Sum
([]
byte
(
sb
.
String
()))
...
...
@@ -188,29 +200,39 @@ func (b *blobUpload) Run(ctx context.Context, opts *RegistryOptions) {
headers
.
Set
(
"Content-Type"
,
"application/octet-stream"
)
headers
.
Set
(
"Content-Length"
,
"0"
)
resp
,
err
:=
makeRequestWithRetry
(
ctx
,
http
.
MethodPut
,
requestURL
,
headers
,
nil
,
opts
)
if
err
!=
nil
{
b
.
err
=
err
for
try
:=
0
;
try
<
maxRetries
;
try
++
{
resp
,
err
:=
makeRequestWithRetry
(
ctx
,
http
.
MethodPut
,
requestURL
,
headers
,
nil
,
opts
)
if
err
!=
nil
{
b
.
err
=
err
if
errors
.
Is
(
err
,
context
.
Canceled
)
{
return
}
sleep
:=
time
.
Second
*
time
.
Duration
(
math
.
Pow
(
2
,
float64
(
try
)))
log
.
Printf
(
"%s complete upload attempt %d failed: %v, retrying in %s"
,
b
.
Digest
[
7
:
19
],
try
,
err
,
sleep
)
time
.
Sleep
(
sleep
)
continue
}
defer
resp
.
Body
.
Close
()
b
.
err
=
nil
b
.
done
=
true
return
}
defer
resp
.
Body
.
Close
()
b
.
done
=
true
}
func
(
b
*
blobUpload
)
uploadChunk
(
ctx
context
.
Context
,
method
string
,
requestURL
*
url
.
URL
,
part
*
blobUploadPart
,
opts
*
RegistryOptions
)
error
{
part
.
Reset
()
headers
:=
make
(
http
.
Header
)
headers
.
Set
(
"Content-Type"
,
"application/octet-stream"
)
headers
.
Set
(
"Content-Length"
,
fmt
.
Sprintf
(
"%d"
,
part
.
Size
))
headers
.
Set
(
"X-Redirect-Uploads"
,
"1"
)
if
method
==
http
.
MethodPatch
{
headers
.
Set
(
"X-Redirect-Uploads"
,
"1"
)
headers
.
Set
(
"Content-Range"
,
fmt
.
Sprintf
(
"%d-%d"
,
part
.
Offset
,
part
.
Offset
+
part
.
Size
-
1
))
}
resp
,
err
:=
makeRequest
(
ctx
,
method
,
requestURL
,
headers
,
io
.
TeeReader
(
part
.
ReadSeeker
,
io
.
MultiWriter
(
part
,
part
.
Hash
)),
opts
)
sr
:=
io
.
NewSectionReader
(
b
.
file
,
part
.
Offset
,
part
.
Size
)
resp
,
err
:=
makeRequest
(
ctx
,
method
,
requestURL
,
headers
,
io
.
TeeReader
(
sr
,
part
),
opts
)
if
err
!=
nil
{
return
err
}
...
...
@@ -235,6 +257,7 @@ func (b *blobUpload) uploadChunk(ctx context.Context, method string, requestURL
return
err
}
// retry uploading to the redirect URL
for
try
:=
0
;
try
<
maxRetries
;
try
++
{
err
=
b
.
uploadChunk
(
ctx
,
http
.
MethodPut
,
redirectURL
,
part
,
nil
)
switch
{
...
...
@@ -243,7 +266,10 @@ func (b *blobUpload) uploadChunk(ctx context.Context, method string, requestURL
case
errors
.
Is
(
err
,
errMaxRetriesExceeded
)
:
return
err
case
err
!=
nil
:
log
.
Printf
(
"%s part %d attempt %d failed: %v, retrying"
,
b
.
Digest
[
7
:
19
],
part
.
N
,
try
,
err
)
part
.
Reset
()
sleep
:=
time
.
Second
*
time
.
Duration
(
math
.
Pow
(
2
,
float64
(
try
)))
log
.
Printf
(
"%s part %d attempt %d failed: %v, retrying in %s"
,
b
.
Digest
[
7
:
19
],
part
.
N
,
try
,
err
,
sleep
)
time
.
Sleep
(
sleep
)
continue
}
...
...
@@ -301,7 +327,7 @@ func (b *blobUpload) Wait(ctx context.Context, fn func(api.ProgressResponse)) er
}
fn
(
api
.
ProgressResponse
{
Status
:
fmt
.
Sprintf
(
"
upload
ing %s"
,
b
.
Digest
),
Status
:
fmt
.
Sprintf
(
"
push
ing %s"
,
b
.
Digest
[
7
:
19
]
),
Digest
:
b
.
Digest
,
Total
:
b
.
Total
,
Completed
:
b
.
Completed
.
Load
(),
...
...
@@ -315,14 +341,10 @@ func (b *blobUpload) Wait(ctx context.Context, fn func(api.ProgressResponse)) er
type
blobUploadPart
struct
{
// N is the part number
N
int
Offset
int64
Size
int64
hash
.
Hash
N
int
Offset
int64
Size
int64
written
int64
io
.
ReadSeeker
*
blobUpload
}
...
...
@@ -334,10 +356,8 @@ func (p *blobUploadPart) Write(b []byte) (n int, err error) {
}
func
(
p
*
blobUploadPart
)
Reset
()
{
p
.
Seek
(
0
,
io
.
SeekStart
)
p
.
Completed
.
Add
(
-
int64
(
p
.
written
))
p
.
written
=
0
p
.
Hash
=
md5
.
New
()
}
func
uploadBlob
(
ctx
context
.
Context
,
mp
ModelPath
,
layer
*
Layer
,
opts
*
RegistryOptions
,
fn
func
(
api
.
ProgressResponse
))
error
{
...
...
@@ -352,7 +372,7 @@ func uploadBlob(ctx context.Context, mp ModelPath, layer *Layer, opts *RegistryO
default
:
defer
resp
.
Body
.
Close
()
fn
(
api
.
ProgressResponse
{
Status
:
fmt
.
Sprintf
(
"
upload
ing %s"
,
layer
.
Digest
),
Status
:
fmt
.
Sprintf
(
"
push
ing %s"
,
layer
.
Digest
[
7
:
19
]
),
Digest
:
layer
.
Digest
,
Total
:
layer
.
Size
,
Completed
:
layer
.
Size
,
...
...
Prev
1
2
Next
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