github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/app/fetcher_file.go (about)

     1  package app
     2  
     3  import (
     4  	"io"
     5  	"net/url"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"github.com/cozy/cozy-stack/pkg/appfs"
    10  	"github.com/cozy/cozy-stack/pkg/logger"
    11  	"github.com/cozy/cozy-stack/pkg/utils"
    12  )
    13  
    14  type fileFetcher struct {
    15  	manFilename string
    16  	log         logger.Logger
    17  }
    18  
    19  // The file fetcher is mostly used in development mode. The version of the
    20  // application installed with this mode is appended with a random number so
    21  // that multiple version can be installed from the same directory without
    22  // having to increase the version number from the manifest.
    23  func newFileFetcher(manFilename string, log logger.Logger) *fileFetcher {
    24  	return &fileFetcher{
    25  		manFilename: manFilename,
    26  		log:         log,
    27  	}
    28  }
    29  
    30  func (f *fileFetcher) FetchManifest(src *url.URL) (io.ReadCloser, error) {
    31  	r, err := os.Open(filepath.Join(src.Path, f.manFilename))
    32  	if os.IsNotExist(err) {
    33  		return nil, ErrManifestNotReachable
    34  	}
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return r, nil
    39  }
    40  
    41  func (f *fileFetcher) Fetch(src *url.URL, fs appfs.Copier, man Manifest) (err error) {
    42  	version := man.Version() + "-" + utils.RandomString(10)
    43  	man.SetVersion(version)
    44  	exists, err := fs.Start(man.Slug(), man.Version(), "")
    45  	if err != nil || exists {
    46  		return err
    47  	}
    48  	defer func() {
    49  		if err != nil {
    50  			_ = fs.Abort()
    51  		} else {
    52  			err = fs.Commit()
    53  		}
    54  	}()
    55  	return copyRec(src.Path, "/", fs)
    56  }
    57  
    58  func copyRec(root, path string, fs appfs.Copier) error {
    59  	files, err := os.ReadDir(filepath.Join(root, path))
    60  	if err != nil {
    61  		return err
    62  	}
    63  	for _, file := range files {
    64  		relpath := filepath.Join(path, file.Name())
    65  		if file.IsDir() {
    66  			if file.Name() == ".git" {
    67  				continue
    68  			}
    69  			if err = copyRec(root, relpath, fs); err != nil {
    70  				return err
    71  			}
    72  			continue
    73  		}
    74  		fullpath := filepath.Join(root, path, file.Name())
    75  		f, err := os.Open(fullpath)
    76  		if err != nil {
    77  			return err
    78  		}
    79  		fileinfo, err := file.Info()
    80  		if err != nil {
    81  			return err
    82  		}
    83  		info := appfs.NewFileInfo(relpath, fileinfo.Size(), fileinfo.Mode())
    84  		err = fs.Copy(info, f)
    85  		f.Close()
    86  		if err != nil {
    87  			return err
    88  		}
    89  	}
    90  	return nil
    91  }