Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable linking on other operating systems #666

Merged
merged 46 commits into from
Apr 28, 2020
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
21a7e18
Remove linux check for symlink step
MDrakos Apr 23, 2020
289a1a3
Add simple symlink test
MDrakos Apr 23, 2020
1bcee02
Ensure symlink tests pass on Windows
MDrakos Apr 23, 2020
d5870b6
Move windows specific logic to its own file
MDrakos Apr 23, 2020
97eb652
Fix symlink test
MDrakos Apr 23, 2020
099c48a
Fix other failing tests
MDrakos Apr 23, 2020
39a47e8
Enable force flag on other operating systems
MDrakos Apr 24, 2020
601cdf6
Use shortcuts on Windows
MDrakos Apr 24, 2020
1b8784c
Remove unnecessary test helpers
MDrakos Apr 24, 2020
a986ea7
Fix failing test
MDrakos Apr 24, 2020
eaf9e82
Fix unit test on Windows
MDrakos Apr 24, 2020
a5968cd
Merge branch 'master' into enable-symlinks-172342127
MDrakos Apr 24, 2020
4ad43ac
Run go mod vendor
MDrakos Apr 24, 2020
7de650e
Add comment explaining modification of PATHEXT
MDrakos Apr 24, 2020
f5cf67e
Fix failing unit test
MDrakos Apr 27, 2020
f006207
Merge branch 'enable-symlinks-172342127' of github.com:ActiveState/cl…
MDrakos Apr 27, 2020
89365f5
Update report message on Windows
MDrakos Apr 27, 2020
7318fdc
Move platform specific functions to separate files
MDrakos Apr 27, 2020
46a31c7
Fix typo
MDrakos Apr 27, 2020
1cd749f
Merge branch 'master' into enable-symlinks-172342127
MDrakos Apr 27, 2020
c7e0e4d
Fix typo
MDrakos Apr 27, 2020
dbcebe2
Merge branch 'master' into enable-symlinks-172342127
MDrakos Apr 27, 2020
884ac2a
Reverse logic on executable function
MDrakos Apr 27, 2020
4f93720
Move PATHEXT modification to GetEnv
MDrakos Apr 27, 2020
0627270
Fix deploy unit test
MDrakos Apr 28, 2020
a9adec8
Move IsWritable to fileutils
MDrakos Apr 28, 2020
0b788cb
Merge branch 'enable-symlinks-172342127' of github.com:ActiveState/cl…
MDrakos Apr 28, 2020
7917c3c
Use deploy message
MDrakos Apr 28, 2020
9f9f54f
Remove unit test in lieu of incoming integration tests
MDrakos Apr 28, 2020
489d3fc
Remove unused function
MDrakos Apr 28, 2020
0847480
Remove unused testdata
MDrakos Apr 28, 2020
433396f
Use locale errors when creating shortcuts
MDrakos Apr 28, 2020
36593e0
Revert whitespace change
MDrakos Apr 28, 2020
ee5cf12
Remove dir check from IsWritable
MDrakos Apr 28, 2020
2c74f6a
Remove deployMessage function
MDrakos Apr 28, 2020
2f4d791
Move PATHEXT modification to virtualenvironment.GetEnv
MDrakos Apr 28, 2020
20795b8
Use Powershell script over library to create shortcuts
MDrakos Apr 28, 2020
a99cdd6
Run go mod tidy
MDrakos Apr 28, 2020
5b53db0
Remove unnecessary debugging statements
MDrakos Apr 28, 2020
300301f
Fix report test
MDrakos Apr 28, 2020
1a81c45
Call IsDir before checking if writable
MDrakos Apr 28, 2020
b118660
Fix whitespace again
MDrakos Apr 28, 2020
6928b22
Fix locale key
MDrakos Apr 28, 2020
43f10b7
Create new IsDir fileutils function
MDrakos Apr 28, 2020
fb8e1b2
Merge branch 'enable-symlinks-172342127' of github.com:ActiveState/cl…
MDrakos Apr 28, 2020
f979477
Don't modify PATHEXT
MDrakos Apr 28, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions assets/scripts/createShortcut.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
param ( [string]$SourceExe, [string]$DestinationPath )

