Skip to content

Commit 70aa399

Browse files
committed
Add a package for backing up files
This can be used for recovery in the event something goes wrong while in the middle of a operation that modified the production files content.
1 parent 611225b commit 70aa399

File tree

2 files changed

+201
-0
lines changed

2 files changed

+201
-0
lines changed

internal/backup/backup.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// This file is part of libraries-repository-engine.
2+
//
3+
// Copyright 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
//
18+
// You can be released from the requirements of the above licenses by purchasing
19+
// a commercial license. Buying such a license is mandatory if you want to
20+
// modify or otherwise use the software for commercial activities involving the
21+
// Arduino software without disclosing the source code of your own applications.
22+
// To purchase a commercial license, send an email to [email protected].
23+
24+
// Package backup does backup and restore of files.
25+
package backup
26+
27+
import (
28+
"github.com/arduino/go-paths-helper"
29+
)
30+
31+
type backup struct {
32+
originalPath *paths.Path
33+
backupPath *paths.Path
34+
}
35+
36+
var backupsFolder *paths.Path
37+
var backups []backup
38+
39+
// Backup saves a backup copy of the given path.
40+
func Backup(originalPath *paths.Path) error {
41+
if backupsFolder == nil {
42+
// Create a parent folder to store all backups of this session.
43+
var err error
44+
if backupsFolder, err = paths.MkTempDir("", "libraries-repository-engine-backup"); err != nil {
45+
return err
46+
}
47+
}
48+
49+
// Create a folder for this individual backup item.
50+
backupFolder, err := backupsFolder.MkTempDir("")
51+
if err != nil {
52+
return err
53+
}
54+
55+
backupPath := backupFolder.Join(originalPath.Base())
56+
57+
isDir, err := originalPath.IsDirCheck()
58+
if err != nil {
59+
return err
60+
}
61+
if isDir {
62+
if err := originalPath.CopyDirTo(backupPath); err != nil {
63+
return err
64+
}
65+
} else {
66+
if err := originalPath.CopyTo(backupPath); err != nil {
67+
return err
68+
}
69+
}
70+
71+
backups = append(backups, backup{originalPath: originalPath, backupPath: backupPath})
72+
73+
return nil
74+
}
75+
76+
// Restore restores all backed up files.
77+
func Restore() error {
78+
for _, backup := range backups {
79+
isDir, err := backup.backupPath.IsDirCheck()
80+
if err != nil {
81+
return err
82+
}
83+
if isDir {
84+
if err := backup.originalPath.RemoveAll(); err != nil {
85+
return err
86+
}
87+
if err := backup.backupPath.CopyDirTo(backup.originalPath); err != nil {
88+
return err
89+
}
90+
} else {
91+
if err := backup.backupPath.CopyTo(backup.originalPath); err != nil {
92+
return err
93+
}
94+
}
95+
}
96+
97+
return nil
98+
}
99+
100+
// Clean deletes all the backup files.
101+
func Clean() error {
102+
if backupsFolder == nil {
103+
return nil
104+
}
105+
106+
return backupsFolder.RemoveAll()
107+
}

internal/backup/backup_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// This file is part of libraries-repository-engine.
2+
//
3+
// Copyright 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
//
18+
// You can be released from the requirements of the above licenses by purchasing
19+
// a commercial license. Buying such a license is mandatory if you want to
20+
// modify or otherwise use the software for commercial activities involving the
21+
// Arduino software without disclosing the source code of your own applications.
22+
// To purchase a commercial license, send an email to [email protected].
23+
24+
package backup
25+
26+
import (
27+
"testing"
28+
29+
"github.com/arduino/go-paths-helper"
30+
"github.com/stretchr/testify/assert"
31+
"github.com/stretchr/testify/require"
32+
)
33+
34+
var testDataPath string
35+
36+
func TestAll(t *testing.T) {
37+
var err error
38+
originalsFolder, err := paths.MkTempDir("", "backup-test-testall")
39+
require.NoError(t, err)
40+
41+
// Generate test content.
42+
originalContent := []byte("foo")
43+
modifyFile, err := paths.WriteToTempFile(originalContent, originalsFolder, "")
44+
require.NoError(t, err)
45+
modifyFolder, err := originalsFolder.MkTempDir("")
46+
require.NoError(t, err)
47+
modifyFolderFile, err := paths.WriteToTempFile(originalContent, modifyFolder, "")
48+
require.NoError(t, err)
49+
deleteFile, err := paths.WriteToTempFile(originalContent, originalsFolder, "")
50+
require.NoError(t, err)
51+
deleteFolder, err := originalsFolder.MkTempDir("")
52+
require.NoError(t, err)
53+
deleteFolderFile, err := paths.WriteToTempFile(originalContent, deleteFolder, "")
54+
require.NoError(t, err)
55+
56+
// Backup test content.
57+
err = Backup(modifyFile)
58+
require.NoError(t, err)
59+
err = Backup(modifyFolder)
60+
require.NoError(t, err)
61+
err = Backup(deleteFile)
62+
require.NoError(t, err)
63+
err = Backup(deleteFolder)
64+
require.NoError(t, err)
65+
66+
// Change the originals.
67+
err = modifyFile.WriteFile([]byte("bar"))
68+
require.NoError(t, err)
69+
err = modifyFolderFile.WriteFile([]byte("bar"))
70+
require.NoError(t, err)
71+
err = deleteFile.Remove()
72+
require.NoError(t, err)
73+
err = deleteFolder.RemoveAll()
74+
require.NoError(t, err)
75+
76+
err = Restore()
77+
require.NoError(t, err)
78+
79+
// Verify changes to originals were reverted.
80+
content, err := modifyFile.ReadFile()
81+
require.NoError(t, err)
82+
assert.Equal(t, originalContent, content)
83+
84+
content, err = modifyFolderFile.ReadFile()
85+
require.NoError(t, err)
86+
assert.Equal(t, originalContent, content)
87+
88+
assert.True(t, deleteFile.Exist())
89+
assert.True(t, deleteFolderFile.Exist())
90+
91+
// Clean the backups.
92+
err = Clean()
93+
require.NoError(t, err)
94+
}

0 commit comments

Comments
 (0)