Skip to content

Commit b8cf32d

Browse files
authored
Add archive command to zip a sketch and its files (#931)
1 parent e6f1947 commit b8cf32d

24 files changed

+5713
-321
lines changed

Diff for: cli/sketch/archive.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package sketch
17+
18+
import (
19+
"context"
20+
"os"
21+
22+
"github.com/arduino/arduino-cli/cli/errorcodes"
23+
"github.com/arduino/arduino-cli/cli/feedback"
24+
"github.com/arduino/arduino-cli/commands/sketch"
25+
rpc "github.com/arduino/arduino-cli/rpc/commands"
26+
"github.com/sirupsen/logrus"
27+
"github.com/spf13/cobra"
28+
)
29+
30+
var includeBuildDir bool
31+
32+
// initArchiveCommand creates a new `archive` command
33+
func initArchiveCommand() *cobra.Command {
34+
command := &cobra.Command{
35+
Use: "archive <sketchPath> <archivePath>",
36+
Short: "Creates a zip file containing all sketch files.",
37+
Long: "Creates a zip file containing all sketch files.",
38+
Example: "" +
39+
" " + os.Args[0] + " archive\n" +
40+
" " + os.Args[0] + " archive .\n" +
41+
" " + os.Args[0] + " archive . MySketchArchive.zip\n" +
42+
" " + os.Args[0] + " archive /home/user/Arduino/MySketch\n" +
43+
" " + os.Args[0] + " archive /home/user/Arduino/MySketch /home/user/MySketchArchive.zip",
44+
Args: cobra.MaximumNArgs(2),
45+
Run: runArchiveCommand,
46+
}
47+
48+
command.Flags().BoolVar(&includeBuildDir, "include-build-dir", false, "Includes build directory in the archive.")
49+
50+
return command
51+
}
52+
53+
func runArchiveCommand(cmd *cobra.Command, args []string) {
54+
logrus.Info("Executing `arduino sketch archive`")
55+
56+
sketchPath := ""
57+
if len(args) >= 1 {
58+
sketchPath = args[0]
59+
}
60+
61+
archivePath := ""
62+
if len(args) == 2 {
63+
archivePath = args[1]
64+
}
65+
66+
_, err := sketch.ArchiveSketch(context.Background(),
67+
&rpc.ArchiveSketchReq{
68+
SketchPath: sketchPath,
69+
ArchivePath: archivePath,
70+
IncludeBuildDir: includeBuildDir,
71+
})
72+
73+
if err != nil {
74+
feedback.Errorf("Error archiving: %v", err)
75+
os.Exit(errorcodes.ErrGeneric)
76+
}
77+
}

Diff for: cli/sketch/sketch.go

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func NewCommand() *cobra.Command {
3131
}
3232

3333
cmd.AddCommand(initNewCommand())
34+
cmd.AddCommand(initArchiveCommand())
3435

3536
return cmd
3637
}

