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}