Unnecessary quotation of subkey and iteration thro

2019-08-17 01:39发布

问题:

I have the next code:

import gnupg
import re
import textwrap
from pprint import pprint
import yaml
from yaml.events import *

class AppendableEvents:
  def __init__(self, path, events):
    self.path = path
    self.events = events

  def correct_position(self, levels):
    if len(self.path) != len(levels):
      return False
    for index, expected in enumerate(self.path):
      if expected != levels[index].cur_id:
        return False
    return True

class Level:
  def __init__(self, mode):
    self.mode = mode
    self.cur_id = -1 if mode == "item" else ""

def append_to_yaml(yamlFile, targetFile, items):
  events = []
  levels = []
  with open(yamlFile, 'r') as handle:
    for event in yaml.parse(handle):
      if isinstance(event, StreamStartEvent) or \
         isinstance(event, StreamEndEvent) or \
         isinstance(event, DocumentStartEvent) or \
         isinstance(event, DocumentEndEvent):
        pass
      elif isinstance(event, CollectionStartEvent):
        if len(levels) > 0:
          if levels[-1].mode == "key":
            # we can only handle scalar keys
            raise ValueError("encountered complex key!")
          else:
            if levels[-1].mode == "value":
              levels[-1].mode = "key"
        if isinstance(event, MappingStartEvent):
          levels.append(Level("key"))
        else: # SequenceStartEvent
          levels.append(Level("item"))
      elif isinstance(event, ScalarEvent):
        if len(levels) > 0:
          if levels[-1].mode == "item":
            levels[-1].cur_id += 1
          elif levels[-1].mode == "key":
            levels[-1].cur_id = event.value
            levels[-1].mode = "value"
          else: # mode == "value"
            levels[-1].mode = "key"
      elif isinstance(event, CollectionEndEvent):
        # here we check whether we want to append anything
        levels.pop()
        for item in items:
          if item.correct_position(levels):
            for additional_event in item.events:
              events.append(additional_event)
      events.append(event)
  with open(targetFile, mode="w") as handle:
    yaml.emit(events, handle,line_break=True)

def key(name):
  return ScalarEvent(None, None, (True, True), name)

def literal_value(content):
  return ScalarEvent(None, None, (False, True), content, style="|")

def map(*scalarValues):
  return [MappingStartEvent(None, None, True)] + \
    [ScalarEvent(None, None, (False, True), v, style="|") for v in scalarValues] + \
    [MappingEndEvent()]


gpg = gnupg.GPG(gnupghome='~/.gnupg')
gpg.encoding = 'utf-8'

def ExistingFile():
    with open(creds) as sensitive_data:
        for line in sensitive_data:
            encrypted_value = gpg.encrypt(
                re.sub(r'^( +?|[A-Za-z0-9]|[A-Za]|[0-9])+( +)?' + '=' + '( +)?', '', line, 1),
                recipients="test", always_trust=True)
            if not encrypted_value.ok:
                print(encrypted_value.status, '\n', encrypted_value.stderr)
                break
            line = re.sub(r'^( +)?|( +)?' + '=' + '.*', '', line.rstrip('\n'))
            append_to_yaml(f1, f1, [
              AppendableEvents(["global","app1"], [
                key("app2")] + map(line, encrypted_value.data.decode()))])
                #key(line), literal_value(encrypted_value.data.decode())])])

ExistingFile()

Content of creds file is:

1=1
sadsa=ars

Content of f1 file is:

global:
    app1:
      test: |
        -----BEGIN PGP MESSAGE-----
        Version: GnuPG v1
        -----END PGP MESSAGE----- 

In this code necessary key, subkey and values are being appended to appropriate block in yaml file.

But the problem is that value which I pass in key methods is being iterated and thus appends twice or more depending on content in creds file:

global:
    app1:
      test: |
        -----BEGIN PGP MESSAGE-----
        Version: GnuPG v1
        -----END PGP MESSAGE-----     
    app2:
      "1": |
        -----BEGIN PGP MESSAGE-----
        Version: GnuPG v1
        -----END PGP MESSAGE-----
    app2:
      "sadsa": |
        -----BEGIN PGP MESSAGE-----
        Version: GnuPG v1
        -----END PGP MESSAGE-----

Also subkeys "1" and "sadsa" are being appended with double quotes.

I want to get rid of double quotes and that value which I pass in key method will be appended to file only one time when I combine it with map method.

So the final result will be for example:

global:
    app1:
      test: |
        -----BEGIN PGP MESSAGE-----
        Version: GnuPG v1
        -----END PGP MESSAGE-----     
    app2:
      1: |
        -----BEGIN PGP MESSAGE-----
        Version: GnuPG v1
        -----END PGP MESSAGE-----
      sadsa: |
        -----BEGIN PGP MESSAGE-----
        Version: GnuPG v1
        -----END PGP MESSAGE-----

Note: Commented line with literal_value method works pretty fine so I don't want to break it's logic doing changes for case with map method.

回答1:

First of all, please provide a minimal example when asking a question. I removed the gnupg stuff from your code because it is not relevant at all to your question. It is your responsibility to provide only relevant parts of your actual code so that people trying to help you do not need to dig through irrelevant lines.

Now, to solve your question: You simply need to construct the events you output appropriately. Here's a solution (without the gnupg stuff):

def ExistingFile():
  with open(creds) as sensitive_data:
    additions = [key("app2"), MappingStartEvent(None, None, True)]
    for line in sensitive_data:
      encrypted_value = re.sub(r'^( +?|[A-Za-z0-9]|[A-Za]|[0-9])+( +)?' + '=' + '( +)?', '', line, 1)
      line = re.sub(r'^( +)?|( +)?' + '=' + '.*', '', line.rstrip('\n'))
      additions.extend(
        [ScalarEvent(None, None, (True, False), line),
         ScalarEvent(None, None, (False, True), encrypted_value, style='|')])
    additions.append(MappingEndEvent())
    append_to_yaml(f1, f1_mod, [AppendableEvents(["global", "app1"], additions)])

As you can see, I construct the scalar event for the key differently from that for the value, so that the value is presented as literal scalar and the key as plain scalar (without quotes).

I also call append_to_yaml only once so that app2 is only created once.