Commits

Manabu TERADA committed e6ee7f0

finished base functions

  • Participants
  • Parent commits 3083922

Comments (0)

Files changed (5)

 1.0a1 (xxxx-xx-xx)
 ------------------
 
-- Created recipe with ZopeSkel
-  [Manabu TERADA]
+- Created recipe with ZopeSkel [Manabu TERADA]
+- Created base function & supported hg only, (no supporting git yet) [Manabu TERADA]
-.. contents::
+Requirement
+================
 
-.. Note to recipe author!
-   ---------------------
-   Update the following URLs to point to your:
-   
-   - code repository
-   - bug tracker 
-   - questions/comments feedback mail 
-   (do not set a real mail, to avoid spams)
+This recipe supports Python 2.6+, because using 'json' module.
 
-   Or remove it if not used.
 
-- Code repository: http://svn.somewhere.com/...
-- Questions and comments to somemailing_list
-- Report bugs at http://bug.somewhere.com/..
+Information
+================
 
+- Code repository: https://bitbucket.org/cmscom/c2.recipe.bitbucketbk
+- Questions and comments to terada@cmscom.jp
+- Report bugs at https://bitbucket.org/cmscom/c2.recipe.bitbucketbk/issues
+
+
+Simple usage
+==============
+
+Modify buildout.cfg ::
+
+    parts = 
+       ...
+       bitbucketbk
+
+    [bitbucketbk]
+    recipe = c2.recipe.bitbucketbk
+    username = xxxxxxxxxxxxx
+    password = xxxxxxxxxxxxxxxxxx
+	location = backups
+
+Run the buildout ::
+
+    bin/buildout -N
+
+You can use backup scripts ::
+
+    bin/bitbucketbk
+
+You will see backups in  `var/backups`.
+

c2/recipe/bitbucketbk/README.txt

 
 The recipe supports the following options:
 
-.. Note to recipe author!
-   ----------------------
-   For each option the recipe uses you should include a description
-   about the purpose of the option, the format and semantics of the
-   values it accepts, whether it is mandatory or optional and what the
-   default value is if it is omitted.
+username
+    username of bitbucket.org
 
-option1
-    Description for ``option1``...
+password
+    password of bitbucket.org
 
-option2
-    Description for ``option2``...
-
+location
+    backup location
+    default : buckups
 
 Example usage
 =============
 
