Skip to content

Commit

Permalink
lib install implemented, needs refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
saniales committed Jun 13, 2017
1 parent 152af0c commit 8f0b394
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 51 deletions.
4 changes: 2 additions & 2 deletions cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
// installCmd represents the lib install command.
var installCmd = &cobra.Command{
Use: "install",
Short: "Installs a specified library into the system.",
Long: `Installs a specified library into the system.`,
Short: "Installs one of more specified libraries into the system.",
Long: `Installs one or more specified libraries into the system.`,
RunE: executeInstallCommand,
}

Expand Down
70 changes: 66 additions & 4 deletions common/common.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,95 @@
package common

import (
"archive/zip"
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"runtime"
)

// GetDefaultArduinoFolder returns the default data folder for Arduino platform
func GetDefaultArduinoFolder() (string, error) {
var folder string

usr, err := user.Current()
if err != nil {
return "", err
}

switch runtime.GOOS {
case "linux":
return filepath.Join(usr.HomeDir, ".arduino15"), nil
folder = filepath.Join(usr.HomeDir, ".arduino15")
case "darwin":
return filepath.Join(usr.HomeDir, "Library", "arduino15"), nil
folder = filepath.Join(usr.HomeDir, "Library", "arduino15")
default:
return "", fmt.Errorf("Unsupported OS: %s", runtime.GOOS)
}
_, err = os.Stat(folder)
if os.IsNotExist(err) {
fmt.Print("Cannot find default arduino folder, attemping to create it ...")
err = os.MkdirAll(folder, 0755)
if err != nil {
fmt.Println("ERROR")
fmt.Println("Cannot create arduino folder")
return "", err
}
fmt.Println("OK")
}
return folder, nil
}

// GetDefaultLibFolder get the default folder of downloaded libraries.
func GetDefaultLibFolder() (string, error) {
usr, err := user.Current()
baseFolder, err := GetDefaultArduinoFolder()
if err != nil {
return "", err
}
return filepath.Join(usr.HomeDir, "Arduino", "libraries"), nil

libFolder := filepath.Join(baseFolder, "libraries")
_, err = os.Stat(libFolder)
if os.IsNotExist(err) {
fmt.Print("Cannot find libraries folder, attempting to create it ... ")
err = os.MkdirAll(libFolder, 0755)
if err != nil {
fmt.Println("ERROR")
fmt.Println("Cannot create libraries folder")
return "", err
}
fmt.Println("OK")
}
return libFolder, nil
}

func Unzip(archive *zip.Reader, destination string) error {
for _, file := range archive.File {
path := filepath.Join(destination, file.Name)
if file.FileInfo().IsDir() {
err := os.MkdirAll(path, 0755)
if err != nil {
return fmt.Errorf("Cannot create directory during extraction. Process has been aborted")
}
} else {
err := os.MkdirAll(filepath.Dir(path), 0755)
if err != nil {
return fmt.Errorf("Cannot create directory tree of file during extraction. Process has been aborted")
}

fileOpened, err := file.Open()
if err != nil {
return fmt.Errorf("Cannot open archived file, process has been aborted")
}
content, err := ioutil.ReadAll(fileOpened)
if err != nil {
return fmt.Errorf("Cannot read archived file, process has been aborted")
}
err = ioutil.WriteFile(path, content, 0664)
if err != nil {
return fmt.Errorf("Cannot copy archived file, process has been aborted, %s", err)
}
}
}
return nil
}
120 changes: 75 additions & 45 deletions libraries/install_uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,94 @@ import (
"github.com/bcmi-labs/arduino-cli/common"
)

// DownloadAndInstall downloads a library and installs it to its specified location.
func DownloadAndInstall(library *Library) error {
// download downloads a library from arduino repository.
func download(library *Library) ([]byte, error) {
client := http.DefaultClient

request, err := http.NewRequest("GET", library.Latest.URL, nil)
if err != nil {
return nil, fmt.Errorf("Cannot create HTTP request")
}

response, err := client.Do(request)
if err != nil {
return nil, fmt.Errorf("Cannot fetch library. Response creation error")
} else if response.StatusCode != 200 {
response.Body.Close()
return nil, fmt.Errorf("Cannot fetch library. Source responded with a status %d code", response.StatusCode)
}
defer response.Body.Close()

// Download completed, now move the archive to temp location and unpack it.
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, fmt.Errorf("Cannot read response body")
}
return body, nil
}

