Skip to content

Commit 51af785

Browse files
authored
Merge pull request ActiveState#3502 from ActiveState/mitchell/dx-2943
Test for hardlink support on Windows before doing it.
2 parents 8550d6b + d4008ea commit 51af785

File tree

3 files changed

+87
-18
lines changed

3 files changed

+87
-18
lines changed

pkg/runtime/links_unix.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//go:build linux || darwin
2+
// +build linux darwin
3+
4+
package runtime
5+
6+
func supportsHardLinks(path string) bool {
7+
return true
8+
}

pkg/runtime/links_windows.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package runtime
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
7+
"github.com/ActiveState/cli/internal/fileutils"
8+
"github.com/ActiveState/cli/internal/logging"
9+
"github.com/ActiveState/cli/internal/multilog"
10+
"github.com/ActiveState/cli/internal/smartlink"
11+
)
12+
13+
const linkTarget = "__target__"
14+
const link = "__link__"
15+
16+
func supportsHardLinks(path string) (supported bool) {
17+
defer func() {
18+
if !supported {
19+
logging.Debug("Enforcing deployment via copy, as hardlinks are not supported")
20+
}
21+
}()
22+
23+
target := filepath.Join(path, linkTarget)
24+
err := fileutils.Touch(target)
25+
if err != nil {
26+
multilog.Error("Error touching target: %v", err)
27+
return false
28+
}
29+
defer func() {
30+
err := os.Remove(target)
31+
if err != nil {
32+
multilog.Error("Error removing target: %v", err)
33+
}
34+
}()
35+
36+
lnk := filepath.Join(path, link)
37+
if fileutils.TargetExists(lnk) {
38+
err := os.Remove(lnk)
39+
if err != nil {
40+
multilog.Error("Error removing previous link: %v", err)
41+
return false
42+
}
43+
}
44+
45+
logging.Debug("Attempting to link '%s' to '%s'", lnk, target)
46+
err = smartlink.Link(target, lnk)
47+
if err != nil {
48+
logging.Debug("Test link creation failed: %v", err)
49+
return false
50+
}
51+
err = os.Remove(lnk)
52+
if err != nil {
53+
multilog.Error("Error removing link: %v", err)
54+
}
55+
56+
return true
57+
}

pkg/runtime/setup.go

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,12 @@ type Opts struct {
6262
type SetOpt func(*Opts)
6363

6464
type setup struct {
65-
path string
66-
opts *Opts
67-
depot *depot
68-
env *envdef.Collection
69-
buildplan *buildplan.BuildPlan
65+
path string
66+
opts *Opts
67+
depot *depot
68+
supportsHardLinks bool
69+
env *envdef.Collection
70+
buildplan *buildplan.BuildPlan
7071

7172
// toBuild encompasses all artifacts that will need to be build for this runtime.
7273
// This does NOT mean every artifact in the runtime closure if this is an update (as oppose to a fresh toInstall).
@@ -163,16 +164,17 @@ func newSetup(path string, bp *buildplan.BuildPlan, env *envdef.Collection, depo
163164
}
164165

165166
return &setup{
166-
path: path,
167-
opts: opts,
168-
env: env,
169-
depot: depot,
170-
buildplan: bp,
171-
toBuild: artifactsToBuild.ToIDMap(),
172-
toDownload: artifactsToDownload.ToIDMap(),
173-
toUnpack: artifactsToUnpack.ToIDMap(),
174-
toInstall: artifactsToInstall.ToIDMap(),
175-
toUninstall: artifactsToUninstall,
167+
path: path,
168+
opts: opts,
169+
env: env,
170+
depot: depot,
171+
supportsHardLinks: supportsHardLinks(depot.depotPath),
172+
buildplan: bp,
173+
toBuild: artifactsToBuild.ToIDMap(),
174+
toDownload: artifactsToDownload.ToIDMap(),
175+
toUnpack: artifactsToUnpack.ToIDMap(),
176+
toInstall: artifactsToInstall.ToIDMap(),
177+
toUninstall: artifactsToUninstall,
176178
}, nil
177179
}
178180

@@ -463,12 +465,14 @@ func (s *setup) install(id strfmt.UUID) (rerr error) {
463465
return errs.Wrap(err, "Could not get env")
464466
}
465467

466-
if envDef.NeedsTransforms() {
468+
if envDef.NeedsTransforms() || !s.supportsHardLinks {
467469
if err := s.depot.DeployViaCopy(id, envDef.InstallDir, s.path); err != nil {
468470
return errs.Wrap(err, "Could not deploy artifact via copy")
469471
}
470-
if err := envDef.ApplyFileTransforms(s.path); err != nil {
471-
return errs.Wrap(err, "Could not apply env transforms")
472+
if envDef.NeedsTransforms() {
473+
if err := envDef.ApplyFileTransforms(s.path); err != nil {
474+
return errs.Wrap(err, "Could not apply env transforms")
475+
}
472476
}
473477
} else {
474478
if err := s.depot.DeployViaLink(id, envDef.InstallDir, s.path); err != nil {

0 commit comments

Comments
 (0)