{ "info": { "author": "Michael Elsd\u00f6rfer", "author_email": "michael@elsdoerfer.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: BSD License" ], "description": "wsconfig\n========\n\nThis is a small utility I am using to auto-configure my workstations:\nInstalling packages, linking dotfiles etc.\n\nDesign goals (aka \"why not a shell script?\"):\n\n- Provide a tagging system to select which commands to run on a particular\n system.\n\n- Provide high-level commands, so the same script may on different operating\n systems with less duplication.\n\n- Simplify certain things, like symlinking: ``ln`` on Linux requires knowledge\n of the relative path between target and source.\n\nI put my wsconfig script together with my dotfiles and even some binaries\nin Dropbox.\n\n\nLanguage\n--------\n\nPut each command on it's own line::\n\n mkdir ~/bla\n link vimrc ~/.vimrc\n $ echo 'hello world' >> /tmp/test\n\n``mkdir`` and ``link`` are high-level commands implemented in Python. ``$`` is\nrun directly in the shell. See further below for all commands.\n\nTo restrict commands to a specific operating system::\n\n sys:osx {\n $ defaults write NSGlobalDomain AppleShowScrollBars -string \"Always\"\n }\n\n\nThe list of predefined tags on the current system can be displayed by running\n``wsconfig --defaults``. Tags that you might see there are ``sys:windows``,\n``sys:linux``, ``sys:macos``, but also ``sys:ubuntu``, ``sys:ubuntu:natty``\nor ``sys:windows:7``.\n\nCustom tags can be used::\n\n DevEnvironment {\n dpkg python-setuptools\n }\n\n\nBecause the tag in the above example starts with an uppercase letter,\n``wsconfig`` will consider it \"public\" and present it to you as a choice to\ndefine on the command line. You can use lowercase tags internally to split\ncommands into blocks::\n\n DevEnvironment {\n define php\n define python\n }\n\n python {\n dpkg python-setuptools\n $ easy_install pip\n }\n\n php {\n dpkg php5-cli php5-xdebug\n }\n\nAt this point it is worth pointing out that even though ``php`` and ``python``\nabove appears to look like \"packages\" of some sort, thinking about them in\nthta way is not correct. They are really \"if conditions\", and the commands are\nguaranteed to run in the order they appear in the script file - i.e., first\nthe commands in the ``python`` block, then those in the ``php`` block.\n\nWhat's more, the ``define`` statements are executed sequentially as well, thus\nthe following will not be want you want, because the ``define`` appears to late\nto have any actual effect::\n\n php {\n dpkg php5-cli\n }\n DevEnvironment {\n define php\n }\n\n\nYou can nest conditions::\n\n python {\n sys:linux { dpkg: python-setuptools }\n sys:osx { $ brew install python-setuptools }\n }\n\n\nA condition can also specify multiple tags. The following is the exact\nequivalent to the above. What you prefer is a matter of style::\n\n python sys:linux { dpkg: python-setuptools }\n python sys:osx { $ brew install python-setuptools }\n\n\nIf you combine a capitalized tag with a system tag, the capitalized tag will\nonly be offered as choice when running on that system::\n\n sys:linux VirtualMachine {\n $ gconftool-2 -s /apps/gnome-screensaver/lock_enabled --type=bool false\n }\n\nWhen running the above on Windows, ``wsconfig`` is smart enough to realize\nthat there are no commands backing the ``VirtualMachine`` tag, and will\nignore it.\n\nNested conditions, and tags combined with whitespace or both treated as ``AND``.\nYou can als do ``OR``, by using a comma::\n\n sys.linux, sys.osx { link: ssh/config ~/.ssh/config }\n\n\n``AND`` and ``OR`` can be combined (but complex expressions using brackets\nare currently not supported)::\n\n sys.linux, sys.windows Cygwin {\n define tarsnap\n }\n\nAbove, the tag ``tarsnap`` will only be defined if we're on Linux, or if we're\non Windows *and* the ``Cygwin`` tag has been selected (remember, since it's\nuppercase, the user will be presented ``Cygwin`` as a choice).\n\nTags can also be negated. If you want to install Thunderbird only when not in\na virtualized environment::\n\n sys:linux !Vm {\n dpkg thunderbird\n }\n\nFinally, you can also use comments, of course:\n\n # To fix monospace fonts in Java apps\n # https//bugs.launchpad.net/ubuntu/+source/sun-java6/+bug/569396\n dpkg ttf-dejavu\n\nThere is no syntax for multiline comments, but if you're paying attention,\nthere's an obvious way to implement them: Use a tag selector to disable a\nblock of statements::\n\n comment {\n sys:linux (\n ...\n }\n }\n\n\nVariables\n---------\n\nSometimes you want to use machine-specific values in the script; ``wsconfig``\nhas a variable system that allows you to do this. You will be asked to provide\nvalues for all the variables used in the effective script (that is, you won't\nbe bothered with variables that are only used in commands that won't run) at\nthe start of an ``apply`` run.\n\nThe syntax uses a double-@ notation::\n\n $ sudo scutil --set ComputerName \"@@hostname@@\"\n\nVariables are case-sensitive.\n\n\nRoot usage\n----------\n\nYou'll want to run some commands as root, but usually not all - you want your\nconfig files to be created with you as the owner. ``wsconfig`` uses ``sudo``\nto run commands as root.\n\nSome commands, like ``dpkg``, use sudo by default. Others, like ``link`` or\n``mkdir``, to run them as root, you can prefix them with the term ``sudo``::\n\n sudo mkdir /opt/foo\n\nFor shell commands, you are free to do whatever you like, since they will be\npiped directly to the shell::\n\n $ sudo apt-get update\n $ su -c \"apt-get update\"\n\n\nAvailable commands\n------------------\n\n$\n Execute something in the shell. These are not parsed like other commands -\n instead, content is given to the shell as-is. A multiline shell syntax\n is also supported::\n\n $: set -e\n FOO=bar\n echo $FOO\n\n Whitespace is significant here. After the colon, every line that is\n indented at least as many characters as the position of the colon will\n be considered part of the shell command. The first line with an indentation\n level equal or lower than the column will be the next regular command::\n\n $:\n FOO=bar\n echo $FOO\n remind \"This is no longer shell\"\n\ndpkg\n Install dpkg packages on Debian-systems, using apt-get.\n\nbrew\n Installs a formula via homebrew; Preferred over the native command\n because the latter returns an error code if the requested formula\n is already installed.\n\nlink\n Create a symbolic link. Both pathnames can be relative to the config\n file itself, wsconfig will properly construct the link target path.\n\n The command will fail if the target file already exists with a different\n link target than the one you wish to say. You can add an ``-f`` option\n to force a link overwrite::\n\n link -f virtualenvs/postmkvirtualenv ~/.virtualenvs/postmkvirtualenv\n\nmkdir\n Creates a directory, if it does't exist yet.\n\npip\n Install a Python package using \"pip\". pip needs to be available.\n\nwine\n Run a windows executable via wine.\n\nremind\n Remind yourself of some manual setup step. These will be collected and\n presented at the end of the script.\n\nensure_line\n Add a line to the given file, but only if it doesn't exist yet::\n\n ensure_line ~/.bashrc \"~/.bashrc_michael\"\n\n\n\nApplying a config file:\n----------------------\n\n::\n\n $ wsconfig my_config_file\n Available choices:\n Dev\n Vm\n $ wsconfig my_config_file apply Development\n\n\nTagging in-depth\n----------------\n\nHere are some extended thoughts on the tagging system, and my thinking about\nit (currently still an ongoing process).\n\nInitially, the ``define`` command was considered out-of-sequence. It was being\npreprocessed such that the following worked as expected::\n\n foo bar qux { remind \"Stop drinking\" }\n bar { define qux }\n foo { define bar }\n define foo\n\nWe would traverse the document until no new ``defines`` are activated, and then\nuse all discovered tags as the starting set. However, this seemed kid of\nschizophrenic. The inclination would be to use it like this::\n\n sys.linux {\n ...\n foo\n ...\n\n define chrome\n\n ...\n }\n\nI.e., as a sort of \"call\" or \"include\", with the ``chrome`` selector serving\nto encapsulate the relevant commands visually/structurally. And while the above\ndoes indeed work, even now, if the ``chrome`` block comes after it, the whole\npoint of this being supposed to be an include is that it shouldn't matter where\nin the file it is located.\nBut that's not really what ``define`` is. If above the ``foo`` command fails,\nand the script is aborted at this point, you'd expect a ``chrome`` block to not\nbe processed. However, if ``defines`` are preprocessed as was the case, then\nsuch a block might have already run.\n\nSo to combat that, I wanted to add restrictions on ``define``, such that they\nmay only be used in selectors that have no other commands::\n\n sys:linux {\n define base-linux\n define foo\n }\n Development {\n define base-development\n define python\n define php\n }\n\n\nIt would be an artificial restriction intended to make things clearer, but as\nyou can see, it leads to an entirely different style of writing config files.\nYou'd be forced to put ALL commands within faux selectors (like ``base-linux``),\nwhich is ugly, while at best making the problem, that here is no longer a\nclear order of execution, only somewhat more bearable (if the above looks clear,\nthink about a large file with sequential commands being intermixed with such\npackages.\n\nIt just doesn't make sense to encourage using ``define`` as an inclusion\nconcept, which is what preprocessing them in this way does. It's schizophrenic\nbecause it is confused about whether tag selectors are what the claim to be,\n\"if conditions\", or whether they should be viewed as \"packages\".\n\nInstead, if needed, a package concept could be introduced separately::\n\n @chrome (\n ...\n )\n\n sys:linux {\n ....\n @chrome # Include the chrome package.\n }\n\nThe @()-syntax could indicate a package, NOT a selector, and they would only\never run when included (but only once). These could also have other uses, like\nindicating a \"unit of execution\", where errors would be caught, such that an\nerror in the package causes subsequent statements in the package to be skipped,\nbut further statements outside to be run.\n\nOn the other hand, introducing a different type of syntax might already be too\nmuch. This is supposed to be simple after all. There is another potential\nsolution: A multi-pass apply process. So if we take the example from before::\n\n sys.linux {\n ...\n foo\n ...\n\n define chrome\n ...\n }\n\nThen ``chrome`` would not be preprocessed. If the script ends with ``foo``,\nthen no ``chrome`` block will have run. Instead, code processing the document\ncomes across the ``define`` only when ``foo`` has already run, and when it\ndoes, it schedules another document traverse. The second time, commands that\nhave already run skipped, but commands newly unlocked by the tag are run now.\n\nThis might be the perfect solution because:\n - No extra syntax.\n - The order in which commands run is not any more confusing then with @(),\n and it could be used equally as effectively to structure code.\n - It avoids the main conceptional issue with the original ``define`` -\n that it was processed out-of-order.\n - The @() syntax would need to implement code to avoid running multiple\n times as well.\n - It fixes the problem that defines have now, that they have no effect\n if in the wrong order.\n\n----\n\n\nThere's a further aspect that I'm currently not happy with. Take the following\npieces of code::\n\n DevEnviron {\n Python {}\n Php {}\n }\n\n::\n\n DevEnviron {\n define python\n }\n python {\n Python3 {}\n }\n\nIn both cases, only the ``DevEnviron`` tag will be presented as a choice.\nWhy? ``wsconfig`` would either have to indiscriminately present all such tags\nas choices, as a flat list, without recognizing the dependencies, even though,\nin the first example, defining ``Python`` has no effect without also defining\n``DevEnviron`` (this could be an optional ``--all`` switch).\nOr it would have to present you with a tree of choices, i.e. recognizing the\ndependency between ``Dev`` and ``Python``. This could happen through a smart\nalgorithm, or by going through a multi-step choice process (choose\n``DevEnviron``, then choose ``Python``, after each step traversing the tree for\nnew tags that become available).\n\nInitially, I thought about validation rules that prevented such tags from being\n``hidden``, but that doesn't really make a lot of sense, and one reason is how\neasy it can be worked around. If this fails validation::\n\n Python {\n Dev {}\n }\n\nThen the following would bypass it, but have the same effect (the Python\ntag being useless without the Dev tag)::\n\n Dev {\n python { noop }\n }\n Python { define python }\n\n\n\n\n \nSimilar tools\n-------------\n\nhttps://github.com/technicalpickles/homesick\n", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/miracle2k/wsconfig", "keywords": null, "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "wsconfig", "package_url": "https://pypi.org/project/wsconfig/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/wsconfig/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://github.com/miracle2k/wsconfig" }, "release_url": "https://pypi.org/project/wsconfig/0.2/", "requires_dist": null, "requires_python": null, "summary": "A tiny utility to automatize setting up a new workstation; linking config files and installing packages.", "version": "0.2" }, "last_serial": 801739, "releases": { "0.2": [ { "comment_text": "", "digests": { "md5": "493d315bc9dc4e45f3a59e44d65ae94d", "sha256": "c944615c16212fc3941e3d4f01ac6a564b432218d6f3c10067d3da594cfb78ef" }, "downloads": -1, "filename": "wsconfig-0.2.tar.gz", "has_sig": false, "md5_digest": "493d315bc9dc4e45f3a59e44d65ae94d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20659, "upload_time": "2012-08-12T20:55:30", "url": "https://files.pythonhosted.org/packages/05/77/dc02d949fcdce8489e8f449fbba7a814831c01ba276f55a7aa663df3e03d/wsconfig-0.2.tar.gz" } ], "0.2.dev": [] }, "urls": [ { "comment_text": "", "digests": { "md5": "493d315bc9dc4e45f3a59e44d65ae94d", "sha256": "c944615c16212fc3941e3d4f01ac6a564b432218d6f3c10067d3da594cfb78ef" }, "downloads": -1, "filename": "wsconfig-0.2.tar.gz", "has_sig": false, "md5_digest": "493d315bc9dc4e45f3a59e44d65ae94d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20659, "upload_time": "2012-08-12T20:55:30", "url": "https://files.pythonhosted.org/packages/05/77/dc02d949fcdce8489e8f449fbba7a814831c01ba276f55a7aa663df3e03d/wsconfig-0.2.tar.gz" } ] }