Below is the file 'restrictions.cc' from this revision. You can also download the file.

// copyright (C) 2005 derek scherger <derek@echologic.com>
// all rights reserved.
// licensed to the public under the terms of the GNU GPL (>= 2)
// see the file COPYING for details

#include <map>
#include <string>
#include <vector>

#include "manifest.hh"
#include "restrictions.hh"
#include "revision.hh"
#include "transforms.hh"

void
extract_rearranged_paths(change_set::path_rearrangement const & rearrangement, path_set & paths)
{
  paths.insert(rearrangement.deleted_files.begin(), rearrangement.deleted_files.end());
  paths.insert(rearrangement.deleted_dirs.begin(), rearrangement.deleted_dirs.end());

  for (std::map<file_path, file_path>::const_iterator i = rearrangement.renamed_files.begin();
       i != rearrangement.renamed_files.end(); ++i)
    {
      paths.insert(i->first);
      paths.insert(i->second);
    }

  for (std::map<file_path, file_path>::const_iterator i = rearrangement.renamed_dirs.begin();
       i != rearrangement.renamed_dirs.end(); ++i)
    {
      paths.insert(i->first);
      paths.insert(i->second);
    }

  paths.insert(rearrangement.added_files.begin(), rearrangement.added_files.end());
}

static void
extract_delta_paths(change_set::delta_map const & deltas, path_set & paths)
{
  for (change_set::delta_map::const_iterator i = deltas.begin(); i != deltas.end(); ++i)
    {
      paths.insert(i->first);
    }
}

static void
extract_changed_paths(change_set const & cs, path_set & paths)
{
  extract_rearranged_paths(cs.rearrangement, paths);
  extract_delta_paths(cs.deltas, paths);
}

void
add_intermediate_paths(path_set & paths)
{
  path_set intermediate_paths;

  for (path_set::const_iterator i = paths.begin(); i != paths.end(); ++i)
    {
      // we know that file_path's are normalized relative paths.  So we can
      // find intermediate paths simply by searching for /.
      std::string::size_type j = std::string::npos;
      while ((j = (*i).as_internal().rfind('/', j)) != std::string::npos)
        {
          file_path dir = file_path_internal((*i).as_internal().substr(0, j));
          if (intermediate_paths.find(dir) != intermediate_paths.end()) break;
          if (paths.find(dir) != paths.end()) break;
          intermediate_paths.insert(dir);
          --j;
        }
    }

  paths.insert(intermediate_paths.begin(), intermediate_paths.end());
}


static void
restrict_path_set(std::string const & type,
                  path_set const & paths,
                  path_set & included,
                  path_set & excluded,
                  app_state & app)
{
  for (path_set::const_iterator i = paths.begin(); i != paths.end(); ++i)
    {
      if (app.restriction_includes(*i))
        {
          L(F("restriction includes %s %s\n") % type % *i);
          included.insert(*i);
        }
      else
        {
          L(F("restriction excludes %s %s\n") % type % *i);
          excluded.insert(*i);
        }
    }
}

static void
restrict_rename_set(std::string const & type,
                    std::map<file_path, file_path> const & renames,
                    std::map<file_path, file_path> & included,
                    std::map<file_path, file_path> & excluded,
                    app_state & app)
{
  for (std::map<file_path, file_path>::const_iterator i = renames.begin();
       i != renames.end(); ++i)
    {
      // include renames if either source or target name is included in the restriction
      if (app.restriction_includes(i->first) || app.restriction_includes(i->second))
        {
          L(F("restriction includes %s '%s' to '%s'\n") % type % i->first % i->second);
          included.insert(*i);
        }
      else
        {
          L(F("restriction excludes %s '%s' to '%s'\n") % type % i->first % i->second);
          excluded.insert(*i);
        }
    }
}

void
restrict_path_rearrangement(change_set::path_rearrangement const & work,
                            change_set::path_rearrangement & included,
                            change_set::path_rearrangement & excluded,
                            app_state & app)
{
  restrict_path_set("delete file", work.deleted_files,
                    included.deleted_files, excluded.deleted_files, app);
  restrict_path_set("delete dir", work.deleted_dirs,
                    included.deleted_dirs, excluded.deleted_dirs, app);

  restrict_rename_set("rename file", work.renamed_files,
                      included.renamed_files, excluded.renamed_files, app);
  restrict_rename_set("rename dir", work.renamed_dirs,
                      included.renamed_dirs, excluded.renamed_dirs, app);

  restrict_path_set("add file", work.added_files,
                    included.added_files, excluded.added_files, app);
}

