@ -22,6 +22,7 @@ __metaclass__ = type
import copy
import os
import json
import re
import tempfile
from yaml import YAMLError
@ -42,6 +43,10 @@ except ImportError:
from ansible . utils . display import Display
display = Display ( )
# Tries to determine if a path is inside a role, last dir must be 'tasks'
# this is not perfect but people should really avoid 'tasks' dirs outside roles when using Ansible.
RE_TASKS = re . compile ( u ' (?:^| %s )+tasks %s ?$ ' % ( os . path . sep , os . path . sep ) )
class DataLoader :
@ -184,7 +189,7 @@ class DataLoader:
b_file_name = to_bytes ( file_name )
if not self . path_exists ( b_file_name ) or not self . is_file ( b_file_name ) :
raise AnsibleFileNotFound ( " the file named ' %s ' does not exist, or is not readable " % file_name )
raise AnsibleFileNotFound ( " Unable to retrieve file contents" , file_name = file_name )
show_content = True
try :
@ -233,35 +238,33 @@ class DataLoader:
given = unquote ( given )
given = to_text ( given , errors = ' surrogate_or_strict ' )
if given . startswith ( u " / " ) :
return os . path . abspath ( given )
elif given . startswith ( u " ~ " ) :
return os . path . abspath ( os . path . expanduser ( given ) )
if given . startswith ( to_text ( os . path . sep ) ) or given . startswith ( u ' ~ ' ) :
path = given
else :
basedir = to_text ( self . _basedir , errors = ' surrogate_or_strict ' )
return os . path . abspath ( os . path . join ( basedir , given ) )
path = os . path . join ( basedir , given )
return unfrackpath ( path , follow = False )
def _is_role ( self , path ) :
''' imperfect role detection, roles are still valid w/o main.yml/yaml/ etc '''
''' imperfect role detection, roles are still valid w/o tasks|meta/main.yml|yaml| etc '''
isit = False
b_path = to_bytes ( path , errors = ' surrogate_or_strict ' )
b_upath = to_bytes ( unfrackpath ( path ) , errors = ' surrogate_or_strict ' )
for suffix in ( b ' .yml ' , b ' .yaml ' , b ' ' ) :
b_main = b ' main %s ' % ( suffix )
b_tasked = b ' tasks/ %s ' % ( b_main )
if (
b_path . endswith ( b ' tasks ' ) and
os . path . exists ( os . path . join ( b_path , b_main ) ) or
os . path . exists ( os . path . join ( b_upath , b_tasked ) ) or
os . path . exists ( os . path . join ( os . path . dirname ( b_path ) , b_tasked ) )
) :
isit = True
break
return isit
b_upath = to_bytes ( unfrackpath ( path , follow = False ) , errors = ' surrogate_or_strict ' )
for finddir in ( b ' meta ' , b ' tasks ' ) :
for suffix in ( b ' .yml ' , b ' .yaml ' , b ' ' ) :
b_main = b ' main %s ' % ( suffix )
b_tasked = b ' %s / %s ' % ( finddir , b_main )
if (
RE_TASKS . search ( path ) and
os . path . exists ( os . path . join ( b_path , b_main ) ) or
os . path . exists ( os . path . join ( b_upath , b_tasked ) ) or
os . path . exists ( os . path . join ( os . path . dirname ( b_path ) , b_tasked ) )
) :
return True
return False
def path_dwim_relative ( self , path , dirname , source , is_role = False ) :
'''
@ -273,35 +276,35 @@ class DataLoader:
'''
search = [ ]
source = to_text ( source , errors = ' surrogate_or_strict ' )
# I have full path, nothing else needs to be looked at
if source . startswith ( ' ~ ' ) or source . startswith ( os . path . sep ) :
search . append ( self . path_dwim ( sourc e) )
if source . startswith ( to_text ( os . path . sep ) ) or source . startswith ( u ' ~ ' ) :
search . append ( unfrack path( sourc e, follow = Fals e) )
else :
# base role/play path + templates/files/vars + relative filename
search . append ( os . path . join ( path , dirname , source ) )
basedir = unfrackpath ( path )
basedir = unfrackpath ( path , follow = False )
# not told if role, but detect if it is a role and if so make sure you get correct base path
if not is_role :
is_role = self . _is_role ( path )
if is_role and path. endswith ( ' tasks ' ) :
basedir = unfrackpath ( os . path . dirname ( path ) )
if is_role and RE_TASKS. search ( path ) :
basedir = unfrackpath ( os . path . dirname ( path ) , follow = False )
cur_basedir = self . _basedir
self . set_basedir ( basedir )
# resolved base role/play path + templates/files/vars + relative filename
search . append ( self . path_dwim ( os . path . join ( basedir , dirname , source ) ) )
search . append ( unfrackpath ( os . path . join ( basedir , dirname , source ) , follow = False ) )
self . set_basedir ( cur_basedir )
if is_role and not source . endswith ( dirname ) :
# look in role's tasks dir w/o dirname
search . append ( self . path_dwim ( os . path . join ( basedir , ' tasks ' , source ) ) )
search . append ( unfrackpath ( os . path . join ( basedir , ' tasks ' , source ) , follow = False ) )
# try to create absolute path for loader basedir + templates/files/vars + filename
search . append ( self . path_dwim ( os . path . join ( dirname , source ) ) )
search . append ( self . path_dwim ( os . path . join ( basedir , source ) ) )
search . append ( unfrackpath ( os . path . join ( dirname , source ) , follow = False ) )
# try to create absolute path for loader basedir + filename
search . append ( self . path_dwim ( source ) )
@ -321,24 +324,25 @@ class DataLoader:
is prepended to the source to form the path to search for .
: arg source : A text string which is the filename to search for
: rtype : A text string
: returns : An absolute path to the filename ` ` source ` `
: returns : An absolute path to the filename ` ` source ` ` if found
: raises : An AnsibleFileNotFound Exception if the file is found to exist in the search paths
'''
b_dirname = to_bytes ( dirname )
b_source = to_bytes ( source )
result = None
search = [ ]
if source is None :
display . warning ( ' Invalid request to find a file that matches a " null " value ' )
elif source and ( source . startswith ( ' ~ ' ) or source . startswith ( os . path . sep ) ) :
# path is absolute, no relative needed, check existence and return source
test_path = unfrackpath ( b_source )
test_path = unfrackpath ( b_source , follow = False )
if os . path . exists ( to_bytes ( test_path , errors = ' surrogate_or_strict ' ) ) :
result = test_path
else :
search = [ ]
display . debug ( u ' evaluation_path: \n \t %s ' % ' \n \t ' . join ( paths ) )
for path in paths :
upath = unfrackpath ( path )
upath = unfrackpath ( path , follow = False )
b_upath = to_bytes ( upath , errors = ' surrogate_or_strict ' )
b_mydir = os . path . dirname ( b_upath )
@ -373,6 +377,9 @@ class DataLoader:
result = to_text ( b_candidate )
break
if result is None :
raise AnsibleFileNotFound ( file_name = source , paths = search )
return result
def _create_content_tempfile ( self , content ) :
@ -401,7 +408,7 @@ class DataLoader:
b_file_path = to_bytes ( file_path , errors = ' surrogate_or_strict ' )
if not self . path_exists ( b_file_path ) or not self . is_file ( b_file_path ) :
raise AnsibleFileNotFound ( " the file named ' %s ' does not exist, or is not accessible " % to_native ( file_path ) )
raise AnsibleFileNotFound ( file_name = file_path )
if not self . _vault :
self . _vault = VaultLib ( b_password = " " )
@ -420,7 +427,7 @@ class DataLoader:
# since the decrypt function doesn't know the file name
data = f . read ( )
if not self . _b_vault_password :
raise AnsibleParserError ( " A vault password must be specified to decrypt %s " % file_path)
raise AnsibleParserError ( " A vault password must be specified to decrypt %s " % to_native( file_path) )
data = self . _vault . decrypt ( data , filename = real_path )
# Make a temp file