// New builder with option func New(opt *BuildOption) *Builder { if !com.IsDir(opt.SrcDir) { return &Builder{Error: ErrSrcDirMissing} } if !com.IsDir(opt.TplDir) { return &Builder{Error: ErrTplDirMissing} } builder := &Builder{ parsers: []parser.Parser{ parser.NewCommonParser(), parser.NewMdParser(), }, Version: builderVersion{ Num: opt.Version, Date: opt.VerDate, }, opt: opt, } builder.render = render.New(builder.opt.TplDir) builder.tasks = []*BuildTask{ {"Data", builder.ReadData, nil}, {"Compile", builder.Compile, nil}, {"Feed", builder.WriteFeed, nil}, {"Copy", builder.CopyAssets, nil}, } log15.Debug("Build.Source." + opt.SrcDir) log15.Debug("Build.Template." + opt.TplDir) log15.Debug("Build.Theme." + opt.Theme) return builder }
func TestGetAndRun(t *testing.T) { os.Chdir("testproject") defer func() { os.RemoveAll("src/github.com") os.Remove("bin") os.Remove("pkg") os.Remove(".gopmfile") os.Chdir("..") }() _, err := exec.Command("gopm", "gen", "-l").Output() if err != nil { t.Log(err) } if !com.IsDir("bin") || !com.IsDir("pkg") { t.Fatal("Gen bin and pkg directories failed.") } _, err = exec.Command("gopm", "get", "-l").Output() if !com.IsDir("src/github.com") { t.Fatal("Get packages failed") } out, err := exec.Command("gopm", "run", "-l").Output() if err != nil || string(out) != "TEST\n" { t.Fatal("Run failed \t", err.Error()) } }
// ReadTheme read *Theme to *Context func ReadTheme(ctx *Context) { if ctx.Source == nil { ctx.Err = fmt.Errorf("theme depends on loaded source data") return } dir, _ := toDir(ctx.ThemeName) if !com.IsDir(dir) { ctx.Err = fmt.Errorf("theme directory '%s' is missing", dir) return } log15.Info("Theme|%s", dir) ctx.Theme = theme.New(dir) ctx.Theme.Func("url", func(str ...string) string { if len(str) > 0 { if ur, _ := url.Parse(str[0]); ur != nil { if ur.Host != "" { return str[0] } } } return path.Join(append([]string{ctx.Source.Meta.Path}, str...)...) }) ctx.Theme.Func("fullUrl", func(str ...string) string { return ctx.Source.Meta.Root + path.Join(str...) }) if err := ctx.Theme.Validate(); err != nil { log15.Warn("Theme|%s|%s", dir, err.Error()) } }
// build site function func buildSite(opt *builder.BuildOption) func(ctx *cli.Context) { return func(ctx *cli.Context) { // ctrl+C capture signalChan := make(chan os.Signal) signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) opt.Theme = ctx.String("theme") b := builder.New(opt) if b.Error != nil { log15.Crit("Builder.Fail", "error", b.Error.Error()) } targetDir := ctx.String("dest") log15.Info("Dest." + targetDir) if com.IsDir(targetDir) { log15.Warn("Dest." + targetDir + ".Existed") } // auto watching b.Build(targetDir) if err := b.Context().Error; err != nil { log15.Crit("Build.Fail", "error", err.Error()) } if !ctx.Bool("nowatch") { b.Watch(targetDir) <-signalChan } log15.Info("Build.Close") } }
func runRun(ctx *cli.Context) { setup(ctx) // Get GOPATH. installGopath = com.GetGOPATHs()[0] if com.IsDir(installGopath) { isHasGopath = true log.Log("Indicated GOPATH: %s", installGopath) installGopath += "/src" } genNewGoPath(ctx, false) log.Trace("Running...") cmdArgs := []string{"go", "run"} cmdArgs = append(cmdArgs, ctx.Args()...) err := execCmd(newGoPath, newCurPath, cmdArgs...) if err != nil { log.Error("run", "Fail to run program:") log.Fatal("", "\t"+err.Error()) } log.Success("SUCC", "run", "Command executed successfully!") }
func Download(ctx *middleware.Context) { ext := "." + ctx.Params(":ext") var archivePath string switch ext { case ".zip": archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/zip") case ".tar.gz": archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/targz") default: ctx.Error(404) return } if !com.IsDir(archivePath) { if err := os.MkdirAll(archivePath, os.ModePerm); err != nil { ctx.Handle(500, "Download -> os.MkdirAll(archivePath)", err) return } } archivePath = path.Join(archivePath, ctx.Repo.CommitId+ext) if !com.IsFile(archivePath) { if err := ctx.Repo.Commit.CreateArchive(archivePath, git.ZIP); err != nil { ctx.Handle(500, "Download -> CreateArchive "+archivePath, err) return } } ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+base.ShortSha(ctx.Repo.CommitId)+ext) }
// new theme manager func NewTheme(dir, name string) *Theme { // try to create dir if !com.IsDir(dir) { os.MkdirAll(dir, os.ModePerm) } return &Theme{dir, name} }
func ZipDownload(ctx *middleware.Context, params martini.Params) { commitId := ctx.Repo.CommitId archivesPath := filepath.Join(ctx.Repo.GitRepo.Path, "archives") if !com.IsDir(archivesPath) { if err := os.Mkdir(archivesPath, 0755); err != nil { ctx.Handle(404, "ZipDownload -> os.Mkdir(archivesPath)", err) return } } zipPath := filepath.Join(archivesPath, commitId+".zip") if com.IsFile(zipPath) { ctx.ServeFile(zipPath, ctx.Repo.Repository.Name+".zip") return } err := ctx.Repo.Commit.CreateArchive(zipPath) if err != nil { ctx.Handle(404, "ZipDownload -> CreateArchive "+zipPath, err) return } ctx.ServeFile(zipPath, ctx.Repo.Repository.Name+".zip") }
func TestBuilderBuild(t *testing.T) { Convey("Build Process", t, func() { b.Build(target) So(b.Error, ShouldBeNil) So(b.Context(), ShouldNotBeNil) So(b.Context().Error, ShouldBeNil) // check dirs and files Convey("Check Built And Files", func() { var flag = true t := path.Join(target, b.Context().Meta.Base) for _, dir := range shoudlExistDirs { if flag = flag && com.IsDir(path.Join(t, dir)); !flag { break } } So(flag, ShouldBeTrue) for _, f := range shouldExistFiles { if flag = flag && com.IsFile(path.Join(t, f)); !flag { break } } So(flag, ShouldBeTrue) }) }) }
// ReadLang read languages in srcDir func ReadLang(srcDir string) map[string]*helper.I18n { if !com.IsDir(srcDir) { return nil } langs := make(map[string]*helper.I18n) filepath.Walk(srcDir, func(p string, fi os.FileInfo, err error) error { if err != nil { return err } if fi.IsDir() { return nil } p = filepath.ToSlash(p) ext := filepath.Ext(p) if ext == ".toml" || ext == ".ini" { log15.Debug("Read|%s", p) b, err := ioutil.ReadFile(p) if err != nil { log15.Warn("Read|Lang|%s|%v", p, err) return nil } lang := strings.TrimSuffix(filepath.Base(p), ext) i18n, err := helper.NewI18n(lang, b, ext) if err != nil { log15.Warn("Read|Lang|%s|%v", p, err) return nil } langs[lang] = i18n } return nil }) return langs }
func LoadRepoConfig() { // Load .gitignore and license files. types := []string{"gitignore", "license"} typeFiles := make([][]string, 2) for i, t := range types { files := getAssetList(path.Join("conf", t)) customPath := path.Join(setting.CustomPath, "conf", t) if com.IsDir(customPath) { customFiles, err := com.StatDir(customPath) if err != nil { log.Fatal("Fail to get custom %s files: %v", t, err) } for _, f := range customFiles { if !com.IsSliceContainsStr(files, f) { files = append(files, f) } } } typeFiles[i] = files } LanguageIgns = typeFiles[0] Licenses = typeFiles[1] sort.Strings(LanguageIgns) sort.Strings(Licenses) }
func LoadRepoConfig() { workDir, err := base.ExecDir() if err != nil { qlog.Fatalf("Fail to get work directory: %s\n", err) } // Load .gitignore and license files. types := []string{"gitignore", "license"} typeFiles := make([][]string, 2) for i, t := range types { cfgPath := filepath.Join(workDir, "conf", t) files, err := com.StatDir(cfgPath) if err != nil { qlog.Fatalf("Fail to get default %s files: %v\n", t, err) } cfgPath = filepath.Join(workDir, "custom/conf/gitignore") if com.IsDir(cfgPath) { customFiles, err := com.StatDir(cfgPath) if err != nil { qlog.Fatalf("Fail to get custom %s files: %v\n", t, err) } for _, f := range customFiles { if !com.IsSliceContainsStr(files, f) { files = append(files, f) } } } typeFiles[i] = files } LanguageIgns = typeFiles[0] Licenses = typeFiles[1] }
func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { ctx.Data["Title"] = ctx.Tr("new_migrate") ctxUser := checkContextUser(ctx, form.Uid) if ctx.Written() { return } ctx.Data["ContextUser"] = ctxUser if ctx.HasError() { ctx.HTML(200, MIGRATE) return } // Remote address can be HTTP/HTTPS/Git URL or local path. // Note: remember to change api/v1/repo.go: MigrateRepo // FIXME: merge these two functions with better error handling remoteAddr := form.CloneAddr if strings.HasPrefix(form.CloneAddr, "http://") || strings.HasPrefix(form.CloneAddr, "https://") || strings.HasPrefix(form.CloneAddr, "git://") { u, err := url.Parse(form.CloneAddr) if err != nil { ctx.Data["Err_CloneAddr"] = true ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form) return } if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 { u.User = url.UserPassword(form.AuthUsername, form.AuthPassword) } remoteAddr = u.String() } else if !com.IsDir(remoteAddr) { ctx.Data["Err_CloneAddr"] = true ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form) return } repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) if err == nil { log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName) return } if repo != nil { if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil { log.Error(4, "DeleteRepository: %v", errDelete) } } if strings.Contains(err.Error(), "Authentication failed") || strings.Contains(err.Error(), " not found") || strings.Contains(err.Error(), "could not read Username") { ctx.Data["Err_Auth"] = true ctx.RenderWithErr(ctx.Tr("form.auth_failed", strings.Replace(err.Error(), ":"+form.AuthPassword+"@", ":<password>@", 1)), MIGRATE, &form) return } handleCreateError(ctx, err, "MigratePost", MIGRATE, &form) }
func LoadRepoConfig() { // Load .gitignore and license files and readme templates. types := []string{"gitignore", "license", "readme"} typeFiles := make([][]string, 3) for i, t := range types { files, err := bindata.AssetDir("conf/" + t) if err != nil { log.Fatal(4, "Fail to get %s files: %v", t, err) } customPath := path.Join(setting.CustomPath, "conf", t) if com.IsDir(customPath) { customFiles, err := com.StatDir(customPath) if err != nil { log.Fatal(4, "Fail to get custom %s files: %v", t, err) } for _, f := range customFiles { if !com.IsSliceContainsStr(files, f) { files = append(files, f) } } } typeFiles[i] = files } Gitignores = typeFiles[0] Licenses = typeFiles[1] Readmes = typeFiles[2] sort.Strings(Gitignores) sort.Strings(Licenses) sort.Strings(Readmes) }
func isRepositoryExist(e Engine, u *User, repoName string) (bool, error) { has, err := e.Get(&Repository{ OwnerID: u.Id, LowerName: strings.ToLower(repoName), }) return has && com.IsDir(RepoPath(u.Name, repoName)), err }
// create or read table in directory with schema. func NewTable(name string, directory string, sc *Schema, s Mapper) (t *Table, e error) { if !com.IsDir(directory) { if e = os.MkdirAll(directory, os.ModePerm); e != nil { return } } t = new(Table) t.name = name t.directory = directory t.s = s t.sc = sc // add or read pk index t.pkIndex, e = NewPkIndex(path.Join(directory, strings.ToLower(sc.PK+".pk")), s) if e != nil { return } // add or read value index t.valueIndex = make(map[string]*Index) for _, v := range sc.Index { t.valueIndex[v], e = NewIndex(strings.ToLower(name+"_"+v), path.Join(directory, strings.ToLower(v+".idx")), s) if e != nil { return } } // add or read chunk t.chunk, e = NewChunk(directory, s, sc.ChunkSize) return }
// init pk. // create files in first init. // read files after first init. func (p *PK) init() (e error) { if !com.IsDir(p.directory) { return p.firstInit() } // try to use optimized files if e = p.tryOptimized(); e != nil { return } // read auto increment if p.auto { p.autoFile = path.Join(p.directory, "auto.pk") e = p.ReadIncrement() if e != nil { return } } // read file in p.file, e = os.OpenFile(path.Join(p.directory, "pk.pk"), os.O_APPEND|os.O_RDWR, os.ModePerm) if e != nil { return } e = p.Read() //println("read pk items :", len(p.data)) if e != nil && e != io.EOF { return } e = nil return }
func (ms *MediaService) Upload(v interface{}) (*Result, error) { opt, ok := v.(MediaUploadOption) if !ok { return nil, ErrServiceFuncNeedType(ms.Upload, opt) } f, h, err := opt.Ctx.Req().FormFile(opt.FormName) if err != nil { return nil, err } defer f.Close() // check file size size, err := getUploadFileSize(f) if err != nil { return nil, err } if (size / 1024) > Setting.Media.MaxFileSize { return nil, ErrMediaTooLarge } // check file type ext := path.Ext(h.Filename) fileType := Setting.Media.GetType(ext) if fileType == 0 { return nil, ErrMediaDisAllowType } // hash file name, make dir now := time.Now() hashName := utils.Md5String(fmt.Sprintf("%d%s%d", opt.User, h.Filename, now.UnixNano())) + ext fileName := path.Join("static/upload", hashName) fileDir := path.Dir(fileName) if !com.IsDir(fileDir) { if err = os.MkdirAll(fileDir, os.ModePerm); err != nil { return nil, err } } if err = opt.Ctx.SaveToFile(opt.FormName, fileName); err != nil { return nil, err } // save media data media := &model.Media{ UserId: opt.User, Name: h.Filename, FileName: hashName, FilePath: fileName, FileSize: size, FileType: fileType, } if _, err := core.Db.Insert(media); err != nil { return nil, err } defer ms.msgUpload(media) return newResult(ms.Upload, media), nil }
func TarGzDownload(ctx *middleware.Context, params martini.Params) { commitId := ctx.Repo.CommitId archivesPath := filepath.Join(ctx.Repo.GitRepo.Path, "archives/targz") if !com.IsDir(archivesPath) { if err := os.MkdirAll(archivesPath, 0755); err != nil { ctx.Handle(404, "TarGzDownload -> os.Mkdir(archivesPath)", err) return } } archivePath := filepath.Join(archivesPath, commitId+".tar.gz") if com.IsFile(archivePath) { ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+".tar.gz") return } err := ctx.Repo.Commit.CreateArchive(archivePath, git.AT_TARGZ) if err != nil { ctx.Handle(404, "TarGzDownload -> CreateArchive "+archivePath, err) return } ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+".tar.gz") }
// IsRepositoryExist returns true if the repository with given name under user has already existed. func IsRepositoryExist(u *User, repoName string) bool { has, _ := x.Get(&Repository{ OwnerId: u.Id, LowerName: strings.ToLower(repoName), }) return has && com.IsDir(RepoPath(u.Name, repoName)) }
func ExampleIsDir() { if com.IsDir("files") { fmt.Println("directory 'files' exists") return } fmt.Println("'files' is not a directory or does not exist") }
// load theme by name func (r *Render) Load(name string) (*Theme, error) { dir := path.Join(r.dir, name) if !com.IsDir(dir) { return nil, ErrRenderDirMissing } theme := NewTheme(dir, r.funcMap, r.extensions) return theme, theme.Load() }
// Create creates git deploy settings in Context func (g *Git) Create(ctx *cli.Context) (Method, error) { g2 := &Git{ Repo: ctx.String("repo"), Message: ctx.String("message"), Local: ctx.String("local"), Branch: ctx.String("branch"), } if !com.IsDir(g2.Local) { return nil, fmt.Errorf("directory '%s' is not existed", g2.Local) } if !com.IsDir(g2.Repo) || !com.IsDir(filepath.Join(g2.Repo, ".git")) { return nil, fmt.Errorf("directory '%s' is not a git repository", g2.Repo) } if g2.Message == "" { g2.Message = "PUGO BUILD UPDATE - {t}" } return g2, nil }
func ReloadDocs() error { tocLocker.Lock() defer tocLocker.Unlock() localRoot := setting.Docs.Target // Fetch docs from remote. if setting.Docs.Type.IsRemote() { localRoot = docsRoot absRoot, err := filepath.Abs(localRoot) if err != nil { return fmt.Errorf("filepath.Abs: %v", err) } // Clone new or pull to update. if com.IsDir(absRoot) { stdout, stderr, err := com.ExecCmdDir(absRoot, "git", "pull") if err != nil { return fmt.Errorf("Fail to update docs from remote source(%s): %v - %s", setting.Docs.Target, err, stderr) } fmt.Println(stdout) } else { os.MkdirAll(filepath.Dir(absRoot), os.ModePerm) stdout, stderr, err := com.ExecCmd("git", "clone", setting.Docs.Target, absRoot) if err != nil { return fmt.Errorf("Fail to clone docs from remote source(%s): %v - %s", setting.Docs.Target, err, stderr) } fmt.Println(stdout) } } if !com.IsDir(localRoot) { return fmt.Errorf("Documentation not found: %s - %s", setting.Docs.Type, localRoot) } tocs, err := initToc(localRoot) if err != nil { return fmt.Errorf("initToc: %v", err) } initDocs(tocs, localRoot) Tocs = tocs return reloadProtects(localRoot) }
// build site function func buildSite(opt *builder.BuildOption, mustWatch bool) func(ctx *cli.Context) { return func(ctx *cli.Context) { // ctrl+C capture signalChan := make(chan os.Signal) signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) opt.Theme = ctx.String("theme") b := builder.New(opt) if b.Error != nil { log15.Crit("Builder.Fail", "error", b.Error.Error()) } targetDir := ctx.String("dest") if targetDir == "template" || targetDir == "source" { log15.Crit("Builder.Fail", "error", "destination directory should not be 'template' or 'source'") } // detect deploy callback way, err := deploy.Detect(ctx) if err != nil { log15.Crit("Deploy.Fail", "error", err.Error()) } if way != nil { targetDir = way.Dir() opt.After(func(b *builder.Builder, ctx *builder.Context) error { t := time.Now() if err := way.Do(b, ctx); err != nil { return err } log15.Info("Deploy.Finish", "duration", time.Since(t)) return nil }) } // make directory log15.Info("Dest." + targetDir) if com.IsDir(targetDir) { log15.Warn("Dest." + targetDir + ".Existed") } // auto watching b.Build(targetDir) if err := b.Context().Error; err != nil { log15.Crit("Build.Fail", "error", err.Error()) } if ctx.Bool("watch") || mustWatch { b.Watch(targetDir) <-signalChan } log15.Info("Build.Close") } }
// IsRepositoryExist returns true if the repository with given name under user has already existed. func IsRepositoryExist(user *User, repoName string) (bool, error) { repo := Repository{OwnerId: user.Id} has, err := orm.Where("lower_name = ?", strings.ToLower(repoName)).Get(&repo) if err != nil { return has, err } else if !has { return false, nil } return com.IsDir(RepoPath(user.Name, repoName)), nil }
// create storage in directory. // it doesn't load data, // util call Sync(...) to load data. func NewStorage(directory string) (s *Storage, e error) { if !com.IsDir(directory) { if e = os.MkdirAll(directory, os.ModePerm); e != nil { return } } s = &Storage{ directory: directory, tables: make(map[reflect.Type]*Table), } return }
// ReadPosts read posts files in srcDir/post func ReadPosts(ctx *Context) ([]*model.Post, error) { srcDir := ctx.SrcPostDir() if !com.IsDir(srcDir) { return nil, fmt.Errorf("posts directory '%s' is missing", srcDir) } log15.Info("Read|Posts|%s", srcDir) // try load post.toml or post.ini to read total meta file var ( err error postMeta = make(map[string]*model.Post) ) for t, f := range model.ShouldPostMetaFiles() { file := filepath.Join(ctx.SrcDir(), f) if !com.IsFile(file) { continue } postMeta, err = model.NewPostsFrontMatter(file, t) if err != nil { return nil, err } log15.Debug("Read|PostMeta|%s", file) break } var posts []*model.Post err = filepath.Walk(srcDir, func(p string, fi os.FileInfo, err error) error { if err != nil { return err } if fi.IsDir() { return nil } p = filepath.ToSlash(p) if filepath.Ext(p) == ".md" { metaKey := strings.TrimPrefix(p, filepath.ToSlash(srcDir+"/")) log15.Debug("Read|%s|%v", p, postMeta[metaKey] != nil) post, err := model.NewPostOfMarkdown(p, postMeta[metaKey]) if err != nil { log15.Warn("Read|Post|%s|%v", p, err) return nil } else if post != nil && !post.Draft { posts = append(posts, post) } if post.Draft == true { log15.Warn("Draft|%s", p) } } return nil }) sort.Sort(model.Posts(posts)) return posts, err }
func (bs *BackupService) Backup(v interface{}) (*Result, error) { if bs.IsBackupDoing { return nil, ErrBackupDoing } opt, ok := v.(BackupOption) if !ok { return nil, ErrServiceFuncNeedType(bs.Backup, opt) } root, err := os.Getwd() if err != nil { return nil, err } bs.IsBackupDoing = true defer func() { bs.IsBackupDoing = false }() fileName := fmt.Sprintf("%s/%s.zip", core.BackupDirectory, time.Now().Format("20060102150405")) dirName := path.Dir(fileName) if !com.IsDir(dirName) { if err := os.MkdirAll(dirName, os.ModePerm); err != nil { return nil, err } } fileWriter, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_SYNC, os.ModePerm) if err != nil { return nil, err } defer fileWriter.Close() zip.Verbose = false zipWriter := zip.New(fileWriter) defer zipWriter.Close() if opt.WithBasic { zipWriter.AddFile("config.ini", path.Join(root, "config.ini")) } if opt.WithData { zipWriter.AddDir("data", path.Join(root, "data")) } if opt.WithStatic { zipWriter.AddDir("static", path.Join(root, "static")) } if opt.WithTheme { zipWriter.AddDir("theme", path.Join(root, "theme")) } if err := zipWriter.Flush(); err != nil { return nil, err } go bs.msgCreate(fileName) return newResult(bs.Backup, &fileName), nil }
// SyncDir sync directory files to syncer's directory func (s *Syncer) SyncDir(dir string, opt *DirOption) error { if !com.IsDir(dir) { return nil } var ( relFile string dstFile string ) return filepath.Walk(dir, func(p string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } if opt != nil && opt.Filter != nil { if !opt.Filter(p) { return nil } } relFile, _ = filepath.Rel(dir, p) if opt != nil { if len(opt.Ignore) > 0 { for _, ignore := range opt.Ignore { if strings.HasPrefix(relFile, ignore) { return nil } } } if opt.Prefix != "" { relFile = filepath.Join(opt.Prefix, relFile) } } dstFile = filepath.Join(s.dir, relFile) if com.IsFile(dstFile) { hash1, _ := helper.Md5File(p) hash2, _ := helper.Md5File(dstFile) if hash1 == hash2 { log15.Debug("Sync|Keep|%s", dstFile) s.SetSynced(dstFile) return nil } } os.MkdirAll(filepath.Dir(dstFile), os.ModePerm) if err := com.Copy(p, dstFile); err != nil { return err } log15.Debug("Sync|Write|%s", dstFile) s.SetSynced(dstFile) return nil }) }