/** * Updates the file in the working tree with content and mode from an entry in the index. The new * content is first written to a new temporary file in the same directory as the real file. Then * that new file is renamed to the final filename. * * <p>TODO: this method works directly on File IO, we may need another abstraction (like * WorkingTreeIterator). This way we could tell e.g. Eclipse that Files in the workspace got * changed * * @param repo * @param f the file to be modified. The parent directory for this file has to exist already * @param entry the entry containing new mode and content * @param or object reader to use for checkout * @throws IOException */ public static void checkoutEntry( final Repository repo, File f, DirCacheEntry entry, ObjectReader or) throws IOException { ObjectLoader ol = or.open(entry.getObjectId()); File parentDir = f.getParentFile(); parentDir.mkdirs(); File tmpFile = File.createTempFile("._" + f.getName(), null, parentDir); // $NON-NLS-1$ WorkingTreeOptions opt = repo.getConfig().get(WorkingTreeOptions.KEY); FileOutputStream rawChannel = new FileOutputStream(tmpFile); OutputStream channel; if (opt.getAutoCRLF() == AutoCRLF.TRUE) channel = new AutoCRLFOutputStream(rawChannel); else channel = rawChannel; try { ol.copyTo(channel); } finally { channel.close(); } FS fs = repo.getFS(); if (opt.isFileMode() && fs.supportsExecute()) { if (FileMode.EXECUTABLE_FILE.equals(entry.getRawMode())) { if (!fs.canExecute(tmpFile)) fs.setExecute(tmpFile, true); } else { if (fs.canExecute(tmpFile)) fs.setExecute(tmpFile, false); } } try { FileUtils.rename(tmpFile, f); } catch (IOException e) { throw new IOException( MessageFormat.format(JGitText.get().couldNotWriteFile, tmpFile.getPath(), f.getPath())); } entry.setLastModified(f.lastModified()); if (opt.getAutoCRLF() != AutoCRLF.FALSE) entry.setLength(f.length()); // AutoCRLF wants on-disk-size else entry.setLength((int) ol.getSize()); }
/** * Checks whether this entry differs from a given entry from the {@link DirCache}. * * <p>File status information is used and if status is same we consider the file identical to the * state in the working directory. Native git uses more stat fields than we have accessible in * Java. * * @param entry the entry from the dircache we want to compare against * @param forceContentCheck True if the actual file content should be checked if modification time * differs. * @return true if content is most likely different. */ public boolean isModified(DirCacheEntry entry, boolean forceContentCheck) { if (entry.isAssumeValid()) return false; if (entry.isUpdateNeeded()) return true; if (!entry.isSmudged() && (getEntryLength() != entry.getLength())) return true; // Determine difference in mode-bits of file and index-entry. In the // bitwise presentation of modeDiff we'll have a '1' when the two modes // differ at this position. int modeDiff = getEntryRawMode() ^ entry.getRawMode(); // Ignore the executable file bits if checkFilemode tells me to do so. // Ignoring is done by setting the bits representing a EXECUTABLE_FILE // to '0' in modeDiff if (!state.options.isFileMode()) modeDiff &= ~FileMode.EXECUTABLE_FILE.getBits(); if (modeDiff != 0) // Report a modification if the modes still (after potentially // ignoring EXECUTABLE_FILE bits) differ return true; // Git under windows only stores seconds so we round the timestamp // Java gives us if it looks like the timestamp in index is seconds // only. Otherwise we compare the timestamp at millisecond precision. long cacheLastModified = entry.getLastModified(); long fileLastModified = getEntryLastModified(); if (cacheLastModified % 1000 == 0) fileLastModified = fileLastModified - fileLastModified % 1000; if (fileLastModified != cacheLastModified) { // The file is dirty by timestamps if (forceContentCheck) { // But we are told to look at content even though timestamps // tell us about modification return contentCheck(entry); } else { // We are told to assume a modification if timestamps differs return true; } } else { // The file is clean when you look at timestamps. if (entry.isSmudged()) { // The file is clean by timestamps but the entry was smudged. // Lets do a content check return contentCheck(entry); } else { // The file is clean by timestamps and the entry is not // smudged: Can't get any cleaner! return false; } } }
void updateSubmoduleSubscriptions(ReviewDb db, Branch.NameKey destBranch) throws SubmoduleException { if (urlProvider.get() == null) { logAndThrowSubmoduleException( "Cannot establish canonical web url used " + "to access gerrit. It should be provided in gerrit.config file."); } try (Repository repo = repoManager.openRepository(destBranch.getParentKey()); RevWalk rw = new RevWalk(repo)) { ObjectId id = repo.resolve(destBranch.get()); RevCommit commit = rw.parseCommit(id); Set<SubmoduleSubscription> oldSubscriptions = Sets.newHashSet(db.submoduleSubscriptions().bySuperProject(destBranch)); Set<SubmoduleSubscription> newSubscriptions; TreeWalk tw = TreeWalk.forPath(repo, GIT_MODULES, commit.getTree()); if (tw != null && (FileMode.REGULAR_FILE.equals(tw.getRawMode(0)) || FileMode.EXECUTABLE_FILE.equals(tw.getRawMode(0)))) { BlobBasedConfig bbc = new BlobBasedConfig(null, repo, commit, GIT_MODULES); String thisServer = new URI(urlProvider.get()).getHost(); newSubscriptions = subSecParserFactory.create(bbc, thisServer, destBranch).parseAllSections(); } else { newSubscriptions = Collections.emptySet(); } Set<SubmoduleSubscription> alreadySubscribeds = new HashSet<>(); for (SubmoduleSubscription s : newSubscriptions) { if (oldSubscriptions.contains(s)) { alreadySubscribeds.add(s); } } oldSubscriptions.removeAll(newSubscriptions); newSubscriptions.removeAll(alreadySubscribeds); if (!oldSubscriptions.isEmpty()) { db.submoduleSubscriptions().delete(oldSubscriptions); } if (!newSubscriptions.isEmpty()) { db.submoduleSubscriptions().insert(newSubscriptions); } } catch (OrmException e) { logAndThrowSubmoduleException( "Database problem at update of subscriptions table from " + GIT_MODULES + " file.", e); } catch (ConfigInvalidException e) { logAndThrowSubmoduleException( "Problem at update of subscriptions table: " + GIT_MODULES + " config file is invalid.", e); } catch (IOException e) { logAndThrowSubmoduleException( "Problem at update of subscriptions table from " + GIT_MODULES + ".", e); } catch (URISyntaxException e) { logAndThrowSubmoduleException( "Incorrect gerrit canonical web url provided in gerrit.config file.", e); } }