Diff for: commands/daemon/daemon.go

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/arduino/arduino-cli/commands/compile"
2727
"github.com/arduino/arduino-cli/commands/core"
2828
"github.com/arduino/arduino-cli/commands/lib"
29+
"github.com/arduino/arduino-cli/commands/sketch"
2930
"github.com/arduino/arduino-cli/commands/upload"
3031
rpc "github.com/arduino/arduino-cli/rpc/commands"
3132
)
@@ -337,3 +338,8 @@ func (s *ArduinoCoreServerImpl) LibrarySearch(ctx context.Context, req *rpc.Libr
337338
func (s *ArduinoCoreServerImpl) LibraryList(ctx context.Context, req *rpc.LibraryListReq) (*rpc.LibraryListResp, error) {
338339
return lib.LibraryList(ctx, req)
339340
}
341+
342+
// ArchiveSketch FIXMEDOC
343+
func (s *ArduinoCoreServerImpl) ArchiveSketch(ctx context.Context, req *rpc.ArchiveSketchReq) (*rpc.ArchiveSketchResp, error) {
344+
return sketch.ArchiveSketch(ctx, req)
345+
}

Diff for: commands/sketch/archive.go

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package sketch
17+
18+
import (
19+
"archive/zip"
20+
"context"
21+
"fmt"
22+
"io"
23+
"path/filepath"
24+
"strings"
25+
26+
rpc "github.com/arduino/arduino-cli/rpc/commands"
27+
paths "github.com/arduino/go-paths-helper"
28+
)
29+
30+
// ArchiveSketch FIXMEDOC
31+
func ArchiveSketch(ctx context.Context, req *rpc.ArchiveSketchReq) (*rpc.ArchiveSketchResp, error) {
32+
// sketchName is the name of the sketch without extension, for example "MySketch"
33+
var sketchName string
34+
35+
sketchPath := paths.New(req.SketchPath)
36+
if sketchPath == nil {
37+
sketchPath = paths.New(".")
38+
}
39+
40+
sketchPath, err := sketchPath.Clean().Abs()
41+
if err != nil {
42+
return nil, fmt.Errorf("Error getting absolute sketch path %v", err)
43+
}
44+
45+
// Get the sketch name and make sketchPath point to the ino file
46+
if sketchPath.IsDir() {
47+
sketchName = sketchPath.Base()
48+
sketchPath = sketchPath.Join(sketchName + ".ino")
49+
} else if sketchPath.Ext() == ".ino" {
50+
sketchName = strings.TrimSuffix(sketchPath.Base(), ".ino")
51+
}
52+
53+
// Checks if it's really a sketch
54+
if sketchPath.NotExist() {
55+
return nil, fmt.Errorf("specified path is not a sketch: %v", sketchPath.String())
56+
}
57+
58+
archivePath := paths.New(req.ArchivePath)
59+
if archivePath == nil {
60+
archivePath = sketchPath.Parent().Parent()
61+
}
62+
63+
archivePath, err = archivePath.Clean().Abs()
64+
if err != nil {
65+
return nil, fmt.Errorf("Error getting absolute archive path %v", err)
66+
}
67+
68+
// Makes archivePath point to a zip file
69+
if archivePath.IsDir() {
70+
archivePath = archivePath.Join(sketchName + ".zip")
71+
} else if archivePath.Ext() == "" {
72+
archivePath = paths.New(archivePath.String() + ".zip")
73+
}
74+
75+
if archivePath.Exist() {
76+
return nil, fmt.Errorf("archive already exists")
77+
}
78+
79+
filesToZip, err := sketchPath.Parent().ReadDirRecursive()
80+
if err != nil {
81+
return nil, fmt.Errorf("Error retrieving sketch files: %v", err)
82+
}
83+
filesToZip.FilterOutDirs()
84+
85+
archive, err := archivePath.Create()
86+
if err != nil {
87+
return nil, fmt.Errorf("Error creating archive: %v", err)
88+
}
89+
defer archive.Close()
90+
91+
zipWriter := zip.NewWriter(archive)
92+
defer zipWriter.Close()
93+
94+
for _, f := range filesToZip {
95+
96+
if !req.IncludeBuildDir {
97+
filePath, err := sketchPath.Parent().Parent().RelTo(f)
98+
if err != nil {
99+
return nil, fmt.Errorf("Error calculating relative file path: %v", err)
100+
}
101+
102+
// Skips build folder
103+
if strings.HasPrefix(filePath.String(), sketchName+string(filepath.Separator)+"build") {
104+
continue
105+
}
106+
}
107+
108+
// We get the parent path since we want the archive to unpack as a folder.
109+
// If we don't do this the archive would contain all the sketch files as top level.
110+
err = addFileToSketchArchive(zipWriter, f, sketchPath.Parent().Parent())
111+
if err != nil {
112+
return nil, fmt.Errorf("Error adding file to archive: %v", err)
113+
}
114+
}
115+
116+
return &rpc.ArchiveSketchResp{}, nil
117+
}
118+
119+
// Adds a single file to an existing zip file
120+
func addFileToSketchArchive(zipWriter *zip.Writer, filePath, sketchPath *paths.Path) error {
121+
f, err := filePath.Open()
122+
if err != nil {
123+
return err
124+
}
125+
defer f.Close()
126+
127+
info, err := f.Stat()
128+
if err != nil {
129+
return err
130+
}
131+
132+
header, err := zip.FileInfoHeader(info)
133+
if err != nil {
134+
return err
135+
}
136+
137+
filePath, err = sketchPath.RelTo(filePath)
138+
if err != nil {
139+
return err
140+
}
141+
142+
header.Name = filePath.String()
143+
header.Method = zip.Deflate
144+
145+
writer, err := zipWriter.CreateHeader(header)
146+
if err != nil {
147+
return err
148+
}
149+
150+
_, err = io.Copy(writer, f)
151+
return err
152+
}

Diff for: go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
bou.ke/monkey v1.0.1
1010
github.com/GeertJohan/go.rice v1.0.0
1111
github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c
12-
github.com/arduino/go-paths-helper v1.2.0
12+
github.com/arduino/go-paths-helper v1.3.1
1313
github.com/arduino/go-properties-orderedmap v1.3.0
1414
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b
1515
github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b

Diff for: go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ github.com/arduino/go-paths-helper v1.0.1 h1:utYXLM2RfFlc9qp/MJTIYp3t6ux/xM6mWje
1616
github.com/arduino/go-paths-helper v1.0.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
1717
github.com/arduino/go-paths-helper v1.2.0 h1:qDW93PR5IZUN/jzO4rCtexiwF8P4OIcOmcSgAYLZfY4=
1818
github.com/arduino/go-paths-helper v1.2.0/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
19+
github.com/arduino/go-paths-helper v1.3.1 h1:Gz+PVt0luQyH4nffDePd8WBs/O5P05jADtJsY8NqvCM=
20+
github.com/arduino/go-paths-helper v1.3.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
1921
github.com/arduino/go-properties-orderedmap v1.3.0 h1:4No/vQopB36e7WUIk6H6TxiSEJPiMrVOCZylYmua39o=
2022
github.com/arduino/go-properties-orderedmap v1.3.0/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk=
2123
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b h1:9hDi4F2st6dbLC3y4i02zFT5quS4X6iioWifGlVwfy4=

0 commit comments

Comments
 (0)