ignore.cc #1

  • //
  • guest/
  • Newtopian/
  • p4/
  • 2015.1/
  • support/
  • ignore.cc
  • View
  • Commits
  • Open Download .zip Download (6 KB)
/*
 * Copyright 1995, 2003 Perforce Software.  All rights reserved.
 *
 * This file is part of Perforce - the FAST SCM System.
 *
 * Git style ignore file for add/reconcile
 */

# include <stdhdrs.h>
# include <strbuf.h>
# include <error.h>
# include <pathsys.h>
# include <filesys.h>
# include <debug.h>
# include <strarray.h>
# include <maptable.h>
# include "ignore.h"

# ifdef OS_NT
# define SLASH "\\"
# else
# define SLASH "/"
# endif

# define ELLIPSE "..."

Ignore::Ignore()
{
	ignoreList = 0;
}

Ignore::~Ignore()
{
	delete ignoreList;
}

int
Ignore::Reject( 
	const StrPtr &path, 
	const StrPtr &ignoreName,
	const char *configName )
{
	// If we don't have an ignore file, we can just load up the defaults
	// and test against those. If we've already loaded them, lets not do
	// it again and use the existing list instead.
	
	if( !strcmp( ignoreName.Text(), "unset" ) )
	{
	    if( !ignoreList )
	        ignoreList = new StrArray;

	    if( !ignoreList->Count() )
	        InsertDefaults( configName );

	    return RejectCheck( path );
	}

	PathSys *p = PathSys::Create();
	p->Set( path );
	p->ToParent();

	StrBuf saveDepth;

	// Try real hard not to regenerate the ignorelist, this
	// optimization uses the current directory depth and the
	// last found ignorefile depth to reduce the search for
	// config files.

	if( ignoreList && dirDepth.Length() )
	{
	    if( !dirDepth.SCompare( *p ) )
	    {
	        // matching depth bail early

	        delete p;
	        return RejectCheck( path );
	    }
	    else if( !dirDepth.SCompareN( *p ) )
	    {
	        // descending directories can be shortcut.

	        saveDepth << dirDepth;
	    }
	    else if( !p->SCompareN( dirDepth ) &&
	             foundDepth.Length() && !foundDepth.SCompareN( *p ) )
	    {
	        // ascending directories can be shortcut.

	        dirDepth.Set( *p );
	        delete p;
	        return RejectCheck( path );
	    }
	}
	
	StrBuf line;
	Error e;

	dirDepth.Set( *p );

	// No descending optimization, remove list we will recreate it

	if( !saveDepth.Length() )
	{
	    delete ignoreList;
	    ignoreList = new StrArray;
	}
	
	if( !ignoreList->Count() )
	    InsertDefaults( configName );

	PathSys *q = PathSys::Create();
	FileSys *f = FileSys::Create( FileSysType( FST_TEXT|FST_L_CRLF ) );

	// starting from the directory in which the argument supplied file
	// lives,  walk up the tree collecting ignore files as we go

	int found = 0;

	do {
	    if( saveDepth.Length() && !saveDepth.SCompare( *p ) )
	    {
	        delete p;
	        return RejectCheck( path );
	    }

	    e.Clear();
	    StrArray *subList = new StrArray();

	    q->SetLocal( *p, ignoreName );
	    f->Set( *q );

	    f->Open( FOM_READ, &e );

	    if( e.Test() )
	    {
	        delete subList;
	        continue;
	    }

	    // Found ignore file, clear any optimization, reuse foundDepth

	    if( saveDepth.Length() )
	    {
	        delete ignoreList;
	        ignoreList = new StrArray;
	        InsertDefaults( configName );
	        saveDepth.Clear();
	    }

	    // Set foundDepth

	    if( !found++ )
	        foundDepth.Set( *p );

	    while( f->ReadLine( &line, &e ) )
	    {
	        line.TrimBlanks();
	        if( !line.Length() || line.Text()[0] == '#' )
	            continue;
	        Insert( subList, line.Text(), p->Text() );
	    }

	    f->Close( &e );

	    if( DEBUG_MATCH || DEBUG_LIST )
	    {
	        line.Clear();
	        line << "#FILE ";
	        line << f->Name();
	        subList->Put()->Set( line );
	    }

	    // Add this ignorefile to a list (reversing it as its added)

	    for( int i = subList->Count(); i > 0; --i )
	        ignoreList->Put()->Set( subList->Get( i - 1 ) );
	
	    delete subList;
	}
	while( p->ToParent() );

	delete q;
	delete p;
	delete f;

	if( DEBUG_LIST )
	{
	    p4debug.printf("\n\tIgnore list:\n\n");
	    for( int j = 0; j < ignoreList->Count(); ++j )
	    {
	        char *p = ignoreList->Get( j )->Text();
	        p4debug.printf("\t%s\n", p);
	    }
	    p4debug.printf("\n");
	}

	return RejectCheck( path );
}

