Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 91d6d4236ce0baa85f8a68818f247228cadbea34 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/*******************************************************************************
 * Copyright (c) 2009, 2012 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *     Sonatype, Inc. - ongoing development
 *******************************************************************************/
package org.eclipse.equinox.p2.internal.repository.tools;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.equinox.internal.p2.engine.*;
import org.eclipse.equinox.internal.p2.engine.phases.Collect;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.engine.*;
import org.eclipse.equinox.p2.engine.spi.ProvisioningAction;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.*;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;

/**
 * The transformer takes an existing p2 repository (local or remote), iterates over 
 * its list of IUs, and fetches all of the corresponding artifacts to a user-specified location. 
 * Once fetched, the artifacts will be in "runnable" form... that is directory-based bundles will be
 * extracted into folders and packed JAR files will be un-packed.
 * 
 * @since 1.0
 */
public class Repo2Runnable extends AbstractApplication implements IApplication {
	private static final String NATIVE_ARTIFACTS = "nativeArtifacts"; //$NON-NLS-1$
	private static final String NATIVE_TYPE = "org.eclipse.equinox.p2.native"; //$NON-NLS-1$
	private static final String PARM_OPERAND = "operand"; //$NON-NLS-1$
	private static final String PARM_PROFILE = "profile"; //$NON-NLS-1$

	private boolean flagAsRunnable = false;

	protected class CollectNativesAction extends ProvisioningAction {
		public IStatus execute(Map<String, Object> parameters) {
			InstallableUnitOperand operand = (InstallableUnitOperand) parameters.get(PARM_OPERAND);
			IInstallableUnit installableUnit = operand.second();

			IArtifactRepositoryManager manager = getArtifactRepositoryManager();
			Collection<IArtifactKey> toDownload = installableUnit.getArtifacts();
			if (toDownload == null)
				return Status.OK_STATUS;

			@SuppressWarnings("unchecked")
			List<IArtifactRequest> artifactRequests = (List<IArtifactRequest>) parameters.get(NATIVE_ARTIFACTS);

			IProfile profile = (IProfile) parameters.get(PARM_PROFILE);
			String statsParameter = null;
			if (profile != null)
				statsParameter = profile.getProperty(IProfile.PROP_STATS_PARAMETERS);

			for (IArtifactKey keyToDownload : toDownload) {
				IArtifactRequest request = manager.createMirrorRequest(keyToDownload, destinationArtifactRepository, null, null, statsParameter);
				artifactRequests.add(request);
			}
			return Status.OK_STATUS;
		}

		public IStatus undo(Map<String, Object> parameters) {
			// nothing to do for now
			return Status.OK_STATUS;
		}
	}

	protected class CollectNativesPhase extends InstallableUnitPhase {
		public CollectNativesPhase(int weight) {
			super(NATIVE_ARTIFACTS, weight);
		}

		protected List<ProvisioningAction> getActions(InstallableUnitOperand operand) {
			IInstallableUnit unit = operand.second();
			if (unit.getTouchpointType().getId().equals(NATIVE_TYPE)) {
				return Collections.<ProvisioningAction> singletonList(new CollectNativesAction());
			}
			return null;
		}

		protected IStatus initializePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters) {
			parameters.put(NATIVE_ARTIFACTS, new ArrayList<Object>());
			return null;
		}

