예제 #1
0
    #print(installed)
    aur = AUR()
    #print(aur.info('mysql'))
    #[{'ID': 69409, 'NumVotes': 4, 'OutOfDate': 0, 'CategoryID': 2, 'FirstSubmitted': 1366917203, 'Version': '5.6.13-1', 'URL': 'https://www.mysql.com/products/community/', 'LastModified': 1375714132, 'Name': 'mysql', 'Maintainer': 'rustam', 'Description': 'A fast SQL database server', 'License': 'GPL', 'URLPath': '/packages/my/mysql/mysql.tar.gz'}]
    #print(aur.info(('mysql','heidisql')))
    #[{'NumVotes': 4, 'Version': '5.6.13-1', 'URL': 'https://www.mysql.com/products/community/', 'Name': 'mysql', 'License': 'GPL', 'FirstSubmitted': 1366917203, 'Maintainer': 'rustam', 'URLPath': '/packages/my/mysql/mysql.tar.gz', 'ID': 69409, 'OutOfDate': 0, 'LastModified': 1375714132, 'Description': 'A fast SQL database server', 'CategoryID': 2}, {'NumVotes': 9, 'ID': 65392, 'URL': 'http://www.heidisql.com/', 'Name': 'heidisql', 'License': 'GPL', 'FirstSubmitted': 1355313819, 'Maintainer': 'crush', 'URLPath': '/packages/he/heidisql/heidisql.tar.gz', 'Version': '7.0-2', 'OutOfDate': 1372029392, 'LastModified': 1355314287, 'Description': 'A lightweight, Windows based interface for managing MySQL and Microsoft SQL databases. (uses Wine).', 'CategoryID': 3}]
    #display_fields = ('LocalVersion','Version', 'LastModified')
    #aurpkg['LastModified'] = strftime('%Y-%m-%d %H:%M:%S', localtime(aurpkg['LastModified']))
    offical_repo = ['core', 'extra', 'community', 'multilib']
    for db in h.get_syncdbs():
        if db.name in offical_repo:
            for item in list(installed):
                if db.get_pkg(item.name):
                    installed.remove(item)
            #print(pkg)
            #pkgname = pkg.name
            #syncpkg = db.get_pkg(pkgname)
            #print(syncpkg)
    #print(installed)
    pkgs = [pkg.name for pkg in installed]
    for item in aur.info(pkgs):
        for localpkg in installed:
            if localpkg.name == item['Name']:
                if pyalpm.vercmp(item['Version'], localpkg.version) != 0:
                    if pyalpm.vercmp(item['Version'], localpkg.version) > 0:
                        eq = '\033[1;31m=>\033[0m'
                        #eq = '\033[1;37;40m=>\033[2;32;40m'
                    else:
                        eq = '<='
                    print(localpkg.name, localpkg.version, eq, item['Version'])
예제 #2
0
class Aurploader(object):
  """
  A user object for interactive actions.
  """

  def __init__(
    self,
    cookiejar_path=None,
    cookiejar=None,
    token=None,
    categories=None
  ):
    """
    cookiejar: a MozillaCookieJar object

    token: a user token for submitting form data

    categories: package categories
    """

    if cookiejar_path is None:
      cookiejar_path = get_default_cookiejar_path()
    self.cookiejar_path = cookiejar_path

    if cookiejar is None:
      self.cookiejar = MozillaCookieJar()
      self.load_cookies()
    else:
      self.cookiejar = cookiejar

    # TODO
    # Find way to use this with URL opener. (urlopen accepts a capath arg)
    # CA_PATH = '/etc/ssl/certs'
    self.opener = build_opener(HTTPCookieProcessor(self.cookiejar))
    self.token = token
    self.categories = categories

