def install(self): egg=Eggs(self.buildout, self.options["recipe"], self.options) reqs,ws=egg.working_set() path=[pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) output=WRAPPER_TEMPLATE % dict( syspath=",\n ".join((repr(p) for p in path)) ) location=self.buildout["buildout"]["bin-directory"] if not os.path.exists(location): os.mkdir(location) self.options.created(location) target=os.path.join(location, self.name) f=open(target, "wt") f.write(output) f.close() os.chmod(target, 0755) self.options.created(target) return self.options.created()
def install(self): bin_dir = self.buildout['buildout']['bin-directory'] egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) template_vars = {'python': self.buildout['buildout']['executable'], 'pypath': ",\n ".join((repr(p) for p in path)), 'config': self.options['ini_file'], 'buildout_dir': self.buildout['buildout']['directory'], 'script_path': bin_dir, 'script_name': self.options['script_name'] } wsgi_script = '%s/%s.wsgi' % (bin_dir, self.options['script_name']) open(wsgi_script, 'w').writelines(WSGI_TEMPLATE % template_vars) os.chmod(wsgi_script, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH ) if self.options.get('apache_config', None): open(self.options['apache_config'], 'w').writelines(APACHE_SKEL_TEMPLATE % template_vars) return []
def install(self): egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) # Do not put None into 'quotes' # Everything else should be a string pointing to a pipeline app_name = self.options.get('app_name') if app_name is not None: app_name = '"%s"' % app_name gevent_patch_enabled = self.options.get('gevent-monkey-patch', '') # TODO: would be nice to also support selective patching, e.g. just # socket or just threading gevent_patch = '' if gevent_patch_enabled.lower() in ('true', 'yes'): gevent_patch = """ try: import gevent.monkey gevent.monkey.patch_all() except ImportError: pass """ output = WRAPPER_TEMPLATE % dict( config=self.options["config-file"], syspath=",\n ".join((repr(p) for p in path)), app_name=app_name, gevent_monkey_patch=gevent_patch ) target = self.options.get("target") if target is None: location = os.path.join( self.buildout["buildout"]["parts-directory"], self.name) if not os.path.exists(location): os.mkdir(location) self.options.created(location) target = os.path.join(location, "wsgi") else: if os.path.lexists(target) and not os.path.exists(target): # Can't write to a broken symlink, so remove it os.unlink(target) f = open(target, "wt") try: f.write(output) finally: f.close() exec_mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH os.chmod(target, os.stat(target).st_mode | exec_mask) self.options.created(target) return self.options.created()
def install(self): egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) output = WRAPPER_TEMPLATE % dict( config=self.options["config-file"], syspath=",\n ".join((repr(p) for p in path)) ) location = os.path.join(self.buildout["buildout"]["parts-directory"], self.name) if not os.path.exists(location): os.mkdir(location) self.options.created(location) target = os.path.join(location, "wsgi") f = open(target, "wt") f.write(output) f.close() exec_mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH os.chmod(target, os.stat(target).st_mode | exec_mask) self.options.created(target) return self.options.created()
def install(self): egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) # Do not put None into 'quotes' # Everything else should be a string pointing to a pipeline app_name = self.options.get('app_name') if app_name is not None: app_name = '"%s"' % app_name env = self.options.get('env') if env: output = ENV_TEMPLATE for line in env.splitlines(): key, value = line.split('=') output += "os.environ['%s'] = '%s'\n" % (key, value) output += '\n' else: output = '' output += WSGI_TEMPLATE % dict( configfile=self.options["config-file"], syspath=",\n ".join((repr(p) for p in path)), app_name=app_name ) target = self.options.get("target") if target is None: location = os.path.join( self.buildout["buildout"]["parts-directory"], self.name) if not os.path.exists(location): os.mkdir(location) self.options.created(location) target = os.path.join(location, "wsgi") else: self.options.created(target) f = open(target, "wt") f.write(output) f.close() exec_mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH os.chmod(target, os.stat(target).st_mode | exec_mask) self.options.created(target) return self.options.created()
def install(self): egg = Eggs(self.buildout, self.options['recipe'], self.options) requirements, working_set = egg.working_set() sys_paths = [dist.location for dist in working_set] if sys_paths: sys_paths = ''.join(" '{}',\n".format(p) for p in sys_paths) sys_paths = '\n{}'.format(sys_paths) else: sys_paths = '' extra_settings = {} for k, v in self.options.items(): include = ( (k not in self.buildout['buildout']) and (k not in ( '_d', '_e', 'recipe', 'eggs', 'app-factory', 'settings-file', 'initialization')) ) if include: extra_settings[k] = v if extra_settings: extra_settings = ''.join( " '{}': '{}',\n" .format(k, v) for (k, v) in extra_settings.items()) extra_settings = '\n{}'.format(extra_settings) else: extra_settings = '' initialization = self.options.get('initialization', '') if initialization: initialization = '\n{}\n'.format(initialization) contents = TEMPLATE.format( sys_paths=sys_paths, factory=self.options['app-factory'], settings_file=self.options['settings-file'], extra_settings=extra_settings, initialization=initialization, ) output_file = self.options.get('output-file') if output_file is None: output_file = os.path.join( self.buildout['buildout']['directory'], 'application.wsgi') with open(output_file, 'w') as fp: fp.write(contents) self.options.created(output_file) return self.options.created()
def install(self): egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) # Do not put None into 'quotes' # Everything else should be a string pointing to a pipeline app_name = self.options.get('app_name') if app_name is not None: app_name = '"%s"' % app_name env = self.options.get('env') if env: output = ENV_TEMPLATE for line in env.splitlines(): key, value = line.split('=') output += "os.environ['%s'] = '%s'\n" % (key, value) output += '\n' else: output = '' output += WSGI_TEMPLATE % dict(configfile=self.options["config-file"], syspath=",\n ".join( (repr(p) for p in path)), app_name=app_name) target = self.options.get("target") if target is None: location = os.path.join( self.buildout["buildout"]["parts-directory"], self.name) if not os.path.exists(location): os.mkdir(location) self.options.created(location) target = os.path.join(location, "wsgi") else: self.options.created(target) f = open(target, "wt") f.write(output) f.close() exec_mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH os.chmod(target, os.stat(target).st_mode | exec_mask) self.options.created(target) return self.options.created()
def install(self): egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) # Do not put None into 'quotes' # Everything else should be a string pointing to a pipeline app_name = self.options.get('app_name') if app_name is not None: app_name = '"%s"' % app_name output = WRAPPER_TEMPLATE % dict( config=self.options["config-file"], syspath=",\n ".join((repr(p) for p in path)), app_name=app_name ) target = self.options.get("target") if target is None: location = os.path.join( self.buildout["buildout"]["parts-directory"], self.name) if not os.path.exists(location): os.mkdir(location) self.options.created(location) target = os.path.join(location, "wsgi") else: if os.path.lexists(target) and not os.path.exists(target): # Can't write to a broken symlink, so remove it os.unlink(target) f = open(target, "wt") try: f.write(output) finally: f.close() exec_mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH os.chmod(target, os.stat(target).st_mode | exec_mask) self.options.created(target) return self.options.created()
def install(self): egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) # Do not put None into 'quotes' # Everything else should be a string pointing to a pipeline app_name = self.options.get('app_name') if app_name is not None: app_name = '"%s"' % app_name output = WRAPPER_TEMPLATE % dict(config=self.options["config-file"], syspath=",\n ".join( (repr(p) for p in path)), app_name=app_name) target = self.options.get("target") if target is None: location = os.path.join( self.buildout["buildout"]["parts-directory"], self.name) if not os.path.exists(location): os.mkdir(location) self.options.created(location) target = os.path.join(location, "wsgi") else: if os.path.lexists(target) and not os.path.exists(target): # Can't write to a broken symlink, so remove it os.unlink(target) f = open(target, "wt") try: f.write(output) finally: f.close() exec_mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH os.chmod(target, os.stat(target).st_mode | exec_mask) self.options.created(target) return self.options.created()
def __init__(self, buildout, name, options): self.__name = name self.__logger = logging.getLogger(name) eggs = options['eggs'] eggs = eggs.split('\n') eggs = list(egg.strip() for egg in eggs) for egg in eggs: self.__logger.info('egg: %s', egg) from zc.recipe.egg.egg import Eggs eggs_recipe = Eggs(buildout, name, options) req, ws = eggs_recipe.working_set() for dist in ws: self.__logger.debug('dist: %s %s at %s', dist, dist.key, dist.location) dist_locations = dict((dist.key, dist.location) for dist in ws) egg_path = list(dist_locations[egg] for egg in eggs) for p in egg_path: self.__logger.info('egg-path: %s', p) options['egg-path'] = ' '.join(egg_path)
def install(self): bin_dir = self.buildout["buildout"]["bin-directory"] egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get("extra-paths", "") extra_paths = extra_paths.split() path.extend(extra_paths) template_vars = { "python": self.buildout["buildout"]["executable"], "pypath": ",\n ".join((repr(p) for p in path)), "config": self.options["ini_file"], "buildout_dir": self.buildout["buildout"]["directory"], "script_path": bin_dir, "script_name": self.options["script_name"], } wsgi_script = "%s/%s.wsgi" % (bin_dir, self.options["script_name"]) open(wsgi_script, "w").writelines(WSGI_TEMPLATE % template_vars) os.chmod( wsgi_script, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH, ) if self.options.get("apache_config", None): open(self.options["apache_config"], "w").writelines(APACHE_SKEL_TEMPLATE % template_vars) return []
def install(self): egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) output = WRAPPER_TEMPLATE % dict( wsgi_module=self.options["wsgi-module"], syspath=",\n ".join((repr(p) for p in path)), initialization=self.options.get('initialization', ''), finalization=self.options.get('finalization', ''), ) target = self.options.get("target") if target is None: location = os.path.join( self.buildout["buildout"]["parts-directory"], self.name) if not os.path.exists(location): os.mkdir(location) self.options.created(location) target = os.path.join(location, "wsgi") else: outputdir, filename = os.path.split(os.path.realpath(target)) if not os.path.exists(outputdir) and self.make_target_dir: os.makedirs(outputdir) self.options.created(target) f = open(target, "wt") f.write(output) f.close() exec_mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH os.chmod(target, os.stat(target).st_mode | exec_mask) self.options.created(target) return self.options.created()
def install(self): bin_dir = self.buildout['buildout']['bin-directory'] egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) template_vars = { 'python': self.buildout['buildout']['executable'], 'pypath': ",\n ".join((repr(p) for p in path)), 'config': self.options['ini_file'], 'buildout_dir': self.buildout['buildout']['directory'], 'script_path': bin_dir, 'script_name': self.options['script_name'], 'initialization': self.options.get('initialization', ''), } wsgi_script = '%s/%s.wsgi' % (bin_dir, self.options['script_name']) open(wsgi_script, 'w').writelines(WSGI_TEMPLATE % template_vars) os.chmod(wsgi_script, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) if self.options.get('apache_config', None): open(self.options['apache_config'], 'w').writelines(APACHE_SKEL_TEMPLATE % template_vars) return []
def install(self): egg = Eggs(self.buildout, self.options["recipe"], self.options) reqs, ws = egg.working_set() path = [pkg.location for pkg in ws] extra_paths = self.options.get('extra-paths', '') extra_paths = extra_paths.split() path.extend(extra_paths) output = WRAPPER_TEMPLATE % dict( syspath=",\n ".join((repr(p) for p in path))) location = self.buildout["buildout"]["bin-directory"] if not os.path.exists(location): os.mkdir(location) self.options.created(location) target = os.path.join(location, self.name) f = open(target, "wt") f.write(output) f.close() os.chmod(target, 0755) self.options.created(target) return self.options.created()
def make_wsgi_script(recipe, buildout): """Build the script for Apache/mod_wsgi """ # Late import: zc.recipe.egg may not be installed when executing 1st # function from zc.recipe.egg.egg import Eggs app_egg = recipe['egg'] wsgi_filepath = recipe['script'] app_mod, app_obj = recipe['app'].rsplit('.', 1) # 'a.b.c.d' -> 'a.b.c', 'd' working_dir = recipe['working_dir'] relative_paths = recipe["relative-paths"] reqs, ws = Eggs(buildout, app_egg, recipe).working_set() egg_paths = [pkg.location for pkg in ws] if relative_paths == "false": src_egg_paths = ',\n'.join([" '{0}'".format(path) for path in egg_paths]) else: src_egg_paths = ',\n'.join(["join(base, '{0}')".format("/".join(path.split("/")[-2:])) for path in egg_paths]) src_egg_paths = "base, \n%s" % src_egg_paths with open(wsgi_filepath, 'w') as fh: fh.write(WSGISCRIPT_TEMPLATE.format(src_egg_paths, app_mod, app_obj, working_dir)) return
def install(self): """ Recipe install function. """ # Helper functions def split(s): """ Template filter splitting on any whitespace. """ return re.split("\s+", s.strip()) def as_bool(s): """ Template filter which translates the given string into a boolean. """ return s.lower() in ("yes", "true", "1", "on") def strip_dict(d): """ Strips the values of a dictionary in place. All values are assumed to be strings. The same dictionary object is returned. """ for k, v in d.iteritems(): d[k] = v.strip() return d # Validate template and target lists template_files = split(self.options["template-file"]) target_files = split(self.options["target-file"]) if len(template_files) != len(target_files): raise zc.buildout.UserError( "The number of template and target files must match") # Validate and normalise target executable option target_executables = split(self.options.get("target-executable", "false")) target_executables = [as_bool(v) for v in target_executables] if len(target_executables) == 1: value = target_executables[0] target_executables = (value for i in xrange(len(template_files))) else: if len(target_executables) != len(template_files): raise zc.buildout.UserError("The number of target executables" "must 0, 1 or match the number of template files") # Assemble lists files = zip(template_files, target_files, target_executables) # Assemble template context context = strip_dict(dict(self.options)) # Handle eggs specially if "eggs" in context: log.info("Making working set out of the eggs") eggs = Eggs(self.buildout, self.options["recipe"], self.options) names, eggs = eggs.working_set() context["eggs"] = eggs # Make options from other parts available. part_options = self.buildout if 'parts' not in context.keys(): context.update({'parts': part_options}) else: log.error("You should not use parts as a name of a variable," " since it is used internally by this receipe") raise zc.buildout.UserError("parts used as a variable in %s" % self.name) # Set up jinja2 environment jinja2_env = self._jinja2_env(filters={ "split": split, "as_bool": as_bool, "type": type, }) # Load, render, and save files for template_file, target_file, executable in files: template = self._load_template(jinja2_env, template_file) output = template.render(**context) # Make target file target_file = os.path.abspath(target_file) self._ensure_dir(os.path.dirname(target_file)) fp = open(target_file, "wt") fp.write(output) fp.close() # Chmod target file if executable: os.chmod(target_file, 0755) self.options.created(target_file) return self.options.created()
def install(self): """ Recipe install function. """ # Helper functions def split(s): """ Template filter splitting on any whitespace. """ return re.split("\s+", s.strip()) def as_bool(s): """ Template filter which translates the given string into a boolean. """ return s.lower() in ("yes", "true", "1", "on") def strip_dict(d): """ Strips the values of a dictionary in place. All values are assumed to be strings. The same dictionary object is returned. """ for k, v in d.iteritems(): d[k] = v.strip() return d # Validate template and target lists template_file_option = self.options.get( "template-file", self.options.get("input") ) target_file_option = self.options.get( "target-file", self.options.get("output") ) template_files = split(template_file_option) target_files = split(target_file_option) if len(template_files) != len(target_files): raise zc.buildout.UserError( "The number of template and target files must match") # Validate and normalise target executable option target_executables = split(self.options.get("target-executable", "false")) target_executables = [as_bool(v) for v in target_executables] if len(target_executables) == 1: value = target_executables[0] target_executables = (value for i in xrange(len(template_files))) else: if len(target_executables) != len(template_files): raise zc.buildout.UserError("The number of target executables" "must 0, 1 or match the number of template files") # Assemble lists files = zip(template_files, target_files, target_executables) # Assemble template context context = strip_dict(dict(self.options)) # Handle eggs specially if "eggs" in context: log.info("Making working set out of the eggs") eggs = Eggs(self.buildout, self.options["recipe"], self.options) names, eggs = eggs.working_set() context["eggs"] = eggs # Make recursive dict to be enable access dashed values. context['context'] = context # Make options from other parts available. part_options = dict(self.buildout) if 'parts' not in context.keys(): context.update({'parts': part_options}) else: log.error("You should not use parts as a name of a variable," " since it is used internally by this receipe") raise zc.buildout.UserError("parts used as a variable in %s" % self.name) filters = self.options.get('jinja2_filters') if filters: jinja2_filters = {} filters = filters.split() for filter_ in filters: try: jinja2_filters[filter_.split('.')[-1]] = resolve_dotted(filter_) except ImportError, e: raise zc.buildout.UserError("Filter '%s' not found.\n%s" % (filter_, e))
def install(self): """ Recipe install function. """ parse_list = lambda s: s.strip().split() # Validate template and target lists template_files = parse_list(self.options["template-file"]) target_files = parse_list(self.options["target-file"]) if len(template_files) != len(target_files): raise zc.buildout.UserError( "The number of template and target files must match") # Validate and normalise target executable option target_executables = parse_list(self.options.get("target-executable", "false")) target_executables = [as_bool(v) for v in target_executables] if len(target_executables) == 1: value = target_executables[0] target_executables = (value for i in range(len(template_files))) else: if len(target_executables) != len(template_files): raise zc.buildout.UserError("The number of target executables" "must 0, 1 or match the number of template files") # Assemble lists files = zip(template_files, target_files, target_executables) # Assemble template context context = {k: v.strip() for k, v in self.options.items()} # Handle eggs specially if "eggs" in context: log.info("Making working set out of the eggs") eggs = Eggs(self.buildout, self.options["recipe"], self.options) names, eggs = eggs.working_set() context["eggs"] = eggs # Make options from other parts available. part_options = self.buildout if 'parts' not in context: context.update({'parts': part_options}) else: log.error("You should not use parts as a name of a variable," " since it is used internally by this receipe") raise zc.buildout.UserError("parts used as a variable in {}".format(self.name)) # Set up jinja2 environment jinja2_env = self.create_jinja2_env( filters={ "as_bool": as_bool, "shell_quote": quote, }, builtins={ "randomstring": randomstring, }) # Load, render, and save files for template_file, target_file, executable in files: template = get_template(jinja2_env, template_file) output = template.render(**context) # Make target file target_file = os.path.abspath(target_file) ensure_dir(os.path.dirname(target_file)) fp = open(target_file, "wt") fp.write(output) fp.close() # Chmod target file if executable: os.chmod(target_file, 0o755) self.options.created(target_file) return self.options.created()
def install(self): """ Recipe install function. """ # Helper functions def split(s): """ Template filter splitting on any whitespace. """ return re.split(r'\s+', s.strip()) def as_bool(s): """ Template filter which translates the given string into a boolean. """ return s.lower() in ("yes", "true", "1", "on") def strip_dict(d): """ Strips the values of a dictionary in place. All values are assumed to be strings. The same dictionary object is returned. """ for k, v in d.items(): d[k] = v.strip() return d # Validate template and target lists template_file_option = self.options.get( "template-file", self.options.get("input"), ) target_file_option = self.options.get( "target-file", self.options.get("output"), ) template_files = split(template_file_option) target_files = split(target_file_option) if len(template_files) != len(target_files): raise zc.buildout.UserError( "The number of template and target files must match") # Validate and normalise target executable option target_executables = split( self.options.get("target-executable", "false")) target_executables = [as_bool(v) for v in target_executables] if len(target_executables) == 1: value = target_executables[0] target_executables = (value for i in range(len(template_files))) else: if len(target_executables) != len(template_files): raise zc.buildout.UserError( "The number of target executables" "must 0, 1 or match the number of template files") # Assemble lists files = zip(template_files, target_files, target_executables) # Assemble template context context = strip_dict(dict(self.options)) # Handle eggs specially if "eggs" in context: log.info("Making working set out of the eggs") eggs = Eggs(self.buildout, self.options["recipe"], self.options) names, eggs = eggs.working_set() context["eggs"] = eggs # Make recursive dict to be enable access dashed values. context['context'] = context # Make options from other parts available. part_options = SafeBuildout(self.buildout) if 'parts' not in context.keys(): context.update({'parts': part_options}) else: log.error("You should not use parts as a name of a variable," " since it is used internally by this recipe") raise zc.buildout.UserError("parts used as a variable in %s" % self.name) filters = self.options.get('jinja2_filters') if filters: jinja2_filters = {} filters = filters.split() for filter_ in filters: try: jinja2_filters[filter_.split('.')[-1]] = resolve_dotted( filter_) except ImportError as e: raise zc.buildout.UserError("Filter '%s' not found.\n%s" % (filter_, e)) else: jinja2_filters = {} filters = { "split": split, "as_bool": as_bool, "type": type, "eval": eval, "re_escape": re.escape, } filters.update(jinja2_filters) # Set up jinja2 environment jinja2_env = self._jinja2_env(filters=filters) # Load, render, and save files for template_file, target_file, executable in files: template = self._load_template(jinja2_env, template_file) output = template.render(**context) # Make target file target_file = os.path.abspath(target_file) self._ensure_dir(os.path.dirname(target_file)) fp = open(target_file, "wt") fp.write(output) fp.close() # Chmod target file if executable: os.chmod(target_file, 0o755) self.options.created(target_file) return self.options.created()