		protected IStatus completePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters) {
			@SuppressWarnings("unchecked")
			List<IArtifactRequest> artifactRequests = (List<IArtifactRequest>) parameters.get(NATIVE_ARTIFACTS);
			ProvisioningContext context = (ProvisioningContext) parameters.get(PARM_CONTEXT);
			IProvisioningAgent agent = (IProvisioningAgent) parameters.get(PARM_AGENT);
			DownloadManager dm = new DownloadManager(context, agent);
			for (IArtifactRequest request : artifactRequests) {
				dm.add(request);
			}
			return dm.start(monitor);
		}
	}

	// the list of IUs that we actually transformed... could have come from the repo 
	// or have been user-specified.
	private Collection<IInstallableUnit> processedIUs = new ArrayList<IInstallableUnit>();

	/*
	 * Perform the transformation.
	 */
	public IStatus run(IProgressMonitor monitor) throws ProvisionException {
		SubMonitor progress = SubMonitor.convert(monitor, 5);

		initializeRepos(progress);

		// ensure all the right parameters are set
		validate();

		// figure out which IUs we need to process
		collectIUs(progress.newChild(1));

		// call the engine with only the "collect" phase so all we do is download
		IProfile profile = createProfile();
		try {
			IEngine engine = (IEngine) agent.getService(IEngine.SERVICE_NAME);
			if (engine == null)
				throw new ProvisionException(Messages.exception_noEngineService);
			ProvisioningContext context = new ProvisioningContext(agent);
			context.setMetadataRepositories(getRepositories(true));
			context.setArtifactRepositories(getRepositories(false));
			IProvisioningPlan plan = engine.createPlan(profile, context);
			for (Iterator<IInstallableUnit> iterator = processedIUs.iterator(); iterator.hasNext();) {
				plan.addInstallableUnit(iterator.next());
			}
			IStatus result = engine.perform(plan, getPhaseSet(), progress.newChild(1));
			PhaseSet nativeSet = getNativePhase();
			if (nativeSet != null)
				engine.perform(plan, nativeSet, progress.newChild(1));

			// publish the metadata to a destination - if requested
			publishMetadata(progress.newChild(1));

			setRunnableProperty(destinationArtifactRepository);
			// return the resulting status
			return result;
		} finally {
			// cleanup by removing the temporary profile and unloading the repos which were new
			removeProfile(profile);
			finalizeRepositories();
		}
	}

	private void setRunnableProperty(IArtifactRepository destinationArtifactRepository) {
		if (flagAsRunnable)
			destinationArtifactRepository.setProperty(IArtifactRepository.PROP_RUNNABLE, Boolean.TRUE.toString(), new NullProgressMonitor());
	}

	protected URI[] getRepositories(boolean metadata) {
		List<URI> repos = new ArrayList<URI>();
		for (RepositoryDescriptor repo : sourceRepositories) {
			if (metadata ? repo.isMetadata() : repo.isArtifact())
				repos.add(repo.getRepoLocation());
		}
		return repos.toArray(new URI[repos.size()]);
	}

	protected PhaseSet getPhaseSet() {
		return new PhaseSet(new Phase[] {new Collect(100)}) { /* nothing to override */};
	}

	protected PhaseSet getNativePhase() {
		return new PhaseSet(new Phase[] {new CollectNativesPhase(100)}) { /*nothing to override */};
	}

	/*
	 * Figure out exactly which IUs we have to process.
	 */
	private void collectIUs(IProgressMonitor monitor) throws ProvisionException {
		// if the user told us exactly which IUs to process, then just set it and return.
		if (sourceIUs != null && !sourceIUs.isEmpty()) {
			processedIUs = sourceIUs;
			return;
		}
		// get all IUs from the repos
		if (!hasMetadataSources())
			throw new ProvisionException(Messages.exception_needIUsOrNonEmptyRepo);

		Iterator<IInstallableUnit> itor = getAllIUs(getCompositeMetadataRepository(), monitor).iterator();
		while (itor.hasNext())
			processedIUs.add(itor.next());

		if (processedIUs.isEmpty())
			throw new ProvisionException(Messages.exception_needIUsOrNonEmptyRepo);
	}

	/*
	 * If there is a destination metadata repository set, then add all our transformed
	 * IUs to it. 
	 */
	private void publishMetadata(IProgressMonitor monitor) {
		// publishing the metadata is optional
		if (destinationMetadataRepository == null)
			return;
		destinationMetadataRepository.addInstallableUnits(processedIUs);
	}

	/*
	 * Return a collector over all the IUs contained in the given repository.
	 */
	private IQueryResult<IInstallableUnit> getAllIUs(IMetadataRepository repository, IProgressMonitor monitor) {
		SubMonitor progress = SubMonitor.convert(monitor, 2);
		try {
			return repository.query(QueryUtil.createIUAnyQuery(), progress.newChild(1));
		} finally {
			progress.done();
		}
	}

	/*
	 * Remove the given profile from the profile registry.
	 */
	private void removeProfile(IProfile profile) throws ProvisionException {
		IProfileRegistry registry = Activator.getProfileRegistry();
		registry.removeProfile(profile.getProfileId());
	}

	/*
	 * Create and return a new profile.
	 */
	private IProfile createProfile() throws ProvisionException {
		Map<String, String> properties = new HashMap<String, String>();
		properties.put(IProfile.PROP_CACHE, URIUtil.toFile(destinationArtifactRepository.getLocation()).getAbsolutePath());
		properties.put(IProfile.PROP_INSTALL_FOLDER, URIUtil.toFile(destinationArtifactRepository.getLocation()).getAbsolutePath());
		IProfileRegistry registry = Activator.getProfileRegistry();
		return registry.addProfile(System.currentTimeMillis() + "-" + Math.random(), properties); //$NON-NLS-1$
	}

	/* (non-Javadoc)
	 * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
	 */
	public Object start(IApplicationContext context) throws Exception {
		String[] args = (String[]) context.getArguments().get(IApplicationContext.APPLICATION_ARGS);
		processCommandLineArgs(args);
		// perform the transformation
		run(null);
		return IApplication.EXIT_OK;
	}

	/*
	 * Iterate over the command-line arguments and prepare the transformer for processing.
	 */
	private void processCommandLineArgs(String[] args) throws URISyntaxException {
		if (args == null)
			return;
		for (int i = 0; i < args.length; i++) {
			String option = args[i];
			if (i == args.length - 1 || args[i + 1].startsWith("-")) //$NON-NLS-1$
				continue;
			String arg = args[++i];

			if (option.equalsIgnoreCase("-source")) { //$NON-NLS-1$
				RepositoryDescriptor source = new RepositoryDescriptor();
				source.setLocation(URIUtil.fromString(arg));
				addSource(source);
			}

			if (option.equalsIgnoreCase("-destination")) { //$NON-NLS-1$
				RepositoryDescriptor destination = new RepositoryDescriptor();
				destination.setLocation(URIUtil.fromString(arg));
				addDestination(destination);
			}

			if (option.equalsIgnoreCase("-flagAsRunnable")) { //$NON-NLS-1$
				setFlagAsRunnable(true);
			}
		}
	}

	public void setFlagAsRunnable(boolean runnable) {
		flagAsRunnable = runnable;
	}

	/*
	 * Ensure all mandatory parameters have been set. Throw an exception if there
	 * are any missing. We don't require the user to specify the artifact repository here,
	 * we will default to the ones already registered in the manager. (callers are free
	 * to add more if they wish)
	 */
	private void validate() throws ProvisionException {
		if (!hasMetadataSources() && sourceIUs == null)
			throw new ProvisionException(Messages.exception_needIUsOrNonEmptyRepo);
		if (destinationArtifactRepository == null)
			throw new ProvisionException(Messages.exception_needDestinationRepo);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.equinox.app.IApplication#stop()
	 */
	public void stop() {
		// nothing to do
	}
}

Back to the top