Package com.puppetlabs.geppetto.ruby.resource

Source Code of com.puppetlabs.geppetto.ruby.resource.PptpRubyResource$RubySyntaxExceptionDiagnostic

/**
* Copyright (c) 2013 Puppet Labs, Inc. and other contributors, as listed below.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*   Puppet Labs
*/
package com.puppetlabs.geppetto.ruby.resource;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;

import com.puppetlabs.geppetto.pp.pptp.Function;
import com.puppetlabs.geppetto.pp.pptp.MetaType;
import com.puppetlabs.geppetto.pp.pptp.PPTPFactory;
import com.puppetlabs.geppetto.pp.pptp.Parameter;
import com.puppetlabs.geppetto.pp.pptp.Property;
import com.puppetlabs.geppetto.pp.pptp.Type;
import com.puppetlabs.geppetto.pp.pptp.TypeFragment;
import com.puppetlabs.geppetto.ruby.PPFunctionInfo;
import com.puppetlabs.geppetto.ruby.PPTypeInfo;
import com.puppetlabs.geppetto.ruby.RubyHelper;
import com.puppetlabs.geppetto.ruby.RubySyntaxException;
import com.puppetlabs.geppetto.ruby.spi.IRubyIssue;
import com.puppetlabs.geppetto.ruby.spi.IRubyParseResult;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;

/**
* A Resource that loads .rb files containing Puppet "target platform"
* information. Ruby source on particular paths are transformed into PPTP model
* contents.
*
*/
public class PptpRubyResource extends ResourceImpl {

  public enum LoadType {
    TYPE, TYPEFRAGMENT, META, FUNCTION, IGNORED;

  }

  public static class RubyIssueDiagnostic implements Diagnostic {
    private IRubyIssue issue;

    public RubyIssueDiagnostic(IRubyIssue issue) {
      this.issue = issue;
    }

    /**
     * @throws UnsupportedOperationException
     *             - column is not available.
     */
    @Override
    public int getColumn() {
      throw new UnsupportedOperationException();
    }

    @Override
    public int getLine() {
      return issue.getLine();
    }

    @Override
    public String getLocation() {
      return issue.getFileName();
    }

    @Override
    public String getMessage() {
      return issue.getMessage();
    }

  }

  public static class RubySyntaxExceptionDiagnostic implements Diagnostic {
    private RubySyntaxException issue;

    public RubySyntaxExceptionDiagnostic(RubySyntaxException issue) {
      this.issue = issue;
    }

    /**
     * @throws UnsupportedOperationException
     *             - column is not available.
     */
    @Override
    public int getColumn() {
      throw new UnsupportedOperationException();
    }

    @Override
    public int getLine() {
      return issue.getLine();
    }

    @Override
    public String getLocation() {
      return issue.getFilename();
    }

    @Override
    public String getMessage() {
      return issue.getMessage();
    }

  }

  /**
   * (SOMEROOT/lib/puppet/) parser/functions/F.rb (SOMEROOT/lib/puppet/)
   * type/T.rb (SOMEROOT/lib/puppet/) type/FRAGMENTDIR/TypeFragment.rb
   * (SOMEROOT/lib/puppet/) type.rb - META TYPE (typically in a distro)
   *
   * @return
   */
  public static LoadType detectLoadType(URI uri) {
    List<String> segments = uri.segmentsList();
    final int lastPuppet = segments.lastIndexOf("puppet");
    final int segmentCount = segments.size();
    if(lastPuppet < 0)
      return LoadType.IGNORED;

    int idx = lastPuppet + 1;
    if(idx < segmentCount) {
      String segment = segments.get(idx);
      if("parser".equals(segment)) {
        idx++;
        if(idx < segmentCount) {
          segment = segments.get(idx);
          if("functions".equals(segment)) {
            idx++;
            if(idx == segmentCount - 1 && segments.get(idx).endsWith(".rb"))
              return LoadType.FUNCTION;
          }
        }
      }
      else if("type".equals(segment)) {
        idx++;
        if(idx < segmentCount) {
          segment = segments.get(idx);
          // a .rb file under type
          if(segment.endsWith(".rb") && idx == segmentCount - 1)
            return LoadType.TYPE;

          // typefragment must be in a subdir of type, e.g.
          // type/file/X.rb
          idx++;
          if(idx == segmentCount - 1 && segments.get(idx).endsWith(".rb"))
            return LoadType.TYPEFRAGMENT;
        }
      }
      else if("type.rb".equals(segment) && idx == segmentCount - 1) {
        return LoadType.META;
      }
    }
    return LoadType.IGNORED;
  }

  private LoadType loadType;

  /**
   * Create an instance with a reference to a resource in Ruby text format.
   *
   * @param uri
   */
  public PptpRubyResource(URI uri) {
    super(uri);
  }

  protected LoadType detectLoadType() {
    return detectLoadType(getURI());
  }

  @Override
  public void doLoad(InputStream in, Map<?, ?> options) throws IOException {
    loadType = detectLoadType();
    internalLoadRuby(in);
  }