static void
restrict_delta_map(change_set::delta_map const & deltas,
                   change_set::delta_map & included,
                   change_set::delta_map & excluded,
                   app_state & app)
{
  for (change_set::delta_map::const_iterator i = deltas.begin(); i!= deltas.end(); ++i)
    {
      if (app.restriction_includes(i->first))
        {
          L(F("restriction includes delta on %s\n") % i->first);
          included.insert(*i);
        }
      else
        {
          L(F("restriction excludes delta on %s\n") % i->first);
          excluded.insert(*i);
        }
    }
}

void
calculate_restricted_rearrangement(app_state & app,
                                   std::vector<utf8> const & args,
                                   manifest_id & old_manifest_id,
                                   revision_id & old_revision_id,
                                   manifest_map & m_old,
                                   path_set & old_paths,
                                   path_set & new_paths,
                                   change_set::path_rearrangement & included,
                                   change_set::path_rearrangement & excluded)
{
  change_set::path_rearrangement work;

  get_base_revision(app,
                    old_revision_id,
                    old_manifest_id, m_old);

  extract_path_set(m_old, old_paths);

  get_path_rearrangement(work);

  path_set valid_paths(old_paths);
  extract_rearranged_paths(work, valid_paths);
  add_intermediate_paths(valid_paths);

  app.set_restriction(valid_paths, args);

  restrict_path_rearrangement(work, included, excluded, app);

  apply_path_rearrangement(old_paths, included, new_paths);
}

void
calculate_restricted_revision(app_state & app,
                              std::vector<utf8> const & args,
                              revision_set & rev,
                              manifest_map & m_old,
                              manifest_map & m_new,
                              change_set::path_rearrangement & excluded)
{
  manifest_id old_manifest_id;
  revision_id old_revision_id;
  boost::shared_ptr<change_set> cs(new change_set());
  path_set old_paths, new_paths;

  rev.edges.clear();
  m_old.clear();
  m_new.clear();

  calculate_restricted_rearrangement(app, args,
                                     old_manifest_id, old_revision_id,
                                     m_old, old_paths, new_paths,
                                     cs->rearrangement, excluded);

  build_restricted_manifest_map(new_paths, m_old, m_new, app);
  complete_change_set(m_old, m_new, *cs);

  calculate_ident(m_new, rev.new_manifest);
  L(F("new manifest is %s\n") % rev.new_manifest);

  rev.edges.insert(std::make_pair(old_revision_id,
                                  std::make_pair(old_manifest_id, cs)));
}

void
calculate_restricted_revision(app_state & app,
                              std::vector<utf8> const & args,
                              revision_set & rev,
                              manifest_map & m_old,
                              manifest_map & m_new)
{
  change_set::path_rearrangement work;
  calculate_restricted_revision(app, args, rev, m_old, m_new, work);
}

void
calculate_unrestricted_revision(app_state & app,
                                revision_set & rev,
                                manifest_map & m_old,
                                manifest_map & m_new)
{
  std::vector<utf8> empty_args;
  std::set<utf8> saved_exclude_patterns(app.exclude_patterns);
  app.exclude_patterns.clear();
  calculate_restricted_revision(app, empty_args, rev, m_old, m_new);
  app.exclude_patterns = saved_exclude_patterns;
}

void
calculate_restricted_change_set(app_state & app,
                                std::vector<utf8> const & args,
                                change_set const & cs,
                                change_set & included,
                                change_set & excluded)
{
  path_set valid_paths;

  extract_changed_paths(cs, valid_paths);
  add_intermediate_paths(valid_paths);

  app.set_restriction(valid_paths, args);

  restrict_path_rearrangement(cs.rearrangement,
                              included.rearrangement, excluded.rearrangement, app);

  restrict_delta_map(cs.deltas, included.deltas, excluded.deltas, app);
}