@@ -23,31 +23,38 @@ var VERBOSE bool
2323var DEBUG bool
2424
2525type Unit struct {
26- name string
27- sources []string
28- destination string
29- excludes []string
30- archiveType string
31- addSubfolder bool
32- enabled bool
26+ name string
27+ sources []string
28+ destination string
29+ excludes []string
30+ archiveType string
31+ addSubfolder bool
32+ enabled bool
33+ useAbsolutePaths bool
3334}
3435
3536type Config struct {
3637 units []Unit
3738}
3839
40+ type BackupFileMetadata struct {
41+ path string
42+ backupBasePath string
43+ }
44+
3945func (config Config ) FromYaml (yamlData []byte ) (Config , error ) {
4046 // Create a config object from yaml byte array
4147 log .Println ("Parsing config yaml" )
4248
4349 // Helper struct for parsing the yaml
4450 type YamlUnit struct {
45- Sources * []string `yaml:"sources"`
46- Destination * string `yaml:"destination"`
47- Excludes * []string `yaml:"excludes"`
48- ArchiveType * string `yaml:"archive_type"`
49- AddSubfolder * bool `yaml:"add_subfolder"`
50- Enabled * bool `yaml:"enabled"`
51+ Sources * []string `yaml:"sources"`
52+ Destination * string `yaml:"destination"`
53+ Excludes * []string `yaml:"excludes"`
54+ ArchiveType * string `yaml:"archive_type"`
55+ AddSubfolder * bool `yaml:"add_subfolder"`
56+ Enabled * bool `yaml:"enabled"`
57+ UseAbsolutePaths * bool `yaml:"use_absolute_paths"`
5158 }
5259
5360 // Sample yaml config:
@@ -97,6 +104,11 @@ func (config Config) FromYaml(yamlData []byte) (Config, error) {
97104 unit .excludes = * yamlUnit .Excludes
98105 }
99106
107+ unit .useAbsolutePaths = true
108+ if yamlUnit .UseAbsolutePaths != nil {
109+ unit .useAbsolutePaths = * yamlUnit .UseAbsolutePaths
110+ }
111+
100112 if yamlUnit .Sources == nil || yamlUnit .Destination == nil {
101113 log .Fatalf ("Sources or destination can't be parsed for unit '%s'" , unitName )
102114 } else {
@@ -147,9 +159,9 @@ func handleExcludes(path string, excludes []string) bool {
147159 return false
148160}
149161
150- func getFiles (sourcePath string , excludes []string ) ([]string , error ) {
162+ func getFiles (sourcePath string , excludes []string ) ([]BackupFileMetadata , error ) {
151163 // Returns all file paths recursively within a certain source directory
152- var pathsToBackup []string
164+ var pathsToBackup []BackupFileMetadata
153165
154166 _ , statErr := os .Stat (sourcePath )
155167 if statErr != nil {
@@ -174,7 +186,11 @@ func getFiles(sourcePath string, excludes []string) ([]string, error) {
174186 return nil
175187 }
176188
177- pathsToBackup = append (pathsToBackup , path )
189+ fileMetadata := BackupFileMetadata {
190+ path : path ,
191+ backupBasePath : sourcePath ,
192+ }
193+ pathsToBackup = append (pathsToBackup , fileMetadata )
178194 return nil
179195 })
180196 if err != nil {
@@ -200,50 +216,86 @@ func validatePath(path string, mustBeDir bool) bool {
200216 return true
201217}
202218
203- func writeTar (backupArchivePath string , filesToBackup []string ) {
204- file , err := os .Create (backupArchivePath )
219+ func getPathInArchive (filePath string , backupBasePath string , unit Unit ) string {
220+ // Remove the base path from the file path within the archive, if option is set
221+ pathInArchive := filePath
222+ if ! unit .useAbsolutePaths {
223+ parentBasePath := filepath .Dir (backupBasePath )
224+ pathInArchive = strings .ReplaceAll (filePath , parentBasePath , "" )
225+
226+ if strings .HasPrefix (pathInArchive , "\\ " ) {
227+ pathInArchive = pathInArchive [1 :]
228+ }
229+ }
230+ return pathInArchive
231+ }
232+
233+ func writeArchive (backupArchivePath string , filesToBackup []BackupFileMetadata , unit Unit ) {
234+ archiveFile , err := os .Create (backupArchivePath )
205235 if err != nil {
206236 log .Fatalln (err )
207237 }
208- defer file .Close ()
209- // set up the gzip writer
210- gw := gzip .NewWriter (file )
238+ defer archiveFile .Close ()
239+
240+ switch unit .archiveType {
241+ case "tar.gz" :
242+ writeTar (archiveFile , filesToBackup , unit )
243+ case "zip" :
244+ writeZip (archiveFile , filesToBackup , unit )
245+ default :
246+ log .Fatalf ("Can't handle archive type '%s'" , unit .archiveType )
247+ }
248+ }
249+
250+ func writeTar (archiveFile * os.File , filesToBackup []BackupFileMetadata , unit Unit ) {
251+ // set up the gzip and tar writer
252+ gw := gzip .NewWriter (archiveFile )
211253 defer gw .Close ()
212254 tw := tar .NewWriter (gw )
213255 defer tw .Close ()
214256
257+ // Init progress bar
215258 bar := pb .StartNew (len (filesToBackup ))
216259 for i := range filesToBackup {
217- if err := addFileToTar (tw , filesToBackup [i ]); err != nil {
260+ fileMetadata := filesToBackup [i ]
261+ filePath := fileMetadata .path
262+
263+ pathInArchive := getPathInArchive (filePath , fileMetadata .backupBasePath , unit )
264+
265+ if err := addFileToTar (tw , filePath , pathInArchive ); err != nil {
218266 log .Fatalln (err )
219267 }
220268 bar .Increment ()
221269 }
222270 bar .Finish ()
223271}
224272
225- func writeZip (backupArchivePath string , filesToBackup []string ) {
226- file , err := os .Create (backupArchivePath )
227- if err != nil {
228- log .Fatalln (err )
229- }
230- defer file .Close ()
231- zw := zip .NewWriter (file )
273+ func writeZip (archiveFile * os.File , filesToBackup []BackupFileMetadata , unit Unit ) {
274+ zw := zip .NewWriter (archiveFile )
232275 defer zw .Close ()
233276
277+ bar := pb .StartNew (len (filesToBackup ))
234278 for i := range filesToBackup {
235- if err := addFileToZip (zw , filesToBackup [i ]); err != nil {
279+ fileMetadata := filesToBackup [i ]
280+ filePath := fileMetadata .path
281+
282+ pathInArchive := getPathInArchive (filePath , fileMetadata .backupBasePath , unit )
283+
284+ if err := addFileToZip (zw , filePath , pathInArchive ); err != nil {
236285 log .Fatalln (err )
237286 }
287+ bar .Increment ()
238288 }
289+ bar .Finish ()
239290}
240291
241- func writeBackup (filesToBackup []string , backupBasePath string , unitName string , fileExt string , addSubfolder bool ) {
292+ func writeBackup (filesToBackup []BackupFileMetadata , unit Unit ) {
242293 now := time .Now ()
243294 timeStamp := now .Format ("2006-01-02_15-04" )
295+ backupBasePath := unit .destination
244296
245- if addSubfolder {
246- newBackupBasePath := filepath .Join (backupBasePath , unitName )
297+ if unit . addSubfolder {
298+ newBackupBasePath := filepath .Join (unit . destination , unit . name )
247299 pathExists := validatePath (newBackupBasePath , true )
248300
249301 if ! pathExists {
@@ -256,19 +308,12 @@ func writeBackup(filesToBackup []string, backupBasePath string, unitName string,
256308 backupBasePath = newBackupBasePath
257309 }
258310
259- backupArchiveName := unitName + "-" + timeStamp + "." + fileExt
311+ backupArchiveName := unit . name + "-" + timeStamp + "." + unit . archiveType
260312 backupArchivePath := filepath .Join (backupBasePath , backupArchiveName )
261313
262314 // TODO check if archive already exists. If yes, append -1 to it and try again
263315
264- if fileExt == "tar.gz" {
265- writeTar (backupArchivePath , filesToBackup )
266- } else if fileExt == "zip" {
267- writeZip (backupArchivePath , filesToBackup )
268- } else {
269- log .Fatalf ("Can't handle archive type '%s'" , fileExt )
270- }
271-
316+ writeArchive (backupArchivePath , filesToBackup , unit )
272317 log .Printf ("Archive created successfully at '%s'" , backupArchivePath )
273318}
274319
@@ -280,7 +325,7 @@ func backupUnit(unit Unit) {
280325 }
281326
282327 log .Printf ("Creating backup for unit '%s'\n " , unit .name )
283- var filesToBackup []string
328+ var filesToBackup []BackupFileMetadata
284329
285330 // Check all source files from the disk in the specified source directories
286331 for _ , sourcePath := range unit .sources {
@@ -296,7 +341,7 @@ func backupUnit(unit Unit) {
296341 log .Printf ("No files found for sources in unit '%s'. Creating no backup!" , unit .name )
297342 return
298343 }
299- writeBackup (filesToBackup , unit . destination , unit . name , unit . archiveType , unit . addSubfolder )
344+ writeBackup (filesToBackup , unit )
300345}
301346
302347func runBackup (config Config ) {
@@ -356,7 +401,7 @@ func readConfig(configPath string) (Config, error) {
356401 return c , validateErr
357402}
358403
359- func addFileToTar (tw * tar.Writer , path string ) error {
404+ func addFileToTar (tw * tar.Writer , path string , pathInArchive string ) error {
360405 file , err := os .Open (path )
361406 if err != nil {
362407 return err
@@ -367,7 +412,7 @@ func addFileToTar(tw *tar.Writer, path string) error {
367412 // now lets create the header as needed for this file within the tarball
368413 header := new (tar.Header )
369414 header .Format = tar .FormatGNU
370- header .Name = path
415+ header .Name = pathInArchive
371416 header .Size = stat .Size ()
372417 header .Mode = int64 (stat .Mode ())
373418 header .ModTime = stat .ModTime ()
@@ -383,7 +428,7 @@ func addFileToTar(tw *tar.Writer, path string) error {
383428 return nil
384429}
385430
386- func addFileToZip (zw * zip.Writer , path string ) error {
431+ func addFileToZip (zw * zip.Writer , path string , pathInArchive string ) error {
387432 file , err := os .Open (path )
388433 if err != nil {
389434 return err
@@ -395,7 +440,7 @@ func addFileToZip(zw *zip.Writer, path string) error {
395440 if headerErr != nil {
396441 return headerErr
397442 }
398- header .Name = path
443+ header .Name = pathInArchive
399444 // write the header to the zip archive
400445 writer , headerErr := zw .CreateHeader (header )
401446 if headerErr != nil {
0 commit comments