-.. Note to recipe author!
-   ----------------------
-   zc.buildout provides a nice testing environment which makes it
-   relatively easy to write doctests that both demonstrate the use of
-   the recipe and test it.
-   You can find examples of recipe doctests from the PyPI, e.g.
-   
-     http://pypi.python.org/pypi/zc.recipe.egg
-
-   The PyPI page for zc.buildout contains documentation about the test
-   environment.
-
-     http://pypi.python.org/pypi/zc.buildout#testing-support
-
-   Below is a skeleton doctest that you can start with when building
-   your own tests.
-
 We'll start by creating a buildout that uses the recipe::
 
     >>> write('buildout.cfg',
     ... """
     ... [buildout]
-    ... parts = test1
+    ... parts = bitbucketbk
     ...
-    ... [test1]
+    ... [bitbucketbk]
     ... recipe = c2.recipe.bitbucketbk
-    ... option1 = %(foo)s
-    ... option2 = %(bar)s
-    ... """ % { 'foo' : 'value1', 'bar' : 'value2'})
+    ... username = %(username)s
+    ... password = %(password)s
+    ... location = %(location)s
+    ... """ % { 'username' : 'value1', 'password' : 'value2', 'location' : 'value3'})
 
 Running the buildout gives us::
 
     >>> print 'start', system(buildout) 
     start...
-    Installing test1.
-    Unused options for test1: 'option2' 'option1'.
+    Installing bitbucketbk.
+    Unused options for bitbucketbk: 'location' 'password' 'username'.
     <BLANKLINE>
 
 
+Backup
+=============
+
+Calling ``bin/bitbucketbk``
+
+    >>> import sys
+    >>> write('bin', 'bitbucketbk',
+    ...       "#!%s\nimport sys\nprint ' '.join(sys.argv[1:])" % sys.executable)
+    >>> dontcare = system('chmod u+x bin/bitbucketbk')
+
+By default, backups are done in ``var/bitbucketbk``::
+
+    >>> print system('bin/bitbucketbk')
+    ...

c2/recipe/bitbucketbk/__init__.py

 # -*- coding: utf-8 -*-
 """Recipe bitbucketbk"""
 
+import os
+import zc.buildout
+import logging
+
+logger = logging.getLogger('bitbucketbk')
+
 class Recipe(object):
     """zc.buildout recipe"""
 
     def __init__(self, buildout, name, options):
         self.buildout, self.name, self.options = buildout, name, options
+        bin_dir = self.buildout['buildout']['bin-directory']
+        buildout_dir = os.path.join(bin_dir, os.path.pardir)
+        options.setdefault('buildout_dir', buildout_dir)
+        
+        options.setdefault('username', '')
+        options.setdefault('password', '')
+        options.setdefault('location', 'backups')
+        
+        python = buildout['buildout']['python']
+        options['executable'] = buildout[python]['executable']
+        options['bin-directory'] = buildout['buildout']['bin-directory']
+        options['backup_name'] = self.name
+        check_for_true(options, [])
+        self.options = options
 
     def install(self):
         """Installer"""
         
         # Return files that were created by the recipe. The buildout
         # will remove all returned files upon reinstall.
-        return tuple()
+        buildout_dir = self.options['buildout_dir']
+        backup_location = construct_path(
+            buildout_dir, self.options['location'])
+
+        if not os.path.isdir(backup_location):
+            os.makedirs(backup_location)
+            logger.info('Created %s', backup_location)
+
+        #
+        initialization_template = """
+import logging
+loglevel = logging.INFO
+# Allow the user to make the script more quiet (say in a cronjob):
+# if sys.argv[-1] in ('-q', '--quiet'):
+#     loglevel = logging.WARN
+# logging.basicConfig(level=loglevel,
+#     format='%%(levelname)s: %%(message)s')
+username = %(username)r
+password = %(password)r
+location = %(location)r
+"""
+        opts = self.options.copy()
+        initialization = initialization_template % opts
+        requirements, ws = self.egg.working_set(['c2.recipe.bkups3',
+                                                 'zc.buildout',
+                                                 'zc.recipe.egg'])
+        
+        scripts = zc.buildout.easy_install.scripts(
+            [(self.options['backup_name'],
+              'c2.recipe.bitbucketbk.backuprunner',
+              'backup_main')],
+            #requirements,
+            ws, self.options['executable'], self.options['bin-directory'],
+            arguments=('username, password, location'),
+            initialization=initialization)
+        return scripts
+
 
     def update(self):
         """Updater"""
         pass
+
+
+def check_for_true(options, keys):
+    """Set the truth options right.
+
+    Default value is False, set it to True only if we're passed the string
+    'true' or 'True'. Unify on a capitalized True/False string.
+
+    """
+    for key in keys:
+        if options[key].lower() == 'true':
+            options[key] = 'True'
+        else:
+            options[key] = 'False'
+
+def construct_path(buildout_dir, path):
+    """Return absolute path, taking into account buildout dir and ~ expansion.
+
+    Normal paths are relative to the buildout dir::
+
+      >>> buildout_dir = '/somewhere/buildout'
+      >>> construct_path(buildout_dir, 'var/filestorage/Data.fs')
+      '/somewhere/buildout/var/filestorage/Data.fs'
+
+    Absolute paths also work::
+
+      >>> construct_path(buildout_dir, '/var/filestorage/Data.fs')
+      '/var/filestorage/Data.fs'
+
+    And a tilde, too::
+
+      >>> userdir = os.path.expanduser('~')
+      >>> desired = userdir + '/var/filestorage/Data.fs'
+      >>> result = construct_path(buildout_dir, '~/var/filestorage/Data.fs')
+      >>> result == desired
+      True
+
+    Relative links are nicely normalized::
+
+      >>> construct_path(buildout_dir, '../var/filestorage/Data.fs')
+      '/somewhere/var/filestorage/Data.fs'
+
+    Also $HOME-style environment variables are expanded::
+
+      >>> import os
+      >>> os.environ['BACKUPDIR'] = '/var/backups'
+      >>> construct_path(buildout_dir, '$BACKUPDIR/myproject')
+      '/var/backups/myproject'
+
+    """
+    path = os.path.expanduser(path)
+    path = os.path.expandvars(path)
+    combination = os.path.join(buildout_dir, path)
+    normalized = os.path.normpath(combination)
+    return normalized

c2/recipe/bitbucketbk/backuprunner.py

+#!/usr/bin/env python
+# encoding: utf-8
+"""
+backuprunner.py
+
+Created by Manabu Terada on 2012-01-08.
+Copyright (c) 2012 CMScom. All rights reserved.
+"""
+
+import sys
+import os
+import json
+
+from urllib2 #import urlopen, HTTPBasicAuthHandler, build_opener, install_opener
+import base64
+
+from mercurial import hg, ui, commands
+
+BITBUCKET_API = "https://api.bitbucket.org/1.0/"
+BITBUCKET_BASE_URL = "https://%(user)s:%(passwd)s@bitbucket.org/"
+
+def get_repositories(user, passwd):
+    """no Longin"""
+    api_url = BITBUCKET_API + "users/" + user
+
+    authString = base64.encodestring('%s:%s' % (user, passwd))
+    headers = {'Authorization':"Basic %s" % authString}
+    req = urllib2.Request(api_url, None, headers)
+    bitbucket_obj = urllib2.urlopen(req)
+    
+    repos = json.load(bitbucket_obj).get('repositoryes', [])
+    for repo in repos:
+        yield repo.get('name', None), repo.get('scm', '')
+
+def has_repo(repo_name, location):
+    if repo_name in os.listdir(location):
+        return True
+    else:
+        return False
+
+def create_hg_repo(repo_url, location):
+    # repo = hg.repository(ui.ui(), repo_url)
+    commands.clone(ui.ui(), repo_url, dest=location, insecure=True) 
+    
+
+def get_hg_data(repo_url, location):
+    repo = hg.repository(ui.ui(), location)
+    commands.pull(ui.ui(), repo, source=repo_url) 
+    
+
+def backup_main(username, password, location):
+    """Main method, gets called by generated bin/bitbucketbk.
+    """
+    repos = get_repositories(user, passwd)
+    print list(repos)
+    for repo_name, scm in repos:
+        if scm == "hg":
+            base_url = BITBUCKET_BASE_URL % {'user' : username, 'passwd' : password}
+            repo_url = base_url + user + '/' + repo_name
+            folder_location = os.path.join(location, repo_name)
+            if not has_repo(repo_name, location):
+                create_hg_repo(repo_url, folder_location)
+            else:
+                get_hg_data(repo_url, folder_location)
+        else:
+            return None
+
+if __name__ == '__main__':
+    backup_main()
+