Config: Show error if originals and storage path seem identical #1642
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
parent
7917482580
commit
86dc89c4b9
37 changed files with 464 additions and 235 deletions
|
@ -68,7 +68,7 @@ func SaveConfigOptions(router *gin.RouterGroup) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(yamlData, v); err != nil {
|
||||
if err = yaml.Unmarshal(yamlData, v); err != nil {
|
||||
log.Warnf("config: failed parsing values in %s (%s)", clean.Log(fileName), err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, err)
|
||||
return
|
||||
|
@ -90,21 +90,21 @@ func SaveConfigOptions(router *gin.RouterGroup) {
|
|||
}
|
||||
|
||||
// Make sure directory exists.
|
||||
if err := os.MkdirAll(filepath.Dir(fileName), fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(filepath.Dir(fileName)); err != nil {
|
||||
log.Errorf("config: failed creating config path %s (%s)", filepath.Dir(fileName), err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Write YAML data to file.
|
||||
if err := os.WriteFile(fileName, yamlData, fs.ModeFile); err != nil {
|
||||
if err = fs.WriteFile(fileName, yamlData); err != nil {
|
||||
log.Errorf("config: failed writing values to %s (%s)", clean.Log(fileName), err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Reload options.
|
||||
if err := conf.Options().Load(fileName); err != nil {
|
||||
if err = conf.Options().Load(fileName); err != nil {
|
||||
log.Warnf("config: failed loading values from %s (%s)", clean.Log(fileName), err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, err)
|
||||
return
|
||||
|
@ -113,7 +113,7 @@ func SaveConfigOptions(router *gin.RouterGroup) {
|
|||
// Set restart flag.
|
||||
mutex.Restart.Store(true)
|
||||
|
||||
// Propagate changes.
|
||||
// Update package defaults.
|
||||
conf.Propagate()
|
||||
|
||||
// Flush session cache and update client config.
|
||||
|
|
|
@ -43,7 +43,7 @@ func SharePreview(router *gin.RouterGroup) {
|
|||
|
||||
thumbPath := path.Join(conf.ThumbCachePath(), "share")
|
||||
|
||||
if err := os.MkdirAll(thumbPath, fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(thumbPath); err != nil {
|
||||
log.Error(err)
|
||||
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
||||
return
|
||||
|
|
|
@ -98,7 +98,7 @@ func GetVideo(router *gin.RouterGroup) {
|
|||
AddVideoCacheHeader(c, conf.CdnVideo())
|
||||
c.DataFromReader(http.StatusOK, info.VideoSize(), info.VideoContentType(), reader, nil)
|
||||
return
|
||||
} else if cacheName, cacheErr := fs.CacheFile(filepath.Join(conf.MediaFileCachePath(f.FileHash), f.FileHash+info.VideoFileExt()), reader); cacheErr != nil {
|
||||
} else if cacheName, cacheErr := fs.CacheFileFromReader(filepath.Join(conf.MediaFileCachePath(f.FileHash), f.FileHash+info.VideoFileExt()), reader); cacheErr != nil {
|
||||
log.Errorf("video: failed to cache %s embedded in %s (%s)", strings.ToUpper(videoFileType), clean.Log(f.FileName), cacheErr)
|
||||
AddContentTypeHeader(c, video.ContentTypeAVC)
|
||||
c.File(get.Config().StaticFile("video/404.mp4"))
|
||||
|
|
|
@ -110,7 +110,7 @@ func backupAction(ctx *cli.Context) error {
|
|||
|
||||
// Create backup directory if not exists.
|
||||
if dir := filepath.Dir(indexFileName); dir != "." {
|
||||
if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,8 +105,10 @@ func startAction(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
if child != nil {
|
||||
if !fs.Overwrite(conf.PIDFilename(), []byte(strconv.Itoa(child.Pid))) {
|
||||
if writeErr := fs.WriteString(conf.PIDFilename(), strconv.Itoa(child.Pid)); writeErr != nil {
|
||||
log.Error(writeErr)
|
||||
log.Fatalf("failed writing process id to %s", clean.Log(conf.PIDFilename()))
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("daemon started with process id %v\n", child.Pid)
|
||||
|
|
|
@ -138,7 +138,7 @@ func NewConfig(ctx *cli.Context) *Config {
|
|||
start: start,
|
||||
}
|
||||
|
||||
// Overwrite values with options.yml from config path.
|
||||
// WriteFile values with options.yml from config path.
|
||||
if optionsYaml := c.OptionsYaml(); fs.FileExists(optionsYaml) {
|
||||
if err := c.options.Load(optionsYaml); err != nil {
|
||||
log.Warnf("config: failed loading values from %s (%s)", clean.Log(optionsYaml), err)
|
||||
|
@ -243,17 +243,22 @@ func (c *Config) Propagate() {
|
|||
func (c *Config) Init() error {
|
||||
start := time.Now()
|
||||
|
||||
// Create configured directory paths.
|
||||
// Fail if the originals and storage path are identical.
|
||||
if c.OriginalsPath() == c.StoragePath() {
|
||||
return fmt.Errorf("config: originals and storage folder must be different directories")
|
||||
}
|
||||
|
||||
// Make sure that the configured storage directories exist and are properly configured.
|
||||
if err := c.CreateDirectories(); err != nil {
|
||||
return fmt.Errorf("config: %s", err)
|
||||
}
|
||||
|
||||
// Init storage directories with a random serial.
|
||||
// Initialize the storage path with a random serial.
|
||||
if err := c.InitSerial(); err != nil {
|
||||
return fmt.Errorf("config: %s", err)
|
||||
}
|
||||
|
||||
// Detect case-insensitive file system.
|
||||
// Detect whether files are stored on a case-insensitive file system.
|
||||
if insensitive, err := c.CaseInsensitive(); err != nil {
|
||||
return err
|
||||
} else if insensitive {
|
||||
|
@ -261,12 +266,12 @@ func (c *Config) Init() error {
|
|||
fs.IgnoreCase()
|
||||
}
|
||||
|
||||
// Detect CPU.
|
||||
// Detect the CPU type and available memory.
|
||||
if cpuName := cpuid.CPU.BrandName; cpuName != "" {
|
||||
log.Debugf("config: running on %s, %s memory detected", clean.Log(cpuid.CPU.BrandName), humanize.Bytes(TotalMem))
|
||||
}
|
||||
|
||||
// Exit if less than 128 MB RAM was detected.
|
||||
// Fail if less than 128 MB of memory were detected.
|
||||
if TotalMem < 128*Megabyte {
|
||||
return fmt.Errorf("config: %s of memory detected, %d GB required", humanize.Bytes(TotalMem), MinMem/Gigabyte)
|
||||
}
|
||||
|
@ -277,18 +282,17 @@ func (c *Config) Init() error {
|
|||
log.Warnf("config: tensorflow as well as indexing and conversion of RAW images have been disabled automatically")
|
||||
}
|
||||
|
||||
// Show swap info.
|
||||
// Show swap space disclaimer.
|
||||
if TotalMem < RecommendedMem {
|
||||
log.Infof("config: make sure your server has enough swap configured to prevent restarts when there are memory usage spikes")
|
||||
}
|
||||
|
||||
// Show wakeup interval warning if face recognition is enabled
|
||||
// and the worker runs less than once per hour.
|
||||
// Show wake-up interval warning if face recognition is activated and the worker runs less than once an hour.
|
||||
if !c.DisableFaces() && !c.Unsafe() && c.WakeupInterval() > time.Hour {
|
||||
log.Warnf("config: the wakeup interval is %s, but must be 1h or less for face recognition to work", c.WakeupInterval().String())
|
||||
}
|
||||
|
||||
// Set HTTPS proxy for outgoing connections.
|
||||
// Configure HTTPS proxy for outgoing connections.
|
||||
if httpsProxy := c.HttpsProxy(); httpsProxy != "" {
|
||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: c.HttpsProxyInsecure(),
|
||||
|
@ -297,13 +301,13 @@ func (c *Config) Init() error {
|
|||
_ = os.Setenv("HTTPS_PROXY", httpsProxy)
|
||||
}
|
||||
|
||||
// Set HTTP user agent.
|
||||
// Configure HTTP user agent.
|
||||
places.UserAgent = c.UserAgent()
|
||||
|
||||
c.initSettings()
|
||||
c.initHub()
|
||||
|
||||
// Propagate configuration.
|
||||
// Update package defaults.
|
||||
c.Propagate()
|
||||
|
||||
// Connect to database.
|
||||
|
|
|
@ -60,122 +60,153 @@ func findBin(configBin, defaultBin string) (binPath string) {
|
|||
|
||||
// CreateDirectories creates directories for storing photos, metadata and cache files.
|
||||
func (c *Config) CreateDirectories() error {
|
||||
// Make sure the configured assets path exits.
|
||||
if c.AssetsPath() == "" {
|
||||
return notFoundError("assets")
|
||||
} else if err := os.MkdirAll(c.AssetsPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.AssetsPath(), err)
|
||||
// Error if the originals and storage path are identical.
|
||||
if c.OriginalsPath() == c.StoragePath() {
|
||||
return fmt.Errorf("originals and storage folder must be different directories")
|
||||
}
|
||||
|
||||
// Make sure the configured storage folder exists and create a ".ppstorage" file in it.
|
||||
// Make sure that the configured storage path exists and initialize it with
|
||||
// ".ppstorage" and ".ppignore files" so that it is not accidentally indexed.
|
||||
if dir := c.StoragePath(); dir == "" {
|
||||
return notFoundError("storage")
|
||||
} else if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
} else if err = fs.Touch(filepath.Join(dir, fs.PPStorageFilename)); err != nil {
|
||||
} else if _, err = fs.WriteUnixTime(filepath.Join(dir, fs.PPStorageFilename)); err != nil {
|
||||
return fmt.Errorf("%s file in %s could not be created", fs.PPStorageFilename, clean.Log(dir))
|
||||
} else if err = fs.WriteString(filepath.Join(dir, fs.PPIgnoreFilename), fs.PPIgnoreAll); err != nil {
|
||||
return fmt.Errorf("%s file in %s could not be created", fs.PPIgnoreFilename, clean.Log(dir))
|
||||
}
|
||||
|
||||
if c.UsersPath() == "" {
|
||||
return notFoundError("users")
|
||||
} else if err := os.MkdirAll(c.UsersStoragePath(), fs.ModeDir); err != nil {
|
||||
return createError(c.UsersStoragePath(), err)
|
||||
}
|
||||
|
||||
if c.CmdCachePath() == "" {
|
||||
return notFoundError("cmd cache")
|
||||
} else if err := os.MkdirAll(c.CmdCachePath(), fs.ModeDir); err != nil {
|
||||
return createError(c.CmdCachePath(), err)
|
||||
}
|
||||
|
||||
if c.BackupPath() == "" {
|
||||
return notFoundError("backup")
|
||||
} else if err := os.MkdirAll(c.BackupPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.BackupPath(), err)
|
||||
}
|
||||
|
||||
if c.OriginalsPath() == "" {
|
||||
// Create originals path if it does not exist yet and return an error if it could be a storage folder.
|
||||
if dir := c.OriginalsPath(); dir == "" {
|
||||
return notFoundError("originals")
|
||||
} else if err := os.MkdirAll(c.OriginalsPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.OriginalsPath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
} else if fs.FileExists(filepath.Join(dir, fs.PPStorageFilename)) {
|
||||
return fmt.Errorf("originals path %s contains a %s file", clean.Log(dir), fs.PPStorageFilename)
|
||||
}
|
||||
|
||||
if c.ImportPath() == "" {
|
||||
// Create import path if it does not exist yet and return an error if it could be a storage folder.
|
||||
if dir := c.ImportPath(); dir == "" {
|
||||
return notFoundError("import")
|
||||
} else if err := os.MkdirAll(c.ImportPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.ImportPath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
} else if fs.FileExists(filepath.Join(dir, fs.PPStorageFilename)) {
|
||||
return fmt.Errorf("import path %s contains a %s file", clean.Log(dir), fs.PPStorageFilename)
|
||||
}
|
||||
|
||||
if filepath.IsAbs(c.SidecarPath()) {
|
||||
if err := os.MkdirAll(c.SidecarPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.SidecarPath(), err)
|
||||
// Create storage path if it doesn't exist yet.
|
||||
if dir := c.UsersStoragePath(); dir == "" {
|
||||
return notFoundError("users storage")
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
// Create assets path if it doesn't exist yet.
|
||||
if dir := c.AssetsPath(); dir == "" {
|
||||
return notFoundError("assets")
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
// Create command cache storage path if it doesn't exist yet.
|
||||
if dir := c.CmdCachePath(); dir == "" {
|
||||
return notFoundError("cmd cache")
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
// Create backup storage path if it doesn't exist yet.
|
||||
if dir := c.BackupPath(); dir == "" {
|
||||
return notFoundError("backup")
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
// Create sidecar storage path if it doesn't exist yet.
|
||||
if dir := c.SidecarPath(); filepath.IsAbs(dir) {
|
||||
if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
if c.CachePath() == "" {
|
||||
// Create and initialize cache storage directory.
|
||||
if dir := c.CachePath(); dir == "" {
|
||||
return notFoundError("cache")
|
||||
} else if err := os.MkdirAll(c.CachePath(), fs.ModeDir); err != nil {
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(c.CachePath(), err)
|
||||
} else if err = fs.WriteString(filepath.Join(dir, fs.PPIgnoreFilename), fs.PPIgnoreAll); err != nil {
|
||||
return fmt.Errorf("%s file in %s could not be created", fs.PPIgnoreFilename, clean.Log(dir))
|
||||
}
|
||||
|
||||
if c.MediaCachePath() == "" {
|
||||
// Create media cache storage path if it doesn't exist yet.
|
||||
if dir := c.MediaCachePath(); dir == "" {
|
||||
return notFoundError("media")
|
||||
} else if err := os.MkdirAll(c.MediaCachePath(), fs.ModeDir); err != nil {
|
||||
return createError(c.MediaCachePath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if c.ThumbCachePath() == "" {
|
||||
// Create thumbnail cache storage path if it doesn't exist yet.
|
||||
if dir := c.ThumbCachePath(); dir == "" {
|
||||
return notFoundError("thumbs")
|
||||
} else if err := os.MkdirAll(c.ThumbCachePath(), fs.ModeDir); err != nil {
|
||||
return createError(c.ThumbCachePath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if c.ConfigPath() == "" {
|
||||
// Create and initialize config directory.
|
||||
if dir := c.ConfigPath(); dir == "" {
|
||||
return notFoundError("config")
|
||||
} else if err := os.MkdirAll(c.ConfigPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.ConfigPath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
} else if err = fs.WriteString(filepath.Join(dir, fs.PPIgnoreFilename), fs.PPIgnoreAll); err != nil {
|
||||
return fmt.Errorf("%s file in %s could not be created", fs.PPIgnoreFilename, clean.Log(dir))
|
||||
}
|
||||
|
||||
if c.CertificatesPath() == "" {
|
||||
// Create certificates config path if it doesn't exist yet.
|
||||
if dir := c.CertificatesPath(); dir == "" {
|
||||
return notFoundError("certificates")
|
||||
} else if err := os.MkdirAll(c.CertificatesPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.CertificatesPath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if c.TempPath() == "" {
|
||||
// Create temporary file path if it doesn't exist yet.
|
||||
if dir := c.TempPath(); dir == "" {
|
||||
return notFoundError("temp")
|
||||
} else if err := os.MkdirAll(c.TempPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.TempPath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if c.AlbumsPath() == "" {
|
||||
// Create albums backup path if it doesn't exist yet.
|
||||
if dir := c.AlbumsPath(); dir == "" {
|
||||
return notFoundError("albums")
|
||||
} else if err := os.MkdirAll(c.AlbumsPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.AlbumsPath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if c.TensorFlowModelPath() == "" {
|
||||
// Create TensorFlow model path if it doesn't exist yet.
|
||||
if dir := c.TensorFlowModelPath(); dir == "" {
|
||||
return notFoundError("tensorflow model")
|
||||
} else if err := os.MkdirAll(c.TensorFlowModelPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.TensorFlowModelPath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if c.BuildPath() == "" {
|
||||
// Create frontend build path if it doesn't exist yet.
|
||||
if dir := c.BuildPath(); dir == "" {
|
||||
return notFoundError("build")
|
||||
} else if err := os.MkdirAll(c.BuildPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.BuildPath(), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if filepath.Dir(c.PIDFilename()) == "" {
|
||||
if dir := filepath.Dir(c.PIDFilename()); dir == "" {
|
||||
return notFoundError("pid file")
|
||||
} else if err := os.MkdirAll(filepath.Dir(c.PIDFilename()), fs.ModeDir); err != nil {
|
||||
return createError(filepath.Dir(c.PIDFilename()), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if filepath.Dir(c.LogFilename()) == "" {
|
||||
if dir := filepath.Dir(c.LogFilename()); dir == "" {
|
||||
return notFoundError("log file")
|
||||
} else if err := os.MkdirAll(filepath.Dir(c.LogFilename()), fs.ModeDir); err != nil {
|
||||
return createError(filepath.Dir(c.LogFilename()), err)
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
return createError(dir, err)
|
||||
}
|
||||
|
||||
if c.DarktableEnabled() {
|
||||
|
@ -341,7 +372,7 @@ func (c *Config) UserStoragePath(userUid string) string {
|
|||
|
||||
dir := filepath.Join(c.UsersStoragePath(), userUid)
|
||||
|
||||
if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(dir); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
@ -356,7 +387,7 @@ func (c *Config) UserUploadPath(userUid, token string) (string, error) {
|
|||
|
||||
dir := filepath.Join(c.UserStoragePath(userUid), "upload", clean.Token(token))
|
||||
|
||||
if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(dir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
@ -395,7 +426,7 @@ func (c *Config) tempPath() string {
|
|||
if c.options.TempPath != "" {
|
||||
if dir := fs.Abs(c.options.TempPath); dir == "" {
|
||||
// Ignore.
|
||||
} else if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
// Ignore.
|
||||
} else if fs.PathWritable(dir) {
|
||||
return dir
|
||||
|
@ -405,7 +436,7 @@ func (c *Config) tempPath() string {
|
|||
// Find alternative temp path based on storage serial checksum.
|
||||
if dir := filepath.Join(osTempDir, "photoprism_"+c.SerialChecksum()); dir == "" {
|
||||
// Ignore.
|
||||
} else if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
} else if err := fs.MkdirAll(dir); err != nil {
|
||||
// Ignore.
|
||||
} else if fs.PathWritable(dir) {
|
||||
return dir
|
||||
|
@ -414,7 +445,7 @@ func (c *Config) tempPath() string {
|
|||
// Find alternative temp path based on built-in TempDir() function.
|
||||
if dir, err := ioutil.TempDir(osTempDir, "photoprism_"); err != nil || dir == "" {
|
||||
// Ignore.
|
||||
} else if err = os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
} else if err = fs.MkdirAll(dir); err != nil {
|
||||
// Ignore.
|
||||
} else if fs.PathWritable(dir) {
|
||||
return dir
|
||||
|
@ -467,7 +498,7 @@ func (c *Config) MediaFileCachePath(hash string) string {
|
|||
}
|
||||
|
||||
// Ensure the subdirectory exists, or log an error otherwise.
|
||||
if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(dir); err != nil {
|
||||
log.Errorf("cache: failed to create subdirectory for media file")
|
||||
}
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ func TestConfig_OriginalsAlbumsPath(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestConfig_CreateDirectories(t *testing.T) {
|
||||
t.Run("no error", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
testConfigMutex.Lock()
|
||||
defer testConfigMutex.Unlock()
|
||||
|
||||
|
@ -194,9 +194,21 @@ func TestConfig_CreateDirectories(t *testing.T) {
|
|||
token: rnd.Base36(8),
|
||||
}
|
||||
|
||||
if err := c.CreateDirectories(); err != nil {
|
||||
t.Fatal(err)
|
||||
assert.NoError(t, c.CreateDirectories())
|
||||
})
|
||||
t.Run("IdenticalPaths", func(t *testing.T) {
|
||||
testConfigMutex.Lock()
|
||||
defer testConfigMutex.Unlock()
|
||||
|
||||
c := &Config{
|
||||
options: NewTestOptions("config"),
|
||||
token: rnd.Base36(8),
|
||||
}
|
||||
|
||||
c.options.StoragePath = "./testdata"
|
||||
c.options.OriginalsPath = "./testdata"
|
||||
|
||||
assert.Error(t, c.CreateDirectories())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
)
|
||||
|
||||
|
@ -42,7 +40,7 @@ func (c *Config) CreateDarktableCachePath() (string, error) {
|
|||
|
||||
if cachePath == "" {
|
||||
return "", nil
|
||||
} else if err := os.MkdirAll(cachePath, fs.ModeDir); err != nil {
|
||||
} else if err := fs.MkdirAll(cachePath); err != nil {
|
||||
return cachePath, err
|
||||
} else {
|
||||
c.options.DarktableCachePath = cachePath
|
||||
|
@ -57,7 +55,7 @@ func (c *Config) CreateDarktableConfigPath() (string, error) {
|
|||
|
||||
if configPath == "" {
|
||||
return "", nil
|
||||
} else if err := os.MkdirAll(configPath, fs.ModeDir); err != nil {
|
||||
} else if err := fs.MkdirAll(configPath); err != nil {
|
||||
return configPath, err
|
||||
} else {
|
||||
c.options.DarktableConfigPath = configPath
|
||||
|
|
|
@ -47,7 +47,7 @@ func (ext Extensions) Init(c *Config) {
|
|||
start := time.Now()
|
||||
|
||||
if err := e.init(c); err != nil {
|
||||
log.Warnf("config: %s while initializing the %s extension [%s]", err, clean.Log(e.name), time.Since(start))
|
||||
log.Warnf("config: %s when loading %s extension", err, clean.Log(e.name))
|
||||
} else {
|
||||
log.Tracef("config: %s extension loaded [%s]", clean.Log(e.name), time.Since(start))
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/internal/customize"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
|
@ -25,7 +23,7 @@ func (c *Config) initSettings() {
|
|||
defaultsFile := c.SettingsYamlDefaults(settingsFile)
|
||||
|
||||
// Make sure that the config path exists.
|
||||
if err := os.MkdirAll(configPath, fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(configPath); err != nil {
|
||||
log.Errorf("settings: %s", createError(configPath, err))
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ func NewTestConfig(pkg string) *Config {
|
|||
|
||||
s := customize.NewSettings(c.DefaultTheme(), c.DefaultLocale())
|
||||
|
||||
if err := os.MkdirAll(c.ConfigPath(), fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(c.ConfigPath()); err != nil {
|
||||
log.Fatalf("config: %s", err.Error())
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ func (m *Album) SaveAsYaml(fileName string) error {
|
|||
}
|
||||
|
||||
// Make sure directory exists.
|
||||
if err := os.MkdirAll(filepath.Dir(fileName), fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(filepath.Dir(fileName)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ func (m *Album) SaveAsYaml(fileName string) error {
|
|||
defer albumYamlMutex.Unlock()
|
||||
|
||||
// Write YAML data to file.
|
||||
if err := os.WriteFile(fileName, data, fs.ModeFile); err != nil {
|
||||
if err = fs.WriteFile(fileName, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ func (m *Photo) SaveAsYaml(fileName string) error {
|
|||
}
|
||||
|
||||
// Make sure directory exists.
|
||||
if err := os.MkdirAll(filepath.Dir(fileName), fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(filepath.Dir(fileName)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ func (m *Photo) SaveAsYaml(fileName string) error {
|
|||
defer photoYamlMutex.Unlock()
|
||||
|
||||
// Write YAML data to file.
|
||||
if err := os.WriteFile(fileName, data, fs.ModeFile); err != nil {
|
||||
if err = fs.WriteFile(fileName, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ func (c *Config) ReSync(token string) (err error) {
|
|||
c.session = nil
|
||||
|
||||
// Make sure storage folder exists.
|
||||
if err = os.MkdirAll(filepath.Dir(c.FileName), fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(filepath.Dir(c.FileName)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -330,11 +330,11 @@ func (c *Config) Save() error {
|
|||
|
||||
c.Propagate()
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(c.FileName), fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(filepath.Dir(c.FileName)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.WriteFile(c.FileName, data, fs.ModeFile); err != nil {
|
||||
if err = fs.WriteFile(c.FileName, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package photoprism
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
|
@ -63,7 +62,7 @@ func ImportWorker(jobs <-chan ImportJob) {
|
|||
|
||||
if fs.PathExists(destDir) {
|
||||
// Do nothing.
|
||||
} else if err := os.MkdirAll(destDir, fs.ModeDir); err != nil {
|
||||
} else if err := fs.MkdirAll(destDir); err != nil {
|
||||
log.Errorf("import: failed creating folder for %s (%s)", clean.Log(f.BaseName()), err.Error())
|
||||
} else {
|
||||
destDirRel := fs.RelName(destDir, imp.originalsPath())
|
||||
|
|
|
@ -549,7 +549,7 @@ func (m *MediaFile) HasSameName(f *MediaFile) bool {
|
|||
|
||||
// Move file to a new destination with the filename provided in parameter.
|
||||
func (m *MediaFile) Move(dest string) error {
|
||||
if err := os.MkdirAll(filepath.Dir(dest), fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(filepath.Dir(dest)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -576,7 +576,7 @@ func (m *MediaFile) Move(dest string) error {
|
|||
|
||||
// Copy a MediaFile to another file by destinationFilename.
|
||||
func (m *MediaFile) Copy(dest string) error {
|
||||
if err := os.MkdirAll(filepath.Dir(dest), fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(filepath.Dir(dest)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -798,7 +798,7 @@ func TestMediaFile_Move(t *testing.T) {
|
|||
origName := tmpPath + "/original.jpg"
|
||||
destName := tmpPath + "/destination.jpg"
|
||||
|
||||
if err := os.MkdirAll(tmpPath, fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(tmpPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -834,7 +834,7 @@ func TestMediaFile_Copy(t *testing.T) {
|
|||
|
||||
tmpPath := conf.CachePath() + "/_tmp/TestMediaFile_Copy"
|
||||
|
||||
if err := os.MkdirAll(tmpPath, fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(tmpPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -2303,14 +2303,14 @@ func TestMediaFile_RenameSidecarFiles(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(conf.SidecarPath(), "foo"), fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(filepath.Join(conf.SidecarPath(), "foo")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
srcName := filepath.Join(conf.SidecarPath(), "foo/bar.jpg.json")
|
||||
dstName := filepath.Join(conf.SidecarPath(), "2020/12/foobar.jpg.json")
|
||||
|
||||
if err := os.WriteFile(srcName, []byte("{}"), 0666); err != nil {
|
||||
if err = os.WriteFile(srcName, []byte("{}"), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -267,7 +267,7 @@ func (c *Client) Download(src, dest string, force bool) (err error) {
|
|||
|
||||
if err != nil {
|
||||
// Create local storage path.
|
||||
if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(dir); err != nil {
|
||||
return fmt.Errorf("webdav: cannot create folder %s (%s)", clean.Log(dir), err)
|
||||
}
|
||||
} else if !dirInfo.IsDir() {
|
||||
|
|
|
@ -49,7 +49,7 @@ func (ext Extensions) Init(router *gin.Engine, conf *config.Config) {
|
|||
start := time.Now()
|
||||
|
||||
if err := e.init(router, conf); err != nil {
|
||||
log.Warnf("server: %s while initializing the %s extension [%s]", err, clean.Log(e.name), time.Since(start))
|
||||
log.Warnf("server: %s when loading %s extension", err, clean.Log(e.name))
|
||||
} else {
|
||||
log.Tracef("server: %s extension loaded [%s]", clean.Log(e.name), time.Since(start))
|
||||
}
|
||||
|
|
|
@ -165,13 +165,13 @@ func WebDAVSetFavoriteFlag(fileName string) {
|
|||
}
|
||||
|
||||
// Make sure directory exists.
|
||||
if err := os.MkdirAll(filepath.Dir(yamlName), fs.ModeDir); err != nil {
|
||||
if err := fs.MkdirAll(filepath.Dir(yamlName)); err != nil {
|
||||
log.Errorf("webdav: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Write YAML data to file.
|
||||
if err := os.WriteFile(yamlName, []byte("Favorite: true\n"), fs.ModeFile); err != nil {
|
||||
if err := fs.WriteFile(yamlName, []byte("Favorite: true\n")); err != nil {
|
||||
log.Errorf("webdav: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package server
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -122,7 +121,7 @@ func WebDAVAuth(conf *config.Config) gin.HandlerFunc {
|
|||
event.AuditWarn([]string{clientIp, "client %s", "session %s", "access webdav as %s", message}, clean.Log(sess.ClientInfo()), sess.RefID, clean.LogQuote(user.Username()))
|
||||
WebDAVAbortUnauthorized(c)
|
||||
return
|
||||
} else if err := os.MkdirAll(filepath.Join(conf.OriginalsPath(), user.GetUploadPath()), fs.ModeDir); err != nil {
|
||||
} else if err := fs.MkdirAll(filepath.Join(conf.OriginalsPath(), user.GetUploadPath())); err != nil {
|
||||
// Log warning if upload path could not be created.
|
||||
message := "failed to create user upload path"
|
||||
event.AuditWarn([]string{clientIp, "client %s", "session %s", "access webdav as %s", message}, clean.Log(sess.ClientInfo()), sess.RefID, clean.LogQuote(user.Username()))
|
||||
|
@ -177,7 +176,7 @@ func WebDAVAuth(conf *config.Config) gin.HandlerFunc {
|
|||
message := "webdav access is disabled"
|
||||
event.AuditWarn([]string{clientIp, "webdav login as %s", message}, clean.LogQuote(username))
|
||||
event.LoginError(clientIp, "webdav", username, api.UserAgent(c), message)
|
||||
} else if err = os.MkdirAll(filepath.Join(conf.OriginalsPath(), user.GetUploadPath()), fs.ModeDir); err != nil {
|
||||
} else if err = fs.MkdirAll(filepath.Join(conf.OriginalsPath(), user.GetUploadPath())); err != nil {
|
||||
// Abort if upload path could not be created.
|
||||
message := "failed to create user upload path"
|
||||
event.AuditWarn([]string{clientIp, "webdav login as %s", message}, clean.LogQuote(username))
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"image"
|
||||
"image/png"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -45,7 +44,7 @@ func FileName(hash, thumbPath string, width, height int, opts ...ResampleOption)
|
|||
suffix := Suffix(width, height, opts...)
|
||||
p := path.Join(thumbPath, hash[0:1], hash[1:2], hash[2:3])
|
||||
|
||||
if err := os.MkdirAll(p, fs.ModeDir); err != nil {
|
||||
if err = fs.MkdirAll(p); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
|
@ -39,21 +39,25 @@ func testFastWalk(t *testing.T, files map[string]string, callback func(path stri
|
|||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempdir)
|
||||
|
||||
for path, contents := range files {
|
||||
file := filepath.Join(tempdir, "/src", path)
|
||||
if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(file), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var err error
|
||||
|
||||
if strings.HasPrefix(contents, "LINK:") {
|
||||
err = os.Symlink(strings.TrimPrefix(contents, "LINK:"), file)
|
||||
} else {
|
||||
err = os.WriteFile(file, []byte(contents), 0644)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
got := map[string]os.FileMode{}
|
||||
var mu sync.Mutex
|
||||
if err := fastwalk.Walk(tempdir, func(path string, typ os.FileMode) error {
|
||||
|
|
|
@ -2,7 +2,6 @@ package fs
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
|
@ -19,7 +18,7 @@ func CachePath(basePath, fileHash, namespace string, create bool) (cachePath str
|
|||
cachePath = path.Join(basePath, namespace, fileHash[0:1], fileHash[1:2], fileHash[2:3])
|
||||
|
||||
if create {
|
||||
if err := os.MkdirAll(cachePath, ModeDir); err != nil {
|
||||
if err = MkdirAll(cachePath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package fs
|
|||
|
||||
const (
|
||||
PPIgnoreFilename = ".ppignore"
|
||||
PPIgnoreAll = "*"
|
||||
PPStorageFilename = ".ppstorage"
|
||||
PPHiddenPathname = ".photoprism"
|
||||
)
|
||||
|
|
|
@ -15,7 +15,7 @@ func Copy(src, dest string) (err error) {
|
|||
}
|
||||
}()
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(dest), ModeDir); err != nil {
|
||||
if err = MkdirAll(filepath.Dir(dest)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ func Dirs(root string, recursive bool, followLinks bool) (result []string, err e
|
|||
return result, err
|
||||
}
|
||||
|
||||
// FindDir checks if any of the specified directories exist and returns the absolute path of the first directory found.
|
||||
func FindDir(dirs []string) string {
|
||||
for _, dir := range dirs {
|
||||
absDir := Abs(dir)
|
||||
|
@ -199,3 +200,9 @@ func FindDir(dirs []string) string {
|
|||
|
||||
return ""
|
||||
}
|
||||
|
||||
// MkdirAll creates a directory including all parent directories that might not yet exist.
|
||||
// No error is returned if the directory already exists.
|
||||
func MkdirAll(dir string) error {
|
||||
return os.MkdirAll(dir, ModeDir)
|
||||
}
|
|
@ -81,14 +81,19 @@ func TestDirs(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestFindDirs(t *testing.T) {
|
||||
t.Run("/directory", func(t *testing.T) {
|
||||
result := FindDir([]string{"/directory", "/directory/subdirectory", "/linked"})
|
||||
assert.Equal(t, "", result)
|
||||
})
|
||||
|
||||
t.Run("./testdata", func(t *testing.T) {
|
||||
func TestFindDir(t *testing.T) {
|
||||
t.Run("Found", func(t *testing.T) {
|
||||
result := FindDir([]string{"./testdata"})
|
||||
assert.True(t, strings.HasSuffix(result, "/pkg/fs/testdata"))
|
||||
})
|
||||
t.Run("NotFound", func(t *testing.T) {
|
||||
result := FindDir([]string{"/directory", "/directory/subdirectory", "/linked"})
|
||||
assert.Equal(t, "", result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMkdirAll(t *testing.T) {
|
||||
t.Run("Exists", func(t *testing.T) {
|
||||
assert.NoError(t, MkdirAll("testdata"))
|
||||
})
|
||||
}
|
18
pkg/fs/fs.go
18
pkg/fs/fs.go
|
@ -100,17 +100,6 @@ func PathWritable(path string) bool {
|
|||
return Writable(path)
|
||||
}
|
||||
|
||||
// Overwrite overwrites the file with data. Creates file if not present.
|
||||
func Overwrite(fileName string, data []byte) bool {
|
||||
f, err := os.Create(fileName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err = f.Write(data)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Abs returns the full path of a file or directory, "~" is replaced with home.
|
||||
func Abs(name string) string {
|
||||
if name == "" {
|
||||
|
@ -147,7 +136,7 @@ func copyToFile(f *zip.File, dest string) (fileName string, err error) {
|
|||
|
||||
if f.FileInfo().IsDir() {
|
||||
// Make Folder
|
||||
return fileName, os.MkdirAll(fileName, ModeDir)
|
||||
return fileName, MkdirAll(fileName)
|
||||
}
|
||||
|
||||
// Make File
|
||||
|
@ -157,8 +146,7 @@ func copyToFile(f *zip.File, dest string) (fileName string, err error) {
|
|||
fdir = fileName[:lastIndex]
|
||||
}
|
||||
|
||||
err = os.MkdirAll(fdir, ModeDir)
|
||||
if err != nil {
|
||||
if err = MkdirAll(fdir); err != nil {
|
||||
return fileName, err
|
||||
}
|
||||
|
||||
|
@ -181,7 +169,7 @@ func copyToFile(f *zip.File, dest string) (fileName string, err error) {
|
|||
func Download(fileName string, url string) error {
|
||||
if dir := filepath.Dir(fileName); dir == "" || dir == "/" || dir == "." || dir == ".." {
|
||||
return fmt.Errorf("invalid path")
|
||||
} else if err := os.MkdirAll(dir, ModeDir); err != nil {
|
||||
} else if err := MkdirAll(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -57,19 +57,6 @@ func TestWritable(t *testing.T) {
|
|||
assert.False(t, Writable(""))
|
||||
}
|
||||
|
||||
func TestOverwrite(t *testing.T) {
|
||||
data := make([]byte, 3)
|
||||
data[1] = 3
|
||||
data[2] = 8
|
||||
tmpPath := "./testdata/_tmp"
|
||||
os.Mkdir(tmpPath, 0777)
|
||||
|
||||
defer os.RemoveAll(tmpPath)
|
||||
result := Overwrite("./testdata/_tmp/notyetexisting.jpg", data)
|
||||
assert.FileExists(t, "./testdata/_tmp/notyetexisting.jpg")
|
||||
assert.True(t, result)
|
||||
}
|
||||
|
||||
func TestExpandedFilename(t *testing.T) {
|
||||
t.Run("test.jpg", func(t *testing.T) {
|
||||
filename := Abs("./testdata/test.jpg")
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"path/filepath"
|
||||
)
|
||||
|
||||
// Moves a file to a new destination.
|
||||
// Move moves an existing file to a new destination and returns an error if it fails.
|
||||
func Move(src, dest string) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
@ -14,19 +14,19 @@ func Move(src, dest string) (err error) {
|
|||
}
|
||||
}()
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(dest), ModeDir); err != nil {
|
||||
if err = MkdirAll(filepath.Dir(dest)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Rename(src, dest); err == nil {
|
||||
if err = os.Rename(src, dest); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := Copy(src, dest); err != nil {
|
||||
if err = Copy(src, dest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Remove(src); err != nil {
|
||||
if err = os.Remove(src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -9,19 +9,19 @@ import (
|
|||
|
||||
// FileName returns the relative filename with the same base and a given extension in a directory.
|
||||
func FileName(fileName, dirName, baseDir, fileExt string) string {
|
||||
fileDir := filepath.Dir(fileName)
|
||||
dir := filepath.Dir(fileName)
|
||||
|
||||
if dirName == "" || dirName == "." {
|
||||
dirName = fileDir
|
||||
} else if fileDir != dirName {
|
||||
dirName = dir
|
||||
} else if dir != dirName {
|
||||
if filepath.IsAbs(dirName) {
|
||||
dirName = filepath.Join(dirName, RelName(fileDir, baseDir))
|
||||
dirName = filepath.Join(dirName, RelName(dir, baseDir))
|
||||
} else {
|
||||
dirName = filepath.Join(fileDir, dirName)
|
||||
dirName = filepath.Join(dir, dirName)
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(dirName, ModeDir); err != nil {
|
||||
if err := MkdirAll(dirName); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Touch creates a file with the specified name that contains the current Unix timestamp.
|
||||
// If the file path does not exist or it cannot be written, an error is returned.
|
||||
func Touch(fileName string) error {
|
||||
return os.WriteFile(fileName, []byte(strconv.FormatInt(time.Now().Unix(), 10)), ModeFile)
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTouch(t *testing.T) {
|
||||
t.Run("Testdata", func(t *testing.T) {
|
||||
fileName := filepath.Join("testdata", PPStorageFilename)
|
||||
assert.False(t, FileExists(fileName))
|
||||
assert.False(t, FileExistsNotEmpty(fileName))
|
||||
|
||||
// Create "testdata/.ppstorage" file.
|
||||
assert.NoError(t, Touch(fileName))
|
||||
|
||||
assert.True(t, FileExists(fileName))
|
||||
assert.True(t, FileExistsNotEmpty(fileName))
|
||||
|
||||
// Delete "testdata/.ppstorage" file.
|
||||
assert.NoError(t, os.Remove(fileName))
|
||||
|
||||
assert.False(t, FileExists(fileName))
|
||||
assert.False(t, FileExistsNotEmpty(fileName))
|
||||
})
|
||||
}
|
|
@ -4,39 +4,74 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// WriteFile writes data from a reader to a new file.
|
||||
func WriteFile(fileName string, reader io.Reader) (err error) {
|
||||
// WriteFile overwrites a file with the specified bytes as content.
|
||||
// If the path does not exist or the file cannot be written, an error is returned.
|
||||
func WriteFile(fileName string, data []byte) error {
|
||||
file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, ModeFile)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = file.Write(data)
|
||||
|
||||
if closeErr := file.Close(); closeErr != nil && err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteString overwrites a file with the specified string as content.
|
||||
// If the path does not exist or the file cannot be written, an error is returned.
|
||||
func WriteString(fileName string, s string) error {
|
||||
return WriteFile(fileName, []byte(s))
|
||||
}
|
||||
|
||||
// WriteUnixTime overwrites a file with the current Unix timestamp as content.
|
||||
// If the path does not exist or the file cannot be written, an error is returned.
|
||||
func WriteUnixTime(fileName string) (unixTime int64, err error) {
|
||||
unixTime = time.Now().Unix()
|
||||
return unixTime, WriteString(fileName, strconv.FormatInt(unixTime, 10))
|
||||
}
|
||||
|
||||
// WriteFileFromReader writes data from an io.Reader to a newly created file with the specified name.
|
||||
// If the path does not exist or the file cannot be written, an error is returned.
|
||||
func WriteFileFromReader(fileName string, reader io.Reader) (err error) {
|
||||
if fileName == "" {
|
||||
return errors.New("filename missing")
|
||||
} else if reader == nil {
|
||||
return errors.New("reader missing")
|
||||
}
|
||||
|
||||
var f *os.File
|
||||
var file *os.File
|
||||
|
||||
if f, err = os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, ModeFile); err != nil {
|
||||
if file, err = os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, ModeFile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
_, err = io.Copy(file, reader)
|
||||
|
||||
if _, err = io.Copy(f, reader); err != nil {
|
||||
return err
|
||||
if closeErr := file.Close(); closeErr != nil && err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// CacheFile writes data from a reader to a new file if it does not already exist,
|
||||
// and returns the name of the file or an error otherwise.
|
||||
func CacheFile(fileName string, reader io.Reader) (string, error) {
|
||||
// CacheFileFromReader writes data from an io.Reader to a file with the specified name if it does not exist.
|
||||
// If the path does not exist or the file cannot be written, an error is returned.
|
||||
// No error is returned if the file already exists.
|
||||
func CacheFileFromReader(fileName string, reader io.Reader) (string, error) {
|
||||
if FileExistsNotEmpty(fileName) {
|
||||
return fileName, nil
|
||||
}
|
||||
|
||||
if err := WriteFile(fileName, reader); err != nil {
|
||||
if err := WriteFileFromReader(fileName, reader); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
203
pkg/fs/write_test.go
Normal file
203
pkg/fs/write_test.go
Normal file
|
@ -0,0 +1,203 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWriteFile(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
pathName := "./testdata/_WriteFile_Success"
|
||||
fileName := filepath.Join(pathName, "notyetexisting.jpg")
|
||||
fileData := []byte("foobar")
|
||||
|
||||
if err := MkdirAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = os.Remove(fileName)
|
||||
|
||||
if err := os.RemoveAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
assert.True(t, PathExists(pathName))
|
||||
|
||||
fileErr := WriteFile(fileName, fileData)
|
||||
|
||||
assert.NoError(t, fileErr)
|
||||
assert.FileExists(t, fileName)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWriteString(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
pathName := "./testdata/_WriteString_Success"
|
||||
fileName := filepath.Join(pathName, PPIgnoreFilename)
|
||||
fileData := "*"
|
||||
|
||||
if err := MkdirAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = os.Remove(fileName)
|
||||
|
||||
if err := os.RemoveAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
assert.True(t, PathExists(pathName))
|
||||
|
||||
fileErr := WriteString(fileName, fileData)
|
||||
|
||||
assert.NoError(t, fileErr)
|
||||
assert.FileExists(t, fileName)
|
||||
|
||||
readLines, readErr := ReadLines(fileName)
|
||||
|
||||
assert.NoError(t, readErr)
|
||||
assert.Len(t, readLines, 1)
|
||||
assert.Equal(t, fileData, readLines[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestWriteUnixTime(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
pathName := "./testdata/_WriteUnixTime_Success"
|
||||
fileName := filepath.Join(pathName, PPStorageFilename)
|
||||
|
||||
if err := MkdirAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = os.Remove(fileName)
|
||||
|
||||
if err := os.RemoveAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
assert.True(t, PathExists(pathName))
|
||||
|
||||
unixTime, fileErr := WriteUnixTime(fileName)
|
||||
|
||||
assert.NoError(t, fileErr)
|
||||
assert.FileExists(t, fileName)
|
||||
|
||||
readLines, readErr := ReadLines(fileName)
|
||||
|
||||
assert.NoError(t, readErr)
|
||||
assert.Len(t, readLines, 1)
|
||||
assert.Equal(t, strconv.FormatInt(unixTime, 10), readLines[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestWriteFileFromReader(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
pathName := "./testdata/_WriteFileFromReader_Success"
|
||||
|
||||
fileName1 := filepath.Join(pathName, "1.txt")
|
||||
fileName2 := filepath.Join(pathName, "2.txt")
|
||||
|
||||
if err := MkdirAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = os.Remove(fileName1)
|
||||
_ = os.Remove(fileName2)
|
||||
|
||||
if err := os.RemoveAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
assert.True(t, PathExists(pathName))
|
||||
|
||||
unixTime, writeErr := WriteUnixTime(fileName1)
|
||||
assert.NoError(t, writeErr)
|
||||
assert.True(t, unixTime >= time.Now().Unix())
|
||||
|
||||
fileReader, readerErr := os.Open(fileName1)
|
||||
assert.NoError(t, readerErr)
|
||||
|
||||
fileErr := WriteFileFromReader(fileName2, fileReader)
|
||||
|
||||
assert.NoError(t, fileErr)
|
||||
|
||||
readLines, readErr := ReadLines(fileName2)
|
||||
|
||||
assert.NoError(t, readErr)
|
||||
assert.Len(t, readLines, 1)
|
||||
assert.Equal(t, strconv.FormatInt(unixTime, 10), readLines[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestCacheFileFromReader(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
pathName := "./testdata/_CacheFileFromReader_Success"
|
||||
|
||||
fileName1 := filepath.Join(pathName, "1.txt")
|
||||
fileName2 := filepath.Join(pathName, "2.txt")
|
||||
fileName3 := filepath.Join(pathName, "3.txt")
|
||||
|
||||
if err := MkdirAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = os.Remove(fileName1)
|
||||
_ = os.Remove(fileName2)
|
||||
_ = os.Remove(fileName3)
|
||||
|
||||
if err := os.RemoveAll(pathName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
assert.True(t, PathExists(pathName))
|
||||
|
||||
unixTime, writeErr := WriteUnixTime(fileName1)
|
||||
assert.NoError(t, writeErr)
|
||||
assert.True(t, unixTime >= time.Now().Unix())
|
||||
|
||||
fileReader, readerErr := os.Open(fileName1)
|
||||
assert.NoError(t, readerErr)
|
||||
|
||||
cacheFile, cacheErr := CacheFileFromReader(fileName2, fileReader)
|
||||
|
||||
assert.NoError(t, cacheErr)
|
||||
assert.Equal(t, fileName2, cacheFile)
|
||||
|
||||
readLines, readErr := ReadLines(cacheFile)
|
||||
|
||||
assert.NoError(t, readErr)
|
||||
assert.Len(t, readLines, 1)
|
||||
assert.Equal(t, strconv.FormatInt(unixTime, 10), readLines[0])
|
||||
|
||||
if err := WriteString(fileName3, "0"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cacheFile, cacheErr = CacheFileFromReader(fileName3, fileReader)
|
||||
|
||||
assert.NoError(t, cacheErr)
|
||||
assert.Equal(t, fileName3, cacheFile)
|
||||
|
||||
readLines, readErr = ReadLines(cacheFile)
|
||||
|
||||
assert.NoError(t, readErr)
|
||||
assert.Len(t, readLines, 1)
|
||||
assert.Equal(t, "0", readLines[0])
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue