Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Most of the work for StorageProviders is done. #1

Merged
merged 2 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .run/Reposilite.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="MAIN_CLASS_NAME" value="org.panda_lang.reposilite.ReposiliteLauncher" />
<module name="reposilite" />
<option name="VM_PARAMETERS" value="-Xmx14M -Dreposilite.debugEnabled=true -Dtinylog.writerActive.level=DEBUG" />
<option name="VM_PARAMETERS" value="-Xmx2G -Dreposilite.debugEnabled=true -Dtinylog.writerActive.level=DEBUG" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/reposilite-backend/src/test/workspace" />
<method v="2">
<option name="Make" enabled="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public final class Reposilite {
private final Path configurationFile;
private final Path workingDirectory;
private final boolean testEnvEnabled;
private final StorageProvider storageProvider;
private final FileSystemStorageProvider storageProvider;
private final Configuration configuration;
private final ReposiliteContextFactory contextFactory;
private final ReposiliteExecutor executor;
Expand Down Expand Up @@ -92,11 +92,11 @@ public final class Reposilite {
this.executor = new ReposiliteExecutor(testEnvEnabled, failureService);
this.tokenService = new TokenService(workingDirectory, storageProvider);
this.statsService = new StatsService(workingDirectory, failureService, storageProvider);
this.repositoryService = new RepositoryService(workingDirectory, storageProvider);
this.metadataService = new MetadataService(failureService, storageProvider);
this.repositoryService = new RepositoryService();
this.metadataService = new MetadataService(failureService);

this.authenticator = new Authenticator(repositoryService, tokenService);
this.repositoryAuthenticator = new RepositoryAuthenticator(configuration.rewritePathsEnabled, authenticator, repositoryService, storageProvider);
this.repositoryAuthenticator = new RepositoryAuthenticator(configuration.rewritePathsEnabled, authenticator, repositoryService);
this.authService = new AuthService(authenticator);
this.deployService = new DeployService(configuration.deployEnabled, configuration.rewritePathsEnabled, authenticator, repositoryService, metadataService, storageProvider);
this.lookupService = new LookupService(repositoryAuthenticator, metadataService, repositoryService, storageProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,9 @@ void start(Configuration configuration, Runnable onStart) {
reposilite.getFailureService());

LookupApiEndpoint lookupApiEndpoint = new LookupApiEndpoint(
configuration.rewritePathsEnabled,
reposilite.getContextFactory(),
reposilite.getRepositoryAuthenticator(),
reposilite.getRepositoryService(),
reposilite.getStorageProvider());
reposilite.getRepositoryService());

CliController cliController = new CliController(
reposilite.getContextFactory(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.panda_lang.reposilite;

import org.jetbrains.annotations.Nullable;
import org.panda_lang.reposilite.repository.Repository;
import org.panda_lang.reposilite.repository.RepositoryService;
import org.panda_lang.utilities.commons.StringUtils;
Expand All @@ -30,14 +31,12 @@ private ReposiliteUtils() { }
* <ul>
* <li>Remove root slash</li>
* <li>Remove illegal path modifiers like .. and ~</li>
* <li>Insert repository name if missing</li>
* </ul>
*
* @param rewritePathsEnabled determines if path reqriting is enabled
* @param uri the uri to process
* @return the normalized uri
*/
public static String normalizeUri(boolean rewritePathsEnabled, RepositoryService repositoryService, String uri) {
public static String normalizeUri(String uri) {
if (uri.startsWith("/")) {
uri = uri.substring(1);
}
Expand All @@ -46,21 +45,29 @@ public static String normalizeUri(boolean rewritePathsEnabled, RepositoryService
return StringUtils.EMPTY;
}

if (!rewritePathsEnabled) {
return uri;
return uri;
}

public static @Nullable Repository getRepository(boolean rewritePathsEnabled, RepositoryService repositoryService, String uri) {
String repositoryName = uri;

if (repositoryName.startsWith("/")) {
repositoryName = repositoryName.substring(1);
}

if (StringUtils.countOccurrences(uri, "/") <= 1) {
return uri;
if (repositoryName.contains("..") || repositoryName.contains("~") || repositoryName.contains(":") || repositoryName.contains("\\")) {
return null;
}

for (Repository repository : repositoryService.getRepositories()) {
if (uri.startsWith(repository.getName())) {
return uri;
}

String repository = StringUtils.countOccurrences(repositoryName, "/") > 0
? repositoryName.substring(0, repositoryName.indexOf('/'))
: repositoryName;

if (rewritePathsEnabled && repositoryService.getRepository(repository) == null) {
repository = repositoryService.getPrimaryRepository().getName();
}

return repositoryService.getPrimaryRepository().getName() + "/" + uri;
return repositoryService.getRepository(repository);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.panda_lang.reposilite.repository.Repository;
import org.panda_lang.utilities.commons.StringUtils;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

Expand All @@ -27,9 +28,9 @@ public final class Session {
public static final String WILDCARD = "*";

private final Token token;
private final List<Repository> repositories;
private final Collection<Repository> repositories;

public Session(Token token, List<Repository> repositories) {
public Session(Token token, Collection<Repository> repositories) {
this.token = token;
this.repositories = repositories;
}
Expand Down Expand Up @@ -59,7 +60,7 @@ public boolean hasPermissionTo(String path) {
return path.startsWith(tokenPath) || path.startsWith(tokenPath + "/");
}

public List<Repository> getRepositories() {
public Collection<Repository> getRepositories() {
return repositories;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ public final class Configuration implements Serializable {
public String diskQuota = "10GB";
@Description("# List of supported Maven repositories.")
@Description("# First directory on the list is the main (primary) repository.")
@Description("# Tu mark repository as private, prefix its name with a dot, e.g. \".private\"")
public List<String> repositories = Arrays.asList("releases", "snapshots");
@Description("# Tu mark repository as private, add the \"--private\" flag")
public List<String> repositories = Arrays.asList("releases --no-redeploy", "snapshots");
@Description("# Allow to omit name of the main repository in request")
@Description("# e.g. /org/panda-lang/reposilite will be redirected to /releases/org/panda-lang/reposilite")
public Boolean rewritePathsEnabled = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.panda_lang.reposilite.config;

import java.util.regex.Pattern;

public final class RepositoryConfig {
private static final Pattern UNESCAPED_SPACE = Pattern.compile("(?<!\\\\) ");

private final String repositoryName;

private RepositoryConfig(String repositoryName) {
this.repositoryName = repositoryName;
}

@Override
public String toString() {
return "RepositoryConfig[" + this.repositoryName + "]";
}

public String getRepositoryName() {
return this.repositoryName;
}

public <T> T get(RepositoryOption<T> option) {
return option.get(this);
}

public static RepositoryConfig parse(String string) {
String[] strings = UNESCAPED_SPACE.split(string);
String repositoryName = strings[0].startsWith(".") ? strings[0].substring(1) : strings[0];
RepositoryConfig config = new RepositoryConfig(repositoryName);

for (RepositoryOption<?> option : RepositoryOption.getOptions()) {
option.parse(config, strings);
}

return config;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package org.panda_lang.reposilite.config;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.panda_lang.reposilite.storage.FileSystemStorageProvider;
import org.panda_lang.reposilite.storage.S3StorageProvider;
import org.panda_lang.reposilite.storage.StorageProvider;

import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;

public final class RepositoryOption<T> {
private static final Map<String, RepositoryOption<?>> OPTIONS = new HashMap<>();

public static final RepositoryOption<Boolean> PRIVATE = create("private", () -> false, strings -> strings[0].startsWith(".") || contains("--private", strings));
public static final RepositoryOption<Boolean> NO_REDEPLOY = create("no-redeploy", () -> false, strings -> contains("--no-redeploy", strings)); // TODO Actually prevent redeploy
public static final RepositoryOption<StorageProvider> STORAGE_PROVIDER = create("storage-provider", () -> null, strings -> {
String provider = getValue("--storage-provider", strings);

if (provider != null) {
if (provider.equalsIgnoreCase("files")) {
String diskQuota = getValue("--disk-quota", strings);

if (diskQuota == null) {
throw new UnsupportedOperationException("'--disk-quota' cannot be null");
} else {
return FileSystemStorageProvider.of(Paths.get("repositories").resolve(strings[0]), diskQuota);
}
} else if (provider.equalsIgnoreCase("s3")) {
String s3BucketName = getValue("--s3-bucket", strings);
String region = getValue("--s3-region", strings);

if (s3BucketName == null) {
throw new UnsupportedOperationException("'--s3-bucket' cannot be null");
} else if (region == null) {
throw new UnsupportedOperationException("'--s3-region' cannot be null");
} else {
return new S3StorageProvider(s3BucketName, region);
}
} else if (provider.equalsIgnoreCase("rest")) {
// TODO REST API storage endpoint
}
}

throw new UnsupportedOperationException("Storage provider specifier is required");
});

private final String name;
private final Map<RepositoryConfig, T> values = new HashMap<>();
private final Function<RepositoryConfig, T> defaultValue;
private final Function<String[], T> parser;

private RepositoryOption(String name, Supplier<T> defaultValue, Function<String[], T> parser) {
this.name = name;
this.defaultValue = config -> defaultValue.get();
this.parser = parser;
}

@Override
public String toString() {
return "RepositoryOption[" + this.name + "]";
}

public T get(RepositoryConfig config) {
return this.values.computeIfAbsent(config, this.defaultValue);
}

public void parse(RepositoryConfig config, String[] args) {
this.values.put(config, this.parser.apply(args));
}

void put(RepositoryConfig config, T value) {
this.values.put(config, value);
}

public static <T> RepositoryOption<T> create(@NotNull String name, Supplier<T> defaultValue, Function<String[], T> parser) {
RepositoryOption<T> option = new RepositoryOption<>(name, defaultValue, parser);

OPTIONS.put(name, option);

return option;
}

public static RepositoryOption<?> get(String name) {
return OPTIONS.get(name);
}

public static Collection<RepositoryOption<?>> getOptions() {
return OPTIONS.values();
}

private static boolean contains(String name, String[] strings) {
// The first arg is the repository name, so we skip it.
for (int i = 1; i < strings.length; ++i) {
if (strings[i].equals(name)) {
return true;
}
}

return false;
}

private static @Nullable String getValue(String name, String[] strings) {
String key = name + '=';
// The first arg is the repository name, so we skip it.
for (int i = 1; i < strings.length; ++i) {
if (strings[i].startsWith(key)) {
return strings[i].substring(key.length());
}
}

return null;
}
}
Loading