// getDownloadCacheFolder gets the folder where temp installs are stored until installation complete (libraries).
func getDownloadCacheFolder(library *Library) (string, error) {
libFolder, err := common.GetDefaultLibFolder()
if err != nil {
fmt.Print("Cannot find lib folder, trying to create it ... ")
baseFolder, err := common.GetDefaultArduinoFolder()
return "", err
}

stagingFolder := filepath.Join(libFolder, "cache")
_, err = os.Stat(stagingFolder)
if err != nil {
fmt.Print("Cannot find cache folder of libraries, attempting to create it ... ")
err = os.MkdirAll(stagingFolder, 0755)
if err != nil {
fmt.Println("ERROR")
fmt.Println("Cannot create libraries folder, no current user defined")
return fmt.Errorf("Cannot create libraries folder")
fmt.Println("Cannot create cache folder of libraries")
return "", err
}
libFolder = filepath.Join(baseFolder, "Arduino", "libraries")
fmt.Println("OK")
}
return stagingFolder, nil
}

// getLibFolder returns the destination folder of the downloaded specified library.
// It creates the folder if does not find it.
func getLibFolder(library *Library) (string, error) {
baseFolder, err := common.GetDefaultLibFolder()
if err != nil {
return "", err
}

libFolder := filepath.Join(baseFolder, fmt.Sprintf("%s-%s", library.Name, library.Latest.Version))

_, err = os.Stat(libFolder)
if os.IsNotExist(err) {
fmt.Print("Cannot find lib folder, trying to create it ... ")
err = os.MkdirAll(libFolder, 0755)
if err != nil {
fmt.Println("ERROR")
fmt.Println("Cannot create libraries folder")
return fmt.Errorf("Cannot create libraries folder")
fmt.Println("Cannot create lib folder")
return "", err
}
fmt.Println("OK")
}

request, err := http.NewRequest("GET", library.Latest.URL, nil)
return libFolder, nil
}

// DownloadAndInstall downloads a library and installs it to its specified location.
func DownloadAndInstall(library *Library) error {
libFolder, err := common.GetDefaultLibFolder()
if err != nil {
return fmt.Errorf("Cannot create HTTP request")
return fmt.Errorf("Cannot get Lib destination directory")
}
response, err := client.Do(request)

stagingFolder, err := getDownloadCacheFolder(library)
if err != nil {
return fmt.Errorf("Cannot fetch library. Response creation error")
} else if response.StatusCode != 200 {
response.Body.Close()
return fmt.Errorf("Cannot fetch library. Source responded with a status %d code", response.StatusCode)
return fmt.Errorf("Cannot get staging installs folder")
}
defer response.Body.Close()

// Download completed, now move the archive to temp location and unpack it.
body, err := ioutil.ReadAll(response.Body)
body, err := download(library)
if err != nil {
return fmt.Errorf("Cannot read response body")
return err
}

reader := bytes.NewReader(body)
Expand All @@ -60,34 +109,15 @@ func DownloadAndInstall(library *Library) error {
return fmt.Errorf("Cannot read downloaded archive")
}

zipExtractionPath := filepath.Join(libFolder, fmt.Sprintf("%s-%s", library.Name, library.Latest.Version))

err = os.MkdirAll(zipExtractionPath, 0755)
// if I can read the archive I save it to staging folder.
err = ioutil.WriteFile(filepath.Join(stagingFolder, fmt.Sprintf("%s-%s.zip", library.Name, library.Latest.Version)), body, 0666)
if err != nil {
return fmt.Errorf("Cannot create library final destination directory")
return fmt.Errorf("Cannot write download to cache folder, %s", err.Error())
}

for _, file := range archive.File {
if file.FileInfo().IsDir() {
err = os.MkdirAll(filepath.Join(zipExtractionPath, file.Name), 0755)
if err != nil {
return fmt.Errorf("Cannot create directory during extraction. Process has been aborted")
}
} else {

}
fileOpened, err := file.Open()
if err != nil {
return fmt.Errorf("Cannot open archived file, process has been aborted")
}
content, err := ioutil.ReadAll(fileOpened)
if err != nil {
return fmt.Errorf("Cannot read archived file, process has been aborted")
}
err = ioutil.WriteFile(filepath.Join(zipExtractionPath, file.Name), content, 0666)
if err != nil {
return fmt.Errorf("Cannot copy archived file, process has been aborted")
}
err = common.Unzip(archive, libFolder)
if err != nil {
return err
}

return nil
Expand Down

0 comments on commit 8f0b394

Please sign in to comment.