mirror of
https://github.com/gen2brain/cbconvert
synced 2025-10-14 02:28:51 +02:00
Add support for adding/removing files
This commit is contained in:
@@ -158,9 +158,13 @@ This is what it looks like in the PCManFM file manager:
|
|||||||
--cover
|
--cover
|
||||||
Print cover name (default "false")
|
Print cover name (default "false")
|
||||||
--comment
|
--comment
|
||||||
Print zip comment (default "false")
|
Print zip comment (default "false")
|
||||||
--comment-body
|
--comment-body
|
||||||
Set zip comment (default "")
|
Set zip comment (default "")
|
||||||
|
--file-add
|
||||||
|
Add file to archive (default "")
|
||||||
|
--file-remove
|
||||||
|
Remove file(s) from archive (glob pattern, i.e. *.xml) (default "")
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
173
cbconvert.go
173
cbconvert.go
@@ -104,6 +104,10 @@ type Options struct {
|
|||||||
Comment bool
|
Comment bool
|
||||||
// ZIP comment body
|
// ZIP comment body
|
||||||
CommentBody string
|
CommentBody string
|
||||||
|
// Add file
|
||||||
|
FileAdd string
|
||||||
|
// Remove file
|
||||||
|
FileRemove string
|
||||||
// Output file
|
// Output file
|
||||||
Outfile string
|
Outfile string
|
||||||
// Output directory
|
// Output directory
|
||||||
@@ -980,6 +984,165 @@ func (c *Convertor) archiveSetComment(fileName, commentBody string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// archiveFileAdd adds file to archive.
|
||||||
|
func (c *Convertor) archiveFileAdd(fileName, newFileName string) error {
|
||||||
|
zr, err := zip.OpenReader(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
defer zr.Close()
|
||||||
|
|
||||||
|
zf, err := os.CreateTemp(os.TempDir(), "cbc")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpName := zf.Name()
|
||||||
|
defer os.Remove(tmpName)
|
||||||
|
|
||||||
|
zw := zip.NewWriter(zf)
|
||||||
|
|
||||||
|
for _, item := range zr.File {
|
||||||
|
if item.Name == newFileName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ir, err := item.OpenRaw()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
item := item
|
||||||
|
|
||||||
|
it, err := zw.CreateRaw(&item.FileHeader)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(it, ir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(newFileName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newData, err := os.ReadFile(newFileName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
zipInfo, err := zip.FileInfoHeader(info)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
zipInfo.Method = zip.Deflate
|
||||||
|
w, err := zw.CreateHeader(zipInfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write(newData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zw.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zf.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(tmpName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(fileName, data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileAdd: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// archiveFileRemove removes files from archive.
|
||||||
|
func (c *Convertor) archiveFileRemove(fileName, pattern string) error {
|
||||||
|
zr, err := zip.OpenReader(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
defer zr.Close()
|
||||||
|
|
||||||
|
zf, err := os.CreateTemp(os.TempDir(), "cbc")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpName := zf.Name()
|
||||||
|
defer os.Remove(tmpName)
|
||||||
|
|
||||||
|
zw := zip.NewWriter(zf)
|
||||||
|
|
||||||
|
for _, item := range zr.File {
|
||||||
|
matched, err := filepath.Match(pattern, item.Name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matched {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ir, err := item.OpenRaw()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
item := item
|
||||||
|
|
||||||
|
it, err := zw.CreateRaw(&item.FileHeader)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(it, ir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zw.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zf.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(tmpName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(fileName, data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("archiveFileRemove: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// coverArchive extracts cover from archive.
|
// coverArchive extracts cover from archive.
|
||||||
func (c *Convertor) coverArchive(fileName string) (image.Image, error) {
|
func (c *Convertor) coverArchive(fileName string) (image.Image, error) {
|
||||||
var images []string
|
var images []string
|
||||||
@@ -1560,6 +1723,16 @@ func (c *Convertor) Meta(fileName string) (any, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s: %w", fileName, err)
|
return nil, fmt.Errorf("%s: %w", fileName, err)
|
||||||
}
|
}
|
||||||
|
case c.Opts.FileAdd != "":
|
||||||
|
err := c.archiveFileAdd(fileName, c.Opts.FileAdd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s: %w", fileName, err)
|
||||||
|
}
|
||||||
|
case c.Opts.FileRemove != "":
|
||||||
|
err := c.archiveFileRemove(fileName, c.Opts.FileRemove)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s: %w", fileName, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", nil
|
return "", nil
|
||||||
|
@@ -194,6 +194,8 @@ func parseFlags() (cbconvert.Options, []string) {
|
|||||||
meta.BoolVar(&opts.Cover, "cover", false, "Print cover name")
|
meta.BoolVar(&opts.Cover, "cover", false, "Print cover name")
|
||||||
meta.BoolVar(&opts.Comment, "comment", false, "Print zip comment")
|
meta.BoolVar(&opts.Comment, "comment", false, "Print zip comment")
|
||||||
meta.StringVar(&opts.CommentBody, "comment-body", "", "Set zip comment")
|
meta.StringVar(&opts.CommentBody, "comment-body", "", "Set zip comment")
|
||||||
|
meta.StringVar(&opts.FileAdd, "file-add", "", "Add file to archive")
|
||||||
|
meta.StringVar(&opts.FileRemove, "file-remove", "", "Remove file from archive (glob pattern, i.e. *.xml)")
|
||||||
|
|
||||||
convert.Usage = func() {
|
convert.Usage = func() {
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Usage: %s <command> [<flags>] [file1 dir1 ... fileOrDirN]\n\n", filepath.Base(os.Args[0]))
|
_, _ = fmt.Fprintf(os.Stderr, "Usage: %s <command> [<flags>] [file1 dir1 ... fileOrDirN]\n\n", filepath.Base(os.Args[0]))
|
||||||
|
Reference in New Issue
Block a user