001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2017 MicroBean.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
014 * implied.  See the License for the specific language governing
015 * permissions and limitations under the License.
016 */
017package org.microbean.helm.chart;
018
019import java.io.BufferedWriter;
020import java.io.IOException;
021import java.io.OutputStream;
022import java.io.OutputStreamWriter;
023import java.io.Writer;
024
025import java.nio.charset.StandardCharsets;
026
027import java.util.Collection;
028import java.util.Objects;
029
030import com.google.protobuf.AnyOrBuilder;
031import com.google.protobuf.ByteString;
032
033import hapi.chart.ChartOuterClass.Chart;
034import hapi.chart.ChartOuterClass.ChartOrBuilder;
035import hapi.chart.ConfigOuterClass.ConfigOrBuilder;
036import hapi.chart.MetadataOuterClass.Metadata;
037import hapi.chart.MetadataOuterClass.MetadataOrBuilder;
038import hapi.chart.TemplateOuterClass.Template;
039import hapi.chart.TemplateOuterClass.TemplateOrBuilder;
040
041import org.kamranzafar.jtar.TarEntry;
042import org.kamranzafar.jtar.TarHeader;
043import org.kamranzafar.jtar.TarOutputStream;
044
045import org.yaml.snakeyaml.Yaml;
046
047/**
048 * An {@link AbstractArchiveChartWriter} that saves {@link
049 * ChartOrBuilder} objects to a {@linkplain
050 * #TapeArchiveChartWriter(OutputStream) supplied
051 * <code>OutputStream</code>} in <a
052 * href="https://www.gnu.org/software/tar/manual/html_node/Standard.html">TAR
053 * format</a>, using a {@link TarOutputStream} internally.
054 *
055 * @author <a href="https://about.me/lairdnelson"
056 * target="_parent">Laird Nelson</a>
057 */
058public class TapeArchiveChartWriter extends AbstractArchiveChartWriter {
059
060
061  /*
062   * Instance fields.
063   */
064
065
066  /**
067   * The {@link TarOutputStream} to write to.
068   *
069   * <p>This field is never {@code null}.</p>
070   *
071   * @see #TapeArchiveChartWriter(OutputStream)
072   */
073  private final TarOutputStream outputStream;
074
075
076  /*
077   * Constructors.
078   */
079
080
081  /**
082   * Creates a new {@link TapeArchiveChartWriter}.
083   *
084   * @param outputStream the {@link OutputStream} to write to; must
085   * not be {@code null} and should be buffered at some level
086   *
087   * @see
088   * AbstractArchiveChartWriter#AbstractArchiveChartWriter()
089   *
090   * @see TarOutputStream#TarOutputStream(OutputStream)
091   */
092  public TapeArchiveChartWriter(final OutputStream outputStream) {
093    super();
094    Objects.requireNonNull(outputStream);
095    this.outputStream = new TarOutputStream(outputStream);
096  }
097
098
099  /*
100   * Instance methods.
101   */
102  
103
104  /**
105   * Creates a new {@link TarHeader} and a {@link TarEntry} wrapping
106   * it and writes it and the supplied {@code contents} to the
107   * underlying {@link TarOutputStream}.
108   *
109   * @param context the {@link Context} describing the write operation
110   * in effect; must not be {@code null}
111   *
112   * @param path the path within a tape archive to write; interpreted
113   * as being relative to the current chart path; must not be {@code
114   * null} or {@linkplain String#isEmpty() empty}
115   *
116   * @param contents the contents to write; must not be {@code null}
117   *
118   * @exception IOException if a write error occurs
119   *
120   * @exception NullPointerException if {@code context}, {@code path}
121   * or {@code contents} is {@code null}
122   *
123   * @exception IllegalArgumentException if {@code path} {@linkplain
124   * String#isEmpty() is empty}
125   */
126  @Override
127  protected void writeEntry(final Context context, final String path, final String contents) throws IOException {
128    Objects.requireNonNull(context);
129    Objects.requireNonNull(path);
130    Objects.requireNonNull(contents);
131    if (path.isEmpty()) {
132      throw new IllegalArgumentException("path", new IllegalStateException("path.isEmpty()"));
133    }
134
135    final byte[] contentsBytes = contents.getBytes(StandardCharsets.UTF_8);
136    final long size = contentsBytes.length;
137    final TarHeader tarHeader = TarHeader.createHeader(new StringBuilder(context.get("path", String.class)).append(path).toString(), size, System.currentTimeMillis(), false, 0755);
138    final TarEntry tarEntry = new TarEntry(tarHeader);
139    this.outputStream.putNextEntry(tarEntry);
140    this.outputStream.write(contentsBytes);
141    this.outputStream.flush();
142  }
143
144  /**
145   * Closes this {@link TapeArchiveChartWriter} by closing its
146   * underlying {@link TarOutputStream}.  This {@link
147   * TapeArchiveChartWriter} cannot be used again.
148   *
149   * @exception IOException if there was a problem closing the
150   * underlying {@link TarOutputStream}
151   */
152  @Override
153  public void close() throws IOException {
154    this.outputStream.close();
155  }
156  
157}