void put(final URI uri, ArtifactData data) throws Exception {
   reporter.trace("put %s %s", uri, data);
   File tmp = createTempFile(repoDir, "mtp", ".whatever");
   tmp.deleteOnExit();
   try {
     copy(uri.toURL(), tmp);
     byte[] sha = SHA1.digest(tmp).digest();
     reporter.trace("SHA %s %s", uri, Hex.toHexString(sha));
     ArtifactData existing = get(sha);
     if (existing != null) {
       reporter.trace("existing");
       xcopy(existing, data);
       return;
     }
     File meta = new File(repoDir, Hex.toHexString(sha) + ".json");
     File file = new File(repoDir, Hex.toHexString(sha));
     rename(tmp, file);
     reporter.trace("file %s", file);
     data.file = file.getAbsolutePath();
     data.sha = sha;
     data.busy = false;
     CommandData cmddata = parseCommandData(data);
     if (cmddata.bsn != null) {
       data.name = cmddata.bsn + "-" + cmddata.version;
     } else data.name = Strings.display(cmddata.title, cmddata.bsn, cmddata.name, uri);
     codec.enc().to(meta).put(data);
     reporter.trace("TD = " + data);
   } finally {
     tmp.delete();
     reporter.trace("puted %s %s", uri, data);
   }
 }
示例#2
0
  public static void testBump() throws Exception {
    File tmp = new File("tmp-ws");
    if (tmp.exists()) IO.deleteWithException(tmp);
    tmp.mkdir();
    assertTrue(tmp.isDirectory());

    try {
      IO.copy(new File("test/ws"), tmp);
      Workspace ws = Workspace.getWorkspace(tmp);
      Project project = ws.getProject("p1");
      int size = project.getProperties().size();
      Version old = new Version(project.getProperty("Bundle-Version"));
      System.err.println("Old version " + old);
      project.bump("=+0");
      Version newv = new Version(project.getProperty("Bundle-Version"));
      System.err.println("New version " + newv);
      assertEquals(old.getMajor(), newv.getMajor());
      assertEquals(old.getMinor() + 1, newv.getMinor());
      assertEquals(0, newv.getMicro());
      assertEquals(size, project.getProperties().size());
      assertEquals("sometime", newv.getQualifier());
    } finally {
      IO.deleteWithException(tmp);
    }
  }
示例#3
0
  public static void testBumpIncludeFile() throws Exception {
    File tmp = new File("tmp-ws");
    if (tmp.exists()) IO.deleteWithException(tmp);
    tmp.mkdir();
    assertTrue(tmp.isDirectory());

    try {
      IO.copy(new File("test/ws"), tmp);
      Workspace ws = Workspace.getWorkspace(tmp);
      Project project = ws.getProject("bump-included");
      project.setTrace(true);
      Version old = new Version(project.getProperty("Bundle-Version"));
      assertEquals(new Version(1, 0, 0), old);
      project.bump("=+0");

      Processor processor = new Processor();
      processor.setProperties(project.getFile("include.txt"));

      Version newv = new Version(processor.getProperty("Bundle-Version"));
      System.err.println("New version " + newv);
      assertEquals(1, newv.getMajor());
      assertEquals(1, newv.getMinor());
      assertEquals(0, newv.getMicro());
    } finally {
      IO.deleteWithException(tmp);
    }
  }
  private Service getService(File base) throws Exception {
    File dataFile = new File(base, "data");
    if (!dataFile.isFile()) return null;

    ServiceData data = getData(ServiceData.class, dataFile);
    return new Service(this, data);
  }
