Rename product to dockmv (container, image, module, env vars)
Container/image/service name, Go module path, CLI binary name, and DOCKER_MIGRATE_* env vars still used the old working name; the project is branded DockMV everywhere else (README, logo, Gitea repo). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
832af4aaae
commit
34e18987a0
32 files changed
+113
-109
No files matched your search
+2
-2
@@ -1,8 +1,8 @@
|
||||
.git
|
||||
.gitignore
|
||||
dist/
|
||||
docker-migrate
|
||||
docker-migrate.exe
|
||||
dockmv
|
||||
dockmv.exe
|
||||
web/node_modules
|
||||
internal/webui/dist
|
||||
*.test
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# Binaries
|
||||
/docker-migrate
|
||||
/docker-migrate.exe
|
||||
/dockmv
|
||||
/dockmv.exe
|
||||
/dist/
|
||||
*.test
|
||||
*.test.exe
|
||||
|
||||
+4
-4
@@ -18,22 +18,22 @@ COPY --from=ui /src/internal/webui/dist ./internal/webui/dist
|
||||
# artifact be copied onto a bare-metal host.
|
||||
RUN CGO_ENABLED=0 go build -trimpath \
|
||||
-ldflags "-s -w -X main.version=${VERSION}" \
|
||||
-o /out/docker-migrate .
|
||||
-o /out/dockmv .
|
||||
|
||||
FROM alpine:3.22
|
||||
RUN apk add --no-cache ca-certificates tzdata && \
|
||||
adduser -D -u 10001 migrate
|
||||
COPY --from=build /out/docker-migrate /usr/local/bin/docker-migrate
|
||||
COPY --from=build /out/dockmv /usr/local/bin/dockmv
|
||||
|
||||
# The container talks to the Docker socket mounted from the host, which is
|
||||
# owned by root:docker. It therefore runs as root by default; set --user to
|
||||
# override when the socket permissions on your host allow it.
|
||||
ENV DOCKER_MIGRATE_DATA=/data
|
||||
ENV DOCKMV_DATA=/data
|
||||
VOLUME ["/data"]
|
||||
EXPOSE 8080
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s \
|
||||
CMD wget -qO- http://127.0.0.1:8080/api/health >/dev/null || exit 1
|
||||
|
||||
ENTRYPOINT ["docker-migrate"]
|
||||
ENTRYPOINT ["dockmv"]
|
||||
CMD ["serve", "--addr", "0.0.0.0:8080"]
|
||||
@@ -1,6 +1,6 @@
|
||||
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
|
||||
LDFLAGS := -s -w -X main.version=$(VERSION)
|
||||
BIN := docker-migrate
|
||||
BIN := dockmv
|
||||
OUT := dist
|
||||
|
||||
# PowerShell 7+. The publish path lives in scripts/*.ps1 because uploading a
|
||||
@@ -47,7 +47,7 @@ fmt:
|
||||
cd web && npx tsc -b --noEmit
|
||||
|
||||
docker:
|
||||
docker build --build-arg VERSION=$(VERSION) -t docker-migrate:$(VERSION) -t docker-migrate:latest .
|
||||
docker build --build-arg VERSION=$(VERSION) -t dockmv:$(VERSION) -t dockmv:latest .
|
||||
|
||||
release: ui
|
||||
@mkdir -p $(OUT)
|
||||
|
||||
@@ -25,9 +25,9 @@ CLI, `bash` and `gzip`.
|
||||
On the **source** host:
|
||||
|
||||
```bash
|
||||
git clone <this repo> docker-migrate && cd docker-migrate
|
||||
git clone <this repo> dockmv && cd dockmv
|
||||
docker compose up -d --build
|
||||
docker compose logs docker-migrate # prints the URL, including the access token
|
||||
docker compose logs dockmv # prints the URL, including the access token
|
||||
```
|
||||
|
||||
Then open the printed URL. It binds to `127.0.0.1` only; reach it from your laptop with a tunnel:
|
||||
@@ -42,16 +42,16 @@ The binary is fully static and embeds the web UI, so there is nothing to install
|
||||
|
||||
```bash
|
||||
make build # needs Go 1.25+ and Node 20+ ... or just `go build .` if you skip the UI rebuild
|
||||
./docker-migrate serve
|
||||
./dockmv serve
|
||||
```
|
||||
|
||||
Prebuilt for several platforms:
|
||||
|
||||
```bash
|
||||
make release # dist/docker-migrate-linux-amd64, -linux-arm64, -darwin-arm64, -windows-amd64
|
||||
make release # dist/dockmv-linux-amd64, -linux-arm64, -darwin-arm64, -windows-amd64
|
||||
```
|
||||
|
||||
`docker-migrate` needs access to the Docker socket on the source host, so run it as a user in the
|
||||
`dockmv` needs access to the Docker socket on the source host, so run it as a user in the
|
||||
`docker` group (or as root).
|
||||
|
||||
---
|
||||
@@ -206,9 +206,9 @@ free disk space and architecture.
|
||||
## Command line
|
||||
|
||||
```
|
||||
docker-migrate [serve] [flags] start the web interface (default)
|
||||
docker-migrate inspect [flags] print the source inventory as JSON
|
||||
docker-migrate version
|
||||
dockmv [serve] [flags] start the web interface (default)
|
||||
dockmv inspect [flags] print the source inventory as JSON
|
||||
dockmv version
|
||||
```
|
||||
|
||||
`serve` flags:
|
||||
@@ -225,7 +225,7 @@ docker-migrate version
|
||||
`inspect` is handy for scripting and for reporting bugs:
|
||||
|
||||
```bash
|
||||
docker-migrate inspect --sizes | jq '.containers[] | {name, image, mounts}'
|
||||
dockmv inspect --sizes | jq '.containers[] | {name, image, mounts}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
+6
-6
@@ -1,20 +1,20 @@
|
||||
# docker-migrate, running on the SOURCE host.
|
||||
# dockmv, running on the SOURCE host.
|
||||
#
|
||||
# docker compose up -d
|
||||
# docker compose logs docker-migrate # the URL and access token are printed here
|
||||
# docker compose logs dockmv # the URL and access token are printed here
|
||||
#
|
||||
# The container needs the Docker socket to read containers and stream their
|
||||
# data. That is equivalent to root on this host, so the UI is protected by a
|
||||
# generated token and should not be published to an untrusted network.
|
||||
|
||||
services:
|
||||
docker-migrate:
|
||||
dockmv:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
VERSION: ${VERSION:-dev}
|
||||
image: docker-migrate:latest
|
||||
container_name: docker-migrate
|
||||
image: dockmv:latest
|
||||
container_name: dockmv
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
# Bind to loopback only. Use an SSH tunnel to reach it from elsewhere:
|
||||
@@ -26,7 +26,7 @@ services:
|
||||
- migrate-data:/data
|
||||
environment:
|
||||
# Set a fixed token to keep the same URL across restarts.
|
||||
# DOCKER_MIGRATE_TOKEN: change-me
|
||||
# DOCKMV_TOKEN: change-me
|
||||
TZ: ${TZ:-UTC}
|
||||
command:
|
||||
- serve
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module github.com/arescom/docker-migrate
|
||||
module github.com/arescom/dockmv
|
||||
|
||||
go 1.25.0
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/dkr"
|
||||
"github.com/arescom/docker-migrate/internal/job"
|
||||
"github.com/arescom/docker-migrate/internal/migrate"
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/docker-migrate/internal/sshx"
|
||||
"github.com/arescom/docker-migrate/internal/store"
|
||||
"github.com/arescom/dockmv/internal/dkr"
|
||||
"github.com/arescom/dockmv/internal/job"
|
||||
"github.com/arescom/dockmv/internal/migrate"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/sshx"
|
||||
"github.com/arescom/dockmv/internal/store"
|
||||
)
|
||||
|
||||
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/dkr"
|
||||
"github.com/arescom/docker-migrate/internal/job"
|
||||
"github.com/arescom/docker-migrate/internal/sshx"
|
||||
"github.com/arescom/docker-migrate/internal/store"
|
||||
"github.com/arescom/dockmv/internal/dkr"
|
||||
"github.com/arescom/dockmv/internal/job"
|
||||
"github.com/arescom/dockmv/internal/sshx"
|
||||
"github.com/arescom/dockmv/internal/store"
|
||||
)
|
||||
|
||||
// Config configures the HTTP server.
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
imagetypes "github.com/docker/docker/api/types/image"
|
||||
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
)
|
||||
|
||||
// TestLiveInventory is a smoke test against whatever daemon the environment
|
||||
// points at. It is skipped unless DOCKER_MIGRATE_LIVE_TEST is set, because it
|
||||
// points at. It is skipped unless DOCKMV_LIVE_TEST is set, because it
|
||||
// needs a real Docker host.
|
||||
func TestLiveInventory(t *testing.T) {
|
||||
if os.Getenv("DOCKER_MIGRATE_LIVE_TEST") == "" {
|
||||
t.Skip("set DOCKER_MIGRATE_LIVE_TEST=1 to run against the local daemon")
|
||||
if os.Getenv("DOCKMV_LIVE_TEST") == "" {
|
||||
t.Skip("set DOCKMV_LIVE_TEST=1 to run against the local daemon")
|
||||
}
|
||||
c, err := New("")
|
||||
if err != nil {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
)
|
||||
|
||||
// renderInstaller generates the shell script shipped inside a migration
|
||||
@@ -451,14 +451,14 @@ seed_readonly() { # container image destination relpath compressed
|
||||
store="$(resolve_mount "$1" "$3")" || { err "cannot resolve storage behind $3"; return 1; }
|
||||
base="${3##*/}"
|
||||
stage="dm-stage-$$-${RANDOM}"
|
||||
mountat="/__docker_migrate/$base"
|
||||
mountat="/__dockmv/$base"
|
||||
$DOCKER create --name "$stage" --volume "$store:$mountat" "$2" >/dev/null \
|
||||
|| { err "could not create staging container for $3"; return 1; }
|
||||
local rc=0
|
||||
if [ "$5" = 1 ]; then
|
||||
gzip -dc -- "$PKGDIR/$4" | $DOCKER cp -a - "$stage:/__docker_migrate" || rc=$?
|
||||
gzip -dc -- "$PKGDIR/$4" | $DOCKER cp -a - "$stage:/__dockmv" || rc=$?
|
||||
else
|
||||
$DOCKER cp -a - "$stage:/__docker_migrate" < "$PKGDIR/$4" || rc=$?
|
||||
$DOCKER cp -a - "$stage:/__dockmv" < "$PKGDIR/$4" || rc=$?
|
||||
fi
|
||||
$DOCKER rm -f "$stage" >/dev/null 2>&1 || true
|
||||
if [ "$rc" != 0 ]; then
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
)
|
||||
|
||||
func buildPrepared(t *testing.T, c *spec.Container, vols []spec.Volume, nets []spec.Network) *Prepared {
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/dkr"
|
||||
"github.com/arescom/docker-migrate/internal/job"
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/dkr"
|
||||
"github.com/arescom/dockmv/internal/job"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
)
|
||||
|
||||
// PackageFormat selects how the finished package is laid out on disk.
|
||||
@@ -102,7 +102,7 @@ func (p *Packager) Run(ctx context.Context, j *job.Job) (*Result, error) {
|
||||
man := spec.Manifest{
|
||||
FormatVersion: 1,
|
||||
CreatedAt: time.Now(),
|
||||
CreatedBy: "docker-migrate",
|
||||
CreatedBy: "dockmv",
|
||||
SourceHost: p.SourceHost,
|
||||
Options: opts,
|
||||
Items: p.Plan.Items,
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
)
|
||||
|
||||
// Prepared is one container resolved against the user's selection: the spec as
|
||||
@@ -189,7 +189,7 @@ func Prepare(
|
||||
|
||||
// StagingMountPath is where a read-only destination is mounted inside the
|
||||
// temporary staging container used to seed it.
|
||||
const stagingRoot = "/__docker_migrate"
|
||||
const stagingRoot = "/__dockmv"
|
||||
|
||||
// StagingPaths returns the mount point and the extraction directory used when
|
||||
// seeding a read-only mount through a staging container. The volume is mounted
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
)
|
||||
|
||||
func sample() *spec.Container {
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/dkr"
|
||||
"github.com/arescom/docker-migrate/internal/job"
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/docker-migrate/internal/sshx"
|
||||
"github.com/arescom/dockmv/internal/dkr"
|
||||
"github.com/arescom/dockmv/internal/job"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/sshx"
|
||||
)
|
||||
|
||||
// SSHRunner migrates containers straight from the local daemon to a target
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
)
|
||||
|
||||
// RemoteDocker drives the docker CLI on a target host over SSH. It assumes
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/sshx"
|
||||
"github.com/arescom/dockmv/internal/sshx"
|
||||
)
|
||||
|
||||
// ErrNotFound is returned for an unknown connection id.
|
||||
|
||||
Vendored
+1
-1
@@ -6,6 +6,6 @@
|
||||
`+o[a].replace(" at new "," at ");return l.displayName&&j.includes("<anonymous>")&&(j=j.replace("<anonymous>",l.displayName)),j}while(1<=a&&0<=n);break}}}finally{Wu=!1,Error.prepareStackTrace=e}return(e=l?l.displayName||l.name:"")?Me(e):""}function Yr(l,t){switch(l.tag){case 26:case 27:case 5:return Me(l.type);case 16:return Me("Lazy");case 13:return l.child!==t&&t!==null?Me("Suspense Fallback"):Me("Suspense");case 19:return Me("SuspenseList");case 0:case 15:return Fu(l.type,!1);case 11:return Fu(l.type.render,!1);case 1:return Fu(l.type,!0);case 31:return Me("Activity");default:return""}}function Ef(l){try{var t="",e=null;do t+=Yr(l,e),e=l,l=l.return;while(l);return t}catch(a){return`
|
||||
Error generating stack: `+a.message+`
|
||||
`+a.stack}}var Iu=Object.prototype.hasOwnProperty,Pu=h.unstable_scheduleCallback,li=h.unstable_cancelCallback,Gr=h.unstable_shouldYield,Xr=h.unstable_requestPaint,ot=h.unstable_now,Qr=h.unstable_getCurrentPriorityLevel,Af=h.unstable_ImmediatePriority,Nf=h.unstable_UserBlockingPriority,Un=h.unstable_NormalPriority,Zr=h.unstable_LowPriority,_f=h.unstable_IdlePriority,Lr=h.log,Vr=h.unstable_setDisableYieldValue,Ra=null,dt=null;function ne(l){if(typeof Lr=="function"&&Vr(l),dt&&typeof dt.setStrictMode=="function")try{dt.setStrictMode(Ra,l)}catch{}}var rt=Math.clz32?Math.clz32:wr,Kr=Math.log,Jr=Math.LN2;function wr(l){return l>>>=0,l===0?32:31-(Kr(l)/Jr|0)|0}var Cn=256,Hn=262144,Rn=4194304;function De(l){var t=l&42;if(t!==0)return t;switch(l&-l){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return l&261888;case 262144:case 524288:case 1048576:case 2097152:return l&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return l&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return l}}function qn(l,t,e){var a=l.pendingLanes;if(a===0)return 0;var n=0,u=l.suspendedLanes,i=l.pingedLanes;l=l.warmLanes;var f=a&134217727;return f!==0?(a=f&~u,a!==0?n=De(a):(i&=f,i!==0?n=De(i):e||(e=f&~l,e!==0&&(n=De(e))))):(f=a&~u,f!==0?n=De(f):i!==0?n=De(i):e||(e=a&~l,e!==0&&(n=De(e)))),n===0?0:t!==0&&t!==n&&(t&u)===0&&(u=n&-n,e=t&-t,u>=e||u===32&&(e&4194048)!==0)?t:n}function qa(l,t){return(l.pendingLanes&~(l.suspendedLanes&~l.pingedLanes)&t)===0}function kr(l,t){switch(l){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Of(){var l=Rn;return Rn<<=1,(Rn&62914560)===0&&(Rn=4194304),l}function ti(l){for(var t=[],e=0;31>e;e++)t.push(l);return t}function Ba(l,t){l.pendingLanes|=t,t!==268435456&&(l.suspendedLanes=0,l.pingedLanes=0,l.warmLanes=0)}function $r(l,t,e,a,n,u){var i=l.pendingLanes;l.pendingLanes=e,l.suspendedLanes=0,l.pingedLanes=0,l.warmLanes=0,l.expiredLanes&=e,l.entangledLanes&=e,l.errorRecoveryDisabledLanes&=e,l.shellSuspendCounter=0;var f=l.entanglements,o=l.expirationTimes,v=l.hiddenUpdates;for(e=i&~e;0<e;){var j=31-rt(e),T=1<<j;f[j]=0,o[j]=-1;var b=v[j];if(b!==null)for(v[j]=null,j=0;j<b.length;j++){var S=b[j];S!==null&&(S.lane&=-536870913)}e&=~T}a!==0&&Mf(l,a,0),u!==0&&n===0&&l.tag!==0&&(l.suspendedLanes|=u&~(i&~t))}function Mf(l,t,e){l.pendingLanes|=t,l.suspendedLanes&=~t;var a=31-rt(t);l.entangledLanes|=t,l.entanglements[a]=l.entanglements[a]|1073741824|e&261930}function Df(l,t){var e=l.entangledLanes|=t;for(l=l.entanglements;e;){var a=31-rt(e),n=1<<a;n&t|l[a]&t&&(l[a]|=t),e&=~n}}function Uf(l,t){var e=t&-t;return e=(e&42)!==0?1:ei(e),(e&(l.suspendedLanes|t))!==0?0:e}function ei(l){switch(l){case 2:l=1;break;case 8:l=4;break;case 32:l=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:l=128;break;case 268435456:l=134217728;break;default:l=0}return l}function ai(l){return l&=-l,2<l?8<l?(l&134217727)!==0?32:268435456:8:2}function Cf(){var l=C.p;return l!==0?l:(l=window.event,l===void 0?32:Sr(l.type))}function Hf(l,t){var e=C.p;try{return C.p=l,t()}finally{C.p=e}}var ue=Math.random().toString(36).slice(2),Jl="__reactFiber$"+ue,et="__reactProps$"+ue,$e="__reactContainer$"+ue,ni="__reactEvents$"+ue,Wr="__reactListeners$"+ue,Fr="__reactHandles$"+ue,Rf="__reactResources$"+ue,Ya="__reactMarker$"+ue;function ui(l){delete l[Jl],delete l[et],delete l[ni],delete l[Wr],delete l[Fr]}function We(l){var t=l[Jl];if(t)return t;for(var e=l.parentNode;e;){if(t=e[$e]||e[Jl]){if(e=t.alternate,t.child!==null||e!==null&&e.child!==null)for(l=ar(l);l!==null;){if(e=l[Jl])return e;l=ar(l)}return t}l=e,e=l.parentNode}return null}function Fe(l){if(l=l[Jl]||l[$e]){var t=l.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return l}return null}function Ga(l){var t=l.tag;if(t===5||t===26||t===27||t===6)return l.stateNode;throw Error(s(33))}function Ie(l){var t=l[Rf];return t||(t=l[Rf]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function Vl(l){l[Ya]=!0}var qf=new Set,Bf={};function Ue(l,t){Pe(l,t),Pe(l+"Capture",t)}function Pe(l,t){for(Bf[l]=t,l=0;l<t.length;l++)qf.add(t[l])}var Ir=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u21
Line truncated
|
||||
`).replace(Om,"")}function wd(l,t){return t=Jd(t),Jd(l)===t}function Sl(l,t,e,a,n,u){switch(e){case"children":typeof a=="string"?t==="body"||t==="textarea"&&a===""||ta(l,a):(typeof a=="number"||typeof a=="bigint")&&t!=="body"&&ta(l,""+a);break;case"className":Yn(l,"class",a);break;case"tabIndex":Yn(l,"tabindex",a);break;case"dir":case"role":case"viewBox":case"width":case"height":Yn(l,e,a);break;case"style":Jf(l,a,u);break;case"data":if(t!=="object"){Yn(l,"data",a);break}case"src":case"href":if(a===""&&(t!=="a"||e!=="href")){l.removeAttribute(e);break}if(a==null||typeof a=="function"||typeof a=="symbol"||typeof a=="boolean"){l.removeAttribute(e);break}a=Xn(""+a),l.setAttribute(e,a);break;case"action":case"formAction":if(typeof a=="function"){l.setAttribute(e,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof u=="function"&&(e==="formAction"?(t!=="input"&&Sl(l,t,"name",n.name,n,null),Sl(l,t,"formEncType",n.formEncType,n,null),Sl(l,t,"formMethod",n.formMethod,n,null),Sl(l,t,"formTarget",n.formTarget,n,null)):(Sl(l,t,"encType",n.encType,n,null),Sl(l,t,"method",n.method,n,null),Sl(l,t,"target",n.target,n,null)));if(a==null||typeof a=="symbol"||typeof a=="boolean"){l.removeAttribute(e);break}a=Xn(""+a),l.setAttribute(e,a);break;case"onClick":a!=null&&(l.onclick=Xt);break;case"onScroll":a!=null&&tl("scroll",l);break;case"onScrollEnd":a!=null&&tl("scrollend",l);break;case"dangerouslySetInnerHTML":if(a!=null){if(typeof a!="object"||!("__html"in a))throw Error(s(61));if(e=a.__html,e!=null){if(n.children!=null)throw Error(s(60));l.innerHTML=e}}break;case"multiple":l.multiple=a&&typeof a!="function"&&typeof a!="symbol";break;case"muted":l.muted=a&&typeof a!="function"&&typeof a!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(a==null||typeof a=="function"||typeof a=="boolean"||typeof a=="symbol"){l.removeAttribute("xlink:href");break}e=Xn(""+a),l.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",e);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":a!=null&&typeof a!="function"&&typeof a!="symbol"?l.setAttribute(e,""+a):l.removeAttribute(e);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":a&&typeof a!="function"&&typeof a!="symbol"?l.setAttribute(e,""):l.removeAttribute(e);break;case"capture":case"download":a===!0?l.setAttribute(e,""):a!==!1&&a!=null&&typeof a!="function"&&typeof a!="symbol"?l.setAttribute(e,a):l.removeAttribute(e);break;case"cols":case"rows":case"size":case"span":a!=null&&typeof a!="function"&&typeof a!="symbol"&&!isNaN(a)&&1<=a?l.setAttribute(e,a):l.removeAttribute(e);break;case"rowSpan":case"start":a==null||typeof a=="function"||typeof a=="symbol"||isNaN(a)?l.removeAttribute(e):l.setAttribute(e,a);break;case"popover":tl("beforetoggle",l),tl("toggle",l),Bn(l,"popover",a);break;case"xlinkActuate":Gt(l,"http://www.w3.org/1999/xlink","xlink:actuate",a);break;case"xlinkArcrole":Gt(l,"http://www.w3.org/1999/xlink","xlink:arcrole",a);break;case"xlinkRole":Gt(l,"http://www.w3.org/1999/xlink","xlink:role",a);break;case"xlinkShow":Gt(l,"http://www.w3.org/1999/xlink","xlink:show",a);break;case"xlinkTitle":Gt(l,"http://www.w3.org/1999/xlink","xlink:title",a);break;case"xlinkType":Gt(l,"http://www.w3.org/1999/xlink","xlink:type",a);break;case"xmlBase":Gt(l,"http://www.w3.org/XML/1998/namespace","xml:base",a);break;case"xmlLang":Gt(l,"http://www.w3.org/XML/1998/namespace","xml:lang",a);break;case"xmlSpace":Gt(l,"http://www.w3.org/XML/1998/namespace","xml:space",a);break;case"is":Bn(l,"is",a);break;case"innerText":case"textContent":break;default:(!(2<e.length)||e[0]!=="o"&&e[0]!=="O"||e[1]!=="n"&&e[1]!=="N")&&(e=ah.get(e)||e,Bn(l,e,a))}}function $c(l,t,e,a,n,u){switch(e){case"style":Jf(l,a,u);break;case"dangerouslySetInnerHTML":if(a!=null){if(typeof a!="object"||!("__html"in a))throw Error(s(61));if(e=a.__html,e!=null){if(n.children!=null)throw Error(s(60));l.innerHTML=e}}break;case"children":typeof a=="string"?ta(l,a):(typeof a=="number"||typeof a=="bigint")&&ta(l,""+a);break;case"onScroll":a!=null&&tl("scroll",l);break;case"onScrollEnd":a!=null&&tl("scrollend",l);break;case"onClick":a!=null&&(l.onclick=Xt);break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"inne
Line truncated
|
||||
`).replace(Om,"")}function wd(l,t){return t=Jd(t),Jd(l)===t}function Sl(l,t,e,a,n,u){switch(e){case"children":typeof a=="string"?t==="body"||t==="textarea"&&a===""||ta(l,a):(typeof a=="number"||typeof a=="bigint")&&t!=="body"&&ta(l,""+a);break;case"className":Yn(l,"class",a);break;case"tabIndex":Yn(l,"tabindex",a);break;case"dir":case"role":case"viewBox":case"width":case"height":Yn(l,e,a);break;case"style":Jf(l,a,u);break;case"data":if(t!=="object"){Yn(l,"data",a);break}case"src":case"href":if(a===""&&(t!=="a"||e!=="href")){l.removeAttribute(e);break}if(a==null||typeof a=="function"||typeof a=="symbol"||typeof a=="boolean"){l.removeAttribute(e);break}a=Xn(""+a),l.setAttribute(e,a);break;case"action":case"formAction":if(typeof a=="function"){l.setAttribute(e,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof u=="function"&&(e==="formAction"?(t!=="input"&&Sl(l,t,"name",n.name,n,null),Sl(l,t,"formEncType",n.formEncType,n,null),Sl(l,t,"formMethod",n.formMethod,n,null),Sl(l,t,"formTarget",n.formTarget,n,null)):(Sl(l,t,"encType",n.encType,n,null),Sl(l,t,"method",n.method,n,null),Sl(l,t,"target",n.target,n,null)));if(a==null||typeof a=="symbol"||typeof a=="boolean"){l.removeAttribute(e);break}a=Xn(""+a),l.setAttribute(e,a);break;case"onClick":a!=null&&(l.onclick=Xt);break;case"onScroll":a!=null&&tl("scroll",l);break;case"onScrollEnd":a!=null&&tl("scrollend",l);break;case"dangerouslySetInnerHTML":if(a!=null){if(typeof a!="object"||!("__html"in a))throw Error(s(61));if(e=a.__html,e!=null){if(n.children!=null)throw Error(s(60));l.innerHTML=e}}break;case"multiple":l.multiple=a&&typeof a!="function"&&typeof a!="symbol";break;case"muted":l.muted=a&&typeof a!="function"&&typeof a!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(a==null||typeof a=="function"||typeof a=="boolean"||typeof a=="symbol"){l.removeAttribute("xlink:href");break}e=Xn(""+a),l.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",e);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":a!=null&&typeof a!="function"&&typeof a!="symbol"?l.setAttribute(e,""+a):l.removeAttribute(e);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":a&&typeof a!="function"&&typeof a!="symbol"?l.setAttribute(e,""):l.removeAttribute(e);break;case"capture":case"download":a===!0?l.setAttribute(e,""):a!==!1&&a!=null&&typeof a!="function"&&typeof a!="symbol"?l.setAttribute(e,a):l.removeAttribute(e);break;case"cols":case"rows":case"size":case"span":a!=null&&typeof a!="function"&&typeof a!="symbol"&&!isNaN(a)&&1<=a?l.setAttribute(e,a):l.removeAttribute(e);break;case"rowSpan":case"start":a==null||typeof a=="function"||typeof a=="symbol"||isNaN(a)?l.removeAttribute(e):l.setAttribute(e,a);break;case"popover":tl("beforetoggle",l),tl("toggle",l),Bn(l,"popover",a);break;case"xlinkActuate":Gt(l,"http://www.w3.org/1999/xlink","xlink:actuate",a);break;case"xlinkArcrole":Gt(l,"http://www.w3.org/1999/xlink","xlink:arcrole",a);break;case"xlinkRole":Gt(l,"http://www.w3.org/1999/xlink","xlink:role",a);break;case"xlinkShow":Gt(l,"http://www.w3.org/1999/xlink","xlink:show",a);break;case"xlinkTitle":Gt(l,"http://www.w3.org/1999/xlink","xlink:title",a);break;case"xlinkType":Gt(l,"http://www.w3.org/1999/xlink","xlink:type",a);break;case"xmlBase":Gt(l,"http://www.w3.org/XML/1998/namespace","xml:base",a);break;case"xmlLang":Gt(l,"http://www.w3.org/XML/1998/namespace","xml:lang",a);break;case"xmlSpace":Gt(l,"http://www.w3.org/XML/1998/namespace","xml:space",a);break;case"is":Bn(l,"is",a);break;case"innerText":case"textContent":break;default:(!(2<e.length)||e[0]!=="o"&&e[0]!=="O"||e[1]!=="n"&&e[1]!=="N")&&(e=ah.get(e)||e,Bn(l,e,a))}}function $c(l,t,e,a,n,u){switch(e){case"style":Jf(l,a,u);break;case"dangerouslySetInnerHTML":if(a!=null){if(typeof a!="object"||!("__html"in a))throw Error(s(61));if(e=a.__html,e!=null){if(n.children!=null)throw Error(s(60));l.innerHTML=e}}break;case"children":typeof a=="string"?ta(l,a):(typeof a=="number"||typeof a=="bigint")&&ta(l,""+a);break;case"onScroll":a!=null&&tl("scroll",l);break;case"onScrollEnd":a!=null&&tl("scrollend",l);break;case"onClick":a!=null&&(l.onclick=Xt);break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"inne
Line truncated
|
||||
`)})]}),h.items.map(s=>c.jsxs("div",{children:[c.jsxs("h3",{style:{margin:"0 0 6px",fontSize:12},children:[s.name,s.targetName!==s.name&&c.jsxs("span",{className:"faint",children:[" → ",s.targetName]})]}),(s.warnings??[]).map((_,H)=>c.jsx(Dt,{kind:"warn",children:_},`w${H}`)),(s.notes??[]).map((_,H)=>c.jsxs("div",{className:"small faint",children:["· ",_]},`n${H}`)),c.jsx("pre",{className:"cmdblock",children:(s.commands??[]).join(`
|
||||
`)})]},s.containerId))]})})}function Ty({jobs:h,activeJob:N,setActiveJob:O,reload:s,reloadPackages:_}){const H=N||h[0]?.id||"";return h.length===0?c.jsx("div",{className:"empty",children:"no migrations yet — select containers and start one"}):c.jsxs("div",{style:{display:"flex",minHeight:0,height:"100%"},children:[c.jsx("div",{className:"joblist",style:{width:320,flex:"0 0 320px",overflow:"auto"},children:h.map(E=>c.jsxs("div",{className:`jobcard${E.id===H?" active":""}`,onClick:()=>O(E.id),children:[c.jsxs("div",{className:"row",children:[c.jsx(Mn,{state:E.state}),c.jsx("span",{className:"spacer"}),c.jsx("span",{className:"small faint",children:E.kind==="ssh"?"ssh":"package"})]}),c.jsx("div",{className:"truncate",style:{marginTop:2},children:E.title}),c.jsxs("div",{className:"small faint",children:[new Date(E.createdAt).toLocaleTimeString()," · ",qr(E.startedAt,E.endedAt),E.dryRun&&" · dry run"]}),c.jsx("div",{style:{marginTop:6},children:c.jsx(jf,{done:E.bytesDone,total:E.bytesTotal,state:E.state})})]},E.id))}),c.jsx("div",{style:{flex:1,minWidth:0,overflow:"auto",borderLeft:"1px solid var(--border)"},children:H&&c.jsx(Ey,{id:H,reload:s,reloadPackages:_})})]})}function Ey({id:h,reload:N,reloadPackages:O}){const[s,_]=K.useState(null),[H,E]=K.useState(!0),k=K.useRef(null),D=K.useRef(!0);K.useEffect(()=>{_(null);let A=!1;Gl.job(h).then(dl=>!A&&_(dl)).catch(()=>{});const B=Gl.jobEvents(h);return B.onmessage=dl=>{try{_(JSON.parse(dl.data))}catch{}},B.addEventListener("done",()=>{B.close(),N(),O()}),B.onerror=()=>B.close(),()=>{A=!0,B.close()}},[h,N,O]);const g=K.useMemo(()=>(s?.log??[]).filter(A=>H||A.level!=="cmd"),[s,H]);if(K.useEffect(()=>{const A=k.current;A&&D.current&&(A.scrollTop=A.scrollHeight)},[g]),!s)return c.jsx("div",{className:"empty",children:"loading…"});const J=s.state==="running"||s.state==="pending";return c.jsxs("div",{style:{padding:16,display:"flex",flexDirection:"column",gap:14},children:[c.jsxs("div",{className:"row",children:[c.jsx(Mn,{state:s.state}),c.jsx("b",{children:s.title}),s.dryRun&&c.jsx("span",{className:"badge",children:"dry run"}),c.jsx("span",{className:"spacer"}),c.jsxs("span",{className:"small faint",children:[ae(s.bytesDone),s.bytesTotal>0&&c.jsxs(c.Fragment,{children:[" of ",ae(s.bytesTotal)]})," · ",qr(s.startedAt,s.endedAt)]}),J?c.jsx("button",{className:"btn tiny danger",onClick:()=>Gl.cancelJob(s.id).then(N),children:"cancel"}):c.jsx("button",{className:"btn tiny ghost",onClick:()=>Gl.deleteJob(s.id).then(N),children:"remove"})]}),c.jsx(jf,{done:s.bytesDone,total:s.bytesTotal,state:s.state}),s.error&&c.jsx(Dt,{kind:"err",children:s.error}),s.state==="succeeded"&&s.artifact&&c.jsxs(Dt,{kind:"ok",children:["Package ready at ",c.jsx("span",{className:"mono",children:s.artifact})," (",ae(s.artifactBytes??0),")."," ","Open the Packages tab to download it."]}),s.items.map(A=>c.jsxs("div",{style:{border:"1px solid var(--border)",borderRadius:6,padding:"8px 10px"},children:[c.jsxs("div",{className:"row",children:[c.jsx(Mn,{state:A.state}),c.jsx("b",{children:A.name}),c.jsx("span",{className:"spacer"}),c.jsxs("span",{className:"small faint",children:[A.steps.filter(B=>B.state==="succeeded").length,"/",A.steps.length," steps"]})]}),A.error&&c.jsx("div",{className:"small",style:{color:"var(--err)"},children:A.error}),(A.warnings??[]).map((B,dl)=>c.jsxs("div",{className:"small",style:{color:"var(--warn)"},children:["! ",B]},dl)),c.jsx("div",{className:"steps",children:A.steps.map(B=>c.jsxs("div",{className:`step ${B.state}`,children:[c.jsx(Mn,{state:B.state,label:""}),c.jsx("span",{className:"label truncate",title:B.error||B.label,children:B.label}),c.jsx("span",{children:B.bytesTotal>0||B.bytesDone>0?c.jsx(jf,{done:B.bytesDone,total:B.bytesTotal,state:B.state}):null}),c.jsx("span",{className:"faint nowrap",style:{textAlign:"right"},children:B.bytesDone>0?ae(B.bytesDone):B.state==="skipped"?"skipped":""})]},B.id))})]},A.id)),c.jsxs("div",{className:"row",children:[c.jsx("h3",{style:{margin:0,fontSize:12},children:"log"}),c.jsx("span",{className:"spacer"}),c.jsxs("label",{className:"check small",children:[c.jsx("input",{type:"checkbox",checked:H,onChange:A=>E(A.target.checked)}),c.jsx("span",{children:"show commands"})]})]}),c.jsxs("div",{className:"log",ref:k,onScroll:A=>{const B=A.currentTarget;D.current=B.scrollHeight-B.scrollTop-B.clientHeight<24},children:[g.map(A=>c.jsxs("div",{className:`l-${A.level}`,children:[c.jsxs("span",{className:"ts",children:[new Date(A.at).toLocaleTimeString()," "]}),A.message]},A.seq)),g.length===0&&c.jsx("span",{className:"faint",children:"nothing logged yet"})]})]})}function Ay({packages:h,reload:N}){return h.length===0?c.jsx("div",{className:"empty",children:"no packages built yet"}):c.jsxs("div",{style:{padding:16,display:"flex",flexDirection:"column",gap:12},children:[c.jsxs(Dt,{kind:"info",children:["Copy a package to the target host, then run ",c.jsx("span",{className:"mono",children:"./install.sh --dry-run"})," to review it and"
Line truncated
|
||||
Vendored
+1
-1
@@ -6,7 +6,7 @@
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
<title>DockMV</title>
|
||||
<script type="module" crossorigin src="/assets/index-DJVzxyBi.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-2w4y0Lpg.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CKzWD9Xt.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Command docker-migrate moves Docker containers, together with their volumes
|
||||
// Command dockmv moves Docker containers, together with their volumes
|
||||
// and bind mounts, from one host to another.
|
||||
//
|
||||
// It runs either as a web application (the default) or as a one-shot inventory
|
||||
@@ -26,9 +26,9 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/api"
|
||||
"github.com/arescom/docker-migrate/internal/dkr"
|
||||
"github.com/arescom/docker-migrate/internal/webui"
|
||||
"github.com/arescom/dockmv/internal/api"
|
||||
"github.com/arescom/dockmv/internal/dkr"
|
||||
"github.com/arescom/dockmv/internal/webui"
|
||||
)
|
||||
|
||||
// version is overridden at build time with -ldflags "-X main.version=...".
|
||||
@@ -55,7 +55,7 @@ func run(args []string) error {
|
||||
case "inspect":
|
||||
return inspect(args)
|
||||
case "version":
|
||||
fmt.Printf("docker-migrate %s (%s %s/%s)\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
fmt.Printf("dockmv %s (%s %s/%s)\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
return nil
|
||||
case "help", "-h", "--help":
|
||||
usage()
|
||||
@@ -67,14 +67,14 @@ func run(args []string) error {
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprint(os.Stderr, `docker-migrate - move Docker containers and their data between hosts
|
||||
fmt.Fprint(os.Stderr, `dockmv - move Docker containers and their data between hosts
|
||||
|
||||
Usage:
|
||||
docker-migrate [serve] [flags] start the web interface (default)
|
||||
docker-migrate inspect [flags] print the source inventory as JSON
|
||||
docker-migrate version print the version
|
||||
dockmv [serve] [flags] start the web interface (default)
|
||||
dockmv inspect [flags] print the source inventory as JSON
|
||||
dockmv version print the version
|
||||
|
||||
Run "docker-migrate serve -h" for the server flags.
|
||||
Run "dockmv serve -h" for the server flags.
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func serve(args []string) error {
|
||||
dockerHost := fs.String("docker-host", "", "source docker daemon (default: the DOCKER_HOST environment)")
|
||||
verbose := fs.Bool("v", false, "verbose logging")
|
||||
fs.Usage = func() {
|
||||
fmt.Fprintln(os.Stderr, "Usage: docker-migrate serve [flags]\n\nFlags:")
|
||||
fmt.Fprintln(os.Stderr, "Usage: dockmv serve [flags]\n\nFlags:")
|
||||
fs.PrintDefaults()
|
||||
}
|
||||
if err := fs.Parse(args); err != nil {
|
||||
@@ -148,7 +148,7 @@ func serve(args []string) error {
|
||||
if authToken != "" {
|
||||
url += "/?token=" + authToken
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "\n docker-migrate %s\n open %s\n data: %s\n\n", version, url, *dataDir)
|
||||
fmt.Fprintf(os.Stderr, "\n dockmv %s\n open %s\n data: %s\n\n", version, url, *dataDir)
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
@@ -176,7 +176,7 @@ func inspect(args []string) error {
|
||||
dockerHost := fs.String("docker-host", "", "docker daemon to read (default: the DOCKER_HOST environment)")
|
||||
sizes := fs.Bool("sizes", false, "also measure volume sizes (slower)")
|
||||
fs.Usage = func() {
|
||||
fmt.Fprintln(os.Stderr, "Usage: docker-migrate inspect [flags]\n\nFlags:")
|
||||
fmt.Fprintln(os.Stderr, "Usage: dockmv inspect [flags]\n\nFlags:")
|
||||
fs.PrintDefaults()
|
||||
}
|
||||
if err := fs.Parse(args); err != nil {
|
||||
@@ -207,15 +207,15 @@ func inspect(args []string) error {
|
||||
}
|
||||
|
||||
// defaultDataDir picks a per-user location, honouring the container-friendly
|
||||
// DOCKER_MIGRATE_DATA override.
|
||||
// DOCKMV_DATA override.
|
||||
func defaultDataDir() string {
|
||||
if v := os.Getenv("DOCKER_MIGRATE_DATA"); v != "" {
|
||||
if v := os.Getenv("DOCKMV_DATA"); v != "" {
|
||||
return v
|
||||
}
|
||||
if dir, err := os.UserConfigDir(); err == nil {
|
||||
return filepath.Join(dir, "docker-migrate")
|
||||
return filepath.Join(dir, "dockmv")
|
||||
}
|
||||
return ".docker-migrate"
|
||||
return ".dockmv"
|
||||
}
|
||||
|
||||
func randomToken() string {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Build the docker-migrate web UI and cross-compile release binaries.
|
||||
Build the dockmv web UI and cross-compile release binaries.
|
||||
|
||||
.DESCRIPTION
|
||||
Produces dist/docker-migrate-<os>-<arch>[.exe] for every target, one archive
|
||||
Produces dist/dockmv-<os>-<arch>[.exe] for every target, one archive
|
||||
per binary (.zip for Windows, .tar.gz elsewhere) and dist/SHA256SUMS.txt.
|
||||
|
||||
The PowerShell equivalent of `make release`, so a Windows host without make
|
||||
@@ -130,11 +130,11 @@ try {
|
||||
if (-not $Tag) { $Tag = "dev" }
|
||||
}
|
||||
|
||||
$bin = "docker-migrate"
|
||||
$bin = "dockmv"
|
||||
$distDir = Join-Path $repoRoot "dist"
|
||||
$ldflags = "-s -w -X main.version=$Tag"
|
||||
|
||||
Write-Host "docker-migrate release build" -ForegroundColor Cyan
|
||||
Write-Host "dockmv release build" -ForegroundColor Cyan
|
||||
Write-Host " go : $Go"
|
||||
Write-Host " tag : $Tag"
|
||||
Write-Host " targets : $($Targets -join ', ')"
|
||||
@@ -152,13 +152,17 @@ try {
|
||||
# run before the compile — not after, and not in parallel with it.
|
||||
if (-not $SkipUi) {
|
||||
Write-Host "Building web UI..." -ForegroundColor Cyan
|
||||
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
|
||||
# npm.cmd, not npm(.ps1): the ps1 shim reparses $MyInvocation.Line as text
|
||||
# when called via `& $Exe @Args`, which mangles splatted args into a bogus
|
||||
# single token and makes npm print usage instead of running the command.
|
||||
$npmCmd = (Get-Command npm.cmd -ErrorAction SilentlyContinue).Source
|
||||
if (-not $npmCmd) {
|
||||
throw "npm not found — install Node 22+, or pass -SkipUi to reuse the committed internal/webui/dist."
|
||||
}
|
||||
Push-Location (Join-Path $repoRoot "web")
|
||||
try {
|
||||
Invoke-Checked npm @("ci", "--no-audit", "--no-fund")
|
||||
Invoke-Checked npm @("run", "build")
|
||||
Invoke-Checked $npmCmd @("ci", "--no-audit", "--no-fund")
|
||||
Invoke-Checked $npmCmd @("run", "build")
|
||||
}
|
||||
finally { Pop-Location }
|
||||
Write-Host ""
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
#requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Build the docker-migrate container image + release binaries; push the image to
|
||||
Build the dockmv container image + release binaries; push the image to
|
||||
the Gitea registry and attach the binaries to a Gitea release.
|
||||
|
||||
.DESCRIPTION
|
||||
@@ -58,7 +58,7 @@ param(
|
||||
[string]$Owner = "kawa",
|
||||
|
||||
# Image name.
|
||||
[string]$Image = "docker-migrate",
|
||||
[string]$Image = "dockmv",
|
||||
|
||||
# Repository name holding the releases. The image and the repo are not named
|
||||
# the same here, so this is separate from -Image.
|
||||
@@ -242,7 +242,7 @@ function Publish-BinaryRelease {
|
||||
Write-Host " creating release $Tag in $RepoPath..." -ForegroundColor DarkGray
|
||||
$release = Invoke-GiteaApi -Method POST -Uri $releasesUri -Token $Token -Body @{
|
||||
tag_name = $Tag
|
||||
name = "docker-migrate $Tag"
|
||||
name = "dockmv $Tag"
|
||||
body = "Standalone binaries for linux, macOS and Windows. Container image: see the package registry."
|
||||
draft = $false
|
||||
}
|
||||
@@ -311,7 +311,7 @@ try {
|
||||
$tags = @("$base`:$Tag")
|
||||
if (-not $NoLatest -and $Tag -ne "latest") { $tags += "$base`:latest" }
|
||||
|
||||
Write-Host "docker-migrate publish" -ForegroundColor Cyan
|
||||
Write-Host "dockmv publish" -ForegroundColor Cyan
|
||||
Write-Host " registry : $Registry"
|
||||
if ($pushImage) {
|
||||
Write-Host " image : $base"
|
||||
@@ -358,10 +358,10 @@ try {
|
||||
|
||||
# Uploading a binary older than the code it claims to be is the one way
|
||||
# this flag can quietly go wrong, so say so rather than assume.
|
||||
$oldest = (Get-ChildItem $distDir -Filter "docker-migrate-$Tag-*" -File |
|
||||
$oldest = (Get-ChildItem $distDir -Filter "dockmv-$Tag-*" -File |
|
||||
Sort-Object LastWriteTime | Select-Object -First 1)
|
||||
if (-not $oldest) {
|
||||
throw "no archives named docker-migrate-$Tag-* in $distDir — the exe on disk was built under a different tag. Drop -NoBinaryBuild."
|
||||
throw "no archives named dockmv-$Tag-* in $distDir — the exe on disk was built under a different tag. Drop -NoBinaryBuild."
|
||||
}
|
||||
$newer = Get-ChildItem $repoRoot -Recurse -Include *.go, *.ts, *.tsx, *.css, *.html -File |
|
||||
Where-Object {
|
||||
@@ -383,7 +383,7 @@ try {
|
||||
& (Join-Path $PSScriptRoot "build-release.ps1") -Tag $Tag -Targets $Targets -SkipUi:$SkipUi
|
||||
}
|
||||
|
||||
$artifacts = @(Get-ChildItem $distDir -Filter "docker-migrate-$Tag-*" -File | ForEach-Object FullName)
|
||||
$artifacts = @(Get-ChildItem $distDir -Filter "dockmv-$Tag-*" -File | ForEach-Object FullName)
|
||||
if (-not $artifacts.Count) { throw "no release archives for $Tag found in $distDir." }
|
||||
$sums = Join-Path $distDir "SHA256SUMS.txt"
|
||||
if (Test-Path $sums) { $artifacts += $sums }
|
||||
|
||||
+4
-4
@@ -20,10 +20,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/dkr"
|
||||
"github.com/arescom/docker-migrate/internal/job"
|
||||
"github.com/arescom/docker-migrate/internal/migrate"
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/dkr"
|
||||
"github.com/arescom/dockmv/internal/job"
|
||||
"github.com/arescom/dockmv/internal/migrate"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ package e2e
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/sshx"
|
||||
"github.com/arescom/dockmv/internal/sshx"
|
||||
)
|
||||
|
||||
// asHostKeyError unwraps err into a *sshx.HostKeyError if it is one.
|
||||
|
||||
@@ -10,11 +10,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/arescom/docker-migrate/internal/dkr"
|
||||
"github.com/arescom/docker-migrate/internal/job"
|
||||
"github.com/arescom/docker-migrate/internal/migrate"
|
||||
"github.com/arescom/docker-migrate/internal/spec"
|
||||
"github.com/arescom/docker-migrate/internal/sshx"
|
||||
"github.com/arescom/dockmv/internal/dkr"
|
||||
"github.com/arescom/dockmv/internal/job"
|
||||
"github.com/arescom/dockmv/internal/migrate"
|
||||
"github.com/arescom/dockmv/internal/spec"
|
||||
"github.com/arescom/dockmv/internal/sshx"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
|
||||
Generated
+2
-2
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "docker-migrate-ui",
|
||||
"name": "dockmv-ui",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "docker-migrate-ui",
|
||||
"name": "dockmv-ui",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"react": "^19.2.0",
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "docker-migrate-ui",
|
||||
"name": "dockmv-ui",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
|
||||
+2
-2
@@ -425,7 +425,7 @@ function ConnectionDialog({
|
||||
|
||||
{c.auth === 'agent' && (
|
||||
<div className="small muted">
|
||||
Uses the agent at <span className="mono">$SSH_AUTH_SOCK</span> of the process running docker-migrate.
|
||||
Uses the agent at <span className="mono">$SSH_AUTH_SOCK</span> of the process running dockmv.
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -452,7 +452,7 @@ function ConnectionDialog({
|
||||
</Notice>
|
||||
) : (
|
||||
<div className="small faint">
|
||||
Credentials stay in memory and are lost when docker-migrate restarts.
|
||||
Credentials stay in memory and are lost when dockmv restarts.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* docker-migrate UI.
|
||||
/* dockmv UI.
|
||||
An operations tool: dense, monospace-leaning, dark by default. Colour is
|
||||
reserved for state, never for decoration. */
|
||||
|
||||
|
||||
Reference in new issue
Block a user