#     self.rpc = AUR(ttl=0, clean=False)
    self.rpc = AUR()



  def get_info(self, pkgname):
    """
    Get package information from the RPC interface.
    """
    for pkg in self.rpc.info(pkgname):
      return pkg


  def parse_pkgsubmit(self):
    """
    Parse the pkgsubmit page.

    This will return package categories along with hidden inputs such as the
    the token. If the returned values are empty then the user is not currently
    logged in, so it doubles as a login check.
    """
    parser = pkgsubmitParser()
    with self.opener.open(PKGSUBMIT_URL) as f:
      parser.feed(f.read().decode())
    if parser.token:
      self.token = parser.token
    self.categories = parser.categories



  def login(self, user=None, passwd=None, login_file=None, remember_me=True):
    """
    Log in to the AUR.
    """
    if login_file is not None:
      user, passwd = load_login_file(login_file)

    if user is None or passwd is None:
      self.rpc.log("logging in to the AUR")

    if user is None:
      user = input('Username: '******'user', user),
      ('passwd', passwd)
    ]

    if remember_me:
      data.append(('remember_me', '1'))

    data = urlencode(data).encode('UTF-8')

    with self.opener.open(LOGIN_URL, data) as f:
      pass



  # python3-AUR could be used to cache the data, but sometimes the data must be
  # fresh, such as when confirming the upload.
  def submit_package_form(
    self, pkginfo, action,
    confirm_delete=False, merge_into=None, comment=None, category=None,
  ):
    """
    Submit a form to the AUR.
    """
    ID = pkginfo['ID']
    url = AUR_URL + '/packages/{}/'.format(pkginfo['Name'])
    # Old form actions, converted to links with AUR 2.0
    do_actions = {
  #     'do_Vote'     : 'Vote',
  #     'do_UnVote'   : 'UnVote',
  #     'do_Notify'   : 'Notify',
  #     'do_UnNotify' : 'UnNotify',
  #     'do_Flag'     : 'Flag Out-of-date',
      'do_Disown'   : 'Disown Packages',
      'do_Delete'   : 'Delete Packages',
      'do_Adopt'    : 'Adopt Packages',
    }
    if action in do_actions:
      url = AUR_URL + '/packages/'
      data = [
        ('IDs[{!s}]'.format(ID), '1'),
        ('ID', ID),
        ('token', self.token),
        (action, do_actions[action])
      ]
      if confirm_delete:
        data.append(('confirm_Delete', '1'))
      if merge_into:
        data.append(('merge_Into', merge_into))

    elif action == 'comment':
      if comment:
        data = (
          ('ID', ID),
          ('token', self.token),
          ('comment', comment)
        )
      else:
        raise AurploaderError("no comment submitted")

    elif action == 'do_ChangeCategory':
      if category:
        data = (
          ('action', 'do_ChangeCategory'),
          ('category_id', category),
          ('token', self.token)
        )
      else:
        raise AurploaderError("no category submitted for do_ChangeCategory")

    elif action == 'do_DeleteComment':
      if category:
        data = (
          ('action', 'do_DeleteComment'),
          ('comment_id', comment_id),
          ('token', self.token),
          ('submit', '1')
        )
      else:
        raise AurploaderError("no category submitted for do_ChangeCategory")


    data = urlencode(data).encode('UTF-8')
    with self.opener.open(url, data) as f:
      pass



  def do_package_action(self, pkginfo, action):
    """
    Perform one of the link-based package actions.

    Use submit_package_form() for form-based actions.
    """
    actions = PACKAGE_ACTIONS

    if action in actions:
      url = AUR_URL + '/packages/{}/{}'.format(pkginfo['Name'], action)
      with self.opener.open(url) as f:
        pass
    else:
      raise AurploaderError("unrecognized action ({})".format(action)
      )


  def prompt_categories(self, name, default_category=None):
    """
    Prompt the user to select a category for the given package.
    """
    if not self.categories:
      raise AurploaderError("no categories")
    if default_category not in self.categories:
      default_category = None
    while True:
      print('Select category for {}'.format(name))
      for n in sorted(self.categories):
        print('  {:2d}) {}'.format(n, self.categories[n]))
      print('Enter "x" to skip this package.')
      if default_category:
        category = input('Category [{}]: '.format(default_category))
      else:
        category = input('Category: ')
      if category.lower() == 'x':
        return None
      elif not category and default_category:
        return default_category
      else:
        try:
          category = int(category)
          if category in self.categories:
            return category
        except ValueError:
          continue



  # Python has had an open request for multipart/form-data since 2008-06-30
  # http://bugs.python.org/issue3244

  # At the time of writing, the latest submitted code does not work and hacking
  # together something that does is just not worth it right now.
  def upload_pkg(self, fpath, category=None, auto_category=False, confirm=True):
    """
    Upload a package to the AUR.
    """
    fname = os.path.basename(fpath)
    pkginfo = None

    try:
      pkg, ext = fname.split('.src.', 1)
      name, ver, rel = pkg.rsplit('-', 2)
    except ValueError:
      raise AurploaderError('unexpected filename format: {}\nexpected <pkgname>-<pkgver>-<pkgrel>.src.<ext>'.format(fname))

    if category not in self.categories:
      category = None
    if category is None:
      pkginfo = self.get_info(name)
      if pkginfo:
        category = int(pkginfo['CategoryID'])

    if category is None or not auto_category:
      category = self.prompt_categories(name, default_category=category)

    # This is not an error. A user may abort the upload by entering "x" at the
    # category prompt.
    if category is None:
      return

    cmd = [
      '/usr/bin/curl',
      '-#',
      '-H', 'Expect:',
      '-b', self.cookiejar_path,
      '-c', self.cookiejar_path,
      '-F', 'category={}'.format(category),
      '-F', 'pfile=@{}'.format(fpath),
      '-F', 'pkgsubmit=1',
      '-F', 'token={}'.format(self.token)
    ]

    cmd.append(PKGSUBMIT_URL)

    self.save_cookies()

    with open(os.devnull, 'w') as null:
      p = Popen(cmd, stdout=null)
      e = p.wait()
      if e != 0:
        raise AurploaderError("curl exited with non-zero status ({:d})".format(e))

    self.load_cookies()

    if confirm:
      expected = '{}-{}'.format(ver, rel)
      ttl = self.rpc.ttl
      self.rpc.ttl = 0
      try:
        pkginfo = self.get_info(name)
      finally:
        self.rpc.ttl = ttl
      if not pkginfo or pkginfo['Version'] != expected:
        raise AurploaderError('failed to confirm upload')

    return pkginfo



  def save_cookies(self, path=None):
    """
    Save cookie jar.
    """
    if path is None:
      path = self.cookiejar_path
    if path is None:
      raise AurploaderError('no cookiejar path given')
    # For Curl compatibility (not sure which one fails to comply with the standard.
    for cookie in self.cookiejar:
      if not cookie.expires:
        cookie.expires = 0
    self.cookiejar.save(path, ignore_discard=True, ignore_expires=True)


  def load_cookies(self, path=None):
    """
    Load cookie jar.
    """
    if path is None:
      path = self.cookiejar_path
    if path is None:
      raise AurploaderError('no cookiejar path given')
    try:
      # For Curl compatibility (not sure which one fails to comply with the standard.
      self.cookiejar.load(path, ignore_discard=True, ignore_expires=True)
      for cookie in self.cookiejar:
        if not cookie.expires:
          cookie.expires = None
    except LoadError:
      pass
    except IOError as e:
      if e.errno != errno.ENOENT:
        raise e



  def initialize(self, user=None, passwd=None, login_file=None, cookiejar_path=None):
    """
    Login if necessary and load categories and token.
    """
    self.load_cookies(cookiejar_path)
    self.parse_pkgsubmit()
    if not self.categories or not self.token:
      self.login(user=user, passwd=passwd, login_file=login_file)
      self.parse_pkgsubmit()
      if not self.categories or not self.token:
        raise AurploaderError('login appears to have failed\n')
      elif cookiejar_path:
        self.save_cookies(cookiejar_path)