1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.config.remote; 17 18 import com.android.tradefed.build.BuildRetrievalError; 19 import com.android.tradefed.device.ITestDevice; 20 import com.android.tradefed.result.error.InfraErrorIdentifier; 21 22 import java.io.File; 23 import java.util.LinkedHashMap; 24 import java.util.Map; 25 26 import javax.annotation.Nonnull; 27 28 /** 29 * Interface for objects that can resolve a remote file into a local one. For example: 30 * gs://bucket/dir/file.txt would be downloaded and changed to a local path. 31 */ 32 public interface IRemoteFileResolver { 33 34 /** 35 * Resolve the remote file. 36 * 37 * @param consideredFile {@link File} evaluated as remote. 38 * @return The resolved local file. 39 * @throws BuildRetrievalError if something goes wrong. 40 */ resolveRemoteFiles(File consideredFile)41 public default @Nonnull File resolveRemoteFiles(File consideredFile) 42 throws BuildRetrievalError { 43 throw new BuildRetrievalError( 44 "Should not have been called", InfraErrorIdentifier.ARTIFACT_UNSUPPORTED_PATH); 45 } 46 47 /** 48 * Resolve the remote file. 49 * 50 * @param consideredFile {@link File} evaluated as remote. 51 * @param queryArgs The arguments passed as a query to the URL. 52 * @return The resolved local file. 53 * @throws BuildRetrievalError if something goes wrong. 54 */ resolveRemoteFiles( File consideredFile, Map<String, String> queryArgs)55 public default @Nonnull File resolveRemoteFiles( 56 File consideredFile, Map<String, String> queryArgs) throws BuildRetrievalError { 57 return resolveRemoteFiles(consideredFile); 58 } 59 60 /** 61 * Resolve the remote file in a future-proof interface 62 * 63 * @param args {@link RemoteFileResolverArgs} describing the remote to download and how. 64 * @return The resolved local file representation. 65 * @throws BuildRetrievalError if something goes wrong. 66 */ resolveRemoteFile(RemoteFileResolverArgs args)67 public default @Nonnull ResolvedFile resolveRemoteFile(RemoteFileResolverArgs args) 68 throws BuildRetrievalError { 69 File file = resolveRemoteFiles(args.getConsideredFile(), args.getQueryArgs()); 70 return new ResolvedFile(file); 71 } 72 73 /** Returns the associated protocol supported for download. */ getSupportedProtocol()74 public @Nonnull String getSupportedProtocol(); 75 76 /** 77 * Optional way for the implementation to receive an {@ink ITestDevice} representation of the 78 * device under tests. 79 * 80 * @param device The {@link ITestDevice} of the current invocation. 81 */ setPrimaryDevice(ITestDevice device)82 public default void setPrimaryDevice(ITestDevice device) { 83 // Do nothing by default 84 } 85 86 /** The args passed to the resolvers */ 87 public class RemoteFileResolverArgs { 88 89 private File mConsideredFile; 90 private Map<String, String> mQueryArgs = new LinkedHashMap<>(); 91 private File mDestinationDir; 92 setConsideredFile(File consideredFile)93 public RemoteFileResolverArgs setConsideredFile(File consideredFile) { 94 mConsideredFile = consideredFile; 95 return this; 96 } 97 addQueryArg(String key, String value)98 public RemoteFileResolverArgs addQueryArg(String key, String value) { 99 mQueryArgs.put(key, value); 100 return this; 101 } 102 addQueryArgs(Map<String, String> queryArgs)103 public RemoteFileResolverArgs addQueryArgs(Map<String, String> queryArgs) { 104 mQueryArgs.putAll(queryArgs); 105 return this; 106 } 107 setDestinationDir(File destinationDir)108 public RemoteFileResolverArgs setDestinationDir(File destinationDir) { 109 mDestinationDir = destinationDir; 110 return this; 111 } 112 getConsideredFile()113 public File getConsideredFile() { 114 return mConsideredFile; 115 } 116 getQueryArgs()117 public Map<String, String> getQueryArgs() { 118 return mQueryArgs; 119 } 120 getDestinationDir()121 public File getDestinationDir() { 122 return mDestinationDir; 123 } 124 125 @Override hashCode()126 public int hashCode() { 127 final int prime = 31; 128 int result = 1; 129 result = prime * result + ((mConsideredFile == null) ? 0 : mConsideredFile.hashCode()); 130 result = prime * result + ((mDestinationDir == null) ? 0 : mDestinationDir.hashCode()); 131 result = prime * result + ((mQueryArgs == null) ? 0 : mQueryArgs.hashCode()); 132 return result; 133 } 134 135 @Override equals(Object obj)136 public boolean equals(Object obj) { 137 if (this == obj) { 138 return true; 139 } 140 if (obj == null) { 141 return false; 142 } 143 if (getClass() != obj.getClass()) { 144 return false; 145 } 146 RemoteFileResolverArgs other = (RemoteFileResolverArgs) obj; 147 if (mConsideredFile == null) { 148 if (other.mConsideredFile != null) { 149 return false; 150 } 151 } else if (!mConsideredFile.equals(other.mConsideredFile)) { 152 return false; 153 } 154 if (mDestinationDir == null) { 155 if (other.mDestinationDir != null) { 156 return false; 157 } 158 } else if (!mDestinationDir.equals(other.mDestinationDir)) { 159 return false; 160 } 161 if (mQueryArgs == null) { 162 if (other.mQueryArgs != null) { 163 return false; 164 } 165 } else if (!mQueryArgs.equals(other.mQueryArgs)) { 166 return false; 167 } 168 return true; 169 } 170 } 171 172 /** Class holding information about the resolved file and some metadata. */ 173 public class ResolvedFile { 174 private File mResolvedFile; 175 private boolean mShouldCleanUp = true; 176 ResolvedFile(File resolvedFile)177 public ResolvedFile(File resolvedFile) { 178 mResolvedFile = resolvedFile; 179 } 180 getResolvedFile()181 public File getResolvedFile() { 182 return mResolvedFile; 183 } 184 185 /** 186 * Whether the resolved file should be deleted at the end of the invocation or not. Set to 187 * false for a file that shouldn't be deleted. For example: a local file you own. 188 */ cleanUp(boolean cleanUp)189 public ResolvedFile cleanUp(boolean cleanUp) { 190 mShouldCleanUp = cleanUp; 191 return this; 192 } 193 shouldCleanUp()194 public boolean shouldCleanUp() { 195 return mShouldCleanUp; 196 } 197 } 198 } 199