|
@ -30,13 +30,13 @@ import ( |
|
|
"github.com/urfave/cli/v2" |
|
|
"github.com/urfave/cli/v2" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
// Version is the current version of distribusi-go
|
|
|
// Version is the current version of distribusi-go.
|
|
|
var Version string |
|
|
var Version string |
|
|
|
|
|
|
|
|
// Commit is the current commit of distribusi-go
|
|
|
// Commit is the current commit of distribusi-go.
|
|
|
var Commit string |
|
|
var Commit string |
|
|
|
|
|
|
|
|
// port is the web server port
|
|
|
// port is the web server port.
|
|
|
var port = ":3000" |
|
|
var port = ":3000" |
|
|
|
|
|
|
|
|
// exiftooInstalled tells us if the exiftool binary is installed or not.
|
|
|
// exiftooInstalled tells us if the exiftool binary is installed or not.
|
|
@ -107,13 +107,13 @@ var htmlBody = ` |
|
|
// fileType is a file type identifier such as "image" or "audio".
|
|
|
// fileType is a file type identifier such as "image" or "audio".
|
|
|
type fileType = string |
|
|
type fileType = string |
|
|
|
|
|
|
|
|
// subType is a more specific file type identifier compared to fileType, such as "gif" and "mp4".
|
|
|
// subType is a more specific file type identifier compared to fileType, such as "gif" or "mp4".
|
|
|
type subType = string |
|
|
type subType = string |
|
|
|
|
|
|
|
|
// htmlTag is an appropriate html tag element for a specific fileType & subType.
|
|
|
// htmlTag is an appropriate HTML tag element for a specific fileType & subType.
|
|
|
type htmlTag = string |
|
|
type htmlTag = string |
|
|
|
|
|
|
|
|
// htmlTags is a fileType/subType to htmlTag mapping for HTML generation purposes.
|
|
|
// htmlTags is a fileType/subType to htmlTag mapping.
|
|
|
var htmlTags = map[fileType]map[subType]htmlTag{ |
|
|
var htmlTags = map[fileType]map[subType]htmlTag{ |
|
|
"text": { |
|
|
"text": { |
|
|
"html": `<section id="%s">%s</section>`, |
|
|
"html": `<section id="%s">%s</section>`, |
|
@ -154,7 +154,7 @@ var htmlTags = map[fileType]map[subType]htmlTag{ |
|
|
}, |
|
|
}, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// main is the command-line entrypoint.
|
|
|
// main is the command-line entrypoint for the program.
|
|
|
func main() { |
|
|
func main() { |
|
|
if Version == "" { |
|
|
if Version == "" { |
|
|
Version = "dev" |
|
|
Version = "dev" |
|
@ -458,7 +458,7 @@ func distribusify(c *cli.Context, root string, ignore []string) error { |
|
|
progress.Add(1) |
|
|
progress.Add(1) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if err := writeIndex(absPath, html, c.String("css")); err != nil { |
|
|
if err := mkIndex(absPath, html, c.String("css")); err != nil { |
|
|
logrus.Debugf("unable to generated %s, skipping", path.Join(absPath, "index.html")) |
|
|
logrus.Debugf("unable to generated %s, skipping", path.Join(absPath, "index.html")) |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
@ -495,8 +495,7 @@ func removeIndex(fpath string) error { |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// getMtype determines file mimetype which helps to arrange HTML tags
|
|
|
// getMtype reads file mimetypes directlry from files.
|
|
|
// appropriate for the file type.
|
|
|
|
|
|
func getMtype(fpath string) (string, error) { |
|
|
func getMtype(fpath string) (string, error) { |
|
|
mtype, err := mimetype.DetectFile(fpath) |
|
|
mtype, err := mimetype.DetectFile(fpath) |
|
|
if err != nil { |
|
|
if err != nil { |
|
@ -507,7 +506,7 @@ func getMtype(fpath string) (string, error) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// genThumb generates an in-memory image thumbnail and encodes it into a base64
|
|
|
// genThumb generates an in-memory image thumbnail and encodes it into a base64
|
|
|
// representation which is suitable for embedding in HTML pages.
|
|
|
// representation which is suitable for embedding in HTML pages.
|
|
|
func genThumb(c *cli.Context, fpath, caption string) (string, error) { |
|
|
func genThumb(c *cli.Context, fpath, caption string) (string, error) { |
|
|
imgSrc, err := imaging.Open(fpath, imaging.AutoOrientation(true)) |
|
|
imgSrc, err := imaging.Open(fpath, imaging.AutoOrientation(true)) |
|
|
if err != nil { |
|
|
if err != nil { |
|
@ -526,8 +525,8 @@ func genThumb(c *cli.Context, fpath, caption string) (string, error) { |
|
|
return imgBase64Str, nil |
|
|
return imgBase64Str, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// getCaption retrieves an embedded image caption via exif-tool. If not
|
|
|
// getCaption retrieves an embedded image caption via exif-tool. If exiftool is
|
|
|
// exiftool is installed, we gracefully bail out. The caller is responsible for
|
|
|
// not installed, we gracefully bail out. The caller is responsible for
|
|
|
// handling the alternative.
|
|
|
// handling the alternative.
|
|
|
func getCaption(c *cli.Context, fpath string) (string, error) { |
|
|
func getCaption(c *cli.Context, fpath string) (string, error) { |
|
|
var caption string |
|
|
var caption string |
|
@ -669,7 +668,9 @@ func mkHref(c *cli.Context, fpath string, mtype string) (bool, string, error) { |
|
|
return unknown, href, nil |
|
|
return unknown, href, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// mkDiv cosntructs a HTML div for inclusion in the generated index.html.
|
|
|
// mkDiv cosntructs a HTML div for inclusion in the generated index.html. These
|
|
|
|
|
|
// dives are used to wrap the elements that appear on generated pages with
|
|
|
|
|
|
// relevant identifiers for convenient styling.
|
|
|
func mkDiv(c *cli.Context, mtype string, href, fname string, unknown bool) (string, error) { |
|
|
func mkDiv(c *cli.Context, mtype string, href, fname string, unknown bool) (string, error) { |
|
|
var div string |
|
|
var div string |
|
|
var divTemplate string |
|
|
var divTemplate string |
|
@ -716,8 +717,8 @@ func mkDiv(c *cli.Context, mtype string, href, fname string, unknown bool) (stri |
|
|
return div, nil |
|
|
return div, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// writeIndex writes a new index.html.
|
|
|
// mkIndex writes a new generated index.html file to the file system.
|
|
|
func writeIndex(fpath string, html []string, styles string) error { |
|
|
func mkIndex(fpath string, html []string, styles string) error { |
|
|
body := fmt.Sprintf(htmlBody, generatedInDistribusi, "", strings.Join(html, "\n")) |
|
|
body := fmt.Sprintf(htmlBody, generatedInDistribusi, "", strings.Join(html, "\n")) |
|
|
|
|
|
|
|
|
if styles != "" { |
|
|
if styles != "" { |
|
@ -769,7 +770,11 @@ func writeIndex(fpath string, html []string, styles string) error { |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// serveHTTP serves a web server for browsing distribusi.
|
|
|
// serveHTTP serves a web server for browsing distribusi generated files. This
|
|
|
|
|
|
// is mostly convenient when doing development work or showing something
|
|
|
|
|
|
// quickly on your work station. It should be fine to serve "for production"
|
|
|
|
|
|
// though too as it uses the stdlib Go HTTP server. Distribusi still works just
|
|
|
|
|
|
// fine with the usual Nginx, Apache, etc.
|
|
|
func serveHTTP(fpath string) error { |
|
|
func serveHTTP(fpath string) error { |
|
|
fs := http.FileServer(http.Dir(fpath)) |
|
|
fs := http.FileServer(http.Dir(fpath)) |
|
|
http.Handle("/", fs) |
|
|
http.Handle("/", fs) |
|
@ -783,7 +788,9 @@ func serveHTTP(fpath string) error { |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// wipeGeneratedFiles removes all distribusi generated files.
|
|
|
// wipeGeneratedFiles removes all distribusi generated files under a file
|
|
|
|
|
|
// system path. We do take care to avoid deleting files that distribusi has not
|
|
|
|
|
|
// generated by checking their contents.
|
|
|
func wipeGeneratedFiles(dir string) error { |
|
|
func wipeGeneratedFiles(dir string) error { |
|
|
if err := filepath.WalkDir(dir, func(fpath string, dirEntry fs.DirEntry, err error) error { |
|
|
if err := filepath.WalkDir(dir, func(fpath string, dirEntry fs.DirEntry, err error) error { |
|
|
fname := filepath.Base(fpath) |
|
|
fname := filepath.Base(fpath) |
|
@ -801,7 +808,9 @@ func wipeGeneratedFiles(dir string) error { |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// shouldSkip checks if paths should be skipped over.
|
|
|
// shouldSkip checks if a specific file system path should be skipped over when
|
|
|
|
|
|
// running distribusi file generation. This might happen due to being a hidden
|
|
|
|
|
|
// directory or matching a pattern provided by the end-user.
|
|
|
func shouldSkip(c *cli.Context, fpath string, ignore []string) (bool, error) { |
|
|
func shouldSkip(c *cli.Context, fpath string, ignore []string) (bool, error) { |
|
|
for _, pattern := range ignore { |
|
|
for _, pattern := range ignore { |
|
|
match, err := filepath.Match(pattern, filepath.Base(fpath)) |
|
|
match, err := filepath.Match(pattern, filepath.Base(fpath)) |
|
@ -827,7 +836,9 @@ func shouldSkip(c *cli.Context, fpath string, ignore []string) (bool, error) { |
|
|
return false, nil |
|
|
return false, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// getLogFile creates a new log file for debug output.
|
|
|
// getLogFile creates a new log file for debug output. We do this because the
|
|
|
|
|
|
// standard debug listing is quite verbose and it is often more convenient to
|
|
|
|
|
|
// read it from file. Also handier for bug reports.
|
|
|
func getLogFile() (*os.File, error) { |
|
|
func getLogFile() (*os.File, error) { |
|
|
cTime := time.Now() |
|
|
cTime := time.Now() |
|
|
timeNow := fmt.Sprintf("%v-%v-%v", cTime.Hour(), cTime.Minute(), cTime.Second()) |
|
|
timeNow := fmt.Sprintf("%v-%v-%v", cTime.Hour(), cTime.Minute(), cTime.Second()) |
|
@ -843,7 +854,8 @@ func getLogFile() (*os.File, error) { |
|
|
return file, nil |
|
|
return file, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// mkProgressBar creates a progress bar.
|
|
|
// mkProgressBar creates a customised progress bar. This bar is used to give
|
|
|
|
|
|
// real-time updates on the progress of running distribusi.
|
|
|
func mkProgressBar() *progressbar.ProgressBar { |
|
|
func mkProgressBar() *progressbar.ProgressBar { |
|
|
bar := progressbar.NewOptions(-1, |
|
|
bar := progressbar.NewOptions(-1, |
|
|
progressbar.OptionSetDescription("distribusifying..."), |
|
|
progressbar.OptionSetDescription("distribusifying..."), |
|
@ -852,5 +864,6 @@ func mkProgressBar() *progressbar.ProgressBar { |
|
|
progressbar.OptionShowCount(), |
|
|
progressbar.OptionShowCount(), |
|
|
progressbar.OptionSpinnerType(9), |
|
|
progressbar.OptionSpinnerType(9), |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
return bar |
|
|
return bar |
|
|
} |
|
|
} |
|
|