private String[] getEntityDetails(String filename, List<JarEntity> list) throws Sha1Exception { ArrayList<String> result = new ArrayList<String>(); result.add( String.format("Found %d versions of %s in the dependency list,", list.size(), filename)); result.add( "but not all the versions are identical (check is based on SHA-1 only at this time)."); result.add("All versions of the libraries must be the same at this time."); result.add("Versions found are:"); for (JarEntity entity : list) { result.add("Path: " + entity.getFile().getAbsolutePath()); result.add("\tLength: " + entity.getLength()); result.add("\tSHA-1: " + entity.getSha1()); } return result.toArray(new String[result.size()]); }
private void writeJarList(Map<String, List<JarEntity>> nameMap) { File cacheFile = new File(mOut, CACHE_FILENAME); OutputStreamWriter writer = null; try { writer = new OutputStreamWriter(new FileOutputStream(cacheFile), "UTF-8"); writer.write("# cache for current jar dependency. DO NOT EDIT.\n"); writer.write("# format is <lastModified> <length> <SHA-1> <path>\n"); writer.write("# Encoding is UTF-8\n"); for (List<JarEntity> list : nameMap.values()) { // clean up the list of files that don't have a sha1. for (int i = 0; i < list.size(); ) { JarEntity entity = list.get(i); if (entity.hasSha1()) { i++; } else { list.remove(i); } } if (list.size() > 1) { for (JarEntity entity : list) { writer.write( String.format( "%d %d %s %s\n", entity.getLastModified(), entity.getLength(), entity.getSha1(), entity.getFile().getAbsolutePath())); } } } } catch (IOException e) { mOutStream.println( "WARNING: unable to write jarlist cache file " + cacheFile.getAbsolutePath()); } catch (Sha1Exception e) { // shouldn't happen here since we check that the sha1 is present first, meaning it's // already been computing. } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { } } } }
/** * Checks whether a given list of duplicates can be replaced by a single one. * * @param filename the filename of the files * @param list the list of dup files * @throws DifferentLibException * @throws Sha1Exception */ private void checkEntities(String filename, List<JarEntity> list) throws DifferentLibException, Sha1Exception { if (list.size() == 1) { return; } JarEntity baseEntity = list.get(0); long baseLength = baseEntity.getLength(); String baseSha1 = baseEntity.getSha1(); final int count = list.size(); for (int i = 1; i < count; i++) { JarEntity entity = list.get(i); if (entity.getLength() != baseLength || entity.getSha1().equals(baseSha1) == false) { throw new DifferentLibException( "Jar mismatch! Fix your dependencies", getEntityDetails(filename, list)); } } }
/** * Sanitize a given list of files * * @param files the list to sanitize * @return a new list containing no duplicates. * @throws DifferentLibException * @throws Sha1Exception */ public List<File> sanitize(Collection<File> files) throws DifferentLibException, Sha1Exception { List<File> results = new ArrayList<File>(); // get the cache list. Map<String, JarEntity> jarList = getCachedJarList(); boolean updateJarList = false; // clean it up of removed files. // use results as a temp storage to store the files to remove as we go through the map. for (JarEntity entity : jarList.values()) { if (entity.getFile().exists() == false) { results.add(entity.getFile()); } } // the actual clean up. if (results.size() > 0) { for (File f : results) { jarList.remove(f.getAbsolutePath()); } results.clear(); updateJarList = true; } Map<String, List<JarEntity>> nameMap = new HashMap<String, List<JarEntity>>(); // update the current jar list if needed, while building a secondary map based on // filename only. for (File file : files) { String path = file.getAbsolutePath(); JarEntity entity = jarList.get(path); if (entity == null) { entity = new JarEntity(file); jarList.put(path, entity); updateJarList = true; } else { updateJarList |= entity.checkValidity(); } String filename = file.getName(); List<JarEntity> nameList = nameMap.get(filename); if (nameList == null) { nameList = new ArrayList<JarEntity>(); nameMap.put(filename, nameList); } nameList.add(entity); } try { // now look for duplicates. Each name list can have more than one file but they must // have the same size/sha1 for (Entry<String, List<JarEntity>> entry : nameMap.entrySet()) { List<JarEntity> list = entry.getValue(); checkEntities(entry.getKey(), list); // if we are here, there's no issue. Add the first of the list to the results. results.add(list.get(0).getFile()); } // special case for android-support-v4/13 checkSupportLibs(nameMap, results); } finally { if (updateJarList) { writeJarList(nameMap); } } return results; }