diff options
| -rwxr-xr-x | BuildParams | 9 | ||||
| -rwxr-xr-x | indra/llcorehttp/CMakeLists.txt | 37 | ||||
| -rw-r--r-- | indra/media_plugins/cef/CMakeLists.txt | 8 | ||||
| -rwxr-xr-x | indra/newview/lllocalbitmaps.cpp | 10 | ||||
| -rwxr-xr-x | indra/newview/llpanelface.cpp | 2 | ||||
| -rwxr-xr-x | indra/newview/lltexturectrl.cpp | 2 | ||||
| -rwxr-xr-x | indra/newview/lltexturefetch.cpp | 2 | ||||
| -rwxr-xr-x | indra/newview/llviewerparcelmgr.cpp | 4 | ||||
| -rwxr-xr-x | indra/newview/llviewertexture.cpp | 14 | ||||
| -rwxr-xr-x | indra/newview/llviewertexturelist.cpp | 16 | ||||
| -rwxr-xr-x | indra/newview/llviewertexturelist.h | 4 | ||||
| -rwxr-xr-x | indra/newview/llvoavatar.cpp | 8 | ||||
| -rwxr-xr-x | indra/newview/viewer_manifest.py | 41 | 
13 files changed, 111 insertions, 46 deletions
| diff --git a/BuildParams b/BuildParams index 15fb56ec17..aeea3b1246 100755 --- a/BuildParams +++ b/BuildParams @@ -70,15 +70,12 @@ additional_packages = ""  # the viewer_channel_suffix is prefixed by a blank and then appended to the viewer_channel  # for the package in a setting that overrides the compiled-in value  ################################################################ -## Removed 2015-07-02 (MAINT-5360) until we fix packaging step in Team City -## additional_packages = "EDU" +additional_packages = "EDU"  # The EDU package allows us to create a separate release channel whose expirations  # are synchronized as much as possible with the academic year -## Removed 2015-07-02 (MAINT-5360) until we fix packaging step in Team City -## EDU_sourceid = "" -## Removed 2015-07-02 (MAINT-5360) until we fix packaging step in Team City -## EDU_viewer_channel_suffix = "edu" +EDU_sourceid = "" +EDU_viewer_channel_suffix = "edu"  # Notifications - to configure email notices, add a setting like this:  # <username>_<reponame>.email = <email-address> diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index a0b1ea13b1..8567254147 100755 --- a/indra/llcorehttp/CMakeLists.txt +++ b/indra/llcorehttp/CMakeLists.txt @@ -141,6 +141,43 @@ if (LL_TESTS)                            "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llcorehttp_peer.py"                            ) +if (DARWIN) +  # Path inside the app bundle where we'll need to copy libraries +  set(LL_TEST_DESTINATION_DIR +    ${CMAKE_SOURCE_DIR}/../build-darwin-i386/sharedlibs/Resources +  ) + +  # Create the Contents/Resources directory +  add_custom_command( +    TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD +    COMMAND ${CMAKE_COMMAND} +    ARGS +      -E +      make_directory +      ${LL_TEST_DESTINATION_DIR} +    COMMENT "Creating Resources directory in app bundle." +  ) +   +  # Copy the required libraries to the package app +  add_custom_command(TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD +    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libapr-1.0.dylib ${LL_TEST_DESTINATION_DIR} +    DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libapr-1.0.dylib +  ) +  add_custom_command(TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD +    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libaprutil-1.0.dylib ${LL_TEST_DESTINATION_DIR} +    DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libaprutil-1.0.dylib +  ) +  add_custom_command(TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD +    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexception_handler.dylib ${LL_TEST_DESTINATION_DIR} +    DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexception_handler.dylib +  ) +  add_custom_command(TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD +    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexpat.1.5.2.dylib ${LL_TEST_DESTINATION_DIR} +    DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexpat.1.5.2.dylib +  ) + +endif (DARWIN) +    #    # Example Programs    # diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index 1f6163e41e..388030c979 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -114,4 +114,12 @@ if (DARWIN)      LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp"    ) +  add_custom_command(TARGET media_plugin_cef +    POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "@executable_path/Chromium Embedded Framework" +        "@executable_path/../../../../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" +        "$<TARGET_FILE:media_plugin_cef>" +    VERBATIM +    COMMENT "Fixing path to CEF Framework" +  ) +  endif (DARWIN) diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index aa934f95a1..366b9ac034 100755 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -135,7 +135,7 @@ LLLocalBitmap::~LLLocalBitmap()  	}  	// delete self from gimagelist -	LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_STANDARD); +	LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_DISCARD);  	gTextureList.deleteImage(image);  	if (image) @@ -207,7 +207,7 @@ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate)  					texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image);  					texture->ref();  -					gTextureList.addImage(texture, TEX_LIST_STANDARD); +					gTextureList.addImage(texture, TEX_LIST_DISCARD);  					if (optional_firstupdate != UT_FIRSTUSE)  					{ @@ -215,7 +215,7 @@ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate)  						replaceIDs(old_id, mWorldID);  						// remove old_id from gimagelist -						LLViewerFetchedTexture* image = gTextureList.findImage(old_id, TEX_LIST_STANDARD); +						LLViewerFetchedTexture* image = gTextureList.findImage(old_id, TEX_LIST_DISCARD);  						if (image != NULL)  						{  							gTextureList.deleteImage(image); @@ -384,7 +384,7 @@ void LLLocalBitmap::replaceIDs(LLUUID old_id, LLUUID new_id)  std::vector<LLViewerObject*> LLLocalBitmap::prepUpdateObjects(LLUUID old_id, U32 channel)  {  	std::vector<LLViewerObject*> obj_list; -	LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); +	LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_DISCARD);  	for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++)  	{ @@ -502,7 +502,7 @@ void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel)  void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id)  { -	LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); +	LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_DISCARD);  	for(U32 volume_iter = 0; volume_iter < old_texture->getNumVolumes(); volume_iter++)  	{  		LLVOVolume* volume_to_object = (*old_texture->getVolumeList())[volume_iter]; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index ec2d37c30d..551495c6ad 100755 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -2214,7 +2214,7 @@ void LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)  				LLTextureEntry *te = object->getTE(te_index);  				if (te)  				{ -					LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; +					LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_DISCARD) : NULL;  					if(!tex)  					{  						tex = LLViewerFetchedTexture::sDefaultImagep; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index e5aa740a33..980810835e 100755 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1393,7 +1393,7 @@ void LLTextureCtrl::setOnTextureSelectedCallback(texture_selected_callback cb)  void	LLTextureCtrl::setImageAssetName(const std::string& name)  { -	LLPointer<LLUIImage> imagep = LLUI::getUIImage(name, LLGLTexture::BOOST_PREVIEW); +	LLPointer<LLUIImage> imagep = LLUI::getUIImage(name);  	if(imagep)  	{  		LLViewerFetchedTexture* pTexture = dynamic_cast<LLViewerFetchedTexture*>(imagep->getImage().get()); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index bb93597651..27d754bed2 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -4460,7 +4460,7 @@ void LLTextureFetchDebugger::addHistoryEntry(LLTextureFetchWorker* worker)  			mRefetchedAllData += worker->mFormattedImage->getDataSize();  			// refetch list only requests/creates normal images, so requesting ui='false' -			LLViewerFetchedTexture* tex = LLViewerTextureManager::findFetchedTexture(worker->mID, TEX_LIST_STANDARD); +			LLViewerFetchedTexture* tex = LLViewerTextureManager::findFetchedTexture(worker->mID, TEX_LIST_DISCARD);  			if(tex && mRefetchList[tex].begin() != mRefetchList[tex].end())  			{  				if(worker->mDecodedDiscard == mFetchingHistory[mRefetchList[tex][0]].mDecodedLevel) diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index e72ae88ba2..aafb6b4d12 100755 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -143,8 +143,8 @@ LLViewerParcelMgr::LLViewerParcelMgr()  	// JC: Resolved a merge conflict here, eliminated  	// mBlockedImage->setAddressMode(LLTexUnit::TAM_WRAP);  	// because it is done in llviewertexturelist.cpp -	mBlockedImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png"); -	mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png"); +	mBlockedImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI); +	mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI);  	S32 overlay_size = mParcelsPerEdge * mParcelsPerEdge / PARCEL_OVERLAY_CHUNKS;  	sPackedOverlay = new U8[overlay_size]; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index c5e07f009f..3e059f3b68 100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3323,7 +3323,7 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL  	setCategory(LLGLTexture::MEDIA); -	LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); +	LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_DISCARD);  	if(tex) //this media is a parcel media for tex.  	{  		tex->setParcelMedia(this); @@ -3333,7 +3333,7 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL  //virtual   LLViewerMediaTexture::~LLViewerMediaTexture()   {	 -	LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); +	LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_DISCARD);  	if(tex) //this media is a parcel media for tex.  	{  		tex->setParcelMedia(NULL); @@ -3388,7 +3388,7 @@ BOOL LLViewerMediaTexture::findFaces()  	BOOL ret = TRUE; -	LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); +	LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_DISCARD);  	if(tex) //this media is a parcel media for tex.  	{  		for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) @@ -3497,7 +3497,7 @@ void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep)  	const LLTextureEntry* te = facep->getTextureEntry();  	if(te && te->getID().notNull())  	{ -		LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); +		LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_DISCARD);  		if(tex)  		{  			mTextureList.push_back(tex);//increase the reference number by one for tex to avoid deleting it. @@ -3526,7 +3526,7 @@ void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep)  	const LLTextureEntry* te = facep->getTextureEntry();  	if(te && te->getID().notNull())  	{ -		LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); +		LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_DISCARD);  		if(tex)  		{  			for(std::list< LLPointer<LLViewerTexture> >::iterator iter = mTextureList.begin(); @@ -3635,10 +3635,10 @@ void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep)  			const LLTextureEntry* te = facep->getTextureEntry();  			if(te)  			{ -				LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; +				LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_DISCARD) : NULL;  				if(!tex && te->getID() != mID)//try parcel media.  				{ -					tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); +					tex = gTextureList.findImage(mID, TEX_LIST_DISCARD);  				}  				if(!tex)  				{ diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 6be8e4e1e8..e580ecaba1 100755 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -72,18 +72,20 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMAGES("Process Images");  ETexListType get_element_type(S32 priority)  { -    if (priority == LLViewerFetchedTexture::BOOST_ICON) +    // don't discard flag can be used in some cases, but it usually is not set yet +    if (priority == LLViewerFetchedTexture::BOOST_ICON +        || priority == LLViewerFetchedTexture::BOOST_UI)      { -        return TEX_LIST_SCALE; +        return TEX_LIST_UI;      } -    return TEX_LIST_STANDARD; +    return TEX_LIST_DISCARD;  }  ///////////////////////////////////////////////////////////////////////////////  LLTextureKey::LLTextureKey()  : textureId(LLUUID::null), -textureType(TEX_LIST_STANDARD) +textureType(TEX_LIST_DISCARD)  {  } @@ -589,7 +591,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,  void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<LLViewerFetchedTexture*> &output)  { -    LLTextureKey search_key(image_id, TEX_LIST_STANDARD); +    LLTextureKey search_key(image_id, TEX_LIST_DISCARD);      uuid_map_t::iterator iter = mUUIDMap.lower_bound(search_key);      while (iter != mUUIDMap.end() && iter->first.textureId == image_id)      { @@ -1595,14 +1597,14 @@ void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **  	LLUUID image_id;  	msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id); -	LLViewerFetchedTexture* image = gTextureList.findImage( image_id, TEX_LIST_STANDARD); +	LLViewerFetchedTexture* image = gTextureList.findImage( image_id, TEX_LIST_DISCARD);  	if( image )  	{  		LL_WARNS() << "Image not in db" << LL_ENDL;  		image->setIsMissingAsset();  	} -    image = gTextureList.findImage(image_id, TEX_LIST_SCALE); +    image = gTextureList.findImage(image_id, TEX_LIST_UI);      if (image)      {          LL_WARNS() << "Icon not in db" << LL_ENDL; diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 53ea3e05a0..9f94f2f1bc 100755 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -61,8 +61,8 @@ typedef	void (*LLImageCallback)(BOOL success,  enum ETexListType  { -    TEX_LIST_STANDARD = 0, -    TEX_LIST_SCALE // images that will be scaled, they should not be mixed up with regular images +    TEX_LIST_DISCARD = 0, +    TEX_LIST_UI  };  struct LLTextureKey diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 6f96eb9772..a26b5e0a98 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1992,7 +1992,7 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU  		uuid == IMG_INVISIBLE)  	{  		// Should already exist, don't need to find it on sim or baked-texture host. -		result = gTextureList.findImage(uuid, TEX_LIST_STANDARD); +		result = gTextureList.findImage(uuid, TEX_LIST_DISCARD);  	}  	if (!result)  	{ @@ -4313,7 +4313,7 @@ bool LLVOAvatar::allTexturesCompletelyDownloaded(std::set<LLUUID>& ids) const  {  	for (std::set<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it)  	{ -		LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); +		LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_DISCARD);  		if (imagep && imagep->getDiscardLevel()!=0)  		{  			return false; @@ -4385,7 +4385,7 @@ S32Bytes LLVOAvatar::totalTextureMemForUUIDS(std::set<LLUUID>& ids)  	S32Bytes result(0);  	for (std::set<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it)  	{ -		LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); +		LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_DISCARD);  		if (imagep)  		{  			result += imagep->getTextureMemory(); @@ -4473,7 +4473,7 @@ void LLVOAvatar::releaseOldTextures()  	{  		if (new_texture_ids.find(*it) == new_texture_ids.end())  		{ -			LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); +			LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_DISCARD);  			if (imagep)  			{  				current_texture_mem += imagep->getTextureMemory(); diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index f7992dba90..ab87f0da35 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -28,6 +28,7 @@ $/LicenseInfo$  """  import sys  import os.path +import shutil  import errno  import re  import tarfile @@ -855,14 +856,17 @@ class Darwin_i386_Manifest(ViewerManifest):                  # This code constructs a relative path from the                  # target framework folder back to the location of the symlink.                  # It needs to be relative so that the symlink still works when -                # (as is normal) the user moves the app bunlde out of the DMG +                # (as is normal) the user moves the app bundle out of the DMG                  # and into the /Applications folder. Note we also call 'raise'                  # to terminate the process if we get an error since without                  # this symlink, Second Life web media can't possibly work.                  # Real Framework folder:                  #   Second Life.app/Contents/Frameworks/Chromium Embedded Framework.framework/ -                # Location of symlink and why it'ds relavie  +                # Location of symlink and why it'ds relative                   #   Second Life.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework/ +                # Real Frameworks folder, with the symlink inside the bundled SLPlugin.app (and why it's relative) +                #   <top level>.app/Contents/Frameworks/Chromium Embedded Framework.framework/ +                #   <top level>.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework ->                  frameworkpath = os.path.join(os.pardir, os.pardir, os.pardir, os.pardir, "Frameworks", "Chromium Embedded Framework.framework")                  try:                      symlinkf(frameworkpath, pluginframeworkpath) @@ -872,10 +876,6 @@ class Darwin_i386_Manifest(ViewerManifest):              self.end_prefix("Contents") -        # fix up media_plugin.dylib so it knows where to look for CEF files it needs -        self.run_command('install_name_tool -change "@executable_path/Chromium Embedded Framework" "@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "%(config)s/Second Life.app/Contents/Resources/llplugin/media_plugin_cef.dylib"' % -                        { 'config' : self.args['configuration'] }) -          # NOTE: the -S argument to strip causes it to keep enough info for          # annotated backtraces (i.e. function names in the crash log).  'strip' with no          # arguments yields a slightly smaller binary but makes crash logs mostly useless. @@ -1247,12 +1247,33 @@ def symlinkf(src, dst):          # file, but that strategy doesn't work so well if we don't have          # permissions to remove it. Check to see if it's already the          # symlink we want, which is the usual reason for EEXIST. -        if not (os.path.islink(dst) and os.readlink(dst) == src): -            # Here either dst isn't a symlink or it's the wrong symlink. -            # Remove and recreate. Caller will just have to deal with any -            # exceptions at this stage. +        elif os.path.islink(dst): +            if os.readlink(dst) == src: +                # the requested link already exists +                pass +            else: +                # dst is the wrong symlink; attempt to remove and recreate it +                os.remove(dst) +                os.symlink(src, dst) +        elif os.path.isdir(dst): +            print "Requested symlink (%s) exists but is a directory; replacing" % dst +            shutil.rmtree(dst) +            os.symlink(src, dst) +        elif os.path.exists(dst): +            print "Requested symlink (%s) exists but is a file; replacing" % dst              os.remove(dst)              os.symlink(src, dst) +        else: +            # see if the problem is that the parent directory does not exist +            # and try to explain what is missing +            (parent, tail) = os.path.split(dst) +            while not os.path.exists(parent): +                (parent, tail) = os.path.split(parent) +            if tail: +                raise Exception("Requested symlink (%s) cannot be created because %s does not exist" +                                % os.path.join(parent, tail)) +            else: +                raise  if __name__ == "__main__":      main() | 
