<commit_before>package fitnesse.wiki.fs;

import fitnesse.wiki.NoSuchVersionException;
import fitnesse.wiki.PageData;
import fitnesse.wiki.VersionInfo;
import fitnesse.wiki.WikiPageProperties;
import util.StreamReader;

import java.io.*;
import java.util.*;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import static fitnesse.wiki.fs.SimpleFileVersionsController.contentFilename;
import static fitnesse.wiki.fs.SimpleFileVersionsController.propertiesFilename;

public class ZipFileVersionsController implements VersionsController {

  public static final Pattern ZIP_FILE_PATTERN = Pattern.compile("(\\S+)?\\d+(~\\d+)?\\.zip");

  private int daysTillVersionsExpire = 14;

  private VersionsController persistence;

  public ZipFileVersionsController() {
    // Fix on Disk file system, since that's what ZipFileVersionsController can deal with.
    persistence = new SimpleFileVersionsController(new DiskFileSystem());
  }

  @Override
  public void setHistoryDepth(int historyDepth) {
    daysTillVersionsExpire = historyDepth;
  }

  @Override
  public PageData getRevisionData(final FileSystemPage page, final String label) {
    if (label == null) {
      return persistence.getRevisionData(page, null);
    }
    final String filename = page.getFileSystemPath() + "/" + label + ".zip";
    final File file = new File(filename);
    if (!file.exists()) {
      throw new NoSuchVersionException("There is no version '" + label + "'");
    }

    ZipFile zipFile = null;
    try {
      final PageData data = new PageData(page);
      zipFile = new ZipFile(file);
      loadVersionContent(zipFile, data);
      loadVersionAttributes(zipFile, data);
      return data;
    } catch (Throwable th) {
      throw new RuntimeException(th);
    } finally {
      try {
        if (zipFile != null) {
          zipFile.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  @Override
  public Collection<ZipFileVersionInfo> history(final FileSystemPage page) {
    final File dir = new File(page.getFileSystemPath());
    final File[] files = dir.listFiles();
    final Set<ZipFileVersionInfo> versions = new HashSet<ZipFileVersionInfo>();
    if (files != null) {
      for (final File file : files) {
        if (isVersionFile(file)) {
          versions.add(ZipFileVersionInfo.makeVersionInfo(file));
        }
      }
    }
    return versions;
  }

  @Override
  public VersionInfo makeVersion(final FileSystemPage page, final PageData data) {
    makeZipVersion(page, page.getData());
    return persistence.makeVersion(page, data);
  }

  @Override
  public VersionInfo getCurrentVersion(FileSystemPage page) {
    return persistence.getCurrentVersion(page);
  }

  @Override
  public void delete(FileSystemPage page) {
    persistence.delete(page);
  }

  protected VersionInfo makeZipVersion(FileSystemPage page, PageData data) {
    final String dirPath = page.getFileSystemPath();
    final Set<File> filesToZip = getFilesToZip(dirPath);

    final VersionInfo version = VersionInfo.makeVersionInfo(data);

    if (filesToZip.size() == 0) {
      return version;
    }
    ZipOutputStream zos = null;
    try {
      final String filename = makeVersionFileName(page, version.getName());
      zos = new ZipOutputStream(new FileOutputStream(filename));
      for (File aFilesToZip : filesToZip) {
        addToZip(aFilesToZip, zos);
      }
      return version;
    } catch (Throwable th) {
      throw new RuntimeException(th);
    } finally {
      try {
        if (zos != null) {
          zos.finish();
          zos.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      pruneVersions(page, history(page));
    }
  }

  private void addToZip(final File file, final ZipOutputStream zos) throws IOException {
    final ZipEntry entry = new ZipEntry(file.getName());
    zos.putNextEntry(entry);
    final FileInputStream is = new FileInputStream(file);
    final int size = (int) file.length();
    final byte[] bytes = new byte[size];
    is.read(bytes);
    is.close();
    zos.write(bytes, 0, size);
  }

  private Set<File> getFilesToZip(final String dirPath) {
    final Set<File> filesToZip = new HashSet<File>();
    final File dir = new File(dirPath);
    final File[] files = dir.listFiles();
    if (files == null) {
      return filesToZip;
    }
    for (final File file : files) {
      if (!(isVersionFile(file) || file.isDirectory())) {
        filesToZip.add(file);
      }
    }
    return filesToZip;
  }

  private boolean isVersionFile(final File file) {
    return ZIP_FILE_PATTERN.matcher(file.getName()).matches();
  }

  private void loadVersionAttributes(final ZipFile zipFile, final PageData data) {
    final ZipEntry attributes = zipFile.getEntry(propertiesFilename);
    if (attributes != null) {
      InputStream attributeIS = null;
      try {
        attributeIS = zipFile.getInputStream(attributes);
        final WikiPageProperties props = new WikiPageProperties(attributeIS);
        data.setProperties(props);
      } catch (Throwable th) {
        throw new RuntimeException(th);
      } finally {
        try {
          if (attributeIS != null) {
            attributeIS.close();
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
      }<commit_msg>Make ZipFileVersionsController be more explicit about the content that's saved.<commit_after>package fitnesse.wiki.fs;

import fitnesse.wiki.NoSuchVersionException;
import fitnesse.wiki.PageData;
import fitnesse.wiki.VersionInfo;
import fitnesse.wiki.WikiPageProperties;
import util.StreamReader;

import java.io.*;
import java.util.*;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import static fitnesse.wiki.fs.SimpleFileVersionsController.contentFilename;
import static fitnesse.wiki.fs.SimpleFileVersionsController.propertiesFilename;

public class ZipFileVersionsController implements VersionsController {

  public static final Pattern ZIP_FILE_PATTERN = Pattern.compile("(\\S+)?\\d+(~\\d+)?\\.zip");

  private int daysTillVersionsExpire = 14;

  private VersionsController persistence;

  public ZipFileVersionsController() {
    // Fix on Disk file system, since that's what ZipFileVersionsController can deal with.
    persistence = new SimpleFileVersionsController(new DiskFileSystem());
  }

  @Override
  public void setHistoryDepth(int historyDepth) {
    daysTillVersionsExpire = historyDepth;
  }

  @Override
  public PageData getRevisionData(final FileSystemPage page, final String label) {
    if (label == null) {
      return persistence.getRevisionData(page, null);
    }
    final String filename = page.getFileSystemPath() + "/" + label + ".zip";
    final File file = new File(filename);
    if (!file.exists()) {
      throw new NoSuchVersionException("There is no version '" + label + "'");
    }

    ZipFile zipFile = null;
    try {
      final PageData data = new PageData(page);
      zipFile = new ZipFile(file);
      loadVersionContent(zipFile, data);
      loadVersionAttributes(zipFile, data);
      return data;
    } catch (Throwable th) {
      throw new RuntimeException(th);
    } finally {
      try {
        if (zipFile != null) {
          zipFile.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  @Override
  public Collection<ZipFileVersionInfo> history(final FileSystemPage page) {
    final File dir = new File(page.getFileSystemPath());
    final File[] files = dir.listFiles();
    final Set<ZipFileVersionInfo> versions = new HashSet<ZipFileVersionInfo>();
    if (files != null) {
      for (final File file : files) {
        if (isVersionFile(file)) {
          versions.add(ZipFileVersionInfo.makeVersionInfo(file));
        }
      }
    }
    return versions;
  }

  @Override
  public VersionInfo makeVersion(final FileSystemPage page, final PageData data) {
    makeZipVersion(page, page.getData());
    return persistence.makeVersion(page, data);
  }

  @Override
  public VersionInfo getCurrentVersion(FileSystemPage page) {
    return persistence.getCurrentVersion(page);
  }

  @Override
  public void delete(FileSystemPage page) {
    persistence.delete(page);
  }

  protected VersionInfo makeZipVersion(FileSystemPage page, PageData data) {
    final String dirPath = page.getFileSystemPath();
    final File contentFile = new File(dirPath, contentFilename);
    final File propertiesFile = new File(dirPath, propertiesFilename);
    final VersionInfo version = VersionInfo.makeVersionInfo(data);

    if (!contentFile.exists() || !propertiesFile.exists()) {
      return version;
    }

    ZipOutputStream zos = null;
    try {
      final String filename = makeVersionFileName(page, version.getName());
      zos = new ZipOutputStream(new FileOutputStream(filename));
      addToZip(contentFile, zos);
      addToZip(propertiesFile, zos);
      return version;
    } catch (Throwable th) {
      throw new RuntimeException(th);
    } finally {
      try {
        if (zos != null) {
          zos.finish();
          zos.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      pruneVersions(page, history(page));
    }
  }

  private void addToZip(final File file, final ZipOutputStream zos) throws IOException {
    final ZipEntry entry = new ZipEntry(file.getName());
    zos.putNextEntry(entry);
    final FileInputStream is = new FileInputStream(file);
    final int size = (int) file.length();
    final byte[] bytes = new byte[size];
    is.read(bytes);
    is.close();
    zos.write(bytes, 0, size);
  }

  private boolean isVersionFile(final File file) {
    return ZIP_FILE_PATTERN.matcher(file.getName()).matches();
  }

  private void loadVersionAttributes(final ZipFile zipFile, final PageData data) {
    final ZipEntry attributes = zipFile.getEntry(propertiesFilename);
    if (attributes != null) {
      InputStream attributeIS = null;
      try {
        attributeIS = zipFile.getInputStream(attributes);
        final WikiPageProperties props = new WikiPageProperties(attributeIS);
        data.setProperties(props);
      } catch (Throwable th) {
        throw new RuntimeException(th);
      } finally {
        try {
          if (attributeIS != null) {
            attributeIS.close();
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
{'fraction_non_alphanumeric': 0.10457516339869281, 'fraction_numerical': 0.0006630671592308421, 'mean_word_length': 3.191345772131798, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4037917', 'n_tokens_mistral': 3087, 'n_tokens_neox': 2947, 'n_words': 752}