示例#5
0
  public static void testBumpSubBuilders() throws Exception {
    File tmp = new File("tmp-ws");
    if (tmp.exists()) IO.deleteWithException(tmp);
    tmp.mkdir();
    assertTrue(tmp.isDirectory());

    try {
      IO.copy(new File("test/ws"), tmp);
      Workspace ws = Workspace.getWorkspace(tmp);
      Project project = ws.getProject("bump-sub");
      project.setTrace(true);

      assertNull(project.getProperty("Bundle-Version"));

      project.bump("=+0");

      assertNull(project.getProperty("Bundle-Version"));

      for (Builder b : project.getSubBuilders()) {
        assertEquals(new Version(1, 1, 0), new Version(b.getVersion()));
      }
    } finally {
      IO.deleteWithException(tmp);
    }
  }
示例#6
0
 private static void checkPackageInfoFiles(
     Project project, String packageName, boolean expectPackageInfo, boolean expectPackageInfoJava)
     throws Exception {
   File pkgInfo = IO.getFile(project.getSrc(), packageName + "/packageinfo");
   File pkgInfoJava = IO.getFile(project.getSrc(), packageName + "/package-info.java");
   assertEquals(expectPackageInfo, pkgInfo.exists());
   assertEquals(expectPackageInfoJava, pkgInfoJava.exists());
 }