void
Ignore::InsertDefaults( const char *configName )
{
	// Always add in .p4root and P4CONFIG to the top of new lists

	if( DEBUG_MATCH || DEBUG_LIST )
	    ignoreList->Put()->Set( StrRef( "#FILE - defaults" ) );

	StrBuf line;
	line << ELLIPSE << SLASH << ".p4root";
	ignoreList->Put()->Set( line );
	line << SLASH << ELLIPSE;
	ignoreList->Put()->Set( line );

	if( configName )
	{
	    line.Clear();
	    line << ELLIPSE << SLASH << configName;
	    ignoreList->Put()->Set( line );
	    line << SLASH << ELLIPSE;
	    ignoreList->Put()->Set( line );
	}
}

void
Ignore::Insert( StrArray *subList, const char *ignore, const char *cwd )
{
	StrBuf buf;
	StrBuf buf2;
	const char *lastChar = cwd + strlen( cwd ) - 1;
	char *terminating = (char *)SLASH;

	int reverse = ( *ignore == '!' );
	int isWild = strchr( ignore, '*' ) != 0;

	if( strstr( ignore, "*****" ) || strstr( ignore, "..." ) )
	    buf << "### SENSELESS JUXTAPOSITION ";

	if( reverse )
	{
	    buf << "!";
	    ignore++;
	}

	buf << cwd;
	
	if( *lastChar != *terminating )
	    buf << SLASH;

	// Non wildcard, assume directory

	if( !isWild || *ignore != '*' )
	{
	    buf2 << buf;
	    buf << ignore;
	    subList->Put()->Set( buf );
	    buf2 << ELLIPSE << SLASH << ignore;
	    subList->Put()->Set( buf2 );

	    if( isWild )
	        return;

	    buf << SLASH << ELLIPSE;
	    subList->Put()->Set( buf );
	    buf2 << SLASH << ELLIPSE;
	    subList->Put()->Set( buf2 );
	    return;
	}

	buf << ELLIPSE  << ++ignore;
	subList->Put()->Set( buf );
}

int
Ignore::RejectCheck( const StrPtr &path )
{
	char *ignoreFile;

	for( int i = 0; i < ignoreList->Count(); ++i )
	{
	    char *p = ignoreList->Get( i )->Text();

	    if( ( DEBUG_MATCH ) && !strncmp( p, "#FILE ", 6 ) )
	    {
	        ignoreFile = p+6;
	        continue;
	    }

	    int doAdd = ( *p == '!' );

	    if( doAdd )
	        ++p;

	    if( MapTable::Match( StrRef( p ), path ) )
	    {
	        if( DEBUG_MATCH )
	            p4debug.printf(
	                "\n\tfile[%s]\n\tmatch[%s%s]%s\n\tignore[%s]\n\n",
	                path.Text(), doAdd ? "+" : "-", p, 
	                doAdd ? "KEEP" : "REJECT", ignoreFile );
	        return doAdd ? 0 : 1;
	    }
	}

	return 0;
}

# Change User Description Committed
#1 14945 Newtopian Merging

//guest/perforce_software/p4/...

to //guest/Newtopian/p4/...
//guest/perforce_software/p4/2015.1/support/ignore.cc
#1 12190 Matt Attaway Initial drop of 2015.1 p4/p4api source