  /**
   * Loads one (or more) PPTP Type, PPTP Function, PPTP Meta, or PPTP Fragment
   * depending on the type of load (determined by looking at the path to the
   * parsed .rb file).
   *
   * @throws IOException
   */
  protected void internalLoadRuby(InputStream inputStream) throws IOException {
    if(loadType == LoadType.IGNORED) {
      this.getContents().clear();
      return;
    }
    RubyHelper helper = new RubyHelper();
    helper.setUp();

    URI uri = getURI();
    try {
      switch(loadType) {
        case TYPE: {
          List<PPTypeInfo> typeInfo = helper.getTypeInfo(uri.path(), new InputStreamReader(inputStream));
          for(PPTypeInfo info : typeInfo) {
            Type type = PPTPFactory.eINSTANCE.createType();
            type.setName(info.getTypeName());
            type.setDocumentation(info.getDocumentation());
            for(Map.Entry<String, PPTypeInfo.Entry> entry : info.getParameters().entrySet()) {
              Parameter parameter = PPTPFactory.eINSTANCE.createParameter();
              parameter.setName(entry.getKey());
              parameter.setDocumentation(entry.getValue().documentation);
              parameter.setRequired(entry.getValue().isRequired());
              type.getParameters().add(parameter);
            }
            for(Map.Entry<String, PPTypeInfo.Entry> entry : info.getProperties().entrySet()) {
              Property property = PPTPFactory.eINSTANCE.createProperty();
              property.setName(entry.getKey());
              property.setDocumentation(entry.getValue().documentation);
              property.setRequired(entry.getValue().isRequired());
              type.getProperties().add(property);
            }
            getContents().add(type);
          }
        }
          break;

        case FUNCTION: {
          List<PPFunctionInfo> functions = helper.getFunctionInfo(uri.path(), new InputStreamReader(
            inputStream));

          for(PPFunctionInfo info : functions) {
            Function pptpFunc = PPTPFactory.eINSTANCE.createFunction();
            pptpFunc.setName(info.getFunctionName());
            pptpFunc.setRValue(info.isRValue());
            pptpFunc.setDocumentation(info.getDocumentation());
            getContents().add(pptpFunc);
          }
        }
          break;

        case META: {
          PPTypeInfo info = helper.getMetaTypeInfo(uri.path(), new InputStreamReader(inputStream));

          MetaType type = PPTPFactory.eINSTANCE.createMetaType();
          type.setName(info.getTypeName());
          type.setDocumentation(info.getDocumentation());
          for(Map.Entry<String, PPTypeInfo.Entry> entry : info.getParameters().entrySet()) {
            Parameter parameter = PPTPFactory.eINSTANCE.createParameter();
            parameter.setName(entry.getKey());
            parameter.setDocumentation(entry.getValue().documentation);
            parameter.setRequired(entry.getValue().isRequired());
            type.getParameters().add(parameter);
          }
          // TODO: Scan the puppet source for providers for the type
          // This is a CHEAT -
          // https://github.com/puppetlabs/geppetto/issues/37
          Parameter p = PPTPFactory.eINSTANCE.createParameter();
          p.setName("provider");
          p.setDocumentation("");
          p.setRequired(false);
          type.getParameters().add(p);

          getContents().add(type);
          break;
        }

        case TYPEFRAGMENT: {
          for(PPTypeInfo type : helper.getTypeFragments(uri.path(), new InputStreamReader(inputStream))) {
            TypeFragment fragment = PPTPFactory.eINSTANCE.createTypeFragment();
            fragment.setName(type.getTypeName());

            // add the properties (will typically load just one).
            for(Map.Entry<String, PPTypeInfo.Entry> entry : type.getProperties().entrySet()) {
              Property property = PPTPFactory.eINSTANCE.createProperty();
              property.setName(entry.getKey());
              property.setDocumentation(entry.getValue().documentation);
              property.setRequired(entry.getValue().isRequired());
              fragment.getProperties().add(property);
            }

            // add the parameters (will typically load just one).
            for(Map.Entry<String, PPTypeInfo.Entry> entry : type.getParameters().entrySet()) {
              Parameter parameter = PPTPFactory.eINSTANCE.createParameter();
              parameter.setName(entry.getKey());
              parameter.setDocumentation(entry.getValue().documentation);
              parameter.setRequired(entry.getValue().isRequired());
              fragment.getParameters().add(parameter);
            }
            getContents().add(fragment);
          }
          break;
        }
        case IGNORED:
          break;
      }
    }
    catch(RubySyntaxException syntaxException) {
      getErrors().add(new RubySyntaxExceptionDiagnostic(syntaxException));
    }
    finally {
      helper.tearDown();
    }
  }

  @Override
  public void load(Map<?, ?> options) throws IOException {
    if(!super.isLoaded) {
      super.isLoading = true;

      loadType = detectLoadType();
      internalLoadRuby(getURIConverter().createInputStream(uri));

      super.isLoading = false;
      super.isLoaded = true;
    }
  }

  /**
   * Translates ruby issues to diagnostics using instances of {@link RubyIssueDiagnostic}. All syntax issues are reported as errors,
   * all others as warnings.
   *
   * @param parseResult
   */
  protected void rubyIssuesToDiagnostics(IRubyParseResult parseResult) {
    for(IRubyIssue issue : parseResult.getIssues()) {
      if(issue.isSyntaxError())
        getErrors().add(new RubyIssueDiagnostic(issue));
      else
        getWarnings().add(new RubyIssueDiagnostic(issue));
    }
  }

  @Override
  public void save(Map<?, ?> options) throws IOException {
    throw new UnsupportedOperationException("Save of PPTP parsed from a ruby file is not possible.");
  }
}
TOP

Related Classes of com.puppetlabs.geppetto.ruby.resource.PptpRubyResource$RubySyntaxExceptionDiagnostic

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.