示例#7
0
  @Override
  protected void setUp() throws Exception {
    tmp = IO.getFile("generated/tmp");
    tmp.mkdirs();
    IO.copy(IO.getFile("testdata/ws"), tmp);
    workspace = Workspace.getWorkspace(tmp);
    workspace.refresh();

    InfoRepository repo = workspace.getPlugin(InfoRepository.class);
    t1 = create("bsn-1", new Version(1, 0, 0));
    t2 = create("bsn-2", new Version(1, 0, 0));

    repo.put(new FileInputStream(t1), null);
    repo.put(new FileInputStream(t2), null);
    t1 = repo.get("bsn-1", new Version(1, 0, 0), null);
    t2 = repo.get("bsn-2", new Version(1, 0, 0), null);
    repo.put(new FileInputStream(IO.getFile("generated/biz.aQute.remote.launcher.jar")), null);

    workspace.getPlugins().add(repo);

    File storage = IO.getFile("generated/storage-1");
    storage.mkdirs();

    configuration = new HashMap<String, Object>();
    configuration.put(
        Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
    configuration.put(Constants.FRAMEWORK_STORAGE, storage.getAbsolutePath());

    configuration.put(
        Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "org.osgi.framework.launch;version=1.2");

    framework = new org.apache.felix.framework.FrameworkFactory().newFramework(configuration);
    framework.init();
    framework.start();
    context = framework.getBundleContext();
    location = "reference:" + IO.getFile("generated/biz.aQute.remote.agent.jar").toURI().toString();
    agent = context.installBundle(location);
    agent.start();

    thread =
        new Thread() {
          @Override
          public void run() {
            try {
              Main.main(
                  new String[] {
                    "-s", "generated/storage", "-c", "generated/cache", "-p", "1090", "-et"
                  });
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        };
    thread.setDaemon(true);
    thread.start();

    super.setUp();
  }
示例#8
0
 public static void testClasspath() throws Exception {
   File project = new File("").getAbsoluteFile();
   File workspace = project.getParentFile();
   Processor processor = new Processor();
   EclipseClasspath p = new EclipseClasspath(processor, workspace, project);
   System.err.println(p.getDependents());
   System.err.println(p.getClasspath());
   System.err.println(p.getSourcepath());
   System.err.println(p.getOutput());
 }
示例#9
0
文件: Macro.java 项目: bramk/bnd
 public String _isdir(String args[]) {
   if (args.length < 2) {
     domain.warning("Need at least one file name for ${isdir;...}");
     return null;
   }
   boolean isdir = true;
   for (int i = 1; i < args.length; i++) {
     File f = new File(args[i]).getAbsoluteFile();
     isdir &= f.isDirectory();
   }
   return isdir ? "true" : "false";
 }
示例#10
0
  public List<CommandData> getCommands(File commandDir) throws Exception {
    List<CommandData> result = new ArrayList<CommandData>();

    if (!commandDir.exists()) {
      return result;
    }

    for (File f : commandDir.listFiles()) {
      CommandData data = getData(CommandData.class, f);
      if (data != null) result.add(data);
    }
    return result;
  }
示例#11
0
文件: Macro.java 项目: bramk/bnd
  public String _fmodified(String args[]) throws Exception {
    verifyCommand(args, _fmodifiedHelp, null, 2, Integer.MAX_VALUE);

    long time = 0;
    Collection<String> names = new ArrayList<String>();
    for (int i = 1; i < args.length; i++) {
      Processor.split(args[i], names);
    }
    for (String name : names) {
      File f = new File(name);
      if (f.exists() && f.lastModified() > time) time = f.lastModified();
    }
    return "" + time;
  }
示例#12
0
  public List<ServiceData> getServices(File serviceDir) throws Exception {
    List<ServiceData> result = new ArrayList<ServiceData>();

    if (!serviceDir.exists()) {
      return result;
    }

    for (File sdir : serviceDir.listFiles()) {
      File dataFile = new File(sdir, "data");
      ServiceData data = getData(ServiceData.class, dataFile);
      result.add(data);
    }
    return result;
  }
示例#13
0
文件: Macro.java 项目: bramk/bnd
  String ls(String args[], boolean relative) {
    if (args.length < 2)
      throw new IllegalArgumentException(
          "the ${ls} macro must at least have a directory as parameter");

    File dir = domain.getFile(args[1]);
    if (!dir.isAbsolute())
      throw new IllegalArgumentException(
          "the ${ls} macro directory parameter is not absolute: " + dir);

    if (!dir.exists())
      throw new IllegalArgumentException(
          "the ${ls} macro directory parameter does not exist: " + dir);

    if (!dir.isDirectory())
      throw new IllegalArgumentException(
          "the ${ls} macro directory parameter points to a file instead of a directory: " + dir);

    Collection<File> files = new ArrayList<File>(new SortedList<File>(dir.listFiles()));

    for (int i = 2; i < args.length; i++) {
      Instructions filters = new Instructions(args[i]);
      files = filters.select(files, true);
    }

    List<String> result = new ArrayList<String>();
    for (File file : files) result.add(relative ? file.getName() : file.getAbsolutePath());

    return Processor.join(result, ",");
  }
示例#14
0
  /*
   * Launches against the agent
   */
  public void testSimpleLauncher() throws Exception {
    Project project = workspace.getProject("p1");
    Run bndrun = new Run(workspace, project.getBase(), project.getFile("one.bndrun"));
    bndrun.setProperty("-runpath", "biz.aQute.remote.launcher");
    bndrun.setProperty("-runbundles", "bsn-1,bsn-2");
    bndrun.setProperty("-runremote", "test");

    final RemoteProjectLauncherPlugin pl =
        (RemoteProjectLauncherPlugin) bndrun.getProjectLauncher();
    pl.prepare();
    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicInteger exitCode = new AtomicInteger(-1);

    List<? extends RunSession> sessions = pl.getRunSessions();
    assertEquals(1, sessions.size());

    final RunSession session = sessions.get(0);

    Thread t =
        new Thread("test-launch") {
          public void run() {
            try {
              exitCode.set(session.launch());
            } catch (Exception e) {
              e.printStackTrace();
            } finally {
              latch.countDown();
            }
          }
        };
    t.start();
    Thread.sleep(500);

    for (Bundle b : context.getBundles()) {
      System.out.println(b.getLocation());
    }
    assertEquals(4, context.getBundles().length);
    String p1 = t1.getAbsolutePath();
    System.out.println(p1);

    assertNotNull(context.getBundle(p1));
    assertNotNull(context.getBundle(t2.getAbsolutePath()));

    pl.cancel();
    latch.await();

    assertEquals(-3, exitCode.get());

    bndrun.close();
  }
示例#15
0
  @Override
  protected void setUp() throws Exception {
    tmp = IO.getFile("generated/tmp");
    tmp.mkdirs();

    configuration = new HashMap<String, Object>();
    configuration.put(
        Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
    configuration.put(Constants.FRAMEWORK_STORAGE, new File(tmp, "fwstorage").getAbsolutePath());
    configuration.put(
        Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "org.osgi.framework.launch;version=1.4");
    framework = new org.apache.felix.framework.FrameworkFactory().newFramework(configuration);
    framework.init();
    framework.start();
    BundleContext context = framework.getBundleContext();

    String[] bundles = {
      "../cnf/repo/osgi.cmpn/osgi.cmpn-4.3.1.jar", "testdata/slf4j-simple-1.7.12.jar",
      "testdata/slf4j-api-1.7.12.jar", "testdata/org.apache.aries.util-1.1.0.jar",
      "testdata/org.apache.aries.jmx-1.1.1.jar", "generated/biz.aQute.remote.test.jmx.jar"
    };

    for (String bundle : bundles) {
      String location = "reference:" + IO.getFile(bundle).toURI().toString();
      Bundle b = context.installBundle(location);
      if (!bundle.contains("slf4j-simple")) {
        b.start();
      }
    }

    super.setUp();
  }
示例#16
0
 public void init() throws IOException {
   URL s = getClass().getClassLoader().getResource(SERVICE_JAR_FILE);
   if (s == null)
     if (underTest) return;
     else throw new Error("No " + SERVICE_JAR_FILE + " resource in jar");
   service.getParentFile().mkdirs();
   IO.copy(s, service);
 }
示例#17
0
文件: Macro.java 项目: bramk/bnd
 public String _basename(String args[]) {
   if (args.length < 2) {
     domain.warning("Need at least one file name for ${basename;...}");
     return null;
   }
   String del = "";
   StringBuilder sb = new StringBuilder();
   for (int i = 1; i < args.length; i++) {
     File f = domain.getFile(args[i]);
     if (f.exists() && f.getParentFile().exists()) {
       sb.append(del);
       sb.append(f.getName());
       del = ",";
     }
   }
   return sb.toString();
 }
示例#18
0
文件: Macro.java 项目: bramk/bnd
 /**
  * Get the contents of a file.
  *
  * @param in
  * @return
  * @throws IOException
  */
 public String _cat(String args[]) throws IOException {
   verifyCommand(args, "${cat;<in>}, get the content of a file", null, 2, 2);
   File f = domain.getFile(args[1]);
   if (f.isFile()) {
     return IO.collect(f);
   } else if (f.isDirectory()) {
     return Arrays.toString(f.list());
   } else {
     try {
       URL url = new URL(args[1]);
       return IO.collect(url, "UTF-8");
     } catch (MalformedURLException mfue) {
       // Ignore here
     }
     return null;
   }
 }
示例#19
0
  private void copy(File workspaceDir, InputStream in, Pattern glob, boolean overwrite)
      throws Exception {

    Jar jar = new Jar("dot", in);
    try {
      for (Entry<String, Resource> e : jar.getResources().entrySet()) {

        String path = e.getKey();
        bnd.trace("path %s", path);

        if (glob != null && !glob.matcher(path).matches()) continue;

        Resource r = e.getValue();
        File dest = Processor.getFile(workspaceDir, path);
        if (overwrite
            || !dest.isFile()
            || dest.lastModified() < r.lastModified()
            || r.lastModified() <= 0) {

          bnd.trace("copy %s to %s", path, dest);

          File dp = dest.getParentFile();
          if (!dp.exists() && !dp.mkdirs()) {
            throw new IOException("Could not create directory " + dp);
          }

          IO.copy(r.openInputStream(), dest);
        }
      }
    } finally {
      jar.close();
    }
  }
示例#20
0
  private File create(String bsn, Version v) throws Exception {
    String name = bsn + "-" + v;
    Builder b = new Builder();
    b.setBundleSymbolicName(bsn);
    b.setBundleVersion(v);
    b.setProperty("Random", random++ + "");
    b.setProperty("-resourceonly", true + "");
    b.setIncludeResource("foo;literal='foo'");
    Jar jar = b.build();
    assertTrue(b.check());

    File file = IO.getFile(tmp, name + ".jar");
    file.getParentFile().mkdirs();
    jar.updateModified(System.currentTimeMillis(), "Force it to now");
    jar.write(file);
    b.close();
    return file;
  }
示例#21
0
  private String listFiles(final File cache, List<File> toDelete) throws Exception {
    boolean stopServices = false;
    if (toDelete == null) {
      toDelete = new ArrayList<File>();
    } else {
      stopServices = true;
    }
    int count = 0;
    Formatter f = new Formatter();

    f.format(" - Cache:%n    * %s%n", cache.getCanonicalPath());
    f.format(" - Commands:%n");
    for (CommandData cdata : getCommands(new File(cache, COMMANDS))) {
      f.format("    * %s \t0 handle for \"%s\"%n", cdata.bin, cdata.name);
      toDelete.add(new File(cdata.bin));
      count++;
    }
    f.format(" - Services:%n");
    for (ServiceData sdata : getServices(new File(cache, SERVICE))) {
      if (sdata != null) {
        f.format("    * %s \t0 service directory for \"%s\"%n", sdata.sdir, sdata.name);
        toDelete.add(new File(sdata.sdir));
        File initd = platform.getInitd(sdata);
        if (initd != null && initd.exists()) {
          f.format("    * %s \t0 init.d file for \"%s\"%n", initd.getCanonicalPath(), sdata.name);
          toDelete.add(initd);
        }
        if (stopServices) {
          Service s = getService(sdata);
          try {
            s.stop();
          } catch (Exception e) {
          }
        }
        count++;
      }
    }
    f.format("%n");

    String result = (count > 0) ? f.toString() : null;
    f.close();
    return result;
  }
示例#22
0
  private String listSupportFiles(List<File> toDelete) throws Exception {
    Formatter f = new Formatter();
    try {
      if (toDelete == null) {
        toDelete = new ArrayList<File>();
      }
      int precount = toDelete.size();
      File confFile = IO.getFile(platform.getConfigFile()).getCanonicalFile();
      if (confFile.exists()) {
        f.format("    * %s \t0 Config file%n", confFile);
        toDelete.add(confFile);
      }

      String result = (toDelete.size() > precount) ? f.toString() : null;
      return result;
    } finally {
      f.close();
    }
  }
示例#23
0
  public ArtifactData get(byte[] sha) throws Exception {
    String name = Hex.toHexString(sha);
    File data = IO.getFile(repoDir, name + ".json");
    reporter.trace("artifact data file %s", data);
    if (data.isFile()) { // Bin + metadata
      ArtifactData artifact = codec.dec().from(data).get(ArtifactData.class);
      artifact.file = IO.getFile(repoDir, name).getAbsolutePath();
      return artifact;
    }
    File bin = IO.getFile(repoDir, name);
    if (bin.exists()) { // Only bin
      ArtifactData artifact = new ArtifactData();
      artifact.file = bin.getAbsolutePath();
      artifact.sha = sha;
      return artifact;
    }

    return null;
  }
示例#24
0
  private void copy(String source, String dest, Project p) throws IOException {

    File f = p.getWorkspace().getFile("maven/" + source + ".tmpl");
    InputStream in;

    if (f.isFile()) {
      in = new FileInputStream(f);
    } else {
      in = MavenPlugin.class.getResourceAsStream(source);
      if (in == null) {
        p.error("Cannot find Maven default for %s", source);
        return;
      }
    }

    String s = IO.collect(in);
    String process = p.getReplacer().process(s);

    File d = p.getFile(dest);
    d.getParentFile().mkdirs();
    IO.store(process, d);
  }
示例#25
0
  public static void testOutofDate() throws Exception {
    Workspace ws = Workspace.getWorkspace(new File("test/ws"));
    Project project = ws.getProject("p3");
    File bnd = new File("test/ws/p3/bnd.bnd");
    assertTrue(bnd.exists());

    project.clean();
    File pt = project.getTarget();
    if (!pt.exists() && !pt.mkdirs()) {
      throw new IOException("Could not create directory " + pt);
    }
    try {
      // Now we build it.
      File[] files = project.build();
      System.err.println(project.getErrors());
      System.err.println(project.getWarnings());
      assertTrue(project.isOk());
      assertNotNull(files);
      assertEquals(1, files.length);

      // Now we should not rebuild it
      long lastTime = files[0].lastModified();
      files = project.build();
      assertEquals(1, files.length);
      assertTrue(files[0].lastModified() == lastTime);

      Thread.sleep(2000);

      project.updateModified(System.currentTimeMillis(), "Testing");
      files = project.build();
      assertEquals(1, files.length);
      assertTrue("Must have newer files now", files[0].lastModified() > lastTime);
    } finally {
      project.clean();
    }
  }
示例#26
0
  /**
   * @param data
   * @param target
   * @throws Exception
   * @throws IOException
   */
  public String createCommand(CommandData data, boolean force) throws Exception, IOException {

    // TODO
    // if (Data.validate(data) != null)
    // return "Invalid command data: " + Data.validate(data);

    Map<String, String> map = null;
    if (data.trace) {
      map = new HashMap<String, String>();
      map.put("java.security.manager", "aQute.jpm.service.TraceSecurityManager");
      reporter.trace("tracing");
    }
    String s = platform.createCommand(data, map, force, service.getAbsolutePath());
    if (s == null) storeData(new File(commandDir, data.name), data);
    return s;
  }
示例#27
0
  /**
   * Constructor
   *
   * @throws IOException
   */
  public JustAnotherPackageManager(Reporter reporter, Platform platform, File homeDir, File binDir)
      throws IOException {
    this.platform = platform;
    this.reporter = reporter;
    this.homeDir = homeDir;
    if (!homeDir.exists() && !homeDir.mkdirs())
      throw new IllegalArgumentException("Could not create directory " + homeDir);

    repoDir = IO.getFile(homeDir, "repo");
    if (!repoDir.exists() && !repoDir.mkdirs())
      throw new IllegalArgumentException("Could not create directory " + repoDir);

    commandDir = new File(homeDir, COMMANDS);
    serviceDir = new File(homeDir, SERVICE);
    commandDir.mkdir();
    serviceDir.mkdir();
    service = new File(repoDir, SERVICE_JAR_FILE);
    if (!service.isFile()) init();

    this.binDir = binDir;
    if (!binDir.exists() && !binDir.mkdirs())
      throw new IllegalArgumentException("Could not create bin directory " + binDir);
  }
示例#28
0
  /**
   * Garbage collect repository
   *
   * @throws Exception
   */
  public void gc() throws Exception {
    HashSet<byte[]> deps = new HashSet<byte[]>();

    // deps.add(SERVICE_JAR_FILE);

    for (File cmd : commandDir.listFiles()) {
      CommandData data = getData(CommandData.class, cmd);
      addDependencies(deps, data);
    }

    for (File service : serviceDir.listFiles()) {
      File dataFile = new File(service, "data");
      ServiceData data = getData(ServiceData.class, dataFile);
      addDependencies(deps, data);
    }

    int count = 0;
    for (File f : repoDir.listFiles()) {
      String name = f.getName();
      if (!deps.contains(name)) {
        if (!name.endsWith(".json")
            || !deps.contains(name.substring(0, name.length() - ".json".length()))) { // Remove
          // json
          // files
          // only
          // if
          // the
          // bin
          // is
          // going
          // as
          // well
          f.delete();
          count++;
        } else {

        }
      }
    }
    System.out.format("Garbage collection done (%d file(s) removed)%n", count);
  }
示例#29
0
  /**
   * @param data
   * @param target
   * @throws Exception
   * @throws IOException
   */
  public String createService(ServiceData data) throws Exception, IOException {

    File sdir = new File(serviceDir, data.name);
    if (!sdir.exists() && !sdir.mkdirs()) {
      throw new IOException("Could not create directory " + data.sdir);
    }
    data.sdir = sdir.getAbsolutePath();

    File lock = new File(data.sdir, LOCK);
    data.lock = lock.getAbsolutePath();

    if (data.work == null) data.work = new File(data.sdir, "work").getAbsolutePath();
    if (data.user == null) data.user = platform.user();

    if (data.user == null) data.user = "******";

    new File(data.work).mkdir();

    if (data.log == null) data.log = new File(data.sdir, "log").getAbsolutePath();

    // TODO
    // if (Data.validate(data) != null)
    // return "Invalid service data: " + Data.validate(data);

    if (service == null)
      throw new RuntimeException(
          "Missing biz.aQute.jpm.service in repo, should have been installed by init, try reiniting");

    data.serviceLib = service.getAbsolutePath();

    platform.chown(data.user, true, new File(data.sdir));

    String s = platform.createService(data, null, false);
    if (s == null) storeData(new File(data.sdir, "data"), data);
    return s;
  }
示例#30
0
  public void _workspace(WorkspaceOptions opts) throws Exception {
    File base = bnd.getBase();

    String name = opts._arguments().get(0);

    File workspaceDir = Processor.getFile(base, name);
    name = workspaceDir.getName();
    base = workspaceDir.getParentFile();

    if (base == null) {
      bnd.error(
          "You cannot create a workspace in the root (%s). The parent of a workspace %n"
              + "must be a valid directory. Recommended is to dedicate a directory to %n"
              + "all (or related) workspaces.",
          workspaceDir);
      return;
    }

    if (!opts.anyname() && !Verifier.isBsn(name)) {
      bnd.error(
          "You specified a workspace name that does not follow the recommended pattern "
              + "(it should be like a Bundle Symbolic name). It is a bit pedantic but it "
              + "really helps hwne you get many workspaces. If you insist on this name, use the -a/--anyname option.");
      return;
    }

    Workspace ws = bnd.getWorkspace((File) null);

    if (ws != null && ws.isValid()) {
      bnd.error(
          "You are currently in a workspace already (%s) in %s. You can only create a new workspace outside an existing workspace",
          ws, base);
      return;
    }

    File eclipseDir = workspaceDir;
    workspaceDir.mkdirs();

    if (!opts.single()) workspaceDir = new File(workspaceDir, "scm");

    workspaceDir.mkdirs();

    if (!base.isDirectory()) {
      bnd.error("Could not create directory for the bnd workspace %s", base);
    } else if (!eclipseDir.isDirectory()) {
      bnd.error("Could not create directory for the Eclipse workspace %s", eclipseDir);
    }

    if (!workspaceDir.isDirectory()) {
      bnd.error("Could not create the workspace directory %s", workspaceDir);
      return;
    }

    if (!opts.update() && !opts.force() && workspaceDir.list().length > 0) {
      bnd.error(
          "The workspace directory %s is not empty, specify -u/--update to update or -f/--force to replace",
          workspaceDir);
    }

    InputStream in = getClass().getResourceAsStream("/templates/enroute.zip");
    if (in == null) {
      bnd.error("Cannot find template in this jar %s", "/templates/enroute.zip");
      return;
    }

    Pattern glob = Pattern.compile("[^/]+|cnf/.*|\\...+/.*");

    copy(workspaceDir, in, glob, opts.force());

    File readme = new File(workspaceDir, "README.md");
    if (readme.isFile()) IO.copy(readme, bnd.out);

    bnd.out.printf(
        "%nWorkspace %s created.%n%n" //
            + " Start Eclipse:%n" //
            + "   1) Select the Eclipse workspace %s%n" //
            + "   2) Package Explorer context menu: Import/General/Existing Projects from %s%n"
            + "%n"
            + "", //
        workspaceDir.getName(), eclipseDir, workspaceDir);
  }