• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

UiPath / uipathcli / 13285657222

12 Feb 2025 12:41PM UTC coverage: 90.092% (-0.4%) from 90.522%
13285657222

push

github

thschmitt
Download .NET runtime for cross-platform Studio Projects

- Downloading the required .NET runtime when the user builds
  cross-platform Studio projects which allows the uipathcli to work
  without any additional dependencies

- Added support to for tar.gz archives which is needed to extract
  dotnet runtime archives on Linux and MacOS

88 of 121 new or added lines in 5 files covered. (72.73%)

4 existing lines in 2 files now uncovered.

5074 of 5632 relevant lines covered (90.09%)

1.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.61
/plugin/external_plugin.go
1
package plugin
2

3
import (
4
        "crypto/rand"
5
        "crypto/sha256"
6
        "fmt"
7
        "io"
8
        "math"
9
        "math/big"
10
        "net/http"
11
        "os"
12
        "path/filepath"
13

14
        "github.com/UiPath/uipathcli/log"
15
        "github.com/UiPath/uipathcli/utils/directories"
16
        "github.com/UiPath/uipathcli/utils/resiliency"
17
        "github.com/UiPath/uipathcli/utils/visualization"
18
)
19

20
const pluginDirectoryPermissions = 0700
21

22
type ExternalPlugin struct {
23
        Logger log.Logger
24
}
25

26
func (p ExternalPlugin) GetTool(name string, url string, archiveType ArchiveType, executable string) (string, error) {
1✔
27
        pluginDirectory, err := p.pluginDirectory(name, url)
1✔
28
        if err != nil {
1✔
29
                return "", fmt.Errorf("Could not download %s: %v", name, err)
×
30
        }
×
31
        path := filepath.Join(pluginDirectory, executable)
1✔
32
        if _, err := os.Stat(path); err == nil {
2✔
33
                return path, nil
1✔
34
        }
1✔
35

36
        tmpPluginDirectory := pluginDirectory + "-" + p.randomFolderName()
1✔
37
        _ = os.MkdirAll(tmpPluginDirectory, pluginDirectoryPermissions)
1✔
38

1✔
39
        progressBar := visualization.NewProgressBar(p.Logger)
1✔
40
        defer progressBar.Remove()
1✔
41
        progressBar.UpdatePercentage("downloading...", 0)
1✔
42
        archivePath := filepath.Join(tmpPluginDirectory, name)
1✔
43
        err = p.download(name, url, archivePath, progressBar)
1✔
44
        if err != nil {
1✔
45
                return "", err
×
46
        }
×
47
        archive := newArchive(archiveType)
1✔
48
        err = archive.Extract(archivePath, tmpPluginDirectory, pluginDirectoryPermissions)
1✔
49
        if err != nil {
1✔
50
                return "", fmt.Errorf("Could not extract %s archive: %v", name, err)
×
51
        }
×
52
        os.Remove(archivePath)
1✔
53
        err = p.rename(tmpPluginDirectory, pluginDirectory)
1✔
54
        if err != nil {
1✔
55
                return "", fmt.Errorf("Could not install %s: %v", name, err)
×
56
        }
×
57
        return path, nil
1✔
58
}
59

60
func (p ExternalPlugin) rename(source string, target string) error {
1✔
61
        return resiliency.RetryN(10, func() error {
2✔
62
                err := os.Rename(source, target)
1✔
63
                if err != nil {
1✔
NEW
64
                        return resiliency.Retryable(err)
×
NEW
65
                }
×
66
                return nil
1✔
67
        })
68
}
69

70
func (p ExternalPlugin) download(name string, url string, destination string, progressBar *visualization.ProgressBar) error {
1✔
71
        out, err := os.Create(destination)
1✔
72
        if err != nil {
1✔
73
                return fmt.Errorf("Could not download %s: %v", name, err)
×
74
        }
×
75
        defer out.Close()
1✔
76

1✔
77
        request, err := http.NewRequest(http.MethodGet, url, nil)
1✔
78
        if err != nil {
1✔
79
                return fmt.Errorf("Could not download %s: %v", name, err)
×
80
        }
×
81
        response, err := http.DefaultClient.Do(request)
1✔
82
        if err != nil {
1✔
83
                return fmt.Errorf("Could not download %s: %v", name, err)
×
84
        }
×
85
        downloadReader := p.progressReader("downloading...", "installing... ", response.Body, response.ContentLength, progressBar)
1✔
86
        _, err = io.Copy(out, downloadReader)
1✔
87
        if err != nil {
1✔
88
                return fmt.Errorf("Could not download %s: %v", name, err)
×
89
        }
×
90
        return nil
1✔
91
}
92

93
func (p ExternalPlugin) progressReader(text string, completedText string, reader io.Reader, length int64, progressBar *visualization.ProgressBar) io.Reader {
1✔
94
        progressReader := visualization.NewProgressReader(reader, func(progress visualization.Progress) {
2✔
95
                displayText := text
1✔
96
                if progress.Completed {
2✔
97
                        displayText = completedText
1✔
98
                }
1✔
99
                progressBar.UpdateProgress(displayText, progress.BytesRead, length, progress.BytesPerSecond)
1✔
100
        })
101
        return progressReader
1✔
102
}
103

104
func (p ExternalPlugin) pluginDirectory(name string, url string) (string, error) {
1✔
105
        pluginDirectory, err := directories.Plugin()
1✔
106
        if err != nil {
1✔
107
                return "", err
×
108
        }
×
109
        hash := sha256.Sum256([]byte(url))
1✔
110
        subdirectory := fmt.Sprintf("%s-%x", name, hash)
1✔
111
        return filepath.Join(pluginDirectory, subdirectory), nil
1✔
112
}
113

114
func (p ExternalPlugin) randomFolderName() string {
1✔
115
        value, _ := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
1✔
116
        return value.String()
1✔
117
}
1✔
118

119
func NewExternalPlugin(logger log.Logger) *ExternalPlugin {
1✔
120
        return &ExternalPlugin{logger}
1✔
121
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc