0

I am trying to create a module to hold configurations for a Fabric file. This configuration file will hold project dependent settings, so I can use the same fabfile for all our projects.

I want the fabfile to look like this:

import config
from fabric.api import local

def deploy(env='staging'):
    config.env = env
    local("xcopy {project_dir} {deploy_target} /u /r /y".format(project_dir=config.project_dir, 
                                                                deploy_target=config.deploy_target))
    #Ok, this will be more involved than that, but it is enough to explain my problem

and the config file to look like this:

env = 'staging'
project_dir = r'c:\some\unimportant\path'
deploy_target = r'c:\some\target\path\based\on\{env}'.format(env=env)

So I can use: fab deploy or fab deploy:staging to deploy to the staging environment and fab deploy:production to deploy to the production environment.

What I am trying to figure out is how to update the variables in the module when the env variable gets changed.

I want my config file as simple as possible, ideally, just variable assignments, but I could live with a few functions if really required. There will be a lot of variables in the settings file so updating the values in a function, using the global keyword would look really ugly.

Martin
  • 5,954
  • 5
  • 30
  • 46
  • Does the config file need to be permanently changed when you deploy it, or is it OK if the values go back to their defaults after the deployment finishes? The latter should be easy, but the former is quite a bit more complicated. – Blckknght Sep 07 '12 at 19:04
  • The config file is to be unique on a per project basis. The settings in the config.py module are pretty much set in stone. They won't change very often. There will usually be only 2-3 environments per project. The path are pretty similar, with just a few characters changing, sometimes a server name, but that is about it. – Martin Sep 07 '12 at 19:08
  • It is ok if they return to their defaults after deployment, since all commands in the fabfile will take an env argument which will set the values accordingly in the config module(if I manage to achieve what I am trying to do). – Martin Sep 07 '12 at 19:15

2 Answers2

0

Store you configuration parameters in a dictionary.

So, in a directory with an __init__.py file have a file called my_config.py (note, this will have to be in your python_path) with something like:

my_params = {'env': 'staging',
             'project_dir': r'c:\some\unimportant\path',
             'deploy_target': r'c:\some\target\path\based\on\staging',
            }

I'm not sure how you plan on passing your configuration settings to your fabfile, but with a dictionary in a configuration file, accessing your settings are pretty simple. If you have all of your configuration settings for a single project defined in a single dictionary (as above) then the following could go in your fabfile:

config = __import__('my_config')

At which point you can access your configuration settings with:

env = config.my_params['env']

Again, I'm not entirely sure how you plan on passing in which configuration you're looking for, so comment if I missed the mark. In any case, dictionaries are the pythonic method of storing information like this, and make it easy to import those values if you need them.

Wilduck
  • 13,822
  • 10
  • 58
  • 90
  • Currently, I have a folder called Deploy which contains fabfile.py and config.py. This folder is to be copied in each projects we have. When we create a new project, only the config.py file should be updated. What I want to do is to be able to call `import config` in the fabfile. After the config module has been imported, I want to be able to set the environment by calling `config.env = 'environment_name'`. Changing the value of config.env should update the values of all the settings dependant on this value in the config module. – Martin Sep 07 '12 at 19:05
  • I would prefer not to have a dict per environment. – Martin Sep 07 '12 at 19:05
  • Okay, I think I see what you're saying. I'm going to maintain that using dictionaries is the easiest way to do what you want. The most substantial change is that you'll have to use bracket syntax instead of dot syntax to access your configuration settings. If you want to go a route without dictionaries you're going to be using what I would consider to be hacks. Is there a specific reason why you'd rather not use dictionaries? – Wilduck Sep 07 '12 at 19:54
  • The config file might be maintained by non python programmers, so it has to be as simple as possible. With the dict, wouldn't I have to maintain one dict per env per project ? – Martin Sep 07 '12 at 21:38
0

I think to get variables in your config module being updated whenever you change config.env, you're going to need to use at least one function.

The simplest approach might be to drop env as a variable and instead make a setEnv function (which sets all the other module variables to appropriate values). Another option is be to leave env be, but to call functions to get the other values (e.g. config.get_deploy_target()).

It's even possible to make the module look like it contains only values, when in fact some or all of them are calculated on the fly, based on env or other values. This requires doing some tricks with the Python module lookup system, so that you're actually reading values from a class instance, rather than an actual module. This allows the code that uses the config module to be simple, but at the cost of making config.py itself much more complicated:

# config.py

class Config(object):
    def __init__(self):
        self.env = "staging"
        self.project_dir = r'c:\some\unimportant\path'

    @property
    def deploy_target(self):
        return r'c:\some\target\path\based\on\{env}'.format(env=self.env)

import sys
sys.modules["config"] = Config()
Blckknght
  • 100,903
  • 11
  • 120
  • 169