$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($DestinationPath)
$Shortcut.TargetPath = $SourceExe
$Shortcut.Save()
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/fatih/color v1.5.0
github.com/fsnotify/fsnotify v1.4.7
github.com/go-ini/ini v1.32.0 // indirect
github.com/go-ole/go-ole v1.2.4
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/go-openapi/analysis v0.0.0-20180418034448-863ac7f90e00 // indirect
github.com/go-openapi/errors v0.0.0-20171226161601-7bcb96a367ba
github.com/go-openapi/jsonpointer v0.0.0-20180322222829-3a0015ad55fa // indirect
Expand Down
17 changes: 17 additions & 0 deletions internal/fileutils/fileutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/ActiveState/cli/internal/failures"
"github.com/ActiveState/cli/internal/locale"
"github.com/ActiveState/cli/internal/logging"
"github.com/google/uuid"
)

// FailFindInPathNotFound indicates the specified file was not found in the given path or parent directories
Expand Down Expand Up @@ -742,3 +743,19 @@ func HomeDir() (string, error) {

return usr.HomeDir, nil
}

// IsWritable returns true if the given path is writable
func IsWritable(path string) bool {
fpath := filepath.Join(path, uuid.New().String())
if fail := Touch(fpath); fail != nil {
logging.Error("Could not create file: %v", fail.ToError())
return false
}

if errr := os.Remove(fpath); errr != nil {
logging.Error("Could not clean up test file: %v", errr)
return false
}

return true
}
19 changes: 15 additions & 4 deletions internal/runners/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package deploy
import (
"os"
"path/filepath"
rt "runtime"
"strings"

"github.com/thoas/go-funk"
Expand Down Expand Up @@ -154,7 +155,7 @@ func install(installer installable, out output.Outputer) (runtime.EnvGetter, err
if fail != nil {
return envGetter, errs.Wrap(fail, "Install failed")
}
if !installed {
if ! installed {
out.Notice(locale.T("using_cached_env"))
}
return envGetter, nil
Expand Down Expand Up @@ -224,7 +225,7 @@ func symlinkWithTarget(overwrite bool, path string, bins []string, out output.Ou
for _, bin := range bins {
err := filepath.Walk(bin, func(fpath string, info os.FileInfo, err error) error {
// Filter out files that are not executable
if info == nil || info.IsDir() || !executable(fpath, info) { // check if executable by anyone
if info == nil || info.IsDir() || !fileutils.IsExecutable(fpath) { // check if executable by anyone
return nil // not executable
}

Expand Down Expand Up @@ -279,7 +280,11 @@ func report(envGetter runtime.EnvGetter, out output.Outputer) error {
Environment: env,
})

out.Notice(locale.T("deploy_restart_shell"))
if rt.GOOS == "windows" {
out.Notice(locale.T("deploy_restart_cmd"))
} else {
out.Notice(locale.T("deploy_restart_shell"))
}

return nil
}
Expand All @@ -297,7 +302,13 @@ func usablePath() (string, error) {
}
var result string
for _, path := range paths {
if !isWritable(path) {
info, err := os.Stat(path)
if err != nil {
logging.Debug("Could not stat path: %v", err)
continue
}

if path == "" || !info.IsDir() || !fileutils.IsWritable(path) {
MDrakos marked this conversation as resolved.
Show resolved Hide resolved
continue
}

Expand Down
117 changes: 6 additions & 111 deletions internal/runners/deploy/deploy_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
package deploy

import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"reflect"
rt "runtime"
"strings"
"testing"

"github.com/ActiveState/cli/internal/environment"
"github.com/ActiveState/cli/internal/failures"
"github.com/ActiveState/cli/internal/fileutils"
"github.com/ActiveState/cli/internal/output"
"github.com/ActiveState/cli/internal/testhelpers/outputhelper"
"github.com/ActiveState/cli/pkg/platform/runtime"
Expand Down Expand Up @@ -40,15 +34,6 @@ func (e *EnvGetMock) GetEnv(inherit bool, projectDir string) (map[string]string,
return e.callback(inherit, projectDir)
}

type OutputterMock struct{}

func (o *OutputterMock) Print(value interface{}) {}
func (o *OutputterMock) Error(value interface{}) {}
func (o *OutputterMock) Notice(value interface{}) {}
func (o *OutputterMock) Config() *output.Config {
return nil
}

func Test_runStepsWithFuncs(t *testing.T) {
type args struct {
installer installable
Expand Down Expand Up @@ -185,7 +170,11 @@ func Test_report(t *testing.T) {
"KEY1": "VAL1",
"KEY2": "VAL2",
}
prepareDeployEnv(baseEnv)

if rt.GOOS == "windows" {
originalExtenstions := os.Getenv("PATHEXT")
baseEnv["PATHEXT"] = originalExtenstions + ";.LNK"
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem necessary for our tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

virtualenvironment.GetEnv() now returns an environment with this updated PATHEXT.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, but what does that have to do with the code in this test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The report function calls virtualenvironment.GetEnv() so it now includes the updated PATHEXT


type args struct {
envGetter runtime.EnvGetter
Expand All @@ -202,7 +191,7 @@ func Test_report(t *testing.T) {
args{
&EnvGetMock{
func(inherit bool, projectDir string) (map[string]string, *failures.Failure) {
baseEnv["PATH"] = "PATH1" + string(os.PathListSeparator) + "PATH2"
baseEnv["PATH"] = "PATH1" + string(os.PathListSeparator) + "PATH2"
return baseEnv, nil
},
},
Expand Down Expand Up @@ -235,97 +224,3 @@ func Test_report(t *testing.T) {
})
}
}

func Test_symlinkWithTarget(t *testing.T) {
root, err := environment.GetRootPath()
if err != nil {
t.Error(err)
}

testDataDir := filepath.Join(root, "internal", "runners", "deploy", "testdata")
testFile := filepath.Join(testDataDir, "main.go")
binaryName := "test-bin"
if rt.GOOS == "windows" {
binaryName += ".exe"
}

cmd := exec.Command("go", "build", "-o", filepath.Join(testDataDir, binaryName), testFile)
err = cmd.Run()
if err != nil {
t.Error(err)
}

installDir, err := ioutil.TempDir("", "install-dir")
if err != nil {
t.Error(err)
}

targetDir, err := ioutil.TempDir("", "target-dir")
if err != nil {
t.Error(err)
}

fail := fileutils.CopyFile(filepath.Join(testDataDir, binaryName), filepath.Join(installDir, binaryName))
if fail != nil {
t.Error(fail.ToError())
}

if rt.GOOS != "windows" {
cmd = exec.Command("chmod", "+x", filepath.Join(installDir, binaryName))
err = cmd.Run()
if err != nil {
t.Error(err)
}
}

type args struct {
overwrite bool
path string
bins []string
out output.Outputer
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "Symlink binary file",
args: args{
overwrite: false,
path: targetDir,
bins: []string{installDir},
out: &OutputterMock{},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := symlinkWithTarget(tt.args.overwrite, tt.args.path, tt.args.bins, tt.args.out); (err != nil) != tt.wantErr {
t.Errorf("symlinkWithTarget() error = %v, wantErr %v", err, tt.wantErr)
}
defer func() {
os.RemoveAll(installDir)
os.RemoveAll(targetDir)
os.Remove(filepath.Join(testDataDir, binaryName))
}()

var cmd *exec.Cmd
if rt.GOOS == "windows" {
shortcut := strings.TrimSuffix(binaryName, ".exe")
shortcut += ".lnk"
cmd = exec.Command("cmd.exe", "/c", filepath.Join(targetDir, shortcut))
} else {
cmd = exec.Command(filepath.Join(targetDir, binaryName))
}

out, err := cmd.Output()
if err != nil {
t.Error(err)
}
if strings.TrimSpace(string(out)) != "Hello World!" {
t.Fatalf("Unexpected output: %s", string(out))
}
})
}
}
48 changes: 0 additions & 48 deletions internal/runners/deploy/helpers_lin_mac.go

This file was deleted.

Loading