Example #1
0
  /** Creates a patch from the two passed in files, writing the result to <code>os</code>. */
  public static void createPatch(String oldPath, String newPath, OutputStream os, boolean minimal)
      throws IOException {
    JarFile2 oldJar = new JarFile2(oldPath);
    JarFile2 newJar = new JarFile2(newPath);

    try {
      Iterator entries;
      HashMap moved = new HashMap();
      HashSet visited = new HashSet();
      HashSet implicit = new HashSet();
      HashSet moveSrc = new HashSet();
      HashSet newEntries = new HashSet();

      // FIRST PASS
      // Go through the entries in new jar and
      // determine which files are candidates for implicit moves
      // ( files that has the same filename and same content in old.jar
      // and new.jar )
      // and for files that cannot be implicitly moved, we will either
      // find out whether it is moved or new (modified)
      entries = newJar.getJarEntries();
      if (entries != null) {
        while (entries.hasNext()) {
          JarEntry newEntry = (JarEntry) entries.next();
          String newname = newEntry.getName();

          // Return best match of contents, will return a name match if possible
          String oldname = oldJar.getBestMatch(newJar, newEntry);
          if (oldname == null) {
            // New or modified entry
            if (_debug) {
              System.out.println("NEW: " + newname);
            }
            newEntries.add(newname);
          } else {
            // Content already exist - need to do a move

            // Should do implicit move? Yes, if names are the same, and
            // no move command already exist from oldJar
            if (oldname.equals(newname) && !moveSrc.contains(oldname)) {
              if (_debug) {
                System.out.println(newname + " added to implicit set!");
              }
              implicit.add(newname);
            } else {
              // The 1.0.1/1.0 JarDiffPatcher cannot handle
              // multiple MOVE command with same src.
              // The work around here is if we are going to generate
              // a MOVE command with duplicate src, we will
              // instead add the target as a new file.  This way
              // the jardiff can be applied by 1.0.1/1.0
              // JarDiffPatcher also.
              if (!minimal && (implicit.contains(oldname) || moveSrc.contains(oldname))) {

                // generate non-minimal jardiff
                // for backward compatibility

                if (_debug) {

                  System.out.println("NEW: " + newname);
                }
                newEntries.add(newname);
              } else {
                // Use newname as key, since they are unique
                if (_debug) {
                  System.err.println("moved.put " + newname + " " + oldname);
                }
                moved.put(newname, oldname);
                moveSrc.add(oldname);
              }
              // Check if this disables an implicit 'move <oldname> <oldname>'
              if (implicit.contains(oldname) && minimal) {

                if (_debug) {
                  System.err.println("implicit.remove " + oldname);

                  System.err.println("moved.put " + oldname + " " + oldname);
                }
                implicit.remove(oldname);
                moved.put(oldname, oldname);
                moveSrc.add(oldname);
              }
            }
          }
        }
      } // if (entries != null)

      // SECOND PASS: <deleted files> = <oldjarnames> - <implicitmoves> -
      // <source of move commands> - <new or modified entries>
      ArrayList deleted = new ArrayList();
      entries = oldJar.getJarEntries();
      if (entries != null) {
        while (entries.hasNext()) {
          JarEntry oldEntry = (JarEntry) entries.next();
          String oldName = oldEntry.getName();
          if (!implicit.contains(oldName)
              && !moveSrc.contains(oldName)
              && !newEntries.contains(oldName)) {
            if (_debug) {
              System.err.println("deleted.add " + oldName);
            }
            deleted.add(oldName);
          }
        }
      }

      // DEBUG
      if (_debug) {
        // DEBUG:  print out moved map
        entries = moved.keySet().iterator();
        if (entries != null) {
          System.out.println("MOVED MAP!!!");
          while (entries.hasNext()) {
            String newName = (String) entries.next();
            String oldName = (String) moved.get(newName);
            System.out.println("key is " + newName + " value is " + oldName);
          }
        }

        // DEBUG:  print out IMOVE map
        entries = implicit.iterator();
        if (entries != null) {
          System.out.println("IMOVE MAP!!!");
          while (entries.hasNext()) {
            String newName = (String) entries.next();
            System.out.println("key is " + newName);
          }
        }
      }

      JarOutputStream jos = new JarOutputStream(os);

      // Write out all the MOVEs and REMOVEs
      createIndex(jos, deleted, moved);

      // Put in New and Modified entries
      entries = newEntries.iterator();
      if (entries != null) {

        while (entries.hasNext()) {
          String newName = (String) entries.next();
          if (_debug) {
            System.out.println("New File: " + newName);
          }
          writeEntry(jos, newJar.getEntryByName(newName), newJar);
        }
      }

      jos.finish();
      jos.close();

    } catch (IOException ioE) {
      throw ioE;
    } finally {
      try {
        oldJar.getJarFile().close();
      } catch (IOException e1) {
        // ignore
      }
      try {
        newJar.getJarFile().close();
      } catch (IOException e1) {
        // ignore
      }
    } // finally
  }