| 1128 | } |
| 1129 | |
| 1130 | func ZipFile(ctx context.Context, files []archiver.File, dst afero.File, progress func(current, total int, message string)) error { |
| 1131 | zw := zip.NewWriter(dst) |
| 1132 | defer zw.Close() |
| 1133 | |
| 1134 | total := len(files) |
| 1135 | for i, file := range files { |
| 1136 | if ctx != nil { |
| 1137 | select { |
| 1138 | case <-ctx.Done(): |
| 1139 | return ctx.Err() |
| 1140 | default: |
| 1141 | } |
| 1142 | } |
| 1143 | hdr, err := zip.FileInfoHeader(file) |
| 1144 | if err != nil { |
| 1145 | return err |
| 1146 | } |
| 1147 | hdr.Method = zip.Deflate |
| 1148 | hdr.Name = file.NameInArchive |
| 1149 | if file.IsDir() { |
| 1150 | if !strings.HasSuffix(hdr.Name, "/") { |
| 1151 | hdr.Name += "/" |
| 1152 | } |
| 1153 | } |
| 1154 | w, err := zw.CreateHeader(hdr) |
| 1155 | if err != nil { |
| 1156 | return err |
| 1157 | } |
| 1158 | if file.IsDir() { |
| 1159 | continue |
| 1160 | } |
| 1161 | |
| 1162 | if file.LinkTarget != "" { |
| 1163 | _, err = w.Write([]byte(filepath.ToSlash(file.LinkTarget))) |
| 1164 | if err != nil { |
| 1165 | return err |
| 1166 | } |
| 1167 | } else { |
| 1168 | fileReader, err := file.Open() |
| 1169 | if err != nil { |
| 1170 | return err |
| 1171 | } |
| 1172 | _, err = io.Copy(w, newContextReader(ctx, fileReader)) |
| 1173 | fileReader.Close() |
| 1174 | if err != nil { |
| 1175 | return err |
| 1176 | } |
| 1177 | } |
| 1178 | if progress != nil { |
| 1179 | progress(i+1, total, file.NameInArchive) |
| 1180 | } |
| 1181 | } |
| 1182 | return nil |
| 1183 | } |
| 1184 | |
| 1185 | type contextReader struct { |
| 1186 | ctx context.Context |